24 #include <Qt3DCore/QTransform> 25 #include <Qt3DExtras/QPhongMaterial> 26 #include <Qt3DRender/QEffect> 27 #include <Qt3DRender/QTechnique> 28 #include <Qt3DRender/QCullFace> 29 #include <Qt3DRender/QGeometryRenderer> 41 class QgsPolygon3DSymbolHandler :
public QgsFeature3DHandler
45 : mSymbol( symbol ), mSelectedIds( selectedIds ) {}
47 bool prepare(
const Qgs3DRenderContext &context, QSet<QString> &attributeNames )
override;
48 void processFeature(
QgsFeature &feature,
const Qgs3DRenderContext &context )
override;
49 void finalize( Qt3DCore::QEntity *parent,
const Qgs3DRenderContext &context )
override;
56 std::unique_ptr<QgsTessellator> tessellator;
57 QVector<QgsFeatureId> triangleIndexFids;
58 QVector<uint> triangleIndexStartingIndices;
61 void processPolygon(
QgsPolygon *polyClone,
QgsFeatureId fid,
float height,
float extrusionHeight,
const Qgs3DRenderContext &context, PolygonData &out );
62 void makeEntity( Qt3DCore::QEntity *parent,
const Qgs3DRenderContext &context, PolygonData &out,
bool selected );
71 PolygonData outNormal;
72 PolygonData outSelected;
74 QgsLineVertexData outEdges;
78 bool QgsPolygon3DSymbolHandler::prepare(
const Qgs3DRenderContext &context, QSet<QString> &attributeNames )
80 outEdges.withAdjacency =
true;
81 outEdges.init( mSymbol.altitudeClamping(), mSymbol.altitudeBinding(), mSymbol.height(), &context.map() );
83 outNormal.tessellator.reset(
new QgsTessellator( context.map().origin().x(), context.map().origin().y(),
true, mSymbol.invertNormals(), mSymbol.addBackFaces() ) );
84 outSelected.tessellator.reset(
new QgsTessellator( context.map().origin().x(), context.map().origin().y(),
true, mSymbol.invertNormals(), mSymbol.addBackFaces() ) );
87 attributeNames.unite( attrs );
91 void QgsPolygon3DSymbolHandler::processPolygon(
QgsPolygon *polyClone,
QgsFeatureId fid,
float height,
float extrusionHeight,
const Qgs3DRenderContext &context, PolygonData &out )
93 if ( mSymbol.edgesEnabled() )
96 outEdges.addLineString( *static_cast<const QgsLineString *>( polyClone->
exteriorRing() ) );
98 outEdges.addLineString( *static_cast<const QgsLineString *>( polyClone->
interiorRing( i ) ) );
100 if ( extrusionHeight )
104 outEdges.addLineString( *exterior, extrusionHeight );
105 outEdges.addVerticalLines( *exterior, extrusionHeight );
109 outEdges.addLineString( *interior, extrusionHeight );
110 outEdges.addVerticalLines( *interior, extrusionHeight );
117 Q_ASSERT( out.tessellator->dataVerticesCount() % 3 == 0 );
118 uint startingTriangleIndex =
static_cast<uint
>( out.tessellator->dataVerticesCount() / 3 );
119 out.triangleIndexStartingIndices.append( startingTriangleIndex );
120 out.triangleIndexFids.append( fid );
121 out.tessellator->addPolygon( *polyClone, extrusionHeight );
125 void QgsPolygon3DSymbolHandler::processFeature(
QgsFeature &f,
const Qgs3DRenderContext &context )
130 PolygonData &out = mSelectedIds.contains( f.
id() ) ? outSelected : outNormal;
144 float height = mSymbol.height();
145 float extrusionHeight = mSymbol.extrusionHeight();
148 if ( hasDDExtrusion )
151 if (
const QgsPolygon *poly = qgsgeometry_cast< const QgsPolygon *>( g ) )
154 processPolygon( polyClone, f.
id(), height, extrusionHeight, context, out );
156 else if (
const QgsMultiPolygon *mpoly = qgsgeometry_cast< const QgsMultiPolygon *>( g ) )
158 for (
int i = 0; i < mpoly->numGeometries(); ++i )
163 processPolygon( polyClone, f.
id(), height, extrusionHeight, context, out );
168 for (
int i = 0; i < gc->numGeometries(); ++i )
174 processPolygon( polyClone, f.
id(), height, extrusionHeight, context, out );
179 qDebug() <<
"not a polygon";
183 void QgsPolygon3DSymbolHandler::finalize( Qt3DCore::QEntity *parent,
const Qgs3DRenderContext &context )
186 makeEntity( parent, context, outNormal,
false );
187 makeEntity( parent, context, outSelected,
true );
189 mZMin = std::min( outNormal.tessellator->zMinimum(), outSelected.tessellator->zMinimum() );
190 mZMax = std::max( outNormal.tessellator->zMaximum(), outSelected.tessellator->zMaximum() );
193 if ( mSymbol.edgesEnabled() && !outEdges.indexes.isEmpty() )
195 QgsLineMaterial *mat =
new QgsLineMaterial;
196 mat->setLineColor( mSymbol.edgeColor() );
197 mat->setLineWidth( mSymbol.edgeWidth() );
199 Qt3DCore::QEntity *entity =
new Qt3DCore::QEntity;
202 Qt3DRender::QGeometryRenderer *renderer =
new Qt3DRender::QGeometryRenderer;
203 renderer->setPrimitiveType( Qt3DRender::QGeometryRenderer::LineStripAdjacency );
204 renderer->setGeometry( outEdges.createGeometry( entity ) );
205 renderer->setVertexCount( outEdges.indexes.count() );
206 renderer->setPrimitiveRestartEnabled(
true );
207 renderer->setRestartIndexValue( 0 );
210 entity->addComponent( renderer );
211 entity->addComponent( mat );
212 entity->setParent( parent );
217 void QgsPolygon3DSymbolHandler::makeEntity( Qt3DCore::QEntity *parent,
const Qgs3DRenderContext &context, PolygonData &out,
bool selected )
219 if ( out.tessellator->dataVerticesCount() == 0 )
222 Qt3DExtras::QPhongMaterial *mat = material( mSymbol );
226 mat->setDiffuse( context.map().selectionColor() );
227 mat->setAmbient( context.map().selectionColor().darker() );
231 QByteArray data( (
const char * )out.tessellator->data().constData(), out.tessellator->data().count() *
sizeof( float ) );
232 int nVerts = data.count() / out.tessellator->stride();
237 geometry->
setData( data, nVerts, out.triangleIndexFids, out.triangleIndexStartingIndices );
239 Qt3DRender::QGeometryRenderer *renderer =
new Qt3DRender::QGeometryRenderer;
240 renderer->setGeometry( geometry );
243 Qt3DCore::QEntity *entity =
new Qt3DCore::QEntity;
244 entity->addComponent( renderer );
245 entity->addComponent( mat );
246 entity->setParent( parent );
249 entity->findChild<Qt3DRender::QGeometryRenderer *>()->setObjectName( QStringLiteral(
"main" ) );
262 return Qt3DRender::QCullFace::NoCulling;
265 Qt3DExtras::QPhongMaterial *QgsPolygon3DSymbolHandler::material(
const QgsPolygon3DSymbol &symbol )
const 267 Qt3DExtras::QPhongMaterial *material =
new Qt3DExtras::QPhongMaterial;
270 auto techniques = material->effect()->techniques();
271 for (
auto tit = techniques.constBegin(); tit != techniques.constEnd(); ++tit )
273 auto renderPasses = ( *tit )->renderPasses();
274 for (
auto rpit = renderPasses.begin(); rpit != renderPasses.end(); ++rpit )
276 Qt3DRender::QCullFace *cullFace =
new Qt3DRender::QCullFace;
277 cullFace->setMode( _qt3DcullingMode( symbol.
cullingMode() ) );
278 ( *rpit )->addRenderState( cullFace );
293 namespace Qgs3DSymbolImpl
304 QgsFeature3DHandler *handler = handlerForPolygon3DSymbol( layer, symbol );
305 Qt3DCore::QEntity *e = entityFromHandler( handler, map, layer );
float shininess() const
Returns shininess of the surface.
QSet< QgsFeatureId > QgsFeatureIds
void setInvertNormals(bool invert)
Sets whether the normals of triangles will be inverted (useful for fixing clockwise / counter-clockwi...
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...
QColor specular() const
Returns specular color component.
const QgsCurve * interiorRing(int i) const
Retrieves an interior ring from the curve polygon.
3 3D symbol that draws polygon geometries as planar polygons, optionally extruded (with added walls)...
CullingMode
Triangle culling mode.
QgsPropertyCollection & dataDefinedProperties()
Returns a reference to the symbol layer's property collection, used for data defined overrides...
Extrusion height (zero means no extrusion)
A geometry is the spatial representation of a feature.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Will not render anything.
QgsPhongMaterialSettings material() const
Returns material used for shading of the symbol.
3 Definition of the world
bool isActive(int key) const override
Returns true if the collection contains an active property with the specified key.
Class that takes care of tessellation of polygons into triangles.
int numInteriorRings() const
Returns the number of interior rings contained with the curve polygon.
Will render only front faces of triangles (recommended when input data are consistent) ...
Q_INVOKABLE const QgsFeatureIds & selectedFeatureIds() const
Returns a list of the selected features IDs in this layer.
Will render only back faces of triangles.
Will render both front and back faces of triangles.
3 Class derived from Qt3DRender::QGeometry that represents polygons tessellated into 3D geometry...
void setAddBackFaces(bool add)
Sets whether also triangles facing the other side will be created.
Abstract base class for all geometries.
QgsWkbTypes::Type wkbType() const
Returns the WKB type of the geometry.
Qgs3DTypes::CullingMode cullingMode() const
Returns front/back culling mode.
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.
const QgsAbstractGeometry * constGet() const
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
QSet< QString > referencedFields(const QgsExpressionContext &context=QgsExpressionContext()) const override
Returns the set of any fields referenced by the active properties from the collection.
Multi polygon geometry collection.
static bool isCurvedType(Type type)
Returns true if the WKB type is a curved type or can contain curved geometries.
Line string geometry type, with support for z-dimension and m-values.
QgsPolygon * clone() const override
Clones the geometry by performing a deep copy.
QColor ambient() const
Returns ambient color component.
A grouped map of multiple QgsProperty objects, each referenced by a integer key value.
static void clampAltitudes(QgsLineString *lineString, Qgs3DTypes::AltitudeClamping altClamp, Qgs3DTypes::AltitudeBinding altBind, const QgsPoint ¢roid, float height, const Qgs3DMapSettings &map)
Clamps altitude of vertices of a linestring according to the settings.
QColor diffuse() const
Returns diffuse color component.
const QgsCurve * exteriorRing() const
Returns the curve polygon's exterior ring.
Represents a vector layer which manages a vector based data sets.
static Type flatType(Type type)
Returns the flat type for a WKB type.
virtual QgsAbstractGeometry * segmentize(double tolerance=M_PI/180., SegmentationToleranceType toleranceType=MaximumAngle) const
Returns a version of the geometry without curves.