gcpmanager.py 105 KB

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