QGIS API Documentation 3.43.0-Master (37eec98dbf6)
qgsline3dsymbol_p.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsline3dsymbol_p.cpp
3 --------------------------------------
4 Date : July 2017
5 Copyright : (C) 2017 by Martin Dobias
6 Email : wonder dot sk at gmail dot com
7 ***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15
16#include "qgsline3dsymbol_p.h"
17
18#include "qgsgeotransform.h"
19#include "qgsline3dsymbol.h"
20#include "qgslinematerial_p.h"
21#include "qgslinevertexdata_p.h"
23#include "qgstessellator.h"
24#include "qgs3dmapsettings.h"
25//#include "qgsterraingenerator.h"
26#include "qgs3dutils.h"
27
28#include "qgsvectorlayer.h"
29#include "qgsmultilinestring.h"
30#include "qgsmultipolygon.h"
31#include "qgsgeos.h"
33#include "qgspolygon.h"
35#include "qgsmessagelog.h"
36
37#include <Qt3DCore/QTransform>
38#include <Qt3DExtras/QPhongMaterial>
39#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
40#include <Qt3DRender/QAttribute>
41#include <Qt3DRender/QBuffer>
42
43typedef Qt3DRender::QAttribute Qt3DQAttribute;
44typedef Qt3DRender::QBuffer Qt3DQBuffer;
45typedef Qt3DRender::QGeometry Qt3DQGeometry;
46#else
47#include <Qt3DCore/QAttribute>
48#include <Qt3DCore/QBuffer>
49
50typedef Qt3DCore::QAttribute Qt3DQAttribute;
51typedef Qt3DCore::QBuffer Qt3DQBuffer;
52typedef Qt3DCore::QGeometry Qt3DQGeometry;
53#endif
54#include <Qt3DRender/QGeometryRenderer>
55
57
58// -----------
59
60
61class QgsBufferedLine3DSymbolHandler : public QgsFeature3DHandler
62{
63 public:
64 QgsBufferedLine3DSymbolHandler( const QgsLine3DSymbol *symbol, const QgsFeatureIds &selectedIds )
65 : mSymbol( static_cast<QgsLine3DSymbol *>( symbol->clone() ) )
66 , mSelectedIds( selectedIds ) {}
67
68 bool prepare( const Qgs3DRenderContext &context, QSet<QString> &attributeNames, const QgsVector3D &chunkOrigin ) override;
69 void processFeature( const QgsFeature &feature, const Qgs3DRenderContext &context ) override;
70 void finalize( Qt3DCore::QEntity *parent, const Qgs3DRenderContext &context ) override;
71
72 private:
74 struct LineData
75 {
76 std::unique_ptr<QgsTessellator> tessellator;
77 QVector<QgsFeatureId> triangleIndexFids;
78 QVector<uint> triangleIndexStartingIndices;
79 };
80
81 void processPolygon( QgsPolygon *polyBuffered, QgsFeatureId fid, float height, float extrusionHeight, const Qgs3DRenderContext &context, LineData &lineData );
82
83 void makeEntity( Qt3DCore::QEntity *parent, const Qgs3DRenderContext &context, LineData &lineData, bool selected );
84
85 // input specific for this class
86 std::unique_ptr<QgsLine3DSymbol> mSymbol;
87 // inputs - generic
88 QgsFeatureIds mSelectedIds;
89
91 QgsVector3D mChunkOrigin;
92
93 // outputs
94 LineData mLineDataNormal;
95 LineData mLineDataSelected;
96};
97
98
99bool QgsBufferedLine3DSymbolHandler::prepare( const Qgs3DRenderContext &, QSet<QString> &attributeNames, const QgsVector3D &chunkOrigin )
100{
101 Q_UNUSED( attributeNames )
102
103 mChunkOrigin = chunkOrigin;
104
105 const QgsPhongTexturedMaterialSettings *texturedMaterialSettings = dynamic_cast<const QgsPhongTexturedMaterialSettings *>( mSymbol->materialSettings() );
106
107 const float textureRotation = texturedMaterialSettings ? static_cast<float>( texturedMaterialSettings->textureRotation() ) : 0;
108 const bool requiresTextureCoordinates = texturedMaterialSettings ? texturedMaterialSettings->requiresTextureCoordinates() : false;
109 mLineDataNormal.tessellator.reset( new QgsTessellator( chunkOrigin.x(), chunkOrigin.y(), true, false, false, false, requiresTextureCoordinates, 3, textureRotation ) );
110 mLineDataSelected.tessellator.reset( new QgsTessellator( chunkOrigin.x(), chunkOrigin.y(), true, false, false, false, requiresTextureCoordinates, 3, textureRotation ) );
111
112 mLineDataNormal.tessellator->setOutputZUp( true );
113 mLineDataSelected.tessellator->setOutputZUp( true );
114
115 return true;
116}
117
118void QgsBufferedLine3DSymbolHandler::processFeature( const QgsFeature &feature, const Qgs3DRenderContext &context )
119{
120 if ( feature.geometry().isNull() )
121 return;
122
123 LineData &lineData = mSelectedIds.contains( feature.id() ) ? mLineDataSelected : mLineDataNormal;
124
125 QgsGeometry geom = feature.geometry();
126 const QgsAbstractGeometry *abstractGeom = geom.constGet()->simplifiedTypeRef();
127
128 // segmentize curved geometries if necessary
129 if ( QgsWkbTypes::isCurvedType( abstractGeom->wkbType() ) )
130 {
131 geom = QgsGeometry( abstractGeom->segmentize() );
132 abstractGeom = geom.constGet()->simplifiedTypeRef();
133 }
134
135 // TODO: configurable
136 const int nSegments = 4;
138 const Qgis::JoinStyle joinStyle = Qgis::JoinStyle::Round;
139 const double mitreLimit = 0;
140
141 const QgsGeos engine( abstractGeom );
142
143 double width = mSymbol->width();
144 if ( qgsDoubleNear( width, 0 ) )
145 {
146 // a zero-width buffered line should be treated like a "wall" or "fence" -- we fake this by bumping the width to a very tiny amount,
147 // so that we get a very narrow polygon shape to work with...
148 width = 0.001;
149 }
150
151 QgsAbstractGeometry *buffered = engine.buffer( width / 2., nSegments, endCapStyle, joinStyle, mitreLimit ); // factory
152 if ( !buffered )
153 return;
154
156 {
157 QgsPolygon *polyBuffered = qgsgeometry_cast<QgsPolygon *>( buffered );
158 processPolygon( polyBuffered, feature.id(), mSymbol->offset(), mSymbol->extrusionHeight(), context, lineData );
159 }
160 else if ( QgsWkbTypes::flatType( buffered->wkbType() ) == Qgis::WkbType::MultiPolygon )
161 {
162 QgsMultiPolygon *mpolyBuffered = qgsgeometry_cast<QgsMultiPolygon *>( buffered );
163 for ( int i = 0; i < mpolyBuffered->numGeometries(); ++i )
164 {
165 QgsPolygon *polyBuffered = qgsgeometry_cast<QgsPolygon *>( mpolyBuffered->polygonN( i ) )->clone(); // need to clone individual geometry parts
166 processPolygon( polyBuffered, feature.id(), mSymbol->offset(), mSymbol->extrusionHeight(), context, lineData );
167 }
168 delete buffered;
169 }
170 mFeatureCount++;
171}
172
173void QgsBufferedLine3DSymbolHandler::processPolygon( QgsPolygon *polyBuffered, QgsFeatureId fid, float height, float extrusionHeight, const Qgs3DRenderContext &context, LineData &lineData )
174{
175 Qgs3DUtils::clampAltitudes( polyBuffered, mSymbol->altitudeClamping(), mSymbol->altitudeBinding(), height, context );
176
177 Q_ASSERT( lineData.tessellator->dataVerticesCount() % 3 == 0 );
178 const uint startingTriangleIndex = static_cast<uint>( lineData.tessellator->dataVerticesCount() / 3 );
179 lineData.triangleIndexStartingIndices.append( startingTriangleIndex );
180 lineData.triangleIndexFids.append( fid );
181 lineData.tessellator->addPolygon( *polyBuffered, extrusionHeight );
182 if ( !lineData.tessellator->error().isEmpty() )
183 {
184 QgsMessageLog::logMessage( lineData.tessellator->error(), QObject::tr( "3D" ) );
185 }
186
187 delete polyBuffered;
188}
189
190void QgsBufferedLine3DSymbolHandler::finalize( Qt3DCore::QEntity *parent, const Qgs3DRenderContext &context )
191{
192 // create entity for selected and not selected
193 makeEntity( parent, context, mLineDataNormal, false );
194 makeEntity( parent, context, mLineDataSelected, true );
195
196 mZMin = std::min( mLineDataNormal.tessellator->zMinimum(), mLineDataSelected.tessellator->zMinimum() );
197 mZMax = std::max( mLineDataNormal.tessellator->zMaximum(), mLineDataSelected.tessellator->zMaximum() );
198}
199
200
201void QgsBufferedLine3DSymbolHandler::makeEntity( Qt3DCore::QEntity *parent, const Qgs3DRenderContext &context, LineData &lineData, bool selected )
202{
203 if ( lineData.tessellator->dataVerticesCount() == 0 )
204 return; // nothing to show - no need to create the entity
205
206 QgsMaterialContext materialContext;
207 materialContext.setIsSelected( selected );
208 materialContext.setSelectionColor( context.selectionColor() );
209 QgsMaterial *material = mSymbol->materialSettings()->toMaterial( QgsMaterialSettingsRenderingTechnique::Triangles, materialContext );
210
211 // extract vertex buffer data from tessellator
212 const QByteArray data( ( const char * ) lineData.tessellator->data().constData(), static_cast<int>( lineData.tessellator->data().count() * sizeof( float ) ) );
213 const int nVerts = data.count() / lineData.tessellator->stride();
214
215 const QgsPhongTexturedMaterialSettings *texturedMaterialSettings = dynamic_cast<const QgsPhongTexturedMaterialSettings *>( mSymbol->materialSettings() );
216
217 QgsTessellatedPolygonGeometry *geometry = new QgsTessellatedPolygonGeometry( true, false, false, texturedMaterialSettings ? texturedMaterialSettings->requiresTextureCoordinates() : false );
218 geometry->setData( data, nVerts, lineData.triangleIndexFids, lineData.triangleIndexStartingIndices );
219
220 Qt3DRender::QGeometryRenderer *renderer = new Qt3DRender::QGeometryRenderer;
221 renderer->setGeometry( geometry );
222
223 // add transform (our geometry has coordinates relative to mChunkOrigin)
224 QgsGeoTransform *transform = new QgsGeoTransform;
225 transform->setGeoTranslation( mChunkOrigin );
226
227 // make entity
228 Qt3DCore::QEntity *entity = new Qt3DCore::QEntity;
229 entity->addComponent( renderer );
230 entity->addComponent( material );
231 entity->addComponent( transform );
232 entity->setParent( parent );
233
234 if ( !selected )
235 renderer->setProperty( Qgs3DTypes::PROP_NAME_3D_RENDERER_FLAG, Qgs3DTypes::Main3DRenderer ); // temporary measure to distinguish between "selected" and "main"
236
237 // cppcheck wrongly believes entity will leak
238 // cppcheck-suppress memleak
239}
240
241
242// --------------
243
244
245class QgsThickLine3DSymbolHandler : public QgsFeature3DHandler
246{
247 public:
248 QgsThickLine3DSymbolHandler( const QgsLine3DSymbol *symbol, const QgsFeatureIds &selectedIds )
249 : mSymbol( static_cast<QgsLine3DSymbol *>( symbol->clone() ) )
250 , mSelectedIds( selectedIds )
251 {
252 }
253
254 bool prepare( const Qgs3DRenderContext &context, QSet<QString> &attributeNames, const QgsVector3D &chunkOrigin ) override;
255 void processFeature( const QgsFeature &feature, const Qgs3DRenderContext &context ) override;
256 void finalize( Qt3DCore::QEntity *parent, const Qgs3DRenderContext &context ) override;
257
258 private:
259 void makeEntity( Qt3DCore::QEntity *parent, const Qgs3DRenderContext &context, QgsLineVertexData &lineVertexData, bool selected );
260 Qt3DExtras::QPhongMaterial *material( const QgsLine3DSymbol &symbol ) const;
261 void processMaterialDatadefined( uint verticesCount, const QgsExpressionContext &context, QgsLineVertexData &lineVertexData );
262
263 // input specific for this class
264 std::unique_ptr<QgsLine3DSymbol> mSymbol;
265 // inputs - generic
266 QgsFeatureIds mSelectedIds;
267
269 QgsVector3D mChunkOrigin;
270
271 // outputs
272 QgsLineVertexData mLineDataNormal;
273 QgsLineVertexData mLineDataSelected;
274};
275
276
277bool QgsThickLine3DSymbolHandler::prepare( const Qgs3DRenderContext &context, QSet<QString> &attributeNames, const QgsVector3D &chunkOrigin )
278{
279 Q_UNUSED( attributeNames )
280
281 mChunkOrigin = chunkOrigin;
282
283 mLineDataNormal.withAdjacency = true;
284 mLineDataSelected.withAdjacency = true;
285 mLineDataNormal.init( mSymbol->altitudeClamping(), mSymbol->altitudeBinding(), mSymbol->offset(), context, chunkOrigin );
286 mLineDataSelected.init( mSymbol->altitudeClamping(), mSymbol->altitudeBinding(), mSymbol->offset(), context, chunkOrigin );
287
288 QSet<QString> attrs = mSymbol->dataDefinedProperties().referencedFields( context.expressionContext() );
289 attributeNames.unite( attrs );
290 attrs = mSymbol->materialSettings()->dataDefinedProperties().referencedFields( context.expressionContext() );
291 attributeNames.unite( attrs );
292
293 if ( mSymbol->materialSettings()->dataDefinedProperties().isActive( QgsAbstractMaterialSettings::Property::Ambient ) )
294 {
295 processMaterialDatadefined( mLineDataNormal.vertices.size(), context.expressionContext(), mLineDataNormal );
296 processMaterialDatadefined( mLineDataSelected.vertices.size(), context.expressionContext(), mLineDataSelected );
297 }
298
299 return true;
300}
301
302void QgsThickLine3DSymbolHandler::processFeature( const QgsFeature &feature, const Qgs3DRenderContext &context )
303{
304 Q_UNUSED( context )
305 if ( feature.geometry().isNull() )
306 return;
307
308 QgsLineVertexData &lineVertexData = mSelectedIds.contains( feature.id() ) ? mLineDataSelected : mLineDataNormal;
309
310 const int oldVerticesCount = lineVertexData.vertices.size();
311
312 QgsGeometry geom = feature.geometry();
313 const QgsAbstractGeometry *abstractGeom = geom.constGet()->simplifiedTypeRef();
314
315 // segmentize curved geometries if necessary
316 if ( QgsWkbTypes::isCurvedType( abstractGeom->wkbType() ) )
317 {
318 geom = QgsGeometry( abstractGeom->segmentize() );
319 abstractGeom = geom.constGet()->simplifiedTypeRef();
320 }
321
322 if ( const QgsLineString *lineString = qgsgeometry_cast<const QgsLineString *>( abstractGeom ) )
323 {
324 lineVertexData.addLineString( *lineString );
325 }
326 else if ( const QgsMultiLineString *multiLineString = qgsgeometry_cast<const QgsMultiLineString *>( abstractGeom ) )
327 {
328 for ( int nGeom = 0; nGeom < multiLineString->numGeometries(); ++nGeom )
329 {
330 const QgsLineString *lineString = multiLineString->lineStringN( nGeom );
331 lineVertexData.addLineString( *lineString );
332 }
333 }
334
335 if ( mSymbol->materialSettings()->dataDefinedProperties().isActive( QgsAbstractMaterialSettings::Property::Ambient ) )
336 processMaterialDatadefined( lineVertexData.vertices.size() - oldVerticesCount, context.expressionContext(), lineVertexData );
337
338 mFeatureCount++;
339}
340
341void QgsThickLine3DSymbolHandler::finalize( Qt3DCore::QEntity *parent, const Qgs3DRenderContext &context )
342{
343 // create entity for selected and not selected
344 makeEntity( parent, context, mLineDataNormal, false );
345 makeEntity( parent, context, mLineDataSelected, true );
346
347 updateZRangeFromPositions( mLineDataNormal.vertices );
348 updateZRangeFromPositions( mLineDataSelected.vertices );
349}
350
351
352void QgsThickLine3DSymbolHandler::makeEntity( Qt3DCore::QEntity *parent, const Qgs3DRenderContext &context, QgsLineVertexData &lineVertexData, bool selected )
353{
354 if ( lineVertexData.indexes.isEmpty() )
355 return;
356
357 // material (only ambient color is used for the color)
358 QgsMaterialContext materialContext;
359 materialContext.setIsSelected( selected );
360 materialContext.setSelectionColor( context.selectionColor() );
361 QgsMaterial *material = mSymbol->materialSettings()->toMaterial( QgsMaterialSettingsRenderingTechnique::Lines, materialContext );
362 if ( !material )
363 {
364 const QgsSimpleLineMaterialSettings defaultMaterial;
365 material = defaultMaterial.toMaterial( QgsMaterialSettingsRenderingTechnique::Lines, materialContext );
366 }
367
368 if ( QgsLineMaterial *lineMaterial = dynamic_cast<QgsLineMaterial *>( material ) )
369 lineMaterial->setLineWidth( mSymbol->width() );
370
371 Qt3DCore::QEntity *entity = new Qt3DCore::QEntity;
372
373 // geometry renderer
374 Qt3DRender::QGeometryRenderer *renderer = new Qt3DRender::QGeometryRenderer;
375 renderer->setPrimitiveType( Qt3DRender::QGeometryRenderer::LineStripAdjacency );
376 Qt3DQGeometry *geometry = lineVertexData.createGeometry( entity );
377
378 if ( mSymbol->materialSettings()->dataDefinedProperties().isActive( QgsAbstractMaterialSettings::Property::Ambient ) )
379 mSymbol->materialSettings()->applyDataDefinedToGeometry( geometry, lineVertexData.vertices.size(), lineVertexData.materialDataDefined );
380
381 renderer->setGeometry( geometry );
382
383 renderer->setVertexCount( lineVertexData.indexes.count() );
384 renderer->setPrimitiveRestartEnabled( true );
385 renderer->setRestartIndexValue( 0 );
386
387 // add transform (our geometry has coordinates relative to mChunkOrigin)
388 QgsGeoTransform *transform = new QgsGeoTransform;
389 transform->setGeoTranslation( mChunkOrigin );
390
391 // make entity
392 entity->addComponent( renderer );
393 entity->addComponent( material );
394 entity->addComponent( transform );
395 entity->setParent( parent );
396}
397
398void QgsThickLine3DSymbolHandler::processMaterialDatadefined( uint verticesCount, const QgsExpressionContext &context, QgsLineVertexData &lineVertexData )
399{
400 const QByteArray bytes = mSymbol->materialSettings()->dataDefinedVertexColorsAsByte( context );
401 lineVertexData.materialDataDefined.append( bytes.repeated( static_cast<int>( verticesCount ) ) );
402}
403
404
405// --------------
406
407
408namespace Qgs3DSymbolImpl
409{
410
411 QgsFeature3DHandler *handlerForLine3DSymbol( QgsVectorLayer *layer, const QgsAbstract3DSymbol *symbol )
412 {
413 const QgsLine3DSymbol *lineSymbol = dynamic_cast<const QgsLine3DSymbol *>( symbol );
414 if ( !lineSymbol )
415 return nullptr;
416
417 if ( lineSymbol->renderAsSimpleLines() )
418 return new QgsThickLine3DSymbolHandler( lineSymbol, layer->selectedFeatureIds() );
419 else
420 return new QgsBufferedLine3DSymbolHandler( lineSymbol, layer->selectedFeatureIds() );
421 }
422} // namespace Qgs3DSymbolImpl
423
JoinStyle
Join styles for buffers.
Definition qgis.h:2084
@ Round
Use rounded joins.
EndCapStyle
End cap styles for buffers.
Definition qgis.h:2071
@ Round
Round cap.
@ Polygon
Polygon.
@ MultiPolygon
MultiPolygon.
Rendering context for preparation of 3D entities.
QColor selectionColor() const
Returns color used for selected features.
QgsExpressionContext & expressionContext()
Gets the expression context.
@ Main3DRenderer
Renderer for normal entities.
Definition qgs3dtypes.h:48
static const char * PROP_NAME_3D_RENDERER_FLAG
Qt property name to hold the 3D geometry renderer flag.
Definition qgs3dtypes.h:43
static void clampAltitudes(QgsLineString *lineString, Qgis::AltitudeClamping altClamp, Qgis::AltitudeBinding altBind, const QgsPoint &centroid, float offset, const Qgs3DRenderContext &context)
Clamps altitude of vertices of a linestring according to the settings.
Abstract base class for 3D symbols that are used by VectorLayer3DRenderer objects.
Abstract base class for all geometries.
virtual const QgsAbstractGeometry * simplifiedTypeRef() const
Returns a reference to the simplest lossless representation of this geometry, e.g.
virtual QgsAbstractGeometry * segmentize(double tolerance=M_PI/180., SegmentationToleranceType toleranceType=MaximumAngle) const
Returns a version of the geometry without curves.
Qgis::WkbType wkbType() const
Returns the WKB type of the geometry.
@ Ambient
Ambient color (phong material)
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition qgsfeature.h:58
QgsFeatureId id
Definition qgsfeature.h:66
QgsGeometry geometry
Definition qgsfeature.h:69
int numGeometries() const
Returns the number of geometries within the collection.
A geometry is the spatial representation of a feature.
const QgsAbstractGeometry * constGet() const
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
Does vector analysis using the GEOS library and handles import, export, and exception handling.
Definition qgsgeos.h:139
3D symbol that draws linestring geometries as planar polygons (created from lines using a buffer with...
bool renderAsSimpleLines() const
Returns whether the renderer will render data with simple lines (otherwise it uses buffer)
QgsAbstract3DSymbol * clone() const override SIP_FACTORY
Line string geometry type, with support for z-dimension and m-values.
Context settings for a material.
void setIsSelected(bool isSelected)
Sets whether the material should represent a selected state.
void setSelectionColor(const QColor &color)
Sets the color for representing materials in a selected state.
Base class for all materials used within QGIS 3D views.
Definition qgsmaterial.h:39
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true, const char *file=__builtin_FILE(), const char *function=__builtin_FUNCTION(), int line=__builtin_LINE())
Adds a message to the log instance (and creates it if necessary).
Multi line string geometry collection.
Multi polygon geometry collection.
QgsPolygon * polygonN(int index)
Returns the polygon with the specified index.
A Phong shading model with diffuse texture map.
bool requiresTextureCoordinates() const
Returns true if the material requires texture coordinates to be generated during triangulation....
double textureRotation() const
Returns the texture rotation, in degrees.
Polygon geometry type.
Definition qgspolygon.h:33
QgsPolygon * clone() const override
Clones the geometry by performing a deep copy.
Basic shading material used for rendering simple lines as solid line components.
QgsMaterial * toMaterial(QgsMaterialSettingsRenderingTechnique technique, const QgsMaterialContext &context) const override
Creates a new QgsMaterial object representing the material settings.
Qt3DRender::QGeometry subclass that represents polygons tessellated into 3D geometry.
void setData(const QByteArray &vertexBufferData, int vertexCount, const QVector< QgsFeatureId > &triangleIndexFids, const QVector< uint > &triangleIndexStartingIndices)
Initializes vertex buffer (and other members) from data that were already tessellated.
Tessellates polygons into triangles.
A 3D vector (similar to QVector3D) with the difference that it uses double precision instead of singl...
Definition qgsvector3d.h:30
double y() const
Returns Y coordinate.
Definition qgsvector3d.h:49
double x() const
Returns X coordinate.
Definition qgsvector3d.h:47
Represents a vector layer which manages a vector based dataset.
Q_INVOKABLE const QgsFeatureIds & selectedFeatureIds() const
Returns a list of the selected features IDs in this layer.
static bool isCurvedType(Qgis::WkbType type)
Returns true if the WKB type is a curved type or can contain curved geometries.
static Qgis::WkbType flatType(Qgis::WkbType type)
Returns the flat type for a WKB type.
@ Triangles
Triangle based rendering (default)
@ Lines
Line based rendering, requires line data.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition qgis.h:6286
Qt3DCore::QGeometry Qt3DQGeometry
QSet< QgsFeatureId > QgsFeatureIds
qint64 QgsFeatureId
64 bit feature ids negative numbers are used for uncommitted/newly added features
Qt3DCore::QAttribute Qt3DQAttribute
Qt3DCore::QBuffer Qt3DQBuffer
Qt3DCore::QGeometry Qt3DQGeometry