Changeset 65205


Ignore:
Timestamp:
May 10, 2015, 2:01:38 AM (9 years ago)
Author:
martinl
Message:

wxGUI: implement RenderLayerMgr and RenderMapMgr to render map layers in threads

Location:
grass/trunk/gui/wxpython
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • grass/trunk/gui/wxpython/core/render.py

    r65158 r65205  
    33
    44@brief Rendering map layers and overlays into map composition image.
    5 
    6 .. todo::
    7     Implement RenderManager also for other layers (see WMS
    8     implementation for details)
    9 
    10 .. todo::
    11     Render classes should not care about updating statusbar (change
    12     emiting events).
    135
    146Classes:
     
    179 - render::Overlay
    1810 - render::Map
     11 - render::RenderLayerMgr
     12 - render::RenderMapMgr
    1913
    2014(C) 2006-2015 by the GRASS Development Team
     
    4135from grass.script import core as grass
    4236from grass.script.utils import try_remove
    43 from grass.script.task import cmdlist_to_tuple
     37from grass.script.task import cmdlist_to_tuple, cmdtuple_to_list
    4438from grass.pydispatch.signal import Signal
    4539
     
    5044from core.debug    import Debug
    5145from core.settings import UserSettings
     46from core.gconsole import CmdThread, GStderr, EVT_CMD_DONE
    5247
    5348class Layer(object):
     
    123118
    124119    def __str__(self):
    125         return self.name
     120        return self.GetCmd(string=True)
    126121
    127122    def __repr__(self):
     
    151146                                 {'type' : self.type, 'name' : self.name})
    152147
     148        # render layers
    153149        env.update(self.render_env)
    154         # execute command
    155150        try:
    156151            if self.type == 'command':
    157                 read = False
     152                first = True
    158153                for c in self.cmd:
    159                     ret, msg = self._runCommand(c, env)
    160                     if ret != 0:
    161                         break
    162                     if not read:
     154                    self.renderMgr.Render(c, env)
     155                    if first:
    163156                        env["GRASS_RENDER_FILE_READ"] = "TRUE"
    164 
    165                 env["GRASS_RENDER_FILE_READ"] = "FALSE"
     157                        first = False
    166158            else:
    167                 ret, msg = self._runCommand(self.cmd, env)
    168             if ret != 0:
    169                 sys.stderr.write(_("Command '%s' failed\n") % self.GetCmd(string = True))
    170                 if msg:
    171                     sys.stderr.write(_("Details: %s\n") % msg)
    172                 raise GException()
    173 
     159                self.renderMgr.Render(self.cmd, env)
    174160        except GException:
     161            sys.stderr.write(_("Command '%s' failed\n") % self.GetCmd(string = True))
     162            sys.stderr.write(_("Details: %s\n") % e)
     163           
    175164            # clean up after problems
    176165            for f in [self.mapfile, self.maskfile]:
     
    179168                try_remove(f)
    180169                f = None
    181 
    182         self.forceRender = False
    183 
     170       
    184171        return self.mapfile
    185 
    186     def _runCommand(self, cmd, env):
    187         """Run command to render data
    188         """
    189         if self.type == 'wms':
    190             ret = 0
    191             msg = ''
    192             self.renderMgr.Render(cmd, env=env)
    193         else:
    194             ret, msg = RunCommand(cmd[0],
    195                                   getErrorMsg = True,
    196                                   quiet = True,
    197                                   env=env,
    198                                   **cmd[1])
    199 
    200         return ret, msg
    201 
     172   
    202173    def GetCmd(self, string = False):
    203174        """Get GRASS command as list of string.
     
    276247            raise GException(_("Unsupported map layer type '%s'") % ltype)
    277248
    278         if ltype == 'wms' and not isinstance(self.renderMgr, RenderWMSMgr):
    279             self.renderMgr = RenderWMSMgr(layer=self,
    280                                           mapfile=self.mapfile,
    281                                           maskfile=self.maskfile)
    282         elif self.type == 'wms' and ltype != 'wms':
    283             self.renderMgr = None
    284 
     249        if not self.renderMgr:
     250            if ltype == 'wms':
     251                renderMgr = RenderWMSMgr
     252            else:
     253                renderMgr = RenderLayerMgr
     254            self.renderMgr = renderMgr(self)
     255       
    285256        self.type = ltype
    286257
     
    321292    def IsDownloading(self):
    322293        """Is data downloading from web server e. g. wms"""
    323         if self.renderMgr is None:
    324             return False
    325         else:
    326             return self.renderMgr.IsDownloading()
     294        return self.renderMgr.IsDownloading()
    327295
    328296    def AbortThread(self):
    329297        """Abort running thread e. g. downloading data"""
    330         if self.renderMgr is None:
    331             return
    332         else:
    333             self.renderMgr.Abort()
     298        self.renderMgr.Abort()
    334299
    335300    def GetRenderMgr(self):
     
    368333        self.render_env["GRASS_RENDER_TRANSPARENT"] = "TRUE"
    369334       
     335class RenderLayerMgr(wx.EvtHandler):
     336    def __init__(self, layer):
     337        """Render layer into image
     338
     339        :param layer: Layer to be rendered
     340        """
     341        self.layer = layer
     342         
     343        wx.EvtHandler.__init__(self)
     344        self.thread = CmdThread(self)
     345        self.cmdStdErr = GStderr(self)
     346       
     347        self.updateProgress = Signal('RenderLayerMgr.updateProgress')
     348        self.Bind(EVT_CMD_DONE, self.OnRenderDone)
     349       
     350        self._startTime = None
     351         
     352    def Render(self, cmd, env):
     353        """Render layer
     354
     355        :param cmd: display command given as tuple
     356        :param env: environmental variables used for rendering
     357        """
     358        Debug.msg(1, "RenderLayerMgr.Render(%s): force=%d img=%s" % \
     359                  (self.layer, self.layer.forceRender, self.layer.mapfile))
     360       
     361        env_cmd = env.copy()
     362        env_cmd['GRASS_RENDER_FILE'] = self.layer.mapfile
     363       
     364        cmd[1]['quiet'] = True # be quiet
     365        cmd_tuple = cmdtuple_to_list(cmd)
     366       
     367        self._startTime = time.time()
     368        self.thread.RunCmd(cmd_tuple, env=env_cmd, stderr=self.cmdStdErr)
     369        self.layer.forceRender = False
     370       
     371    def Abort(self):
     372        """Abort rendering process"""
     373        self.thread.abort(abortall = True)       
     374
     375    def IsDownloading(self):
     376        """Is downloading
     377
     378        :return: always False
     379        """
     380        return False
     381   
     382    def OnRenderDone(self, event):
     383        """Rendering done
     384
     385        Emits updateProcess
     386        """
     387        stop = time.time()
     388        Debug.msg(1, "RenderLayerMgr.OnRenderDone(%s): ret=%d time=%f" % \
     389                      (self.layer, event.returncode, stop - self._startTime))
     390        self.updateProgress.emit(layer=self.layer)
     391       
     392class RenderMapMgr(wx.EvtHandler):
     393    def __init__(self, Map):
     394        """Render map layers as image composition
     395
     396        :param Map: Map object to be rendered
     397        """
     398        wx.EvtHandler.__init__(self)
     399
     400        self.Map = Map
     401        self.thread = CmdThread(self)
     402        self.cmdStdErr = GStderr(self)
     403       
     404        self.updateMap = Signal('RenderMapMgr.updateMap')
     405        self.updateProgress = Signal('RenderMapMgr.updateProgress')
     406        self.renderDone = Signal('RenderMapMgr.renderDone')
     407        self.renderDone.connect(self.OnRenderDone)
     408       
     409        # GRASS environment variable (for rendering)
     410        self._render_env = {"GRASS_RENDER_BACKGROUNDCOLOR" : "000000",
     411                            "GRASS_RENDER_FILE_COMPRESSION" : "0",
     412                            "GRASS_RENDER_TRUECOLOR"       : "TRUE",
     413                            "GRASS_RENDER_TRANSPARENT"     : "TRUE" }
     414       
     415        self._init()
     416        self._rendering = False
     417       
     418    def _init(self, env=None):
     419        """Init render manager
     420
     421        :param env: environmental variables or None
     422        """
     423        self._startTime = time.time()
     424        self.progressInfo = None
     425        self._env = env
     426        self.layers = []
     427       
     428        # re-render from scratch
     429        if os.path.exists(self.Map.mapfile):
     430            os.remove(self.Map.mapfile)
     431       
     432    def _renderLayers(self, env, force = False, overlaysOnly = False):
     433        """Render all map layers into files
     434
     435        :param dict env: environmental variables to be used for rendering process
     436        :param bool force: True to force rendering
     437        :param bool overlaysOnly: True to render only overlays
     438
     439        :return: number of layers to be rendered
     440        """
     441        if overlaysOnly:
     442            self.layers = self.Map.GetListOfLayers(ltype='overlay', active=True)
     443        else:
     444            self.layers = self.Map.GetListOfLayers(active=True)
     445       
     446        # reset progress
     447        self.ReportProgress()
     448
     449        # render map layers if forced
     450        nlayers = 0
     451        for layer in self.layers:
     452            if force or layer.forceRender:
     453                nlayers += 1
     454                layer.Render(env)
     455            else:
     456                layer.GetRenderMgr().updateProgress.emit(layer=layer)
     457       
     458        Debug.msg(1, "RenderMapMgr.Render(): %d layers to be rendered "
     459                  "(force=%d, all active layers -> %d)" % (nlayers, force,
     460                                                           len(self.layers)))
     461       
     462        return nlayers
     463   
     464    def Render(self, force = False, windres = False):
     465        """Render map composition
     466
     467        :param bool force: force rendering all map layers in the composition
     468        :param windres: True for region resolution instead for map resolution
     469        """
     470        if self._rendering:
     471            Debug.msg(1, "RenderMapMgr().Render(): cancelled (already rendering)")
     472            return
     473       
     474        wx.BeginBusyCursor()
     475        self._rendering = True
     476       
     477        env = os.environ.copy()
     478        env.update(self._render_env)
     479        # use external gisrc if defined
     480        if self.Map.gisrc:
     481            env['GISRC'] = self.Map.gisrc
     482        env['GRASS_REGION'] = self.Map.SetRegion(windres)
     483        env['GRASS_RENDER_WIDTH'] = str(self.Map.width)
     484        env['GRASS_RENDER_HEIGHT'] = str(self.Map.height)
     485        driver = UserSettings.Get(group = 'display', key = 'driver', subkey = 'type')
     486        if driver == 'png':
     487            env['GRASS_RENDER_IMMEDIATE'] = 'png'
     488        else:
     489            env['GRASS_RENDER_IMMEDIATE'] = 'cairo'
     490       
     491        self._init(env)
     492        if self._renderLayers(env, force, windres) == 0:
     493            self.renderDone.emit()
     494       
     495    def OnRenderDone(self):
     496        """Rendering process done
     497
     498        Make image composiotion, emits updateMap event.
     499        """
     500        stopTime = time.time()
     501       
     502        maps = list()
     503        masks = list()
     504        opacities = list()
     505       
     506        for layer in self.layers:
     507            maps.append(layer.mapfile)
     508            masks.append(layer.maskfile)
     509            opacities.append(str(layer.opacity))
     510       
     511        # run g.pngcomp to get composite image
     512        bgcolor = ':'.join(map(str, UserSettings.Get(group = 'display', key = 'bgcolor',
     513                                                     subkey = 'color')))
     514        startCompTime = time.time()
     515        if maps:
     516            ret, msg = RunCommand('g.pnmcomp',
     517                                  getErrorMsg = True,
     518                                  overwrite = True,
     519                                  input = '%s' % ",".join(maps),
     520                                  mask = '%s' % ",".join(masks),
     521                                  opacity = '%s' % ",".join(opacities),
     522                                  bgcolor = bgcolor,
     523                                  width = self.Map.width,
     524                                  height = self.Map.height,
     525                                  output = self.Map.mapfile,
     526                                  env=self._env)
     527            if ret != 0:
     528                raise GException(_("Rendering failed: %s" % msg))
     529       
     530        stop = time.time()
     531        Debug.msg (1, "RenderMapMgr.OnRenderDone() time=%f sec (comp: %f)" % \
     532                   (stop - self._startTime, stop - startCompTime))
     533       
     534        self._rendering = False
     535        wx.EndBusyCursor()
     536       
     537        self.updateMap.emit()
     538
     539    def Abort(self):
     540        """Abort all rendering processes"""
     541        for layer in self.layers:
     542            layer.GetRenderMgr().Abort()
     543       
     544    def ReportProgress(self, layer=None):
     545        """Calculates progress in rendering/downloading
     546        and emits signal to inform progress bar about progress.
     547
     548        Emits renderDone event when progressVal is equal to range.
     549       
     550        :param layer: Layer to be processed or None to reset
     551        """
     552        if self.progressInfo is None or layer is None:
     553            self.progressInfo = {'progresVal' : 0,   # current progress value
     554                                 'downloading' : [], # layers, which are downloading data
     555                                 'rendered' : [],    # already rendered layers
     556                                 'range' : len(self.layers)}
     557        else:
     558            if layer not in self.progressInfo['rendered']:
     559                self.progressInfo['rendered'].append(layer)
     560            if layer.IsDownloading() and \
     561                    layer not in self.progressInfo['downloading']:
     562                self.progressInfo['downloading'].append(layer)
     563            else:
     564                self.progressInfo['progresVal'] += 1
     565                if layer in self.progressInfo['downloading']:
     566                    self.progressInfo['downloading'].remove(layer)
     567
     568        # for updating statusbar text
     569        stText = ''
     570        first = True
     571        for layer in self.progressInfo['downloading']:
     572            if first:
     573                stText += _("Downloading data ")
     574                first = False
     575            else:
     576                stText += ', '
     577            stText += '<%s>' % layer.GetName()
     578        if stText:
     579            stText += '...'
     580
     581        if  self.progressInfo['range'] != len(self.progressInfo['rendered']):
     582            if stText:
     583                stText = _('Rendering & ') + stText
     584            else:
     585                stText = _('Rendering...')
     586       
     587        self.updateProgress.emit(range=self.progressInfo['range'],
     588                                 value=self.progressInfo['progresVal'],
     589                                 text=stText)
     590       
     591        if layer and self.progressInfo['progresVal'] == self.progressInfo['range']:
     592            self.renderDone.emit()
     593
    370594class Map(object):
    371595    def __init__(self, gisrc = None):
     
    374598        :param gisrc: alternative gisrc (used eg. by georectifier)
    375599        """
    376         Debug.msg (1, "Map.__init__(): %s" % gisrc)
     600        Debug.msg (1, "Map.__init__(): gisrc=%s" % gisrc)
    377601        # region/extent settigns
    378602        self.wind      = dict() # WIND settings (wind file)
     
    389613        # path to external gisrc
    390614        self.gisrc = gisrc
    391 
     615       
    392616        # generated file for g.pnmcomp output for rendering the map
    393617        self.mapfile = grass.tempfile(create = False) + '.ppm'
     
    398622            RunCommand('g.region', flags='d')
    399623
    400         # info to report progress
    401         self.progressInfo = None
    402 
    403         # GRASS environment variable (for rendering)
    404         self.render_env = {"GRASS_RENDER_BACKGROUNDCOLOR" : "000000",
    405                             "GRASS_RENDER_FILE_COMPRESSION" : "0",
    406                             "GRASS_RENDER_TRUECOLOR"       : "TRUE",
    407                             "GRASS_RENDER_TRANSPARENT"     : "TRUE",
    408                             }
    409 
    410624        # projection info
    411625        self.projinfo = self._projInfo()
    412626
    413         # is some layer being downloaded?
    414         self.downloading = False
    415 
    416627        self.layerChanged = Signal('Map.layerChanged')
    417         self.updateProgress = Signal('Map.updateProgress')
    418628        self.layerRemoved = Signal('Map:layerRemoved')
    419629        self.layerAdded = Signal('Map:layerAdded')
    420 
     630       
     631        self.renderMgr = RenderMapMgr(self)
     632
     633    def GetRenderMgr(self):
     634        """Get render manager """
     635        return self.renderMgr
     636       
    421637    def GetProjInfo(self):
    422638        """Get projection info"""
     
    8451061        return selected
    8461062
    847     def _renderLayers(self, env, force = False, overlaysOnly = False):
    848         """Render all map layers into files
    849 
    850         :param bool force: True to force rendering
    851         :param bool overlaysOnly: True to render only overlays
    852 
    853         :return: list of maps, masks and opacities
    854         """
    855         maps = list()
    856         masks = list()
    857         opacities = list()
    858         # render map layers
    859         if overlaysOnly:
    860             layers = self.overlays
    861         else:
    862             layers = self.layers + self.overlays
    863 
    864         self.downloading = False
    865        
    866         self.ReportProgress(layer=None)
    867 
    868         for layer in layers:
    869             # skip non-active map layers
    870             if not layer or not layer.active:
    871                 continue
    872 
    873             # render
    874             if force or layer.forceRender:
    875                 if not layer.Render(env):
    876                     continue
    877 
    878             if layer.IsDownloading():
    879                 self.downloading = True
    880 
    881             self.ReportProgress(layer=layer)
    882 
    883             # skip map layers when rendering fails
    884             if not os.path.exists(layer.mapfile):
    885                 continue
    886 
    887             # add image to compositing list
    888             if layer.type != "overlay":
    889                 maps.append(layer.mapfile)
    890                 masks.append(layer.maskfile)
    891                 opacities.append(str(layer.opacity))
    892        
    893         return maps, masks, opacities
    894 
    895     def GetMapsMasksAndOpacities(self, force, windres, env):
    896         """
    897         Used by Render function.
    898 
    899         :return: maps, masks, opacities
    900         """
    901         return self._renderLayers(force=force, env=env)
    902 
    9031063    def Render(self, force = False, windres = False):
    9041064        """Creates final image composite
     
    9101070        :param windres: use region resolution (True) otherwise display
    9111071                        resolution
    912 
    913         :return: name of file with rendered image or None
    914         """
    915         wx.BeginBusyCursor()
    916         env = os.environ.copy()
    917         env.update(self.render_env)
    918         # use external gisrc if defined
    919         if self.gisrc:
    920             env['GISRC'] = self.gisrc
    921         env['GRASS_REGION'] = self.SetRegion(windres)
    922         env['GRASS_RENDER_WIDTH'] = str(self.width)
    923         env['GRASS_RENDER_HEIGHT'] = str(self.height)
    924         driver = UserSettings.Get(group = 'display', key = 'driver', subkey = 'type')
    925         if driver == 'png':
    926             env['GRASS_RENDER_IMMEDIATE'] = 'png'
    927         else:
    928             env['GRASS_RENDER_IMMEDIATE'] = 'cairo'
    929        
    930         start = time.time()
    931         maps, masks, opacities = self.GetMapsMasksAndOpacities(force, windres, env)
    932 
    933         # ugly hack for MSYS
    934         if sys.platform != 'win32':
    935             mapstr = ",".join(maps)
    936             maskstr = ",".join(masks)
    937         else:
    938             mapstr = ""
    939             for item in maps:
    940                 mapstr += item.replace('\\', '/')
    941             mapstr = mapstr.rstrip(',')
    942             maskstr = ""
    943             for item in masks:
    944                 maskstr += item.replace('\\', '/')
    945             maskstr = maskstr.rstrip(',')
    946 
    947         # run g.pngcomp to get composite image
    948         bgcolor = ':'.join(map(str, UserSettings.Get(group = 'display', key = 'bgcolor',
    949                                                      subkey = 'color')))
    950         startComp = time.time()
    951         if maps:
    952             ret, msg = RunCommand('g.pnmcomp',
    953                                   getErrorMsg = True,
    954                                   overwrite = True,
    955                                   input = '%s' % ",".join(maps),
    956                                   mask = '%s' % ",".join(masks),
    957                                   opacity = '%s' % ",".join(opacities),
    958                                   bgcolor = bgcolor,
    959                                   width = self.width,
    960                                   height = self.height,
    961                                   output = self.mapfile,
    962                                   env=env)
    963 
    964             if ret != 0:
    965                 print >> sys.stderr, _("ERROR: Rendering failed. Details: %s") % msg
    966                 wx.EndBusyCursor()
    967                 return None
    968 
    969         stop = time.time()
    970         Debug.msg (1, "Map.Render() force=%s -> time=%f (comp: %f)" % \
    971                    (force, stop - start, stop - startComp))
    972        
    973         wx.EndBusyCursor()
    974         if not maps:
    975             return None
    976 
    977         return self.mapfile
    978 
     1072        """
     1073        self.renderMgr.Render(force, windres)
     1074       
    9791075    def _addLayer(self, layer, render=False, pos=-1):
    9801076        if layer.type == 'overlay':
     
    10241120        renderMgr = layer.GetRenderMgr()
    10251121        if renderMgr:
    1026             renderMgr.dataFetched.connect(self.layerChanged)
    1027             renderMgr.updateProgress.connect(self.ReportProgress)
     1122            if layer.type == 'wms':
     1123                renderMgr.dataFetched.connect(self.layerChanged)
     1124            renderMgr.updateProgress.connect(self.renderMgr.ReportProgress)
    10281125       
    10291126        self.layerAdded.emit(layer=layer)
     
    11081205            layer.SetOpacity(kargs['opacity'])
    11091206
     1207
    11101208        if render and not layer.Render():
    11111209            raise GException(_("Unable to render map layer <%s>.") %
    11121210                             layer.GetName())
    1113 
     1211       
    11141212        self.layerChanged(layer=layer)
     1213       
    11151214        return layer
    11161215
     
    13221421        for l in self.layers + self.overlays:
    13231422            l.AbortThread()
    1324 
    1325     def ReportProgress(self, layer):
    1326         """Calculates progress in rendering/downloading
    1327         and emits signal to inform progress bar about progress.
    1328         """
    1329         if self.progressInfo is None or layer is None:
    1330             self.progressInfo = {'progresVal' : 0, # current progress value
    1331                                  'downloading' : [], # layers, which are downloading data
    1332                                  'rendered' : [], # already rendered layers
    1333                                  'range' : len(self.GetListOfLayers(active = True)) +
    1334                                            len(self.GetListOfLayers(active = True, ltype = 'overlay')) -
    1335                                            len(self.GetListOfLayers(active = True, ltype = '3d-raster'))}
    1336         else:
    1337             if layer not in self.progressInfo['rendered']:
    1338                 self.progressInfo['rendered'].append(layer)
    1339             if layer.IsDownloading() and \
    1340                     layer not in self.progressInfo['downloading']:
    1341                 self.progressInfo['downloading'].append(layer)
    1342             else:
    1343                 self.progressInfo['progresVal'] += 1
    1344                 if layer in self.progressInfo['downloading']:
    1345                     self.progressInfo['downloading'].remove(layer)
    1346 
    1347         # for updating statusbar text
    1348         stText = ''
    1349         first = True
    1350         for layer in self.progressInfo['downloading']:
    1351             if first:
    1352                 stText += _("Downloading data ")
    1353                 first = False
    1354             else:
    1355                 stText += ', '
    1356             stText += '<%s>' % layer.GetName()
    1357         if stText:
    1358             stText += '...'
    1359 
    1360         if  self.progressInfo['range'] != len(self.progressInfo['rendered']):
    1361             if stText:
    1362                 stText = _('Rendering & ') + stText
    1363             else:
    1364                 stText = _('Rendering...')
    1365 
    1366         self.updateProgress.emit(range=self.progressInfo['range'],
    1367                                  value=self.progressInfo['progresVal'],
    1368                                  text=stText)
  • grass/trunk/gui/wxpython/core/ws.py

    r64406 r65205  
    4646    """Fetch and prepare WMS data for rendering.
    4747    """
    48     def __init__(self, layer, mapfile, maskfile):
     48    def __init__(self, layer):
    4949        if not haveGdal:
    5050            sys.stderr.write(_("Unable to load GDAL Python bindings.\n"\
     
    5252
    5353        self.layer = layer
    54 
     54       
    5555        wx.EvtHandler.__init__(self)
    5656
     
    6666        self.cmdStdErr = GStderr(self)
    6767
    68         self.mapfile = mapfile
    69         self.maskfile = maskfile
    7068        self.tempMap = grass.tempfile()
    7169        self.dstSize = {}
     
    120118            self.renderedRegion = region
    121119
    122             try_remove(self.mapfile)
     120            try_remove(self.layer.mapfile)
    123121            try_remove(self.tempMap)
    124122
     
    160158            return
    161159
    162         self.mapMerger = GDALRasterMerger(targetFile = self.mapfile, region = self.renderedRegion,
     160        self.mapMerger = GDALRasterMerger(targetFile = self.layer.mapfile,
     161                                          region = self.renderedRegion,
    163162                                          bandsNum = 3, gdalDriver = 'PNM', fillValue = 0)
    164163        self.mapMerger.AddRasterBands(self.tempMap, {1 : 1, 2 : 2, 3 : 3})
    165164        del self.mapMerger
    166165
    167         self.maskMerger = GDALRasterMerger(targetFile = self.maskfile, region = self.renderedRegion,
     166        self.maskMerger = GDALRasterMerger(targetFile = self.layer.maskfile, region = self.renderedRegion,
    168167                                           bandsNum = 1, gdalDriver = 'PNM', fillValue = 0)
    169168        #{4 : 1} alpha channel (4) to first and only channel (1) in mask
  • grass/trunk/gui/wxpython/lmgr/layertree.py

    r64876 r65205  
    371371            self.rerender = False
    372372            if self.mapdisplay.IsAutoRendered():
    373                 self.mapdisplay.GetMapWindow().UpdateMap(render=True)
     373                self.mapdisplay.GetMapWindow().UpdateMap(render=False)
    374374       
    375375        event.Skip()
     
    11041104            checked = lchecked
    11051105        else:
    1106             checked = True
     1106            checked = False
    11071107       
    11081108        self.forceCheck = True
     
    11441144                ctrlId = None
    11451145           
    1146             # add a data object to hold the layer's command (does not apply to generic command layers)
     1146            # add a data object to hold the layer's command (does not
     1147            # apply to generic command layers)
    11471148            self.SetPyData(layer, ({'cmd'      : cmd,
    11481149                                    'type'     : ltype,
     
    11541155                                    'propwin'  : None},
    11551156                                   None))
     1157           
    11561158            # must be after SetPyData because it calls OnLayerChecked
    11571159            # which calls GetVisibleLayers which requires already set PyData
     
    11841186            else:
    11851187                self.first = False
    1186        
    11871188        else: # group
    11881189            self.SetPyData(layer, ({'cmd'      : None,
     
    12101211                self.OnRenameLayer(None)
    12111212
    1212        
    12131213        return layer
    12141214
     
    12241224            else:
    12251225                win.Show()
    1226            
    12271226            return
    12281227       
     
    12311230        Debug.msg (3, "LayerTree.PropertiesDialog(): ltype=%s" % \
    12321231                   ltype)
    1233 
     1232       
    12341233        cmd = None
    12351234        if self.GetLayerInfo(layer, key = 'cmd'):
    1236 
    12371235            module = GUI(parent = self, show = show, centreOnParent = False)
    12381236            module.ParseCommand(self.GetLayerInfo(layer, key = 'cmd'),
    1239                                 completed = (self.GetOptData,layer,params))
    1240            
     1237                                completed = (self.GetOptData, layer, params))
    12411238            self.SetLayerInfo(layer, key = 'cmd', value = module.GetCmd())
    12421239        elif self.GetLayerInfo(layer, key = 'type') != 'command':
    12431240            cmd = [ltype2command[ltype]]
    1244             if ltype == 'raster':
    1245                 if UserSettings.Get(group = 'rasterLayer', key = 'opaque', subkey = 'enabled'):
    1246                     cmd.append('-n')
    1247             elif ltype == 'rgb':
     1241            if ltype in ('raster', 'rgb'):
    12481242                if UserSettings.Get(group = 'rasterLayer', key = 'opaque', subkey = 'enabled'):
    12491243                    cmd.append('-n')
    12501244            elif ltype == 'vector':
    12511245                cmd += GetDisplayVectSettings()
    1252            
     1246       
    12531247        if cmd:
    1254             GUI(parent = self, centreOnParent = False).ParseCommand(cmd,
    1255                                                                     completed = (self.GetOptData,layer,params))
    1256        
     1248            module = GUI(parent = self, centreOnParent = False)
     1249            module.ParseCommand(cmd,
     1250                                completed = (self.GetOptData,layer,params))
     1251           
    12571252    def OnActivateLayer(self, event):
    12581253        """Double click on the layer item.
     
    16671662                         message = _("Map <%s> not found.") % mapName)
    16681663                return
    1669        
     1664
     1665            if not mapLayer.IsActive():
     1666                self.forceCheck = True
     1667                self.CheckItem(layer, True)
     1668                mapLayer.SetActive(True)
     1669               
    16701670        # update layer data
    16711671        if params:
     
    16741674       
    16751675        # change parameters for item in layers list in render.Map
    1676         self.ChangeLayer(layer)
    1677        
     1676        if params:
     1677            self.ChangeLayer(layer)
     1678
    16781679        # set region if auto-zooming is enabled or layer tree contains
    16791680        # only one map layer
    16801681        if dcmd:
    1681             if not self.mapdisplay.IsPaneShown('3d') and (self.first or
    1682                     UserSettings.Get(group = 'display', key = 'autoZooming', subkey = 'enabled')):
     1682            if not self.mapdisplay.IsPaneShown('3d') and \
     1683               (self.first or \
     1684                UserSettings.Get(group = 'display', key = 'autoZooming', subkey = 'enabled')):
    16831685                mapLayer = self.GetLayerInfo(layer, key = 'maplayer')
    16841686                if mapLayer.GetType() in ('raster', 'vector'):
    16851687                    self.mapdisplay.MapWindow.ZoomToMap(layers = [mapLayer,],
    16861688                                                        render = False)
    1687            
     1689                   
    16881690            self.first = False # first layer has been already added to
    16891691                               # the layer tree
     
    17171719                if nlayers < 2:
    17181720                    mapWin.ResetView()
    1719 
     1721       
    17201722    def GetVisibleLayers(self, skipDigitized=False):
    17211723        # make a list of visible layers
     
    17761778                if not found:
    17771779                    layerName = self.GetItemText(item)
    1778        
    1779         maplayer = self.Map.ChangeLayer(layer = self.GetLayerInfo(item, key = 'maplayer'), type = type,
    1780                                         command = cmdlist, name = layerName,
    1781                                         active = chk, hidden = hidden, opacity = opac, render = False)
     1780
     1781        maplayer = self.Map.ChangeLayer(layer = self.GetLayerInfo(item, key = 'maplayer'),
     1782                                        type = type, command = cmdlist, name = layerName,
     1783                                        active = chk, hidden = hidden, opacity = opac)
    17821784       
    17831785        self.SetLayerInfo(item, key = 'maplayer', value = maplayer)
     
    17861788        if self.mapdisplay.GetToolbar('vdigit'):
    17871789            self.mapdisplay.GetToolbar('vdigit').UpdateListOfLayers(updateTool = True)
    1788 
     1790       
    17891791        self.Map.SetLayers(self.GetVisibleLayers())
     1792       
    17901793        # redraw map if auto-rendering is enabled
    17911794        self.rerender = True
  • grass/trunk/gui/wxpython/mapdisp/frame.py

    r64610 r65205  
    248248       
    249249        #
    250         self.Map.updateProgress.connect(self.statusbarManager.SetProgress)
     250        self.Map.GetRenderMgr().updateProgress.connect(self.statusbarManager.SetProgress)
    251251       
    252252    def GetMapWindow(self):
  • grass/trunk/gui/wxpython/mapdisp/main.py

    r65158 r65205  
    66Classes:
    77 - mapdisp::DMonMap
    8  - mapdisp::DMonMapDirect
    98 - mapdisp::Layer
    109 - mapdisp::LayerList
     
    3938from core.giface   import StandaloneGrassInterface
    4039from core.gcmd     import RunCommand
    41 from core.render   import Map, MapLayer, Overlay
     40from core.render   import Map, MapLayer, Overlay, RenderMapMgr
    4241from core.utils import _
    4342from mapdisp.frame import MapFrame
     
    6766        """
    6867        Map.__init__(self)
    69 
     68       
    7069        self._giface = giface
    7170
     
    9493        self.query = Signal('DMonMap.query')
    9594
    96     def GetLayersFromCmdFile(self, mapfile=None):
     95        self.renderMgr = RenderMapMgr(self)
     96       
     97    def GetLayersFromCmdFile(self):
    9798        """Get list of map layers from cmdfile
    9899        """
     
    156157                else:
    157158                    classLayer = MapLayer
    158                     args['mapfile'] = mapfile
    159159                    args['ltype'] = ltype
    160160               
    161161                mapLayer = classLayer(name = name, cmd = cmd, Map = None,
    162162                                      hidden = True, **args)
    163                
     163                mapLayer.GetRenderMgr().updateProgress.connect(self.GetRenderMgr().ReportProgress)
     164
    164165                exists = False
    165166                for i, layer in enumerate(existingLayers):
     
    246247        #return layer
    247248
    248 class DMonMapDirect(DMonMap):
    249     def __init__(self, giface, cmdfile=None, mapfile=None):
    250         """Map composition (stack of map layers and overlays)
    251 
    252         :param cmdline: full path to the cmd file (defined by d.mon)
    253         :param mapfile: full path to the map file (defined by d.mon)
    254         """
    255         DMonMap.__init__(self, giface, cmdfile, mapfile)
    256        
    257         self.render_env['GRASS_RENDER_BACKGROUNDCOLOR'] = 'FFFFFF'
    258         self.render_env['GRASS_RENDER_TRANSPARENT'] = 'FALSE'
    259         self.render_env['GRASS_RENDER_FILE_READ'] = 'TRUE'
    260        
    261     def Render(self, *args, **kwargs):
    262         """Render layer to image.
    263 
    264         For input params and returned data see overridden method in Map class.
    265         """
    266         wx.BeginBusyCursor()
    267         env = os.environ.copy()
    268         env.update(self.render_env)
    269         # use external gisrc if defined
    270         if self.gisrc:
    271             env['GISRC'] = self.gisrc
    272         env['GRASS_REGION'] = self.SetRegion(kwargs.get('windres', False))
    273         env['GRASS_RENDER_WIDTH'] = str(self.width)
    274         env['GRASS_RENDER_HEIGHT'] = str(self.height)
    275         driver = UserSettings.Get(group = 'display', key = 'driver', subkey = 'type')
    276         if driver == 'png':
    277             env['GRASS_RENDER_IMMEDIATE'] = 'png'
    278         else:
    279             env['GRASS_RENDER_IMMEDIATE'] = 'cairo'
    280 
    281         if os.path.exists(self.mapfile):
    282             os.remove(self.mapfile)
    283        
    284         self.GetMapsMasksAndOpacities(kwargs['force'], kwargs.get('windres', False), env)
    285         wx.EndBusyCursor()
    286 
    287         return self.mapfile
    288 
    289     def GetLayersFromCmdFile(self):
    290         super(self.__class__, self).GetLayersFromCmdFile(self.mapfile)
    291        
    292249class Layer(object):
    293250    """@implements core::giface::Layer"""
     
    445402
    446403        if __name__ == "__main__":
    447             dmonMap = DMonMapDirect
    448             # if decorations:
    449             #    dmonMap = DMonMap
    450404            self.cmdTimeStamp = os.path.getmtime(monFile['cmd'])
    451             self.Map = dmonMap(giface=self._giface, cmdfile=monFile['cmd'],
     405            self.Map = DMonMap(giface=self._giface, cmdfile=monFile['cmd'],
    452406                               mapfile = monFile['map'])
    453407           
  • grass/trunk/gui/wxpython/mapwin/buffered.py

    r64627 r65205  
    150150
    151151        # render output objects
    152         self.mapfile = None   # image file to be rendered
    153152        self.img     = None   # wx.Image object (self.mapfile)
    154153        # decoration overlays
     
    182181
    183182        # rerender when Map reports change
    184         self.Map.layerChanged.connect(self.OnUpdateMap)
    185 
     183        ### self.Map.layerChanged.connect(self.OnUpdateMap)
     184        self.Map.GetRenderMgr().renderDone.connect(self._updateMFinished)
     185       
    186186        # vars for handling mouse clicks
    187187        self.dragid   = -1
     
    705705        """
    706706        imgId = 99
    707         if self.mapfile and self.Map.mapfile and os.path.isfile(self.Map.mapfile) and \
     707        if self.Map.mapfile and os.path.isfile(self.Map.mapfile) and \
    708708                os.path.getsize(self.Map.mapfile):
    709709            img = wx.Image(self.Map.mapfile, wx.BITMAP_TYPE_ANY)
     
    809809        :func:`UpdateMap` for arguments description.
    810810        """
     811        Debug.msg (1, "BufferedWindow.UpdateMap(): started "
     812                   "(render=%s, renderVector=%s)" % (render, renderVector))
     813
    811814        self.resize = False
    812815
     
    814817        if self.IsAlwaysRenderEnabled() and self.img is None:
    815818            render = True
    816 
    817 
    818         #
    819         # render background image if needed
    820         #
    821 
    822         # here was the change of the layertree rerender variable
    823         # but it is fully the problem of layertree
    824         # and so it is handled there
    825         # remove this comment when it is old enough
    826 
     819       
    827820        try:
    828821            if render:
    829822                # update display size
    830823                self.Map.ChangeMapSize(self.GetClientSize())
    831                 if self._properties.resolution:
    832                     # use computation region resolution for rendering
    833                     windres = True
    834                 else:
    835                     windres = False
    836 
    837                 self.mapfile = self.Map.Render(force = True,
    838                                                windres = windres)
    839             else:
    840                 self.mapfile = self.Map.Render(force = False)
    841 
     824               
     825            self.Map.Render(force=render,
     826                            windres=self._properties.resolution)
    842827        except GException as e:
    843             GError(message = e.value)
    844             self.mapfile = None
    845 
     828                GError(message=e.value)
     829
     830    def _updateMFinished(self, renderVector=True):
     831        Debug.msg (1, "BufferedWindow.UpdateMap(): finished")
    846832        self.img = self.GetImage() # id=99
    847 
     833       
    848834        #
    849835        # clear pseudoDcs
     
    854840            pdc.Clear()
    855841            pdc.RemoveAll()
    856 
     842       
    857843        #
    858844        # draw background map image to PseudoDC
     
    863849            try:
    864850                id = self.imagedict[self.img]['id']
    865             except:
     851            except Exception as e:
     852                Debug.mgs(1, "UpdateMap() failed: %s", e)
    866853                return False
    867 
    868854            self.Draw(self.pdc, self.img, drawid = id)
    869855
     
    873859        if renderVector and hasattr(self, "digit"):
    874860            self._updateMap()
     861       
    875862        #
    876863        # render overlays
     
    881868                id = self.imagedict[img]['id']
    882869                self.Draw(self.pdc, img = img, drawid = id,
    883                           pdctype = self.overlays[id].pdcType, coords = self.overlays[id].coords)
    884 
     870                          pdctype = self.overlays[id].pdcType,
     871                          coords = self.overlays[id].coords)
     872       
    885873        for id in self.textdict.keys():
    886874            self.Draw(self.pdc, img = self.textdict[id], drawid = id,
    887875                      pdctype = 'text', coords = [10, 10, 10, 10])
    888 
     876       
    889877        # optionally draw computational extent box
    890878        self.DrawCompRegionExtent()
    891 
     879       
    892880        #
    893881        # redraw pdcTmp if needed
    894882        #
    895 
     883       
    896884        # draw registered graphics
    897885        if  len(self.graphicsSetList) > 0:
     
    913901        if len(self.polycoords) > 0:
    914902            self.DrawLines(self.pdcTmp)
    915        
    916         Debug.msg (1, "BufferedWindow.UpdateMap(): render=%s, renderVector=%s" % \
    917                    (render, renderVector))
    918        
     903
    919904        return True
    920 
     905   
    921906    def DrawCompRegionExtent(self):
    922907        """Draw computational region extent in the display
Note: See TracChangeset for help on using the changeset viewer.