QGIS API Documentation 3.99.0-Master (e9821da5c6b)
Loading...
Searching...
No Matches
qgstriangulatedsurface.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgstriangulatedsurface.cpp
3 ---------------------
4 begin : August 2024
5 copyright : (C) 2024 by Jean Felder
6 email : jean dot felder at oslandia dot com
7 ***************************************************************************/
8
9/***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17
19
20#include <memory>
21#include <nlohmann/json.hpp>
22
23#include "qgsgeometryutils.h"
24#include "qgslogger.h"
26#include "qgstriangle.h"
27#include "qgsvertexid.h"
28
29#include <QString>
30
31using namespace Qt::StringLiterals;
32
37
42
44{
45 auto result = std::make_unique< QgsTriangulatedSurface >();
46 result->mWkbType = mWkbType;
47 return result.release();
48}
49
51{
52 return u"TIN"_s;
53}
54
61
62// cppcheck-suppress operatorEqVarError
64{
65 if ( &p != this )
66 {
68 }
69 return *this;
70}
71
76
78{
80 qDeleteAll( mPatches );
81 mPatches.clear();
82 clearCache();
83}
84
85
87{
88 clear();
89
90 if ( !wkbPtr )
91 {
92 return false;
93 }
94
95 Qgis::WkbType type = wkbPtr.readHeader();
97 {
98 return false;
99 }
100 mWkbType = type;
101
102 int nTriangles;
103 wkbPtr >> nTriangles;
104 std::unique_ptr< QgsTriangle > currentTriangle;
105 for ( int i = 0; i < nTriangles; ++i )
106 {
107 Qgis::WkbType triangleType = wkbPtr.readHeader();
108 wkbPtr -= 1 + sizeof( int );
109 Qgis::WkbType flatTriangleType = QgsWkbTypes::flatType( triangleType );
110 if ( flatTriangleType == Qgis::WkbType::Triangle )
111 {
112 currentTriangle = std::make_unique<QgsTriangle>( );
113 }
114 else
115 {
116 return false;
117 }
118 currentTriangle->fromWkb( wkbPtr ); // also updates wkbPtr
119 mPatches.append( currentTriangle.release() );
120 }
121
122 return true;
123}
124
125bool QgsTriangulatedSurface::fromWkt( const QString &wkt )
126{
127 clear();
128
129 QPair<Qgis::WkbType, QString> parts = QgsGeometryUtils::wktReadBlock( wkt );
130
132 return false;
133
134 mWkbType = parts.first;
135
136 QString secondWithoutParentheses = parts.second;
137 secondWithoutParentheses = secondWithoutParentheses.remove( '(' ).remove( ')' ).simplified().remove( ' ' );
138 if ( ( parts.second.compare( "EMPTY"_L1, Qt::CaseInsensitive ) == 0 ) ||
139 secondWithoutParentheses.isEmpty() )
140 return true;
141
142 QString defaultChildWkbType = u"Triangle%1%2"_s.arg( is3D() ? u"Z"_s : QString(), isMeasure() ? u"M"_s : QString() );
143
144 const QStringList blocks = QgsGeometryUtils::wktGetChildBlocks( parts.second, defaultChildWkbType );
145 for ( const QString &childWkt : blocks )
146 {
147 QPair<Qgis::WkbType, QString> childParts = QgsGeometryUtils::wktReadBlock( childWkt );
148
149 if ( QgsWkbTypes::flatType( childParts.first ) == Qgis::WkbType::Triangle )
150 {
151 mPatches.append( new QgsTriangle() );
152 }
153 else
154 {
155 clear();
156 return false;
157 }
158
159 if ( !mPatches.back()->fromWkt( childWkt ) )
160 {
161 clear();
162 return false;
163 }
164 }
165
166 return true;
167}
168
169QDomElement QgsTriangulatedSurface::asGml2( QDomDocument &, int, const QString &, const AxisOrder ) const
170{
171 QgsDebugError( u"gml version 2 does not support TIN geometry"_s );
172 return QDomElement();
173}
174
175QDomElement QgsTriangulatedSurface::asGml3( QDomDocument &doc, int precision, const QString &ns, const QgsAbstractGeometry::AxisOrder axisOrder ) const
176{
177 QDomElement elemTriangulatedSurface = doc.createElementNS( ns, u"TriangulatedSurface"_s );
178
179 if ( isEmpty() )
180 return elemTriangulatedSurface;
181
182 QDomElement elemPatches = doc.createElementNS( ns, u"patches"_s );
183 for ( QgsPolygon *patch : mPatches )
184 {
185 QgsTriangle *triangle = qgsgeometry_cast<QgsTriangle *>( patch );
186 if ( !triangle )
187 continue;
188
189 QDomElement elemTriangle = triangle->asGml3( doc, precision, ns, axisOrder );
190 elemPatches.appendChild( elemTriangle );
191 }
192 elemTriangulatedSurface.appendChild( elemPatches );
193
194 return elemTriangulatedSurface;
195}
196
198{
199 QgsDebugError( u"kml format does not support TIN geometry"_s );
200 return QString( "" );
201}
202
204{
205 for ( QgsPolygon *patch : mPatches )
206 {
207 QgsTriangle *triangle = qgsgeometry_cast<QgsTriangle *>( patch );
208 if ( !triangle )
209 continue;
210
211 QgsCurve *exteriorRing = triangle->exteriorRing();
212 if ( !exteriorRing )
213 continue;
214
215 exteriorRing->normalize();
216 }
217}
218
219QgsTriangulatedSurface *QgsTriangulatedSurface::snappedToGrid( double hSpacing, double vSpacing, double dSpacing, double mSpacing, bool removeRedundantPoints ) const
220{
221 std::unique_ptr< QgsTriangulatedSurface > surface( createEmptyWithSameType() );
222
223 for ( QgsPolygon *patch : mPatches )
224 {
225 QgsTriangle *triangle = qgsgeometry_cast<QgsTriangle *>( patch );
226 if ( !triangle )
227 continue;
228
229 std::unique_ptr<QgsCurve> exteriorRing( qgsgeometry_cast< QgsCurve *>( triangle->exteriorRing()->snappedToGrid( hSpacing, vSpacing, dSpacing, mSpacing, removeRedundantPoints ) ) );
230 if ( !exteriorRing )
231 {
232 return nullptr;
233 }
234
235 auto gridifiedTriangle = std::make_unique<QgsTriangle>();
236 gridifiedTriangle->setExteriorRing( exteriorRing.release() );
237 surface->addPatch( gridifiedTriangle.release() );
238 }
239
240 return surface.release();
241}
242
243void QgsTriangulatedSurface::setTriangles( const QVector<QgsTriangle *> &triangles )
244{
245 qDeleteAll( mPatches );
246 mPatches.clear();
247
248 for ( QgsTriangle *triangle : triangles )
249 {
250 addPatch( triangle );
251 }
252
253 clearCache();
254}
255
257{
258 QgsTriangle *triangle = qgsgeometry_cast<QgsTriangle *>( patch );
259 if ( !triangle )
260 {
261 if ( patch )
262 {
263 delete patch;
264 }
265 return;
266 }
267
268 if ( mPatches.empty() )
269 {
271 }
272
273 // Ensure dimensionality of patch matches TIN
274 if ( !is3D() )
275 triangle->dropZValue();
276 else if ( !triangle->is3D() )
277 triangle->addZValue();
278
279 if ( !isMeasure() )
280 triangle->dropMValue();
281 else if ( !triangle->isMeasure() )
282 triangle->addMValue();
283
284 mPatches.append( triangle );
285 clearCache();
286}
287
289{
290 addPatch( triangle );
291}
292
297
299{
301}
302
304{
305 Q_UNUSED( vId )
306 Q_UNUSED( vertex )
307 return false;
308}
309
311{
312 Q_UNUSED( vId )
313 return false;
314}
315
317{
318 const QgsTriangulatedSurface *otherTriangulatedSurface = qgsgeometry_cast<const QgsTriangulatedSurface *>( other );
319 if ( !otherTriangulatedSurface )
320 return -1;
321
322 const int nTriangles1 = mPatches.size();
323 const int nTriangles2 = otherTriangulatedSurface->mPatches.size();
324 if ( nTriangles1 < nTriangles2 )
325 {
326 return -1;
327 }
328 if ( nTriangles1 > nTriangles2 )
329 {
330 return 1;
331 }
332
333 for ( int i = 0; i < nTriangles1; i++ )
334 {
335 const int triangleComp = mPatches.at( i )->compareTo( otherTriangulatedSurface->mPatches.at( i ) );
336 if ( triangleComp != 0 )
337 {
338 return triangleComp;
339 }
340 }
341
342 return 0;
343}
@ Polygon
Polygons.
Definition qgis.h:368
WkbType
The WKB type describes the number of dimensions a geometry has.
Definition qgis.h:280
@ TIN
TIN.
Definition qgis.h:296
@ Triangle
Triangle.
Definition qgis.h:285
virtual QgsAbstractGeometry * snappedToGrid(double hSpacing, double vSpacing, double dSpacing=0, double mSpacing=0, bool removeRedundantPoints=false) const =0
Makes a new geometry with all the points or vertices snapped to the closest point of the grid.
bool isMeasure() const
Returns true if the geometry contains m values.
bool is3D() const
Returns true if the geometry is 3D and contains a z-value.
AxisOrder
Axis order for GML generation.
void setZMTypeFromSubGeometry(const QgsAbstractGeometry *subggeom, Qgis::WkbType baseGeomType)
Updates the geometry type based on whether sub geometries contain z or m values.
QgsAbstractGeometry()=default
QgsGeometryConstPartIterator parts() const
Returns Java-style iterator for traversal of parts of the geometry.
A const WKB pointer.
Definition qgswkbptr.h:139
Qgis::WkbType readHeader() const
readHeader
Definition qgswkbptr.cpp:60
bool addZValue(double zValue=0) override
Adds a z-dimension to the geometry, initialized to a preset value.
const QgsCurve * exteriorRing() const
Returns the curve polygon's exterior ring.
bool addMValue(double mValue=0) override
Adds a measure to the geometry, initialized to a preset value.
bool dropZValue() override
Drops any z-dimensions which exist in the geometry.
bool dropMValue() override
Drops any measure values which exist in the geometry.
Abstract base class for curved geometry type.
Definition qgscurve.h:36
void normalize() final
Reorganizes the geometry into a normalized form (or "canonical" form).
Definition qgscurve.cpp:212
static QStringList wktGetChildBlocks(const QString &wkt, const QString &defaultType=QString())
Parses a WKT string and returns of list of blocks contained in the WKT.
static QPair< Qgis::WkbType, QString > wktReadBlock(const QString &wkt)
Parses a WKT block of the format "TYPE( contents )" and returns a pair of geometry type to contents (...
Point geometry type, with support for z-dimension and m-values.
Definition qgspoint.h:53
Polygon geometry type.
Definition qgspolygon.h:37
QVector< QgsPolygon * > mPatches
bool isEmpty() const override
Returns true if the geometry is empty.
const QgsPolygon * patchN(int i) const
Retrieves a patch from the polyhedral surface.
QgsPolyhedralSurface & operator=(const QgsPolyhedralSurface &p)
void clearCache() const override
Clears any cached parameters associated with the geometry, e.g., bounding boxes.
Triangle geometry type.
Definition qgstriangle.h:33
QDomElement asGml3(QDomDocument &doc, int precision=17, const QString &ns="gml", QgsAbstractGeometry::AxisOrder axisOrder=QgsAbstractGeometry::AxisOrder::XY) const override
Returns a GML3 representation of the geometry.
bool fromWkt(const QString &wkt) override
Sets the geometry from a WKT string.
QDomElement asGml3(QDomDocument &doc, int precision=17, const QString &ns="gml", QgsAbstractGeometry::AxisOrder axisOrder=QgsAbstractGeometry::AxisOrder::XY) const override
Returns a GML3 representation of the geometry.
void clear() override
Clears the geometry, ie reset it to a null geometry.
bool insertVertex(QgsVertexId position, const QgsPoint &vertex) override
Inserts a vertex into the geometry.
QString asKml(int precision=17) const override
Returns a KML representation of the geometry.
void setTriangles(const QVector< QgsTriangle * > &triangles)
Sets all triangles, transferring ownership to the polyhedral surface.
void addTriangle(QgsTriangle *triangle)
Adds a triangle to the geometry, transferring ownership to the polyhedral surface.
QgsTriangulatedSurface * createEmptyWithSameType() const override
Creates a new geometry with the same class and same WKB type as the original and transfers ownership.
QgsTriangle * triangleN(int index)
Returns the triangle with the specified index.
bool deleteVertex(QgsVertexId position) override
Deletes a vertex within the geometry.
void addPatch(QgsPolygon *patch) override
Adds a patch to the geometry, transferring ownership to the polyhedral surface.
QgsTriangulatedSurface * clone() const override
Clones the geometry by performing a deep copy.
QgsTriangulatedSurface * snappedToGrid(double hSpacing, double vSpacing, double dSpacing=0, double mSpacing=0, bool removeRedundantPoints=false) const override
Makes a new geometry with all the points or vertices snapped to the closest point of the grid.
QDomElement asGml2(QDomDocument &doc, int precision=17, const QString &ns="gml", QgsAbstractGeometry::AxisOrder axisOrder=QgsAbstractGeometry::AxisOrder::XY) const override
Returns a GML2 representation of the geometry.
QString geometryType() const override
Returns a unique string representing the geometry type.
int compareToSameClass(const QgsAbstractGeometry *other) const final
Compares to an other geometry of the same class, and returns a integer for sorting of the two geometr...
void normalize() override
Reorganizes the geometry into a normalized form (or "canonical" form).
bool fromWkb(QgsConstWkbPtr &wkb) override
Sets the geometry from a WKB string.
QgsTriangulatedSurface & operator=(const QgsTriangulatedSurface &p)
static Qgis::GeometryType geometryType(Qgis::WkbType type)
Returns the geometry type for a WKB type, e.g., both MultiPolygon and CurvePolygon would have a Polyg...
static Qgis::WkbType flatType(Qgis::WkbType type)
Returns the flat type for a WKB type.
T qgsgeometry_cast(QgsAbstractGeometry *geom)
#define QgsDebugError(str)
Definition qgslogger.h:59
Utility class for identifying a unique vertex within a geometry.
Definition qgsvertexid.h:34