/
qgsgeos.h
435 lines (376 loc) · 19.9 KB
/
qgsgeos.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
/***************************************************************************
qgsgeos.h
-------------------------------------------------------------------
Date : 22 Sept 2014
Copyright : (C) 2014 by Marco Hugentobler
email : marco.hugentobler at sourcepole dot com
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#ifndef QGSGEOS_H
#define QGSGEOS_H
#define SIP_NO_FILE
#include "qgis_core.h"
#include "qgsgeometryengine.h"
#include "qgsgeometry.h"
#include <geos_c.h>
#if defined(GEOS_VERSION_MAJOR) && (GEOS_VERSION_MAJOR<3)
#define GEOSGeometry struct GEOSGeom_t
#define GEOSCoordSequence struct GEOSCoordSeq_t
#endif
class QgsLineString;
class QgsPolygon;
class QgsGeometry;
class QgsGeometryCollection;
/**
* Contains geos related utilities and functions.
* \note not available in Python bindings.
* \since QGIS 3.0
*/
namespace geos
{
/**
* Destroys the GEOS geometry \a geom, using the static QGIS
* geos context.
*/
struct GeosDeleter
{
/**
* Destroys the GEOS geometry \a geom, using the static QGIS
* geos context.
*/
void CORE_EXPORT operator()( GEOSGeometry *geom );
/**
* Destroys the GEOS prepared geometry \a geom, using the static QGIS
* geos context.
*/
void CORE_EXPORT operator()( const GEOSPreparedGeometry *geom );
/**
* Destroys the GEOS buffer params \a params, using the static QGIS
* geos context.
*/
void CORE_EXPORT operator()( GEOSBufferParams *params );
/**
* Destroys the GEOS coordinate sequence \a sequence, using the static QGIS
* geos context.
*/
void CORE_EXPORT operator()( GEOSCoordSequence *sequence );
};
/**
* Scoped GEOS pointer.
*/
using unique_ptr = std::unique_ptr< GEOSGeometry, GeosDeleter>;
/**
* Scoped GEOS prepared geometry pointer.
*/
using prepared_unique_ptr = std::unique_ptr< const GEOSPreparedGeometry, GeosDeleter>;
/**
* Scoped GEOS buffer params pointer.
*/
using buffer_params_unique_ptr = std::unique_ptr< GEOSBufferParams, GeosDeleter>;
/**
* Scoped GEOS coordinate sequence pointer.
*/
using coord_sequence_unique_ptr = std::unique_ptr< GEOSCoordSequence, GeosDeleter>;
}
/**
* \ingroup core
* Does vector analysis using the geos library and handles import, export, exception handling*
* \note not available in Python bindings
*/
class CORE_EXPORT QgsGeos: public QgsGeometryEngine
{
public:
/**
* GEOS geometry engine constructor
* \param geometry The geometry
* \param precision The precision of the grid to which to snap the geometry vertices. If 0, no snapping is performed.
*/
QgsGeos( const QgsAbstractGeometry *geometry, double precision = 0 );
/**
* Creates a new QgsGeometry object, feeding in a geometry in GEOS format.
* This class will take ownership of the buffer.
*/
static QgsGeometry geometryFromGeos( GEOSGeometry *geos );
/**
* Creates a new QgsGeometry object, feeding in a geometry in GEOS format.
*/
static QgsGeometry geometryFromGeos( const geos::unique_ptr &geos );
/**
* Adds a new island polygon to a multipolygon feature
* \param geometry geometry to add part to
* \param newPart part to add. Ownership is NOT transferred.
* \returns OperationResult a result code: success or reason of failure
*/
static QgsGeometry::OperationResult addPart( QgsGeometry &geometry, GEOSGeometry *newPart );
void geometryChanged() override;
void prepareGeometry() override;
QgsAbstractGeometry *intersection( const QgsAbstractGeometry *geom, QString *errorMsg = nullptr ) const override;
QgsAbstractGeometry *difference( const QgsAbstractGeometry *geom, QString *errorMsg = nullptr ) const override;
/**
* Performs a fast, non-robust intersection between the geometry and
* a \a rectangle. The returned geometry may be invalid.
*/
std::unique_ptr< QgsAbstractGeometry > clip( const QgsRectangle &rectangle, QString *errorMsg = nullptr ) const;
/**
* Subdivides the geometry. The returned geometry will be a collection containing subdivided parts
* from the original geometry, where no part has more then the specified maximum number of nodes (\a maxNodes).
*
* This is useful for dividing a complex geometry into less complex parts, which are better able to be spatially
* indexed and faster to perform further operations such as intersects on. The returned geometry parts may
* not be valid and may contain self-intersections.
*
* The minimum allowed value for \a maxNodes is 8.
*
* Curved geometries are not supported.
*
* \since QGIS 3.0
*/
std::unique_ptr< QgsAbstractGeometry > subdivide( int maxNodes, QString *errorMsg = nullptr ) const;
QgsAbstractGeometry *combine( const QgsAbstractGeometry *geom, QString *errorMsg = nullptr ) const override;
QgsAbstractGeometry *combine( const QVector<QgsAbstractGeometry *> &geomList, QString *errorMsg ) const override;
QgsAbstractGeometry *combine( const QVector< QgsGeometry > &, QString *errorMsg = nullptr ) const override;
QgsAbstractGeometry *symDifference( const QgsAbstractGeometry *geom, QString *errorMsg = nullptr ) const override;
QgsAbstractGeometry *buffer( double distance, int segments, QString *errorMsg = nullptr ) const override;
QgsAbstractGeometry *buffer( double distance, int segments, int endCapStyle, int joinStyle, double miterLimit, QString *errorMsg = nullptr ) const override;
QgsAbstractGeometry *simplify( double tolerance, QString *errorMsg = nullptr ) const override;
QgsAbstractGeometry *interpolate( double distance, QString *errorMsg = nullptr ) const override;
QgsAbstractGeometry *envelope( QString *errorMsg = nullptr ) const override;
QgsPoint *centroid( QString *errorMsg = nullptr ) const override;
QgsPoint *pointOnSurface( QString *errorMsg = nullptr ) const override;
QgsAbstractGeometry *convexHull( QString *errorMsg = nullptr ) const override;
double distance( const QgsAbstractGeometry *geom, QString *errorMsg = nullptr ) const override;
/**
* Returns the Hausdorff distance between this geometry and \a geom. This is basically a measure of how similar or dissimilar 2 geometries are.
*
* This algorithm is an approximation to the standard Hausdorff distance. This approximation is exact or close enough for a large
* subset of useful cases. Examples of these are:
*
* - computing distance between Linestrings that are roughly parallel to each other,
* and roughly equal in length. This occurs in matching linear networks.
* - Testing similarity of geometries.
*
* If the default approximate provided by this method is insufficient, use hausdorffDistanceDensify() instead.
*
* \see hausdorffDistanceDensify()
* \since QGIS 3.0
*/
double hausdorffDistance( const QgsAbstractGeometry *geom, QString *errorMsg = nullptr ) const;
/**
* Returns the Hausdorff distance between this geometry and \a geom. This is basically a measure of how similar or dissimilar 2 geometries are.
*
* This function accepts a \a densifyFraction argument. The function performs a segment
* densification before computing the discrete Hausdorff distance. The \a densifyFraction parameter
* sets the fraction by which to densify each segment. Each segment will be split into a
* number of equal-length subsegments, whose fraction of the total length is
* closest to the given fraction.
*
* This method can be used when the default approximation provided by hausdorffDistance()
* is not sufficient. Decreasing the \a densifyFraction parameter will make the
* distance returned approach the true Hausdorff distance for the geometries.
*
* \see hausdorffDistance()
* \since QGIS 3.0
*/
double hausdorffDistanceDensify( const QgsAbstractGeometry *geom, double densifyFraction, QString *errorMsg = nullptr ) const;
bool intersects( const QgsAbstractGeometry *geom, QString *errorMsg = nullptr ) const override;
bool touches( const QgsAbstractGeometry *geom, QString *errorMsg = nullptr ) const override;
bool crosses( const QgsAbstractGeometry *geom, QString *errorMsg = nullptr ) const override;
bool within( const QgsAbstractGeometry *geom, QString *errorMsg = nullptr ) const override;
bool overlaps( const QgsAbstractGeometry *geom, QString *errorMsg = nullptr ) const override;
bool contains( const QgsAbstractGeometry *geom, QString *errorMsg = nullptr ) const override;
bool disjoint( const QgsAbstractGeometry *geom, QString *errorMsg = nullptr ) const override;
QString relate( const QgsAbstractGeometry *geom, QString *errorMsg = nullptr ) const override;
bool relatePattern( const QgsAbstractGeometry *geom, const QString &pattern, QString *errorMsg = nullptr ) const override;
double area( QString *errorMsg = nullptr ) const override;
double length( QString *errorMsg = nullptr ) const override;
bool isValid( QString *errorMsg = nullptr, bool allowSelfTouchingHoles = false ) const override;
bool isEqual( const QgsAbstractGeometry *geom, QString *errorMsg = nullptr ) const override;
bool isEmpty( QString *errorMsg = nullptr ) const override;
bool isSimple( QString *errorMsg = nullptr ) const override;
EngineOperationResult splitGeometry( const QgsLineString &splitLine,
QVector<QgsGeometry> &newGeometries,
bool topological,
QgsPointSequence &topologyTestPoints,
QString *errorMsg = nullptr ) const override;
QgsAbstractGeometry *offsetCurve( double distance, int segments, int joinStyle, double miterLimit, QString *errorMsg = nullptr ) const override;
/**
* Returns a single sided buffer for a geometry. The buffer is only
* applied to one side of the geometry.
* \param distance buffer distance
* \param segments for round joins, number of segments to approximate quarter-circle
* \param side side of geometry to buffer (0 = left, 1 = right)
* \param joinStyle join style for corners ( Round (1) / Miter (2) / Bevel (3) )
* \param miterLimit limit on the miter ratio used for very sharp corners
* \param errorMsg error messages emitted, if any
* \returns buffered geometry, or an nullptr if buffer could not be
* calculated
* \since QGIS 3.0
*/
std::unique_ptr< QgsAbstractGeometry > singleSidedBuffer( double distance, int segments, int side,
int joinStyle, double miterLimit,
QString *errorMsg = nullptr ) const;
/**
* Reshapes the geometry using a line
* \param reshapeWithLine the line used to reshape lines or polygons
* \param errorCode if specified, provides result of operation (success or reason of failure)
* \param errorMsg if specified, provides more details about failure
* \return the reshaped geometry
*/
std::unique_ptr< QgsAbstractGeometry > reshapeGeometry( const QgsLineString &reshapeWithLine, EngineOperationResult *errorCode, QString *errorMsg = nullptr ) const;
/**
* Merges any connected lines in a LineString/MultiLineString geometry and
* converts them to single line strings.
* \param errorMsg if specified, will be set to any reported GEOS errors
* \returns a LineString or MultiLineString geometry, with any connected lines
* joined. An empty geometry will be returned if the input geometry was not a
* LineString/MultiLineString geometry.
* \since QGIS 3.0
*/
QgsGeometry mergeLines( QString *errorMsg = nullptr ) const;
/**
* Returns the closest point on the geometry to the other geometry.
* \see shortestLine()
* \since QGIS 2.14
*/
QgsGeometry closestPoint( const QgsGeometry &other, QString *errorMsg = nullptr ) const;
/**
* Returns the shortest line joining this geometry to the other geometry.
* \see closestPoint()
* \since QGIS 2.14
*/
QgsGeometry shortestLine( const QgsGeometry &other, QString *errorMsg = nullptr ) const;
/**
* Returns a distance representing the location along this linestring of the closest point
* on this linestring geometry to the specified point. Ie, the returned value indicates
* how far along this linestring you need to traverse to get to the closest location
* where this linestring comes to the specified point.
* \param point point to seek proximity to
* \param errorMsg error messages emitted, if any
* \returns distance along line, or -1 on error
* \note only valid for linestring geometries
*/
double lineLocatePoint( const QgsPoint &point, QString *errorMsg = nullptr ) const;
/**
* Creates a GeometryCollection geometry containing possible polygons formed from the constituent
* linework of a set of \a geometries. The input geometries must be fully noded (i.e. nodes exist
* at every common intersection of the geometries). The easiest way to ensure this is to first
* unary union these geometries by calling combine() on the set of input geometries and then
* pass the result to polygonize().
* An empty geometry will be returned in the case of errors.
* \since QGIS 3.0
*/
static QgsGeometry polygonize( const QVector<const QgsAbstractGeometry *> &geometries, QString *errorMsg = nullptr );
/**
* Creates a Voronoi diagram for the nodes contained within the geometry.
*
* Returns the Voronoi polygons for the nodes contained within the geometry.
* If \a extent is specified then it will be used as a clipping envelope for the diagram.
* If no extent is set then the clipping envelope will be automatically calculated.
* In either case the diagram will be clipped to the larger of the provided envelope
* OR the envelope surrounding all input nodes.
* The \a tolerance parameter specifies an optional snapping tolerance which can
* be used to improve the robustness of the diagram calculation.
* If \a edgesOnly is true than line string boundary geometries will be returned
* instead of polygons.
* An empty geometry will be returned if the diagram could not be calculated.
* \since QGIS 3.0
*/
QgsGeometry voronoiDiagram( const QgsAbstractGeometry *extent = nullptr, double tolerance = 0.0, bool edgesOnly = false, QString *errorMsg = nullptr ) const;
/**
* Returns the Delaunay triangulation for the vertices of the geometry.
* The \a tolerance parameter specifies an optional snapping tolerance which can
* be used to improve the robustness of the triangulation.
* If \a edgesOnly is true than line string boundary geometries will be returned
* instead of polygons.
* An empty geometry will be returned if the diagram could not be calculated.
* \since QGIS 3.0
*/
QgsGeometry delaunayTriangulation( double tolerance = 0.0, bool edgesOnly = false, QString *errorMsg = nullptr ) const;
/**
* Create a geometry from a GEOSGeometry
* \param geos GEOSGeometry. Ownership is NOT transferred.
*/
static std::unique_ptr< QgsAbstractGeometry > fromGeos( const GEOSGeometry *geos );
static std::unique_ptr< QgsPolygon > fromGeosPolygon( const GEOSGeometry *geos );
/**
* Returns a geos geometry - caller takes ownership of the object (should be deleted with GEOSGeom_destroy_r)
* \param geometry geometry to convert to GEOS representation
* \param precision The precision of the grid to which to snap the geometry vertices. If 0, no snapping is performed.
*/
static geos::unique_ptr asGeos( const QgsGeometry &geometry, double precision = 0 );
/**
* Returns a geos geometry - caller takes ownership of the object (should be deleted with GEOSGeom_destroy_r)
* \param geometry geometry to convert to GEOS representation
* \param precision The precision of the grid to which to snap the geometry vertices. If 0, no snapping is performed.
*/
static geos::unique_ptr asGeos( const QgsAbstractGeometry *geometry, double precision = 0 );
static QgsPoint coordSeqPoint( const GEOSCoordSequence *cs, int i, bool hasZ, bool hasM );
static GEOSContextHandle_t getGEOSHandler();
private:
mutable geos::unique_ptr mGeos;
geos::prepared_unique_ptr mGeosPrepared;
double mPrecision = 0.0;
enum Overlay
{
OverlayIntersection,
OverlayDifference,
OverlayUnion,
OverlaySymDifference
};
enum Relation
{
RelationIntersects,
RelationTouches,
RelationCrosses,
RelationWithin,
RelationOverlaps,
RelationContains,
RelationDisjoint
};
//geos util functions
void cacheGeos() const;
std::unique_ptr< QgsAbstractGeometry > overlay( const QgsAbstractGeometry *geom, Overlay op, QString *errorMsg = nullptr ) const;
bool relation( const QgsAbstractGeometry *geom, Relation r, QString *errorMsg = nullptr ) const;
static GEOSCoordSequence *createCoordinateSequence( const QgsCurve *curve, double precision, bool forceClose = false );
static std::unique_ptr< QgsLineString > sequenceToLinestring( const GEOSGeometry *geos, bool hasZ, bool hasM );
static int numberOfGeometries( GEOSGeometry *g );
static geos::unique_ptr nodeGeometries( const GEOSGeometry *splitLine, const GEOSGeometry *geom );
int mergeGeometriesMultiTypeSplit( QVector<GEOSGeometry *> &splitResult ) const;
/**
* Ownership of geoms is transferred
*/
static geos::unique_ptr createGeosCollection( int typeId, const QVector<GEOSGeometry *> &geoms );
static geos::unique_ptr createGeosPointXY( double x, double y, bool hasZ, double z, bool hasM, double m, int coordDims, double precision );
static geos::unique_ptr createGeosPoint( const QgsAbstractGeometry *point, int coordDims, double precision );
static geos::unique_ptr createGeosLinestring( const QgsAbstractGeometry *curve, double precision );
static geos::unique_ptr createGeosPolygon( const QgsAbstractGeometry *poly, double precision );
//utils for geometry split
bool topologicalTestPointsSplit( const GEOSGeometry *splitLine, QgsPointSequence &testPoints, QString *errorMsg = nullptr ) const;
geos::unique_ptr linePointDifference( GEOSGeometry *GEOSsplitPoint ) const;
EngineOperationResult splitLinearGeometry( GEOSGeometry *splitLine, QVector<QgsGeometry > &newGeometries ) const;
EngineOperationResult splitPolygonGeometry( GEOSGeometry *splitLine, QVector<QgsGeometry > &newGeometries ) const;
//utils for reshape
static geos::unique_ptr reshapeLine( const GEOSGeometry *line, const GEOSGeometry *reshapeLineGeos, double precision );
static geos::unique_ptr reshapePolygon( const GEOSGeometry *polygon, const GEOSGeometry *reshapeLineGeos, double precision );
static int lineContainedInLine( const GEOSGeometry *line1, const GEOSGeometry *line2 );
static int pointContainedInLine( const GEOSGeometry *point, const GEOSGeometry *line );
static int geomDigits( const GEOSGeometry *geom );
void subdivideRecursive( const GEOSGeometry *currentPart, int maxNodes, int depth, QgsGeometryCollection *parts, const QgsRectangle &clipRect ) const;
};
/// @cond PRIVATE
class GEOSException : public std::runtime_error
{
public:
explicit GEOSException( const QString &message )
: std::runtime_error( message.toUtf8().constData() )
{
}
};
/// @endcond
#endif // QGSGEOS_H