QGIS API Documentation 4.0.0-Norrköping (1ddcee3d0e4)
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 "qgscadutils.h"
18
19#include "qgscurvepolygon.h"
21#include "qgsgeometryutils.h"
22#include "qgslogger.h"
23#include "qgssnappingutils.h"
24
25#include <QQueue>
26#include <QString>
27
28using namespace Qt::StringLiterals;
29
30// tolerances for soft constraints (last values, and common angles)
31// for angles, both tolerance in pixels and degrees are used for better performance
32static const double SOFT_CONSTRAINT_TOLERANCE_PIXEL = 15;
33static const double SOFT_CONSTRAINT_TOLERANCE_DEGREES = 10;
34
35
37struct EdgesOnlyFilter : public QgsPointLocator::MatchFilter
38{
39 bool acceptMatch( const QgsPointLocator::Match &m ) override { return m.hasEdge(); }
40};
42
43
45{
47 res.valid = true;
48 res.softLockCommonAngle = -1;
49
51 res.softLockX = std::numeric_limits<double>::quiet_NaN();
52 res.softLockY = std::numeric_limits<double>::quiet_NaN();
53
54 // try to snap to project layer(s) as well as visible construction guides
55 QgsPointLocator::Match snapMatch = ctx.snappingUtils->snapToMap( originalMapPoint, nullptr, true );
56 res.snapMatch = snapMatch;
57 QgsPointXY point = snapMatch.isValid() ? snapMatch.point() : originalMapPoint;
58 QgsPointXY edgePt0, edgePt1;
59 if ( snapMatch.hasEdge() )
60 {
61 snapMatch.edgePoints( edgePt0, edgePt1 );
62 // note : res.edgeMatch should be removed, as we can just check snapMatch.hasEdge()
63 res.edgeMatch = snapMatch;
64 }
65 else
66 {
68 }
69
70 int numberOfHardLock = 0;
71 if ( ctx.xConstraint.locked )
72 ++numberOfHardLock;
73 if ( ctx.yConstraint.locked )
74 ++numberOfHardLock;
75 if ( ctx.angleConstraint.locked )
76 ++numberOfHardLock;
77 if ( ctx.distanceConstraint.locked )
78 ++numberOfHardLock;
79
80 QgsPointXY previousPt, penultimatePt;
81 if ( ctx.cadPoints().count() >= 2 )
82 previousPt = ctx.cadPoint( 1 );
83 if ( ctx.cadPoints().count() >= 3 )
84 penultimatePt = ctx.cadPoint( 2 );
85
86 // *****************************
87 // ---- X constraint
88 if ( ctx.xConstraint.locked )
89 {
90 if ( !ctx.xConstraint.relative )
91 {
92 point.setX( ctx.xConstraint.value );
93 }
94 else if ( ctx.cadPoints().count() >= 2 )
95 {
96 point.setX( previousPt.x() + ctx.xConstraint.value );
97 }
98 if ( snapMatch.hasEdge() && !ctx.yConstraint.locked )
99 {
100 // intersect with snapped segment line at X coordinate
101 const double dx = edgePt1.x() - edgePt0.x();
102 if ( dx == 0 )
103 {
104 point.setY( edgePt0.y() );
105 }
106 else
107 {
108 const double dy = edgePt1.y() - edgePt0.y();
109 point.setY( edgePt0.y() + ( dy * ( point.x() - edgePt0.x() ) ) / dx );
110 }
111 }
112 }
113 else if ( numberOfHardLock < 2 && ctx.xyVertexConstraint.locked )
114 {
115 for ( QgsPointLocator::Match snapMatch : ctx.lockedSnapVertices() )
116 {
117 const QgsPointXY vertex = snapMatch.point();
118 if ( vertex.isEmpty() )
119 continue;
120
121 if ( std::abs( point.x() - vertex.x() ) / ctx.mapUnitsPerPixel < SOFT_CONSTRAINT_TOLERANCE_PIXEL )
122 {
123 point.setX( vertex.x() );
124 res.softLockX = vertex.x();
125 }
126 }
127 }
128
129 // *****************************
130 // ---- Y constraint
131 if ( ctx.yConstraint.locked )
132 {
133 if ( !ctx.yConstraint.relative )
134 {
135 point.setY( ctx.yConstraint.value );
136 }
137 else if ( ctx.cadPoints().count() >= 2 )
138 {
139 point.setY( previousPt.y() + ctx.yConstraint.value );
140 }
141 if ( snapMatch.hasEdge() && !ctx.xConstraint.locked )
142 {
143 // intersect with snapped segment line at Y coordinate
144 const double dy = edgePt1.y() - edgePt0.y();
145 if ( dy == 0 )
146 {
147 point.setX( edgePt0.x() );
148 }
149 else
150 {
151 const double dx = edgePt1.x() - edgePt0.x();
152 point.setX( edgePt0.x() + ( dx * ( point.y() - edgePt0.y() ) ) / dy );
153 }
154 }
155 }
156 else if ( numberOfHardLock < 2 && ctx.xyVertexConstraint.locked )
157 {
158 for ( QgsPointLocator::Match snapMatch : ctx.lockedSnapVertices() )
159 {
160 const QgsPointXY vertex = snapMatch.point();
161 if ( vertex.isEmpty() )
162 continue;
163
164 if ( std::abs( point.y() - vertex.y() ) / ctx.mapUnitsPerPixel < SOFT_CONSTRAINT_TOLERANCE_PIXEL )
165 {
166 point.setY( vertex.y() );
167 res.softLockY = vertex.y();
168 }
169 }
170 }
171
172 // *****************************
173 // ---- Common Angle constraint
174 if ( numberOfHardLock < 2
175 && !ctx.angleConstraint.locked
176 && ctx.cadPoints().count() >= 2
178 && ctx.commonAngleConstraint.value != 0
179 // Skip common angle constraint if the snapping to features has priority
180 && ( !snapMatch.isValid() || !ctx.snappingToFeaturesOverridesCommonAngle ) )
181 {
182 const double commonAngle = ctx.commonAngleConstraint.value * M_PI / 180;
183 // see if soft common angle constraint should be performed
184 // only if not in HardLock mode
185 double softAngle = std::atan2( point.y() - previousPt.y(), point.x() - previousPt.x() );
186 double deltaAngle = 0;
187 if ( ctx.commonAngleConstraint.relative && ctx.cadPoints().count() >= 3 )
188 {
189 // compute the angle relative to the last segment (0° is aligned with last segment)
190 deltaAngle = std::atan2( previousPt.y() - penultimatePt.y(), previousPt.x() - penultimatePt.x() );
191 softAngle -= deltaAngle;
192 }
193 const int quo = std::round( softAngle / commonAngle );
194 if ( std::fabs( softAngle - quo * commonAngle ) * 180.0 * M_1_PI <= SOFT_CONSTRAINT_TOLERANCE_DEGREES )
195 {
196 // also check the distance in pixel to the line, otherwise it's too sticky at long ranges
197 softAngle = quo * commonAngle;
198 // http://mathworld.wolfram.com/Point-LineDistance2-Dimensional.html
199 // use the direction vector (cos(a),sin(a)) from previous point. |x2-x1|=1 since sin2+cos2=1
200 const double dist = std::fabs( std::cos( softAngle + deltaAngle ) * ( previousPt.y() - point.y() ) - std::sin( softAngle + deltaAngle ) * ( previousPt.x() - point.x() ) );
201 if ( dist / ctx.mapUnitsPerPixel < SOFT_CONSTRAINT_TOLERANCE_PIXEL )
202 {
203 res.softLockCommonAngle = 180.0 / M_PI * softAngle;
204 }
205 }
206 }
207
208 // angle can be locked in one of the two ways:
209 // 1. "hard" lock defined by the user
210 // 2. "soft" lock from common angle (e.g. 45 degrees)
211 bool angleLocked = false, angleRelative = false;
212 double angleValueDeg = 0;
213 if ( ctx.angleConstraint.locked )
214 {
215 angleLocked = true;
216 angleRelative = ctx.angleConstraint.relative;
217 angleValueDeg = ctx.angleConstraint.value;
218 }
219 else if ( res.softLockCommonAngle != -1 )
220 {
221 angleLocked = true;
222 angleRelative = ctx.commonAngleConstraint.relative;
223 angleValueDeg = res.softLockCommonAngle;
224 }
225
226 // *****************************
227 // ---- Angle constraint
228 // input angles are in degrees
229 if ( angleLocked )
230 {
231 double angleValue = angleValueDeg * M_PI / 180;
232 if ( angleRelative && ctx.cadPoints().count() >= 3 )
233 {
234 // compute the angle relative to the last segment (0° is aligned with last segment)
235 angleValue += std::atan2( previousPt.y() - penultimatePt.y(), previousPt.x() - penultimatePt.x() );
236 }
237
238 const double cosa = std::cos( angleValue );
239 const double sina = std::sin( angleValue );
240 const double v = ( point.x() - previousPt.x() ) * cosa + ( point.y() - previousPt.y() ) * sina;
241 if ( ctx.xConstraint.locked && ctx.yConstraint.locked )
242 {
243 // do nothing if both X,Y are already locked
244 }
245 else if ( ctx.xConstraint.locked || !std::isnan( res.softLockX ) )
246 {
247 if ( qgsDoubleNear( cosa, 0.0 ) )
248 {
249 res.valid = false;
250 }
251 else
252 {
253 double x = ctx.xConstraint.value;
254 if ( !ctx.xConstraint.relative )
255 {
256 x -= previousPt.x();
257 }
258 point.setY( previousPt.y() + x * sina / cosa );
259 }
260 }
261 else if ( ctx.yConstraint.locked || !std::isnan( res.softLockY ) )
262 {
263 if ( qgsDoubleNear( sina, 0.0 ) )
264 {
265 res.valid = false;
266 }
267 else
268 {
269 double y = ctx.yConstraint.value;
270 if ( !ctx.yConstraint.relative )
271 {
272 y -= previousPt.y();
273 }
274 point.setX( previousPt.x() + y * cosa / sina );
275 }
276 }
277 else
278 {
279 point.setX( previousPt.x() + cosa * v );
280 point.setY( previousPt.y() + sina * v );
281 }
282
283 if ( snapMatch.hasEdge() && !ctx.distanceConstraint.locked )
284 {
285 // magnetize to the intersection of the snapped segment and the lockedAngle
286
287 // line of previous point + locked angle
288 const double x1 = previousPt.x();
289 const double y1 = previousPt.y();
290 const double x2 = previousPt.x() + cosa;
291 const double y2 = previousPt.y() + sina;
292 // line of snapped segment
293 const double x3 = edgePt0.x();
294 const double y3 = edgePt0.y();
295 const double x4 = edgePt1.x();
296 const double y4 = edgePt1.y();
297
298 const double d = ( x1 - x2 ) * ( y3 - y4 ) - ( y1 - y2 ) * ( x3 - x4 );
299
300 // do not compute intersection if lines are almost parallel
301 // this threshold might be adapted
302 if ( std::fabs( d ) > 0.01 )
303 {
304 point.setX( ( ( x3 - x4 ) * ( x1 * y2 - y1 * x2 ) - ( x1 - x2 ) * ( x3 * y4 - y3 * x4 ) ) / d );
305 point.setY( ( ( y3 - y4 ) * ( x1 * y2 - y1 * x2 ) - ( y1 - y2 ) * ( x3 * y4 - y3 * x4 ) ) / d );
306 }
307 }
308 }
309
310 // *****************************
311 // ---- Line Extension Constraint
312
313 QgsPointXY lineExtensionPt1;
314 QgsPointXY lineExtensionPt2;
315 if ( numberOfHardLock < 2 && ctx.lineExtensionConstraint.locked && ctx.lockedSnapVertices().length() != 0 )
316 {
317 const QgsPointLocator::Match snap = ctx.lockedSnapVertices().last();
318 const QgsPointXY extensionPoint = snap.point();
319
320 if ( snap.layer() && !extensionPoint.isEmpty() )
321 {
322 auto checkLineExtension = [&]( QgsPoint vertex ) {
323 if ( vertex.isEmpty() )
324 {
325 return false;
326 }
327
328 const double distance = QgsGeometryUtils::distToInfiniteLine( QgsPoint( point ), QgsPoint( extensionPoint ), vertex );
329
330 if ( distance / ctx.mapUnitsPerPixel < SOFT_CONSTRAINT_TOLERANCE_PIXEL )
331 {
332 if ( ctx.xConstraint.locked || !std::isnan( res.softLockX ) )
333 {
334 QgsPoint intersection;
335 const bool intersect = QgsGeometryUtils::lineIntersection( QgsPoint( point ), QgsVector( 0, 1 ), QgsPoint( extensionPoint ), QgsPoint( extensionPoint ) - vertex, intersection );
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( QgsPoint( point ), QgsVector( 1, 0 ), QgsPoint( extensionPoint ), QgsPoint( extensionPoint ) - vertex, intersection );
345 if ( intersect )
346 {
347 point = QgsPointXY( intersection );
348 }
349 }
350 else if ( angleLocked )
351 {
352 const double angleValue = angleValueDeg * M_PI / 180;
353 const double cosa = std::cos( angleValue );
354 const double sina = std::sin( angleValue );
355
356 QgsPoint intersection;
357 QgsGeometryUtils::lineIntersection( QgsPoint( previousPt ), QgsVector( cosa, sina ), QgsPoint( extensionPoint ), QgsPoint( extensionPoint ) - vertex, intersection );
358 point = QgsPointXY( intersection );
359 }
360 else
361 {
362 double angleValue = std::atan2( extensionPoint.y() - vertex.y(), extensionPoint.x() - vertex.x() );
363
364 const double cosa = std::cos( angleValue );
365 const double sina = std::sin( angleValue );
366 const double v = ( point.x() - extensionPoint.x() ) * cosa + ( point.y() - extensionPoint.y() ) * sina;
367
368 point.setX( extensionPoint.x() + cosa * v );
369 point.setY( extensionPoint.y() + sina * v );
370 }
371
372 return true;
373 }
374 return false;
375 };
376
378 req.setFilterFid( snap.featureId() );
379 req.setNoAttributes();
381 QgsFeatureIterator featureIt = snap.layer()->getFeatures( req );
382
383 QgsFeature feature;
384 featureIt.nextFeature( feature );
385
386 const QgsGeometry geometry = feature.geometry();
387 const QgsAbstractGeometry *geom = geometry.constGet();
388
389 QgsVertexId vertexId;
390 if ( geometry.vertexIdFromVertexNr( snap.vertexIndex(), vertexId ) && vertexId.isValid() )
391 {
392 QgsVertexId previousVertexId;
393 QgsVertexId nextVertexId;
394 geom->adjacentVertices( vertexId, previousVertexId, nextVertexId );
395
396 bool checked = checkLineExtension( geom->vertexAt( previousVertexId ) );
397 if ( checked )
398 {
400 lineExtensionPt1 = snap.point();
401 lineExtensionPt2 = QgsPointXY( geom->vertexAt( previousVertexId ) );
402 }
403
404 checked = checkLineExtension( geom->vertexAt( nextVertexId ) );
405 if ( checked )
406 {
408 lineExtensionPt1 = snap.point();
409 lineExtensionPt2 = QgsPointXY( geom->vertexAt( nextVertexId ) );
410 }
411 }
412 }
413 }
414
415 // *****************************
416 // ---- Distance constraint
417 if ( ctx.distanceConstraint.locked && ctx.cadPoints().count() >= 2 )
418 {
419 if ( ctx.xConstraint.locked || ctx.yConstraint.locked || !std::isnan( res.softLockX ) || !std::isnan( res.softLockY ) )
420 {
421 // perform both to detect errors in constraints
422 if ( ctx.xConstraint.locked || !std::isnan( res.softLockX ) )
423 {
424 const QgsPointXY verticalPt0( point.x(), point.y() );
425 const QgsPointXY verticalPt1( point.x(), point.y() + 1 );
426 const bool intersect = QgsGeometryUtils::lineCircleIntersection( previousPt, ctx.distanceConstraint.value, verticalPt0, verticalPt1, point );
427
428 if ( ctx.xConstraint.locked )
429 {
430 res.valid &= intersect;
431 }
432 else if ( !intersect )
433 {
434 res.softLockX = std::numeric_limits<double>::quiet_NaN();
435 res.softLockY = std::numeric_limits<double>::quiet_NaN(); // in the case of the 2 soft locks are activated
436 res.valid &= QgsGeometryUtils::lineCircleIntersection( previousPt, ctx.distanceConstraint.value, previousPt, point, point );
437 }
438 }
439 if ( ctx.yConstraint.locked || !std::isnan( res.softLockY ) )
440 {
441 const QgsPointXY horizontalPt0( point.x(), point.y() );
442 const QgsPointXY horizontalPt1( point.x() + 1, point.y() );
443 const bool intersect = QgsGeometryUtils::lineCircleIntersection( previousPt, ctx.distanceConstraint.value, horizontalPt0, horizontalPt1, point );
444
445 if ( ctx.yConstraint.locked )
446 {
447 res.valid &= intersect;
448 }
449 else if ( !intersect )
450 {
451 res.softLockY = std::numeric_limits<double>::quiet_NaN();
452 res.valid &= QgsGeometryUtils::lineCircleIntersection( previousPt, ctx.distanceConstraint.value, previousPt, point, point );
453 }
454 }
455 }
457 {
458 const bool intersect = QgsGeometryUtils::lineCircleIntersection( previousPt, ctx.distanceConstraint.value, lineExtensionPt1, lineExtensionPt2, point );
459 if ( !intersect )
460 {
462 res.valid &= QgsGeometryUtils::lineCircleIntersection( previousPt, ctx.distanceConstraint.value, previousPt, point, point );
463 }
464 }
465 else
466 {
467 const double dist = std::sqrt( point.sqrDist( previousPt ) );
468 if ( dist == 0 )
469 {
470 // handle case where mouse is over origin and distance constraint is enabled
471 // take arbitrary horizontal line
472 point.set( previousPt.x() + ctx.distanceConstraint.value, previousPt.y() );
473 }
474 else
475 {
476 const double vP = ctx.distanceConstraint.value / dist;
477 point.set( previousPt.x() + ( point.x() - previousPt.x() ) * vP, previousPt.y() + ( point.y() - previousPt.y() ) * vP );
478 }
479
480 if ( snapMatch.hasEdge() && !ctx.angleConstraint.locked )
481 {
482 // we will magnietize to the intersection of that segment and the lockedDistance !
483 res.valid &= QgsGeometryUtils::lineCircleIntersection( previousPt, ctx.distanceConstraint.value, edgePt0, edgePt1, point );
484 }
485 }
486 }
487
488 // *****************************
489 // ---- calculate CAD values
490 QgsDebugMsgLevel( u"point: %1 %2"_s.arg( point.x() ).arg( point.y() ), 4 );
491 QgsDebugMsgLevel( u"previous point: %1 %2"_s.arg( previousPt.x() ).arg( previousPt.y() ), 4 );
492 QgsDebugMsgLevel( u"penultimate point: %1 %2"_s.arg( penultimatePt.x() ).arg( penultimatePt.y() ), 4 );
493 //QgsDebugMsgLevel( u"dx: %1 dy: %2"_s.arg( point.x() - previousPt.x() ).arg( point.y() - previousPt.y() ), 4 );
494 //QgsDebugMsgLevel( u"ddx: %1 ddy: %2"_s.arg( previousPt.x() - penultimatePt.x() ).arg( previousPt.y() - penultimatePt.y() ), 4 );
495
496 res.finalMapPoint = point;
497
498 return res;
499}
500
502{
503 QgsDebugMsgLevel( u"Constraints (locked / relative / value"_s, 1 );
504 QgsDebugMsgLevel( u"Angle: %1 %2 %3"_s.arg( angleConstraint.locked ).arg( angleConstraint.relative ).arg( angleConstraint.value ), 1 );
505 QgsDebugMsgLevel( u"Distance: %1 %2 %3"_s.arg( distanceConstraint.locked ).arg( distanceConstraint.relative ).arg( distanceConstraint.value ), 1 );
506 QgsDebugMsgLevel( u"X: %1 %2 %3"_s.arg( xConstraint.locked ).arg( xConstraint.relative ).arg( xConstraint.value ), 1 );
507 QgsDebugMsgLevel( u"Y: %1 %2 %3"_s.arg( yConstraint.locked ).arg( yConstraint.relative ).arg( yConstraint.value ), 1 );
508}
@ AfterVertex
Lock to next vertex.
Definition qgis.h:4180
@ NoVertex
Don't lock to vertex.
Definition qgis.h:4181
@ BeforeVertex
Lock to previous vertex.
Definition qgis.h:4179
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:52
double value
Numeric value of the constraint (coordinate/distance in map units or angle in degrees).
Definition qgscadutils.h:56
bool relative
Whether the value is relative to previous value.
Definition qgscadutils.h:54
Defines constraints for the QgsCadUtils::alignMapPoint() method.
Definition qgscadutils.h:97
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:64
Qgis::LineExtensionSide softLockLineExtension
Definition qgscadutils.h:87
QgsPointXY finalMapPoint
map point aligned according to the constraints
Definition qgscadutils.h:70
bool valid
Whether the combination of constraints is actually valid.
Definition qgscadutils.h:67
QgsPointLocator::Match snapMatch
Snapped point - only valid if actually used for something.
Definition qgscadutils.h:76
QgsPointLocator::Match edgeMatch
Snapped segment - only valid if actually used for something.
Definition qgscadutils.h:82
double softLockCommonAngle
Angle (in degrees) to which we have soft-locked ourselves (if not set it is -1).
Definition qgscadutils.h:85
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.
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:60
QgsGeometry geometry
Definition qgsfeature.h:71
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...
Represents a 2D point.
Definition qgspointxy.h:62
double sqrDist(double x, double y) const
Returns the squared distance between this point a specified x, y coordinate.
Definition qgspointxy.h:189
void setY(double y)
Sets the y value of the point.
Definition qgspointxy.h:132
void set(double x, double y)
Sets the x and y value of the point.
Definition qgspointxy.h:139
double y
Definition qgspointxy.h:66
double x
Definition qgspointxy.h:65
void setX(double x)
Sets the x value of the point.
Definition qgspointxy.h:122
bool isEmpty() const
Returns true if the geometry is empty.
Definition qgspointxy.h:245
Point geometry type, with support for z-dimension and m-values.
Definition qgspoint.h:53
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.
Represent a 2-dimensional vector.
Definition qgsvector.h:34
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference).
Definition qgis.h:6975
#define QgsDebugMsgLevel(str, level)
Definition qgslogger.h:63
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:34
bool isValid() const
Returns true if the vertex id is valid.
Definition qgsvertexid.h:50