manager.py 104 KB

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