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