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