gcpmanager.py 101 KB

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