26#include <Qt3DCore/QTransform>
27#include <Qt3DExtras/QPhongMaterial>
29#include <Qt3DExtras/QDiffuseMapMaterial>
30#include <Qt3DRender/QAbstractTextureImage>
31#include <Qt3DRender/QTexture>
33#include <Qt3DRender/QEffect>
34#include <Qt3DRender/QTechnique>
35#include <Qt3DRender/QCullFace>
36#include <Qt3DRender/QGeometryRenderer>
50class QgsPolygon3DSymbolHandler :
public QgsFeature3DHandler
55 , mSelectedIds( selectedIds ) {}
59 void finalize( Qt3DCore::QEntity *parent,
const Qgs3DRenderContext &context )
override;
66 std::unique_ptr<QgsTessellator> tessellator;
67 QVector<QgsFeatureId> triangleIndexFids;
68 QVector<uint> triangleIndexStartingIndices;
69 QByteArray materialDataDefined;
73 void processMaterialDatadefined( uint verticesCount,
const QgsExpressionContext &context, PolygonData &out );
74 void makeEntity( Qt3DCore::QEntity *parent,
const Qgs3DRenderContext &context, PolygonData &out,
bool selected );
78 std::unique_ptr< QgsPolygon3DSymbol > mSymbol;
86 PolygonData outNormal;
87 PolygonData outSelected;
89 QgsLineVertexData outEdges;
95 outEdges.withAdjacency =
true;
96 outEdges.init( mSymbol->altitudeClamping(), mSymbol->altitudeBinding(), 0, context, chunkOrigin );
98 mChunkOrigin = chunkOrigin;
102 outNormal.tessellator.reset(
new QgsTessellator( chunkOrigin.
x(), chunkOrigin.
y(),
true, mSymbol->invertNormals(), mSymbol->addBackFaces(),
false,
104 mSymbol->renderedFacade(),
105 texturedMaterialSettings ? texturedMaterialSettings->
textureRotation() : 0 ) );
106 outSelected.tessellator.reset(
new QgsTessellator( chunkOrigin.
x(), chunkOrigin.
y(),
true, mSymbol->invertNormals(),
107 mSymbol->addBackFaces(),
false,
109 mSymbol->renderedFacade(),
110 texturedMaterialSettings ? texturedMaterialSettings->
textureRotation() : 0 ) );
112 outNormal.tessellator->setOutputZUp(
true );
113 outSelected.tessellator->setOutputZUp(
true );
116 attributeNames.unite( attrs );
117 attrs = mSymbol->materialSettings()->dataDefinedProperties().referencedFields( context.
expressionContext() );
118 attributeNames.unite( attrs );
124 std::unique_ptr< QgsPolygon > polyClone( poly->
clone() );
126 const uint oldVerticesCount = out.tessellator->dataVerticesCount();
127 if ( mSymbol->edgesEnabled() )
130 outEdges.addLineString( *
static_cast<const QgsLineString *
>( polyClone->exteriorRing() ), offset );
131 for (
int i = 0; i < polyClone->numInteriorRings(); ++i )
132 outEdges.addLineString( *
static_cast<const QgsLineString *
>( polyClone->interiorRing( i ) ), offset );
134 if ( extrusionHeight )
138 outEdges.addLineString( *exterior, extrusionHeight + offset );
139 outEdges.addVerticalLines( *exterior, extrusionHeight, offset );
140 for (
int i = 0; i < polyClone->numInteriorRings(); ++i )
143 outEdges.addLineString( *interior, extrusionHeight + offset );
144 outEdges.addVerticalLines( *interior, extrusionHeight, offset );
151 Q_ASSERT( out.tessellator->dataVerticesCount() % 3 == 0 );
152 const uint startingTriangleIndex =
static_cast<uint
>( out.tessellator->dataVerticesCount() / 3 );
153 out.triangleIndexStartingIndices.append( startingTriangleIndex );
154 out.triangleIndexFids.append( fid );
155 out.tessellator->addPolygon( *polyClone, extrusionHeight );
156 if ( !out.tessellator->error().isEmpty() )
161 if ( mSymbol->materialSettings()->dataDefinedProperties().hasActiveProperties() )
162 processMaterialDatadefined( out.tessellator->dataVerticesCount() - oldVerticesCount, context.
expressionContext(), out );
165void QgsPolygon3DSymbolHandler::processMaterialDatadefined( uint verticesCount,
const QgsExpressionContext &context, QgsPolygon3DSymbolHandler::PolygonData &out )
167 const QByteArray bytes = mSymbol->materialSettings()->dataDefinedVertexColorsAsByte( context );
168 out.materialDataDefined.append( bytes.repeated( verticesCount ) );
176 PolygonData &out = mSelectedIds.contains( f.
id() ) ? outSelected : outNormal;
192 float offset = mSymbol->offset();
193 float extrusionHeight = mSymbol->extrusionHeight();
196 if ( hasDDExtrusion )
199 if (
const QgsPolygon *poly = qgsgeometry_cast< const QgsPolygon *>( g ) )
201 processPolygon( poly, f.
id(), offset, extrusionHeight, context, out );
203 else if (
const QgsMultiPolygon *mpoly = qgsgeometry_cast< const QgsMultiPolygon *>( g ) )
205 for (
int i = 0; i < mpoly->numGeometries(); ++i )
207 const QgsPolygon *poly = mpoly->polygonN( i );
208 processPolygon( poly, f.
id(), offset, extrusionHeight, context, out );
213 for (
int i = 0; i < gc->numGeometries(); ++i )
219 processPolygon( poly, f.
id(), offset, extrusionHeight, context, out );
223 else if (
const QgsPolyhedralSurface *polySurface = qgsgeometry_cast< const QgsPolyhedralSurface *>( g ) )
225 for (
int i = 0; i < polySurface->numPatches(); ++i )
227 const QgsPolygon *poly = polySurface->patchN( i );
228 processPolygon( poly, f.
id(), offset, extrusionHeight, context, out );
232 qWarning() <<
"not a polygon";
237void QgsPolygon3DSymbolHandler::finalize( Qt3DCore::QEntity *parent,
const Qgs3DRenderContext &context )
240 makeEntity( parent, context, outNormal,
false );
241 makeEntity( parent, context, outSelected,
true );
243 mZMin = std::min( outNormal.tessellator->zMinimum(), outSelected.tessellator->zMinimum() );
244 mZMax = std::max( outNormal.tessellator->zMaximum(), outSelected.tessellator->zMaximum() );
247 if ( mSymbol->edgesEnabled() && !outEdges.indexes.isEmpty() )
249 QgsLineMaterial *mat =
new QgsLineMaterial;
250 mat->setLineColor( mSymbol->edgeColor() );
251 mat->setLineWidth( mSymbol->edgeWidth() );
253 Qt3DCore::QEntity *entity =
new Qt3DCore::QEntity;
254 entity->setObjectName( parent->objectName() +
"_EDGES" );
257 Qt3DRender::QGeometryRenderer *renderer =
new Qt3DRender::QGeometryRenderer;
258 renderer->setPrimitiveType( Qt3DRender::QGeometryRenderer::LineStripAdjacency );
259 renderer->setGeometry( outEdges.createGeometry( entity ) );
260 renderer->setVertexCount( outEdges.indexes.count() );
261 renderer->setPrimitiveRestartEnabled(
true );
262 renderer->setRestartIndexValue( 0 );
265 Qt3DCore::QTransform *tr =
new Qt3DCore::QTransform;
266 QVector3D nodeTranslation = ( mChunkOrigin - context.
origin() ).toVector3D();
267 tr->setTranslation( nodeTranslation );
270 entity->addComponent( renderer );
271 entity->addComponent( mat );
272 entity->addComponent( tr );
273 entity->setParent( parent );
278void QgsPolygon3DSymbolHandler::makeEntity( Qt3DCore::QEntity *parent,
const Qgs3DRenderContext &context, PolygonData &polyData,
bool selected )
280 if ( polyData.tessellator->dataVerticesCount() == 0 )
283 QgsMaterial *mat = material( mSymbol.get(), selected, context );
286 const QByteArray data(
reinterpret_cast<const char *
>( polyData.tessellator->data().constData() ),
static_cast<int>( polyData.tessellator->data().count() *
sizeof(
float ) ) );
287 const int nVerts = data.count() / polyData.tessellator->stride();
294 geometry->
setData( data, nVerts, polyData.triangleIndexFids, polyData.triangleIndexStartingIndices );
296 if ( mSymbol->materialSettings()->dataDefinedProperties().hasActiveProperties() )
297 mSymbol->materialSettings()->applyDataDefinedToGeometry( geometry, nVerts, polyData.materialDataDefined );
299 Qt3DRender::QGeometryRenderer *renderer =
new Qt3DRender::QGeometryRenderer;
300 renderer->setGeometry( geometry );
303 Qt3DCore::QTransform *tr =
new Qt3DCore::QTransform;
304 QVector3D nodeTranslation = ( mChunkOrigin - context.
origin() ).toVector3D();
305 tr->setTranslation( nodeTranslation );
308 Qt3DCore::QEntity *entity =
new Qt3DCore::QEntity;
309 entity->setObjectName( parent->objectName() +
"_CHUNK_MESH" );
310 entity->addComponent( renderer );
311 entity->addComponent( mat );
312 entity->addComponent( tr );
313 entity->setParent( parent );
325 const auto techniques = material->effect()->techniques();
326 for (
auto tit = techniques.constBegin(); tit != techniques.constEnd(); ++tit )
328 auto renderPasses = ( *tit )->renderPasses();
329 for (
auto rpit = renderPasses.begin(); rpit != renderPasses.end(); ++rpit )
331 Qt3DRender::QCullFace *cullFace =
new Qt3DRender::QCullFace;
333 ( *rpit )->addRenderState( cullFace );
344 const bool dataDefined = mSymbol->materialSettings()->dataDefinedProperties().hasActiveProperties();
348 applyCullingMode( symbol->
cullingMode(), material );
356namespace Qgs3DSymbolImpl
363 if ( !polygonSymbol )
QColor selectionColor() const
Returns color used for selected features.
QgsExpressionContext & expressionContext()
Gets the expression context.
QgsVector3D origin() const
Returns coordinates in map CRS at which 3D scene has origin (0,0,0)
@ Main3DRenderer
Renderer for normal entities.
static const char * PROP_NAME_3D_RENDERER_FLAG
Qt property name to hold the 3D geometry renderer flag.
CullingMode
Triangle culling mode.
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 ¢roid, float offset, const Qgs3DRenderContext &context)
Clamps altitude of vertices of a linestring according to the settings.
@ ExtrusionHeight
Extrusion height (zero means no extrusion)
@ Height
Height (altitude)
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 QgsMaterial * toMaterial(QgsMaterialSettingsRenderingTechnique technique, const QgsMaterialContext &context) const =0
Creates a new QgsMaterial object representing the material settings.
QgsPropertyCollection dataDefinedProperties() const
Returns the symbol material property collection, used for data defined overrides.
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.
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...
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.
Line string geometry type, with support for z-dimension and m-values.
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.
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
Multi polygon geometry collection.
bool requiresTextureCoordinates() const
Returns true if the material requires texture coordinates to be generated during triangulation....
float textureRotation() const
Returns the texture rotation, in degrees.
QgsAbstractMaterialSettings * materialSettings() const
Returns material settings used for shading of the symbol.
Qgs3DTypes::CullingMode cullingMode() const
Returns front/back culling mode.
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 a integer key value.
bool isActive(int key) const final
Returns true if the collection contains an active property with the specified key.
QSet< QString > referencedFields(const QgsExpressionContext &context=QgsExpressionContext(), bool ignoreContext=false) const final
Returns the set of any fields referenced by the active properties from the collection.
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.
Class that takes care of tessellation of polygons into triangles.
Class for storage of 3D vectors similar to QVector3D, with the difference that it uses double precisi...
double y() const
Returns Y coordinate.
double x() const
Returns X coordinate.
Represents a vector layer which manages a vector based data sets.
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.
QgsMaterialSettingsRenderingTechnique
Material rendering techniques 3.
@ Triangles
Triangle based rendering (default)
@ TrianglesDataDefined
Triangle based rendering with possibility of datadefined color.
QSet< QgsFeatureId > QgsFeatureIds
qint64 QgsFeatureId
64 bit feature ids negative numbers are used for uncommitted/newly added features