manager.py 106 KB

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