manager.py 103 KB

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