[GRASS-SVN] r70552 - in grass/trunk/gui/wxpython: . iphoto2image
svn_grass at osgeo.org
svn_grass at osgeo.org
Mon Feb 13 10:20:04 PST 2017
Author: ychemin
Date: 2017-02-13 10:20:04 -0800 (Mon, 13 Feb 2017)
New Revision: 70552
Added:
grass/trunk/gui/wxpython/iphoto2image/
grass/trunk/gui/wxpython/iphoto2image/Makefile
grass/trunk/gui/wxpython/iphoto2image/__init__.py
grass/trunk/gui/wxpython/iphoto2image/g.gui.iphoto2image.html
grass/trunk/gui/wxpython/iphoto2image/g.gui.iphoto2image.py
grass/trunk/gui/wxpython/iphoto2image/ip2i_manager.py
grass/trunk/gui/wxpython/iphoto2image/ip2i_mapdisplay.py
grass/trunk/gui/wxpython/iphoto2image/ip2i_statusbar.py
grass/trunk/gui/wxpython/iphoto2image/ip2i_toolbars.py
grass/trunk/gui/wxpython/iphoto2image/wxGUI_iphoto2image_frame.jpg
Modified:
grass/trunk/gui/wxpython/Makefile
Log:
Added g.gui.iphoto2image, part of i.ortho.photo suite
Modified: grass/trunk/gui/wxpython/Makefile
===================================================================
--- grass/trunk/gui/wxpython/Makefile 2017-02-13 16:43:14 UTC (rev 70551)
+++ grass/trunk/gui/wxpython/Makefile 2017-02-13 18:20:04 UTC (rev 70552)
@@ -1,6 +1,6 @@
MODULE_TOPDIR = ../..
-SUBDIRS = docs animation datacatalog mapswipe gmodeler rlisetup psmap dbmgr vdigit iclass gcp timeline tplot
+SUBDIRS = docs animation datacatalog mapswipe gmodeler rlisetup psmap dbmgr vdigit iclass gcp timeline tplot iphoto2image
EXTRA_CLEAN_FILES = menustrings.py build_ext.pyc xml/menudata.xml xml/module_tree_menudata.xml */*.pyc
include $(MODULE_TOPDIR)/include/Make/Dir.make
@@ -12,7 +12,7 @@
$(wildcard animation/*.py core/*.py datacatalog/*.py dbmgr/*.py gcp/*.py gmodeler/*.py \
gui_core/*.py iclass/*.py lmgr/*.py location_wizard/*.py mapwin/*.py mapdisp/*.py \
mapswipe/*.py modules/*.py nviz/*.py psmap/*.py rdigit/*.py rlisetup/*.py timeline/*.py vdigit/*.py \
- vnet/*.py web_services/*.py wxplot/*.py iscatt/*.py tplot/*.py) \
+ vnet/*.py web_services/*.py wxplot/*.py iscatt/*.py tplot/*.py iphoto2image/*.py) \
gis_set.py gis_set_error.py wxgui.py README
DSTFILES := $(patsubst %,$(DSTDIR)/%,$(SRCFILES)) \
@@ -20,7 +20,7 @@
PYDSTDIRS := $(patsubst %,$(DSTDIR)/%,animation core datacatalog dbmgr gcp gmodeler \
gui_core iclass lmgr location_wizard mapwin mapdisp modules nviz psmap \
- mapswipe vdigit wxplot web_services rdigit rlisetup vnet timeline iscatt tplot)
+ mapswipe vdigit wxplot web_services rdigit rlisetup vnet timeline iscatt tplot iphoto2image)
DSTDIRS := $(patsubst %,$(DSTDIR)/%,icons scripts xml)
Added: grass/trunk/gui/wxpython/iphoto2image/Makefile
===================================================================
--- grass/trunk/gui/wxpython/iphoto2image/Makefile (rev 0)
+++ grass/trunk/gui/wxpython/iphoto2image/Makefile 2017-02-13 18:20:04 UTC (rev 70552)
@@ -0,0 +1,5 @@
+MODULE_TOPDIR = ../../..
+
+include $(MODULE_TOPDIR)/include/Make/GuiScript.make
+
+default: guiscript
Added: grass/trunk/gui/wxpython/iphoto2image/__init__.py
===================================================================
--- grass/trunk/gui/wxpython/iphoto2image/__init__.py (rev 0)
+++ grass/trunk/gui/wxpython/iphoto2image/__init__.py 2017-02-13 18:20:04 UTC (rev 70552)
@@ -0,0 +1,5 @@
+all = [
+ 'ip2i_manager',
+ 'ip2i_mapdisplay',
+ 'ip2i_toolbars',
+]
Added: grass/trunk/gui/wxpython/iphoto2image/g.gui.iphoto2image.html
===================================================================
--- grass/trunk/gui/wxpython/iphoto2image/g.gui.iphoto2image.html (rev 0)
+++ grass/trunk/gui/wxpython/iphoto2image/g.gui.iphoto2image.html 2017-02-13 18:20:04 UTC (rev 70552)
@@ -0,0 +1,65 @@
+<!-- meta page description: wxGUI GCP Manager for photo to image registration -->
+<!-- meta page index: topic_gui|GUI -->
+<h2>DESCRIPTION</h2>
+This module is based on <b>g.gui.gcp</b>, the GCP manager of GRASS GIS.
+It is part of i.ortho.photo suite.
+
+<p>
+The aim of this module is to give absolute location values to the fiducial
+points present (in number of 4 or 8) in a <i>scanned</i> aerial photo.
+
+<p>
+This is necessary as (manual) scanning introduces distortions, rotations and also
+may not be limited to scan the boundary of the photo itself. It is thus necessary
+to give to each fiducial the exact coordinates in mm as given by the aerial
+photographic instrument design, which is unique per camera.
+
+<p>
+This module requires you to have made a group with your aerial photo <b>(i.group)</b>, a camera
+description file <b>(i.ortho.target)</b> and use them to launch the module. Additional requirements
+are the order of rectification (1 if no of Fiducials is 4, 2 if no of Fiducials is 8) and
+an extension file (if not given, defaults to \$filename_ip2i_out)
+
+<p>
+An example for Location <b>imagery60</b>:
+<br>
+g.gui.iphoto2image group=aerial at PERMANENT raster=gs13.1 at PERMANENT camera=gscamera order=2 extension=try --o
+
+<p>
+<h3>Screenshot of g.gui.iphoto2image</h3>
+
+<center>
+ <br><img src="wxGUI_iphoto2image_frame.jpg" border="0" alt="iphoto2image"><br><br>
+</center>
+
+
+<h2>For a detailed operation manual please read</h2>
+<em>
+ <a href="wxGUI.html">wxGUI</a><br>
+ <a href="wxGUI.components.html">wxGUI components</a>
+</em>
+
+<p>
+See also <a href="http://grasswiki.osgeo.org/wiki/WxGUI/Video_tutorials#Georectifier">video
+tutorials</a> on GRASS Wiki.
+
+<p>
+<h2>SEE ALSO</h2>
+<em>
+<a href="i.ortho.photo.html">i.rectify</a>,
+<a href="i.group.html">i.rectify</a>,
+<a href="i.ortho.camera.html">i.rectify</a>,
+<a href="i.ortho.target.html">i.rectify</a>,
+<a href="i.rectify.html">i.rectify</a>,
+<a href="m.transform.html">m.transform</a>,
+<a href="v.rectify.html">v.rectify</a>
+</em>
+
+<h2>AUTHORS</h2>
+
+Markus Metz<br><br>
+<em>Based on the Georectifier (GRASS 6.4.0)</em> by Michael Barton<br>
+Martin Landa, Czech Technical University in Prague, Czech Republic
+
+<p>
+<i>$Date: 2016-09-19 11:37:30 +0200 (lun., 19 sept. 2016) $</i>
Added: grass/trunk/gui/wxpython/iphoto2image/g.gui.iphoto2image.py
===================================================================
--- grass/trunk/gui/wxpython/iphoto2image/g.gui.iphoto2image.py (rev 0)
+++ grass/trunk/gui/wxpython/iphoto2image/g.gui.iphoto2image.py 2017-02-13 18:20:04 UTC (rev 70552)
@@ -0,0 +1,127 @@
+#!/usr/bin/env python
+
+############################################################################
+#
+# MODULE: Correcting distortions of a scanned photo (modified from GCP Manager)
+# AUTHOR(S): Yann modified the code (was Markus Metz for the GCP Manager)
+# PURPOSE: Takes a scanned photo and fits fiducial points to known geometry
+# COPYRIGHT: (C) 2012-2017 by Markus Metz, 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: Corrects scanning distortions of a paper photo.
+#% keyword: imagery
+#% keyword: aerial
+#% keyword: photo
+#% keyword: GUI
+#%end
+
+#%option G_OPT_I_GROUP
+#% key: group
+#% required: yes
+#%end
+
+#%option G_OPT_R_INPUT
+#% key: raster
+#% required: yes
+#%end
+
+#%option
+#% key: camera
+#% type: string
+#% label: The name of the camera (generated in i.ortho.camera)
+#% description: The name of the camera (generated in i.ortho.camera)
+#% required: yes
+#%end
+
+#%option
+#% key: order
+#% type: string
+#% label: The rectification order (no of Fiducial=4 -> order=1, no of Fiducial=8 -> order=2)
+#% description: The rectification order (no of Fiducial=4 -> order=1, no of Fiducial=8 -> order=2)
+#% required: yes
+#% answer: 1
+#%end
+
+#%option
+#% key: extension
+#% type: string
+#% label: The name of the output files extension (used in i.rectify)
+#% description: The name of the output files extension (used in i.rectify)
+#% required: yes
+#% answer: _ip2i_out
+#%end
+
+"""
+Module to run GCP management tool as stadalone application.
+ at author Vaclav Petras <wenzeslaus gmail.com> (standalone module)
+"""
+import os
+import grass.script as gscript
+
+def main():
+ """Sets the GRASS display driver
+ """
+ options, flags = gscript.parser()
+
+ import wx
+ from grass.script.setup import set_gui_path
+ set_gui_path()
+
+ from core.settings import UserSettings
+ from core.globalvar import CheckWxVersion
+ from core.giface import StandaloneGrassInterface
+ from iphoto2image.ip2i_manager import GCPWizard
+
+ 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'
+
+ if options['group']:
+ group = options['group']
+ else:
+ gscript.fatal(_("Please provide a group name to process"))
+
+ if options['raster']:
+ raster = options['raster']
+ else:
+ gscript.fatal(_("Please provide a raster map name to process"))
+
+ if options['camera']:
+ camera = options['camera']
+ else:
+ gscript.fatal(_("Please provide a camera name (generated by i.ortho.camera)"))
+
+ if options['order']:
+ order = options['order']
+ else:
+ gscript.fatal(_("Please provive an order value (1 if 4 Fiducials, 2 if 8 Fiducials)"))
+
+ if options['extension']:
+ extension = options['extension']
+ else:
+ gscript.fatal(_("Please provive an output files extension (used by i.rectify)"))
+
+ app = wx.App()
+ if not CheckWxVersion([2, 9]):
+ wx.InitAllImageHandlers()
+
+ wizard = GCPWizard(parent=None, giface=StandaloneGrassInterface(), group=group,
+ raster=raster, raster1=raster, camera=camera, order=order, extension=extension)
+ app.MainLoop()
+
+if __name__ == '__main__':
+ main()
Property changes on: grass/trunk/gui/wxpython/iphoto2image/g.gui.iphoto2image.py
___________________________________________________________________
Added: svn:executable
+ *
Added: grass/trunk/gui/wxpython/iphoto2image/ip2i_manager.py
===================================================================
--- grass/trunk/gui/wxpython/iphoto2image/ip2i_manager.py (rev 0)
+++ grass/trunk/gui/wxpython/iphoto2image/ip2i_manager.py 2017-02-13 18:20:04 UTC (rev 70552)
@@ -0,0 +1,2397 @@
+"""
+ at package iphoto2image.ip2i_manager
+
+ at brief Scanning distortion correction of a photo for GRASS GIS.
+Includes ground control point management and interactive point
+and click GCP creation
+
+Classes:
+ - ip2i_manager::GCPWizard
+ - ip2i_manager::GCP
+ - ip2i_manager::GCPList
+ - ip2i_manager::EditGCP
+ - ip2i_manager::GrSettingsDialog
+
+(C) 2006-2017 by the GRASS Development Team
+
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
+
+ at author Original author Michael Barton
+ at author Original version improved by Martin Landa <landa.martin gmail.com>
+ at author Rewritten by Markus Metz redesign georectfier -> GCP Manage
+ at author Support for GraphicsSet added by Stepan Turek <stepan.turek seznam.cz> (2012)
+ at author Yann modified: graphical replacement of i.photo.2image (was in v6 using Vask lib)
+"""
+
+import os
+import sys
+import shutil
+import time
+from copy import copy
+
+import wx
+from wx.lib.mixins.listctrl import CheckListCtrlMixin, ColumnSorterMixin, ListCtrlAutoWidthMixin
+import wx.lib.colourselect as csel
+
+from core import globalvar
+if globalvar.wxPythonPhoenix:
+ from wx.adv import Wizard as wiz
+else:
+ import wx.wizard as wiz
+
+import grass.script as grass
+
+from core import utils
+from core.render import Map
+from core.utils import _
+from gui_core.gselect import Select, LocationSelect, MapsetSelect
+from gui_core.dialogs import GroupDialog
+from core.gcmd import RunCommand, GMessage, GError, GWarning, EncodeString
+from core.settings import UserSettings
+from iphoto2image.ip2i_mapdisplay import MapFrame
+from core.giface import Notification
+from gui_core.wrap import SpinCtrl
+
+from location_wizard.wizard import TitledPage as TitledPage
+
+#
+# global variables
+#
+global src_map
+global tgt_map
+global maptype
+
+src_map = ''
+tgt_map = ''
+maptype = 'raster'
+
+
+def getSmallUpArrowImage():
+ stream = open(os.path.join(globalvar.IMGDIR, 'small_up_arrow.png'), 'rb')
+ try:
+ img = wx.ImageFromStream(stream)
+ finally:
+ stream.close()
+ return img
+
+
+def getSmallDnArrowImage():
+ stream = open(os.path.join(globalvar.IMGDIR, 'small_down_arrow.png'), 'rb')
+ try:
+ img = wx.ImageFromStream(stream)
+ finally:
+ stream.close()
+ stream.close()
+ return img
+
+
+class GCPWizard(object):
+ """
+ Not a wizard anymore
+ """
+
+ def __init__(self, parent, giface, group, raster, raster1, camera, order, extension):
+ global maptype
+ global src_map
+ global tgt_map
+ maptype = 'raster'
+ rendertype = 'raster'
+ self.parent = parent # GMFrame
+ self._giface = giface
+ self.group = group
+ self.src_map = raster
+ self.tgt_map = raster1
+ self.camera = camera
+ self.order = int(order)
+ self.extension = extension
+ self.src_maps=self.src_map
+
+ #
+ # get environmental variables
+ #
+ self.grassdatabase = grass.gisenv()['GISDBASE']
+
+ #
+ # read original environment settings
+ #
+ self.target_gisrc = os.environ['GISRC']
+ self.source_gisrc = os.environ['GISRC']
+ self.gisrc_dict = {}
+ try:
+ f = open(self.target_gisrc, 'r')
+ for line in f.readlines():
+ line = line.replace('\n', '').strip()
+ if len(line) < 1:
+ continue
+ key, value = line.split(':', 1)
+ self.gisrc_dict[key.strip()] = value.strip()
+ finally:
+ f.close()
+
+ self.currentlocation = self.gisrc_dict['LOCATION_NAME']
+ self.currentmapset = self.gisrc_dict['MAPSET']
+ # location for xy map to georectify
+ self.newlocation = self.currentlocation
+ self.xylocation = self.currentlocation
+ # mapset for xy map to georectify
+ self.newmapset = self.currentmapset
+ self.xymapset = self.currentmapset
+ # get group name from command line
+ self.xygroup = self.group
+
+ # GISRC file for source location/mapset of map(s) to georectify
+ self.SetSrcEnv(self.currentlocation,self.currentmapset)
+
+ #
+ # start GCP display
+ #
+ # instance of render.Map to be associated with display
+ self.SwitchEnv('source')
+ self.SrcMap = Map(gisrc=self.source_gisrc)
+ self.SwitchEnv('target')
+ self.TgtMap = Map(gisrc=self.target_gisrc)
+ self.Map = self.SrcMap
+
+ #
+ # add layer to source map
+ #
+ try:
+ # set computational region to match selected map and zoom display
+ # to region
+ p = RunCommand('g.region', 'raster='+self.src_map)
+
+ if p.returncode == 0:
+ print 'returncode = ', str(p.returncode)
+ self.Map.region = self.Map.GetRegion()
+ except:
+ pass
+
+ self.SwitchEnv('source')
+ cmdlist = ['d.rast', 'map=%s' % self.src_map]
+ name, found = utils.GetLayerNameFromCmd(cmdlist)
+ self.SrcMap.AddLayer(
+ ltype=rendertype,
+ command=cmdlist,
+ active=True,
+ name=name,
+ hidden=False,
+ opacity=1.0,
+ render=False)
+
+ #
+ # add raster layer to target map
+ #
+ self.SwitchEnv('target')
+ cmdlist = ['d.rast', 'map=%s' % self.tgt_map]
+ name, found = utils.GetLayerNameFromCmd(cmdlist)
+ self.TgtMap.AddLayer(
+ ltype=rendertype,
+ command=cmdlist,
+ active=True,
+ name=name,
+ hidden=False,
+ opacity=1.0,
+ render=False)
+
+ #
+ # start GCP Manager
+ #
+ self.gcpmgr = GCP(self.parent, giface=self._giface,
+ grwiz=self, size=globalvar.MAP_WINDOW_SIZE,
+ toolbars=["gcpdisp"],
+ Map=self.SrcMap, lmgr=self.parent, camera=camera)
+
+ # load GCPs
+ self.gcpmgr.InitMapDisplay()
+ self.gcpmgr.CenterOnScreen()
+ self.gcpmgr.Show()
+ # need to update AUI here for wingrass
+ self.gcpmgr._mgr.Update()
+ self.SwitchEnv('target')
+
+ def SetSrcEnv(self, location, mapset):
+ """Create environment to use for location and mapset
+ that are the source of the file(s) to georectify
+
+ :param location: source location
+ :param mapset: source mapset
+
+ :return: False on error
+ :return: True on success
+ """
+
+ self.newlocation = location
+ self.newmapset = mapset
+
+ # check to see if we are georectifying map in current working
+ # location/mapset
+ if self.newlocation == self.currentlocation and self.newmapset == self.currentmapset:
+ return False
+
+ self.gisrc_dict['LOCATION_NAME'] = location
+ self.gisrc_dict['MAPSET'] = mapset
+
+ self.source_gisrc = EncodeString(utils.GetTempfile())
+
+ try:
+ f = open(self.source_gisrc, mode='w')
+ for line in self.gisrc_dict.items():
+ f.write(line[0] + ": " + line[1] + "\n")
+ finally:
+ f.close()
+
+ return True
+
+ def SwitchEnv(self, grc):
+ """
+ Switches between original working location/mapset and
+ location/mapset that is source of file(s) to georectify
+ """
+ # check to see if we are georectifying map in current working
+ # location/mapset
+ if self.newlocation == self.currentlocation and self.newmapset == self.currentmapset:
+ return False
+
+ if grc == 'target':
+ os.environ['GISRC'] = str(self.target_gisrc)
+ elif grc == 'source':
+ os.environ['GISRC'] = str(self.source_gisrc)
+
+ return True
+
+ def OnGLMFocus(self, event):
+ """Layer Manager focus"""
+ # self.SwitchEnv('target')
+
+ event.Skip()
+
+class GCP(MapFrame, ColumnSorterMixin):
+ """
+ Manages ground control points for georectifying. Calculates RMS statistics.
+ Calls i.rectify or v.rectify to georectify map.
+ """
+
+ def __init__(self, parent, giface, grwiz=None, id=wx.ID_ANY,
+ title=_("Manage Location of Fiducial Points on a Scanned Photo"),
+ size=(700, 300), toolbars=["gcpdisp"], Map=None, lmgr=None, camera=None):
+
+ self.grwiz = grwiz # GR Wizard
+ self._giface = giface
+
+ if tgt_map == '':
+ self.show_target = False
+ else:
+ self.show_target = True
+
+ self.camera = camera
+
+ #wx.Frame.__init__(self, parent, id, title, size = size, name = "GCPFrame")
+ MapFrame.__init__(
+ self,
+ parent=parent,
+ giface=self._giface,
+ title=title,
+ size=size,
+ Map=Map,
+ toolbars=toolbars,
+ name='GCPMapWindow')
+
+ # init variables
+ self.parent = parent
+
+ #
+ # register data structures for drawing GCP's
+ #
+ self.pointsToDrawTgt = self.TgtMapWindow.RegisterGraphicsToDraw(
+ graphicsType="point", setStatusFunc=self.SetGCPSatus)
+ self.pointsToDrawSrc = self.SrcMapWindow.RegisterGraphicsToDraw(
+ graphicsType="point", setStatusFunc=self.SetGCPSatus)
+
+ # connect to the map windows signals
+ # used to add or edit GCP
+ self.SrcMapWindow.mouseLeftUpPointer.connect(
+ lambda x, y:
+ self._onMouseLeftUpPointer(self.SrcMapWindow, x, y))
+ self.TgtMapWindow.mouseLeftUpPointer.connect(
+ lambda x, y:
+ self._onMouseLeftUpPointer(self.TgtMapWindow, x, y))
+
+ # window resized
+ self.resize = False
+
+ self.grassdatabase = self.grwiz.grassdatabase
+
+ self.currentlocation = self.grwiz.currentlocation
+ self.currentmapset = self.grwiz.currentmapset
+
+ self.newlocation = self.grwiz.newlocation
+ self.newmapset = self.grwiz.newmapset
+
+ self.xylocation = self.grwiz.gisrc_dict['LOCATION_NAME']
+ self.xymapset = self.grwiz.gisrc_dict['MAPSET']
+ self.xygroup = self.grwiz.xygroup.split("@")[0]
+ self.src_maps = self.grwiz.src_maps
+ self.extension = self.grwiz.extension
+ self.outname = ''
+
+ self.file = {
+ 'camera': os.path.join(self.grassdatabase,
+ self.xylocation,
+ self.xymapset,
+ 'camera',
+ self.camera),
+ 'points': os.path.join(self.grassdatabase,
+ self.xylocation,
+ self.xymapset,
+ 'group',
+ self.xygroup,
+ 'POINTS'),
+ 'points_bak': os.path.join(self.grassdatabase,
+ self.xylocation,
+ self.xymapset,
+ 'group',
+ self.xygroup,
+ 'POINTS_BAK'),
+ 'rgrp': os.path.join(self.grassdatabase,
+ self.xylocation,
+ self.xymapset,
+ 'group',
+ self.xygroup,
+ 'REF'),
+ 'target': os.path.join(self.grassdatabase,
+ self.xylocation,
+ self.xymapset,
+ 'group',
+ self.xygroup,
+ 'TARGET'),
+ }
+
+ # make a backup of the current points file if exists
+ if os.path.exists(self.file['points']):
+ shutil.copy(self.file['points'], self.file['points_bak'])
+ GMessage (_("An POINTS file exists, renaming it to POINTS_BAK"))
+
+ #"""Make a POINTS file """
+ import re,sys
+ try:
+ fc = open(self.file['camera'], mode='r')
+ fc_count=0
+ for line in fc:
+ fc_count+=1
+ if re.search("NUM", line):
+ storeLine=fc_count
+ numberOfFiducial = int(line.split()[-1])
+ dataFiducialX=[]
+ dataFiducialY=[]
+ fc = open(self.file['camera'], mode='r')
+ fc_count=0
+ for line in fc:
+ fc_count+=1
+ if fc_count > storeLine :
+ dataFiducialX.append(line.split()[1])
+ dataFiducialY.append(line.split()[2])
+
+ except IOError as err:
+ GError(
+ parent=self,
+ message="%s <%s>. %s%s" %
+ (_("Opening CAMERA file failed"),
+ self.file['camera'],
+ os.linesep,
+ err))
+ return
+
+ self.GCPcount = 0
+ try:
+ f = open(self.file['points'], mode='w')
+ # use os.linesep or '\n' here ???
+ f.write('# Ground Control Points File\n')
+ f.write("# \n")
+ f.write("# target location: " + self.currentlocation + '\n')
+ f.write("# target mapset: " + self.currentmapset + '\n')
+ f.write("#\tsource\t\ttarget\t\tstatus\n")
+ f.write("#\teast\tnorth\teast\tnorth\t(1=ok, 0=ignore)\n")
+ f.write(
+ "#----------------------- ----------------------- ---------------\n")
+
+ check = "0"
+ for index in range(numberOfFiducial):
+ coordX0 = "0"
+ coordY0 = "0"
+ coordX1 = dataFiducialX[index]
+ coordY1 = dataFiducialY[index]
+ f.write(coordX0 + ' ' +
+ coordY0 + ' ' +
+ coordX1 + ' ' +
+ coordY1 + ' ' +
+ check + '\n')
+
+ except IOError as err:
+ GError(
+ parent=self,
+ message="%s <%s>. %s%s" %
+ (_("Writing POINTS file failed"),
+ self.file['points'],
+ os.linesep,
+ err))
+ return
+
+ f.close()
+
+ # polynomial order transformation for georectification
+ self.gr_order = self.grwiz.order
+ # interpolation method for georectification
+ self.gr_method = 'nearest'
+ # region clipping for georectified map
+ self.clip_to_region = False
+ # number of GCPs selected to be used for georectification (checked)
+ self.GCPcount = 0
+ # forward RMS error
+ self.fwd_rmserror = 0.0
+ # backward RMS error
+ self.bkw_rmserror = 0.0
+ # list map coords and ID of map display they came from
+ self.mapcoordlist = []
+ self.mapcoordlist.append([0, # GCP number
+ 0.0, # source east
+ 0.0, # source north
+ 0.0, # target east
+ 0.0, # target north
+ 0.0, # forward error
+ 0.0]) # backward error
+
+ # init vars to highlight high RMS errors
+ self.highest_only = True
+ self.show_unused = True
+ self.highest_key = -1
+ self.rmsthresh = 0
+ self.rmsmean = 0
+ self.rmssd = 0
+
+ self.SetTarget(self.xygroup, self.currentlocation, self.currentmapset)
+
+ self.itemDataMap = None
+
+ # images for column sorting
+ # CheckListCtrlMixin must set an ImageList first
+ self.il = self.list.GetImageList(wx.IMAGE_LIST_SMALL)
+
+ SmallUpArrow = wx.BitmapFromImage(getSmallUpArrowImage())
+ SmallDnArrow = wx.BitmapFromImage(getSmallDnArrowImage())
+ self.sm_dn = self.il.Add(SmallDnArrow)
+ self.sm_up = self.il.Add(SmallUpArrow)
+
+ # set mouse characteristics
+ self.mapwin = self.SrcMapWindow
+ self.mapwin.mouse['box'] = 'point'
+ self.mapwin.mouse["use"] == "pointer"
+ self.mapwin.zoomtype = 0
+ self.mapwin.pen = wx.Pen(colour='black', width=2, style=wx.SOLID)
+ self.mapwin.SetNamedCursor('cross')
+
+ self.mapwin = self.TgtMapWindow
+
+ # set mouse characteristics
+ self.mapwin.mouse['box'] = 'point'
+ self.mapwin.mouse["use"] == "pointer"
+ self.mapwin.zoomtype = 0
+ self.mapwin.pen = wx.Pen(colour='black', width=2, style=wx.SOLID)
+ self.mapwin.SetNamedCursor('cross')
+
+ #
+ # show new display & draw map
+ #
+ if self.show_target:
+ self.MapWindow = self.TgtMapWindow
+ self.Map = self.TgtMap
+ self.OnZoomToMap(None)
+
+ self.MapWindow = self.SrcMapWindow
+ self.Map = self.SrcMap
+ self.OnZoomToMap(None)
+
+ #
+ # bindings
+ #
+ self.Bind(wx.EVT_ACTIVATE, self.OnFocus)
+ self.Bind(wx.EVT_SIZE, self.OnSize)
+ self.Bind(wx.EVT_IDLE, self.OnIdle)
+ self.Bind(wx.EVT_CLOSE, self.OnQuit)
+
+ self.SetSettings()
+
+ def __del__(self):
+ """Disable GCP manager mode"""
+ # leaving the method here but was used only to delete gcpmanagement
+ # from layer manager which is now not needed
+ pass
+
+ def CreateGCPList(self):
+ """Create GCP List Control"""
+
+ return GCPList(parent=self, gcp=self)
+
+ # Used by the ColumnSorterMixin, see wx/lib/mixins/listctrl.py
+ def GetListCtrl(self):
+ return self.list
+
+ def GetMapCoordList(self):
+ return self.mapcoordlist
+
+ # Used by the ColumnSorterMixin, see wx/lib/mixins/listctrl.py
+ def GetSortImages(self):
+ return (self.sm_dn, self.sm_up)
+
+ def GetFwdError(self):
+ return self.fwd_rmserror
+
+ def GetBkwError(self):
+ return self.bkw_rmserror
+
+ def InitMapDisplay(self):
+ self.list.LoadData()
+
+ # initialize column sorter
+ self.itemDataMap = self.mapcoordlist
+ ncols = self.list.GetColumnCount()
+ ColumnSorterMixin.__init__(self, ncols)
+ # init to ascending sort on first click
+ self._colSortFlag = [1] * ncols
+
+ def SetTarget(self, tgroup, tlocation, tmapset):
+ """
+ Sets rectification target to current location and mapset
+ """
+ # check to see if we are georectifying map in current working
+ # location/mapset
+ if self.newlocation == self.currentlocation and self.newmapset == self.currentmapset:
+ RunCommand('i.target',
+ parent=self,
+ flags='c',
+ group=tgroup)
+ else:
+ self.grwiz.SwitchEnv('source')
+ RunCommand('i.target',
+ parent=self,
+ group=tgroup,
+ location=tlocation,
+ mapset=tmapset)
+ self.grwiz.SwitchEnv('target')
+
+ def AddGCP(self, event):
+ """
+ Appends an item to GCP list
+ """
+ keyval = self.list.AddGCPItem() + 1
+ # source east, source north, target east, target north, forward error,
+ # backward error
+ self.mapcoordlist.append([keyval, # GCP number
+ 0.0, # source east
+ 0.0, # source north
+ 0.0, # target east
+ 0.0, # target north
+ 0.0, # forward error
+ 0.0]) # backward error
+
+ if self.statusbarManager.GetMode() == 8: # go to
+ self.StatusbarUpdate()
+
+ def DeleteGCP(self, event):
+ """
+ Deletes selected item in GCP list
+ """
+ minNumOfItems = self.OnGROrder(None)
+
+ if self.list.GetItemCount() <= minNumOfItems:
+ GMessage(
+ parent=self,
+ message=_("At least %d GCPs required. Operation canceled.") %
+ minNumOfItems)
+ return
+
+ key = self.list.DeleteGCPItem()
+ del self.mapcoordlist[key]
+
+ # update key and GCP number
+ for newkey in range(key, len(self.mapcoordlist)):
+ index = self.list.FindItemData(-1, newkey + 1)
+ self.mapcoordlist[newkey][0] = newkey
+ self.list.SetStringItem(index, 0, str(newkey))
+ self.list.SetItemData(index, newkey)
+
+ # update selected
+ if self.list.GetItemCount() > 0:
+ if self.list.selected < self.list.GetItemCount():
+ self.list.selectedkey = self.list.GetItemData(
+ self.list.selected)
+ else:
+ self.list.selected = self.list.GetItemCount() - 1
+ self.list.selectedkey = self.list.GetItemData(
+ self.list.selected)
+
+ self.list.SetItemState(self.list.selected,
+ wx.LIST_STATE_SELECTED,
+ wx.LIST_STATE_SELECTED)
+ else:
+ self.list.selected = wx.NOT_FOUND
+ self.list.selectedkey = -1
+
+ self.UpdateColours()
+
+ if self.statusbarManager.GetMode() == 8: # go to
+ self.StatusbarUpdate()
+ if self.list.selectedkey > 0:
+ self.statusbarManager.SetProperty(
+ 'gotoGCP', self.list.selectedkey)
+
+ def ClearGCP(self, event):
+ """
+ Clears all values in selected item of GCP list and unchecks it
+ """
+ index = self.list.GetSelected()
+ key = self.list.GetItemData(index)
+
+ for i in range(1, 5):
+ self.list.SetStringItem(index, i, '0.0')
+ self.list.SetStringItem(index, 5, '')
+ self.list.SetStringItem(index, 6, '')
+ self.list.CheckItem(index, False)
+
+ # GCP number, source E, source N, target E, target N, fwd error, bkwd
+ # error
+ self.mapcoordlist[key] = [key, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
+
+ def SetSettings(self):
+ """Sets settings for drawing of GCP's.
+ """
+ self.highest_only = UserSettings.Get(
+ group='gcpman', key='rms', subkey='highestonly')
+ self.show_unused = UserSettings.Get(
+ group='gcpman', key='symbol', subkey='unused')
+
+ colours = {"color": "default",
+ "hcolor": "highest",
+ "scolor": "selected",
+ "ucolor": "unused"}
+ wpx = UserSettings.Get(group='gcpman', key='symbol', subkey='width')
+
+ for k, v in colours.iteritems():
+ col = UserSettings.Get(group='gcpman', key='symbol', subkey=k)
+ self.pointsToDrawSrc.GetPen(v).SetColour(wx.Colour(
+ col[0], col[1], col[2], 255)) # TODO GetPen neni to spatne?
+ self.pointsToDrawTgt.GetPen(v).SetColour(
+ wx.Colour(col[0], col[1], col[2], 255))
+
+ self.pointsToDrawSrc.GetPen(v).SetWidth(wpx)
+ self.pointsToDrawTgt.GetPen(v).SetWidth(wpx)
+
+ spx = UserSettings.Get(group='gcpman', key='symbol', subkey='size')
+ self.pointsToDrawSrc.SetPropertyVal("size", int(spx))
+ self.pointsToDrawTgt.SetPropertyVal("size", int(spx))
+
+ font = self.GetFont()
+ font.SetPointSize(int(spx) + 2)
+
+ textProp = {}
+ textProp['active'] = True
+ textProp['font'] = font
+ self.pointsToDrawSrc.SetPropertyVal("text", textProp)
+ self.pointsToDrawTgt.SetPropertyVal("text", copy(textProp))
+
+ def SetGCPSatus(self, item, itemIndex):
+ """Before GCP is drawn, decides it's colour and whether it
+ will be drawed.
+ """
+ key = self.list.GetItemData(itemIndex)
+ # incremented because of itemDataMap (has one more item) - will be
+ # changed
+ itemIndex += 1
+
+ if not self.list.IsChecked(key - 1):
+ wxPen = "unused"
+ if not self.show_unused:
+ item.SetPropertyVal('hide', True)
+ else:
+ item.SetPropertyVal('hide', False)
+
+ else:
+ item.SetPropertyVal('hide', False)
+ if self.highest_only == True:
+ if itemIndex == self.highest_key:
+ wxPen = "highest"
+ else:
+ wxPen = "default"
+ else:
+ if (self.mapcoordlist[key][5] > self.rmsthresh):
+ wxPen = "highest"
+ else:
+ wxPen = "default"
+
+ if itemIndex == self.list.selectedkey:
+ wxPen = "selected"
+
+ item.SetPropertyVal('label', str(itemIndex))
+ item.SetPropertyVal('penName', wxPen)
+
+ def SetGCPData(self, coordtype, coord, mapdisp=None, confirm=False):
+ """Inserts coordinates from file, mouse click on map, or
+ after editing into selected item of GCP list and checks it for
+ use.
+ """
+ index = self.list.GetSelected()
+ if index == wx.NOT_FOUND:
+ return
+
+ coord0 = coord[0]
+ coord1 = coord[1]
+
+ key = self.list.GetItemData(index)
+ if confirm:
+ if self.MapWindow == self.SrcMapWindow:
+ currloc = _("source")
+ else:
+ currloc = _("target")
+ ret = wx.MessageBox(
+ parent=self, caption=_("Set GCP coordinates"),
+ message=_(
+ 'Set %(coor)s coordinates for GCP No. %(key)s? \n\n'
+ 'East: %(coor0)s \n'
+ 'North: %(coor1)s') %
+ {'coor': currloc, 'key': str(key),
+ 'coor0': str(coord0),
+ 'coor1': str(coord1)},
+ style=wx.ICON_QUESTION | wx.YES_NO | wx.CENTRE)
+
+ # for wingrass
+ if os.name == 'nt':
+ self.MapWindow.SetFocus()
+ if ret == wx.NO:
+ return
+
+ if coordtype == 'source':
+ self.list.SetStringItem(index, 1, str(coord0))
+ self.list.SetStringItem(index, 2, str(coord1))
+ self.mapcoordlist[key][1] = coord[0]
+ self.mapcoordlist[key][2] = coord[1]
+ self.pointsToDrawSrc.GetItem(key - 1).SetCoords([coord0, coord1])
+
+ elif coordtype == 'target':
+ self.list.SetStringItem(index, 3, str(coord0))
+ self.list.SetStringItem(index, 4, str(coord1))
+ self.mapcoordlist[key][3] = coord[0]
+ self.mapcoordlist[key][4] = coord[1]
+ self.pointsToDrawTgt.GetItem(key - 1).SetCoords([coord0, coord1])
+
+ self.list.SetStringItem(index, 5, '0')
+ self.list.SetStringItem(index, 6, '0')
+ self.mapcoordlist[key][5] = 0.0
+ self.mapcoordlist[key][6] = 0.0
+
+ # self.list.ResizeColumns()
+
+ def SaveGCPs(self, event):
+ """Make a POINTS file or save GCP coordinates to existing
+ POINTS file
+ """
+ self.GCPcount = 0
+ try:
+ f = open(self.file['points'], mode='w')
+ # use os.linesep or '\n' here ???
+ f.write('# Ground Control Points File\n')
+ f.write("# \n")
+ f.write("# target location: " + self.currentlocation + '\n')
+ f.write("# target mapset: " + self.currentmapset + '\n')
+ f.write("#\tsource\t\ttarget\t\tstatus\n")
+ f.write("#\teast\tnorth\teast\tnorth\t(1=ok, 0=ignore)\n")
+ f.write(
+ "#----------------------- ----------------------- ---------------\n")
+
+ for index in range(self.list.GetItemCount()):
+ if self.list.IsChecked(index) == True:
+ check = "1"
+ self.GCPcount += 1
+ else:
+ check = "0"
+ coord0 = self.list.GetItem(index, 1).GetText()
+ coord1 = self.list.GetItem(index, 2).GetText()
+ coord2 = self.list.GetItem(index, 3).GetText()
+ coord3 = self.list.GetItem(index, 4).GetText()
+ f.write(
+ coord0 +
+ ' ' +
+ coord1 +
+ ' ' +
+ coord2 +
+ ' ' +
+ coord3 +
+ ' ' +
+ check +
+ '\n')
+
+ except IOError as err:
+ GError(
+ parent=self,
+ message="%s <%s>. %s%s" %
+ (_("Writing POINTS file failed"),
+ self.file['points'],
+ os.linesep,
+ err))
+ return
+
+ f.close()
+
+ # if event != None save also to backup file
+ if event:
+ shutil.copy(self.file['points'], self.file['points_bak'])
+ self._giface.WriteLog(
+ _('POINTS file saved for group <%s>') %
+ self.xygroup)
+ #self.SetStatusText(_('POINTS file saved'))
+
+ def ReadGCPs(self):
+ """
+ Reads GCPs and georectified coordinates from POINTS file
+ """
+
+ self.GCPcount = 0
+
+ sourceMapWin = self.SrcMapWindow
+ targetMapWin = self.TgtMapWindow
+
+ if not sourceMapWin:
+ GError(parent=self,
+ message="%s. %s%s" % (_("source mapwin not defined"),
+ os.linesep, err))
+
+ if not targetMapWin:
+ GError(parent=self,
+ message="%s. %s%s" % (_("target mapwin not defined"),
+ os.linesep, err))
+
+ try:
+ f = open(self.file['points'], 'r')
+ GCPcnt = 0
+
+ for line in f.readlines():
+ if line[0] == '#' or line == '':
+ continue
+ line = line.replace('\n', '').strip()
+ coords = map(float, line.split())
+ if coords[4] == 1:
+ check = True
+ self.GCPcount += 1
+ else:
+ check = False
+
+ self.AddGCP(event=None)
+ self.SetGCPData('source', (coords[0], coords[1]), sourceMapWin)
+ self.SetGCPData('target', (coords[2], coords[3]), targetMapWin)
+ index = self.list.GetSelected()
+ if index != wx.NOT_FOUND:
+ self.list.CheckItem(index, check)
+ GCPcnt += 1
+
+ except IOError as err:
+ GError(
+ parent=self,
+ message="%s <%s>. %s%s" %
+ (_("Reading POINTS file failed"),
+ self.file['points'],
+ os.linesep,
+ err))
+ return
+
+ f.close()
+
+ if GCPcnt == 0:
+ # 3 gcp is minimum
+ for i in range(3):
+ self.AddGCP(None)
+
+ if self.CheckGCPcount():
+ # calculate RMS
+ self.RMSError(self.xygroup, self.gr_order)
+
+ def ReloadGCPs(self, event):
+ """Reload data from file"""
+
+ # use backup
+ shutil.copy(self.file['points_bak'], self.file['points'])
+
+ # delete all items in mapcoordlist
+ self.mapcoordlist = []
+ self.mapcoordlist.append([0, # GCP number
+ 0.0, # source east
+ 0.0, # source north
+ 0.0, # target east
+ 0.0, # target north
+ 0.0, # forward error
+ 0.0]) # backward error
+
+ self.list.LoadData()
+ self.itemDataMap = self.mapcoordlist
+
+ if self._col != -1:
+ self.list.ClearColumnImage(self._col)
+ self._colSortFlag = [1] * self.list.GetColumnCount()
+
+ # draw GCPs (source and target)
+ sourceMapWin = self.SrcMapWindow
+ sourceMapWin.UpdateMap(render=False)
+ if self.show_target:
+ targetMapWin = self.TgtMapWindow
+ targetMapWin.UpdateMap(render=False)
+
+ def OnFocus(self, event):
+ # TODO: it is here just to remove old or obsolate beavior of base class gcp/MapFrame?
+ # self.grwiz.SwitchEnv('source')
+ pass
+
+ def _onMouseLeftUpPointer(self, mapWindow, x, y):
+ if mapWindow == self.SrcMapWindow:
+ coordtype = 'source'
+ else:
+ coordtype = 'target'
+
+ coord = (x, y)
+ self.SetGCPData(coordtype, coord, self, confirm=True)
+ mapWindow.UpdateMap(render=False)
+
+ def OnRMS(self, event):
+ """
+ RMS button handler
+ """
+ self.RMSError(self.xygroup, self.gr_order)
+
+ sourceMapWin = self.SrcMapWindow
+ sourceMapWin.UpdateMap(render=False)
+ if self.show_target:
+ targetMapWin = self.TgtMapWindow
+ targetMapWin.UpdateMap(render=False)
+
+ def CheckGCPcount(self, msg=False):
+ """
+ Checks to make sure that the minimum number of GCPs have been defined and
+ are active for the selected transformation order
+ """
+ if (self.GCPcount < 3 and self.gr_order == 1) or \
+ (self.GCPcount < 6 and self.gr_order == 2) or \
+ (self.GCPcount < 10 and self.gr_order == 3):
+ if msg:
+ GWarning(
+ parent=self, message=_(
+ 'Insufficient points defined and active (checked) '
+ 'for selected rectification method (order: %d).\n'
+ '3+ points needed for 1st order,\n'
+ '6+ points for 2nd order, and\n'
+ '10+ points for 3rd order.') %
+ self.gr_order)
+ return False
+ else:
+ return True
+
+ def OnGeorect(self, event):
+ """
+ Georectifies map(s) in group using i.rectify or v.transform
+ """
+ global maptype
+ self.SaveGCPs(None)
+
+ if self.CheckGCPcount(msg=True) == False:
+ return
+
+ if maptype == 'raster':
+ self.grwiz.SwitchEnv('source')
+
+ if self.clip_to_region:
+ flags = "ac"
+ else:
+ flags = "a"
+
+ busy = wx.BusyInfo(message=_("Rectifying images, please wait..."),
+ parent=self)
+ wx.Yield()
+
+ ret, msg = RunCommand('i.rectify',
+ parent=self,
+ getErrorMsg=True,
+ quiet=True,
+ group=self.xygroup,
+ extension=self.extension,
+ order=self.gr_order,
+ method=self.gr_method,
+ flags=flags)
+
+ busy.Destroy()
+
+ # provide feedback on failure
+ if ret != 0:
+ print >> sys.stderr, msg
+
+ self.grwiz.SwitchEnv('target')
+
+ def OnGeorectDone(self, **kargs):
+ """Print final message"""
+ global maptype
+ if maptype == 'raster':
+ return
+
+ def OnSettings(self, event):
+ """GCP Manager settings"""
+ dlg = GrSettingsDialog(parent=self, giface=self._giface,
+ id=wx.ID_ANY, title=_('GCP Manager settings'))
+
+ if dlg.ShowModal() == wx.ID_OK:
+ pass
+
+ dlg.Destroy()
+
+ def UpdateColours(self, srcrender=False,
+ tgtrender=False):
+ """update colours"""
+ highest_fwd_err = 0.0
+ self.highest_key = 0
+ highest_idx = 0
+
+ for index in range(self.list.GetItemCount()):
+ if self.list.IsChecked(index):
+ key = self.list.GetItemData(index)
+ fwd_err = self.mapcoordlist[key][5]
+
+ if self.highest_only == True:
+ self.list.SetItemTextColour(index, wx.BLACK)
+ if highest_fwd_err < fwd_err:
+ highest_fwd_err = fwd_err
+ self.highest_key = key
+ highest_idx = index
+ elif self.rmsthresh > 0:
+ if (fwd_err > self.rmsthresh):
+ self.list.SetItemTextColour(index, wx.RED)
+ else:
+ self.list.SetItemTextColour(index, wx.BLACK)
+ else:
+ self.list.SetItemTextColour(index, wx.BLACK)
+
+ if self.highest_only and highest_fwd_err > 0.0:
+ self.list.SetItemTextColour(highest_idx, wx.RED)
+
+ sourceMapWin = self.SrcMapWindow
+ sourceMapWin.UpdateMap(render=srcrender)
+ if self.show_target:
+ targetMapWin = self.TgtMapWindow
+ targetMapWin.UpdateMap(render=tgtrender)
+
+ def OnQuit(self, event):
+ """Quit georectifier"""
+ ret = wx.MessageBox(
+ parent=self, caption=_("Quit GCP Manager"),
+ message=_('Save ground control points?'),
+ style=wx.ICON_QUESTION | wx.YES_NO | wx.CANCEL | wx.CENTRE)
+
+ if ret != wx.CANCEL:
+ if ret == wx.YES:
+ self.SaveGCPs(None)
+ elif ret == wx.NO:
+ # restore POINTS file from backup
+ if os.path.exists(self.file['points_bak']):
+ shutil.copy(self.file['points_bak'], self.file['points'])
+
+ if os.path.exists(self.file['points_bak']):
+ os.unlink(self.file['points_bak'])
+
+ self.SrcMap.Clean()
+ self.TgtMap.Clean()
+
+ self.Destroy()
+
+ # event.Skip()
+
+ def OnGROrder(self, event):
+ """
+ sets transformation order for georectifying
+ """
+ if event:
+ self.gr_order = event.GetInt() + 1
+
+ numOfItems = self.list.GetItemCount()
+ minNumOfItems = numOfItems
+
+ if self.gr_order == 1:
+ minNumOfItems = 3
+ # self.SetStatusText(_('Insufficient points, 3+ points needed for 1st order'))
+
+ elif self.gr_order == 2:
+ minNumOfItems = 6
+ diff = 6 - numOfItems
+ # self.SetStatusText(_('Insufficient points, 6+ points needed for 2nd order'))
+
+ elif self.gr_order == 3:
+ minNumOfItems = 10
+ # self.SetStatusText(_('Insufficient points, 10+ points needed for 3rd order'))
+
+ for i in range(minNumOfItems - numOfItems):
+ self.AddGCP(None)
+
+ return minNumOfItems
+
+ def RMSError(self, xygroup, order):
+ """
+ Uses m.transform to calculate forward and backward error for each used GCP
+ in POINTS file and insert error values into GCP list.
+ Calculates total forward and backward RMS error for all used points
+ """
+ # save GCPs to points file to make sure that all checked GCPs are used
+ self.SaveGCPs(None)
+ # self.SetStatusText('')
+
+ if self.CheckGCPcount(msg=True) == False:
+ return
+
+ # get list of forward and reverse rms error values for each point
+ self.grwiz.SwitchEnv('source')
+
+ ret = RunCommand('m.transform',
+ parent=self,
+ read=True,
+ group=xygroup,
+ order=order)
+
+ self.grwiz.SwitchEnv('target')
+
+ if ret:
+ errlist = ret.splitlines()
+ else:
+ GError(parent=self,
+ message=_('Could not calculate RMS Error.\n'
+ 'Possible error with m.transform.'))
+ return
+
+ # insert error values into GCP list for checked items
+ sdfactor = float(
+ UserSettings.Get(
+ group='gcpman',
+ key='rms',
+ subkey='sdfactor'))
+ GCPcount = 0
+ sumsq_fwd_err = 0.0
+ sumsq_bkw_err = 0.0
+ sum_fwd_err = 0.0
+ highest_fwd_err = 0.0
+ self.highest_key = 0
+ highest_idx = 0
+
+ for index in range(self.list.GetItemCount()):
+ key = self.list.GetItemData(index)
+ if self.list.IsChecked(index):
+ fwd_err, bkw_err = errlist[GCPcount].split()
+ self.list.SetStringItem(index, 5, fwd_err)
+ self.list.SetStringItem(index, 6, bkw_err)
+ self.mapcoordlist[key][5] = float(fwd_err)
+ self.mapcoordlist[key][6] = float(bkw_err)
+ self.list.SetItemTextColour(index, wx.BLACK)
+ if self.highest_only:
+ if highest_fwd_err < float(fwd_err):
+ highest_fwd_err = float(fwd_err)
+ self.highest_key = key
+ highest_idx = index
+
+ sumsq_fwd_err += float(fwd_err)**2
+ sumsq_bkw_err += float(bkw_err)**2
+ sum_fwd_err += float(fwd_err)
+ GCPcount += 1
+ else:
+ self.list.SetStringItem(index, 5, '')
+ self.list.SetStringItem(index, 6, '')
+ self.mapcoordlist[key][5] = 0.0
+ self.mapcoordlist[key][6] = 0.0
+ self.list.SetItemTextColour(index, wx.BLACK)
+
+ # SD
+ if GCPcount > 0:
+ self.rmsmean = sum_fwd_err / GCPcount
+ self.rmssd = ((sumsq_fwd_err - self.rmsmean**2)**0.5)
+ self.rmsthresh = self.rmsmean + sdfactor * self.rmssd
+ else:
+ self.rmsthresh = 0
+ self.rmsmean = 0
+ self.rmssd = 0
+
+ if self.highest_only and highest_fwd_err > 0.0:
+ self.list.SetItemTextColour(highest_idx, wx.RED)
+ elif GCPcount > 0 and self.rmsthresh > 0 and not self.highest_only:
+ for index in range(self.list.GetItemCount()):
+ if self.list.IsChecked(index):
+ key = self.list.GetItemData(index)
+ if (self.mapcoordlist[key][5] > self.rmsthresh):
+ self.list.SetItemTextColour(index, wx.RED)
+
+ # calculate global RMS error (geometric mean)
+ self.fwd_rmserror = round((sumsq_fwd_err / GCPcount)**0.5, 4)
+ self.bkw_rmserror = round((sumsq_bkw_err / GCPcount)**0.5, 4)
+ self.list.ResizeColumns()
+
+ def GetNewExtent(self, region, map=None):
+
+ coord_file = utils.GetTempfile()
+ newreg = {'n': 0.0, 's': 0.0, 'e': 0.0, 'w': 0.0, }
+
+ try:
+ f = open(coord_file, mode='w')
+ # NW corner
+ f.write(str(region['e']) + " " + str(region['n']) + "\n")
+ # NE corner
+ f.write(str(region['e']) + " " + str(region['s']) + "\n")
+ # SW corner
+ f.write(str(region['w']) + " " + str(region['n']) + "\n")
+ # SE corner
+ f.write(str(region['w']) + " " + str(region['s']) + "\n")
+ finally:
+ f.close()
+
+ # save GCPs to points file to make sure that all checked GCPs are used
+ self.SaveGCPs(None)
+
+ order = self.gr_order
+ self.gr_order = 1
+
+ if self.CheckGCPcount(msg=True) == False:
+ self.gr_order = order
+ return
+
+ self.gr_order = order
+
+ # get list of forward and reverse rms error values for each point
+ self.grwiz.SwitchEnv('source')
+
+ if map == 'source':
+ ret = RunCommand('m.transform',
+ parent=self,
+ read=True,
+ group=self.xygroup,
+ order=1,
+ format='dst',
+ coords=coord_file)
+
+ elif map == 'target':
+ ret = RunCommand('m.transform',
+ parent=self,
+ read=True,
+ group=self.xygroup,
+ order=1,
+ flags='r',
+ format='src',
+ coords=coord_file)
+
+ os.unlink(coord_file)
+
+ self.grwiz.SwitchEnv('target')
+
+ if ret:
+ errlist = ret.splitlines()
+ else:
+ GError(parent=self,
+ message=_('Could not calculate new extends.\n'
+ 'Possible error with m.transform.'))
+ return
+
+ # fist corner
+ e, n = errlist[0].split()
+ fe = float(e)
+ fn = float(n)
+ newreg['n'] = fn
+ newreg['s'] = fn
+ newreg['e'] = fe
+ newreg['w'] = fe
+ # other three corners
+ for i in range(1, 4):
+ e, n = errlist[i].split()
+ fe = float(e)
+ fn = float(n)
+ if fe < newreg['w']:
+ newreg['w'] = fe
+ if fe > newreg['e']:
+ newreg['e'] = fe
+ if fn < newreg['s']:
+ newreg['s'] = fn
+ if fn > newreg['n']:
+ newreg['n'] = fn
+
+ return newreg
+
+ def OnHelp(self, event):
+ """Show GCP Manager manual page"""
+ self._giface.Help(entry='wxGUI.gcp')
+
+ def OnUpdateActive(self, event):
+
+ if self.activemap.GetSelection() == 0:
+ self.MapWindow = self.SrcMapWindow
+ self.Map = self.SrcMap
+ else:
+ self.MapWindow = self.TgtMapWindow
+ self.Map = self.TgtMap
+
+ self.UpdateActive(self.MapWindow)
+ # for wingrass
+ if os.name == 'nt':
+ self.MapWindow.SetFocus()
+
+ def UpdateActive(self, win):
+
+ # optionally disable tool zoomback tool
+ self.GetMapToolbar().Enable('zoomback',
+ enable=(len(self.MapWindow.zoomhistory) > 1))
+
+ if self.activemap.GetSelection() != (win == self.TgtMapWindow):
+ self.activemap.SetSelection(win == self.TgtMapWindow)
+ self.StatusbarUpdate()
+
+ def AdjustMap(self, newreg):
+ """Adjust map window to new extents
+ """
+
+ # adjust map window
+ self.Map.region['n'] = newreg['n']
+ self.Map.region['s'] = newreg['s']
+ self.Map.region['e'] = newreg['e']
+ self.Map.region['w'] = newreg['w']
+
+ self.MapWindow.ZoomHistory(self.Map.region['n'], self.Map.region['s'],
+ self.Map.region['e'], self.Map.region['w'])
+
+ # LL locations
+ if self.Map.projinfo['proj'] == 'll':
+ if newreg['n'] > 90.0:
+ newreg['n'] = 90.0
+ if newreg['s'] < -90.0:
+ newreg['s'] = -90.0
+
+ ce = newreg['w'] + (newreg['e'] - newreg['w']) / 2
+ cn = newreg['s'] + (newreg['n'] - newreg['s']) / 2
+
+ # calculate new center point and display resolution
+ self.Map.region['center_easting'] = ce
+ self.Map.region['center_northing'] = cn
+ self.Map.region["ewres"] = (newreg['e'] - newreg['w']) / self.Map.width
+ self.Map.region["nsres"] = (
+ newreg['n'] - newreg['s']) / self.Map.height
+ self.Map.AlignExtentFromDisplay()
+
+ self.MapWindow.ZoomHistory(self.Map.region['n'], self.Map.region['s'],
+ self.Map.region['e'], self.Map.region['w'])
+
+ if self.MapWindow.redrawAll is False:
+ self.MapWindow.redrawAll = True
+
+ self.MapWindow.UpdateMap()
+ self.StatusbarUpdate()
+
+ def OnZoomToSource(self, event):
+ """Set target map window to match extents of source map window
+ """
+
+ if not self.MapWindow == self.TgtMapWindow:
+ self.MapWindow = self.TgtMapWindow
+ self.Map = self.TgtMap
+ self.UpdateActive(self.TgtMapWindow)
+
+ # get new N, S, E, W for target
+ newreg = self.GetNewExtent(self.SrcMap.region, 'source')
+ if newreg:
+ self.AdjustMap(newreg)
+
+ def OnZoomToTarget(self, event):
+ """Set source map window to match extents of target map window
+ """
+
+ if not self.MapWindow == self.SrcMapWindow:
+ self.MapWindow = self.SrcMapWindow
+ self.Map = self.SrcMap
+ self.UpdateActive(self.SrcMapWindow)
+
+ # get new N, S, E, W for target
+ newreg = self.GetNewExtent(self.TgtMap.region, 'target')
+ if newreg:
+ self.AdjustMap(newreg)
+
+ def OnZoomMenuGCP(self, event):
+ """Popup Zoom menu
+ """
+ point = wx.GetMousePosition()
+ zoommenu = wx.Menu()
+ # Add items to the menu
+
+ zoomsource = wx.MenuItem(zoommenu, wx.ID_ANY, _(
+ 'Adjust source display to target display'))
+ zoommenu.AppendItem(zoomsource)
+ self.Bind(wx.EVT_MENU, self.OnZoomToTarget, zoomsource)
+
+ zoomtarget = wx.MenuItem(zoommenu, wx.ID_ANY, _(
+ 'Adjust target display to source display'))
+ zoommenu.AppendItem(zoomtarget)
+ self.Bind(wx.EVT_MENU, self.OnZoomToSource, zoomtarget)
+
+ # Popup the menu. If an item is selected then its handler
+ # will be called before PopupMenu returns.
+ self.PopupMenu(zoommenu)
+ zoommenu.Destroy()
+
+ def OnSize(self, event):
+ """Adjust Map Windows after GCP Map Display has been resized
+ """
+ # re-render image on idle
+ self.resize = time.clock()
+ super(MapFrame, self).OnSize(event)
+
+ def OnIdle(self, event):
+ """GCP Map Display resized, adjust Map Windows
+ """
+ if self.GetMapToolbar():
+ if self.resize and self.resize + 0.2 < time.clock():
+ srcwidth, srcheight = self.SrcMapWindow.GetSize()
+ tgtwidth, tgtheight = self.TgtMapWindow.GetSize()
+ srcwidth = (srcwidth + tgtwidth) / 2
+ if self.show_target:
+ self._mgr.GetPane("target").Hide()
+ self._mgr.Update()
+ self._mgr.GetPane("source").BestSize((srcwidth, srcheight))
+ self._mgr.GetPane("target").BestSize((srcwidth, tgtheight))
+ if self.show_target:
+ self._mgr.GetPane("target").Show()
+ self._mgr.Update()
+ self.resize = False
+ elif self.resize:
+ event.RequestMore()
+ pass
+
+
+class GCPList(wx.ListCtrl,
+ CheckListCtrlMixin,
+ ListCtrlAutoWidthMixin):
+
+ def __init__(self, parent, gcp, id=wx.ID_ANY,
+ pos=wx.DefaultPosition, size=wx.DefaultSize,
+ style=wx.LC_REPORT | wx.SUNKEN_BORDER | wx.LC_HRULES |
+ wx.LC_SINGLE_SEL):
+
+ wx.ListCtrl.__init__(self, parent, id, pos, size, style)
+
+ self.gcp = gcp # GCP class
+ self.render = True
+
+ # Mixin settings
+ CheckListCtrlMixin.__init__(self)
+ ListCtrlAutoWidthMixin.__init__(self)
+ # TextEditMixin.__init__(self)
+
+ # tracks whether list items are checked or not
+ self.CheckList = []
+
+ self._Create()
+
+ self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected)
+ self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.OnItemActivated)
+ self.Bind(wx.EVT_LIST_COL_CLICK, self.OnColClick)
+
+ self.selected = wx.NOT_FOUND
+ self.selectedkey = -1
+
+ def _Create(self):
+
+ if 0:
+ # normal, simple columns
+ idx_col = 0
+ for col in (_('use'),
+ _('source X'),
+ _('source Y'),
+ _('target X'),
+ _('target Y'),
+ _('Forward error'),
+ _('Backward error')):
+ self.InsertColumn(idx_col, col)
+ idx_col += 1
+ else:
+ # the hard way: we want images on the column header
+ info = wx.ListItem()
+ info.SetMask(
+ wx.LIST_MASK_TEXT | wx.LIST_MASK_IMAGE | wx.LIST_MASK_FORMAT)
+ info.SetImage(-1)
+ info.m_format = wx.LIST_FORMAT_LEFT
+
+ idx_col = 0
+ for lbl in (_('use'),
+ _('source X'),
+ _('source Y'),
+ _('target X'),
+ _('target Y'),
+ _('Forward error'),
+ _('Backward error')):
+ info.SetText(lbl)
+ self.InsertColumnInfo(idx_col, info)
+ idx_col += 1
+
+ def LoadData(self):
+ """Load data into list"""
+ self.DeleteAllItems()
+
+ self.render = False
+ if os.path.isfile(self.gcp.file['points']):
+ self.gcp.ReadGCPs()
+ else:
+ # 3 gcp is minimum
+ for i in range(3):
+ self.gcp.AddGCP(None)
+
+ # select first point by default
+ self.selected = 0
+ self.selectedkey = self.GetItemData(self.selected)
+ self.SetItemState(self.selected,
+ wx.LIST_STATE_SELECTED,
+ wx.LIST_STATE_SELECTED)
+
+ self.ResizeColumns()
+ self.render = True
+
+ self.EnsureVisible(self.selected)
+
+ def OnCheckItem(self, index, flag):
+ """Item is checked/unchecked"""
+
+ if self.render:
+ # redraw points
+ sourceMapWin = self.gcp.SrcMapWindow
+ sourceMapWin.UpdateMap(render=False)
+ if self.gcp.show_target:
+ targetMapWin = self.gcp.TgtMapWindow
+ targetMapWin.UpdateMap(render=False)
+
+ def AddGCPItem(self):
+ """
+ Appends an item to GCP list
+ """
+ self.selectedkey = self.GetItemCount() + 1
+
+ self.Append([str(self.selectedkey), # GCP number
+ '0.0', # source E
+ '0.0', # source N
+ '0.0', # target E
+ '0.0', # target N
+ '', # forward error
+ '']) # backward error
+
+ self.selected = self.GetItemCount() - 1
+ self.SetItemData(self.selected, self.selectedkey)
+
+ self.SetItemState(self.selected,
+ wx.LIST_STATE_SELECTED,
+ wx.LIST_STATE_SELECTED)
+
+ self.ResizeColumns()
+
+ self.gcp.pointsToDrawSrc.AddItem(
+ coords=[0, 0], label=str(self.selectedkey))
+ self.gcp.pointsToDrawTgt.AddItem(
+ coords=[0, 0], label=str(self.selectedkey))
+
+ self.EnsureVisible(self.selected)
+
+ return self.selected
+
+ def DeleteGCPItem(self):
+ """Deletes selected item in GCP list.
+ """
+ if self.selected == wx.NOT_FOUND:
+ return
+
+ key = self.GetItemData(self.selected)
+ self.DeleteItem(self.selected)
+
+ if self.selected != wx.NOT_FOUND:
+ item = self.gcp.pointsToDrawSrc.GetItem(key - 1)
+ self.gcp.pointsToDrawSrc.DeleteItem(item)
+
+ item = self.gcp.pointsToDrawTgt.GetItem(key - 1)
+ self.gcp.pointsToDrawTgt.DeleteItem(item)
+
+ return key
+
+ def ResizeColumns(self):
+ """Resize columns"""
+ minWidth = [90, 120]
+ for i in range(self.GetColumnCount()):
+ self.SetColumnWidth(i, wx.LIST_AUTOSIZE)
+ # first column is checkbox, don't set to minWidth
+ if i > 0 and self.GetColumnWidth(i) < minWidth[i > 4]:
+ self.SetColumnWidth(i, minWidth[i > 4])
+
+ self.SendSizeEvent()
+
+ def GetSelected(self):
+ """Get index of selected item"""
+ return self.selected
+
+ def OnItemSelected(self, event):
+ """Item selected
+ """
+ if self.render and self.selected != event.GetIndex():
+ self.selected = event.GetIndex()
+ self.selectedkey = self.GetItemData(self.selected)
+ sourceMapWin = self.gcp.SrcMapWindow
+ sourceMapWin.UpdateMap(render=False)
+ if self.gcp.show_target:
+ targetMapWin = self.gcp.TgtMapWindow
+ targetMapWin.UpdateMap(render=False)
+ event.Skip()
+
+ def OnItemActivated(self, event):
+ """
+ When item double clicked, open editor to update coordinate values
+ """
+ coords = []
+ index = event.GetIndex()
+ key = self.GetItemData(index)
+ changed = False
+
+ for i in range(1, 5):
+ coords.append(self.GetItem(index, i).GetText())
+
+ dlg = EditGCP(parent=self, id=wx.ID_ANY, data=coords, gcpno=key)
+
+ if dlg.ShowModal() == wx.ID_OK:
+ values = dlg.GetValues() # string
+
+ if len(values) == 0:
+ GError(parent=self, message=_(
+ "Invalid coordinate value. Operation canceled."))
+ else:
+ for i in range(len(values)):
+ if values[i] != coords[i]:
+ self.SetStringItem(index, i + 1, values[i])
+ changed = True
+
+ if changed:
+ # reset RMS and update mapcoordlist
+ self.SetStringItem(index, 5, '')
+ self.SetStringItem(index, 6, '')
+ key = self.GetItemData(index)
+ self.gcp.mapcoordlist[key] = [key,
+ float(values[0]),
+ float(values[1]),
+ float(values[2]),
+ float(values[3]),
+ 0.0,
+ 0.0]
+
+ self.gcp.pointsToDrawSrc.GetItem(
+ key - 1).SetCoords([float(values[0]), float(values[1])])
+ self.gcp.pointsToDrawTgt.GetItem(
+ key - 1).SetCoords([float(values[2]), float(values[3])])
+ self.gcp.UpdateColours()
+
+ def OnColClick(self, event):
+ """ListCtrl forgets selected item..."""
+ self.selected = self.FindItemData(-1, self.selectedkey)
+ self.SetItemState(self.selected,
+ wx.LIST_STATE_SELECTED,
+ wx.LIST_STATE_SELECTED)
+
+ event.Skip()
+
+class EditGCP(wx.Dialog):
+
+ def __init__(self, parent, data, gcpno, id=wx.ID_ANY,
+ title=_("Edit GCP"),
+ style=wx.DEFAULT_DIALOG_STYLE):
+ """Dialog for editing GPC and map coordinates in list control"""
+
+ wx.Dialog.__init__(self, parent, id, title=title, style=style)
+
+ panel = wx.Panel(parent=self)
+
+ sizer = wx.BoxSizer(wx.VERTICAL)
+
+ box = wx.StaticBox(
+ parent=panel, id=wx.ID_ANY, label=" %s %s " %
+ (_("Ground Control Point No."), str(gcpno)))
+ boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+
+ # source coordinates
+ gridSizer = wx.GridBagSizer(vgap=5, hgap=5)
+
+ self.xcoord = wx.TextCtrl(parent=panel, id=wx.ID_ANY, size=(150, -1))
+ self.ycoord = wx.TextCtrl(parent=panel, id=wx.ID_ANY, size=(150, -1))
+ self.ecoord = wx.TextCtrl(parent=panel, id=wx.ID_ANY, size=(150, -1))
+ self.ncoord = wx.TextCtrl(parent=panel, id=wx.ID_ANY, size=(150, -1))
+
+ # swap source N, target E
+ tmp_coord = data[1]
+ data[1] = data[2]
+ data[2] = tmp_coord
+
+ row = 0
+ col = 0
+ idx = 0
+ for label, win in ((_("source X:"), self.xcoord),
+ (_("target X:"), self.ecoord),
+ (_("source Y:"), self.ycoord),
+ (_("target Y:"), self.ncoord)):
+ label = wx.StaticText(parent=panel, id=wx.ID_ANY,
+ label=label)
+ gridSizer.Add(label,
+ flag=wx.ALIGN_CENTER_VERTICAL,
+ pos=(row, col))
+
+ col += 1
+ win.SetValue(str(data[idx]))
+
+ gridSizer.Add(win,
+ pos=(row, col))
+
+ col += 1
+ idx += 1
+
+ if col > 3:
+ row += 1
+ col = 0
+
+ boxSizer.Add(gridSizer, proportion=1,
+ flag=wx.EXPAND | wx.ALL, border=5)
+
+ sizer.Add(boxSizer, proportion=1,
+ flag=wx.EXPAND | wx.ALL, border=5)
+
+ #
+ # buttons
+ #
+ self.btnCancel = wx.Button(panel, wx.ID_CANCEL)
+ self.btnOk = wx.Button(panel, wx.ID_OK)
+ self.btnOk.SetDefault()
+
+ btnSizer = wx.StdDialogButtonSizer()
+ btnSizer.AddButton(self.btnCancel)
+ btnSizer.AddButton(self.btnOk)
+ btnSizer.Realize()
+
+ sizer.Add(btnSizer, proportion=0,
+ flag=wx.ALIGN_RIGHT | wx.ALL, border=5)
+
+ panel.SetSizer(sizer)
+ sizer.Fit(self)
+
+ def GetValues(self, columns=None):
+ """Return list of values (as strings).
+ """
+ valuelist = []
+ try:
+ float(self.xcoord.GetValue())
+ float(self.ycoord.GetValue())
+ float(self.ecoord.GetValue())
+ float(self.ncoord.GetValue())
+ except ValueError:
+ return valuelist
+
+ valuelist.append(self.xcoord.GetValue())
+ valuelist.append(self.ycoord.GetValue())
+ valuelist.append(self.ecoord.GetValue())
+ valuelist.append(self.ncoord.GetValue())
+
+ return valuelist
+
+
+class GrSettingsDialog(wx.Dialog):
+
+ def __init__(
+ self, parent, id, giface, title, pos=wx.DefaultPosition,
+ size=wx.DefaultSize, style=wx.DEFAULT_DIALOG_STYLE):
+ wx.Dialog.__init__(self, parent, id, title, pos, size, style)
+ """
+ Dialog to set profile text options: font, title
+ and font size, axis labels and font size
+ """
+ #
+ # initialize variables
+ #
+ self.parent = parent
+ self.new_src_map = src_map
+ self.new_tgt_map = {'raster': tgt_map['raster']}
+ self.sdfactor = 0
+
+ self.symbol = {}
+
+ self.methods = ["nearest",
+ "linear",
+ "linear_f",
+ "cubic",
+ "cubic_f",
+ "lanczos",
+ "lanczos_f"]
+
+ # notebook
+ notebook = wx.Notebook(parent=self, id=wx.ID_ANY, style=wx.BK_DEFAULT)
+ self.__CreateSymbologyPage(notebook)
+ self.__CreateRectificationPage(notebook)
+
+ # buttons
+ btnSave = wx.Button(self, wx.ID_SAVE)
+ btnApply = wx.Button(self, wx.ID_APPLY)
+ btnClose = wx.Button(self, wx.ID_CLOSE)
+ btnApply.SetDefault()
+
+ # bindings
+ btnApply.Bind(wx.EVT_BUTTON, self.OnApply)
+ btnApply.SetToolTipString(_("Apply changes for the current session"))
+ btnSave.Bind(wx.EVT_BUTTON, self.OnSave)
+ btnSave.SetToolTipString(
+ _("Apply and save changes to user settings file (default for next sessions)"))
+ btnClose.Bind(wx.EVT_BUTTON, self.OnClose)
+ btnClose.SetToolTipString(_("Close dialog"))
+
+ # sizers
+ btnSizer = wx.BoxSizer(wx.HORIZONTAL)
+ btnSizer.Add(btnApply, flag=wx.LEFT | wx.RIGHT, border=5)
+ btnSizer.Add(btnSave, flag=wx.LEFT | wx.RIGHT, border=5)
+ btnSizer.Add(btnClose, flag=wx.LEFT | wx.RIGHT, border=5)
+
+ # sizers
+ mainSizer = wx.BoxSizer(wx.VERTICAL)
+ mainSizer.Add(
+ notebook,
+ proportion=1,
+ flag=wx.EXPAND | wx.ALL,
+ border=5)
+ mainSizer.Add(btnSizer, proportion=0,
+ flag=wx.ALIGN_RIGHT | wx.ALL, border=5)
+ # flag=wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border=5)
+
+ self.SetSizer(mainSizer)
+ mainSizer.Fit(self)
+
+ def __CreateSymbologyPage(self, notebook):
+ """Create notebook page with symbology settings"""
+
+ panel = wx.Panel(parent=notebook, id=wx.ID_ANY)
+ notebook.AddPage(page=panel, text=_("Symbology"))
+
+ sizer = wx.BoxSizer(wx.VERTICAL)
+
+ rmsgridSizer = wx.GridBagSizer(vgap=5, hgap=5)
+
+ # highlight only highest forward RMS error
+ self.highlighthighest = wx.CheckBox(
+ parent=panel, id=wx.ID_ANY,
+ label=_("Highlight highest RMS error only"))
+ hh = UserSettings.Get(group='gcpman', key='rms', subkey='highestonly')
+ self.highlighthighest.SetValue(hh)
+ rmsgridSizer.Add(
+ self.highlighthighest,
+ flag=wx.ALIGN_CENTER_VERTICAL,
+ pos=(
+ 0,
+ 0))
+
+ # RMS forward error threshold
+ rmslabel = wx.StaticText(
+ parent=panel, id=wx.ID_ANY,
+ label=_("Highlight RMS error > M + SD * factor:"))
+ rmslabel.SetToolTip(
+ wx.ToolTip(
+ _(
+ "Highlight GCPs with an RMS error larger than \n"
+ "mean + standard deviation * given factor. \n"
+ "Recommended values for this factor are between 1 and 2.")))
+ rmsgridSizer.Add(
+ rmslabel,
+ flag=wx.ALIGN_CENTER_VERTICAL,
+ pos=(
+ 1,
+ 0))
+ sdfactor = UserSettings.Get(
+ group='gcpman', key='rms', subkey='sdfactor')
+ self.rmsWin = wx.TextCtrl(parent=panel, id=wx.ID_ANY,
+ size=(70, -1), style=wx.TE_NOHIDESEL)
+ self.rmsWin.SetValue("%s" % str(sdfactor))
+ if (self.parent.highest_only == True):
+ self.rmsWin.Disable()
+
+ self.symbol['sdfactor'] = self.rmsWin.GetId()
+ rmsgridSizer.Add(self.rmsWin, flag=wx.ALIGN_RIGHT, pos=(1, 1))
+ rmsgridSizer.AddGrowableCol(1)
+ sizer.Add(rmsgridSizer, flag=wx.EXPAND | wx.ALL, border=5)
+
+ box = wx.StaticBox(parent=panel, id=wx.ID_ANY,
+ label=" %s " % _("Symbol settings"))
+ boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+ gridSizer = wx.GridBagSizer(vgap=5, hgap=5)
+
+ #
+ # general symbol color
+ #
+ row = 0
+ label = wx.StaticText(parent=panel, id=wx.ID_ANY, label=_("Color:"))
+ gridSizer.Add(label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
+ col = UserSettings.Get(group='gcpman', key='symbol', subkey='color')
+ colWin = csel.ColourSelect(parent=panel, id=wx.ID_ANY,
+ colour=wx.Colour(col[0],
+ col[1],
+ col[2],
+ 255))
+ self.symbol['color'] = colWin.GetId()
+ gridSizer.Add(colWin,
+ flag=wx.ALIGN_RIGHT,
+ pos=(row, 1))
+
+ #
+ # symbol color for high forward RMS error
+ #
+ row += 1
+ label = wx.StaticText(
+ parent=panel,
+ id=wx.ID_ANY,
+ label=_("Color for high RMS error:"))
+ gridSizer.Add(label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
+ hcol = UserSettings.Get(group='gcpman', key='symbol', subkey='hcolor')
+ hcolWin = csel.ColourSelect(parent=panel, id=wx.ID_ANY,
+ colour=wx.Colour(hcol[0],
+ hcol[1],
+ hcol[2],
+ 255))
+ self.symbol['hcolor'] = hcolWin.GetId()
+ gridSizer.Add(hcolWin,
+ flag=wx.ALIGN_RIGHT,
+ pos=(row, 1))
+
+ #
+ # symbol color for selected GCP
+ #
+ row += 1
+ label = wx.StaticText(
+ parent=panel,
+ id=wx.ID_ANY,
+ label=_("Color for selected GCP:"))
+ gridSizer.Add(label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
+ scol = UserSettings.Get(group='gcpman', key='symbol', subkey='scolor')
+ scolWin = csel.ColourSelect(parent=panel, id=wx.ID_ANY,
+ colour=wx.Colour(scol[0],
+ scol[1],
+ scol[2],
+ 255))
+ self.symbol['scolor'] = scolWin.GetId()
+ gridSizer.Add(scolWin,
+ flag=wx.ALIGN_RIGHT,
+ pos=(row, 1))
+
+ #
+ # symbol color for unused GCP
+ #
+ row += 1
+ label = wx.StaticText(
+ parent=panel,
+ id=wx.ID_ANY,
+ label=_("Color for unused GCPs:"))
+ gridSizer.Add(label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
+ ucol = UserSettings.Get(group='gcpman', key='symbol', subkey='ucolor')
+ ucolWin = csel.ColourSelect(parent=panel, id=wx.ID_ANY,
+ colour=wx.Colour(ucol[0],
+ ucol[1],
+ ucol[2],
+ 255))
+ self.symbol['ucolor'] = ucolWin.GetId()
+ gridSizer.Add(ucolWin,
+ flag=wx.ALIGN_RIGHT,
+ pos=(row, 1))
+
+ # show unused GCPs
+ row += 1
+ self.showunused = wx.CheckBox(parent=panel, id=wx.ID_ANY,
+ label=_("Show unused GCPs"))
+ shuu = UserSettings.Get(group='gcpman', key='symbol', subkey='unused')
+ self.showunused.SetValue(shuu)
+ gridSizer.Add(
+ self.showunused,
+ flag=wx.ALIGN_CENTER_VERTICAL,
+ pos=(
+ row,
+ 0))
+
+ #
+ # symbol size
+ #
+ row += 1
+ label = wx.StaticText(
+ parent=panel,
+ id=wx.ID_ANY,
+ label=_("Symbol size:"))
+ gridSizer.Add(label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
+ symsize = int(
+ UserSettings.Get(
+ group='gcpman',
+ key='symbol',
+ subkey='size'))
+ sizeWin = SpinCtrl(parent=panel, id=wx.ID_ANY,
+ min=1, max=20)
+ sizeWin.SetValue(symsize)
+ self.symbol['size'] = sizeWin.GetId()
+ gridSizer.Add(sizeWin,
+ flag=wx.ALIGN_RIGHT,
+ pos=(row, 1))
+
+ #
+ # symbol width
+ #
+ row += 1
+ label = wx.StaticText(
+ parent=panel,
+ id=wx.ID_ANY,
+ label=_("Line width:"))
+ gridSizer.Add(label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
+ width = int(
+ UserSettings.Get(
+ group='gcpman',
+ key='symbol',
+ subkey='width'))
+ widWin = SpinCtrl(parent=panel, id=wx.ID_ANY,
+ min=1, max=10)
+ widWin.SetValue(width)
+ self.symbol['width'] = widWin.GetId()
+ gridSizer.Add(widWin,
+ flag=wx.ALIGN_RIGHT,
+ pos=(row, 1))
+ gridSizer.AddGrowableCol(1)
+
+ boxSizer.Add(gridSizer, flag=wx.EXPAND)
+ sizer.Add(boxSizer, flag=wx.EXPAND | wx.ALL, border=5)
+
+ #
+ # maps to display
+ #
+ # source map to display
+ self.srcselection = Select(
+ panel,
+ id=wx.ID_ANY,
+ size=globalvar.DIALOG_GSELECT_SIZE,
+ type='maptype',
+ updateOnPopup=False)
+ self.parent.grwiz.SwitchEnv('source')
+ self.srcselection.SetElementList(maptype)
+ # filter out all maps not in group
+ self.srcselection.tcp.GetElementList(elements=self.parent.src_maps)
+
+ # target map(s) to display
+ self.parent.grwiz.SwitchEnv('target')
+ self.tgtrastselection = Select(
+ panel, id=wx.ID_ANY, size=globalvar.DIALOG_GSELECT_SIZE,
+ type='raster', updateOnPopup=False)
+ self.tgtrastselection.SetElementList('cell')
+ self.tgtrastselection.GetElementList()
+
+ sizer.Add(
+ wx.StaticText(
+ parent=panel,
+ id=wx.ID_ANY,
+ label=_('Select source map to display:')),
+ proportion=0,
+ flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL,
+ border=5)
+ sizer.Add(
+ self.srcselection,
+ proportion=0,
+ flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL,
+ border=5)
+ self.srcselection.SetValue(src_map)
+ sizer.Add(
+ wx.StaticText(
+ parent=panel,
+ id=wx.ID_ANY,
+ label=_('Select target raster map to display:')),
+ proportion=0,
+ flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL,
+ border=5)
+ sizer.Add(
+ self.tgtrastselection,
+ proportion=0,
+ flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL,
+ border=5)
+ self.tgtrastselection.SetValue(tgt_map['raster'])
+
+ # bindings
+ self.highlighthighest.Bind(wx.EVT_CHECKBOX, self.OnHighlight)
+ self.rmsWin.Bind(wx.EVT_TEXT, self.OnSDFactor)
+ self.srcselection.Bind(wx.EVT_TEXT, self.OnSrcSelection)
+ self.tgtrastselection.Bind(wx.EVT_TEXT, self.OnTgtRastSelection)
+
+ panel.SetSizer(sizer)
+
+ return panel
+
+ def __CreateRectificationPage(self, notebook):
+ """Create notebook page with symbology settings"""
+
+ panel = wx.Panel(parent=notebook, id=wx.ID_ANY)
+ notebook.AddPage(page=panel, text=_("Rectification"))
+
+ sizer = wx.BoxSizer(wx.VERTICAL)
+
+ # transformation order
+ self.rb_grorder = wx.RadioBox(
+ parent=panel,
+ id=wx.ID_ANY,
+ label=" %s " %
+ _("Select rectification order"),
+ choices=[
+ _('1st order'),
+ _('2nd order'),
+ _('3rd order')],
+ majorDimension=wx.RA_SPECIFY_COLS)
+ sizer.Add(self.rb_grorder, proportion=0,
+ flag=wx.EXPAND | wx.ALL, border=5)
+ self.rb_grorder.SetSelection(self.parent.gr_order - 1)
+
+ # interpolation method
+ gridSizer = wx.GridBagSizer(vgap=5, hgap=5)
+ gridSizer.Add(
+ wx.StaticText(
+ parent=panel,
+ id=wx.ID_ANY,
+ label=_('Select interpolation method:')),
+ pos=(
+ 0,
+ 0),
+ flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL,
+ border=5)
+ self.grmethod = wx.Choice(parent=panel, id=wx.ID_ANY,
+ choices=self.methods)
+ gridSizer.Add(self.grmethod, pos=(0, 1),
+ flag=wx.ALIGN_RIGHT, border=5)
+ self.grmethod.SetStringSelection(self.parent.gr_method)
+ gridSizer.AddGrowableCol(1)
+ sizer.Add(gridSizer, flag=wx.EXPAND | wx.ALL, border=5)
+
+ # clip to region
+ self.check = wx.CheckBox(parent=panel, id=wx.ID_ANY, label=_(
+ "clip to computational region in target location"))
+ sizer.Add(self.check, proportion=0,
+ flag=wx.EXPAND | wx.ALL, border=5)
+ self.check.SetValue(self.parent.clip_to_region)
+
+ # extension
+ sizer.Add(
+ wx.StaticText(
+ parent=panel,
+ id=wx.ID_ANY,
+ label=_('Extension for output maps:')),
+ proportion=0,
+ flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL,
+ border=5)
+ self.ext_txt = wx.TextCtrl(
+ parent=panel, id=wx.ID_ANY, value="", size=(
+ 350, -1))
+ self.ext_txt.SetValue(self.parent.extension)
+ sizer.Add(
+ self.ext_txt,
+ proportion=0,
+ flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL,
+ border=5)
+
+ # bindings
+ self.ext_txt.Bind(wx.EVT_TEXT, self.OnExtension)
+ self.Bind(wx.EVT_RADIOBOX, self.parent.OnGROrder, self.rb_grorder)
+ self.Bind(wx.EVT_CHOICE, self.OnMethod, self.grmethod)
+ self.Bind(wx.EVT_CHECKBOX, self.OnClipRegion, self.check)
+
+ panel.SetSizer(sizer)
+
+ return panel
+
+ def OnHighlight(self, event):
+ """Checkbox 'highlighthighest' checked/unchecked"""
+ if self.highlighthighest.IsChecked():
+ self.parent.highest_only = True
+ self.rmsWin.Disable()
+ else:
+ self.parent.highest_only = False
+ self.rmsWin.Enable()
+
+ def OnSDFactor(self, event):
+ """New factor for RMS threshold = M + SD * factor"""
+ try:
+ self.sdfactor = float(self.rmsWin.GetValue())
+ except ValueError:
+ return
+ if self.sdfactor <= 0:
+ GError(parent=self,
+ message=_('RMS threshold factor must be > 0'))
+ elif self.sdfactor < 1:
+ GError(parent=self,
+ message=_('RMS threshold factor is < 1\n'
+ 'Too many points might be highlighted'))
+
+ def OnSrcSelection(self, event):
+ """Source map to display selected"""
+ global src_map
+
+ tmp_map = self.srcselection.GetValue()
+
+ if not tmp_map == '' and not tmp_map == src_map:
+ self.new_src_map = tmp_map
+
+ def OnTgtRastSelection(self, event):
+ """Target map to display selected"""
+ global tgt_map
+
+ self.new_tgt_map['raster'] = self.tgtrastselection.GetValue()
+
+ def OnMethod(self, event):
+ self.parent.gr_method = self.methods[event.GetSelection()]
+
+ def OnClipRegion(self, event):
+ self.parent.clip_to_region = event.IsChecked()
+
+ def OnExtension(self, event):
+ self.parent.extension = self.ext_txt.GetValue()
+
+ def UpdateSettings(self):
+ global src_map
+ global tgt_map
+ global maptype
+
+ layers = None
+
+ UserSettings.Set(group='gcpman', key='rms', subkey='highestonly',
+ value=self.highlighthighest.GetValue())
+
+ if self.sdfactor > 0:
+ UserSettings.Set(group='gcpman', key='rms', subkey='sdfactor',
+ value=self.sdfactor)
+
+ self.parent.sdfactor = self.sdfactor
+ if self.parent.rmsthresh > 0:
+ self.parent.rmsthresh = self.parent.rmsmean + self.parent.sdfactor * self.parent.rmssd
+
+ UserSettings.Set(
+ group='gcpman',
+ key='symbol',
+ subkey='color',
+ value=tuple(
+ wx.FindWindowById(
+ self.symbol['color']).GetColour()))
+ UserSettings.Set(
+ group='gcpman',
+ key='symbol',
+ subkey='hcolor',
+ value=tuple(
+ wx.FindWindowById(
+ self.symbol['hcolor']).GetColour()))
+ UserSettings.Set(
+ group='gcpman',
+ key='symbol',
+ subkey='scolor',
+ value=tuple(
+ wx.FindWindowById(
+ self.symbol['scolor']).GetColour()))
+ UserSettings.Set(
+ group='gcpman',
+ key='symbol',
+ subkey='ucolor',
+ value=tuple(
+ wx.FindWindowById(
+ self.symbol['ucolor']).GetColour()))
+ UserSettings.Set(group='gcpman', key='symbol', subkey='unused',
+ value=self.showunused.GetValue())
+ UserSettings.Set(
+ group='gcpman',
+ key='symbol',
+ subkey='size',
+ value=wx.FindWindowById(
+ self.symbol['size']).GetValue())
+ UserSettings.Set(
+ group='gcpman',
+ key='symbol',
+ subkey='width',
+ value=wx.FindWindowById(
+ self.symbol['width']).GetValue())
+
+ srcrender = False
+ tgtrender = False
+ reload_target = False
+ if self.new_src_map != src_map:
+ # remove old layer
+ layers = self.parent.grwiz.SrcMap.GetListOfLayers()
+ self.parent.grwiz.SrcMap.DeleteLayer(layers[0])
+
+ src_map = self.new_src_map
+ if maptype == 'raster':
+ cmdlist = ['d.rast', 'map=%s' % src_map]
+ srcrender = True
+ self.parent.grwiz.SwitchEnv('source')
+ name, found = utils.GetLayerNameFromCmd(cmdlist)
+ self.parent.grwiz.SrcMap.AddLayer(
+ ltype=maptype, command=cmdlist, active=True, name=name,
+ hidden=False, opacity=1.0, render=False)
+
+ self.parent.grwiz.SwitchEnv('target')
+
+ if self.new_tgt_map['raster'] != tgt_map['raster']:
+ # remove all layers
+ layers = self.parent.grwiz.TgtMap.GetListOfLayers()
+ while layers:
+ self.parent.grwiz.TgtMap.DeleteLayer(layers[0])
+ del layers[0]
+ layers = self.parent.grwiz.TgtMap.GetListOfLayers()
+ # self.parent.grwiz.TgtMap.DeleteAllLayers()
+ reload_target = True
+ tgt_map['raster'] = self.new_tgt_map['raster']
+
+ if tgt_map['raster'] != '':
+ cmdlist = ['d.rast', 'map=%s' % tgt_map['raster']]
+ name, found = utils.GetLayerNameFromCmd(cmdlist)
+ self.parent.grwiz.TgtMap.AddLayer(
+ ltype='raster', command=cmdlist, active=True, name=name,
+ hidden=False, opacity=1.0, render=False)
+
+ tgtrender = True
+
+ if tgt_map['raster'] == '':
+ if self.parent.show_target == True:
+ self.parent.show_target = False
+ self.parent._mgr.GetPane("target").Hide()
+ self.parent._mgr.Update()
+ self.parent.activemap.SetSelection(0)
+ self.parent.activemap.Enable(False)
+ self.parent.GetMapToolbar().Enable('zoommenu', enable=False)
+ else:
+ if self.parent.show_target == False:
+ self.parent.show_target = True
+ self.parent._mgr.GetPane("target").Show()
+ self.parent._mgr.Update()
+ self.parent.activemap.SetSelection(0)
+ self.parent.activemap.Enable(True)
+ self.parent.GetMapToolbar().Enable('zoommenu', enable=True)
+ self.parent.TgtMapWindow.ZoomToMap(
+ layers=self.parent.TgtMap.GetListOfLayers())
+
+ self.parent.UpdateColours(
+ srcrender,
+ tgtrender)
+ self.parent.SetSettings()
+
+ def OnSave(self, event):
+ """Button 'Save' pressed"""
+ self.UpdateSettings()
+ fileSettings = {}
+ UserSettings.ReadSettingsFile(settings=fileSettings)
+ fileSettings['gcpman'] = UserSettings.Get(group='gcpman')
+ file = UserSettings.SaveToFile(fileSettings)
+ self.parent._giface.WriteLog(
+ _('GCP Manager settings saved to file \'%s\'.') %
+ file)
+ # self.Close()
+
+ def OnApply(self, event):
+ """Button 'Apply' pressed"""
+ self.UpdateSettings()
+ # self.Close()
+
+ def OnClose(self, event):
+ """Button 'Cancel' pressed"""
+ self.Close()
Added: grass/trunk/gui/wxpython/iphoto2image/ip2i_mapdisplay.py
===================================================================
--- grass/trunk/gui/wxpython/iphoto2image/ip2i_mapdisplay.py (rev 0)
+++ grass/trunk/gui/wxpython/iphoto2image/ip2i_mapdisplay.py 2017-02-13 18:20:04 UTC (rev 70552)
@@ -0,0 +1,532 @@
+"""
+ at package iphoto2image.ip2i_mapdisplay
+
+ at brief Display to manage ground control points with two toolbars, one
+for various display management functions, one for manipulating GCPs.
+
+Classes:
+- mapdisplay::MapFrame
+
+(C) 2006-2011 by the GRASS Development Team
+
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
+
+ at author Markus Metz
+"""
+
+import os
+import math
+import platform
+
+from core import globalvar
+import wx
+import wx.aui
+
+from mapdisp.toolbars import MapToolbar
+from gcp.toolbars import GCPDisplayToolbar, GCPManToolbar
+from mapdisp.gprint import PrintOptions
+from core.gcmd import GMessage
+from core.utils import _
+from gui_core.dialogs import GetImageHandlers, ImageSizeDialog
+from gui_core.mapdisp import SingleMapFrame
+from core.settings import UserSettings
+from mapwin.buffered import BufferedMapWindow
+from mapwin.base import MapWindowProperties
+
+import mapdisp.statusbar as sb
+import gcp.statusbar as sbgcp
+
+# for standalone app
+cmdfilename = None
+
+
+class MapFrame(SingleMapFrame):
+ """Main frame for map display window. Drawing takes place in
+ child double buffered drawing window.
+ """
+
+ def __init__(self, parent, giface,
+ title=_("GRASS GIS Manage Location of Tick Points on a Scanned Photo"),
+ toolbars=["gcpdisp"], Map=None, auimgr=None,
+ name='GCPMapWindow', **kwargs):
+ """Main map display window with toolbars, statusbar and
+ DrawWindow
+
+ :param giface: GRASS interface instance
+ :param title: window title
+ :param toolbars: array of activated toolbars, e.g. ['map', 'digit']
+ :param map: instance of render.Map
+ :param auimgs: AUI manager
+ :param kwargs: wx.Frame attribures
+ """
+
+ SingleMapFrame.__init__(
+ self,
+ parent=parent,
+ giface=giface,
+ title=title,
+ Map=Map,
+ auimgr=auimgr,
+ name=name,
+ **kwargs)
+
+ self._giface = giface
+ # properties are shared in other objects, so defining here
+ self.mapWindowProperties = MapWindowProperties()
+ self.mapWindowProperties.setValuesFromUserSettings()
+ self.mapWindowProperties.alignExtent = True
+
+ #
+ # Add toolbars
+ #
+ for toolb in toolbars:
+ self.AddToolbar(toolb)
+
+ self.activemap = self.toolbars['gcpdisp'].togglemap
+ self.activemap.SetSelection(0)
+
+ self.SrcMap = self.grwiz.SrcMap # instance of render.Map
+ self.TgtMap = self.grwiz.TgtMap # instance of render.Map
+ self._mgr.SetDockSizeConstraint(0.5, 0.5)
+
+ #
+ # Add statusbar
+ #
+
+ # items for choice
+ self.statusbarItems = [sb.SbCoordinates,
+ sb.SbRegionExtent,
+ sb.SbCompRegionExtent,
+ sb.SbShowRegion,
+ sb.SbResolution,
+ sb.SbDisplayGeometry,
+ sb.SbMapScale,
+ sb.SbProjection,
+ sbgcp.SbGoToGCP,
+ sbgcp.SbRMSError]
+
+ # create statusbar and its manager
+ statusbar = self.CreateStatusBar(number=4, style=0)
+ statusbar.SetStatusWidths([-5, -2, -1, -1])
+ self.statusbarManager = sb.SbManager(
+ mapframe=self, statusbar=statusbar)
+
+ # fill statusbar manager
+ self.statusbarManager.AddStatusbarItemsByClass(
+ self.statusbarItems, mapframe=self, statusbar=statusbar)
+ self.statusbarManager.AddStatusbarItem(
+ sb.SbMask(self, statusbar=statusbar, position=2))
+ self.statusbarManager.AddStatusbarItem(
+ sb.SbRender(self, statusbar=statusbar, position=3))
+
+ self.statusbarManager.SetMode(8) # goto GCP
+
+ #
+ # Init map display (buffered DC & set default cursor)
+ #
+ self.grwiz.SwitchEnv('source')
+ self.SrcMapWindow = BufferedMapWindow(
+ parent=self, giface=self._giface, id=wx.ID_ANY,
+ properties=self.mapWindowProperties, Map=self.SrcMap)
+
+ self.grwiz.SwitchEnv('target')
+ self.TgtMapWindow = BufferedMapWindow(
+ parent=self, giface=self._giface, id=wx.ID_ANY,
+ properties=self.mapWindowProperties, Map=self.TgtMap)
+ self.MapWindow = self.SrcMapWindow
+ self.Map = self.SrcMap
+ self._setUpMapWindow(self.SrcMapWindow)
+ self._setUpMapWindow(self.TgtMapWindow)
+ self.SrcMapWindow.SetNamedCursor('cross')
+ self.TgtMapWindow.SetNamedCursor('cross')
+ # used to switch current map (combo box in toolbar)
+ self.SrcMapWindow.mouseEntered.connect(
+ lambda:
+ self._setActiveMapWindow(self.SrcMapWindow))
+ self.TgtMapWindow.mouseEntered.connect(
+ lambda:
+ self._setActiveMapWindow(self.TgtMapWindow))
+
+ #
+ # initialize region values
+ #
+ self._initMap(Map=self.SrcMap)
+ self._initMap(Map=self.TgtMap)
+
+ self.GetMapToolbar().SelectDefault()
+
+ #
+ # Bind various events
+ #
+ self.activemap.Bind(wx.EVT_CHOICE, self.OnUpdateActive)
+ self.Bind(wx.EVT_SIZE, self.OnSize)
+
+ #
+ # Update fancy gui style
+ #
+ # AuiManager wants a CentrePane, workaround to get two equally sized
+ # windows
+ self.list = self.CreateGCPList()
+
+ #self.SrcMapWindow.SetSize((300, 300))
+ #self.TgtMapWindow.SetSize((300, 300))
+ self.list.SetSize((100, 150))
+ self._mgr.AddPane(self.list, wx.aui.AuiPaneInfo().
+ Name("gcplist").Caption(_("GCP List")).LeftDockable(False).
+ RightDockable(False).PinButton().FloatingSize((600, 200)).
+ CloseButton(False).DestroyOnClose(True).
+ Top().Layer(1).MinSize((200, 100)))
+ self._mgr.AddPane(self.SrcMapWindow, wx.aui.AuiPaneInfo().
+ Name("source").Caption(_("Source Display")).Dockable(False).
+ CloseButton(False).DestroyOnClose(True).Floatable(False).
+ Centre())
+ self._mgr.AddPane(self.TgtMapWindow, wx.aui.AuiPaneInfo().
+ Name("target").Caption(_("Target Display")).Dockable(False).
+ CloseButton(False).DestroyOnClose(True).Floatable(False).
+ Right().Layer(0))
+
+ srcwidth, srcheight = self.SrcMapWindow.GetSize()
+ tgtwidth, tgtheight = self.TgtMapWindow.GetSize()
+ srcwidth = (srcwidth + tgtwidth) / 2
+ self._mgr.GetPane("target").Hide()
+ self._mgr.Update()
+ self._mgr.GetPane("source").BestSize((srcwidth, srcheight))
+ self._mgr.GetPane("target").BestSize((srcwidth, srcheight))
+ if self.show_target:
+ self._mgr.GetPane("target").Show()
+ else:
+ self.activemap.Enable(False)
+ # needed by Mac OS, does not harm on Linux, breaks display on Windows
+ if platform.system() != 'Windows':
+ self._mgr.Update()
+
+ #
+ # Init print module and classes
+ #
+ self.printopt = PrintOptions(self, self.MapWindow)
+
+ #
+ # Initialization of digitization tool
+ #
+ self.digit = None
+
+ # set active map
+ self.MapWindow = self.SrcMapWindow
+ self.Map = self.SrcMap
+
+ # do not init zoom history here, that happens when zooming to map(s)
+
+ #
+ # Re-use dialogs
+ #
+ self.dialogs = {}
+ self.dialogs['attributes'] = None
+ self.dialogs['category'] = None
+ self.dialogs['barscale'] = None
+ self.dialogs['legend'] = None
+
+ self.decorationDialog = None # decoration/overlays
+
+ # doing nice things in statusbar when other things are ready
+ self.statusbarManager.Update()
+
+ def _setUpMapWindow(self, mapWindow):
+ # TODO: almost the smae implementation as for MapFrameBase (only names differ)
+ # enable or disable zoom history tool
+ mapWindow.zoomHistoryAvailable.connect(
+ lambda:
+ self.GetMapToolbar().Enable('zoomback', enable=True))
+ mapWindow.zoomHistoryUnavailable.connect(
+ lambda:
+ self.GetMapToolbar().Enable('zoomback', enable=False))
+ mapWindow.mouseMoving.connect(self.CoordinatesChanged)
+
+ def AddToolbar(self, name):
+ """Add defined toolbar to the window
+
+ Currently known toolbars are:
+ - 'map' - basic map toolbar
+ - 'gcpdisp' - GCP Manager, Display
+ - 'gcpman' - GCP Manager, points management
+ - 'nviz' - 3D view mode
+ """
+ # default toolbar
+ if name == "map":
+ self.toolbars['map'] = MapToolbar(self, self._toolSwitcher)
+
+ self._mgr.AddPane(self.toolbars['map'],
+ wx.aui.AuiPaneInfo().
+ Name("maptoolbar").Caption(_("Map Toolbar")).
+ ToolbarPane().Top().
+ LeftDockable(False).RightDockable(False).
+ BottomDockable(False).TopDockable(True).
+ CloseButton(False).Layer(2).
+ BestSize((self.toolbars['map'].GetSize())))
+
+ # GCP display
+ elif name == "gcpdisp":
+ self.toolbars['gcpdisp'] = GCPDisplayToolbar(
+ self, self._toolSwitcher)
+
+ self._mgr.AddPane(self.toolbars['gcpdisp'],
+ wx.aui.AuiPaneInfo().
+ Name("gcpdisplaytoolbar").Caption(_("GCP Display toolbar")).
+ ToolbarPane().Top().
+ LeftDockable(False).RightDockable(False).
+ BottomDockable(False).TopDockable(True).
+ CloseButton(False).Layer(2))
+
+ if self.show_target == False:
+ self.toolbars['gcpdisp'].Enable('zoommenu', enable=False)
+
+ self.toolbars['gcpman'] = GCPManToolbar(self)
+
+ self._mgr.AddPane(self.toolbars['gcpman'],
+ wx.aui.AuiPaneInfo().
+ Name("gcpmanagertoolbar").Caption(_("GCP Manager toolbar")).
+ ToolbarPane().Top().Row(1).
+ LeftDockable(False).RightDockable(False).
+ BottomDockable(False).TopDockable(True).
+ CloseButton(False).Layer(2))
+
+ self._mgr.Update()
+
+ def OnUpdateProgress(self, event):
+ """
+ Update progress bar info
+ """
+ self.GetProgressBar().UpdateProgress(event.layer, event.map)
+
+ event.Skip()
+
+ def OnFocus(self, event):
+ """
+ Change choicebook page to match display.
+ Or set display for georectifying
+ """
+ # was in if layer manager but considering the state it was executed
+ # always, moreover, there is no layer manager dependent code
+
+ # in GCP Management, set focus to current MapWindow for mouse actions
+ self.OnPointer(event)
+ self.MapWindow.SetFocus()
+
+ event.Skip()
+
+ def OnDraw(self, event):
+ """Re-display current map composition
+ """
+ self.MapWindow.UpdateMap(render=False)
+
+ def OnRender(self, event):
+ """Re-render map composition (each map layer)
+ """
+ # FIXME: remove qlayer code or use RemoveQueryLayer() now in mapdisp.frame
+ # delete tmp map layers (queries)
+ qlayer = self.Map.GetListOfLayers(name=globalvar.QUERYLAYER)
+ for layer in qlayer:
+ self.Map.DeleteLayer(layer)
+
+ self.SrcMapWindow.UpdateMap(render=True)
+ if self.show_target:
+ self.TgtMapWindow.UpdateMap(render=True)
+
+ # update statusbar
+ self.StatusbarUpdate()
+
+ def OnPointer(self, event):
+ """Pointer button clicked
+ """
+ self.SrcMapWindow.SetModePointer()
+ self.TgtMapWindow.SetModePointer()
+ # change the default cursor
+ self.SrcMapWindow.SetNamedCursor('cross')
+ self.TgtMapWindow.SetNamedCursor('cross')
+
+ def OnZoomIn(self, event):
+ """Zoom in the map."""
+ self.SrcMapWindow.SetModeZoomIn()
+ self.TgtMapWindow.SetModeZoomIn()
+
+ def OnZoomOut(self, event):
+ """Zoom out the map."""
+ self.SrcMapWindow.SetModeZoomOut()
+ self.TgtMapWindow.SetModeZoomOut()
+
+ def OnPan(self, event):
+ """Panning, set mouse to drag"""
+ self.SrcMapWindow.SetModePan()
+ self.TgtMapWindow.SetModePan()
+
+ def OnErase(self, event):
+ """
+ Erase the canvas
+ """
+ self.MapWindow.EraseMap()
+
+ if self.MapWindow == self.SrcMapWindow:
+ win = self.TgtMapWindow
+ elif self.MapWindow == self.TgtMapWindow:
+ win = self.SrcMapWindow
+
+ win.EraseMap()
+
+ def SaveToFile(self, event):
+ """Save map to image
+ """
+ img = self.MapWindow.img
+ if not img:
+ GMessage(parent=self, message=_(
+ "Nothing to render (empty map). Operation canceled."))
+ return
+ filetype, ltype = GetImageHandlers(img)
+
+ # get size
+ dlg = ImageSizeDialog(self)
+ dlg.CentreOnParent()
+ if dlg.ShowModal() != wx.ID_OK:
+ dlg.Destroy()
+ return
+ width, height = dlg.GetValues()
+ dlg.Destroy()
+
+ # get filename
+ dlg = wx.FileDialog(parent=self,
+ message=_("Choose a file name to save the image "
+ "(no need to add extension)"),
+ wildcard=filetype,
+ style=wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT)
+
+ if dlg.ShowModal() == wx.ID_OK:
+ path = dlg.GetPath()
+ if not path:
+ dlg.Destroy()
+ return
+
+ base, ext = os.path.splitext(path)
+ fileType = ltype[dlg.GetFilterIndex()]['type']
+ extType = ltype[dlg.GetFilterIndex()]['ext']
+ if ext != extType:
+ path = base + '.' + extType
+
+ self.MapWindow.SaveToFile(path, fileType,
+ width, height)
+
+ dlg.Destroy()
+
+ def PrintMenu(self, event):
+ """
+ Print options and output menu for map display
+ """
+ point = wx.GetMousePosition()
+ printmenu = wx.Menu()
+ # Add items to the menu
+ setup = wx.MenuItem(printmenu, wx.ID_ANY, _('Page setup'))
+ printmenu.AppendItem(setup)
+ self.Bind(wx.EVT_MENU, self.printopt.OnPageSetup, setup)
+
+ preview = wx.MenuItem(printmenu, wx.ID_ANY, _('Print preview'))
+ printmenu.AppendItem(preview)
+ self.Bind(wx.EVT_MENU, self.printopt.OnPrintPreview, preview)
+
+ doprint = wx.MenuItem(printmenu, wx.ID_ANY, _('Print display'))
+ printmenu.AppendItem(doprint)
+ self.Bind(wx.EVT_MENU, self.printopt.OnDoPrint, doprint)
+
+ # Popup the menu. If an item is selected then its handler
+ # will be called before PopupMenu returns.
+ self.PopupMenu(printmenu)
+ printmenu.Destroy()
+
+ def OnZoomToRaster(self, event):
+ """
+ Set display extents to match selected raster map (ignore NULLs)
+ """
+ self.MapWindow.ZoomToMap(ignoreNulls=True)
+
+ def OnZoomToSaved(self, event):
+ """Set display geometry to match extents in
+ saved region file
+ """
+ self.MapWindow.SetRegion(zoomOnly=True)
+
+ def OnDisplayToWind(self, event):
+ """Set computational region (WIND file) to match display
+ extents
+ """
+ self.MapWindow.DisplayToWind()
+
+ def SaveDisplayRegion(self, event):
+ """Save display extents to named region file.
+ """
+ self.MapWindow.SaveDisplayRegion()
+
+ def OnZoomMenu(self, event):
+ """Popup Zoom menu
+ """
+ point = wx.GetMousePosition()
+ zoommenu = wx.Menu()
+ # Add items to the menu
+
+ zoomwind = wx.MenuItem(zoommenu, wx.ID_ANY, _(
+ 'Zoom to computational region (set with g.region)'))
+ zoommenu.AppendItem(zoomwind)
+ self.Bind(wx.EVT_MENU, self.OnZoomToWind, zoomwind)
+
+ zoomdefault = wx.MenuItem(
+ zoommenu, wx.ID_ANY, _('Zoom to default region'))
+ zoommenu.AppendItem(zoomdefault)
+ self.Bind(wx.EVT_MENU, self.OnZoomToDefault, zoomdefault)
+
+ zoomsaved = wx.MenuItem(zoommenu, wx.ID_ANY, _('Zoom to saved region'))
+ zoommenu.AppendItem(zoomsaved)
+ self.Bind(wx.EVT_MENU, self.OnZoomToSaved, zoomsaved)
+
+ savewind = wx.MenuItem(zoommenu, wx.ID_ANY, _(
+ 'Set computational region from display'))
+ zoommenu.AppendItem(savewind)
+ self.Bind(wx.EVT_MENU, self.OnDisplayToWind, savewind)
+
+ savezoom = wx.MenuItem(zoommenu, wx.ID_ANY, _(
+ 'Save display geometry to named region'))
+ zoommenu.AppendItem(savezoom)
+ self.Bind(wx.EVT_MENU, self.SaveDisplayRegion, savezoom)
+
+ # Popup the menu. If an item is selected then its handler
+ # will be called before PopupMenu returns.
+ self.PopupMenu(zoommenu)
+ zoommenu.Destroy()
+
+ def IsStandalone(self):
+ """Check if Map display is standalone"""
+ # we do not know and we do not care, so always False
+ return True
+
+ def GetLayerManager(self):
+ """Get reference to Layer Manager
+
+ :return: always None
+ """
+ return None
+
+ def GetSrcWindow(self):
+ return self.SrcMapWindow
+
+ def GetTgtWindow(self):
+ return self.TgtMapWindow
+
+ def GetShowTarget(self):
+ return self.show_target
+
+ def GetMapToolbar(self):
+ """Returns toolbar with zooming tools"""
+ return self.toolbars['gcpdisp']
+
+ def _setActiveMapWindow(self, mapWindow):
+ if not self.MapWindow == mapWindow:
+ self.MapWindow = mapWindow
+ self.Map = mapWindow.Map
+ self.UpdateActive(mapWindow)
+ # needed for wingrass
+ self.SetFocus()
Added: grass/trunk/gui/wxpython/iphoto2image/ip2i_statusbar.py
===================================================================
--- grass/trunk/gui/wxpython/iphoto2image/ip2i_statusbar.py (rev 0)
+++ grass/trunk/gui/wxpython/iphoto2image/ip2i_statusbar.py 2017-02-13 18:20:04 UTC (rev 70552)
@@ -0,0 +1,128 @@
+"""
+ at package iphoto2image.ip2i_statusbar
+
+ at brief Classes for statusbar management in GCP Manager
+
+Classes:
+ - statusbar::SbRMSError
+ - statusbar::SbGoToGCP
+
+(C) 2012-2013 by the GRASS Development Team
+
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
+
+ at author Vaclav Petras <wenzeslaus gmail.com> (statusbar refactoring)
+ at author Anna Kratochvilova <kratochanna gmail.com> (statusbar refactoring)
+"""
+
+
+import wx
+
+from core.gcmd import GMessage
+from core.utils import _
+from mapdisp.statusbar import SbItem, SbTextItem
+from gui_core.wrap import SpinCtrl
+
+
+class SbGoToGCP(SbItem):
+ """SpinCtrl to select GCP to focus on
+
+ Requires MapFrame.GetSrcWindow, MapFrame.GetTgtWindow,
+ MapFrame.GetListCtrl, MapFrame.GetMapCoordList.
+ """
+
+ def __init__(self, mapframe, statusbar, position=0):
+ SbItem.__init__(self, mapframe, statusbar, position)
+ self.name = 'gotoGCP'
+ self.label = _("Go to GCP No.")
+
+ self.widget = SpinCtrl(parent=self.statusbar, id=wx.ID_ANY,
+ value="", min=0)
+ self.widget.Hide()
+
+ self.widget.Bind(wx.EVT_TEXT_ENTER, self.OnGoToGCP)
+ self.widget.Bind(wx.EVT_SPINCTRL, self.OnGoToGCP)
+
+ def OnGoToGCP(self, event):
+ """Zooms to given GCP."""
+ gcpNumber = self.GetValue()
+ mapCoords = self.mapFrame.GetMapCoordList()
+
+ # always false, spin checks it
+ if gcpNumber < 0 or gcpNumber > len(mapCoords):
+ GMessage(parent=self,
+ message="%s 1 - %s." % (_("Valid Range:"),
+ len(mapCoords)))
+ return
+
+ if gcpNumber == 0:
+ return
+
+ listCtrl = self.mapFrame.GetListCtrl()
+
+ listCtrl.selectedkey = gcpNumber
+ listCtrl.selected = listCtrl.FindItemData(-1, gcpNumber)
+ listCtrl.render = False
+ listCtrl.SetItemState(listCtrl.selected,
+ wx.LIST_STATE_SELECTED,
+ wx.LIST_STATE_SELECTED)
+ listCtrl.render = True
+
+ listCtrl.EnsureVisible(listCtrl.selected)
+
+ srcWin = self.mapFrame.GetSrcWindow()
+ tgtWin = self.mapFrame.GetTgtWindow()
+
+ # Source MapWindow:
+ begin = (mapCoords[gcpNumber][1], mapCoords[gcpNumber][2])
+ begin = srcWin.Cell2Pixel(begin)
+ end = begin
+ srcWin.Zoom(begin, end, 0)
+
+ # redraw map
+ srcWin.UpdateMap()
+
+ if self.mapFrame.GetShowTarget():
+ # Target MapWindow:
+ begin = (mapCoords[gcpNumber][3], mapCoords[gcpNumber][4])
+ begin = tgtWin.Cell2Pixel(begin)
+ end = begin
+ tgtWin.Zoom(begin, end, 0)
+
+ # redraw map
+ tgtWin.UpdateMap()
+
+ self.GetWidget().SetFocus()
+
+ def Update(self):
+ """Checks the number of items in the gcp list
+ and sets the spin limits accordingly."""
+ self.statusbar.SetStatusText("")
+ maximum = self.mapFrame.GetListCtrl().GetItemCount()
+ if maximum < 1:
+ maximum = 1
+ self.widget.SetRange(0, maximum)
+ self.Show()
+
+ # disable long help
+ self.mapFrame.StatusbarEnableLongHelp(False)
+
+
+class SbRMSError(SbTextItem):
+ """Shows RMS error.
+
+ Requires MapFrame.GetFwdError, MapFrame.GetBkwError.
+ """
+
+ def __init__(self, mapframe, statusbar, position=0):
+ SbTextItem.__init__(self, mapframe, statusbar, position)
+ self.name = 'RMSError'
+ self.label = _("RMS error")
+
+ def Show(self):
+ """Shows the RMS errors."""
+ self.SetValue(_("Forward: %(forw)s, Backward: %(back)s") %
+ {'forw': self.mapFrame.GetFwdError(),
+ 'back': self.mapFrame.GetBkwError()})
+ SbTextItem.Show(self)
Added: grass/trunk/gui/wxpython/iphoto2image/ip2i_toolbars.py
===================================================================
--- grass/trunk/gui/wxpython/iphoto2image/ip2i_toolbars.py (rev 0)
+++ grass/trunk/gui/wxpython/iphoto2image/ip2i_toolbars.py 2017-02-13 18:20:04 UTC (rev 70552)
@@ -0,0 +1,163 @@
+"""
+ at package iphoto2image.ip2i_toolbars
+
+ at brief Georectification module - toolbars
+
+Classes:
+ - toolbars::GCPMapToolbar
+ - toolbars::GCPDisplayToolbar
+
+(C) 2007-2011 by the GRASS Development Team
+
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
+
+ at author Markus Metz
+"""
+
+import os
+import sys
+
+import wx
+
+from core import globalvar
+from core.utils import _
+from gui_core.toolbars import BaseToolbar, BaseIcons
+from icons.icon import MetaIcon
+
+
+class GCPManToolbar(BaseToolbar):
+ """Toolbar for managing ground control points
+
+ :param parent: reference to GCP widget
+ """
+
+ def __init__(self, parent):
+ BaseToolbar.__init__(self, parent)
+
+ self.InitToolbar(self._toolbarData())
+
+ # realize the toolbar
+ self.Realize()
+
+ def _toolbarData(self):
+ icons = {
+ 'gcpAdd': MetaIcon(img='gcp-add',
+ label=_('Add new GCP to the list')),
+ 'gcpDelete': MetaIcon(img='gcp-delete',
+ label=_('Delete selected GCP')),
+ 'gcpClear': MetaIcon(img='gcp-remove',
+ label=_('Clear selected GCP')),
+ 'gcpRms': MetaIcon(img='gcp-rms',
+ label=_('Recalculate RMS error')),
+ 'georectify': MetaIcon(img='georectify',
+ label=_('Georectify')),
+ 'gcpSave': MetaIcon(img='gcp-save',
+ label=_('Save GCPs to POINTS file')),
+ 'gcpReload': MetaIcon(img='reload',
+ label=_('Reload GCPs from POINTS file')),
+ }
+
+ return self._getToolbarData((('gcpAdd', icons["gcpAdd"],
+ self.parent.AddGCP),
+ ('gcpDelete', icons["gcpDelete"],
+ self.parent.DeleteGCP),
+ ('gcpClear', icons["gcpClear"],
+ self.parent.ClearGCP),
+ (None, ),
+ ('rms', icons["gcpRms"],
+ self.parent.OnRMS),
+ ('georect', icons["georectify"],
+ self.parent.OnGeorect),
+ (None, ),
+ ('gcpSave', icons["gcpSave"],
+ self.parent.SaveGCPs),
+ ('gcpReload', icons["gcpReload"],
+ self.parent.ReloadGCPs))
+ )
+
+
+class GCPDisplayToolbar(BaseToolbar):
+ """GCP Display toolbar
+ """
+
+ def __init__(self, parent, toolSwitcher):
+ """GCP Display toolbar constructor
+ """
+ BaseToolbar.__init__(self, parent, toolSwitcher)
+
+ self.InitToolbar(self._toolbarData())
+ self._default = self.gcpset
+
+ # add tool to toggle active map window
+ self.togglemapid = wx.NewId()
+ self.togglemap = wx.Choice(parent=self, id=self.togglemapid,
+ choices=[_('source'), _('target')])
+
+ self.InsertControl(10, self.togglemap)
+
+ self.SetToolShortHelp(
+ self.togglemapid, '%s %s %s' %
+ (_('Set map canvas for '),
+ BaseIcons["zoomBack"].GetLabel(),
+ _(' / Zoom to map')))
+
+ for tool in (self.gcpset, self.pan, self.zoomin, self.zoomout):
+ self.toolSwitcher.AddToolToGroup(
+ group='mouseUse', toolbar=self, tool=tool)
+
+ # realize the toolbar
+ self.Realize()
+
+ self.EnableTool(self.zoomback, False)
+
+ def _toolbarData(self):
+ """Toolbar data"""
+ icons = {
+ 'gcpSet': MetaIcon(
+ img='gcp-create',
+ label=_('Update GCP coordinates'),
+ desc=_('Update GCP coordinates)')),
+ 'quit': BaseIcons['quit'].SetLabel(
+ _('Quit georectification tool')),
+ 'settings': BaseIcons['settings'].SetLabel(
+ _('Georectifier settings')),
+ 'help': BaseIcons['help'].SetLabel(
+ _('Georectifier manual')),
+ }
+
+ return self._getToolbarData((("displaymap", BaseIcons["display"],
+ self.parent.OnDraw),
+ ("rendermap", BaseIcons["render"],
+ self.parent.OnRender),
+ ("erase", BaseIcons["erase"],
+ self.parent.OnErase),
+ (None, ),
+ ("gcpset", icons["gcpSet"],
+ self.parent.OnPointer,
+ wx.ITEM_CHECK),
+ ("pan", BaseIcons["pan"],
+ self.parent.OnPan,
+ wx.ITEM_CHECK),
+ ("zoomin", BaseIcons["zoomIn"],
+ self.parent.OnZoomIn,
+ wx.ITEM_CHECK),
+ ("zoomout", BaseIcons["zoomOut"],
+ self.parent.OnZoomOut,
+ wx.ITEM_CHECK),
+ ("zoommenu", BaseIcons["zoomMenu"],
+ self.parent.OnZoomMenuGCP),
+ (None, ),
+ ("zoomback", BaseIcons["zoomBack"],
+ self.parent.OnZoomBack),
+ ("zoomtomap", BaseIcons["zoomExtent"],
+ self.parent.OnZoomToMap),
+ (None, ),
+ ('settings', icons["settings"],
+ self.parent.OnSettings),
+ ('help', icons["help"],
+ self.parent.OnHelp),
+ (None, ),
+ ('quit', icons["quit"],
+ self.parent.OnQuit))
+ )
Added: grass/trunk/gui/wxpython/iphoto2image/wxGUI_iphoto2image_frame.jpg
===================================================================
(Binary files differ)
Property changes on: grass/trunk/gui/wxpython/iphoto2image/wxGUI_iphoto2image_frame.jpg
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
More information about the grass-commit
mailing list