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 );
1751 if ( e->button() != Qt::LeftButton )
1755 bool isMatchPointZ =
false;
1756 bool isMatchPointM =
false;
1767 if ( isMatchPointM && isMatchPointZ )
1771 else if ( isMatchPointM )
1775 else if ( isMatchPointZ )
1779 savePoint =
QgsPoint( geomType, fetchPoint.
x(), fetchPoint.
y(), fetchPoint.
z(), fetchPoint.
m() );
1785 savePoint =
QgsPoint( point.
x(), point.
y(), fetchPoint.
z(), fetchPoint.
m() );
1795 QgsGeometry g( std::make_unique<QgsPoint>( savePoint ) );
1812 bool digitizingFinished =
false;
1814 QVector<double> nurbsWeights;
1819 if ( e->button() == Qt::LeftButton )
1822 mBezierDragging =
false;
1823 mBezierDragAnchorIndex = -1;
1824 mBezierDragHandleIndex = -1;
1825 mBezierMoveAnchorIndex = -1;
1828 if ( mBezierMarker )
1830 mBezierMarker->setHighlightedAnchor( -1 );
1831 mBezierMarker->setHighlightedHandle( -1 );
1832 mBezierMarker->updateFromData( *mBezierData );
1837 else if ( e->button() == Qt::RightButton )
1840 mBezierDragging =
false;
1841 mBezierDragAnchorIndex = -1;
1842 mBezierDragHandleIndex = -1;
1843 mBezierMoveAnchorIndex = -1;
1845 if ( mBezierData && mBezierData->anchorCount() >= 2 )
1848 std::unique_ptr<QgsNurbsCurve> nurbsCurve = mBezierData->asNurbsCurve();
1871 std::unique_ptr<QgsCurve> curveToAdd;
1877 auto compound = std::make_unique<QgsCompoundCurve>();
1878 compound->addCurve( nurbsCurve.release() );
1880 auto closingSegment = std::make_unique<QgsLineString>();
1881 closingSegment->addVertex( compound->endPoint() );
1882 closingSegment->addVertex( compound->startPoint() );
1883 compound->addCurve( closingSegment.release() );
1884 curveToAdd = std::move( compound );
1888 curveToAdd.reset( nurbsCurve.release() );
1900 auto poly = std::make_unique<QgsCurvePolygon>();
1901 poly->setExteriorRing( curveToAdd.release() );
1907 digitizingFinished =
true;
1912 if ( mBezierMarker )
1913 mBezierMarker->clear();
1914 mBezierData.reset();
1915 mBezierMarker.reset();
1923 if ( !mCurrentShapeMapTool )
1930 if ( !mTempRubberBand )
1932 mTempRubberBand.reset( createCurveRubberBand() );
1933 mTempRubberBand->setStringType( mLineDigitizingType );
1937 digitizingFinished = mCurrentShapeMapTool->cadCanvasReleaseEvent( e, mCaptureMode );
1938 if ( digitizingFinished )
1939 mCurrentShapeMapTool->clean();
1945 if ( e->button() == Qt::LeftButton )
1957 else if ( e->button() == Qt::RightButton )
1964 const int rbPointCount = mTempRubberBand->pointsCount();
1965 if ( rbPointCount > 1 )
1968 for (
int i = 0; i < rbPointCount - 1; ++i )
1970 nurbsControlPoints.append( mTempRubberBand->pointFromEnd( rbPointCount - 1 - i ) );
1973 const QVector<double> &rbWeights = mTempRubberBand->weights();
1974 for (
int i = 0; i < rbPointCount - 1; ++i )
1976 if ( i < rbWeights.size() )
1977 nurbsWeights.append( rbWeights[i] );
1979 nurbsWeights.append( 1.0 );
2022 nurbsControlPoints.append( nurbsControlPoints.first() );
2023 if ( !nurbsWeights.isEmpty() )
2024 nurbsWeights.append( nurbsWeights.first() );
2032 digitizingFinished =
true;
2036 if ( digitizingFinished )
2039 std::unique_ptr<QgsCurve> curveToAdd;
2046 const int n = nurbsControlPoints.size();
2049 if ( n < degree + 1 )
2051 degree = std::max( 1, n - 1 );
2054 curveToAdd = std::make_unique<QgsLineString>( nurbsControlPoints );
2061 const int knotCount = n + degree + 1;
2062 QVector<double> knots( knotCount );
2065 for (
int i = 0; i <= degree; ++i )
2069 for (
int i = knotCount - degree - 1; i < knotCount; ++i )
2073 const int numMiddleKnots = n - degree - 1;
2074 for (
int i = 0; i < numMiddleKnots; ++i )
2076 knots[degree + 1 + i] =
static_cast<double>( i + 1 ) / ( numMiddleKnots + 1 );
2080 QVector<double> weights = nurbsWeights;
2081 while ( weights.size() < n )
2082 weights.append( 1.0 );
2083 weights.resize( n );
2085 curveToAdd = std::make_unique<QgsNurbsCurve>( nurbsControlPoints, degree, knots, weights );
2127 if ( compound->nCurves() == 1 )
2131 curveToAdd.reset( circularPart->clone() );
2155 if ( hasCurvedSegments && providerSupportsCurvedSegments )
2169 auto poly = std::make_unique<QgsCurvePolygon>();
2170 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.
virtual int numPoints() const =0
Returns the number of points in the curve.
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.