manager.py 105 KB

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