QGIS API Documentation 4.1.0-Master (31622b25bb0)
Loading...
Searching...
No Matches
qgspolygon3dsymbol_p.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgspolygon3dsymbol_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
17
18#include "qgs3d.h"
19#include "qgs3drendercontext.h"
20#include "qgs3dutils.h"
22#include "qgsgeotransform.h"
23#include "qgslinematerial_p.h"
24#include "qgslinestring.h"
25#include "qgslinevertexdata_p.h"
27#include "qgsmessagelog.h"
28#include "qgsmultilinestring.h"
29#include "qgsmultipolygon.h"
31#include "qgspolygon.h"
32#include "qgspolygon3dsymbol.h"
35#include "qgstessellator.h"
36#include "qgsvectorlayer.h"
37
38#include <Qt3DExtras/QPhongMaterial>
39#include <Qt3DRender/QAbstractTextureImage>
40#include <Qt3DRender/QCullFace>
41#include <Qt3DRender/QEffect>
42#include <Qt3DRender/QGeometryRenderer>
43#include <Qt3DRender/QTechnique>
44#include <Qt3DRender/QTexture>
45
47
48
49class QgsPolygon3DSymbolHandler : public QgsFeature3DHandler
50{
51 public:
52 QgsPolygon3DSymbolHandler( const QgsPolygon3DSymbol *symbol, const QgsFeatureIds &selectedIds )
53 : mSymbol( static_cast<QgsPolygon3DSymbol *>( symbol->clone() ) )
54 , mSelectedIds( selectedIds )
55 {}
56
57 bool prepare( const Qgs3DRenderContext &context, QSet<QString> &attributeNames, const QgsBox3D &chunkExtent ) override;
58 void processFeature( const QgsFeature &f, const Qgs3DRenderContext &context ) override;
59 void finalize( Qt3DCore::QEntity *parent, const Qgs3DRenderContext &context ) override;
60
61 private:
63 struct PolygonData
64 {
65 std::unique_ptr<QgsTessellator> tessellator;
66 QVector<QgsFeatureId> triangleIndexFids;
67 QVector<uint> triangleIndexStartingIndices;
68 QByteArray materialDataDefined;
69 };
70
71 void processPolygon( const QgsPolygon *poly, QgsFeatureId fid, float offset, float extrusionHeight, const Qgs3DRenderContext &context, PolygonData &out );
72 void processMaterialDatadefined( uint verticesCount, const QgsExpressionContext &context, PolygonData &out );
73 void makeEntity( Qt3DCore::QEntity *parent, const Qgs3DRenderContext &context, PolygonData &out, bool selected );
74 QgsMaterial *material( const QgsPolygon3DSymbol *symbol, bool isSelected, const Qgs3DRenderContext &context ) const;
75
76 // input specific for this class
77 std::unique_ptr<QgsPolygon3DSymbol> mSymbol;
78 // inputs - generic
79 QgsFeatureIds mSelectedIds;
80 // outputs
81 PolygonData outNormal;
82 PolygonData outSelected;
83
84 QgsLineVertexData outEdges;
85
87 bool mWasClippedToExtent = false;
88};
89
90
91bool QgsPolygon3DSymbolHandler::prepare( const Qgs3DRenderContext &context, QSet<QString> &attributeNames, const QgsBox3D &chunkExtent )
92{
93 mChunkOrigin = chunkExtent.center();
94 mChunkOrigin.setZ( 0. ); // set the chunk origin to the bottom of the box, as the tessellator currently always considers origin z to be zero
95 mChunkExtent = chunkExtent;
96
97 outEdges.withAdjacency = true;
98 outEdges.init( mSymbol->altitudeClamping(), mSymbol->altitudeBinding(), 0, context, mChunkOrigin );
99
100 const bool requiresTextureCoordinates = mSymbol->materialSettings() && mSymbol->materialSettings()->requiresTextureCoordinates();
101 const bool requiresTangents = mSymbol->materialSettings() && mSymbol->materialSettings()->requiresTangents();
102
103 auto tessellator = std::make_unique<QgsTessellator>();
104 tessellator->setOrigin( mChunkOrigin );
105 tessellator->setAddNormals( true );
106 tessellator->setInvertNormals( mSymbol->invertNormals() );
107 tessellator->setBackFacesEnabled( mSymbol->addBackFaces() );
108 tessellator->setExtrusionFaces( mSymbol->extrusionFaces() );
109 tessellator->setAddTextureUVs( requiresTextureCoordinates );
110 tessellator->setAddTangents( requiresTangents );
111 tessellator->setTriangulationAlgorithm( Qgis::TriangulationAlgorithm::Earcut );
112
113 outNormal.tessellator = std::move( tessellator );
114
115 tessellator = std::make_unique<QgsTessellator>();
116 tessellator->setOrigin( mChunkOrigin );
117 tessellator->setAddNormals( true );
118 tessellator->setInvertNormals( mSymbol->invertNormals() );
119 tessellator->setBackFacesEnabled( mSymbol->addBackFaces() );
120 tessellator->setExtrusionFaces( mSymbol->extrusionFaces() );
121 tessellator->setAddTextureUVs( requiresTextureCoordinates );
122 tessellator->setAddTangents( requiresTangents );
123 tessellator->setTriangulationAlgorithm( Qgis::TriangulationAlgorithm::Earcut );
124
125 outSelected.tessellator = std::move( tessellator );
126
127 QSet<QString> attrs = mSymbol->dataDefinedProperties().referencedFields( context.expressionContext() );
128 attributeNames.unite( attrs );
129 attrs = mSymbol->materialSettings()->dataDefinedProperties().referencedFields( context.expressionContext() );
130 attributeNames.unite( attrs );
131 return true;
132}
133
134void QgsPolygon3DSymbolHandler::processPolygon( const QgsPolygon *poly, QgsFeatureId fid, float offset, float extrusionHeight, const Qgs3DRenderContext &context, PolygonData &out )
135{
136 std::unique_ptr<QgsPolygon> polyClone( poly->clone() );
137
138 if ( mSymbol->edgesEnabled() )
139 {
140 // add edges before the polygon gets the Z values modified because addLineString() does its own altitude handling
141 const QgsAbstractGeometry *exteriorRing = static_cast<const QgsLineString *>( polyClone->exteriorRing() );
142
143 // This geometry will take ownership of the cleaned exteriorRing abstract geom.
144 // We need this to live for as long as exteriorRing is used.
145 QgsGeometry cleanedExteriorRingGeometry;
146
147 if ( mWasClippedToExtent )
148 {
149 // if the polygon was clipped to the chunk extent, then we need to remove any part of the exterior ring that
150 // overlaps the chunk extent line, otherwise the chunk extents will appear as edges. Any interior rings
151 // that were intersected by the extent will now be part of the exterior ring of the clipped geometry.
152 const QVector< QgsPointXY > extentPoints {
153 { mChunkExtent.xMinimum(), mChunkExtent.yMinimum() },
154 { mChunkExtent.xMaximum(), mChunkExtent.yMinimum() },
155 { mChunkExtent.xMaximum(), mChunkExtent.yMaximum() },
156 { mChunkExtent.xMinimum(), mChunkExtent.yMaximum() },
157 { mChunkExtent.xMinimum(), mChunkExtent.yMinimum() }
158 };
159 auto extentLinestring = std::make_unique<QgsLineString>( extentPoints );
160
161 const QgsGeometry exteriorRingGeometry( exteriorRing->clone() );
162 // it should be safe to perform the diff without any tolerance, the extent line string is a simple rectangle (chunk perimeter)
163 cleanedExteriorRingGeometry = exteriorRingGeometry.difference( QgsGeometry( extentLinestring.release() ) );
164 // make sure the diff didn't produce some degenerate geometry
165 ( void ) cleanedExteriorRingGeometry.convertGeometryCollectionToSubclass( Qgis::GeometryType::Line );
166 exteriorRing = cleanedExteriorRingGeometry.constGet()->simplifiedTypeRef();
167 }
168
169 if ( const QgsLineString *line = qgsgeometry_cast<const QgsLineString *>( exteriorRing ) )
170 {
171 outEdges.addLineString( *line, offset );
172 }
173 // if geometry was clipped to the chunk extents, we might now have a multilinestring
174 else if ( const QgsMultiLineString *mline = qgsgeometry_cast<const QgsMultiLineString *>( exteriorRing ) )
175 {
176 for ( int i = 0; i < mline->numGeometries(); ++i )
177 {
178 const QgsLineString *line = mline->lineStringN( i );
179 outEdges.addLineString( *line, offset );
180 }
181 }
182
183 // if geometry was clipped to the chunk extents and the chunk extents intersected an interior ring, then
184 // that ring is now part of the exterior ring. Hence we don't need to treat interior rings any differently
185 for ( int i = 0; i < polyClone->numInteriorRings(); ++i )
186 outEdges.addLineString( *static_cast<const QgsLineString *>( polyClone->interiorRing( i ) ), offset );
187
188 if ( extrusionHeight != 0.f )
189 {
190 // add roof and wall edges
191
192 if ( const QgsLineString *line = qgsgeometry_cast<const QgsLineString *>( exteriorRing ) )
193 {
194 outEdges.addLineString( *line, extrusionHeight + offset );
195 outEdges.addVerticalLines( *line, extrusionHeight, offset );
196 }
197 // if geometry was clipped to the chunk extents, we might now have a multilinestring
198 else if ( const QgsMultiLineString *mline = qgsgeometry_cast<const QgsMultiLineString *>( exteriorRing ) )
199 {
200 for ( int i = 0; i < mline->numGeometries(); ++i )
201 {
202 const QgsLineString *line = mline->lineStringN( i );
203 outEdges.addLineString( *line, extrusionHeight + offset );
204 outEdges.addVerticalLines( *line, extrusionHeight, offset );
205 }
206 }
207
208 // if geometry was clipped to the chunk extents and the chunk extents intersected an interior ring, then
209 // that ring is now part of the exterior ring. Hence we don't need to treat interior rings any differently
210 for ( int i = 0; i < polyClone->numInteriorRings(); ++i )
211 {
212 const QgsLineString *interior = static_cast<const QgsLineString *>( polyClone->interiorRing( i ) );
213 outEdges.addLineString( *interior, extrusionHeight + offset );
214 outEdges.addVerticalLines( *interior, extrusionHeight, offset );
215 }
216 }
217 }
218
219 Qgs3DUtils::clampAltitudes( polyClone.get(), mSymbol->altitudeClamping(), mSymbol->altitudeBinding(), offset, context );
220
221 Q_ASSERT( out.tessellator->dataVerticesCount() % 3 == 0 );
222 const uint startingTriangleIndex = static_cast<uint>( out.tessellator->dataVerticesCount() / 3 );
223 out.triangleIndexStartingIndices.append( startingTriangleIndex );
224 out.triangleIndexFids.append( fid );
225
226 const size_t oldVertexCount = out.tessellator->uniqueVertexCount();
227 out.tessellator->addPolygon( *polyClone, extrusionHeight );
228 if ( !out.tessellator->error().isEmpty() )
229 {
230 QgsMessageLog::logMessage( out.tessellator->error(), QObject::tr( "3D" ) );
231 }
232
233 if ( mSymbol->materialSettings()->dataDefinedProperties().hasActiveProperties() )
234 {
235 const uint newUniqueVertices = out.tessellator->uniqueVertexCount() - oldVertexCount;
236 processMaterialDatadefined( newUniqueVertices, context.expressionContext(), out );
237 }
238}
239
240void QgsPolygon3DSymbolHandler::processMaterialDatadefined( uint verticesCount, const QgsExpressionContext &context, QgsPolygon3DSymbolHandler::PolygonData &out )
241{
242 QByteArray bytes;
243 if ( const QgsAbstractMaterial3DHandler *handler = Qgs3D::handlerForMaterialSettings( mSymbol->materialSettings() ) )
244 {
245 bytes = handler->dataDefinedVertexColorsAsByte( mSymbol->materialSettings(), context );
246 }
247 out.materialDataDefined.append( bytes.repeated( verticesCount ) );
248}
249
250void QgsPolygon3DSymbolHandler::processFeature( const QgsFeature &f, const Qgs3DRenderContext &context )
251{
252 if ( f.geometry().isNull() )
253 return;
254
255 PolygonData &out = mSelectedIds.contains( f.id() ) ? outSelected : outNormal;
256
257 QgsGeometry geom = f.geometry();
258 mWasClippedToExtent = clipGeometryIfTooLarge( geom );
259
260 if ( geom.isEmpty() )
261 return;
262
264
265 // segmentize curved geometries if necessary
267 {
268 geom = QgsGeometry( g->segmentize() );
269 g = geom.constGet()->simplifiedTypeRef();
270 }
271
272 const QgsPropertyCollection &ddp = mSymbol->dataDefinedProperties();
273 const bool hasDDHeight = ddp.isActive( QgsAbstract3DSymbol::Property::Height );
274 const bool hasDDExtrusion = ddp.isActive( QgsAbstract3DSymbol::Property::ExtrusionHeight );
275
276 float offset = mSymbol->offset();
277 float extrusionHeight = mSymbol->extrusionHeight();
278 if ( hasDDHeight )
279 offset = static_cast<float>( ddp.valueAsDouble( QgsAbstract3DSymbol::Property::Height, context.expressionContext(), offset ) );
280 if ( hasDDExtrusion )
281 extrusionHeight = ddp.valueAsDouble( QgsAbstract3DSymbol::Property::ExtrusionHeight, context.expressionContext(), extrusionHeight );
282
283 if ( const QgsPolygon *poly = qgsgeometry_cast<const QgsPolygon *>( g ) )
284 {
285 processPolygon( poly, f.id(), offset, extrusionHeight, context, out );
286 }
287 else if ( const QgsMultiPolygon *mpoly = qgsgeometry_cast<const QgsMultiPolygon *>( g ) )
288 {
289 for ( int i = 0; i < mpoly->numGeometries(); ++i )
290 {
291 const QgsPolygon *poly = mpoly->polygonN( i );
292 processPolygon( poly, f.id(), offset, extrusionHeight, context, out );
293 }
294 }
296 {
297 for ( int i = 0; i < gc->numGeometries(); ++i )
298 {
299 const QgsAbstractGeometry *g2 = gc->geometryN( i );
301 {
302 const QgsPolygon *poly = static_cast<const QgsPolygon *>( g2 );
303 processPolygon( poly, f.id(), offset, extrusionHeight, context, out );
304 }
305 }
306 }
307 else if ( const QgsPolyhedralSurface *polySurface = qgsgeometry_cast<const QgsPolyhedralSurface *>( g ) )
308 {
309 for ( int i = 0; i < polySurface->numPatches(); ++i )
310 {
311 const QgsPolygon *poly = polySurface->patchN( i );
312 processPolygon( poly, f.id(), offset, extrusionHeight, context, out );
313 }
314 }
315 else
316 qWarning() << "not a polygon";
317
318 mFeatureCount++;
319}
320
321void QgsPolygon3DSymbolHandler::finalize( Qt3DCore::QEntity *parent, const Qgs3DRenderContext &context )
322{
323 // create entity for selected and not selected
324 makeEntity( parent, context, outNormal, false );
325 makeEntity( parent, context, outSelected, true );
326
327 mZMin = std::min( outNormal.tessellator->zMinimum(), outSelected.tessellator->zMinimum() );
328 mZMax = std::max( outNormal.tessellator->zMaximum(), outSelected.tessellator->zMaximum() );
329
330 // add entity for edges, but not when doing highlighting
331 if ( mSymbol->edgesEnabled() && !outEdges.indexes.isEmpty() && !mHighlightingEnabled )
332 {
333 QgsLineMaterial *mat = new QgsLineMaterial;
334 mat->setLineColor( mSymbol->edgeColor() );
335 mat->setLineWidth( mSymbol->edgeWidth() );
336
337 Qt3DCore::QEntity *entity = new Qt3DCore::QEntity;
338 entity->setObjectName( parent->objectName() + "_EDGES" );
339
340 // geometry renderer
341 Qt3DRender::QGeometryRenderer *renderer = new Qt3DRender::QGeometryRenderer;
342 renderer->setPrimitiveType( Qt3DRender::QGeometryRenderer::LineStripAdjacency );
343 renderer->setGeometry( outEdges.createGeometry( entity ) );
344 renderer->setVertexCount( outEdges.indexes.count() );
345 renderer->setPrimitiveRestartEnabled( true );
346 renderer->setRestartIndexValue( 0 );
347
348 // add transform (our geometry has coordinates relative to mChunkOrigin)
349 QgsGeoTransform *tr = new QgsGeoTransform;
350 tr->setGeoTranslation( mChunkOrigin );
351
352 // make entity
353 entity->addComponent( renderer );
354 entity->addComponent( mat );
355 entity->addComponent( tr );
356 entity->setParent( parent );
357 }
358}
359
360
361void QgsPolygon3DSymbolHandler::makeEntity( Qt3DCore::QEntity *parent, const Qgs3DRenderContext &context, PolygonData &polyData, bool selected )
362{
363 if ( polyData.tessellator->dataVerticesCount() == 0 )
364 return; // nothing to show - no need to create the entity
365
366 QgsMaterial *mat = material( mSymbol.get(), selected, context );
367
368 // extract vertex buffer data from tessellator
369 const QByteArray vertexBuffer = polyData.tessellator->vertexBuffer();
370 const QByteArray indexBuffer = polyData.tessellator->indexBuffer();
371 const int vertexCount = polyData.tessellator->uniqueVertexCount();
372 const size_t indexCount = polyData.tessellator->dataVerticesCount();
373
375 true,
376 mSymbol->invertNormals(),
377 mSymbol->addBackFaces(),
378 mSymbol->materialSettings() && mSymbol->materialSettings()->requiresTextureCoordinates(),
379 mSymbol->materialSettings() && mSymbol->materialSettings()->requiresTangents()
380 );
381
382 geometry->setVertexBufferData( vertexBuffer, vertexCount, polyData.triangleIndexFids, polyData.triangleIndexStartingIndices );
383 geometry->setIndexBufferData( indexBuffer, indexCount );
384
385 if ( mSymbol->materialSettings()->dataDefinedProperties().hasActiveProperties() )
386 {
387 if ( const QgsAbstractMaterial3DHandler *handler = Qgs3D::handlerForMaterialSettings( mSymbol->materialSettings() ) )
388 {
389 handler->applyDataDefinedToGeometry( mSymbol->materialSettings(), geometry, vertexCount, polyData.materialDataDefined );
390 }
391 }
392 Qt3DRender::QGeometryRenderer *renderer = new Qt3DRender::QGeometryRenderer;
393 renderer->setGeometry( geometry );
394
395 // add transform (our geometry has coordinates relative to mChunkOrigin)
396 QgsGeoTransform *tr = new QgsGeoTransform;
397 tr->setGeoTranslation( mChunkOrigin );
398
399 // make entity
400 Qt3DCore::QEntity *entity = new Qt3DCore::QEntity;
401 entity->setObjectName( parent->objectName() + "_CHUNK_MESH" );
402 entity->addComponent( renderer );
403 entity->addComponent( mat );
404 entity->addComponent( tr );
405 entity->setParent( parent );
406
407 if ( !selected )
408 renderer->setProperty( Qgs3DTypes::PROP_NAME_3D_RENDERER_FLAG, Qgs3DTypes::Main3DRenderer ); // temporary measure to distinguish between "selected" and "main"
409
410 // cppcheck wrongly believes entity will leak
411 // cppcheck-suppress memleak
412}
413
414// front/back side culling
415static void applyCullingMode( Qgs3DTypes::CullingMode cullingMode, QgsMaterial *material )
416{
417 const auto techniques = material->effect()->techniques();
418 for ( auto tit = techniques.constBegin(); tit != techniques.constEnd(); ++tit )
419 {
420 auto renderPasses = ( *tit )->renderPasses();
421 for ( auto rpit = renderPasses.begin(); rpit != renderPasses.end(); ++rpit )
422 {
423 Qt3DRender::QCullFace *cullFace = new Qt3DRender::QCullFace;
424 cullFace->setMode( Qgs3DUtils::qt3DcullingMode( cullingMode ) );
425 ( *rpit )->addRenderState( cullFace );
426 }
427 }
428}
429
430QgsMaterial *QgsPolygon3DSymbolHandler::material( const QgsPolygon3DSymbol *symbol, bool isSelected, const Qgs3DRenderContext &context ) const
431{
433 materialContext.setIsSelected( isSelected );
434 materialContext.setIsHighlighted( mHighlightingEnabled );
435
436 const bool dataDefined = mSymbol->materialSettings()->dataDefinedProperties().hasActiveProperties();
438 applyCullingMode( symbol->cullingMode(), material );
439 return material;
440}
441
442
443// --------------
444
445
446namespace Qgs3DSymbolImpl
447{
448
449
450 QgsFeature3DHandler *handlerForPolygon3DSymbol( const QgsVectorLayer *layer, const QgsAbstract3DSymbol *symbol )
451 {
452 const QgsPolygon3DSymbol *polygonSymbol = dynamic_cast<const QgsPolygon3DSymbol *>( symbol );
453 if ( !polygonSymbol )
454 return nullptr;
455
456 return new QgsPolygon3DSymbolHandler( polygonSymbol, layer->selectedFeatureIds() );
457 }
458} // namespace Qgs3DSymbolImpl
459
@ Line
Lines.
Definition qgis.h:381
@ Triangles
Triangle based rendering (default).
Definition qgis.h:4343
@ TrianglesDataDefined
Triangle based rendering with possibility of datadefined color.
Definition qgis.h:4349
@ Polygon
Polygon.
Definition qgis.h:298
Rendering context for preparation of 3D entities.
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
CullingMode
Triangle culling mode.
Definition qgs3dtypes.h:35
static Qt3DRender::QCullFace::CullingMode qt3DcullingMode(Qgs3DTypes::CullingMode mode)
Converts Qgs3DTypes::CullingMode mode into its Qt3D equivalent.
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.
static QgsMaterial * toMaterial(const QgsAbstractMaterialSettings *settings, Qgis::MaterialRenderingTechnique technique, const QgsMaterialContext &context)
Creates a new QgsMaterial object representing the material settings.
Definition qgs3d.cpp:152
static const QgsAbstractMaterial3DHandler * handlerForMaterialSettings(const QgsAbstractMaterialSettings *settings)
Returns the handler to use for a material settings.
Definition qgs3d.cpp:135
@ ExtrusionHeight
Extrusion height (zero means no extrusion).
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.
virtual QgsAbstractGeometry * clone() const =0
Clones the geometry by performing a deep copy.
Abstract base class for material 3D handlers.
double valueAsDouble(int key, const QgsExpressionContext &context, double defaultValue=0.0, bool *ok=nullptr) const
Calculates the current value of the property with the specified key and interprets it as a double.
A 3-dimensional box composed of x, y, z coordinates.
Definition qgsbox3d.h:45
QgsVector3D center() const
Returns the center of the box as a vector.
Definition qgsbox3d.cpp:124
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:60
QgsFeatureId id
Definition qgsfeature.h:63
QgsGeometry geometry
Definition qgsfeature.h:66
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.
bool isEmpty() const
Returns true if the geometry is empty (eg a linestring with no vertices, or a collection with no geom...
bool convertGeometryCollectionToSubclass(Qgis::GeometryType geomType)
Converts geometry collection to a the desired geometry type subclass (multi-point,...
QgsGeometry difference(const QgsGeometry &geometry, const QgsGeometryParameters &parameters=QgsGeometryParameters(), QgsFeedback *feedback=nullptr) const
Returns a geometry representing the points making up this geometry that do not make up other.
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 setIsHighlighted(bool isHighlighted)
Sets whether the material should represent a highlighted state.
static QgsMaterialContext fromRenderContext(const Qgs3DRenderContext &context)
Constructs a material context from the settings in a 3D render context.
Base class for all materials used within QGIS 3D views.
Definition qgsmaterial.h:40
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(), Qgis::StringFormat format=Qgis::StringFormat::PlainText)
Adds a message to the log instance (and creates it if necessary).
Multi line string geometry collection.
Multi polygon geometry collection.
3D symbol that draws polygon geometries as planar polygons, optionally extruded (with added walls).
Qgs3DTypes::CullingMode cullingMode() const
Returns front/back culling mode.
QgsAbstractMaterialSettings * materialSettings() const override
Returns material settings used for shading of the symbol.
Polygon geometry type.
Definition qgspolygon.h:37
QgsPolygon * clone() const override
Clones the geometry by performing a deep copy.
Polyhedral surface geometry type.
A grouped map of multiple QgsProperty objects, each referenced by an integer key value.
bool isActive(int key) const final
Returns true if the collection contains an active property with the specified key.
Qt3DRender::QGeometry subclass that represents polygons tessellated into 3D geometry.
void setVertexBufferData(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.
void setIndexBufferData(const QByteArray &indexBufferData, size_t indexCount)
Sets index buffer data.
void setZ(double z)
Sets Z coordinate.
Definition qgsvector3d.h:80
Q_INVOKABLE const QgsFeatureIds & selectedFeatureIds() const
Returns a list of the selected features IDs in this layer.
static Q_INVOKABLE 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.
T qgsgeometry_cast(QgsAbstractGeometry *geom)
QSet< QgsFeatureId > QgsFeatureIds
qint64 QgsFeatureId
64 bit feature ids negative numbers are used for uncommitted/newly added features