QGIS API Documentation 3.39.0-Master (d85f3c2a281)
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
20#include "qgslogger.h"
21#include "qgstriangle.h"
22#include "qgsvertexid.h"
23#include "qgsgeometryutils.h"
24
25#include <memory>
26#include <nlohmann/json.hpp>
27
32
37
39{
40 auto result = std::make_unique< QgsTriangulatedSurface >();
41 result->mWkbType = mWkbType;
42 return result.release();
43}
44
46{
47 return QStringLiteral( "TIN" );
48}
49
56
57// cppcheck-suppress operatorEqVarError
59{
60 if ( &p != this )
61 {
63 }
64 return *this;
65}
66
71
73{
75 qDeleteAll( mPatches );
76 mPatches.clear();
77 clearCache();
78}
79
80
82{
83 clear();
84
85 if ( !wkbPtr )
86 {
87 return false;
88 }
89
90 Qgis::WkbType type = wkbPtr.readHeader();
92 {
93 return false;
94 }
95 mWkbType = type;
96
97 int nTriangles;
98 wkbPtr >> nTriangles;
99 std::unique_ptr< QgsTriangle > currentTriangle;
100 for ( int i = 0; i < nTriangles; ++i )
101 {
102 Qgis::WkbType triangleType = wkbPtr.readHeader();
103 wkbPtr -= 1 + sizeof( int );
104 Qgis::WkbType flatTriangleType = QgsWkbTypes::flatType( triangleType );
105 if ( flatTriangleType == Qgis::WkbType::Triangle )
106 {
107 currentTriangle.reset( new QgsTriangle() );
108 }
109 else
110 {
111 return false;
112 }
113 currentTriangle->fromWkb( wkbPtr ); // also updates wkbPtr
114 mPatches.append( currentTriangle.release() );
115 }
116
117 return true;
118}
119
120bool QgsTriangulatedSurface::fromWkt( const QString &wkt )
121{
122 clear();
123
124 QPair<Qgis::WkbType, QString> parts = QgsGeometryUtils::wktReadBlock( wkt );
125
127 return false;
128
129 mWkbType = parts.first;
130
131 QString secondWithoutParentheses = parts.second;
132 secondWithoutParentheses = secondWithoutParentheses.remove( '(' ).remove( ')' ).simplified().remove( ' ' );
133 if ( ( parts.second.compare( QLatin1String( "EMPTY" ), Qt::CaseInsensitive ) == 0 ) ||
134 secondWithoutParentheses.isEmpty() )
135 return true;
136
137 QString defaultChildWkbType = QStringLiteral( "Triangle%1%2" ).arg( is3D() ? QStringLiteral( "Z" ) : QString(), isMeasure() ? QStringLiteral( "M" ) : QString() );
138
139 const QStringList blocks = QgsGeometryUtils::wktGetChildBlocks( parts.second, defaultChildWkbType );
140 for ( const QString &childWkt : blocks )
141 {
142 QPair<Qgis::WkbType, QString> childParts = QgsGeometryUtils::wktReadBlock( childWkt );
143
144 if ( QgsWkbTypes::flatType( childParts.first ) == Qgis::WkbType::Triangle )
145 {
146 mPatches.append( new QgsTriangle() );
147 }
148 else
149 {
150 clear();
151 return false;
152 }
153
154 if ( !mPatches.back()->fromWkt( childWkt ) )
155 {
156 clear();
157 return false;
158 }
159 }
160
161 return true;
162}
163
164QDomElement QgsTriangulatedSurface::asGml2( QDomDocument &, int, const QString &, const AxisOrder ) const
165{
166 QgsDebugError( QStringLiteral( "gml version 2 does not support TIN geometry" ) );
167 return QDomElement();
168}
169
170QDomElement QgsTriangulatedSurface::asGml3( QDomDocument &doc, int precision, const QString &ns, const QgsAbstractGeometry::AxisOrder axisOrder ) const
171{
172 QDomElement elemTriangulatedSurface = doc.createElementNS( ns, QStringLiteral( "TriangulatedSurface" ) );
173
174 if ( isEmpty() )
175 return elemTriangulatedSurface;
176
177 QDomElement elemPatches = doc.createElementNS( ns, QStringLiteral( "patches" ) );
178 for ( QgsPolygon *patch : mPatches )
179 {
180 QgsTriangle *triangle = qgsgeometry_cast<QgsTriangle *>( patch );
181 if ( !triangle )
182 continue;
183
184 QDomElement elemTriangle = triangle->asGml3( doc, precision, ns, axisOrder );
185 elemPatches.appendChild( elemTriangle );
186 }
187 elemTriangulatedSurface.appendChild( elemPatches );
188
189 return elemTriangulatedSurface;
190}
191
193{
194 QgsDebugError( QStringLiteral( "kml format does not support TIN geometry" ) );
195 return QString( "" );
196}
197
199{
200 for ( QgsPolygon *patch : mPatches )
201 {
202 QgsTriangle *triangle = qgsgeometry_cast<QgsTriangle *>( patch );
203 if ( !triangle )
204 continue;
205
206 QgsCurve *exteriorRing = triangle->exteriorRing();
207 if ( !exteriorRing )
208 continue;
209
210 exteriorRing->normalize();
211 }
212}
213
214QgsTriangulatedSurface *QgsTriangulatedSurface::snappedToGrid( double hSpacing, double vSpacing, double dSpacing, double mSpacing, bool removeRedundantPoints ) const
215{
216 std::unique_ptr< QgsTriangulatedSurface > surface( createEmptyWithSameType() );
217
218 for ( QgsPolygon *patch : mPatches )
219 {
220 QgsTriangle *triangle = qgsgeometry_cast<QgsTriangle *>( patch );
221 if ( !triangle )
222 continue;
223
224 std::unique_ptr<QgsCurve> exteriorRing( qgsgeometry_cast< QgsCurve *>( triangle->exteriorRing()->snappedToGrid( hSpacing, vSpacing, dSpacing, mSpacing, removeRedundantPoints ) ) );
225 if ( !exteriorRing )
226 {
227 return nullptr;
228 }
229
230 std::unique_ptr<QgsTriangle> gridifiedTriangle = std::make_unique<QgsTriangle>();
231 gridifiedTriangle->setExteriorRing( exteriorRing.release() );
232 surface->addPatch( gridifiedTriangle.release() );
233 }
234
235 return surface.release();
236}
237
238void QgsTriangulatedSurface::setTriangles( const QVector<QgsTriangle *> &triangles )
239{
240 qDeleteAll( mPatches );
241 mPatches.clear();
242
243 for ( QgsTriangle *triangle : triangles )
244 {
245 addPatch( triangle );
246 }
247
248 clearCache();
249}
250
252{
253 QgsTriangle *triangle = qgsgeometry_cast<QgsTriangle *>( patch );
254 if ( !triangle )
255 {
256 if ( patch )
257 {
258 delete patch;
259 }
260 return;
261 }
262
263 if ( mPatches.empty() )
264 {
266 }
267
268 // Ensure dimensionality of patch matches TIN
269 if ( !is3D() )
270 triangle->dropZValue();
271 else if ( !triangle->is3D() )
272 triangle->addZValue();
273
274 if ( !isMeasure() )
275 triangle->dropMValue();
276 else if ( !triangle->isMeasure() )
277 triangle->addMValue();
278
279 mPatches.append( triangle );
280 clearCache();
281}
282
284{
285 addPatch( triangle );
286}
287
289{
290 return qgsgeometry_cast< QgsTriangle * >( patchN( index ) );
291}
292
294{
295 return qgsgeometry_cast< const QgsTriangle * >( patchN( index ) );
296}
297
299{
300 Q_UNUSED( vId )
301 Q_UNUSED( vertex )
302 return false;
303}
304
306{
307 Q_UNUSED( vId )
308 return false;
309}
310
312{
313 const QgsTriangulatedSurface *otherTriangulatedSurface = qgsgeometry_cast<const QgsTriangulatedSurface *>( other );
314 if ( !otherTriangulatedSurface )
315 return -1;
316
317 const int nTriangles1 = mPatches.size();
318 const int nTriangles2 = otherTriangulatedSurface->mPatches.size();
319 if ( nTriangles1 < nTriangles2 )
320 {
321 return -1;
322 }
323 if ( nTriangles1 > nTriangles2 )
324 {
325 return 1;
326 }
327
328 for ( int i = 0; i < nTriangles1; i++ )
329 {
330 const int triangleComp = mPatches.at( i )->compareTo( otherTriangulatedSurface->mPatches.at( i ) );
331 if ( triangleComp != 0 )
332 {
333 return triangleComp;
334 }
335 }
336
337 return 0;
338}
@ Polygon
Polygons.
WkbType
The WKB type describes the number of dimensions a geometry has.
Definition qgis.h:256
@ Triangle
Triangle.
Abstract base class for all geometries.
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.
QgsGeometryConstPartIterator parts() const
Returns Java-style iterator for traversal of parts of the geometry.
A const WKB pointer.
Definition qgswkbptr.h:138
Qgis::WkbType readHeader() const
readHeader
Definition qgswkbptr.cpp:55
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:35
void normalize() final
Reorganizes the geometry into a normalized form (or "canonical" form).
Definition qgscurve.cpp:211
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:49
Polygon geometry type.
Definition qgspolygon.h:33
Polyhedral surface geometry type.
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.
Triangulated surface geometry type.
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.
#define QgsDebugError(str)
Definition qgslogger.h:38
int precision
Utility class for identifying a unique vertex within a geometry.
Definition qgsvertexid.h:30