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() );
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 return mRubberBand.release();
478 if ( mCurrentCaptureTechnique == technique )
481 mStartNewCurve =
true;
485 setCurrentShapeMapToolIsActivated(
false );
510 if ( mTempRubberBand )
511 mTempRubberBand->setStringType( mLineDigitizingType );
513 mCurrentCaptureTechnique = technique;
518 setCurrentShapeMapToolIsActivated(
true );
524 if ( mCurrentShapeMapTool )
526 if ( shapeMapToolMetadata && mCurrentShapeMapTool->
id() == shapeMapToolMetadata->
id() )
530 setCurrentShapeMapToolIsActivated(
false );
532 mCurrentShapeMapTool->deleteLater();
535 mCurrentShapeMapTool.reset( shapeMapToolMetadata ? shapeMapToolMetadata->
factory(
this ) :
nullptr );
540 if ( mCurrentShapeMapTool )
542 setCurrentShapeMapToolIsActivated(
true );
552 if ( e->button() == Qt::LeftButton )
558 mBezierData = std::make_unique<QgsBezierData>();
559 if ( !mBezierMarker )
560 mBezierMarker = std::make_unique<QgsBezierMarker>(
mCanvas );
565 mBezierDragAnchorIndex = -1;
566 mBezierDragHandleIndex = -1;
567 mBezierMoveAnchorIndex = -1;
570 const int handleIdx = mBezierData->findClosestHandle(
mapPoint, tolerance );
571 if ( handleIdx >= 0 )
574 mBezierDragHandleIndex = handleIdx;
575 mBezierDragging =
true;
576 mBezierMarker->setHighlightedHandle( handleIdx );
581 const int anchorIdx = mBezierData->findClosestAnchor(
mapPoint, tolerance );
582 if ( anchorIdx >= 0 )
584 if ( e->modifiers() & Qt::AltModifier )
587 mBezierDragAnchorIndex = anchorIdx;
588 mBezierDragging =
true;
589 mBezierMarker->setHighlightedAnchor( anchorIdx );
594 mBezierMoveAnchorIndex = anchorIdx;
595 mBezierDragging =
true;
596 mBezierMarker->setHighlightedAnchor( anchorIdx );
603 mBezierDragAnchorIndex = mBezierData->anchorCount() - 1;
604 mBezierDragging =
true;
607 mBezierMarker->updateFromData( *mBezierData );
621 if ( mCaptureModeFromLayer && ( !
canvas()->currentLayer() || !
canvas()->currentLayer()->isSpatial() ) )
632 if ( !mCurrentShapeMapTool )
638 if ( !mTempRubberBand )
640 mTempRubberBand.reset( createCurveRubberBand() );
641 mTempRubberBand->setStringType( mLineDigitizingType );
645 mCurrentShapeMapTool->cadCanvasMoveEvent( e, mCaptureMode );
660 const int handleIdx = mBezierData->findClosestHandle(
mapPoint, tolerance );
662 const int anchorIdx = mBezierData->findClosestAnchor(
mapPoint, tolerance );
664 if ( handleIdx >= 0 || anchorIdx >= 0 )
676 if ( mBezierDragging && mBezierData )
678 if ( mBezierDragHandleIndex >= 0 )
681 mBezierData->moveHandle( mBezierDragHandleIndex,
mapPoint );
683 else if ( mBezierDragAnchorIndex >= 0 )
686 mBezierData->calculateSymmetricHandles( mBezierDragAnchorIndex,
mapPoint );
691 mBezierMarker->updateFromData( *mBezierData );
694 else if ( mBezierData && mBezierData->anchorCount() > 0 && mBezierMarker && mCapturing )
696 QgsBezierData previewData = *mBezierData;
699 mBezierMarker->updateCurve( previewData );
703 if ( !mTempRubberBand )
705 mTempRubberBand.reset( createCurveRubberBand() );
706 mTempRubberBand->setStringType( mLineDigitizingType );
714 mTempRubberBand->addPoint( pt );
720 targetCrs = l->crs();
725 auto lineString = std::make_unique<QgsLineString>(
points );
729 auto curvePolygon = std::make_unique<QgsCurvePolygon>();
731 curvePolygon->setExteriorRing( lineString.release() );
750 targetCrs = l->crs();
753 if ( mCaptureMode !=
CapturePoint && mTempRubberBand && mCapturing )
755 bool hasTrace =
false;
759 if ( !mCaptureCurve.isEmpty() )
761 const QgsPoint prevPoint = mCaptureCurve.curveAt( mCaptureCurve.nCurves() - 1 )->endPoint();
766 mAllowAddingStreamingPoints =
true;
768 mAllowAddingStreamingPoints =
false;
770 std::unique_ptr< QgsCompoundCurve > tempCurve( mCaptureCurve.clone() );
773 auto curvePolygon = std::make_unique< QgsCurvePolygon >();
775 curvePolygon->setExteriorRing( tempCurve.release() );
783 else if ( tracingEnabled() && mCaptureCurve.numPoints() != 0 )
789 mCircularItermediatePoint = mTempRubberBand->pointFromEnd( 1 );
791 mCircularItermediatePoint =
QgsPoint();
793 hasTrace = tracingMouseMove( e );
799 mTempRubberBand->addPoint( mCaptureLastPoint );
800 if ( !mCircularItermediatePoint.isEmpty() )
802 mTempRubberBand->movePoint( mCircularItermediatePoint );
803 mTempRubberBand->addPoint( mCircularItermediatePoint );
810 if ( mCaptureCurve.numPoints() > 0 )
812 const QgsPoint mapPt = mCaptureLastPoint;
814 if ( mTempRubberBand )
816 mTempRubberBand->movePoint(
mapPoint );
817 mTempRubberBand->movePoint( 0, mapPt );
821 if ( mRubberBand->numberOfVertices() )
822 mRubberBand->movePoint( mapPt );
824 std::unique_ptr< QgsCompoundCurve > tempCurve( mCaptureCurve.clone() );
831 tempCurve->addCurve(
new QgsLineString( tempCurve->endPoint(), hoverPointTargetCrs ) );
840 auto curvePolygon = std::make_unique< QgsCurvePolygon >();
842 curvePolygon->setExteriorRing( tempCurve.release() );
850 else if ( mTempRubberBand )
851 mTempRubberBand->movePoint(
mapPoint );
865 const bool is3D = layerPoint.
is3D();
866 const bool isMeasure = layerPoint.
isMeasure();
868 layerPoint =
QgsPoint( layerPoint.
wkbType(), mapP.
x(), mapP.
y(), layerPoint.
z(), layerPoint.
m() );
876 QgsDebugError( u
"transformation to layer coordinate failed"_s );
908 if ( match.
isValid() && sourceLayer )
912 if ( sourceLayer->
crs() != vlayer->
crs() )
995 mCaptureCurve.addVertex( layerPoint );
996 mSnappingMatches.append( match );
1000 if ( mCaptureFirstPoint.isEmpty() )
1008 if ( !mTempRubberBand )
1010 mTempRubberBand.reset( createCurveRubberBand() );
1011 mTempRubberBand->setStringType( mLineDigitizingType );
1015 bool traceCreated =
false;
1016 if ( tracingEnabled() )
1018 traceCreated = tracingAddVertex(
mapPoint );
1023 mTracingStartPoint = traceCreated ? point :
QgsPointXY();
1025 if ( !traceCreated )
1028 mTempRubberBand->movePoint(
mapPoint );
1029 if ( mTempRubberBand->curveIsComplete() )
1031 if (
QgsCurve *curve = mTempRubberBand->curve() )
1036 if ( match.
isValid() && mSnappingMatches.count() > 0 && !mSnappingMatches.last().isValid() )
1038 mSnappingMatches.removeLast();
1042 mSnappingMatches.removeLast();
1043 mSnappingMatches.append( mCircularIntermediateMatch );
1045 mSnappingMatches.append( match );
1051 else if ( mTempRubberBand->pointsCount() == 0 )
1054 mCaptureCurve.addVertex( layerPoint );
1055 mSnappingMatches.append( match );
1061 mCircularIntermediateMatch = match;
1065 mTempRubberBand->addPoint(
mapPoint );
1070 mTempRubberBand->addPoint( mCaptureLastPoint );
1074 updateExtraSnapLayer();
1092 if ( mTempRubberBand )
1096 mTempRubberBand->addPoint( endPt );
1099 const int countBefore = mCaptureCurve.vertexCount();
1101 if ( mCaptureCurve.numPoints() == 1 )
1102 mCaptureCurve.removeCurve( 0 );
1112 mCaptureCurve.addCurve( segmented,
false );
1119 mCaptureCurve.addCurve(
c, !mStartNewCurve );
1122 mStartNewCurve =
false;
1124 const int countAfter = mCaptureCurve.vertexCount();
1125 const int addedPoint = countAfter - countBefore;
1127 updateExtraSnapLayer();
1129 for (
int i = 0; i < addedPoint; ++i )
1139 mCaptureCurve.clear();
1140 updateExtraSnapLayer();
1145 return mSnappingMatches;
1157 mBezierData->deleteAnchor( mBezierData->anchorCount() - 1 );
1158 if ( mBezierMarker )
1159 mBezierMarker->updateFromData( *mBezierData );
1161 mBezierDragging =
false;
1162 mBezierDragAnchorIndex = -1;
1163 mBezierDragHandleIndex = -1;
1164 mBezierMoveAnchorIndex = -1;
1169 if ( mTempRubberBand )
1176 const QgsPoint lastPoint = mTempRubberBand->lastPoint();
1177 mTempRubberBand->removeLastPoint();
1178 mTempRubberBand->movePoint( lastPoint );
1183 if (
size() <= 1 && mTempRubberBand->pointsCount() != 0 )
1186 if ( isAutoRepeat && mIgnoreSubsequentAutoRepeatUndo )
1188 mIgnoreSubsequentAutoRepeatUndo =
false;
1190 const QgsPoint lastPoint = mTempRubberBand->lastPoint();
1194 mTempRubberBand->removeLastPoint();
1195 mTempRubberBand->movePoint( lastPoint );
1202 mTempRubberBand->removeLastPoint();
1203 mTempRubberBand->movePoint( lastPoint );
1209 vertexToRemove.
part = 0;
1210 vertexToRemove.
ring = 0;
1217 const int previousCurveIndex = mCaptureCurve.nCurves() - 1;
1218 const QgsCurve *curve = mCaptureCurve.curveAt( previousCurveIndex );
1220 mCaptureCurve.removeCurve( previousCurveIndex );
1222 if ( mCaptureCurve.numPoints() == 2 && mCaptureCurve.nCurves() == 1 )
1226 const QgsPoint fp = mCaptureCurve.startPoint();
1228 mCaptureCurve.addVertex( fp );
1232 const int curvesBefore = mCaptureCurve.nCurves();
1235 const int pointsCountBefore = mCaptureCurve.numPoints();
1236 mCaptureCurve.deleteVertex( vertexToRemove );
1237 int pointsCountAfter = mCaptureCurve.numPoints();
1238 for ( ; pointsCountAfter < pointsCountBefore; pointsCountAfter++ )
1239 if ( !mSnappingMatches.empty() )
1240 mSnappingMatches.removeLast();
1246 if ( mCaptureCurve.nCurves() < curvesBefore && lastCurveIsLineString )
1247 mIgnoreSubsequentAutoRepeatUndo =
true;
1250 updateExtraSnapLayer();
1256 if ( mCaptureCurve.numPoints() > 0 )
1258 const QgsPoint lastPt = mCaptureCurve.endPoint();
1260 mTempRubberBand->addPoint( mCaptureLastPoint );
1261 mTempRubberBand->movePoint( lastPoint );
1273 mCurrentShapeMapTool->keyPressEvent( e );
1274 if ( e->isAccepted() )
1285 if ( e->key() == Qt::Key_Backspace || e->key() == Qt::Key_Delete )
1289 if ( !e->isAutoRepeat() )
1291 mCurrentShapeMapTool->undo();
1296 undo( e->isAutoRepeat() );
1302 else if ( e->key() == Qt::Key_Escape )
1304 if ( mCurrentShapeMapTool )
1305 mCurrentShapeMapTool->clean();
1312 else if ( e->key() == Qt::Key_W && !e->isAutoRepeat() )
1317 mWeightEditMode =
true;
1319 mWeightEditControlPointIndex = mTempRubberBand->pointsCount() - 2;
1324 cadDockWidget()->
setWeight( QString::number( mTempRubberBand->weight( mWeightEditControlPointIndex ),
'f', 2 ),
true );
1333 if ( e->key() == Qt::Key_W && !e->isAutoRepeat() )
1335 if ( mWeightEditMode )
1337 mWeightEditMode =
false;
1338 mWeightEditControlPointIndex = -1;
1356 if ( mWeightEditMode )
1362 double adjustment = e->angleDelta().y() > 0 ? 0.1 : -0.1;
1363 if ( e->modifiers() & Qt::ControlModifier )
1365 else if ( e->modifiers() & Qt::ShiftModifier )
1368 const double currentWeight = mTempRubberBand->weight( mWeightEditControlPointIndex );
1369 const double newWeight = std::max( 0.01, currentWeight + adjustment );
1371 if ( mTempRubberBand->setWeight( mWeightEditControlPointIndex, newWeight ) )
1398 mRubberBand.reset();
1403 if ( mWeightEditMode )
1405 mWeightEditMode =
false;
1406 mWeightEditControlPointIndex = -1;
1413 qDeleteAll( mGeomErrorMarkers );
1414 mGeomErrorMarkers.clear();
1415 mGeomErrors.clear();
1423 mCaptureCurve.clear();
1424 updateExtraSnapLayer();
1425 mSnappingMatches.clear();
1428 if ( mBezierMarker )
1429 mBezierMarker->clear();
1430 mBezierData.reset();
1431 mBezierMarker.reset();
1432 mBezierDragging =
false;
1433 mBezierDragAnchorIndex = -1;
1436 lCurrentVectorLayer->triggerRepaint();
1443 mTempRubberBand.reset();
1450 mCurrentShapeMapTool->clean();
1457 mCaptureCurve.close();
1458 updateExtraSnapLayer();
1461void QgsMapToolCapture::validateGeometry()
1468 mValidator->deleteLater();
1469 mValidator =
nullptr;
1472 mGeomErrors.clear();
1473 while ( !mGeomErrorMarkers.isEmpty() )
1475 delete mGeomErrorMarkers.takeFirst();
1480 switch ( mCaptureMode )
1488 geom = QgsGeometry( mCaptureCurve.curveToLine() );
1493 QgsLineString *exteriorRing = mCaptureCurve.curveToLine();
1494 exteriorRing->
close();
1495 QgsPolygon *polygon =
new QgsPolygon();
1497 geom = QgsGeometry( polygon );
1505 mValidator =
new QgsGeometryValidator( geom,
nullptr, method );
1507 mValidator->start();
1514 QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>(
layer() );
1520 QgsVertexMarker *vm =
new QgsVertexMarker(
mCanvas );
1524 vm->setToolTip( e.
what() );
1526 vm->setZValue( vm->zValue() + 1 );
1527 mGeomErrorMarkers << vm;
1533 return mCaptureCurve.numPoints();
1538 QVector<QgsPointXY> pointsXY;
1547 mCaptureCurve.points( pts );
1554 mCaptureCurve.clear();
1555 mCaptureCurve.addCurve( line );
1556 updateExtraSnapLayer();
1557 mSnappingMatches.clear();
1558 for (
int i = 0; i < line->
length(); ++i )
1566 mCaptureCurve.clear();
1567 mCaptureCurve.addCurve( line );
1568 updateExtraSnapLayer();
1569 mSnappingMatches.clear();
1570 for (
int i = 0; i < line->
length(); ++i )
1627 if ( match.
layer() )
1645void QgsMapToolCapture::updateExtraSnapLayer()
1647 if ( !mExtraSnapLayer )
1650 if (
canvas()->snappingUtils()->config().selfSnapping() &&
layer() )
1661 auto collection = std::make_unique<QgsGeometryCollection>();
1664 const int pointCount = mTempRubberBand->pointsCount();
1666 for (
int i = 0; i < pointCount - 1; ++i )
1668 collection->addGeometry(
new QgsPoint( mTempRubberBand->pointFromEnd( pointCount - 1 - i ) ) );
1672 std::unique_ptr<QgsCurve> nurbsCurve( mTempRubberBand->curve() );
1675 std::unique_ptr<QgsLineString> curvePoints( nurbsCurve->curveToLine() );
1679 if ( mCaptureMode ==
CapturePolygon && curvePoints->numPoints() >= 3 )
1681 curvePoints->close();
1683 collection->addGeometry( curvePoints.release() );
1687 geom = QgsGeometry( collection.release() );
1689 else if ( mBezierData && mBezierData->anchorCount() >= 2 )
1692 auto collection = std::make_unique<QgsGeometryCollection>();
1695 const QVector<QgsPoint> anchors = mBezierData->anchors();
1696 for (
const QgsPoint &point : anchors )
1698 collection->addGeometry(
new QgsPoint( point ) );
1702 const QVector<QgsPoint> handles = mBezierData->handles();
1703 for (
const QgsPoint &point : handles )
1705 collection->addGeometry(
new QgsPoint( point ) );
1710 if ( !interpolated.isEmpty() )
1712 auto curveLineString = std::make_unique<QgsLineString>( interpolated );
1714 if ( mCaptureMode ==
CapturePolygon && curveLineString->numPoints() >= 3 )
1716 curveLineString->close();
1718 collection->addGeometry( curveLineString.release() );
1721 geom = QgsGeometry( collection.release() );
1723 else if ( mCaptureCurve.numPoints() >= 2 )
1726 geom = QgsGeometry( mCaptureCurve.clone() );
1728 if ( mCaptureMode ==
CapturePolygon && mCaptureCurve.numPoints() >= 3 )
1734 mExtraSnapLayer->changeGeometry( mExtraSnapFeatureId, geom );
1739 mExtraSnapLayer->changeGeometry( mExtraSnapFeatureId, geom );
1745 QgsReferencedGeometry correctedGeometry = geometry;
1752 auto convertedToPolygon = std::make_unique< QgsCurvePolygon >();
1753 convertedToPolygon->setExteriorRing( curve->clone() );
1754 correctedGeometry = QgsReferencedGeometry( QgsGeometry( std::move( convertedToPolygon ) ), correctedGeometry.
crs() );
1762 correctedGeometry = QgsReferencedGeometry( QgsGeometry( std::move( exterior ) ), correctedGeometry.
crs() );
1774 if ( e->button() != Qt::LeftButton )
1778 bool isMatchPointZ =
false;
1779 bool isMatchPointM =
false;
1790 if ( isMatchPointM && isMatchPointZ )
1794 else if ( isMatchPointM )
1798 else if ( isMatchPointZ )
1802 savePoint =
QgsPoint( geomType, fetchPoint.
x(), fetchPoint.
y(), fetchPoint.
z(), fetchPoint.
m() );
1808 savePoint =
QgsPoint( point.
x(), point.
y(), fetchPoint.
z(), fetchPoint.
m() );
1818 QgsGeometry g( std::make_unique<QgsPoint>( savePoint ) );
1835 bool digitizingFinished =
false;
1837 QVector<double> nurbsWeights;
1842 if ( e->button() == Qt::LeftButton )
1845 mBezierDragging =
false;
1846 mBezierDragAnchorIndex = -1;
1847 mBezierDragHandleIndex = -1;
1848 mBezierMoveAnchorIndex = -1;
1851 if ( mBezierMarker )
1853 mBezierMarker->setHighlightedAnchor( -1 );
1854 mBezierMarker->setHighlightedHandle( -1 );
1855 mBezierMarker->updateFromData( *mBezierData );
1860 else if ( e->button() == Qt::RightButton )
1863 mBezierDragging =
false;
1864 mBezierDragAnchorIndex = -1;
1865 mBezierDragHandleIndex = -1;
1866 mBezierMoveAnchorIndex = -1;
1868 if ( mBezierData && mBezierData->anchorCount() >= 2 )
1871 std::unique_ptr<QgsNurbsCurve> nurbsCurve = mBezierData->asNurbsCurve();
1894 std::unique_ptr<QgsCurve> curveToAdd;
1900 auto compound = std::make_unique<QgsCompoundCurve>();
1901 compound->addCurve( nurbsCurve.release() );
1903 auto closingSegment = std::make_unique<QgsLineString>();
1904 closingSegment->addVertex( compound->endPoint() );
1905 closingSegment->addVertex( compound->startPoint() );
1906 compound->addCurve( closingSegment.release() );
1907 curveToAdd = std::move( compound );
1911 curveToAdd.reset( nurbsCurve.release() );
1923 auto poly = std::make_unique<QgsCurvePolygon>();
1924 poly->setExteriorRing( curveToAdd.release() );
1930 digitizingFinished =
true;
1935 if ( mBezierMarker )
1936 mBezierMarker->clear();
1937 mBezierData.reset();
1938 mBezierMarker.reset();
1946 if ( !mCurrentShapeMapTool )
1953 if ( !mTempRubberBand )
1955 mTempRubberBand.reset( createCurveRubberBand() );
1956 mTempRubberBand->setStringType( mLineDigitizingType );
1960 digitizingFinished = mCurrentShapeMapTool->cadCanvasReleaseEvent( e, mCaptureMode );
1961 if ( digitizingFinished )
1962 mCurrentShapeMapTool->clean();
1968 if ( e->button() == Qt::LeftButton )
1980 else if ( e->button() == Qt::RightButton )
1987 const int rbPointCount = mTempRubberBand->pointsCount();
1988 if ( rbPointCount > 1 )
1991 for (
int i = 0; i < rbPointCount - 1; ++i )
1993 nurbsControlPoints.append( mTempRubberBand->pointFromEnd( rbPointCount - 1 - i ) );
1996 const QVector<double> &rbWeights = mTempRubberBand->weights();
1997 for (
int i = 0; i < rbPointCount - 1; ++i )
1999 if ( i < rbWeights.size() )
2000 nurbsWeights.append( rbWeights[i] );
2002 nurbsWeights.append( 1.0 );
2045 nurbsControlPoints.append( nurbsControlPoints.first() );
2046 if ( !nurbsWeights.isEmpty() )
2047 nurbsWeights.append( nurbsWeights.first() );
2055 digitizingFinished =
true;
2059 if ( digitizingFinished )
2062 std::unique_ptr<QgsCurve> curveToAdd;
2069 const int n = nurbsControlPoints.size();
2072 if ( n < degree + 1 )
2074 degree = std::max( 1, n - 1 );
2077 curveToAdd = std::make_unique<QgsLineString>( nurbsControlPoints );
2084 const int knotCount = n + degree + 1;
2085 QVector<double> knots( knotCount );
2088 for (
int i = 0; i <= degree; ++i )
2092 for (
int i = knotCount - degree - 1; i < knotCount; ++i )
2096 const int numMiddleKnots = n - degree - 1;
2097 for (
int i = 0; i < numMiddleKnots; ++i )
2099 knots[degree + 1 + i] =
static_cast<double>( i + 1 ) / ( numMiddleKnots + 1 );
2103 QVector<double> weights = nurbsWeights;
2104 while ( weights.size() < n )
2105 weights.append( 1.0 );
2106 weights.resize( n );
2108 curveToAdd = std::make_unique<QgsNurbsCurve>( nurbsControlPoints, degree, knots, weights );
2150 if ( compound->nCurves() == 1 )
2154 curveToAdd.reset( circularPart->clone() );
2178 if ( hasCurvedSegments && providerSupportsCurvedSegments )
2192 auto poly = std::make_unique<QgsCurvePolygon>();
2193 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.
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.