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 );
1507 mValidator =
new QgsGeometryValidator( geom,
nullptr, method );
1509 mValidator->start();
1516 QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>(
layer() );
1522 QgsVertexMarker *vm =
new QgsVertexMarker(
mCanvas );
1526 vm->setToolTip( e.
what() );
1528 vm->setZValue( vm->zValue() + 1 );
1529 mGeomErrorMarkers << vm;
1535 return mCaptureCurve.numPoints();
1540 QVector<QgsPointXY> pointsXY;
1549 mCaptureCurve.points( pts );
1556 mCaptureCurve.clear();
1557 mCaptureCurve.addCurve( line );
1558 updateExtraSnapLayer();
1559 mSnappingMatches.clear();
1560 for (
int i = 0; i < line->
length(); ++i )
1568 mCaptureCurve.clear();
1569 mCaptureCurve.addCurve( line );
1570 updateExtraSnapLayer();
1571 mSnappingMatches.clear();
1572 for (
int i = 0; i < line->
length(); ++i )
1629 if ( match.
layer() )
1647void QgsMapToolCapture::updateExtraSnapLayer()
1649 if ( !mExtraSnapLayer )
1652 if (
canvas()->snappingUtils()->config().selfSnapping() &&
layer() )
1663 auto collection = std::make_unique<QgsGeometryCollection>();
1666 const int pointCount = mTempRubberBand->pointsCount();
1668 for (
int i = 0; i < pointCount - 1; ++i )
1670 collection->addGeometry(
new QgsPoint( mTempRubberBand->pointFromEnd( pointCount - 1 - i ) ) );
1674 std::unique_ptr<QgsCurve> nurbsCurve( mTempRubberBand->curve() );
1677 std::unique_ptr<QgsLineString> curvePoints( nurbsCurve->curveToLine() );
1681 if ( mCaptureMode ==
CapturePolygon && curvePoints->numPoints() >= 3 )
1683 curvePoints->close();
1685 collection->addGeometry( curvePoints.release() );
1689 geom = QgsGeometry( collection.release() );
1691 else if ( mBezierData && mBezierData->anchorCount() >= 2 )
1694 auto collection = std::make_unique<QgsGeometryCollection>();
1697 const QVector<QgsPoint> anchors = mBezierData->anchors();
1698 for (
const QgsPoint &point : anchors )
1700 collection->addGeometry(
new QgsPoint( point ) );
1704 const QVector<QgsPoint> handles = mBezierData->handles();
1705 for (
const QgsPoint &point : handles )
1707 collection->addGeometry(
new QgsPoint( point ) );
1712 if ( !interpolated.isEmpty() )
1714 auto curveLineString = std::make_unique<QgsLineString>( interpolated );
1716 if ( mCaptureMode ==
CapturePolygon && curveLineString->numPoints() >= 3 )
1718 curveLineString->close();
1720 collection->addGeometry( curveLineString.release() );
1723 geom = QgsGeometry( collection.release() );
1725 else if ( mCaptureCurve.numPoints() >= 2 )
1728 geom = QgsGeometry( mCaptureCurve.clone() );
1730 if ( mCaptureMode ==
CapturePolygon && mCaptureCurve.numPoints() >= 3 )
1736 mExtraSnapLayer->changeGeometry( mExtraSnapFeatureId, geom );
1741 mExtraSnapLayer->changeGeometry( mExtraSnapFeatureId, geom );
1747 QgsReferencedGeometry correctedGeometry = geometry;
1754 auto convertedToPolygon = std::make_unique< QgsCurvePolygon >();
1755 convertedToPolygon->setExteriorRing( curve->clone() );
1756 correctedGeometry = QgsReferencedGeometry( QgsGeometry( std::move( convertedToPolygon ) ), correctedGeometry.
crs() );
1764 correctedGeometry = QgsReferencedGeometry( QgsGeometry( std::move( exterior ) ), correctedGeometry.
crs() );
1776 if ( e->button() != Qt::LeftButton )
1780 bool isMatchPointZ =
false;
1781 bool isMatchPointM =
false;
1792 if ( isMatchPointM && isMatchPointZ )
1796 else if ( isMatchPointM )
1800 else if ( isMatchPointZ )
1804 savePoint =
QgsPoint( geomType, fetchPoint.
x(), fetchPoint.
y(), fetchPoint.
z(), fetchPoint.
m() );
1810 savePoint =
QgsPoint( point.
x(), point.
y(), fetchPoint.
z(), fetchPoint.
m() );
1820 QgsGeometry g( std::make_unique<QgsPoint>( savePoint ) );
1837 bool digitizingFinished =
false;
1839 QVector<double> nurbsWeights;
1844 if ( e->button() == Qt::LeftButton )
1847 mBezierDragging =
false;
1848 mBezierDragAnchorIndex = -1;
1849 mBezierDragHandleIndex = -1;
1850 mBezierMoveAnchorIndex = -1;
1853 if ( mBezierMarker )
1855 mBezierMarker->setHighlightedAnchor( -1 );
1856 mBezierMarker->setHighlightedHandle( -1 );
1857 mBezierMarker->updateFromData( *mBezierData );
1862 else if ( e->button() == Qt::RightButton )
1865 mBezierDragging =
false;
1866 mBezierDragAnchorIndex = -1;
1867 mBezierDragHandleIndex = -1;
1868 mBezierMoveAnchorIndex = -1;
1870 if ( mBezierData && mBezierData->anchorCount() >= 2 )
1873 std::unique_ptr<QgsNurbsCurve> nurbsCurve = mBezierData->asNurbsCurve();
1896 std::unique_ptr<QgsCurve> curveToAdd;
1902 auto compound = std::make_unique<QgsCompoundCurve>();
1903 compound->addCurve( nurbsCurve.release() );
1905 auto closingSegment = std::make_unique<QgsLineString>();
1906 closingSegment->addVertex( compound->endPoint() );
1907 closingSegment->addVertex( compound->startPoint() );
1908 compound->addCurve( closingSegment.release() );
1909 curveToAdd = std::move( compound );
1913 curveToAdd.reset( nurbsCurve.release() );
1925 auto poly = std::make_unique<QgsCurvePolygon>();
1926 poly->setExteriorRing( curveToAdd.release() );
1932 digitizingFinished =
true;
1937 if ( mBezierMarker )
1938 mBezierMarker->clear();
1939 mBezierData.reset();
1940 mBezierMarker.reset();
1948 if ( !mCurrentShapeMapTool )
1955 if ( !mTempRubberBand )
1957 mTempRubberBand.reset( createCurveRubberBand() );
1958 mTempRubberBand->setStringType( mLineDigitizingType );
1962 digitizingFinished = mCurrentShapeMapTool->cadCanvasReleaseEvent( e, mCaptureMode );
1963 if ( digitizingFinished )
1964 mCurrentShapeMapTool->clean();
1970 if ( e->button() == Qt::LeftButton )
1982 else if ( e->button() == Qt::RightButton )
1989 const int rbPointCount = mTempRubberBand->pointsCount();
1990 if ( rbPointCount > 1 )
1993 for (
int i = 0; i < rbPointCount - 1; ++i )
1995 nurbsControlPoints.append( mTempRubberBand->pointFromEnd( rbPointCount - 1 - i ) );
1998 const QVector<double> &rbWeights = mTempRubberBand->weights();
1999 for (
int i = 0; i < rbPointCount - 1; ++i )
2001 if ( i < rbWeights.size() )
2002 nurbsWeights.append( rbWeights[i] );
2004 nurbsWeights.append( 1.0 );
2047 nurbsControlPoints.append( nurbsControlPoints.first() );
2048 if ( !nurbsWeights.isEmpty() )
2049 nurbsWeights.append( nurbsWeights.first() );
2057 digitizingFinished =
true;
2061 if ( digitizingFinished )
2064 std::unique_ptr<QgsCurve> curveToAdd;
2071 const int n = nurbsControlPoints.size();
2074 if ( n < degree + 1 )
2076 degree = std::max( 1, n - 1 );
2079 curveToAdd = std::make_unique<QgsLineString>( nurbsControlPoints );
2086 const int knotCount = n + degree + 1;
2087 QVector<double> knots( knotCount );
2090 for (
int i = 0; i <= degree; ++i )
2094 for (
int i = knotCount - degree - 1; i < knotCount; ++i )
2098 const int numMiddleKnots = n - degree - 1;
2099 for (
int i = 0; i < numMiddleKnots; ++i )
2101 knots[degree + 1 + i] =
static_cast<double>( i + 1 ) / ( numMiddleKnots + 1 );
2105 QVector<double> weights = nurbsWeights;
2106 while ( weights.size() < n )
2107 weights.append( 1.0 );
2108 weights.resize( n );
2110 curveToAdd = std::make_unique<QgsNurbsCurve>( nurbsControlPoints, degree, knots, weights );
2152 if ( compound->nCurves() == 1 )
2156 curveToAdd.reset( circularPart->clone() );
2180 if ( hasCurvedSegments && providerSupportsCurvedSegments )
2194 auto poly = std::make_unique<QgsCurvePolygon>();
2195 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.
@ QgisInternal
Use internal QgsGeometryValidator method.
@ Geos
Use GEOS validation methods.
@ 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.
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 transform(const QgsCoordinateTransform &ct, Qgis::TransformDirection d=Qgis::TransformDirection::Forward, bool transformZ=false) override
Transforms the geometry using a coordinate transform.
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 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.