QGIS API Documentation 3.37.0-Master (684a802617f)
Loading...
Searching...
No Matches
qgscadutils.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgscadutils.cpp
3 -------------------
4 begin : September 2017
5 copyright : (C) 2017 by Martin Dobias
6 email : wonder dot sk at gmail dot com
7 ***************************************************************************/
8/***************************************************************************
9 * *
10 * This program is free software; you can redistribute it and/or modify *
11 * it under the terms of the GNU General Public License as published by *
12 * the Free Software Foundation; either version 2 of the License, or *
13 * (at your option) any later version. *
14 * *
15 ***************************************************************************/
16
17#include <QQueue>
18
19#include "qgscadutils.h"
20
21#include "qgslogger.h"
22#include "qgssnappingutils.h"
23#include "qgsgeometryutils.h"
25#include "qgscurvepolygon.h"
26
27// tolerances for soft constraints (last values, and common angles)
28// for angles, both tolerance in pixels and degrees are used for better performance
29static const double SOFT_CONSTRAINT_TOLERANCE_PIXEL = 15;
30static const double SOFT_CONSTRAINT_TOLERANCE_DEGREES = 10;
31
32
34struct EdgesOnlyFilter : public QgsPointLocator::MatchFilter
35{
36 bool acceptMatch( const QgsPointLocator::Match &m ) override { return m.hasEdge(); }
37};
39
40
42{
44 res.valid = true;
45 res.softLockCommonAngle = -1;
46
48 res.softLockX = std::numeric_limits<double>::quiet_NaN();
49 res.softLockY = std::numeric_limits<double>::quiet_NaN();
50
51 // try to snap to anything
52 const QgsPointLocator::Match snapMatch = ctx.snappingUtils->snapToMap( originalMapPoint, nullptr, true );
53 res.snapMatch = snapMatch;
54 QgsPointXY point = snapMatch.isValid() ? snapMatch.point() : originalMapPoint;
55 QgsPointXY edgePt0, edgePt1;
56 if ( snapMatch.hasEdge() )
57 {
58 snapMatch.edgePoints( edgePt0, edgePt1 );
59 // note : res.edgeMatch should be removed, as we can just check snapMatch.hasEdge()
60 res.edgeMatch = snapMatch;
61 }
62 else
63 {
65 }
66
67 int numberOfHardLock = 0;
68 if ( ctx.xConstraint.locked ) ++numberOfHardLock;
69 if ( ctx.yConstraint.locked ) ++numberOfHardLock;
70 if ( ctx.angleConstraint.locked ) ++numberOfHardLock;
71 if ( ctx.distanceConstraint.locked ) ++numberOfHardLock;
72
73 QgsPointXY previousPt, penultimatePt;
74 if ( ctx.cadPoints().count() >= 2 )
75 previousPt = ctx.cadPoint( 1 );
76 if ( ctx.cadPoints().count() >= 3 )
77 penultimatePt = ctx.cadPoint( 2 );
78
79 // *****************************
80 // ---- X constraint
81 if ( ctx.xConstraint.locked )
82 {
83 if ( !ctx.xConstraint.relative )
84 {
85 point.setX( ctx.xConstraint.value );
86 }
87 else if ( ctx.cadPoints().count() >= 2 )
88 {
89 point.setX( previousPt.x() + ctx.xConstraint.value );
90 }
91 if ( snapMatch.hasEdge() && !ctx.yConstraint.locked )
92 {
93 // intersect with snapped segment line at X coordinate
94 const double dx = edgePt1.x() - edgePt0.x();
95 if ( dx == 0 )
96 {
97 point.setY( edgePt0.y() );
98 }
99 else
100 {
101 const double dy = edgePt1.y() - edgePt0.y();
102 point.setY( edgePt0.y() + ( dy * ( point.x() - edgePt0.x() ) ) / dx );
103 }
104 }
105 }
106 else if ( numberOfHardLock < 2 && ctx.xyVertexConstraint.locked )
107 {
108 for ( QgsPointLocator::Match snapMatch : ctx.lockedSnapVertices() )
109 {
110 const QgsPointXY vertex = snapMatch.point();
111 if ( vertex.isEmpty() )
112 continue;
113
114 if ( std::abs( point.x() - vertex.x() ) / ctx.mapUnitsPerPixel < SOFT_CONSTRAINT_TOLERANCE_PIXEL )
115 {
116 point.setX( vertex.x() );
117 res.softLockX = vertex.x();
118 }
119 }
120 }
121
122 // *****************************
123 // ---- Y constraint
124 if ( ctx.yConstraint.locked )
125 {
126 if ( !ctx.yConstraint.relative )
127 {
128 point.setY( ctx.yConstraint.value );
129 }
130 else if ( ctx.cadPoints().count() >= 2 )
131 {
132 point.setY( previousPt.y() + ctx.yConstraint.value );
133 }
134 if ( snapMatch.hasEdge() && !ctx.xConstraint.locked )
135 {
136 // intersect with snapped segment line at Y coordinate
137 const double dy = edgePt1.y() - edgePt0.y();
138 if ( dy == 0 )
139 {
140 point.setX( edgePt0.x() );
141 }
142 else
143 {
144 const double dx = edgePt1.x() - edgePt0.x();
145 point.setX( edgePt0.x() + ( dx * ( point.y() - edgePt0.y() ) ) / dy );
146 }
147 }
148 }
149 else if ( numberOfHardLock < 2 && ctx.xyVertexConstraint.locked )
150 {
151 for ( QgsPointLocator::Match snapMatch : ctx.lockedSnapVertices() )
152 {
153 const QgsPointXY vertex = snapMatch.point();
154 if ( vertex.isEmpty() )
155 continue;
156
157 if ( std::abs( point.y() - vertex.y() ) / ctx.mapUnitsPerPixel < SOFT_CONSTRAINT_TOLERANCE_PIXEL )
158 {
159 point.setY( vertex.y() );
160 res.softLockY = vertex.y();
161 }
162 }
163 }
164
165 // *****************************
166 // ---- Common Angle constraint
167 if ( numberOfHardLock < 2 && !ctx.angleConstraint.locked && ctx.cadPoints().count() >= 2 && ctx.commonAngleConstraint.locked && ctx.commonAngleConstraint.value != 0
168 // Skip common angle constraint if the snapping to features has priority
169 && ( ! snapMatch.isValid() || ! ctx.snappingToFeaturesOverridesCommonAngle )
170 )
171 {
172 const double commonAngle = ctx.commonAngleConstraint.value * M_PI / 180;
173 // see if soft common angle constraint should be performed
174 // only if not in HardLock mode
175 double softAngle = std::atan2( point.y() - previousPt.y(),
176 point.x() - previousPt.x() );
177 double deltaAngle = 0;
178 if ( ctx.commonAngleConstraint.relative && ctx.cadPoints().count() >= 3 )
179 {
180 // compute the angle relative to the last segment (0° is aligned with last segment)
181 deltaAngle = std::atan2( previousPt.y() - penultimatePt.y(),
182 previousPt.x() - penultimatePt.x() );
183 softAngle -= deltaAngle;
184 }
185 const int quo = std::round( softAngle / commonAngle );
186 if ( std::fabs( softAngle - quo * commonAngle ) * 180.0 * M_1_PI <= SOFT_CONSTRAINT_TOLERANCE_DEGREES )
187 {
188 // also check the distance in pixel to the line, otherwise it's too sticky at long ranges
189 softAngle = quo * commonAngle;
190 // http://mathworld.wolfram.com/Point-LineDistance2-Dimensional.html
191 // use the direction vector (cos(a),sin(a)) from previous point. |x2-x1|=1 since sin2+cos2=1
192 const double dist = std::fabs( std::cos( softAngle + deltaAngle ) * ( previousPt.y() - point.y() )
193 - std::sin( softAngle + deltaAngle ) * ( previousPt.x() - point.x() ) );
194 if ( dist / ctx.mapUnitsPerPixel < SOFT_CONSTRAINT_TOLERANCE_PIXEL )
195 {
196 res.softLockCommonAngle = 180.0 / M_PI * softAngle;
197 }
198 }
199 }
200
201 // angle can be locked in one of the two ways:
202 // 1. "hard" lock defined by the user
203 // 2. "soft" lock from common angle (e.g. 45 degrees)
204 bool angleLocked = false, angleRelative = false;
205 double angleValueDeg = 0;
206 if ( ctx.angleConstraint.locked )
207 {
208 angleLocked = true;
209 angleRelative = ctx.angleConstraint.relative;
210 angleValueDeg = ctx.angleConstraint.value;
211 }
212 else if ( res.softLockCommonAngle != -1 )
213 {
214 angleLocked = true;
215 angleRelative = ctx.commonAngleConstraint.relative;
216 angleValueDeg = res.softLockCommonAngle;
217 }
218
219 // *****************************
220 // ---- Angle constraint
221 // input angles are in degrees
222 if ( angleLocked )
223 {
224 double angleValue = angleValueDeg * M_PI / 180;
225 if ( angleRelative && ctx.cadPoints().count() >= 3 )
226 {
227 // compute the angle relative to the last segment (0° is aligned with last segment)
228 angleValue += std::atan2( previousPt.y() - penultimatePt.y(),
229 previousPt.x() - penultimatePt.x() );
230 }
231
232 const double cosa = std::cos( angleValue );
233 const double sina = std::sin( angleValue );
234 const double v = ( point.x() - previousPt.x() ) * cosa + ( point.y() - previousPt.y() ) * sina;
235 if ( ctx.xConstraint.locked && ctx.yConstraint.locked )
236 {
237 // do nothing if both X,Y are already locked
238 }
239 else if ( ctx.xConstraint.locked || !std::isnan( res.softLockX ) )
240 {
241 if ( qgsDoubleNear( cosa, 0.0 ) )
242 {
243 res.valid = false;
244 }
245 else
246 {
247 double x = ctx.xConstraint.value;
248 if ( !ctx.xConstraint.relative )
249 {
250 x -= previousPt.x();
251 }
252 point.setY( previousPt.y() + x * sina / cosa );
253 }
254 }
255 else if ( ctx.yConstraint.locked || !std::isnan( res.softLockY ) )
256 {
257 if ( qgsDoubleNear( sina, 0.0 ) )
258 {
259 res.valid = false;
260 }
261 else
262 {
263 double y = ctx.yConstraint.value;
264 if ( !ctx.yConstraint.relative )
265 {
266 y -= previousPt.y();
267 }
268 point.setX( previousPt.x() + y * cosa / sina );
269 }
270 }
271 else
272 {
273 point.setX( previousPt.x() + cosa * v );
274 point.setY( previousPt.y() + sina * v );
275 }
276
277 if ( snapMatch.hasEdge() && !ctx.distanceConstraint.locked )
278 {
279 // magnetize to the intersection of the snapped segment and the lockedAngle
280
281 // line of previous point + locked angle
282 const double x1 = previousPt.x();
283 const double y1 = previousPt.y();
284 const double x2 = previousPt.x() + cosa;
285 const double y2 = previousPt.y() + sina;
286 // line of snapped segment
287 const double x3 = edgePt0.x();
288 const double y3 = edgePt0.y();
289 const double x4 = edgePt1.x();
290 const double y4 = edgePt1.y();
291
292 const double d = ( x1 - x2 ) * ( y3 - y4 ) - ( y1 - y2 ) * ( x3 - x4 );
293
294 // do not compute intersection if lines are almost parallel
295 // this threshold might be adapted
296 if ( std::fabs( d ) > 0.01 )
297 {
298 point.setX( ( ( x3 - x4 ) * ( x1 * y2 - y1 * x2 ) - ( x1 - x2 ) * ( x3 * y4 - y3 * x4 ) ) / d );
299 point.setY( ( ( y3 - y4 ) * ( x1 * y2 - y1 * x2 ) - ( y1 - y2 ) * ( x3 * y4 - y3 * x4 ) ) / d );
300 }
301 }
302 }
303
304 // *****************************
305 // ---- Line Extension Constraint
306
307 QgsPointXY lineExtensionPt1;
308 QgsPointXY lineExtensionPt2;
309 if ( numberOfHardLock < 2 && ctx.lineExtensionConstraint.locked && ctx.lockedSnapVertices().length() != 0 )
310 {
311 const QgsPointLocator::Match snap = ctx.lockedSnapVertices().last();
312 const QgsPointXY extensionPoint = snap.point();
313
314 if ( snap.layer() && !extensionPoint.isEmpty() )
315 {
316 auto checkLineExtension = [&]( QgsPoint vertex )
317 {
318 if ( vertex.isEmpty() )
319 {
320 return false;
321 }
322
323 const double distance = QgsGeometryUtils::distToInfiniteLine(
324 QgsPoint( point ), QgsPoint( extensionPoint ), vertex );
325
326 if ( distance / ctx.mapUnitsPerPixel < SOFT_CONSTRAINT_TOLERANCE_PIXEL )
327 {
328 if ( ctx.xConstraint.locked || !std::isnan( res.softLockX ) )
329 {
330 QgsPoint intersection;
331 const bool intersect = QgsGeometryUtils::lineIntersection(
332 QgsPoint( point ), QgsVector( 0, 1 ),
333 QgsPoint( extensionPoint ), QgsPoint( extensionPoint ) - vertex,
334 intersection
335 );
336 if ( intersect )
337 {
338 point = QgsPointXY( intersection );
339 }
340 }
341 else if ( ctx.yConstraint.locked || !std::isnan( res.softLockY ) )
342 {
343 QgsPoint intersection;
344 const bool intersect = QgsGeometryUtils::lineIntersection(
345 QgsPoint( point ), QgsVector( 1, 0 ),
346 QgsPoint( extensionPoint ), QgsPoint( extensionPoint ) - vertex,
347 intersection
348 );
349 if ( intersect )
350 {
351 point = QgsPointXY( intersection );
352 }
353 }
354 else if ( angleLocked )
355 {
356 const double angleValue = angleValueDeg * M_PI / 180;
357 const double cosa = std::cos( angleValue );
358 const double sina = std::sin( angleValue );
359
360 QgsPoint intersection;
362 QgsPoint( previousPt ), QgsVector( cosa, sina ),
363 QgsPoint( extensionPoint ), QgsPoint( extensionPoint ) - vertex,
364 intersection
365 );
366 point = QgsPointXY( intersection );
367 }
368 else
369 {
370 double angleValue = std::atan2( extensionPoint.y() - vertex.y(),
371 extensionPoint.x() - vertex.x() );
372
373 const double cosa = std::cos( angleValue );
374 const double sina = std::sin( angleValue );
375 const double v = ( point.x() - extensionPoint.x() ) * cosa + ( point.y() - extensionPoint.y() ) * sina;
376
377 point.setX( extensionPoint.x() + cosa * v );
378 point.setY( extensionPoint.y() + sina * v );
379 }
380
381 return true;
382 }
383 return false;
384 };
385
387 req.setFilterFid( snap.featureId() );
388 req.setNoAttributes();
390 QgsFeatureIterator featureIt = snap.layer()->getFeatures( req );
391
392 QgsFeature feature;
393 featureIt.nextFeature( feature );
394
395 const QgsGeometry geometry = feature.geometry();
396 const QgsAbstractGeometry *geom = geometry.constGet();
397
398 QgsVertexId vertexId;
399 geometry.vertexIdFromVertexNr( snap.vertexIndex(), vertexId );
400 if ( vertexId.isValid() )
401 {
402 QgsVertexId previousVertexId;
403 QgsVertexId nextVertexId;
404 geom->adjacentVertices( vertexId, previousVertexId, nextVertexId );
405
406 bool checked = checkLineExtension( geom->vertexAt( previousVertexId ) );
407 if ( checked )
408 {
410 lineExtensionPt1 = snap.point();
411 lineExtensionPt2 = QgsPointXY( geom->vertexAt( previousVertexId ) );
412 }
413
414 checked = checkLineExtension( geom->vertexAt( nextVertexId ) );
415 if ( checked )
416 {
418 lineExtensionPt1 = snap.point();
419 lineExtensionPt2 = QgsPointXY( geom->vertexAt( nextVertexId ) );
420 }
421 }
422 }
423 }
424
425 // *****************************
426 // ---- Distance constraint
427 if ( ctx.distanceConstraint.locked && ctx.cadPoints().count() >= 2 )
428 {
429 if ( ctx.xConstraint.locked || ctx.yConstraint.locked
430 || !std::isnan( res.softLockX ) || !std::isnan( res.softLockY ) )
431 {
432 // perform both to detect errors in constraints
433 if ( ctx.xConstraint.locked || !std::isnan( res.softLockX ) )
434 {
435 const QgsPointXY verticalPt0( point.x(), point.y() );
436 const QgsPointXY verticalPt1( point.x(), point.y() + 1 );
437 const bool intersect = QgsGeometryUtils::lineCircleIntersection( previousPt, ctx.distanceConstraint.value, verticalPt0, verticalPt1, point );
438
439 if ( ctx.xConstraint.locked )
440 {
441 res.valid &= intersect;
442 }
443 else if ( !intersect )
444 {
445 res.softLockX = std::numeric_limits<double>::quiet_NaN();
446 res.softLockY = std::numeric_limits<double>::quiet_NaN(); // in the case of the 2 soft locks are activated
447 res.valid &= QgsGeometryUtils::lineCircleIntersection( previousPt, ctx.distanceConstraint.value, previousPt, point, point );
448 }
449 }
450 if ( ctx.yConstraint.locked || !std::isnan( res.softLockY ) )
451 {
452 const QgsPointXY horizontalPt0( point.x(), point.y() );
453 const QgsPointXY horizontalPt1( point.x() + 1, point.y() );
454 const bool intersect = QgsGeometryUtils::lineCircleIntersection( previousPt, ctx.distanceConstraint.value, horizontalPt0, horizontalPt1, point );
455
456 if ( ctx.yConstraint.locked )
457 {
458 res.valid &= intersect;
459 }
460 else if ( !intersect )
461 {
462 res.softLockY = std::numeric_limits<double>::quiet_NaN();
463 res.valid &= QgsGeometryUtils::lineCircleIntersection( previousPt, ctx.distanceConstraint.value, previousPt, point, point );
464 }
465 }
466 }
468 {
469 const bool intersect = QgsGeometryUtils::lineCircleIntersection( previousPt, ctx.distanceConstraint.value, lineExtensionPt1, lineExtensionPt2, point );
470 if ( !intersect )
471 {
473 res.valid &= QgsGeometryUtils::lineCircleIntersection( previousPt, ctx.distanceConstraint.value, previousPt, point, point );
474 }
475 }
476 else
477 {
478 const double dist = std::sqrt( point.sqrDist( previousPt ) );
479 if ( dist == 0 )
480 {
481 // handle case where mouse is over origin and distance constraint is enabled
482 // take arbitrary horizontal line
483 point.set( previousPt.x() + ctx.distanceConstraint.value, previousPt.y() );
484 }
485 else
486 {
487 const double vP = ctx.distanceConstraint.value / dist;
488 point.set( previousPt.x() + ( point.x() - previousPt.x() ) * vP,
489 previousPt.y() + ( point.y() - previousPt.y() ) * vP );
490 }
491
492 if ( snapMatch.hasEdge() && !ctx.angleConstraint.locked )
493 {
494 // we will magnietize to the intersection of that segment and the lockedDistance !
495 res.valid &= QgsGeometryUtils::lineCircleIntersection( previousPt, ctx.distanceConstraint.value, edgePt0, edgePt1, point );
496 }
497 }
498 }
499
500 // *****************************
501 // ---- calculate CAD values
502 QgsDebugMsgLevel( QStringLiteral( "point: %1 %2" ).arg( point.x() ).arg( point.y() ), 4 );
503 QgsDebugMsgLevel( QStringLiteral( "previous point: %1 %2" ).arg( previousPt.x() ).arg( previousPt.y() ), 4 );
504 QgsDebugMsgLevel( QStringLiteral( "penultimate point: %1 %2" ).arg( penultimatePt.x() ).arg( penultimatePt.y() ), 4 );
505 //QgsDebugMsgLevel( QStringLiteral( "dx: %1 dy: %2" ).arg( point.x() - previousPt.x() ).arg( point.y() - previousPt.y() ), 4 );
506 //QgsDebugMsgLevel( QStringLiteral( "ddx: %1 ddy: %2" ).arg( previousPt.x() - penultimatePt.x() ).arg( previousPt.y() - penultimatePt.y() ), 4 );
507
508 res.finalMapPoint = point;
509
510 return res;
511}
512
514{
515 QgsDebugMsgLevel( QStringLiteral( "Constraints (locked / relative / value" ), 1 );
516 QgsDebugMsgLevel( QStringLiteral( "Angle: %1 %2 %3" ).arg( angleConstraint.locked ).arg( angleConstraint.relative ).arg( angleConstraint.value ), 1 );
517 QgsDebugMsgLevel( QStringLiteral( "Distance: %1 %2 %3" ).arg( distanceConstraint.locked ).arg( distanceConstraint.relative ).arg( distanceConstraint.value ), 1 );
518 QgsDebugMsgLevel( QStringLiteral( "X: %1 %2 %3" ).arg( xConstraint.locked ).arg( xConstraint.relative ).arg( xConstraint.value ), 1 );
519 QgsDebugMsgLevel( QStringLiteral( "Y: %1 %2 %3" ).arg( yConstraint.locked ).arg( yConstraint.relative ).arg( yConstraint.value ), 1 );
520}
@ AfterVertex
Lock to next vertex.
@ NoVertex
Don't lock to vertex.
@ BeforeVertex
Lock to previous vertex.
Abstract base class for all geometries.
virtual QgsPoint vertexAt(QgsVertexId id) const =0
Returns the point corresponding to a specified vertex id.
virtual void adjacentVertices(QgsVertexId vertex, QgsVertexId &previousVertex, QgsVertexId &nextVertex) const =0
Returns the vertices adjacent to a specified vertex within a geometry.
bool locked
Whether the constraint is active, i.e. should be considered.
Definition qgscadutils.h:55
double value
Numeric value of the constraint (coordinate/distance in map units or angle in degrees)
Definition qgscadutils.h:59
bool relative
Whether the value is relative to previous value.
Definition qgscadutils.h:57
Defines constraints for the QgsCadUtils::alignMapPoint() method.
QgsCadUtils::AlignMapPointConstraint xyVertexConstraint
QgsCadUtils::AlignMapPointConstraint yConstraint
Constraint for Y coordinate.
QgsCadUtils::AlignMapPointConstraint xConstraint
Constraint for X coordinate.
double mapUnitsPerPixel
Map units/pixel ratio from map canvas.
QgsPoint cadPoint(int index) const
Returns the recent CAD point at the specified index (in map coordinates).
QgsCadUtils::AlignMapPointConstraint distanceConstraint
Constraint for distance.
bool snappingToFeaturesOverridesCommonAngle
Flag to set snapping to features priority over common angle.
QgsSnappingUtils * snappingUtils
Snapping utils that will be used to snap point to map. Must not be nullptr.
QgsCadUtils::AlignMapPointConstraint commonAngleConstraint
Constraint for soft lock to a common angle.
QQueue< QgsPointLocator::Match > lockedSnapVertices() const
Returns the queue of point locator matches that contain the locked vertices.
QgsCadUtils::AlignMapPointConstraint lineExtensionConstraint
QList< QgsPoint > cadPoints() const
Returns the list of recent CAD points in map coordinates.
void dump() const
Dumps the context's properties, for debugging.
QgsCadUtils::AlignMapPointConstraint angleConstraint
Constraint for angle.
Structure returned from alignMapPoint() method.
Definition qgscadutils.h:67
Qgis::LineExtensionSide softLockLineExtension
Definition qgscadutils.h:90
QgsPointXY finalMapPoint
map point aligned according to the constraints
Definition qgscadutils.h:73
bool valid
Whether the combination of constraints is actually valid.
Definition qgscadutils.h:70
QgsPointLocator::Match snapMatch
Snapped point - only valid if actually used for something.
Definition qgscadutils.h:79
QgsPointLocator::Match edgeMatch
Snapped segment - only valid if actually used for something.
Definition qgscadutils.h:85
double softLockCommonAngle
Angle (in degrees) to which we have soft-locked ourselves (if not set it is -1)
Definition qgscadutils.h:88
static QgsCadUtils::AlignMapPointOutput alignMapPoint(const QgsPointXY &originalMapPoint, const QgsCadUtils::AlignMapPointContext &ctx)
Applies X/Y/angle/distance constraints from the given context to a map point.
Wrapper for iterator of features from vector data provider or vector layer.
bool nextFeature(QgsFeature &f)
Fetch next feature and stores in f, returns true on success.
This class wraps a request for features to a vector layer (or directly its vector data provider).
QgsFeatureRequest & setDestinationCrs(const QgsCoordinateReferenceSystem &crs, const QgsCoordinateTransformContext &context)
Sets the destination crs for feature's geometries.
QgsFeatureRequest & setNoAttributes()
Set that no attributes will be fetched.
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:58
QgsGeometry geometry
Definition qgsfeature.h:69
static bool lineIntersection(const QgsPoint &p1, QgsVector v1, const QgsPoint &p2, QgsVector v2, QgsPoint &intersection)
Computes the intersection between two lines.
static bool lineCircleIntersection(const QgsPointXY &center, double radius, const QgsPointXY &linePoint1, const QgsPointXY &linePoint2, QgsPointXY &intersection)
Compute the intersection of a line and a circle.
static double distToInfiniteLine(const QgsPoint &point, const QgsPoint &linePoint1, const QgsPoint &linePoint2, double epsilon=1e-7)
Returns the distance between a point and an infinite line.
A geometry is the spatial representation of a feature.
bool vertexIdFromVertexNr(int number, QgsVertexId &id) const
Calculates the vertex ID from a vertex number.
const QgsAbstractGeometry * constGet() const
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
QgsCoordinateReferenceSystem destinationCrs() const
Returns the destination coordinate reference system for the map render.
QgsCoordinateTransformContext transformContext() const
Returns the coordinate transform context, which stores various information regarding which datum tran...
A class to represent a 2D point.
Definition qgspointxy.h:60
double sqrDist(double x, double y) const
Returns the squared distance between this point a specified x, y coordinate.
Definition qgspointxy.h:187
void setY(double y)
Sets the y value of the point.
Definition qgspointxy.h:130
void set(double x, double y)
Sets the x and y value of the point.
Definition qgspointxy.h:137
double y
Definition qgspointxy.h:64
double x
Definition qgspointxy.h:63
void setX(double x)
Sets the x value of the point.
Definition qgspointxy.h:120
bool isEmpty() const
Returns true if the geometry is empty.
Definition qgspointxy.h:243
Point geometry type, with support for z-dimension and m-values.
Definition qgspoint.h:49
QgsMapSettings mapSettings() const
QgsPointLocator::Match snapToMap(QPoint point, QgsPointLocator::MatchFilter *filter=nullptr, bool relaxed=false)
Snap to map according to the current configuration.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const FINAL
Queries the layer for features specified in request.
A class to represent a vector.
Definition qgsvector.h:30
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition qgis.h:5445
#define QgsDebugMsgLevel(str, level)
Definition qgslogger.h:39
Interface that allows rejection of some matches in intersection queries (e.g.
virtual bool acceptMatch(const QgsPointLocator::Match &match)=0
QgsFeatureId featureId() const
The id of the feature to which the snapped geometry belongs.
QgsVectorLayer * layer() const
The vector layer where the snap occurred.
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.
void edgePoints(QgsPointXY &pt1, QgsPointXY &pt2) const
Only for a valid edge match - obtain endpoints of the edge.
int vertexIndex() const
for vertex / edge match (first vertex of the edge)
Utility class for identifying a unique vertex within a geometry.
Definition qgsvertexid.h:30
bool isValid() const
Returns true if the vertex id is valid.
Definition qgsvertexid.h:45