QGIS API Documentation 3.99.0-Master (8e76e220402)
Loading...
Searching...
No Matches
qgsmaptooladvanceddigitizing.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsmaptooladvanceddigitizing.cpp - map tool with event in map coordinates
3 ----------------------
4 begin : October 2014
5 copyright : (C) Denis Rouzaud
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
17
19#include "qgsgeometryoptions.h"
20#include "qgsmapcanvas.h"
21#include "qgsmapmouseevent.h"
22#include "qgsmeasureutils.h"
26#include "qgsstatusbar.h"
27#include "qgsunittypes.h"
28#include "qgsvectorlayer.h"
29
30#include <QString>
31
32#include "moc_qgsmaptooladvanceddigitizing.cpp"
33
34using namespace Qt::StringLiterals;
35
43
45
47{
48 if ( isAdvancedDigitizingAllowed() && mCadDockWidget->cadEnabled() )
49 {
50 mCadDockWidget->applyConstraints( e ); // updates event's map point
51 mCadDockWidget->processCanvasPressEvent( e );
52 if ( !e->isAccepted() )
53 {
54 return; // The dock widget has taken the event
55 }
56 }
57 else if ( isAutoSnapEnabled() )
58 {
59 e->snapPoint();
60 }
61
63 if ( mSnapToLayerGridEnabled && layer )
64 {
65 e->snapToGrid( layer->geometryOptions()->geometryPrecision(), layer->crs() );
66 }
67
69}
70
72{
73 if ( isAdvancedDigitizingAllowed() && mCadDockWidget->cadEnabled() )
74 {
75 mCadDockWidget->processCanvasReleaseEvent( e );
76 if ( !e->isAccepted() )
77 {
78 return; // The dock widget has taken the event
79 }
80 }
81 else if ( isAutoSnapEnabled() )
82 {
83 e->snapPoint();
84 }
85
87 if ( mSnapToGridCanvasItem && mSnapToLayerGridEnabled && layer )
88 {
89 e->snapToGrid( layer->geometryOptions()->geometryPrecision(), layer->crs() );
90 }
91
93}
94
96{
97 if ( isAdvancedDigitizingAllowed() && mCadDockWidget->cadEnabled() )
98 {
99 mCadDockWidget->applyConstraints( e ); // updates event's map point
100 mCadDockWidget->processCanvasMoveEvent( e );
101 if ( !e->isAccepted() )
102 {
103 return; // The dock widget has taken the event
104 }
105 }
106 else if ( isAutoSnapEnabled() )
107 {
108 e->snapPoint();
109 }
110
112 if ( mSnapToGridCanvasItem && mSnapToLayerGridEnabled && layer )
113 {
114 e->snapToGrid( layer->geometryOptions()->geometryPrecision(), layer->crs() );
115 mSnapToGridCanvasItem->setPoint( e->mapPoint() );
116 }
117
118 if ( mSnapIndicator )
119 {
120 mSnapIndicator->setMatch( e->mapPointMatch() );
121 }
122
124}
125
127{
129 connect( mCadDockWidget, &QgsAdvancedDigitizingDockWidget::pointChangedV2, this, &QgsMapToolAdvancedDigitizing::cadPointChanged );
130 connect( this, &QgsMapToolAdvancedDigitizing::transientGeometryChanged, this, &QgsMapToolAdvancedDigitizing::onTransientGeometryChanged );
131 mCadDockWidget->enable();
132 mSnapToGridCanvasItem = new QgsSnapToGridCanvasItem( mCanvas );
134 if ( layer )
135 {
136 mSnapToGridCanvasItem->setCrs( currentVectorLayer()->crs() );
137 mSnapToGridCanvasItem->setPrecision( currentVectorLayer()->geometryOptions()->geometryPrecision() );
138 }
139 mSnapToGridCanvasItem->setEnabled( mSnapToLayerGridEnabled );
140}
141
143{
145 disconnect( mCadDockWidget, &QgsAdvancedDigitizingDockWidget::pointChangedV2, this, &QgsMapToolAdvancedDigitizing::cadPointChanged );
146 disconnect( this, &QgsMapToolAdvancedDigitizing::transientGeometryChanged, this, &QgsMapToolAdvancedDigitizing::onTransientGeometryChanged );
147 mCadDockWidget->disable();
148 delete mSnapToGridCanvasItem;
149 mSnapToGridCanvasItem = nullptr;
150
151 if ( mSnapIndicator )
152 mSnapIndicator->setMatch( QgsPointLocator::Match() );
153}
154
159
161{
162 return static_cast<bool>( mSnapIndicator.get() );
163}
164
165void QgsMapToolAdvancedDigitizing::calculateGeometryMeasures( const QgsReferencedGeometry &geometry, const QgsCoordinateReferenceSystem &destinationCrs, Qgis::CadMeasurementDisplayType areaType, Qgis::CadMeasurementDisplayType totalLengthType, QString &areaString, QString &totalLengthString )
166{
167 areaString = QString();
168 totalLengthString = QString();
169
170 // transform to map crs
171 QgsGeometry g = geometry;
172 const QgsCoordinateTransform ct( geometry.crs(), destinationCrs, QgsProject::instance()->transformContext() );
173 try
174 {
175 g.transform( ct );
176 }
177 catch ( QgsCsException &e )
178 {
179 QgsDebugError( u"Error transforming transient geometry: %1"_s.arg( e.what() ) );
180 return;
181 }
182
183 std::unique_ptr< QgsDistanceArea > distanceArea;
184 auto createDistanceArea = [destinationCrs, &distanceArea] {
185 // reuse existing if we've already created one
186 if ( distanceArea )
187 return;
188
189 distanceArea = std::make_unique< QgsDistanceArea >();
190 distanceArea->setSourceCrs( destinationCrs, QgsProject::instance()->transformContext() );
191 distanceArea->setEllipsoid( QgsProject::instance()->ellipsoid() );
192 };
193
195 {
196 switch ( areaType )
197 {
199 break;
200
202 {
204 break;
205 }
206
208 {
209 createDistanceArea();
210 const double area = distanceArea->measureArea( g );
211 areaString = QgsMeasureUtils::formatAreaForProject( QgsProject::instance(), area, distanceArea->areaUnits() );
212 break;
213 }
214 }
215 }
216
217 switch ( totalLengthType )
218 {
220 break;
221
223 {
224 totalLengthString = QgsMeasureUtils::formatDistanceForProject( QgsProject::instance(), g.length(), destinationCrs.mapUnits() );
225 break;
226 }
228 {
229 createDistanceArea();
230 const double length = g.type() == Qgis::GeometryType::Polygon ? distanceArea->measurePerimeter( g ) : distanceArea->measureLength( g );
231 totalLengthString = QgsMeasureUtils::formatDistanceForProject( QgsProject::instance(), length, distanceArea->lengthUnits() );
232 break;
233 }
234 }
235}
236
238{
239 if ( enabled && !mSnapIndicator )
240 {
241 mSnapIndicator = std::make_unique<QgsSnapIndicator>( mCanvas );
242 }
243 else if ( !enabled && mSnapIndicator )
244 {
245 mSnapIndicator.reset();
246 }
247}
248
249void QgsMapToolAdvancedDigitizing::cadPointChanged( const QgsPointXY &point )
250{
251 Q_UNUSED( point )
252 QMouseEvent *ev = new QMouseEvent( QEvent::MouseMove, mCanvas->mouseLastXY(), Qt::NoButton, Qt::NoButton, Qt::NoModifier );
253 qApp->postEvent( mCanvas->viewport(), ev ); // event queue will delete the event when processed
254}
255
256void QgsMapToolAdvancedDigitizing::onCurrentLayerChanged()
257{
258 if ( mSnapToGridCanvasItem )
259 {
260 QgsVectorLayer *layer = currentVectorLayer();
261 if ( layer && mSnapToLayerGridEnabled )
262 {
263 mSnapToGridCanvasItem->setPrecision( layer->geometryOptions()->geometryPrecision() );
264 mSnapToGridCanvasItem->setCrs( layer->crs() );
265 }
266 if ( !layer || !layer->isSpatial() )
267 {
268 mCadDockWidget->clear();
269 mCadDockWidget->disable();
270 mSnapToGridCanvasItem->setEnabled( false );
271 }
272 else
273 {
274 mCadDockWidget->enable();
275 mSnapToGridCanvasItem->setEnabled( mSnapToLayerGridEnabled );
276 }
277 }
278}
279
280void QgsMapToolAdvancedDigitizing::onTransientGeometryChanged( const QgsReferencedGeometry &geometry )
281{
282 if ( mCadDockWidget )
283 mCadDockWidget->updateTransientGeometryProperties( geometry );
284
285 QgsStatusBar *statusBar = mCanvas ? mCanvas->statusBar() : nullptr;
286 if ( !statusBar )
287 return;
288
291 if ( areaDisplayType == Qgis::CadMeasurementDisplayType::Hidden && totalLengthDisplayType == Qgis::CadMeasurementDisplayType::Hidden )
292 return;
293
294 if ( geometry.isEmpty() )
295 {
296 statusBar->clearMessage();
297 }
298 else
299 {
300 QString areaString;
301 QString totalLengthString;
302 QgsMapToolAdvancedDigitizing::calculateGeometryMeasures( geometry, mCanvas->mapSettings().destinationCrs(), areaDisplayType, totalLengthDisplayType, areaString, totalLengthString );
303
304 QStringList messageParts;
305 if ( !areaString.isEmpty() )
306 messageParts.append( tr( "Total area: %1" ).arg( areaString ) );
307 if ( !totalLengthString.isEmpty() )
308 {
309 if ( geometry.type() == Qgis::GeometryType::Polygon )
310 messageParts.append( tr( "Perimeter: %1" ).arg( totalLengthString ) );
311 else
312 messageParts.append( tr( "Total length: %1" ).arg( totalLengthString ) );
313 }
314
315 statusBar->showMessage( messageParts.join( ' ' ) );
316 }
317}
318
320{
321 return mSnapToLayerGridEnabled;
322}
323
325{
326 mSnapToLayerGridEnabled = snapToGridEnabled;
327
328 if ( mSnapToGridCanvasItem )
329 {
330 mSnapToGridCanvasItem->setEnabled( snapToGridEnabled );
331 }
332}
@ Polygon
Polygons.
Definition qgis.h:368
CadMeasurementDisplayType
Advanced digitizing measurement display types.
Definition qgis.h:4161
@ Hidden
Hide measurement.
Definition qgis.h:4162
@ Cartesian
Use Cartesian measurements.
Definition qgis.h:4163
@ Ellipsoidal
Use Ellipsoidal measurements.
Definition qgis.h:4164
A dockable widget used to handle the CAD tools on top of a selection of map tools.
void pointChangedV2(const QgsPoint &point)
Sometimes a constraint may change the current point out of a mouse event.
Represents a coordinate reference system (CRS).
Handles coordinate transforms between two coordinate systems.
Custom exception class for Coordinate Reference System related exceptions.
QString what() const
A geometry is the spatial representation of a feature.
double length() const
Returns the planar, 2-dimensional length of geometry.
Qgis::GeometryOperationResult transform(const QgsCoordinateTransform &ct, Qgis::TransformDirection direction=Qgis::TransformDirection::Forward, bool transformZ=false)
Transforms this geometry as described by the coordinate transform ct.
Qgis::GeometryType type
double area() const
Returns the planar, 2-dimensional area of the geometry.
bool isEmpty() const
Returns true if the geometry is empty (eg a linestring with no vertices, or a collection with no geom...
void currentLayerChanged(QgsMapLayer *layer)
Emitted when the current layer is changed.
QgsMapLayer * currentLayer()
returns current layer (set by legend widget)
Base class for all map layer types.
Definition qgsmaplayer.h:83
A mouse event which is the result of a user interaction with a QgsMapCanvas.
QgsPointXY mapPoint() const
mapPoint returns the point in coordinates
QgsPointLocator::Match mapPointMatch() const
Returns the matching data from the most recently snapped point.
void snapToGrid(double precision, const QgsCoordinateReferenceSystem &crs)
Snaps the mapPoint to a grid with the given precision.
QgsPointXY snapPoint()
snapPoint will snap the points using the map canvas snapping utils configuration
virtual void cadCanvasMoveEvent(QgsMapMouseEvent *e)
Override this method when subclassing this class.
bool isAutoSnapEnabled() const
Returns whether mouse events (press/move/release) should automatically try to snap mouse position (ac...
static void calculateGeometryMeasures(const QgsReferencedGeometry &geometry, const QgsCoordinateReferenceSystem &destinationCrs, Qgis::CadMeasurementDisplayType areaType, Qgis::CadMeasurementDisplayType totalLengthType, QString &areaString, QString &totalLengthString)
Calculates geometry measures for a geometry, including area and total length (or perimeter).
QgsAdvancedDigitizingDockWidget * mCadDockWidget
bool useSnappingIndicator() const
Returns whether the snapping indicator should automatically be used.
void deactivate() override
Unregisters this maptool from the cad dock widget.
bool snapToLayerGridEnabled() const
Enables or disables snap to grid of mouse events.
void canvasMoveEvent(QgsMapMouseEvent *e) override
Catch the mouse move event, filters it, transforms it to map coordinates and send it to virtual metho...
virtual void cadCanvasPressEvent(QgsMapMouseEvent *e)
Override this method when subclassing this class.
virtual QgsMapLayer * layer() const
Returns the layer associated with the map tool.
QgsAdvancedDigitizingDockWidget * cadDockWidget() const
~QgsMapToolAdvancedDigitizing() override
void setSnapToLayerGridEnabled(bool snapToLayerGridEnabled)
Enables or disables snap to grid of mouse events.
void canvasPressEvent(QgsMapMouseEvent *e) override
Catch the mouse press event, filters it, transforms it to map coordinates and send it to virtual meth...
void setUseSnappingIndicator(bool enabled)
Sets whether a snapping indicator should automatically be used.
virtual void cadCanvasReleaseEvent(QgsMapMouseEvent *e)
Override this method when subclassing this class.
void canvasReleaseEvent(QgsMapMouseEvent *e) override
Catch the mouse release event, filters it, transforms it to map coordinates and send it to virtual me...
QgsMapToolAdvancedDigitizing(QgsMapCanvas *canvas, QgsAdvancedDigitizingDockWidget *cadDockWidget)
Creates an advanced digitizing maptool.
void activate() override
Registers this maptool with the cad dock widget.
void transientGeometryChanged(const QgsReferencedGeometry &geometry)
Emitted whenever the geometry associated with the tool is changed, including transient (i....
bool isAdvancedDigitizingAllowed() const
Returns whether functionality of advanced digitizing dock widget is currently allowed.
QgsMapToolEdit(QgsMapCanvas *canvas)
QgsVectorLayer * currentVectorLayer()
Returns the current vector layer of the map canvas or 0.
QgsMapCanvas * canvas() const
returns pointer to the tool's map canvas
QPointer< QgsMapCanvas > mCanvas
The pointer to the map canvas.
Definition qgsmaptool.h:369
friend class QgsMapCanvas
Definition qgsmaptool.h:389
virtual void activate()
called when set as currently active map tool
virtual void deactivate()
called when map tool is being deactivated
static Q_INVOKABLE QString formatAreaForProject(QgsProject *project, double area, Qgis::AreaUnit unit)
Formats an area measurement (with the specified unit) for use with a project, respecting the project'...
static Q_INVOKABLE QString formatDistanceForProject(QgsProject *project, double distance, Qgis::DistanceUnit unit)
Formats a distance measurement (with the specified unit) for use with a project, respecting the proje...
Represents a 2D point.
Definition qgspointxy.h:62
static QgsProject * instance()
Returns the QgsProject singleton instance.
QgsCoordinateReferenceSystem crs() const
Returns the associated coordinate reference system, or an invalid CRS if no reference system is set.
A QgsGeometry with associated coordinate reference system.
T value(const QString &dynamicKeyPart=QString()) const
Returns settings value.
static const QgsSettingsEntryEnumFlag< Qgis::CadMeasurementDisplayType > * settingsDigitizingStatusBarTotalLengthDisplay
Settings entry digitizing status bar perimeter/total length display.
static const QgsSettingsEntryEnumFlag< Qgis::CadMeasurementDisplayType > * settingsDigitizingStatusBarAreaDisplay
Settings entry digitizing status bar area display.
Shows a grid on the map canvas given a spatial resolution.
void clearMessage()
Removes any temporary message being shown.
void showMessage(const QString &message, int timeout=0)
Displays the given message for the specified number of milli-seconds (timeout).
static Q_INVOKABLE Qgis::AreaUnit distanceToAreaUnit(Qgis::DistanceUnit distanceUnit)
Converts a distance unit to its corresponding area unit, e.g., meters to square meters.
Represents a vector layer which manages a vector based dataset.
#define QgsDebugError(str)
Definition qgslogger.h:59