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()
217QgsPointXY QgsMapToolCapture::tracingStartPoint()
221 if ( mTracingStartPoint != QgsPointXY() )
222 return mTracingStartPoint;
224 return mCaptureLastPoint;
233 QgsPointXY pt0 = tracingStartPoint();
234 if ( pt0 == QgsPointXY() )
250 mTempRubberBand->addPoint( mCaptureLastPoint );
256 const QgsPoint lastPoint = mCaptureLastPoint;
257 QgsPointXY lastPointXY( lastPoint );
258 if ( lastPointXY == pt0 &&
points[0] != lastPointXY )
260 if ( mRubberBand->numberOfVertices() != 0 )
264 if ( mRubberBand->numberOfVertices() > 2 || ( mRubberBand->numberOfVertices() == 2 && *mRubberBand->getPoint( 0, 0 ) != *mRubberBand->getPoint( 0, 1 ) ) )
265 mRubberBand->movePoint(
points[0] );
268 mTempRubberBand->movePoint( 0, QgsPoint(
points[0] ) );
271 mTempRubberBand->movePoint( QgsPoint(
points[0] ) );
274 for (
int i = 1; i <
points.count(); ++i )
275 mTempRubberBand->addPoint( QgsPoint(
points.at( i ) ), i ==
points.count() - 1 );
278 mTempRubberBand->addPoint( QgsPoint(
points[
points.size() - 1] ) );
282 QgsCoordinateReferenceSystem targetCrs =
mCanvas->mapSettings().destinationCrs();
283 if ( QgsMapLayer *l =
layer() )
286 targetCrs = l->crs();
289 std::unique_ptr< QgsCompoundCurve > tempCurve( mCaptureCurve.clone() );
292 std::unique_ptr< QgsCurve > tracedCurve( mTempRubberBand->curve() );
294 tempCurve->addCurve( tracedCurve.release() );
298 auto curvePolygon = std::make_unique< QgsCurvePolygon >();
299 curvePolygon->setExteriorRing( tempCurve.release() );
307 catch ( QgsCsException &e )
316bool QgsMapToolCapture::tracingAddVertex(
const QgsPointXY &point )
322 if ( mTempRubberBand->pointsCount() == 0 )
324 if ( !tracer->
init() )
334 mTracingStartPoint = point;
339 QgsPointXY pt0 = tracingStartPoint();
340 if ( pt0 == QgsPointXY() )
344 const QVector<QgsPointXY> tracedPointsInMapCrs = tracer->
findShortestPath( pt0, point, &err );
345 if ( tracedPointsInMapCrs.isEmpty() )
350 layerPoints.reserve( tracedPointsInMapCrs.size() );
352 mapPoints.reserve( tracedPointsInMapCrs.size() );
353 for (
const QgsPointXY &tracedPointMapCrs : tracedPointsInMapCrs )
355 QgsPoint
mapPoint( tracedPointMapCrs );
373 const QgsVertexId lastVertexId( 0, 0, mCaptureCurve.numPoints() - 1 );
374 mCaptureCurve.moveVertex( lastVertexId, layerPoints.first() );
375 mSnappingMatches.removeLast();
376 mSnappingMatches.append( QgsPointLocator::Match() );
378 addCurve(
new QgsLineString( mapPoints ) );
386 QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>(
layer() );
389 const QgsGeometry linear = QgsGeometry( mCaptureCurve.segmentize() );
396 mCaptureCurve.clear();
405 mSnappingMatches.resize( mCaptureCurve.numPoints() );
411 const QgsPoint lastPt = mCaptureCurve.endPoint();
417QgsMapToolCaptureRubberBand *QgsMapToolCapture::createCurveRubberBand()
const
419 QgsMapToolCaptureRubberBand *rb =
new QgsMapToolCaptureRubberBand(
mCanvas );
424 color.setAlphaF( color.alphaF() * alphaScale );
425 rb->setLineStyle( Qt::DotLine );
426 rb->setStrokeColor( color );
429 rb->setFillColor( fillColor );
434void QgsMapToolCapture::resetRubberBand()
438 QgsLineString *lineString = mCaptureCurve.curveToLine();
441 mRubberBand->addGeometry( QgsGeometry( lineString ),
layer() );
444void QgsMapToolCapture::setCurrentShapeMapToolIsActivated(
bool activated )
449 mCurrentShapeMapTool->activate( mCaptureMode, mCaptureLastPoint );
454 mCurrentShapeMapTool->deactivate();
460 return mRubberBand.release();
481 if ( mCurrentCaptureTechnique == technique )
484 mStartNewCurve =
true;
488 setCurrentShapeMapToolIsActivated(
false );
513 if ( mTempRubberBand )
514 mTempRubberBand->setStringType( mLineDigitizingType );
516 mCurrentCaptureTechnique = technique;
521 setCurrentShapeMapToolIsActivated(
true );
527 if ( mCurrentShapeMapTool )
529 if ( shapeMapToolMetadata && mCurrentShapeMapTool->
id() == shapeMapToolMetadata->
id() )
533 setCurrentShapeMapToolIsActivated(
false );
535 mCurrentShapeMapTool->deleteLater();
538 mCurrentShapeMapTool.reset( shapeMapToolMetadata ? shapeMapToolMetadata->
factory(
this ) :
nullptr );
543 if ( mCurrentShapeMapTool )
545 setCurrentShapeMapToolIsActivated(
true );
556 if ( e->button() == Qt::LeftButton )
562 mBezierData = std::make_unique<QgsBezierData>();
563 if ( !mBezierMarker )
564 mBezierMarker = std::make_unique<QgsBezierMarker>(
mCanvas );
569 mBezierDragAnchorIndex = -1;
570 mBezierDragHandleIndex = -1;
571 mBezierMoveAnchorIndex = -1;
574 const int handleIdx = mBezierData->findClosestHandle(
mapPoint, tolerance );
575 if ( handleIdx >= 0 )
578 mBezierDragHandleIndex = handleIdx;
579 mBezierDragging =
true;
580 mBezierMarker->setHighlightedHandle( handleIdx );
585 const int anchorIdx = mBezierData->findClosestAnchor(
mapPoint, tolerance );
586 if ( anchorIdx >= 0 )
588 if ( e->modifiers() & Qt::AltModifier )
591 mBezierDragAnchorIndex = anchorIdx;
592 mBezierDragging =
true;
593 mBezierMarker->setHighlightedAnchor( anchorIdx );
598 mBezierMoveAnchorIndex = anchorIdx;
599 mBezierDragging =
true;
600 mBezierMarker->setHighlightedAnchor( anchorIdx );
607 mBezierDragAnchorIndex = mBezierData->anchorCount() - 1;
608 mBezierDragging =
true;
611 mBezierMarker->updateFromData( *mBezierData );
625 if ( mCaptureModeFromLayer && ( !
canvas()->currentLayer() || !
canvas()->currentLayer()->isSpatial() ) )
636 if ( !mCurrentShapeMapTool )
642 if ( !mTempRubberBand )
644 mTempRubberBand.reset( createCurveRubberBand() );
645 mTempRubberBand->setStringType( mLineDigitizingType );
649 mCurrentShapeMapTool->cadCanvasMoveEvent( e, mCaptureMode );
664 const int handleIdx = mBezierData->findClosestHandle(
mapPoint, tolerance );
666 const int anchorIdx = mBezierData->findClosestAnchor(
mapPoint, tolerance );
668 if ( handleIdx >= 0 || anchorIdx >= 0 )
680 if ( mBezierDragging && mBezierData )
682 if ( mBezierDragHandleIndex >= 0 )
685 mBezierData->moveHandle( mBezierDragHandleIndex,
mapPoint );
687 else if ( mBezierDragAnchorIndex >= 0 )
690 mBezierData->calculateSymmetricHandles( mBezierDragAnchorIndex,
mapPoint );
695 mBezierMarker->updateFromData( *mBezierData );
698 else if ( mBezierData && mBezierData->anchorCount() > 0 && mBezierMarker && mCapturing )
700 QgsBezierData previewData = *mBezierData;
703 mBezierMarker->updateCurve( previewData );
707 if ( !mTempRubberBand )
709 mTempRubberBand.reset( createCurveRubberBand() );
710 mTempRubberBand->setStringType( mLineDigitizingType );
718 mTempRubberBand->addPoint( pt );
724 targetCrs = l->crs();
729 auto lineString = std::make_unique<QgsLineString>(
points );
733 auto curvePolygon = std::make_unique<QgsCurvePolygon>();
735 curvePolygon->setExteriorRing( lineString.release() );
754 targetCrs = l->crs();
757 if ( mCaptureMode !=
CapturePoint && mTempRubberBand && mCapturing )
759 bool hasTrace =
false;
763 if ( !mCaptureCurve.isEmpty() )
765 const QgsPoint prevPoint = mCaptureCurve.curveAt( mCaptureCurve.nCurves() - 1 )->endPoint();
770 mAllowAddingStreamingPoints =
true;
772 mAllowAddingStreamingPoints =
false;
774 std::unique_ptr< QgsCompoundCurve > tempCurve( mCaptureCurve.clone() );
777 auto curvePolygon = std::make_unique< QgsCurvePolygon >();
779 curvePolygon->setExteriorRing( tempCurve.release() );
787 else if ( tracingEnabled() && mCaptureCurve.numPoints() != 0 )
793 mCircularItermediatePoint = mTempRubberBand->pointFromEnd( 1 );
795 mCircularItermediatePoint =
QgsPoint();
797 hasTrace = tracingMouseMove( e );
803 mTempRubberBand->addPoint( mCaptureLastPoint );
804 if ( !mCircularItermediatePoint.isEmpty() )
806 mTempRubberBand->movePoint( mCircularItermediatePoint );
807 mTempRubberBand->addPoint( mCircularItermediatePoint );
814 if ( mCaptureCurve.numPoints() > 0 )
816 const QgsPoint mapPt = mCaptureLastPoint;
818 if ( mTempRubberBand )
820 mTempRubberBand->movePoint(
mapPoint );
821 mTempRubberBand->movePoint( 0, mapPt );
825 if ( mRubberBand->numberOfVertices() )
826 mRubberBand->movePoint( mapPt );
828 std::unique_ptr< QgsCompoundCurve > tempCurve( mCaptureCurve.clone() );
835 tempCurve->addCurve(
new QgsLineString( tempCurve->endPoint(), hoverPointTargetCrs ) );
844 auto curvePolygon = std::make_unique< QgsCurvePolygon >();
846 curvePolygon->setExteriorRing( tempCurve.release() );
854 else if ( mTempRubberBand )
855 mTempRubberBand->movePoint(
mapPoint );
869 const bool is3D = layerPoint.
is3D();
870 const bool isMeasure = layerPoint.
isMeasure();
872 layerPoint =
QgsPoint( layerPoint.
wkbType(), mapP.
x(), mapP.
y(), layerPoint.
z(), layerPoint.
m() );
880 QgsDebugError( u
"transformation to layer coordinate failed"_s );
912 if ( match.
isValid() && sourceLayer )
916 if ( sourceLayer->
crs() != vlayer->
crs() )
999 mCaptureCurve.addVertex( layerPoint );
1000 mSnappingMatches.append( match );
1004 if ( mCaptureFirstPoint.isEmpty() )
1012 if ( !mTempRubberBand )
1014 mTempRubberBand.reset( createCurveRubberBand() );
1015 mTempRubberBand->setStringType( mLineDigitizingType );
1019 bool traceCreated =
false;
1020 if ( tracingEnabled() )
1022 traceCreated = tracingAddVertex(
mapPoint );
1027 mTracingStartPoint = traceCreated ? point :
QgsPointXY();
1029 if ( !traceCreated )
1032 mTempRubberBand->movePoint(
mapPoint );
1033 if ( mTempRubberBand->curveIsComplete() )
1035 if (
QgsCurve *curve = mTempRubberBand->curve() )
1040 if ( match.
isValid() && mSnappingMatches.count() > 0 && !mSnappingMatches.last().isValid() )
1042 mSnappingMatches.removeLast();
1046 mSnappingMatches.removeLast();
1047 mSnappingMatches.append( mCircularIntermediateMatch );
1049 mSnappingMatches.append( match );
1055 else if ( mTempRubberBand->pointsCount() == 0 )
1058 mCaptureCurve.addVertex( layerPoint );
1059 mSnappingMatches.append( match );
1065 mCircularIntermediateMatch = match;
1069 mTempRubberBand->addPoint(
mapPoint );
1074 mTempRubberBand->addPoint( mCaptureLastPoint );
1078 updateExtraSnapLayer();
1096 if ( mTempRubberBand )
1100 mTempRubberBand->addPoint( endPt );
1103 const int countBefore = mCaptureCurve.vertexCount();
1105 if ( mCaptureCurve.numPoints() == 1 )
1106 mCaptureCurve.removeCurve( 0 );
1116 mCaptureCurve.addCurve( segmented,
false );
1123 mCaptureCurve.addCurve(
c, !mStartNewCurve );
1126 mStartNewCurve =
false;
1128 const int countAfter = mCaptureCurve.vertexCount();
1129 const int addedPoint = countAfter - countBefore;
1131 updateExtraSnapLayer();
1133 for (
int i = 0; i < addedPoint; ++i )
1143 mCaptureCurve.clear();
1144 updateExtraSnapLayer();
1149 return mSnappingMatches;
1160 && mBezierData && mBezierData->anchorCount() > 0 )
1162 mBezierData->deleteAnchor( mBezierData->anchorCount() - 1 );
1163 if ( mBezierMarker )
1164 mBezierMarker->updateFromData( *mBezierData );
1166 mBezierDragging =
false;
1167 mBezierDragAnchorIndex = -1;
1168 mBezierDragHandleIndex = -1;
1169 mBezierMoveAnchorIndex = -1;
1174 if ( mTempRubberBand )
1181 const QgsPoint lastPoint = mTempRubberBand->lastPoint();
1182 mTempRubberBand->removeLastPoint();
1183 mTempRubberBand->movePoint( lastPoint );
1188 if (
size() <= 1 && mTempRubberBand->pointsCount() != 0 )
1191 if ( isAutoRepeat && mIgnoreSubsequentAutoRepeatUndo )
1193 mIgnoreSubsequentAutoRepeatUndo =
false;
1195 const QgsPoint lastPoint = mTempRubberBand->lastPoint();
1199 mTempRubberBand->removeLastPoint();
1200 mTempRubberBand->movePoint( lastPoint );
1207 mTempRubberBand->removeLastPoint();
1208 mTempRubberBand->movePoint( lastPoint );
1214 vertexToRemove.
part = 0;
1215 vertexToRemove.
ring = 0;
1222 mCaptureCurve.removeCurve( mCaptureCurve.nCurves() - 1 );
1224 if ( mCaptureCurve.numPoints() == 2 && mCaptureCurve.nCurves() == 1 )
1228 const QgsPoint fp = mCaptureCurve.startPoint();
1230 mCaptureCurve.addVertex( fp );
1234 const int curvesBefore = mCaptureCurve.nCurves();
1237 const int pointsCountBefore = mCaptureCurve.numPoints();
1238 mCaptureCurve.deleteVertex( vertexToRemove );
1239 int pointsCountAfter = mCaptureCurve.numPoints();
1240 for ( ; pointsCountAfter < pointsCountBefore; pointsCountAfter++ )
1241 if ( !mSnappingMatches.empty() )
1242 mSnappingMatches.removeLast();
1248 if ( mCaptureCurve.nCurves() < curvesBefore && lastCurveIsLineString )
1249 mIgnoreSubsequentAutoRepeatUndo =
true;
1252 updateExtraSnapLayer();
1258 if ( mCaptureCurve.numPoints() > 0 )
1260 const QgsPoint lastPt = mCaptureCurve.endPoint();
1262 mTempRubberBand->addPoint( mCaptureLastPoint );
1263 mTempRubberBand->movePoint( lastPoint );
1275 mCurrentShapeMapTool->keyPressEvent( e );
1276 if ( e->isAccepted() )
1287 if ( e->key() == Qt::Key_Backspace || e->key() == Qt::Key_Delete )
1291 if ( !e->isAutoRepeat() )
1293 mCurrentShapeMapTool->undo();
1298 undo( e->isAutoRepeat() );
1304 else if ( e->key() == Qt::Key_Escape )
1306 if ( mCurrentShapeMapTool )
1307 mCurrentShapeMapTool->clean();
1314 else if ( e->key() == Qt::Key_W && !e->isAutoRepeat() )
1319 mWeightEditMode =
true;
1321 mWeightEditControlPointIndex = mTempRubberBand->pointsCount() - 2;
1326 cadDockWidget()->
setWeight( QString::number( mTempRubberBand->weight( mWeightEditControlPointIndex ),
'f', 2 ),
true );
1335 if ( e->key() == Qt::Key_W && !e->isAutoRepeat() )
1337 if ( mWeightEditMode )
1339 mWeightEditMode =
false;
1340 mWeightEditControlPointIndex = -1;
1358 if ( mWeightEditMode )
1364 double adjustment = e->angleDelta().y() > 0 ? 0.1 : -0.1;
1365 if ( e->modifiers() & Qt::ControlModifier )
1367 else if ( e->modifiers() & Qt::ShiftModifier )
1370 const double currentWeight = mTempRubberBand->weight( mWeightEditControlPointIndex );
1371 const double newWeight = std::max( 0.01, currentWeight + adjustment );
1373 if ( mTempRubberBand->setWeight( mWeightEditControlPointIndex, newWeight ) )
1400 mRubberBand.reset();
1405 if ( mWeightEditMode )
1407 mWeightEditMode =
false;
1408 mWeightEditControlPointIndex = -1;
1415 qDeleteAll( mGeomErrorMarkers );
1416 mGeomErrorMarkers.clear();
1417 mGeomErrors.clear();
1425 mCaptureCurve.clear();
1426 updateExtraSnapLayer();
1427 mSnappingMatches.clear();
1430 if ( mBezierMarker )
1431 mBezierMarker->clear();
1432 mBezierData.reset();
1433 mBezierMarker.reset();
1434 mBezierDragging =
false;
1435 mBezierDragAnchorIndex = -1;
1438 lCurrentVectorLayer->triggerRepaint();
1445 mTempRubberBand.reset();
1452 mCurrentShapeMapTool->clean();
1459 mCaptureCurve.close();
1460 updateExtraSnapLayer();
1463void QgsMapToolCapture::validateGeometry()
1471 mValidator->deleteLater();
1472 mValidator =
nullptr;
1475 mGeomErrors.clear();
1476 while ( !mGeomErrorMarkers.isEmpty() )
1478 delete mGeomErrorMarkers.takeFirst();
1483 switch ( mCaptureMode )
1491 geom = QgsGeometry( mCaptureCurve.curveToLine() );
1496 QgsLineString *exteriorRing = mCaptureCurve.curveToLine();
1497 exteriorRing->
close();
1498 QgsPolygon *polygon =
new QgsPolygon();
1500 geom = QgsGeometry( polygon );
1510 mValidator =
new QgsGeometryValidator( geom,
nullptr, method );
1512 mValidator->start();
1519 QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>(
layer() );
1525 QgsVertexMarker *vm =
new QgsVertexMarker(
mCanvas );
1529 vm->setToolTip( e.
what() );
1531 vm->setZValue( vm->zValue() + 1 );
1532 mGeomErrorMarkers << vm;
1538 return mCaptureCurve.numPoints();
1543 QVector<QgsPointXY> pointsXY;
1552 mCaptureCurve.points( pts );
1559 mCaptureCurve.clear();
1560 mCaptureCurve.addCurve( line );
1561 updateExtraSnapLayer();
1562 mSnappingMatches.clear();
1563 for (
int i = 0; i < line->
length(); ++i )
1571 mCaptureCurve.clear();
1572 mCaptureCurve.addCurve( line );
1573 updateExtraSnapLayer();
1574 mSnappingMatches.clear();
1575 for (
int i = 0; i < line->
length(); ++i )
1632 if ( match.
layer() )
1650void QgsMapToolCapture::updateExtraSnapLayer()
1652 if ( !mExtraSnapLayer )
1655 if (
canvas()->snappingUtils()->config().selfSnapping() &&
layer() )
1666 auto collection = std::make_unique<QgsGeometryCollection>();
1669 const int pointCount = mTempRubberBand->pointsCount();
1671 for (
int i = 0; i < pointCount - 1; ++i )
1673 collection->addGeometry(
new QgsPoint( mTempRubberBand->pointFromEnd( pointCount - 1 - i ) ) );
1677 std::unique_ptr<QgsCurve> nurbsCurve( mTempRubberBand->curve() );
1680 std::unique_ptr<QgsLineString> curvePoints( nurbsCurve->curveToLine() );
1684 if ( mCaptureMode ==
CapturePolygon && curvePoints->numPoints() >= 3 )
1686 curvePoints->close();
1688 collection->addGeometry( curvePoints.release() );
1692 geom = QgsGeometry( collection.release() );
1694 else if ( mBezierData && mBezierData->anchorCount() >= 2 )
1697 auto collection = std::make_unique<QgsGeometryCollection>();
1700 const QVector<QgsPoint> anchors = mBezierData->anchors();
1701 for (
const QgsPoint &point : anchors )
1703 collection->addGeometry(
new QgsPoint( point ) );
1707 const QVector<QgsPoint> handles = mBezierData->handles();
1708 for (
const QgsPoint &point : handles )
1710 collection->addGeometry(
new QgsPoint( point ) );
1715 if ( !interpolated.isEmpty() )
1717 auto curveLineString = std::make_unique<QgsLineString>( interpolated );
1719 if ( mCaptureMode ==
CapturePolygon && curveLineString->numPoints() >= 3 )
1721 curveLineString->close();
1723 collection->addGeometry( curveLineString.release() );
1726 geom = QgsGeometry( collection.release() );
1728 else if ( mCaptureCurve.numPoints() >= 2 )
1731 geom = QgsGeometry( mCaptureCurve.clone() );
1733 if ( mCaptureMode ==
CapturePolygon && mCaptureCurve.numPoints() >= 3 )
1739 mExtraSnapLayer->changeGeometry( mExtraSnapFeatureId, geom );
1744 mExtraSnapLayer->changeGeometry( mExtraSnapFeatureId, geom );
1754 if ( e->button() != Qt::LeftButton )
1758 bool isMatchPointZ =
false;
1759 bool isMatchPointM =
false;
1770 if ( isMatchPointM && isMatchPointZ )
1774 else if ( isMatchPointM )
1778 else if ( isMatchPointZ )
1782 savePoint =
QgsPoint( geomType, fetchPoint.
x(), fetchPoint.
y(), fetchPoint.
z(), fetchPoint.
m() );
1788 savePoint =
QgsPoint( point.
x(), point.
y(), fetchPoint.
z(), fetchPoint.
m() );
1798 QgsGeometry g( std::make_unique<QgsPoint>( savePoint ) );
1815 bool digitizingFinished =
false;
1817 QVector<double> nurbsWeights;
1822 if ( e->button() == Qt::LeftButton )
1825 mBezierDragging =
false;
1826 mBezierDragAnchorIndex = -1;
1827 mBezierDragHandleIndex = -1;
1828 mBezierMoveAnchorIndex = -1;
1831 if ( mBezierMarker )
1833 mBezierMarker->setHighlightedAnchor( -1 );
1834 mBezierMarker->setHighlightedHandle( -1 );
1835 mBezierMarker->updateFromData( *mBezierData );
1840 else if ( e->button() == Qt::RightButton )
1843 mBezierDragging =
false;
1844 mBezierDragAnchorIndex = -1;
1845 mBezierDragHandleIndex = -1;
1846 mBezierMoveAnchorIndex = -1;
1848 if ( mBezierData && mBezierData->anchorCount() >= 2 )
1851 std::unique_ptr<QgsNurbsCurve> nurbsCurve = mBezierData->asNurbsCurve();
1874 std::unique_ptr<QgsCurve> curveToAdd;
1880 auto compound = std::make_unique<QgsCompoundCurve>();
1881 compound->addCurve( nurbsCurve.release() );
1883 auto closingSegment = std::make_unique<QgsLineString>();
1884 closingSegment->addVertex( compound->endPoint() );
1885 closingSegment->addVertex( compound->startPoint() );
1886 compound->addCurve( closingSegment.release() );
1887 curveToAdd = std::move( compound );
1891 curveToAdd.reset( nurbsCurve.release() );
1903 auto poly = std::make_unique<QgsCurvePolygon>();
1904 poly->setExteriorRing( curveToAdd.release() );
1910 digitizingFinished =
true;
1915 if ( mBezierMarker )
1916 mBezierMarker->clear();
1917 mBezierData.reset();
1918 mBezierMarker.reset();
1926 if ( !mCurrentShapeMapTool )
1933 if ( !mTempRubberBand )
1935 mTempRubberBand.reset( createCurveRubberBand() );
1936 mTempRubberBand->setStringType( mLineDigitizingType );
1940 digitizingFinished = mCurrentShapeMapTool->cadCanvasReleaseEvent( e, mCaptureMode );
1941 if ( digitizingFinished )
1942 mCurrentShapeMapTool->clean();
1948 if ( e->button() == Qt::LeftButton )
1960 else if ( e->button() == Qt::RightButton )
1967 const int rbPointCount = mTempRubberBand->pointsCount();
1968 if ( rbPointCount > 1 )
1971 for (
int i = 0; i < rbPointCount - 1; ++i )
1973 nurbsControlPoints.append( mTempRubberBand->pointFromEnd( rbPointCount - 1 - i ) );
1976 const QVector<double> &rbWeights = mTempRubberBand->weights();
1977 for (
int i = 0; i < rbPointCount - 1; ++i )
1979 if ( i < rbWeights.size() )
1980 nurbsWeights.append( rbWeights[i] );
1982 nurbsWeights.append( 1.0 );
2025 nurbsControlPoints.append( nurbsControlPoints.first() );
2026 if ( !nurbsWeights.isEmpty() )
2027 nurbsWeights.append( nurbsWeights.first() );
2035 digitizingFinished =
true;
2039 if ( digitizingFinished )
2042 std::unique_ptr<QgsCurve> curveToAdd;
2049 const int n = nurbsControlPoints.size();
2052 if ( n < degree + 1 )
2054 degree = std::max( 1, n - 1 );
2057 curveToAdd = std::make_unique<QgsLineString>( nurbsControlPoints );
2064 const int knotCount = n + degree + 1;
2065 QVector<double> knots( knotCount );
2068 for (
int i = 0; i <= degree; ++i )
2072 for (
int i = knotCount - degree - 1; i < knotCount; ++i )
2076 const int numMiddleKnots = n - degree - 1;
2077 for (
int i = 0; i < numMiddleKnots; ++i )
2079 knots[degree + 1 + i] =
static_cast<double>( i + 1 ) / ( numMiddleKnots + 1 );
2083 QVector<double> weights = nurbsWeights;
2084 while ( weights.size() < n )
2085 weights.append( 1.0 );
2086 weights.resize( n );
2088 curveToAdd = std::make_unique<QgsNurbsCurve>( nurbsControlPoints, degree, knots, weights );
2130 if ( compound->nCurves() == 1 )
2134 curveToAdd.reset( circularPart->clone() );
2158 if ( hasCurvedSegments && providerSupportsCurvedSegments )
2172 auto poly = std::make_unique<QgsCurvePolygon>();
2173 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.
Abstract base class for curved geometry type.
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
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.