1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261 |
- """
- @package vdigit.mapwindow
- @brief Map display canvas for wxGUI vector digitizer
- Classes:
- - mapwindow::VDigitWindow
- (C) 2011-2013 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 <landa.martin gmail.com>
- """
- import wx
- import tempfile
- import six
- from grass.pydispatch.signal import Signal
- from dbmgr.dialogs import DisplayAttributesDialog
- from core.gcmd import RunCommand, GMessage, GError
- from core.debug import Debug
- from mapwin.buffered import BufferedMapWindow
- from core.settings import UserSettings
- from core.utils import ListOfCatsToRange
- from core.units import ConvertValue as UnitsConvertValue
- from core.globalvar import QUERYLAYER
- from vdigit.dialogs import (
- VDigitCategoryDialog,
- VDigitZBulkDialog,
- VDigitDuplicatesDialog,
- )
- from gui_core import gselect
- from gui_core.wrap import PseudoDC, NewId
- class VDigitWindow(BufferedMapWindow):
- """A Buffered window extended for vector digitizer."""
- def __init__(
- self,
- parent,
- giface,
- Map,
- properties,
- tree=None,
- id=wx.ID_ANY,
- lmgr=None,
- style=wx.NO_FULL_REPAINT_ON_RESIZE,
- **kwargs,
- ):
- BufferedMapWindow.__init__(
- self,
- parent=parent,
- giface=giface,
- Map=Map,
- properties=properties,
- style=style,
- **kwargs,
- )
- self.lmgr = lmgr
- self.tree = tree
- self.pdcVector = PseudoDC()
- self.toolbar = self.parent.GetToolbar("vdigit")
- self.digit = None # wxvdigit.IVDigit
- self._digitizingInfo = False # digitizing with info
- # Emitted when info about digitizing updated
- # Parameter text is a string with information
- # currently used only for coordinates of mouse cursor + segmnt and
- # total feature length
- self.digitizingInfo = Signal("VDigitWindow.digitizingInfo")
- # Emitted when some info about digitizing is or will be availbale
- self.digitizingInfoAvailable = Signal("VDigitWindow.digitizingInfo")
- # Emitted when some info about digitizing is or will be availbale
- # digitizingInfo signal is emitted only between digitizingInfoAvailable
- # and digitizingInfoUnavailable signals
- self.digitizingInfoUnavailable = Signal("VDigitWindow.digitizingInfo")
- self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
- self.mouseMoving.connect(self._mouseMovingToDigitizingInfo)
- def GetDisplay(self):
- if self.digit:
- return self.digit.GetDisplay()
- return None
- def GetDigit(self):
- """Get digit class"""
- return self.digit
- def SetToolbar(self, toolbar):
- """Set up related toolbar"""
- self.toolbar = toolbar
- def _mouseMovingToDigitizingInfo(self, x, y):
- e, n = x, y
- precision = int(
- UserSettings.Get(group="projection", key="format", subkey="precision")
- )
- if (
- self.toolbar.GetAction() != "addLine"
- or self.toolbar.GetAction("type") not in ("line", "boundary")
- or len(self.polycoords) == 0
- ):
- # we cannot provide info, so find out if it is something new
- if self._digitizingInfo:
- self._digitizingInfo = False
- self.digitizingInfoUnavailable.emit()
- return
- # else, we can provide info, so find out if it is first time
- if not self._digitizingInfo:
- self._digitizingInfo = True
- self.digitizingInfoAvailable.emit()
- # 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]
- text = "seg: %.*f; tot: %.*f" % (
- precision,
- distance_seg,
- precision,
- distance_tot,
- )
- self.digitizingInfo.emit(text=text)
- 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 attribute 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 = 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():
- addRecordDlg.ShowModal()
- addRecordDlg.Destroy()
- elif self.toolbar.GetAction("type") in ["line", "boundary", "area"]:
- # add new point to the line
- self.polycoords.append(self.Pixel2Cell(event.GetPosition()))
- 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.GetLayerInfo(item, key="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.GetLayerInfo(item, key="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 six.iteritems(self.digit.GetLineCats(fid)):
- table = dbInfo.GetTable(layer)
- for attrb, item in six.iteritems(vdigit["geomAttr"]):
- 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()
- RunCommand("db.execute", parent=True, quiet=True, input=sqlfile.name)
- def _updateATM(self):
- """Update open Attribute Table Manager
- .. todo::
- use AddDataRow() instead
- """
- if not self.lmgr:
- return
- # 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(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"] = 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.GetPosition()))
- 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,
- "VDigitWindow.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",
- "deleteArea",
- "moveLine",
- "splitLine",
- "addVertex",
- "removeVertex",
- "moveVertex",
- "copyCats",
- "flipLine",
- "mergeLine",
- "snapLine",
- "connectLine",
- "copyLine",
- "queryLine",
- "breakLine",
- "typeConv",
- ]:
- # various 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:
- GMessage(parent=self, message=_("No vector map selected for editing."))
- event.Skip()
- return
- action = self.toolbar.GetAction()
- if not action:
- GMessage(
- parent=self,
- message=_(
- "Nothing to do. " "Choose appropriate tool from digitizer toolbar."
- ),
- )
- event.Skip()
- return
- if action not in ("moveVertex", "addVertex", "removeVertex", "editLine"):
- # set pen
- self.pen = wx.Pen(
- colour=UserSettings.Get(
- group="vdigit", key="symbol", subkey=["newSegment", "color"]
- ),
- width=2,
- style=wx.SHORT_DASH,
- )
- self.polypen = wx.Pen(
- colour=UserSettings.Get(
- group="vdigit", key="symbol", subkey=["newLine", "color"]
- ),
- 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 = int(
- self.digit.GetDisplay().SelectLineByPoint(pos1)["line"] != -1
- )
- 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 = int(
- self.digit.GetDisplay().SelectLineByPoint(pos1)["line"] != -1
- )
- 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:
- nselected = int(
- self.digit.GetDisplay().SelectLineByPoint(pos1)["line"] != -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 == "deleteArea":
- nselected = int(
- self.digit.GetDisplay().SelectAreaByPoint(pos1)["area"] != -1
- )
- else:
- if action == "moveLine":
- drawSeg = True
- else:
- drawSeg = False
- nselected = self.digit.GetDisplay().SelectLinesByBox(
- bbox=(pos1, pos2), drawSeg=drawSeg
- )
- if nselected == 0:
- nselected = int(
- self.digit.GetDisplay().SelectLineByPoint(pos1)["line"]
- != -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", settings_type="internal"
- )
- == ""
- ):
- # no background map -> copy from current vector map layer
- nselected = self.digit.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",
- settings_type="internal",
- ),
- "cats=%s" % ListOfCatsToRange(self.copyIds),
- "-i",
- "color=%s" % colorStr,
- "fill_color=%s" % colorStr,
- "type=point,line,boundary,centroid",
- "width=2",
- ]
- if not self.layerTmp:
- self.layerTmp = self.Map.AddLayer(
- ltype="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 event.ControlDown():
- return
- 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",
- "deleteArea",
- "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.GetPosition())
- 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
- 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 attribute table
- if self._addRecord() 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 = 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.IsFound():
- addRecordDlg.ShowModal()
- addRecordDlg.Destroy()
- elif action == "deleteLine":
- # -> delete selected vector features
- if self.digit.DeleteSelectedLines() < 0:
- return
- self._updateATM()
- elif action == "deleteArea":
- # -> delete selected vector areas
- if self.digit.DeleteSelectedAreas() < 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.GetPosition()
- Debug.msg(
- 5,
- "VDigitWindow.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)
- def _addRecord(self):
- return UserSettings.Get(group="vdigit", key="addRecord", subkey="enabled")
|