Bläddra i källkod

wxGUI/g.gui.rdigit: raster digitizer as standalone module (#1051)

Tomas Zigo 4 år sedan
förälder
incheckning
9aaecf0889

+ 1 - 1
gui/wxpython/Makefile

@@ -1,6 +1,6 @@
 MODULE_TOPDIR = ../..
 
-SUBDIRS = docs animation datacatalog mapswipe gmodeler rlisetup psmap dbmgr vdigit iclass gcp timeline tplot photo2image image2target
+SUBDIRS = docs animation datacatalog mapswipe gmodeler rlisetup psmap dbmgr vdigit rdigit iclass gcp timeline tplot photo2image image2target
 EXTRA_CLEAN_FILES = menustrings.py build_ext.pyc xml/menudata.xml xml/module_tree_menudata.xml */*.pyc
 
 include $(MODULE_TOPDIR)/include/Make/Dir.make

+ 2 - 1
gui/wxpython/docs/wxGUI.components.html

@@ -30,7 +30,8 @@ List of available <em><a href="wxGUI.html">wxGUI</a></em> components:
      available also as a command line tool <em><a href="g.gui.tplot.html">g.gui.tplot</a></em></li>
   <li><a href="wxGUI.vdigit.html">Vector Digitizer</a>,
      available also as a command line tool <em><a href="g.gui.vdigit.html">g.gui.vdigit</a></em></li>
-  <li><a href="wxGUI.rdigit.html">Raster Digitizer</a></li>
+  <li><a href="wxGUI.rdigit.html">Raster Digitizer</a>
+    available also as a command line tool <em><a href="g.gui.rdigit.html">g.gui.rdigit</a></em></li>
   <li><a href="wxGUI.vnet.html">Vector Network Analysis Tool</a></li>
 </ul>
 

+ 19 - 9
gui/wxpython/mapdisp/frame.py

@@ -528,6 +528,11 @@ class MapFrame(SingleMapFrame):
             self.toolbars['map'].combo.SetValue(_("Vector digitizer"))
             self._addToolbarVDigit()
 
+        # raster digitizer
+        elif name == "rdigit":
+            self.toolbars['map'].combo.SetValue(_("Raster digitizer"))
+            self.AddRDigit()
+
         if fixed:
             self.toolbars['map'].combo.Disable()
 
@@ -1579,15 +1584,20 @@ class MapFrame(SingleMapFrame):
     def QuitRDigit(self):
         """Calls digitizer cleanup, removes digitizer object and disconnects
         signals from Map."""
-        self.rdigit.CleanUp()
-        # disconnect updating layers
-        self.GetMap().layerAdded.disconnect(self._updateRDigitLayers)
-        self.GetMap().layerRemoved.disconnect(self._updateRDigitLayers)
-        self.GetMap().layerChanged.disconnect(self._updateRDigitLayers)
-        self._toolSwitcher.toggleToolChanged.disconnect(self.toolbars['rdigit'].CheckSelectedTool)
-
-        self.RemoveToolbar('rdigit', destroy=True)
-        self.rdigit = None
+        if not self.IsStandalone():
+            self.rdigit.CleanUp()
+            # disconnect updating layers
+            self.GetMap().layerAdded.disconnect(self._updateRDigitLayers)
+            self.GetMap().layerRemoved.disconnect(self._updateRDigitLayers)
+            self.GetMap().layerChanged.disconnect(self._updateRDigitLayers)
+            self._toolSwitcher.toggleToolChanged.disconnect(
+                self.toolbars['rdigit'].CheckSelectedTool,
+            )
+
+            self.RemoveToolbar('rdigit', destroy=True)
+            self.rdigit = None
+        else:
+            self.Close()
 
     def QuitVDigit(self):
         """Quit VDigit"""

+ 5 - 0
gui/wxpython/rdigit/Makefile

@@ -0,0 +1,5 @@
+MODULE_TOPDIR = ../../..
+
+include $(MODULE_TOPDIR)/include/Make/GuiScript.make
+
+default: guiscript

+ 3 - 1
gui/wxpython/rdigit/__init__.py

@@ -1,4 +1,6 @@
 all = [
     'controller',
-    'toolbars'
+    'toolbars',
+    'dialogs',
+    'g.gui.rdigit',
 ]

+ 48 - 14
gui/wxpython/rdigit/controller.py

@@ -393,26 +393,60 @@ class RDigitController(wx.EvtHandler):
         self._editOldRaster = True
         return True
 
-    def SelectNewMap(self):
+    def SelectNewMap(
+            self, standalone=False, mapName=None, bgMap=None,
+            mapType=None,
+
+    ):
         """After selecting new raster, shows dialog to choose name,
-        background map and type of the new map."""
-        dlg = NewRasterDialog(parent=self._mapWindow)
-        dlg.CenterOnParent()
-        if dlg.ShowModal() == wx.ID_OK:
+        background map and type of the new map.
+
+        :params standalone, mapName, bgMap, mapType: if digitizer is
+        launched as standalone module
+
+        :param bool standalone: if digitizer is launched as standalone
+        module
+        :param str mapName: edited raster map name
+        :param str bgMap: background raster map name
+        :param str mapType: raster map type CELL, FCELL, DCELL
+        """
+        if standalone:
             try:
-                self._createNewMap(mapName=dlg.GetMapName(),
-                                   backgroundMap=dlg.GetBackgroundMapName(),
-                                   mapType=dlg.GetMapType())
+                self._createNewMap(
+                    mapName=mapName, backgroundMap=bgMap,
+                    mapType=mapType,
+                )
             except ScriptError:
-                GError(parent=self._mapWindow, message=_(
-                    "Failed to create new raster map."))
+                GError(
+                    parent=self._mapWindow, message=_(
+                        "Failed to create new raster map."
+                    ),
+                )
                 return False
-            finally:
-                dlg.Destroy()
             return True
         else:
-            dlg.Destroy()
-            return False
+            dlg = NewRasterDialog(parent=self._mapWindow)
+            dlg.CenterOnParent()
+            if dlg.ShowModal() == wx.ID_OK:
+                try:
+                    self._createNewMap(
+                        mapName=dlg.GetMapName(),
+                        backgroundMap=dlg.GetBackgroundMapName(),
+                        mapType=dlg.GetMapType(),
+                    )
+                except ScriptError:
+                    GError(
+                        parent=self._mapWindow, message=_(
+                            "Failed to create new raster map."
+                        ),
+                    )
+                    return False
+                finally:
+                    dlg.Destroy()
+                return True
+            else:
+                dlg.Destroy()
+                return False
 
     def _createNewMap(self, mapName, backgroundMap, mapType):
         """Creates a new raster map based on specified background and type."""

+ 5 - 4
gui/wxpython/docs/wxGUI.rdigit.html

@@ -7,9 +7,9 @@
 
 <h2>DESCRIPTION</h2>
 
-<b>Raster Digitizer</b> is a simple tool to quickly
-to draw lines, areas, and circles and save these features in a raster map.
-It is accessible from Map Display toolbar (from the combo box on the right).
+<b>Raster Digitizer</b> is a simple tool to quickly draw lines, areas,
+and circles and save these features in a raster map. It is accessible
+from the Map Display toolbar (from the combo box on the right).
 
 <p>
 <em>Raster Digitizer</em> currently allows you to:
@@ -78,7 +78,8 @@ r.sun elevation=elev_edited aspect=elev_aspect slope=elev_slope beam_rad=beam da
 </em>
 
 <h2>AUTHOR</h2>
-Anna Petrasova, NCSU GeoForALL Laboratory
+Anna Petrasova, NCSU GeoForALL Laboratory<br>
+Tomas Zigo (standalone module)
 
 <!--
 <p>

+ 199 - 0
gui/wxpython/rdigit/g.gui.rdigit.py

@@ -0,0 +1,199 @@
+#!/usr/bin/env python3
+############################################################################
+#
+# MODULE:    g.gui.rdigit
+# AUTHOR(S): Anna Petrasova <kratochanna gmail.com>,
+#            Tomas Zigo <tomas.zigo slovanet.sk> (standalone module)
+# PURPOSE:   wxGUI Raster Digitizer
+# COPYRIGHT: (C) 2014-2020 by Anna Petrasova, and the GRASS Development Team
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License as
+#  published by the Free Software Foundation; either version 2 of the
+#  License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful, but
+#  WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  General Public License for more details.
+#
+############################################################################
+
+#%module
+#% description: Interactive editing and digitizing of raster maps.
+#% keyword: general
+#% keyword: GUI
+#% keyword: raster
+#% keyword: editing
+#% keyword: digitizer
+#%end
+#%option G_OPT_R_OUTPUT
+#% key: create
+#% label: Name of new raster map to create
+#% required: no
+#% guisection: Create
+#%end
+#%option G_OPT_R_BASE
+#% required: no
+#% guisection: Create
+#%end
+#%option G_OPT_R_TYPE
+#% answer: CELL
+#% required: no
+#% guisection: Create
+#%end
+#%option G_OPT_R_INPUT
+#% key: edit
+#% required: no
+#% label: Name of existing raster map to edit
+#% guisection: Edit
+#%end
+#%rules
+#% exclusive: create, edit
+#% required: create, edit
+#% requires: base, create
+#%end
+
+import os
+
+import grass.script as gs
+
+
+def main():
+    gs.set_raise_on_error(False)
+
+    options, flags = gs.parser()
+
+    # import wx only after running parser
+    # to avoid issues with complex imports when only interface is needed
+    import wx
+
+    from grass.script.setup import set_gui_path
+    set_gui_path()
+
+    from core.render import Map
+    from mapdisp.frame import MapFrame
+    from mapdisp.main import DMonGrassInterface
+    from core.settings import UserSettings
+    from grass.exceptions import CalledModuleError
+
+    # define classes which needs imports as local
+    # for longer definitions, a separate file would be a better option
+    class RDigitMapFrame(MapFrame):
+
+        def __init__(
+                self, new_map=None, base_map=None, edit_map=None,
+                map_type=None,
+        ):
+            MapFrame.__init__(
+                self, parent=None, Map=Map(),
+                giface=DMonGrassInterface(None),
+                title=_("GRASS GIS Raster Digitizer"), size=(850, 600),
+            )
+            # this giface issue not solved yet, we must set mapframe aferwards
+            self._giface._mapframe = self
+            self._giface.mapCreated.connect(self.OnMapCreated)
+            self._mapObj = self.GetMap()
+
+            # load raster map
+            self._addLayer(name=new_map if new_map else edit_map)
+
+            # switch toolbar
+            self.AddToolbar('rdigit', fixed=True)
+
+            rdigit = self.toolbars['rdigit']
+            if new_map:
+                rdigit._mapSelectionCombo.Unbind(wx.EVT_COMBOBOX)
+                self.rdigit.SelectNewMap(
+                    standalone=True, mapName=new_map, bgMap=base_map,
+                    mapType=map_type,
+                )
+                rdigit._mapSelectionCombo.Bind(
+                    wx.EVT_COMBOBOX, rdigit.OnMapSelection,
+                )
+            else:
+                rdigit._mapSelectionCombo.SetSelection(n=1)
+                rdigit.OnMapSelection()
+
+        def _addLayer(self, name, ltype='raster'):
+            """Add layer into map
+
+            :param str name: map name
+            :param str ltype: layer type
+            """
+            mapLayer = self._mapObj.AddLayer(
+                ltype=ltype, name=name,
+                command=['d.rast', "map={}".format(name)],
+                active=True, hidden=False, opacity=1.0, render=True,
+            )
+
+        def OnMapCreated(self, name, ltype):
+            """Add new created raster layer into map
+
+            :param str name: map name
+            :param str ltype: layer type
+            """
+            self._mapObj.Clean()
+            self._addLayer(name=name, ltype=ltype)
+            self.GetMapWindow().UpdateMap()
+
+    kwargs = {
+        'new_map': options['create'],
+        'base_map': options['base'],
+        'edit_map': options['edit'],
+        'map_type': options['type'],
+    }
+
+    mapset = gs.gisenv()['MAPSET']
+
+    if kwargs['edit_map']:
+        edit_map = gs.find_file(
+            name=kwargs['edit_map'], element='raster',
+            mapset=mapset,
+        )['fullname']
+
+        if not edit_map:
+            gs.fatal(
+                _(
+                    "Raster map <{}> not found in current mapset.".format(
+                        options['edit'],
+                    ),
+                ),
+            )
+        else:
+            kwargs['edit_map'] = edit_map
+    else:
+        if kwargs['base_map']:
+            base_map = gs.find_file(
+                name=kwargs['base_map'], element='raster',
+                mapset=mapset,
+            )['fullname']
+            if not base_map:
+                gs.fatal(
+                    _(
+                        "Base raster map <{}> not found in "
+                        "current mapset."
+                        .format(
+                            options['base'],
+                        ),
+                    ),
+                )
+            kwargs['base_map'] = base_map
+
+    # allow immediate rendering
+    driver = UserSettings.Get(
+        group='display', key='driver', subkey='type',
+    )
+    if driver == 'png':
+        os.environ['GRASS_RENDER_IMMEDIATE'] = 'png'
+    else:
+        os.environ['GRASS_RENDER_IMMEDIATE'] = 'cairo'
+
+    app = wx.App()
+    frame = RDigitMapFrame(**kwargs)
+    frame.Show()
+
+    app.MainLoop()
+
+if __name__ == "__main__":
+    main()

+ 1 - 1
gui/wxpython/rdigit/toolbars.py

@@ -143,7 +143,7 @@ class RDigitToolbar(BaseToolbar):
         items.insert(0, new)
         self._mapSelectionCombo.SetItems(items)
 
-    def OnMapSelection(self, event):
+    def OnMapSelection(self, event=None):
         """!Either map to edit or create new map selected."""
         idx = self._mapSelectionCombo.GetSelection()
         if idx == 0:

gui/wxpython/docs/wxGUI_rdigit_step1.png → gui/wxpython/rdigit/wxGUI_rdigit_step1.png


gui/wxpython/docs/wxGUI_rdigit_step2.png → gui/wxpython/rdigit/wxGUI_rdigit_step2.png


gui/wxpython/docs/wxGUI_rdigit_step3.png → gui/wxpython/rdigit/wxGUI_rdigit_step3.png


gui/wxpython/docs/wxGUI_rdigit_step4.png → gui/wxpython/rdigit/wxGUI_rdigit_step4.png


gui/wxpython/docs/wxGUI_rdigit_step5.png → gui/wxpython/rdigit/wxGUI_rdigit_step5.png