GRASS Programmer's Manual  6.5.svn(2014)-r66266
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
gcp/manager.py
Go to the documentation of this file.
1 """!
2 @package gcp.manager
3 
4 @brief Georectification module for GRASS GIS. Includes ground control
5 point management and interactive point and click GCP creation
6 
7 Classes:
8  - manager::GCPWizard
9  - manager::LocationPage
10  - manager::GroupPage
11  - manager::DispMapPage
12  - manager::GCP
13  - manager::GCPList
14  - manager::VectGroup
15  - manager::EditGCP
16  - manager::GrSettingsDialog
17 
18 (C) 2006-2011 by the GRASS Development Team
19 
20 This program is free software under the GNU General Public License
21 (>=v2). Read the file COPYING that comes with GRASS for details.
22 
23 @author Michael Barton
24 @author Updated by Martin Landa <landa.martin gmail.com>
25 @author Markus Metz redesign georectfier -> GCP Manager
26 """
27 
28 import os
29 import sys
30 import shutil
31 
32 import wx
33 from wx.lib.mixins.listctrl import CheckListCtrlMixin, ColumnSorterMixin, ListCtrlAutoWidthMixin
34 import wx.lib.colourselect as csel
35 import wx.wizard as wiz
36 
37 import grass.script as grass
38 
39 from core import globalvar
40 from core import utils
41 from core.render import Map
42 from gui_core.gselect import Select, LocationSelect, MapsetSelect
43 from gui_core.dialogs import GroupDialog
44 from core.gcmd import RunCommand, GMessage, GError, GWarning
45 from core.settings import UserSettings
46 from gcp.mapdisplay import MapFrame
47 
48 from location_wizard.wizard import TitledPage
49 
50 #
51 # global variables
52 #
53 global src_map
54 global tgt_map
55 global maptype
56 
57 src_map = ''
58 tgt_map = ''
59 maptype = 'cell'
60 
62  stream = open(os.path.join(globalvar.ETCIMGDIR, 'small_up_arrow.png'), 'rb')
63  try:
64  img = wx.ImageFromStream(stream)
65  finally:
66  stream.close()
67  return img
68 
70  stream = open(os.path.join(globalvar.ETCIMGDIR, 'small_down_arrow.png'), 'rb')
71  try:
72  img = wx.ImageFromStream(stream)
73  finally:
74  stream.close()
75  stream.close()
76  return img
77 
78 class GCPWizard(object):
79  """
80  Start wizard here and finish wizard here
81  """
82 
83  def __init__(self, parent):
84  self.parent = parent # GMFrame
85 
86  #
87  # get environmental variables
88  #
89  self.grassdatabase = grass.gisenv()['GISDBASE']
90 
91  #
92  # read original environment settings
93  #
94  self.target_gisrc = os.environ['GISRC']
95  self.gisrc_dict = {}
96  try:
97  f = open(self.target_gisrc, 'r')
98  for line in f.readlines():
99  line = line.replace('\n', '').strip()
100  if len(line) < 1:
101  continue
102  key, value = line.split(':', 1)
103  self.gisrc_dict[key.strip()] = value.strip()
104  finally:
105  f.close()
106 
107  self.currentlocation = self.gisrc_dict['LOCATION_NAME']
108  self.currentmapset = self.gisrc_dict['MAPSET']
109  # location for xy map to georectify
110  self.newlocation = ''
111  # mapset for xy map to georectify
112  self.newmapset = ''
113 
114  global maptype
115  global src_map
116  global tgt_map
117 
118  src_map = ''
119  tgt_map = ''
120  maptype = 'cell'
121 
122  # GISRC file for source location/mapset of map(s) to georectify
123  self.source_gisrc = ''
124  self.src_maps = []
125 
126  #
127  # define wizard pages
128  #
129  self.wizard = wiz.Wizard(parent=parent, id=wx.ID_ANY, title=_("Setup for georectification"))
130  self.startpage = LocationPage(self.wizard, self)
131  self.grouppage = GroupPage(self.wizard, self)
132  self.mappage = DispMapPage(self.wizard, self)
133 
134  #
135  # set the initial order of the pages
136  #
137  self.startpage.SetNext(self.grouppage)
138  self.grouppage.SetPrev(self.startpage)
139  self.grouppage.SetNext(self.mappage)
140  self.mappage.SetPrev(self.grouppage)
141 
142  #
143  # do pages layout
144  #
145  self.startpage.DoLayout()
146  self.grouppage.DoLayout()
147  self.mappage.DoLayout()
148  self.wizard.FitToPage(self.startpage)
149 
150  # self.Bind(wx.EVT_CLOSE, self.Cleanup)
151  # self.parent.Bind(wx.EVT_ACTIVATE, self.OnGLMFocus)
152 
153  success = False
154 
155  #
156  # run wizard
157  #
158  if self.wizard.RunWizard(self.startpage):
159  success = self.OnWizFinished()
160  if success == False:
161  GMessage(parent = self.parent,
162  message = _("Georectifying setup canceled."))
163  self.Cleanup()
164  else:
165  GMessage(parent = self.parent,
166  message = _("Georectifying setup canceled."))
167  self.Cleanup()
168 
169  #
170  # start GCP display
171  #
172  if success != False:
173  # instance of render.Map to be associated with display
174  self.SwitchEnv('source')
175  self.SrcMap = Map(gisrc=self.source_gisrc)
176  self.SwitchEnv('target')
177  self.TgtMap = Map(gisrc=self.target_gisrc)
178  self.Map = self.SrcMap
179 
180  #
181  # add layer to source map
182  #
183  if maptype == 'cell':
184  rendertype = 'raster'
185  cmdlist = ['d.rast', 'map=%s' % src_map]
186  else: # -> vector layer
187  rendertype = 'vector'
188  cmdlist = ['d.vect', 'map=%s' % src_map]
189 
190  self.SwitchEnv('source')
191  name, found = utils.GetLayerNameFromCmd(cmdlist)
192  self.SrcMap.AddLayer(type=rendertype, command=cmdlist, l_active=True,
193  name=name, l_hidden=False, l_opacity=1.0, l_render=False)
194 
195  if tgt_map:
196  #
197  # add layer to target map
198  #
199  if maptype == 'cell':
200  rendertype = 'raster'
201  cmdlist = ['d.rast', 'map=%s' % tgt_map]
202  else: # -> vector layer
203  rendertype = 'vector'
204  cmdlist = ['d.vect', 'map=%s' % tgt_map]
205 
206  self.SwitchEnv('target')
207  name, found = utils.GetLayerNameFromCmd(cmdlist)
208  self.TgtMap.AddLayer(type=rendertype, command=cmdlist, l_active=True,
209  name=name, l_hidden=False, l_opacity=1.0, l_render=False)
210 
211  #
212  # start GCP Manager
213  #
214  self.gcpmgr = GCP(self.parent, grwiz=self, size=globalvar.MAP_WINDOW_SIZE,
215  toolbars=["gcpdisp"],
216  Map=self.SrcMap, lmgr=self.parent)
217 
218  # load GCPs
219  self.gcpmgr.InitMapDisplay()
220  self.gcpmgr.CenterOnScreen()
221  self.gcpmgr.Show()
222  # need to update AUI here for wingrass
223  self.gcpmgr._mgr.Update()
224  else:
225  self.Cleanup()
226 
227  def SetSrcEnv(self, location, mapset):
228  """!Create environment to use for location and mapset
229  that are the source of the file(s) to georectify
230 
231  @param location source location
232  @param mapset source mapset
233 
234  @return False on error
235  @return True on success
236  """
237 
238  self.newlocation = location
239  self.newmapset = mapset
240 
241  # check to see if we are georectifying map in current working location/mapset
242  if self.newlocation == self.currentlocation and self.newmapset == self.currentmapset:
243  return False
244 
245  self.gisrc_dict['LOCATION_NAME'] = location
246  self.gisrc_dict['MAPSET'] = mapset
247 
249 
250  try:
251  f = open(self.source_gisrc, mode='w')
252  for line in self.gisrc_dict.items():
253  f.write(line[0] + ": " + line[1] + "\n")
254  finally:
255  f.close()
256 
257  return True
258 
259  def SwitchEnv(self, grc):
260  """
261  Switches between original working location/mapset and
262  location/mapset that is source of file(s) to georectify
263  """
264  # check to see if we are georectifying map in current working location/mapset
265  if self.newlocation == self.currentlocation and self.newmapset == self.currentmapset:
266  return False
267 
268  if grc == 'target':
269  os.environ['GISRC'] = str(self.target_gisrc)
270  elif grc == 'source':
271  os.environ['GISRC'] = str(self.source_gisrc)
272 
273  return True
274 
275  def OnWizFinished(self):
276  # self.Cleanup()
277 
278  return True
279 
280  def OnGLMFocus(self, event):
281  """!Layer Manager focus"""
282  # self.SwitchEnv('target')
283 
284  event.Skip()
285 
286  def Cleanup(self):
287  """!Return to current location and mapset"""
288  self.SwitchEnv('target')
289  self.parent.gcpmanagement = None
290 
291  self.wizard.Destroy()
292 
293 class LocationPage(TitledPage):
294  """
295  Set map type (raster or vector) to georectify and
296  select location/mapset of map(s) to georectify.
297  """
298  def __init__(self, wizard, parent):
299  TitledPage.__init__(self, wizard, _("Select map type and location/mapset"))
300 
301  self.parent = parent
302  self.grassdatabase = self.parent.grassdatabase
303 
304  self.xylocation = ''
305  self.xymapset = ''
306 
307  #
308  # layout
309  #
310  # map type
311  self.rb_maptype = wx.RadioBox(parent=self, id=wx.ID_ANY,
312  label=' %s ' % _("Map type to georectify"),
313  choices=[_('raster'), _('vector')],
314  majorDimension=wx.RA_SPECIFY_COLS)
315  self.sizer.Add(item=self.rb_maptype,
316  flag=wx.ALIGN_CENTER | wx.ALL | wx.EXPAND, border=5,
317  pos=(1, 1), span=(1, 2))
318 
319  # location
320  self.sizer.Add(item=wx.StaticText(parent=self, id=wx.ID_ANY, label=_('Select source location:')),
321  flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5,
322  pos=(2, 1))
323  self.cb_location = LocationSelect(parent = self, gisdbase = self.grassdatabase)
324  self.sizer.Add(item=self.cb_location,
325  flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5,
326  pos=(2, 2))
327 
328  # mapset
329  self.sizer.Add(item=wx.StaticText(parent=self, id=wx.ID_ANY, label=_('Select source mapset:')),
330  flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5,
331  pos=(3, 1))
332  self.cb_mapset = MapsetSelect(parent = self, gisdbase = self.grassdatabase,
333  setItems = False)
334  self.sizer.Add(item=self.cb_mapset,
335  flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5,
336  pos=(3,2))
337 
338  self.sizer.AddGrowableCol(2)
339  #
340  # bindings
341  #
342  self.Bind(wx.EVT_RADIOBOX, self.OnMaptype, self.rb_maptype)
343  self.Bind(wx.EVT_COMBOBOX, self.OnLocation, self.cb_location)
344  self.Bind(wx.EVT_COMBOBOX, self.OnMapset, self.cb_mapset)
345  self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
346  self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage)
347  # self.Bind(wx.EVT_CLOSE, self.parent.Cleanup)
348 
349  def OnMaptype(self,event):
350  """!Change map type"""
351  global maptype
352 
353  if event.GetInt() == 0:
354  maptype = 'cell'
355  else:
356  maptype = 'vector'
357 
358  def OnLocation(self, event):
359  """!Sets source location for map(s) to georectify"""
360  self.xylocation = event.GetString()
361 
362  #create a list of valid mapsets
363  tmplist = os.listdir(os.path.join(self.grassdatabase, self.xylocation))
364  self.mapsetList = []
365  for item in tmplist:
366  if os.path.isdir(os.path.join(self.grassdatabase, self.xylocation, item)) and \
367  os.path.exists(os.path.join(self.grassdatabase, self.xylocation, item, 'WIND')):
368  if item != 'PERMANENT':
369  self.mapsetList.append(item)
370 
371  self.xymapset = 'PERMANENT'
373  self.mapsetList.insert(0, 'PERMANENT')
374  self.cb_mapset.SetItems(self.mapsetList)
375  self.cb_mapset.SetStringSelection(self.xymapset)
376 
377  if not wx.FindWindowById(wx.ID_FORWARD).IsEnabled():
378  wx.FindWindowById(wx.ID_FORWARD).Enable(True)
379 
380  def OnMapset(self, event):
381  """!Sets source mapset for map(s) to georectify"""
382  if self.xylocation == '':
383  GMessage(_('You must select a valid location '
384  'before selecting a mapset'),
385  parent = self)
386  return
387 
388  self.xymapset = event.GetString()
389 
390  if not wx.FindWindowById(wx.ID_FORWARD).IsEnabled():
391  wx.FindWindowById(wx.ID_FORWARD).Enable(True)
392 
393  def OnPageChanging(self, event=None):
394  if event.GetDirection() and \
395  (self.xylocation == '' or self.xymapset == ''):
396  GMessage(_('You must select a valid location '
397  'and mapset in order to continue'),
398  parent = self)
399  event.Veto()
400  return
401 
402  self.parent.SetSrcEnv(self.xylocation, self.xymapset)
403 
404  def OnEnterPage(self, event=None):
405  if self.xylocation == '' or self.xymapset == '':
406  wx.FindWindowById(wx.ID_FORWARD).Enable(False)
407  else:
408  wx.FindWindowById(wx.ID_FORWARD).Enable(True)
409 
410 class GroupPage(TitledPage):
411  """
412  Set group to georectify. Create group if desired.
413  """
414  def __init__(self, wizard, parent):
415  TitledPage.__init__(self, wizard, _("Select image/map group to georectify"))
416 
417  self.parent = parent
418 
419  self.grassdatabase = self.parent.grassdatabase
420  self.groupList = []
421 
422  self.xylocation = ''
423  self.xymapset = ''
424  self.xygroup = ''
425 
426  # default extension
427  self.extension = '.georect' + str(os.getpid())
428 
429  #
430  # layout
431  #
432  # group
433  self.sizer.Add(item=wx.StaticText(parent=self, id=wx.ID_ANY, label=_('Select group:')),
434  flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5,
435  pos=(1, 1))
436  self.cb_group = wx.ComboBox(parent=self, id=wx.ID_ANY,
437  choices=self.groupList, size=(350, -1),
438  style=wx.CB_DROPDOWN | wx.CB_READONLY)
439  self.sizer.Add(item=self.cb_group,
440  flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5,
441  pos=(1, 2))
442 
443  # create group
444  self.sizer.Add(item=wx.StaticText(parent=self, id=wx.ID_ANY, label=_('Create group if none exists')),
445  flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5,
446  pos=(2, 1))
447  btnSizer = wx.BoxSizer(wx.HORIZONTAL)
448  self.btn_mkgroup = wx.Button(parent=self, id=wx.ID_ANY, label=_("Create/edit group..."))
449  self.btn_vgroup = wx.Button(parent=self, id=wx.ID_ANY, label=_("Add vector map to group..."))
450  btnSizer.Add(item=self.btn_mkgroup,
451  flag=wx.RIGHT, border=5)
452 
453  btnSizer.Add(item=self.btn_vgroup,
454  flag=wx.LEFT, border=5)
455 
456  self.sizer.Add(item=btnSizer,
457  flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5,
458  pos=(2, 2))
459 
460  # extension
461  self.sizer.Add(item=wx.StaticText(parent=self, id=wx.ID_ANY, label=_('Extension for output maps:')),
462  flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5,
463  pos=(3, 1))
464  self.ext_txt = wx.TextCtrl(parent=self, id=wx.ID_ANY, value="", size=(350,-1))
465  self.ext_txt.SetValue(self.extension)
466  self.sizer.Add(item=self.ext_txt,
467  flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5,
468  pos=(3, 2))
469  self.sizer.AddGrowableCol(2)
470 
471  #
472  # bindings
473  #
474  self.Bind(wx.EVT_COMBOBOX, self.OnGroup, self.cb_group)
475  self.Bind(wx.EVT_TEXT, self.OnExtension, self.ext_txt)
476  self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
477  self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage)
478  self.Bind(wx.EVT_CLOSE, self.parent.Cleanup)
479 
480  # hide vector group button by default
481  self.btn_vgroup.Hide()
482 
483  def OnGroup(self, event):
484  self.xygroup = event.GetString()
485 
486  def OnMkGroup(self, event):
487  """!Create new group in source location/mapset"""
488  dlg = GroupDialog(parent = self, defaultGroup = self.xygroup)
489 
490  dlg.ShowModal()
491  gr = dlg.GetSelectedGroup()
492  if gr in dlg.GetExistGroups():
493  self.xygroup = gr
494  else:
495  gr = ''
496  dlg.Destroy()
497 
498  self.OnEnterPage()
499  self.Update()
500 
501  def OnVGroup(self, event):
502  """!Add vector maps to group"""
503  dlg = VectGroup(parent = self,
504  id = wx.ID_ANY,
505  grassdb = self.grassdatabase,
506  location = self.xylocation,
507  mapset = self.xymapset,
508  group = self.xygroup)
509 
510  if dlg.ShowModal() != wx.ID_OK:
511  return
512 
513  dlg.MakeVGroup()
514  self.OnEnterPage()
515 
516  def OnExtension(self, event):
517  self.extension = self.ext_txt.GetValue()
518 
519  def OnPageChanging(self, event=None):
520  if event.GetDirection() and self.xygroup == '':
521  GMessage(_('You must select a valid image/map '
522  'group in order to continue'),
523  parent = self)
524  event.Veto()
525  return
526 
527  if event.GetDirection() and self.extension == '':
528  GMessage(_('You must enter an map name '
529  'extension in order to continue'),
530  parent = self)
531  event.Veto()
532  return
533 
534  def OnEnterPage(self, event=None):
535  global maptype
536 
537  self.groupList = []
538 
539  self.xylocation = self.parent.gisrc_dict['LOCATION_NAME']
540  self.xymapset = self.parent.gisrc_dict['MAPSET']
541 
542  # create a list of groups in selected mapset
543  if os.path.isdir(os.path.join(self.grassdatabase,
544  self.xylocation,
545  self.xymapset,
546  'group')):
547  tmplist = os.listdir(os.path.join(self.grassdatabase,
548  self.xylocation,
549  self.xymapset,
550  'group'))
551  for item in tmplist:
552  if os.path.isdir(os.path.join(self.grassdatabase,
553  self.xylocation,
554  self.xymapset,
555  'group',
556  item)):
557  self.groupList.append(item)
558 
559  if maptype == 'cell':
560  self.btn_vgroup.Hide()
561  self.Bind(wx.EVT_BUTTON, self.OnMkGroup, self.btn_mkgroup)
562 
563  elif maptype == 'vector':
564  self.btn_vgroup.Show()
565  self.Bind(wx.EVT_BUTTON, self.OnMkGroup, self.btn_mkgroup)
566  self.Bind(wx.EVT_BUTTON, self.OnVGroup, self.btn_vgroup)
567 
569  self.cb_group.SetItems(self.groupList)
570 
571  if len(self.groupList) > 0:
572  if self.xygroup and self.xygroup in self.groupList:
573  self.cb_group.SetStringSelection(self.xygroup)
574  else:
575  self.cb_group.SetSelection(0)
576  self.xygroup = self.groupList[0]
577 
578  if self.xygroup == '' or \
579  self.extension == '':
580  wx.FindWindowById(wx.ID_FORWARD).Enable(False)
581  else:
582  wx.FindWindowById(wx.ID_FORWARD).Enable(True)
583 
584  # switch to source
585  self.parent.SwitchEnv('source')
586 
587 class DispMapPage(TitledPage):
588  """
589  Select ungeoreferenced map to display for interactively
590  setting ground control points (GCPs).
591  """
592  def __init__(self, wizard, parent):
593  TitledPage.__init__(self, wizard,
594  _("Select maps to display for ground control point (GCP) creation"))
595 
596  self.parent = parent
597  global maptype
598 
599  #
600  # layout
601  #
602  self.sizer.Add(item=wx.StaticText(parent=self, id=wx.ID_ANY, label=_('Select source map to display:')),
603  flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5,
604  pos=(1, 1))
605 
606  self.srcselection = Select(self, id=wx.ID_ANY,
607  size=globalvar.DIALOG_GSELECT_SIZE, type=maptype, updateOnPopup = False)
608 
609  self.sizer.Add(item=self.srcselection,
610  flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5,
611  pos=(1, 2))
612 
613  self.sizer.Add(item=wx.StaticText(parent=self, id=wx.ID_ANY, label=_('Select target map to display:')),
614  flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5,
615  pos=(2, 1))
616 
617  self.tgtselection = Select(self, id = wx.ID_ANY,
618  size = globalvar.DIALOG_GSELECT_SIZE, type=maptype, updateOnPopup = False)
619 
620  self.sizer.Add(item=self.tgtselection,
621  flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5,
622  pos=(2, 2))
623 
624  #
625  # bindings
626  #
627  self.srcselection.Bind(wx.EVT_TEXT, self.OnSrcSelection)
628  self.tgtselection.Bind(wx.EVT_TEXT, self.OnTgtSelection)
629  self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
630  self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage)
631  self.Bind(wx.EVT_CLOSE, self.parent.Cleanup)
632 
633  def OnSrcSelection(self,event):
634  """!Source map to display selected"""
635  global src_map
636  global maptype
637 
638  src_map = self.srcselection.GetValue()
639 
640  if src_map == '':
641  wx.FindWindowById(wx.ID_FORWARD).Enable(False)
642  else:
643  wx.FindWindowById(wx.ID_FORWARD).Enable(True)
644 
645  try:
646  # set computational region to match selected map and zoom display to region
647  if maptype == 'cell':
648  p = RunCommand('g.region', rast='src_map')
649  elif maptype == 'vector':
650  p = RunCommand('g.region', vect='src_map')
651 
652  if p.returncode == 0:
653  print 'returncode = ', str(p.returncode)
654  self.parent.Map.region = self.parent.Map.GetRegion()
655  except:
656  pass
657 
658  def OnTgtSelection(self,event):
659  """!Source map to display selected"""
660  global tgt_map
661 
662  tgt_map = self.tgtselection.GetValue()
663 
664  def OnPageChanging(self, event=None):
665  global src_map
666  global tgt_map
667 
668  if event.GetDirection() and (src_map == ''):
669  GMessage(_('You must select a source map '
670  'in order to continue'),
671  parent = self)
672  event.Veto()
673  return
674 
675  self.parent.SwitchEnv('target')
676 
677  def OnEnterPage(self, event=None):
678  global maptype
679  global src_map
680  global tgt_map
681 
682  self.srcselection.SetElementList(maptype)
683  ret = RunCommand('i.group',
684  parent = self,
685  read = True,
686  group = self.parent.grouppage.xygroup,
687  flags = 'g')
688 
689  if ret:
690  self.parent.src_maps = ret.splitlines()
691  else:
692  GError(parent = self,
693  message = _('No maps in selected group <%s>.\n'
694  'Please edit group or select another group.') %
695  self.parent.grouppage.xygroup)
696  return
697 
698  # filter out all maps not in group
699  self.srcselection.tcp.GetElementList(elements = self.parent.src_maps)
700  src_map = self.parent.src_maps[0]
701  self.srcselection.SetValue(src_map)
702 
703  self.parent.SwitchEnv('target')
704  self.tgtselection.SetElementList(maptype)
705  self.tgtselection.GetElementList()
706  self.parent.SwitchEnv('source')
707 
708  if src_map == '':
709  wx.FindWindowById(wx.ID_FORWARD).Enable(False)
710  else:
711  wx.FindWindowById(wx.ID_FORWARD).Enable(True)
712 
713 class GCP(MapFrame, ColumnSorterMixin):
714  """!
715  Manages ground control points for georectifying. Calculates RMS statics.
716  Calls i.rectify or v.transform to georectify map.
717  """
718  def __init__(self, parent, grwiz = None, id = wx.ID_ANY,
719  title = _("Manage Ground Control Points"),
720  size = (700, 300), toolbars = ["gcpdisp"], Map = None, lmgr = None):
721 
722  self.grwiz = grwiz # GR Wizard
723 
724  if tgt_map == '':
725  self.show_target = False
726  else:
727  self.show_target = True
728 
729  #wx.Frame.__init__(self, parent, id, title, size = size, name = "GCPFrame")
730  MapFrame.__init__(self, parent = parent, title = title, size = size,
731  Map = Map, toolbars = toolbars, lmgr = lmgr, name = 'GCPMapWindow')
732 
733  #
734  # init variables
735  #
736  self.parent = parent # GMFrame
737  self.parent.gcpmanagement = self
738 
739  self.grassdatabase = self.grwiz.grassdatabase
740 
741  self.currentlocation = self.grwiz.currentlocation
742  self.currentmapset = self.grwiz.currentmapset
743 
744  self.newlocation = self.grwiz.newlocation
745  self.newmapset = self.grwiz.newmapset
746 
747  self.xylocation = self.grwiz.gisrc_dict['LOCATION_NAME']
748  self.xymapset = self.grwiz.gisrc_dict['MAPSET']
749  self.xygroup = self.grwiz.grouppage.xygroup
750  self.src_maps = self.grwiz.src_maps
751  self.extension = self.grwiz.grouppage.extension
752  self.outname = ''
753  self.VectGRList = []
754 
755  self.file = {
756  'points' : os.path.join(self.grassdatabase,
757  self.xylocation,
758  self.xymapset,
759  'group',
760  self.xygroup,
761  'POINTS'),
762  'points_bak' : os.path.join(self.grassdatabase,
763  self.xylocation,
764  self.xymapset,
765  'group',
766  self.xygroup,
767  'POINTS_BAK'),
768  'rgrp' : os.path.join(self.grassdatabase,
769  self.xylocation,
770  self.xymapset,
771  'group',
772  self.xygroup,
773  'REF'),
774  'vgrp' : os.path.join(self.grassdatabase,
775  self.xylocation,
776  self.xymapset,
777  'group',
778  self.xygroup,
779  'VREF'),
780  'target' : os.path.join(self.grassdatabase,
781  self.xylocation,
782  self.xymapset,
783  'group',
784  self.xygroup,
785  'TARGET'),
786  }
787 
788  # make a backup of the current points file
789  if os.path.exists(self.file['points']):
790  shutil.copy(self.file['points'], self.file['points_bak'])
791 
792  # polynomial order transformation for georectification
793  self.gr_order = 1
794  # interpolation method for georectification
795  self.gr_method = 'nearest'
796  # region clipping for georectified map
797  self.clip_to_region = False
798  # number of GCPs selected to be used for georectification (checked)
799  self.GCPcount = 0
800  # forward RMS error
801  self.fwd_rmserror = 0.0
802  # backward RMS error
803  self.bkw_rmserror = 0.0
804  # list map coords and ID of map display they came from
805  self.mapcoordlist = []
806  self.mapcoordlist.append([ 0, # GCP number
807  0.0, # source east
808  0.0, # source north
809  0.0, # target east
810  0.0, # target north
811  0.0, # forward error
812  0.0 ] ) # backward error
813 
814  # init vars to highlight high RMS errors
815  self.highest_only = True
816  self.show_unused = True
817  self.highest_key = -1
818  self.rmsthresh = 0
819  self.rmsmean = 0
820  self.rmssd = 0
821 
822  self.SetTarget(self.xygroup, self.currentlocation, self.currentmapset)
823 
824  self.itemDataMap = None
825 
826  # images for column sorting
827  # CheckListCtrlMixin must set an ImageList first
828  self.il = self.list.GetImageList(wx.IMAGE_LIST_SMALL)
829 
830  SmallUpArrow = wx.BitmapFromImage(getSmallUpArrowImage())
831  SmallDnArrow = wx.BitmapFromImage(getSmallDnArrowImage())
832  self.sm_dn = self.il.Add(SmallDnArrow)
833  self.sm_up = self.il.Add(SmallUpArrow)
834 
835  # set mouse characteristics
836  self.mapwin = self.SrcMapWindow
837  self.mapwin.mouse['box'] = 'point'
838  self.mapwin.mouse["use"] == "pointer"
839  self.mapwin.zoomtype = 0
840  self.mapwin.pen = wx.Pen(colour='black', width=2, style=wx.SOLID)
841  self.mapwin.SetCursor(self.cursors["cross"])
842 
843  self.mapwin = self.TgtMapWindow
844 
845  # set mouse characteristics
846  self.mapwin.mouse['box'] = 'point'
847  self.mapwin.mouse["use"] == "pointer"
848  self.mapwin.zoomtype = 0
849  self.mapwin.pen = wx.Pen(colour='black', width=2, style=wx.SOLID)
850  self.mapwin.SetCursor(self.cursors["cross"])
851 
852  #
853  # show new display & draw map
854  #
855  if self.show_target:
856  self.MapWindow = self.TgtMapWindow
857  self.Map = self.TgtMap
858  self.OnZoomToMap(None)
859 
860  self.MapWindow = self.SrcMapWindow
861  self.Map = self.SrcMap
862  self.OnZoomToMap(None)
863 
864  #
865  # bindings
866  #
867  self.Bind(wx.EVT_ACTIVATE, self.OnFocus)
868  self.Bind(wx.EVT_CLOSE, self.OnQuit)
869 
870  def __del__(self):
871  """!Disable GCP manager mode"""
872  self.parent.gcpmanagement = None
873 
874  def CreateGCPList(self):
875  """!Create GCP List Control"""
876 
877  return GCPList(parent=self, gcp=self)
878 
879  # Used by the ColumnSorterMixin, see wx/lib/mixins/listctrl.py
880  def GetListCtrl(self):
881  return self.list
882 
883  def GetMapCoordList(self):
884  return self.mapcoordlist
885 
886  # Used by the ColumnSorterMixin, see wx/lib/mixins/listctrl.py
887  def GetSortImages(self):
888  return (self.sm_dn, self.sm_up)
889 
890  def GetFwdError(self):
891  return self.fwd_rmserror
892 
893  def GetBkwError(self):
894  return self.bkw_rmserror
895 
896  def InitMapDisplay(self):
897  self.list.LoadData()
898 
899  # initialize column sorter
900  self.itemDataMap = self.mapcoordlist
901  ncols = self.list.GetColumnCount()
902  ColumnSorterMixin.__init__(self, ncols)
903  # init to ascending sort on first click
904  self._colSortFlag = [1] * ncols
905 
906  def SetTarget(self, tgroup, tlocation, tmapset):
907  """
908  Sets rectification target to current location and mapset
909  """
910  # check to see if we are georectifying map in current working location/mapset
911  if self.newlocation == self.currentlocation and self.newmapset == self.currentmapset:
912  RunCommand('i.target',
913  parent = self,
914  flags = 'c',
915  group = tgroup)
916  else:
917  self.grwiz.SwitchEnv('source')
918  RunCommand('i.target',
919  parent = self,
920  group = tgroup,
921  location = tlocation,
922  mapset = tmapset)
923  self.grwiz.SwitchEnv('target')
924 
925  def AddGCP(self, event):
926  """
927  Appends an item to GCP list
928  """
929  keyval = self.list.AddGCPItem() + 1
930  # source east, source north, target east, target north, forward error, backward error
931  self.mapcoordlist.append([ keyval, # GCP number
932  0.0, # source east
933  0.0, # source north
934  0.0, # target east
935  0.0, # target north
936  0.0, # forward error
937  0.0 ] ) # backward error
938 
939  if self.statusbarManager.GetMode() == 8: # go to
940  self.StatusbarUpdate()
941 
942  def DeleteGCP(self, event):
943  """
944  Deletes selected item in GCP list
945  """
946  minNumOfItems = self.OnGROrder(None)
947 
948  if self.list.GetItemCount() <= minNumOfItems:
949  GMessage(parent = self,
950  message=_("At least %d GCPs required. Operation canceled.") % minNumOfItems)
951  return
952 
953  key = self.list.DeleteGCPItem()
954  del self.mapcoordlist[key]
955 
956  # update key and GCP number
957  for newkey in range(key, len(self.mapcoordlist)):
958  index = self.list.FindItemData(-1, newkey + 1)
959  self.mapcoordlist[newkey][0] = newkey
960  self.list.SetStringItem(index, 0, str(newkey))
961  self.list.SetItemData(index, newkey)
962 
963  # update selected
964  if self.list.GetItemCount() > 0:
965  if self.list.selected < self.list.GetItemCount():
966  self.list.selectedkey = self.list.GetItemData(self.list.selected)
967  else:
968  self.list.selected = self.list.GetItemCount() - 1
969  self.list.selectedkey = self.list.GetItemData(self.list.selected)
970 
971  self.list.SetItemState(self.list.selected,
972  wx.LIST_STATE_SELECTED,
973  wx.LIST_STATE_SELECTED)
974  else:
975  self.list.selected = wx.NOT_FOUND
976  self.list.selectedkey = -1
977 
978  self.UpdateColours()
979 
980  if self.statusbarManager.GetMode() == 8: # go to
981  self.StatusbarUpdate()
982  if self.list.selectedkey > 0:
983  self.statusbarManager.SetProperty('gotoGCP', self.list.selectedkey)
984 
985  def ClearGCP(self, event):
986  """
987  Clears all values in selected item of GCP list and unchecks it
988  """
989  index = self.list.GetSelected()
990  key = self.list.GetItemData(index)
991 
992  for i in range(1, 5):
993  self.list.SetStringItem(index, i, '0.0')
994  self.list.SetStringItem(index, 5, '')
995  self.list.SetStringItem(index, 6, '')
996  self.list.CheckItem(index, False)
997 
998  # GCP number, source E, source N, target E, target N, fwd error, bkwd error
999  self.mapcoordlist[key] = [key, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
1000 
1001  def DrawGCP(self, coordtype):
1002  """
1003  Updates GCP and map coord maps and redraws
1004  active (checked) GCP markers
1005  """
1006  self.highest_only = UserSettings.Get(group='gcpman', key='rms', subkey='highestonly')
1007 
1008  self.show_unused = UserSettings.Get(group='gcpman', key='symbol', subkey='unused')
1009  col = UserSettings.Get(group='gcpman', key='symbol', subkey='color')
1010  wxLowCol = wx.Colour(col[0], col[1], col[2], 255)
1011  col = UserSettings.Get(group='gcpman', key='symbol', subkey='hcolor')
1012  wxHiCol = wx.Colour(col[0], col[1], col[2], 255)
1013  col = UserSettings.Get(group='gcpman', key='symbol', subkey='scolor')
1014  wxSelCol = wx.Colour(col[0], col[1], col[2], 255)
1015  col = UserSettings.Get(group='gcpman', key='symbol', subkey='ucolor')
1016  wxUnCol = wx.Colour(col[0], col[1], col[2], 255)
1017  spx = UserSettings.Get(group='gcpman', key='symbol', subkey='size')
1018  wpx = UserSettings.Get(group='gcpman', key='symbol', subkey='width')
1019  font = self.GetFont()
1020  font.SetPointSize(int(spx) + 2)
1021 
1022  penOrig = polypenOrig = None
1023 
1024  mapWin = None
1025 
1026  if coordtype == 'source':
1027  mapWin = self.SrcMapWindow
1028  e_idx = 1
1029  n_idx = 2
1030  elif coordtype == 'target':
1031  mapWin = self.TgtMapWindow
1032  e_idx = 3
1033  n_idx = 4
1034 
1035  if not mapWin:
1036  GError(parent = self,
1037  message="%s%s." % (_("mapwin not defined for "),
1038  str(idx)))
1039  return
1040 
1041  #for gcp in self.mapcoordlist:
1042  for idx in range(self.list.GetItemCount()):
1043 
1044  key = self.list.GetItemData(idx)
1045  gcp = self.mapcoordlist[key]
1046 
1047  if not self.list.IsChecked(idx):
1048  if self.show_unused:
1049  wxCol = wxUnCol
1050  else:
1051  continue
1052  else:
1053  if self.highest_only == True:
1054  if key == self.highest_key:
1055  wxCol = wxHiCol
1056  else:
1057  wxCol = wxLowCol
1058  elif self.rmsthresh > 0:
1059  if (gcp[5] > self.rmsthresh):
1060  wxCol = wxHiCol
1061  else:
1062  wxCol = wxLowCol
1063 
1064  if idx == self.list.selected:
1065  wxCol = wxSelCol
1066 
1067  if not penOrig:
1068  penOrig = mapWin.pen
1069  polypenOrig = mapWin.polypen
1070  mapWin.pen = wx.Pen(colour=wxCol, width=wpx, style=wx.SOLID)
1071  mapWin.polypen = wx.Pen(colour=wxCol, width=wpx, style=wx.SOLID) # ?
1072 
1073  mapWin.pen.SetColour(wxCol)
1074  mapWin.polypen.SetColour(wxCol)
1075 
1076  coord = mapWin.Cell2Pixel((gcp[e_idx], gcp[n_idx]))
1077  mapWin.DrawCross(pdc=mapWin.pdcTmp, coords=coord,
1078  size=spx, text={ 'text' : '%s' % str(gcp[0]),
1079  'active' : True,
1080  'font' : font,
1081  'color': wxCol,
1082  'coords': [coord[0] + 5,
1083  coord[1] + 5,
1084  5,
1085  5]})
1086 
1087  if penOrig:
1088  mapWin.pen = penOrig
1089  mapWin.polypen = polypenOrig
1090 
1091  def SetGCPData(self, coordtype, coord, mapdisp=None, confirm=False):
1092  """
1093  Inserts coordinates from file, mouse click on map, or after editing
1094  into selected item of GCP list and checks it for use
1095  """
1096 
1097  index = self.list.GetSelected()
1098  if index == wx.NOT_FOUND:
1099  return
1100 
1101  coord0 = coord[0]
1102  coord1 = coord[1]
1103 
1104  key = self.list.GetItemData(index)
1105  if confirm:
1106  if self.MapWindow == self.SrcMapWindow:
1107  currloc = _("source")
1108  else:
1109  currloc = _("target")
1110  ret = wx.MessageBox(parent=self,
1111  caption=_("Set GCP coordinates"),
1112  message=_('Set %(coor)s coordinates for GCP No. %(key)s? \n\n'
1113  'East: %(coor0)s \n'
1114  'North: %(coor1)s') % \
1115  { 'coor' : currloc,
1116  'key' : str(key),
1117  'coor0' : str(coord0),
1118  'coor1' : str(coord1) },
1119  style=wx.ICON_QUESTION | wx.YES_NO | wx.CENTRE)
1120 
1121  # for wingrass
1122  if os.name == 'nt':
1123  self.MapWindow.SetFocus()
1124  if ret == wx.NO:
1125  return
1126 
1127  if coordtype == 'source':
1128  self.list.SetStringItem(index, 1, str(coord0))
1129  self.list.SetStringItem(index, 2, str(coord1))
1130  self.mapcoordlist[key][1] = coord[0]
1131  self.mapcoordlist[key][2] = coord[1]
1132  elif coordtype == 'target':
1133  self.list.SetStringItem(index, 3, str(coord0))
1134  self.list.SetStringItem(index, 4, str(coord1))
1135  self.mapcoordlist[key][3] = coord[0]
1136  self.mapcoordlist[key][4] = coord[1]
1137 
1138  self.list.SetStringItem(index, 5, '0')
1139  self.list.SetStringItem(index, 6, '0')
1140  self.mapcoordlist[key][5] = 0.0
1141  self.mapcoordlist[key][6] = 0.0
1142 
1143  # self.list.ResizeColumns()
1144 
1145  def SaveGCPs(self, event):
1146  """
1147  Make a POINTS file or save GCP coordinates to existing POINTS file
1148  """
1149 
1150  self.GCPcount = 0
1151  try:
1152  f = open(self.file['points'], mode='w')
1153  # use os.linesep or '\n' here ???
1154  f.write('# Ground Control Points File\n')
1155  f.write("# \n")
1156  f.write("# target location: " + self.currentlocation + '\n')
1157  f.write("# target mapset: " + self.currentmapset + '\n')
1158  f.write("#\tsource\t\ttarget\t\tstatus\n")
1159  f.write("#\teast\tnorth\teast\tnorth\t(1=ok, 0=ignore)\n")
1160  f.write("#----------------------- ----------------------- ---------------\n")
1161 
1162  for index in range(self.list.GetItemCount()):
1163  if self.list.IsChecked(index) == True:
1164  check = "1"
1165  self.GCPcount += 1
1166  else:
1167  check = "0"
1168  coord0 = self.list.GetItem(index, 1).GetText()
1169  coord1 = self.list.GetItem(index, 2).GetText()
1170  coord2 = self.list.GetItem(index, 3).GetText()
1171  coord3 = self.list.GetItem(index, 4).GetText()
1172  f.write(coord0 + ' ' + coord1 + ' ' + coord2 + ' ' + coord3 + ' ' + check + '\n')
1173 
1174  except IOError, err:
1175  GError(parent = self,
1176  message="%s <%s>. %s%s" % (_("Writing POINTS file failed"),
1177  self.file['points'], os.linesep, err))
1178  return
1179 
1180  f.close()
1181 
1182  # if event != None save also to backup file
1183  if event:
1184  shutil.copy(self.file['points'], self.file['points_bak'])
1185  self.parent.goutput.WriteLog(_('POINTS file saved for group <%s>') % self.xygroup)
1186  #self.SetStatusText(_('POINTS file saved'))
1187 
1188  def ReadGCPs(self):
1189  """
1190  Reads GCPs and georectified coordinates from POINTS file
1191  """
1192 
1193  self.GCPcount = 0
1194 
1195  sourceMapWin = self.SrcMapWindow
1196  targetMapWin = self.TgtMapWindow
1197 
1198  if not sourceMapWin:
1199  GError(parent = self,
1200  message = "%s. %s%s" % (_("source mapwin not defined"),
1201  os.linesep, err))
1202 
1203  if not targetMapWin:
1204  GError(parent = self,
1205  message="%s. %s%s" % (_("target mapwin not defined"),
1206  os.linesep, err))
1207 
1208  try:
1209  f = open(self.file['points'], 'r')
1210  GCPcnt = 0
1211 
1212  for line in f.readlines():
1213  if line[0] == '#' or line =='':
1214  continue
1215  line = line.replace('\n', '').strip()
1216  coords = map(float, line.split())
1217  if coords[4] == 1:
1218  check = True
1219  self.GCPcount +=1
1220  else:
1221  check = False
1222 
1223  self.AddGCP(event=None)
1224  self.SetGCPData('source', (coords[0], coords[1]), sourceMapWin)
1225  self.SetGCPData('target', (coords[2], coords[3]), targetMapWin)
1226  index = self.list.GetSelected()
1227  if index != wx.NOT_FOUND:
1228  self.list.CheckItem(index, check)
1229  GCPcnt += 1
1230 
1231  except IOError, err:
1232  GError(parent = self,
1233  message = "%s <%s>. %s%s" % (_("Reading POINTS file failed"),
1234  self.file['points'], os.linesep, err))
1235  return
1236 
1237  f.close()
1238 
1239  if GCPcnt == 0:
1240  # 3 gcp is minimum
1241  for i in range(3):
1242  self.AddGCP(None)
1243 
1244  if self.CheckGCPcount():
1245  # calculate RMS
1246  self.RMSError(self.xygroup, self.gr_order)
1247 
1248  def ReloadGCPs(self, event):
1249  """!Reload data from file"""
1250 
1251  # use backup
1252  shutil.copy(self.file['points_bak'], self.file['points'])
1253 
1254  # delete all items in mapcoordlist
1255  self.mapcoordlist = []
1256  self.mapcoordlist.append([ 0, # GCP number
1257  0.0, # source east
1258  0.0, # source north
1259  0.0, # target east
1260  0.0, # target north
1261  0.0, # forward error
1262  0.0 ] ) # backward error
1263 
1264  self.list.LoadData()
1265  self.itemDataMap = self.mapcoordlist
1266 
1267  if self._col != -1:
1268  self.list.ClearColumnImage(self._col)
1269  self._colSortFlag = [1] * self.list.GetColumnCount()
1270 
1271  # draw GCPs (source and target)
1272  sourceMapWin = self.SrcMapWindow
1273  sourceMapWin.UpdateMap(render=False, renderVector=False)
1274  if self.show_target:
1275  targetMapWin = self.TgtMapWindow
1276  targetMapWin.UpdateMap(render=False, renderVector=False)
1277 
1278  def OnFocus(self, event):
1279  # self.grwiz.SwitchEnv('source')
1280  pass
1281 
1282  def OnRMS(self, event):
1283  """
1284  RMS button handler
1285  """
1286  self.RMSError(self.xygroup,self.gr_order)
1287 
1288  sourceMapWin = self.SrcMapWindow
1289  sourceMapWin.UpdateMap(render=False, renderVector=False)
1290  if self.show_target:
1291  targetMapWin = self.TgtMapWindow
1292  targetMapWin.UpdateMap(render=False, renderVector=False)
1293 
1294  def CheckGCPcount(self, msg=False):
1295  """
1296  Checks to make sure that the minimum number of GCPs have been defined and
1297  are active for the selected transformation order
1298  """
1299  if (self.GCPcount < 3 and self.gr_order == 1) or \
1300  (self.GCPcount < 6 and self.gr_order == 2) or \
1301  (self.GCPcount < 10 and self.gr_order == 3):
1302  if msg:
1303  GWarning(parent = self,
1304  message=_('Insufficient points defined and active (checked) '
1305  'for selected rectification method.\n'
1306  '3+ points needed for 1st order,\n'
1307  '6+ points for 2nd order, and\n'
1308  '10+ points for 3rd order.'))
1309  return False
1310  else:
1311  return True
1312 
1313  def OnGeorect(self, event):
1314  """
1315  Georectifies map(s) in group using i.rectify or v.transform
1316  """
1317  global maptype
1318  self.SaveGCPs(None)
1319 
1320  if self.CheckGCPcount(msg=True) == False:
1321  return
1322 
1323  if maptype == 'cell':
1324  self.grwiz.SwitchEnv('source')
1325 
1326  if self.clip_to_region:
1327  flags = "ac"
1328  else:
1329  flags = "a"
1330 
1331  busy = wx.BusyInfo(message=_("Rectifying images, please wait..."),
1332  parent=self)
1333  wx.Yield()
1334 
1335  ret, msg = RunCommand('i.rectify',
1336  parent = self,
1337  getErrorMsg = True,
1338  quiet = True,
1339  group = self.xygroup,
1340  extension = self.extension,
1341  order = self.gr_order,
1342  method=self.gr_method,
1343  flags = flags)
1344 
1345  busy.Destroy()
1346 
1347  # provide feedback on failure
1348  if ret != 0:
1349  print >> sys.stderr, msg
1350 
1351  elif maptype == 'vector':
1352  outmsg = ''
1353  # loop through all vectors in VREF
1354  # and move resulting vector to target location
1355 
1356  # make sure current mapset has a vector folder
1357  if not os.path.isdir(os.path.join(self.grassdatabase,
1358  self.currentlocation,
1359  self.currentmapset,
1360  'vector')):
1361  os.mkdir(os.path.join(self.grassdatabase,
1362  self.currentlocation,
1363  self.currentmapset,
1364  'vector'))
1365 
1366  self.grwiz.SwitchEnv('source')
1367 
1368  # make list of vectors to georectify from VREF
1369  f = open(self.file['vgrp'])
1370  vectlist = []
1371  try:
1372  for vect in f.readlines():
1373  vect = vect.strip('\n')
1374  if len(vect) < 1:
1375  continue
1376  vectlist.append(vect)
1377  finally:
1378  f.close()
1379 
1380  # georectify each vector in VREF using v.transform
1381  for vect in vectlist:
1382  self.outname = vect + '_' + self.extension
1383  self.parent.goutput.WriteLog(text = _('Transforming <%s>...') % vect,
1384  switchPage = True)
1385  msg = err = ''
1386 
1387  ret, out, err = RunCommand('v.transform',
1388  overwrite = True,
1389  input = vect,
1390  output = self.outname,
1391  pointsfile = self.file['points'],
1392  getErrorMsg = True, read = True)
1393 
1394  if ret == 0:
1395  self.VectGRList.append(self.outname)
1396  # note: WriteLog doesn't handle GRASS_INFO_PERCENT well, so using a print here
1397  # self.parent.goutput.WriteLog(text = _(err), switchPage = True)
1398  self.parent.goutput.WriteLog(text = out, switchPage = True)
1399  else:
1400  self.parent.goutput.WriteError(_('Georectification of vector map <%s> failed') %
1401  self.outname)
1402  self.parent.goutput.WriteError(err)
1403 
1404  # FIXME
1405  # Copying database information not working.
1406  # Does not copy from xy location to current location
1407  # TODO: replace $GISDBASE etc with real paths
1408  # xyLayer = []
1409  # for layer in grass.vector_db(map = vect).itervalues():
1410  # xyLayer.append((layer['driver'],
1411  # layer['database'],
1412  # layer['table']))
1413 
1414 
1415  # dbConnect = grass.db_connection()
1416  # print 'db connection =', dbConnect
1417  # for layer in xyLayer:
1418  # self.parent.goutput.RunCmd(['db.copy',
1419  # '--q',
1420  # '--o',
1421  # 'from_driver=%s' % layer[0],
1422  # 'from_database=%s' % layer[1],
1423  # 'from_table=%s' % layer[2],
1424  # 'to_driver=%s' % dbConnect['driver'],
1425  # 'to_database=%s' % dbConnect['database'],
1426  # 'to_table=%s' % layer[2] + '_' + self.extension])
1427 
1428  # copy all georectified vectors from source location to current location
1429  for name in self.VectGRList:
1430  xyvpath = os.path.join(self.grassdatabase,
1431  self.xylocation,
1432  self.xymapset,
1433  'vector',
1434  name)
1435  vpath = os.path.join(self.grassdatabase,
1436  self.currentlocation,
1437  self.currentmapset,
1438  'vector',
1439  name)
1440 
1441  if os.path.isdir(vpath):
1442  self.parent.goutput.WriteWarning(_('Vector map <%s> already exists. '
1443  'Change extension name and '
1444  'georectify again.') % self.outname)
1445  break
1446  else:
1447  # use shutil.copytree() because shutil.move() deletes src dir
1448  shutil.copytree(xyvpath, vpath)
1449 
1450  # TODO: connect vectors to copied tables with v.db.connect
1451 
1452  GMessage(_('For all vector maps georectified successfully,') + '\n' +
1453  _('you will need to copy any attribute tables') + '\n' +
1454  _('and reconnect them to the georectified vectors'),
1455  parent = self)
1456 
1457  self.grwiz.SwitchEnv('target')
1458 
1459  def OnGeorectDone(self, **kargs):
1460  """!Print final message"""
1461  global maptype
1462  if maptype == 'cell':
1463  return
1464 
1465  returncode = kargs['returncode']
1466 
1467  if returncode == 0:
1468  self.VectGRList.append(self.outname)
1469  print '*****vector list = ' + str(self.VectGRList)
1470  else:
1471  self.parent.goutput.WriteError(_('Georectification of vector map <%s> failed') %
1472  self.outname)
1473 
1474 
1475  def OnSettings(self, event):
1476  """!GCP Manager settings"""
1477  dlg = GrSettingsDialog(parent=self, id=wx.ID_ANY, title=_('GCP Manager settings'))
1478 
1479  if dlg.ShowModal() == wx.ID_OK:
1480  pass
1481 
1482  dlg.Destroy()
1483 
1484  def UpdateColours(self, srcrender=False, srcrenderVector=False,
1485  tgtrender=False, tgtrenderVector=False):
1486  """!update colours"""
1487  highest_fwd_err = 0.0
1488  self.highest_key = 0
1489  highest_idx = 0
1490 
1491  for index in range(self.list.GetItemCount()):
1492  if self.list.IsChecked(index):
1493  key = self.list.GetItemData(index)
1494  fwd_err = self.mapcoordlist[key][5]
1495 
1496  if self.highest_only == True:
1497  self.list.SetItemTextColour(index, wx.BLACK)
1498  if highest_fwd_err < fwd_err:
1499  highest_fwd_err = fwd_err
1500  self.highest_key = key
1501  highest_idx = index
1502  elif self.rmsthresh > 0:
1503  if (fwd_err > self.rmsthresh):
1504  self.list.SetItemTextColour(index, wx.RED)
1505  else:
1506  self.list.SetItemTextColour(index, wx.BLACK)
1507  else:
1508  self.list.SetItemTextColour(index, wx.BLACK)
1509 
1510  if self.highest_only and highest_fwd_err > 0.0:
1511  self.list.SetItemTextColour(highest_idx, wx.RED)
1512 
1513  sourceMapWin = self.SrcMapWindow
1514  sourceMapWin.UpdateMap(render=srcrender, renderVector=srcrenderVector)
1515  if self.show_target:
1516  targetMapWin = self.TgtMapWindow
1517  targetMapWin.UpdateMap(render=tgtrender, renderVector=tgtrenderVector)
1518 
1519  def OnQuit(self, event):
1520  """!Quit georectifier"""
1521  ret = wx.MessageBox(parent=self,
1522  caption=_("Quit GCP Manager"),
1523  message=_('Save ground control points?'),
1524  style=wx.ICON_QUESTION | wx.YES_NO | wx.CANCEL | wx.CENTRE)
1525 
1526  if ret != wx.CANCEL:
1527  if ret == wx.YES:
1528  self.SaveGCPs(None)
1529  elif ret == wx.NO:
1530  # restore POINTS file from backup
1531  if os.path.exists(self.file['points_bak']):
1532  shutil.copy(self.file['points_bak'], self.file['points'])
1533 
1534  if os.path.exists(self.file['points_bak']):
1535  os.unlink(self.file['points_bak'])
1536 
1537  self.SrcMap.Clean()
1538  self.TgtMap.Clean()
1539 
1540  self.grwiz.Cleanup()
1541 
1542  self.Destroy()
1543 
1544  #event.Skip()
1545 
1546  def OnGROrder(self, event):
1547  """
1548  sets transformation order for georectifying
1549  """
1550  if event:
1551  self.gr_order = event.GetInt() + 1
1552 
1553  numOfItems = self.list.GetItemCount()
1554  minNumOfItems = numOfItems
1555 
1556  if self.gr_order == 1:
1557  minNumOfItems = 3
1558  # self.SetStatusText(_('Insufficient points, 3+ points needed for 1st order'))
1559 
1560  elif self.gr_order == 2:
1561  minNumOfItems = 6
1562  diff = 6 - numOfItems
1563  # self.SetStatusText(_('Insufficient points, 6+ points needed for 2nd order'))
1564 
1565  elif self.gr_order == 3:
1566  minNumOfItems = 10
1567  # self.SetStatusText(_('Insufficient points, 10+ points needed for 3rd order'))
1568 
1569  for i in range(minNumOfItems - numOfItems):
1570  self.AddGCP(None)
1571 
1572  return minNumOfItems
1573 
1574  def RMSError(self, xygroup, order):
1575  """
1576  Uses g.transform to calculate forward and backward error for each used GCP
1577  in POINTS file and insert error values into GCP list.
1578  Calculates total forward and backward RMS error for all used points
1579  """
1580  # save GCPs to points file to make sure that all checked GCPs are used
1581  self.SaveGCPs(None)
1582  #self.SetStatusText('')
1583 
1584  if self.CheckGCPcount(msg=True) == False:
1585  return
1586 
1587  # get list of forward and reverse rms error values for each point
1588  self.grwiz.SwitchEnv('source')
1589 
1590  ret = RunCommand('g.transform',
1591  parent = self,
1592  read = True,
1593  group = xygroup,
1594  order = order)
1595 
1596  self.grwiz.SwitchEnv('target')
1597 
1598  if ret:
1599  errlist = ret.splitlines()
1600  else:
1601  GError(parent = self,
1602  message=_('Could not calculate RMS Error.\n'
1603  'Possible error with g.transform.'))
1604  return
1605 
1606  # insert error values into GCP list for checked items
1607  sdfactor = float(UserSettings.Get(group='gcpman', key='rms', subkey='sdfactor'))
1608  GCPcount = 0
1609  sumsq_fwd_err = 0.0
1610  sumsq_bkw_err = 0.0
1611  sum_fwd_err = 0.0
1612  highest_fwd_err = 0.0
1613  self.highest_key = 0
1614  highest_idx = 0
1615 
1616  for index in range(self.list.GetItemCount()):
1617  key = self.list.GetItemData(index)
1618  if self.list.IsChecked(index):
1619  fwd_err, bkw_err = errlist[GCPcount].split()
1620  self.list.SetStringItem(index, 5, fwd_err)
1621  self.list.SetStringItem(index, 6, bkw_err)
1622  self.mapcoordlist[key][5] = float(fwd_err)
1623  self.mapcoordlist[key][6] = float(bkw_err)
1624  self.list.SetItemTextColour(index, wx.BLACK)
1625  if self.highest_only:
1626  if highest_fwd_err < float(fwd_err):
1627  highest_fwd_err = float(fwd_err)
1628  self.highest_key = key
1629  highest_idx = index
1630 
1631  sumsq_fwd_err += float(fwd_err)**2
1632  sumsq_bkw_err += float(bkw_err)**2
1633  sum_fwd_err += float(fwd_err)
1634  GCPcount += 1
1635  else:
1636  self.list.SetStringItem(index, 5, '')
1637  self.list.SetStringItem(index, 6, '')
1638  self.mapcoordlist[key][5] = 0.0
1639  self.mapcoordlist[key][6] = 0.0
1640  self.list.SetItemTextColour(index, wx.BLACK)
1641 
1642  # SD
1643  if GCPcount > 0:
1644  sum_fwd_err /= GCPcount
1645  self.rmsmean = sum_fwd_err /GCPcount
1646  self.rmssd = (((sumsq_fwd_err/GCPcount) - self.rmsmean**2)**0.5)
1647  self.rmsthresh = self.rmsmean + sdfactor * self.rmssd
1648  else:
1649  self.rmsthresh = 0
1650  self.rmsmean = 0
1651  self.rmssd = 0
1652 
1653  if self.highest_only and highest_fwd_err > 0.0:
1654  self.list.SetItemTextColour(highest_idx, wx.RED)
1655  elif GCPcount > 0 and self.rmsthresh > 0 and not self.highest_only:
1656  for index in range(self.list.GetItemCount()):
1657  if self.list.IsChecked(index):
1658  key = self.list.GetItemData(index)
1659  if (self.mapcoordlist[key][5] > self.rmsthresh):
1660  self.list.SetItemTextColour(index, wx.RED)
1661 
1662  # calculate global RMS error (geometric mean)
1663  self.fwd_rmserror = round((sumsq_fwd_err/GCPcount)**0.5,4)
1664  self.bkw_rmserror = round((sumsq_bkw_err/GCPcount)**0.5,4)
1665  self.list.ResizeColumns()
1666 
1667  def GetNewExtent(self, region, map = None):
1668 
1669  coord_file = utils.GetTempfile()
1670  newreg = { 'n' : 0.0, 's' : 0.0, 'e' : 0.0, 'w' : 0.0,}
1671 
1672  try:
1673  f = open(coord_file, mode='w')
1674  # NW corner
1675  f.write(str(region['e']) + " " + str(region['n']) + "\n")
1676  # NE corner
1677  f.write(str(region['e']) + " " + str(region['s']) + "\n")
1678  # SW corner
1679  f.write(str(region['w']) + " " + str(region['n']) + "\n")
1680  # SE corner
1681  f.write(str(region['w']) + " " + str(region['s']) + "\n")
1682  finally:
1683  f.close()
1684 
1685  # save GCPs to points file to make sure that all checked GCPs are used
1686  self.SaveGCPs(None)
1687 
1688  order = self.gr_order
1689  self.gr_order = 1
1690 
1691  if self.CheckGCPcount(msg=True) == False:
1692  self.gr_order = order
1693  return
1694 
1695  self.gr_order = order
1696 
1697  # get list of forward and reverse rms error values for each point
1698  self.grwiz.SwitchEnv('source')
1699 
1700  if map == 'source':
1701  ret = RunCommand('g.transform',
1702  parent = self,
1703  read = True,
1704  group = self.xygroup,
1705  order = 1,
1706  format = 'dst',
1707  coords = coord_file)
1708 
1709  elif map == 'target':
1710  ret = RunCommand('g.transform',
1711  parent = self,
1712  read = True,
1713  group = self.xygroup,
1714  order = 1,
1715  flags = 'r',
1716  format = 'src',
1717  coords = coord_file)
1718 
1719  os.unlink(coord_file)
1720 
1721  self.grwiz.SwitchEnv('target')
1722 
1723  if ret:
1724  errlist = ret.splitlines()
1725  else:
1726  GError(parent = self,
1727  message=_('Could not calculate new extends.\n'
1728  'Possible error with g.transform.'))
1729  return
1730 
1731  # fist corner
1732  e, n = errlist[0].split()
1733  fe = float(e)
1734  fn = float(n)
1735  newreg['n'] = fn
1736  newreg['s'] = fn
1737  newreg['e'] = fe
1738  newreg['w'] = fe
1739  # other three corners
1740  for i in range(1, 4):
1741  e, n = errlist[i].split()
1742  fe = float(e)
1743  fn = float(n)
1744  if fe < newreg['w']:
1745  newreg['w'] = fe
1746  if fe > newreg['e']:
1747  newreg['e'] = fe
1748  if fn < newreg['s']:
1749  newreg['s'] = fn
1750  if fn > newreg['n']:
1751  newreg['n'] = fn
1752 
1753  return newreg
1754 
1755  def OnHelp(self, event):
1756  """!Show GCP Manager manual page"""
1757  cmdlist = ['g.manual', 'entry=wxGUI.GCP_Manager']
1758  self.parent.goutput.RunCmd(cmdlist, compReg=False,
1759  switchPage=False)
1760 
1761  def OnUpdateActive(self, event):
1762 
1763  if self.activemap.GetSelection() == 0:
1764  self.MapWindow = self.SrcMapWindow
1765  self.Map = self.SrcMap
1766  else:
1767  self.MapWindow = self.TgtMapWindow
1768  self.Map = self.TgtMap
1769 
1770  self.UpdateActive(self.MapWindow)
1771  # for wingrass
1772  if os.name == 'nt':
1773  self.MapWindow.SetFocus()
1774 
1775  def UpdateActive(self, win):
1776 
1777  # optionally disable tool zoomback tool
1778  self.GetMapToolbar().Enable('zoomback', enable = (len(self.MapWindow.zoomhistory) > 1))
1779 
1780  if self.activemap.GetSelection() != (win == self.TgtMapWindow):
1781  self.activemap.SetSelection(win == self.TgtMapWindow)
1782  self.StatusbarUpdate()
1783 
1784  def AdjustMap(self, newreg):
1785  """!Adjust map window to new extents
1786  """
1787 
1788  # adjust map window
1789  self.Map.region['n'] = newreg['n']
1790  self.Map.region['s'] = newreg['s']
1791  self.Map.region['e'] = newreg['e']
1792  self.Map.region['w'] = newreg['w']
1793 
1794  self.MapWindow.ZoomHistory(self.Map.region['n'], self.Map.region['s'],
1795  self.Map.region['e'], self.Map.region['w'])
1796 
1797  # LL locations
1798  if self.Map.projinfo['proj'] == 'll':
1799  if newreg['n'] > 90.0:
1800  newreg['n'] = 90.0
1801  if newreg['s'] < -90.0:
1802  newreg['s'] = -90.0
1803 
1804  ce = newreg['w'] + (newreg['e'] - newreg['w']) / 2
1805  cn = newreg['s'] + (newreg['n'] - newreg['s']) / 2
1806 
1807  # calculate new center point and display resolution
1808  self.Map.region['center_easting'] = ce
1809  self.Map.region['center_northing'] = cn
1810  self.Map.region["ewres"] = (newreg['e'] - newreg['w']) / self.Map.width
1811  self.Map.region["nsres"] = (newreg['n'] - newreg['s']) / self.Map.height
1812  self.Map.AlignExtentFromDisplay()
1813 
1814  self.MapWindow.ZoomHistory(self.Map.region['n'], self.Map.region['s'],
1815  self.Map.region['e'], self.Map.region['w'])
1816 
1817  if self.MapWindow.redrawAll is False:
1818  self.MapWindow.redrawAll = True
1819 
1820  self.MapWindow.UpdateMap()
1821  self.StatusbarUpdate()
1822 
1823  def OnZoomToSource(self, event):
1824  """!Set target map window to match extents of source map window
1825  """
1826 
1827  if not self.MapWindow == self.TgtMapWindow:
1828  self.MapWindow = self.TgtMapWindow
1829  self.Map = self.TgtMap
1830  self.UpdateActive(self.TgtMapWindow)
1831 
1832  # get new N, S, E, W for target
1833  newreg = self.GetNewExtent(self.SrcMap.region, 'source')
1834  if newreg:
1835  self.AdjustMap(newreg)
1836 
1837  def OnZoomToTarget(self, event):
1838  """!Set source map window to match extents of target map window
1839  """
1840 
1841  if not self.MapWindow == self.SrcMapWindow:
1842  self.MapWindow = self.SrcMapWindow
1843  self.Map = self.SrcMap
1844  self.UpdateActive(self.SrcMapWindow)
1845 
1846  # get new N, S, E, W for target
1847  newreg = self.GetNewExtent(self.TgtMap.region, 'target')
1848  if newreg:
1849  self.AdjustMap(newreg)
1850 
1851  def OnZoomMenuGCP(self, event):
1852  """!Popup Zoom menu
1853  """
1854  point = wx.GetMousePosition()
1855  zoommenu = wx.Menu()
1856  # Add items to the menu
1857 
1858  zoomsource = wx.MenuItem(zoommenu, wx.ID_ANY, _('Adjust source display to target display'))
1859  zoommenu.AppendItem(zoomsource)
1860  self.Bind(wx.EVT_MENU, self.OnZoomToTarget, zoomsource)
1861 
1862  zoomtarget = wx.MenuItem(zoommenu, wx.ID_ANY, _('Adjust target display to source display'))
1863  zoommenu.AppendItem(zoomtarget)
1864  self.Bind(wx.EVT_MENU, self.OnZoomToSource, zoomtarget)
1865 
1866  # Popup the menu. If an item is selected then its handler
1867  # will be called before PopupMenu returns.
1868  self.PopupMenu(zoommenu)
1869  zoommenu.Destroy()
1870 
1871  def OnDispResize(self, event):
1872  """!GCP Map Display resized, adjust Map Windows
1873  """
1874  if self.GetMapToolbar():
1875  srcwidth, srcheight = self.SrcMapWindow.GetSize()
1876  tgtwidth, tgtheight = self.TgtMapWindow.GetSize()
1877  srcwidth = (srcwidth + tgtwidth) / 2
1878  self._mgr.GetPane("target").Hide()
1879  self._mgr.Update()
1880  self._mgr.GetPane("source").BestSize((srcwidth, srcheight))
1881  self._mgr.GetPane("target").BestSize((srcwidth, tgtheight))
1882  if self.show_target:
1883  self._mgr.GetPane("target").Show()
1884  self._mgr.Update()
1885  pass
1886 
1887 class GCPList(wx.ListCtrl,
1888  CheckListCtrlMixin,
1889  ListCtrlAutoWidthMixin):
1890 
1891  def __init__(self, parent, gcp, id=wx.ID_ANY,
1892  pos=wx.DefaultPosition, size=wx.DefaultSize,
1893  style=wx.LC_REPORT | wx.SUNKEN_BORDER | wx.LC_HRULES |
1894  wx.LC_SINGLE_SEL):
1895 
1896  wx.ListCtrl.__init__(self, parent, id, pos, size, style)
1897 
1898  self.gcp = gcp # GCP class
1899  self.render = True
1900 
1901  # Mixin settings
1902  CheckListCtrlMixin.__init__(self)
1903  ListCtrlAutoWidthMixin.__init__(self)
1904  # TextEditMixin.__init__(self)
1905 
1906  # tracks whether list items are checked or not
1907  self.CheckList = []
1908 
1909  self._Create()
1910 
1911  self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected)
1912  self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.OnItemActivated)
1913  self.Bind(wx.EVT_LIST_COL_CLICK, self.OnColClick)
1914 
1915  self.selected = wx.NOT_FOUND
1916  self.selectedkey = -1
1917 
1918  def _Create(self):
1919 
1920  if 0:
1921  # normal, simple columns
1922  idx_col = 0
1923  for col in (_('use'),
1924  _('source E'),
1925  _('source N'),
1926  _('target E'),
1927  _('target N'),
1928  _('Forward error'),
1929  _('Backward error')):
1930  self.InsertColumn(idx_col, col)
1931  idx_col += 1
1932  else:
1933  # the hard way: we want images on the column header
1934  info = wx.ListItem()
1935  info.SetMask(wx.LIST_MASK_TEXT | wx.LIST_MASK_IMAGE | wx.LIST_MASK_FORMAT)
1936  info.SetImage(-1)
1937  info.m_format = wx.LIST_FORMAT_LEFT
1938 
1939  idx_col = 0
1940  for lbl in (_('use'),
1941  _('source E'),
1942  _('source N'),
1943  _('target E'),
1944  _('target N'),
1945  _('Forward error'),
1946  _('Backward error')):
1947  info.SetText(lbl)
1948  self.InsertColumnInfo(idx_col, info)
1949  idx_col += 1
1950 
1951  def LoadData(self):
1952  """!Load data into list"""
1953  self.DeleteAllItems()
1954 
1955  self.render = False
1956  if os.path.isfile(self.gcp.file['points']):
1957  self.gcp.ReadGCPs()
1958  else:
1959  # 3 gcp is minimum
1960  for i in range(3):
1961  self.gcp.AddGCP(None)
1962 
1963  # select first point by default
1964  self.selected = 0
1965  self.selectedkey = self.GetItemData(self.selected)
1966  self.SetItemState(self.selected,
1967  wx.LIST_STATE_SELECTED,
1968  wx.LIST_STATE_SELECTED)
1969 
1970  self.ResizeColumns()
1971  self.render = True
1972 
1973  self.EnsureVisible(self.selected)
1974 
1975  def OnCheckItem(self, index, flag):
1976  """!Item is checked/unchecked"""
1977 
1978  if self.render:
1979  # redraw points
1980  sourceMapWin = self.gcp.SrcMapWindow
1981  sourceMapWin.UpdateMap(render=False, renderVector=False)
1982  if self.gcp.show_target:
1983  targetMapWin = self.gcp.TgtMapWindow
1984  targetMapWin.UpdateMap(render=False, renderVector=False)
1985 
1986  pass
1987 
1988  def AddGCPItem(self):
1989  """
1990  Appends an item to GCP list
1991  """
1992  self.selectedkey = self.GetItemCount() + 1
1993 
1994  self.Append([str(self.selectedkey), # GCP number
1995  '0.0', # source E
1996  '0.0', # source N
1997  '0.0', # target E
1998  '0.0', # target N
1999  '', # forward error
2000  '']) # backward error
2001 
2002  self.selected = self.GetItemCount() - 1
2003  self.SetItemData(self.selected, self.selectedkey)
2004 
2005  self.SetItemState(self.selected,
2006  wx.LIST_STATE_SELECTED,
2007  wx.LIST_STATE_SELECTED)
2008 
2009  self.ResizeColumns()
2010 
2011  self.EnsureVisible(self.selected)
2012 
2013  return self.selected
2014 
2015  def DeleteGCPItem(self):
2016  """
2017  Deletes selected item in GCP list
2018  """
2019  if self.selected == wx.NOT_FOUND:
2020  return
2021 
2022  key = self.GetItemData(self.selected)
2023  self.DeleteItem(self.selected)
2024 
2025  return key
2026 
2027  def ResizeColumns(self):
2028  """!Resize columns"""
2029  minWidth = [90, 120]
2030  for i in range(self.GetColumnCount()):
2031  self.SetColumnWidth(i, wx.LIST_AUTOSIZE)
2032  # first column is checkbox, don't set to minWidth
2033  if i > 0 and self.GetColumnWidth(i) < minWidth[i > 4]:
2034  self.SetColumnWidth(i, minWidth[i > 4])
2035 
2036  self.SendSizeEvent()
2037 
2038  def GetSelected(self):
2039  """!Get index of selected item"""
2040  return self.selected
2041 
2042  def OnItemSelected(self, event):
2043  """
2044  Item selected
2045  """
2046 
2047  if self.render and self.selected != event.GetIndex():
2048  self.selected = event.GetIndex()
2049  self.selectedkey = self.GetItemData(self.selected)
2050  sourceMapWin = self.gcp.SrcMapWindow
2051  sourceMapWin.UpdateMap(render=False, renderVector=False)
2052  if self.gcp.show_target:
2053  targetMapWin = self.gcp.TgtMapWindow
2054  targetMapWin.UpdateMap(render=False, renderVector=False)
2055 
2056  event.Skip()
2057 
2058  def OnItemActivated(self, event):
2059  """
2060  When item double clicked, open editor to update coordinate values
2061  """
2062  coords = []
2063  index = event.GetIndex()
2064  key = self.GetItemData(index)
2065  changed = False
2066 
2067  for i in range(1, 5):
2068  coords.append(self.GetItem(index, i).GetText())
2069 
2070  dlg = EditGCP(parent=self, id=wx.ID_ANY, data=coords, gcpno=key)
2071 
2072  if dlg.ShowModal() == wx.ID_OK:
2073  values = dlg.GetValues() # string
2074 
2075  if len(values) == 0:
2076  GError(parent = self,
2077  message=_("Invalid coordinate value. Operation canceled."))
2078  else:
2079  for i in range(len(values)):
2080  if values[i] != coords[i]:
2081  self.SetStringItem(index, i + 1, values[i])
2082  changed = True
2083 
2084  if changed:
2085  # reset RMS and update mapcoordlist
2086  self.SetStringItem(index, 5, '')
2087  self.SetStringItem(index, 6, '')
2088  key = self.GetItemData(index)
2089  self.gcp.mapcoordlist[key] = [key,
2090  float(values[0]),
2091  float(values[1]),
2092  float(values[2]),
2093  float(values[3]),
2094  0.0,
2095  0.0]
2096  self.gcp.UpdateColours()
2097 
2098  def OnColClick(self, event):
2099  """!ListCtrl forgets selected item..."""
2100  self.selected = self.FindItemData(-1, self.selectedkey)
2101  self.SetItemState(self.selected,
2102  wx.LIST_STATE_SELECTED,
2103  wx.LIST_STATE_SELECTED)
2104  event.Skip()
2105 
2106 class VectGroup(wx.Dialog):
2107  """
2108  Dialog to create a vector group (VREF file) for georectifying
2109 
2110  @todo Replace by g.group
2111  """
2112  def __init__(self, parent, id, grassdb, location, mapset, group,
2113  style=wx.DEFAULT_DIALOG_STYLE):
2114 
2115  wx.Dialog.__init__(self, parent, id, style=style,
2116  title = _("Create vector map group"))
2117 
2118  self.grassdatabase = grassdb
2119  self.xylocation = location
2120  self.xymapset = mapset
2121  self.xygroup = group
2122 
2123  #
2124  # get list of valid vector directories
2125  #
2126  vectlist = os.listdir(os.path.join(self.grassdatabase,
2127  self.xylocation,
2128  self.xymapset,
2129  'vector'))
2130  for dir in vectlist:
2131  if not os.path.isfile(os.path.join(self.grassdatabase,
2132  self.xylocation,
2133  self.xymapset,
2134  'vector',
2135  dir,
2136  'coor')):
2137  vectlist.remove(dir)
2138 
2139  utils.ListSortLower(vectlist)
2140 
2141  # path to vref file
2142  self.vgrpfile = os.path.join(self.grassdatabase,
2143  self.xylocation,
2144  self.xymapset,
2145  'group',
2146  self.xygroup,
2147  'VREF')
2148 
2149  #
2150  # buttons
2151  #
2152  self.btnCancel = wx.Button(parent = self,
2153  id = wx.ID_CANCEL)
2154  self.btnOK = wx.Button(parent = self,
2155  id = wx.ID_OK)
2156  self.btnOK.SetDefault()
2157 
2158 
2159  #
2160  # list of vector maps
2161  #
2162  self.listMap = wx.CheckListBox(parent = self, id = wx.ID_ANY,
2163  choices = vectlist)
2164 
2165  if os.path.isfile(self.vgrpfile):
2166  f = open(self.vgrpfile)
2167  try:
2168  checked = []
2169  for line in f.readlines():
2170  line = line.replace('\n', '')
2171  if len(line) < 1:
2172  continue
2173  checked.append(line)
2174  self.listMap.SetCheckedStrings(checked)
2175  finally:
2176  f.close()
2177 
2178  line = wx.StaticLine(parent = self,
2179  id = wx.ID_ANY, size = (20, -1),
2180  style = wx.LI_HORIZONTAL)
2181 
2182  #
2183  # layout
2184  #
2185  sizer = wx.BoxSizer(wx.VERTICAL)
2186 
2187  box = wx.BoxSizer(wx.HORIZONTAL)
2188  box.Add(item = wx.StaticText(parent = self, id = wx.ID_ANY,
2189  label = _('Select vector map(s) to add to group:')),
2190  flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT | wx.LEFT,
2191  border = 5)
2192 
2193  box.Add(item = self.listMap,
2194  flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT | wx.LEFT,
2195  border = 5)
2196 
2197 
2198  sizer.Add(box, flag = wx.ALIGN_RIGHT | wx.ALL,
2199  border = 3)
2200 
2201  sizer.Add(item = line, proportion = 0,
2202  flag = wx.GROW | wx.ALIGN_CENTER_VERTICAL | wx.LEFT | wx.RIGHT,
2203  border = 5)
2204 
2205  # buttons
2206  btnSizer = wx.StdDialogButtonSizer()
2207  btnSizer.AddButton(self.btnCancel)
2208  btnSizer.AddButton(self.btnOK)
2209  btnSizer.Realize()
2210 
2211  sizer.Add(item = btnSizer, proportion = 0,
2212  flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER,
2213  border = 5)
2214 
2215  self.SetSizer(sizer)
2216  sizer.Fit(self)
2217  self.Layout()
2218 
2219  def MakeVGroup(self):
2220  """!Create VREF file"""
2221  vgrouplist = []
2222  for item in range(self.listMap.GetCount()):
2223  if not self.listMap.IsChecked(item):
2224  continue
2225  vgrouplist.append(self.listMap.GetString(item))
2226 
2227  f = open(self.vgrpfile, mode='w')
2228  try:
2229  for vect in vgrouplist:
2230  f.write(vect + '\n')
2231  finally:
2232  f.close()
2233 
2234 class EditGCP(wx.Dialog):
2235  def __init__(self, parent, data, gcpno, id=wx.ID_ANY,
2236  title=_("Edit GCP"),
2237  style=wx.DEFAULT_DIALOG_STYLE):
2238  """!Dialog for editing GPC and map coordinates in list control"""
2239 
2240  wx.Dialog.__init__(self, parent, id, title=title, style=style)
2241 
2242  panel = wx.Panel(parent=self)
2243 
2244  sizer = wx.BoxSizer(wx.VERTICAL)
2245 
2246  box = wx.StaticBox (parent=panel, id=wx.ID_ANY,
2247  label=" %s %s " % (_("Ground Control Point No."), str(gcpno)))
2248  boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
2249 
2250  # source coordinates
2251  gridSizer = wx.GridBagSizer(vgap=5, hgap=5)
2252 
2253  self.xcoord = wx.TextCtrl(parent=panel, id=wx.ID_ANY, size=(150, -1))
2254  self.ycoord = wx.TextCtrl(parent=panel, id=wx.ID_ANY, size=(150, -1))
2255  self.ecoord = wx.TextCtrl(parent=panel, id=wx.ID_ANY, size=(150, -1))
2256  self.ncoord = wx.TextCtrl(parent=panel, id=wx.ID_ANY, size=(150, -1))
2257 
2258  # swap source N, target E
2259  tmp_coord = data[1]
2260  data[1] = data[2]
2261  data[2] = tmp_coord
2262 
2263  row = 0
2264  col = 0
2265  idx = 0
2266  for label, win in ((_("source E:"), self.xcoord),
2267  (_("target E:"), self.ecoord),
2268  (_("source N:"), self.ycoord),
2269  (_("target N:"), self.ncoord)):
2270  label = wx.StaticText(parent=panel, id=wx.ID_ANY,
2271  label=label)
2272  gridSizer.Add(item=label,
2273  flag=wx.ALIGN_CENTER_VERTICAL,
2274  pos=(row, col))
2275 
2276  col += 1
2277  win.SetValue(str(data[idx]))
2278 
2279  gridSizer.Add(item=win,
2280  pos=(row, col))
2281 
2282  col += 1
2283  idx += 1
2284 
2285  if col > 3:
2286  row += 1
2287  col = 0
2288 
2289  boxSizer.Add(item=gridSizer, proportion=1,
2290  flag=wx.EXPAND | wx.ALL, border=5)
2291 
2292  sizer.Add(item=boxSizer, proportion=1,
2293  flag=wx.EXPAND | wx.ALL, border=5)
2294 
2295  #
2296  # buttons
2297  #
2298  self.btnCancel = wx.Button(panel, wx.ID_CANCEL)
2299  self.btnOk = wx.Button(panel, wx.ID_OK)
2300  self.btnOk.SetDefault()
2301 
2302  btnSizer = wx.StdDialogButtonSizer()
2303  btnSizer.AddButton(self.btnCancel)
2304  btnSizer.AddButton(self.btnOk)
2305  btnSizer.Realize()
2306 
2307  sizer.Add(item=btnSizer, proportion=0,
2308  flag=wx.ALIGN_RIGHT | wx.ALL, border=5)
2309 
2310  panel.SetSizer(sizer)
2311  sizer.Fit(self)
2312 
2313  def GetValues(self, columns=None):
2314  """!Return list of values (as strings).
2315  """
2316  valuelist = []
2317  try:
2318  float(self.xcoord.GetValue())
2319  float(self.ycoord.GetValue())
2320  float(self.ecoord.GetValue())
2321  float(self.ncoord.GetValue())
2322  except ValueError:
2323  return valuelist
2324 
2325  valuelist.append(self.xcoord.GetValue())
2326  valuelist.append(self.ycoord.GetValue())
2327  valuelist.append(self.ecoord.GetValue())
2328  valuelist.append(self.ncoord.GetValue())
2329 
2330  return valuelist
2331 
2332 class GrSettingsDialog(wx.Dialog):
2333  def __init__(self, parent, id, title, pos=wx.DefaultPosition, size=wx.DefaultSize,
2334  style=wx.DEFAULT_DIALOG_STYLE):
2335  wx.Dialog.__init__(self, parent, id, title, pos, size, style)
2336  """
2337  Dialog to set profile text options: font, title
2338  and font size, axis labels and font size
2339  """
2340  #
2341  # initialize variables
2342  #
2343  self.parent = parent
2344  self.new_src_map = src_map
2345  self.new_tgt_map = tgt_map
2346  self.sdfactor = 0
2347 
2348  self.symbol = {}
2349 
2350  self.methods = ["nearest",
2351  "bilinear",
2352  "bilinear_f",
2353  "cubic",
2354  "cubic_f"]
2355 
2356  # notebook
2357  notebook = wx.Notebook(parent=self, id=wx.ID_ANY, style=wx.BK_DEFAULT)
2358  self.__CreateSymbologyPage(notebook)
2359  self.__CreateRectificationPage(notebook)
2360 
2361  # buttons
2362  btnSave = wx.Button(self, wx.ID_SAVE)
2363  btnApply = wx.Button(self, wx.ID_APPLY)
2364  btnClose = wx.Button(self, wx.ID_CLOSE)
2365  btnApply.SetDefault()
2366 
2367  # bindings
2368  btnApply.Bind(wx.EVT_BUTTON, self.OnApply)
2369  btnApply.SetToolTipString(_("Apply changes for the current session"))
2370  btnSave.Bind(wx.EVT_BUTTON, self.OnSave)
2371  btnSave.SetToolTipString(_("Apply and save changes to user settings file (default for next sessions)"))
2372  btnClose.Bind(wx.EVT_BUTTON, self.OnClose)
2373  btnClose.SetToolTipString(_("Close dialog"))
2374 
2375  # sizers
2376  btnSizer = wx.BoxSizer(wx.HORIZONTAL)
2377  btnSizer.Add(btnApply, flag=wx.LEFT | wx.RIGHT, border=5)
2378  btnSizer.Add(btnSave, flag=wx.LEFT | wx.RIGHT, border=5)
2379  btnSizer.Add(btnClose, flag=wx.LEFT | wx.RIGHT, border=5)
2380 
2381  # sizers
2382  mainSizer = wx.BoxSizer(wx.VERTICAL)
2383  mainSizer.Add(item=notebook, proportion=1, flag=wx.EXPAND | wx.ALL, border=5)
2384  mainSizer.Add(item=btnSizer, proportion=0,
2385  flag=wx.ALIGN_RIGHT | wx.ALL, border=5)
2386  # flag=wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border=5)
2387 
2388  self.SetSizer(mainSizer)
2389  mainSizer.Fit(self)
2390 
2391  def __CreateSymbologyPage(self, notebook):
2392  """!Create notebook page with symbology settings"""
2393 
2394  panel = wx.Panel(parent=notebook, id=wx.ID_ANY)
2395  notebook.AddPage(page=panel, text=_("Symbology"))
2396 
2397  sizer = wx.BoxSizer(wx.VERTICAL)
2398 
2399  rmsgridSizer = wx.GridBagSizer(vgap=5, hgap=5)
2400 
2401  # highlight only highest forward RMS error
2402  self.highlighthighest = wx.CheckBox(parent=panel, id=wx.ID_ANY,
2403  label=_("Highlight highest RMS error only"))
2404  hh = UserSettings.Get(group='gcpman', key='rms', subkey='highestonly')
2405  self.highlighthighest.SetValue(hh)
2406  rmsgridSizer.Add(item=self.highlighthighest, flag=wx.ALIGN_CENTER_VERTICAL, pos=(0, 0))
2407 
2408  # RMS forward error threshold
2409  rmslabel = wx.StaticText(parent=panel, id=wx.ID_ANY, label=_("Highlight RMS error > M + SD * factor:"))
2410  rmslabel.SetToolTip(wx.ToolTip(_("Highlight GCPs with an RMS error larger than \n"
2411  "mean + standard deviation * given factor. \n"
2412  "Recommended values for this factor are between 1 and 2.")))
2413  rmsgridSizer.Add(item=rmslabel, flag=wx.ALIGN_CENTER_VERTICAL, pos=(1, 0))
2414  sdfactor = UserSettings.Get(group='gcpman', key='rms', subkey='sdfactor')
2415  self.rmsWin = wx.TextCtrl(parent=panel, id=wx.ID_ANY,
2416  size=(70,-1), style=wx.TE_NOHIDESEL)
2417  self.rmsWin.SetValue("%s" % str(sdfactor))
2418  if (self.parent.highest_only == True):
2419  self.rmsWin.Disable()
2420 
2421  self.symbol['sdfactor'] = self.rmsWin.GetId()
2422  rmsgridSizer.Add(item=self.rmsWin, flag=wx.ALIGN_RIGHT, pos=(1, 1))
2423  rmsgridSizer.AddGrowableCol(1)
2424  sizer.Add(item=rmsgridSizer, flag=wx.EXPAND | wx.ALL, border=5)
2425 
2426  box = wx.StaticBox(parent=panel, id=wx.ID_ANY,
2427  label=" %s " % _("Symbol settings"))
2428  boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
2429  gridSizer = wx.GridBagSizer(vgap=5, hgap=5)
2430 
2431  #
2432  # general symbol color
2433  #
2434  row = 0
2435  label = wx.StaticText(parent=panel, id=wx.ID_ANY, label=_("Color:"))
2436  gridSizer.Add(item=label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
2437  col = UserSettings.Get(group='gcpman', key='symbol', subkey='color')
2438  colWin = csel.ColourSelect(parent=panel, id=wx.ID_ANY,
2439  colour=wx.Colour(col[0],
2440  col[1],
2441  col[2],
2442  255))
2443  self.symbol['color'] = colWin.GetId()
2444  gridSizer.Add(item=colWin,
2445  flag=wx.ALIGN_RIGHT,
2446  pos=(row, 1))
2447 
2448  #
2449  # symbol color for high forward RMS error
2450  #
2451  row += 1
2452  label = wx.StaticText(parent=panel, id=wx.ID_ANY, label=_("Color for high RMS error:"))
2453  gridSizer.Add(item=label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
2454  hcol = UserSettings.Get(group='gcpman', key='symbol', subkey='hcolor')
2455  hcolWin = csel.ColourSelect(parent=panel, id=wx.ID_ANY,
2456  colour=wx.Colour(hcol[0],
2457  hcol[1],
2458  hcol[2],
2459  255))
2460  self.symbol['hcolor'] = hcolWin.GetId()
2461  gridSizer.Add(item=hcolWin,
2462  flag=wx.ALIGN_RIGHT,
2463  pos=(row, 1))
2464 
2465  #
2466  # symbol color for selected GCP
2467  #
2468  row += 1
2469  label = wx.StaticText(parent=panel, id=wx.ID_ANY, label=_("Color for selected GCP:"))
2470  gridSizer.Add(item=label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
2471  scol = UserSettings.Get(group='gcpman', key='symbol', subkey='scolor')
2472  scolWin = csel.ColourSelect(parent=panel, id=wx.ID_ANY,
2473  colour=wx.Colour(scol[0],
2474  scol[1],
2475  scol[2],
2476  255))
2477  self.symbol['scolor'] = scolWin.GetId()
2478  gridSizer.Add(item=scolWin,
2479  flag=wx.ALIGN_RIGHT,
2480  pos=(row, 1))
2481 
2482  #
2483  # symbol color for unused GCP
2484  #
2485  row += 1
2486  label = wx.StaticText(parent=panel, id=wx.ID_ANY, label=_("Color for unused GCPs:"))
2487  gridSizer.Add(item=label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
2488  ucol = UserSettings.Get(group='gcpman', key='symbol', subkey='ucolor')
2489  ucolWin = csel.ColourSelect(parent=panel, id=wx.ID_ANY,
2490  colour=wx.Colour(ucol[0],
2491  ucol[1],
2492  ucol[2],
2493  255))
2494  self.symbol['ucolor'] = ucolWin.GetId()
2495  gridSizer.Add(item=ucolWin,
2496  flag=wx.ALIGN_RIGHT,
2497  pos=(row, 1))
2498 
2499  # show unused GCPs
2500  row += 1
2501  self.showunused = wx.CheckBox(parent=panel, id=wx.ID_ANY,
2502  label=_("Show unused GCPs"))
2503  shuu = UserSettings.Get(group='gcpman', key='symbol', subkey='unused')
2504  self.showunused.SetValue(shuu)
2505  gridSizer.Add(item=self.showunused, flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
2506 
2507  #
2508  # symbol size
2509  #
2510  row += 1
2511  label = wx.StaticText(parent=panel, id=wx.ID_ANY, label=_("Symbol size:"))
2512  gridSizer.Add(item=label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
2513  symsize = int(UserSettings.Get(group='gcpman', key='symbol', subkey='size'))
2514  sizeWin = wx.SpinCtrl(parent=panel, id=wx.ID_ANY,
2515  min=1, max=20)
2516  sizeWin.SetValue(symsize)
2517  self.symbol['size'] = sizeWin.GetId()
2518  gridSizer.Add(item=sizeWin,
2519  flag=wx.ALIGN_RIGHT,
2520  pos=(row, 1))
2521 
2522  #
2523  # symbol width
2524  #
2525  row += 1
2526  label = wx.StaticText(parent=panel, id=wx.ID_ANY, label=_("Line width:"))
2527  gridSizer.Add(item=label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
2528  width = int(UserSettings.Get(group='gcpman', key='symbol', subkey='width'))
2529  widWin = wx.SpinCtrl(parent=panel, id=wx.ID_ANY,
2530  min=1, max=10)
2531  widWin.SetValue(width)
2532  self.symbol['width'] = widWin.GetId()
2533  gridSizer.Add(item=widWin,
2534  flag=wx.ALIGN_RIGHT,
2535  pos=(row, 1))
2536  gridSizer.AddGrowableCol(1)
2537 
2538  boxSizer.Add(item=gridSizer, flag=wx.EXPAND)
2539  sizer.Add(item=boxSizer, flag=wx.EXPAND | wx.ALL, border=5)
2540 
2541  #
2542  # maps to display
2543  #
2544  # source map to display
2545  self.srcselection = Select(panel, id=wx.ID_ANY,
2546  size=globalvar.DIALOG_GSELECT_SIZE, type='cell', updateOnPopup = False)
2547  self.parent.grwiz.SwitchEnv('source')
2548  self.srcselection.SetElementList(maptype)
2549  # filter out all maps not in group
2550  self.srcselection.tcp.GetElementList(elements = self.parent.src_maps)
2551 
2552  # target map to display
2553  self.tgtselection = Select(panel, id=wx.ID_ANY,
2554  size=globalvar.DIALOG_GSELECT_SIZE, type='cell', updateOnPopup = False)
2555  self.parent.grwiz.SwitchEnv('target')
2556  self.tgtselection.SetElementList(maptype)
2557  self.tgtselection.GetElementList()
2558 
2559  sizer.Add(item=wx.StaticText(parent=panel, id=wx.ID_ANY, label=_('Select source map to display:')),
2560  proportion=0, flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5)
2561  sizer.Add(item=self.srcselection, proportion=0,
2562  flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5)
2563  self.srcselection.SetValue(src_map)
2564  sizer.Add(item=wx.StaticText(parent=panel, id=wx.ID_ANY, label=_('Select target map to display:')),
2565  proportion=0, flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5)
2566  sizer.Add(item=self.tgtselection, proportion=0,
2567  flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5)
2568  self.tgtselection.SetValue(tgt_map)
2569 
2570  # bindings
2571  self.highlighthighest.Bind(wx.EVT_CHECKBOX, self.OnHighlight)
2572  self.rmsWin.Bind(wx.EVT_TEXT, self.OnSDFactor)
2573  self.srcselection.Bind(wx.EVT_TEXT, self.OnSrcSelection)
2574  self.tgtselection.Bind(wx.EVT_TEXT, self.OnTgtSelection)
2575 
2576  panel.SetSizer(sizer)
2577 
2578  return panel
2579 
2580  def __CreateRectificationPage(self, notebook):
2581  """!Create notebook page with symbology settings"""
2582 
2583  panel = wx.Panel(parent=notebook, id=wx.ID_ANY)
2584  notebook.AddPage(page=panel, text=_("Rectification"))
2585 
2586  sizer = wx.BoxSizer(wx.VERTICAL)
2587 
2588  # transformation order
2589  self.rb_grorder = wx.RadioBox(parent=panel, id=wx.ID_ANY,
2590  label=" %s " % _("Select rectification order"),
2591  choices=[_('1st order'), _('2nd order'), _('3rd order')],
2592  majorDimension=wx.RA_SPECIFY_COLS)
2593  sizer.Add(item=self.rb_grorder, proportion=0,
2594  flag=wx.EXPAND | wx.ALL, border=5)
2595  self.rb_grorder.SetSelection(self.parent.gr_order - 1)
2596 
2597  # interpolation method
2598  gridSizer = wx.GridBagSizer(vgap=5, hgap=5)
2599  gridSizer.Add(item=wx.StaticText(parent=panel, id=wx.ID_ANY, label=_('Select interpolation method:')),
2600  pos=(0,0), flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5)
2601  self.grmethod = wx.Choice(parent=panel, id=wx.ID_ANY,
2602  choices = self.methods)
2603  gridSizer.Add(item=self.grmethod, pos=(0,1),
2604  flag=wx.ALIGN_RIGHT, border=5)
2605  self.grmethod.SetStringSelection(self.parent.gr_method)
2606  gridSizer.AddGrowableCol(1)
2607  sizer.Add(item=gridSizer, flag=wx.EXPAND | wx.ALL, border=5)
2608 
2609  # clip to region
2610  self.check = wx.CheckBox(parent=panel, id=wx.ID_ANY,
2611  label=_("clip to computational region in target location"))
2612  sizer.Add(item=self.check, proportion=0,
2613  flag=wx.EXPAND | wx.ALL, border=5)
2614  self.check.SetValue(self.parent.clip_to_region)
2615 
2616  # extension
2617  sizer.Add(item=wx.StaticText(parent=panel, id=wx.ID_ANY, label=_('Extension for output maps:')),
2618  proportion=0, flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5)
2619  self.ext_txt = wx.TextCtrl(parent=panel, id=wx.ID_ANY, value="", size=(350,-1))
2620  self.ext_txt.SetValue(self.parent.extension)
2621  sizer.Add(item=self.ext_txt,
2622  proportion=0, flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5)
2623 
2624  # bindings
2625  self.ext_txt.Bind(wx.EVT_TEXT, self.OnExtension)
2626  self.Bind(wx.EVT_RADIOBOX, self.parent.OnGROrder, self.rb_grorder)
2627  self.Bind(wx.EVT_CHOICE, self.OnMethod, self.grmethod)
2628  self.Bind(wx.EVT_CHECKBOX, self.OnClipRegion, self.check)
2629 
2630  panel.SetSizer(sizer)
2631 
2632  return panel
2633 
2634  def OnHighlight(self, event):
2635  """!Checkbox 'highlighthighest' checked/unchecked"""
2636  if self.highlighthighest.IsChecked():
2637  self.parent.highest_only = True
2638  self.rmsWin.Disable()
2639  else:
2640  self.parent.highest_only = False
2641  self.rmsWin.Enable()
2642 
2643  def OnSDFactor(self,event):
2644  """!New factor for RMS threshold = M + SD * factor"""
2645  try:
2646  self.sdfactor = float(self.rmsWin.GetValue())
2647  except ValueError:
2648  return
2649 
2650  if self.sdfactor <= 0:
2651  GError(parent = self,
2652  message=_('RMS threshold factor must be > 0'))
2653  elif self.sdfactor < 1:
2654  GError(parent = self,
2655  message=_('RMS threshold factor is < 1\n'
2656  'Too many points might be highlighted'))
2657 
2658  def OnSrcSelection(self,event):
2659  """!Source map to display selected"""
2660  global src_map
2661 
2662  tmp_map = self.srcselection.GetValue()
2663 
2664  if not tmp_map == '' and not tmp_map == src_map:
2665  self.new_src_map = tmp_map
2666 
2667  def OnTgtSelection(self,event):
2668  """!Target map to display selected"""
2669  global tgt_map
2670 
2671  tmp_map = self.tgtselection.GetValue()
2672 
2673  if not tmp_map == tgt_map:
2674  self.new_tgt_map = tmp_map
2675 
2676  def OnMethod(self, event):
2677  self.parent.gr_method = self.methods[event.GetSelection()]
2678 
2679  def OnClipRegion(self, event):
2680  self.parent.clip_to_region = event.IsChecked()
2681 
2682  def OnExtension(self, event):
2683  self.parent.extension = self.ext_txt.GetValue()
2684 
2685  def UpdateSettings(self):
2686  global src_map
2687  global tgt_map
2688 
2689  layers = None
2690 
2691  UserSettings.Set(group='gcpman', key='rms', subkey='highestonly',
2692  value=self.highlighthighest.GetValue())
2693  if self.sdfactor > 0:
2694  UserSettings.Set(group='gcpman', key='rms', subkey='sdfactor',
2695  value=self.sdfactor)
2696 
2697  self.parent.sdfactor = self.sdfactor
2698  if self.parent.rmsthresh > 0:
2699  self.parent.rmsthresh = self.parent.mean + self.parent.sdfactor * self.parent.rmssd
2700 
2701  UserSettings.Set(group='gcpman', key='symbol', subkey='color',
2702  value=tuple(wx.FindWindowById(self.symbol['color']).GetColour()))
2703  UserSettings.Set(group='gcpman', key='symbol', subkey='hcolor',
2704  value=tuple(wx.FindWindowById(self.symbol['hcolor']).GetColour()))
2705  UserSettings.Set(group='gcpman', key='symbol', subkey='scolor',
2706  value=tuple(wx.FindWindowById(self.symbol['scolor']).GetColour()))
2707  UserSettings.Set(group='gcpman', key='symbol', subkey='ucolor',
2708  value=tuple(wx.FindWindowById(self.symbol['ucolor']).GetColour()))
2709  UserSettings.Set(group='gcpman', key='symbol', subkey='unused',
2710  value=self.showunused.GetValue())
2711  UserSettings.Set(group='gcpman', key='symbol', subkey='size',
2712  value=wx.FindWindowById(self.symbol['size']).GetValue())
2713  UserSettings.Set(group='gcpman', key='symbol', subkey='width',
2714  value=wx.FindWindowById(self.symbol['width']).GetValue())
2715 
2716  srcrender = False
2717  srcrenderVector = False
2718  tgtrender = False
2719  tgtrenderVector = False
2720  if self.new_src_map != src_map:
2721  # remove old layer
2722  layers = self.parent.grwiz.SrcMap.GetListOfLayers()
2723  self.parent.grwiz.SrcMap.DeleteLayer(layers[0])
2724 
2725  src_map = self.new_src_map
2726  cmdlist = ['d.rast', 'map=%s' % src_map]
2727  self.parent.grwiz.SwitchEnv('source')
2728  name, found = utils.GetLayerNameFromCmd(cmdlist),
2729  self.parent.grwiz.SrcMap.AddLayer(type='raster', command=cmdlist, l_active=True,
2730  name=name, l_hidden=False, l_opacity=1.0, l_render=False)
2731 
2732  self.parent.grwiz.SwitchEnv('target')
2733  srcrender = True
2734 
2735  if self.new_tgt_map != tgt_map:
2736  # remove old layer
2737  layers = self.parent.grwiz.TgtMap.GetListOfLayers()
2738  if layers:
2739  self.parent.grwiz.TgtMap.DeleteLayer(layers[0])
2740  tgt_map = self.new_tgt_map
2741 
2742  if tgt_map != '':
2743  cmdlist = ['d.rast', 'map=%s' % tgt_map]
2744  name, found = utils.GetLayerNameFromCmd(cmdlist)
2745  self.parent.grwiz.TgtMap.AddLayer(type='raster', command=cmdlist, l_active=True,
2746  name=name, l_hidden=False, l_opacity=1.0, l_render=False)
2747 
2748  tgtrender = True
2749  if self.parent.show_target == False:
2750  self.parent.show_target = True
2751  self.parent._mgr.GetPane("target").Show()
2752  self.parent._mgr.Update()
2753  self.parent.GetMapToolbar().Enable('zoommenu', enable = True)
2754  self.parent.activemap.Enable()
2755  self.parent.TgtMapWindow.ZoomToMap(layers = self.parent.TgtMap.GetListOfLayers())
2756  else: # tgt_map == ''
2757  if self.parent.show_target == True:
2758  self.parent.show_target = False
2759  self.parent._mgr.GetPane("target").Hide()
2760  self.parent._mgr.Update()
2761  self.parent.activemap.SetSelection(0)
2762  self.parent.activemap.Enable(False)
2763  self.parent.GetMapToolbar().Enable('zoommenu', enable = False)
2764 
2765  self.parent.UpdateColours(srcrender, srcrenderVector, tgtrender, tgtrenderVector)
2766 
2767  def OnSave(self, event):
2768  """!Button 'Save' pressed"""
2769  self.UpdateSettings()
2770  fileSettings = {}
2771  UserSettings.ReadSettingsFile(settings=fileSettings)
2772  fileSettings['gcpman'] = UserSettings.Get(group='gcpman')
2773  file = UserSettings.SaveToFile(fileSettings)
2774  self.parent.parent.goutput.WriteLog(_('GCP Manager settings saved to file \'%s\'.') % file)
2775  #self.Close()
2776 
2777  def OnApply(self, event):
2778  """!Button 'Apply' pressed"""
2779  self.UpdateSettings()
2780  #self.Close()
2781 
2782  def OnClose(self, event):
2783  """!Button 'Cancel' pressed"""
2784  self.Close()
def OnMaptype
Change map type.
Definition: gcp/manager.py:349
def OnVGroup
Add vector maps to group.
Definition: gcp/manager.py:501
def OnSrcSelection
Source map to display selected.
Definition: gcp/manager.py:633
def GetValue
Definition: widgets.py:118
wxGUI command interface
def MakeVGroup
Create VREF file.
def OnZoomToTarget
Set source map window to match extents of target map window.
def AdjustMap
Adjust map window to new extents.
Manages ground control points for georectifying.
Definition: gcp/manager.py:713
def GetSelected
Get index of selected item.
Location wizard - creates a new GRASS Location.
def OnZoomMenuGCP
Popup Zoom menu.
def OnGeorectDone
Print final message.
def GetValues
Return list of values (as strings).
def OnSrcSelection
Source map to display selected.
def OnApply
Button &#39;Apply&#39; pressed.
def GetMapCoordList
Definition: gcp/manager.py:883
def OnHighlight
Checkbox &#39;highlighthighest&#39; checked/unchecked.
def OnTgtSelection
Target map to display selected.
Various dialogs used in wxGUI.
def OnQuit
Quit georectifier.
Custom control that selects elements.
Rendering map layers and overlays into map composition image.
def split
Platform spefic shlex.split.
Definition: core/utils.py:37
def ReloadGCPs
Reload data from file.
def getSmallDnArrowImage
Definition: gcp/manager.py:69
def OnCheckItem
Item is checked/unchecked.
def OnColClick
ListCtrl forgets selected item...
def OnGLMFocus
Layer Manager focus.
Definition: gcp/manager.py:280
def GetLayerNameFromCmd
Get map name from GRASS command.
Definition: core/utils.py:73
def __CreateSymbologyPage
Create notebook page with symbology settings.
def InitMapDisplay
Definition: gcp/manager.py:896
def ListSortLower
Sort list items (not case-sensitive)
Definition: core/utils.py:287
def __del__
Disable GCP manager mode.
Definition: gcp/manager.py:870
def OnMapset
Sets source mapset for map(s) to georectify.
Definition: gcp/manager.py:380
def OnSettings
GCP Manager settings.
def GetSortImages
Definition: gcp/manager.py:887
def GetTempfile
Creates GRASS temporary file using defined prefix.
Definition: core/utils.py:44
def ResizeColumns
Resize columns.
Display to manage ground control points with two toolbars, one for various display management functio...
def OnMkGroup
Create new group in source location/mapset.
Definition: gcp/manager.py:486
def OnDispResize
GCP Map Display resized, adjust Map Windows.
def OnTgtSelection
Source map to display selected.
Definition: gcp/manager.py:658
def __CreateRectificationPage
Create notebook page with symbology settings.
def OnZoomToSource
Set target map window to match extents of source map window.
def UpdateColours
update colours
def SetSrcEnv
Create environment to use for location and mapset that are the source of the file(s) to georectify...
Definition: gcp/manager.py:227
def __init__
Dialog for editing GPC and map coordinates in list control.
def Cleanup
Return to current location and mapset.
Definition: gcp/manager.py:286
def OnUpdateActive
def OnSDFactor
New factor for RMS threshold = M + SD * factor.
def LoadData
Load data into list.
def OnLocation
Sets source location for map(s) to georectify.
Definition: gcp/manager.py:358
#define round(x)
Definition: draw2.c:71
Default GUI settings.
tuple range
Definition: tools.py:1406
def getSmallUpArrowImage
Definition: gcp/manager.py:61
def CreateGCPList
Create GCP List Control.
Definition: gcp/manager.py:874
def OnClose
Button &#39;Cancel&#39; pressed.
def OnSave
Button &#39;Save&#39; pressed.
def RunCommand
Run GRASS command.
Definition: gcmd.py:625
def OnHelp
Show GCP Manager manual page.