58#include "moc_qgsmaptoolcapture.cpp"
60using namespace Qt::StringLiterals;
64 , mCaptureMode(
mode )
67 mTempRubberBand.setParentOwner(
canvas );
69 mSnapIndicator = std::make_unique<QgsSnapIndicator>(
canvas );
78 mExtraSnapLayer =
new QgsVectorLayer( u
"LineString?crs="_s, u
"extra snap"_s, u
"memory"_s, layerOptions );
79 mExtraSnapLayer->startEditing();
81 mExtraSnapLayer->addFeature( f );
82 mExtraSnapFeatureId = f.
id();
86 currentLayerChanged(
canvas->currentLayer() );
97 mCanvas->snappingUtils()->removeExtraSnapLayer( mExtraSnapLayer );
99 mExtraSnapLayer->deleteLater();
100 mExtraSnapLayer =
nullptr;
106 mValidator->deleteLater();
107 mValidator =
nullptr;
134 if ( mTempRubberBand )
135 mTempRubberBand->show();
137 mCanvas->snappingUtils()->addExtraSnapLayer( mExtraSnapLayer );
142 setCurrentShapeMapToolIsActivated(
true );
148 if ( mTempRubberBand )
149 mTempRubberBand->hide();
153 mCanvas->snappingUtils()->removeExtraSnapLayer( mExtraSnapLayer );
157 setCurrentShapeMapToolIsActivated(
false );
163void QgsMapToolCapture::currentLayerChanged(
QgsMapLayer *layer )
165 if ( !mCaptureModeFromLayer )
201 if ( mTempRubberBand )
209bool QgsMapToolCapture::tracingEnabled()
216QgsPointXY QgsMapToolCapture::tracingStartPoint()
220 if ( mTracingStartPoint != QgsPointXY() )
221 return mTracingStartPoint;
223 return mCaptureLastPoint;
232 QgsPointXY pt0 = tracingStartPoint();
233 if ( pt0 == QgsPointXY() )
249 mTempRubberBand->addPoint( mCaptureLastPoint );
255 const QgsPoint lastPoint = mCaptureLastPoint;
256 QgsPointXY lastPointXY( lastPoint );
257 if ( lastPointXY == pt0 &&
points[0] != lastPointXY )
259 if ( mRubberBand->numberOfVertices() != 0 )
263 if ( mRubberBand->numberOfVertices() > 2 || ( mRubberBand->numberOfVertices() == 2 && *mRubberBand->getPoint( 0, 0 ) != *mRubberBand->getPoint( 0, 1 ) ) )
264 mRubberBand->movePoint(
points[0] );
267 mTempRubberBand->movePoint( 0, QgsPoint(
points[0] ) );
270 mTempRubberBand->movePoint( QgsPoint(
points[0] ) );
273 for (
int i = 1; i <
points.count(); ++i )
274 mTempRubberBand->addPoint( QgsPoint(
points.at( i ) ), i ==
points.count() - 1 );
277 mTempRubberBand->addPoint( QgsPoint(
points[
points.size() - 1] ) );
281 QgsCoordinateReferenceSystem targetCrs =
mCanvas->mapSettings().destinationCrs();
282 if ( QgsMapLayer *l =
layer() )
285 targetCrs = l->crs();
288 std::unique_ptr< QgsCompoundCurve > tempCurve( mCaptureCurve.clone() );
291 std::unique_ptr< QgsCurve > tracedCurve( mTempRubberBand->curve() );
293 tempCurve->addCurve( tracedCurve.release() );
297 auto curvePolygon = std::make_unique< QgsCurvePolygon >();
298 curvePolygon->setExteriorRing( tempCurve.release() );
299 onTransientGeometryChanged( QgsReferencedGeometry( QgsGeometry( std::move( curvePolygon ) ), targetCrs ) );
303 onTransientGeometryChanged( QgsReferencedGeometry( QgsGeometry( std::move( tempCurve ) ), targetCrs ) );
306 catch ( QgsCsException &e )
315bool QgsMapToolCapture::tracingAddVertex(
const QgsPointXY &point )
321 if ( mTempRubberBand->pointsCount() == 0 )
323 if ( !tracer->
init() )
333 mTracingStartPoint = point;
338 QgsPointXY pt0 = tracingStartPoint();
339 if ( pt0 == QgsPointXY() )
343 const QVector<QgsPointXY> tracedPointsInMapCrs = tracer->
findShortestPath( pt0, point, &err );
344 if ( tracedPointsInMapCrs.isEmpty() )
349 layerPoints.reserve( tracedPointsInMapCrs.size() );
351 mapPoints.reserve( tracedPointsInMapCrs.size() );
352 for (
const QgsPointXY &tracedPointMapCrs : tracedPointsInMapCrs )
354 QgsPoint
mapPoint( tracedPointMapCrs );
372 const QgsVertexId lastVertexId( 0, 0, mCaptureCurve.numPoints() - 1 );
373 mCaptureCurve.moveVertex( lastVertexId, layerPoints.first() );
374 mSnappingMatches.removeLast();
375 mSnappingMatches.append( QgsPointLocator::Match() );
377 addCurve(
new QgsLineString( mapPoints ) );
385 QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>(
layer() );
388 const QgsGeometry linear = QgsGeometry( mCaptureCurve.segmentize() );
389 const QgsGeometry curved
393 mCaptureCurve.clear();
402 mSnappingMatches.resize( mCaptureCurve.numPoints() );
408 const QgsPoint lastPt = mCaptureCurve.endPoint();
414QgsMapToolCaptureRubberBand *QgsMapToolCapture::createCurveRubberBand()
const
416 QgsMapToolCaptureRubberBand *rb =
new QgsMapToolCaptureRubberBand(
mCanvas );
421 color.setAlphaF( color.alphaF() * alphaScale );
422 rb->setLineStyle( Qt::DotLine );
423 rb->setStrokeColor( color );
426 rb->setFillColor( fillColor );
431void QgsMapToolCapture::resetRubberBand()
435 QgsLineString *lineString = mCaptureCurve.curveToLine();
438 mRubberBand->addGeometry( QgsGeometry( lineString ),
layer() );
441void QgsMapToolCapture::setCurrentShapeMapToolIsActivated(
bool activated )
446 mCurrentShapeMapTool->activate( mCaptureMode, mCaptureLastPoint );
451 mCurrentShapeMapTool->deactivate();
457 if ( mLayerPreviewRubberBand )
459 mLayerPreviewRubberBand->setToGeometry( geometry, geometry.
crs() );
467 return mRubberBand.release();
488 if ( mCurrentCaptureTechnique == technique )
491 mStartNewCurve =
true;
495 setCurrentShapeMapToolIsActivated(
false );
520 if ( mTempRubberBand )
521 mTempRubberBand->setStringType( mLineDigitizingType );
523 mCurrentCaptureTechnique = technique;
528 setCurrentShapeMapToolIsActivated(
true );
534 if ( mCurrentShapeMapTool )
536 if ( shapeMapToolMetadata && mCurrentShapeMapTool->
id() == shapeMapToolMetadata->
id() )
540 setCurrentShapeMapToolIsActivated(
false );
542 mCurrentShapeMapTool->deleteLater();
545 mCurrentShapeMapTool.reset( shapeMapToolMetadata ? shapeMapToolMetadata->
factory(
this ) :
nullptr );
550 if ( mCurrentShapeMapTool )
552 setCurrentShapeMapToolIsActivated(
true );
562 if ( e->button() == Qt::LeftButton )
568 mBezierData = std::make_unique<QgsBezierData>();
569 if ( !mBezierMarker )
570 mBezierMarker = std::make_unique<QgsBezierMarker>(
mCanvas );
575 mBezierDragAnchorIndex = -1;
576 mBezierDragHandleIndex = -1;
577 mBezierMoveAnchorIndex = -1;
580 const int handleIdx = mBezierData->findClosestHandle(
mapPoint, tolerance );
581 if ( handleIdx >= 0 )
584 mBezierDragHandleIndex = handleIdx;
585 mBezierDragging =
true;
586 mBezierMarker->setHighlightedHandle( handleIdx );
591 const int anchorIdx = mBezierData->findClosestAnchor(
mapPoint, tolerance );
592 if ( anchorIdx >= 0 )
594 if ( e->modifiers() & Qt::AltModifier )
597 mBezierDragAnchorIndex = anchorIdx;
598 mBezierDragging =
true;
599 mBezierMarker->setHighlightedAnchor( anchorIdx );
604 mBezierMoveAnchorIndex = anchorIdx;
605 mBezierDragging =
true;
606 mBezierMarker->setHighlightedAnchor( anchorIdx );
613 mBezierDragAnchorIndex = mBezierData->anchorCount() - 1;
614 mBezierDragging =
true;
617 mBezierMarker->updateFromData( *mBezierData );
631 if ( mCaptureModeFromLayer && ( !
canvas()->currentLayer() || !
canvas()->currentLayer()->isSpatial() ) )
642 if ( !mCurrentShapeMapTool )
648 if ( !mTempRubberBand )
650 mTempRubberBand.reset( createCurveRubberBand() );
651 mTempRubberBand->setStringType( mLineDigitizingType );
655 mCurrentShapeMapTool->cadCanvasMoveEvent( e, mCaptureMode );
670 const int handleIdx = mBezierData->findClosestHandle(
mapPoint, tolerance );
672 const int anchorIdx = mBezierData->findClosestAnchor(
mapPoint, tolerance );
674 if ( handleIdx >= 0 || anchorIdx >= 0 )
686 if ( mBezierDragging && mBezierData )
688 if ( mBezierDragHandleIndex >= 0 )
691 mBezierData->moveHandle( mBezierDragHandleIndex,
mapPoint );
693 else if ( mBezierDragAnchorIndex >= 0 )
696 mBezierData->calculateSymmetricHandles( mBezierDragAnchorIndex,
mapPoint );
701 mBezierMarker->updateFromData( *mBezierData );
704 else if ( mBezierData && mBezierData->anchorCount() > 0 && mBezierMarker && mCapturing )
706 QgsBezierData previewData = *mBezierData;
709 mBezierMarker->updateCurve( previewData );
713 if ( !mTempRubberBand )
715 mTempRubberBand.reset( createCurveRubberBand() );
716 mTempRubberBand->setStringType( mLineDigitizingType );
724 mTempRubberBand->addPoint( pt );
730 targetCrs = l->crs();
735 auto lineString = std::make_unique<QgsLineString>(
points );
739 auto curvePolygon = std::make_unique<QgsCurvePolygon>();
741 curvePolygon->setExteriorRing( lineString.release() );
760 targetCrs = l->crs();
763 if ( mCaptureMode !=
CapturePoint && mTempRubberBand && mCapturing )
765 bool hasTrace =
false;
769 if ( !mCaptureCurve.isEmpty() )
771 const QgsPoint prevPoint = mCaptureCurve.curveAt( mCaptureCurve.nCurves() - 1 )->endPoint();
776 mAllowAddingStreamingPoints =
true;
778 mAllowAddingStreamingPoints =
false;
780 std::unique_ptr< QgsCompoundCurve > tempCurve( mCaptureCurve.clone() );
783 auto curvePolygon = std::make_unique< QgsCurvePolygon >();
785 curvePolygon->setExteriorRing( tempCurve.release() );
793 else if ( tracingEnabled() && mCaptureCurve.numPoints() != 0 )
799 mCircularItermediatePoint = mTempRubberBand->pointFromEnd( 1 );
801 mCircularItermediatePoint =
QgsPoint();
803 hasTrace = tracingMouseMove( e );
809 mTempRubberBand->addPoint( mCaptureLastPoint );
810 if ( !mCircularItermediatePoint.isEmpty() )
812 mTempRubberBand->movePoint( mCircularItermediatePoint );
813 mTempRubberBand->addPoint( mCircularItermediatePoint );
820 if ( mCaptureCurve.numPoints() > 0 )
822 const QgsPoint mapPt = mCaptureLastPoint;
824 if ( mTempRubberBand )
826 mTempRubberBand->movePoint(
mapPoint );
827 mTempRubberBand->movePoint( 0, mapPt );
831 if ( mRubberBand->numberOfVertices() )
832 mRubberBand->movePoint( mapPt );
834 std::unique_ptr< QgsCompoundCurve > tempCurve( mCaptureCurve.clone() );
841 tempCurve->addCurve(
new QgsLineString( tempCurve->endPoint(), hoverPointTargetCrs ) );
850 auto curvePolygon = std::make_unique< QgsCurvePolygon >();
852 curvePolygon->setExteriorRing( tempCurve.release() );
860 else if ( mTempRubberBand )
861 mTempRubberBand->movePoint(
mapPoint );
875 const bool is3D = layerPoint.
is3D();
876 const bool isMeasure = layerPoint.
isMeasure();
878 layerPoint =
QgsPoint( layerPoint.
wkbType(), mapP.
x(), mapP.
y(), layerPoint.
z(), layerPoint.
m() );
886 QgsDebugError( u
"transformation to layer coordinate failed"_s );
918 if ( match.
isValid() && sourceLayer )
922 if ( sourceLayer->
crs() != vlayer->
crs() )
1005 mCaptureCurve.addVertex( layerPoint );
1006 mSnappingMatches.append( match );
1010 if ( mCaptureFirstPoint.isEmpty() )
1019 if ( !mLayerPreviewRubberBand )
1025 if ( !mTempRubberBand )
1027 mTempRubberBand.reset( createCurveRubberBand() );
1028 mTempRubberBand->setStringType( mLineDigitizingType );
1032 bool traceCreated =
false;
1033 if ( tracingEnabled() )
1035 traceCreated = tracingAddVertex(
mapPoint );
1040 mTracingStartPoint = traceCreated ? point :
QgsPointXY();
1042 if ( !traceCreated )
1045 mTempRubberBand->movePoint(
mapPoint );
1046 if ( mTempRubberBand->curveIsComplete() )
1048 if (
QgsCurve *curve = mTempRubberBand->curve() )
1053 if ( match.
isValid() && mSnappingMatches.count() > 0 && !mSnappingMatches.last().isValid() )
1055 mSnappingMatches.removeLast();
1059 mSnappingMatches.removeLast();
1060 mSnappingMatches.append( mCircularIntermediateMatch );
1062 mSnappingMatches.append( match );
1068 else if ( mTempRubberBand->pointsCount() == 0 )
1071 mCaptureCurve.addVertex( layerPoint );
1072 mSnappingMatches.append( match );
1078 mCircularIntermediateMatch = match;
1082 mTempRubberBand->addPoint(
mapPoint );
1087 mTempRubberBand->addPoint( mCaptureLastPoint );
1091 updateExtraSnapLayer();
1108 if ( !mLayerPreviewRubberBand )
1114 if ( mTempRubberBand )
1118 mTempRubberBand->addPoint( endPt );
1121 const int countBefore = mCaptureCurve.vertexCount();
1123 if ( mCaptureCurve.numPoints() == 1 )
1124 mCaptureCurve.removeCurve( 0 );
1134 mCaptureCurve.addCurve( segmented,
false );
1141 mCaptureCurve.addCurve(
c, !mStartNewCurve );
1144 mStartNewCurve =
false;
1146 const int countAfter = mCaptureCurve.vertexCount();
1147 const int addedPoint = countAfter - countBefore;
1149 updateExtraSnapLayer();
1151 for (
int i = 0; i < addedPoint; ++i )
1161 mCaptureCurve.clear();
1162 updateExtraSnapLayer();
1167 return mSnappingMatches;
1179 mBezierData->deleteAnchor( mBezierData->anchorCount() - 1 );
1180 if ( mBezierMarker )
1181 mBezierMarker->updateFromData( *mBezierData );
1183 mBezierDragging =
false;
1184 mBezierDragAnchorIndex = -1;
1185 mBezierDragHandleIndex = -1;
1186 mBezierMoveAnchorIndex = -1;
1191 if ( mTempRubberBand )
1198 const QgsPoint lastPoint = mTempRubberBand->lastPoint();
1199 mTempRubberBand->removeLastPoint();
1200 mTempRubberBand->movePoint( lastPoint );
1205 if (
size() <= 1 && mTempRubberBand->pointsCount() != 0 )
1208 if ( isAutoRepeat && mIgnoreSubsequentAutoRepeatUndo )
1210 mIgnoreSubsequentAutoRepeatUndo =
false;
1212 const QgsPoint lastPoint = mTempRubberBand->lastPoint();
1216 mTempRubberBand->removeLastPoint();
1217 mTempRubberBand->movePoint( lastPoint );
1224 mTempRubberBand->removeLastPoint();
1225 mTempRubberBand->movePoint( lastPoint );
1231 vertexToRemove.
part = 0;
1232 vertexToRemove.
ring = 0;
1239 const int previousCurveIndex = mCaptureCurve.nCurves() - 1;
1240 const QgsCurve *curve = mCaptureCurve.curveAt( previousCurveIndex );
1242 mCaptureCurve.removeCurve( previousCurveIndex );
1244 if ( mCaptureCurve.numPoints() == 2 && mCaptureCurve.nCurves() == 1 )
1248 const QgsPoint fp = mCaptureCurve.startPoint();
1250 mCaptureCurve.addVertex( fp );
1254 const int curvesBefore = mCaptureCurve.nCurves();
1257 const int pointsCountBefore = mCaptureCurve.numPoints();
1258 mCaptureCurve.deleteVertex( vertexToRemove );
1259 int pointsCountAfter = mCaptureCurve.numPoints();
1260 for ( ; pointsCountAfter < pointsCountBefore; pointsCountAfter++ )
1261 if ( !mSnappingMatches.empty() )
1262 mSnappingMatches.removeLast();
1268 if ( mCaptureCurve.nCurves() < curvesBefore && lastCurveIsLineString )
1269 mIgnoreSubsequentAutoRepeatUndo =
true;
1272 updateExtraSnapLayer();
1278 if ( mCaptureCurve.numPoints() > 0 )
1280 const QgsPoint lastPt = mCaptureCurve.endPoint();
1282 mTempRubberBand->addPoint( mCaptureLastPoint );
1283 mTempRubberBand->movePoint( lastPoint );
1293 if ( mCaptureCurve.numPoints() > 0 )
1295 std::unique_ptr< QgsCompoundCurve > tempCurve( mCaptureCurve.clone() );
1298 auto curvePolygon = std::make_unique< QgsCurvePolygon >();
1300 curvePolygon->setExteriorRing( tempCurve.release() );
1319 mCurrentShapeMapTool->keyPressEvent( e );
1320 if ( e->isAccepted() )
1331 if ( e->key() == Qt::Key_Backspace || e->key() == Qt::Key_Delete )
1335 if ( !e->isAutoRepeat() )
1337 mCurrentShapeMapTool->undo();
1342 undo( e->isAutoRepeat() );
1348 else if ( e->key() == Qt::Key_Escape )
1350 if ( mCurrentShapeMapTool )
1351 mCurrentShapeMapTool->clean();
1358 else if ( e->key() == Qt::Key_W && !e->isAutoRepeat() )
1363 mWeightEditMode =
true;
1365 mWeightEditControlPointIndex = mTempRubberBand->pointsCount() - 2;
1370 cadDockWidget()->
setWeight( QString::number( mTempRubberBand->weight( mWeightEditControlPointIndex ),
'f', 2 ),
true );
1379 if ( e->key() == Qt::Key_W && !e->isAutoRepeat() )
1381 if ( mWeightEditMode )
1383 mWeightEditMode =
false;
1384 mWeightEditControlPointIndex = -1;
1402 if ( mWeightEditMode )
1408 double adjustment = e->angleDelta().y() > 0 ? 0.1 : -0.1;
1409 if ( e->modifiers() & Qt::ControlModifier )
1411 else if ( e->modifiers() & Qt::ShiftModifier )
1414 const double currentWeight = mTempRubberBand->weight( mWeightEditControlPointIndex );
1415 const double newWeight = std::max( 0.01, currentWeight + adjustment );
1417 if ( mTempRubberBand->setWeight( mWeightEditControlPointIndex, newWeight ) )
1444 mRubberBand.reset();
1445 mLayerPreviewRubberBand.reset();
1450 if ( mWeightEditMode )
1452 mWeightEditMode =
false;
1453 mWeightEditControlPointIndex = -1;
1460 qDeleteAll( mGeomErrorMarkers );
1461 mGeomErrorMarkers.clear();
1462 mGeomErrors.clear();
1470 mCaptureCurve.clear();
1471 updateExtraSnapLayer();
1472 mSnappingMatches.clear();
1475 if ( mBezierMarker )
1476 mBezierMarker->clear();
1477 mBezierData.reset();
1478 mBezierMarker.reset();
1479 mBezierDragging =
false;
1480 mBezierDragAnchorIndex = -1;
1483 lCurrentVectorLayer->triggerRepaint();
1490 mTempRubberBand.reset();
1497 mCurrentShapeMapTool->clean();
1504 mCaptureCurve.close();
1505 updateExtraSnapLayer();
1508void QgsMapToolCapture::validateGeometry()
1515 mValidator->deleteLater();
1516 mValidator =
nullptr;
1519 mGeomErrors.clear();
1520 while ( !mGeomErrorMarkers.isEmpty() )
1522 delete mGeomErrorMarkers.takeFirst();
1527 switch ( mCaptureMode )
1535 geom = QgsGeometry( mCaptureCurve.curveToLine() );
1540 QgsLineString *exteriorRing = mCaptureCurve.curveToLine();
1541 exteriorRing->
close();
1542 QgsPolygon *polygon =
new QgsPolygon();
1544 geom = QgsGeometry( polygon );
1552 mValidator =
new QgsGeometryValidator( geom,
nullptr, method );
1554 mValidator->start();
1561 QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>(
layer() );
1567 QgsVertexMarker *vm =
new QgsVertexMarker(
mCanvas );
1571 vm->setToolTip( e.
what() );
1573 vm->setZValue( vm->zValue() + 1 );
1574 mGeomErrorMarkers << vm;
1580 return mCaptureCurve.numPoints();
1585 QVector<QgsPointXY> pointsXY;
1594 mCaptureCurve.points( pts );
1601 mCaptureCurve.clear();
1602 mCaptureCurve.addCurve( line );
1603 updateExtraSnapLayer();
1604 mSnappingMatches.clear();
1605 for (
int i = 0; i < line->
length(); ++i )
1613 mCaptureCurve.clear();
1614 mCaptureCurve.addCurve( line );
1615 updateExtraSnapLayer();
1616 mSnappingMatches.clear();
1617 for (
int i = 0; i < line->
length(); ++i )
1674 if ( match.
layer() )
1692void QgsMapToolCapture::updateExtraSnapLayer()
1694 if ( !mExtraSnapLayer )
1697 if (
canvas()->snappingUtils()->config().selfSnapping() &&
layer() )
1708 auto collection = std::make_unique<QgsGeometryCollection>();
1711 const int pointCount = mTempRubberBand->pointsCount();
1713 for (
int i = 0; i < pointCount - 1; ++i )
1715 collection->addGeometry(
new QgsPoint( mTempRubberBand->pointFromEnd( pointCount - 1 - i ) ) );
1719 std::unique_ptr<QgsCurve> nurbsCurve( mTempRubberBand->curve() );
1722 std::unique_ptr<QgsLineString> curvePoints( nurbsCurve->curveToLine() );
1726 if ( mCaptureMode ==
CapturePolygon && curvePoints->numPoints() >= 3 )
1728 curvePoints->close();
1730 collection->addGeometry( curvePoints.release() );
1734 geom = QgsGeometry( collection.release() );
1736 else if ( mBezierData && mBezierData->anchorCount() >= 2 )
1739 auto collection = std::make_unique<QgsGeometryCollection>();
1742 const QVector<QgsPoint> anchors = mBezierData->anchors();
1743 for (
const QgsPoint &point : anchors )
1745 collection->addGeometry(
new QgsPoint( point ) );
1749 const QVector<QgsPoint> handles = mBezierData->handles();
1750 for (
const QgsPoint &point : handles )
1752 collection->addGeometry(
new QgsPoint( point ) );
1757 if ( !interpolated.isEmpty() )
1759 auto curveLineString = std::make_unique<QgsLineString>( interpolated );
1761 if ( mCaptureMode ==
CapturePolygon && curveLineString->numPoints() >= 3 )
1763 curveLineString->close();
1765 collection->addGeometry( curveLineString.release() );
1768 geom = QgsGeometry( collection.release() );
1770 else if ( mCaptureCurve.numPoints() >= 2 )
1773 geom = QgsGeometry( mCaptureCurve.clone() );
1775 if ( mCaptureMode ==
CapturePolygon && mCaptureCurve.numPoints() >= 3 )
1781 mExtraSnapLayer->changeGeometry( mExtraSnapFeatureId, geom );
1786 mExtraSnapLayer->changeGeometry( mExtraSnapFeatureId, geom );
1792 QgsReferencedGeometry correctedGeometry = geometry;
1799 auto convertedToPolygon = std::make_unique< QgsCurvePolygon >();
1800 convertedToPolygon->setExteriorRing( curve->clone() );
1801 correctedGeometry = QgsReferencedGeometry( QgsGeometry( std::move( convertedToPolygon ) ), correctedGeometry.
crs() );
1809 correctedGeometry = QgsReferencedGeometry( QgsGeometry( std::move( exterior ) ), correctedGeometry.
crs() );
1813 onTransientGeometryChanged( correctedGeometry );
1821 if ( e->button() != Qt::LeftButton )
1825 bool isMatchPointZ =
false;
1826 bool isMatchPointM =
false;
1837 if ( isMatchPointM && isMatchPointZ )
1841 else if ( isMatchPointM )
1845 else if ( isMatchPointZ )
1849 savePoint =
QgsPoint( geomType, fetchPoint.
x(), fetchPoint.
y(), fetchPoint.
z(), fetchPoint.
m() );
1855 savePoint =
QgsPoint( point.
x(), point.
y(), fetchPoint.
z(), fetchPoint.
m() );
1865 QgsGeometry g( std::make_unique<QgsPoint>( savePoint ) );
1882 bool digitizingFinished =
false;
1884 QVector<double> nurbsWeights;
1889 if ( e->button() == Qt::LeftButton )
1892 mBezierDragging =
false;
1893 mBezierDragAnchorIndex = -1;
1894 mBezierDragHandleIndex = -1;
1895 mBezierMoveAnchorIndex = -1;
1898 if ( mBezierMarker )
1900 mBezierMarker->setHighlightedAnchor( -1 );
1901 mBezierMarker->setHighlightedHandle( -1 );
1902 mBezierMarker->updateFromData( *mBezierData );
1907 else if ( e->button() == Qt::RightButton )
1910 mBezierDragging =
false;
1911 mBezierDragAnchorIndex = -1;
1912 mBezierDragHandleIndex = -1;
1913 mBezierMoveAnchorIndex = -1;
1915 if ( mBezierData && mBezierData->anchorCount() >= 2 )
1918 std::unique_ptr<QgsNurbsCurve> nurbsCurve = mBezierData->asNurbsCurve();
1941 std::unique_ptr<QgsCurve> curveToAdd;
1947 auto compound = std::make_unique<QgsCompoundCurve>();
1948 compound->addCurve( nurbsCurve.release() );
1950 auto closingSegment = std::make_unique<QgsLineString>();
1951 closingSegment->addVertex( compound->endPoint() );
1952 closingSegment->addVertex( compound->startPoint() );
1953 compound->addCurve( closingSegment.release() );
1954 curveToAdd = std::move( compound );
1958 curveToAdd.reset( nurbsCurve.release() );
1970 auto poly = std::make_unique<QgsCurvePolygon>();
1971 poly->setExteriorRing( curveToAdd.release() );
1977 digitizingFinished =
true;
1982 if ( mBezierMarker )
1983 mBezierMarker->clear();
1984 mBezierData.reset();
1985 mBezierMarker.reset();
1993 if ( !mCurrentShapeMapTool )
2000 if ( !mTempRubberBand )
2002 mTempRubberBand.reset( createCurveRubberBand() );
2003 mTempRubberBand->setStringType( mLineDigitizingType );
2007 digitizingFinished = mCurrentShapeMapTool->cadCanvasReleaseEvent( e, mCaptureMode );
2008 if ( digitizingFinished )
2009 mCurrentShapeMapTool->clean();
2015 if ( e->button() == Qt::LeftButton )
2027 else if ( e->button() == Qt::RightButton )
2034 const int rbPointCount = mTempRubberBand->pointsCount();
2035 if ( rbPointCount > 1 )
2038 for (
int i = 0; i < rbPointCount - 1; ++i )
2040 nurbsControlPoints.append( mTempRubberBand->pointFromEnd( rbPointCount - 1 - i ) );
2043 const QVector<double> &rbWeights = mTempRubberBand->weights();
2044 for (
int i = 0; i < rbPointCount - 1; ++i )
2046 if ( i < rbWeights.size() )
2047 nurbsWeights.append( rbWeights[i] );
2049 nurbsWeights.append( 1.0 );
2092 nurbsControlPoints.append( nurbsControlPoints.first() );
2093 if ( !nurbsWeights.isEmpty() )
2094 nurbsWeights.append( nurbsWeights.first() );
2102 digitizingFinished =
true;
2106 if ( digitizingFinished )
2109 std::unique_ptr<QgsCurve> curveToAdd;
2116 const int n = nurbsControlPoints.size();
2119 if ( n < degree + 1 )
2121 degree = std::max( 1, n - 1 );
2124 curveToAdd = std::make_unique<QgsLineString>( nurbsControlPoints );
2131 const int knotCount = n + degree + 1;
2132 QVector<double> knots( knotCount );
2135 for (
int i = 0; i <= degree; ++i )
2139 for (
int i = knotCount - degree - 1; i < knotCount; ++i )
2143 const int numMiddleKnots = n - degree - 1;
2144 for (
int i = 0; i < numMiddleKnots; ++i )
2146 knots[degree + 1 + i] =
static_cast<double>( i + 1 ) / ( numMiddleKnots + 1 );
2150 QVector<double> weights = nurbsWeights;
2151 while ( weights.size() < n )
2152 weights.append( 1.0 );
2153 weights.resize( n );
2155 curveToAdd = std::make_unique<QgsNurbsCurve>( nurbsControlPoints, degree, knots, weights );
2197 if ( compound->nCurves() == 1 )
2201 curveToAdd.reset( circularPart->clone() );
2225 if ( hasCurvedSegments && providerSupportsCurvedSegments )
2239 auto poly = std::make_unique<QgsCurvePolygon>();
2240 poly->setExteriorRing( curveToAdd.release() );
@ CircularGeometries
Supports circular geometry types (circularstring, compoundcurve, curvepolygon).
CaptureTechnique
Capture technique.
@ NurbsCurve
Digitizes NURBS curves with control points (curve is attracted to but does not pass through control p...
@ StraightSegments
Default capture mode - capture occurs with straight line segments.
@ CircularString
Capture in circular strings.
@ Streaming
Streaming points digitizing mode (points are automatically added as the mouse cursor moves).
@ PolyBezier
Digitizes poly-Bézier curves with anchors and tangent handles (curve passes through anchor points).
GeometryValidationEngine
Available engines for validating geometries.
@ Warning
Warning message.
@ PreviewItems
Preview overlayer items.
WkbType
The WKB type describes the number of dimensions a geometry has.
@ CompoundCurve
CompoundCurve.
@ CircularString
CircularString.
@ Reverse
Reverse/inverse transform (from destination to source).
bool isMeasure() const
Returns true if the geometry contains m values.
bool is3D() const
Returns true if the geometry is 3D and contains a z-value.
virtual QgsPoint vertexAt(QgsVertexId id) const =0
Returns the point corresponding to a specified vertex id.
Qgis::WkbType wkbType() const
Returns the WKB type of the geometry.
static QCursor getThemeCursor(Cursor cursor)
Helper to get a theme cursor.
@ CapturePoint
Select and capture a point or a feature.
Circular string geometry type.
Compound curve geometry type.
bool hasCurvedSegments() const override
Returns true if the geometry contains curved segments.
Represents a coordinate reference system (CRS).
Custom exception class for Coordinate Reference System related exceptions.
const QgsCurve * exteriorRing() const
Returns the curve polygon's exterior ring.
Abstract base class for curved geometry type.
virtual int numPoints() const =0
Returns the number of points in the curve.
QgsCurve * clone() const override=0
Clones the geometry by performing a deep copy.
bool nextFeature(QgsFeature &f)
Fetch next feature and stores in f, returns true on success.
Wraps a request for features to a vector layer (or directly its vector data provider).
QgsFeatureRequest & setFilterFid(QgsFeatureId fid)
Sets the feature ID that should be fetched.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
void errorFound(const QgsGeometry::Error &error)
Sent when an error has been found during the validation process.
static Qgis::GeometryValidationEngine defaultValidationEngine()
Returns the geometry validation engine configured in the application settings.
bool hasWhere() const
true if the location available from
QgsPointXY where() const
The coordinates at which the error is located and should be visualized.
QString what() const
A human readable error message containing details about the error.
A geometry is the spatial representation of a feature.
bool vertexIdFromVertexNr(int number, QgsVertexId &id) const
Calculates the vertex ID from a vertex number.
QgsPoint vertexAt(int atVertex) const
Returns coordinates of a vertex.
QgsAbstractGeometry * get()
Returns a modifiable (non-const) reference to the underlying abstract geometry primitive.
const QgsAbstractGeometry * constGet() const
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
QgsGeometry convertToCurves(double distanceTolerance=1e-8, double angleTolerance=1e-8) const
Attempts to convert a non-curved geometry into a curved geometry type (e.g.
static void convertPointList(const QVector< QgsPointXY > &input, QgsPointSequence &output)
Upgrades a point list from QgsPointXY to QgsPoint.
Qgis::WkbType wkbType() const
Returns type of the geometry as a WKB type (point / linestring / polygon etc.).
Line string geometry type, with support for z-dimension and m-values.
double length() const override
Returns the planar, 2-dimensional length of the geometry.
void close()
Closes the line string by appending the first point to the end of the line, if it is not already clos...
QAction * actionEnableSnapping() const
Access to action that user may use to toggle snapping on/off.
void reportError(PathError err, bool addingVertex)
Report a path finding error to the user.
QAction * actionEnableTracing() const
Access to action that user may use to toggle tracing on/off. May be nullptr if no action was associat...
static QgsMapCanvasTracer * tracerForCanvas(QgsMapCanvas *canvas)
Retrieve instance of this class associated with given canvas (if any).
void currentLayerChanged(QgsMapLayer *layer)
Emitted when the current layer is changed.
Base class for all map layer types.
QgsCoordinateReferenceSystem crs
void setCrs(const QgsCoordinateReferenceSystem &srs, bool emitSignal=true)
Sets layer's spatial reference system.
A mouse event which is the result of a user interaction with a QgsMapCanvas.
bool isSnapped() const
Returns true if there is a snapped point cached.
QgsPointXY mapPoint() const
mapPoint returns the point in coordinates
QgsPointLocator::Match mapPointMatch() const
Returns the matching data from the most recently snapped point.
Point geometry type, with support for z-dimension and m-values.
bool addMValue(double mValue=0) override
Adds a measure to the geometry, initialized to a preset value.
bool dropMValue() override
Drops any measure values which exist in the geometry.
bool addZValue(double zValue=0) override
Adds a z-dimension to the geometry, initialized to a preset value.
bool deleteVertex(QgsVertexId position) override
Deletes a vertex within the geometry.
void setM(double m)
Sets the point's m-value.
bool convertTo(Qgis::WkbType type) override
Converts the geometry to a specified type.
void transform(const QgsCoordinateTransform &ct, Qgis::TransformDirection d=Qgis::TransformDirection::Forward, bool transformZ=false) override
Transforms the geometry using a coordinate transform.
void setZ(double z)
Sets the point's z-coordinate.
bool dropZValue() override
Drops any z-dimensions which exist in the geometry.
void setExteriorRing(QgsCurve *ring) override
Sets the exterior ring of the polygon.
static QgsProject * instance()
Returns the QgsProject singleton instance.
void snappingConfigChanged(const QgsSnappingConfig &config)
Emitted whenever the configuration for snapping has changed.
QgsCoordinateTransformContext transformContext
QgsCoordinateReferenceSystem crs() const
Returns the associated coordinate reference system, or an invalid CRS if no reference system is set.
A QgsGeometry with associated coordinate reference system.
Responsible for drawing transient features (e.g.
T value(const QString &dynamicKeyPart=QString()) const
Returns settings value.
static const QgsSettingsEntryInteger * settingsDigitizingStreamTolerance
Settings entry digitizing stream tolerance.
static const QgsSettingsEntryDouble * settingsDigitizingLineColorAlphaScale
Settings entry digitizing line color alpha scale.
static const QgsSettingsEntryInteger * settingsDigitizingNurbsDegree
Settings entry digitizing NURBS curve degree.
static const QgsSettingsEntryDouble * settingsDigitizingConvertToCurveAngleTolerance
Settings entry digitizing convert to curve angle tolerance.
static const QgsSettingsEntryDouble * settingsDigitizingConvertToCurveDistanceTolerance
Settings entry digitizing convert to curve distance tolerance.
static const QgsSettingsEntryInteger * settingsDigitizingValidateGeometries
Settings entry digitizing validate geometries.
static const QgsSettingsEntryBool * settingsDigitizingConvertToCurve
Settings entry digitizing convert to curve.
bool transform(QgsAbstractGeometryTransformer *transformer, QgsFeedback *feedback=nullptr) override
Transforms the vertices from the geometry in place, using the specified geometry transformer object.
bool isPointSnapped(const QgsPointXY &pt)
Find out whether the point is snapped to a vertex or edge (i.e. it can be used for tracing start/stop...
QVector< QgsPointXY > findShortestPath(const QgsPointXY &p1, const QgsPointXY &p2, PathError *error=nullptr)
Given two points, find the shortest path and return points on the way.
PathError
Possible errors that may happen when calling findShortestPath().
@ ErrTooManyFeatures
Max feature count threshold was reached while reading features.
bool init()
Build the internal data structures.
virtual Q_INVOKABLE Qgis::VectorProviderCapabilities capabilities() const
Returns flags containing the supported capabilities.
Represents a vector layer which manages a vector based dataset.
bool isSpatial() const final
Returns true if this is a geometry layer and false in case of NoGeometry (table only) or UnknownGeome...
Q_INVOKABLE Qgis::WkbType wkbType() const final
Returns the WKBType or WKBUnknown in case of error.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const final
Queries the layer for features specified in request.
Q_INVOKABLE Qgis::GeometryType geometryType() const
Returns point, line or polygon.
Q_INVOKABLE QgsFeature getFeature(QgsFeatureId fid) const
Queries the layer for the feature with the given id.
QgsVectorDataProvider * dataProvider() final
Returns the layer's data provider, it may be nullptr.
void setPenWidth(int width)
void setCenter(const QgsPointXY &point)
Sets the center point of the marker, in map coordinates.
void setIconType(int iconType)
void setColor(const QColor &color)
Sets the stroke color for the marker.
static Q_INVOKABLE bool hasZ(Qgis::WkbType type)
Tests whether a WKB type contains the z-dimension.
static Q_INVOKABLE bool hasM(Qgis::WkbType type)
Tests whether a WKB type contains m values.
static Q_INVOKABLE bool isNurbsType(Qgis::WkbType type)
Returns true if the WKB type is a NURBS curve type.
static Qgis::WkbType flatType(Qgis::WkbType type)
Returns the flat type for a WKB type.
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
#define BUILTIN_UNREACHABLE
T qgsgeometry_cast(QgsAbstractGeometry *geom)
QVector< QgsPoint > QgsPointSequence
#define QgsDebugMsgLevel(str, level)
#define QgsDebugError(str)
QgsFeatureId featureId() const
The id of the feature to which the snapped geometry belongs.
QgsVectorLayer * layer() const
The vector layer where the snap occurred.
QgsPoint interpolatedPoint(const QgsCoordinateReferenceSystem &destinationCrs=QgsCoordinateReferenceSystem()) const
Convenient method to return a point on an edge with linear interpolation of the Z value.
bool hasEdge() const
Returns true if the Match is an edge.
bool hasLineEndpoint() const
Returns true if the Match is a line endpoint (start or end vertex).
bool hasMiddleSegment() const
Returns true if the Match is the middle of a segment.
int vertexIndex() const
for vertex / edge match (first vertex of the edge)
bool hasVertex() const
Returns true if the Match is a vertex.
Setting options for loading vector layers.
bool skipCrsValidation
Controls whether the layer is allowed to have an invalid/unknown CRS.
bool loadDefaultStyle
Set to true if the default layer style should be loaded.
Utility class for identifying a unique vertex within a geometry.