123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170 |
- """
- MODULE: georect.py
- CLASSES:
- * Georectify
- * GCP
- * GRMap
- PURPOSE: Georectification module for GRASS GIS. Includes ground control
- point management and interactive point and click GCP creation
- AUTHORS: The GRASS Development Team
- Michael Barton
- COPYRIGHT: (C) 2006-2007 by the GRASS Development Team
- This program is free software under the GNU General Public
- License (>=v2). Read the file COPYING that comes with GRASS
- for details.
- """
- # recheck once completed to see how many of these are still needed
- import os
- import sys
- import time
- import glob
- import math
- import tempfile
- import shutil
- import wx
- import wx.aui
- import wx.lib.filebrowsebutton as filebrowse
- from wx.lib.mixins.listctrl import CheckListCtrlMixin, ListCtrlAutoWidthMixin, TextEditMixin
- import wx.wizard as wiz
- import wx.grid as gridlib
- from threading import Thread
- import globalvar
- import mapdisp
- import render
- import toolbars
- import menuform
- import gselect
- import disp_print
- import gcmd
- import utils
- import menuform
- from debug import Debug as Debug
- from icon import Icons as Icons
- try:
- import subprocess # Not needed if GRASS commands could actually be quiet
- except:
- CompatPath = globalvar.ETCWXDIR
- sys.path.append(CompatPath)
- from compat import subprocess
- gmpath = os.path.join(globalvar.ETCWXDIR, "icons")
- sys.path.append(gmpath)
- import images
- imagepath = images.__path__[0]
- sys.path.append(imagepath)
- # global variables
- global xy_map
- global maptype
- xy_map = ''
- maptype = 'cell'
- class TitledPage(wiz.WizardPageSimple):
- """
- Class to make wizard pages. Generic methods to make
- labels, text entries, and buttons.
- """
- def __init__(self, parent, title):
- wiz.WizardPageSimple.__init__(self, parent)
- self.title = wx.StaticText(self,-1,title)
- self.title.SetFont(wx.Font(13, wx.SWISS, wx.NORMAL, wx.BOLD))
- self.sizer = wx.BoxSizer(wx.VERTICAL)
- tmpsizer = wx.BoxSizer(wx.VERTICAL)
- tmpsizer.Add(self.title, 0, wx.ALIGN_CENTRE|wx.ALL, 5)
- tmpsizer.AddSpacer(10)
- tmpsizer.Add(wx.StaticLine(self, -1), 0, wx.EXPAND|wx.ALL, 0)
- tmpsizer.Add(self.sizer, wx.EXPAND)
- self.SetSizer(tmpsizer)
- self.SetAutoLayout(True)
- tmpsizer.Fit(self)
- class GeorectWizard(object):
- """
- Start wizard here and finish wizard here
- """
- def __init__(self, parent):
- #
- # define wizard image
- #
- # file = "loc_wizard.png"
- #file = "loc_wizard_qgis.png"
- #imagePath = os.path.join(globalvar.ETCWXDIR, "images",
- # file)
- #wizbmp = wx.Image(imagePath, wx.BITMAP_TYPE_PNG)
- ## wizbmp.Rescale(250,600)
- #wizbmp = wizbmp.ConvertToBitmap()
- self.parent = parent
- #set environmental variables
- cmdlist = ['g.gisenv', 'get=GISDBASE']
- #global grassdatabase
- p = gcmd.Command(cmdlist)
- self.grassdatabase = p.ReadStdOutput()[0]
-
- # read original environment settings
- #self.orig_env = os.environ.copy()
- self.orig_gisrc = os.environ['GISRC']
- f = open(self.orig_gisrc)
- self.gisrc_dict = {}
- try:
- for line in f:
- if line != '':
- line = line.strip(' \n')
- self.gisrc_dict[line.split(':')[0]] = line.split(':')[1].strip()
- finally:
- f.close()
-
- self.currentlocation = self.gisrc_dict['LOCATION_NAME']
- self.currentmapset = self.gisrc_dict['MAPSET']
- self.newlocation = '' #location for xy map to georectify
- self.newmapset = '' #mapset for xy map to georectify
-
- self.new_gisrc = '' #GISRC file for source location/mapset of map(s) to georectify
-
- # define wizard pages
- self.wizard = wiz.Wizard(parent, -1, "Setup for georectification")
- self.startpage = LocationPage(self.wizard, self)
- self.grouppage = GroupPage(self.wizard, self)
- self.mappage = DispMapPage(self.wizard, self)
- # Set the initial order of the pages
- self.startpage.SetNext(self.grouppage)
- self.grouppage.SetPrev(self.startpage)
- self.grouppage.SetNext(self.mappage)
- self.mappage.SetPrev(self.grouppage)
- self.wizard.FitToPage(self.startpage)
- #self.Bind(wx.EVT_CLOSE, self.Cleanup)
- self.parent.Bind(wx.EVT_ACTIVATE, self.OnGLMFocus)
- success = False
- if self.wizard.RunWizard(self.startpage):
- success = self.onWizFinished()
- if success == True:
- pass
- else:
- wx.MessageBox("Georectifying setup canceled.")
- self.Cleanup()
- else:
- wx.MessageBox("Georectifying setup canceled.")
- self.Cleanup()
- # start display showing xymap
- if success != False:
- self.Map = render.Map() # instance of render.Map to be associated with display
-
- global maptype
- global xy_map
-
- if maptype == 'cell':
- rendertype = 'raster'
- cmdlist = ['d.rast', 'map=%s' % xy_map]
- elif maptype == 'vector':
- rendertype = 'vector'
- cmdlist = ['d.vect', 'map=%s' % xy_map]
-
- self.Map.AddLayer(type=rendertype, command=cmdlist,l_active=True,
- l_hidden=False, l_opacity=1, l_render=False)
-
- self.xy_mapdisp = mapdisp.MapFrame(self.parent, title="Set ground control points (GCPs)",
- pos=wx.DefaultPosition, size=(640,480),
- style=wx.DEFAULT_FRAME_STYLE, toolbars=["georect"],
- Map=self.Map, gismgr=self.parent, georect=True)
-
- self.mapwin = self.xy_mapdisp.MapWindow
-
- # set mouse characteristics
- self.mapwin.mouse['box'] = 'point'
- self.mapwin.mouse["use"] == "pointer"
- self.mapwin.zoomtype = 0
- self.mapwin.pen = wx.Pen(colour='black', width=2, style=wx.SOLID)
- self.mapwin.SetCursor(self.xy_mapdisp.cursors["cross"])
-
- # draw selected xy map
- self.xy_mapdisp.MapWindow.UpdateMap()
- #show new display
- self.xy_mapdisp.Show()
- self.xy_mapdisp.Refresh()
- self.xy_mapdisp.Update()
-
- # start GCP form
- self.gcpmgr = GCP(self.parent, grwiz=self)
- self.gcpmgr.Show()
- self.gcpmgr.Refresh()
- self.gcpmgr.Update()
- else:
- self.Cleanup()
-
- def SetSrcEnv(self, location, mapset):
- """Create environment to use for location and mapset
- that are the source of the file(s) to georectify"""
-
- self.newlocation = location
- self.newmapset = mapset
-
- # check to see if we are georectifying map in current working location/mapset
- if self.newlocation == self.currentlocation and self.newmapset == self.currentmapset:
- return
-
- self.gisrc_dict['LOCATION_NAME'] = location
- self.gisrc_dict['MAPSET'] = mapset
- self.new_gisrc = utils.GetTempfile()
- f = open(self.new_gisrc, mode='w')
- for line in self.gisrc_dict.items():
- f.write(line[0]+": "+line[1]+"\n")
- f.close()
- def SwitchEnv(self, grc):
- """
- Switches between original working location/mapset and
- location/mapset that is source of file(s) to georectify
- """
- # check to see if we are georectifying map in current working location/mapset
- if self.newlocation == self.currentlocation and self.newmapset == self.currentmapset:
- return
- if grc == 'original':
- os.environ["GISRC"] = str(self.orig_gisrc)
- elif grc == 'new':
- os.environ["GISRC"] = str(self.new_gisrc)
-
- def onWizFinished(self):
- return True
- self.Cleanup()
-
- def OnGLMFocus(self, event):
- #self.SwitchEnv('original')
- pass
- def Cleanup(self):
- # return to current location and mapset
- self.SwitchEnv('original')
- self.parent.georectifying = False
- try:
- self.xy_mapdisp.Destroy()
- self.wizard.Destroy()
- except:
- pass
- class LocationPage(TitledPage):
- """
- Set map type (raster or vector) to georectify and
- select location/mapset of map(s) to georectify.
- """
- def __init__(self, wizard, parent):
- TitledPage.__init__(self, wizard, "Select map type and location/mapset")
- self.parent = parent
- self.grassdatabase = self.parent.grassdatabase
-
- self.xylocation = ''
- self.xymapset = ''
- tmplist = os.listdir(self.grassdatabase)
- self.locList = []
- # Create a list of valid locations
- for item in tmplist:
- if os.path.isdir(os.path.join(self.grassdatabase,item)) and \
- os.path.exists(os.path.join(self.grassdatabase,item,'PERMANENT')):
- self.locList.append(item)
- self.mapsetList = []
- box = wx.BoxSizer(wx.HORIZONTAL)
- self.rb_maptype = wx.RadioBox(self, -1, "Map type to georectify",
- wx.DefaultPosition, wx.DefaultSize,
- ['raster','vector'], 2, wx.RA_SPECIFY_COLS)
- box.Add(self.rb_maptype, 0, wx.ALIGN_CENTER|wx.ALL, 5)
- self.sizer.Add(box, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
- box = wx.BoxSizer(wx.HORIZONTAL)
- label = wx.StaticText(self, -1, 'select location:',
- style=wx.ALIGN_RIGHT)
- box.Add(label, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
- self.cb_location = wx.ComboBox(self, wx.ID_ANY, "",
- wx.DefaultPosition,
- wx.DefaultSize,
- choices = self.locList,
- style=wx.CB_DROPDOWN|wx.CB_READONLY)
- box.Add(self.cb_location, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
- self.sizer.Add(box, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
- box = wx.BoxSizer(wx.HORIZONTAL)
- label = wx.StaticText(self, -1, 'select mapset:',
- style=wx.ALIGN_RIGHT)
- box.Add(label, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
- self.cb_mapset = wx.ComboBox(self, wx.ID_ANY, "",
- wx.DefaultPosition,
- wx.DefaultSize,
- choices = self.mapsetList,
- style=wx.CB_DROPDOWN|wx.CB_READONLY)
- box.Add(self.cb_mapset, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
- self.sizer.Add(box, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
- self.Bind(wx.EVT_RADIOBOX, self.OnMaptype, self.rb_maptype)
- self.Bind(wx.EVT_COMBOBOX, self.OnLocation, self.cb_location)
- self.Bind(wx.EVT_COMBOBOX, self.OnMapset, self.cb_mapset)
- self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.onPageChanging)
- self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
- self.Bind(wx.EVT_CLOSE, self.parent.Cleanup)
- def OnMaptype(self,event):
- global maptype
- if event.GetInt() == 0:
- maptype = 'cell'
- elif event.GetInt() == 1:
- maptype = 'vector'
- def OnLocation(self, event):
- """Sets source location for map(s) to georectify"""
- self.xylocation = event.GetString()
-
- #create a list of valid mapsets
- tmplist = os.listdir(os.path.join(self.grassdatabase,self.xylocation))
- self.mapsetList = []
- for item in tmplist:
- if os.path.isdir(os.path.join(self.grassdatabase,self.xylocation,item)) and \
- os.path.exists(os.path.join(self.grassdatabase,self.xylocation,item,'WIND')):
- self.mapsetList.append(item)
- self.cb_mapset.SetItems(self.mapsetList)
- def OnMapset(self, event):
- """Sets source mapset for map(s) to georectify"""
- if self.xylocation == '':
- wx.MessageBox('You must select a valid location before selecting a mapset')
- return
- self.xymapset = event.GetString()
- def onPageChanging(self,event=None):
- if event.GetDirection() and (self.xylocation == '' or self.xymapset == ''):
- wx.MessageBox('You must select a valid location and mapset in order to continue')
- event.Veto()
- return
- else:
- self.parent.SetSrcEnv(self.xylocation, self.xymapset)
- def OnPageChanged(self,event=None):
- pass
- class GroupPage(TitledPage):
- """
- Set group to georectify. Create group if desired.
- """
- def __init__(self, wizard, parent):
- TitledPage.__init__(self, wizard, "Select image/map group to georectify")
- self.parent = parent
- self.groupList = []
- self.grassdatabase = self.parent.grassdatabase
- self.xylocation = ''
- self.xymapset = ''
- self.xygroup = ''
-
- self.extension = 'georect'+str(os.getpid())
-
- box = wx.BoxSizer(wx.HORIZONTAL)
- label = wx.StaticText(self, -1, 'select group:',
- style=wx.ALIGN_RIGHT)
- box.Add(label, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
- self.cb_group = wx.ComboBox(self, wx.ID_ANY, "",
- wx.DefaultPosition,
- wx.DefaultSize,
- choices = self.groupList,
- style=wx.CB_DROPDOWN|wx.CB_READONLY)
- box.Add(self.cb_group, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
- self.sizer.Add(box, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
- box = wx.BoxSizer(wx.HORIZONTAL)
- label = wx.StaticText(self, -1, 'Create group if none exists', style=wx.ALIGN_LEFT)
- box.Add(label, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
- self.btn_mkgroup = wx.Button(self, wx.ID_ANY, "Create/edit group ...")
- box.Add(self.btn_mkgroup, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
- self.sizer.Add(box, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
- box = wx.BoxSizer(wx.HORIZONTAL)
- label = wx.StaticText(self, -1, 'Extension for output maps:', style=wx.ALIGN_LEFT)
- box.Add(label, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
- self.ext_txt = wx.wx.TextCtrl(self, -1, "", size=(150,-1))
- self.ext_txt.SetValue(self.extension)
- box.Add(self.ext_txt, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
- self.sizer.Add(box, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
- self.Bind(wx.EVT_COMBOBOX, self.OnGroup, self.cb_group)
- self.Bind(wx.EVT_BUTTON, self.OnMkGroup, self.btn_mkgroup)
- self.Bind(wx.EVT_TEXT, self.OnExtension, self.ext_txt)
- self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.onPageChanging)
- self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
- self.Bind(wx.EVT_CLOSE, self.parent.Cleanup)
- def OnGroup(self, event):
- self.xygroup = event.GetString()
-
- def OnMkGroup(self, event):
- global maptype
-
- self.parent.SwitchEnv('new')
- if maptype == 'cell':
- cmdlist = ['i.group']
- menuform.GUI().ParseCommand(cmdlist, parentframe=self.parent.parent)
- elif maptype == 'vector':
- dlg = VectGroup(self, wx.ID_ANY, self.grassdatabase, self.xylocation, self.xymapset, self.xygroup)
- if dlg.ShowModal() == wx.ID_OK:
- dlg.MakeVGroup()
-
- #refresh combobox list
- try:
- tmplist = os.listdir(os.path.join(self.grassdatabase,self.xylocation,self.xymapset,'group'))
- except:
- return
- if tmplist != []:
- for item in tmplist:
- if os.path.isdir(os.path.join(self.grassdatabase,self.xylocation,self.xymapset,'group',item)):
- self.groupList.append(item)
- self.cb_group.SetItems(self.groupList)
-
- def OnExtension(self, event):
- self.extension = event.GetString()
- def onPageChanging(self,event=None):
- if event.GetDirection() and self.xygroup == '':
- wx.MessageBox('You must select a valid image/map group in order to continue')
- event.Veto()
- return
- if event.GetDirection() and self.extension == '':
- wx.MessageBox('You must enter an map name extension in order to continue')
- event.Veto()
- return
- def OnPageChanged(self,event=None):
- self.groupList = []
- tmplist = []
- self.xylocation = self.parent.gisrc_dict['LOCATION_NAME']
- self.xymapset = self.parent.gisrc_dict['MAPSET']
- # create a list of groups in selected mapset
- tmplist = os.listdir(os.path.join(self.grassdatabase,self.xylocation,self.xymapset,'group'))
- if event.GetDirection() and self.xygroup == '':
- if tmplist == []:
- wx.MessageBox('No map/imagery groups exist to georectify. You will need to create one')
- else:
- for item in tmplist:
- if os.path.isdir(os.path.join(self.grassdatabase,self.xylocation,self.xymapset,'group',item)):
- self.groupList.append(item)
-
- self.cb_group.SetItems(self.groupList)
-
- class DispMapPage(TitledPage):
- """
- Select ungeoreferenced map to display for interactively
- setting ground control points (GCPs).
- """
- def __init__(self, wizard, parent):
- TitledPage.__init__(self, wizard, "Select image/map to display for ground control point (GCP) creation")
- self.parent = parent
- global maptype
- self.parent = parent
- box = wx.BoxSizer(wx.HORIZONTAL)
- label = wx.StaticText(self, -1, 'Select display image/map:', style=wx.ALIGN_LEFT)
- box.Add(label, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
- self.selection = gselect.Select(self, id=wx.ID_ANY, size=(300,-1),
- type=maptype )
- box.Add(self.selection, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
- self.sizer.Add(box, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
- self.selection.Bind(wx.EVT_TEXT, self.OnSelection)
- self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.onPageChanging)
- self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
- self.Bind(wx.EVT_CLOSE, self.parent.Cleanup)
- def OnSelection(self,event):
- global xy_map
- xy_map = event.GetString()
- def onPageChanging(self,event=None):
- global xy_map
- if event.GetDirection() and xy_map == '':
- wx.MessageBox('You must select a valid image/map in order to continue')
- event.Veto()
- return
- def OnPageChanged(self,event=None):
- global maptype
- if event.GetDirection():
- # switch to xy location if coming into the page from preceding
- self.parent.SwitchEnv('new')
- self.selection.SetElementList(maptype)
- else:
- # switch back to current location if leaving the page
- self.parent.SwitchEnv('original')
- class GCP(wx.Frame):
- """
- Manages ground control points for georectifying. Calculates RMS statics.
- Calls i.rectify or v.transform to georectify map.
- """
- def __init__(self,parent,id=-1,title="Create & manage ground control points",
- size=wx.DefaultSize, grwiz=None):
- wx.Frame.__init__(self, parent, id , title, size=(600,300))
- self.Centre(wx.HORIZONTAL)
- toolbar = self.__createToolBar()
-
- self.parent = parent
- self.grwiz = grwiz
- self.grassdatabase = self.grwiz.grassdatabase
- self.currentlocation = self.grwiz.currentlocation
- self.currentmapset = self.grwiz.currentmapset
- self.newlocation = self.grwiz.newlocation
- self.newmapset = self.grwiz.newmapset
- self.xylocation = self.grwiz.gisrc_dict['LOCATION_NAME']
- self.xymapset = self.grwiz.gisrc_dict['MAPSET']
- self.xygroup = self.grwiz.grouppage.xygroup
- self.extension = self.grwiz.grouppage.extension
- self.pointsfile = os.path.join(self.grassdatabase,self.xylocation,self.xymapset,'group',self.xygroup,'POINTS')
- self.rgrpfile = os.path.join(self.grassdatabase,self.xylocation,self.xymapset,'group',self.xygroup,'REF')
- self.vgrpfile = os.path.join(self.grassdatabase,self.xylocation,self.xymapset,'group',self.xygroup,'VREF')
- self.targetfile = os.path.join(self.grassdatabase,self.xylocation,self.xymapset,'group',self.xygroup,'TARGET')
-
- self.SetTarget(self.xygroup, self.currentlocation, self.currentmapset)
- self.gr_order = 1 #polynomial order transformation for georectification
- self.selected = 0 #gcp list item selected
- self.GCPcount = 0 #number of GCPs selected to be used for georectification (checked)
- self.fwd_rmserror = 0.0 # forward RMS error
- self.bkw_rmserror = 0.0 # backward RMS error
- self.mapcoordlist = [(0000000.00,0000000.00,'')] #list map coords and ID of map display they came from
-
- self.CreateStatusBar(3,1,-1,'gcpstatusbar')
- self.SetStatusText('RMS error for selected points',0)
-
- # can put guage into custom statusbar for progress if can figure out how to get progress text from i.rectify
- #self.gr_gauge = wx.Gauge(self, -1, 100, (-1,-1), (100, 25))
- #self.gr_guage.Pulse()
- p = wx.Panel(self, -1, style=0)
- self.sizer = wx.BoxSizer(wx.VERTICAL)
- box = wx.BoxSizer(wx.HORIZONTAL)
- self.rb_grmethod = wx.RadioBox(p, -1, "Select rectification method for rasters ",
- wx.DefaultPosition, wx.DefaultSize,
- ['1st order','2nd order', '3rd order'], 3, wx.RA_SPECIFY_COLS)
- box.Add(self.rb_grmethod, 0, wx.ALIGN_CENTER|wx.ALL, 5)
- self.sizer.Add(box, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
- # initialize list control for GCP management
- self.list = CheckListCtrl(p, -1, style=wx.LC_REPORT | wx.SUNKEN_BORDER | wx.LC_HRULES)
- self.list.InsertColumn(0, 'use| X coord', width=120)
- self.list.InsertColumn(1, 'Y coord')
- self.list.InsertColumn(2, 'N coord')
- self.list.InsertColumn(3, 'E coord')
- self.list.InsertColumn(4, 'Forward error')
- self.list.InsertColumn(5, 'Backward error')
-
- if os.path.isfile(self.pointsfile):
- self.ReadGCPs()
- self.ResizeColumns()
- elif self.list.GetItemCount() == 0:
- # initialize 3 blank lines in the GCP list (minimum for georectification)
- i = ('0000000.00','0000000.00','0000000.00','0000000.00','','')
- index = self.list.InsertStringItem(sys.maxint, i[0])
- self.list.SetStringItem(index, 1, i[1])
- self.list.SetStringItem(index, 2, i[2])
- self.list.SetStringItem(index, 3, i[3])
- self.list.SetStringItem(index, 4, i[4])
- self.list.SetStringItem(index, 5, i[5])
- self.list.CheckItem(0, True)
- self.AddGCP(None)
- self.AddGCP(None)
- self.ResizeColumns()
- self.sizer.Add(self.list, 1, wx.EXPAND|wx.ALL, 5)
- p.SetSizer(self.sizer)
- self.Bind(wx.EVT_RADIOBOX, self.OnGRMethod, self.rb_grmethod)
- self.list.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected)
- self.list.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.OnItemActivated)
- self.Bind(wx.EVT_ACTIVATE, self.OnFocus)
- self.Bind(wx.EVT_CLOSE, self.grwiz.Cleanup)
- def __createToolBar(self):
- """Creates toolbar"""
- toolbar = self.CreateToolBar()
- for each in self.toolbarData():
- self.addToolbarButton(toolbar, *each)
- toolbar.Realize()
-
- def OnFocus(self, event):
- self.grwiz.SwitchEnv('new')
-
- def ResizeColumns(self):
- for i in range(6):
- self.list.SetColumnWidth(i, wx.LIST_AUTOSIZE)
-
- def SetTarget(self, tgroup, tlocation, tmapset):
- """
- Sets rectification target to current location and mapset
- """
- # check to see if we are georectifying map in current working location/mapset
- if self.newlocation == self.currentlocation and self.newmapset == self.currentmapset:
- cmdlist = ['i.target', 'c', 'group=%s' % tgroup]
- else:
- self.grwiz.SwitchEnv('new')
- cmdlist = ['i.target', 'group=%s' % tgroup, 'location=%s' % tlocation, 'mapset=%s' % tmapset]
- gcmd.Command(cmd=cmdlist)
- def addToolbarButton(self, toolbar, label, icon, help, handler):
- """Adds button to the given toolbar"""
- if not label:
- toolbar.AddSeparator()
- return
- tool = toolbar.AddLabelTool(id=wx.ID_ANY, label=label, bitmap=icon, shortHelp=help)
- self.Bind(wx.EVT_TOOL, handler, tool)
- def toolbarData(self):
- return (
- ('savegcp', Icons["savefile"].GetBitmap(), 'Save GCPs to POINTS file', self.SaveGCPs),
- ('addgcp', wx.ArtProvider.GetBitmap(wx.ART_NEW, wx.ART_TOOLBAR, (16,16)), 'Add new GCP', self.AddGCP),
- ('deletegcp', wx.ArtProvider.GetBitmap(wx.ART_DELETE, wx.ART_TOOLBAR, (16,16)), 'Delete selected GCP', self.DeleteGCP),
- ('cleargcp', Icons["cleargcp"].GetBitmap(), Icons["cleargcp"].GetLabel(), self.ClearGCP),
- ('refreshgcp', Icons["refreshgcp"].GetBitmap(), Icons["refreshgcp"].GetLabel(), self.RefreshGCPMarks),
- ('rms', Icons["rms"].GetBitmap(), Icons["rms"].GetLabel(), self.OnRMS),
- ('georect', Icons["georect"].GetBitmap(), Icons["georect"].GetLabel(), self.OnGeorect),
- ('quit', wx.ArtProvider.GetBitmap(wx.ART_QUIT, wx.ART_TOOLBAR, (16,16)), 'Quit georectification module', self.OnQuit)
- )
- def SaveGCPs(self, event):
- """
- Make a POINTS file or save GCP coordinates to existing POINTS file
- """
-
- self.GCPcount = 0
- f = open(self.pointsfile, mode='w')
- try:
- f.write('# Ground Control Points File\n')
- f.write("# \n")
- f.write("# target location: "+self.currentlocation+'\n')
- f.write("# target mapset: "+self.currentmapset+'\n')
- f.write("#unrectified xy georectified east north 1=use gcp point\n")
- f.write("#-------------- ----------------------- ---------------\n")
- for index in range(self.list.GetItemCount()):
- if self.list.IsChecked(index) == True:
- check = "1"
- self.GCPcount += 1
- else:
- check = "0"
- coord0 = self.list.GetItem(index, 0).GetText()
- coord1 = self.list.GetItem(index, 1).GetText()
- coord2 = self.list.GetItem(index, 2).GetText()
- coord3 = self.list.GetItem(index, 3).GetText()
- f.write(coord0+' '+coord1+' '+coord2+' '+coord3+' '+check+'\n')
- finally:
- f.close()
- pass
- def DeleteGCP(self, event):
- """
- Deletes selected item in GCP list
- """
-
- self.list.DeleteItem(self.selected)
- del self.mapcoordlist[self.selected]
- def AddGCP(self, event):
- """
- Appends an item to GCP list
- """
-
- self.list.Append(['0000000.00','0000000.00','0000000.00','0000000.00','',''])
- index = self.list.GetItemCount() - 1
- self.mapcoordlist.append((0000000.00,0000000.00,''))
- self.list.SetItemState(index, wx.LIST_STATE_SELECTED, wx.LIST_STATE_SELECTED)
- self.ResizeColumns()
- return index
-
- def SetGCPData(self, coordtype, coord, mapdisp=None, check=True):
- """
- Inserts coordinates from mouse click on map
- into selected item of GCP list and checks it for use
- """
-
- index = self.selected
- coord0 = str(coord[0])
- coord1 = str(coord[1])
- if coordtype == 'gcpcoord':
- self.list.SetStringItem(index, 0, coord0)
- self.list.SetStringItem(index, 1, coord1)
- if coordtype == 'mapcoord':
- self.list.SetStringItem(index, 2, coord0)
- self.list.SetStringItem(index, 3, coord1)
- self.mapcoordlist[index] = (coord[0], coord[1], mapdisp)
- self.list.CheckItem(index, check)
- self.ResizeColumns()
- def ClearGCP(self, event):
- """
- Clears all values in selected item of GCP list and unchecks it
- """
-
- index = self.selected
- for i in range(4):
- self.list.SetStringItem(index, i, '0000000.00')
- self.list.SetStringItem(index, 4, '')
- self.list.SetStringItem(index, 5, '')
- self.mapcoordlist[index] = (0000000.00,0000000.00,'')
- self.list.CheckItem(index, False)
-
- def ReadGCPs(self):
- """
- Reads GCPs and georectified coordinates from POINTS file
- """
-
- self.GCPcount = 0
- f = open(self.pointsfile)
- try:
- GCPcnt = 0
- for line in f:
- if line[0] != '#' and line !='':
- line = line.strip(' \n')
- coords = line.split()
- if coords[4] == '1':
- check = True
- self.GCPcount +=1
- else:
- check = False
- index = self.AddGCP(event=None)
- for i in range(4):
- self.list.SetStringItem(index, i, coords[i])
- self.list.CheckItem(index, check)
- finally:
- f.close()
- self.RefreshGCPMarks(None)
- if self.CheckGCPcount():
- self.RMSError(self.xygroup, self.gr_order)
-
- def OnRMS(self, event):
- """
- RMS button handler
- """
- self.RMSError(self.xygroup,self.gr_order)
-
- def CheckGCPcount(self, msg=False):
- """
- Checks to make sure that the minimum number of GCPs have been defined and
- are active for the selected transformation order
- """
- if (self.GCPcount < 3 and self.gr_order == 1) or \
- (self.GCPcount < 6 and self.gr_order == 2) or \
- (self.GCPcount < 10 and self.gr_order == 3):
- if msg:
- s1 = 'Insufficient points defined and active (checked)\n'
- s2 = 'for selected rectification method.\n'
- s3 = '3+ points needed for 1st order,\n'
- s4 = '6+ points for 2nd order, and\n'
- s5 = '10+ points for 3rd order.'
- wx.MessageBox('%s%s%s%s%s' % (s1, s2, s3, s4, s5))
- return False
- else:
- return True
- def OnGeorect(self, event):
- """
- Georectifies map(s) in group using i.rectify or v.transform
- """
- global maptype
- self.SaveGCPs()
-
- if self.CheckGCPcount(msg=True) == False:
- return
-
- if maptype == 'cell':
- cmdlist = ['i.rectify', '-ca', 'group=%s' % self.xygroup, 'extension=%s' % self.extension, 'order=%s' % self.gr_order]
- p = gcmd.Command(cmd=cmdlist)
- stdout = p.ReadStdOutput()
- stderr = p.ReadErrOutput()
- msg = err = ''
- if p.returncode == 0:
- for line in stdout:
- msg = msg+line+'\n'
- for line in stderr:
- err = err+line+'\n'
- wx.MessageBox('All maps georectified successfully\n'+msg+'\n'+err)
- else:
- for line in stderr:
- err = err+line+'\n'
- wx.MessageBox(err)
- elif maptype == 'vector':
- # loop through all vectors in VREF and move resulting vector to target location
- f = open(self.vgrpfile)
- vectlist = []
- try:
- for vect in f:
- vect = vect.strip(' \n')
- vectlist.append(vect)
- finally:
- f.close()
- for vect in vectlist:
- outname = vect+'_'+self.extension
- cmdlist = ['v.transform', '--q', 'input=%s' % vect, 'output=%s' % outname, 'pointsfile=%s' % self.pointsfile]
-
- p = gcmd.Command(cmd=cmdlist)
- stdout = p.ReadStdOutput()
- msg = '****'+outname+'****\n'
- for line in stdout:
- msg = msg+line+'\n'
- wx.MessageBox(msg)
-
- if p.returncode == 0:
- wx.MessageBox("All maps were georectified successfully")
- for vect in vectlist:
- outname = vect+'_'+self.extension
- xyvpath = os.path.join(self.grassdatabase,self.xylocation,self.xymapset,'vector',outname)
- vpath = os.path.join(self.grassdatabase,self.currentlocation,self.currentmapset,'vector',outname)
- if os.path.isfile(vpath):
- wx.MessageBox("%s already exists. Change extension name and georectify again" % outname)
- else:
- shutil.move(xyvpath, vpath)
-
- wx.MessageBox('For vector files with attribute tables, you will need to manually copy the tables to the new location')
- else:
- wx.MessageBox('Some maps were not georectified successfully')
- else:
- return
- def OnQuit(self, event):
- self.Destroy()
- self.grwiz.Cleanup()
- def OnItemSelected(self, event):
- self.selected = event.GetIndex()
-
- def OnItemActivated(self, event):
- """
- When item double clicked, open editor to update coordinate values
- """
- coords = []
- index = event.m_itemIndex
- for i in range(4):
- coords.append(self.list.GetItem(index, i).GetText())
-
- dlg = EditGPC(self, -1, data=coords)
- if dlg.ShowModal() == wx.ID_OK:
- values = dlg.GetValues() # string
-
- for i in range(4):
- if values[i] != coords[i]:
- self.list.SetStringItem(index, i, values[i])
-
- def RefreshGCPMarks(self, event):
- """
- Updates GCP and map coord maps and redraws
- active (checked) GCP markers
- """
- self.grwiz.SwitchEnv("new")
- self.grwiz.mapwin.UpdateMap()
- self.grwiz.SwitchEnv("original")
- mapid = ''
- for map in self.mapcoordlist:
- if map[2] != mapid and map[2] != '':
- map[2].UpdateMap()
- mapid = map[2]
- for index in range(self.list.GetItemCount()):
- if self.list.IsChecked(index) and (
- (self.list.GetItem(index, 0).GetText() != '0000000.00' and
- self.list.GetItem(index, 1).GetText() != '0000000.00') or
- (self.list.GetItem(index, 2).GetText() != '0000000.00' and
- self.list.GetItem(index, 3).GetText() != '0000000.00')
- ):
- coord0 = float(self.list.GetItem(index, 0).GetText())
- coord1 = float(self.list.GetItem(index, 1).GetText())
- coord2 = float(self.list.GetItem(index, 2).GetText())
- coord3 = float(self.list.GetItem(index, 3).GetText())
-
- self.grwiz.SwitchEnv("new")
- pxcoord1 = self.grwiz.mapwin.Cell2Pixel((coord0, coord1))
- self.grwiz.mapwin.DrawCross(pdc=self.grwiz.mapwin.pdcTmp,
- coords=pxcoord1, size=5)
- if self.mapcoordlist != [] and self.mapcoordlist[index][2] != '':
- self.grwiz.SwitchEnv("original")
- pxcoord2 = self.mapcoordlist[index][2].Cell2Pixel((coord2, coord3))
- self.mapcoordlist[index][2].DrawCross(pdc=self.mapcoordlist[index][2].pdcTmp,
- coords=pxcoord2, size=5)
-
- def OnGRMethod(self, event):
- """
- sets transformation order for georectifying
- """
- self.gr_order = event.GetInt() + 1
-
- def RMSError(self, xygroup, order):
- """
- Uses g.transform to calculate forward and backward error for each used GCP
- in POINTS file and insert error values into GCP list.
- Calculates total forward and backward RMS error for all used points
- """
-
- # save GCPs to points file to make sure that all checked GCPs are used
- self.SaveGCPs(None)
-
- if self.CheckGCPcount(msg=True) == False:
- return
-
- #get list of forward and reverse rms error values for each point
- self.grwiz.SwitchEnv('new')
- cmdlist = ['g.transform', 'group=%s' % xygroup, 'order=%s' % order]
- p = gcmd.Command(cmdlist)
- errlist = p.ReadStdOutput()
- if errlist == []:
- return
-
- #insert error values into GCP list for checked items
- i = 0
- sumsq_fwd_err = 0.0
- sumsq_bkw_err = 0.0
- for index in range(self.list.GetItemCount()):
- if self.list.IsChecked(index):
- fwd_err,bkw_err = errlist[i].split()
- self.list.SetStringItem(index, 4, fwd_err)
- self.list.SetStringItem(index, 5, bkw_err)
- sumsq_fwd_err += float(fwd_err)**2
- sumsq_bkw_err += float(bkw_err)**2
- i += 1
- else:
- self.list.SetStringItem(index, 4, '')
- self.list.SetStringItem(index, 5, '')
-
- #calculate RMS error
- self.fwd_rmserror = round((sumsq_fwd_err/i)**0.5,4)
- self.bkw_rmserror = round((sumsq_bkw_err/i)**0.5,4)
- self.ResizeColumns()
- self.SetStatusText('forward: %s' % self.fwd_rmserror,1)
- self.SetStatusText('backward: %s' % self.bkw_rmserror,2)
- class CheckListCtrl(wx.ListCtrl, CheckListCtrlMixin, ListCtrlAutoWidthMixin):
- def __init__(self, parent, ID=-1, pos=wx.DefaultPosition, size=wx.DefaultSize,
- style=0):
- wx.ListCtrl.__init__(self, parent, -ID, pos, size, style)
- CheckListCtrlMixin.__init__(self)
- ListCtrlAutoWidthMixin.__init__(self)
-
- self.CheckList = [] # tracks whether list items are checked or not
- #self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.OnItemActivated)
- # this is called by the base class when an item is checked/unchecked
- def OnCheckItem(self, index, flag):
- pass
-
- class VectGroup(wx.Dialog):
- """
- Dialog to create a vector group (VREF file) for georectifying
- """
- def __init__(self, parent, id, grassdb, location, mapset, group,
- style=wx.DEFAULT_DIALOG_STYLE):
-
- wx.Dialog.__init__(self, parent, id, style=style)
-
- self.grassdatabase = grassdb
- self.xylocation = location
- self.xymapset = mapset
- self.xygroup = group
-
- # get list of valid vector directories
- vectlist = os.listdir(os.path.join(self.grassdatabase,self.xylocation,self.xymapset,'vector'))
- for dir in vectlist:
- if os.path.isfile(os.path.join(self.grassdatabase,self.xylocation,self.xymapset,'vector',dir,'coor')):
- pass
- else:
- vectlist.remove(dir)
-
- self.vgrouplist = []
- self.vgrpfile = os.path.join(self.grassdatabase,self.xylocation,self.xymapset,'group',self.xygroup,'VREF')
- if os.path.isfile(self.vgrpfile):
- f = open(self.vgrpfile)
- try:
- for line in f:
- if line != '':
- self.vgrouplist.append(line.strip(' \n'))
- finally:
- f.close()
-
- self.btnCancel = wx.Button(self, wx.ID_CANCEL)
- self.btnSubmit = wx.Button(self, wx.ID_OK)
- self.btnSubmit.SetDefault()
- sizer = wx.BoxSizer(wx.VERTICAL)
-
- box = wx.BoxSizer(wx.HORIZONTAL)
- label = wx.StaticText(parent=self, id=wx.ID_ANY,
- label='Select vector map(s) to add to group:')
- box.Add(label, flag=wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT | wx.LEFT, border=5)
- self.addmap = wx.CheckListBox(self, -1, wx.DefaultPosition, wx.DefaultSize, vectlist)
- box.Add(self.addmap, flag=wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT| wx.LEFT, border=5)
- sizer.Add(box, flag=wx.ALIGN_RIGHT | wx.ALL, border=3)
-
- box = wx.BoxSizer(wx.HORIZONTAL)
- label = wx.StaticText(parent=self, id=wx.ID_ANY,
- label='Select vector map(s) to remove from group:')
- box.Add(label, flag=wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT | wx.LEFT, border=5)
- self.remmap = wx.CheckListBox(self, -1, wx.DefaultPosition, wx.DefaultSize, self.vgrouplist)
- box.Add(self.remmap, flag=wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT| wx.LEFT, border=5)
- sizer.Add(box, flag=wx.ALIGN_RIGHT | wx.ALL, border=3)
- # buttons
- btnSizer = wx.StdDialogButtonSizer()
- btnSizer.AddButton(self.btnCancel)
- btnSizer.AddButton(self.btnSubmit)
- btnSizer.Realize()
- sizer.Add(item=btnSizer, proportion=0,
- flag=wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border=5)
- self.SetSizer(sizer)
- sizer.Fit(self)
- self.Layout()
-
- self.Bind(wx.EVT_CHECKLISTBOX, self.AddVect, self.addmap)
- self.Bind(wx.EVT_CHECKLISTBOX, self.RemoveVect, self.remmap)
- def AddVect(self, event):
- index = event.GetSelection()
- label = self.addmap.GetString(index)
- if self.addmap.IsChecked(index):
- self.vgrouplist.append(label)
- self.addmap.SetSelection(index)
- event.Skip()
-
- def RemoveVect(self, event):
- index = event.GetSelection()
- label = self.remmap.GetString(index)
- if self.remmap.IsChecked(index):
- self.vgrouplist.remove(label)
- self.remmap.SetSelection(index)
- event.Skip()
-
- def MakeVGroup(self):
- f = open(self.vgrpfile, mode='w')
- for vect in self.vgrouplist:
- f.write(vect+'\n')
-
- class EditGPC(wx.Dialog):
- """Dialog for editing GPC and map coordinates in list control"""
- def __init__(self, parent, id, data,
- style=wx.DEFAULT_DIALOG_STYLE):
-
- wx.Dialog.__init__(self, parent, id, style=style)
- self.btnCancel = wx.Button(self, wx.ID_CANCEL)
- self.btnSubmit = wx.Button(self, wx.ID_OK)
- self.btnSubmit.SetDefault()
- sizer = wx.BoxSizer(wx.VERTICAL)
-
- box = wx.BoxSizer(wx.HORIZONTAL)
- xlabel = wx.StaticText(parent=self, id=wx.ID_ANY,
- label='X:')
- box.Add(xlabel, flag=wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT | wx.LEFT, border=5)
- self.xcoord = wx.TextCtrl(parent=self, id=wx.ID_ANY,
- value=data[0], size=(150, -1))
- box.Add(self.xcoord, flag=wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT| wx.LEFT, border=5)
- ylabel = wx.StaticText(parent=self, id=wx.ID_ANY,
- label='Y:')
- box.Add(ylabel, flag=wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT| wx.LEFT, border=5)
- self.ycoord = wx.TextCtrl(parent=self, id=wx.ID_ANY,
- value=data[1], size=(150, -1))
- box.Add(self.ycoord, flag=wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT| wx.LEFT | wx.RIGHT, border=5)
- sizer.Add(box, flag=wx.ALL, border=3)
- box = wx.BoxSizer(wx.HORIZONTAL)
- elabel = wx.StaticText(parent=self, id=wx.ID_ANY,
- label='E:')
- box.Add(elabel, flag=wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT| wx.LEFT, border=5)
- self.ecoord = wx.TextCtrl(parent=self, id=wx.ID_ANY,
- value=data[2], size=(150, -1))
- box.Add(self.ecoord, flag=wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT| wx.LEFT, border=5)
- nlabel = wx.StaticText(parent=self, id=wx.ID_ANY,
- label='N:')
- box.Add(nlabel, flag=wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT| wx.LEFT, border=5)
- self.ncoord = wx.TextCtrl(parent=self, id=wx.ID_ANY,
- value=data[3], size=(150, -1))
- box.Add(self.ncoord, flag=wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT| wx.LEFT | wx.RIGHT, border=5)
- sizer.Add(box, flag=wx.ALL, border=3)
- # buttons
- btnSizer = wx.StdDialogButtonSizer()
- btnSizer.AddButton(self.btnCancel)
- btnSizer.AddButton(self.btnSubmit)
- btnSizer.Realize()
- sizer.Add(item=btnSizer, proportion=0,
- flag=wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border=5)
- self.SetSizer(sizer)
- sizer.Fit(self)
- self.Layout()
- def GetValues(self, columns=None):
- """Return list of values (as strings).
- """
- valuelist = []
- valuelist.append(self.xcoord.GetValue())
- valuelist.append(self.ycoord.GetValue())
- valuelist.append(self.ecoord.GetValue())
- valuelist.append(self.ncoord.GetValue())
- return valuelist
|