manager.py 106 KB

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