georect.py 45 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170
  1. """
  2. MODULE: georect.py
  3. CLASSES:
  4. * Georectify
  5. * GCP
  6. * GRMap
  7. PURPOSE: Georectification module for GRASS GIS. Includes ground control
  8. point management and interactive point and click GCP creation
  9. AUTHORS: The GRASS Development Team
  10. Michael Barton
  11. COPYRIGHT: (C) 2006-2007 by the GRASS Development Team
  12. This program is free software under the GNU General Public
  13. License (>=v2). Read the file COPYING that comes with GRASS
  14. for details.
  15. """
  16. # recheck once completed to see how many of these are still needed
  17. import os
  18. import sys
  19. import time
  20. import glob
  21. import math
  22. import tempfile
  23. import shutil
  24. import wx
  25. import wx.aui
  26. import wx.lib.filebrowsebutton as filebrowse
  27. from wx.lib.mixins.listctrl import CheckListCtrlMixin, ListCtrlAutoWidthMixin, TextEditMixin
  28. import wx.wizard as wiz
  29. import wx.grid as gridlib
  30. from threading import Thread
  31. import globalvar
  32. import mapdisp
  33. import render
  34. import toolbars
  35. import menuform
  36. import gselect
  37. import disp_print
  38. import gcmd
  39. import utils
  40. import menuform
  41. from debug import Debug as Debug
  42. from icon import Icons as Icons
  43. try:
  44. import subprocess # Not needed if GRASS commands could actually be quiet
  45. except:
  46. CompatPath = globalvar.ETCWXDIR
  47. sys.path.append(CompatPath)
  48. from compat import subprocess
  49. gmpath = os.path.join(globalvar.ETCWXDIR, "icons")
  50. sys.path.append(gmpath)
  51. import images
  52. imagepath = images.__path__[0]
  53. sys.path.append(imagepath)
  54. # global variables
  55. global xy_map
  56. global maptype
  57. xy_map = ''
  58. maptype = 'cell'
  59. class TitledPage(wiz.WizardPageSimple):
  60. """
  61. Class to make wizard pages. Generic methods to make
  62. labels, text entries, and buttons.
  63. """
  64. def __init__(self, parent, title):
  65. wiz.WizardPageSimple.__init__(self, parent)
  66. self.title = wx.StaticText(self,-1,title)
  67. self.title.SetFont(wx.Font(13, wx.SWISS, wx.NORMAL, wx.BOLD))
  68. self.sizer = wx.BoxSizer(wx.VERTICAL)
  69. tmpsizer = wx.BoxSizer(wx.VERTICAL)
  70. tmpsizer.Add(self.title, 0, wx.ALIGN_CENTRE|wx.ALL, 5)
  71. tmpsizer.AddSpacer(10)
  72. tmpsizer.Add(wx.StaticLine(self, -1), 0, wx.EXPAND|wx.ALL, 0)
  73. tmpsizer.Add(self.sizer, wx.EXPAND)
  74. self.SetSizer(tmpsizer)
  75. self.SetAutoLayout(True)
  76. tmpsizer.Fit(self)
  77. class GeorectWizard(object):
  78. """
  79. Start wizard here and finish wizard here
  80. """
  81. def __init__(self, parent):
  82. #
  83. # define wizard image
  84. #
  85. # file = "loc_wizard.png"
  86. #file = "loc_wizard_qgis.png"
  87. #imagePath = os.path.join(globalvar.ETCWXDIR, "images",
  88. # file)
  89. #wizbmp = wx.Image(imagePath, wx.BITMAP_TYPE_PNG)
  90. ## wizbmp.Rescale(250,600)
  91. #wizbmp = wizbmp.ConvertToBitmap()
  92. self.parent = parent
  93. #set environmental variables
  94. cmdlist = ['g.gisenv', 'get=GISDBASE']
  95. #global grassdatabase
  96. p = gcmd.Command(cmdlist)
  97. self.grassdatabase = p.ReadStdOutput()[0]
  98. # read original environment settings
  99. #self.orig_env = os.environ.copy()
  100. self.orig_gisrc = os.environ['GISRC']
  101. f = open(self.orig_gisrc)
  102. self.gisrc_dict = {}
  103. try:
  104. for line in f:
  105. if line != '':
  106. line = line.strip(' \n')
  107. self.gisrc_dict[line.split(':')[0]] = line.split(':')[1].strip()
  108. finally:
  109. f.close()
  110. self.currentlocation = self.gisrc_dict['LOCATION_NAME']
  111. self.currentmapset = self.gisrc_dict['MAPSET']
  112. self.newlocation = '' #location for xy map to georectify
  113. self.newmapset = '' #mapset for xy map to georectify
  114. self.new_gisrc = '' #GISRC file for source location/mapset of map(s) to georectify
  115. # define wizard pages
  116. self.wizard = wiz.Wizard(parent, -1, "Setup for georectification")
  117. self.startpage = LocationPage(self.wizard, self)
  118. self.grouppage = GroupPage(self.wizard, self)
  119. self.mappage = DispMapPage(self.wizard, self)
  120. # Set the initial order of the pages
  121. self.startpage.SetNext(self.grouppage)
  122. self.grouppage.SetPrev(self.startpage)
  123. self.grouppage.SetNext(self.mappage)
  124. self.mappage.SetPrev(self.grouppage)
  125. self.wizard.FitToPage(self.startpage)
  126. #self.Bind(wx.EVT_CLOSE, self.Cleanup)
  127. self.parent.Bind(wx.EVT_ACTIVATE, self.OnGLMFocus)
  128. success = False
  129. if self.wizard.RunWizard(self.startpage):
  130. success = self.onWizFinished()
  131. if success == True:
  132. pass
  133. else:
  134. wx.MessageBox("Georectifying setup canceled.")
  135. self.Cleanup()
  136. else:
  137. wx.MessageBox("Georectifying setup canceled.")
  138. self.Cleanup()
  139. # start display showing xymap
  140. if success != False:
  141. self.Map = render.Map() # instance of render.Map to be associated with display
  142. global maptype
  143. global xy_map
  144. if maptype == 'cell':
  145. rendertype = 'raster'
  146. cmdlist = ['d.rast', 'map=%s' % xy_map]
  147. elif maptype == 'vector':
  148. rendertype = 'vector'
  149. cmdlist = ['d.vect', 'map=%s' % xy_map]
  150. self.Map.AddLayer(type=rendertype, command=cmdlist,l_active=True,
  151. l_hidden=False, l_opacity=1, l_render=False)
  152. self.xy_mapdisp = mapdisp.MapFrame(self.parent, title="Set ground control points (GCPs)",
  153. pos=wx.DefaultPosition, size=(640,480),
  154. style=wx.DEFAULT_FRAME_STYLE, toolbars=["georect"],
  155. Map=self.Map, gismgr=self.parent, georect=True)
  156. self.mapwin = self.xy_mapdisp.MapWindow
  157. # set mouse characteristics
  158. self.mapwin.mouse['box'] = 'point'
  159. self.mapwin.mouse["use"] == "pointer"
  160. self.mapwin.zoomtype = 0
  161. self.mapwin.pen = wx.Pen(colour='black', width=2, style=wx.SOLID)
  162. self.mapwin.SetCursor(self.xy_mapdisp.cursors["cross"])
  163. # draw selected xy map
  164. self.xy_mapdisp.MapWindow.UpdateMap()
  165. #show new display
  166. self.xy_mapdisp.Show()
  167. self.xy_mapdisp.Refresh()
  168. self.xy_mapdisp.Update()
  169. # start GCP form
  170. self.gcpmgr = GCP(self.parent, grwiz=self)
  171. self.gcpmgr.Show()
  172. self.gcpmgr.Refresh()
  173. self.gcpmgr.Update()
  174. else:
  175. self.Cleanup()
  176. def SetSrcEnv(self, location, mapset):
  177. """Create environment to use for location and mapset
  178. that are the source of the file(s) to georectify"""
  179. self.newlocation = location
  180. self.newmapset = mapset
  181. # check to see if we are georectifying map in current working location/mapset
  182. if self.newlocation == self.currentlocation and self.newmapset == self.currentmapset:
  183. return
  184. self.gisrc_dict['LOCATION_NAME'] = location
  185. self.gisrc_dict['MAPSET'] = mapset
  186. self.new_gisrc = utils.GetTempfile()
  187. f = open(self.new_gisrc, mode='w')
  188. for line in self.gisrc_dict.items():
  189. f.write(line[0]+": "+line[1]+"\n")
  190. f.close()
  191. def SwitchEnv(self, grc):
  192. """
  193. Switches between original working location/mapset and
  194. location/mapset that is source of file(s) to georectify
  195. """
  196. # check to see if we are georectifying map in current working location/mapset
  197. if self.newlocation == self.currentlocation and self.newmapset == self.currentmapset:
  198. return
  199. if grc == 'original':
  200. os.environ["GISRC"] = str(self.orig_gisrc)
  201. elif grc == 'new':
  202. os.environ["GISRC"] = str(self.new_gisrc)
  203. def onWizFinished(self):
  204. return True
  205. self.Cleanup()
  206. def OnGLMFocus(self, event):
  207. #self.SwitchEnv('original')
  208. pass
  209. def Cleanup(self):
  210. # return to current location and mapset
  211. self.SwitchEnv('original')
  212. self.parent.georectifying = False
  213. try:
  214. self.xy_mapdisp.Destroy()
  215. self.wizard.Destroy()
  216. except:
  217. pass
  218. class LocationPage(TitledPage):
  219. """
  220. Set map type (raster or vector) to georectify and
  221. select location/mapset of map(s) to georectify.
  222. """
  223. def __init__(self, wizard, parent):
  224. TitledPage.__init__(self, wizard, "Select map type and location/mapset")
  225. self.parent = parent
  226. self.grassdatabase = self.parent.grassdatabase
  227. self.xylocation = ''
  228. self.xymapset = ''
  229. tmplist = os.listdir(self.grassdatabase)
  230. self.locList = []
  231. # Create a list of valid locations
  232. for item in tmplist:
  233. if os.path.isdir(os.path.join(self.grassdatabase,item)) and \
  234. os.path.exists(os.path.join(self.grassdatabase,item,'PERMANENT')):
  235. self.locList.append(item)
  236. self.mapsetList = []
  237. box = wx.BoxSizer(wx.HORIZONTAL)
  238. self.rb_maptype = wx.RadioBox(self, -1, "Map type to georectify",
  239. wx.DefaultPosition, wx.DefaultSize,
  240. ['raster','vector'], 2, wx.RA_SPECIFY_COLS)
  241. box.Add(self.rb_maptype, 0, wx.ALIGN_CENTER|wx.ALL, 5)
  242. self.sizer.Add(box, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
  243. box = wx.BoxSizer(wx.HORIZONTAL)
  244. label = wx.StaticText(self, -1, 'select location:',
  245. style=wx.ALIGN_RIGHT)
  246. box.Add(label, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
  247. self.cb_location = wx.ComboBox(self, wx.ID_ANY, "",
  248. wx.DefaultPosition,
  249. wx.DefaultSize,
  250. choices = self.locList,
  251. style=wx.CB_DROPDOWN|wx.CB_READONLY)
  252. box.Add(self.cb_location, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
  253. self.sizer.Add(box, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
  254. box = wx.BoxSizer(wx.HORIZONTAL)
  255. label = wx.StaticText(self, -1, 'select mapset:',
  256. style=wx.ALIGN_RIGHT)
  257. box.Add(label, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
  258. self.cb_mapset = wx.ComboBox(self, wx.ID_ANY, "",
  259. wx.DefaultPosition,
  260. wx.DefaultSize,
  261. choices = self.mapsetList,
  262. style=wx.CB_DROPDOWN|wx.CB_READONLY)
  263. box.Add(self.cb_mapset, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
  264. self.sizer.Add(box, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
  265. self.Bind(wx.EVT_RADIOBOX, self.OnMaptype, self.rb_maptype)
  266. self.Bind(wx.EVT_COMBOBOX, self.OnLocation, self.cb_location)
  267. self.Bind(wx.EVT_COMBOBOX, self.OnMapset, self.cb_mapset)
  268. self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.onPageChanging)
  269. self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
  270. self.Bind(wx.EVT_CLOSE, self.parent.Cleanup)
  271. def OnMaptype(self,event):
  272. global maptype
  273. if event.GetInt() == 0:
  274. maptype = 'cell'
  275. elif event.GetInt() == 1:
  276. maptype = 'vector'
  277. def OnLocation(self, event):
  278. """Sets source location for map(s) to georectify"""
  279. self.xylocation = event.GetString()
  280. #create a list of valid mapsets
  281. tmplist = os.listdir(os.path.join(self.grassdatabase,self.xylocation))
  282. self.mapsetList = []
  283. for item in tmplist:
  284. if os.path.isdir(os.path.join(self.grassdatabase,self.xylocation,item)) and \
  285. os.path.exists(os.path.join(self.grassdatabase,self.xylocation,item,'WIND')):
  286. self.mapsetList.append(item)
  287. self.cb_mapset.SetItems(self.mapsetList)
  288. def OnMapset(self, event):
  289. """Sets source mapset for map(s) to georectify"""
  290. if self.xylocation == '':
  291. wx.MessageBox('You must select a valid location before selecting a mapset')
  292. return
  293. self.xymapset = event.GetString()
  294. def onPageChanging(self,event=None):
  295. if event.GetDirection() and (self.xylocation == '' or self.xymapset == ''):
  296. wx.MessageBox('You must select a valid location and mapset in order to continue')
  297. event.Veto()
  298. return
  299. else:
  300. self.parent.SetSrcEnv(self.xylocation, self.xymapset)
  301. def OnPageChanged(self,event=None):
  302. pass
  303. class GroupPage(TitledPage):
  304. """
  305. Set group to georectify. Create group if desired.
  306. """
  307. def __init__(self, wizard, parent):
  308. TitledPage.__init__(self, wizard, "Select image/map group to georectify")
  309. self.parent = parent
  310. self.groupList = []
  311. self.grassdatabase = self.parent.grassdatabase
  312. self.xylocation = ''
  313. self.xymapset = ''
  314. self.xygroup = ''
  315. self.extension = 'georect'+str(os.getpid())
  316. box = wx.BoxSizer(wx.HORIZONTAL)
  317. label = wx.StaticText(self, -1, 'select group:',
  318. style=wx.ALIGN_RIGHT)
  319. box.Add(label, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
  320. self.cb_group = wx.ComboBox(self, wx.ID_ANY, "",
  321. wx.DefaultPosition,
  322. wx.DefaultSize,
  323. choices = self.groupList,
  324. style=wx.CB_DROPDOWN|wx.CB_READONLY)
  325. box.Add(self.cb_group, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
  326. self.sizer.Add(box, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
  327. box = wx.BoxSizer(wx.HORIZONTAL)
  328. label = wx.StaticText(self, -1, 'Create group if none exists', style=wx.ALIGN_LEFT)
  329. box.Add(label, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
  330. self.btn_mkgroup = wx.Button(self, wx.ID_ANY, "Create/edit group ...")
  331. box.Add(self.btn_mkgroup, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
  332. self.sizer.Add(box, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
  333. box = wx.BoxSizer(wx.HORIZONTAL)
  334. label = wx.StaticText(self, -1, 'Extension for output maps:', style=wx.ALIGN_LEFT)
  335. box.Add(label, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
  336. self.ext_txt = wx.wx.TextCtrl(self, -1, "", size=(150,-1))
  337. self.ext_txt.SetValue(self.extension)
  338. box.Add(self.ext_txt, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
  339. self.sizer.Add(box, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
  340. self.Bind(wx.EVT_COMBOBOX, self.OnGroup, self.cb_group)
  341. self.Bind(wx.EVT_BUTTON, self.OnMkGroup, self.btn_mkgroup)
  342. self.Bind(wx.EVT_TEXT, self.OnExtension, self.ext_txt)
  343. self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.onPageChanging)
  344. self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
  345. self.Bind(wx.EVT_CLOSE, self.parent.Cleanup)
  346. def OnGroup(self, event):
  347. self.xygroup = event.GetString()
  348. def OnMkGroup(self, event):
  349. global maptype
  350. self.parent.SwitchEnv('new')
  351. if maptype == 'cell':
  352. cmdlist = ['i.group']
  353. menuform.GUI().ParseCommand(cmdlist, parentframe=self.parent.parent)
  354. elif maptype == 'vector':
  355. dlg = VectGroup(self, wx.ID_ANY, self.grassdatabase, self.xylocation, self.xymapset, self.xygroup)
  356. if dlg.ShowModal() == wx.ID_OK:
  357. dlg.MakeVGroup()
  358. #refresh combobox list
  359. try:
  360. tmplist = os.listdir(os.path.join(self.grassdatabase,self.xylocation,self.xymapset,'group'))
  361. except:
  362. return
  363. if tmplist != []:
  364. for item in tmplist:
  365. if os.path.isdir(os.path.join(self.grassdatabase,self.xylocation,self.xymapset,'group',item)):
  366. self.groupList.append(item)
  367. self.cb_group.SetItems(self.groupList)
  368. def OnExtension(self, event):
  369. self.extension = event.GetString()
  370. def onPageChanging(self,event=None):
  371. if event.GetDirection() and self.xygroup == '':
  372. wx.MessageBox('You must select a valid image/map group in order to continue')
  373. event.Veto()
  374. return
  375. if event.GetDirection() and self.extension == '':
  376. wx.MessageBox('You must enter an map name extension in order to continue')
  377. event.Veto()
  378. return
  379. def OnPageChanged(self,event=None):
  380. self.groupList = []
  381. tmplist = []
  382. self.xylocation = self.parent.gisrc_dict['LOCATION_NAME']
  383. self.xymapset = self.parent.gisrc_dict['MAPSET']
  384. # create a list of groups in selected mapset
  385. tmplist = os.listdir(os.path.join(self.grassdatabase,self.xylocation,self.xymapset,'group'))
  386. if event.GetDirection() and self.xygroup == '':
  387. if tmplist == []:
  388. wx.MessageBox('No map/imagery groups exist to georectify. You will need to create one')
  389. else:
  390. for item in tmplist:
  391. if os.path.isdir(os.path.join(self.grassdatabase,self.xylocation,self.xymapset,'group',item)):
  392. self.groupList.append(item)
  393. self.cb_group.SetItems(self.groupList)
  394. class DispMapPage(TitledPage):
  395. """
  396. Select ungeoreferenced map to display for interactively
  397. setting ground control points (GCPs).
  398. """
  399. def __init__(self, wizard, parent):
  400. TitledPage.__init__(self, wizard, "Select image/map to display for ground control point (GCP) creation")
  401. self.parent = parent
  402. global maptype
  403. self.parent = parent
  404. box = wx.BoxSizer(wx.HORIZONTAL)
  405. label = wx.StaticText(self, -1, 'Select display image/map:', style=wx.ALIGN_LEFT)
  406. box.Add(label, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
  407. self.selection = gselect.Select(self, id=wx.ID_ANY, size=(300,-1),
  408. type=maptype )
  409. box.Add(self.selection, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
  410. self.sizer.Add(box, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
  411. self.selection.Bind(wx.EVT_TEXT, self.OnSelection)
  412. self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.onPageChanging)
  413. self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
  414. self.Bind(wx.EVT_CLOSE, self.parent.Cleanup)
  415. def OnSelection(self,event):
  416. global xy_map
  417. xy_map = event.GetString()
  418. def onPageChanging(self,event=None):
  419. global xy_map
  420. if event.GetDirection() and xy_map == '':
  421. wx.MessageBox('You must select a valid image/map in order to continue')
  422. event.Veto()
  423. return
  424. def OnPageChanged(self,event=None):
  425. global maptype
  426. if event.GetDirection():
  427. # switch to xy location if coming into the page from preceding
  428. self.parent.SwitchEnv('new')
  429. self.selection.SetElementList(maptype)
  430. else:
  431. # switch back to current location if leaving the page
  432. self.parent.SwitchEnv('original')
  433. class GCP(wx.Frame):
  434. """
  435. Manages ground control points for georectifying. Calculates RMS statics.
  436. Calls i.rectify or v.transform to georectify map.
  437. """
  438. def __init__(self,parent,id=-1,title="Create & manage ground control points",
  439. size=wx.DefaultSize, grwiz=None):
  440. wx.Frame.__init__(self, parent, id , title, size=(600,300))
  441. self.Centre(wx.HORIZONTAL)
  442. toolbar = self.__createToolBar()
  443. self.parent = parent
  444. self.grwiz = grwiz
  445. self.grassdatabase = self.grwiz.grassdatabase
  446. self.currentlocation = self.grwiz.currentlocation
  447. self.currentmapset = self.grwiz.currentmapset
  448. self.newlocation = self.grwiz.newlocation
  449. self.newmapset = self.grwiz.newmapset
  450. self.xylocation = self.grwiz.gisrc_dict['LOCATION_NAME']
  451. self.xymapset = self.grwiz.gisrc_dict['MAPSET']
  452. self.xygroup = self.grwiz.grouppage.xygroup
  453. self.extension = self.grwiz.grouppage.extension
  454. self.pointsfile = os.path.join(self.grassdatabase,self.xylocation,self.xymapset,'group',self.xygroup,'POINTS')
  455. self.rgrpfile = os.path.join(self.grassdatabase,self.xylocation,self.xymapset,'group',self.xygroup,'REF')
  456. self.vgrpfile = os.path.join(self.grassdatabase,self.xylocation,self.xymapset,'group',self.xygroup,'VREF')
  457. self.targetfile = os.path.join(self.grassdatabase,self.xylocation,self.xymapset,'group',self.xygroup,'TARGET')
  458. self.SetTarget(self.xygroup, self.currentlocation, self.currentmapset)
  459. self.gr_order = 1 #polynomial order transformation for georectification
  460. self.selected = 0 #gcp list item selected
  461. self.GCPcount = 0 #number of GCPs selected to be used for georectification (checked)
  462. self.fwd_rmserror = 0.0 # forward RMS error
  463. self.bkw_rmserror = 0.0 # backward RMS error
  464. self.mapcoordlist = [(0000000.00,0000000.00,'')] #list map coords and ID of map display they came from
  465. self.CreateStatusBar(3,1,-1,'gcpstatusbar')
  466. self.SetStatusText('RMS error for selected points',0)
  467. # can put guage into custom statusbar for progress if can figure out how to get progress text from i.rectify
  468. #self.gr_gauge = wx.Gauge(self, -1, 100, (-1,-1), (100, 25))
  469. #self.gr_guage.Pulse()
  470. p = wx.Panel(self, -1, style=0)
  471. self.sizer = wx.BoxSizer(wx.VERTICAL)
  472. box = wx.BoxSizer(wx.HORIZONTAL)
  473. self.rb_grmethod = wx.RadioBox(p, -1, "Select rectification method for rasters ",
  474. wx.DefaultPosition, wx.DefaultSize,
  475. ['1st order','2nd order', '3rd order'], 3, wx.RA_SPECIFY_COLS)
  476. box.Add(self.rb_grmethod, 0, wx.ALIGN_CENTER|wx.ALL, 5)
  477. self.sizer.Add(box, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
  478. # initialize list control for GCP management
  479. self.list = CheckListCtrl(p, -1, style=wx.LC_REPORT | wx.SUNKEN_BORDER | wx.LC_HRULES)
  480. self.list.InsertColumn(0, 'use| X coord', width=120)
  481. self.list.InsertColumn(1, 'Y coord')
  482. self.list.InsertColumn(2, 'N coord')
  483. self.list.InsertColumn(3, 'E coord')
  484. self.list.InsertColumn(4, 'Forward error')
  485. self.list.InsertColumn(5, 'Backward error')
  486. if os.path.isfile(self.pointsfile):
  487. self.ReadGCPs()
  488. self.ResizeColumns()
  489. elif self.list.GetItemCount() == 0:
  490. # initialize 3 blank lines in the GCP list (minimum for georectification)
  491. i = ('0000000.00','0000000.00','0000000.00','0000000.00','','')
  492. index = self.list.InsertStringItem(sys.maxint, i[0])
  493. self.list.SetStringItem(index, 1, i[1])
  494. self.list.SetStringItem(index, 2, i[2])
  495. self.list.SetStringItem(index, 3, i[3])
  496. self.list.SetStringItem(index, 4, i[4])
  497. self.list.SetStringItem(index, 5, i[5])
  498. self.list.CheckItem(0, True)
  499. self.AddGCP(None)
  500. self.AddGCP(None)
  501. self.ResizeColumns()
  502. self.sizer.Add(self.list, 1, wx.EXPAND|wx.ALL, 5)
  503. p.SetSizer(self.sizer)
  504. self.Bind(wx.EVT_RADIOBOX, self.OnGRMethod, self.rb_grmethod)
  505. self.list.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected)
  506. self.list.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.OnItemActivated)
  507. self.Bind(wx.EVT_ACTIVATE, self.OnFocus)
  508. self.Bind(wx.EVT_CLOSE, self.grwiz.Cleanup)
  509. def __createToolBar(self):
  510. """Creates toolbar"""
  511. toolbar = self.CreateToolBar()
  512. for each in self.toolbarData():
  513. self.addToolbarButton(toolbar, *each)
  514. toolbar.Realize()
  515. def OnFocus(self, event):
  516. self.grwiz.SwitchEnv('new')
  517. def ResizeColumns(self):
  518. for i in range(6):
  519. self.list.SetColumnWidth(i, wx.LIST_AUTOSIZE)
  520. def SetTarget(self, tgroup, tlocation, tmapset):
  521. """
  522. Sets rectification target to current location and mapset
  523. """
  524. # check to see if we are georectifying map in current working location/mapset
  525. if self.newlocation == self.currentlocation and self.newmapset == self.currentmapset:
  526. cmdlist = ['i.target', 'c', 'group=%s' % tgroup]
  527. else:
  528. self.grwiz.SwitchEnv('new')
  529. cmdlist = ['i.target', 'group=%s' % tgroup, 'location=%s' % tlocation, 'mapset=%s' % tmapset]
  530. gcmd.Command(cmd=cmdlist)
  531. def addToolbarButton(self, toolbar, label, icon, help, handler):
  532. """Adds button to the given toolbar"""
  533. if not label:
  534. toolbar.AddSeparator()
  535. return
  536. tool = toolbar.AddLabelTool(id=wx.ID_ANY, label=label, bitmap=icon, shortHelp=help)
  537. self.Bind(wx.EVT_TOOL, handler, tool)
  538. def toolbarData(self):
  539. return (
  540. ('savegcp', Icons["savefile"].GetBitmap(), 'Save GCPs to POINTS file', self.SaveGCPs),
  541. ('addgcp', wx.ArtProvider.GetBitmap(wx.ART_NEW, wx.ART_TOOLBAR, (16,16)), 'Add new GCP', self.AddGCP),
  542. ('deletegcp', wx.ArtProvider.GetBitmap(wx.ART_DELETE, wx.ART_TOOLBAR, (16,16)), 'Delete selected GCP', self.DeleteGCP),
  543. ('cleargcp', Icons["cleargcp"].GetBitmap(), Icons["cleargcp"].GetLabel(), self.ClearGCP),
  544. ('refreshgcp', Icons["refreshgcp"].GetBitmap(), Icons["refreshgcp"].GetLabel(), self.RefreshGCPMarks),
  545. ('rms', Icons["rms"].GetBitmap(), Icons["rms"].GetLabel(), self.OnRMS),
  546. ('georect', Icons["georect"].GetBitmap(), Icons["georect"].GetLabel(), self.OnGeorect),
  547. ('quit', wx.ArtProvider.GetBitmap(wx.ART_QUIT, wx.ART_TOOLBAR, (16,16)), 'Quit georectification module', self.OnQuit)
  548. )
  549. def SaveGCPs(self, event):
  550. """
  551. Make a POINTS file or save GCP coordinates to existing POINTS file
  552. """
  553. self.GCPcount = 0
  554. f = open(self.pointsfile, mode='w')
  555. try:
  556. f.write('# Ground Control Points File\n')
  557. f.write("# \n")
  558. f.write("# target location: "+self.currentlocation+'\n')
  559. f.write("# target mapset: "+self.currentmapset+'\n')
  560. f.write("#unrectified xy georectified east north 1=use gcp point\n")
  561. f.write("#-------------- ----------------------- ---------------\n")
  562. for index in range(self.list.GetItemCount()):
  563. if self.list.IsChecked(index) == True:
  564. check = "1"
  565. self.GCPcount += 1
  566. else:
  567. check = "0"
  568. coord0 = self.list.GetItem(index, 0).GetText()
  569. coord1 = self.list.GetItem(index, 1).GetText()
  570. coord2 = self.list.GetItem(index, 2).GetText()
  571. coord3 = self.list.GetItem(index, 3).GetText()
  572. f.write(coord0+' '+coord1+' '+coord2+' '+coord3+' '+check+'\n')
  573. finally:
  574. f.close()
  575. pass
  576. def DeleteGCP(self, event):
  577. """
  578. Deletes selected item in GCP list
  579. """
  580. self.list.DeleteItem(self.selected)
  581. del self.mapcoordlist[self.selected]
  582. def AddGCP(self, event):
  583. """
  584. Appends an item to GCP list
  585. """
  586. self.list.Append(['0000000.00','0000000.00','0000000.00','0000000.00','',''])
  587. index = self.list.GetItemCount() - 1
  588. self.mapcoordlist.append((0000000.00,0000000.00,''))
  589. self.list.SetItemState(index, wx.LIST_STATE_SELECTED, wx.LIST_STATE_SELECTED)
  590. self.ResizeColumns()
  591. return index
  592. def SetGCPData(self, coordtype, coord, mapdisp=None, check=True):
  593. """
  594. Inserts coordinates from mouse click on map
  595. into selected item of GCP list and checks it for use
  596. """
  597. index = self.selected
  598. coord0 = str(coord[0])
  599. coord1 = str(coord[1])
  600. if coordtype == 'gcpcoord':
  601. self.list.SetStringItem(index, 0, coord0)
  602. self.list.SetStringItem(index, 1, coord1)
  603. if coordtype == 'mapcoord':
  604. self.list.SetStringItem(index, 2, coord0)
  605. self.list.SetStringItem(index, 3, coord1)
  606. self.mapcoordlist[index] = (coord[0], coord[1], mapdisp)
  607. self.list.CheckItem(index, check)
  608. self.ResizeColumns()
  609. def ClearGCP(self, event):
  610. """
  611. Clears all values in selected item of GCP list and unchecks it
  612. """
  613. index = self.selected
  614. for i in range(4):
  615. self.list.SetStringItem(index, i, '0000000.00')
  616. self.list.SetStringItem(index, 4, '')
  617. self.list.SetStringItem(index, 5, '')
  618. self.mapcoordlist[index] = (0000000.00,0000000.00,'')
  619. self.list.CheckItem(index, False)
  620. def ReadGCPs(self):
  621. """
  622. Reads GCPs and georectified coordinates from POINTS file
  623. """
  624. self.GCPcount = 0
  625. f = open(self.pointsfile)
  626. try:
  627. GCPcnt = 0
  628. for line in f:
  629. if line[0] != '#' and line !='':
  630. line = line.strip(' \n')
  631. coords = line.split()
  632. if coords[4] == '1':
  633. check = True
  634. self.GCPcount +=1
  635. else:
  636. check = False
  637. index = self.AddGCP(event=None)
  638. for i in range(4):
  639. self.list.SetStringItem(index, i, coords[i])
  640. self.list.CheckItem(index, check)
  641. finally:
  642. f.close()
  643. self.RefreshGCPMarks(None)
  644. if self.CheckGCPcount():
  645. self.RMSError(self.xygroup, self.gr_order)
  646. def OnRMS(self, event):
  647. """
  648. RMS button handler
  649. """
  650. self.RMSError(self.xygroup,self.gr_order)
  651. def CheckGCPcount(self, msg=False):
  652. """
  653. Checks to make sure that the minimum number of GCPs have been defined and
  654. are active for the selected transformation order
  655. """
  656. if (self.GCPcount < 3 and self.gr_order == 1) or \
  657. (self.GCPcount < 6 and self.gr_order == 2) or \
  658. (self.GCPcount < 10 and self.gr_order == 3):
  659. if msg:
  660. s1 = 'Insufficient points defined and active (checked)\n'
  661. s2 = 'for selected rectification method.\n'
  662. s3 = '3+ points needed for 1st order,\n'
  663. s4 = '6+ points for 2nd order, and\n'
  664. s5 = '10+ points for 3rd order.'
  665. wx.MessageBox('%s%s%s%s%s' % (s1, s2, s3, s4, s5))
  666. return False
  667. else:
  668. return True
  669. def OnGeorect(self, event):
  670. """
  671. Georectifies map(s) in group using i.rectify or v.transform
  672. """
  673. global maptype
  674. self.SaveGCPs()
  675. if self.CheckGCPcount(msg=True) == False:
  676. return
  677. if maptype == 'cell':
  678. cmdlist = ['i.rectify', '-ca', 'group=%s' % self.xygroup, 'extension=%s' % self.extension, 'order=%s' % self.gr_order]
  679. p = gcmd.Command(cmd=cmdlist)
  680. stdout = p.ReadStdOutput()
  681. stderr = p.ReadErrOutput()
  682. msg = err = ''
  683. if p.returncode == 0:
  684. for line in stdout:
  685. msg = msg+line+'\n'
  686. for line in stderr:
  687. err = err+line+'\n'
  688. wx.MessageBox('All maps georectified successfully\n'+msg+'\n'+err)
  689. else:
  690. for line in stderr:
  691. err = err+line+'\n'
  692. wx.MessageBox(err)
  693. elif maptype == 'vector':
  694. # loop through all vectors in VREF and move resulting vector to target location
  695. f = open(self.vgrpfile)
  696. vectlist = []
  697. try:
  698. for vect in f:
  699. vect = vect.strip(' \n')
  700. vectlist.append(vect)
  701. finally:
  702. f.close()
  703. for vect in vectlist:
  704. outname = vect+'_'+self.extension
  705. cmdlist = ['v.transform', '--q', 'input=%s' % vect, 'output=%s' % outname, 'pointsfile=%s' % self.pointsfile]
  706. p = gcmd.Command(cmd=cmdlist)
  707. stdout = p.ReadStdOutput()
  708. msg = '****'+outname+'****\n'
  709. for line in stdout:
  710. msg = msg+line+'\n'
  711. wx.MessageBox(msg)
  712. if p.returncode == 0:
  713. wx.MessageBox("All maps were georectified successfully")
  714. for vect in vectlist:
  715. outname = vect+'_'+self.extension
  716. xyvpath = os.path.join(self.grassdatabase,self.xylocation,self.xymapset,'vector',outname)
  717. vpath = os.path.join(self.grassdatabase,self.currentlocation,self.currentmapset,'vector',outname)
  718. if os.path.isfile(vpath):
  719. wx.MessageBox("%s already exists. Change extension name and georectify again" % outname)
  720. else:
  721. shutil.move(xyvpath, vpath)
  722. wx.MessageBox('For vector files with attribute tables, you will need to manually copy the tables to the new location')
  723. else:
  724. wx.MessageBox('Some maps were not georectified successfully')
  725. else:
  726. return
  727. def OnQuit(self, event):
  728. self.Destroy()
  729. self.grwiz.Cleanup()
  730. def OnItemSelected(self, event):
  731. self.selected = event.GetIndex()
  732. def OnItemActivated(self, event):
  733. """
  734. When item double clicked, open editor to update coordinate values
  735. """
  736. coords = []
  737. index = event.m_itemIndex
  738. for i in range(4):
  739. coords.append(self.list.GetItem(index, i).GetText())
  740. dlg = EditGPC(self, -1, data=coords)
  741. if dlg.ShowModal() == wx.ID_OK:
  742. values = dlg.GetValues() # string
  743. for i in range(4):
  744. if values[i] != coords[i]:
  745. self.list.SetStringItem(index, i, values[i])
  746. def RefreshGCPMarks(self, event):
  747. """
  748. Updates GCP and map coord maps and redraws
  749. active (checked) GCP markers
  750. """
  751. self.grwiz.SwitchEnv("new")
  752. self.grwiz.mapwin.UpdateMap()
  753. self.grwiz.SwitchEnv("original")
  754. mapid = ''
  755. for map in self.mapcoordlist:
  756. if map[2] != mapid and map[2] != '':
  757. map[2].UpdateMap()
  758. mapid = map[2]
  759. for index in range(self.list.GetItemCount()):
  760. if self.list.IsChecked(index) and (
  761. (self.list.GetItem(index, 0).GetText() != '0000000.00' and
  762. self.list.GetItem(index, 1).GetText() != '0000000.00') or
  763. (self.list.GetItem(index, 2).GetText() != '0000000.00' and
  764. self.list.GetItem(index, 3).GetText() != '0000000.00')
  765. ):
  766. coord0 = float(self.list.GetItem(index, 0).GetText())
  767. coord1 = float(self.list.GetItem(index, 1).GetText())
  768. coord2 = float(self.list.GetItem(index, 2).GetText())
  769. coord3 = float(self.list.GetItem(index, 3).GetText())
  770. self.grwiz.SwitchEnv("new")
  771. pxcoord1 = self.grwiz.mapwin.Cell2Pixel((coord0, coord1))
  772. self.grwiz.mapwin.DrawCross(pdc=self.grwiz.mapwin.pdcTmp,
  773. coords=pxcoord1, size=5)
  774. if self.mapcoordlist != [] and self.mapcoordlist[index][2] != '':
  775. self.grwiz.SwitchEnv("original")
  776. pxcoord2 = self.mapcoordlist[index][2].Cell2Pixel((coord2, coord3))
  777. self.mapcoordlist[index][2].DrawCross(pdc=self.mapcoordlist[index][2].pdcTmp,
  778. coords=pxcoord2, size=5)
  779. def OnGRMethod(self, event):
  780. """
  781. sets transformation order for georectifying
  782. """
  783. self.gr_order = event.GetInt() + 1
  784. def RMSError(self, xygroup, order):
  785. """
  786. Uses g.transform to calculate forward and backward error for each used GCP
  787. in POINTS file and insert error values into GCP list.
  788. Calculates total forward and backward RMS error for all used points
  789. """
  790. # save GCPs to points file to make sure that all checked GCPs are used
  791. self.SaveGCPs(None)
  792. if self.CheckGCPcount(msg=True) == False:
  793. return
  794. #get list of forward and reverse rms error values for each point
  795. self.grwiz.SwitchEnv('new')
  796. cmdlist = ['g.transform', 'group=%s' % xygroup, 'order=%s' % order]
  797. p = gcmd.Command(cmdlist)
  798. errlist = p.ReadStdOutput()
  799. if errlist == []:
  800. return
  801. #insert error values into GCP list for checked items
  802. i = 0
  803. sumsq_fwd_err = 0.0
  804. sumsq_bkw_err = 0.0
  805. for index in range(self.list.GetItemCount()):
  806. if self.list.IsChecked(index):
  807. fwd_err,bkw_err = errlist[i].split()
  808. self.list.SetStringItem(index, 4, fwd_err)
  809. self.list.SetStringItem(index, 5, bkw_err)
  810. sumsq_fwd_err += float(fwd_err)**2
  811. sumsq_bkw_err += float(bkw_err)**2
  812. i += 1
  813. else:
  814. self.list.SetStringItem(index, 4, '')
  815. self.list.SetStringItem(index, 5, '')
  816. #calculate RMS error
  817. self.fwd_rmserror = round((sumsq_fwd_err/i)**0.5,4)
  818. self.bkw_rmserror = round((sumsq_bkw_err/i)**0.5,4)
  819. self.ResizeColumns()
  820. self.SetStatusText('forward: %s' % self.fwd_rmserror,1)
  821. self.SetStatusText('backward: %s' % self.bkw_rmserror,2)
  822. class CheckListCtrl(wx.ListCtrl, CheckListCtrlMixin, ListCtrlAutoWidthMixin):
  823. def __init__(self, parent, ID=-1, pos=wx.DefaultPosition, size=wx.DefaultSize,
  824. style=0):
  825. wx.ListCtrl.__init__(self, parent, -ID, pos, size, style)
  826. CheckListCtrlMixin.__init__(self)
  827. ListCtrlAutoWidthMixin.__init__(self)
  828. self.CheckList = [] # tracks whether list items are checked or not
  829. #self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.OnItemActivated)
  830. # this is called by the base class when an item is checked/unchecked
  831. def OnCheckItem(self, index, flag):
  832. pass
  833. class VectGroup(wx.Dialog):
  834. """
  835. Dialog to create a vector group (VREF file) for georectifying
  836. """
  837. def __init__(self, parent, id, grassdb, location, mapset, group,
  838. style=wx.DEFAULT_DIALOG_STYLE):
  839. wx.Dialog.__init__(self, parent, id, style=style)
  840. self.grassdatabase = grassdb
  841. self.xylocation = location
  842. self.xymapset = mapset
  843. self.xygroup = group
  844. # get list of valid vector directories
  845. vectlist = os.listdir(os.path.join(self.grassdatabase,self.xylocation,self.xymapset,'vector'))
  846. for dir in vectlist:
  847. if os.path.isfile(os.path.join(self.grassdatabase,self.xylocation,self.xymapset,'vector',dir,'coor')):
  848. pass
  849. else:
  850. vectlist.remove(dir)
  851. self.vgrouplist = []
  852. self.vgrpfile = os.path.join(self.grassdatabase,self.xylocation,self.xymapset,'group',self.xygroup,'VREF')
  853. if os.path.isfile(self.vgrpfile):
  854. f = open(self.vgrpfile)
  855. try:
  856. for line in f:
  857. if line != '':
  858. self.vgrouplist.append(line.strip(' \n'))
  859. finally:
  860. f.close()
  861. self.btnCancel = wx.Button(self, wx.ID_CANCEL)
  862. self.btnSubmit = wx.Button(self, wx.ID_OK)
  863. self.btnSubmit.SetDefault()
  864. sizer = wx.BoxSizer(wx.VERTICAL)
  865. box = wx.BoxSizer(wx.HORIZONTAL)
  866. label = wx.StaticText(parent=self, id=wx.ID_ANY,
  867. label='Select vector map(s) to add to group:')
  868. box.Add(label, flag=wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT | wx.LEFT, border=5)
  869. self.addmap = wx.CheckListBox(self, -1, wx.DefaultPosition, wx.DefaultSize, vectlist)
  870. box.Add(self.addmap, flag=wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT| wx.LEFT, border=5)
  871. sizer.Add(box, flag=wx.ALIGN_RIGHT | wx.ALL, border=3)
  872. box = wx.BoxSizer(wx.HORIZONTAL)
  873. label = wx.StaticText(parent=self, id=wx.ID_ANY,
  874. label='Select vector map(s) to remove from group:')
  875. box.Add(label, flag=wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT | wx.LEFT, border=5)
  876. self.remmap = wx.CheckListBox(self, -1, wx.DefaultPosition, wx.DefaultSize, self.vgrouplist)
  877. box.Add(self.remmap, flag=wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT| wx.LEFT, border=5)
  878. sizer.Add(box, flag=wx.ALIGN_RIGHT | wx.ALL, border=3)
  879. # buttons
  880. btnSizer = wx.StdDialogButtonSizer()
  881. btnSizer.AddButton(self.btnCancel)
  882. btnSizer.AddButton(self.btnSubmit)
  883. btnSizer.Realize()
  884. sizer.Add(item=btnSizer, proportion=0,
  885. flag=wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border=5)
  886. self.SetSizer(sizer)
  887. sizer.Fit(self)
  888. self.Layout()
  889. self.Bind(wx.EVT_CHECKLISTBOX, self.AddVect, self.addmap)
  890. self.Bind(wx.EVT_CHECKLISTBOX, self.RemoveVect, self.remmap)
  891. def AddVect(self, event):
  892. index = event.GetSelection()
  893. label = self.addmap.GetString(index)
  894. if self.addmap.IsChecked(index):
  895. self.vgrouplist.append(label)
  896. self.addmap.SetSelection(index)
  897. event.Skip()
  898. def RemoveVect(self, event):
  899. index = event.GetSelection()
  900. label = self.remmap.GetString(index)
  901. if self.remmap.IsChecked(index):
  902. self.vgrouplist.remove(label)
  903. self.remmap.SetSelection(index)
  904. event.Skip()
  905. def MakeVGroup(self):
  906. f = open(self.vgrpfile, mode='w')
  907. for vect in self.vgrouplist:
  908. f.write(vect+'\n')
  909. class EditGPC(wx.Dialog):
  910. """Dialog for editing GPC and map coordinates in list control"""
  911. def __init__(self, parent, id, data,
  912. style=wx.DEFAULT_DIALOG_STYLE):
  913. wx.Dialog.__init__(self, parent, id, style=style)
  914. self.btnCancel = wx.Button(self, wx.ID_CANCEL)
  915. self.btnSubmit = wx.Button(self, wx.ID_OK)
  916. self.btnSubmit.SetDefault()
  917. sizer = wx.BoxSizer(wx.VERTICAL)
  918. box = wx.BoxSizer(wx.HORIZONTAL)
  919. xlabel = wx.StaticText(parent=self, id=wx.ID_ANY,
  920. label='X:')
  921. box.Add(xlabel, flag=wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT | wx.LEFT, border=5)
  922. self.xcoord = wx.TextCtrl(parent=self, id=wx.ID_ANY,
  923. value=data[0], size=(150, -1))
  924. box.Add(self.xcoord, flag=wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT| wx.LEFT, border=5)
  925. ylabel = wx.StaticText(parent=self, id=wx.ID_ANY,
  926. label='Y:')
  927. box.Add(ylabel, flag=wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT| wx.LEFT, border=5)
  928. self.ycoord = wx.TextCtrl(parent=self, id=wx.ID_ANY,
  929. value=data[1], size=(150, -1))
  930. box.Add(self.ycoord, flag=wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT| wx.LEFT | wx.RIGHT, border=5)
  931. sizer.Add(box, flag=wx.ALL, border=3)
  932. box = wx.BoxSizer(wx.HORIZONTAL)
  933. elabel = wx.StaticText(parent=self, id=wx.ID_ANY,
  934. label='E:')
  935. box.Add(elabel, flag=wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT| wx.LEFT, border=5)
  936. self.ecoord = wx.TextCtrl(parent=self, id=wx.ID_ANY,
  937. value=data[2], size=(150, -1))
  938. box.Add(self.ecoord, flag=wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT| wx.LEFT, border=5)
  939. nlabel = wx.StaticText(parent=self, id=wx.ID_ANY,
  940. label='N:')
  941. box.Add(nlabel, flag=wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT| wx.LEFT, border=5)
  942. self.ncoord = wx.TextCtrl(parent=self, id=wx.ID_ANY,
  943. value=data[3], size=(150, -1))
  944. box.Add(self.ncoord, flag=wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT| wx.LEFT | wx.RIGHT, border=5)
  945. sizer.Add(box, flag=wx.ALL, border=3)
  946. # buttons
  947. btnSizer = wx.StdDialogButtonSizer()
  948. btnSizer.AddButton(self.btnCancel)
  949. btnSizer.AddButton(self.btnSubmit)
  950. btnSizer.Realize()
  951. sizer.Add(item=btnSizer, proportion=0,
  952. flag=wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border=5)
  953. self.SetSizer(sizer)
  954. sizer.Fit(self)
  955. self.Layout()
  956. def GetValues(self, columns=None):
  957. """Return list of values (as strings).
  958. """
  959. valuelist = []
  960. valuelist.append(self.xcoord.GetValue())
  961. valuelist.append(self.ycoord.GetValue())
  962. valuelist.append(self.ecoord.GetValue())
  963. valuelist.append(self.ncoord.GetValue())
  964. return valuelist