gcpmanager.py 101 KB

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