GRASS Programmer's Manual  6.4.2(2012)
vclean.py
Go to the documentation of this file.
00001 """
00002 @package vclean.py
00003 
00004 @brief Dialog for interactive construction of vector cleaning
00005 operations
00006 
00007 Classes:
00008  - VectorCleaningFrame
00009 
00010 (C) 2010-2011 by the GRASS Development Team
00011 
00012 This program is free software under the GNU General Public License
00013 (>=v2). Read the file COPYING that comes with GRASS for details.
00014 
00015 @author Markus Metz
00016 """
00017 
00018 import os
00019 import sys
00020 import shutil
00021 
00022 import wx
00023 import wx.lib.scrolledpanel as scrolled
00024 
00025 from grass.script import core as grass
00026 
00027 import dbm
00028 import gcmd
00029 import globalvar
00030 import gselect
00031 import render
00032 import utils
00033 from debug import Debug as Debug
00034 from preferences import globalSettings as UserSettings
00035 
00036 class VectorCleaningFrame(wx.Frame):
00037     def __init__(self, parent, id=wx.ID_ANY, title=_('set up vector cleaning tools'),
00038                  pos=wx.DefaultPosition, size=(-1, -1),
00039                  style=wx.DEFAULT_FRAME_STYLE | wx.RESIZE_BORDER,
00040                  **kwargs):
00041         """!
00042         Dialog for interactively defining vector cleaning tools
00043         """
00044         wx.Frame.__init__(self, parent, id, title, pos, size, style)
00045 
00046         self.parent = parent # GMFrame
00047         if self.parent:
00048             self.log = self.parent.GetLogWindow()
00049         else:
00050             self.log = None
00051   
00052         # grass command
00053         self.cmd = 'v.clean'
00054         
00055         # statusbar
00056         self.CreateStatusBar()
00057 
00058         # icon
00059         self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass.ico'), wx.BITMAP_TYPE_ICO))
00060 
00061         # self.panel not set as in colorrules
00062         # self.panel = wx.Panel(parent = self, id = wx.ID_ANY)
00063         
00064         # input map to clean
00065         self.inmap = ''
00066         
00067         # cleaned output map
00068         self.outmap = ''
00069 
00070         self.ftype = ''
00071 
00072         # cleaning tools
00073         self.toolslines = {}
00074 
00075         self.tool_desc_list = [
00076             _('break lines/boundaries'),
00077             _('remove duplicates'),
00078             _('remove dangles'),
00079             _('change boundary dangles to lines'),
00080             _('remove bridges'),
00081             _('change bridges to lines'),
00082             _('snap lines/boundaries'),
00083             _('remove duplicate area centroids'),
00084             _('break polygons'),
00085             _('prune lines/boundaries'),
00086             _('remove small areas'),
00087             _('remove lines/boundaries of zero length'),
00088             _('remove small angles at nodes')
00089             ]
00090 
00091         self.tool_list = [
00092             'break',
00093             'rmdupl',
00094             'rmdangle',
00095             'chdangle',
00096             'rmbridge',
00097             'chbridge',
00098             'snap',
00099             'rmdac',
00100             'bpol',
00101             'prune',
00102             'rmarea',
00103             'rmline',
00104             'rmsa'
00105             ]
00106 
00107         self.ftype = [
00108             'point',
00109             'line',
00110             'boundary',
00111             'centroid',
00112             'area',
00113             'face']
00114 
00115         self.n_ftypes = 6
00116         
00117         self.tools_string = ''
00118         self.thresh_string = ''
00119         self.ftype_string = ''
00120 
00121         self.SetTitle(_('Set up vector cleaning tools'))
00122         self.SetStatusText(_("Set up vector cleaning tools"))
00123         self.elem = 'vector'
00124         self.ctlabel = _('Choose cleaning tools and set thresholds')
00125 
00126         # top controls
00127         self.inmaplabel = wx.StaticText(parent = self, id = wx.ID_ANY,
00128                                          label= _('Select input vector map:'))
00129         self.selectionInput = gselect.Select(parent=self, id=wx.ID_ANY,
00130                                              size=globalvar.DIALOG_GSELECT_SIZE,
00131                                              type='vector')
00132         self.ftype_check = {}
00133         ftypeBox = wx.StaticBox(parent=self, id=wx.ID_ANY,
00134                                 label=_(' Feature type: '))
00135         self.ftypeSizer = wx.StaticBoxSizer(ftypeBox, wx.HORIZONTAL)
00136 
00137         self.outmaplabel = wx.StaticText(parent = self, id = wx.ID_ANY,
00138                                          label= _('Select output vector map:'))
00139         self.selectionOutput = gselect.Select(parent=self, id=wx.ID_ANY,
00140                                              size=globalvar.DIALOG_GSELECT_SIZE,
00141                                              type='vector')
00142         
00143         self.overwrite = wx.CheckBox(parent=self, id=wx.ID_ANY,
00144                                        label=_('Allow output files to overwrite existing files'))
00145         self.overwrite.SetValue(UserSettings.Get(group='cmd', key='overwrite', subkey='enabled'))
00146 
00147         # cleaning tools
00148         self.ct_label = wx.StaticText(parent=self, id=wx.ID_ANY,
00149                                       label=self.ctlabel)
00150 
00151         self.ct_panel = self.__toolsPanel()
00152 
00153         # buttons to manage cleaning tools
00154         self.btn_add = wx.Button(parent=self, id=wx.ID_ADD)
00155         self.btn_remove = wx.Button(parent=self, id=wx.ID_REMOVE)
00156         self.btn_moveup = wx.Button(parent=self, id=wx.ID_UP)
00157         self.btn_movedown = wx.Button(parent=self, id=wx.ID_DOWN)
00158 
00159         # add one tool as default
00160         self.AddTool()
00161         self.selected = -1
00162         
00163         # Buttons
00164         self.btn_close = wx.Button(parent = self, id = wx.ID_CLOSE)
00165         self.btn_run = wx.Button(parent = self, id = wx.ID_ANY, label = _("&Run"))
00166         self.btn_run.SetDefault()
00167         self.btn_clipboard = wx.Button(parent=self, id=wx.ID_COPY)
00168         self.btn_clipboard.SetToolTipString(_("Copy the current command string to the clipboard (Ctrl+C)"))
00169         self.btn_help = wx.Button(parent = self, id = wx.ID_HELP)
00170         
00171         # bindings
00172         self.btn_close.Bind(wx.EVT_BUTTON, self.OnClose)
00173         self.btn_run.Bind(wx.EVT_BUTTON, self.OnCleaningRun)
00174         self.btn_clipboard.Bind(wx.EVT_BUTTON, self.OnCopy)
00175         self.btn_help.Bind(wx.EVT_BUTTON, self.OnHelp)
00176 
00177         self.btn_add.Bind(wx.EVT_BUTTON, self.OnAddTool)
00178         self.btn_remove.Bind(wx.EVT_BUTTON, self.OnClearTool)
00179         self.btn_moveup.Bind(wx.EVT_BUTTON, self.OnMoveToolUp)
00180         self.btn_movedown.Bind(wx.EVT_BUTTON, self.OnMoveToolDown)
00181 
00182         self.SetMinSize(self.GetBestSize())
00183 
00184         # layout
00185         self._layout()
00186 
00187         self.CentreOnScreen()
00188         self.Show()
00189         
00190     def _layout(self):
00191         sizer = wx.BoxSizer(wx.VERTICAL)
00192         
00193         #
00194         # input output
00195         #
00196         inSizer = wx.GridBagSizer(hgap=5, vgap=5)
00197 
00198         inSizer.Add(item=self.inmaplabel, pos=(0, 0),
00199                        flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL | wx.EXPAND, border=1)
00200         inSizer.Add(item=self.selectionInput, pos=(1, 0),
00201                        flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL | wx.EXPAND, border=1)
00202 
00203         self.ftype_check = [
00204             wx.CheckBox(parent=self, id=wx.ID_ANY, label=_('point')),
00205             wx.CheckBox(parent=self, id=wx.ID_ANY, label=_('line')),
00206             wx.CheckBox(parent=self, id=wx.ID_ANY, label=_('boundary')),
00207             wx.CheckBox(parent=self, id=wx.ID_ANY, label=_('centroid')),
00208             wx.CheckBox(parent=self, id=wx.ID_ANY, label=_('area')),
00209             wx.CheckBox(parent=self, id=wx.ID_ANY, label=_('face'))
00210             ]
00211 
00212         typeoptSizer = wx.BoxSizer(wx.HORIZONTAL)
00213         for num in range(0, self.n_ftypes):
00214             type_box = self.ftype_check[num]
00215             typeoptSizer.Add(item=type_box, flag=wx.ALIGN_LEFT, border=1)
00216 
00217         self.ftypeSizer.Add(item = typeoptSizer,
00218                    flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=2)
00219 
00220         outSizer = wx.GridBagSizer(hgap=5, vgap=5)
00221 
00222         outSizer.Add(item=self.outmaplabel, pos=(0, 0),
00223                        flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL | wx.EXPAND, border=1)
00224         outSizer.Add(item=self.selectionOutput, pos=(1, 0),
00225                        flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL | wx.EXPAND, border=1)
00226         replaceSizer = wx.BoxSizer(wx.HORIZONTAL)
00227         replaceSizer.Add(item=self.overwrite, proportion=1,
00228                          flag=wx.ALL | wx.EXPAND, border=1)
00229 
00230         outSizer.Add(item=replaceSizer, pos=(2, 0),
00231                        flag=wx.ALL | wx.EXPAND, border=1)
00232 
00233         #
00234         # tools selection
00235         #
00236         bodySizer = wx.GridBagSizer(hgap=5, vgap=5)
00237 
00238         bodySizer.Add(item=self.ct_label, pos=(0, 0), span=(1, 2),
00239                       flag=wx.ALL, border=5)
00240 
00241         bodySizer.Add(item=self.ct_panel, pos=(1, 0), span=(1, 2))
00242 
00243         manageBoxSizer = wx.GridBagSizer(hgap=10, vgap=1)
00244         # start with row 1 for nicer layout
00245         manageBoxSizer.Add(item=self.btn_add, pos=(1, 0), border=2, flag=wx.ALL | wx.EXPAND)
00246         manageBoxSizer.Add(item=self.btn_remove, pos=(2, 0), border=2, flag=wx.ALL | wx.EXPAND)
00247         manageBoxSizer.Add(item=self.btn_moveup, pos=(3, 0), border=2, flag=wx.ALL | wx.EXPAND)
00248         manageBoxSizer.Add(item=self.btn_movedown, pos=(4, 0), border=2, flag=wx.ALL | wx.EXPAND)
00249 
00250         bodySizer.Add(item=manageBoxSizer, pos=(1, 2),
00251                       flag=wx.EXPAND | wx.LEFT | wx.RIGHT, border=5)
00252 
00253         bodySizer.AddGrowableCol(2)
00254         
00255         #
00256         # standard buttons
00257         #
00258         btnSizer = wx.BoxSizer(wx.HORIZONTAL)
00259         btnSizer.Add(self.btn_close,
00260                      flag=wx.LEFT | wx.RIGHT, border=5)
00261         btnSizer.Add(self.btn_run,
00262                      flag=wx.LEFT | wx.RIGHT, border=5)
00263         btnSizer.Add(self.btn_clipboard,
00264                      flag=wx.LEFT | wx.RIGHT, border=5)
00265         btnSizer.Add(self.btn_help,
00266                      flag=wx.LEFT | wx.RIGHT, border=5)
00267         
00268         #
00269         # put it all together
00270         #
00271         sizer.Add(item=inSizer, proportion=0,
00272                   flag=wx.ALL | wx.EXPAND, border=5)
00273         
00274         sizer.Add(item=self.ftypeSizer, proportion=0,
00275                   flag=wx.ALL | wx.EXPAND, border=5)
00276 
00277         sizer.Add(item=outSizer, proportion=0,
00278                   flag=wx.ALL | wx.EXPAND, border=5)
00279 
00280         sizer.Add(item=wx.StaticLine(parent=self, id=wx.ID_ANY,
00281                   style=wx.LI_HORIZONTAL), proportion=0,
00282                   flag=wx.EXPAND | wx.ALL, border=5) 
00283         
00284         sizer.Add(item=bodySizer, proportion=1,
00285                   flag=wx.ALL | wx.EXPAND, border=5)
00286 
00287         sizer.Add(item=wx.StaticLine(parent=self, id=wx.ID_ANY,
00288                   style=wx.LI_HORIZONTAL), proportion=0,
00289                   flag=wx.EXPAND | wx.ALL, border=5) 
00290         
00291         sizer.Add(item=btnSizer, proportion=0,
00292                   flag=wx.ALL | wx.ALIGN_RIGHT, border=5)
00293         
00294         self.SetSizer(sizer)
00295         sizer.Fit(self)
00296         self.Layout()
00297         
00298     def __toolsPanel(self):
00299         ct_panel = scrolled.ScrolledPanel(parent=self, id=wx.ID_ANY,
00300                                           size=(500, 240),
00301                                           style=wx.SUNKEN_BORDER)
00302 
00303         self.ct_sizer = wx.GridBagSizer(vgap=2, hgap=4)
00304         
00305         ct_panel.SetSizer(self.ct_sizer)
00306         ct_panel.SetAutoLayout(True)
00307         
00308         return ct_panel        
00309 
00310     def OnAddTool(self, event):
00311         """!Add tool button pressed"""
00312         self.AddTool()
00313 
00314     def AddTool(self):
00315         snum = len(self.toolslines.keys())
00316         num = snum + 1
00317         # tool number
00318         tool_no = wx.StaticText(parent = self.ct_panel, id = 3000+num,
00319                                          label= str(num)+'.')
00320         # tool
00321         tool_cbox = wx.ComboBox(parent = self.ct_panel, id=1000+num, 
00322                                 size = (300, -1), choices = self.tool_desc_list,
00323                                 style = wx.CB_DROPDOWN |
00324                                 wx.CB_READONLY | wx.TE_PROCESS_ENTER)
00325         self.Bind(wx.EVT_COMBOBOX, self.OnSetTool, tool_cbox)
00326         # threshold
00327         txt_ctrl = wx.TextCtrl(parent=self.ct_panel, id=2000+num, value='0.00',
00328                                size=(100,-1),
00329                                style=wx.TE_NOHIDESEL)
00330         self.Bind(wx.EVT_TEXT, self.OnThreshValue, txt_ctrl)
00331 
00332         # select
00333         select = wx.CheckBox(parent=self.ct_panel, id=num)
00334         select.SetValue(False)
00335         self.Bind(wx.EVT_CHECKBOX, self.OnSelect, select)
00336 
00337         # start with row 1 and col 1 for nicer layout
00338         self.ct_sizer.Add(item=tool_no, pos=(num, 1),
00339                           flag=wx.ALIGN_CENTER_VERTICAL, border=5)
00340         self.ct_sizer.Add(item=tool_cbox, pos=(num, 2),
00341                           flag=wx.ALIGN_CENTER | wx.RIGHT, border=5)
00342         self.ct_sizer.Add(item=txt_ctrl, pos=(num, 3),
00343                           flag=wx.ALIGN_CENTER | wx.RIGHT, border=5)
00344         self.ct_sizer.Add(item=select, pos=(num, 4),
00345                           flag=wx.ALIGN_CENTER | wx.RIGHT)
00346 
00347         self.toolslines[num] = {
00348             'tool_desc' : '' ,
00349             'tool' : '' ,
00350             'thresh' : '0.00' }
00351         
00352         self.ct_panel.Layout()
00353         self.ct_panel.SetupScrolling()
00354         
00355     def OnClearTool(self, event):
00356         """!Remove tool button pressed"""
00357         id = self.selected
00358 
00359         if id > 0:
00360             self.FindWindowById(id+1000).SetValue('')
00361             self.toolslines[id]['tool_desc'] = ''
00362             self.toolslines[id]['tool'] = ''
00363             self.SetStatusText(_("%s. cleaning tool removed, will be ignored") % id)
00364         else:
00365             self.SetStatusText(_("Please select a cleaning tool to remove"))
00366 
00367     def OnMoveToolUp(self, event):
00368         """!Move up tool button pressed"""
00369         id = self.selected
00370 
00371         if id > 1:
00372             id_up = id - 1
00373             this_toolline = self.toolslines[id]
00374             up_toolline = self.toolslines[id_up]
00375             
00376             self.FindWindowById(id_up).SetValue(True)
00377             self.FindWindowById(id_up+1000).SetValue(this_toolline['tool_desc'])
00378             self.FindWindowById(id_up+2000).SetValue(this_toolline['thresh'])
00379             self.toolslines[id_up] = this_toolline
00380             
00381             self.FindWindowById(id).SetValue(False)
00382             self.FindWindowById(id+1000).SetValue(up_toolline['tool_desc'])
00383             self.FindWindowById(id+2000).SetValue(up_toolline['thresh'])
00384             self.toolslines[id] = up_toolline
00385             self.selected = id_up
00386             self.SetStatusText(_("%s. cleaning tool moved up") % id)
00387         elif id == 1:
00388             self.SetStatusText(_("1. cleaning tool can not be moved up "))
00389         elif id == -1:
00390             self.SetStatusText(_("Please select a cleaning tool to move up"))
00391 
00392 
00393     def OnMoveToolDown(self, event):
00394         """!Move down tool button pressed"""
00395         id = self.selected
00396         snum = len(self.toolslines.keys())
00397 
00398         if id > 0 and id < snum:
00399             id_down = id + 1
00400             this_toolline = self.toolslines[id]
00401             down_toolline = self.toolslines[id_down]
00402             
00403             self.FindWindowById(id_down).SetValue(True)
00404             self.FindWindowById(id_down+1000).SetValue(this_toolline['tool_desc'])
00405             self.FindWindowById(id_down+2000).SetValue(this_toolline['thresh'])
00406             self.toolslines[id_down] = this_toolline
00407             
00408             self.FindWindowById(id).SetValue(False)
00409             self.FindWindowById(id+1000).SetValue(down_toolline['tool_desc'])
00410             self.FindWindowById(id+2000).SetValue(down_toolline['thresh'])
00411             self.toolslines[id] = down_toolline
00412             self.selected = id_down
00413             self.SetStatusText(_("%s. cleaning tool moved down") % id)
00414         elif id == snum:
00415             self.SetStatusText(_("Last cleaning tool can not be moved down "))
00416         elif id == -1:
00417             self.SetStatusText(_("Please select a cleaning tool to move down"))
00418 
00419     def OnSetTool(self, event):
00420         """!Tool was defined"""
00421         id = event.GetId()
00422         tool_no = id-1000
00423         num = self.FindWindowById(id).GetCurrentSelection()
00424 
00425         self.toolslines[tool_no]['tool_desc'] = self.tool_desc_list[num]
00426         self.toolslines[tool_no]['tool'] = self.tool_list[num]
00427 
00428         self.SetStatusText( str(tool_no) + '. ' + _("cleaning tool: '%s'") % (self.tool_list[num]))
00429 
00430     def OnThreshValue(self, event):
00431         """!Threshold value was entered"""
00432         id = event.GetId()
00433         num = id-2000
00434         self.toolslines[num]['thresh'] = self.FindWindowById(id).GetValue()
00435 
00436         self.SetStatusText(_("Threshold for %(num)s. tool '%(tool)s': %(thresh)s") % \
00437                                { 'num' : num,
00438                                  'tool' : self.toolslines[num]['tool'],
00439                                  'thresh' : self.toolslines[num]['thresh'] })
00440 
00441     def OnSelect(self, event):
00442         """!Tool was selected"""
00443         id = event.GetId()
00444 
00445         if self.selected > -1 and self.selected != id:
00446             win = self.FindWindowById(self.selected)
00447             win.SetValue(False)
00448 
00449         if self.selected != id:
00450             self.selected = id
00451         else:
00452             self.selected = -1
00453 
00454     def OnCleaningRun(self, event):
00455         """!Builds options and runs v.clean
00456         """
00457         self.SetStatusText(_("Executing selected cleaning operations..."))
00458         snum = len(self.toolslines.keys())
00459         self.GetCmdStrings()
00460 
00461         if self.log:
00462             cmd = [ self.cmd,
00463                     'input=%s' % self.inmap,
00464                     'output=%s' % self.outmap,
00465                     'tool=%s' % self.tools_string,
00466                     'thres=%s' % self.thresh_string ]
00467             if self.ftype_string:
00468                 cmd.append('type=%s' % self.ftype_string)
00469             if self.overwrite.IsChecked():
00470                 cmd.append('--overwrite')
00471             
00472             self.log.RunCmd(cmd)
00473             self.parent.Raise()
00474         else:
00475             if self.overwrite.IsChecked():
00476                 overwrite = True
00477             else:
00478                 overwrite = False
00479             
00480             gcmd.RunCommand(self.cmd,
00481                             input = self.inmap,
00482                             output = self.outmap,
00483                             type = self.ftype_string,
00484                             tool = self.tools_string,
00485                             thresh = self.thresh_string,
00486                             overwrite = overwrite)
00487 
00488     def OnClose(self, event):
00489         self.Destroy()
00490         
00491     def OnHelp(self, event):
00492         """!Show GRASS manual page"""
00493         gcmd.RunCommand('g.manual',
00494                         quiet = True,
00495                         parent = self,
00496                         entry = self.cmd)
00497         
00498     def OnCopy(self, event):
00499         """!Copy the command"""
00500         cmddata = wx.TextDataObject()
00501         # get tool and thresh strings
00502         self.GetCmdStrings()
00503         cmdstring = '%s' % (self.cmd)
00504         # list -> string
00505         cmdstring += ' input=%s output=%s type=%s tool=%s thres=%s' % \
00506             (self.inmap, self.outmap, self.ftype_string, self.tools_string, self.thresh_string)
00507         if self.overwrite.IsChecked():
00508             cmdstring += ' --overwrite'
00509  
00510         cmddata.SetText(cmdstring)
00511         if wx.TheClipboard.Open():
00512             wx.TheClipboard.SetData(cmddata)
00513             wx.TheClipboard.Close()
00514             self.SetStatusText(_("Vector cleaning command copied to clipboard"))
00515 
00516     def GetCmdStrings(self):
00517         self.tools_string = ''
00518         self.thresh_string = ''
00519         self.ftype_string = ''
00520         # feature types
00521         first = 1
00522         for num in range(0, self.n_ftypes - 1):
00523             if self.ftype_check[num].IsChecked():
00524                 if first:
00525                     self.ftype_string = '%s' % self.ftype[num]
00526                     first = 0
00527                 else:
00528                     self.ftype_string += ',%s' % self.ftype[num]
00529                     
00530             
00531         # cleaning tools
00532         first = 1
00533         snum = len(self.toolslines.keys())
00534         for num in range(1, snum + 1):
00535             if self.toolslines[num]['tool']:
00536                 if first:
00537                     self.tools_string = '%s' % self.toolslines[num]['tool']
00538                     self.thresh_string = '%s' % self.toolslines[num]['thresh']
00539                     first = 0
00540                 else:
00541                     self.tools_string += ',%s' % self.toolslines[num]['tool']
00542                     self.thresh_string += ',%s' % self.toolslines[num]['thresh']
00543 
00544         self.inmap = self.selectionInput.GetValue()
00545         self.outmap = self.selectionOutput.GetValue()
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines