GRASS Programmer's Manual  6.4.3(2013)-r
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties 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  self.sizer.AddGrowableCol(2)
311  # map type
312  self.rb_maptype = wx.RadioBox(parent=self, id=wx.ID_ANY,
313  label=' %s ' % _("Map type to georectify"),
314  choices=[_('raster'), _('vector')],
315  majorDimension=wx.RA_SPECIFY_COLS)
316  self.sizer.Add(item=self.rb_maptype,
317  flag=wx.ALIGN_CENTER | wx.ALL | wx.EXPAND, border=5,
318  pos=(1, 1), span=(1, 2))
319 
320  # location
321  self.sizer.Add(item=wx.StaticText(parent=self, id=wx.ID_ANY, label=_('Select source location:')),
322  flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5,
323  pos=(2, 1))
324  self.cb_location = LocationSelect(parent = self, gisdbase = self.grassdatabase)
325  self.sizer.Add(item=self.cb_location,
326  flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5,
327  pos=(2, 2))
328 
329  # mapset
330  self.sizer.Add(item=wx.StaticText(parent=self, id=wx.ID_ANY, label=_('Select source mapset:')),
331  flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5,
332  pos=(3, 1))
333  self.cb_mapset = MapsetSelect(parent = self, gisdbase = self.grassdatabase,
334  setItems = False)
335  self.sizer.Add(item=self.cb_mapset,
336  flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5,
337  pos=(3,2))
338 
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  self.sizer.AddGrowableCol(2)
433  # group
434  self.sizer.Add(item=wx.StaticText(parent=self, id=wx.ID_ANY, label=_('Select group:')),
435  flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5,
436  pos=(1, 1))
437  self.cb_group = wx.ComboBox(parent=self, id=wx.ID_ANY,
438  choices=self.groupList, size=(350, -1),
439  style=wx.CB_DROPDOWN | wx.CB_READONLY)
440  self.sizer.Add(item=self.cb_group,
441  flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5,
442  pos=(1, 2))
443 
444  # create group
445  self.sizer.Add(item=wx.StaticText(parent=self, id=wx.ID_ANY, label=_('Create group if none exists')),
446  flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5,
447  pos=(2, 1))
448  btnSizer = wx.BoxSizer(wx.HORIZONTAL)
449  self.btn_mkgroup = wx.Button(parent=self, id=wx.ID_ANY, label=_("Create/edit group..."))
450  self.btn_vgroup = wx.Button(parent=self, id=wx.ID_ANY, label=_("Add vector map to group..."))
451  btnSizer.Add(item=self.btn_mkgroup,
452  flag=wx.RIGHT, border=5)
453 
454  btnSizer.Add(item=self.btn_vgroup,
455  flag=wx.LEFT, border=5)
456 
457  self.sizer.Add(item=btnSizer,
458  flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5,
459  pos=(2, 2))
460 
461  # extension
462  self.sizer.Add(item=wx.StaticText(parent=self, id=wx.ID_ANY, label=_('Extension for output maps:')),
463  flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5,
464  pos=(3, 1))
465  self.ext_txt = wx.TextCtrl(parent=self, id=wx.ID_ANY, value="", size=(350,-1))
466  self.ext_txt.SetValue(self.extension)
467  self.sizer.Add(item=self.ext_txt,
468  flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5,
469  pos=(3, 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 = event.GetString()
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 = event.GetString()
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 = event.GetString()
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  #targetMapWin = self.parent.curr_page.maptree.mapdisplay.MapWindow
1198 
1199  if not sourceMapWin:
1200  GError(parent = self,
1201  message = "%s. %s%s" % (_("source mapwin not defined"),
1202  os.linesep, err))
1203 
1204  if not targetMapWin:
1205  GError(parent = self,
1206  message="%s. %s%s" % (_("target mapwin not defined"),
1207  os.linesep, err))
1208 
1209  try:
1210  f = open(self.file['points'], 'r')
1211  GCPcnt = 0
1212 
1213  for line in f.readlines():
1214  if line[0] == '#' or line =='':
1215  continue
1216  line = line.replace('\n', '').strip()
1217  coords = map(float, line.split())
1218  if coords[4] == 1:
1219  check = True
1220  self.GCPcount +=1
1221  else:
1222  check = False
1223 
1224  self.AddGCP(event=None)
1225  self.SetGCPData('source', (coords[0], coords[1]), sourceMapWin)
1226  self.SetGCPData('target', (coords[2], coords[3]), targetMapWin)
1227  index = self.list.GetSelected()
1228  if index != wx.NOT_FOUND:
1229  self.list.CheckItem(index, check)
1230  GCPcnt += 1
1231 
1232  except IOError, err:
1233  GError(parent = self,
1234  message = "%s <%s>. %s%s" % (_("Reading POINTS file failed"),
1235  self.file['points'], os.linesep, err))
1236  return
1237 
1238  f.close()
1239 
1240  if GCPcnt == 0:
1241  # 3 gcp is minimum
1242  for i in range(3):
1243  self.AddGCP(None)
1244 
1245  if self.CheckGCPcount():
1246  # calculate RMS
1247  self.RMSError(self.xygroup, self.gr_order)
1248 
1249  def ReloadGCPs(self, event):
1250  """!Reload data from file"""
1251 
1252  # use backup
1253  shutil.copy(self.file['points_bak'], self.file['points'])
1254 
1255  # delete all items in mapcoordlist
1256  self.mapcoordlist = []
1257  self.mapcoordlist.append([ 0, # GCP number
1258  0.0, # source east
1259  0.0, # source north
1260  0.0, # target east
1261  0.0, # target north
1262  0.0, # forward error
1263  0.0 ] ) # backward error
1264 
1265  self.list.LoadData()
1266  self.itemDataMap = self.mapcoordlist
1267 
1268  if self._col != -1:
1269  self.list.ClearColumnImage(self._col)
1270  self._colSortFlag = [1] * self.list.GetColumnCount()
1271 
1272  # draw GCPs (source and target)
1273  sourceMapWin = self.SrcMapWindow
1274  sourceMapWin.UpdateMap(render=False, renderVector=False)
1275  if self.show_target:
1276  targetMapWin = self.TgtMapWindow
1277  targetMapWin.UpdateMap(render=False, renderVector=False)
1278 
1279  def OnFocus(self, event):
1280  # self.grwiz.SwitchEnv('source')
1281  pass
1282 
1283  def OnRMS(self, event):
1284  """
1285  RMS button handler
1286  """
1287  self.RMSError(self.xygroup,self.gr_order)
1288 
1289  sourceMapWin = self.SrcMapWindow
1290  sourceMapWin.UpdateMap(render=False, renderVector=False)
1291  if self.show_target:
1292  targetMapWin = self.TgtMapWindow
1293  targetMapWin.UpdateMap(render=False, renderVector=False)
1294 
1295  def CheckGCPcount(self, msg=False):
1296  """
1297  Checks to make sure that the minimum number of GCPs have been defined and
1298  are active for the selected transformation order
1299  """
1300  if (self.GCPcount < 3 and self.gr_order == 1) or \
1301  (self.GCPcount < 6 and self.gr_order == 2) or \
1302  (self.GCPcount < 10 and self.gr_order == 3):
1303  if msg:
1304  GWarning(parent = self,
1305  message=_('Insufficient points defined and active (checked) '
1306  'for selected rectification method.\n'
1307  '3+ points needed for 1st order,\n'
1308  '6+ points for 2nd order, and\n'
1309  '10+ points for 3rd order.'))
1310  return False
1311  else:
1312  return True
1313 
1314  def OnGeorect(self, event):
1315  """
1316  Georectifies map(s) in group using i.rectify or v.transform
1317  """
1318  global maptype
1319  self.SaveGCPs(None)
1320 
1321  if self.CheckGCPcount(msg=True) == False:
1322  return
1323 
1324  if maptype == 'cell':
1325  self.grwiz.SwitchEnv('source')
1326 
1327  if self.clip_to_region:
1328  flags = "ac"
1329  else:
1330  flags = "a"
1331 
1332  busy = wx.BusyInfo(message=_("Rectifying images, please wait..."),
1333  parent=self)
1334  wx.Yield()
1335 
1336  ret, msg = RunCommand('i.rectify',
1337  parent = self,
1338  getErrorMsg = True,
1339  quiet = True,
1340  group = self.xygroup,
1341  extension = self.extension,
1342  order = self.gr_order,
1343  method=self.gr_method,
1344  flags = flags)
1345 
1346  busy.Destroy()
1347 
1348  # provide feedback on failure
1349  if ret != 0:
1350  print >> sys.stderr, msg
1351 
1352  elif maptype == 'vector':
1353  outmsg = ''
1354  # loop through all vectors in VREF
1355  # and move resulting vector to target location
1356 
1357  # make sure current mapset has a vector folder
1358  if not os.path.isdir(os.path.join(self.grassdatabase,
1359  self.currentlocation,
1360  self.currentmapset,
1361  'vector')):
1362  os.mkdir(os.path.join(self.grassdatabase,
1363  self.currentlocation,
1364  self.currentmapset,
1365  'vector'))
1366 
1367  self.grwiz.SwitchEnv('source')
1368 
1369  # make list of vectors to georectify from VREF
1370  f = open(self.file['vgrp'])
1371  vectlist = []
1372  try:
1373  for vect in f.readlines():
1374  vect = vect.strip('\n')
1375  if len(vect) < 1:
1376  continue
1377  vectlist.append(vect)
1378  finally:
1379  f.close()
1380 
1381  # georectify each vector in VREF using v.transform
1382  for vect in vectlist:
1383  self.outname = vect + '_' + self.extension
1384  self.parent.goutput.WriteLog(text = _('Transforming <%s>...') % vect,
1385  switchPage = True)
1386  msg = err = ''
1387 
1388  ret, out, err = RunCommand('v.transform',
1389  overwrite = True,
1390  input = vect,
1391  output = self.outname,
1392  pointsfile = self.file['points'],
1393  getErrorMsg = True, read = True)
1394 
1395  if ret == 0:
1396  self.VectGRList.append(self.outname)
1397  # note: WriteLog doesn't handle GRASS_INFO_PERCENT well, so using a print here
1398  # self.parent.goutput.WriteLog(text = _(err), switchPage = True)
1399  self.parent.goutput.WriteLog(text = out, switchPage = True)
1400  else:
1401  self.parent.goutput.WriteError(_('Georectification of vector map <%s> failed') %
1402  self.outname)
1403  self.parent.goutput.WriteError(err)
1404 
1405  # FIXME
1406  # Copying database information not working.
1407  # Does not copy from xy location to current location
1408  # TODO: replace $GISDBASE etc with real paths
1409  # xyLayer = []
1410  # for layer in grass.vector_db(map = vect).itervalues():
1411  # xyLayer.append((layer['driver'],
1412  # layer['database'],
1413  # layer['table']))
1414 
1415 
1416  # dbConnect = grass.db_connection()
1417  # print 'db connection =', dbConnect
1418  # for layer in xyLayer:
1419  # self.parent.goutput.RunCmd(['db.copy',
1420  # '--q',
1421  # '--o',
1422  # 'from_driver=%s' % layer[0],
1423  # 'from_database=%s' % layer[1],
1424  # 'from_table=%s' % layer[2],
1425  # 'to_driver=%s' % dbConnect['driver'],
1426  # 'to_database=%s' % dbConnect['database'],
1427  # 'to_table=%s' % layer[2] + '_' + self.extension])
1428 
1429  # copy all georectified vectors from source location to current location
1430  for name in self.VectGRList:
1431  xyvpath = os.path.join(self.grassdatabase,
1432  self.xylocation,
1433  self.xymapset,
1434  'vector',
1435  name)
1436  vpath = os.path.join(self.grassdatabase,
1437  self.currentlocation,
1438  self.currentmapset,
1439  'vector',
1440  name)
1441 
1442  if os.path.isdir(vpath):
1443  self.parent.goutput.WriteWarning(_('Vector map <%s> already exists. '
1444  'Change extension name and '
1445  'georectify again.') % self.outname)
1446  break
1447  else:
1448  # use shutil.copytree() because shutil.move() deletes src dir
1449  shutil.copytree(xyvpath, vpath)
1450 
1451  # TODO: connect vectors to copied tables with v.db.connect
1452 
1453  GMessage(_('For all vector maps georectified successfully,') + '\n' +
1454  _('you will need to copy any attribute tables') + '\n' +
1455  _('and reconnect them to the georectified vectors'),
1456  parent = self)
1457 
1458  self.grwiz.SwitchEnv('target')
1459 
1460  def OnGeorectDone(self, **kargs):
1461  """!Print final message"""
1462  global maptype
1463  if maptype == 'cell':
1464  return
1465 
1466  returncode = kargs['returncode']
1467 
1468  if returncode == 0:
1469  self.VectGRList.append(self.outname)
1470  print '*****vector list = ' + str(self.VectGRList)
1471  else:
1472  self.parent.goutput.WriteError(_('Georectification of vector map <%s> failed') %
1473  self.outname)
1474 
1475 
1476  def OnSettings(self, event):
1477  """!GCP Manager settings"""
1478  dlg = GrSettingsDialog(parent=self, id=wx.ID_ANY, title=_('GCP Manager settings'))
1479 
1480  if dlg.ShowModal() == wx.ID_OK:
1481  pass
1482 
1483  dlg.Destroy()
1484 
1485  def UpdateColours(self, srcrender=False, srcrenderVector=False,
1486  tgtrender=False, tgtrenderVector=False):
1487  """!update colours"""
1488  highest_fwd_err = 0.0
1489  self.highest_key = 0
1490  highest_idx = 0
1491 
1492  for index in range(self.list.GetItemCount()):
1493  if self.list.IsChecked(index):
1494  key = self.list.GetItemData(index)
1495  fwd_err = self.mapcoordlist[key][5]
1496 
1497  if self.highest_only == True:
1498  self.list.SetItemTextColour(index, wx.BLACK)
1499  if highest_fwd_err < fwd_err:
1500  highest_fwd_err = fwd_err
1501  self.highest_key = key
1502  highest_idx = index
1503  elif self.rmsthresh > 0:
1504  if (fwd_err > self.rmsthresh):
1505  self.list.SetItemTextColour(index, wx.RED)
1506  else:
1507  self.list.SetItemTextColour(index, wx.BLACK)
1508  else:
1509  self.list.SetItemTextColour(index, wx.BLACK)
1510 
1511  if self.highest_only and highest_fwd_err > 0.0:
1512  self.list.SetItemTextColour(highest_idx, wx.RED)
1513 
1514  sourceMapWin = self.SrcMapWindow
1515  sourceMapWin.UpdateMap(render=srcrender, renderVector=srcrenderVector)
1516  if self.show_target:
1517  targetMapWin = self.TgtMapWindow
1518  targetMapWin.UpdateMap(render=tgtrender, renderVector=tgtrenderVector)
1519 
1520  def OnQuit(self, event):
1521  """!Quit georectifier"""
1522  ret = wx.MessageBox(parent=self,
1523  caption=_("Quit GCP Manager"),
1524  message=_('Save ground control points?'),
1525  style=wx.ICON_QUESTION | wx.YES_NO | wx.CANCEL | wx.CENTRE)
1526 
1527  if ret != wx.CANCEL:
1528  if ret == wx.YES:
1529  self.SaveGCPs(None)
1530  elif ret == wx.NO:
1531  # restore POINTS file from backup
1532  if os.path.exists(self.file['points_bak']):
1533  shutil.copy(self.file['points_bak'], self.file['points'])
1534 
1535  if os.path.exists(self.file['points_bak']):
1536  os.unlink(self.file['points_bak'])
1537 
1538  self.SrcMap.Clean()
1539  self.TgtMap.Clean()
1540 
1541  self.grwiz.Cleanup()
1542 
1543  self.Destroy()
1544 
1545  #event.Skip()
1546 
1547  def OnGROrder(self, event):
1548  """
1549  sets transformation order for georectifying
1550  """
1551  if event:
1552  self.gr_order = event.GetInt() + 1
1553 
1554  numOfItems = self.list.GetItemCount()
1555  minNumOfItems = numOfItems
1556 
1557  if self.gr_order == 1:
1558  minNumOfItems = 3
1559  # self.SetStatusText(_('Insufficient points, 3+ points needed for 1st order'))
1560 
1561  elif self.gr_order == 2:
1562  minNumOfItems = 6
1563  diff = 6 - numOfItems
1564  # self.SetStatusText(_('Insufficient points, 6+ points needed for 2nd order'))
1565 
1566  elif self.gr_order == 3:
1567  minNumOfItems = 10
1568  # self.SetStatusText(_('Insufficient points, 10+ points needed for 3rd order'))
1569 
1570  for i in range(minNumOfItems - numOfItems):
1571  self.AddGCP(None)
1572 
1573  return minNumOfItems
1574 
1575  def RMSError(self, xygroup, order):
1576  """
1577  Uses g.transform to calculate forward and backward error for each used GCP
1578  in POINTS file and insert error values into GCP list.
1579  Calculates total forward and backward RMS error for all used points
1580  """
1581  # save GCPs to points file to make sure that all checked GCPs are used
1582  self.SaveGCPs(None)
1583  #self.SetStatusText('')
1584 
1585  if self.CheckGCPcount(msg=True) == False:
1586  return
1587 
1588  # get list of forward and reverse rms error values for each point
1589  self.grwiz.SwitchEnv('source')
1590 
1591  ret = RunCommand('g.transform',
1592  parent = self,
1593  read = True,
1594  group = xygroup,
1595  order = order)
1596 
1597  self.grwiz.SwitchEnv('target')
1598 
1599  if ret:
1600  errlist = ret.splitlines()
1601  else:
1602  GError(parent = self,
1603  message=_('Could not calculate RMS Error.\n'
1604  'Possible error with g.transform.'))
1605  return
1606 
1607  # insert error values into GCP list for checked items
1608  sdfactor = float(UserSettings.Get(group='gcpman', key='rms', subkey='sdfactor'))
1609  GCPcount = 0
1610  sumsq_fwd_err = 0.0
1611  sumsq_bkw_err = 0.0
1612  sum_fwd_err = 0.0
1613  highest_fwd_err = 0.0
1614  self.highest_key = 0
1615  highest_idx = 0
1616 
1617  for index in range(self.list.GetItemCount()):
1618  key = self.list.GetItemData(index)
1619  if self.list.IsChecked(index):
1620  fwd_err, bkw_err = errlist[GCPcount].split()
1621  self.list.SetStringItem(index, 5, fwd_err)
1622  self.list.SetStringItem(index, 6, bkw_err)
1623  self.mapcoordlist[key][5] = float(fwd_err)
1624  self.mapcoordlist[key][6] = float(bkw_err)
1625  self.list.SetItemTextColour(index, wx.BLACK)
1626  if self.highest_only:
1627  if highest_fwd_err < float(fwd_err):
1628  highest_fwd_err = float(fwd_err)
1629  self.highest_key = key
1630  highest_idx = index
1631 
1632  sumsq_fwd_err += float(fwd_err)**2
1633  sumsq_bkw_err += float(bkw_err)**2
1634  sum_fwd_err += float(fwd_err)
1635  GCPcount += 1
1636  else:
1637  self.list.SetStringItem(index, 5, '')
1638  self.list.SetStringItem(index, 6, '')
1639  self.mapcoordlist[key][5] = 0.0
1640  self.mapcoordlist[key][6] = 0.0
1641  self.list.SetItemTextColour(index, wx.BLACK)
1642 
1643  # SD
1644  if GCPcount > 0:
1645  sum_fwd_err /= GCPcount
1646  self.rmsmean = sum_fwd_err /GCPcount
1647  self.rmssd = (((sumsq_fwd_err/GCPcount) - self.rmsmean**2)**0.5)
1648  self.rmsthresh = self.rmsmean + sdfactor * self.rmssd
1649  else:
1650  self.rmsthresh = 0
1651  self.rmsmean = 0
1652  self.rmssd = 0
1653 
1654  if self.highest_only and highest_fwd_err > 0.0:
1655  self.list.SetItemTextColour(highest_idx, wx.RED)
1656  elif GCPcount > 0 and self.rmsthresh > 0 and not self.highest_only:
1657  for index in range(self.list.GetItemCount()):
1658  if self.list.IsChecked(index):
1659  key = self.list.GetItemData(index)
1660  if (self.mapcoordlist[key][5] > self.rmsthresh):
1661  self.list.SetItemTextColour(index, wx.RED)
1662 
1663  # calculate global RMS error (geometric mean)
1664  self.fwd_rmserror = round((sumsq_fwd_err/GCPcount)**0.5,4)
1665  self.bkw_rmserror = round((sumsq_bkw_err/GCPcount)**0.5,4)
1666  self.list.ResizeColumns()
1667 
1668  def GetNewExtent(self, region, map = None):
1669 
1670  coord_file = utils.GetTempfile()
1671  newreg = { 'n' : 0.0, 's' : 0.0, 'e' : 0.0, 'w' : 0.0,}
1672 
1673  try:
1674  f = open(coord_file, mode='w')
1675  # NW corner
1676  f.write(str(region['e']) + " " + str(region['n']) + "\n")
1677  # NE corner
1678  f.write(str(region['e']) + " " + str(region['s']) + "\n")
1679  # SW corner
1680  f.write(str(region['w']) + " " + str(region['n']) + "\n")
1681  # SE corner
1682  f.write(str(region['w']) + " " + str(region['s']) + "\n")
1683  finally:
1684  f.close()
1685 
1686  # save GCPs to points file to make sure that all checked GCPs are used
1687  self.SaveGCPs(None)
1688 
1689  order = self.gr_order
1690  self.gr_order = 1
1691 
1692  if self.CheckGCPcount(msg=True) == False:
1693  self.gr_order = order
1694  return
1695 
1696  self.gr_order = order
1697 
1698  # get list of forward and reverse rms error values for each point
1699  self.grwiz.SwitchEnv('source')
1700 
1701  if map == 'source':
1702  ret = RunCommand('g.transform',
1703  parent = self,
1704  read = True,
1705  group = self.xygroup,
1706  order = 1,
1707  format = 'dst',
1708  coords = coord_file)
1709 
1710  elif map == 'target':
1711  ret = RunCommand('g.transform',
1712  parent = self,
1713  read = True,
1714  group = self.xygroup,
1715  order = 1,
1716  flags = 'r',
1717  format = 'src',
1718  coords = coord_file)
1719 
1720  os.unlink(coord_file)
1721 
1722  self.grwiz.SwitchEnv('target')
1723 
1724  if ret:
1725  errlist = ret.splitlines()
1726  else:
1727  GError(parent = self,
1728  message=_('Could not calculate new extends.\n'
1729  'Possible error with g.transform.'))
1730  return
1731 
1732  # fist corner
1733  e, n = errlist[0].split()
1734  fe = float(e)
1735  fn = float(n)
1736  newreg['n'] = fn
1737  newreg['s'] = fn
1738  newreg['e'] = fe
1739  newreg['w'] = fe
1740  # other three corners
1741  for i in range(1, 4):
1742  e, n = errlist[i].split()
1743  fe = float(e)
1744  fn = float(n)
1745  if fe < newreg['w']:
1746  newreg['w'] = fe
1747  if fe > newreg['e']:
1748  newreg['e'] = fe
1749  if fn < newreg['s']:
1750  newreg['s'] = fn
1751  if fn > newreg['n']:
1752  newreg['n'] = fn
1753 
1754  return newreg
1755 
1756  def OnHelp(self, event):
1757  """!Show GCP Manager manual page"""
1758  cmdlist = ['g.manual', 'entry=wxGUI.GCP_Manager']
1759  self.parent.goutput.RunCmd(cmdlist, compReg=False,
1760  switchPage=False)
1761 
1762  def OnUpdateActive(self, event):
1763 
1764  if self.activemap.GetSelection() == 0:
1765  self.MapWindow = self.SrcMapWindow
1766  self.Map = self.SrcMap
1767  else:
1768  self.MapWindow = self.TgtMapWindow
1769  self.Map = self.TgtMap
1770 
1771  self.UpdateActive(self.MapWindow)
1772  # for wingrass
1773  if os.name == 'nt':
1774  self.MapWindow.SetFocus()
1775 
1776  def UpdateActive(self, win):
1777 
1778  # optionally disable tool zoomback tool
1779  self.GetMapToolbar().Enable('zoomback', enable = (len(self.MapWindow.zoomhistory) > 1))
1780 
1781  if self.activemap.GetSelection() != (win == self.TgtMapWindow):
1782  self.activemap.SetSelection(win == self.TgtMapWindow)
1783  self.StatusbarUpdate()
1784 
1785  def AdjustMap(self, newreg):
1786  """!Adjust map window to new extents
1787  """
1788 
1789  # adjust map window
1790  self.Map.region['n'] = newreg['n']
1791  self.Map.region['s'] = newreg['s']
1792  self.Map.region['e'] = newreg['e']
1793  self.Map.region['w'] = newreg['w']
1794 
1795  self.MapWindow.ZoomHistory(self.Map.region['n'], self.Map.region['s'],
1796  self.Map.region['e'], self.Map.region['w'])
1797 
1798  # LL locations
1799  if self.Map.projinfo['proj'] == 'll':
1800  if newreg['n'] > 90.0:
1801  newreg['n'] = 90.0
1802  if newreg['s'] < -90.0:
1803  newreg['s'] = -90.0
1804 
1805  ce = newreg['w'] + (newreg['e'] - newreg['w']) / 2
1806  cn = newreg['s'] + (newreg['n'] - newreg['s']) / 2
1807 
1808  # calculate new center point and display resolution
1809  self.Map.region['center_easting'] = ce
1810  self.Map.region['center_northing'] = cn
1811  self.Map.region["ewres"] = (newreg['e'] - newreg['w']) / self.Map.width
1812  self.Map.region["nsres"] = (newreg['n'] - newreg['s']) / self.Map.height
1813  self.Map.AlignExtentFromDisplay()
1814 
1815  self.MapWindow.ZoomHistory(self.Map.region['n'], self.Map.region['s'],
1816  self.Map.region['e'], self.Map.region['w'])
1817 
1818  if self.MapWindow.redrawAll is False:
1819  self.MapWindow.redrawAll = True
1820 
1821  self.MapWindow.UpdateMap()
1822  self.StatusbarUpdate()
1823 
1824  def OnZoomToSource(self, event):
1825  """!Set target map window to match extents of source map window
1826  """
1827 
1828  if not self.MapWindow == self.TgtMapWindow:
1829  self.MapWindow = self.TgtMapWindow
1830  self.Map = self.TgtMap
1831  self.UpdateActive(self.TgtMapWindow)
1832 
1833  # get new N, S, E, W for target
1834  newreg = self.GetNewExtent(self.SrcMap.region, 'source')
1835  if newreg:
1836  self.AdjustMap(newreg)
1837 
1838  def OnZoomToTarget(self, event):
1839  """!Set source map window to match extents of target map window
1840  """
1841 
1842  if not self.MapWindow == self.SrcMapWindow:
1843  self.MapWindow = self.SrcMapWindow
1844  self.Map = self.SrcMap
1845  self.UpdateActive(self.SrcMapWindow)
1846 
1847  # get new N, S, E, W for target
1848  newreg = self.GetNewExtent(self.TgtMap.region, 'target')
1849  if newreg:
1850  self.AdjustMap(newreg)
1851 
1852  def OnZoomMenuGCP(self, event):
1853  """!Popup Zoom menu
1854  """
1855  point = wx.GetMousePosition()
1856  zoommenu = wx.Menu()
1857  # Add items to the menu
1858 
1859  zoomsource = wx.MenuItem(zoommenu, wx.ID_ANY, _('Adjust source display to target display'))
1860  zoommenu.AppendItem(zoomsource)
1861  self.Bind(wx.EVT_MENU, self.OnZoomToTarget, zoomsource)
1862 
1863  zoomtarget = wx.MenuItem(zoommenu, wx.ID_ANY, _('Adjust target display to source display'))
1864  zoommenu.AppendItem(zoomtarget)
1865  self.Bind(wx.EVT_MENU, self.OnZoomToSource, zoomtarget)
1866 
1867  # Popup the menu. If an item is selected then its handler
1868  # will be called before PopupMenu returns.
1869  self.PopupMenu(zoommenu)
1870  zoommenu.Destroy()
1871 
1872  def OnDispResize(self, event):
1873  """!GCP Map Display resized, adjust Map Windows
1874  """
1875  if self.GetMapToolbar():
1876  srcwidth, srcheight = self.SrcMapWindow.GetSize()
1877  tgtwidth, tgtheight = self.TgtMapWindow.GetSize()
1878  srcwidth = (srcwidth + tgtwidth) / 2
1879  self._mgr.GetPane("target").Hide()
1880  self._mgr.Update()
1881  self._mgr.GetPane("source").BestSize((srcwidth, srcheight))
1882  self._mgr.GetPane("target").BestSize((srcwidth, tgtheight))
1883  if self.show_target:
1884  self._mgr.GetPane("target").Show()
1885  self._mgr.Update()
1886  pass
1887 
1888 class GCPList(wx.ListCtrl,
1889  CheckListCtrlMixin,
1890  ListCtrlAutoWidthMixin):
1891 
1892  def __init__(self, parent, gcp, id=wx.ID_ANY,
1893  pos=wx.DefaultPosition, size=wx.DefaultSize,
1894  style=wx.LC_REPORT | wx.SUNKEN_BORDER | wx.LC_HRULES |
1895  wx.LC_SINGLE_SEL):
1896 
1897  wx.ListCtrl.__init__(self, parent, id, pos, size, style)
1898 
1899  self.gcp = gcp # GCP class
1900  self.render = True
1901 
1902  # Mixin settings
1903  CheckListCtrlMixin.__init__(self)
1904  ListCtrlAutoWidthMixin.__init__(self)
1905  # TextEditMixin.__init__(self)
1906 
1907  # tracks whether list items are checked or not
1908  self.CheckList = []
1909 
1910  self._Create()
1911 
1912  self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected)
1913  self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.OnItemActivated)
1914  self.Bind(wx.EVT_LIST_COL_CLICK, self.OnColClick)
1915 
1916  self.selected = wx.NOT_FOUND
1917  self.selectedkey = -1
1918 
1919  def _Create(self):
1920 
1921  if 0:
1922  # normal, simple columns
1923  idx_col = 0
1924  for col in (_('use'),
1925  _('source E'),
1926  _('source N'),
1927  _('target E'),
1928  _('target N'),
1929  _('Forward error'),
1930  _('Backward error')):
1931  self.InsertColumn(idx_col, col)
1932  idx_col += 1
1933  else:
1934  # the hard way: we want images on the column header
1935  info = wx.ListItem()
1936  info.SetMask(wx.LIST_MASK_TEXT | wx.LIST_MASK_IMAGE | wx.LIST_MASK_FORMAT)
1937  info.SetImage(-1)
1938  info.m_format = wx.LIST_FORMAT_LEFT
1939 
1940  idx_col = 0
1941  for lbl in (_('use'),
1942  _('source E'),
1943  _('source N'),
1944  _('target E'),
1945  _('target N'),
1946  _('Forward error'),
1947  _('Backward error')):
1948  info.SetText(lbl)
1949  self.InsertColumnInfo(idx_col, info)
1950  idx_col += 1
1951 
1952  def LoadData(self):
1953  """!Load data into list"""
1954  self.DeleteAllItems()
1955 
1956  self.render = False
1957  if os.path.isfile(self.gcp.file['points']):
1958  self.gcp.ReadGCPs()
1959  else:
1960  # 3 gcp is minimum
1961  for i in range(3):
1962  self.gcp.AddGCP(None)
1963 
1964  # select first point by default
1965  self.selected = 0
1966  self.selectedkey = self.GetItemData(self.selected)
1967  self.SetItemState(self.selected,
1968  wx.LIST_STATE_SELECTED,
1969  wx.LIST_STATE_SELECTED)
1970 
1971  self.ResizeColumns()
1972  self.render = True
1973 
1974  self.EnsureVisible(self.selected)
1975 
1976  def OnCheckItem(self, index, flag):
1977  """!Item is checked/unchecked"""
1978 
1979  if self.render:
1980  # redraw points
1981  sourceMapWin = self.gcp.SrcMapWindow
1982  sourceMapWin.UpdateMap(render=False, renderVector=False)
1983  if self.gcp.show_target:
1984  targetMapWin = self.gcp.TgtMapWindow
1985  targetMapWin.UpdateMap(render=False, renderVector=False)
1986 
1987  pass
1988 
1989  def AddGCPItem(self):
1990  """
1991  Appends an item to GCP list
1992  """
1993  self.selectedkey = self.GetItemCount() + 1
1994 
1995  self.Append([str(self.selectedkey), # GCP number
1996  '0.0', # source E
1997  '0.0', # source N
1998  '0.0', # target E
1999  '0.0', # target N
2000  '', # forward error
2001  '']) # backward error
2002 
2003  self.selected = self.GetItemCount() - 1
2004  self.SetItemData(self.selected, self.selectedkey)
2005 
2006  self.SetItemState(self.selected,
2007  wx.LIST_STATE_SELECTED,
2008  wx.LIST_STATE_SELECTED)
2009 
2010  self.ResizeColumns()
2011 
2012  self.EnsureVisible(self.selected)
2013 
2014  return self.selected
2015 
2016  def DeleteGCPItem(self):
2017  """
2018  Deletes selected item in GCP list
2019  """
2020  if self.selected == wx.NOT_FOUND:
2021  return
2022 
2023  key = self.GetItemData(self.selected)
2024  self.DeleteItem(self.selected)
2025 
2026  return key
2027 
2028  def ResizeColumns(self):
2029  """!Resize columns"""
2030  minWidth = [90, 120]
2031  for i in range(self.GetColumnCount()):
2032  self.SetColumnWidth(i, wx.LIST_AUTOSIZE)
2033  # first column is checkbox, don't set to minWidth
2034  if i > 0 and self.GetColumnWidth(i) < minWidth[i > 4]:
2035  self.SetColumnWidth(i, minWidth[i > 4])
2036 
2037  self.SendSizeEvent()
2038 
2039  def GetSelected(self):
2040  """!Get index of selected item"""
2041  return self.selected
2042 
2043  def OnItemSelected(self, event):
2044  """
2045  Item selected
2046  """
2047 
2048  if self.render and self.selected != event.GetIndex():
2049  self.selected = event.GetIndex()
2050  self.selectedkey = self.GetItemData(self.selected)
2051  sourceMapWin = self.gcp.SrcMapWindow
2052  sourceMapWin.UpdateMap(render=False, renderVector=False)
2053  if self.gcp.show_target:
2054  targetMapWin = self.gcp.TgtMapWindow
2055  targetMapWin.UpdateMap(render=False, renderVector=False)
2056 
2057  event.Skip()
2058 
2059  def OnItemActivated(self, event):
2060  """
2061  When item double clicked, open editor to update coordinate values
2062  """
2063  coords = []
2064  index = event.GetIndex()
2065  key = self.GetItemData(index)
2066  changed = False
2067 
2068  for i in range(1, 5):
2069  coords.append(self.GetItem(index, i).GetText())
2070 
2071  dlg = EditGCP(parent=self, id=wx.ID_ANY, data=coords, gcpno=key)
2072 
2073  if dlg.ShowModal() == wx.ID_OK:
2074  values = dlg.GetValues() # string
2075 
2076  if len(values) == 0:
2077  GError(parent = self,
2078  message=_("Invalid coordinate value. Operation canceled."))
2079  else:
2080  for i in range(len(values)):
2081  if values[i] != coords[i]:
2082  self.SetStringItem(index, i + 1, values[i])
2083  changed = True
2084 
2085  if changed:
2086  # reset RMS and update mapcoordlist
2087  self.SetStringItem(index, 5, '')
2088  self.SetStringItem(index, 6, '')
2089  key = self.GetItemData(index)
2090  self.gcp.mapcoordlist[key] = [key,
2091  float(values[0]),
2092  float(values[1]),
2093  float(values[2]),
2094  float(values[3]),
2095  0.0,
2096  0.0]
2097  self.gcp.UpdateColours()
2098 
2099  def OnColClick(self, event):
2100  """!ListCtrl forgets selected item..."""
2101  self.selected = self.FindItemData(-1, self.selectedkey)
2102  self.SetItemState(self.selected,
2103  wx.LIST_STATE_SELECTED,
2104  wx.LIST_STATE_SELECTED)
2105  event.Skip()
2106 
2107 class VectGroup(wx.Dialog):
2108  """
2109  Dialog to create a vector group (VREF file) for georectifying
2110 
2111  @todo Replace by g.group
2112  """
2113  def __init__(self, parent, id, grassdb, location, mapset, group,
2114  style=wx.DEFAULT_DIALOG_STYLE):
2115 
2116  wx.Dialog.__init__(self, parent, id, style=style,
2117  title = _("Create vector map group"))
2118 
2119  self.grassdatabase = grassdb
2120  self.xylocation = location
2121  self.xymapset = mapset
2122  self.xygroup = group
2123 
2124  #
2125  # get list of valid vector directories
2126  #
2127  vectlist = os.listdir(os.path.join(self.grassdatabase,
2128  self.xylocation,
2129  self.xymapset,
2130  'vector'))
2131  for dir in vectlist:
2132  if not os.path.isfile(os.path.join(self.grassdatabase,
2133  self.xylocation,
2134  self.xymapset,
2135  'vector',
2136  dir,
2137  'coor')):
2138  vectlist.remove(dir)
2139 
2140  utils.ListSortLower(vectlist)
2141 
2142  # path to vref file
2143  self.vgrpfile = os.path.join(self.grassdatabase,
2144  self.xylocation,
2145  self.xymapset,
2146  'group',
2147  self.xygroup,
2148  'VREF')
2149 
2150  #
2151  # buttons
2152  #
2153  self.btnCancel = wx.Button(parent = self,
2154  id = wx.ID_CANCEL)
2155  self.btnOK = wx.Button(parent = self,
2156  id = wx.ID_OK)
2157  self.btnOK.SetDefault()
2158 
2159 
2160  #
2161  # list of vector maps
2162  #
2163  self.listMap = wx.CheckListBox(parent = self, id = wx.ID_ANY,
2164  choices = vectlist)
2165 
2166  if os.path.isfile(self.vgrpfile):
2167  f = open(self.vgrpfile)
2168  try:
2169  checked = []
2170  for line in f.readlines():
2171  line = line.replace('\n', '')
2172  if len(line) < 1:
2173  continue
2174  checked.append(line)
2175  self.listMap.SetCheckedStrings(checked)
2176  finally:
2177  f.close()
2178 
2179  line = wx.StaticLine(parent = self,
2180  id = wx.ID_ANY, size = (20, -1),
2181  style = wx.LI_HORIZONTAL)
2182 
2183  #
2184  # layout
2185  #
2186  sizer = wx.BoxSizer(wx.VERTICAL)
2187 
2188  box = wx.BoxSizer(wx.HORIZONTAL)
2189  box.Add(item = wx.StaticText(parent = self, id = wx.ID_ANY,
2190  label = _('Select vector map(s) to add to group:')),
2191  flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT | wx.LEFT,
2192  border = 5)
2193 
2194  box.Add(item = self.listMap,
2195  flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT | wx.LEFT,
2196  border = 5)
2197 
2198 
2199  sizer.Add(box, flag = wx.ALIGN_RIGHT | wx.ALL,
2200  border = 3)
2201 
2202  sizer.Add(item = line, proportion = 0,
2203  flag = wx.GROW | wx.ALIGN_CENTER_VERTICAL | wx.LEFT | wx.RIGHT,
2204  border = 5)
2205 
2206  # buttons
2207  btnSizer = wx.StdDialogButtonSizer()
2208  btnSizer.AddButton(self.btnCancel)
2209  btnSizer.AddButton(self.btnOK)
2210  btnSizer.Realize()
2211 
2212  sizer.Add(item = btnSizer, proportion = 0,
2213  flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER,
2214  border = 5)
2215 
2216  self.SetSizer(sizer)
2217  sizer.Fit(self)
2218  self.Layout()
2219 
2220  def MakeVGroup(self):
2221  """!Create VREF file"""
2222  vgrouplist = []
2223  for item in range(self.listMap.GetCount()):
2224  if not self.listMap.IsChecked(item):
2225  continue
2226  vgrouplist.append(self.listMap.GetString(item))
2227 
2228  f = open(self.vgrpfile, mode='w')
2229  try:
2230  for vect in vgrouplist:
2231  f.write(vect + '\n')
2232  finally:
2233  f.close()
2234 
2235 class EditGCP(wx.Dialog):
2236  def __init__(self, parent, data, gcpno, id=wx.ID_ANY,
2237  title=_("Edit GCP"),
2238  style=wx.DEFAULT_DIALOG_STYLE):
2239  """!Dialog for editing GPC and map coordinates in list control"""
2240 
2241  wx.Dialog.__init__(self, parent, id, title=title, style=style)
2242 
2243  panel = wx.Panel(parent=self)
2244 
2245  sizer = wx.BoxSizer(wx.VERTICAL)
2246 
2247  box = wx.StaticBox (parent=panel, id=wx.ID_ANY,
2248  label=" %s %s " % (_("Ground Control Point No."), str(gcpno)))
2249  boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
2250 
2251  # source coordinates
2252  gridSizer = wx.GridBagSizer(vgap=5, hgap=5)
2253 
2254  self.xcoord = wx.TextCtrl(parent=panel, id=wx.ID_ANY, size=(150, -1))
2255  self.ycoord = wx.TextCtrl(parent=panel, id=wx.ID_ANY, size=(150, -1))
2256  self.ecoord = wx.TextCtrl(parent=panel, id=wx.ID_ANY, size=(150, -1))
2257  self.ncoord = wx.TextCtrl(parent=panel, id=wx.ID_ANY, size=(150, -1))
2258 
2259  # swap source N, target E
2260  tmp_coord = data[1]
2261  data[1] = data[2]
2262  data[2] = tmp_coord
2263 
2264  row = 0
2265  col = 0
2266  idx = 0
2267  for label, win in ((_("source E:"), self.xcoord),
2268  (_("target E:"), self.ecoord),
2269  (_("source N:"), self.ycoord),
2270  (_("target N:"), self.ncoord)):
2271  label = wx.StaticText(parent=panel, id=wx.ID_ANY,
2272  label=label)
2273  gridSizer.Add(item=label,
2274  flag=wx.ALIGN_CENTER_VERTICAL,
2275  pos=(row, col))
2276 
2277  col += 1
2278  win.SetValue(str(data[idx]))
2279 
2280  gridSizer.Add(item=win,
2281  pos=(row, col))
2282 
2283  col += 1
2284  idx += 1
2285 
2286  if col > 3:
2287  row += 1
2288  col = 0
2289 
2290  boxSizer.Add(item=gridSizer, proportion=1,
2291  flag=wx.EXPAND | wx.ALL, border=5)
2292 
2293  sizer.Add(item=boxSizer, proportion=1,
2294  flag=wx.EXPAND | wx.ALL, border=5)
2295 
2296  #
2297  # buttons
2298  #
2299  self.btnCancel = wx.Button(panel, wx.ID_CANCEL)
2300  self.btnOk = wx.Button(panel, wx.ID_OK)
2301  self.btnOk.SetDefault()
2302 
2303  btnSizer = wx.StdDialogButtonSizer()
2304  btnSizer.AddButton(self.btnCancel)
2305  btnSizer.AddButton(self.btnOk)
2306  btnSizer.Realize()
2307 
2308  sizer.Add(item=btnSizer, proportion=0,
2309  flag=wx.ALIGN_RIGHT | wx.ALL, border=5)
2310 
2311  panel.SetSizer(sizer)
2312  sizer.Fit(self)
2313 
2314  def GetValues(self, columns=None):
2315  """!Return list of values (as strings).
2316  """
2317  valuelist = []
2318  try:
2319  float(self.xcoord.GetValue())
2320  float(self.ycoord.GetValue())
2321  float(self.ecoord.GetValue())
2322  float(self.ncoord.GetValue())
2323  except ValueError:
2324  return valuelist
2325 
2326  valuelist.append(self.xcoord.GetValue())
2327  valuelist.append(self.ycoord.GetValue())
2328  valuelist.append(self.ecoord.GetValue())
2329  valuelist.append(self.ncoord.GetValue())
2330 
2331  return valuelist
2332 
2333 class GrSettingsDialog(wx.Dialog):
2334  def __init__(self, parent, id, title, pos=wx.DefaultPosition, size=wx.DefaultSize,
2335  style=wx.DEFAULT_DIALOG_STYLE):
2336  wx.Dialog.__init__(self, parent, id, title, pos, size, style)
2337  """
2338  Dialog to set profile text options: font, title
2339  and font size, axis labels and font size
2340  """
2341  #
2342  # initialize variables
2343  #
2344  self.parent = parent
2345  self.new_src_map = src_map
2346  self.new_tgt_map = tgt_map
2347  self.sdfactor = 0
2348 
2349  self.symbol = {}
2350 
2351  self.methods = ["nearest",
2352  "bilinear",
2353  "bilinear_f",
2354  "cubic",
2355  "cubic_f"]
2356 
2357  # notebook
2358  notebook = wx.Notebook(parent=self, id=wx.ID_ANY, style=wx.BK_DEFAULT)
2359  self.__CreateSymbologyPage(notebook)
2360  self.__CreateRectificationPage(notebook)
2361 
2362  # buttons
2363  btnSave = wx.Button(self, wx.ID_SAVE)
2364  btnApply = wx.Button(self, wx.ID_APPLY)
2365  btnClose = wx.Button(self, wx.ID_CLOSE)
2366  btnApply.SetDefault()
2367 
2368  # bindings
2369  btnApply.Bind(wx.EVT_BUTTON, self.OnApply)
2370  btnApply.SetToolTipString(_("Apply changes for the current session"))
2371  btnSave.Bind(wx.EVT_BUTTON, self.OnSave)
2372  btnSave.SetToolTipString(_("Apply and save changes to user settings file (default for next sessions)"))
2373  btnClose.Bind(wx.EVT_BUTTON, self.OnClose)
2374  btnClose.SetToolTipString(_("Close dialog"))
2375 
2376  # sizers
2377  btnSizer = wx.BoxSizer(wx.HORIZONTAL)
2378  btnSizer.Add(btnApply, flag=wx.LEFT | wx.RIGHT, border=5)
2379  btnSizer.Add(btnSave, flag=wx.LEFT | wx.RIGHT, border=5)
2380  btnSizer.Add(btnClose, flag=wx.LEFT | wx.RIGHT, border=5)
2381 
2382  # sizers
2383  mainSizer = wx.BoxSizer(wx.VERTICAL)
2384  mainSizer.Add(item=notebook, proportion=1, flag=wx.EXPAND | wx.ALL, border=5)
2385  mainSizer.Add(item=btnSizer, proportion=0,
2386  flag=wx.ALIGN_RIGHT | wx.ALL, border=5)
2387  # flag=wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border=5)
2388 
2389  self.SetSizer(mainSizer)
2390  mainSizer.Fit(self)
2391 
2392  def __CreateSymbologyPage(self, notebook):
2393  """!Create notebook page with symbology settings"""
2394 
2395  panel = wx.Panel(parent=notebook, id=wx.ID_ANY)
2396  notebook.AddPage(page=panel, text=_("Symbology"))
2397 
2398  sizer = wx.BoxSizer(wx.VERTICAL)
2399 
2400  rmsgridSizer = wx.GridBagSizer(vgap=5, hgap=5)
2401  rmsgridSizer.AddGrowableCol(1)
2402 
2403  # highlight only highest forward RMS error
2404  self.highlighthighest = wx.CheckBox(parent=panel, id=wx.ID_ANY,
2405  label=_("Highlight highest RMS error only"))
2406  hh = UserSettings.Get(group='gcpman', key='rms', subkey='highestonly')
2407  self.highlighthighest.SetValue(hh)
2408  rmsgridSizer.Add(item=self.highlighthighest, flag=wx.ALIGN_CENTER_VERTICAL, pos=(0, 0))
2409 
2410  # RMS forward error threshold
2411  rmslabel = wx.StaticText(parent=panel, id=wx.ID_ANY, label=_("Highlight RMS error > M + SD * factor:"))
2412  rmslabel.SetToolTip(wx.ToolTip(_("Highlight GCPs with an RMS error larger than \n"
2413  "mean + standard deviation * given factor. \n"
2414  "Recommended values for this factor are between 1 and 2.")))
2415  rmsgridSizer.Add(item=rmslabel, flag=wx.ALIGN_CENTER_VERTICAL, pos=(1, 0))
2416  sdfactor = UserSettings.Get(group='gcpman', key='rms', subkey='sdfactor')
2417  self.rmsWin = wx.TextCtrl(parent=panel, id=wx.ID_ANY,
2418  size=(70,-1), style=wx.TE_NOHIDESEL)
2419  self.rmsWin.SetValue("%s" % str(sdfactor))
2420  if (self.parent.highest_only == True):
2421  self.rmsWin.Disable()
2422 
2423  self.symbol['sdfactor'] = self.rmsWin.GetId()
2424  rmsgridSizer.Add(item=self.rmsWin, flag=wx.ALIGN_RIGHT, pos=(1, 1))
2425  sizer.Add(item=rmsgridSizer, flag=wx.EXPAND | wx.ALL, border=5)
2426 
2427  box = wx.StaticBox(parent=panel, id=wx.ID_ANY,
2428  label=" %s " % _("Symbol settings"))
2429  boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
2430  gridSizer = wx.GridBagSizer(vgap=5, hgap=5)
2431  gridSizer.AddGrowableCol(1)
2432 
2433  #
2434  # general symbol color
2435  #
2436  row = 0
2437  label = wx.StaticText(parent=panel, id=wx.ID_ANY, label=_("Color:"))
2438  gridSizer.Add(item=label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
2439  col = UserSettings.Get(group='gcpman', key='symbol', subkey='color')
2440  colWin = csel.ColourSelect(parent=panel, id=wx.ID_ANY,
2441  colour=wx.Colour(col[0],
2442  col[1],
2443  col[2],
2444  255))
2445  self.symbol['color'] = colWin.GetId()
2446  gridSizer.Add(item=colWin,
2447  flag=wx.ALIGN_RIGHT,
2448  pos=(row, 1))
2449 
2450  #
2451  # symbol color for high forward RMS error
2452  #
2453  row += 1
2454  label = wx.StaticText(parent=panel, id=wx.ID_ANY, label=_("Color for high RMS error:"))
2455  gridSizer.Add(item=label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
2456  hcol = UserSettings.Get(group='gcpman', key='symbol', subkey='hcolor')
2457  hcolWin = csel.ColourSelect(parent=panel, id=wx.ID_ANY,
2458  colour=wx.Colour(hcol[0],
2459  hcol[1],
2460  hcol[2],
2461  255))
2462  self.symbol['hcolor'] = hcolWin.GetId()
2463  gridSizer.Add(item=hcolWin,
2464  flag=wx.ALIGN_RIGHT,
2465  pos=(row, 1))
2466 
2467  #
2468  # symbol color for selected GCP
2469  #
2470  row += 1
2471  label = wx.StaticText(parent=panel, id=wx.ID_ANY, label=_("Color for selected GCP:"))
2472  gridSizer.Add(item=label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
2473  scol = UserSettings.Get(group='gcpman', key='symbol', subkey='scolor')
2474  scolWin = csel.ColourSelect(parent=panel, id=wx.ID_ANY,
2475  colour=wx.Colour(scol[0],
2476  scol[1],
2477  scol[2],
2478  255))
2479  self.symbol['scolor'] = scolWin.GetId()
2480  gridSizer.Add(item=scolWin,
2481  flag=wx.ALIGN_RIGHT,
2482  pos=(row, 1))
2483 
2484  #
2485  # symbol color for unused GCP
2486  #
2487  row += 1
2488  label = wx.StaticText(parent=panel, id=wx.ID_ANY, label=_("Color for unused GCPs:"))
2489  gridSizer.Add(item=label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
2490  ucol = UserSettings.Get(group='gcpman', key='symbol', subkey='ucolor')
2491  ucolWin = csel.ColourSelect(parent=panel, id=wx.ID_ANY,
2492  colour=wx.Colour(ucol[0],
2493  ucol[1],
2494  ucol[2],
2495  255))
2496  self.symbol['ucolor'] = ucolWin.GetId()
2497  gridSizer.Add(item=ucolWin,
2498  flag=wx.ALIGN_RIGHT,
2499  pos=(row, 1))
2500 
2501  # show unused GCPs
2502  row += 1
2503  self.showunused = wx.CheckBox(parent=panel, id=wx.ID_ANY,
2504  label=_("Show unused GCPs"))
2505  shuu = UserSettings.Get(group='gcpman', key='symbol', subkey='unused')
2506  self.showunused.SetValue(shuu)
2507  gridSizer.Add(item=self.showunused, flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
2508 
2509  #
2510  # symbol size
2511  #
2512  row += 1
2513  label = wx.StaticText(parent=panel, id=wx.ID_ANY, label=_("Symbol size:"))
2514  gridSizer.Add(item=label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
2515  symsize = int(UserSettings.Get(group='gcpman', key='symbol', subkey='size'))
2516  sizeWin = wx.SpinCtrl(parent=panel, id=wx.ID_ANY,
2517  min=1, max=20)
2518  sizeWin.SetValue(symsize)
2519  self.symbol['size'] = sizeWin.GetId()
2520  gridSizer.Add(item=sizeWin,
2521  flag=wx.ALIGN_RIGHT,
2522  pos=(row, 1))
2523 
2524  #
2525  # symbol width
2526  #
2527  row += 1
2528  label = wx.StaticText(parent=panel, id=wx.ID_ANY, label=_("Line width:"))
2529  gridSizer.Add(item=label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
2530  width = int(UserSettings.Get(group='gcpman', key='symbol', subkey='width'))
2531  widWin = wx.SpinCtrl(parent=panel, id=wx.ID_ANY,
2532  min=1, max=10)
2533  widWin.SetValue(width)
2534  self.symbol['width'] = widWin.GetId()
2535  gridSizer.Add(item=widWin,
2536  flag=wx.ALIGN_RIGHT,
2537  pos=(row, 1))
2538 
2539  boxSizer.Add(item=gridSizer, flag=wx.EXPAND)
2540  sizer.Add(item=boxSizer, flag=wx.EXPAND | wx.ALL, border=5)
2541 
2542  #
2543  # maps to display
2544  #
2545  # source map to display
2546  self.srcselection = Select(panel, id=wx.ID_ANY,
2547  size=globalvar.DIALOG_GSELECT_SIZE, type='cell', updateOnPopup = False)
2548  self.parent.grwiz.SwitchEnv('source')
2549  self.srcselection.SetElementList(maptype)
2550  # filter out all maps not in group
2551  self.srcselection.tcp.GetElementList(elements = self.parent.src_maps)
2552 
2553  # target map to display
2554  self.tgtselection = Select(panel, id=wx.ID_ANY,
2555  size=globalvar.DIALOG_GSELECT_SIZE, type='cell', updateOnPopup = False)
2556  self.parent.grwiz.SwitchEnv('target')
2557  self.tgtselection.SetElementList(maptype)
2558  self.tgtselection.GetElementList()
2559 
2560  sizer.Add(item=wx.StaticText(parent=panel, id=wx.ID_ANY, label=_('Select source map to display:')),
2561  proportion=0, flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5)
2562  sizer.Add(item=self.srcselection, proportion=0,
2563  flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5)
2564  self.srcselection.SetValue(src_map)
2565  sizer.Add(item=wx.StaticText(parent=panel, id=wx.ID_ANY, label=_('Select target map to display:')),
2566  proportion=0, flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5)
2567  sizer.Add(item=self.tgtselection, proportion=0,
2568  flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5)
2569  self.tgtselection.SetValue(tgt_map)
2570 
2571  # bindings
2572  self.highlighthighest.Bind(wx.EVT_CHECKBOX, self.OnHighlight)
2573  self.rmsWin.Bind(wx.EVT_TEXT, self.OnSDFactor)
2574  self.srcselection.Bind(wx.EVT_TEXT, self.OnSrcSelection)
2575  self.tgtselection.Bind(wx.EVT_TEXT, self.OnTgtSelection)
2576 
2577  panel.SetSizer(sizer)
2578 
2579  return panel
2580 
2581  def __CreateRectificationPage(self, notebook):
2582  """!Create notebook page with symbology settings"""
2583 
2584  panel = wx.Panel(parent=notebook, id=wx.ID_ANY)
2585  notebook.AddPage(page=panel, text=_("Rectification"))
2586 
2587  sizer = wx.BoxSizer(wx.VERTICAL)
2588 
2589  # transformation order
2590  self.rb_grorder = wx.RadioBox(parent=panel, id=wx.ID_ANY,
2591  label=" %s " % _("Select rectification order"),
2592  choices=[_('1st order'), _('2nd order'), _('3rd order')],
2593  majorDimension=wx.RA_SPECIFY_COLS)
2594  sizer.Add(item=self.rb_grorder, proportion=0,
2595  flag=wx.EXPAND | wx.ALL, border=5)
2596  self.rb_grorder.SetSelection(self.parent.gr_order - 1)
2597 
2598  # interpolation method
2599  gridSizer = wx.GridBagSizer(vgap=5, hgap=5)
2600  gridSizer.AddGrowableCol(1)
2601  gridSizer.Add(item=wx.StaticText(parent=panel, id=wx.ID_ANY, label=_('Select interpolation method:')),
2602  pos=(0,0), flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5)
2603  self.grmethod = wx.Choice(parent=panel, id=wx.ID_ANY,
2604  choices = self.methods)
2605  gridSizer.Add(item=self.grmethod, pos=(0,1),
2606  flag=wx.ALIGN_RIGHT, border=5)
2607  self.grmethod.SetStringSelection(self.parent.gr_method)
2608  sizer.Add(item=gridSizer, flag=wx.EXPAND | wx.ALL, border=5)
2609 
2610  # clip to region
2611  self.check = wx.CheckBox(parent=panel, id=wx.ID_ANY,
2612  label=_("clip to computational region in target location"))
2613  sizer.Add(item=self.check, proportion=0,
2614  flag=wx.EXPAND | wx.ALL, border=5)
2615  self.check.SetValue(self.parent.clip_to_region)
2616 
2617  # extension
2618  sizer.Add(item=wx.StaticText(parent=panel, id=wx.ID_ANY, label=_('Extension for output maps:')),
2619  proportion=0, flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5)
2620  self.ext_txt = wx.TextCtrl(parent=panel, id=wx.ID_ANY, value="", size=(350,-1))
2621  self.ext_txt.SetValue(self.parent.extension)
2622  sizer.Add(item=self.ext_txt,
2623  proportion=0, flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5)
2624 
2625  # bindings
2626  self.ext_txt.Bind(wx.EVT_TEXT, self.OnExtension)
2627  self.Bind(wx.EVT_RADIOBOX, self.parent.OnGROrder, self.rb_grorder)
2628  self.Bind(wx.EVT_CHOICE, self.OnMethod, self.grmethod)
2629  self.Bind(wx.EVT_CHECKBOX, self.OnClipRegion, self.check)
2630 
2631  panel.SetSizer(sizer)
2632 
2633  return panel
2634 
2635  def OnHighlight(self, event):
2636  """!Checkbox 'highlighthighest' checked/unchecked"""
2637  if self.highlighthighest.IsChecked():
2638  self.parent.highest_only = True
2639  self.rmsWin.Disable()
2640  else:
2641  self.parent.highest_only = False
2642  self.rmsWin.Enable()
2643 
2644  def OnSDFactor(self,event):
2645  """!New factor for RMS threshold = M + SD * factor"""
2646 
2647  self.sdfactor = float(event.GetString())
2648 
2649  if self.sdfactor <= 0:
2650  GError(parent = self,
2651  message=_('RMS threshold factor must be > 0'))
2652  elif self.sdfactor < 1:
2653  GError(parent = self,
2654  message=_('RMS threshold factor is < 1\n'
2655  'Too many points might be highlighted'))
2656 
2657  def OnSrcSelection(self,event):
2658  """!Source map to display selected"""
2659  global src_map
2660 
2661  tmp_map = event.GetString()
2662 
2663  if not tmp_map == '' and not tmp_map == src_map:
2664  self.new_src_map = tmp_map
2665 
2666  def OnTgtSelection(self,event):
2667  """!Target map to display selected"""
2668  global tgt_map
2669 
2670  tmp_map = event.GetString()
2671 
2672  if not tmp_map == tgt_map:
2673  self.new_tgt_map = tmp_map
2674 
2675  def OnMethod(self, event):
2676  self.parent.gr_method = self.methods[event.GetSelection()]
2677 
2678  def OnClipRegion(self, event):
2679  self.parent.clip_to_region = event.IsChecked()
2680 
2681  def OnExtension(self, event):
2682  self.parent.extension = event.GetString()
2683 
2684  def UpdateSettings(self):
2685  global src_map
2686  global tgt_map
2687 
2688  layers = None
2689 
2690  UserSettings.Set(group='gcpman', key='rms', subkey='highestonly',
2691  value=self.highlighthighest.GetValue())
2692  if self.sdfactor > 0:
2693  UserSettings.Set(group='gcpman', key='rms', subkey='sdfactor',
2694  value=self.sdfactor)
2695 
2696  self.parent.sdfactor = self.sdfactor
2697  if self.parent.rmsthresh > 0:
2698  self.parent.rmsthresh = self.parent.mean + self.parent.sdfactor * self.parent.rmssd
2699 
2700  UserSettings.Set(group='gcpman', key='symbol', subkey='color',
2701  value=tuple(wx.FindWindowById(self.symbol['color']).GetColour()))
2702  UserSettings.Set(group='gcpman', key='symbol', subkey='hcolor',
2703  value=tuple(wx.FindWindowById(self.symbol['hcolor']).GetColour()))
2704  UserSettings.Set(group='gcpman', key='symbol', subkey='scolor',
2705  value=tuple(wx.FindWindowById(self.symbol['scolor']).GetColour()))
2706  UserSettings.Set(group='gcpman', key='symbol', subkey='ucolor',
2707  value=tuple(wx.FindWindowById(self.symbol['ucolor']).GetColour()))
2708  UserSettings.Set(group='gcpman', key='symbol', subkey='unused',
2709  value=self.showunused.GetValue())
2710  UserSettings.Set(group='gcpman', key='symbol', subkey='size',
2711  value=wx.FindWindowById(self.symbol['size']).GetValue())
2712  UserSettings.Set(group='gcpman', key='symbol', subkey='width',
2713  value=wx.FindWindowById(self.symbol['width']).GetValue())
2714 
2715  srcrender = False
2716  srcrenderVector = False
2717  tgtrender = False
2718  tgtrenderVector = False
2719  if self.new_src_map != src_map:
2720  # remove old layer
2721  layers = self.parent.grwiz.SrcMap.GetListOfLayers()
2722  self.parent.grwiz.SrcMap.DeleteLayer(layers[0])
2723 
2724  src_map = self.new_src_map
2725  cmdlist = ['d.rast', 'map=%s' % src_map]
2726  self.parent.grwiz.SwitchEnv('source')
2727  name, found = utils.GetLayerNameFromCmd(cmdlist),
2728  self.parent.grwiz.SrcMap.AddLayer(type='raster', command=cmdlist, l_active=True,
2729  name=name, l_hidden=False, l_opacity=1.0, l_render=False)
2730 
2731  self.parent.grwiz.SwitchEnv('target')
2732  srcrender = True
2733 
2734  if self.new_tgt_map != tgt_map:
2735  # remove old layer
2736  layers = self.parent.grwiz.TgtMap.GetListOfLayers()
2737  if layers:
2738  self.parent.grwiz.TgtMap.DeleteLayer(layers[0])
2739  tgt_map = self.new_tgt_map
2740 
2741  if tgt_map != '':
2742  cmdlist = ['d.rast', 'map=%s' % tgt_map]
2743  name, found = utils.GetLayerNameFromCmd(cmdlist)
2744  self.parent.grwiz.TgtMap.AddLayer(type='raster', command=cmdlist, l_active=True,
2745  name=name, l_hidden=False, l_opacity=1.0, l_render=False)
2746 
2747  tgtrender = True
2748  if self.parent.show_target == False:
2749  self.parent.show_target = True
2750  self.parent._mgr.GetPane("target").Show()
2751  self.parent._mgr.Update()
2752  self.parent.GetMapToolbar().Enable('zoommenu', enable = True)
2753  self.parent.activemap.Enable()
2754  self.parent.TgtMapWindow.ZoomToMap(layers = self.parent.TgtMap.GetListOfLayers())
2755  else: # tgt_map == ''
2756  if self.parent.show_target == True:
2757  self.parent.show_target = False
2758  self.parent._mgr.GetPane("target").Hide()
2759  self.parent._mgr.Update()
2760  self.parent.activemap.SetSelection(0)
2761  self.parent.activemap.Enable(False)
2762  self.parent.GetMapToolbar().Enable('zoommenu', enable = False)
2763 
2764  self.parent.UpdateColours(srcrender, srcrenderVector, tgtrender, tgtrenderVector)
2765 
2766  def OnSave(self, event):
2767  """!Button 'Save' pressed"""
2768  self.UpdateSettings()
2769  fileSettings = {}
2770  UserSettings.ReadSettingsFile(settings=fileSettings)
2771  fileSettings['gcpman'] = UserSettings.Get(group='gcpman')
2772  file = UserSettings.SaveToFile(fileSettings)
2773  self.parent.parent.goutput.WriteLog(_('GCP Manager settings saved to file \'%s\'.') % file)
2774  #self.Close()
2775 
2776  def OnApply(self, event):
2777  """!Button 'Apply' pressed"""
2778  self.UpdateSettings()
2779  #self.Close()
2780 
2781  def OnClose(self, event):
2782  """!Button 'Cancel' pressed"""
2783  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.
int
Definition: y.tab.c:1344
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:1402
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:633
def OnHelp
Show GCP Manager manual page.