gcpmanager.py 95 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537
  1. """!
  2. @package gcpmanager.py
  3. @brief Georectification module for GRASS GIS. Includes ground control
  4. point management and interactive point and click GCP creation
  5. Classes:
  6. - GCPWizard
  7. - LocationPage
  8. - GroupPage
  9. - DispMapPage
  10. - GCP
  11. - GCPList
  12. - VectGroup
  13. - EditGCP
  14. - GrSettingsDialog
  15. (C) 2006-2010 by the GRASS Development Team
  16. This program is free software under the GNU General Public License
  17. (>=v2). Read the file COPYING that comes with GRASS for details.
  18. @author Markus Metz
  19. @author Michael Barton
  20. @author Updated by Martin Landa <landa.martin gmail.com>
  21. """
  22. import os
  23. import sys
  24. import tempfile
  25. import shutil
  26. import time
  27. import wx
  28. from wx.lib.mixins.listctrl import CheckListCtrlMixin, ColumnSorterMixin, ListCtrlAutoWidthMixin
  29. import wx.lib.colourselect as csel
  30. import wx.wizard as wiz
  31. from wx.lib.embeddedimage import PyEmbeddedImage
  32. import grass.script as grass
  33. import globalvar
  34. import render
  35. import toolbars
  36. import menuform
  37. import gselect
  38. import gcmd
  39. import utils
  40. from debug import Debug as Debug
  41. from icon import Icons as Icons
  42. from location_wizard import TitledPage as TitledPage
  43. from preferences import globalSettings as UserSettings
  44. from gcpmapdisp import MapFrame
  45. from mapdisp_window import BufferedWindow
  46. try:
  47. import subprocess # Not needed if GRASS commands could actually be quiet
  48. except:
  49. CompatPath = globalvar.ETCWXDIR
  50. sys.path.append(CompatPath)
  51. from compat import subprocess
  52. gmpath = os.path.join(globalvar.ETCWXDIR, "icons")
  53. sys.path.append(gmpath)
  54. #
  55. # global variables
  56. #
  57. global src_map
  58. global tgt_map
  59. global maptype
  60. src_map = ''
  61. tgt_map = ''
  62. maptype = 'cell'
  63. class GCPWizard(object):
  64. """
  65. Start wizard here and finish wizard here
  66. """
  67. def __init__(self, parent):
  68. self.parent = parent # GMFrame
  69. #
  70. # get environmental variables
  71. #
  72. self.grassdatabase = grass.gisenv()['GISDBASE']
  73. #
  74. # read original environment settings
  75. #
  76. self.target_gisrc = os.environ['GISRC']
  77. self.gisrc_dict = {}
  78. try:
  79. f = open(self.target_gisrc, 'r')
  80. for line in f.readlines():
  81. line = line.replace('\n', '').strip()
  82. if len(line) < 1:
  83. continue
  84. key, value = line.split(':', 1)
  85. self.gisrc_dict[key.strip()] = value.strip()
  86. finally:
  87. f.close()
  88. self.currentlocation = self.gisrc_dict['LOCATION_NAME']
  89. self.currentmapset = self.gisrc_dict['MAPSET']
  90. # location for xy map to georectify
  91. self.newlocation = ''
  92. # mapset for xy map to georectify
  93. self.newmapset = ''
  94. global maptype
  95. global src_map
  96. global tgt_map
  97. src_map = ''
  98. tgt_map = ''
  99. maptype = 'cell'
  100. # GISRC file for source location/mapset of map(s) to georectify
  101. self.source_gisrc = ''
  102. #
  103. # define wizard pages
  104. #
  105. self.wizard = wiz.Wizard(parent=parent, id=wx.ID_ANY, title=_("Setup for georectification"))
  106. self.startpage = LocationPage(self.wizard, self)
  107. self.grouppage = GroupPage(self.wizard, self)
  108. self.mappage = DispMapPage(self.wizard, self)
  109. #
  110. # set the initial order of the pages
  111. #
  112. self.startpage.SetNext(self.grouppage)
  113. self.grouppage.SetPrev(self.startpage)
  114. self.grouppage.SetNext(self.mappage)
  115. self.mappage.SetPrev(self.grouppage)
  116. #
  117. # do pages layout
  118. #
  119. self.startpage.DoLayout()
  120. self.grouppage.DoLayout()
  121. self.mappage.DoLayout()
  122. self.wizard.FitToPage(self.startpage)
  123. # self.Bind(wx.EVT_CLOSE, self.Cleanup)
  124. # self.parent.Bind(wx.EVT_ACTIVATE, self.OnGLMFocus)
  125. success = False
  126. #
  127. # run wizard
  128. #
  129. if self.wizard.RunWizard(self.startpage):
  130. success = self.OnWizFinished()
  131. if success == False:
  132. wx.MessageBox(parent=self.parent,
  133. message=_("Georectifying setup canceled."),
  134. caption=_("Georectify"),
  135. style=wx.OK | wx.ICON_INFORMATION | wx.CENTRE)
  136. self.Cleanup()
  137. else:
  138. wx.MessageBox(parent=self.parent,
  139. message=_("Georectifying setup canceled."),
  140. caption=_("Georectify"),
  141. style=wx.OK | wx.ICON_INFORMATION | wx.CENTRE)
  142. self.Cleanup()
  143. #
  144. # start GCP display
  145. #
  146. if success != False:
  147. # instance of render.Map to be associated with display
  148. self.SwitchEnv('source')
  149. self.SrcMap = render.Map(gisrc=self.source_gisrc)
  150. self.SwitchEnv('target')
  151. self.TgtMap = render.Map(gisrc=self.target_gisrc)
  152. self.Map = self.SrcMap
  153. #
  154. # add layer to source map
  155. #
  156. if maptype == 'cell':
  157. rendertype = 'raster'
  158. cmdlist = ['d.rast', 'map=%s' % src_map]
  159. else: # -> vector layer
  160. rendertype = 'vector'
  161. cmdlist = ['d.vect', 'map=%s' % src_map]
  162. self.SwitchEnv('source')
  163. self.SrcMap.AddLayer(type=rendertype, command=cmdlist, l_active=True,
  164. name=utils.GetLayerNameFromCmd(cmdlist),
  165. l_hidden=False, l_opacity=1.0, l_render=False)
  166. #
  167. # add layer to target map
  168. #
  169. if maptype == 'cell':
  170. rendertype = 'raster'
  171. cmdlist = ['d.rast', 'map=%s' % tgt_map]
  172. else: # -> vector layer
  173. rendertype = 'vector'
  174. cmdlist = ['d.vect', 'map=%s' % tgt_map]
  175. self.SwitchEnv('target')
  176. self.TgtMap.AddLayer(type=rendertype, command=cmdlist, l_active=True,
  177. name=utils.GetLayerNameFromCmd(cmdlist),
  178. l_hidden=False, l_opacity=1.0, l_render=False)
  179. #
  180. # start GCP Manager
  181. #
  182. self.gcpmgr = GCP(self.parent, grwiz=self, size=globalvar.MAP_WINDOW_SIZE,
  183. toolbars=["gcpdisp"],
  184. Map=self.SrcMap, lmgr=self.parent)
  185. # load GCPs
  186. self.gcpmgr.InitMapDisplay()
  187. self.gcpmgr.CenterOnScreen()
  188. self.gcpmgr.Show()
  189. #self.gcpmgr.Centre()
  190. #self.gcpmgr.Raise()
  191. else:
  192. self.Cleanup()
  193. def SetSrcEnv(self, location, mapset):
  194. """!Create environment to use for location and mapset
  195. that are the source of the file(s) to georectify
  196. @param location source location
  197. @param mapset source mapset
  198. @return False on error
  199. @return True on success
  200. """
  201. self.newlocation = location
  202. self.newmapset = mapset
  203. # check to see if we are georectifying map in current working location/mapset
  204. if self.newlocation == self.currentlocation and self.newmapset == self.currentmapset:
  205. return False
  206. self.gisrc_dict['LOCATION_NAME'] = location
  207. self.gisrc_dict['MAPSET'] = mapset
  208. self.source_gisrc = utils.GetTempfile()
  209. try:
  210. f = open(self.source_gisrc, mode='w')
  211. for line in self.gisrc_dict.items():
  212. f.write(line[0] + ": " + line[1] + "\n")
  213. finally:
  214. f.close()
  215. return True
  216. def SwitchEnv(self, grc):
  217. """
  218. Switches between original working location/mapset and
  219. location/mapset that is source of file(s) to georectify
  220. """
  221. # check to see if we are georectifying map in current working location/mapset
  222. if self.newlocation == self.currentlocation and self.newmapset == self.currentmapset:
  223. return False
  224. if grc == 'target':
  225. os.environ["GISRC"] = str(self.target_gisrc)
  226. elif grc == 'source':
  227. os.environ["GISRC"] = str(self.source_gisrc)
  228. return True
  229. def OnWizFinished(self):
  230. # self.Cleanup()
  231. return True
  232. def OnGLMFocus(self, event):
  233. """!Layer Manager focus"""
  234. # self.SwitchEnv('target')
  235. event.Skip()
  236. def Cleanup(self):
  237. """!Return to current location and mapset"""
  238. self.SwitchEnv('target')
  239. self.parent.gcpmanagement = None
  240. self.wizard.Destroy()
  241. class LocationPage(TitledPage):
  242. """
  243. Set map type (raster or vector) to georectify and
  244. select location/mapset of map(s) to georectify.
  245. """
  246. def __init__(self, wizard, parent):
  247. TitledPage.__init__(self, wizard, _("Select map type and location/mapset"))
  248. self.parent = parent
  249. self.grassdatabase = self.parent.grassdatabase
  250. self.xylocation = ''
  251. self.xymapset = ''
  252. #
  253. # layout
  254. #
  255. self.sizer.AddGrowableCol(2)
  256. # map type
  257. self.rb_maptype = wx.RadioBox(parent=self, id=wx.ID_ANY,
  258. label=' %s ' % _("Map type to georectify"),
  259. choices=[_('raster'), _('vector')],
  260. majorDimension=wx.RA_SPECIFY_COLS)
  261. self.sizer.Add(item=self.rb_maptype,
  262. flag=wx.ALIGN_CENTER | wx.ALL | wx.EXPAND, border=5,
  263. pos=(1, 1), span=(1, 2))
  264. # location
  265. self.sizer.Add(item=wx.StaticText(parent=self, id=wx.ID_ANY, label=_('Select source location:')),
  266. flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5,
  267. pos=(2, 1))
  268. self.cb_location = gselect.LocationSelect(parent = self, gisdbase = self.grassdatabase)
  269. self.sizer.Add(item=self.cb_location,
  270. flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5,
  271. pos=(2, 2))
  272. # mapset
  273. self.sizer.Add(item=wx.StaticText(parent=self, id=wx.ID_ANY, label=_('Select source mapset:')),
  274. flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5,
  275. pos=(3, 1))
  276. self.cb_mapset = gselect.MapsetSelect(parent = self, gisdbase = self.grassdatabase,
  277. setItems = False)
  278. self.sizer.Add(item=self.cb_mapset,
  279. flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5,
  280. pos=(3,2))
  281. #
  282. # bindings
  283. #
  284. self.Bind(wx.EVT_RADIOBOX, self.OnMaptype, self.rb_maptype)
  285. self.Bind(wx.EVT_COMBOBOX, self.OnLocation, self.cb_location)
  286. self.Bind(wx.EVT_COMBOBOX, self.OnMapset, self.cb_mapset)
  287. self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
  288. self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage)
  289. # self.Bind(wx.EVT_CLOSE, self.parent.Cleanup)
  290. def OnMaptype(self,event):
  291. """!Change map type"""
  292. global maptype
  293. if event.GetInt() == 0:
  294. maptype = 'cell'
  295. else:
  296. maptype = 'vector'
  297. def OnLocation(self, event):
  298. """!Sets source location for map(s) to georectify"""
  299. self.xylocation = event.GetString()
  300. #create a list of valid mapsets
  301. tmplist = os.listdir(os.path.join(self.grassdatabase, self.xylocation))
  302. self.mapsetList = []
  303. for item in tmplist:
  304. if os.path.isdir(os.path.join(self.grassdatabase, self.xylocation, item)) and \
  305. os.path.exists(os.path.join(self.grassdatabase, self.xylocation, item, 'WIND')):
  306. if item != 'PERMANENT':
  307. self.mapsetList.append(item)
  308. self.xymapset = 'PERMANENT'
  309. utils.ListSortLower(self.mapsetList)
  310. self.mapsetList.insert(0, 'PERMANENT')
  311. self.cb_mapset.SetItems(self.mapsetList)
  312. self.cb_mapset.SetStringSelection(self.xymapset)
  313. if not wx.FindWindowById(wx.ID_FORWARD).IsEnabled():
  314. wx.FindWindowById(wx.ID_FORWARD).Enable(True)
  315. def OnMapset(self, event):
  316. """!Sets source mapset for map(s) to georectify"""
  317. if self.xylocation == '':
  318. wx.MessageBox(_('You must select a valid location before selecting a mapset'))
  319. return
  320. self.xymapset = event.GetString()
  321. if not wx.FindWindowById(wx.ID_FORWARD).IsEnabled():
  322. wx.FindWindowById(wx.ID_FORWARD).Enable(True)
  323. def OnPageChanging(self, event=None):
  324. if event.GetDirection() and \
  325. (self.xylocation == '' or self.xymapset == ''):
  326. wx.MessageBox(_('You must select a valid location and mapset in order to continue'))
  327. event.Veto()
  328. return
  329. self.parent.SetSrcEnv(self.xylocation, self.xymapset)
  330. def OnEnterPage(self, event=None):
  331. if self.xylocation == '' or self.xymapset == '':
  332. wx.FindWindowById(wx.ID_FORWARD).Enable(False)
  333. else:
  334. wx.FindWindowById(wx.ID_FORWARD).Enable(True)
  335. class GroupPage(TitledPage):
  336. """
  337. Set group to georectify. Create group if desired.
  338. """
  339. def __init__(self, wizard, parent):
  340. TitledPage.__init__(self, wizard, _("Select image/map group to georectify"))
  341. self.parent = parent
  342. self.grassdatabase = self.parent.grassdatabase
  343. self.groupList = []
  344. self.xylocation = ''
  345. self.xymapset = ''
  346. self.xygroup = ''
  347. # default extension
  348. self.extension = 'georect' + str(os.getpid())
  349. #
  350. # layout
  351. #
  352. self.sizer.AddGrowableCol(2)
  353. # group
  354. self.sizer.Add(item=wx.StaticText(parent=self, id=wx.ID_ANY, label=_('Select group:')),
  355. flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5,
  356. pos=(1, 1))
  357. self.cb_group = wx.ComboBox(parent=self, id=wx.ID_ANY,
  358. choices=self.groupList, size=(350, -1),
  359. style=wx.CB_DROPDOWN | wx.CB_READONLY)
  360. self.sizer.Add(item=self.cb_group,
  361. flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5,
  362. pos=(1, 2))
  363. # create group
  364. self.sizer.Add(item=wx.StaticText(parent=self, id=wx.ID_ANY, label=_('Create group if none exists')),
  365. flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5,
  366. pos=(2, 1))
  367. btnSizer = wx.BoxSizer(wx.HORIZONTAL)
  368. self.btn_mkgroup = wx.Button(parent=self, id=wx.ID_ANY, label=_("Create/edit group..."))
  369. self.btn_vgroup = wx.Button(parent=self, id=wx.ID_ANY, label=_("Add vector map to group..."))
  370. btnSizer.Add(item=self.btn_mkgroup,
  371. flag=wx.RIGHT, border=5)
  372. btnSizer.Add(item=self.btn_vgroup,
  373. flag=wx.LEFT, border=5)
  374. self.sizer.Add(item=btnSizer,
  375. flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5,
  376. pos=(2, 2))
  377. # extension
  378. self.sizer.Add(item=wx.StaticText(parent=self, id=wx.ID_ANY, label=_('Extension for output maps:')),
  379. flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5,
  380. pos=(3, 1))
  381. self.ext_txt = wx.TextCtrl(parent=self, id=wx.ID_ANY, value="", size=(350,-1))
  382. self.ext_txt.SetValue(self.extension)
  383. self.sizer.Add(item=self.ext_txt,
  384. flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5,
  385. pos=(3, 2))
  386. #
  387. # bindings
  388. #
  389. self.Bind(wx.EVT_COMBOBOX, self.OnGroup, self.cb_group)
  390. self.Bind(wx.EVT_TEXT, self.OnExtension, self.ext_txt)
  391. self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
  392. self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage)
  393. self.Bind(wx.EVT_CLOSE, self.parent.Cleanup)
  394. # hide vector group button by default
  395. self.btn_vgroup.Hide()
  396. def OnGroup(self, event):
  397. self.xygroup = event.GetString()
  398. def OnMkGroup(self, event):
  399. """!Create new group in source location/mapset"""
  400. menuform.GUI().ParseCommand(['i.group'],
  401. completed=(self.GetOptData, None, ''),
  402. parentframe=self.parent.parent, modal=True)
  403. def OnVGroup(self, event):
  404. """!Add vector maps to group"""
  405. dlg = VectGroup(parent = self,
  406. id = wx.ID_ANY,
  407. grassdb = self.grassdatabase,
  408. location = self.xylocation,
  409. mapset = self.xymapset,
  410. group = self.xygroup)
  411. if dlg.ShowModal() != wx.ID_OK:
  412. return
  413. dlg.MakeVGroup()
  414. self.OnEnterPage()
  415. def GetOptData(self, dcmd, layer, params, propwin):
  416. """!Process i.group"""
  417. # update the page
  418. if dcmd:
  419. gcmd.Command(dcmd)
  420. self.OnEnterPage()
  421. self.Update()
  422. def OnExtension(self, event):
  423. self.extension = event.GetString()
  424. def OnPageChanging(self, event=None):
  425. if event.GetDirection() and self.xygroup == '':
  426. wx.MessageBox(_('You must select a valid image/map group in order to continue'))
  427. event.Veto()
  428. return
  429. if event.GetDirection() and self.extension == '':
  430. wx.MessageBox(_('You must enter an map name extension in order to continue'))
  431. event.Veto()
  432. return
  433. def OnEnterPage(self, event=None):
  434. global maptype
  435. self.groupList = []
  436. self.xylocation = self.parent.gisrc_dict['LOCATION_NAME']
  437. self.xymapset = self.parent.gisrc_dict['MAPSET']
  438. # create a list of groups in selected mapset
  439. if os.path.isdir(os.path.join(self.grassdatabase,
  440. self.xylocation,
  441. self.xymapset,
  442. 'group')):
  443. tmplist = os.listdir(os.path.join(self.grassdatabase,
  444. self.xylocation,
  445. self.xymapset,
  446. 'group'))
  447. for item in tmplist:
  448. if os.path.isdir(os.path.join(self.grassdatabase,
  449. self.xylocation,
  450. self.xymapset,
  451. 'group',
  452. item)):
  453. self.groupList.append(item)
  454. if maptype == 'cell':
  455. self.btn_vgroup.Hide()
  456. self.Bind(wx.EVT_BUTTON, self.OnMkGroup, self.btn_mkgroup)
  457. elif maptype == 'vector':
  458. self.btn_vgroup.Show()
  459. self.Bind(wx.EVT_BUTTON, self.OnMkGroup, self.btn_mkgroup)
  460. self.Bind(wx.EVT_BUTTON, self.OnVGroup, self.btn_vgroup)
  461. utils.ListSortLower(self.groupList)
  462. self.cb_group.SetItems(self.groupList)
  463. if len(self.groupList) > 0 and \
  464. self.xygroup == '':
  465. self.cb_group.SetSelection(0)
  466. self.xygroup = self.groupList[0]
  467. if self.xygroup == '' or \
  468. self.extension == '':
  469. wx.FindWindowById(wx.ID_FORWARD).Enable(False)
  470. else:
  471. wx.FindWindowById(wx.ID_FORWARD).Enable(True)
  472. # switch to source
  473. self.parent.SwitchEnv('source')
  474. class DispMapPage(TitledPage):
  475. """
  476. Select ungeoreferenced map to display for interactively
  477. setting ground control points (GCPs).
  478. """
  479. def __init__(self, wizard, parent):
  480. TitledPage.__init__(self, wizard,
  481. _("Select maps to display for ground control point (GCP) creation"))
  482. self.parent = parent
  483. global maptype
  484. #
  485. # layout
  486. #
  487. self.sizer.Add(item=wx.StaticText(parent=self, id=wx.ID_ANY, label=_('Select source map to display:')),
  488. flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5,
  489. pos=(1, 1))
  490. self.srcselection = gselect.Select(self, id=wx.ID_ANY,
  491. size=globalvar.DIALOG_GSELECT_SIZE, type='cell', updateOnPopup = False)
  492. self.sizer.Add(item=self.srcselection,
  493. flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5,
  494. pos=(1, 2))
  495. self.sizer.Add(item=wx.StaticText(parent=self, id=wx.ID_ANY, label=_('Select target map to display:')),
  496. flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5,
  497. pos=(2, 1))
  498. self.tgtselection = gselect.Select(self, id=wx.ID_ANY,
  499. size=globalvar.DIALOG_GSELECT_SIZE, type='cell', updateOnPopup = False)
  500. self.sizer.Add(item=self.tgtselection,
  501. flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5,
  502. pos=(2, 2))
  503. #
  504. # bindings
  505. #
  506. self.srcselection.Bind(wx.EVT_TEXT, self.OnSrcSelection)
  507. self.tgtselection.Bind(wx.EVT_TEXT, self.OnTgtSelection)
  508. self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
  509. self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage)
  510. self.Bind(wx.EVT_CLOSE, self.parent.Cleanup)
  511. def OnSrcSelection(self,event):
  512. """!Source map to display selected"""
  513. global src_map
  514. global maptype
  515. src_map = event.GetString()
  516. if src_map == '' or tgt_map == '':
  517. wx.FindWindowById(wx.ID_FORWARD).Enable(False)
  518. else:
  519. wx.FindWindowById(wx.ID_FORWARD).Enable(True)
  520. try:
  521. # set computational region to match selected map and zoom display to region
  522. if maptype == 'cell':
  523. p = gcmd.Command(['g.region', 'rast=src_map'])
  524. elif maptype == 'vector':
  525. p = gcmd.Command(['g.region', 'vect=src_map'])
  526. if p.returncode == 0:
  527. print 'returncode = ', str(p.returncode)
  528. self.parent.Map.region = self.parent.Map.GetRegion()
  529. except:
  530. pass
  531. def OnTgtSelection(self,event):
  532. """!Source map to display selected"""
  533. global tgt_map
  534. tgt_map = event.GetString()
  535. if src_map == '' or tgt_map == '':
  536. wx.FindWindowById(wx.ID_FORWARD).Enable(False)
  537. else:
  538. wx.FindWindowById(wx.ID_FORWARD).Enable(True)
  539. def OnPageChanging(self, event=None):
  540. global src_map
  541. global tgt_map
  542. if event.GetDirection() and (src_map == '' or tgt_map == ''):
  543. wx.MessageBox(_('You must select maps in order to continue'))
  544. event.Veto()
  545. return
  546. self.parent.SwitchEnv('target')
  547. def OnEnterPage(self, event=None):
  548. global maptype
  549. global src_map
  550. global tgt_map
  551. self.srcselection.SetElementList(maptype,
  552. mapsets = [self.parent.newmapset, ])
  553. self.srcselection.GetElementList()
  554. self.parent.SwitchEnv('target')
  555. self.tgtselection.SetElementList(maptype)
  556. self.tgtselection.GetElementList()
  557. self.parent.SwitchEnv('source')
  558. if src_map == '' or tgt_map == '':
  559. wx.FindWindowById(wx.ID_FORWARD).Enable(False)
  560. else:
  561. wx.FindWindowById(wx.ID_FORWARD).Enable(True)
  562. class GCP(MapFrame, wx.Frame, ColumnSorterMixin):
  563. """!
  564. Manages ground control points for georectifying. Calculates RMS statics.
  565. Calls i.rectify or v.transform to georectify map.
  566. """
  567. def __init__(self, parent, grwiz = None, mapdisp = None, id = wx.ID_ANY,
  568. title = _("Manage Ground Control Points"),
  569. size = (700, 300), toolbars=["gcpdisp"], Map=None, lmgr=None):
  570. self.grwiz = grwiz # GR Wizard
  571. #wx.Frame.__init__(self, parent, id, title, size = size, name = "GCPFrame")
  572. MapFrame.__init__(self, parent, id, title, size = size,
  573. Map=Map, toolbars=["gcpdisp"], lmgr=lmgr, name='GCPMapWindow')
  574. #
  575. # init variables
  576. #
  577. self.parent = parent # GMFrame
  578. self.parent.gcpmanagement = self
  579. self.mapdisp = self # XY-location Map Display
  580. self.grassdatabase = self.grwiz.grassdatabase
  581. self.currentlocation = self.grwiz.currentlocation
  582. self.currentmapset = self.grwiz.currentmapset
  583. self.newlocation = self.grwiz.newlocation
  584. self.newmapset = self.grwiz.newmapset
  585. self.xylocation = self.grwiz.gisrc_dict['LOCATION_NAME']
  586. self.xymapset = self.grwiz.gisrc_dict['MAPSET']
  587. self.xygroup = self.grwiz.grouppage.xygroup
  588. self.extension = self.grwiz.grouppage.extension
  589. self.outname = ''
  590. self.VectGRList = []
  591. self.file = {
  592. 'points' : os.path.join(self.grassdatabase,
  593. self.xylocation,
  594. self.xymapset,
  595. 'group',
  596. self.xygroup,
  597. 'POINTS'),
  598. 'points_bak' : os.path.join(self.grassdatabase,
  599. self.xylocation,
  600. self.xymapset,
  601. 'group',
  602. self.xygroup,
  603. 'POINTS_BAK'),
  604. 'rgrp' : os.path.join(self.grassdatabase,
  605. self.xylocation,
  606. self.xymapset,
  607. 'group',
  608. self.xygroup,
  609. 'REF'),
  610. 'vgrp' : os.path.join(self.grassdatabase,
  611. self.xylocation,
  612. self.xymapset,
  613. 'group',
  614. self.xygroup,
  615. 'VREF'),
  616. 'target' : os.path.join(self.grassdatabase,
  617. self.xylocation,
  618. self.xymapset,
  619. 'group',
  620. self.xygroup,
  621. 'TARGET'),
  622. }
  623. # make a backup of the current points file
  624. shutil.copy(self.file['points'], self.file['points_bak'])
  625. # polynomial order transformation for georectification
  626. self.gr_order = 1
  627. # number of GCPs selected to be used for georectification (checked)
  628. self.GCPcount = 0
  629. # forward RMS error
  630. self.fwd_rmserror = 0.0
  631. # backward RMS error
  632. self.bkw_rmserror = 0.0
  633. # list map coords and ID of map display they came from
  634. self.mapcoordlist = []
  635. self.mapcoordlist.append([ 0, # GCP number
  636. 0.0, # source east
  637. 0.0, # source north
  638. 0.0, # target east
  639. 0.0, # target north
  640. 0.0, # forward error
  641. 0.0 ] ) # backward error
  642. # region clipping for georectified map
  643. self.clip_to_region = False
  644. # init vars to highlight high RMS errors
  645. self.highest_only = True
  646. self.show_unused = True
  647. self.highest_key = -1
  648. self.rmsthresh = 0
  649. self.rmsmean = 0
  650. self.rmssd = 0
  651. self.SetTarget(self.xygroup, self.currentlocation, self.currentmapset)
  652. self.itemDataMap = None
  653. # images for column sorting
  654. SmallUpArrow = PyEmbeddedImage(
  655. "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAADxJ"
  656. "REFUOI1jZGRiZqAEMFGke2gY8P/f3/9kGwDTjM8QnAaga8JlCG3CAJdt2MQxDCAUaOjyjKMp"
  657. "cRAYAABS2CPsss3BWQAAAABJRU5ErkJggg==")
  658. SmallDnArrow = PyEmbeddedImage(
  659. "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAEhJ"
  660. "REFUOI1jZGRiZqAEMFGke9QABgYGBgYWdIH///7+J6SJkYmZEacLkCUJacZqAD5DsInTLhDR"
  661. "bcPlKrwugGnCFy6Mo3mBAQChDgRlP4RC7wAAAABJRU5ErkJggg==")
  662. # CheckListCtrlMixin must set an ImageList first
  663. self.il = self.list.GetImageList(wx.IMAGE_LIST_SMALL)
  664. self.sm_dn = self.il.Add(SmallDnArrow.GetBitmap())
  665. self.sm_up = self.il.Add(SmallUpArrow.GetBitmap())
  666. # set mouse characteristics
  667. self.mapwin = self.SrcMapWindow
  668. self.mapwin.mouse['box'] = 'point'
  669. self.mapwin.mouse["use"] == "pointer"
  670. self.mapwin.zoomtype = 0
  671. self.mapwin.pen = wx.Pen(colour='black', width=2, style=wx.SOLID)
  672. self.mapwin.SetCursor(self.cursors["cross"])
  673. self.mapwin = self.TgtMapWindow
  674. # set mouse characteristics
  675. self.mapwin.mouse['box'] = 'point'
  676. self.mapwin.mouse["use"] == "pointer"
  677. self.mapwin.zoomtype = 0
  678. self.mapwin.pen = wx.Pen(colour='black', width=2, style=wx.SOLID)
  679. self.mapwin.SetCursor(self.cursors["cross"])
  680. #
  681. # show new display & draw map
  682. #
  683. self.MapWindow = self.TgtMapWindow
  684. self.Map = self.TgtMap
  685. self.OnZoomToMap(None)
  686. self.MapWindow = self.SrcMapWindow
  687. self.Map = self.SrcMap
  688. self.OnZoomToMap(None)
  689. #
  690. # bindings
  691. #
  692. self.Bind(wx.EVT_ACTIVATE, self.OnFocus)
  693. self.Bind(wx.EVT_CLOSE, self.OnQuit)
  694. def __del__(self):
  695. """!Disable GCP manager mode"""
  696. self.parent.gcpmanagement = None
  697. def CreateGCPList(self):
  698. """!Create GCP List Control"""
  699. return GCPList(parent=self, gcp=self)
  700. # Used by the ColumnSorterMixin, see wx/lib/mixins/listctrl.py
  701. def GetListCtrl(self):
  702. return self.list
  703. # Used by the ColumnSorterMixin, see wx/lib/mixins/listctrl.py
  704. def GetSortImages(self):
  705. return (self.sm_dn, self.sm_up)
  706. def InitMapDisplay(self):
  707. self.list.LoadData()
  708. # initialize column sorter
  709. self.itemDataMap = self.mapcoordlist
  710. ColumnSorterMixin.__init__(self, self.list.GetColumnCount())
  711. def SetTarget(self, tgroup, tlocation, tmapset):
  712. """
  713. Sets rectification target to current location and mapset
  714. """
  715. # check to see if we are georectifying map in current working location/mapset
  716. if self.newlocation == self.currentlocation and self.newmapset == self.currentmapset:
  717. gcmd.RunCommand('i.target',
  718. parent = self,
  719. flags = 'c',
  720. group = tgroup)
  721. else:
  722. self.grwiz.SwitchEnv('source')
  723. gcmd.RunCommand('i.target',
  724. parent = self,
  725. group = tgroup,
  726. location = tlocation,
  727. mapset = tmapset)
  728. self.grwiz.SwitchEnv('target')
  729. def AddGCP(self, event):
  730. """
  731. Appends an item to GCP list
  732. """
  733. keyval = self.list.AddGCPItem() + 1
  734. # source east, source north, target east, target north, forward error, backward error
  735. self.mapcoordlist.append([ keyval, # GCP number
  736. 0.0, # source east
  737. 0.0, # source north
  738. 0.0, # target east
  739. 0.0, # target north
  740. 0.0, # forward error
  741. 0.0 ] ) # backward error
  742. if self.mapdisp.statusbarWin['toggle'].GetSelection() == 7: # go to
  743. self.mapdisp.StatusbarUpdate()
  744. def DeleteGCP(self, event):
  745. """
  746. Deletes selected item in GCP list
  747. """
  748. minNumOfItems = self.OnGROrder(None)
  749. if self.list.GetItemCount() <= minNumOfItems:
  750. wx.MessageBox(parent=self, message=_("At least %d GCPs required. Operation cancelled.") % minNumOfItems,
  751. caption=_("Delete GCP"), style=wx.OK | wx.ICON_INFORMATION)
  752. return
  753. item = self.list.DeleteGCPItem()
  754. del self.mapcoordlist[item]
  755. if self.mapdisp.statusbarWin['toggle'].GetSelection() == 7: # go to
  756. self.mapdisp.StatusbarUpdate()
  757. self.statusbarWin['goto'].SetValue(0)
  758. def ClearGCP(self, event):
  759. """
  760. Clears all values in selected item of GCP list and unchecks it
  761. """
  762. index = self.list.GetSelected()
  763. for i in range(4):
  764. self.list.SetStringItem(index, i, '0.0')
  765. self.list.SetStringItem(index, 4, '')
  766. self.list.SetStringItem(index, 5, '')
  767. self.list.CheckItem(index, False)
  768. key = self.list.GetItemData(index)
  769. # GCP number, source E, source N, target E, target N, fwd error, bkwd error
  770. self.mapcoordlist[key] = [key, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
  771. def DrawGCP(self, coordtype):
  772. """
  773. Updates GCP and map coord maps and redraws
  774. active (checked) GCP markers
  775. """
  776. self.highest_only = UserSettings.Get(group='gcpman', key='rms', subkey='highestonly')
  777. self.show_unused = UserSettings.Get(group='gcpman', key='symbol', subkey='unused')
  778. col = UserSettings.Get(group='gcpman', key='symbol', subkey='color')
  779. wxLowCol = wx.Colour(col[0], col[1], col[2], 255)
  780. col = UserSettings.Get(group='gcpman', key='symbol', subkey='hcolor')
  781. wxHiCol = wx.Colour(col[0], col[1], col[2], 255)
  782. col = UserSettings.Get(group='gcpman', key='symbol', subkey='scolor')
  783. wxSelCol = wx.Colour(col[0], col[1], col[2], 255)
  784. col = UserSettings.Get(group='gcpman', key='symbol', subkey='ucolor')
  785. wxUnCol = wx.Colour(col[0], col[1], col[2], 255)
  786. spx = UserSettings.Get(group='gcpman', key='symbol', subkey='size')
  787. wpx = UserSettings.Get(group='gcpman', key='symbol', subkey='width')
  788. font = self.GetFont()
  789. font.SetPointSize(int(spx) + 2)
  790. penOrig = polypenOrig = None
  791. mapWin = None
  792. if coordtype == 'source':
  793. mapWin = self.mapdisp.SrcMapWindow
  794. e_idx = 1
  795. n_idx = 2
  796. elif coordtype == 'target':
  797. mapWin = self.mapdisp.TgtMapWindow
  798. e_idx = 3
  799. n_idx = 4
  800. if not mapWin:
  801. wx.MessageBox(parent=self,
  802. message="%s%s." % (_("mapwin not defined for "),
  803. str(idx)),
  804. caption=_("Error"), style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
  805. return
  806. #for gcp in self.mapcoordlist:
  807. for idx in range(self.list.GetItemCount()):
  808. key = self.list.GetItemData(idx)
  809. gcp = self.mapcoordlist[key]
  810. if not self.list.IsChecked(idx):
  811. if self.show_unused:
  812. wxCol = wxUnCol
  813. else:
  814. continue
  815. else:
  816. if self.highest_only == True:
  817. if key == self.highest_key:
  818. wxCol = wxHiCol
  819. else:
  820. wxCol = wxLowCol
  821. elif self.rmsthresh > 0:
  822. if (gcp[5] > self.rmsthresh):
  823. wxCol = wxHiCol
  824. else:
  825. wxCol = wxLowCol
  826. if idx == self.list.selected:
  827. wxCol = wxSelCol
  828. if not penOrig:
  829. penOrig = mapWin.pen
  830. polypenOrig = mapWin.polypen
  831. mapWin.pen = wx.Pen(colour=wxCol, width=wpx, style=wx.SOLID)
  832. mapWin.polypen = wx.Pen(colour=wxCol, width=wpx, style=wx.SOLID) # ?
  833. mapWin.pen.SetColour(wxCol)
  834. mapWin.polypen.SetColour(wxCol)
  835. coord = mapWin.Cell2Pixel((gcp[e_idx], gcp[n_idx]))
  836. mapWin.DrawCross(pdc=mapWin.pdcTmp, coords=coord,
  837. size=spx, text={ 'text' : '%s' % str(gcp[0]),
  838. 'active' : True,
  839. 'font' : font,
  840. 'color': wxCol,
  841. 'coords': [coord[0] + 5,
  842. coord[1] + 5,
  843. 5,
  844. 5]})
  845. if penOrig:
  846. mapWin.pen = penOrig
  847. mapWin.polypen = polypenOrig
  848. def SetGCPData(self, coordtype, coord, mapdisp=None, confirm=False):
  849. """
  850. Inserts coordinates from file, mouse click on map, or after editing
  851. into selected item of GCP list and checks it for use
  852. """
  853. index = self.list.GetSelected()
  854. if index == wx.NOT_FOUND:
  855. return
  856. coord0 = coord[0]
  857. coord1 = coord[1]
  858. key = self.list.GetItemData(index)
  859. if confirm:
  860. if self.mapdisp.MapWindow == self.mapdisp.SrcMapWindow:
  861. currloc = _("source")
  862. else:
  863. currloc = _("target")
  864. ret = wx.MessageBox(parent=self,
  865. caption=_("Set GCP coordinates"),
  866. message=_('Set %s coordinates for GCP No. %s? \n\n'
  867. 'East: %s \n'
  868. 'North: %s') % (currloc, str(key), str(coord0), str(coord1)),
  869. style=wx.ICON_QUESTION | wx.YES_NO | wx.CENTRE)
  870. if ret == wx.NO:
  871. return
  872. if coordtype == 'source':
  873. self.list.SetStringItem(index, 1, str(coord0))
  874. self.list.SetStringItem(index, 2, str(coord1))
  875. self.mapcoordlist[key][1] = coord[0]
  876. self.mapcoordlist[key][2] = coord[1]
  877. elif coordtype == 'target':
  878. self.list.SetStringItem(index, 3, str(coord0))
  879. self.list.SetStringItem(index, 4, str(coord1))
  880. self.mapcoordlist[key][3] = coord[0]
  881. self.mapcoordlist[key][4] = coord[1]
  882. self.list.SetStringItem(index, 5, '0')
  883. self.list.SetStringItem(index, 6, '0')
  884. self.mapcoordlist[key][5] = 0.0
  885. self.mapcoordlist[key][6] = 0.0
  886. # self.list.ResizeColumns()
  887. def SaveGCPs(self, event):
  888. """
  889. Make a POINTS file or save GCP coordinates to existing POINTS file
  890. """
  891. self.GCPcount = 0
  892. try:
  893. f = open(self.file['points'], mode='w')
  894. # use os.linesep or '\n' here ???
  895. f.write('# Ground Control Points File\n')
  896. f.write("# \n")
  897. f.write("# target location: " + self.currentlocation + '\n')
  898. f.write("# target mapset: " + self.currentmapset + '\n')
  899. f.write("#\tsource\t\ttarget\t\tstatus\n")
  900. f.write("#\teast\tnorth\teast\tnorth\t(1=ok, 0=ignore)\n")
  901. f.write("#----------------------- ----------------------- ---------------\n")
  902. for index in range(self.list.GetItemCount()):
  903. if self.list.IsChecked(index) == True:
  904. check = "1"
  905. self.GCPcount += 1
  906. else:
  907. check = "0"
  908. coord0 = self.list.GetItem(index, 1).GetText()
  909. coord1 = self.list.GetItem(index, 2).GetText()
  910. coord2 = self.list.GetItem(index, 3).GetText()
  911. coord3 = self.list.GetItem(index, 4).GetText()
  912. f.write(coord0 + ' ' + coord1 + ' ' + coord2 + ' ' + coord3 + ' ' + check + '\n')
  913. except IOError, err:
  914. wx.MessageBox(parent=self,
  915. message="%s <%s>. %s%s" % (_("Writing POINTS file failed"),
  916. self.file['points'], os.linesep, err),
  917. caption=_("Error"), style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
  918. return
  919. f.close()
  920. # if event != None save also to backup file
  921. if event:
  922. shutil.copy(self.file['points'], self.file['points_bak'])
  923. self.parent.goutput.WriteLog(_('POINTS file saved for group <%s>') % self.xygroup)
  924. #self.SetStatusText(_('POINTS file saved'))
  925. def ReadGCPs(self):
  926. """
  927. Reads GCPs and georectified coordinates from POINTS file
  928. """
  929. self.GCPcount = 0
  930. sourceMapWin = self.mapdisp.SrcMapWindow
  931. targetMapWin = self.mapdisp.TgtMapWindow
  932. #targetMapWin = self.parent.curr_page.maptree.mapdisplay.MapWindow
  933. if not sourceMapWin:
  934. wx.MessageBox(parent=self,
  935. message="%s. %s%s" % (_("source mapwin not defined"),
  936. os.linesep, err),
  937. caption=_("Error"), style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
  938. if not targetMapWin:
  939. wx.MessageBox(parent=self,
  940. message="%s. %s%s" % (_("target mapwin not defined"),
  941. os.linesep, err),
  942. caption=_("Error"), style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
  943. try:
  944. f = open(self.file['points'], 'r')
  945. GCPcnt = 0
  946. for line in f.readlines():
  947. if line[0] == '#' or line =='':
  948. continue
  949. line = line.replace('\n', '').strip()
  950. coords = map(float, line.split())
  951. if coords[4] == 1:
  952. check = True
  953. self.GCPcount +=1
  954. else:
  955. check = False
  956. self.AddGCP(event=None)
  957. self.SetGCPData('source', (coords[0], coords[1]), sourceMapWin)
  958. self.SetGCPData('target', (coords[2], coords[3]), targetMapWin)
  959. index = self.list.GetSelected()
  960. if index != wx.NOT_FOUND:
  961. self.list.CheckItem(index, check)
  962. GCPcnt += 1
  963. except IOError, err:
  964. wx.MessageBox(parent=self,
  965. message="%s <%s>. %s%s" % (_("Reading POINTS file failed"),
  966. self.file['points'], os.linesep, err),
  967. caption=_("Error"), style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
  968. return
  969. f.close()
  970. if GCPcnt == 0:
  971. # 3 gcp is minimum
  972. for i in range(3):
  973. self.AddGCP(None)
  974. if self.CheckGCPcount():
  975. # calculate RMS
  976. self.RMSError(self.xygroup, self.gr_order)
  977. else:
  978. # draw GCPs (source and target)
  979. sourceMapWin.UpdateMap(render=False, renderVector=False)
  980. targetMapWin.UpdateMap(render=False, renderVector=False)
  981. def ReloadGCPs(self, event):
  982. """!Reload data from file"""
  983. # use backup
  984. shutil.copy(self.file['points_bak'], self.file['points'])
  985. # delete all items in mapcoordlist
  986. del self.mapcoordlist
  987. self.mapcoordlist = []
  988. self.mapcoordlist.append([ 0, # GCP number
  989. 0.0, # source east
  990. 0.0, # source north
  991. 0.0, # target east
  992. 0.0, # target north
  993. 0.0, # forward error
  994. 0.0 ] ) # backward error
  995. self.list.LoadData()
  996. def OnFocus(self, event):
  997. # self.grwiz.SwitchEnv('source')
  998. pass
  999. def OnRMS(self, event):
  1000. """
  1001. RMS button handler
  1002. """
  1003. self.RMSError(self.xygroup,self.gr_order)
  1004. def CheckGCPcount(self, msg=False):
  1005. """
  1006. Checks to make sure that the minimum number of GCPs have been defined and
  1007. are active for the selected transformation order
  1008. """
  1009. if (self.GCPcount < 3 and self.gr_order == 1) or \
  1010. (self.GCPcount < 6 and self.gr_order == 2) or \
  1011. (self.GCPcount < 10 and self.gr_order == 3):
  1012. if msg:
  1013. wx.MessageBox(parent=self,
  1014. caption=_("RMS Error"),
  1015. message=_('Insufficient points defined and active (checked) '
  1016. 'for selected rectification method.\n'
  1017. '3+ points needed for 1st order,\n'
  1018. '6+ points for 2nd order, and\n'
  1019. '10+ points for 3rd order.'),
  1020. style=wx.ICON_INFORMATION | wx.ID_OK | wx.CENTRE)
  1021. return False
  1022. else:
  1023. return True
  1024. def OnGeorect(self, event):
  1025. """
  1026. Georectifies map(s) in group using i.rectify or v.transform
  1027. """
  1028. global maptype
  1029. self.SaveGCPs(None)
  1030. if self.CheckGCPcount(msg=True) == False:
  1031. return
  1032. if maptype == 'cell':
  1033. self.grwiz.SwitchEnv('source')
  1034. cmdlist = ['i.rectify','-a','group=%s' % self.xygroup,
  1035. 'extension=%s' % self.extension,'order=%s' % self.gr_order]
  1036. if self.clip_to_region:
  1037. cmdlist.append('-c')
  1038. self.parent.goutput.RunCmd(cmdlist, compReg=False,
  1039. switchPage=True)
  1040. time.sleep(.1)
  1041. elif maptype == 'vector':
  1042. outmsg = ''
  1043. # loop through all vectors in VREF
  1044. # and move resulting vector to target location
  1045. # make sure current mapset has a vector folder
  1046. if not os.path.isdir(os.path.join(self.grassdatabase,
  1047. self.currentlocation,
  1048. self.currentmapset,
  1049. 'vector')):
  1050. os.mkdir(os.path.join(self.grassdatabase,
  1051. self.currentlocation,
  1052. self.currentmapset,
  1053. 'vector'))
  1054. self.grwiz.SwitchEnv('source')
  1055. # make list of vectors to georectify from VREF
  1056. f = open(self.file['vgrp'])
  1057. vectlist = []
  1058. try:
  1059. for vect in f.readlines():
  1060. vect = vect.strip('\n')
  1061. if len(vect) < 1:
  1062. continue
  1063. vectlist.append(vect)
  1064. finally:
  1065. f.close()
  1066. # georectify each vector in VREF using v.transform
  1067. for vect in vectlist:
  1068. self.outname = vect + '_' + self.extension
  1069. self.parent.goutput.WriteLog(text = _('Transforming <%s>...') % vect,
  1070. switchPage = True)
  1071. msg = err = ''
  1072. ret, out, err = gcmd.RunCommand('v.transform',
  1073. flags = '-o',
  1074. input=vect,
  1075. output=self.outname,
  1076. pointsfile=self.file['points'],
  1077. getErrorMsg=True, read=True)
  1078. if ret == 0:
  1079. self.VectGRList.append(self.outname)
  1080. print err
  1081. # note: WriteLog doesn't handle GRASS_INFO_PERCENT well, so using a print here
  1082. # self.parent.goutput.WriteLog(text = _(err), switchPage = True)
  1083. self.parent.goutput.WriteLog(text = _(out), switchPage = True)
  1084. else:
  1085. self.parent.goutput.WriteError(_('Georectification of vector map <%s> failed') %
  1086. self.outname)
  1087. self.parent.goutput.WriteError(_(err))
  1088. # FIXME
  1089. # Copying database information not working.
  1090. # Does not copy from xy location to current location
  1091. # TODO: replace $GISDBASE etc with real paths
  1092. # xyLayer = []
  1093. # for layer in grass.vector_db(map = vect).itervalues():
  1094. # xyLayer.append((layer['driver'],
  1095. # layer['database'],
  1096. # layer['table']))
  1097. # dbConnect = grass.db_connection()
  1098. # print 'db connection =', dbConnect
  1099. # for layer in xyLayer:
  1100. # self.parent.goutput.RunCmd(['db.copy',
  1101. # '--q',
  1102. # '--o',
  1103. # 'from_driver=%s' % layer[0],
  1104. # 'from_database=%s' % layer[1],
  1105. # 'from_table=%s' % layer[2],
  1106. # 'to_driver=%s' % dbConnect['driver'],
  1107. # 'to_database=%s' % dbConnect['database'],
  1108. # 'to_table=%s' % layer[2] + '_' + self.extension])
  1109. # copy all georectified vectors from source location to current location
  1110. for name in self.VectGRList:
  1111. xyvpath = os.path.join(self.grassdatabase,
  1112. self.xylocation,
  1113. self.xymapset,
  1114. 'vector',
  1115. name)
  1116. vpath = os.path.join(self.grassdatabase,
  1117. self.currentlocation,
  1118. self.currentmapset,
  1119. 'vector',
  1120. name)
  1121. if os.path.isdir(vpath):
  1122. self.parent.goutput.WriteWarning(_('Vector map <%s> already exists. '
  1123. 'Change extension name and '
  1124. 'georectify again.') % self.outname)
  1125. break
  1126. else:
  1127. # use shutil.copytree() because shutil.move() deletes src dir
  1128. shutil.copytree(xyvpath, vpath)
  1129. # TODO: connect vectors to copied tables with v.db.connect
  1130. wx.MessageBox('For all vector maps georectified successfully, ' + '\n' +
  1131. 'you will need to copy any attribute tables' + '\n' +
  1132. 'and reconnect them to the georectified vectors')
  1133. self.grwiz.SwitchEnv('target')
  1134. def OnGeorectDone(self, **kargs):
  1135. """!Print final message"""
  1136. global maptype
  1137. if maptype == 'cell':
  1138. return
  1139. returncode = kargs['returncode']
  1140. if returncode == 0:
  1141. self.VectGRList.append(self.outname)
  1142. print '*****vector list = ' + str(self.VectGRList)
  1143. else:
  1144. self.parent.goutput.WriteError(_('Georectification of vector map <%s> failed') %
  1145. self.outname)
  1146. def OnSettings(self, event):
  1147. """!GCP Manager settings"""
  1148. dlg = GrSettingsDialog(parent=self, id=wx.ID_ANY, title=_('GCP Manager settings'))
  1149. if dlg.ShowModal() == wx.ID_OK:
  1150. pass
  1151. dlg.Destroy()
  1152. def UpdateColours(self, srcrender=False, srcrenderVector=False,
  1153. tgtrender=False, tgtrenderVector=False):
  1154. """!update colours"""
  1155. highest_fwd_err = 0.0
  1156. self.highest_key = 0
  1157. highest_idx = 0
  1158. for index in range(self.list.GetItemCount()):
  1159. if self.list.IsChecked(index):
  1160. key = self.list.GetItemData(index)
  1161. fwd_err = self.mapcoordlist[key][5]
  1162. if self.highest_only == True:
  1163. self.list.SetItemTextColour(index, wx.BLACK)
  1164. if highest_fwd_err < fwd_err:
  1165. highest_fwd_err = fwd_err
  1166. self.highest_key = key
  1167. highest_idx = index
  1168. elif self.rmsthresh > 0:
  1169. if (fwd_err > self.rmsthresh):
  1170. self.list.SetItemTextColour(index, wx.RED)
  1171. else:
  1172. self.list.SetItemTextColour(index, wx.BLACK)
  1173. else:
  1174. self.list.SetItemTextColour(index, wx.BLACK)
  1175. if self.highest_only and highest_fwd_err > 0.0:
  1176. self.list.SetItemTextColour(highest_idx, wx.RED)
  1177. sourceMapWin = self.mapdisp.SrcMapWindow
  1178. targetMapWin = self.mapdisp.TgtMapWindow
  1179. sourceMapWin.UpdateMap(render=srcrender, renderVector=srcrenderVector)
  1180. targetMapWin.UpdateMap(render=tgtrender, renderVector=tgtrenderVector)
  1181. def OnQuit(self, event):
  1182. """!Quit georectifier"""
  1183. ret = wx.MessageBox(parent=self,
  1184. caption=_("Quit GCP Manager"),
  1185. message=_('Save ground control points?'),
  1186. style=wx.ICON_QUESTION | wx.YES_NO | wx.CANCEL | wx.CENTRE)
  1187. if ret != wx.CANCEL:
  1188. if ret == wx.YES:
  1189. self.SaveGCPs(None)
  1190. elif ret == wx.NO:
  1191. # restore POINTS file from backup
  1192. shutil.copy(self.file['points_bak'], self.file['points'])
  1193. os.unlink(self.file['points_bak'])
  1194. self.grwiz.Cleanup()
  1195. self.Destroy()
  1196. #event.Skip()
  1197. def OnGROrder(self, event):
  1198. """
  1199. sets transformation order for georectifying
  1200. """
  1201. if event:
  1202. self.gr_order = event.GetInt() + 1
  1203. numOfItems = self.list.GetItemCount()
  1204. minNumOfItems = numOfItems
  1205. if self.gr_order == 1:
  1206. minNumOfItems = 3
  1207. # self.SetStatusText(_('Insufficient points, 3+ points needed for 1st order'))
  1208. elif self.gr_order == 2:
  1209. minNumOfItems = 6
  1210. diff = 6 - numOfItems
  1211. # self.SetStatusText(_('Insufficient points, 6+ points needed for 2nd order'))
  1212. elif self.gr_order == 3:
  1213. minNumOfItems = 10
  1214. # self.SetStatusText(_('Insufficient points, 10+ points needed for 3rd order'))
  1215. for i in range(minNumOfItems - numOfItems):
  1216. self.AddGCP(None)
  1217. return minNumOfItems
  1218. def RMSError(self, xygroup, order):
  1219. """
  1220. Uses g.transform to calculate forward and backward error for each used GCP
  1221. in POINTS file and insert error values into GCP list.
  1222. Calculates total forward and backward RMS error for all used points
  1223. """
  1224. # save GCPs to points file to make sure that all checked GCPs are used
  1225. self.SaveGCPs(None)
  1226. #self.SetStatusText('')
  1227. if self.CheckGCPcount(msg=True) == False:
  1228. return
  1229. # get list of forward and reverse rms error values for each point
  1230. self.grwiz.SwitchEnv('source')
  1231. ret = gcmd.RunCommand('g.transform',
  1232. parent = self,
  1233. read = True,
  1234. group = xygroup,
  1235. order = order)
  1236. self.grwiz.SwitchEnv('target')
  1237. if ret:
  1238. errlist = ret.splitlines()
  1239. else:
  1240. wx.MessageBox(parent=self,
  1241. caption=_("RMS Error"),
  1242. message=_('Could not calculate RMS Error. \n'
  1243. 'Possible error with g.transform.'),
  1244. style=wx.ICON_ERROR | wx.ID_OK | wx.CENTRE)
  1245. return
  1246. # insert error values into GCP list for checked items
  1247. sdfactor = float(UserSettings.Get(group='gcpman', key='rms', subkey='sdfactor'))
  1248. GCPcount = 0
  1249. sumsq_fwd_err = 0.0
  1250. sumsq_bkw_err = 0.0
  1251. sum_fwd_err = 0.0
  1252. highest_fwd_err = 0.0
  1253. self.highest_key = 0
  1254. highest_idx = 0
  1255. for index in range(self.list.GetItemCount()):
  1256. key = self.list.GetItemData(index)
  1257. if self.list.IsChecked(index):
  1258. fwd_err, bkw_err = errlist[GCPcount].split()
  1259. self.list.SetStringItem(index, 5, fwd_err)
  1260. self.list.SetStringItem(index, 6, bkw_err)
  1261. self.mapcoordlist[key][5] = float(fwd_err)
  1262. self.mapcoordlist[key][6] = float(bkw_err)
  1263. self.list.SetItemTextColour(index, wx.BLACK)
  1264. if self.highest_only:
  1265. if highest_fwd_err < float(fwd_err):
  1266. highest_fwd_err = float(fwd_err)
  1267. self.highest_key = key
  1268. highest_idx = index
  1269. sumsq_fwd_err += float(fwd_err)**2
  1270. sumsq_bkw_err += float(bkw_err)**2
  1271. sum_fwd_err += float(fwd_err)
  1272. GCPcount += 1
  1273. else:
  1274. self.list.SetStringItem(index, 5, '')
  1275. self.list.SetStringItem(index, 6, '')
  1276. self.mapcoordlist[key][5] = 0.0
  1277. self.mapcoordlist[key][6] = 0.0
  1278. self.list.SetItemTextColour(index, wx.BLACK)
  1279. # SD
  1280. if GCPcount > 0:
  1281. sum_fwd_err /= GCPcount
  1282. self.rmsmean = sum_fwd_err /GCPcount
  1283. self.rmssd = (((sumsq_fwd_err/GCPcount) - self.rmsmean**2)**0.5)
  1284. self.rmsthresh = self.rmsmean + sdfactor * self.rmssd
  1285. else:
  1286. self.rmsthresh = 0
  1287. self.rmsmean = 0
  1288. self.rmssd = 0
  1289. if self.highest_only and highest_fwd_err > 0.0:
  1290. self.list.SetItemTextColour(highest_idx, wx.RED)
  1291. elif GCPcount > 0 and self.rmsthresh > 0 and not self.highest_only:
  1292. for index in range(self.list.GetItemCount()):
  1293. if self.list.IsChecked(index):
  1294. key = self.list.GetItemData(index)
  1295. if (self.mapcoordlist[key][5] > self.rmsthresh):
  1296. self.list.SetItemTextColour(index, wx.RED)
  1297. # calculate global RMS error (geometric mean)
  1298. self.fwd_rmserror = round((sumsq_fwd_err/GCPcount)**0.5,4)
  1299. self.bkw_rmserror = round((sumsq_bkw_err/GCPcount)**0.5,4)
  1300. self.list.ResizeColumns()
  1301. sourceMapWin = self.mapdisp.SrcMapWindow
  1302. targetMapWin = self.mapdisp.TgtMapWindow
  1303. sourceMapWin.UpdateMap(render=False, renderVector=False)
  1304. targetMapWin.UpdateMap(render=False, renderVector=False)
  1305. def GetNewExtend(self, region, map = None):
  1306. coord_file = utils.GetTempfile()
  1307. newreg = { 'n' : 0.0, 's' : 0.0, 'e' : 0.0, 'w' : 0.0,}
  1308. try:
  1309. f = open(coord_file, mode='w')
  1310. # NW corner
  1311. f.write(str(region['e']) + " " + str(region['n']) + "\n")
  1312. # NE corner
  1313. f.write(str(region['e']) + " " + str(region['s']) + "\n")
  1314. # SW corner
  1315. f.write(str(region['w']) + " " + str(region['n']) + "\n")
  1316. # SE corner
  1317. f.write(str(region['w']) + " " + str(region['s']) + "\n")
  1318. finally:
  1319. f.close()
  1320. # save GCPs to points file to make sure that all checked GCPs are used
  1321. self.SaveGCPs(None)
  1322. order = self.gr_order
  1323. self.gr_order = 1
  1324. if self.CheckGCPcount(msg=True) == False:
  1325. self.gr_order = order
  1326. return
  1327. self.gr_order = order
  1328. # get list of forward and reverse rms error values for each point
  1329. self.grwiz.SwitchEnv('source')
  1330. if map == 'source':
  1331. ret = gcmd.RunCommand('g.transform',
  1332. parent = self,
  1333. read = True,
  1334. group = self.xygroup,
  1335. order = 1,
  1336. format = 'dst',
  1337. coords = coord_file)
  1338. elif map == 'target':
  1339. ret = gcmd.RunCommand('g.transform',
  1340. parent = self,
  1341. read = True,
  1342. group = self.xygroup,
  1343. order = 1,
  1344. flags = 'r',
  1345. format = 'src',
  1346. coords = coord_file)
  1347. os.unlink(coord_file)
  1348. self.grwiz.SwitchEnv('target')
  1349. if ret:
  1350. errlist = ret.splitlines()
  1351. else:
  1352. wx.MessageBox(parent=self,
  1353. caption=_("Adjust GCP Displays "),
  1354. message=_('Could not calculate new extends. \n'
  1355. 'Possible error with g.transform.'),
  1356. style=wx.ICON_ERROR | wx.ID_OK | wx.CENTRE)
  1357. return
  1358. # fist corner
  1359. e, n = errlist[0].split()
  1360. fe = float(e)
  1361. fn = float(n)
  1362. newreg['n'] = fn
  1363. newreg['s'] = fn
  1364. newreg['e'] = fe
  1365. newreg['w'] = fe
  1366. # other three corners
  1367. for i in range(1, 4):
  1368. e, n = errlist[i].split()
  1369. fe = float(e)
  1370. fn = float(n)
  1371. if fe < newreg['w']:
  1372. newreg['w'] = fe
  1373. if fe > newreg['e']:
  1374. newreg['e'] = fe
  1375. if fn < newreg['s']:
  1376. newreg['s'] = fn
  1377. if fn > newreg['n']:
  1378. newreg['n'] = fn
  1379. return newreg
  1380. def OnHelp(self, event):
  1381. """!Show GCP Manager manual page"""
  1382. gcmd.RunCommand('g.manual',
  1383. quiet = True,
  1384. parent = self,
  1385. entry = 'wxGUI.GCP_Manager')
  1386. class GCPList(wx.ListCtrl,
  1387. CheckListCtrlMixin,
  1388. ListCtrlAutoWidthMixin):
  1389. def __init__(self, parent, gcp, id=wx.ID_ANY,
  1390. pos=wx.DefaultPosition, size=wx.DefaultSize,
  1391. style=wx.LC_REPORT | wx.SUNKEN_BORDER | wx.LC_HRULES |
  1392. wx.LC_SINGLE_SEL | wx.LC_SORT_DESCENDING):
  1393. wx.ListCtrl.__init__(self, parent, id, pos, size, style)
  1394. self.gcp = gcp # GCP class
  1395. self.render = True
  1396. # Mixin settings
  1397. CheckListCtrlMixin.__init__(self)
  1398. ListCtrlAutoWidthMixin.__init__(self)
  1399. # TextEditMixin.__init__(self)
  1400. # tracks whether list items are checked or not
  1401. self.CheckList = []
  1402. self._Create()
  1403. self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected)
  1404. self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.OnItemActivated)
  1405. self.Bind(wx.EVT_LIST_COL_CLICK, self.OnColClick)
  1406. self.selected = wx.NOT_FOUND
  1407. self.selectedkey = -1
  1408. def _Create(self):
  1409. if 0:
  1410. # normal, simple columns
  1411. idx_col = 0
  1412. for col in (_('use'),
  1413. _('source E'),
  1414. _('source N'),
  1415. _('target E'),
  1416. _('target N'),
  1417. _('Forward error'),
  1418. _('Backward error')):
  1419. self.InsertColumn(idx_col, col)
  1420. idx_col += 1
  1421. else:
  1422. # the hard way: we want images on the column header
  1423. info = wx.ListItem()
  1424. info.SetMask(wx.LIST_MASK_TEXT | wx.LIST_MASK_IMAGE | wx.LIST_MASK_FORMAT)
  1425. info.SetImage(-1)
  1426. info.m_format = 0
  1427. idx_col = 0
  1428. for lbl in (_('use'),
  1429. _('source E'),
  1430. _('source N'),
  1431. _('target E'),
  1432. _('target N'),
  1433. _('Forward error'),
  1434. _('Backward error')):
  1435. info.SetText(lbl)
  1436. self.InsertColumnInfo(idx_col, info)
  1437. idx_col += 1
  1438. def LoadData(self):
  1439. """!Load data into list"""
  1440. self.DeleteAllItems()
  1441. self.render = False
  1442. if os.path.isfile(self.gcp.file['points']):
  1443. self.gcp.ReadGCPs()
  1444. else:
  1445. # 3 gcp is minimum
  1446. for i in range(3):
  1447. self.gcp.AddGCP(None)
  1448. # select first point by default
  1449. self.selected = 0
  1450. self.selectedkey = self.GetItemData(self.selected)
  1451. self.SetItemState(self.selected,
  1452. wx.LIST_STATE_SELECTED,
  1453. wx.LIST_STATE_SELECTED)
  1454. self.ResizeColumns()
  1455. self.render = True
  1456. def OnCheckItem(self, index, flag):
  1457. """!Item is checked/unchecked"""
  1458. if self.render:
  1459. # redraw points
  1460. sourceMapWin = self.gcp.mapdisp.SrcMapWindow
  1461. targetMapWin = self.gcp.mapdisp.TgtMapWindow
  1462. sourceMapWin.UpdateMap(render=False, renderVector=False)
  1463. targetMapWin.UpdateMap(render=False, renderVector=False)
  1464. pass
  1465. def AddGCPItem(self):
  1466. """
  1467. Appends an item to GCP list
  1468. """
  1469. self.selectedkey = self.GetItemCount() + 1
  1470. self.Append([str(self.selectedkey), # GCP number
  1471. '0.0', # source E
  1472. '0.0', # source N
  1473. '0.0', # target E
  1474. '0.0', # target N
  1475. '', # forward error
  1476. '']) # backward error
  1477. self.selected = self.GetItemCount() - 1
  1478. self.SetItemData(self.selected, self.selectedkey)
  1479. self.SetItemState(self.selected,
  1480. wx.LIST_STATE_SELECTED,
  1481. wx.LIST_STATE_SELECTED)
  1482. self.ResizeColumns()
  1483. return self.selected
  1484. def DeleteGCPItem(self):
  1485. """
  1486. Deletes selected item in GCP list
  1487. """
  1488. if self.selected == wx.NOT_FOUND:
  1489. return
  1490. self.DeleteItem(self.selected)
  1491. if self.GetItemCount() > 0:
  1492. self.selected = self.GetItemCount() - 1
  1493. self.SetItemState(self.selected,
  1494. wx.LIST_STATE_SELECTED,
  1495. wx.LIST_STATE_SELECTED)
  1496. else:
  1497. self.selected = wx.NOT_FOUND
  1498. return self.selected
  1499. def ResizeColumns(self):
  1500. """!Resize columns"""
  1501. minWidth = [90, 120]
  1502. for i in range(self.GetColumnCount()):
  1503. self.SetColumnWidth(i, wx.LIST_AUTOSIZE)
  1504. # first column is checkbox, don't set to minWidth
  1505. if i > 0 and self.GetColumnWidth(i) < minWidth[i > 4]:
  1506. self.SetColumnWidth(i, minWidth[i > 4])
  1507. self.SendSizeEvent()
  1508. def GetSelected(self):
  1509. """!Get index of selected item"""
  1510. return self.selected
  1511. def OnItemSelected(self, event):
  1512. """
  1513. Item selected
  1514. """
  1515. if self.render and self.selected != event.GetIndex():
  1516. self.selected = event.GetIndex()
  1517. self.selectedkey = self.GetItemData(self.selected)
  1518. sourceMapWin = self.gcp.mapdisp.SrcMapWindow
  1519. targetMapWin = self.gcp.mapdisp.TgtMapWindow
  1520. sourceMapWin.UpdateMap(render=False, renderVector=False)
  1521. targetMapWin.UpdateMap(render=False, renderVector=False)
  1522. event.Skip()
  1523. def OnItemActivated(self, event):
  1524. """
  1525. When item double clicked, open editor to update coordinate values
  1526. """
  1527. coords = []
  1528. index = event.GetIndex()
  1529. key = self.GetItemData(index)
  1530. changed = False
  1531. for i in range(1, 5):
  1532. coords.append(self.GetItem(index, i).GetText())
  1533. dlg = EditGCP(parent=self, id=wx.ID_ANY, data=coords, gcpno=key)
  1534. if dlg.ShowModal() == wx.ID_OK:
  1535. values = dlg.GetValues() # string
  1536. if len(values) == 0:
  1537. wx.MessageBox(parent=self,
  1538. caption=_("Edit GCP"),
  1539. message=_("Invalid coordinate value. Operation cancelled."),
  1540. style=wx.CENTRE | wx.ICON_ERROR | wx.ID_OK)
  1541. else:
  1542. for i in range(len(values)):
  1543. if values[i] != coords[i]:
  1544. self.SetStringItem(index, i + 1, values[i])
  1545. changed = True
  1546. if changed:
  1547. # reset RMS and update mapcoordlist
  1548. self.SetStringItem(index, 5, '')
  1549. self.SetStringItem(index, 6, '')
  1550. key = self.GetItemData(index)
  1551. self.gcp.mapcoordlist[key] = [key,
  1552. float(values[0]),
  1553. float(values[1]),
  1554. float(values[2]),
  1555. float(values[3]),
  1556. 0.0,
  1557. 0.0]
  1558. self.gcp.UpdateColours()
  1559. def OnColClick(self, event):
  1560. """!ListCtrl forgets selected item..."""
  1561. self.selected = self.FindItemData(-1, self.selectedkey)
  1562. self.SetItemState(self.selected,
  1563. wx.LIST_STATE_SELECTED,
  1564. wx.LIST_STATE_SELECTED)
  1565. event.Skip()
  1566. class VectGroup(wx.Dialog):
  1567. """
  1568. Dialog to create a vector group (VREF file) for georectifying
  1569. @todo Replace by g.group
  1570. """
  1571. def __init__(self, parent, id, grassdb, location, mapset, group,
  1572. style=wx.DEFAULT_DIALOG_STYLE):
  1573. wx.Dialog.__init__(self, parent, id, style=style,
  1574. title = _("Create vector map group"))
  1575. self.grassdatabase = grassdb
  1576. self.xylocation = location
  1577. self.xymapset = mapset
  1578. self.xygroup = group
  1579. #
  1580. # get list of valid vector directories
  1581. #
  1582. vectlist = os.listdir(os.path.join(self.grassdatabase,
  1583. self.xylocation,
  1584. self.xymapset,
  1585. 'vector'))
  1586. for dir in vectlist:
  1587. if not os.path.isfile(os.path.join(self.grassdatabase,
  1588. self.xylocation,
  1589. self.xymapset,
  1590. 'vector',
  1591. dir,
  1592. 'coor')):
  1593. vectlist.remove(dir)
  1594. utils.ListSortLower(vectlist)
  1595. # path to vref file
  1596. self.vgrpfile = os.path.join(self.grassdatabase,
  1597. self.xylocation,
  1598. self.xymapset,
  1599. 'group',
  1600. self.xygroup,
  1601. 'VREF')
  1602. #
  1603. # buttons
  1604. #
  1605. self.btnCancel = wx.Button(parent = self,
  1606. id = wx.ID_CANCEL)
  1607. self.btnOK = wx.Button(parent = self,
  1608. id = wx.ID_OK)
  1609. self.btnOK.SetDefault()
  1610. #
  1611. # list of vector maps
  1612. #
  1613. self.listMap = wx.CheckListBox(parent = self, id = wx.ID_ANY,
  1614. choices = vectlist)
  1615. if os.path.isfile(self.vgrpfile):
  1616. f = open(self.vgrpfile)
  1617. try:
  1618. checked = []
  1619. for line in f.readlines():
  1620. line = line.replace('\n', '')
  1621. if len(line) < 1:
  1622. continue
  1623. checked.append(line)
  1624. self.listMap.SetCheckedStrings(checked)
  1625. finally:
  1626. f.close()
  1627. line = wx.StaticLine(parent = self,
  1628. id = wx.ID_ANY, size = (20, -1),
  1629. style = wx.LI_HORIZONTAL)
  1630. #
  1631. # layout
  1632. #
  1633. sizer = wx.BoxSizer(wx.VERTICAL)
  1634. box = wx.BoxSizer(wx.HORIZONTAL)
  1635. box.Add(item = wx.StaticText(parent = self, id = wx.ID_ANY,
  1636. label = _('Select vector map(s) to add to group:')),
  1637. flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT | wx.LEFT,
  1638. border = 5)
  1639. box.Add(item = self.listMap,
  1640. flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT | wx.LEFT,
  1641. border = 5)
  1642. sizer.Add(box, flag = wx.ALIGN_RIGHT | wx.ALL,
  1643. border = 3)
  1644. sizer.Add(item = line, proportion = 0,
  1645. flag = wx.GROW | wx.ALIGN_CENTER_VERTICAL | wx.LEFT | wx.RIGHT,
  1646. border = 5)
  1647. # buttons
  1648. btnSizer = wx.StdDialogButtonSizer()
  1649. btnSizer.AddButton(self.btnCancel)
  1650. btnSizer.AddButton(self.btnOK)
  1651. btnSizer.Realize()
  1652. sizer.Add(item = btnSizer, proportion = 0,
  1653. flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER,
  1654. border = 5)
  1655. self.SetSizer(sizer)
  1656. sizer.Fit(self)
  1657. self.Layout()
  1658. def MakeVGroup(self):
  1659. """!Create VREF file"""
  1660. vgrouplist = []
  1661. for item in range(self.listMap.GetCount()):
  1662. if not self.listMap.IsChecked(item):
  1663. continue
  1664. vgrouplist.append(self.listMap.GetString(item))
  1665. f = open(self.vgrpfile, mode='w')
  1666. try:
  1667. for vect in vgrouplist:
  1668. f.write(vect + '\n')
  1669. finally:
  1670. f.close()
  1671. class EditGCP(wx.Dialog):
  1672. def __init__(self, parent, data, gcpno, id=wx.ID_ANY,
  1673. title=_("Edit GCP"),
  1674. style=wx.DEFAULT_DIALOG_STYLE):
  1675. """!Dialog for editing GPC and map coordinates in list control"""
  1676. wx.Dialog.__init__(self, parent, id, title=title, style=style)
  1677. panel = wx.Panel(parent=self)
  1678. sizer = wx.BoxSizer(wx.VERTICAL)
  1679. box = wx.StaticBox (parent=panel, id=wx.ID_ANY,
  1680. label=" %s %s " % (_("Ground Control Point No."), str(gcpno)))
  1681. boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
  1682. # source coordinates
  1683. gridSizer = wx.GridBagSizer(vgap=5, hgap=5)
  1684. self.xcoord = wx.TextCtrl(parent=panel, id=wx.ID_ANY, size=(150, -1))
  1685. self.ycoord = wx.TextCtrl(parent=panel, id=wx.ID_ANY, size=(150, -1))
  1686. self.ecoord = wx.TextCtrl(parent=panel, id=wx.ID_ANY, size=(150, -1))
  1687. self.ncoord = wx.TextCtrl(parent=panel, id=wx.ID_ANY, size=(150, -1))
  1688. # swap source N, target E
  1689. tmp_coord = data[1]
  1690. data[1] = data[2]
  1691. data[2] = tmp_coord
  1692. row = 0
  1693. col = 0
  1694. idx = 0
  1695. for label, win in ((_("source E:"), self.xcoord),
  1696. (_("target E:"), self.ecoord),
  1697. (_("source N:"), self.ycoord),
  1698. (_("target N:"), self.ncoord)):
  1699. label = wx.StaticText(parent=panel, id=wx.ID_ANY,
  1700. label=label)
  1701. gridSizer.Add(item=label,
  1702. flag=wx.ALIGN_CENTER_VERTICAL,
  1703. pos=(row, col))
  1704. col += 1
  1705. win.SetValue(str(data[idx]))
  1706. gridSizer.Add(item=win,
  1707. pos=(row, col))
  1708. col += 1
  1709. idx += 1
  1710. if col > 3:
  1711. row += 1
  1712. col = 0
  1713. boxSizer.Add(item=gridSizer, proportion=1,
  1714. flag=wx.EXPAND | wx.ALL, border=5)
  1715. sizer.Add(item=boxSizer, proportion=1,
  1716. flag=wx.EXPAND | wx.ALL, border=5)
  1717. #
  1718. # buttons
  1719. #
  1720. self.btnCancel = wx.Button(panel, wx.ID_CANCEL)
  1721. self.btnOk = wx.Button(panel, wx.ID_OK)
  1722. self.btnOk.SetDefault()
  1723. btnSizer = wx.StdDialogButtonSizer()
  1724. btnSizer.AddButton(self.btnCancel)
  1725. btnSizer.AddButton(self.btnOk)
  1726. btnSizer.Realize()
  1727. sizer.Add(item=btnSizer, proportion=0,
  1728. flag=wx.ALIGN_RIGHT | wx.ALL, border=5)
  1729. panel.SetSizer(sizer)
  1730. sizer.Fit(self)
  1731. def GetValues(self, columns=None):
  1732. """!Return list of values (as strings).
  1733. """
  1734. valuelist = []
  1735. try:
  1736. float(self.xcoord.GetValue())
  1737. float(self.ycoord.GetValue())
  1738. float(self.ecoord.GetValue())
  1739. float(self.ncoord.GetValue())
  1740. except ValueError:
  1741. return valuelist
  1742. valuelist.append(self.xcoord.GetValue())
  1743. valuelist.append(self.ycoord.GetValue())
  1744. valuelist.append(self.ecoord.GetValue())
  1745. valuelist.append(self.ncoord.GetValue())
  1746. return valuelist
  1747. class GrSettingsDialog(wx.Dialog):
  1748. def __init__(self, parent, id, title, pos=wx.DefaultPosition, size=wx.DefaultSize,
  1749. style=wx.DEFAULT_DIALOG_STYLE):
  1750. wx.Dialog.__init__(self, parent, id, title, pos, size, style)
  1751. """
  1752. Dialog to set profile text options: font, title
  1753. and font size, axis labels and font size
  1754. """
  1755. #
  1756. # initialize variables
  1757. #
  1758. self.parent = parent
  1759. self.new_src_map = None
  1760. self.new_tgt_map = None
  1761. self.sdfactor = 0
  1762. self.symbol = {}
  1763. # notebook
  1764. notebook = wx.Notebook(parent=self, id=wx.ID_ANY, style=wx.BK_DEFAULT)
  1765. self.__CreateSymbologyPage(notebook)
  1766. self.__CreateRectificationPage(notebook)
  1767. # buttons
  1768. btnSave = wx.Button(self, wx.ID_SAVE)
  1769. btnApply = wx.Button(self, wx.ID_APPLY)
  1770. btnClose = wx.Button(self, wx.ID_CLOSE)
  1771. btnApply.SetDefault()
  1772. # bindings
  1773. btnApply.Bind(wx.EVT_BUTTON, self.OnApply)
  1774. btnApply.SetToolTipString(_("Apply changes for the current session"))
  1775. btnSave.Bind(wx.EVT_BUTTON, self.OnSave)
  1776. btnSave.SetToolTipString(_("Apply and save changes to user settings file (default for next sessions)"))
  1777. btnClose.Bind(wx.EVT_BUTTON, self.OnClose)
  1778. btnClose.SetToolTipString(_("Close dialog"))
  1779. # sizers
  1780. btnSizer = wx.BoxSizer(wx.HORIZONTAL)
  1781. btnSizer.Add(btnApply, flag=wx.LEFT | wx.RIGHT, border=5)
  1782. btnSizer.Add(btnSave, flag=wx.LEFT | wx.RIGHT, border=5)
  1783. btnSizer.Add(btnClose, flag=wx.LEFT | wx.RIGHT, border=5)
  1784. # sizers
  1785. mainSizer = wx.BoxSizer(wx.VERTICAL)
  1786. mainSizer.Add(item=notebook, proportion=1, flag=wx.EXPAND | wx.ALL, border=5)
  1787. mainSizer.Add(item=btnSizer, proportion=0,
  1788. flag=wx.ALIGN_RIGHT | wx.ALL, border=5)
  1789. # flag=wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border=5)
  1790. self.SetSizer(mainSizer)
  1791. mainSizer.Fit(self)
  1792. def __CreateSymbologyPage(self, notebook):
  1793. """!Create notebook page with symbology settings"""
  1794. panel = wx.Panel(parent=notebook, id=wx.ID_ANY)
  1795. notebook.AddPage(page=panel, text=_("Symbology"))
  1796. sizer = wx.BoxSizer(wx.VERTICAL)
  1797. rmsgridSizer = wx.GridBagSizer(vgap=5, hgap=5)
  1798. rmsgridSizer.AddGrowableCol(1)
  1799. # highlight only highest forward RMS error
  1800. self.highlighthighest = wx.CheckBox(parent=panel, id=wx.ID_ANY,
  1801. label=_("Highlight highest RMS error only"))
  1802. hh = UserSettings.Get(group='gcpman', key='rms', subkey='highestonly')
  1803. self.highlighthighest.SetValue(hh)
  1804. rmsgridSizer.Add(item=self.highlighthighest, flag=wx.ALIGN_CENTER_VERTICAL, pos=(0, 0))
  1805. # RMS forward error threshold
  1806. rmslabel = wx.StaticText(parent=panel, id=wx.ID_ANY, label=_("Highlight RMS error > M + SD * factor:"))
  1807. rmslabel.SetToolTip(wx.ToolTip(_("Highlight GCPs with an RMS error larger than \n"
  1808. "mean + standard deviation * given factor. \n"
  1809. "Recommended values for this factor are between 1 and 2.")))
  1810. rmsgridSizer.Add(item=rmslabel, flag=wx.ALIGN_CENTER_VERTICAL, pos=(1, 0))
  1811. sdfactor = UserSettings.Get(group='gcpman', key='rms', subkey='sdfactor')
  1812. self.rmsWin = wx.TextCtrl(parent=panel, id=wx.ID_ANY,
  1813. size=(70,-1), style=wx.TE_NOHIDESEL)
  1814. self.rmsWin.SetValue("%s" % str(sdfactor))
  1815. if (self.parent.highest_only == True):
  1816. self.rmsWin.Disable()
  1817. self.symbol['sdfactor'] = self.rmsWin.GetId()
  1818. rmsgridSizer.Add(item=self.rmsWin, flag=wx.ALIGN_RIGHT, pos=(1, 1))
  1819. sizer.Add(item=rmsgridSizer, flag=wx.EXPAND | wx.ALL, border=5)
  1820. box = wx.StaticBox(parent=panel, id=wx.ID_ANY,
  1821. label=" %s " % _("Symbol settings"))
  1822. boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
  1823. gridSizer = wx.GridBagSizer(vgap=5, hgap=5)
  1824. gridSizer.AddGrowableCol(1)
  1825. #
  1826. # general symbol color
  1827. #
  1828. row = 0
  1829. label = wx.StaticText(parent=panel, id=wx.ID_ANY, label=_("Color:"))
  1830. gridSizer.Add(item=label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
  1831. col = UserSettings.Get(group='gcpman', key='symbol', subkey='color')
  1832. colWin = csel.ColourSelect(parent=panel, id=wx.ID_ANY,
  1833. colour=wx.Colour(col[0],
  1834. col[1],
  1835. col[2],
  1836. 255))
  1837. self.symbol['color'] = colWin.GetId()
  1838. gridSizer.Add(item=colWin,
  1839. flag=wx.ALIGN_RIGHT,
  1840. pos=(row, 1))
  1841. #
  1842. # symbol color for high forward RMS error
  1843. #
  1844. row += 1
  1845. label = wx.StaticText(parent=panel, id=wx.ID_ANY, label=_("Color for high RMS error:"))
  1846. gridSizer.Add(item=label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
  1847. hcol = UserSettings.Get(group='gcpman', key='symbol', subkey='hcolor')
  1848. hcolWin = csel.ColourSelect(parent=panel, id=wx.ID_ANY,
  1849. colour=wx.Colour(hcol[0],
  1850. hcol[1],
  1851. hcol[2],
  1852. 255))
  1853. self.symbol['hcolor'] = hcolWin.GetId()
  1854. gridSizer.Add(item=hcolWin,
  1855. flag=wx.ALIGN_RIGHT,
  1856. pos=(row, 1))
  1857. #
  1858. # symbol color for selected GCP
  1859. #
  1860. row += 1
  1861. label = wx.StaticText(parent=panel, id=wx.ID_ANY, label=_("Color for selected GCP:"))
  1862. gridSizer.Add(item=label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
  1863. scol = UserSettings.Get(group='gcpman', key='symbol', subkey='scolor')
  1864. scolWin = csel.ColourSelect(parent=panel, id=wx.ID_ANY,
  1865. colour=wx.Colour(scol[0],
  1866. scol[1],
  1867. scol[2],
  1868. 255))
  1869. self.symbol['scolor'] = scolWin.GetId()
  1870. gridSizer.Add(item=scolWin,
  1871. flag=wx.ALIGN_RIGHT,
  1872. pos=(row, 1))
  1873. #
  1874. # symbol color for unused GCP
  1875. #
  1876. row += 1
  1877. label = wx.StaticText(parent=panel, id=wx.ID_ANY, label=_("Color for unused GCPs:"))
  1878. gridSizer.Add(item=label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
  1879. ucol = UserSettings.Get(group='gcpman', key='symbol', subkey='ucolor')
  1880. ucolWin = csel.ColourSelect(parent=panel, id=wx.ID_ANY,
  1881. colour=wx.Colour(ucol[0],
  1882. ucol[1],
  1883. ucol[2],
  1884. 255))
  1885. self.symbol['ucolor'] = ucolWin.GetId()
  1886. gridSizer.Add(item=ucolWin,
  1887. flag=wx.ALIGN_RIGHT,
  1888. pos=(row, 1))
  1889. # show unused GCPs
  1890. row += 1
  1891. self.showunused = wx.CheckBox(parent=panel, id=wx.ID_ANY,
  1892. label=_("Show unused GCPs"))
  1893. shuu = UserSettings.Get(group='gcpman', key='symbol', subkey='unused')
  1894. self.showunused.SetValue(shuu)
  1895. gridSizer.Add(item=self.showunused, flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
  1896. #
  1897. # symbol size
  1898. #
  1899. row += 1
  1900. label = wx.StaticText(parent=panel, id=wx.ID_ANY, label=_("Symbol size:"))
  1901. gridSizer.Add(item=label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
  1902. symsize = int(UserSettings.Get(group='gcpman', key='symbol', subkey='size'))
  1903. sizeWin = wx.SpinCtrl(parent=panel, id=wx.ID_ANY,
  1904. min=1, max=20)
  1905. sizeWin.SetValue(symsize)
  1906. self.symbol['size'] = sizeWin.GetId()
  1907. gridSizer.Add(item=sizeWin,
  1908. flag=wx.ALIGN_RIGHT,
  1909. pos=(row, 1))
  1910. #
  1911. # symbol width
  1912. #
  1913. row += 1
  1914. label = wx.StaticText(parent=panel, id=wx.ID_ANY, label=_("Line width:"))
  1915. gridSizer.Add(item=label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
  1916. width = int(UserSettings.Get(group='gcpman', key='symbol', subkey='width'))
  1917. widWin = wx.SpinCtrl(parent=panel, id=wx.ID_ANY,
  1918. min=1, max=10)
  1919. widWin.SetValue(width)
  1920. self.symbol['width'] = widWin.GetId()
  1921. gridSizer.Add(item=widWin,
  1922. flag=wx.ALIGN_RIGHT,
  1923. pos=(row, 1))
  1924. boxSizer.Add(item=gridSizer, flag=wx.EXPAND)
  1925. sizer.Add(item=boxSizer, flag=wx.EXPAND | wx.ALL, border=5)
  1926. #
  1927. # maps to display
  1928. #
  1929. # source map to display
  1930. self.srcselection = gselect.Select(panel, id=wx.ID_ANY,
  1931. size=globalvar.DIALOG_GSELECT_SIZE, type='cell', updateOnPopup = False)
  1932. self.parent.grwiz.SwitchEnv('source')
  1933. self.srcselection.SetElementList(maptype,
  1934. mapsets = [self.parent.newmapset, ])
  1935. self.srcselection.GetElementList()
  1936. # target map to display
  1937. self.tgtselection = gselect.Select(panel, id=wx.ID_ANY,
  1938. size=globalvar.DIALOG_GSELECT_SIZE, type='cell', updateOnPopup = False)
  1939. self.parent.grwiz.SwitchEnv('target')
  1940. self.tgtselection.SetElementList(maptype)
  1941. self.tgtselection.GetElementList()
  1942. sizer.Add(item=wx.StaticText(parent=panel, id=wx.ID_ANY, label=_('Select source map to display:')),
  1943. proportion=0, flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5)
  1944. sizer.Add(item=self.srcselection, proportion=0,
  1945. flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5)
  1946. self.srcselection.SetValue(src_map)
  1947. sizer.Add(item=wx.StaticText(parent=panel, id=wx.ID_ANY, label=_('Select target map to display:')),
  1948. proportion=0, flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5)
  1949. sizer.Add(item=self.tgtselection, proportion=0,
  1950. flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5)
  1951. self.tgtselection.SetValue(tgt_map)
  1952. # bindings
  1953. self.highlighthighest.Bind(wx.EVT_CHECKBOX, self.OnHighlight)
  1954. self.rmsWin.Bind(wx.EVT_TEXT, self.OnSDFactor)
  1955. self.srcselection.Bind(wx.EVT_TEXT, self.OnSrcSelection)
  1956. self.tgtselection.Bind(wx.EVT_TEXT, self.OnTgtSelection)
  1957. panel.SetSizer(sizer)
  1958. return panel
  1959. def __CreateRectificationPage(self, notebook):
  1960. """!Create notebook page with symbology settings"""
  1961. panel = wx.Panel(parent=notebook, id=wx.ID_ANY)
  1962. notebook.AddPage(page=panel, text=_("Rectification"))
  1963. sizer = wx.BoxSizer(wx.VERTICAL)
  1964. # transformation order
  1965. self.rb_grmethod = wx.RadioBox(parent=panel, id=wx.ID_ANY,
  1966. label=" %s " % _("Select rectification method for rasters"),
  1967. choices=[_('1st order'), _('2nd order'), _('3rd order')],
  1968. majorDimension=wx.RA_SPECIFY_COLS)
  1969. sizer.Add(item=self.rb_grmethod, proportion=0,
  1970. flag=wx.EXPAND | wx.ALL, border=5)
  1971. self.rb_grmethod.SetSelection(self.parent.gr_order - 1)
  1972. # clip to region
  1973. self.check = wx.CheckBox(parent=panel, id=wx.ID_ANY,
  1974. label=_("clip to computational region in target location"))
  1975. sizer.Add(item=self.check, proportion=0,
  1976. flag=wx.EXPAND | wx.ALL, border=5)
  1977. self.check.SetValue(self.parent.clip_to_region)
  1978. # extension
  1979. sizer.Add(item=wx.StaticText(parent=panel, id=wx.ID_ANY, label=_('Extension for output maps:')),
  1980. proportion=0, flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5)
  1981. self.ext_txt = wx.TextCtrl(parent=panel, id=wx.ID_ANY, value="", size=(350,-1))
  1982. self.ext_txt.SetValue(self.parent.extension)
  1983. sizer.Add(item=self.ext_txt,
  1984. proportion=0, flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5)
  1985. # bindings
  1986. self.ext_txt.Bind(wx.EVT_TEXT, self.OnExtension)
  1987. self.Bind(wx.EVT_RADIOBOX, self.parent.OnGROrder, self.rb_grmethod)
  1988. self.Bind(wx.EVT_CHECKBOX, self.OnClipRegion, self.check)
  1989. panel.SetSizer(sizer)
  1990. return panel
  1991. def OnHighlight(self, event):
  1992. """!Checkbox 'highlighthighest' checked/unchecked"""
  1993. if self.highlighthighest.IsChecked():
  1994. self.parent.highest_only = True
  1995. self.rmsWin.Disable()
  1996. else:
  1997. self.parent.highest_only = False
  1998. self.rmsWin.Enable()
  1999. def OnSDFactor(self,event):
  2000. """!New factor for RMS threshold = M + SD * factor"""
  2001. self.sdfactor = float(event.GetString())
  2002. if self.sdfactor <= 0:
  2003. wx.MessageBox(parent=self,
  2004. caption=_("Update settings"),
  2005. message=_('RMS threshold factor must be > 0'),
  2006. style=wx.ICON_ERROR | wx.ID_OK | wx.CENTRE)
  2007. elif self.sdfactor < 1:
  2008. wx.MessageBox(parent=self,
  2009. caption=_("Update settings"),
  2010. message=_('RMS threshold factor is < 1\n'
  2011. 'Too many points might be highlighted'),
  2012. style=wx.ICON_EXCLAMATION | wx.ID_OK | wx.CENTRE)
  2013. def OnSrcSelection(self,event):
  2014. """!Source map to display selected"""
  2015. global src_map
  2016. tmp_map = event.GetString()
  2017. if not tmp_map == '' and not tmp_map == src_map:
  2018. self.new_src_map = tmp_map
  2019. def OnTgtSelection(self,event):
  2020. """!Target map to display selected"""
  2021. global tgt_map
  2022. tmp_map = event.GetString()
  2023. if not tmp_map == '' and not tmp_map == tgt_map:
  2024. self.new_tgt_map = tmp_map
  2025. def OnClipRegion(self, event):
  2026. self.parent.clip_to_region = event.IsChecked()
  2027. def OnExtension(self, event):
  2028. self.parent.extension = event.GetString()
  2029. def UpdateSettings(self):
  2030. global src_map
  2031. global tgt_map
  2032. layers = None
  2033. UserSettings.Set(group='gcpman', key='rms', subkey='highestonly',
  2034. value=self.highlighthighest.GetValue())
  2035. if self.sdfactor > 0:
  2036. UserSettings.Set(group='gcpman', key='rms', subkey='sdfactor',
  2037. value=self.sdfactor)
  2038. self.parent.sdfactor = self.sdfactor
  2039. if self.parent.rmsthresh > 0:
  2040. self.parent.rmsthresh = self.parent.mean + self.parent.sdfactor * self.parent.rmssd
  2041. UserSettings.Set(group='gcpman', key='symbol', subkey='color',
  2042. value=tuple(wx.FindWindowById(self.symbol['color']).GetColour()))
  2043. UserSettings.Set(group='gcpman', key='symbol', subkey='hcolor',
  2044. value=tuple(wx.FindWindowById(self.symbol['hcolor']).GetColour()))
  2045. UserSettings.Set(group='gcpman', key='symbol', subkey='scolor',
  2046. value=tuple(wx.FindWindowById(self.symbol['scolor']).GetColour()))
  2047. UserSettings.Set(group='gcpman', key='symbol', subkey='ucolor',
  2048. value=tuple(wx.FindWindowById(self.symbol['ucolor']).GetColour()))
  2049. UserSettings.Set(group='gcpman', key='symbol', subkey='unused',
  2050. value=self.showunused.GetValue())
  2051. UserSettings.Set(group='gcpman', key='symbol', subkey='size',
  2052. value=wx.FindWindowById(self.symbol['size']).GetValue())
  2053. UserSettings.Set(group='gcpman', key='symbol', subkey='width',
  2054. value=wx.FindWindowById(self.symbol['width']).GetValue())
  2055. srcrender = False
  2056. srcrenderVector = False
  2057. tgtrender = False
  2058. tgtrenderVector = False
  2059. if self.new_src_map:
  2060. # remove old layer
  2061. layers = self.parent.grwiz.SrcMap.GetListOfLayers()
  2062. self.parent.grwiz.SrcMap.DeleteLayer(layers[0])
  2063. src_map = self.new_src_map
  2064. cmdlist = ['d.rast', 'map=%s' % src_map]
  2065. self.parent.grwiz.SwitchEnv('source')
  2066. self.parent.grwiz.SrcMap.AddLayer(type='raster', command=cmdlist, l_active=True,
  2067. name=utils.GetLayerNameFromCmd(cmdlist),
  2068. l_hidden=False, l_opacity=1.0, l_render=False)
  2069. self.parent.grwiz.SwitchEnv('target')
  2070. srcrender = True
  2071. if self.new_tgt_map:
  2072. # remove old layer
  2073. layers = self.parent.grwiz.TgtMap.GetListOfLayers()
  2074. self.parent.grwiz.TgtMap.DeleteLayer(layers[0])
  2075. tgt_map = self.new_tgt_map
  2076. cmdlist = ['d.rast', 'map=%s' % tgt_map]
  2077. self.parent.grwiz.TgtMap.AddLayer(type='raster', command=cmdlist, l_active=True,
  2078. name=utils.GetLayerNameFromCmd(cmdlist),
  2079. l_hidden=False, l_opacity=1.0, l_render=False)
  2080. tgtrender = True
  2081. self.parent.UpdateColours(srcrender, srcrenderVector, tgtrender, tgtrenderVector)
  2082. def OnSave(self, event):
  2083. """!Button 'Save' pressed"""
  2084. self.UpdateSettings()
  2085. fileSettings = {}
  2086. UserSettings.ReadSettingsFile(settings=fileSettings)
  2087. fileSettings['gcpman'] = UserSettings.Get(group='gcpman')
  2088. file = UserSettings.SaveToFile(fileSettings)
  2089. self.parent.parent.goutput.WriteLog(_('GCP Manager settings saved to file \'%s\'.') % file)
  2090. #self.Close()
  2091. def OnApply(self, event):
  2092. """!Button 'Apply' pressed"""
  2093. self.UpdateSettings()
  2094. #self.Close()
  2095. def OnClose(self, event):
  2096. """!Button 'Cancel' pressed"""
  2097. self.Close()