Преглед изворни кода

wxGUI: fix inconsistent layer sizes during rendering (#552)

Passes environment with width and height throughout the rendering process
to ensure consistent size.

Before rendering, checks already rendered layers have consistent size with
new size, if not, forces them to rerender.

After g.pnmcomp during checking vector legend changes, only render when
there is an actual vector legend overlay present.
Anna Petrasova пре 5 година
родитељ
комит
bf9618a7bc
2 измењених фајлова са 54 додато и 27 уклоњено
  1. 50 23
      gui/wxpython/core/render.py
  2. 4 4
      gui/wxpython/core/ws.py

+ 50 - 23
gui/wxpython/core/render.py

@@ -121,6 +121,7 @@ class Layer(object):
         self.opacity = opacity
         self.opacity = opacity
 
 
         self.forceRender = render
         self.forceRender = render
+        self.renderedSize = None
 
 
         Debug.msg(3, "Layer.__init__(): type=%s, cmd='%s', name=%s, "
         Debug.msg(3, "Layer.__init__(): type=%s, cmd='%s', name=%s, "
                   "active=%d, opacity=%d, hidden=%d" %
                   "active=%d, opacity=%d, hidden=%d" %
@@ -249,6 +250,10 @@ class Layer(object):
                 return {'name': self.name,
                 return {'name': self.name,
                         'mapset': ''}
                         'mapset': ''}
 
 
+    def GetRenderedSize(self):
+        """Get currently rendered size of layer as tuple, None if not rendered"""
+        return self.renderedSize
+
     def IsActive(self):
     def IsActive(self):
         """Check if layer is activated for rendering"""
         """Check if layer is activated for rendering"""
         return self.active
         return self.active
@@ -425,7 +430,7 @@ class RenderLayerMgr(wx.EvtHandler):
 
 
         self._startTime = time.time()
         self._startTime = time.time()
         self.thread.Run(callable=self._render, cmd=cmd_render, env=env_cmd,
         self.thread.Run(callable=self._render, cmd=cmd_render, env=env_cmd,
-                        ondone=self.OnRenderDone, userdata={'cmd': cmd})
+                        ondone=self.OnRenderDone, userdata={'cmd': cmd, 'env': env})
         self.layer.forceRender = False
         self.layer.forceRender = False
 
 
     def _render(self, cmd, env):
     def _render(self, cmd, env):
@@ -465,8 +470,13 @@ class RenderLayerMgr(wx.EvtHandler):
             # don't remove layer if overlay, we need to keep the old one
             # don't remove layer if overlay, we need to keep the old one
             if self.layer.type != 'overlay':
             if self.layer.type != 'overlay':
                 try_remove(self.layer.mapfile)
                 try_remove(self.layer.mapfile)
+                self.layer.renderedSize = None
+        else:
+            env = event.userdata['env']
+            self.layer.renderedSize = (env['GRASS_RENDER_WIDTH'],
+                                       env['GRASS_RENDER_HEIGHT'])
 
 
-        self.updateProgress.emit(layer=self.layer)
+        self.updateProgress.emit(env=event.userdata['env'], layer=self.layer)
 
 
 
 
 class RenderMapMgr(wx.EvtHandler):
 class RenderMapMgr(wx.EvtHandler):
@@ -498,20 +508,28 @@ class RenderMapMgr(wx.EvtHandler):
         self._rendering = False
         self._rendering = False
         self._old_legend = []
         self._old_legend = []
 
 
-    def _init(self, env=None):
-        """Init render manager
-
-        :param env: environmental variables or None
-        """
+    def _init(self):
+        """Init render manager"""
         self._startTime = time.time()
         self._startTime = time.time()
         self.progressInfo = None
         self.progressInfo = None
-        self._env = env
         self.layers = []
         self.layers = []
 
 
         # re-render from scratch
         # re-render from scratch
         if os.path.exists(self.Map.mapfile):
         if os.path.exists(self.Map.mapfile):
             os.remove(self.Map.mapfile)
             os.remove(self.Map.mapfile)
 
 
+    def _checkRenderedSizes(self, env, layers):
+        """Check if rendering size in current env differs from size of
+        already rendered layers, if so, set forceRender to rerender them."""
+        w = env['GRASS_RENDER_WIDTH']
+        h = env['GRASS_RENDER_HEIGHT']
+        for layer in layers:
+            size = layer.GetRenderedSize()
+            if size:
+                # is rendered but its size differes from current env
+                if not layer.forceRender and (size[0] != w or size[1] != h):
+                    layer.forceRender = True
+
     def UpdateRenderEnv(self, env):
     def UpdateRenderEnv(self, env):
         self._render_env.update(env)
         self._render_env.update(env)
 
 
@@ -531,7 +549,12 @@ class RenderMapMgr(wx.EvtHandler):
                                                     except_ltype=True)
                                                     except_ltype=True)
 
 
         # reset progress
         # reset progress
-        self.ReportProgress()
+        self.ReportProgress(env=env)
+
+        # check all already rendered layers have the same size
+        # otherwise force rerendering the layer
+        if not force:
+            self._checkRenderedSizes(env=env, layers=self.layers)
 
 
         # render map layers if forced
         # render map layers if forced
         nlayers = 0
         nlayers = 0
@@ -540,7 +563,7 @@ class RenderMapMgr(wx.EvtHandler):
                 nlayers += 1
                 nlayers += 1
                 layer.Render(env)
                 layer.Render(env)
             else:
             else:
-                layer.GetRenderMgr().updateProgress.emit(layer=layer)
+                layer.GetRenderMgr().updateProgress.emit(env=env, layer=layer)
 
 
         Debug.msg(1, "RenderMapMgr.Render(): %d layers to be rendered "
         Debug.msg(1, "RenderMapMgr.Render(): %d layers to be rendered "
                   "(force=%d, all active layers -> %d)" % (nlayers, force,
                   "(force=%d, all active layers -> %d)" % (nlayers, force,
@@ -580,10 +603,10 @@ class RenderMapMgr(wx.EvtHandler):
         self._rendering = True
         self._rendering = True
 
 
         env = self.GetRenderEnv()
         env = self.GetRenderEnv()
-        self._init(env)
+        self._init()
         # no layer composition afterwards
         # no layer composition afterwards
         if self._renderLayers(env, force, overlaysOnly=True) == 0:
         if self._renderLayers(env, force, overlaysOnly=True) == 0:
-            self.renderDone.emit()
+            self.renderDone.emit(env=env)
 
 
     def Render(self, force=False, windres=False):
     def Render(self, force=False, windres=False):
         """Render map composition
         """Render map composition
@@ -600,12 +623,12 @@ class RenderMapMgr(wx.EvtHandler):
         self._rendering = True
         self._rendering = True
 
 
         env = self.GetRenderEnv(windres)
         env = self.GetRenderEnv(windres)
-        self._init(env)
+        self._init()
         if self._renderLayers(env, force) == 0:
         if self._renderLayers(env, force) == 0:
-            self.renderDone.emit()
+            self.renderDone.emit(env=env)
 
 
 
 
-    def OnRenderDone(self):
+    def OnRenderDone(self, env):
         """Rendering process done
         """Rendering process done
 
 
         Make image composiotion, emits updateMap event.
         Make image composiotion, emits updateMap event.
@@ -639,10 +662,10 @@ class RenderMapMgr(wx.EvtHandler):
                                   mask='%s' % ",".join(masks),
                                   mask='%s' % ",".join(masks),
                                   opacity='%s' % ",".join(opacities),
                                   opacity='%s' % ",".join(opacities),
                                   bgcolor=bgcolor,
                                   bgcolor=bgcolor,
-                                  width=self._env['GRASS_RENDER_WIDTH'],
-                                  height=self._env['GRASS_RENDER_HEIGHT'],
+                                  width=env['GRASS_RENDER_WIDTH'],
+                                  height=env['GRASS_RENDER_HEIGHT'],
                                   output=self.Map.mapfile,
                                   output=self.Map.mapfile,
-                                  env=self._env)
+                                  env=env)
             if ret != 0:
             if ret != 0:
                 self._rendering = False
                 self._rendering = False
                 if wx.IsBusy():
                 if wx.IsBusy():
@@ -673,12 +696,16 @@ class RenderMapMgr(wx.EvtHandler):
         # if legend file changed, rerender vector legend
         # if legend file changed, rerender vector legend
         if new_legend != self._old_legend:
         if new_legend != self._old_legend:
             self._old_legend = new_legend
             self._old_legend = new_legend
+            found = False
             for layer in self.layers:
             for layer in self.layers:
                 if layer.GetType() == 'overlay' and layer.GetName() == 'vectleg':
                 if layer.GetType() == 'overlay' and layer.GetName() == 'vectleg':
                     layer.forceRender = True
                     layer.forceRender = True
-            self.Render()
-        else:
-            self.updateMap.emit()
+                    found = True
+            if found:
+                self.Render()
+                return
+
+        self.updateMap.emit()
 
 
     def Abort(self):
     def Abort(self):
         """Abort all rendering processes"""
         """Abort all rendering processes"""
@@ -691,7 +718,7 @@ class RenderMapMgr(wx.EvtHandler):
             wx.EndBusyCursor()
             wx.EndBusyCursor()
         self.updateProgress.emit(range=0, value=0, text=_("Rendering aborted"))
         self.updateProgress.emit(range=0, value=0, text=_("Rendering aborted"))
 
 
-    def ReportProgress(self, layer=None):
+    def ReportProgress(self, env, layer=None):
         """Calculates progress in rendering/downloading
         """Calculates progress in rendering/downloading
         and emits signal to inform progress bar about progress.
         and emits signal to inform progress bar about progress.
 
 
@@ -740,7 +767,7 @@ class RenderMapMgr(wx.EvtHandler):
 
 
         if layer and self.progressInfo[
         if layer and self.progressInfo[
                 'progresVal'] == self.progressInfo['range']:
                 'progresVal'] == self.progressInfo['range']:
-            self.renderDone.emit()
+            self.renderDone.emit(env=env)
 
 
     def RenderingFailed(self, cmd, error):
     def RenderingFailed(self, cmd, error):
         self.renderingFailed.emit(cmd=cmd, error=error)
         self.renderingFailed.emit(cmd=cmd, error=error)

+ 4 - 4
gui/wxpython/core/ws.py

@@ -135,10 +135,10 @@ class RenderWMSMgr(wx.EvtHandler):
 
 
             self._startTime = time.time()
             self._startTime = time.time()
             self.thread.Run(callable=self._render, cmd=cmd_render, env=env,
             self.thread.Run(callable=self._render, cmd=cmd_render, env=env,
-                            ondone=self.OnRenderDone)
+                            ondone=self.OnRenderDone, userdata={'env': env})
             self.layer.forceRender = False
             self.layer.forceRender = False
 
 
-        self.updateProgress.emit(layer=self.layer)
+        self.updateProgress.emit(env=env, layer=self.layer)
 
 
     def _render(self, cmd, env):
     def _render(self, cmd, env):
         try:
         try:
@@ -156,7 +156,7 @@ class RenderWMSMgr(wx.EvtHandler):
             return
             return
         self.downloading = False
         self.downloading = False
         if not self.updateMap:
         if not self.updateMap:
-            self.updateProgress.emit(layer=self.layer)
+            self.updateProgress.emit(env=event.userdata['env'], layer=self.layer)
             self.renderedRegion = None
             self.renderedRegion = None
             self.fetched_data_cmd = None
             self.fetched_data_cmd = None
             return
             return
@@ -185,7 +185,7 @@ class RenderWMSMgr(wx.EvtHandler):
         Debug.msg(1, "RenderWMSMgr.OnRenderDone(%s): ret=%d time=%f" %
         Debug.msg(1, "RenderWMSMgr.OnRenderDone(%s): ret=%d time=%f" %
                   (self.layer, event.ret, time.time() - self._startTime))
                   (self.layer, event.ret, time.time() - self._startTime))
 
 
-        self.dataFetched.emit(layer=self.layer)
+        self.dataFetched.emit(env=event.userdata['env'], layer=self.layer)
 
 
     def _getRegionDict(self, env):
     def _getRegionDict(self, env):
         """Parse string from GRASS_REGION env variable into dict.
         """Parse string from GRASS_REGION env variable into dict.