void testNearestVertex() { QgsPointLocator loc( mVL ); QgsPointXY pt( 2, 2 ); QgsPointLocator::Match m = loc.nearestVertex( pt, 999 ); QVERIFY( m.isValid() ); QVERIFY( m.hasVertex() ); QCOMPARE( m.layer(), mVL ); QCOMPARE( m.featureId(), ( QgsFeatureId )1 ); QCOMPARE( m.point(), QgsPointXY( 1, 1 ) ); QCOMPARE( m.distance(), std::sqrt( 2.0 ) ); QCOMPARE( m.vertexIndex(), 2 ); }
void testNearestEdge() { QgsPointLocator loc( mVL ); QgsPointXY pt( 1.1, 0.5 ); QgsPointLocator::Match m = loc.nearestEdge( pt, 999 ); QVERIFY( m.isValid() ); QVERIFY( m.hasEdge() ); QCOMPARE( m.layer(), mVL ); QCOMPARE( m.featureId(), ( QgsFeatureId )1 ); QCOMPARE( m.point(), QgsPointXY( 1, 0.5 ) ); QCOMPARE( m.distance(), 0.1 ); QCOMPARE( m.vertexIndex(), 1 ); QgsPointXY pt1, pt2; m.edgePoints( pt1, pt2 ); QCOMPARE( pt1, QgsPointXY( 1, 0 ) ); QCOMPARE( pt2, QgsPointXY( 1, 1 ) ); }
int QgsMapToolCapture::fetchLayerPoint( const QgsPointLocator::Match &match, QgsPoint &layerPoint ) { QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( mCanvas->currentLayer() ); QgsVectorLayer *sourceLayer = match.layer(); if ( match.isValid() && match.hasVertex() && sourceLayer && ( sourceLayer->crs() == vlayer->crs() ) ) { QgsFeature f; QgsFeatureRequest request; request.setFilterFid( match.featureId() ); bool fetched = match.layer()->getFeatures( request ).nextFeature( f ); if ( fetched ) { QgsVertexId vId; if ( !f.geometry().vertexIdFromVertexNr( match.vertexIndex(), vId ) ) return 2; layerPoint = f.geometry().constGet()->vertexAt( vId ); // ZM support depends on the target layer if ( !QgsWkbTypes::hasZ( vlayer->wkbType() ) ) { layerPoint.dropZValue(); } if ( !QgsWkbTypes::hasM( vlayer->wkbType() ) ) { layerPoint.dropMValue(); } return 0; } else { return 2; } } else { return 1; } }
QgsPoint QgsMapToolCapture::mapPoint( const QgsMapMouseEvent &e ) const { QgsPoint newPoint = mapPoint( e.mapPoint() ); // set z value from snapped point if necessary if ( QgsWkbTypes::hasZ( newPoint.wkbType() ) ) { // if snapped, z dimension is taken from the corresponding snapped // point. if ( e.isSnapped() ) { const QgsPointLocator::Match match = e.mapPointMatch(); if ( match.layer() && QgsWkbTypes::hasZ( match.layer()->wkbType() ) ) { const QgsFeature ft = match.layer()->getFeature( match.featureId() ); newPoint.setZ( ft.geometry().vertexAt( match.vertexIndex() ).z() ); } } } return newPoint; }
QgsGeometry* QgsMapToolDeletePart::partUnderPoint( QPoint point, QgsFeatureId& fid, int& partNum ) { QgsFeature f; QgsGeometry* geomPart = new QgsGeometry(); switch ( vlayer->geometryType() ) { case QGis::Point: case QGis::Line: { QgsPointLocator::Match match = mCanvas->snappingUtils()->snapToCurrentLayer( point, QgsPointLocator::Vertex | QgsPointLocator::Edge ); if ( !match.isValid() ) return geomPart; int snapVertex = match.vertexIndex(); vlayer->getFeatures( QgsFeatureRequest().setFilterFid( match.featureId() ) ).nextFeature( f ); const QgsGeometry* g = f.constGeometry(); if ( !g->isMultipart() ) { fid = match.featureId(); delete geomPart; return QgsGeometry::fromPoint( match.point() ); } if ( g->wkbType() == QGis::WKBMultiPoint || g->wkbType() == QGis::WKBMultiPoint25D ) { fid = match.featureId(); partNum = snapVertex; delete geomPart; return QgsGeometry::fromPoint( match.point() ); } if ( g->wkbType() == QGis::WKBMultiLineString || g->wkbType() == QGis::WKBMultiLineString25D ) { QgsMultiPolyline mline = g->asMultiPolyline(); for ( int part = 0; part < mline.count(); part++ ) { if ( snapVertex < mline[part].count() ) { fid = match.featureId(); partNum = part; delete geomPart; return QgsGeometry::fromPolyline( mline[part] ); } snapVertex -= mline[part].count(); } } break; } case QGis::Polygon: { QgsPoint layerCoords = toLayerCoordinates( vlayer, point ); double searchRadius = QgsTolerance::vertexSearchRadius( mCanvas->currentLayer(), mCanvas->mapSettings() ); QgsRectangle selectRect( layerCoords.x() - searchRadius, layerCoords.y() - searchRadius, layerCoords.x() + searchRadius, layerCoords.y() + searchRadius ); QgsFeatureIterator fit = vlayer->getFeatures( QgsFeatureRequest().setFilterRect( selectRect ) ); fit.nextFeature( f ); const QgsGeometry* g = f.constGeometry(); if ( !g ) return geomPart; if ( !g->isMultipart() ) { fid = f.id(); return geomPart; } QgsMultiPolygon mpolygon = g->asMultiPolygon(); for ( int part = 0; part < mpolygon.count(); part++ ) // go through the polygons { const QgsPolygon& polygon = mpolygon[part]; QgsGeometry* partGeo = QgsGeometry::fromPolygon( polygon ); if ( partGeo->contains( &layerCoords ) ) { fid = f.id(); partNum = part; delete geomPart; return partGeo; } delete partGeo; } break; } default: { break; } } return geomPart; }
QgsGeometry QgsMapToolDeletePart::partUnderPoint( QPoint point, QgsFeatureId &fid, int &partNum ) { QgsFeature f; QgsGeometry geomPart; switch ( vlayer->geometryType() ) { case QgsWkbTypes::PointGeometry: case QgsWkbTypes::LineGeometry: { QgsPointLocator::Match match = mCanvas->snappingUtils()->snapToCurrentLayer( point, QgsPointLocator::Types( QgsPointLocator::Vertex | QgsPointLocator::Edge ) ); if ( !match.isValid() ) return geomPart; int snapVertex = match.vertexIndex(); vlayer->getFeatures( QgsFeatureRequest().setFilterFid( match.featureId() ) ).nextFeature( f ); QgsGeometry g = f.geometry(); if ( !g.isMultipart() ) { fid = match.featureId(); return QgsGeometry::fromPointXY( match.point() ); } else if ( QgsWkbTypes::geometryType( g.wkbType() ) == QgsWkbTypes::PointGeometry ) { fid = match.featureId(); partNum = snapVertex; return QgsGeometry::fromPointXY( match.point() ); } else if ( QgsWkbTypes::geometryType( g.wkbType() ) == QgsWkbTypes::LineGeometry ) { QgsMultiPolylineXY mline = g.asMultiPolyline(); for ( int part = 0; part < mline.count(); part++ ) { if ( snapVertex < mline[part].count() ) { fid = match.featureId(); partNum = part; return QgsGeometry::fromPolylineXY( mline[part] ); } snapVertex -= mline[part].count(); } } break; } case QgsWkbTypes::PolygonGeometry: { QgsPointLocator::Match match = mCanvas->snappingUtils()->snapToCurrentLayer( point, QgsPointLocator::Area ); if ( !match.isValid() ) return geomPart; vlayer->getFeatures( QgsFeatureRequest().setFilterFid( match.featureId() ) ).nextFeature( f ); QgsGeometry g = f.geometry(); if ( g.isNull() ) return geomPart; QgsPointXY layerCoords = toLayerCoordinates( vlayer, point ); if ( !g.isMultipart() ) { fid = f.id(); return geomPart; } QgsMultiPolygonXY mpolygon = g.asMultiPolygon(); for ( int part = 0; part < mpolygon.count(); part++ ) // go through the polygons { const QgsPolygonXY &polygon = mpolygon[part]; QgsGeometry partGeo = QgsGeometry::fromPolygonXY( polygon ); if ( partGeo.contains( &layerCoords ) ) { fid = f.id(); partNum = part; return partGeo; } } break; } default: { break; } } return geomPart; }
void QgsMapToolOffsetCurve::prepareGeometry( const QgsPointLocator::Match &match, QgsFeature &snappedFeature ) { QgsVectorLayer *vl = match.layer(); if ( !vl ) { return; } mOriginalGeometry = QgsGeometry(); mManipulatedGeometry = QgsGeometry(); mModifiedPart = -1; mModifiedRing = -1; //assign feature part by vertex number (snap to vertex) or by before vertex number (snap to segment) QgsGeometry geom = snappedFeature.geometry(); if ( geom.isNull() ) { return; } mOriginalGeometry = geom; QgsWkbTypes::Type geomType = geom.wkbType(); if ( QgsWkbTypes::geometryType( geomType ) == QgsWkbTypes::LineGeometry ) { if ( !match.hasEdge() ) { return; } if ( !geom.isMultipart() ) { mManipulatedGeometry = geom; } else { int vertex = match.vertexIndex(); QgsVertexId vertexId; geom.vertexIdFromVertexNr( vertex, vertexId ); mModifiedPart = vertexId.part; QgsMultiPolylineXY multiLine = geom.asMultiPolyline(); mManipulatedGeometry = QgsGeometry::fromPolylineXY( multiLine.at( mModifiedPart ) ); } } else if ( QgsWkbTypes::geometryType( geomType ) == QgsWkbTypes::PolygonGeometry ) { if ( !match.hasEdge() && match.hasArea() ) { if ( !geom.isMultipart() ) { mManipulatedGeometry = geom; } else { // get the correct part QgsMultiPolygonXY mpolygon = geom.asMultiPolygon(); for ( int part = 0; part < mpolygon.count(); part++ ) // go through the polygons { const QgsPolygonXY &polygon = mpolygon[part]; QgsGeometry partGeo = QgsGeometry::fromPolygonXY( polygon ); const QgsPointXY layerCoords = match.point(); if ( partGeo.contains( &layerCoords ) ) { mModifiedPart = part; mManipulatedGeometry = partGeo; } } } } else if ( match.hasEdge() ) { int vertex = match.vertexIndex(); QgsVertexId vertexId; geom.vertexIdFromVertexNr( vertex, vertexId ); QgsDebugMsg( QStringLiteral( "%1" ).arg( vertexId.ring ) ); if ( !geom.isMultipart() ) { QgsPolygonXY poly = geom.asPolygon(); // if has rings if ( poly.count() > 0 ) { mModifiedRing = vertexId.ring; mManipulatedGeometry = QgsGeometry::fromPolygonXY( QgsPolygonXY() << poly.at( mModifiedRing ) ); } else { mManipulatedGeometry = QgsGeometry::fromPolygonXY( poly ); } } else { mModifiedPart = vertexId.part; // get part, get ring QgsMultiPolygonXY multiPoly = geom.asMultiPolygon(); // if has rings if ( multiPoly.at( mModifiedPart ).count() > 0 ) { mModifiedRing = vertexId.ring; mManipulatedGeometry = QgsGeometry::fromPolygonXY( QgsPolygonXY() << multiPoly.at( mModifiedPart ).at( mModifiedRing ) ); } else { mManipulatedGeometry = QgsGeometry::fromPolygonXY( multiPoly.at( mModifiedPart ) ); } } } } }