57#include "moc_qgsmaptoolcapture.cpp"
59using namespace Qt::StringLiterals;
63 , mCaptureMode(
mode )
66 mTempRubberBand.setParentOwner(
canvas );
68 mSnapIndicator = std::make_unique<QgsSnapIndicator>(
canvas );
77 mExtraSnapLayer =
new QgsVectorLayer( u
"LineString?crs="_s, u
"extra snap"_s, u
"memory"_s, layerOptions );
78 mExtraSnapLayer->startEditing();
80 mExtraSnapLayer->addFeature( f );
81 mExtraSnapFeatureId = f.
id();
85 currentLayerChanged(
canvas->currentLayer() );
96 mCanvas->snappingUtils()->removeExtraSnapLayer( mExtraSnapLayer );
98 mExtraSnapLayer->deleteLater();
99 mExtraSnapLayer =
nullptr;
105 mValidator->deleteLater();
106 mValidator =
nullptr;
133 if ( mTempRubberBand )
134 mTempRubberBand->show();
136 mCanvas->snappingUtils()->addExtraSnapLayer( mExtraSnapLayer );
141 setCurrentShapeMapToolIsActivated(
true );
147 if ( mTempRubberBand )
148 mTempRubberBand->hide();
152 mCanvas->snappingUtils()->removeExtraSnapLayer( mExtraSnapLayer );
156 setCurrentShapeMapToolIsActivated(
false );
162void QgsMapToolCapture::currentLayerChanged(
QgsMapLayer *layer )
164 if ( !mCaptureModeFromLayer )
200 if ( mTempRubberBand )
208bool 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() );
395 mCaptureCurve.clear();
404 mSnappingMatches.resize( mCaptureCurve.numPoints() );
410 const QgsPoint lastPt = mCaptureCurve.endPoint();
416QgsMapToolCaptureRubberBand *QgsMapToolCapture::createCurveRubberBand()
const
418 QgsMapToolCaptureRubberBand *rb =
new QgsMapToolCaptureRubberBand(
mCanvas );
423 color.setAlphaF( color.alphaF() * alphaScale );
424 rb->setLineStyle( Qt::DotLine );
425 rb->setStrokeColor( color );
428 rb->setFillColor( fillColor );
433void QgsMapToolCapture::resetRubberBand()
437 QgsLineString *lineString = mCaptureCurve.curveToLine();
440 mRubberBand->addGeometry( QgsGeometry( lineString ),
layer() );
443void QgsMapToolCapture::setCurrentShapeMapToolIsActivated(
bool activated )
448 mCurrentShapeMapTool->activate( mCaptureMode, mCaptureLastPoint );
453 mCurrentShapeMapTool->deactivate();
459 return mRubberBand.release();
480 if ( mCurrentCaptureTechnique == technique )
483 mStartNewCurve =
true;
487 setCurrentShapeMapToolIsActivated(
false );
512 if ( mTempRubberBand )
513 mTempRubberBand->setStringType( mLineDigitizingType );
515 mCurrentCaptureTechnique = technique;
520 setCurrentShapeMapToolIsActivated(
true );
526 if ( mCurrentShapeMapTool )
528 if ( shapeMapToolMetadata && mCurrentShapeMapTool->
id() == shapeMapToolMetadata->
id() )
532 setCurrentShapeMapToolIsActivated(
false );
534 mCurrentShapeMapTool->deleteLater();
537 mCurrentShapeMapTool.reset( shapeMapToolMetadata ? shapeMapToolMetadata->
factory(
this ) :
nullptr );
542 if ( mCurrentShapeMapTool )
544 setCurrentShapeMapToolIsActivated(
true );
555 if ( e->button() == Qt::LeftButton )
561 mBezierData = std::make_unique<QgsBezierData>();
562 if ( !mBezierMarker )
563 mBezierMarker = std::make_unique<QgsBezierMarker>(
mCanvas );
568 mBezierDragAnchorIndex = -1;
569 mBezierDragHandleIndex = -1;
570 mBezierMoveAnchorIndex = -1;
573 const int handleIdx = mBezierData->findClosestHandle(
mapPoint, tolerance );
574 if ( handleIdx >= 0 )
577 mBezierDragHandleIndex = handleIdx;
578 mBezierDragging =
true;
579 mBezierMarker->setHighlightedHandle( handleIdx );
584 const int anchorIdx = mBezierData->findClosestAnchor(
mapPoint, tolerance );
585 if ( anchorIdx >= 0 )
587 if ( e->modifiers() & Qt::AltModifier )
590 mBezierDragAnchorIndex = anchorIdx;
591 mBezierDragging =
true;
592 mBezierMarker->setHighlightedAnchor( anchorIdx );
597 mBezierMoveAnchorIndex = anchorIdx;
598 mBezierDragging =
true;
599 mBezierMarker->setHighlightedAnchor( anchorIdx );
606 mBezierDragAnchorIndex = mBezierData->anchorCount() - 1;
607 mBezierDragging =
true;
610 mBezierMarker->updateFromData( *mBezierData );
624 if ( mCaptureModeFromLayer && ( !
canvas()->currentLayer() || !
canvas()->currentLayer()->isSpatial() ) )
635 if ( !mCurrentShapeMapTool )
641 if ( !mTempRubberBand )
643 mTempRubberBand.reset( createCurveRubberBand() );
644 mTempRubberBand->setStringType( mLineDigitizingType );
648 mCurrentShapeMapTool->cadCanvasMoveEvent( e, mCaptureMode );
663 const int handleIdx = mBezierData->findClosestHandle(
mapPoint, tolerance );
665 const int anchorIdx = mBezierData->findClosestAnchor(
mapPoint, tolerance );
667 if ( handleIdx >= 0 || anchorIdx >= 0 )
679 if ( mBezierDragging && mBezierData )
681 if ( mBezierDragHandleIndex >= 0 )
684 mBezierData->moveHandle( mBezierDragHandleIndex,
mapPoint );
686 else if ( mBezierDragAnchorIndex >= 0 )
689 const QgsPoint &anchor = mBezierData->anchor( mBezierDragAnchorIndex );
690 const int leftHandleIdx = mBezierDragAnchorIndex * 2;
691 const int rightHandleIdx = mBezierDragAnchorIndex * 2 + 1;
694 mBezierData->moveHandle( rightHandleIdx,
mapPoint );
698 mBezierData->moveHandle( leftHandleIdx, leftHandle );
703 mBezierMarker->updateFromData( *mBezierData );
706 else if ( mBezierData && mBezierData->anchorCount() > 0 && mBezierMarker && mCapturing )
708 QgsBezierData previewData = *mBezierData;
711 mBezierMarker->updateCurve( previewData );
715 if ( !mTempRubberBand )
717 mTempRubberBand.reset( createCurveRubberBand() );
718 mTempRubberBand->setStringType( mLineDigitizingType );
726 mTempRubberBand->addPoint( pt );
732 targetCrs = l->crs();
737 auto lineString = std::make_unique<QgsLineString>(
points );
741 auto curvePolygon = std::make_unique<QgsCurvePolygon>();
743 curvePolygon->setExteriorRing( lineString.release() );
762 targetCrs = l->crs();
765 if ( mCaptureMode !=
CapturePoint && mTempRubberBand && mCapturing )
767 bool hasTrace =
false;
771 if ( !mCaptureCurve.isEmpty() )
773 const QgsPoint prevPoint = mCaptureCurve.curveAt( mCaptureCurve.nCurves() - 1 )->endPoint();
778 mAllowAddingStreamingPoints =
true;
780 mAllowAddingStreamingPoints =
false;
782 std::unique_ptr< QgsCompoundCurve > tempCurve( mCaptureCurve.clone() );
785 auto curvePolygon = std::make_unique< QgsCurvePolygon >();
787 curvePolygon->setExteriorRing( tempCurve.release() );
795 else if ( tracingEnabled() && mCaptureCurve.numPoints() != 0 )
801 mCircularItermediatePoint = mTempRubberBand->pointFromEnd( 1 );
803 mCircularItermediatePoint =
QgsPoint();
805 hasTrace = tracingMouseMove( e );
811 mTempRubberBand->addPoint( mCaptureLastPoint );
812 if ( !mCircularItermediatePoint.isEmpty() )
814 mTempRubberBand->movePoint( mCircularItermediatePoint );
815 mTempRubberBand->addPoint( mCircularItermediatePoint );
822 if ( mCaptureCurve.numPoints() > 0 )
824 const QgsPoint mapPt = mCaptureLastPoint;
826 if ( mTempRubberBand )
828 mTempRubberBand->movePoint(
mapPoint );
829 mTempRubberBand->movePoint( 0, mapPt );
833 if ( mRubberBand->numberOfVertices() )
834 mRubberBand->movePoint( mapPt );
836 std::unique_ptr< QgsCompoundCurve > tempCurve( mCaptureCurve.clone() );
843 tempCurve->addCurve(
new QgsLineString( tempCurve->endPoint(), hoverPointTargetCrs ) );
852 auto curvePolygon = std::make_unique< QgsCurvePolygon >();
854 curvePolygon->setExteriorRing( tempCurve.release() );
862 else if ( mTempRubberBand )
863 mTempRubberBand->movePoint(
mapPoint );
877 const bool is3D = layerPoint.
is3D();
878 const bool isMeasure = layerPoint.
isMeasure();
880 layerPoint =
QgsPoint( layerPoint.
wkbType(), mapP.
x(), mapP.
y(), layerPoint.
z(), layerPoint.
m() );
888 QgsDebugError( u
"transformation to layer coordinate failed"_s );
920 if ( match.
isValid() && sourceLayer )
924 if ( sourceLayer->
crs() != vlayer->
crs() )
1007 mCaptureCurve.addVertex( layerPoint );
1008 mSnappingMatches.append( match );
1012 if ( mCaptureFirstPoint.isEmpty() )
1020 if ( !mTempRubberBand )
1022 mTempRubberBand.reset( createCurveRubberBand() );
1023 mTempRubberBand->setStringType( mLineDigitizingType );
1027 bool traceCreated =
false;
1028 if ( tracingEnabled() )
1030 traceCreated = tracingAddVertex(
mapPoint );
1035 mTracingStartPoint = traceCreated ? point :
QgsPointXY();
1037 if ( !traceCreated )
1040 mTempRubberBand->movePoint(
mapPoint );
1041 if ( mTempRubberBand->curveIsComplete() )
1043 if (
QgsCurve *curve = mTempRubberBand->curve() )
1048 if ( match.
isValid() && mSnappingMatches.count() > 0 && !mSnappingMatches.last().isValid() )
1050 mSnappingMatches.removeLast();
1054 mSnappingMatches.removeLast();
1055 mSnappingMatches.append( mCircularIntermediateMatch );
1057 mSnappingMatches.append( match );
1063 else if ( mTempRubberBand->pointsCount() == 0 )
1066 mCaptureCurve.addVertex( layerPoint );
1067 mSnappingMatches.append( match );
1073 mCircularIntermediateMatch = match;
1077 mTempRubberBand->addPoint(
mapPoint );
1082 mTempRubberBand->addPoint( mCaptureLastPoint );
1086 updateExtraSnapLayer();
1104 if ( mTempRubberBand )
1108 mTempRubberBand->addPoint( endPt );
1111 const int countBefore = mCaptureCurve.vertexCount();
1113 if ( mCaptureCurve.numPoints() == 1 )
1114 mCaptureCurve.removeCurve( 0 );
1124 mCaptureCurve.addCurve( segmented,
false );
1131 mCaptureCurve.addCurve(
c, !mStartNewCurve );
1134 mStartNewCurve =
false;
1136 const int countAfter = mCaptureCurve.vertexCount();
1137 const int addedPoint = countAfter - countBefore;
1139 updateExtraSnapLayer();
1141 for (
int i = 0; i < addedPoint; ++i )
1151 mCaptureCurve.clear();
1152 updateExtraSnapLayer();
1157 return mSnappingMatches;
1168 && mBezierData && mBezierData->anchorCount() > 0 )
1170 mBezierData->deleteAnchor( mBezierData->anchorCount() - 1 );
1171 if ( mBezierMarker )
1172 mBezierMarker->updateFromData( *mBezierData );
1174 mBezierDragging =
false;
1175 mBezierDragAnchorIndex = -1;
1176 mBezierDragHandleIndex = -1;
1177 mBezierMoveAnchorIndex = -1;
1182 if ( mTempRubberBand )
1189 const QgsPoint lastPoint = mTempRubberBand->lastPoint();
1190 mTempRubberBand->removeLastPoint();
1191 mTempRubberBand->movePoint( lastPoint );
1196 if (
size() <= 1 && mTempRubberBand->pointsCount() != 0 )
1199 if ( isAutoRepeat && mIgnoreSubsequentAutoRepeatUndo )
1201 mIgnoreSubsequentAutoRepeatUndo =
false;
1203 const QgsPoint lastPoint = mTempRubberBand->lastPoint();
1207 mTempRubberBand->removeLastPoint();
1208 mTempRubberBand->movePoint( lastPoint );
1215 mTempRubberBand->removeLastPoint();
1216 mTempRubberBand->movePoint( lastPoint );
1222 vertexToRemove.
part = 0;
1223 vertexToRemove.
ring = 0;
1230 mCaptureCurve.removeCurve( mCaptureCurve.nCurves() - 1 );
1232 if ( mCaptureCurve.numPoints() == 2 && mCaptureCurve.nCurves() == 1 )
1236 const QgsPoint fp = mCaptureCurve.startPoint();
1238 mCaptureCurve.addVertex( fp );
1242 const int curvesBefore = mCaptureCurve.nCurves();
1245 const int pointsCountBefore = mCaptureCurve.numPoints();
1246 mCaptureCurve.deleteVertex( vertexToRemove );
1247 int pointsCountAfter = mCaptureCurve.numPoints();
1248 for ( ; pointsCountAfter < pointsCountBefore; pointsCountAfter++ )
1249 if ( !mSnappingMatches.empty() )
1250 mSnappingMatches.removeLast();
1256 if ( mCaptureCurve.nCurves() < curvesBefore && lastCurveIsLineString )
1257 mIgnoreSubsequentAutoRepeatUndo =
true;
1260 updateExtraSnapLayer();
1266 if ( mCaptureCurve.numPoints() > 0 )
1268 const QgsPoint lastPt = mCaptureCurve.endPoint();
1270 mTempRubberBand->addPoint( mCaptureLastPoint );
1271 mTempRubberBand->movePoint( lastPoint );
1283 mCurrentShapeMapTool->keyPressEvent( e );
1284 if ( e->isAccepted() )
1295 if ( e->key() == Qt::Key_Backspace || e->key() == Qt::Key_Delete )
1299 if ( !e->isAutoRepeat() )
1301 mCurrentShapeMapTool->undo();
1306 undo( e->isAutoRepeat() );
1312 else if ( e->key() == Qt::Key_Escape )
1314 if ( mCurrentShapeMapTool )
1315 mCurrentShapeMapTool->clean();
1322 else if ( e->key() == Qt::Key_W && !e->isAutoRepeat() )
1327 mWeightEditMode =
true;
1329 mWeightEditControlPointIndex = mTempRubberBand->pointsCount() - 2;
1334 cadDockWidget()->
setWeight( QString::number( mTempRubberBand->weight( mWeightEditControlPointIndex ),
'f', 2 ),
true );
1343 if ( e->key() == Qt::Key_W && !e->isAutoRepeat() )
1345 if ( mWeightEditMode )
1347 mWeightEditMode =
false;
1348 mWeightEditControlPointIndex = -1;
1366 if ( mWeightEditMode )
1372 double adjustment = e->angleDelta().y() > 0 ? 0.1 : -0.1;
1373 if ( e->modifiers() & Qt::ControlModifier )
1375 else if ( e->modifiers() & Qt::ShiftModifier )
1378 const double currentWeight = mTempRubberBand->weight( mWeightEditControlPointIndex );
1379 const double newWeight = std::max( 0.01, currentWeight + adjustment );
1381 if ( mTempRubberBand->setWeight( mWeightEditControlPointIndex, newWeight ) )
1408 mRubberBand.reset();
1413 if ( mWeightEditMode )
1415 mWeightEditMode =
false;
1416 mWeightEditControlPointIndex = -1;
1423 qDeleteAll( mGeomErrorMarkers );
1424 mGeomErrorMarkers.clear();
1425 mGeomErrors.clear();
1433 mCaptureCurve.clear();
1434 updateExtraSnapLayer();
1435 mSnappingMatches.clear();
1438 if ( mBezierMarker )
1439 mBezierMarker->clear();
1440 mBezierData.reset();
1441 mBezierMarker.reset();
1442 mBezierDragging =
false;
1443 mBezierDragAnchorIndex = -1;
1446 lCurrentVectorLayer->triggerRepaint();
1453 mTempRubberBand.reset();
1460 mCurrentShapeMapTool->clean();
1467 mCaptureCurve.close();
1468 updateExtraSnapLayer();
1471void QgsMapToolCapture::validateGeometry()
1479 mValidator->deleteLater();
1480 mValidator =
nullptr;
1483 mGeomErrors.clear();
1484 while ( !mGeomErrorMarkers.isEmpty() )
1486 delete mGeomErrorMarkers.takeFirst();
1491 switch ( mCaptureMode )
1499 geom = QgsGeometry( mCaptureCurve.curveToLine() );
1504 QgsLineString *exteriorRing = mCaptureCurve.curveToLine();
1505 exteriorRing->
close();
1506 QgsPolygon *polygon =
new QgsPolygon();
1508 geom = QgsGeometry( polygon );
1518 mValidator =
new QgsGeometryValidator( geom,
nullptr, method );
1520 mValidator->start();
1527 QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>(
layer() );
1533 QgsVertexMarker *vm =
new QgsVertexMarker(
mCanvas );
1537 vm->setToolTip( e.
what() );
1539 vm->setZValue( vm->zValue() + 1 );
1540 mGeomErrorMarkers << vm;
1546 return mCaptureCurve.numPoints();
1551 QVector<QgsPointXY> pointsXY;
1560 mCaptureCurve.points( pts );
1567 mCaptureCurve.clear();
1568 mCaptureCurve.addCurve( line );
1569 updateExtraSnapLayer();
1570 mSnappingMatches.clear();
1571 for (
int i = 0; i < line->
length(); ++i )
1579 mCaptureCurve.clear();
1580 mCaptureCurve.addCurve( line );
1581 updateExtraSnapLayer();
1582 mSnappingMatches.clear();
1583 for (
int i = 0; i < line->
length(); ++i )
1640 if ( match.
layer() )
1658void QgsMapToolCapture::updateExtraSnapLayer()
1660 if ( !mExtraSnapLayer )
1663 if (
canvas()->snappingUtils()->config().selfSnapping() &&
layer() )
1674 auto collection = std::make_unique<QgsGeometryCollection>();
1677 const int pointCount = mTempRubberBand->pointsCount();
1679 for (
int i = 0; i < pointCount - 1; ++i )
1681 collection->addGeometry(
new QgsPoint( mTempRubberBand->pointFromEnd( pointCount - 1 - i ) ) );
1685 std::unique_ptr<QgsCurve> nurbsCurve( mTempRubberBand->curve() );
1688 std::unique_ptr<QgsLineString> curvePoints( nurbsCurve->curveToLine() );
1692 if ( mCaptureMode ==
CapturePolygon && curvePoints->numPoints() >= 3 )
1694 curvePoints->close();
1696 collection->addGeometry( curvePoints.release() );
1700 geom = QgsGeometry( collection.release() );
1702 else if ( mBezierData && mBezierData->anchorCount() >= 2 )
1705 auto collection = std::make_unique<QgsGeometryCollection>();
1708 const QVector<QgsPoint> anchors = mBezierData->anchors();
1709 for (
const QgsPoint &point : anchors )
1711 collection->addGeometry(
new QgsPoint( point ) );
1715 const QVector<QgsPoint> handles = mBezierData->handles();
1716 for (
const QgsPoint &point : handles )
1718 collection->addGeometry(
new QgsPoint( point ) );
1723 if ( !interpolated.isEmpty() )
1725 auto curveLineString = std::make_unique<QgsLineString>( interpolated );
1727 if ( mCaptureMode ==
CapturePolygon && curveLineString->numPoints() >= 3 )
1729 curveLineString->close();
1731 collection->addGeometry( curveLineString.release() );
1734 geom = QgsGeometry( collection.release() );
1736 else if ( mCaptureCurve.numPoints() >= 2 )
1739 geom = QgsGeometry( mCaptureCurve.clone() );
1741 if ( mCaptureMode ==
CapturePolygon && mCaptureCurve.numPoints() >= 3 )
1747 mExtraSnapLayer->changeGeometry( mExtraSnapFeatureId, geom );
1752 mExtraSnapLayer->changeGeometry( mExtraSnapFeatureId, geom );
1762 if ( e->button() != Qt::LeftButton )
1766 bool isMatchPointZ =
false;
1767 bool isMatchPointM =
false;
1778 if ( isMatchPointM && isMatchPointZ )
1782 else if ( isMatchPointM )
1786 else if ( isMatchPointZ )
1790 savePoint =
QgsPoint( geomType, fetchPoint.
x(), fetchPoint.
y(), fetchPoint.
z(), fetchPoint.
m() );
1796 savePoint =
QgsPoint( point.
x(), point.
y(), fetchPoint.
z(), fetchPoint.
m() );
1806 QgsGeometry g( std::make_unique<QgsPoint>( savePoint ) );
1823 bool digitizingFinished =
false;
1825 QVector<double> nurbsWeights;
1830 if ( e->button() == Qt::LeftButton )
1833 mBezierDragging =
false;
1834 mBezierDragAnchorIndex = -1;
1835 mBezierDragHandleIndex = -1;
1836 mBezierMoveAnchorIndex = -1;
1839 if ( mBezierMarker )
1841 mBezierMarker->setHighlightedAnchor( -1 );
1842 mBezierMarker->setHighlightedHandle( -1 );
1843 mBezierMarker->updateFromData( *mBezierData );
1848 else if ( e->button() == Qt::RightButton )
1851 mBezierDragging =
false;
1852 mBezierDragAnchorIndex = -1;
1853 mBezierDragHandleIndex = -1;
1854 mBezierMoveAnchorIndex = -1;
1856 if ( mBezierData && mBezierData->anchorCount() >= 2 )
1859 std::unique_ptr<QgsNurbsCurve> nurbsCurve = mBezierData->asNurbsCurve();
1882 std::unique_ptr<QgsCurve> curveToAdd;
1888 auto compound = std::make_unique<QgsCompoundCurve>();
1889 compound->addCurve( nurbsCurve.release() );
1891 auto closingSegment = std::make_unique<QgsLineString>();
1892 closingSegment->addVertex( compound->endPoint() );
1893 closingSegment->addVertex( compound->startPoint() );
1894 compound->addCurve( closingSegment.release() );
1895 curveToAdd = std::move( compound );
1899 curveToAdd.reset( nurbsCurve.release() );
1911 auto poly = std::make_unique<QgsCurvePolygon>();
1912 poly->setExteriorRing( curveToAdd.release() );
1918 digitizingFinished =
true;
1923 if ( mBezierMarker )
1924 mBezierMarker->clear();
1925 mBezierData.reset();
1926 mBezierMarker.reset();
1934 if ( !mCurrentShapeMapTool )
1941 if ( !mTempRubberBand )
1943 mTempRubberBand.reset( createCurveRubberBand() );
1944 mTempRubberBand->setStringType( mLineDigitizingType );
1948 digitizingFinished = mCurrentShapeMapTool->cadCanvasReleaseEvent( e, mCaptureMode );
1949 if ( digitizingFinished )
1950 mCurrentShapeMapTool->clean();
1956 if ( e->button() == Qt::LeftButton )
1968 else if ( e->button() == Qt::RightButton )
1975 const int rbPointCount = mTempRubberBand->pointsCount();
1976 if ( rbPointCount > 1 )
1979 for (
int i = 0; i < rbPointCount - 1; ++i )
1981 nurbsControlPoints.append( mTempRubberBand->pointFromEnd( rbPointCount - 1 - i ) );
1984 const QVector<double> &rbWeights = mTempRubberBand->weights();
1985 for (
int i = 0; i < rbPointCount - 1; ++i )
1987 if ( i < rbWeights.size() )
1988 nurbsWeights.append( rbWeights[i] );
1990 nurbsWeights.append( 1.0 );
2033 nurbsControlPoints.append( nurbsControlPoints.first() );
2034 if ( !nurbsWeights.isEmpty() )
2035 nurbsWeights.append( nurbsWeights.first() );
2043 digitizingFinished =
true;
2047 if ( digitizingFinished )
2050 std::unique_ptr<QgsCurve> curveToAdd;
2057 const int n = nurbsControlPoints.size();
2060 if ( n < degree + 1 )
2062 degree = std::max( 1, n - 1 );
2065 curveToAdd = std::make_unique<QgsLineString>( nurbsControlPoints );
2072 const int knotCount = n + degree + 1;
2073 QVector<double> knots( knotCount );
2076 for (
int i = 0; i <= degree; ++i )
2080 for (
int i = knotCount - degree - 1; i < knotCount; ++i )
2084 const int numMiddleKnots = n - degree - 1;
2085 for (
int i = 0; i < numMiddleKnots; ++i )
2087 knots[degree + 1 + i] =
static_cast<double>( i + 1 ) / ( numMiddleKnots + 1 );
2091 QVector<double> weights = nurbsWeights;
2092 while ( weights.size() < n )
2093 weights.append( 1.0 );
2094 weights.resize( n );
2096 curveToAdd = std::make_unique<QgsNurbsCurve>( nurbsControlPoints, degree, knots, weights );
2146 if ( hasCurvedSegments && providerSupportsCurvedSegments )
2160 auto poly = std::make_unique<QgsCurvePolygon>();
2161 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.
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.