gcpmanager.py 103 KB

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