gcpmanager.py 104 KB

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