"""! @package mapdisp_vdigit.py @brief Map display canvas extended for vector digitizer See also vdigit.py, wxvdriver.py and wxvdigit.py Classes: - VDigitWindow (C) 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 Martin Landa """ import wx import dbm_dialogs import gcmd from debug import Debug from mapdisp_window import BufferedWindow from preferences import globalSettings as UserSettings from utils import ListOfCatsToRange from globalvar import QUERYLAYER from vdigit import VDigitCategoryDialog from vdigit import VDigitZBulkDialog from vdigit import VDigitDuplicatesDialog class VDigitWindow(BufferedWindow): """!A Buffered window extended for vector digitizer. """ def __init__(self, parent, id = wx.ID_ANY, Map = None, tree = None, lmgr = None, style = wx.NO_FULL_REPAINT_ON_RESIZE, **kwargs): BufferedWindow.__init__(self, parent, id, Map, tree, lmgr, style, **kwargs) self.pdcVector = wx.PseudoDC() self.toolbar = self.parent.GetToolbar('vdigit') self.digit = None # wxvdigit.IVDigit self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown) def SetToolbar(self, toolbar): """!Set up related toolbar """ self.toolbar = toolbar def _onMotion(self, coord, precision): """!Track mouse motion and update statusbar (see self.Motion) @parem coord easting, northing @param precision formatting precision """ e, n = coord if self.toolbar.GetAction() != 'addLine' or \ self.toolbar.GetAction('type') not in ('line', 'boundary') or \ len(self.polycoords) == 0: return False # for linear feature show segment and total length distance_seg = self.Distance(self.polycoords[-1], (e, n), screen = False)[0] distance_tot = distance_seg for idx in range(1, len(self.polycoords)): distance_tot += self.Distance(self.polycoords[idx-1], self.polycoords[idx], screen = False)[0] self.parent.SetStatusText("%.*f, %.*f (seg: %.*f; tot: %.*f)" % \ (precision, e, precision, n, precision, distance_seg, precision, distance_tot), 0) return True def OnKeyDown(self, event): """!Key pressed""" shift = event.ShiftDown() kc = event.GetKeyCode() event = None if not shift: if kc == ord('P'): event = wx.CommandEvent(winid = self.toolbar.addPoint) tool = self.toolbar.OnAddPoint elif kc == ord('L'): event = wx.CommandEvent(winid = self.toolbar.addLine) tool = self.toolbar.OnAddLine if event: self.toolbar.OnTool(event) tool(event) def _updateMap(self): if not self.toolbar or \ not self.toolbar.GetLayer(): return # set region self.digit.GetDisplay().UpdateRegion() # re-calculate threshold for digitization tool # self.parent.digit.GetDisplay().GetThreshold() # draw map # self.pdcVector.Clear() self.pdcVector.RemoveAll() item = None if self.tree: try: item = self.tree.FindItemByData('maplayer', self.toolbar.GetLayer()) except TypeError: pass if not self.tree or \ (self.tree and item and \ self.tree.IsItemChecked(item)): self.redrawAll = True self.digit.GetDisplay().DrawMap() # translate tmp objects (pointer position) if self.toolbar.GetAction() == 'moveLine' and \ hasattr(self, "moveInfo"): if 'beginDiff' in self.moveInfo: # move line for id in self.moveInfo['id']: self.pdcTmp.TranslateId(id, self.moveInfo['beginDiff'][0], self.moveInfo['beginDiff'][1]) del self.moveInfo['beginDiff'] def OnLeftDownAddLine(self, event): """!Left mouse button pressed - add new feature """ try: mapLayer = self.toolbar.GetLayer().GetName() except: return if self.toolbar.GetAction('type') in ['point', 'centroid']: # add new point / centroiud east, north = self.Pixel2Cell(self.mouse['begin']) nfeat, fids = self.digit.AddFeature(self.toolbar.GetAction('type'), [(east, north)]) if nfeat < 1: return self.UpdateMap(render = False) # redraw map # add new record into atribute table if UserSettings.Get(group = 'vdigit', key = "addRecord", subkey = 'enabled'): # select attributes based on layer and category cats = { fids[0] : { UserSettings.Get(group = 'vdigit', key = "layer", subkey = 'value') : (UserSettings.Get(group = 'vdigit', key = "category", subkey = 'value'), ) }} posWindow = self.ClientToScreen((self.mouse['end'][0] + self.dialogOffset, self.mouse['end'][1] + self.dialogOffset)) addRecordDlg = dbm_dialogs.DisplayAttributesDialog(parent = self, map = mapLayer, cats = cats, pos = posWindow, action = "add", ignoreError = True) if self.toolbar.GetAction('type') == 'centroid': for fid in fids: self._geomAttrb(fid, addRecordDlg, 'area') self._geomAttrb(fid, addRecordDlg, 'perimeter') if addRecordDlg.IsFound() and \ addRecordDlg.ShowModal() == wx.ID_OK: sqlfile = tempfile.NamedTemporaryFile(mode = "w") for sql in addRecordDlg.GetSQLString(): sqlfile.file.write(sql + ";\n") sqlfile.file.flush() gcmd.RunCommand('db.execute', parent = self, quiet = True, input = sqlfile.name) if addRecordDlg.mapDBInfo: self._updateATM() elif self.toolbar.GetAction('type') in ["line", "boundary", "area"]: # add new point to the line self.polycoords.append(self.Pixel2Cell(event.GetPositionTuple()[:])) self.DrawLines(pdc = self.pdcTmp) def _geomAttrb(self, fid, dialog, attrb): """!Define geometry attributes """ mapLayer = self.toolbar.GetLayer() if self.tree: item = self.tree.FindItemByData('maplayer', mapLayer) vdigit = self.tree.GetPyData(item)[0]['vdigit'] else: item = vdigit = None if not vdigit or \ 'geomAttr' not in vdigit or \ attrb not in vdigit['geomAttr']: return val = -1 if attrb == 'length': val = self.digit.GetLineLength(fid) type = attrb elif attrb == 'area': val = self.digit.GetAreaSize(fid) type = attrb elif attrb == 'perimeter': val = self.digit.GetAreaPerimeter(fid) type = 'length' if val > 0: layer = int(UserSettings.Get(group = 'vdigit', key = "layer", subkey = 'value')) column = vdigit['geomAttr'][attrb]['column'] val = UnitsConvertValue(val, type, vdigit['geomAttr'][attrb]['units']) dialog.SetColumnValue(layer, column, val) dialog.OnReset() def _geomAttrbUpdate(self, fids): """!Update geometry atrributes of currently selected features @param fid list feature id """ mapLayer = self.parent.toolbars['vdigit'].GetLayer() vectorName = mapLayer.GetName() if self.tree: item = self.tree.FindItemByData('maplayer', mapLayer) vdigit = self.tree.GetPyData(item)[0]['vdigit'] else: item = vdigit = None if not vdigit or 'geomAttr' not in vdigit: return dbInfo = gselect.VectorDBInfo(vectorName) sqlfile = tempfile.NamedTemporaryFile(mode = "w") for fid in fids: for layer, cats in self.digit.GetLineCats(fid).iteritems(): table = dbInfo.GetTable(layer) for attrb, item in vdigit['geomAttr'].iteritems(): val = -1 if attrb == 'length': val = self.digit.GetLineLength(fid) type = attrb elif attrb == 'area': val = self.digit.GetAreaSize(fid) type = attrb elif attrb == 'perimeter': val = self.digit.GetAreaPerimeter(fid) type = 'length' if val < 0: continue val = UnitsConvertValue(val, type, item['units']) for cat in cats: sqlfile.write('UPDATE %s SET %s = %f WHERE %s = %d;\n' % \ (table, item['column'], val, dbInfo.GetKeyColumn(layer), cat)) sqlfile.file.flush() gcmd.RunCommand('db.execute', parent = True, quiet = True, input = sqlfile.name) def _updateATM(self): """!Update open Attribute Table Manager @todo: use AddDataRow() instead """ # update ATM digitVector = self.toolbar.GetLayer().GetName() for atm in self.lmgr.dialogs['atm']: atmVector = atm.GetVectorName() if atmVector == digitVector: layer = UserSettings.Get(group = 'vdigit', key = "layer", subkey = 'value') # TODO: use AddDataRow instead atm.LoadData(layer) def OnLeftDownEditLine(self, event): """!Left mouse button pressed - edit linear feature - add new vertex. """ self.polycoords.append(self.Pixel2Cell(self.mouse['begin'])) self.moveInfo['id'].append(wx.NewId()) self.DrawLines(pdc = self.pdcTmp) def OnLeftDownMoveLine(self, event): """!Left mouse button pressed - vector digitizer move feature/vertex, edit linear feature """ self.moveInfo = dict() # geographic coordinates of initial position (left-down) self.moveInfo['begin'] = None # list of ids to modify self.moveInfo['id'] = list() # set pen if self.toolbar.GetAction() in ["moveVertex", "editLine"]: pcolor = UserSettings.Get(group = 'vdigit', key = "symbol", subkey = ["highlight", "color"]) self.pen = self.polypen = wx.Pen(colour = pcolor, width = 2, style = wx.SHORT_DASH) self.pdcTmp.SetPen(self.polypen) def OnLeftDownDisplayCA(self, event): """!Left mouse button pressed - vector digitizer display categories or attributes action """ try: mapLayer = self.toolbar.GetLayer().GetName() except: return coords = self.Pixel2Cell(self.mouse['begin']) # unselect self.digit.GetDisplay().SetSelected([]) # select feature by point cats = {} self.digit.GetDisplay().SelectLineByPoint(coords) if not self.digit.GetDisplay().GetSelected(): for key in ('attributes', 'category'): if self.parent.dialogs[key] and \ self.parent.dialogs[key].IsShown(): self.parent.dialogs[key].Hide() self.UpdateMap(render = False, renderVector = True) return if UserSettings.Get(group = 'vdigit', key = 'checkForDupl', subkey = 'enabled'): lines = self.digit.GetDisplay().GetSelected() else: lines = (self.digit.GetDisplay().GetSelected()[0],) # only first found for line in lines: cats[line] = self.digit.GetLineCats(line) posWindow = self.ClientToScreen((self.mouse['end'][0] + self.dialogOffset, self.mouse['end'][1] + self.dialogOffset)) if self.toolbar.GetAction() == "displayAttrs": # select attributes based on coordinates (all layers) if self.parent.dialogs['attributes'] is None: self.parent.dialogs['attributes'] = \ dbm_dialogs.DisplayAttributesDialog(parent = self, map = mapLayer, cats = cats, action = "update") else: # upgrade dialog self.parent.dialogs['attributes'].UpdateDialog(cats = cats) if self.parent.dialogs['attributes'] and \ self.parent.dialogs['attributes'].mapDBInfo: if len(cats.keys()) > 0: # highlight feature & re-draw map if not self.parent.dialogs['attributes'].IsShown(): self.parent.dialogs['attributes'].Show() else: if self.parent.dialogs['attributes'] and \ self.parent.dialogs['attributes'].IsShown(): self.parent.dialogs['attributes'].Hide() else: # displayCats if self.parent.dialogs['category'] is None: # open new dialog dlg = VDigitCategoryDialog(parent = self, vectorName = mapLayer, cats = cats, pos = posWindow, title = _("Update categories")) self.parent.dialogs['category'] = dlg else: # update currently open dialog self.parent.dialogs['category'].UpdateDialog(cats = cats) if self.parent.dialogs['category']: if len(cats.keys()) > 0: # highlight feature & re-draw map if not self.parent.dialogs['category'].IsShown(): self.parent.dialogs['category'].Show() else: if self.parent.dialogs['category'].IsShown(): self.parent.dialogs['category'].Hide() self.UpdateMap(render = False, renderVector = True) def OnLeftDownCopyCA(self, event): """!Left mouse button pressed - vector digitizer copy categories or attributes action """ if not hasattr(self, "copyCatsList"): self.copyCatsList = [] else: self.copyCatsIds = [] self.mouse['box'] = 'box' def OnLeftDownCopyLine(self, event): """!Left mouse button pressed - vector digitizer copy lines action """ if not hasattr(self, "copyIds"): self.copyIds = [] self.layerTmp = None def OnLeftDownBulkLine(self, event): """!Left mouse button pressed - vector digitizer label 3D vector lines """ if len(self.polycoords) > 1: # start new line self.polycoords = [] self.ClearLines(pdc = self.pdcTmp) self.polycoords.append(self.Pixel2Cell(event.GetPositionTuple()[:])) if len(self.polycoords) == 1: begin = self.Pixel2Cell(self.polycoords[-1]) end = self.Pixel2Cell(self.mouse['end']) else: end = self.Pixel2Cell(self.polycoords[-1]) begin = self.Pixel2Cell(self.mouse['begin']) self.DrawLines(self.pdcTmp, polycoords = (begin, end)) def OnLeftDownUndo(self, event): """!Left mouse button pressed with control key - vector digitizer undo functionality """ if self.mouse["use"] != "pointer" or not self.toolbar: return action = self.toolbar.GetAction() if (action == "addLine" and \ self.toolbar.GetAction('type') in ["line", "boundary", "area"]) or \ action == "editLine": # add line or boundary -> remove last point from the line try: removed = self.polycoords.pop() Debug.msg(4, "BufferedWindow.OnMiddleDown(): polycoords_poped=%s" % \ [removed,]) # self.mouse['begin'] = self.Cell2Pixel(self.polycoords[-1]) except: pass if action == "editLine": # remove last vertex & line if len(self.moveInfo['id']) > 1: self.moveInfo['id'].pop() self.UpdateMap(render = False, renderVector = False) elif action in ["deleteLine", "moveLine", "splitLine", "addVertex", "removeVertex", "moveVertex", "copyCats", "flipLine", "mergeLine", "snapLine", "connectLine", "copyLine", "queryLine", "breakLine", "typeConv"]: # varios tools -> unselected selected features self.digit.GetDisplay().SetSelected([]) if action in ["moveLine", "moveVertex", "editLine"] and \ hasattr(self, "moveInfo"): del self.moveInfo elif action == "copyCats": try: del self.copyCatsList del self.copyCatsIds except AttributeError: pass elif action == "copyLine": del self.copyIds if self.layerTmp: self.Map.DeleteLayer(self.layerTmp) self.UpdateMap(render = True, renderVector = False) del self.layerTmp self.polycoords = [] self.UpdateMap(render = False) # render vector elif action == "zbulkLine": # reset polyline self.polycoords = [] self.digit.GetDisplay().SetSelected([]) self.UpdateMap(render = False) self.redrawAll = True self.UpdateMap(render = False, renderVector = False) def _onLeftDown(self, event): """!Left mouse button donw - vector digitizer various actions """ try: mapLayer = self.toolbar.GetLayer().GetName() except: gcmd.GMessage(parent = self, message = _("No vector map selected for editing.")) event.Skip() return action = self.toolbar.GetAction() if not action: return if action not in ("moveVertex", "addVertex", "removeVertex", "editLine"): # set pen self.pen = wx.Pen(colour = 'Red', width = 2, style = wx.SHORT_DASH) self.polypen = wx.Pen(colour = 'dark green', width = 2, style = wx.SOLID) if action in ("addVertex", "removeVertex", "splitLines"): # unselect self.digit.GetDisplay().SetSelected([]) if action == "addLine": self.OnLeftDownAddLine(event) elif action == "editLine" and \ hasattr(self, "moveInfo"): self.OnLeftDownEditLine(event) elif action in ("moveLine", "moveVertex", "editLine") and \ not hasattr(self, "moveInfo"): self.OnLeftDownMoveLine(event) elif action in ("displayAttrs" "displayCats"): self.OnLeftDownDisplayCA(event) elif action in ("copyCats", "copyAttrs"): self.OnLeftDownCopyCA(event) elif action == "copyLine": self.OnLeftDownCopyLine(event) elif action == "zbulkLine": self.OnLeftDownBulkLine(event) def OnLeftUpVarious(self, event): """!Left mouse button released - vector digitizer various actions """ pos1 = self.Pixel2Cell(self.mouse['begin']) pos2 = self.Pixel2Cell(self.mouse['end']) nselected = 0 action = self.toolbar.GetAction() # -> delete line || move line || move vertex if action in ("moveVertex", "editLine"): if len(self.digit.GetDisplay().GetSelected()) == 0: nselected = self.digit.GetDisplay().SelectLineByPoint(pos1)['point'] if action == "editLine": try: selVertex = self.digit.GetDisplay().GetSelectedVertex(pos1)[0] except IndexError: selVertex = None if selVertex: # self.UpdateMap(render=False) ids = self.digit.GetDisplay().GetSelected(grassId = False) # move this line to tmp layer self.polycoords = [] for id in ids: if id % 2: # register only vertices e, n = self.Pixel2Cell(self.pdcVector.GetIdBounds(id)[0:2]) self.polycoords.append((e, n)) self.digit.GetDisplay().DrawSelected(False) if selVertex < ids[-1] / 2: # choose first or last node of line self.moveInfo['id'].reverse() self.polycoords.reverse() else: # unselect self.digit.GetDisplay().SetSelected([]) del self.moveInfo self.UpdateMap(render = False) elif action in ("copyCats", "copyAttrs"): if not hasattr(self, "copyCatsIds"): # 'from' -> select by point nselected = self.digit.GetDisplay().SelectLineByPoint(pos1)['point'] if nselected: self.copyCatsList = self.digit.GetDisplay().GetSelected() else: # -> 'to' -> select by bbox self.digit.GetDisplay().SetSelected([]) # return number of selected features (by box/point) nselected = self.digit.GetDisplay().SelectLinesByBox((pos1, pos2)) if nselected == 0: if self.digit.GetDisplay().SelectLineByPoint(pos1) is not None: nselected = 1 if nselected > 0: self.copyCatsIds = self.digit.GetDisplay().GetSelected() elif action == "queryLine": selected = self.digit.SelectLinesByQuery(bbox = (pos1, pos2)) nselected = len(selected) if nselected > 0: self.digit.GetDisplay().SetSelected(selected) else: # -> moveLine || deleteLine, etc. (select by point/box) if action == 'moveLine' and \ len(self.digit.GetDisplay().GetSelected()) > 0: nselected = 0 else: if action == 'moveLine': drawSeg = True else: drawSeg = False nselected = self.digit.GetDisplay().SelectLinesByBox(bbox = (pos1, pos2), drawSeg = drawSeg) if nselected == 0: if self.digit.GetDisplay().SelectLineByPoint(pos1) is not None: nselected = 1 if nselected > 0: if action in ("moveLine", "moveVertex") and \ hasattr(self, "moveInfo"): # get pseudoDC id of objects which should be redrawn if action == "moveLine": # -> move line self.moveInfo['id'] = self.digit.GetDisplay().GetSelected(grassId = False) else: # moveVertex self.moveInfo['id'] = self.digit.GetDisplay().GetSelectedVertex(pos1) if len(self.moveInfo['id']) == 0: # no vertex found self.digit.GetDisplay().SetSelected([]) # # check for duplicates # if UserSettings.Get(group = 'vdigit', key = 'checkForDupl', subkey = 'enabled'): dupl = self.digit.GetDisplay().GetDuplicates() self.UpdateMap(render = False) if dupl: posWindow = self.ClientToScreen((self.mouse['end'][0] + self.dialogOffset, self.mouse['end'][1] + self.dialogOffset)) dlg = VDigitDuplicatesDialog(parent = self, data = dupl, pos = posWindow) if dlg.ShowModal() == wx.ID_OK: self.digit.GetDisplay().UnSelect(dlg.GetUnSelected()) # update selected self.UpdateMap(render = False) if action != "editLine": # -> move line || move vertex self.UpdateMap(render = False) else: # no vector object found if not (action in ("moveLine", "moveVertex") and \ hasattr(self, "moveInfo") and \ len(self.moveInfo['id']) > 0): # avoid left-click when features are already selected self.UpdateMap(render = False, renderVector = False) def OnLeftUpModifyLine(self, event): """!Left mouse button released - vector digitizer split line, add/remove vertex action """ pos1 = self.Pixel2Cell(self.mouse['begin']) pointOnLine = self.digit.GetDisplay().SelectLineByPoint(pos1)['point'] if not pointOnLine: return if self.toolbar.GetAction() in ["splitLine", "addVertex"]: self.UpdateMap(render = False) # highlight object self.DrawCross(pdc = self.pdcTmp, coords = self.Cell2Pixel((pointOnLine[0], pointOnLine[1])), size = 5) else: # removeVertex # get only id of vertex try: id = self.digit.GetDisplay().GetSelectedVertex(pos1)[0] except IndexError: id = None if id: x, y = self.pdcVector.GetIdBounds(id)[0:2] self.pdcVector.RemoveId(id) self.UpdateMap(render = False) # highlight object self.DrawCross(pdc = self.pdcTmp, coords = (x, y), size = 5) else: # unselect self.digit.GetDisplay().SetSelected([]) self.UpdateMap(render = False) def OnLeftUpCopyLine(self, event): """!Left mouse button released - vector digitizer copy feature action """ pos1 = self.Pixel2Cell(self.mouse['begin']) pos2 = self.Pixel2Cell(self.mouse['end']) if UserSettings.Get(group = 'vdigit', key = 'bgmap', subkey = 'value', internal = True) == '': # no background map -> copy from current vector map layer nselected = self.bdigit.GetDisplay().SelectLinesByBox((pos1, pos2)) if nselected > 0: # highlight selected features self.UpdateMap(render = False) else: self.UpdateMap(render = False, renderVector = False) else: # copy features from background map self.copyIds = self.digit.SelectLinesFromBackgroundMap(bbox = (pos1, pos2)) if len(self.copyIds) > 0: color = UserSettings.Get(group = 'vdigit', key = 'symbol', subkey = ['highlight', 'color']) colorStr = str(color[0]) + ":" + str(color[1]) + ":" + str(color[2]) dVectTmp = ['d.vect', 'map=%s' % UserSettings.Get(group = 'vdigit', key = 'bgmap', subkey = 'value', internal = True), 'cats=%s' % ListOfCatsToRange(self.copyIds), '-i', 'color=%s' % colorStr, 'fcolor=%s' % colorStr, 'type=point,line,boundary,centroid', 'width=2'] if not self.layerTmp: self.layerTmp = self.Map.AddLayer(type = 'vector', name = QUERYLAYER, command = dVectTmp) else: self.layerTmp.SetCmd(dVectTmp) else: if self.layerTmp: self.Map.DeleteLayer(self.layerTmp) self.layerTmp = None self.UpdateMap(render = True, renderVector = True) def OnLeftUpBulkLine(self, event): """!Left mouse button released - vector digitizer z-bulk line action """ # select lines to be labeled pos1 = self.polycoords[0] pos2 = self.polycoords[1] nselected = self.digit.GetDisplay().SelectLinesByBox((pos1, pos2)) if nselected > 0: # highlight selected features self.UpdateMap(render = False) self.DrawLines(pdc = self.pdcTmp) # redraw temp line else: self.UpdateMap(render = False, renderVector = False) def OnLeftUpConnectLine(self, event): """!Left mouse button released - vector digitizer connect line action """ if len(self.digit.GetDisplay().GetSelected()) > 0: self.UpdateMap(render = False) def _onLeftUp(self, event): """!Left mouse button released""" if hasattr(self, "moveInfo"): if len(self.digit.GetDisplay().GetSelected()) == 0: self.moveInfo['begin'] = self.Pixel2Cell(self.mouse['begin']) # left down # eliminate initial mouse moving efect self.mouse['begin'] = self.mouse['end'] action = self.toolbar.GetAction() if action in ("deleteLine", "moveLine", "moveVertex", "copyCats", "copyAttrs", "editLine", "flipLine", "mergeLine", "snapLine", "queryLine", "breakLine", "typeConv", "connectLine"): self.OnLeftUpVarious(event) elif action in ("splitLine", "addVertex", "removeVertex"): self.OnLeftUpModifyLine(event) elif action == "copyLine": self.OnLeftUpCopyLine(event) elif action == "zbulkLine" and \ len(self.polycoords) == 2: self.OnLeftUpBulkLine(event) elif action == "connectLine": self.OnLeftUpConnectLine(event) if len(self.digit.GetDisplay().GetSelected()) > 0: self.redrawAll = None def _onRightDown(self, event): # digitization tool (confirm action) action = self.toolbar.GetAction() if action in ("moveLine", "moveVertex") and \ hasattr(self, "moveInfo"): pFrom = self.moveInfo['begin'] pTo = self.Pixel2Cell(event.GetPositionTuple()) move = (pTo[0] - pFrom[0], pTo[1] - pFrom[1]) if action == "moveLine": # move line if self.digit.MoveSelectedLines(move) < 0: return elif action == "moveVertex": # move vertex fid = self.digit.MoveSelectedVertex(pFrom, move) if fid < 0: return self._geomAttrbUpdate([fid,]) del self.moveInfo def _onRightUp(self, event): """!Right mouse button released (confirm action) """ action = self.toolbar.GetAction() if action == "addLine" and \ self.toolbar.GetAction('type') in ["line", "boundary", "area"]: # -> add new line / boundary try: mapName = self.toolbar.GetLayer().GetName() except: mapName = None gcmd.GError(parent = self, message = _("No vector map selected for editing.")) if mapName: if self.toolbar.GetAction('type') == 'line': line = True else: line = False if len(self.polycoords) < 2: # ignore 'one-point' lines return nfeat, fids = self.digit.AddFeature(self.toolbar.GetAction('type'), self.polycoords) if nfeat < 0: return position = self.Cell2Pixel(self.polycoords[-1]) self.polycoords = [] self.UpdateMap(render = False) self.redrawAll = True self.Refresh() # add new record into atribute table if UserSettings.Get(group = 'vdigit', key = "addRecord", subkey = 'enabled') and \ (line is True or \ (not line and nfeat > 0)): posWindow = self.ClientToScreen((position[0] + self.dialogOffset, position[1] + self.dialogOffset)) # select attributes based on layer and category cats = { fids[0] : { UserSettings.Get(group = 'vdigit', key = "layer", subkey = 'value') : (UserSettings.Get(group = 'vdigit', key = "category", subkey = 'value'), ) }} addRecordDlg = dbm_dialogs.DisplayAttributesDialog(parent = self, map = mapName, cats = cats, pos = posWindow, action = "add", ignoreError = True) for fid in fids: self._geomAttrb(fid, addRecordDlg, 'length') # auto-placing centroid self._geomAttrb(fid, addRecordDlg, 'area') self._geomAttrb(fid, addRecordDlg, 'perimeter') if addRecordDlg.mapDBInfo and \ addRecordDlg.ShowModal() == wx.ID_OK: sqlfile = tempfile.NamedTemporaryFile(mode = "w") for sql in addRecordDlg.GetSQLString(): sqlfile.file.write(sql + ";\n") sqlfile.file.flush() gcmd.RunCommand('db.execute', parent = True, quiet = True, input = sqlfile.name) if addRecordDlg.mapDBInfo: self._updateATM() elif action == "deleteLine": # -> delete selected vector features if self.digit.DeleteSelectedLines() < 0: return self._updateATM() elif action == "splitLine": # split line if self.digit.SplitLine(self.Pixel2Cell(self.mouse['begin'])) < 0: return elif action == "addVertex": # add vertex fid = self.digit.AddVertex(self.Pixel2Cell(self.mouse['begin'])) if fid < 0: return elif action == "removeVertex": # remove vertex fid = self.digit.RemoveVertex(self.Pixel2Cell(self.mouse['begin'])) if fid < 0: return self._geomAttrbUpdate([fid,]) elif action in ("copyCats", "copyAttrs"): if action == 'copyCats': if self.digit.CopyCats(self.copyCatsList, self.copyCatsIds, copyAttrb = False) < 0: return else: if self.digit.CopyCats(self.copyCatsList, self.copyCatsIds, copyAttrb = True) < 0: return del self.copyCatsList del self.copyCatsIds self._updateATM() elif action == "editLine" and \ hasattr(self, "moveInfo"): line = self.digit.GetDisplay().GetSelected()[0] if self.digit.EditLine(line, self.polycoords) < 0: return del self.moveInfo elif action == "flipLine": if self.digit.FlipLine() < 0: return elif action == "mergeLine": if self.digit.MergeLine() < 0: return elif action == "breakLine": if self.digit.BreakLine() < 0: return elif action == "snapLine": if self.digit.SnapLine() < 0: return elif action == "connectLine": if len(self.digit.GetDisplay().GetSelected()) > 1: if self.digit.ConnectLine() < 0: return elif action == "copyLine": if self.digit.CopyLine(self.copyIds) < 0: return del self.copyIds if self.layerTmp: self.Map.DeleteLayer(self.layerTmp) self.UpdateMap(render = True, renderVector = False) del self.layerTmp elif action == "zbulkLine" and len(self.polycoords) == 2: pos1 = self.polycoords[0] pos2 = self.polycoords[1] selected = self.digit.GetDisplay().GetSelected() dlg = VDigitZBulkDialog(parent = self, title = _("Z bulk-labeling dialog"), nselected = len(selected)) if dlg.ShowModal() == wx.ID_OK: if self.digit.ZBulkLines(pos1, pos2, dlg.value.GetValue(), dlg.step.GetValue()) < 0: return self.UpdateMap(render = False) elif action == "typeConv": # -> feature type conversion # - point <-> centroid # - line <-> boundary if self.digit.TypeConvForSelectedLines() < 0: return if action != "addLine": # unselect and re-render self.digit.GetDisplay().SetSelected([]) self.polycoords = [] self.UpdateMap(render = False) def _onMouseMoving(self, event): self.mouse['end'] = event.GetPositionTuple()[:] Debug.msg (5, "BufferedWindow.OnMouseMoving(): coords=%f,%f" % \ (self.mouse['end'][0], self.mouse['end'][1])) action = self.toolbar.GetAction() if action == "addLine" and \ self.toolbar.GetAction('type') in ["line", "boundary", "area"]: if len(self.polycoords) > 0: self.MouseDraw(pdc = self.pdcTmp, begin = self.Cell2Pixel(self.polycoords[-1])) elif action in ["moveLine", "moveVertex", "editLine"] \ and hasattr(self, "moveInfo"): dx = self.mouse['end'][0] - self.mouse['begin'][0] dy = self.mouse['end'][1] - self.mouse['begin'][1] # draw lines on new position if action == "moveLine" and \ len(self.moveInfo['id']) > 0: # move line for id in self.moveInfo['id']: self.pdcTmp.TranslateId(id, dx, dy) elif action in ["moveVertex", "editLine"]: # move vertex -> # (vertex, left vertex, left line, # right vertex, right line) # do not draw static lines if action == "moveVertex" and \ len(self.moveInfo['id']) > 0: self.polycoords = [] self.pdcTmp.RemoveId(self.moveInfo['id'][0]) if self.moveInfo['id'][1] > 0: # previous vertex x, y = self.Pixel2Cell(self.pdcTmp.GetIdBounds(self.moveInfo['id'][1])[0:2]) self.pdcTmp.RemoveId(self.moveInfo['id'][1] + 1) self.polycoords.append((x, y)) self.polycoords.append(self.Pixel2Cell(self.mouse['end'])) if self.moveInfo['id'][2] > 0: # next vertex x, y = self.Pixel2Cell(self.pdcTmp.GetIdBounds(self.moveInfo['id'][2])[0:2]) self.pdcTmp.RemoveId(self.moveInfo['id'][2]-1) self.polycoords.append((x, y)) self.ClearLines(pdc = self.pdcTmp) self.DrawLines(pdc = self.pdcTmp) if action == "editLine": self.MouseDraw(pdc = self.pdcTmp, begin = self.Cell2Pixel(self.polycoords[-1])) self.Refresh() # TODO: use RefreshRect() self.mouse['begin'] = self.mouse['end'] elif action == "zbulkLine": if len(self.polycoords) == 1: # draw mouse moving self.MouseDraw(self.pdcTmp) def _zoom(self, event): tmp1 = self.mouse['end'] tmp2 = self.Cell2Pixel(self.moveInfo['begin']) dx = tmp1[0] - tmp2[0] dy = tmp1[1] - tmp2[1] self.moveInfo['beginDiff'] = (dx, dy) for id in self.moveInfo['id']: self.pdcTmp.RemoveId(id)