[GRASS-SVN] r65205 - in grass/trunk/gui/wxpython: core lmgr mapdisp mapwin
svn_grass at osgeo.org
svn_grass at osgeo.org
Sun May 10 02:01:39 PDT 2015
Author: martinl
Date: 2015-05-10 02:01:38 -0700 (Sun, 10 May 2015)
New Revision: 65205
Modified:
grass/trunk/gui/wxpython/core/render.py
grass/trunk/gui/wxpython/core/ws.py
grass/trunk/gui/wxpython/lmgr/layertree.py
grass/trunk/gui/wxpython/mapdisp/frame.py
grass/trunk/gui/wxpython/mapdisp/main.py
grass/trunk/gui/wxpython/mapwin/buffered.py
Log:
wxGUI: implement RenderLayerMgr and RenderMapMgr to render map layers in threads
Modified: grass/trunk/gui/wxpython/core/render.py
===================================================================
--- grass/trunk/gui/wxpython/core/render.py 2015-05-09 20:47:32 UTC (rev 65204)
+++ grass/trunk/gui/wxpython/core/render.py 2015-05-10 09:01:38 UTC (rev 65205)
@@ -3,19 +3,13 @@
@brief Rendering map layers and overlays into map composition image.
-.. todo::
- Implement RenderManager also for other layers (see WMS
- implementation for details)
-
-.. todo::
- Render classes should not care about updating statusbar (change
- emiting events).
-
Classes:
- render::Layer
- render::MapLayer
- render::Overlay
- render::Map
+ - render::RenderLayerMgr
+ - render::RenderMapMgr
(C) 2006-2015 by the GRASS Development Team
@@ -40,7 +34,7 @@
from grass.script import core as grass
from grass.script.utils import try_remove
-from grass.script.task import cmdlist_to_tuple
+from grass.script.task import cmdlist_to_tuple, cmdtuple_to_list
from grass.pydispatch.signal import Signal
from core import utils
@@ -49,6 +43,7 @@
from core.gcmd import GException, GError, RunCommand
from core.debug import Debug
from core.settings import UserSettings
+from core.gconsole import CmdThread, GStderr, EVT_CMD_DONE
class Layer(object):
"""Virtual class which stores information about layers (map layers and
@@ -122,7 +117,7 @@
(self.name, self.GetCmd(string = True)))
def __str__(self):
- return self.name
+ return self.GetCmd(string=True)
def __repr__(self):
return self.__str__()
@@ -150,55 +145,31 @@
raise GException(_("<%(name)s>: layer type <%(type)s> is not supported") % \
{'type' : self.type, 'name' : self.name})
+ # render layers
env.update(self.render_env)
- # execute command
try:
if self.type == 'command':
- read = False
+ first = True
for c in self.cmd:
- ret, msg = self._runCommand(c, env)
- if ret != 0:
- break
- if not read:
+ self.renderMgr.Render(c, env)
+ if first:
env["GRASS_RENDER_FILE_READ"] = "TRUE"
-
- env["GRASS_RENDER_FILE_READ"] = "FALSE"
+ first = False
else:
- ret, msg = self._runCommand(self.cmd, env)
- if ret != 0:
- sys.stderr.write(_("Command '%s' failed\n") % self.GetCmd(string = True))
- if msg:
- sys.stderr.write(_("Details: %s\n") % msg)
- raise GException()
-
+ self.renderMgr.Render(self.cmd, env)
except GException:
+ sys.stderr.write(_("Command '%s' failed\n") % self.GetCmd(string = True))
+ sys.stderr.write(_("Details: %s\n") % e)
+
# clean up after problems
for f in [self.mapfile, self.maskfile]:
if not f:
continue
try_remove(f)
f = None
-
- self.forceRender = False
-
+
return self.mapfile
-
- def _runCommand(self, cmd, env):
- """Run command to render data
- """
- if self.type == 'wms':
- ret = 0
- msg = ''
- self.renderMgr.Render(cmd, env=env)
- else:
- ret, msg = RunCommand(cmd[0],
- getErrorMsg = True,
- quiet = True,
- env=env,
- **cmd[1])
-
- return ret, msg
-
+
def GetCmd(self, string = False):
"""Get GRASS command as list of string.
@@ -275,13 +246,13 @@
if ltype not in utils.command2ltype.values() + ['overlay', 'command']:
raise GException(_("Unsupported map layer type '%s'") % ltype)
- if ltype == 'wms' and not isinstance(self.renderMgr, RenderWMSMgr):
- self.renderMgr = RenderWMSMgr(layer=self,
- mapfile=self.mapfile,
- maskfile=self.maskfile)
- elif self.type == 'wms' and ltype != 'wms':
- self.renderMgr = None
-
+ if not self.renderMgr:
+ if ltype == 'wms':
+ renderMgr = RenderWMSMgr
+ else:
+ renderMgr = RenderLayerMgr
+ self.renderMgr = renderMgr(self)
+
self.type = ltype
def SetName(self, name):
@@ -320,17 +291,11 @@
def IsDownloading(self):
"""Is data downloading from web server e. g. wms"""
- if self.renderMgr is None:
- return False
- else:
- return self.renderMgr.IsDownloading()
+ return self.renderMgr.IsDownloading()
def AbortThread(self):
"""Abort running thread e. g. downloading data"""
- if self.renderMgr is None:
- return
- else:
- self.renderMgr.Abort()
+ self.renderMgr.Abort()
def GetRenderMgr(self):
"""Get render manager """
@@ -367,13 +332,272 @@
self.render_env["GRASS_RENDER_FILE_READ"] = "FALSE"
self.render_env["GRASS_RENDER_TRANSPARENT"] = "TRUE"
+class RenderLayerMgr(wx.EvtHandler):
+ def __init__(self, layer):
+ """Render layer into image
+
+ :param layer: Layer to be rendered
+ """
+ self.layer = layer
+
+ wx.EvtHandler.__init__(self)
+ self.thread = CmdThread(self)
+ self.cmdStdErr = GStderr(self)
+
+ self.updateProgress = Signal('RenderLayerMgr.updateProgress')
+ self.Bind(EVT_CMD_DONE, self.OnRenderDone)
+
+ self._startTime = None
+
+ def Render(self, cmd, env):
+ """Render layer
+
+ :param cmd: display command given as tuple
+ :param env: environmental variables used for rendering
+ """
+ Debug.msg(1, "RenderLayerMgr.Render(%s): force=%d img=%s" % \
+ (self.layer, self.layer.forceRender, self.layer.mapfile))
+
+ env_cmd = env.copy()
+ env_cmd['GRASS_RENDER_FILE'] = self.layer.mapfile
+
+ cmd[1]['quiet'] = True # be quiet
+ cmd_tuple = cmdtuple_to_list(cmd)
+
+ self._startTime = time.time()
+ self.thread.RunCmd(cmd_tuple, env=env_cmd, stderr=self.cmdStdErr)
+ self.layer.forceRender = False
+
+ def Abort(self):
+ """Abort rendering process"""
+ self.thread.abort(abortall = True)
+
+ def IsDownloading(self):
+ """Is downloading
+
+ :return: always False
+ """
+ return False
+
+ def OnRenderDone(self, event):
+ """Rendering done
+
+ Emits updateProcess
+ """
+ stop = time.time()
+ Debug.msg(1, "RenderLayerMgr.OnRenderDone(%s): ret=%d time=%f" % \
+ (self.layer, event.returncode, stop - self._startTime))
+ self.updateProgress.emit(layer=self.layer)
+
+class RenderMapMgr(wx.EvtHandler):
+ def __init__(self, Map):
+ """Render map layers as image composition
+
+ :param Map: Map object to be rendered
+ """
+ wx.EvtHandler.__init__(self)
+
+ self.Map = Map
+ self.thread = CmdThread(self)
+ self.cmdStdErr = GStderr(self)
+
+ self.updateMap = Signal('RenderMapMgr.updateMap')
+ self.updateProgress = Signal('RenderMapMgr.updateProgress')
+ self.renderDone = Signal('RenderMapMgr.renderDone')
+ self.renderDone.connect(self.OnRenderDone)
+
+ # GRASS environment variable (for rendering)
+ self._render_env = {"GRASS_RENDER_BACKGROUNDCOLOR" : "000000",
+ "GRASS_RENDER_FILE_COMPRESSION" : "0",
+ "GRASS_RENDER_TRUECOLOR" : "TRUE",
+ "GRASS_RENDER_TRANSPARENT" : "TRUE" }
+
+ self._init()
+ self._rendering = False
+
+ def _init(self, env=None):
+ """Init render manager
+
+ :param env: environmental variables or None
+ """
+ self._startTime = time.time()
+ self.progressInfo = None
+ self._env = env
+ self.layers = []
+
+ # re-render from scratch
+ if os.path.exists(self.Map.mapfile):
+ os.remove(self.Map.mapfile)
+
+ def _renderLayers(self, env, force = False, overlaysOnly = False):
+ """Render all map layers into files
+
+ :param dict env: environmental variables to be used for rendering process
+ :param bool force: True to force rendering
+ :param bool overlaysOnly: True to render only overlays
+
+ :return: number of layers to be rendered
+ """
+ if overlaysOnly:
+ self.layers = self.Map.GetListOfLayers(ltype='overlay', active=True)
+ else:
+ self.layers = self.Map.GetListOfLayers(active=True)
+
+ # reset progress
+ self.ReportProgress()
+
+ # render map layers if forced
+ nlayers = 0
+ for layer in self.layers:
+ if force or layer.forceRender:
+ nlayers += 1
+ layer.Render(env)
+ else:
+ layer.GetRenderMgr().updateProgress.emit(layer=layer)
+
+ Debug.msg(1, "RenderMapMgr.Render(): %d layers to be rendered "
+ "(force=%d, all active layers -> %d)" % (nlayers, force,
+ len(self.layers)))
+
+ return nlayers
+
+ def Render(self, force = False, windres = False):
+ """Render map composition
+
+ :param bool force: force rendering all map layers in the composition
+ :param windres: True for region resolution instead for map resolution
+ """
+ if self._rendering:
+ Debug.msg(1, "RenderMapMgr().Render(): cancelled (already rendering)")
+ return
+
+ wx.BeginBusyCursor()
+ self._rendering = True
+
+ env = os.environ.copy()
+ env.update(self._render_env)
+ # use external gisrc if defined
+ if self.Map.gisrc:
+ env['GISRC'] = self.Map.gisrc
+ env['GRASS_REGION'] = self.Map.SetRegion(windres)
+ env['GRASS_RENDER_WIDTH'] = str(self.Map.width)
+ env['GRASS_RENDER_HEIGHT'] = str(self.Map.height)
+ driver = UserSettings.Get(group = 'display', key = 'driver', subkey = 'type')
+ if driver == 'png':
+ env['GRASS_RENDER_IMMEDIATE'] = 'png'
+ else:
+ env['GRASS_RENDER_IMMEDIATE'] = 'cairo'
+
+ self._init(env)
+ if self._renderLayers(env, force, windres) == 0:
+ self.renderDone.emit()
+
+ def OnRenderDone(self):
+ """Rendering process done
+
+ Make image composiotion, emits updateMap event.
+ """
+ stopTime = time.time()
+
+ maps = list()
+ masks = list()
+ opacities = list()
+
+ for layer in self.layers:
+ maps.append(layer.mapfile)
+ masks.append(layer.maskfile)
+ opacities.append(str(layer.opacity))
+
+ # run g.pngcomp to get composite image
+ bgcolor = ':'.join(map(str, UserSettings.Get(group = 'display', key = 'bgcolor',
+ subkey = 'color')))
+ startCompTime = time.time()
+ if maps:
+ ret, msg = RunCommand('g.pnmcomp',
+ getErrorMsg = True,
+ overwrite = True,
+ input = '%s' % ",".join(maps),
+ mask = '%s' % ",".join(masks),
+ opacity = '%s' % ",".join(opacities),
+ bgcolor = bgcolor,
+ width = self.Map.width,
+ height = self.Map.height,
+ output = self.Map.mapfile,
+ env=self._env)
+ if ret != 0:
+ raise GException(_("Rendering failed: %s" % msg))
+
+ stop = time.time()
+ Debug.msg (1, "RenderMapMgr.OnRenderDone() time=%f sec (comp: %f)" % \
+ (stop - self._startTime, stop - startCompTime))
+
+ self._rendering = False
+ wx.EndBusyCursor()
+
+ self.updateMap.emit()
+
+ def Abort(self):
+ """Abort all rendering processes"""
+ for layer in self.layers:
+ layer.GetRenderMgr().Abort()
+
+ def ReportProgress(self, layer=None):
+ """Calculates progress in rendering/downloading
+ and emits signal to inform progress bar about progress.
+
+ Emits renderDone event when progressVal is equal to range.
+
+ :param layer: Layer to be processed or None to reset
+ """
+ if self.progressInfo is None or layer is None:
+ self.progressInfo = {'progresVal' : 0, # current progress value
+ 'downloading' : [], # layers, which are downloading data
+ 'rendered' : [], # already rendered layers
+ 'range' : len(self.layers)}
+ else:
+ if layer not in self.progressInfo['rendered']:
+ self.progressInfo['rendered'].append(layer)
+ if layer.IsDownloading() and \
+ layer not in self.progressInfo['downloading']:
+ self.progressInfo['downloading'].append(layer)
+ else:
+ self.progressInfo['progresVal'] += 1
+ if layer in self.progressInfo['downloading']:
+ self.progressInfo['downloading'].remove(layer)
+
+ # for updating statusbar text
+ stText = ''
+ first = True
+ for layer in self.progressInfo['downloading']:
+ if first:
+ stText += _("Downloading data ")
+ first = False
+ else:
+ stText += ', '
+ stText += '<%s>' % layer.GetName()
+ if stText:
+ stText += '...'
+
+ if self.progressInfo['range'] != len(self.progressInfo['rendered']):
+ if stText:
+ stText = _('Rendering & ') + stText
+ else:
+ stText = _('Rendering...')
+
+ self.updateProgress.emit(range=self.progressInfo['range'],
+ value=self.progressInfo['progresVal'],
+ text=stText)
+
+ if layer and self.progressInfo['progresVal'] == self.progressInfo['range']:
+ self.renderDone.emit()
+
class Map(object):
def __init__(self, gisrc = None):
"""Map composition (stack of map layers and overlays)
:param gisrc: alternative gisrc (used eg. by georectifier)
"""
- Debug.msg (1, "Map.__init__(): %s" % gisrc)
+ Debug.msg (1, "Map.__init__(): gisrc=%s" % gisrc)
# region/extent settigns
self.wind = dict() # WIND settings (wind file)
self.region = dict() # region settings (g.region)
@@ -388,7 +612,7 @@
# path to external gisrc
self.gisrc = gisrc
-
+
# generated file for g.pnmcomp output for rendering the map
self.mapfile = grass.tempfile(create = False) + '.ppm'
@@ -397,27 +621,19 @@
sys.stderr.write(_("Trying to recover from default region..."))
RunCommand('g.region', flags='d')
- # info to report progress
- self.progressInfo = None
-
- # GRASS environment variable (for rendering)
- self.render_env = {"GRASS_RENDER_BACKGROUNDCOLOR" : "000000",
- "GRASS_RENDER_FILE_COMPRESSION" : "0",
- "GRASS_RENDER_TRUECOLOR" : "TRUE",
- "GRASS_RENDER_TRANSPARENT" : "TRUE",
- }
-
# projection info
self.projinfo = self._projInfo()
- # is some layer being downloaded?
- self.downloading = False
-
self.layerChanged = Signal('Map.layerChanged')
- self.updateProgress = Signal('Map.updateProgress')
self.layerRemoved = Signal('Map:layerRemoved')
self.layerAdded = Signal('Map:layerAdded')
+
+ self.renderMgr = RenderMapMgr(self)
+ def GetRenderMgr(self):
+ """Get render manager """
+ return self.renderMgr
+
def GetProjInfo(self):
"""Get projection info"""
return self.projinfo
@@ -844,62 +1060,6 @@
return selected
- def _renderLayers(self, env, force = False, overlaysOnly = False):
- """Render all map layers into files
-
- :param bool force: True to force rendering
- :param bool overlaysOnly: True to render only overlays
-
- :return: list of maps, masks and opacities
- """
- maps = list()
- masks = list()
- opacities = list()
- # render map layers
- if overlaysOnly:
- layers = self.overlays
- else:
- layers = self.layers + self.overlays
-
- self.downloading = False
-
- self.ReportProgress(layer=None)
-
- for layer in layers:
- # skip non-active map layers
- if not layer or not layer.active:
- continue
-
- # render
- if force or layer.forceRender:
- if not layer.Render(env):
- continue
-
- if layer.IsDownloading():
- self.downloading = True
-
- self.ReportProgress(layer=layer)
-
- # skip map layers when rendering fails
- if not os.path.exists(layer.mapfile):
- continue
-
- # add image to compositing list
- if layer.type != "overlay":
- maps.append(layer.mapfile)
- masks.append(layer.maskfile)
- opacities.append(str(layer.opacity))
-
- return maps, masks, opacities
-
- def GetMapsMasksAndOpacities(self, force, windres, env):
- """
- Used by Render function.
-
- :return: maps, masks, opacities
- """
- return self._renderLayers(force=force, env=env)
-
def Render(self, force = False, windres = False):
"""Creates final image composite
@@ -909,73 +1069,9 @@
:param force: force rendering
:param windres: use region resolution (True) otherwise display
resolution
-
- :return: name of file with rendered image or None
"""
- wx.BeginBusyCursor()
- env = os.environ.copy()
- env.update(self.render_env)
- # use external gisrc if defined
- if self.gisrc:
- env['GISRC'] = self.gisrc
- env['GRASS_REGION'] = self.SetRegion(windres)
- env['GRASS_RENDER_WIDTH'] = str(self.width)
- env['GRASS_RENDER_HEIGHT'] = str(self.height)
- driver = UserSettings.Get(group = 'display', key = 'driver', subkey = 'type')
- if driver == 'png':
- env['GRASS_RENDER_IMMEDIATE'] = 'png'
- else:
- env['GRASS_RENDER_IMMEDIATE'] = 'cairo'
+ self.renderMgr.Render(force, windres)
- start = time.time()
- maps, masks, opacities = self.GetMapsMasksAndOpacities(force, windres, env)
-
- # ugly hack for MSYS
- if sys.platform != 'win32':
- mapstr = ",".join(maps)
- maskstr = ",".join(masks)
- else:
- mapstr = ""
- for item in maps:
- mapstr += item.replace('\\', '/')
- mapstr = mapstr.rstrip(',')
- maskstr = ""
- for item in masks:
- maskstr += item.replace('\\', '/')
- maskstr = maskstr.rstrip(',')
-
- # run g.pngcomp to get composite image
- bgcolor = ':'.join(map(str, UserSettings.Get(group = 'display', key = 'bgcolor',
- subkey = 'color')))
- startComp = time.time()
- if maps:
- ret, msg = RunCommand('g.pnmcomp',
- getErrorMsg = True,
- overwrite = True,
- input = '%s' % ",".join(maps),
- mask = '%s' % ",".join(masks),
- opacity = '%s' % ",".join(opacities),
- bgcolor = bgcolor,
- width = self.width,
- height = self.height,
- output = self.mapfile,
- env=env)
-
- if ret != 0:
- print >> sys.stderr, _("ERROR: Rendering failed. Details: %s") % msg
- wx.EndBusyCursor()
- return None
-
- stop = time.time()
- Debug.msg (1, "Map.Render() force=%s -> time=%f (comp: %f)" % \
- (force, stop - start, stop - startComp))
-
- wx.EndBusyCursor()
- if not maps:
- return None
-
- return self.mapfile
-
def _addLayer(self, layer, render=False, pos=-1):
if layer.type == 'overlay':
llist = self.overlays
@@ -1023,8 +1119,9 @@
renderMgr = layer.GetRenderMgr()
if renderMgr:
- renderMgr.dataFetched.connect(self.layerChanged)
- renderMgr.updateProgress.connect(self.ReportProgress)
+ if layer.type == 'wms':
+ renderMgr.dataFetched.connect(self.layerChanged)
+ renderMgr.updateProgress.connect(self.renderMgr.ReportProgress)
self.layerAdded.emit(layer=layer)
@@ -1107,11 +1204,13 @@
if 'opacity' in kargs:
layer.SetOpacity(kargs['opacity'])
+
if render and not layer.Render():
raise GException(_("Unable to render map layer <%s>.") %
layer.GetName())
-
+
self.layerChanged(layer=layer)
+
return layer
def ChangeOpacity(self, layer, opacity):
@@ -1321,48 +1420,3 @@
"""Abort all layers threads e. g. donwloading data"""
for l in self.layers + self.overlays:
l.AbortThread()
-
- def ReportProgress(self, layer):
- """Calculates progress in rendering/downloading
- and emits signal to inform progress bar about progress.
- """
- if self.progressInfo is None or layer is None:
- self.progressInfo = {'progresVal' : 0, # current progress value
- 'downloading' : [], # layers, which are downloading data
- 'rendered' : [], # already rendered layers
- 'range' : len(self.GetListOfLayers(active = True)) +
- len(self.GetListOfLayers(active = True, ltype = 'overlay')) -
- len(self.GetListOfLayers(active = True, ltype = '3d-raster'))}
- else:
- if layer not in self.progressInfo['rendered']:
- self.progressInfo['rendered'].append(layer)
- if layer.IsDownloading() and \
- layer not in self.progressInfo['downloading']:
- self.progressInfo['downloading'].append(layer)
- else:
- self.progressInfo['progresVal'] += 1
- if layer in self.progressInfo['downloading']:
- self.progressInfo['downloading'].remove(layer)
-
- # for updating statusbar text
- stText = ''
- first = True
- for layer in self.progressInfo['downloading']:
- if first:
- stText += _("Downloading data ")
- first = False
- else:
- stText += ', '
- stText += '<%s>' % layer.GetName()
- if stText:
- stText += '...'
-
- if self.progressInfo['range'] != len(self.progressInfo['rendered']):
- if stText:
- stText = _('Rendering & ') + stText
- else:
- stText = _('Rendering...')
-
- self.updateProgress.emit(range=self.progressInfo['range'],
- value=self.progressInfo['progresVal'],
- text=stText)
Modified: grass/trunk/gui/wxpython/core/ws.py
===================================================================
--- grass/trunk/gui/wxpython/core/ws.py 2015-05-09 20:47:32 UTC (rev 65204)
+++ grass/trunk/gui/wxpython/core/ws.py 2015-05-10 09:01:38 UTC (rev 65205)
@@ -45,13 +45,13 @@
class RenderWMSMgr(wx.EvtHandler):
"""Fetch and prepare WMS data for rendering.
"""
- def __init__(self, layer, mapfile, maskfile):
+ def __init__(self, layer):
if not haveGdal:
sys.stderr.write(_("Unable to load GDAL Python bindings.\n"\
"WMS layers can not be displayed without the bindings.\n"))
self.layer = layer
-
+
wx.EvtHandler.__init__(self)
# thread for d.wms commands
@@ -65,8 +65,6 @@
self.cmdStdErr = GStderr(self)
- self.mapfile = mapfile
- self.maskfile = maskfile
self.tempMap = grass.tempfile()
self.dstSize = {}
@@ -119,7 +117,7 @@
self.fetched_data_cmd = None
self.renderedRegion = region
- try_remove(self.mapfile)
+ try_remove(self.layer.mapfile)
try_remove(self.tempMap)
self.currentPid = self.thread.GetId()
@@ -159,12 +157,13 @@
self.fetched_data_cmd = None
return
- self.mapMerger = GDALRasterMerger(targetFile = self.mapfile, region = self.renderedRegion,
+ self.mapMerger = GDALRasterMerger(targetFile = self.layer.mapfile,
+ region = self.renderedRegion,
bandsNum = 3, gdalDriver = 'PNM', fillValue = 0)
self.mapMerger.AddRasterBands(self.tempMap, {1 : 1, 2 : 2, 3 : 3})
del self.mapMerger
- self.maskMerger = GDALRasterMerger(targetFile = self.maskfile, region = self.renderedRegion,
+ self.maskMerger = GDALRasterMerger(targetFile = self.layer.maskfile, region = self.renderedRegion,
bandsNum = 1, gdalDriver = 'PNM', fillValue = 0)
#{4 : 1} alpha channel (4) to first and only channel (1) in mask
self.maskMerger.AddRasterBands(self.tempMap, {4 : 1})
Modified: grass/trunk/gui/wxpython/lmgr/layertree.py
===================================================================
--- grass/trunk/gui/wxpython/lmgr/layertree.py 2015-05-09 20:47:32 UTC (rev 65204)
+++ grass/trunk/gui/wxpython/lmgr/layertree.py 2015-05-10 09:01:38 UTC (rev 65205)
@@ -370,7 +370,7 @@
# can cause another idle event
self.rerender = False
if self.mapdisplay.IsAutoRendered():
- self.mapdisplay.GetMapWindow().UpdateMap(render=True)
+ self.mapdisplay.GetMapWindow().UpdateMap(render=False)
event.Skip()
@@ -1103,7 +1103,7 @@
if lchecked is not None:
checked = lchecked
else:
- checked = True
+ checked = False
self.forceCheck = True
@@ -1143,7 +1143,8 @@
else:
ctrlId = None
- # add a data object to hold the layer's command (does not apply to generic command layers)
+ # add a data object to hold the layer's command (does not
+ # apply to generic command layers)
self.SetPyData(layer, ({'cmd' : cmd,
'type' : ltype,
'ctrl' : ctrlId,
@@ -1153,6 +1154,7 @@
'nviz' : lnviz,
'propwin' : None},
None))
+
# must be after SetPyData because it calls OnLayerChecked
# which calls GetVisibleLayers which requires already set PyData
self.CheckItem(layer, checked=checked)
@@ -1183,7 +1185,6 @@
self.PropertiesDialog(layer, show = True)
else:
self.first = False
-
else: # group
self.SetPyData(layer, ({'cmd' : None,
'type' : ltype,
@@ -1209,7 +1210,6 @@
if ltype == 'group':
self.OnRenameLayer(None)
-
return layer
def PropertiesDialog(self, layer, show = True):
@@ -1223,37 +1223,32 @@
win.SetFocus()
else:
win.Show()
-
return
params = self.GetLayerParams(layer)
Debug.msg (3, "LayerTree.PropertiesDialog(): ltype=%s" % \
ltype)
-
+
cmd = None
if self.GetLayerInfo(layer, key = 'cmd'):
-
module = GUI(parent = self, show = show, centreOnParent = False)
module.ParseCommand(self.GetLayerInfo(layer, key = 'cmd'),
- completed = (self.GetOptData,layer,params))
-
+ completed = (self.GetOptData, layer, params))
self.SetLayerInfo(layer, key = 'cmd', value = module.GetCmd())
elif self.GetLayerInfo(layer, key = 'type') != 'command':
cmd = [ltype2command[ltype]]
- if ltype == 'raster':
+ if ltype in ('raster', 'rgb'):
if UserSettings.Get(group = 'rasterLayer', key = 'opaque', subkey = 'enabled'):
cmd.append('-n')
- elif ltype == 'rgb':
- if UserSettings.Get(group = 'rasterLayer', key = 'opaque', subkey = 'enabled'):
- cmd.append('-n')
elif ltype == 'vector':
cmd += GetDisplayVectSettings()
+
+ if cmd:
+ module = GUI(parent = self, centreOnParent = False)
+ module.ParseCommand(cmd,
+ completed = (self.GetOptData,layer,params))
- if cmd:
- GUI(parent = self, centreOnParent = False).ParseCommand(cmd,
- completed = (self.GetOptData,layer,params))
-
def OnActivateLayer(self, event):
"""Double click on the layer item.
Launch property dialog, or expand/collapse group of items, etc.
@@ -1666,25 +1661,32 @@
GWarning(parent = self,
message = _("Map <%s> not found.") % mapName)
return
-
+
+ if not mapLayer.IsActive():
+ self.forceCheck = True
+ self.CheckItem(layer, True)
+ mapLayer.SetActive(True)
+
# update layer data
if params:
self.SetPyData(layer, (self.GetLayerInfo(layer), params))
self.SetLayerInfo(layer, key = 'propwin', value = propwin)
# change parameters for item in layers list in render.Map
- self.ChangeLayer(layer)
-
+ if params:
+ self.ChangeLayer(layer)
+
# set region if auto-zooming is enabled or layer tree contains
# only one map layer
if dcmd:
- if not self.mapdisplay.IsPaneShown('3d') and (self.first or
- UserSettings.Get(group = 'display', key = 'autoZooming', subkey = 'enabled')):
+ if not self.mapdisplay.IsPaneShown('3d') and \
+ (self.first or \
+ UserSettings.Get(group = 'display', key = 'autoZooming', subkey = 'enabled')):
mapLayer = self.GetLayerInfo(layer, key = 'maplayer')
if mapLayer.GetType() in ('raster', 'vector'):
self.mapdisplay.MapWindow.ZoomToMap(layers = [mapLayer,],
render = False)
-
+
self.first = False # first layer has been already added to
# the layer tree
@@ -1716,7 +1718,7 @@
active = True))
if nlayers < 2:
mapWin.ResetView()
-
+
def GetVisibleLayers(self, skipDigitized=False):
# make a list of visible layers
layers = []
@@ -1775,18 +1777,19 @@
layerName, found = GetLayerNameFromCmd(cmdlist, fullyQualified = True)
if not found:
layerName = self.GetItemText(item)
+
+ maplayer = self.Map.ChangeLayer(layer = self.GetLayerInfo(item, key = 'maplayer'),
+ type = type, command = cmdlist, name = layerName,
+ active = chk, hidden = hidden, opacity = opac)
- maplayer = self.Map.ChangeLayer(layer = self.GetLayerInfo(item, key = 'maplayer'), type = type,
- command = cmdlist, name = layerName,
- active = chk, hidden = hidden, opacity = opac, render = False)
-
self.SetLayerInfo(item, key = 'maplayer', value = maplayer)
# if digitization tool enabled -> update list of available vector map layers
if self.mapdisplay.GetToolbar('vdigit'):
self.mapdisplay.GetToolbar('vdigit').UpdateListOfLayers(updateTool = True)
-
+
self.Map.SetLayers(self.GetVisibleLayers())
+
# redraw map if auto-rendering is enabled
self.rerender = True
Modified: grass/trunk/gui/wxpython/mapdisp/frame.py
===================================================================
--- grass/trunk/gui/wxpython/mapdisp/frame.py 2015-05-09 20:47:32 UTC (rev 65204)
+++ grass/trunk/gui/wxpython/mapdisp/frame.py 2015-05-10 09:01:38 UTC (rev 65205)
@@ -247,7 +247,7 @@
self.statusbarManager.Update()
#
- self.Map.updateProgress.connect(self.statusbarManager.SetProgress)
+ self.Map.GetRenderMgr().updateProgress.connect(self.statusbarManager.SetProgress)
def GetMapWindow(self):
return self.MapWindow
Modified: grass/trunk/gui/wxpython/mapdisp/main.py
===================================================================
--- grass/trunk/gui/wxpython/mapdisp/main.py 2015-05-09 20:47:32 UTC (rev 65204)
+++ grass/trunk/gui/wxpython/mapdisp/main.py 2015-05-10 09:01:38 UTC (rev 65205)
@@ -5,7 +5,6 @@
Classes:
- mapdisp::DMonMap
- - mapdisp::DMonMapDirect
- mapdisp::Layer
- mapdisp::LayerList
- mapdisp::DMonGrassInterface
@@ -38,7 +37,7 @@
from core import utils
from core.giface import StandaloneGrassInterface
from core.gcmd import RunCommand
-from core.render import Map, MapLayer, Overlay
+from core.render import Map, MapLayer, Overlay, RenderMapMgr
from core.utils import _
from mapdisp.frame import MapFrame
from core.debug import Debug
@@ -66,7 +65,7 @@
:param mapfile: full path to the map file (defined by d.mon)
"""
Map.__init__(self)
-
+
self._giface = giface
# environment settings
@@ -93,7 +92,9 @@
# signal sent when d.what.rast/vect appears in cmd file, attribute is cmd
self.query = Signal('DMonMap.query')
- def GetLayersFromCmdFile(self, mapfile=None):
+ self.renderMgr = RenderMapMgr(self)
+
+ def GetLayersFromCmdFile(self):
"""Get list of map layers from cmdfile
"""
if not self.cmdfile:
@@ -155,12 +156,12 @@
args['id'] = 1
else:
classLayer = MapLayer
- args['mapfile'] = mapfile
args['ltype'] = ltype
mapLayer = classLayer(name = name, cmd = cmd, Map = None,
hidden = True, **args)
-
+ mapLayer.GetRenderMgr().updateProgress.connect(self.GetRenderMgr().ReportProgress)
+
exists = False
for i, layer in enumerate(existingLayers):
if layer.GetCmd(string=True) == mapLayer.GetCmd(string=True):
@@ -245,50 +246,6 @@
#return layer
-class DMonMapDirect(DMonMap):
- def __init__(self, giface, cmdfile=None, mapfile=None):
- """Map composition (stack of map layers and overlays)
-
- :param cmdline: full path to the cmd file (defined by d.mon)
- :param mapfile: full path to the map file (defined by d.mon)
- """
- DMonMap.__init__(self, giface, cmdfile, mapfile)
-
- self.render_env['GRASS_RENDER_BACKGROUNDCOLOR'] = 'FFFFFF'
- self.render_env['GRASS_RENDER_TRANSPARENT'] = 'FALSE'
- self.render_env['GRASS_RENDER_FILE_READ'] = 'TRUE'
-
- def Render(self, *args, **kwargs):
- """Render layer to image.
-
- For input params and returned data see overridden method in Map class.
- """
- wx.BeginBusyCursor()
- env = os.environ.copy()
- env.update(self.render_env)
- # use external gisrc if defined
- if self.gisrc:
- env['GISRC'] = self.gisrc
- env['GRASS_REGION'] = self.SetRegion(kwargs.get('windres', False))
- env['GRASS_RENDER_WIDTH'] = str(self.width)
- env['GRASS_RENDER_HEIGHT'] = str(self.height)
- driver = UserSettings.Get(group = 'display', key = 'driver', subkey = 'type')
- if driver == 'png':
- env['GRASS_RENDER_IMMEDIATE'] = 'png'
- else:
- env['GRASS_RENDER_IMMEDIATE'] = 'cairo'
-
- if os.path.exists(self.mapfile):
- os.remove(self.mapfile)
-
- self.GetMapsMasksAndOpacities(kwargs['force'], kwargs.get('windres', False), env)
- wx.EndBusyCursor()
-
- return self.mapfile
-
- def GetLayersFromCmdFile(self):
- super(self.__class__, self).GetLayersFromCmdFile(self.mapfile)
-
class Layer(object):
"""@implements core::giface::Layer"""
def __init__(self, maplayer):
@@ -444,11 +401,8 @@
toolbars.append('map')
if __name__ == "__main__":
- dmonMap = DMonMapDirect
- # if decorations:
- # dmonMap = DMonMap
self.cmdTimeStamp = os.path.getmtime(monFile['cmd'])
- self.Map = dmonMap(giface=self._giface, cmdfile=monFile['cmd'],
+ self.Map = DMonMap(giface=self._giface, cmdfile=monFile['cmd'],
mapfile = monFile['map'])
self.timer = wx.PyTimer(self.watcher)
Modified: grass/trunk/gui/wxpython/mapwin/buffered.py
===================================================================
--- grass/trunk/gui/wxpython/mapwin/buffered.py 2015-05-09 20:47:32 UTC (rev 65204)
+++ grass/trunk/gui/wxpython/mapwin/buffered.py 2015-05-10 09:01:38 UTC (rev 65205)
@@ -149,7 +149,6 @@
self.processMouse = True
# render output objects
- self.mapfile = None # image file to be rendered
self.img = None # wx.Image object (self.mapfile)
# decoration overlays
self.overlays = overlays
@@ -181,8 +180,9 @@
self.Bind(wx.EVT_ERASE_BACKGROUND, lambda x:None)
# rerender when Map reports change
- self.Map.layerChanged.connect(self.OnUpdateMap)
-
+ ### self.Map.layerChanged.connect(self.OnUpdateMap)
+ self.Map.GetRenderMgr().renderDone.connect(self._updateMFinished)
+
# vars for handling mouse clicks
self.dragid = -1
self.lastpos = (0, 0)
@@ -704,7 +704,7 @@
:return: wx.Image instance (map composition)
"""
imgId = 99
- if self.mapfile and self.Map.mapfile and os.path.isfile(self.Map.mapfile) and \
+ if self.Map.mapfile and os.path.isfile(self.Map.mapfile) and \
os.path.getsize(self.Map.mapfile):
img = wx.Image(self.Map.mapfile, wx.BITMAP_TYPE_ANY)
else:
@@ -808,43 +808,29 @@
"""
:func:`UpdateMap` for arguments description.
"""
+ Debug.msg (1, "BufferedWindow.UpdateMap(): started "
+ "(render=%s, renderVector=%s)" % (render, renderVector))
+
self.resize = False
# was if self.Map.cmdfile and ...
if self.IsAlwaysRenderEnabled() and self.img is None:
render = True
-
-
- #
- # render background image if needed
- #
-
- # here was the change of the layertree rerender variable
- # but it is fully the problem of layertree
- # and so it is handled there
- # remove this comment when it is old enough
-
+
try:
if render:
# update display size
self.Map.ChangeMapSize(self.GetClientSize())
- if self._properties.resolution:
- # use computation region resolution for rendering
- windres = True
- else:
- windres = False
-
- self.mapfile = self.Map.Render(force = True,
- windres = windres)
- else:
- self.mapfile = self.Map.Render(force = False)
-
+
+ self.Map.Render(force=render,
+ windres=self._properties.resolution)
except GException as e:
- GError(message = e.value)
- self.mapfile = None
+ GError(message=e.value)
+ def _updateMFinished(self, renderVector=True):
+ Debug.msg (1, "BufferedWindow.UpdateMap(): finished")
self.img = self.GetImage() # id=99
-
+
#
# clear pseudoDcs
#
@@ -853,7 +839,7 @@
self.pdcTmp):
pdc.Clear()
pdc.RemoveAll()
-
+
#
# draw background map image to PseudoDC
#
@@ -862,9 +848,9 @@
else:
try:
id = self.imagedict[self.img]['id']
- except:
+ except Exception as e:
+ Debug.mgs(1, "UpdateMap() failed: %s", e)
return False
-
self.Draw(self.pdc, self.img, drawid = id)
#
@@ -872,6 +858,7 @@
#
if renderVector and hasattr(self, "digit"):
self._updateMap()
+
#
# render overlays
#
@@ -880,19 +867,20 @@
if self.imagedict[img]['layer'].IsActive():
id = self.imagedict[img]['id']
self.Draw(self.pdc, img = img, drawid = id,
- pdctype = self.overlays[id].pdcType, coords = self.overlays[id].coords)
-
+ pdctype = self.overlays[id].pdcType,
+ coords = self.overlays[id].coords)
+
for id in self.textdict.keys():
self.Draw(self.pdc, img = self.textdict[id], drawid = id,
pdctype = 'text', coords = [10, 10, 10, 10])
-
+
# optionally draw computational extent box
self.DrawCompRegionExtent()
-
+
#
# redraw pdcTmp if needed
#
-
+
# draw registered graphics
if len(self.graphicsSetList) > 0:
penOrig = self.pen
@@ -912,12 +900,9 @@
if len(self.polycoords) > 0:
self.DrawLines(self.pdcTmp)
-
- Debug.msg (1, "BufferedWindow.UpdateMap(): render=%s, renderVector=%s" % \
- (render, renderVector))
-
- return True
+ return True
+
def DrawCompRegionExtent(self):
"""Draw computational region extent in the display
More information about the grass-commit
mailing list