QGIS API Documentation  3.24.2-Tisler (13c1a02865)
qgsmaptoolcapture.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsmaptoolcapture.cpp - map tool for capturing points, lines, polygons
3  ---------------------
4  begin : January 2006
5  copyright : (C) 2006 by Martin Dobias
6  email : wonder.sk at gmail dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
16 #include "qgsmaptoolcapture.h"
17 #include "qgsexception.h"
18 #include "qgsfeatureiterator.h"
19 #include "qgsgeometryvalidator.h"
20 #include "qgslayertreeview.h"
21 #include "qgslinestring.h"
22 #include "qgslogger.h"
23 #include "qgsmapcanvas.h"
24 #include "qgsmapcanvastracer.h"
25 #include "qgsmapmouseevent.h"
26 #include "qgspolygon.h"
27 #include "qgsrubberband.h"
28 #include "qgssnapindicator.h"
29 #include "qgsvectorlayer.h"
30 #include "qgsvertexmarker.h"
32 #include "qgsapplication.h"
34 #include "qgsproject.h"
36 
37 #include <QAction>
38 #include <QCursor>
39 #include <QPixmap>
40 #include <QStatusBar>
41 
42 
44  : QgsMapToolAdvancedDigitizing( canvas, cadDockWidget )
45  , mCaptureMode( mode )
46  , mCaptureModeFromLayer( mode == CaptureNone )
47 {
48  mSnapIndicator.reset( new QgsSnapIndicator( canvas ) );
49 
50  setCursor( QgsApplication::getThemeCursor( QgsApplication::Cursor::CapturePoint ) );
51 
53  this, &QgsMapToolCapture::currentLayerChanged );
54 
55  QgsVectorLayer::LayerOptions layerOptions;
56  layerOptions.skipCrsValidation = true;
57  layerOptions.loadDefaultStyle = false;
58  mExtraSnapLayer = new QgsVectorLayer( QStringLiteral( "LineString?crs=" ), QStringLiteral( "extra snap" ), QStringLiteral( "memory" ), layerOptions );
59  mExtraSnapLayer->startEditing();
60  QgsFeature f;
61  mExtraSnapLayer->addFeature( f );
62  mExtraSnapFeatureId = f.id();
63 
65  this, &QgsMapToolCapture::updateExtraSnapLayer );
66 
67  currentLayerChanged( canvas->currentLayer() );
68 }
69 
71 {
72  // during tear down we have to clean up mExtraSnapLayer first, before
73  // we call stop capturing. Otherwise stopCapturing tries to access members
74  // from the mapcanvas, which is likely already being destroyed and triggering
75  // the deletion of this object...
76  mCanvas->snappingUtils()->removeExtraSnapLayer( mExtraSnapLayer );
77  mExtraSnapLayer->deleteLater();
78  mExtraSnapLayer = nullptr;
79 
80  stopCapturing();
81 
82  if ( mValidator )
83  {
84  mValidator->deleteLater();
85  mValidator = nullptr;
86  }
87 }
88 
89 QgsMapToolCapture::Capabilities QgsMapToolCapture::capabilities() const
90 {
92 }
93 
95 {
96  return technique == StraightSegments;
97 }
98 
100 {
101  if ( mTempRubberBand )
102  mTempRubberBand->show();
103 
104  mCanvas->snappingUtils()->addExtraSnapLayer( mExtraSnapLayer );
106 }
107 
109 {
110  if ( mTempRubberBand )
111  mTempRubberBand->hide();
112 
113  mSnapIndicator->setMatch( QgsPointLocator::Match() );
114 
115  mCanvas->snappingUtils()->removeExtraSnapLayer( mExtraSnapLayer );
117 }
118 
119 void QgsMapToolCapture::currentLayerChanged( QgsMapLayer *layer )
120 {
121  if ( !mCaptureModeFromLayer )
122  return;
123 
124  mCaptureMode = CaptureNone;
125 
126  QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( layer );
127  if ( !vlayer )
128  {
129  return;
130  }
131 
132  switch ( vlayer->geometryType() )
133  {
135  mCaptureMode = CapturePoint;
136  break;
138  mCaptureMode = CaptureLine;
139  break;
141  mCaptureMode = CapturePolygon;
142  break;
143  default:
144  mCaptureMode = CaptureNone;
145  break;
146  }
147 
148  if ( mTempRubberBand )
149  mTempRubberBand->setRubberBandGeometryType( mCaptureMode == CapturePolygon ? QgsWkbTypes::PolygonGeometry : QgsWkbTypes::LineGeometry );
150 
151  resetRubberBand();
152  cadDockWidget()->switchZM();
153 }
154 
155 
156 bool QgsMapToolCapture::tracingEnabled()
157 {
159  return tracer && ( !tracer->actionEnableTracing() || tracer->actionEnableTracing()->isChecked() )
160  && ( !tracer->actionEnableSnapping() || tracer->actionEnableSnapping()->isChecked() );
161 }
162 
163 
164 QgsPointXY QgsMapToolCapture::tracingStartPoint()
165 {
166  // if we have starting point from previous trace, then preferably use that one
167  // (useful when tracing with offset)
168  if ( mTracingStartPoint != QgsPointXY() )
169  return mTracingStartPoint;
170 
171  return mCaptureLastPoint;
172 }
173 
174 
175 bool QgsMapToolCapture::tracingMouseMove( QgsMapMouseEvent *e )
176 {
177  if ( !e->isSnapped() )
178  return false;
179 
180  QgsPointXY pt0 = tracingStartPoint();
181  if ( pt0 == QgsPointXY() )
182  return false;
183 
185  if ( !tracer )
186  return false; // this should not happen!
187 
189  QVector<QgsPointXY> points = tracer->findShortestPath( pt0, e->mapPoint(), &err );
190  if ( points.isEmpty() )
191  {
192  tracer->reportError( err, false );
193  return false;
194  }
195 
196  mTempRubberBand->reset( mCaptureMode == CapturePolygon ? QgsWkbTypes::PolygonGeometry : QgsWkbTypes::LineGeometry, QgsWkbTypes::LineString, mCaptureFirstPoint );
197  mTempRubberBand->addPoint( mCaptureLastPoint );
198 
199  // if there is offset, we need to fix the rubber bands to make sure they are aligned correctly.
200  // There are two cases we need to sort out:
201  // 1. the last point of mRubberBand may need to be moved off the traced curve to respect the offset
202  // 2. first point of mTempRubberBand may be needed to be moved to the beginning of the offset trace
203  const QgsPoint lastPoint = mCaptureLastPoint;
204  QgsPointXY lastPointXY( lastPoint );
205  if ( lastPointXY == pt0 && points[0] != lastPointXY )
206  {
207  if ( mRubberBand->numberOfVertices() != 0 )
208  {
209  // if rubber band had just one point, for some strange reason it contains the point twice
210  // we only want to move the last point if there are multiple points already
211  if ( mRubberBand->numberOfVertices() > 2 || ( mRubberBand->numberOfVertices() == 2 && *mRubberBand->getPoint( 0, 0 ) != *mRubberBand->getPoint( 0, 1 ) ) )
212  mRubberBand->movePoint( points[0] );
213  }
214 
215  mTempRubberBand->movePoint( 0, QgsPoint( points[0] ) );
216  }
217 
218  mTempRubberBand->movePoint( QgsPoint( points[0] ) );
219 
220  // update temporary rubberband
221  for ( int i = 1; i < points.count(); ++i ) //points added in the rubber band are 2D but will not be added to the capture curve
222  mTempRubberBand->addPoint( QgsPoint( points.at( i ) ), i == points.count() - 1 );
223 
224 
225  mTempRubberBand->addPoint( QgsPoint( points[points.size() - 1] ) );
226 
227  tracer->reportError( QgsTracer::ErrNone, false ); // clear messagebar if there was any error
228  return true;
229 }
230 
231 
232 bool QgsMapToolCapture::tracingAddVertex( const QgsPointXY &point )
233 {
235  if ( !tracer )
236  return false; // this should not happen!
237 
238  if ( mTempRubberBand->pointsCount() == 0 )
239  {
240  if ( !tracer->init() )
241  {
243  return false;
244  }
245 
246  // only accept first point if it is snapped to the graph (to vertex or edge)
247  const bool res = tracer->isPointSnapped( point );
248  if ( res )
249  {
250  mTracingStartPoint = point;
251  }
252  return false;
253  }
254 
255  QgsPointXY pt0 = tracingStartPoint();
256  if ( pt0 == QgsPointXY() )
257  return false;
258 
260  QVector<QgsPointXY> points = tracer->findShortestPath( pt0, point, &err );
261  if ( points.isEmpty() )
262  return false; // ignore the vertex - can't find path to the end point!
263 
264  // transform points
265  QgsPointSequence layerPoints;
266  QgsPoint lp; // in layer coords
267  for ( int i = 0; i < points.count(); ++i )
268  {
269  if ( nextPoint( QgsPoint( points[i] ), lp ) != 0 )
270  return false;
271  layerPoints << lp;
272  }
273 
274  // Move the last point of the captured curve to the first point on the trace string (necessary if there is offset)
275  const QgsVertexId lastVertexId( 0, 0, mCaptureCurve.numPoints() - 1 );
276  mCaptureCurve.moveVertex( lastVertexId, layerPoints.first() );
277  mSnappingMatches.removeLast();
278  mSnappingMatches.append( QgsPointLocator::Match() );
279 
280  int pointBefore = mCaptureCurve.numPoints();
281  mCaptureCurve.addCurve( new QgsLineString( layerPoints ) );
282 
283  resetRubberBand();
284 
285  // Curves de-approximation
287  {
288  // If the tool and the layer support curves
289  QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( layer() );
290  if ( vlayer && capabilities().testFlag( QgsMapToolCapture::Capability::SupportsCurves ) && vlayer->dataProvider()->capabilities().testFlag( QgsVectorDataProvider::Capability::CircularGeometries ) )
291  {
292  const QgsGeometry linear = QgsGeometry( mCaptureCurve.segmentize() );
293  const QgsGeometry curved = linear.convertToCurves(
296  );
297  mCaptureCurve = *qgsgeometry_cast<QgsCompoundCurve *>( curved.constGet() );
298  }
299  }
300 
301  // sync the snapping matches list
302  const int pointAfter = mCaptureCurve.numPoints();
303  for ( ; pointBefore < pointAfter; ++pointBefore )
304  mSnappingMatches.append( QgsPointLocator::Match() );
305 
306  tracer->reportError( QgsTracer::ErrNone, true ); // clear messagebar if there was any error
307 
308  // adjust last captured point
309  const QgsPoint lastPt = mCaptureCurve.endPoint();
310  mCaptureLastPoint = toMapCoordinates( layer(), lastPt );
311 
312  return true;
313 }
314 
315 QgsMapToolCaptureRubberBand *QgsMapToolCapture::createCurveRubberBand() const
316 {
317  QgsMapToolCaptureRubberBand *rb = new QgsMapToolCaptureRubberBand( mCanvas );
318  rb->setStrokeWidth( digitizingStrokeWidth() );
319  QColor color = digitizingStrokeColor();
320 
322  color.setAlphaF( color.alphaF() * alphaScale );
323  rb->setLineStyle( Qt::DotLine );
324  rb->setStrokeColor( color );
325 
326  const QColor fillColor = digitizingFillColor();
327  rb->setFillColor( fillColor );
328  rb->show();
329  return rb;
330 }
331 
332 void QgsMapToolCapture::resetRubberBand()
333 {
334  if ( !mRubberBand )
335  return;
336  QgsLineString *lineString = mCaptureCurve.curveToLine();
338  mRubberBand->addGeometry( QgsGeometry( lineString ), layer() );
339 }
340 
342 {
343  return mRubberBand.release();
344 }
345 
347 {
348  mDigitizingType = enable ? QgsWkbTypes::CircularString : QgsWkbTypes::LineString;
349  if ( mTempRubberBand )
350  mTempRubberBand->setStringType( mDigitizingType );
351 }
352 
354 {
355  mStreamingEnabled = enable;
356  mStartNewCurve = true;
357  if ( enable )
358  {
360  }
361 }
362 
364 {
366  const QgsPointXY point = e->mapPoint();
367 
368  mSnapIndicator->setMatch( e->mapPointMatch() );
369 
370  const QgsPoint mapPoint = QgsPoint( point );
371 
372  if ( mCaptureMode != CapturePoint && mTempRubberBand && mCapturing )
373  {
374  bool hasTrace = false;
375 
376  if ( mStreamingEnabled )
377  {
378  if ( !mCaptureCurve.isEmpty() )
379  {
380  const QgsPoint prevPoint = mCaptureCurve.curveAt( mCaptureCurve.nCurves() - 1 )->endPoint();
381  if ( QgsPointXY( toCanvasCoordinates( toMapCoordinates( layer(), prevPoint ) ) ).distance( toCanvasCoordinates( point ) ) < mStreamingToleranceInPixels )
382  return;
383  }
384 
385  mAllowAddingStreamingPoints = true;
386  addVertex( mapPoint );
387  mAllowAddingStreamingPoints = false;
388  }
389  else if ( tracingEnabled() && mCaptureCurve.numPoints() != 0 )
390  {
391  // Store the intermediate point for circular string to retrieve after tracing mouse move if
392  // the digitizing type is circular and the temp rubber band is effectivly circular and if this point is existing
393  // Store an empty point if the digitizing type is linear ot the point is not existing (curve not complete)
394  if ( mDigitizingType == QgsWkbTypes::CircularString &&
395  mTempRubberBand->stringType() == QgsWkbTypes::CircularString &&
396  mTempRubberBand->curveIsComplete() )
397  mCircularItermediatePoint = mTempRubberBand->pointFromEnd( 1 );
398  else if ( mDigitizingType == QgsWkbTypes::LineString ||
399  !mTempRubberBand->curveIsComplete() )
400  mCircularItermediatePoint = QgsPoint();
401 
402  hasTrace = tracingMouseMove( e );
403 
404  if ( !hasTrace )
405  {
406  // Restore the temp rubber band
407  mTempRubberBand->reset( mCaptureMode == CapturePolygon ? QgsWkbTypes::PolygonGeometry : QgsWkbTypes::LineGeometry, mDigitizingType, mCaptureFirstPoint );
408  mTempRubberBand->addPoint( mCaptureLastPoint );
409  if ( !mCircularItermediatePoint.isEmpty() )
410  {
411  mTempRubberBand->movePoint( mCircularItermediatePoint );
412  mTempRubberBand->addPoint( mCircularItermediatePoint );
413  }
414  }
415  }
416 
417  if ( !mStreamingEnabled && !hasTrace )
418  {
419  if ( mCaptureCurve.numPoints() > 0 )
420  {
421  const QgsPoint mapPt = mCaptureLastPoint;
422 
423  if ( mTempRubberBand )
424  {
425  mTempRubberBand->movePoint( mapPoint );
426  mTempRubberBand->movePoint( 0, mapPt );
427  }
428 
429  // fix existing rubber band after tracing - the last point may have been moved if using offset
430  if ( mRubberBand->numberOfVertices() )
431  mRubberBand->movePoint( mapPt );
432  }
433  else if ( mTempRubberBand )
434  mTempRubberBand->movePoint( mapPoint );
435  }
436  }
437 } // mouseMoveEvent
438 
439 
440 int QgsMapToolCapture::nextPoint( const QgsPoint &mapPoint, QgsPoint &layerPoint )
441 {
442  if ( QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( layer() ) )
443  {
444  try
445  {
446  const QgsPointXY mapP( mapPoint.x(), mapPoint.y() ); //#spellok
447  layerPoint = QgsPoint( toLayerCoordinates( vlayer, mapP ) ); //transform snapped point back to layer crs //#spellok
448  if ( QgsWkbTypes::hasZ( vlayer->wkbType() ) && !layerPoint.is3D() )
450  if ( QgsWkbTypes::hasM( vlayer->wkbType() ) && !layerPoint.isMeasure() )
452  }
453  catch ( QgsCsException & )
454  {
455  QgsDebugMsg( QStringLiteral( "transformation to layer coordinate failed" ) );
456  return 2;
457  }
458  }
459  else
460  {
461  layerPoint = QgsPoint( toLayerCoordinates( layer(), mapPoint ) );
462  }
463 
464  return 0;
465 }
466 
467 int QgsMapToolCapture::nextPoint( QPoint p, QgsPoint &layerPoint, QgsPoint &mapPoint )
468 {
470  return nextPoint( mapPoint, layerPoint );
471 }
472 
474 {
475  QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( layer() );
476  QgsVectorLayer *sourceLayer = match.layer();
478  {
480  return 0;
481  }
482  else if ( !vlayer )
483  {
484  return 1;
485  }
486  else
487  {
488  if ( match.isValid() && ( match.hasVertex() || match.hasLineEndpoint() || ( QgsProject::instance()->topologicalEditing() && ( match.hasEdge() || match.hasMiddleSegment() ) ) ) && sourceLayer &&
489  ( sourceLayer->crs() == vlayer->crs() ) )
490  {
491  QgsFeature f;
492  QgsFeatureRequest request;
493  request.setFilterFid( match.featureId() );
494  const bool fetched = match.layer()->getFeatures( request ).nextFeature( f );
495  if ( fetched )
496  {
497  QgsVertexId vId;
498  if ( !f.geometry().vertexIdFromVertexNr( match.vertexIndex(), vId ) )
499  return 2;
500 
501  const QgsGeometry geom( f.geometry() );
502  if ( QgsProject::instance()->topologicalEditing() && ( match.hasEdge() || match.hasMiddleSegment() ) )
503  {
504  QgsVertexId vId2;
505  if ( !f.geometry().vertexIdFromVertexNr( match.vertexIndex() + 1, vId2 ) )
506  return 2;
507  const QgsLineString line( geom.constGet()->vertexAt( vId ), geom.constGet()->vertexAt( vId2 ) );
508 
509  layerPoint = QgsGeometryUtils::closestPoint( line, QgsPoint( match.point() ) );
510  }
511  else
512  {
513  layerPoint = geom.constGet()->vertexAt( vId );
514  if ( QgsWkbTypes::hasZ( vlayer->wkbType() ) && !layerPoint.is3D() )
515  layerPoint.addZValue( defaultZValue() );
516  if ( QgsWkbTypes::hasM( vlayer->wkbType() ) && !layerPoint.isMeasure() )
517  layerPoint.addMValue( defaultMValue() );
518  }
519 
520  // ZM support depends on the target layer
521  if ( !QgsWkbTypes::hasZ( vlayer->wkbType() ) )
522  {
523  layerPoint.dropZValue();
524  }
525 
526  if ( !QgsWkbTypes::hasM( vlayer->wkbType() ) )
527  {
528  layerPoint.dropMValue();
529  }
530 
531  return 0;
532  }
533  else
534  {
535  return 2;
536  }
537  }
538  else
539  {
540  return 1;
541  }
542  }
543 }
544 
546 {
547  return addVertex( point, QgsPointLocator::Match() );
548 }
549 
551 {
552  if ( mode() == CaptureNone )
553  {
554  QgsDebugMsg( QStringLiteral( "invalid capture mode" ) );
555  return 2;
556  }
557 
558  if ( mCapturing && mStreamingEnabled && !mAllowAddingStreamingPoints )
559  return 0;
560 
561  QgsPoint layerPoint;
562  if ( layer() )
563  {
564  int res = fetchLayerPoint( match, layerPoint );
565  if ( res != 0 )
566  {
567  res = nextPoint( QgsPoint( point ), layerPoint );
568  if ( res != 0 )
569  {
570  return res;
571  }
572  }
573  }
574  const QgsPoint mapPoint = toMapCoordinates( layer(), layerPoint );
575 
576  if ( mCaptureMode == CapturePoint )
577  {
578  mCaptureCurve.addVertex( layerPoint );
579  mSnappingMatches.append( match );
580  }
581  else
582  {
583  if ( mCaptureFirstPoint.isEmpty() )
584  {
585  mCaptureFirstPoint = mapPoint;
586  }
587 
588  if ( !mRubberBand )
590 
591  if ( !mTempRubberBand )
592  {
593  mTempRubberBand.reset( createCurveRubberBand() );
594  mTempRubberBand->setStringType( mDigitizingType );
595  mTempRubberBand->reset( mCaptureMode == CapturePolygon ? QgsWkbTypes::PolygonGeometry : QgsWkbTypes::LineGeometry, mDigitizingType, mapPoint );
596  }
597 
598  bool traceCreated = false;
599  if ( tracingEnabled() )
600  {
601  traceCreated = tracingAddVertex( mapPoint );
602  }
603 
604  // keep new tracing start point if we created a trace. This is useful when tracing with
605  // offset so that the user stays "snapped"
606  mTracingStartPoint = traceCreated ? point : QgsPointXY();
607 
608  if ( !traceCreated )
609  {
610  // ordinary digitizing
611  mTempRubberBand->movePoint( mapPoint ); //move the last point of the temp rubberband before operating with it
612  if ( mTempRubberBand->curveIsComplete() ) //2 points for line and 3 points for circular
613  {
614  const QgsCurve *curve = mTempRubberBand->curve();
615  if ( curve )
616  {
617  addCurve( curve->clone() );
618  // add curve append only invalid match to mSnappingMatches,
619  // so we need to remove them and add the one from here if it is valid
620  if ( match.isValid() && mSnappingMatches.count() > 0 && !mSnappingMatches.last().isValid() )
621  {
622  mSnappingMatches.removeLast();
623  if ( mTempRubberBand->stringType() == QgsWkbTypes::CircularString )
624  {
625  // for circular string two points are added and match for intermediate point is stored
626  mSnappingMatches.removeLast();
627  mSnappingMatches.append( mCircularIntermediateMatch );
628  }
629  mSnappingMatches.append( match );
630  }
631  }
632  mCaptureLastPoint = mapPoint;
633  mTempRubberBand->reset( mCaptureMode == CapturePolygon ? QgsWkbTypes::PolygonGeometry : QgsWkbTypes::LineGeometry, mDigitizingType, mCaptureFirstPoint );
634  }
635  else if ( mTempRubberBand->pointsCount() == 0 )
636  {
637  mCaptureLastPoint = mapPoint;
638  mCaptureCurve.addVertex( layerPoint );
639  mSnappingMatches.append( match );
640  }
641  else
642  {
643  if ( mTempRubberBand->stringType() == QgsWkbTypes::CircularString )
644  {
645  mCircularIntermediateMatch = match;
646  }
647  }
648 
649  mTempRubberBand->addPoint( mapPoint );
650  }
651  else
652  {
653  mTempRubberBand->reset( mCaptureMode == CapturePolygon ? QgsWkbTypes::PolygonGeometry : QgsWkbTypes::LineGeometry, mDigitizingType, mCaptureFirstPoint );
654  mTempRubberBand->addPoint( mCaptureLastPoint );
655  }
656  }
657 
658  updateExtraSnapLayer();
659  validateGeometry();
660 
661  return 0;
662 }
663 
665 {
666  if ( !c )
667  {
668  return 1;
669  }
670 
671  if ( !mRubberBand )
672  {
674  }
675 
676  if ( mTempRubberBand )
677  {
678  mTempRubberBand->reset( mCaptureMode == CapturePolygon ? QgsWkbTypes::PolygonGeometry : QgsWkbTypes::LineGeometry, mDigitizingType, mCaptureFirstPoint );
679  const QgsPoint endPt = c->endPoint();
680  mTempRubberBand->addPoint( endPt ); //add last point of c
681  }
682 
683  //transform back to layer CRS in case map CRS and layer CRS are different
685  if ( ct.isValid() )
686  {
687  c->transform( ct, Qgis::TransformDirection::Reverse );
688  }
689  const int countBefore = mCaptureCurve.vertexCount();
690  //if there is only one point, this the first digitized point that are in the this first curve added --> remove the point
691  if ( mCaptureCurve.numPoints() == 1 )
692  mCaptureCurve.removeCurve( 0 );
693 
694  // we set the extendPrevious option to true to avoid creating compound curves with many 2 vertex linestrings -- instead we prefer
695  // to extend linestring curves so that they continue the previous linestring wherever possible...
696  mCaptureCurve.addCurve( c, !mStartNewCurve );
697  mStartNewCurve = false;
698 
699  const int countAfter = mCaptureCurve.vertexCount();
700  const int addedPoint = countAfter - countBefore;
701 
702  updateExtraSnapLayer();
703 
704  for ( int i = 0; i < addedPoint; ++i )
705  mSnappingMatches.append( QgsPointLocator::Match() );
706 
707  resetRubberBand();
708 
709  return 0;
710 }
711 
713 {
714  mCaptureCurve.clear();
715  updateExtraSnapLayer();
716 }
717 
718 QList<QgsPointLocator::Match> QgsMapToolCapture::snappingMatches() const
719 {
720  return mSnappingMatches;
721 }
722 
723 void QgsMapToolCapture::undo( bool isAutoRepeat )
724 {
725  mTracingStartPoint = QgsPointXY();
726 
727  if ( mTempRubberBand )
728  {
729  if ( size() <= 1 && mTempRubberBand->pointsCount() != 0 )
730  return;
731 
732  if ( isAutoRepeat && mIgnoreSubsequentAutoRepeatUndo )
733  return;
734  mIgnoreSubsequentAutoRepeatUndo = false;
735 
736  const QgsPoint lastPoint = mTempRubberBand->lastPoint();
737 
738  if ( mTempRubberBand->stringType() == QgsWkbTypes::CircularString && mTempRubberBand->pointsCount() > 2 )
739  {
740  mTempRubberBand->removeLastPoint();
741  mTempRubberBand->movePoint( lastPoint );
742  return;
743  }
744 
745  QgsVertexId vertexToRemove;
746  vertexToRemove.part = 0;
747  vertexToRemove.ring = 0;
748  vertexToRemove.vertex = size() - 1;
749  if ( mCaptureCurve.numPoints() == 2 && mCaptureCurve.nCurves() == 1 )
750  {
751  // store the first vertex to restore if after deleting the curve
752  // because when only two vertices, removing a point remove all the curve
753  const QgsPoint fp = mCaptureCurve.startPoint();
754  mCaptureCurve.deleteVertex( vertexToRemove );
755  mCaptureCurve.addVertex( fp );
756  }
757  else
758  {
759  const int curvesBefore = mCaptureCurve.nCurves();
760  const bool lastCurveIsLineString = qgsgeometry_cast< QgsLineString * >( mCaptureCurve.curveAt( curvesBefore - 1 ) );
761 
762  const int pointsCountBefore = mCaptureCurve.numPoints();
763  mCaptureCurve.deleteVertex( vertexToRemove );
764  int pointsCountAfter = mCaptureCurve.numPoints();
765  for ( ; pointsCountAfter < pointsCountBefore; pointsCountAfter++ )
766  if ( !mSnappingMatches.empty() )
767  mSnappingMatches.removeLast();
768 
769  // if we have removed the last point in a linestring curve, then we "stick" here and ignore subsequent
770  // autorepeat undo actions until the user releases the undo key and holds it down again. This allows
771  // users to selectively remove portions of the geometry captured with the streaming mode by holding down
772  // the undo key, without risking accidental undo of non-streamed portions.
773  if ( mCaptureCurve.nCurves() < curvesBefore && lastCurveIsLineString )
774  mIgnoreSubsequentAutoRepeatUndo = true;
775  }
776 
777  updateExtraSnapLayer();
778 
779  resetRubberBand();
780 
781  mTempRubberBand->reset( mCaptureMode == CapturePolygon ? QgsWkbTypes::PolygonGeometry : QgsWkbTypes::LineGeometry, mDigitizingType, mCaptureFirstPoint );
782 
783  if ( mCaptureCurve.numPoints() > 0 )
784  {
785  const QgsPoint lastPt = mCaptureCurve.endPoint();
786  mCaptureLastPoint = toMapCoordinates( layer(), lastPt );
787  mTempRubberBand->addPoint( mCaptureLastPoint );
788  mTempRubberBand->movePoint( lastPoint );
789  }
790 
792  validateGeometry();
793  }
794 }
795 
797 {
798  if ( e->key() == Qt::Key_Backspace || e->key() == Qt::Key_Delete )
799  {
800  undo( e->isAutoRepeat() );
801 
802  // Override default shortcut management in MapCanvas
803  e->ignore();
804  }
805  else if ( e->key() == Qt::Key_Escape )
806  {
807  stopCapturing();
808 
809  // Override default shortcut management in MapCanvas
810  e->ignore();
811  }
812 }
813 
815 {
816  mCapturing = true;
817 }
818 
820 {
821  return mCapturing;
822 }
823 
825 {
826  mRubberBand.reset();
827 
829 
830  qDeleteAll( mGeomErrorMarkers );
831  mGeomErrorMarkers.clear();
832  mGeomErrors.clear();
833 
834  mCaptureFirstPoint = QgsPoint();
835  mCaptureLastPoint = QgsPoint();
836 
837  mTracingStartPoint = QgsPointXY();
838 
839  mCapturing = false;
840  mCaptureCurve.clear();
841  updateExtraSnapLayer();
842  mSnappingMatches.clear();
843  if ( auto *lCurrentVectorLayer = currentVectorLayer() )
844  lCurrentVectorLayer->triggerRepaint();
845 }
846 
848 {
849  mTempRubberBand.reset();
850 }
851 
853 {
854  stopCapturing();
855  clearCurve();
856 }
857 
859 {
860  mCaptureCurve.close();
861  updateExtraSnapLayer();
862 }
863 
864 void QgsMapToolCapture::validateGeometry()
865 {
867  || !( capabilities() & ValidateGeometries )
868  )
869  return;
870 
871  if ( mValidator )
872  {
873  mValidator->deleteLater();
874  mValidator = nullptr;
875  }
876 
877  mGeomErrors.clear();
878  while ( !mGeomErrorMarkers.isEmpty() )
879  {
880  delete mGeomErrorMarkers.takeFirst();
881  }
882 
883  QgsGeometry geom;
884 
885  switch ( mCaptureMode )
886  {
887  case CaptureNone:
888  case CapturePoint:
889  return;
890  case CaptureLine:
891  if ( size() < 2 )
892  return;
893  geom = QgsGeometry( mCaptureCurve.curveToLine() );
894  break;
895  case CapturePolygon:
896  if ( size() < 3 )
897  return;
898  QgsLineString *exteriorRing = mCaptureCurve.curveToLine();
899  exteriorRing->close();
900  QgsPolygon *polygon = new QgsPolygon();
901  polygon->setExteriorRing( exteriorRing );
902  geom = QgsGeometry( polygon );
903  break;
904  }
905 
906  if ( geom.isNull() )
907  return;
908 
909  Qgis::GeometryValidationEngine method = Qgis::GeometryValidationEngine::QgisInternal;
911  method = Qgis::GeometryValidationEngine::Geos;
912  mValidator = new QgsGeometryValidator( geom, nullptr, method );
913  connect( mValidator, &QgsGeometryValidator::errorFound, this, &QgsMapToolCapture::addError );
914  mValidator->start();
915  QgsDebugMsgLevel( QStringLiteral( "Validation started" ), 4 );
916 }
917 
918 void QgsMapToolCapture::addError( const QgsGeometry::Error &e )
919 {
920  mGeomErrors << e;
921  QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( layer() );
922  if ( !vlayer )
923  return;
924 
925  if ( e.hasWhere() )
926  {
928  vm->setCenter( mCanvas->mapSettings().layerToMapCoordinates( vlayer, e.where() ) );
930  vm->setPenWidth( 2 );
931  vm->setToolTip( e.what() );
932  vm->setColor( Qt::green );
933  vm->setZValue( vm->zValue() + 1 );
934  mGeomErrorMarkers << vm;
935  }
936 }
937 
939 {
940  return mCaptureCurve.numPoints();
941 }
942 
943 QVector<QgsPointXY> QgsMapToolCapture::points() const
944 {
945  QVector<QgsPointXY> pointsXY;
947 
948  return pointsXY;
949 }
950 
952 {
953  QgsPointSequence pts;
954  mCaptureCurve.points( pts );
955  return pts;
956 }
957 
958 void QgsMapToolCapture::setPoints( const QVector<QgsPointXY> &pointList )
959 {
960  QgsLineString *line = new QgsLineString( pointList );
961  mCaptureCurve.clear();
962  mCaptureCurve.addCurve( line );
963  updateExtraSnapLayer();
964  mSnappingMatches.clear();
965  for ( int i = 0; i < line->length(); ++i )
966  mSnappingMatches.append( QgsPointLocator::Match() );
967  resetRubberBand();
968 }
969 
971 {
972  QgsLineString *line = new QgsLineString( pointList );
973  mCaptureCurve.clear();
974  mCaptureCurve.addCurve( line );
975  updateExtraSnapLayer();
976  mSnappingMatches.clear();
977  for ( int i = 0; i < line->length(); ++i )
978  mSnappingMatches.append( QgsPointLocator::Match() );
979  resetRubberBand();
980 }
981 
983 {
984  QgsPoint newPoint( QgsWkbTypes::Point, point.x(), point.y() );
985 
986  // get current layer
987  QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( layer() );
988  if ( !vlayer )
989  {
990  return newPoint;
991  }
992 
993  // convert to the corresponding type for a full ZM support
994  const QgsWkbTypes::Type type = vlayer->wkbType();
995  if ( QgsWkbTypes::hasZ( type ) && !QgsWkbTypes::hasM( type ) )
996  {
997  newPoint.convertTo( QgsWkbTypes::PointZ );
998  }
999  else if ( !QgsWkbTypes::hasZ( type ) && QgsWkbTypes::hasM( type ) )
1000  {
1001  newPoint.convertTo( QgsWkbTypes::PointM );
1002  }
1003  else if ( QgsWkbTypes::hasZ( type ) && QgsWkbTypes::hasM( type ) )
1004  {
1005  newPoint.convertTo( QgsWkbTypes::PointZM );
1006  }
1007 
1008  // set z value if necessary
1009  if ( QgsWkbTypes::hasZ( newPoint.wkbType() ) )
1010  {
1012  }
1013  // set m value if necessary
1014  if ( QgsWkbTypes::hasM( newPoint.wkbType() ) )
1015  {
1017  }
1018  return newPoint;
1019 }
1020 
1022 {
1023  QgsPoint newPoint = mapPoint( e.mapPoint() );
1024 
1025  // set z or m value from snapped point if necessary
1026  if ( QgsWkbTypes::hasZ( newPoint.wkbType() ) || QgsWkbTypes::hasM( newPoint.wkbType() ) )
1027  {
1028  // if snapped, z and m dimension are taken from the corresponding snapped
1029  // point.
1030  if ( e.isSnapped() )
1031  {
1032  const QgsPointLocator::Match match = e.mapPointMatch();
1033 
1034  if ( match.layer() )
1035  {
1036  const QgsFeature ft = match.layer()->getFeature( match.featureId() );
1037  if ( QgsWkbTypes::hasZ( match.layer()->wkbType() ) )
1038  {
1039  newPoint.setZ( ft.geometry().vertexAt( match.vertexIndex() ).z() );
1040  }
1041  if ( QgsWkbTypes::hasM( match.layer()->wkbType() ) )
1042  {
1043  newPoint.setM( ft.geometry().vertexAt( match.vertexIndex() ).m() );
1044  }
1045  }
1046  }
1047  }
1048 
1049  return newPoint;
1050 }
1051 
1052 void QgsMapToolCapture::updateExtraSnapLayer()
1053 {
1054  if ( !mExtraSnapLayer )
1055  return;
1056 
1057  if ( canvas()->snappingUtils()->config().selfSnapping() && layer() && mCaptureCurve.numPoints() >= 2 )
1058  {
1059  // the current layer may have changed
1060  mExtraSnapLayer->setCrs( layer()->crs() );
1061  QgsGeometry geom = QgsGeometry( mCaptureCurve.clone() );
1062  // we close the curve to allow snapping on last segment
1063  if ( mCaptureMode == CapturePolygon && mCaptureCurve.numPoints() >= 3 )
1064  {
1065  qgsgeometry_cast<QgsCompoundCurve *>( geom.get() )->close();
1066  }
1067  mExtraSnapLayer->changeGeometry( mExtraSnapFeatureId, geom );
1068  }
1069  else
1070  {
1071  QgsGeometry geom;
1072  mExtraSnapLayer->changeGeometry( mExtraSnapFeatureId, geom );
1073  }
1074 }
1075 
T * release()
Clears the pointer and returns it.
void reset(T *p=nullptr)
Will reset the managed pointer to p.
GeometryValidationEngine
Available engines for validating geometries.
Definition: qgis.h:721
bool is3D() const SIP_HOLDGIL
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.
QgsWkbTypes::Type wkbType() const SIP_HOLDGIL
Returns the WKB type of the geometry.
bool isMeasure() const SIP_HOLDGIL
Returns true if the geometry contains m values.
The QgsAdvancedDigitizingDockWidget class is a dockable widget used to handle the CAD tools on top of...
bool cadEnabled() const
determines if CAD tools are enabled or if map tools behaves "nomally"
void switchZM()
Determines if Z or M will be enabled.
double getLineM() const
Convenient method to get the M value from the line edit wiget.
void removePreviousPoint()
Remove previous point in the CAD point list.
double getLineZ() const
Convenient method to get the Z value from the line edit wiget.
QgsPoint currentPointV2(bool *exists=nullptr) const
The last point.
QgsPoint currentPointLayerCoordinates(QgsMapLayer *layer) const
Returns the last CAD point, in a map layer's coordinates.
static QCursor getThemeCursor(Cursor cursor)
Helper to get a theme cursor.
QgsLineString * curveToLine(double tolerance=M_PI_2/90, SegmentationToleranceType toleranceType=MaximumAngle) const override
Returns a new line string geometry corresponding to a segmentized approximation of the curve.
void close()
Appends first point if not already closed.
QgsPoint endPoint() const override SIP_HOLDGIL
Returns the end point of the curve.
const QgsCurve * curveAt(int i) const SIP_HOLDGIL
Returns the curve at the specified index.
int numPoints() const override SIP_HOLDGIL
Returns the number of points in the curve.
void removeCurve(int i)
Removes a curve from the geometry.
void addCurve(QgsCurve *c, bool extendPrevious=false)
Adds a curve to the geometry (takes ownership).
bool moveVertex(QgsVertexId position, const QgsPoint &newPos) override
Moves a vertex within the geometry.
bool deleteVertex(QgsVertexId position) override
Deletes a vertex within the geometry.
QgsCompoundCurve * clone() const override
Clones the geometry by performing a deep copy.
void points(QgsPointSequence &pts) const override
Returns a list of points within the curve.
void clear() override
Clears the geometry, ie reset it to a null geometry.
QgsPoint startPoint() const override SIP_HOLDGIL
Returns the starting point of the curve.
bool isEmpty() const override SIP_HOLDGIL
Returns true if the geometry is empty.
void addVertex(const QgsPoint &pt)
Adds a vertex to the end of the geometry.
int nCurves() const SIP_HOLDGIL
Returns the number of curves in the geometry.
Class for doing transforms between two map coordinate systems.
bool isValid() const
Returns true if the coordinate transform is valid, ie both the source and destination CRS have been s...
Custom exception class for Coordinate Reference System related exceptions.
Definition: qgsexception.h:66
Abstract base class for curved geometry type.
Definition: qgscurve.h:36
QgsCurve * segmentize(double tolerance=M_PI_2/90, SegmentationToleranceType toleranceType=MaximumAngle) const override
Returns a geometry without curves.
Definition: qgscurve.cpp:175
int vertexCount(int part=0, int ring=0) const override
Returns the number of vertices of which this geometry is built.
Definition: qgscurve.cpp:180
QgsCurve * clone() const override=0
Clones the geometry by performing a deep copy.
virtual QgsPoint endPoint() const =0
Returns the end point of the curve.
bool nextFeature(QgsFeature &f)
This class 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...
Definition: qgsfeature.h:56
QgsGeometry geometry
Definition: qgsfeature.h:67
Q_GADGET QgsFeatureId id
Definition: qgsfeature.h:64
static QgsPoint closestPoint(const QgsAbstractGeometry &geometry, const QgsPoint &point)
Returns the nearest point on a segment of a geometry for the specified point.
void errorFound(const QgsGeometry::Error &error)
Sent when an error has been found during the validation process.
A geometry error.
Definition: qgsgeometry.h:2405
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.
Definition: qgsgeometry.h:125
const QgsAbstractGeometry * constGet() const SIP_HOLDGIL
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
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.
Q_GADGET bool isNull
Definition: qgsgeometry.h:127
QgsAbstractGeometry * get()
Returns a modifiable (non-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.
Line string geometry type, with support for z-dimension and m-values.
Definition: qgslinestring.h:44
double length() const override SIP_HOLDGIL
Returns the planar, 2-dimensional length of the geometry.
void close()
Closes the line string by appending the first point to the end of the line, if it is not already clos...
Extension of QgsTracer that provides extra functionality:
QAction * actionEnableTracing() const
Access to action that user may use to toggle tracing on/off. May be nullptr if no action was associat...
void reportError(PathError err, bool addingVertex)
Report a path finding error to the user.
static QgsMapCanvasTracer * tracerForCanvas(QgsMapCanvas *canvas)
Retrieve instance of this class associated with given canvas (if any).
QAction * actionEnableSnapping() const
Access to action that user may use to toggle snapping on/off.
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:90
void currentLayerChanged(QgsMapLayer *layer)
Emitted when the current layer is changed.
QgsSnappingUtils * snappingUtils() const
Returns snapping utility class that is associated with map canvas.
const QgsMapSettings & mapSettings() const
Gets access to properties used for map rendering.
QgsMapLayer * currentLayer()
returns current layer (set by legend widget)
Base class for all map layer types.
Definition: qgsmaplayer.h:73
QgsCoordinateReferenceSystem crs
Definition: qgsmaplayer.h:79
void setCrs(const QgsCoordinateReferenceSystem &srs, bool emitSignal=true)
Sets layer's spatial reference system.
A QgsMapMouseEvent is the result of a user interaction with the mouse on 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.
QgsPointXY layerToMapCoordinates(const QgsMapLayer *layer, QgsPointXY point) const
transform point coordinates from layer's CRS to output CRS
QgsCoordinateTransform layerTransform(const QgsMapLayer *layer) const
Returns the coordinate transform from layer's CRS to destination CRS.
The QgsMapToolAdvancedDigitizing class is a QgsMapTool which gives event directly in map coordinates ...
virtual void cadCanvasMoveEvent(QgsMapMouseEvent *e)
Override this method when subclassing this class.
QgsAdvancedDigitizingDockWidget * mCadDockWidget
void deactivate() override
Unregisters this maptool from the cad dock widget.
virtual QgsMapLayer * layer() const
Returns the layer associated with the map tool.
QgsAdvancedDigitizingDockWidget * cadDockWidget() const
void activate() override
Registers this maptool with the cad dock widget.
void deactivate() override
Unregisters this maptool from the cad dock widget.
void stopCapturing()
Stop capturing.
int size()
Number of points digitized.
CaptureMode mode() const
The capture mode.
QgsMapToolCapture(QgsMapCanvas *canvas, QgsAdvancedDigitizingDockWidget *cadDockWidget, CaptureMode mode)
constructor
void undo(bool isAutoRepeat=false)
Removes the last vertex from mRubberBand and mCaptureList.
QgsPoint mapPoint(const QgsMapMouseEvent &e) const
Creates a QgsPoint with ZM support if necessary (according to the WkbType of the current layer).
void keyPressEvent(QKeyEvent *e) override
Intercept key events like Esc or Del to delete the last point.
void activate() override
Registers this maptool with the cad dock widget.
CaptureMode
Different capture modes.
@ CapturePolygon
Capture polygons.
@ CaptureNone
Do not capture / determine mode from layer geometry type.
@ CapturePoint
Capture points.
@ CaptureLine
Capture lines.
void setCircularDigitizingEnabled(bool enable)
Enable the digitizing with curve.
void deleteTempRubberBand()
Clean a temporary rubberband.
void clean() override
convenient method to clean members
~QgsMapToolCapture() override
CaptureTechnique
Capture technique.
@ StraightSegments
Default capture mode - capture occurs with straight line segments.
void closePolygon()
Close an open polygon.
int addCurve(QgsCurve *c)
Adds a whole curve (e.g. circularstring) to the captured geometry. Curve must be in map CRS.
int fetchLayerPoint(const QgsPointLocator::Match &match, QgsPoint &layerPoint)
Fetches the original point from the source layer if it has the same CRS as the current layer.
QgsPointSequence pointsZM() const
List of digitized points.
Q_DECL_DEPRECATED void setPoints(const QVector< QgsPointXY > &pointList)
Set the points on which to work.
QList< QgsPointLocator::Match > snappingMatches() const
Returns a list of matches for each point on the captureCurve.
Q_DECL_DEPRECATED QVector< QgsPointXY > points() const
List of digitized points.
bool isCapturing() const
Are we currently capturing?
int addVertex(const QgsPointXY &point)
Adds a point to the rubber band (in map coordinates) and to the capture list (in layer coordinates)
@ ValidateGeometries
Tool supports geometry validation (since QGIS 3.22)
virtual QgsMapToolCapture::Capabilities capabilities() const
Returns flags containing the supported capabilities.
void clearCurve()
Clear capture curve.
int nextPoint(const QgsPoint &mapPoint, QgsPoint &layerPoint)
Converts a map point to layer coordinates.
void setStreamDigitizingEnabled(bool enable)
Toggles the stream digitizing mode.
void cadCanvasMoveEvent(QgsMapMouseEvent *e) override
Override this method when subclassing this class.
void startCapturing()
Start capturing.
QgsRubberBand * takeRubberBand()
Returns the rubberBand currently owned by this map tool and transfers ownership to the caller.
virtual bool supportsTechnique(CaptureTechnique technique) const
Returns true if the tool supports the specified capture technique.
double defaultZValue() const
Returns default Z value.
double defaultMValue() const
Returns default M value.
QgsVectorLayer * currentVectorLayer()
Returns the current vector layer of the map canvas or 0.
static QColor digitizingFillColor()
Returns fill color for rubber bands (from global settings)
QgsRubberBand * createRubberBand(QgsWkbTypes::GeometryType geometryType=QgsWkbTypes::LineGeometry, bool alternativeBand=false)
Creates a rubber band with the color/line width from the QGIS settings.
static QColor digitizingStrokeColor()
Returns stroke color for rubber bands (from global settings)
static int digitizingStrokeWidth()
Returns stroke width for rubber bands (from global settings)
QgsPoint toLayerCoordinates(const QgsMapLayer *layer, const QgsPoint &point)
Transforms a point from map coordinates to layer coordinates.
Definition: qgsmaptool.cpp:62
QgsMapCanvas * mCanvas
The pointer to the map canvas.
Definition: qgsmaptool.h:336
QgsMapCanvas * canvas() const
returns pointer to the tool's map canvas
Definition: qgsmaptool.cpp:215
QgsPointXY toMapCoordinates(QPoint point)
Transforms a point from screen coordinates to map coordinates.
Definition: qgsmaptool.cpp:41
virtual void setCursor(const QCursor &cursor)
Sets a user defined cursor.
Definition: qgsmaptool.cpp:160
QPoint toCanvasCoordinates(const QgsPointXY &point) const
Transforms a point from map coordinates to screen coordinates.
Definition: qgsmaptool.cpp:77
A class to represent a 2D point.
Definition: qgspointxy.h:59
double y
Definition: qgspointxy.h:63
Q_GADGET double x
Definition: qgspointxy.h:62
Point geometry type, with support for z-dimension and m-values.
Definition: qgspoint.h:49
bool addMValue(double mValue=0) override
Adds a measure to the geometry, initialized to a preset value.
Definition: qgspoint.cpp:562
bool dropMValue() override
Drops any measure values which exist in the geometry.
Definition: qgspoint.cpp:603
bool isEmpty() const override SIP_HOLDGIL
Returns true if the geometry is empty.
Definition: qgspoint.cpp:767
bool addZValue(double zValue=0) override
Adds a z-dimension to the geometry, initialized to a preset value.
Definition: qgspoint.cpp:551
Q_GADGET double x
Definition: qgspoint.h:52
bool convertTo(QgsWkbTypes::Type type) override
Converts the geometry to a specified type.
Definition: qgspoint.cpp:620
void setZ(double z) SIP_HOLDGIL
Sets the point's z-coordinate.
Definition: qgspoint.h:304
double z
Definition: qgspoint.h:54
bool dropZValue() override
Drops any z-dimensions which exist in the geometry.
Definition: qgspoint.cpp:592
double m
Definition: qgspoint.h:55
double y
Definition: qgspoint.h:53
void setM(double m) SIP_HOLDGIL
Sets the point's m-value.
Definition: qgspoint.h:319
Polygon geometry type.
Definition: qgspolygon.h:34
void setExteriorRing(QgsCurve *ring) override
Sets the exterior ring of the polygon.
Definition: qgspolygon.cpp:219
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:470
void snappingConfigChanged(const QgsSnappingConfig &config)
Emitted whenever the configuration for snapping has changed.
bool topologicalEditing
Definition: qgsproject.h:117
A class for drawing transient features (e.g.
Definition: qgsrubberband.h:52
void movePoint(const QgsPointXY &p, int geometryIndex=0, int ringIndex=0)
Moves the rubber band point specified by index.
const QgsPointXY * getPoint(int i, int j=0, int ringIndex=0) const
Returns a vertex.
void reset(QgsWkbTypes::GeometryType geometryType=QgsWkbTypes::LineGeometry)
Clears all the geometries in this rubberband.
int numberOfVertices() const
Returns count of vertices in all lists of mPoint.
void addGeometry(const QgsGeometry &geometry, QgsMapLayer *layer, bool doUpdate=true)
Adds the geometry of an existing feature to a rubberband This is useful for multi feature highlightin...
double value(const QString &dynamicKeyPart=QString(), bool useDefaultValueOverride=false, double defaultValueOverride=0.0) const
Returns settings value.
qlonglong value(const QString &dynamicKeyPart=QString(), bool useDefaultValueOverride=false, qlonglong defaultValueOverride=0) const
Returns settings value.
static const QgsSettingsEntryBool settingsDigitizingConvertToCurve
Settings entry digitizing convert to curve.
static const QgsSettingsEntryInteger settingsDigitizingStreamTolerance
Settings entry digitizing stream tolerance.
static const QgsSettingsEntryDouble settingsDigitizingConvertToCurveDistanceTolerance
Settings entry digitizing convert to curve distance tolerance.
static const QgsSettingsEntryInteger settingsDigitizingValidateGeometries
Settings entry digitizing validate geometries.
static const QgsSettingsEntryDouble settingsDigitizingConvertToCurveAngleTolerance
Settings entry digitizing convert to curve angle tolerance.
static const QgsSettingsEntryDouble settingsDigitizingLineColorAlphaScale
Settings entry digitizing line color alpha scale.
Class that shows snapping marker on map canvas for the current snapping match.
void addExtraSnapLayer(QgsVectorLayer *vl)
Supply an extra snapping layer (typically a memory layer).
void removeExtraSnapLayer(QgsVectorLayer *vl)
Removes an extra snapping layer.
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...
Definition: qgstracer.cpp:803
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.
Definition: qgstracer.cpp:736
PathError
Possible errors that may happen when calling findShortestPath()
Definition: qgstracer.h:138
@ ErrNone
No error.
Definition: qgstracer.h:139
@ ErrTooManyFeatures
Max feature count threshold was reached while reading features.
Definition: qgstracer.h:140
bool init()
Build the internal data structures.
Definition: qgstracer.cpp:675
virtual Q_INVOKABLE QgsVectorDataProvider::Capabilities capabilities() const
Returns flags containing the supported capabilities.
Represents a vector layer which manages a vector based data sets.
Q_INVOKABLE QgsWkbTypes::Type wkbType() const FINAL
Returns the WKBType or WKBUnknown in case of error.
Q_INVOKABLE QgsWkbTypes::GeometryType geometryType() const
Returns point, line or polygon.
Q_INVOKABLE bool startEditing()
Makes the layer editable.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const FINAL
Queries the layer for features specified in request.
QgsVectorDataProvider * dataProvider() FINAL
Returns the layer's data provider, it may be nullptr.
QgsFeature getFeature(QgsFeatureId fid) const
Queries the layer for the feature with the given id.
bool addFeature(QgsFeature &feature, QgsFeatureSink::Flags flags=QgsFeatureSink::Flags()) FINAL
Adds a single feature to the sink.
bool changeGeometry(QgsFeatureId fid, QgsGeometry &geometry, bool skipDefaultValue=false)
Changes a feature's geometry within the layer's edit buffer (but does not immediately commit the chan...
A class for marking vertices of features using e.g.
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 bool hasM(Type type) SIP_HOLDGIL
Tests whether a WKB type contains m values.
Definition: qgswkbtypes.h:1130
Type
The WKB type describes the number of dimensions a geometry has.
Definition: qgswkbtypes.h:70
static bool hasZ(Type type) SIP_HOLDGIL
Tests whether a WKB type contains the z-dimension.
Definition: qgswkbtypes.h:1080
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
QVector< QgsPoint > QgsPointSequence
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
const QgsCoordinateReferenceSystem & crs
QgsVectorLayer * layer() const
The vector layer where the snap occurred.
QgsFeatureId featureId() const
The id of the feature to which the snapped geometry belongs.
QgsPointXY point() const
for vertex / edge match coords depending on what class returns it (geom.cache: layer coords,...
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.
Definition: qgsvertexid.h:31
int vertex
Vertex number.
Definition: qgsvertexid.h:95
int part
Part number.
Definition: qgsvertexid.h:89
int ring
Ring number.
Definition: qgsvertexid.h:92