QGIS API Documentation 4.1.0-Master (60fea48833c)
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
166 const QgsReferencedGeometry &geometry,
167 const QgsCoordinateReferenceSystem &destinationCrs,
169 Qgis::CadMeasurementDisplayType totalLengthType,
170 QString &areaString,
171 QString &totalLengthString
172)
173{
174 areaString = QString();
175 totalLengthString = QString();
176
177 // transform to map crs
178 QgsGeometry g = geometry;
179 const QgsCoordinateTransform ct( geometry.crs(), destinationCrs, QgsProject::instance()->transformContext() );
180 try
181 {
182 g.transform( ct );
183 }
184 catch ( QgsCsException &e )
185 {
186 QgsDebugError( u"Error transforming transient geometry: %1"_s.arg( e.what() ) );
187 return;
188 }
189
190 std::unique_ptr< QgsDistanceArea > distanceArea;
191 auto createDistanceArea = [destinationCrs, &distanceArea] {
192 // reuse existing if we've already created one
193 if ( distanceArea )
194 return;
195
196 distanceArea = std::make_unique< QgsDistanceArea >();
197 distanceArea->setSourceCrs( destinationCrs, QgsProject::instance()->transformContext() );
198 distanceArea->setEllipsoid( QgsProject::instance()->ellipsoid() );
199 };
200
202 {
203 switch ( areaType )
204 {
206 break;
207
209 {
211 break;
212 }
213
215 {
216 createDistanceArea();
217 const double area = distanceArea->measureArea( g );
218 areaString = QgsMeasureUtils::formatAreaForProject( QgsProject::instance(), area, distanceArea->areaUnits() );
219 break;
220 }
221 }
222 }
223
224 switch ( totalLengthType )
225 {
227 break;
228
230 {
231 totalLengthString = QgsMeasureUtils::formatDistanceForProject( QgsProject::instance(), g.length(), destinationCrs.mapUnits() );
232 break;
233 }
235 {
236 createDistanceArea();
237 const double length = g.type() == Qgis::GeometryType::Polygon ? distanceArea->measurePerimeter( g ) : distanceArea->measureLength( g );
238 totalLengthString = QgsMeasureUtils::formatDistanceForProject( QgsProject::instance(), length, distanceArea->lengthUnits() );
239 break;
240 }
241 }
242}
243
245{
246 if ( enabled && !mSnapIndicator )
247 {
248 mSnapIndicator = std::make_unique<QgsSnapIndicator>( mCanvas );
249 }
250 else if ( !enabled && mSnapIndicator )
251 {
252 mSnapIndicator.reset();
253 }
254}
255
256void QgsMapToolAdvancedDigitizing::cadPointChanged( const QgsPointXY &point )
257{
258 Q_UNUSED( point )
259 QMouseEvent *ev = new QMouseEvent( QEvent::MouseMove, mCanvas->mouseLastXY(), Qt::NoButton, Qt::NoButton, Qt::NoModifier );
260 qApp->postEvent( mCanvas->viewport(), ev ); // event queue will delete the event when processed
261}
262
263void QgsMapToolAdvancedDigitizing::onCurrentLayerChanged()
264{
265 if ( mSnapToGridCanvasItem )
266 {
267 QgsVectorLayer *layer = currentVectorLayer();
268 if ( layer && mSnapToLayerGridEnabled )
269 {
270 mSnapToGridCanvasItem->setPrecision( layer->geometryOptions()->geometryPrecision() );
271 mSnapToGridCanvasItem->setCrs( layer->crs() );
272 }
273 if ( !layer || !layer->isSpatial() )
274 {
275 mCadDockWidget->clear();
276 mCadDockWidget->disable();
277 mSnapToGridCanvasItem->setEnabled( false );
278 }
279 else
280 {
281 mCadDockWidget->enable();
282 mSnapToGridCanvasItem->setEnabled( mSnapToLayerGridEnabled );
283 }
284 }
285}
286
287void QgsMapToolAdvancedDigitizing::onTransientGeometryChanged( const QgsReferencedGeometry &geometry )
288{
289 if ( mCadDockWidget )
290 mCadDockWidget->updateTransientGeometryProperties( geometry );
291
292 QgsStatusBar *statusBar = mCanvas ? mCanvas->statusBar() : nullptr;
293 if ( !statusBar )
294 return;
295
298 if ( areaDisplayType == Qgis::CadMeasurementDisplayType::Hidden && totalLengthDisplayType == Qgis::CadMeasurementDisplayType::Hidden )
299 return;
300
301 if ( geometry.isEmpty() )
302 {
303 statusBar->clearMessage();
304 }
305 else
306 {
307 QString areaString;
308 QString totalLengthString;
309 QgsMapToolAdvancedDigitizing::calculateGeometryMeasures( geometry, mCanvas->mapSettings().destinationCrs(), areaDisplayType, totalLengthDisplayType, areaString, totalLengthString );
310
311 QStringList messageParts;
312 if ( !areaString.isEmpty() )
313 messageParts.append( tr( "Total area: %1" ).arg( areaString ) );
314 if ( !totalLengthString.isEmpty() )
315 {
316 if ( geometry.type() == Qgis::GeometryType::Polygon )
317 messageParts.append( tr( "Perimeter: %1" ).arg( totalLengthString ) );
318 else
319 messageParts.append( tr( "Total length: %1" ).arg( totalLengthString ) );
320 }
321
322 statusBar->showMessage( messageParts.join( ' ' ) );
323 }
324}
325
327{
328 return mSnapToLayerGridEnabled;
329}
330
332{
333 mSnapToLayerGridEnabled = snapToGridEnabled;
334
335 if ( mSnapToGridCanvasItem )
336 {
337 mSnapToGridCanvasItem->setEnabled( snapToGridEnabled );
338 }
339}
@ Polygon
Polygons.
Definition qgis.h:382
CadMeasurementDisplayType
Advanced digitizing measurement display types.
Definition qgis.h:4207
@ Hidden
Hide measurement.
Definition qgis.h:4208
@ Cartesian
Use Cartesian measurements.
Definition qgis.h:4209
@ Ellipsoidal
Use Ellipsoidal measurements.
Definition qgis.h:4210
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