123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556 |
- """
- @package modules.vclean
- @brief Dialog for interactive construction of vector cleaning
- operations
- Classes:
- - vclean::VectorCleaningFrame
- (C) 2010-2011 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.
- @author Markus Metz
- """
- import os
- import wx
- import wx.lib.scrolledpanel as scrolled
- from grass.script import core as grass
- from core.gcmd import RunCommand, GError
- from core import globalvar
- from gui_core.gselect import Select
- from core.debug import Debug
- from core.settings import UserSettings
- class VectorCleaningFrame(wx.Frame):
- def __init__(self, parent, id = wx.ID_ANY, title = _('Set up vector cleaning tools'),
- style = wx.DEFAULT_FRAME_STYLE | wx.RESIZE_BORDER,
- **kwargs):
- """!
- Dialog for interactively defining vector cleaning tools
- """
- wx.Frame.__init__(self, parent, id, title, style = style, **kwargs)
-
- self.parent = parent # GMFrame
- if self.parent:
- self.log = self.parent.GetLogWindow()
- else:
- self.log = None
-
- # grass command
- self.cmd = 'v.clean'
-
- # statusbar
- self.CreateStatusBar()
-
- # icon
- self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass.ico'), wx.BITMAP_TYPE_ICO))
-
- self.panel = wx.Panel(parent = self, id = wx.ID_ANY)
-
- # input map to clean
- self.inmap = ''
-
- # cleaned output map
- self.outmap = ''
-
- self.ftype = ''
-
- # cleaning tools
- self.toolslines = {}
-
- self.tool_desc_list = [
- _('break lines/boundaries'),
- _('remove duplicates'),
- _('remove dangles'),
- _('change boundary dangles to lines'),
- _('remove bridges'),
- _('change bridges to lines'),
- _('snap lines/boundaries'),
- _('remove duplicate area centroids'),
- _('break polygons'),
- _('prune lines/boundaries'),
- _('remove small areas'),
- _('remove lines/boundaries of zero length'),
- _('remove small angles at nodes')
- ]
-
- self.tool_list = [
- 'break',
- 'rmdupl',
- 'rmdangle',
- 'chdangle',
- 'rmbridge',
- 'chbridge',
- 'snap',
- 'rmdac',
- 'bpol',
- 'prune',
- 'rmarea',
- 'rmline',
- 'rmsa'
- ]
-
- self.ftype = [
- 'point',
- 'line',
- 'boundary',
- 'centroid',
- 'area',
- 'face']
-
- self.n_ftypes = len(self.ftype)
-
- self.tools_string = ''
- self.thresh_string = ''
- self.ftype_string = ''
-
- self.SetStatusText(_("Set up vector cleaning tools"))
- self.elem = 'vector'
- self.ctlabel = _('Choose cleaning tools and set thresholds')
-
- # top controls
- self.inmaplabel = wx.StaticText(parent = self.panel, id = wx.ID_ANY,
- label= _('Select input vector map:'))
- self.selectionInput = Select(parent = self.panel, id = wx.ID_ANY,
- size = globalvar.DIALOG_GSELECT_SIZE,
- type = 'vector')
- self.ftype_check = {}
- ftypeBox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
- label = _(' Feature type: '))
- self.ftypeSizer = wx.StaticBoxSizer(ftypeBox, wx.HORIZONTAL)
- self.outmaplabel = wx.StaticText(parent = self.panel, id = wx.ID_ANY,
- label = _('Select output vector map:'))
- self.selectionOutput = Select(parent = self.panel, id = wx.ID_ANY,
- size = globalvar.DIALOG_GSELECT_SIZE,
- type = 'vector')
-
- self.overwrite = wx.CheckBox(parent = self.panel, id = wx.ID_ANY,
- label = _('Allow output files to overwrite existing files'))
- self.overwrite.SetValue(UserSettings.Get(group = 'cmd', key = 'overwrite', subkey = 'enabled'))
- # cleaning tools
- self.ct_label = wx.StaticText(parent = self.panel, id = wx.ID_ANY,
- label = self.ctlabel)
- self.ct_panel = self._toolsPanel()
- # buttons to manage cleaning tools
- self.btn_add = wx.Button(parent = self.panel, id = wx.ID_ADD)
- self.btn_remove = wx.Button(parent = self.panel, id = wx.ID_REMOVE)
- self.btn_moveup = wx.Button(parent = self.panel, id = wx.ID_UP)
- self.btn_movedown = wx.Button(parent = self.panel, id = wx.ID_DOWN)
- # add one tool as default
- self.AddTool()
- self.selected = -1
-
- # Buttons
- self.btn_close = wx.Button(parent = self.panel, id = wx.ID_CLOSE)
- self.btn_run = wx.Button(parent = self.panel, id = wx.ID_ANY, label = _("&Run"))
- self.btn_run.SetDefault()
- self.btn_clipboard = wx.Button(parent = self.panel, id = wx.ID_COPY)
- self.btn_clipboard.SetToolTipString(_("Copy the current command string to the clipboard (Ctrl+C)"))
- self.btn_help = wx.Button(parent = self.panel, id = wx.ID_HELP)
-
- # bindings
- self.btn_close.Bind(wx.EVT_BUTTON, self.OnClose)
- self.btn_run.Bind(wx.EVT_BUTTON, self.OnCleaningRun)
- self.btn_clipboard.Bind(wx.EVT_BUTTON, self.OnCopy)
- self.btn_help.Bind(wx.EVT_BUTTON, self.OnHelp)
- self.btn_add.Bind(wx.EVT_BUTTON, self.OnAddTool)
- self.btn_remove.Bind(wx.EVT_BUTTON, self.OnClearTool)
- self.btn_moveup.Bind(wx.EVT_BUTTON, self.OnMoveToolUp)
- self.btn_movedown.Bind(wx.EVT_BUTTON, self.OnMoveToolDown)
-
- # layout
- self._layout()
-
- self.SetMinSize(self.GetBestSize())
-
- self.CentreOnScreen()
-
- def _layout(self):
- sizer = wx.BoxSizer(wx.VERTICAL)
-
- #
- # input output
- #
- inSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
- inSizer.Add(item = self.inmaplabel, pos = (0, 0),
- flag = wx.ALIGN_CENTER_VERTICAL | wx.ALL | wx.EXPAND, border = 1)
- inSizer.Add(item = self.selectionInput, pos = (1, 0),
- flag = wx.ALIGN_CENTER_VERTICAL | wx.ALL | wx.EXPAND, border = 1)
- self.ftype_check = [
- wx.CheckBox(parent = self.panel, id = wx.ID_ANY, label = _('point')),
- wx.CheckBox(parent = self.panel, id = wx.ID_ANY, label = _('line')),
- wx.CheckBox(parent = self.panel, id = wx.ID_ANY, label = _('boundary')),
- wx.CheckBox(parent = self.panel, id = wx.ID_ANY, label = _('centroid')),
- wx.CheckBox(parent = self.panel, id = wx.ID_ANY, label = _('area')),
- wx.CheckBox(parent = self.panel, id = wx.ID_ANY, label = _('face'))
- ]
- typeoptSizer = wx.BoxSizer(wx.HORIZONTAL)
- for num in range(0, self.n_ftypes):
- type_box = self.ftype_check[num]
- typeoptSizer.Add(item = type_box, flag = wx.ALIGN_LEFT, border = 1)
- self.ftypeSizer.Add(item = typeoptSizer,
- flag = wx.ALIGN_CENTER_VERTICAL | wx.ALL, border = 2)
- outSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
- outSizer.Add(item = self.outmaplabel, pos = (0, 0),
- flag = wx.ALIGN_CENTER_VERTICAL | wx.ALL | wx.EXPAND, border = 1)
- outSizer.Add(item = self.selectionOutput, pos = (1, 0),
- flag = wx.ALIGN_CENTER_VERTICAL | wx.ALL | wx.EXPAND, border = 1)
- replaceSizer = wx.BoxSizer(wx.HORIZONTAL)
- replaceSizer.Add(item = self.overwrite, proportion = 1,
- flag = wx.ALL | wx.EXPAND, border = 1)
- outSizer.Add(item = replaceSizer, pos = (2, 0),
- flag = wx.ALL | wx.EXPAND, border = 1)
- #
- # tools selection
- #
- bodySizer = wx.GridBagSizer(hgap = 5, vgap = 5)
- bodySizer.Add(item = self.ct_label, pos = (0, 0), span = (1, 2),
- flag = wx.ALL, border = 5)
- bodySizer.Add(item = self.ct_panel, pos = (1, 0), span = (1, 2))
- manageBoxSizer = wx.GridBagSizer(hgap = 10, vgap = 1)
- # start with row 1 for nicer layout
- manageBoxSizer.Add(item = self.btn_add, pos = (1, 0), border = 2, flag = wx.ALL | wx.EXPAND)
- manageBoxSizer.Add(item = self.btn_remove, pos = (2, 0), border = 2, flag = wx.ALL | wx.EXPAND)
- manageBoxSizer.Add(item = self.btn_moveup, pos = (3, 0), border = 2, flag = wx.ALL | wx.EXPAND)
- manageBoxSizer.Add(item = self.btn_movedown, pos = (4, 0), border = 2, flag = wx.ALL | wx.EXPAND)
- bodySizer.Add(item = manageBoxSizer, pos = (1, 2),
- flag = wx.EXPAND | wx.LEFT | wx.RIGHT, border = 5)
- bodySizer.AddGrowableCol(2)
-
- #
- # standard buttons
- #
- btnSizer = wx.BoxSizer(wx.HORIZONTAL)
- btnSizer.Add(self.btn_close,
- flag = wx.LEFT | wx.RIGHT, border = 5)
- btnSizer.Add(self.btn_run,
- flag = wx.LEFT | wx.RIGHT, border = 5)
- btnSizer.Add(self.btn_clipboard,
- flag = wx.LEFT | wx.RIGHT, border = 5)
- btnSizer.Add(self.btn_help,
- flag = wx.LEFT | wx.RIGHT, border = 5)
-
- #
- # put it all together
- #
- sizer.Add(item = inSizer, proportion = 0,
- flag = wx.ALL | wx.EXPAND, border = 5)
-
- sizer.Add(item = self.ftypeSizer, proportion = 0,
- flag = wx.ALL | wx.EXPAND, border = 5)
- sizer.Add(item = outSizer, proportion = 0,
- flag = wx.ALL | wx.EXPAND, border = 5)
- sizer.Add(item = wx.StaticLine(parent = self, id = wx.ID_ANY,
- style = wx.LI_HORIZONTAL), proportion = 0,
- flag = wx.EXPAND | wx.ALL, border = 5)
-
- sizer.Add(item = bodySizer, proportion = 1,
- flag = wx.ALL | wx.EXPAND, border = 5)
- sizer.Add(item = wx.StaticLine(parent = self, id = wx.ID_ANY,
- style = wx.LI_HORIZONTAL), proportion = 0,
- flag = wx.EXPAND | wx.ALL, border = 5)
-
- sizer.Add(item = btnSizer, proportion = 0,
- flag = wx.ALL | wx.ALIGN_RIGHT, border = 5)
-
- self.panel.SetAutoLayout(True)
- self.panel.SetSizer(sizer)
- sizer.Fit(self.panel)
-
- self.Layout()
-
- def _toolsPanel(self):
- ct_panel = scrolled.ScrolledPanel(parent = self.panel, id = wx.ID_ANY,
- size = (500, 240),
- style = wx.SUNKEN_BORDER)
- self.ct_sizer = wx.GridBagSizer(vgap = 2, hgap = 4)
-
- ct_panel.SetSizer(self.ct_sizer)
- ct_panel.SetAutoLayout(True)
-
- return ct_panel
- def OnAddTool(self, event):
- """!Add tool button pressed"""
- self.AddTool()
- def AddTool(self):
- snum = len(self.toolslines.keys())
- num = snum + 1
- # tool number
- tool_no = wx.StaticText(parent = self.ct_panel, id = 3000+num,
- label = str(num)+'.')
- # tool
- tool_cbox = wx.ComboBox(parent = self.ct_panel, id = 1000+num,
- size = (300, -1), choices = self.tool_desc_list,
- style = wx.CB_DROPDOWN |
- wx.CB_READONLY | wx.TE_PROCESS_ENTER)
- self.Bind(wx.EVT_COMBOBOX, self.OnSetTool, tool_cbox)
- # threshold
- txt_ctrl = wx.TextCtrl(parent = self.ct_panel, id = 2000+num, value = '0.00',
- size = (100,-1),
- style = wx.TE_NOHIDESEL)
- self.Bind(wx.EVT_TEXT, self.OnThreshValue, txt_ctrl)
- # select
- select = wx.CheckBox(parent = self.ct_panel, id = num)
- select.SetValue(False)
- self.Bind(wx.EVT_CHECKBOX, self.OnSelect, select)
- # start with row 1 and col 1 for nicer layout
- self.ct_sizer.Add(item = tool_no, pos = (num, 1),
- flag = wx.ALIGN_CENTER_VERTICAL, border = 5)
- self.ct_sizer.Add(item = tool_cbox, pos = (num, 2),
- flag = wx.ALIGN_CENTER | wx.RIGHT, border = 5)
- self.ct_sizer.Add(item = txt_ctrl, pos = (num, 3),
- flag = wx.ALIGN_CENTER | wx.RIGHT, border = 5)
- self.ct_sizer.Add(item = select, pos = (num, 4),
- flag = wx.ALIGN_CENTER | wx.RIGHT)
- self.toolslines[num] = {
- 'tool_desc' : '' ,
- 'tool' : '' ,
- 'thresh' : '0.00' }
-
- self.ct_panel.Layout()
- self.ct_panel.SetupScrolling()
-
- def OnClearTool(self, event):
- """!Remove tool button pressed"""
- id = self.selected
- if id > 0:
- self.FindWindowById(id+1000).SetValue('')
- self.toolslines[id]['tool_desc'] = ''
- self.toolslines[id]['tool'] = ''
- self.SetStatusText(_("%s. cleaning tool removed, will be ignored") % id)
- else:
- self.SetStatusText(_("Please select a cleaning tool to remove"))
- def OnMoveToolUp(self, event):
- """!Move up tool button pressed"""
- id = self.selected
- if id > 1:
- id_up = id - 1
- this_toolline = self.toolslines[id]
- up_toolline = self.toolslines[id_up]
-
- self.FindWindowById(id_up).SetValue(True)
- self.FindWindowById(id_up+1000).SetValue(this_toolline['tool_desc'])
- self.FindWindowById(id_up+2000).SetValue(this_toolline['thresh'])
- self.toolslines[id_up] = this_toolline
-
- self.FindWindowById(id).SetValue(False)
- self.FindWindowById(id+1000).SetValue(up_toolline['tool_desc'])
- self.FindWindowById(id+2000).SetValue(up_toolline['thresh'])
- self.toolslines[id] = up_toolline
- self.selected = id_up
- self.SetStatusText(_("%s. cleaning tool moved up") % id)
- elif id == 1:
- self.SetStatusText(_("1. cleaning tool can not be moved up "))
- elif id == -1:
- self.SetStatusText(_("Please select a cleaning tool to move up"))
- def OnMoveToolDown(self, event):
- """!Move down tool button pressed"""
- id = self.selected
- snum = len(self.toolslines.keys())
- if id > 0 and id < snum:
- id_down = id + 1
- this_toolline = self.toolslines[id]
- down_toolline = self.toolslines[id_down]
-
- self.FindWindowById(id_down).SetValue(True)
- self.FindWindowById(id_down+1000).SetValue(this_toolline['tool_desc'])
- self.FindWindowById(id_down+2000).SetValue(this_toolline['thresh'])
- self.toolslines[id_down] = this_toolline
-
- self.FindWindowById(id).SetValue(False)
- self.FindWindowById(id+1000).SetValue(down_toolline['tool_desc'])
- self.FindWindowById(id+2000).SetValue(down_toolline['thresh'])
- self.toolslines[id] = down_toolline
- self.selected = id_down
- self.SetStatusText(_("%s. cleaning tool moved down") % id)
- elif id == snum:
- self.SetStatusText(_("Last cleaning tool can not be moved down "))
- elif id == -1:
- self.SetStatusText(_("Please select a cleaning tool to move down"))
- def OnSetTool(self, event):
- """!Tool was defined"""
- id = event.GetId()
- tool_no = id-1000
- num = self.FindWindowById(id).GetCurrentSelection()
- self.toolslines[tool_no]['tool_desc'] = self.tool_desc_list[num]
- self.toolslines[tool_no]['tool'] = self.tool_list[num]
- self.SetStatusText( str(tool_no) + '. ' + _("cleaning tool: '%s'") % (self.tool_list[num]))
- def OnThreshValue(self, event):
- """!Threshold value was entered"""
- id = event.GetId()
- num = id-2000
- self.toolslines[num]['thresh'] = self.FindWindowById(id).GetValue()
- self.SetStatusText(_("Threshold for %(num)s. tool '%(tool)s': %(thresh)s") % \
- { 'num' : num,
- 'tool' : self.toolslines[num]['tool'],
- 'thresh' : self.toolslines[num]['thresh'] })
- def OnSelect(self, event):
- """!Tool was selected"""
- id = event.GetId()
- if self.selected > -1 and self.selected != id:
- win = self.FindWindowById(self.selected)
- win.SetValue(False)
- if self.selected != id:
- self.selected = id
- else:
- self.selected = -1
- def OnDone(self, cmd, returncode):
- """!Command done"""
- self.SetStatusText('')
-
- def OnCleaningRun(self, event):
- """!Builds options and runs v.clean
- """
- self.GetCmdStrings()
-
- err = list()
- for p, name in ((self.inmap, _('Name of input vector map')),
- (self.outmap, _('Name for output vector map')),
- (self.tools_string, _('Tools')),
- (self.thresh_string, _('Threshold'))):
- if not p:
- err.append(_("'%s' not defined") % name)
- if err:
- GError(_("Some parameters not defined. Operation "
- "canceled.\n\n%s") % '\n'.join(err),
- parent = self)
- return
-
- self.SetStatusText(_("Executing selected cleaning operations..."))
- snum = len(self.toolslines.keys())
-
- if self.log:
- cmd = [ self.cmd,
- 'input=%s' % self.inmap,
- 'output=%s' % self.outmap,
- 'tool=%s' % self.tools_string,
- 'thres=%s' % self.thresh_string ]
- if self.ftype_string:
- cmd.append('type=%s' % self.ftype_string)
- if self.overwrite.IsChecked():
- cmd.append('--overwrite')
-
- self.log.RunCmd(cmd, onDone = self.OnDone)
- self.parent.Raise()
- else:
- if self.overwrite.IsChecked():
- overwrite = True
- else:
- overwrite = False
-
- RunCommand(self.cmd,
- input = self.inmap,
- output = self.outmap,
- type = self.ftype_string,
- tool = self.tools_string,
- thresh = self.thresh_string,
- overwrite = overwrite)
- def OnClose(self, event):
- self.Destroy()
-
- def OnHelp(self, event):
- """!Show GRASS manual page"""
- RunCommand('g.manual',
- quiet = True,
- parent = self,
- entry = self.cmd)
-
- def OnCopy(self, event):
- """!Copy the command"""
- cmddata = wx.TextDataObject()
- # get tool and thresh strings
- self.GetCmdStrings()
- cmdstring = '%s' % (self.cmd)
- # list -> string
- cmdstring += ' input=%s output=%s type=%s tool=%s thres=%s' % \
- (self.inmap, self.outmap, self.ftype_string, self.tools_string, self.thresh_string)
- if self.overwrite.IsChecked():
- cmdstring += ' --overwrite'
-
- cmddata.SetText(cmdstring)
- if wx.TheClipboard.Open():
- wx.TheClipboard.SetData(cmddata)
- wx.TheClipboard.Close()
- self.SetStatusText(_("Vector cleaning command copied to clipboard"))
- def GetCmdStrings(self):
- self.tools_string = ''
- self.thresh_string = ''
- self.ftype_string = ''
- # feature types
- first = 1
- for num in range(0, self.n_ftypes - 1):
- if self.ftype_check[num].IsChecked():
- if first:
- self.ftype_string = '%s' % self.ftype[num]
- first = 0
- else:
- self.ftype_string += ',%s' % self.ftype[num]
-
-
- # cleaning tools
- first = 1
- snum = len(self.toolslines.keys())
- for num in range(1, snum + 1):
- if self.toolslines[num]['tool']:
- if first:
- self.tools_string = '%s' % self.toolslines[num]['tool']
- self.thresh_string = '%s' % self.toolslines[num]['thresh']
- first = 0
- else:
- self.tools_string += ',%s' % self.toolslines[num]['tool']
- self.thresh_string += ',%s' % self.toolslines[num]['thresh']
- self.inmap = self.selectionInput.GetValue()
- self.outmap = self.selectionOutput.GetValue()
|