gcpmanager.py 104 KB

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