QGIS API Documentation  3.6.0-Noosa (5873452)
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 
18 #include "qgsexception.h"
19 #include "qgsfeatureiterator.h"
20 #include "qgsgeometryvalidator.h"
21 #include "qgslayertreeview.h"
22 #include "qgslinestring.h"
23 #include "qgslogger.h"
24 #include "qgsmapcanvas.h"
25 #include "qgsmapcanvastracer.h"
26 #include "qgsmapmouseevent.h"
27 #include "qgspolygon.h"
28 #include "qgsrubberband.h"
29 #include "qgssnapindicator.h"
30 #include "qgsvectorlayer.h"
31 #include "qgsvertexmarker.h"
32 #include "qgssettings.h"
33 #include "qgsapplication.h"
34 
35 #include <QAction>
36 #include <QCursor>
37 #include <QPixmap>
38 #include <QStatusBar>
39 
40 
42  : QgsMapToolAdvancedDigitizing( canvas, cadDockWidget )
43  , mCaptureMode( mode )
44  , mCaptureModeFromLayer( mode == CaptureNone )
45 {
46  mSnapIndicator.reset( new QgsSnapIndicator( canvas ) );
47 
48  setCursor( QgsApplication::getThemeCursor( QgsApplication::Cursor::CapturePoint ) );
49 
50  connect( canvas, &QgsMapCanvas::currentLayerChanged,
51  this, &QgsMapToolCapture::currentLayerChanged );
52 
53  currentLayerChanged( canvas->currentLayer() );
54 }
55 
57 {
58  stopCapturing();
59 
60  if ( mValidator )
61  {
62  mValidator->deleteLater();
63  mValidator = nullptr;
64  }
65 }
66 
68 {
69  if ( mTempRubberBand )
70  mTempRubberBand->show();
71 
73 }
74 
76 {
77  if ( mTempRubberBand )
78  mTempRubberBand->hide();
79 
80  mSnapIndicator->setMatch( QgsPointLocator::Match() );
81 
83 }
84 
85 void QgsMapToolCapture::currentLayerChanged( QgsMapLayer *layer )
86 {
87  if ( !mCaptureModeFromLayer )
88  return;
89 
90  mCaptureMode = CaptureNone;
91 
92  QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( layer );
93  if ( !vlayer )
94  {
95  return;
96  }
97 
98  switch ( vlayer->geometryType() )
99  {
101  mCaptureMode = CapturePoint;
102  break;
104  mCaptureMode = CaptureLine;
105  break;
107  mCaptureMode = CapturePolygon;
108  break;
109  default:
110  mCaptureMode = CaptureNone;
111  break;
112  }
113 }
114 
115 
116 bool QgsMapToolCapture::tracingEnabled()
117 {
119  return tracer && ( !tracer->actionEnableTracing() || tracer->actionEnableTracing()->isChecked() )
120  && ( !tracer->actionEnableSnapping() || tracer->actionEnableSnapping()->isChecked() );
121 }
122 
123 
124 QgsPointXY QgsMapToolCapture::tracingStartPoint()
125 {
126  try
127  {
128  QgsMapLayer *layer = mCanvas->currentLayer();
129  if ( !layer )
130  return QgsPointXY();
131 
132  // if we have starting point from previous trace, then preferably use that one
133  // (useful when tracing with offset)
134  if ( mTracingStartPoint != QgsPointXY() )
135  return mTracingStartPoint;
136 
137  QgsPoint v = mCaptureCurve.endPoint();
138  return toMapCoordinates( layer, QgsPointXY( v.x(), v.y() ) );
139  }
140  catch ( QgsCsException & )
141  {
142  QgsDebugMsg( QStringLiteral( "transformation to layer coordinate failed" ) );
143  return QgsPointXY();
144  }
145 }
146 
147 
148 bool QgsMapToolCapture::tracingMouseMove( QgsMapMouseEvent *e )
149 {
150  if ( !e->isSnapped() )
151  return false;
152 
153  QgsPointXY pt0 = tracingStartPoint();
154  if ( pt0 == QgsPointXY() )
155  return false;
156 
158  if ( !tracer )
159  return false; // this should not happen!
160 
161  mTempRubberBand->reset( mCaptureMode == CapturePolygon ? QgsWkbTypes::PolygonGeometry : QgsWkbTypes::LineGeometry );
162 
164  QVector<QgsPointXY> points = tracer->findShortestPath( pt0, e->mapPoint(), &err );
165  if ( points.isEmpty() )
166  {
167  tracer->reportError( err, false );
168  return false;
169  }
170 
171  if ( mCaptureMode == CapturePolygon )
172  mTempRubberBand->addPoint( *mRubberBand->getPoint( 0, 0 ), false );
173 
174  // if there is offset, we need to fix the rubber bands to make sure they are aligned correctly.
175  // There are two cases we need to sort out:
176  // 1. the last point of mRubberBand may need to be moved off the traced curve to respect the offset
177  // 2. extra first point of mTempRubberBand may be needed if there is gap between where mRubberBand ends and trace starts
178  if ( mRubberBand->numberOfVertices() != 0 )
179  {
180  QgsPointXY lastPoint = *mRubberBand->getPoint( 0, mRubberBand->numberOfVertices() - 1 );
181  if ( lastPoint == pt0 && points[0] != lastPoint )
182  {
183  // if rubber band had just one point, for some strange reason it contains the point twice
184  // we only want to move the last point if there are multiple points already
185  if ( mRubberBand->numberOfVertices() > 2 || ( mRubberBand->numberOfVertices() == 2 && *mRubberBand->getPoint( 0, 0 ) != *mRubberBand->getPoint( 0, 1 ) ) )
186  mRubberBand->movePoint( points[0] );
187  }
188  else
189  {
190  mTempRubberBand->addPoint( lastPoint, false );
191  }
192  }
193 
194  // update rubberband
195  for ( int i = 0; i < points.count(); ++i )
196  mTempRubberBand->addPoint( points.at( i ), i == points.count() - 1 );
197 
198  tracer->reportError( QgsTracer::ErrNone, false ); // clear messagebar if there was any error
199  return true;
200 }
201 
202 
203 bool QgsMapToolCapture::tracingAddVertex( const QgsPointXY &point )
204 {
206  if ( !tracer )
207  return false; // this should not happen!
208 
209  if ( mCaptureCurve.numPoints() == 0 )
210  {
211  if ( !tracer->init() )
212  {
214  return false;
215  }
216 
217  // only accept first point if it is snapped to the graph (to vertex or edge)
218  bool res = tracer->isPointSnapped( point );
219  if ( res )
220  {
221  QgsPoint layerPoint;
222  nextPoint( QgsPoint( point ), layerPoint ); // assuming the transform went fine earlier
223 
224  mRubberBand->addPoint( point );
225  mCaptureCurve.addVertex( layerPoint );
226  mSnappingMatches.append( QgsPointLocator::Match() );
227  }
228  return res;
229  }
230 
231  QgsPointXY pt0 = tracingStartPoint();
232  if ( pt0 == QgsPointXY() )
233  return false;
234 
236  QVector<QgsPointXY> points = tracer->findShortestPath( pt0, point, &err );
237  if ( points.isEmpty() )
238  return false; // ignore the vertex - can't find path to the end point!
239 
240  if ( !mCaptureCurve.isEmpty() )
241  {
242  QgsPoint lp; // in layer coords
243  if ( nextPoint( QgsPoint( pt0 ), lp ) != 0 )
244  return false;
245  QgsPoint last;
247  mCaptureCurve.pointAt( mCaptureCurve.numPoints() - 1, last, type );
248  if ( last == lp )
249  {
250  // remove the last point in the curve if it is the same as our first point
251  if ( mCaptureCurve.numPoints() != 2 )
252  mCaptureCurve.deleteVertex( QgsVertexId( 0, 0, mCaptureCurve.numPoints() - 1 ) );
253  else
254  {
255  // there is a strange behavior in deleteVertex() that with just two points
256  // the whole curve is cleared - so we need to do this little dance to work it around
257  QgsPoint first = mCaptureCurve.startPoint();
258  mCaptureCurve.clear();
259  mCaptureCurve.addVertex( first );
260  }
261  // for unknown reasons, rubber band has 2 points even if only one point has been added - handle that case
262  if ( mRubberBand->numberOfVertices() == 2 && *mRubberBand->getPoint( 0, 0 ) == *mRubberBand->getPoint( 0, 1 ) )
263  mRubberBand->removeLastPoint();
264  mRubberBand->removeLastPoint();
265  mSnappingMatches.removeLast();
266  }
267  }
268 
269  // transform points
270  QgsPointSequence layerPoints;
271  QgsPoint lp; // in layer coords
272  for ( int i = 0; i < points.count(); ++i )
273  {
274  if ( nextPoint( QgsPoint( points[i] ), lp ) != 0 )
275  return false;
276  layerPoints << lp;
277  }
278 
279  for ( int i = 0; i < points.count(); ++i )
280  {
281  if ( i == 0 && !mCaptureCurve.isEmpty() && mCaptureCurve.endPoint() == layerPoints[0] )
282  continue; // avoid duplicate of the first vertex
283  if ( i > 0 && points[i] == points[i - 1] )
284  continue; // avoid duplicate vertices if there are any
285  mRubberBand->addPoint( points[i], i == points.count() - 1 );
286  mCaptureCurve.addVertex( layerPoints[i] );
287  mSnappingMatches.append( QgsPointLocator::Match() );
288  }
289 
290  tracer->reportError( QgsTracer::ErrNone, true ); // clear messagebar if there was any error
291  return true;
292 }
293 
294 
296 {
298  QgsPointXY point = e->mapPoint();
299 
300  mSnapIndicator->setMatch( e->mapPointMatch() );
301 
302  if ( !mTempRubberBand && mCaptureCurve.numPoints() > 0 )
303  {
304  mTempRubberBand = createRubberBand( mCaptureMode == CapturePolygon ? QgsWkbTypes::PolygonGeometry : QgsWkbTypes::LineGeometry, true );
305  QgsPoint pt = mCaptureCurve.endPoint();
306  mTempRubberBand->addPoint( QgsPointXY( pt.x(), pt.y() ) );
307  mTempRubberBand->addPoint( point );
308  }
309 
310 
311  if ( mCaptureMode != CapturePoint && mTempRubberBand && mCapturing )
312  {
313  bool hasTrace = false;
314  if ( tracingEnabled() && mCaptureCurve.numPoints() != 0 )
315  {
316  hasTrace = tracingMouseMove( e );
317  }
318 
319  if ( !hasTrace )
320  {
321  if ( mCaptureCurve.numPoints() > 0 )
322  {
323  // fix temporary rubber band after tracing which may have added multiple points
324  mTempRubberBand->reset( mCaptureMode == CapturePolygon ? QgsWkbTypes::PolygonGeometry : QgsWkbTypes::LineGeometry );
325  if ( mCaptureMode == CapturePolygon )
326  mTempRubberBand->addPoint( *mRubberBand->getPoint( 0, 0 ), false );
327  QgsPoint pt = mCaptureCurve.endPoint();
328  QgsPointXY mapPt = toMapCoordinates( qobject_cast<QgsVectorLayer *>( mCanvas->currentLayer() ), QgsPointXY( pt.x(), pt.y() ) );
329  mTempRubberBand->addPoint( mapPt );
330  mTempRubberBand->addPoint( point );
331 
332  // fix existing rubber band after tracing - the last point may have been moved if using offset
333  if ( mRubberBand->numberOfVertices() )
334  mRubberBand->movePoint( mapPt );
335  }
336  else
337  mTempRubberBand->movePoint( point );
338  }
339  }
340 } // mouseMoveEvent
341 
342 
344 {
345  QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( mCanvas->currentLayer() );
346  if ( !vlayer )
347  {
348  QgsDebugMsg( QStringLiteral( "no vector layer" ) );
349  return 1;
350  }
351  try
352  {
353  QgsPointXY mapP( mapPoint.x(), mapPoint.y() ); //#spellok
354  layerPoint = QgsPoint( toLayerCoordinates( vlayer, mapP ) ); //transform snapped point back to layer crs //#spellok
355  if ( QgsWkbTypes::hasZ( vlayer->wkbType() ) )
356  layerPoint.addZValue( defaultZValue() );
357  if ( QgsWkbTypes::hasM( vlayer->wkbType() ) )
358  layerPoint.addMValue( 0.0 );
359  }
360  catch ( QgsCsException &cse )
361  {
362  Q_UNUSED( cse );
363  QgsDebugMsg( QStringLiteral( "transformation to layer coordinate failed" ) );
364  return 2;
365  }
366 
367  return 0;
368 }
369 
371 {
372  mapPoint = QgsPoint( toMapCoordinates( p ) );
373  return nextPoint( mapPoint, layerPoint );
374 }
375 
377 {
378  QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( mCanvas->currentLayer() );
379  QgsVectorLayer *sourceLayer = match.layer();
380  if ( match.isValid() && match.hasVertex() && sourceLayer &&
381  ( sourceLayer->crs() == vlayer->crs() ) )
382  {
383  QgsFeature f;
384  QgsFeatureRequest request;
385  request.setFilterFid( match.featureId() );
386  bool fetched = match.layer()->getFeatures( request ).nextFeature( f );
387  if ( fetched )
388  {
389  QgsVertexId vId;
390  if ( !f.geometry().vertexIdFromVertexNr( match.vertexIndex(), vId ) )
391  return 2;
392 
393  layerPoint = f.geometry().constGet()->vertexAt( vId );
394 
395  // ZM support depends on the target layer
396  if ( !QgsWkbTypes::hasZ( vlayer->wkbType() ) )
397  {
398  layerPoint.dropZValue();
399  }
400 
401  if ( !QgsWkbTypes::hasM( vlayer->wkbType() ) )
402  {
403  layerPoint.dropMValue();
404  }
405 
406  return 0;
407  }
408  else
409  {
410  return 2;
411  }
412  }
413  else
414  {
415  return 1;
416  }
417 }
418 
420 {
421  return addVertex( point, QgsPointLocator::Match() );
422 }
423 
425 {
426  if ( mode() == CaptureNone )
427  {
428  QgsDebugMsg( QStringLiteral( "invalid capture mode" ) );
429  return 2;
430  }
431 
432  int res;
433  QgsPoint layerPoint;
434  res = fetchLayerPoint( match, layerPoint );
435  if ( res != 0 )
436  {
437  res = nextPoint( QgsPoint( point ), layerPoint );
438  if ( res != 0 )
439  {
440  return res;
441  }
442  }
443 
444  if ( !mRubberBand )
445  {
447  }
448 
449  if ( !mTempRubberBand )
450  {
451  mTempRubberBand = createRubberBand( mCaptureMode == CapturePolygon ? QgsWkbTypes::PolygonGeometry : QgsWkbTypes::LineGeometry, true );
452  }
453  else
454  {
455  mTempRubberBand->reset( mCaptureMode == CapturePolygon ? QgsWkbTypes::PolygonGeometry : QgsWkbTypes::LineGeometry );
456  }
457 
458  bool traceCreated = false;
459  if ( tracingEnabled() )
460  {
461  traceCreated = tracingAddVertex( point );
462  }
463 
464  // keep new tracing start point if we created a trace. This is useful when tracing with
465  // offset so that the user stays "snapped"
466  mTracingStartPoint = traceCreated ? point : QgsPointXY();
467 
468  if ( !traceCreated )
469  {
470  // ordinary digitizing
471  mRubberBand->addPoint( point );
472  mCaptureCurve.addVertex( layerPoint );
473  mSnappingMatches.append( match );
474  }
475 
476  if ( mCaptureMode == CaptureLine )
477  {
478  mTempRubberBand->addPoint( point );
479  }
480  else if ( mCaptureMode == CapturePolygon )
481  {
482  const QgsPointXY *firstPoint = mRubberBand->getPoint( 0, 0 );
483  mTempRubberBand->addPoint( *firstPoint );
484  mTempRubberBand->movePoint( point );
485  mTempRubberBand->addPoint( point );
486  }
487 
488  validateGeometry();
489 
490  return 0;
491 }
492 
494 {
495  if ( !c )
496  {
497  return 1;
498  }
499 
500  if ( !mRubberBand )
501  {
503  }
504 
505  QgsLineString *lineString = c->curveToLine();
506  QgsPointSequence linePoints;
507  lineString->points( linePoints );
508  delete lineString;
509  QgsPointSequence::const_iterator ptIt = linePoints.constBegin();
510  for ( ; ptIt != linePoints.constEnd(); ++ptIt )
511  {
512  mRubberBand->addPoint( QgsPointXY( ptIt->x(), ptIt->y() ) );
513  }
514 
515  if ( !mTempRubberBand )
516  {
517  mTempRubberBand = createRubberBand( mCaptureMode == CapturePolygon ? QgsWkbTypes::PolygonGeometry : QgsWkbTypes::LineGeometry, true );
518  }
519  else
520  {
521  mTempRubberBand->reset();
522  }
523  QgsPoint endPt = c->endPoint();
524  mTempRubberBand->addPoint( QgsPointXY( endPt.x(), endPt.y() ) ); //add last point of c
525 
526  //transform back to layer CRS in case map CRS and layer CRS are different
527  QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( mCanvas->currentLayer() );
529  if ( ct.isValid() )
530  {
532  }
533  mCaptureCurve.addCurve( c );
534  for ( int i = 0; i < c->length(); ++i )
535  mSnappingMatches.append( QgsPointLocator::Match() );
536 
537  return 0;
538 }
539 
541 {
542  mCaptureCurve.clear();
543 }
544 
545 QList<QgsPointLocator::Match> QgsMapToolCapture::snappingMatches() const
546 {
547  return mSnappingMatches;
548 }
549 
550 
552 {
553  mTracingStartPoint = QgsPointXY();
554 
555  if ( mRubberBand )
556  {
557  int rubberBandSize = mRubberBand->numberOfVertices();
558  int tempRubberBandSize = mTempRubberBand->numberOfVertices();
559  int captureListSize = size();
560 
561  if ( rubberBandSize < 1 || captureListSize < 1 )
562  {
563  return;
564  }
565 
566  mRubberBand->removePoint( -1 );
567 
568  if ( rubberBandSize > 1 )
569  {
570  if ( tempRubberBandSize > 1 )
571  {
572  const QgsPointXY *point = mRubberBand->getPoint( 0, rubberBandSize - 2 );
573  mTempRubberBand->movePoint( tempRubberBandSize - 2, *point );
574  }
575  }
576  else
577  {
578  mTempRubberBand->reset( mCaptureMode == CapturePolygon ? QgsWkbTypes::PolygonGeometry : QgsWkbTypes::LineGeometry );
579  }
580 
581  QgsVertexId vertexToRemove;
582  vertexToRemove.part = 0;
583  vertexToRemove.ring = 0;
584  vertexToRemove.vertex = size() - 1;
585  mCaptureCurve.deleteVertex( vertexToRemove );
586  mSnappingMatches.removeAt( vertexToRemove.vertex );
587 
588  validateGeometry();
589  }
590 }
591 
593 {
594  if ( e->key() == Qt::Key_Backspace || e->key() == Qt::Key_Delete )
595  {
596  undo();
597 
598  // Override default shortcut management in MapCanvas
599  e->ignore();
600  }
601  else if ( e->key() == Qt::Key_Escape )
602  {
603  stopCapturing();
604 
605  // Override default shortcut management in MapCanvas
606  e->ignore();
607  }
608 }
609 
611 {
612  mCapturing = true;
613 }
614 
616 {
617  return mCapturing;
618 }
619 
621 {
622  if ( mRubberBand )
623  {
624  delete mRubberBand;
625  mRubberBand = nullptr;
626  }
627 
628  if ( mTempRubberBand )
629  {
630  delete mTempRubberBand;
631  mTempRubberBand = nullptr;
632  }
633 
634  while ( !mGeomErrorMarkers.isEmpty() )
635  {
636  delete mGeomErrorMarkers.takeFirst();
637  }
638 
639  mGeomErrors.clear();
640 
641  mTracingStartPoint = QgsPointXY();
642 
643  mCapturing = false;
644  mCaptureCurve.clear();
645  mSnappingMatches.clear();
646  if ( currentVectorLayer() )
648 }
649 
651 {
652  if ( mTempRubberBand )
653  {
654  delete mTempRubberBand;
655  mTempRubberBand = nullptr;
656  }
657 }
658 
660 {
661  stopCapturing();
662  clearCurve();
663 }
664 
666 {
667  mCaptureCurve.close();
668 }
669 
670 void QgsMapToolCapture::validateGeometry()
671 {
672  QgsSettings settings;
673  if ( settings.value( QStringLiteral( "qgis/digitizing/validate_geometries" ), 1 ).toInt() == 0 )
674  return;
675 
676  if ( mValidator )
677  {
678  mValidator->deleteLater();
679  mValidator = nullptr;
680  }
681 
682  mGeomErrors.clear();
683  while ( !mGeomErrorMarkers.isEmpty() )
684  {
685  delete mGeomErrorMarkers.takeFirst();
686  }
687 
688  QgsGeometry geom;
689 
690  switch ( mCaptureMode )
691  {
692  case CaptureNone:
693  case CapturePoint:
694  return;
695  case CaptureLine:
696  if ( size() < 2 )
697  return;
698  geom = QgsGeometry( mCaptureCurve.curveToLine() );
699  break;
700  case CapturePolygon:
701  if ( size() < 3 )
702  return;
703  QgsLineString *exteriorRing = mCaptureCurve.curveToLine();
704  exteriorRing->close();
705  QgsPolygon *polygon = new QgsPolygon();
706  polygon->setExteriorRing( exteriorRing );
707  geom = QgsGeometry( polygon );
708  break;
709  }
710 
711  if ( geom.isNull() )
712  return;
713 
715  if ( settings.value( QStringLiteral( "qgis/digitizing/validate_geometries" ), 1 ).toInt() == 2 )
717  mValidator = new QgsGeometryValidator( geom, nullptr, method );
718  connect( mValidator, &QgsGeometryValidator::errorFound, this, &QgsMapToolCapture::addError );
719  mValidator->start();
720  QgsDebugMsgLevel( QStringLiteral( "Validation started" ), 4 );
721 }
722 
723 void QgsMapToolCapture::addError( const QgsGeometry::Error &e )
724 {
725  mGeomErrors << e;
726  QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( mCanvas->currentLayer() );
727  if ( !vlayer )
728  return;
729 
730  if ( e.hasWhere() )
731  {
733  vm->setCenter( mCanvas->mapSettings().layerToMapCoordinates( vlayer, e.where() ) );
735  vm->setPenWidth( 2 );
736  vm->setToolTip( e.what() );
737  vm->setColor( Qt::green );
738  vm->setZValue( vm->zValue() + 1 );
739  mGeomErrorMarkers << vm;
740  }
741 }
742 
744 {
745  return mCaptureCurve.numPoints();
746 }
747 
748 QVector<QgsPointXY> QgsMapToolCapture::points() const
749 {
750  QgsPointSequence pts;
751  QVector<QgsPointXY> points;
752  mCaptureCurve.points( pts );
753  QgsGeometry::convertPointList( pts, points );
754  return points;
755 }
756 
757 void QgsMapToolCapture::setPoints( const QVector<QgsPointXY> &pointList )
758 {
759  QgsLineString *line = new QgsLineString( pointList );
760  mCaptureCurve.clear();
761  mCaptureCurve.addCurve( line );
762  mSnappingMatches.clear();
763  for ( int i = 0; i < line->length(); ++i )
764  mSnappingMatches.append( QgsPointLocator::Match() );
765 }
766 
768 {
769  QgsPoint newPoint( QgsWkbTypes::Point, point.x(), point.y() );
770 
771  // get current layer
772  QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( mCanvas->currentLayer() );
773  if ( !vlayer )
774  {
775  return newPoint;
776  }
777 
778  // convert to the corresponding type for a full ZM support
779  const QgsWkbTypes::Type type = vlayer->wkbType();
780  if ( QgsWkbTypes::hasZ( type ) && !QgsWkbTypes::hasM( type ) )
781  {
782  newPoint.convertTo( QgsWkbTypes::PointZ );
783  }
784  else if ( !QgsWkbTypes::hasZ( type ) && QgsWkbTypes::hasM( type ) )
785  {
786  newPoint.convertTo( QgsWkbTypes::PointM );
787  }
788  else if ( QgsWkbTypes::hasZ( type ) && QgsWkbTypes::hasM( type ) )
789  {
790  newPoint.convertTo( QgsWkbTypes::PointZM );
791  }
792 
793  // set z value if necessary
794  if ( QgsWkbTypes::hasZ( newPoint.wkbType() ) )
795  {
796  newPoint.setZ( defaultZValue() );
797  }
798 
799  return newPoint;
800 }
801 
803 {
804  QgsPoint newPoint = mapPoint( e.mapPoint() );
805 
806  // set z value from snapped point if necessary
807  if ( QgsWkbTypes::hasZ( newPoint.wkbType() ) )
808  {
809  // if snapped, z dimension is taken from the corresponding snapped
810  // point.
811  if ( e.isSnapped() )
812  {
813  const QgsPointLocator::Match match = e.mapPointMatch();
814  const QgsWkbTypes::Type snappedType = match.layer()->wkbType();
815 
816  if ( QgsWkbTypes::hasZ( snappedType ) )
817  {
818  const QgsFeature ft = match.layer()->getFeature( match.featureId() );
819  newPoint.setZ( ft.geometry().vertexAt( match.vertexIndex() ).z() );
820  }
821  }
822  }
823 
824  return newPoint;
825 }
QgsPoint startPoint() const override
Returns the starting point of the curve.
Base class for all map layer types.
Definition: qgsmaplayer.h:64
double y
Definition: qgspoint.h:42
int numberOfVertices() const
Returns count of vertices in all lists of mPoint.
void points(QgsPointSequence &pt) const override
Returns a list of points within the curve.
virtual void transform(const QgsCoordinateTransform &ct, QgsCoordinateTransform::TransformDirection d=QgsCoordinateTransform::ForwardTransform, bool transformZ=false) SIP_THROW(QgsCsException)=0
Transforms the geometry using a coordinate transform.
CaptureMode
Different capture modes.
int size()
Number of points digitized.
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...
QgsVectorLayer * layer() const
The vector layer where the snap occurred.
This class is a composition of two QSettings instances:
Definition: qgssettings.h:58
void setZ(double z)
Sets the point&#39;s z-coordinate.
Definition: qgspoint.h:237
Use GEOS validation methods.
Definition: qgsgeometry.h:1857
QgsWkbTypes::Type wkbType() const FINAL
Returns the WKBType or WKBUnknown in case of error.
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
double y
Definition: qgspointxy.h:48
QAction * actionEnableTracing() const
Access to action that user may use to toggle tracing on/off. May be null if no action was associated...
A class to represent a 2D point.
Definition: qgspointxy.h:43
QgsFeature getFeature(QgsFeatureId fid) const
Query the layer for the feature with the given id.
void setPenWidth(int width)
A QgsMapMouseEvent is the result of a user interaction with the mouse on a QgsMapCanvas.
QgsWkbTypes::GeometryType geometryType() const
Returns point, line or polygon.
bool deleteVertex(QgsVertexId position) override
Deletes a vertex within the geometry.
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:106
QgsPointXY toMapCoordinates(QPoint point)
transformation from screen coordinates to map coordinates
Definition: qgsmaptool.cpp:41
void activate() override
Registers this maptool with the cad dock widget.
bool isSnapped() const
Returns true if there is a snapped point cached.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:55
The QgsMapToolAdvancedDigitizing class is a QgsMapTool which gives event directly in map coordinates ...
void clear() override
Clears the geometry, ie reset it to a null geometry.
static bool hasZ(Type type)
Tests whether a WKB type contains the z-dimension.
Definition: qgswkbtypes.h:770
const QgsPointXY * getPoint(int i, int j=0) const
Returns a vertex.
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:73
void addCurve(QgsCurve *c)
Adds a curve to the geometry (takes ownership)
Do not capture / determine mode from layer geometry type.
bool pointAt(int node, QgsPoint &point, QgsVertexId::VertexType &type) const override
Returns the point and vertex id of a point within the curve.
bool dropZValue() override
Drops any z-dimensions which exist in the geometry.
Definition: qgspoint.cpp:510
Extension of QgsTracer that provides extra functionality:
QgsCoordinateTransform layerTransform(const QgsMapLayer *layer) const
Returns the coordinate transform from layer&#39;s CRS to destination CRS.
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
QgsMapCanvas * mCanvas
pointer to map canvas
Definition: qgsmaptool.h:241
virtual QgsPoint endPoint() const =0
Returns the end point of the curve.
QgsFeatureRequest & setFilterFid(QgsFeatureId fid)
Sets feature ID that should be fetched.
CaptureMode mode() const
The capture mode.
virtual double length() const
Returns the length of the geometry.
QAction * actionEnableSnapping() const
Access to action that user may use to toggle snapping on/off.
void setPoints(const QVector< QgsPointXY > &pointList)
Set the points on which to work.
Type
The WKB type describes the number of dimensions a geometry has.
Definition: qgswkbtypes.h:68
bool dropMValue() override
Drops any measure values which exist in the geometry.
Definition: qgspoint.cpp:521
void triggerRepaint(bool deferredUpdate=false)
Will advise the map canvas (and any other interested party) that this layer requires to be repainted...
static QgsMapCanvasTracer * tracerForCanvas(QgsMapCanvas *canvas)
Retrieve instance of this class associated with given canvas (if any).
Utility class for identifying a unique vertex within a geometry.
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
Max feature count threshold was reached while reading features.
Definition: qgstracer.h:135
int addCurve(QgsCurve *c)
Adds a whole curve (e.g. circularstring) to the captured geometry. Curve must be in map CRS...
void removePoint(int index=0, bool doUpdate=true, int geometryIndex=0)
Removes a vertex from the rubberband and (optionally) updates canvas.
void setCenter(const QgsPointXY &point)
void addPoint(const QgsPointXY &p, bool doUpdate=true, int geometryIndex=0)
Adds a vertex to the rubberband and update canvas.
bool isCapturing() const
Are we currently capturing?
void activate() override
Registers this maptool with the cad dock widget.
Use internal QgsGeometryValidator method.
Definition: qgsgeometry.h:1856
void movePoint(const QgsPointXY &p, int geometryIndex=0)
Moves the rubber band point specified by index.
PathError
Possible errors that may happen when calling findShortestPath()
Definition: qgstracer.h:132
This class wraps a request for features to a vector layer (or directly its vector data provider)...
void close()
Closes the line string by appending the first point to the end of the line, if it is not already clos...
A class for marking vertices of features using e.g.
Abstract base class for curved geometry type.
Definition: qgscurve.h:35
double defaultZValue() const
Returns default Z value Use for set Z coordinate to new vertex for 2.5d geometries.
~QgsMapToolCapture() override
QgsWkbTypes::Type wkbType() const
Returns the WKB type of the geometry.
QList< QgsPointLocator::Match > snappingMatches() const
Returns a list of matches for each point on the captureCurve.
Point geometry type, with support for z-dimension and m-values.
Definition: qgspoint.h:37
void undo()
Removes the last vertex from mRubberBand and mCaptureList.
void currentLayerChanged(QgsMapLayer *layer)
Emitted when the current layer is changed.
double x
Definition: qgspointxy.h:47
const QgsAbstractGeometry * constGet() const
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
QgsMapLayer * currentLayer()
returns current layer (set by legend widget)
bool isEmpty() const override
Returns true if the geometry is empty.
QVector< QgsPoint > QgsPointSequence
QgsPoint mapPoint(const QgsMapMouseEvent &e) const
Creates a QgsPoint with ZM support if necessary (according to the WkbType of the current layer)...
const QgsMapSettings & mapSettings() const
Gets access to properties used for map rendering.
void reportError(PathError err, bool addingVertex)
Report a path finding error to the user.
static void convertPointList(const QVector< QgsPointXY > &input, QgsPointSequence &output)
Upgrades a point list from QgsPointXY to QgsPoint.
QgsPointLocator::Match mapPointMatch() const
Returns the matching data from the most recently snapped point.
QgsVectorLayer * currentVectorLayer()
Returns the current vector layer of the map canvas or 0.
void closePolygon()
Close an open polygon.
void deleteTempRubberBand()
Clean a temporary rubberband.
QgsPoint vertexAt(int atVertex) const
Returns coordinates of a vertex.
QgsPointXY toLayerCoordinates(const QgsMapLayer *layer, QPoint point)
transformation from screen coordinates to layer&#39;s coordinates
Definition: qgsmaptool.cpp:53
void deactivate() override
Unregisters this maptool from the cad dock widget.
void setExteriorRing(QgsCurve *ring) override
Sets the exterior ring of the polygon.
Definition: qgspolygon.cpp:179
void startCapturing()
Start capturing.
void keyPressEvent(QKeyEvent *e) override
Intercept key events like Esc or Del to delete the last point.
Transform from destination to source CRS.
QgsPointXY mapPoint() const
mapPoint returns the point in coordinates
int vertexIndex() const
for vertex / edge match (first vertex of the edge)
void addVertex(const QgsPoint &pt)
Adds a vertex to the end of the geometry.
QVector< QgsPointXY > points() const
List of digitized points.
QgsRubberBand * createRubberBand(QgsWkbTypes::GeometryType geometryType=QgsWkbTypes::LineGeometry, bool alternativeBand=false)
Creates a rubber band with the color/line width from the QGIS settings.
QgsPointXY layerToMapCoordinates(const QgsMapLayer *layer, QgsPointXY point) const
transform point coordinates from layer&#39;s CRS to output CRS
Line string geometry type, with support for z-dimension and m-values.
Definition: qgslinestring.h:43
ValidationMethod
Available methods for validating geometries.
Definition: qgsgeometry.h:1854
virtual QgsLineString * curveToLine(double tolerance=M_PI_2/90, SegmentationToleranceType toleranceType=MaximumAngle) const =0
Returns a new line string geometry corresponding to a segmentized approximation of the curve...
void points(QgsPointSequence &pts) const override
Returns a list of points within the curve.
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:727
Class that shows snapping marker on map canvas for the current snapping match.
Class for doing transforms between two map coordinate systems.
void clean() override
convenient method to clean members
void reset(QgsWkbTypes::GeometryType geometryType=QgsWkbTypes::LineGeometry)
Clears all the geometries in this rubberband.
No error.
Definition: qgstracer.h:134
int nextPoint(const QgsPoint &mapPoint, QgsPoint &layerPoint)
Converts a map point to layer coordinates.
virtual void cadCanvasMoveEvent(QgsMapMouseEvent *e)
Override this method when subclassing this class.
bool init()
Build the internal data structures.
Definition: qgstracer.cpp:666
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const FINAL
Query the layer for features specified in request.
virtual void setCursor(const QCursor &cursor)
Sets a user defined cursor.
Definition: qgsmaptool.cpp:148
static bool hasM(Type type)
Tests whether a WKB type contains m values.
Definition: qgswkbtypes.h:820
static QCursor getThemeCursor(Cursor cursor)
Helper to get a theme cursor.
QgsGeometry geometry
Definition: qgsfeature.h:67
void stopCapturing()
Stop capturing.
Custom exception class for Coordinate Reference System related exceptions.
Definition: qgsexception.h:65
void close()
Appends first point if not already closed.
double length() const override
Returns the length of the geometry.
QgsFeatureId featureId() const
The id of the feature to which the snapped geometry belongs.
bool nextFeature(QgsFeature &f)
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:794
bool vertexIdFromVertexNr(int number, QgsVertexId &id) const
Calculates the vertex ID from a vertex number.
void cadCanvasMoveEvent(QgsMapMouseEvent *e) override
Override this method when subclassing this class.
Polygon geometry type.
Definition: qgspolygon.h:31
virtual QgsPoint vertexAt(QgsVertexId id) const =0
Returns the point corresponding to a specified vertex id.
The QgsAdvancedDigitizingDockWidget class is a dockable widget used to handle the CAD tools on top of...
void setColor(const QColor &color)
Sets the stroke color for the marker.
Represents a vector layer which manages a vector based data sets.
void removeLastPoint(int geometryIndex=0, bool doUpdate=true)
Removes the last point.
int numPoints() const override
Returns the number of points in the curve.
void setIconType(int iconType)
void errorFound(const QgsGeometry::Error &error)
Sent when an error has been found during the validation process.
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...
void clearCurve()
Clear capture curve.
QgsCoordinateReferenceSystem crs
Definition: qgsmaplayer.h:71
QgsPoint endPoint() const override
Returns the end point of the curve.
int addVertex(const QgsPointXY &point)
Adds a point to the rubber band (in map coordinates) and to the capture list (in layer coordinates) ...
QgsMapToolCapture(QgsMapCanvas *canvas, QgsAdvancedDigitizingDockWidget *cadDockWidget, CaptureMode mode)
constructor
double x
Definition: qgspoint.h:41
void deactivate() override
Unregisters this maptool from the cad dock widget.