gcpmanager.py 105 KB

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