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 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)
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
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 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) u.setSnapToMapMode(QgsSnappingUtils.SnapAdvanced) layers = [ QgsSnappingUtils.LayerConfig(self.pointsLayer, QgsPointLocator.Vertex, 20, QgsTolerance.Pixels) ] u.setLayers(layers) 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 layers = [ QgsSnappingUtils.LayerConfig(self.pointsLayer, QgsPointLocator.Vertex, 20, QgsTolerance.Pixels), QgsSnappingUtils.LayerConfig(self.pointsLayer2, QgsPointLocator.Vertex, 20, QgsTolerance.Pixels) ] u.setLayers(layers) 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([])