source: grass/trunk/gui/wxpython/gcp/manager.py@ 73229

Last change on this file since 73229 was 73229, checked in by annakrat, 6 years ago

experimental GSoC 2018 Python 3 support by Sanjeet Bhatti

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