def __init__(self, canvas): # some stuff we need from qgis QgsMapTool.__init__(self, canvas) self.canvas = canvas self.snapper = QgsSnappingUtils() # some stuff to control our state self.mCtrl = False self.started = False self.firstTimeOnSegment = True self.lastPointMustStay = False # some stuff to put our temp output self.lastPoint = None self.rb = None self.isPolygon = False # our own fancy cursor self.cursor = QCursor( QPixmap([ "16 16 3 1", " c None", ". c #00FF00", "+ c #FFFFFF", " ", " +.+ ", " ++.++ ", " +.....+ ", " +. .+ ", " +. . .+ ", " +. . .+ ", " ++. . .++", " ... ...+... ...", " ++. . .++", " +. . .+ ", " +. . .+ ", " ++. .+ ", " ++.....+ ", " ++.++ ", " +.+ " ]))
def __updateList(self): """ To update the line layers list that we can use for interpolation """ self.__layerList = [] legend = self.__iface.legendInterface() scale = self.__iface.mapCanvas().scale() for layer in self.__iface.mapCanvas().layers(): noUse, enabled, snappingType, unitType, tolerance, avoidIntersection = \ QgsProject.instance().snapSettingsForLayer(layer.id()) if isinstance(layer, QgsVectorLayer) and layer.hasGeometryType() \ and layer.geometryType() == QGis.Line: if not layer.hasScaleBasedVisibility( ) or layer.minimumScale() < scale <= layer.maximumScale(): if legend.isLayerVisible(layer) and enabled: layerConfig = QgsSnappingUtils.LayerConfig( layer, QgsPointLocator.Vertex, tolerance, unitType) self.__layerList.append(layerConfig) if self.__ownSettings and self.__ownSettings.linesLayer(): noUse, enabled, snappingType, unitType, tolerance, avoidIntersection = \ QgsProject.instance().snapSettingsForLayer(self.__ownSettings.linesLayer().id()) self.__linesConfig = QgsSnappingUtils.LayerConfig( self.__ownSettings.linesLayer(), QgsPointLocator.Vertex, tolerance, unitType)
def set_up_snapper(snap_layers, map_canvas, snap_tolerance=10): layer_configs = [] for layer, snap_type in snap_layers.iteritems(): # point_locator = QgsPointLocator(snap_layers[l]) layer_configs.append(QgsSnappingUtils.LayerConfig(layer, snap_type, snap_tolerance, QgsTolerance.MapUnits)) snapper = QgsSnappingUtils() snapper.setMapSettings(map_canvas.mapSettings()) snapper.setLayers(layer_configs) snapper.setSnapToMapMode(QgsSnappingUtils.SnapAdvanced) return snapper
def snap_to_segment(self, pos): """ Temporarily override snapping config and snap to vertices and edges of any editable vector layer, to allow selection of node for editing (if snapped to edge, it would offer creation of a new vertex there). """ map_point = self.toMapCoordinates(pos) tol = QgsTolerance.vertexSearchRadius(self.canvas.mapSettings()) snap_type = QgsPointLocator.Type(QgsPointLocator.Edge) snap_layers = [] for layer in self.canvas.layers(): if not isinstance(layer, QgsVectorLayer): continue snap_layers.append( QgsSnappingUtils.LayerConfig(layer, snap_type, tol, QgsTolerance.ProjectUnits)) snap_util = self.canvas.snappingUtils() old_layers = snap_util.layers() old_mode = snap_util.snapToMapMode() old_inter = snap_util.snapOnIntersections() snap_util.setLayers(snap_layers) snap_util.setSnapToMapMode(QgsSnappingUtils.SnapAdvanced) snap_util.setSnapOnIntersections(False) m = snap_util.snapToMap(map_point) snap_util.setLayers(old_layers) snap_util.setSnapToMapMode(old_mode) snap_util.setSnapOnIntersections(old_inter) return m
def snap_to_dimension_layer(self, pos): """ Temporarily override snapping config and snap to vertices and edges of any editable vector layer, to allow selection of node for editing (if snapped to edge, it would offer creation of a new vertex there). """ map_point = self.toMapCoordinates(pos) tol = QgsTolerance.vertexSearchRadius(self.canvas().mapSettings()) snap_type = QgsPointLocator.Type(QgsPointLocator.Edge) snap_layers = [ QgsSnappingUtils.LayerConfig(self.layer, snap_type, tol, QgsTolerance.ProjectUnits) ] snap_util = self.canvas().snappingUtils() old_layers = snap_util.layers() old_mode = snap_util.snapToMapMode() old_inter = snap_util.snapOnIntersections() snap_util.setLayers(snap_layers) snap_util.setSnapToMapMode(QgsSnappingUtils.SnapAdvanced) snap_util.setSnapOnIntersections(False) m = snap_util.snapToMap(map_point) snap_util.setLayers(old_layers) snap_util.setSnapToMapMode(old_mode) snap_util.setSnapOnIntersections(old_inter) f = QgsFeature() if m.featureId() is not None: self.layer.getFeatures(QgsFeatureRequest().setFilterFid( m.featureId())).nextFeature(f) return f
def canvasMoveEvent(self, event): """ When the mouse is moved :param event: mouse event """ if not self.__isEditing: laySettings = QgsSnappingUtils.LayerConfig(self.__layer, QgsPointLocator.All, 10, QgsTolerance.Pixels) f_l = Finder.findClosestFeatureAt(event.mapPoint(), self.canvas(), [laySettings]) if f_l is not None: self.__lastFeatureId = f_l[0].id() self.__layer.setSelectedFeatures([f_l[0].id()]) self.__rubber.reset() geom = f_l[0].geometry() index = geom.closestVertex(event.mapPoint())[1] line_v2, curved = GeometryV2.asLineV2(geom, self.__iface) num_p = line_v2.numPoints() if num_p > 2 and (index == 0 or index == (num_p - 1)): self.__rubber.setIcon(4) self.__rubber.setToGeometry( QgsGeometry(line_v2.pointN(index)), None) else: self.__layer.removeSelection() self.__rubber.reset() self.__lastFeatureId = None
def canvasReleaseEvent(self, event): """ When the mouse is clicked :param event: mouse event """ types = [QgsWKBTypes.PointZ, QgsWKBTypes.LineStringZ, QgsWKBTypes.CircularStringZ, QgsWKBTypes.CompoundCurveZ, QgsWKBTypes.CurvePolygonZ, QgsWKBTypes.PolygonZ] display = "" for layer in self.canvas().layers(): if layer.type() == QgsMapLayer.VectorLayer and QGis.fromOldWkbType(layer.wkbType()) in types: layerConfig = QgsSnappingUtils.LayerConfig(layer, QgsPointLocator.Vertex, 10, QgsTolerance.Pixels) features = Finder.findFeaturesAt(event.mapPoint(), layerConfig, self) if len(features) > 0: display += layer.name() + " : \n" for f in features: if f.geometry().type() == QGis.Point: alt = f.geometry().geometry().z() elif f.geometry().type() == QGis.Line: closest = f.geometry().closestVertex(event.mapPoint()) alt = f.geometry().geometry().zAt(closest[1]) elif f.geometry().type() == QGis.Polygon: self.__iface.messageBar().pushMessage( QCoreApplication.translate("VDLTools", "Polygon not yet implemented"), level=QgsMessageBar.WARNING) continue else: continue display += " " + str(f.id()) + " | " + str(alt) + " m.\n" if display != "": QMessageBox.information(None, QCoreApplication.translate("VDLTools", "Id | Elevation"), display)
def snap(mapPoint, mapCanvas, snapIntersections): snap_layers = [] for layer in mapCanvas.layers(): types = [0, 1, 2] if isinstance(layer, QgsVectorLayer) and layer.geometryType() in types: noUse, enabled, snappingType, unitType, tolerance, avoidIntersection = QgsProject.instance( ).snapSettingsForLayer(layer.id()) if isinstance(layer, QgsVectorLayer) and enabled: if snappingType == QgsSnapper.SnapToVertex: snap_type = QgsPointLocator.Vertex elif snappingType == QgsSnapper.SnapToSegment: snap_type = QgsPointLocator.Edge else: snap_type = QgsPointLocator.All snap_layers.append( QgsSnappingUtils.LayerConfig(layer, snap_type, tolerance, unitType)) snap_util = mapCanvas.snappingUtils() old_layers = snap_util.layers() old_mode = snap_util.snapToMapMode() old_inter = snap_util.snapOnIntersections() snap_util.setLayers(snap_layers) snap_util.setSnapToMapMode(QgsSnappingUtils.SnapAdvanced) snap_util.setSnapOnIntersections(snapIntersections) match = snap_util.snapToMap(mapPoint) snap_util.setLayers(old_layers) snap_util.setSnapToMapMode(old_mode) snap_util.setSnapOnIntersections(old_inter) return match
def __lineVertices(self): availableLayers = self.__getPointLayers() pointLayers = [] self.__points = [] self.__selectedStarts = [] num = 0 num_lines = len(self.__selectedIds) for iden in self.__selectedIds: self.__selectedStarts.append(max(0, len(self.__points) - 1)) direction = self.__selectedDirections[num] selected = None for f in self.__lineLayer.selectedFeatures(): if f.id() == iden: selected = f break if selected is None: self.__iface.messageBar().pushMessage( QCoreApplication.translate("VDLTools", "Error"), QCoreApplication.translate("VDLTools", "error on selected"), level=QgsMessageBar.CRITICAL) continue line_v2, curved = GeometryV2.asLineV2(selected.geometry()) if direction: rg = xrange(line_v2.numPoints()) else: rg = xrange(line_v2.numPoints() - 1, -1, -1) for i in rg: pt_v2 = line_v2.pointN(i) x = pt_v2.x() y = pt_v2.y() doublon = False for item in self.__points: if item['x'] == x and item['y'] == y: item['z'][num] = pt_v2.z() doublon = True break if not doublon: z = [] for j in xrange(num_lines): if j == num: z.append(pt_v2.z()) else: z.append(None) self.__points.append({'x': x, 'y': y, 'z': z}) for layer in availableLayers: laySettings = QgsSnappingUtils.LayerConfig( layer, QgsPointLocator.Vertex, 0.03, QgsTolerance.LayerUnits) point = Finder.findClosestFeatureAt( self.toMapCoordinates(layer, QgsPoint(x, y)), laySettings, self) if point is not None: if layer not in pointLayers: pointLayers.append(layer) num += 1 return pointLayers
def setSnapLayers(self, snapper, layers): snap_layers = list() for layer in layers: if layer: snap_layer = QgsSnappingUtils.LayerConfig( layer, QgsPointLocator.All, 16, QgsTolerance.Pixels) snap_layers.append(snap_layer) snapper.setLayers(snap_layers) snapper.setSnapToMapMode(QgsSnappingUtils.SnapAdvanced)
def __updateList(self): """ To update the line layers list that we can use for interpolation """ self.__layerList = [] for layer in self.canvas().layers(): if layer.type() == QgsMapLayer.VectorLayer and layer.hasGeometryType() \ and layer.geometryType() == QGis.Line: self.__layerList.append( QgsSnappingUtils.LayerConfig(layer, QgsPointLocator.All, 10, QgsTolerance.Pixels))
def __updateList(self): """ To update the snapping options of the layer """ noUse, enabled, snappingType, unitType, tolerance, avoidIntersection = \ QgsProject.instance().snapSettingsForLayer(self.__layer.id()) self.__layerConfig = QgsSnappingUtils.LayerConfig(self.__layer, QgsPointLocator.Vertex, tolerance, unitType) if not enabled or tolerance == 0: self.__iface.messageBar().pushMessage( QCoreApplication.translate("VDLTools", "Error"), QCoreApplication.translate("VDLTools", "This layer has no snapping options"), level=QgsMessageBar.CRITICAL)
def snap_to_layer(self, layer, point_locator=QgsPointLocator.All, set_settings=False): """ Set snapping to @layer """ if layer is None: return QgsSnappingUtils.LayerConfig(layer, point_locator, 15, QgsTolerance.Pixels) if set_settings: layer_settings = self.snapping_config.individualLayerSettings(layer) layer_settings.setEnabled(True) self.snapping_config.setIndividualLayerSettings(layer, layer_settings) return layer_settings
def canvasMoveEvent(self, event): """ When the mouse is moved :param event: mouse event """ if not self.__isChoosed: if self.__lineLayer is not None: noUse, enabled, snappingType, unitType, tolerance, avoidIntersection = \ QgsProject.instance().snapSettingsForLayer(self.__lineLayer.id()) layerConfig = QgsSnappingUtils.LayerConfig( self.__lineLayer, QgsPointLocator.Vertex, tolerance, unitType) f = Finder.findClosestFeatureAt(event.mapPoint(), layerConfig, self) if not self.__inSelection: if f is not None and self.__lastFeatureId != f.id(): self.__lastFeature = f self.__lastFeatureId = f.id() self.__lineLayer.setSelectedFeatures([f.id()]) if f is None: self.__lineLayer.removeSelection() self.__lastFeatureId = None self.__selectedIds = None self.__selectedDirections = None self.__startVertex = None self.__endVertex = None else: if f is not None and (not self.__selectedIds or f.id() not in self.__selectedIds): line = f.geometry().asPolyline() if self.contains(line, self.__endVertex) > -1: self.__lastFeature = f self.__lastFeatureId = f.id() features = self.__selectedIds + [f.id()] self.__lineLayer.setSelectedFeatures(features) elif self.contains(line, self.__startVertex) > -1: self.__lastFeature = f self.__lastFeatureId = f.id() features = self.__selectedIds + [f.id()] self.__lineLayer.setSelectedFeatures(features) else: self.__lineLayer.setSelectedFeatures( self.__selectedIds) self.__lastFeatureId = None self.__lastFeature = None if f is None and self.__selectedIds is not None: self.__lineLayer.setSelectedFeatures( self.__selectedIds) self.__lastFeatureId = None self.__lastFeature = None
def test_signalConnection(self): # remove all layers QgsProject.instance().removeAllMapLayers() # set dependencies and add back layers self.pointsLayer = QgsVectorLayer("dbname='%s' table=\"node\" (geom) sql=" % self.fn, "points", "spatialite") assert (self.pointsLayer.isValid()) self.linesLayer = QgsVectorLayer("dbname='%s' table=\"section\" (geom) sql=" % self.fn, "lines", "spatialite") assert (self.linesLayer.isValid()) self.pointsLayer2 = QgsVectorLayer("dbname='%s' table=\"node2\" (geom) sql=" % self.fn, "_points2", "spatialite") assert (self.pointsLayer2.isValid()) self.pointsLayer.setDependencies([QgsMapLayerDependency(self.linesLayer.id())]) self.pointsLayer2.setDependencies([QgsMapLayerDependency(self.pointsLayer.id())]) # this should update connections between layers QgsProject.instance().addMapLayers([self.pointsLayer]) QgsProject.instance().addMapLayers([self.linesLayer]) QgsProject.instance().addMapLayers([self.pointsLayer2]) ms = QgsMapSettings() ms.setOutputSize(QSize(100, 100)) ms.setExtent(QgsRectangle(0, 0, 1, 1)) self.assertTrue(ms.hasValidSettings()) u = QgsSnappingUtils() u.setMapSettings(ms) cfg = u.config() cfg.setEnabled(True) cfg.setMode(QgsSnappingConfig.AdvancedConfiguration) cfg.setIndividualLayerSettings(self.pointsLayer, QgsSnappingConfig.IndividualLayerSettings(True, QgsSnappingConfig.Vertex, 20, QgsTolerance.Pixels)) cfg.setIndividualLayerSettings(self.pointsLayer2, QgsSnappingConfig.IndividualLayerSettings(True, QgsSnappingConfig.Vertex, 20, QgsTolerance.Pixels)) u.setConfig(cfg) # add another line f = QgsFeature(self.linesLayer.fields()) f.setId(4) geom = QgsGeometry.fromWkt("LINESTRING(0.5 0.2,0.6 0)") f.setGeometry(geom) self.linesLayer.startEditing() self.linesLayer.addFeatures([f]) self.linesLayer.commitChanges() # check the second snapped point is OK m = u.snapToMap(QPoint(75, 100 - 0)) self.assertTrue(m.isValid()) self.assertTrue(m.hasVertex()) self.assertEqual(m.point(), QgsPointXY(0.8, 0.0)) self.pointsLayer.setDependencies([]) self.pointsLayer2.setDependencies([])
def test_signalConnection(self): # remove all layers QgsProject.instance().removeAllMapLayers() # set dependencies and add back layers self.pointsLayer = QgsVectorLayer("dbname='%s' table=\"node\" (geom) sql=" % self.fn, "points", "spatialite") assert self.pointsLayer.isValid() self.linesLayer = QgsVectorLayer("dbname='%s' table=\"section\" (geom) sql=" % self.fn, "lines", "spatialite") assert self.linesLayer.isValid() self.pointsLayer2 = QgsVectorLayer( "dbname='%s' table=\"node2\" (geom) sql=" % self.fn, "_points2", "spatialite" ) assert self.pointsLayer2.isValid() self.pointsLayer.setDependencies([QgsMapLayerDependency(self.linesLayer.id())]) self.pointsLayer2.setDependencies([QgsMapLayerDependency(self.pointsLayer.id())]) # this should update connections between layers QgsProject.instance().addMapLayers([self.pointsLayer]) QgsProject.instance().addMapLayers([self.linesLayer]) QgsProject.instance().addMapLayers([self.pointsLayer2]) ms = QgsMapSettings() ms.setOutputSize(QSize(100, 100)) ms.setExtent(QgsRectangle(0, 0, 1, 1)) self.assertTrue(ms.hasValidSettings()) u = QgsSnappingUtils() u.setMapSettings(ms) cfg = u.config() cfg.setEnabled(True) cfg.setMode(QgsSnappingConfig.AdvancedConfiguration) cfg.setIndividualLayerSettings( self.pointsLayer, QgsSnappingConfig.IndividualLayerSettings(True, QgsSnappingConfig.Vertex, 20, QgsTolerance.Pixels), ) cfg.setIndividualLayerSettings( self.pointsLayer2, QgsSnappingConfig.IndividualLayerSettings(True, QgsSnappingConfig.Vertex, 20, QgsTolerance.Pixels), ) u.setConfig(cfg) # add another line f = QgsFeature(self.linesLayer.fields()) f.setFeatureId(4) geom = QgsGeometry.fromWkt("LINESTRING(0.5 0.2,0.6 0)") f.setGeometry(geom) self.linesLayer.startEditing() self.linesLayer.addFeatures([f]) self.linesLayer.commitChanges() # check the second snapped point is ok m = u.snapToMap(QPoint(75, 100 - 0)) self.assertTrue(m.isValid()) self.assertTrue(m.hasVertex()) self.assertEqual(m.point(), QgsPoint(0.8, 0.0)) self.pointsLayer.setDependencies([]) self.pointsLayer2.setDependencies([])
def canvasMoveEvent(self, event): """ When the mouse is moved :param event: mouse event """ if not self.__isChoosed: if self.ownSettings.drawdownLayer is not None: laySettings = QgsSnappingUtils.LayerConfig( self.ownSettings.drawdownLayer, QgsPointLocator.All, 10, QgsTolerance.Pixels) feat = Finder.findClosestFeatureAt(event.mapPoint(), laySettings, self) if not self.__inSelection: if feat is not None and self.__lastFeatureId != feat.id(): self.__lastFeature = feat self.__lastFeatureId = feat.id() self.ownSettings.drawdownLayer.setSelectedFeatures( [feat.id()]) if feat is None: self.__cancel() else: if feat is not None and (self.__selectedIds is None or feat.id() not in self.__selectedIds): line = feat.geometry().asPolyline() if self.__contains(line, self.__endVertex) > -1: self.__lastFeature = feat self.__lastFeatureId = feat.id() features = self.__selectedIds + [feat.id()] self.ownSettings.drawdownLayer.setSelectedFeatures( features) elif self.__contains(line, self.__startVertex) > -1: self.__lastFeature = feat self.__lastFeatureId = feat.id() features = self.__selectedIds + [feat.id()] self.ownSettings.drawdownLayer.setSelectedFeatures( features) else: self.ownSettings.drawdownLayer.setSelectedFeatures( self.__selectedIds) self.__lastFeatureId = None self.__lastFeature = None if feat is None: if self.__selectedIds is not None: self.ownSettings.drawdownLayer.setSelectedFeatures( self.__selectedIds) self.__lastFeatureId = None self.__lastFeature = None
def snapCurvedIntersections(mapPoint, mapCanvas, mapTool, checkForAFeature=False, featureId=None): snap_layers = [] for layer in mapCanvas.layers(): types = [0, 1, 2] if isinstance(layer, QgsVectorLayer) and layer.geometryType() in types: noUse, enabled, snappingType, unitType, tolerance, avoidIntersection = QgsProject.instance( ).snapSettingsForLayer(layer.id()) if isinstance(layer, QgsVectorLayer) and enabled: if snappingType == QgsSnapper.SnapToVertex: snap_type = QgsPointLocator.Vertex elif snappingType == QgsSnapper.SnapToSegment: snap_type = QgsPointLocator.Edge else: snap_type = QgsPointLocator.All snap_layers.append( QgsSnappingUtils.LayerConfig(layer, snap_type, tolerance, unitType)) features = Finder.findFeaturesLayersAt(mapPoint, snap_layers, mapTool) if len(features) > 1: if len(features) > 2: one = [-1, 9999999] two = [-1, 9999999] for i in xrange(len(features)): d = Finder.sqrDistForPoints( mapPoint, features[i].geometry().asPoint()) if d > one[1]: two = one one[0] = i one[1] = d elif d > two[1]: two[0] = i two[1] = d feat1 = features[one[0]] feat2 = features[two[0]] else: feat1 = features[0] feat2 = features[1] if not checkForAFeature or feat1.id() == featureId or feat2.id( ) == featureId: return Finder.intersect(feat1.geometry(), feat2.geometry(), mapPoint) else: return None else: return None
def qgis_manage_snapping_layer(layername, snapping_type=0, tolerance=15.0): """ Manage snapping of @layername """ layer = qgis_get_layer_by_tablename(layername) if not layer: return if snapping_type == 0: snapping_type = QgsPointLocator.Vertex elif snapping_type == 1: snapping_type = QgsPointLocator.Edge elif snapping_type == 2: snapping_type = QgsPointLocator.All QgsSnappingUtils.LayerConfig(layer, snapping_type, tolerance, QgsTolerance.Pixels)
def canvasMoveEvent(self, event): """ When the mouse is moved :param event: mouse event """ if not self.__isEditing: laySettings = QgsSnappingUtils.LayerConfig(self.__layer, QgsPointLocator.All, 10, QgsTolerance.Pixels) f_l = Finder.findClosestFeatureAt(event.mapPoint(), self.canvas(), [laySettings]) if f_l is not None and self.__lastFeatureId != f_l[0].id(): self.__lastFeatureId = f_l[0].id() self.__layer.setSelectedFeatures([f_l[0].id()]) if f_l is None: self.__layer.removeSelection() self.__lastFeatureId = None
def __updateProfile(self): """ To update the profile in the dock after adjustments """ self.__lineVertices() for p in range(len(self.__points)): pt = self.__points[p] x = pt['x'] y = pt['y'] z = pt['z'] for layer in self.__layers: laySettings = QgsSnappingUtils.LayerConfig( layer, QgsPointLocator.All, self.SEARCH_TOLERANCE, QgsTolerance.LayerUnits) fs = Finder.findFeaturesAt(QgsPoint(x, y), laySettings, self) if len(fs) == 0: z.append(None) else: zz = [] for f in fs: if layer == self.ownSettings.drawdownLayer: if f.id() not in self.__selectedIds: closest = f.geometry().closestVertex( QgsPoint(x, y)) if closest[4] < self.SEARCH_TOLERANCE: line, curved = GeometryV2.asLineV2( f.geometry(), self.__iface) zp = line.zAt(closest[1]) if zp is None or zp != zp: zz.append(0) else: zz.append(zp) else: zp = GeometryV2.asPointV2(f.geometry(), self.__iface).z() if zp is None or zp != zp: zp = 0 zz.append(zp) if len(zz) == 0: z.append(None) elif len(zz) == 1: z.append(zz[0]) else: z.append(zz) self.__calculateProfile()
def __layOk(self): self.__features = [] for points in self.__points: feat = [] x = points['x'] y = points['y'] z = points['z'] for layer in self.__layers: laySettings = QgsSnappingUtils.LayerConfig( layer, QgsPointLocator.Vertex, 0.03, QgsTolerance.LayerUnits) point = Finder.findClosestFeatureAt( self.toMapCoordinates(layer, QgsPoint(x, y)), laySettings, self) feat.append(point) if point is None: z.append(None) else: point_v2 = GeometryV2.asPointV2(point.geometry()) zp = point_v2.z() if zp is None or zp != zp: z.append(0) else: z.append(zp) self.__features.append(feat) # points = [] # for key, p in pointz.items(): # if p is not None: # pt = p[0].geometry().asPoint() # i = 0 # for l in layers: # if l == p[1]: # break # i += 1 # attName = attributes[i] # z = p[0].attribute(attName) # points.append({'x': pt.x(), 'y': pt.y(), 'z': z}) names = [self.__lineLayer.name()] for layer in self.__layers: names.append(layer.name()) self.__calculateProfile(names) self.__isChoosed = 0
def getLayersSettings(mapCanvas, types, snapType=None): """ To get the snapping config from different layers :param mapCanvas: the used QgsMapCanvas :param types: geometry types in use :param snapType: snapping type :return: list of layers config """ snap_layers = [] for layer in mapCanvas.layers(): if layer.type() == QgsMapLayer.VectorLayer and layer.geometryType( ) in types: snap_util = mapCanvas.snappingUtils() mode = snap_util.snapToMapMode() if mode == QgsSnappingUtils.SnapCurrentLayer and layer.id( ) != mapCanvas.currentLayer().id(): continue if mode == QgsSnappingUtils.SnapAllLayers: snap_index, tolerance, unitType = snap_util.defaultSettings( ) snap_type = QgsPointLocator.Type(snap_index) else: noUse, enabled, snappingType, unitType, tolerance, avoidIntersection = \ QgsProject.instance().snapSettingsForLayer(layer.id()) if layer.type() == QgsMapLayer.VectorLayer and enabled: if snapType is None: if snappingType == QgsSnapper.SnapToVertex: snap_type = QgsPointLocator.Vertex elif snappingType == QgsSnapper.SnapToSegment: snap_type = QgsPointLocator.Edge elif snappingType == QgsSnapper.SnapToVertexAndSegment: snap_type = QgsPointLocator.Edge and QgsPointLocator.Vertex else: snap_type = QgsPointLocator.All else: snap_type = snapType else: continue snap_layers.append( QgsSnappingUtils.LayerConfig(layer, snap_type, tolerance, unitType)) return snap_layers
def processAlgorithm(self, progress): points_layer = self.getParameterValue(self.POINTS) points_layer = getObjectFromUri(points_layer) add_attribute = self.getParameterValue(self.SNAPPED) fields = points_layer.dataProvider().fields() if add_attribute: fields.append(QgsField('snapped', QVariant.String)) writer = self.getOutputFromName(self.OUTPUT).getVectorWriter( fields, QGis.WKBPoint, points_layer.crs()) snapper = QgsSnappingUtils() snapping_type = QgsSnapper.SnapToSegment tolerance = 1 unit = QgsTolerance.LayerUnits layer_config = QgsSnappingUtils.LayerConfig(layer_edge, snapping_type, tolerance, unit) snapper.setLayers([layer_config]) snap_mode = QgsSnappingUtils.SnapAdvanced snapper.setSnapToMapMode(snap_mode) for feature in vector.features(points_layer): f = QgsFeature() attributes = feature.attributes() result = snapper.snapToMap(feature.geometry().asPoint()) if result.type() == 2: f.setGeometry(QgsGeometry.fromPoint(result.point())) if add_attribute: attributes.append('True') else: f.setGeometry(feature.geometry()) if add_attribute: attributes.append('False') f.setAttributes(attributes) writer.addFeature(f) del writer
# coding: utf-8 from qgis.core import QgsSnappingUtils from qgis.gui import QgsMapCanvasSnappingUtils from qgis.utils import iface canvas = iface.mapCanvas() snapping_utils = QgsSnappingUtils() print(snapping_utils.snapToMapMode()) # Change the mode through the GUI print(snapping_utils.snapToMapMode()) # Retrieve information from the project snapping_utils.readConfigFromProject() # Alternate way to above code snapping_utils = canvas.snappingUtils() # TODO: cast QgsMapCanvasSnappingUtils snapping_utils.defaultSettings() # Find the mode in a readable way print([ i for i in ['SnapCurrentLayer', 'SnapAdvanced', 'SnapAllLayers'] if snapping_utils.snapToMapMode() == getattr(QgsSnappingUtils, i) ][0]) print(snapping_utils.layers()) print(snapping_utils.defaultSettings() ) # where values are type, tolerance and unit map_canvas_snapping_utils = QgsMapCanvasSnappingUtils(canvas)
def test_resetSnappingIndex(self): self.pointsLayer.setDependencies([]) self.linesLayer.setDependencies([]) self.pointsLayer2.setDependencies([]) ms = QgsMapSettings() ms.setOutputSize(QSize(100, 100)) ms.setExtent(QgsRectangle(0, 0, 1, 1)) self.assertTrue(ms.hasValidSettings()) u = QgsSnappingUtils() u.setMapSettings(ms) cfg = u.config() cfg.setMode(QgsSnappingConfig.AdvancedConfiguration) cfg.setIndividualLayerSettings(self.pointsLayer, QgsSnappingConfig.IndividualLayerSettings(True, QgsSnappingConfig.Vertex, 20, QgsTolerance.Pixels)) u.setConfig(cfg) m = u.snapToMap(QPoint(95, 100)) self.assertTrue(m.isValid()) self.assertTrue(m.hasVertex()) self.assertEqual(m.point(), QgsPoint(1, 0)) f = QgsFeature(self.linesLayer.fields()) f.setFeatureId(1) geom = QgsGeometry.fromWkt("LINESTRING(0 0,1 1)") f.setGeometry(geom) self.linesLayer.startEditing() self.linesLayer.addFeatures([f]) self.linesLayer.commitChanges() l1 = len([f for f in self.pointsLayer.getFeatures()]) self.assertEqual(l1, 4) m = u.snapToMap(QPoint(95, 0)) # snapping not updated self.pointsLayer.setDependencies([]) self.assertEqual(m.isValid(), False) # set layer dependencies self.pointsLayer.setDependencies([QgsMapLayerDependency(self.linesLayer.id())]) # add another line f = QgsFeature(self.linesLayer.fields()) f.setFeatureId(2) geom = QgsGeometry.fromWkt("LINESTRING(0 0,0.5 0.5)") f.setGeometry(geom) self.linesLayer.startEditing() self.linesLayer.addFeatures([f]) self.linesLayer.commitChanges() # check the snapped point is ok m = u.snapToMap(QPoint(45, 50)) self.assertTrue(m.isValid()) self.assertTrue(m.hasVertex()) self.assertEqual(m.point(), QgsPoint(0.5, 0.5)) self.pointsLayer.setDependencies([]) # test chained layer dependencies A -> B -> C cfg.setIndividualLayerSettings(self.pointsLayer2, QgsSnappingConfig.IndividualLayerSettings(True, QgsSnappingConfig.Vertex, 20, QgsTolerance.Pixels)) u.setConfig(cfg) self.pointsLayer.setDependencies([QgsMapLayerDependency(self.linesLayer.id())]) self.pointsLayer2.setDependencies([QgsMapLayerDependency(self.pointsLayer.id())]) # add another line f = QgsFeature(self.linesLayer.fields()) f.setFeatureId(3) geom = QgsGeometry.fromWkt("LINESTRING(0 0.2,0.5 0.8)") f.setGeometry(geom) self.linesLayer.startEditing() self.linesLayer.addFeatures([f]) self.linesLayer.commitChanges() # check the second snapped point is ok m = u.snapToMap(QPoint(75, 100 - 80)) self.assertTrue(m.isValid()) self.assertTrue(m.hasVertex()) self.assertEqual(m.point(), QgsPoint(0.7, 0.8)) self.pointsLayer.setDependencies([]) self.pointsLayer2.setDependencies([])
def test_resetSnappingIndex(self): self.pointsLayer.setDependencies([]) self.linesLayer.setDependencies([]) self.pointsLayer2.setDependencies([]) ms = QgsMapSettings() ms.setOutputSize(QSize(100, 100)) ms.setExtent(QgsRectangle(0, 0, 1, 1)) self.assertTrue(ms.hasValidSettings()) u = QgsSnappingUtils() u.setMapSettings(ms) cfg = u.config() cfg.setEnabled(True) cfg.setMode(QgsSnappingConfig.AdvancedConfiguration) cfg.setIndividualLayerSettings(self.pointsLayer, QgsSnappingConfig.IndividualLayerSettings(True, QgsSnappingConfig.Vertex, 20, QgsTolerance.Pixels)) u.setConfig(cfg) m = u.snapToMap(QPoint(95, 100)) self.assertTrue(m.isValid()) self.assertTrue(m.hasVertex()) self.assertEqual(m.point(), QgsPointXY(1, 0)) f = QgsFeature(self.linesLayer.fields()) f.setId(1) geom = QgsGeometry.fromWkt("LINESTRING(0 0,1 1)") f.setGeometry(geom) self.linesLayer.startEditing() self.linesLayer.addFeatures([f]) self.linesLayer.commitChanges() l1 = len([f for f in self.pointsLayer.getFeatures()]) self.assertEqual(l1, 4) m = u.snapToMap(QPoint(95, 0)) # snapping not updated self.pointsLayer.setDependencies([]) self.assertEqual(m.isValid(), False) # set layer dependencies self.pointsLayer.setDependencies([QgsMapLayerDependency(self.linesLayer.id())]) # add another line f = QgsFeature(self.linesLayer.fields()) f.setId(2) geom = QgsGeometry.fromWkt("LINESTRING(0 0,0.5 0.5)") f.setGeometry(geom) self.linesLayer.startEditing() self.linesLayer.addFeatures([f]) self.linesLayer.commitChanges() # check the snapped point is OK m = u.snapToMap(QPoint(45, 50)) self.assertTrue(m.isValid()) self.assertTrue(m.hasVertex()) self.assertEqual(m.point(), QgsPointXY(0.5, 0.5)) self.pointsLayer.setDependencies([]) # test chained layer dependencies A -> B -> C cfg.setIndividualLayerSettings(self.pointsLayer2, QgsSnappingConfig.IndividualLayerSettings(True, QgsSnappingConfig.Vertex, 20, QgsTolerance.Pixels)) u.setConfig(cfg) self.pointsLayer.setDependencies([QgsMapLayerDependency(self.linesLayer.id())]) self.pointsLayer2.setDependencies([QgsMapLayerDependency(self.pointsLayer.id())]) # add another line f = QgsFeature(self.linesLayer.fields()) f.setId(3) geom = QgsGeometry.fromWkt("LINESTRING(0 0.2,0.5 0.8)") f.setGeometry(geom) self.linesLayer.startEditing() self.linesLayer.addFeatures([f]) self.linesLayer.commitChanges() # check the second snapped point is OK m = u.snapToMap(QPoint(75, 100 - 80)) self.assertTrue(m.isValid()) self.assertTrue(m.hasVertex()) self.assertEqual(m.point(), QgsPointXY(0.7, 0.8)) self.pointsLayer.setDependencies([]) self.pointsLayer2.setDependencies([])
# coding: utf-8 from qgis.core import QgsSnappingUtils from qgis.gui import QgsMapCanvasSnappingUtils from qgis.utils import iface canvas = iface.mapCanvas() snapping_utils = QgsSnappingUtils() print(snapping_utils.snapToMapMode()) # Change the mode through the GUI print(snapping_utils.snapToMapMode()) # Retrieve information from the project snapping_utils.readConfigFromProject() # Alternate way to above code snapping_utils = canvas.snappingUtils() # TODO: cast QgsMapCanvasSnappingUtils snapping_utils.defaultSettings() # Find the mode in a readable way print([ i for i in ['SnapCurrentLayer', 'SnapAdvanced', 'SnapAllLayers'] if snapping_utils.snapToMapMode() == getattr(QgsSnappingUtils, i) ][0]) print(snapping_utils.layers()) print(snapping_utils.defaultSettings()) # where values are type, tolerance and unit map_canvas_snapping_utils = QgsMapCanvasSnappingUtils(canvas)
class VertexTracerTool(QgsMapTool): traceFound = pyqtSignal(QgsGeometry) def __init__(self, canvas): # some stuff we need from qgis QgsMapTool.__init__(self, canvas) self.canvas = canvas self.snapper = QgsSnappingUtils() # some stuff to control our state self.mCtrl = False self.started = False self.firstTimeOnSegment = True self.lastPointMustStay = False # some stuff to put our temp output self.lastPoint = None self.rb = None self.isPolygon = False # our own fancy cursor self.cursor = QCursor( QPixmap([ "16 16 3 1", " c None", ". c #00FF00", "+ c #FFFFFF", " ", " +.+ ", " ++.++ ", " +.....+ ", " +. .+ ", " +. . .+ ", " +. . .+ ", " ++. . .++", " ... ...+... ...", " ++. . .++", " +. . .+ ", " +. . .+ ", " ++. .+ ", " ++.....+ ", " ++.++ ", " +.+ " ])) # we need to know, if ctrl-key is pressed def keyPressEvent(self, event): if event.key() == Qt.Key_Control: self.mCtrl = True # and also if ctrl-key is released def keyReleaseEvent(self, event): if event.key() == Qt.Key_Control: self.mCtrl = False # remove the last added point when the delete key is pressed if event.key() == Qt.Key_Backspace: self.rb.removeLastPoint() def canvasPressEvent(self, event): # on left click, we add a point if event.button() == 1: layer = self.canvas.currentLayer() # if it is the start of a new trace, set the rubberband up if not self.started: if layer.geometryType() == 1: self.isPolygon = False if layer.geometryType() == 2: self.isPolygon = True self.rb = QgsRubberBand(self.canvas, layer.geometryType()) self.rb.setColor(QColor(255, 0, 0)) # declare, that are we going to work, now! self.started = True if layer is not None: x = event.pos().x() y = event.pos().y() selPoint = QPoint(x, y) # try to get something snapped (retval, result) = self.snapper.snapToBackgroundLayers(selPoint) # the point we want to have, is either from snapping result if result != []: point = result[0].snappedVertex # if we snapped something, it's either a vertex if result[0].snappedVertexNr != -1: self.firstTimeOnSegment = True # or a point on a segment, so we have to declare, that a point on segment is found else: self.firstTimeOnSegment = False # or its some point from out in the wild else: point = QgsMapToPixel.toMapCoordinates( self.canvas.getCoordinateTransform(), x, y) self.firstTimeOnSegment = True # bring the rubberband to the cursor i.e. the clicked point self.rb.movePoint(point) # and set a new point to go on with self.appendPoint(point) # try to remember that this point was on purpose i.e. clicked by the user self.lastPointMustStay = True self.firstTimeOnSegment = True def canvasMoveEvent(self, event): # QgsMessageLog.logMessage('fts: '+str(self.firstTimeOnSegment), 'state', 0) # QgsMessageLog.logMessage('lpc: '+str(self.lastPointMustStay), 'state', 0) if self.started: # Get the click x = event.pos().x() y = event.pos().y() eventPoint = QPoint(x, y) # only if the ctrl key is pressed if self.mCtrl: layer = self.canvas.currentLayer() if layer is not None: (retval, result) = self.snapper.snapToBackgroundLayers(eventPoint) # so if we have found a snapping if result != []: # pydevd.settrace() # that's the snapped point point = QgsPoint(result[0].snappedVertex) # if it is a vertex, not a point on a segment if result[0].snappedVertexNr != -1: self.rb.movePoint(point) self.appendPoint(point) self.lastPointMustStay = True # the next point found, may be on a segment self.firstTimeOnSegment = True # we are on a segment else: self.rb.movePoint(point) # if we are on a new segment, we add the point in any case if self.firstTimeOnSegment: self.appendPoint(point) self.lastPointMustStay = True self.firstTimeOnSegment = False # if we are not on a new segemnt, we have to test, if this point is realy needed else: # but only if we have already enough points # TODO: check if this is correct for lines also (they only need two points, to be vaild) if self.rb.numberOfVertices() >= 3: max = self.rb.numberOfVertices() lastRbP = self.rb.getPoint(0, max - 2) # QgsMessageLog.logMessage(str(self.rb.getPoint(0, max-1)), 'rb', 0) nextToLastRbP = self.rb.getPoint(0, max - 3) # QgsMessageLog.logMessage(str(self.rb.getPoint(0, max-2)), 'rb', 0) # QgsMessageLog.logMessage(str(point), 'rb', 0) if not self.pointOnLine( lastRbP, nextToLastRbP, QgsPoint(point)): self.appendPoint(point) self.lastPointMustStay = False else: # TODO: schauen, ob der letzte punkt ein klick war, dann nicht löschen. entsrpechend auch die "punkt auf linie" neu berechenen. if not self.lastPointMustStay: self.rb.removeLastPoint() self.rb.movePoint(point) # QgsMessageLog.logMessage('point removed', 'click', 0) # else: # QgsMessageLog.logMessage('sleep', 'rb', 0) else: self.appendPoint(point) self.lastPointMustStay = False self.firstTimeOnSegment = False else: # if nothing specials happens, just update the rubberband to the cursor position point = QgsMapToPixel.toMapCoordinates( self.canvas.getCoordinateTransform(), x, y) self.rb.movePoint(point) else: # in "not-tracing" state, just update the rubberband to the cursor position # but we have still to snap to act like the "normal" digitize tool (retval, result) = self.snapper.snapToBackgroundLayers(eventPoint) if result != []: point = QgsPoint(result[0].snappedVertex) else: point = QgsMapToPixel.toMapCoordinates( self.canvas.getCoordinateTransform(), x, y) self.rb.movePoint(point) def canvasReleaseEvent(self, event): # with right click the digitizing is finished if event.button() == 2: layer = self.canvas.currentLayer() x = event.pos().x() y = event.pos().y() if layer is not None and self.started: selPoint = QPoint(x, y) (retval, result) = self.snapper.snapToBackgroundLayers(selPoint) if result != []: point = result[0].snappedVertex else: point = QgsMapToPixel.toMapCoordinates( self.canvas.getCoordinateTransform(), x, y) # add this last point self.appendPoint(QgsPoint(point)) self.sendGeometry() def appendPoint(self, point): # don't add the point if it is identical to the last point we added if not (self.lastPoint == point): self.rb.addPoint(point) self.lastPoint = QgsPoint(point) else: pass # see: double QgsGeometryValidator::distLine2Point( QgsPoint p, QgsVector v, QgsPoint q ) # distance of point q from line through p in direction v def pointOnLine(self, pntAft, pntBef, pntTest): p = QgsPoint(pntAft) vx = pntBef.x() - pntAft.x() vy = pntBef.y() - pntAft.y() vlength = math.sqrt(vy * vy + vx * vx) if vlength == 0: return False q = QgsPoint(pntTest) res = (vx * (q.y() - p.y()) - vy * (q.x() - p.x())) / vlength # res = 0 means point is on line, but we are not in a perfect world, so a tolerance is needed # to get rid of some numerical problems. Tolerance estimated by solid engenieering work (rule of thumb...) if res < 1E-10: return True else: return False def sendGeometry(self): layer = self.canvas.currentLayer() coords = [] # backward compatiblity for a bug in qgsRubberband, that was fixed in 1.7 if Qgis.QGIS_VERSION_INT >= 10700: [ coords.append(self.rb.getPoint(0, i)) for i in range(self.rb.numberOfVertices()) ] else: [ coords.append(self.rb.getPoint(0, i)) for i in range(1, self.rb.numberOfVertices()) ] # On the Fly reprojection, not necessary any more, mapToLayerCoordinates is clever enough on its own # layerEPSG = layer.srs().epsg() # projectEPSG = self.canvas.mapRenderer().destinationSrs().epsg() # if layerEPSG != projectEPSG: coords_tmp = coords[:] coords = [] for point in coords_tmp: transformedPoint = self.canvas.mapRenderer().mapToLayerCoordinates( layer, point) coords.append(transformedPoint) coords_tmp = coords[:] coords = [] lastPt = None for pt in coords_tmp: if (lastPt != pt): coords.append(pt) lastPt = pt # Add geometry to feature. if self.isPolygon: g = QgsGeometry().fromPolygon([coords]) else: g = QgsGeometry().fromPolyline(coords) self.traceFound.emit(g) self.rb.reset(self.isPolygon) self.started = False def activate(self): self.canvas.setCursor(self.cursor) def deactivate(self): try: self.rb.reset() except AttributeError: pass def isZoomTool(self): return False def isTransient(self): return False def isEditTool(self): return True
def cadCanvasMoveEvent(self, event): """ When the mouse is moved :param event: mouse event """ if type(event) == QMoveEvent: map_point = self.toMapCoordinates(event.pos()) else: map_point = event.mapPoint() if not self.__isEditing and not self.__findVertex and not self.__onMove: laySettings = QgsSnappingUtils.LayerConfig(self.__layer, QgsPointLocator.All, 10, QgsTolerance.Pixels) f_l = Finder.findClosestFeatureAt(map_point, self.canvas(), [laySettings]) if f_l is not None and self.__lastFeatureId != f_l[0].id(): self.__lastFeatureId = f_l[0].id() self.__layer.setSelectedFeatures([f_l[0].id()]) if f_l is None: self.__layer.removeSelection() self.__lastFeatureId = None elif self.__findVertex: if self.__rubberBand is not None: self.__rubberBand.reset() closest = self.__selectedFeature.geometry().closestVertex( map_point) color = QColor("red") color.setAlphaF(0.78) self.__rubberBand.setColor(color) self.__rubberBand.setIcon(4) self.__rubberBand.setIconSize(20) self.__rubberBand.setToGeometry( QgsGeometry().fromPoint(closest[0]), None) elif self.__onMove: if self.__rubberBand is not None: self.__rubberBand.reset() if self.__layer.geometryType() == QGis.Polygon: self.__polygonPreview(map_point) elif self.__layer.geometryType() == QGis.Line: self.__linePreview(map_point) else: self.__pointPreview(map_point) color = QColor("red") color.setAlphaF(0.78) self.__rubberBand.setColor(color) self.__rubberBand.setWidth(2) if self.__layer.geometryType() != QGis.Point: self.__rubberBand.setLineStyle(Qt.DotLine) else: self.__rubberBand.setIcon(4) self.__rubberBand.setIconSize(8) if self.__rubberSnap is not None: self.__rubberSnap.reset() else: self.__rubberSnap = QgsRubberBand(self.canvas(), QGis.Point) self.__rubberSnap.setColor(color) self.__rubberSnap.setWidth(2) self.__rubberSnap.setIconSize(20) match = Finder.snap(map_point, self.canvas()) if match.hasVertex() or match.hasEdge(): point = match.point() if match.hasVertex(): if match.layer(): self.__rubberSnap.setIcon(4) else: self.__rubberSnap.setIcon(1) if match.hasEdge(): intersection = Finder.snapCurvedIntersections( point, self.canvas(), self) if intersection is not None: self.__rubberSnap.setIcon(1) point = intersection else: self.__rubberSnap.setIcon(3) self.__rubberSnap.setToGeometry(QgsGeometry().fromPoint(point), None)
from qgis.core import QgsSnappingUtils snapper = QgsSnappingUtils() layer_edge = QgsMapLayerRegistry.instance().mapLayersByName('edges')[0] snapping_type = QgsSnapper.SnapToSegment tolerance = 1 unit = QgsTolerance.LayerUnits layer_config = QgsSnappingUtils.LayerConfig(layer_edge, snapping_type, tolerance, unit) snapper.setLayers([layer_config]) snap_mode = QgsSnappingUtils.SnapAdvanced snapper.setSnapToMapMode(snap_mode) p1 = QgsPoint(20.4529554239886, -34.0188548283715) r = snapper.snapToMap(p1) print r.type() #snapper=QgsSnapper(iface.mapCanvas().mapSettings()) #snapper = setSnapMode
def setSnapping(self, config): self.snapConfig = config self.snapper = QgsSnappingUtils(self.canvas) self.snapper.setConfig(self.snapConfig) self.snapper.setMapSettings(self.canvas.mapSettings())
class VertexTool(QgsMapTool): canvasReleased = pyqtSignal(QgsPointXY, bool) isActive = pyqtSignal(bool) def __init__(self, iface, canvas, useSnapped=True): super(VertexTool, self).__init__(canvas) self.snapper = None self.markerSnapped = None self.useSnapped = useSnapped self.iface = iface self.canvas = self.iface.mapCanvas() self.setCursor(Qt.CrossCursor) self.prj = QgsProject.instance() self.snapConfig = self.prj.snappingConfig() self.prj.snappingConfigChanged.connect(self.setSnapping) self.setSnapping(self.prj.snappingConfig()) def setSnapping(self, config): self.snapConfig = config self.snapper = QgsSnappingUtils(self.canvas) self.snapper.setConfig(self.snapConfig) self.snapper.setMapSettings(self.canvas.mapSettings()) def canvasMoveEvent(self, event): point = self.toMapCoordinates(event.pos()) if self.snapConfig.enabled() and self.useSnapped: self.isSnapped(point) else: self.resetMarker() def canvasReleaseEvent(self, event): point = self.toMapCoordinates(event.pos()) if self.useSnapped: point, isnaped = self.isSnapped(point) self.canvasReleased.emit(point, isnaped) else: self.canvasReleased.emit(point, False) def activate(self): self.isActive.emit(True) QgsMapTool.activate(self) def deactivate(self): self.resetMarker() self.isActive.emit(False) QgsMapTool.deactivate(self) def isSnapped(self, pointxy): self.resetMarker() matchres = self.snapper.snapToMap(pointxy) # QgsPointLocator.Match if matchres.isValid(): self.markerSnapped = QgsVertexMarker(self.canvas) self.markerSnapped.setColor(Qt.red) self.markerSnapped.setIconSize(7) self.markerSnapped.setIconType(QgsVertexMarker.ICON_BOX) self.markerSnapped.setPenWidth(3) self.markerSnapped.setCenter(matchres.point()) self.markerSnapped.show() return matchres.point(), True else: return pointxy, False def resetMarker(self): self.canvas.scene().removeItem(self.markerSnapped)
def __adjust(self): """ To look for adjustments and to display them """ self.__layers = self.__lineVertices(True) self.__adjustments = [] self.__altitudes = [] for p in range(len(self.__points)): pt = self.__points[p] x = pt['x'] y = pt['y'] z = pt['z'] num_lines = len(self.__selectedIds) drawdown = False level = None for layer in self.ownSettings.refLayers: laySettings = QgsSnappingUtils.LayerConfig( layer, QgsPointLocator.All, self.SEARCH_TOLERANCE, QgsTolerance.LayerUnits) feature = Finder.findClosestFeatureAt( self.toMapCoordinates(layer, QgsPoint(x, y)), laySettings, self) if feature is not None: point_v2 = GeometryV2.asPointV2(feature.geometry(), self.__iface) if point_v2.z() > 0: if level is not None: if (level - point_v2.z()) > 0.005: self.__iface.messageBar( ).pushMessage(QCoreApplication.translate( "VDLTools", "More than one reference point, with 2 different elevations !!" ), level=QgsMessageBar.CRITICAL, duration=0) self.__cancel() return level = point_v2.z() comp = QCoreApplication.translate("VDLTools", " (at invert)") if str(feature.attribute(self.ownSettings.levelAtt) ) in self.ownSettings.levelVals: drawdown = True comp = QCoreApplication.translate( "VDLTools", " (on pipe)") if point_v2.z() == 0: comp = QCoreApplication.translate( "VDLTools", " (no elevation)") self.__adjustments.append({ 'point': p, 'previous': point_v2.z(), 'line': False, 'layer': layer, 'comp': comp, 'feature': feature, 'delta': False }) diam = 0 for i in range(num_lines): if z[i] is None: continue id_s = self.__selectedIds[i] feature = QgsFeature() self.ownSettings.drawdownLayer.getFeatures( QgsFeatureRequest().setFilterFid(id_s)).nextFeature( feature) dtemp = feature.attribute(self.ownSettings.pipeDiam) / 1000 if dtemp > diam: diam = dtemp selected = None for f in self.ownSettings.drawdownLayer.selectedFeatures(): if f.id() == id_s: selected = f break self.__adjustments.append({ 'point': p, 'previous': z[i], 'line': True, 'diam': dtemp, 'layer': self.ownSettings.drawdownLayer, 'feature': selected, 'delta': True }) for layer in self.__layers: laySettings = QgsSnappingUtils.LayerConfig( layer, QgsPointLocator.All, self.SEARCH_TOLERANCE, QgsTolerance.LayerUnits) fs = Finder.findFeaturesAt(QgsPoint(x, y), laySettings, self) if len(fs) == 0: z.append(None) else: zz = [] for f in fs: if layer == self.ownSettings.drawdownLayer: if f.id() not in self.__selectedIds: closest = f.geometry().closestVertex( QgsPoint(x, y)) if closest[4] < self.SEARCH_TOLERANCE: line, curved = GeometryV2.asLineV2( f.geometry(), self.__iface) zp = line.zAt(closest[1]) dtemp = f.attribute( self.ownSettings.pipeDiam) / 1000 if dtemp > diam: diam = dtemp self.__adjustments.append({ 'point': p, 'previous': zp, 'line': False, 'diam': dtemp, 'comp': QCoreApplication.translate( "VDLTools", " connected"), 'feature': f, 'layer': layer, 'delta': True }) if zp is None or zp != zp: zz.append(0) else: zz.append(zp) else: zp = GeometryV2.asPointV2(f.geometry(), self.__iface).z() if zp is None or zp != zp: zp = 0 zz.append(zp) if layer in self.ownSettings.adjLayers: self.__adjustments.append({ 'point': p, 'previous': zp, 'line': False, 'layer': layer, 'feature': f, 'delta': True }) if len(zz) == 0: z.append(None) elif len(zz) == 1: z.append(zz[0]) else: z.append(zz) if level is not None: if drawdown: alt = level - diam else: alt = level else: alt = 0 dd = None if drawdown: dd = QCoreApplication.translate("VDLTools", "drawdown") self.__altitudes.append({'diam': diam, 'drawdown': dd, 'alt': alt}) last = len(self.__altitudes) - 1 self.__extras = [] for i in range(len(self.__altitudes)): if self.__altitudes[i]['alt'] is 0: if 0 < i < last: av = None j = 1 while True: if i - j < 0: break if self.__altitudes[i - j]['alt'] != 0: av = j break j += 1 ap = None j = 1 while True: if i + j > len(self.__points) - 1: break if self.__altitudes[i + j]['alt'] != 0: ap = j break j += 1 if av is not None and ap is not None: prev_alt = self.__altitudes[i - av]['alt'] next_alt = self.__altitudes[i + ap]['alt'] prev_pt = self.__points[i - av] next_pt = self.__points[i + ap] pt = self.__points[i] d0 = Finder.sqrDistForCoords(pt['x'], prev_pt['x'], pt['y'], prev_pt['y']) d1 = Finder.sqrDistForCoords(next_pt['x'], pt['x'], next_pt['y'], pt['y']) inter_alt = round( old_div((d0 * next_alt + d1 * prev_alt), (d0 + d1)), 3) self.__altitudes[i]['alt'] = inter_alt self.__altitudes[i]['drawdown'] = "interpolation" elif i == 0 and len(self.__altitudes) > 2: alt1 = self.__altitudes[1]['alt'] alt2 = self.__altitudes[2]['alt'] if alt1 != 0 and alt2 != 0: pt2 = self.__points[2] pt1 = self.__points[1] pt = self.__points[0] big_d = Finder.sqrDistForCoords( pt2['x'], pt1['x'], pt2['y'], pt1['y']) small_d = Finder.sqrDistForCoords( pt1['x'], pt['x'], pt1['y'], pt['y']) extra_alt = round( alt2 + (1 + old_div(small_d, big_d)) * (alt1 - alt2), 3) if small_d < (old_div(big_d, 4)): self.__altitudes[i]['alt'] = extra_alt self.__altitudes[i]['drawdown'] = "extrapolation" else: self.__extras.append([i, extra_alt]) elif i == last and len(self.__altitudes) > 2: alt1 = self.__altitudes[i - 1]['alt'] alt2 = self.__altitudes[i - 2]['alt'] if alt1 != 0 and alt2 != 0: pt2 = self.__points[i - 2] pt1 = self.__points[i - 1] pt = self.__points[i] big_d = Finder.sqrDistForCoords( pt2['x'], pt1['x'], pt2['y'], pt1['y']) small_d = Finder.sqrDistForCoords( pt1['x'], pt['x'], pt1['y'], pt['y']) extra_alt = round( alt2 + (1 + old_div(small_d, big_d)) * (alt1 - alt2), 3) if small_d < (old_div(big_d, 4)): self.__altitudes[i]['alt'] = extra_alt self.__altitudes[i]['drawdown'] = "extrapolation" else: self.__extras.append([i, extra_alt]) if len(self.__extras) == 0: self.__setAdjustements() else: self.__checkForceExtrapolation()
def __lineVertices(self, checkLayers=False): """ To check if vertices of others layers are crossing the displaying line :param checkLayers: if we want to get the list of the other layers in return :return: other layers list if requested """ if checkLayers: otherLayers = [] self.__points = [] self.__selectedStarts = [] num = 0 num_lines = len(self.__selectedIds) for iden in self.__selectedIds: self.__selectedStarts.append(max(0, len(self.__points) - 1)) direction = self.__selectedDirections[num] selected = None for f in self.ownSettings.drawdownLayer.selectedFeatures(): if f.id() == iden: selected = f break if selected is None: self.__iface.messageBar().pushMessage( QCoreApplication.translate("VDLTools", "Error on selected"), level=QgsMessageBar.CRITICAL, duration=0) continue line_v2, curved = GeometryV2.asLineV2(selected.geometry(), self.__iface) if direction: rg = range(line_v2.numPoints()) else: rg = range(line_v2.numPoints() - 1, -1, -1) rg_positions = [] for i in rg: pt_v2 = line_v2.pointN(i) x = pt_v2.x() y = pt_v2.y() doublon = False for position in rg_positions: if position['x'] == x and position['y'] == y and position[ 'iden'] == iden: self.__iface.messageBar().pushMessage( QCoreApplication.translate( "VDLTools", "Beware! the line ") + str(iden) + QCoreApplication.translate( "VDLTools", " has 2 identical summits on the vertex ") + str(i - 1) + QCoreApplication.translate( "VDLTools", " same coordinates (X and Y). " "Please correct the line geometry."), level=QgsMessageBar.CRITICAL, duration=0) doublon = True break for item in self.__points: if item['x'] == x and item['y'] == y: item['z'][num] = pt_v2.z() rg_positions.append({'x': x, 'y': y, 'iden': iden}) doublon = True break if not doublon: rg_positions.append({'x': x, 'y': y, 'iden': iden}) z = [] for j in range(num_lines): if j == num: if pt_v2.z() == pt_v2.z(): z.append(pt_v2.z()) else: z.append(0) else: z.append(None) self.__points.append({'x': x, 'y': y, 'z': z}) if checkLayers: combinedLayers = [self.ownSettings.drawdownLayer] combinedLayers += self.ownSettings.refLayers + self.ownSettings.adjLayers for layer in combinedLayers: if layer in otherLayers: continue laySettings = QgsSnappingUtils.LayerConfig( layer, QgsPointLocator.All, self.SEARCH_TOLERANCE, QgsTolerance.LayerUnits) fs = Finder.findFeaturesAt(QgsPoint(x, y), laySettings, self) if len(fs) > 0: for f in fs: if layer == self.ownSettings.drawdownLayer: if f.id() not in self.__selectedIds: closest = f.geometry( ).closestVertex(QgsPoint(x, y)) if closest[ 4] < self.SEARCH_TOLERANCE: if layer not in otherLayers: otherLayers.append(layer) elif layer not in otherLayers: otherLayers.append(layer) num += 1 if checkLayers: return otherLayers