36#include <Qt3DExtras/QPhongMaterial>
37#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
38#include <Qt3DRender/QAttribute>
39#include <Qt3DRender/QBuffer>
45#include <Qt3DCore/QAttribute>
46#include <Qt3DCore/QBuffer>
52#include <Qt3DRender/QGeometryRenderer>
59class QgsBufferedLine3DSymbolHandler :
public QgsFeature3DHandler
64 , mSelectedIds( selectedIds ) {}
66 bool prepare(
const Qgs3DRenderContext &context, QSet<QString> &attributeNames )
override;
67 void processFeature(
const QgsFeature &feature,
const Qgs3DRenderContext &context )
override;
68 void finalize( Qt3DCore::QEntity *parent,
const Qgs3DRenderContext &context )
override;
75 std::unique_ptr<QgsTessellator> tessellator;
76 QVector<QgsFeatureId> triangleIndexFids;
77 QVector<uint> triangleIndexStartingIndices;
80 void processPolygon(
QgsPolygon *polyBuffered,
QgsFeatureId fid,
float height,
float extrusionHeight,
const Qgs3DRenderContext &context, LineData &out );
82 void makeEntity( Qt3DCore::QEntity *parent,
const Qgs3DRenderContext &context, LineData &out,
bool selected );
85 std::unique_ptr< QgsLine3DSymbol > mSymbol;
96bool QgsBufferedLine3DSymbolHandler::prepare(
const Qgs3DRenderContext &context, QSet<QString> &attributeNames )
98 Q_UNUSED( attributeNames )
102 outNormal.tessellator.reset(
new QgsTessellator( context.map().origin().x(), context.map().origin().y(),
true,
105 texturedMaterialSettings ? texturedMaterialSettings->textureRotation() : 0 ) );
106 outSelected.tessellator.reset(
new QgsTessellator( context.map().origin().x(), context.map().origin().y(),
true,
109 texturedMaterialSettings ? texturedMaterialSettings->textureRotation() : 0 ) );
114void QgsBufferedLine3DSymbolHandler::processFeature(
const QgsFeature &f,
const Qgs3DRenderContext &context )
119 LineData &out = mSelectedIds.contains( f.
id() ) ? outSelected : outNormal;
132 const int nSegments = 4;
135 const double mitreLimit = 0;
139 double width = mSymbol->width();
147 QgsAbstractGeometry *buffered = engine.buffer( width / 2., nSegments, endCapStyle, joinStyle, mitreLimit );
154 processPolygon( polyBuffered, f.
id(), mSymbol->offset(), mSymbol->extrusionHeight(), context, out );
162 processPolygon( polyBuffered, f.
id(), mSymbol->offset(), mSymbol->extrusionHeight(), context, out );
169void QgsBufferedLine3DSymbolHandler::processPolygon(
QgsPolygon *polyBuffered,
QgsFeatureId fid,
float height,
float extrusionHeight,
const Qgs3DRenderContext &context, LineData &out )
173 Q_ASSERT( out.tessellator->dataVerticesCount() % 3 == 0 );
174 const uint startingTriangleIndex =
static_cast<uint
>( out.tessellator->dataVerticesCount() / 3 );
175 out.triangleIndexStartingIndices.append( startingTriangleIndex );
176 out.triangleIndexFids.append( fid );
177 out.tessellator->addPolygon( *polyBuffered, extrusionHeight );
178 if ( !out.tessellator->error().isEmpty() )
186void QgsBufferedLine3DSymbolHandler::finalize( Qt3DCore::QEntity *parent,
const Qgs3DRenderContext &context )
189 makeEntity( parent, context, outNormal,
false );
190 makeEntity( parent, context, outSelected,
true );
192 mZMin = std::min( outNormal.tessellator->zMinimum(), outSelected.tessellator->zMinimum() );
193 mZMax = std::max( outNormal.tessellator->zMaximum(), outSelected.tessellator->zMaximum() );
197void QgsBufferedLine3DSymbolHandler::makeEntity( Qt3DCore::QEntity *parent,
const Qgs3DRenderContext &context, LineData &out,
bool selected )
199 if ( out.tessellator->dataVerticesCount() == 0 )
208 const QByteArray data( (
const char * )out.tessellator->data().constData(), out.tessellator->data().count() *
sizeof(
float ) );
209 const int nVerts = data.count() / out.tessellator->stride();
215 geometry->
setData( data, nVerts, out.triangleIndexFids, out.triangleIndexStartingIndices );
217 Qt3DRender::QGeometryRenderer *renderer =
new Qt3DRender::QGeometryRenderer;
218 renderer->setGeometry( geometry );
221 Qt3DCore::QEntity *entity =
new Qt3DCore::QEntity;
222 entity->addComponent( renderer );
223 entity->addComponent( mat );
224 entity->setParent( parent );
237class QgsThickLine3DSymbolHandler :
public QgsFeature3DHandler
242 , mSelectedIds( selectedIds )
246 bool prepare(
const Qgs3DRenderContext &context, QSet<QString> &attributeNames )
override;
247 void processFeature(
const QgsFeature &feature,
const Qgs3DRenderContext &context )
override;
248 void finalize( Qt3DCore::QEntity *parent,
const Qgs3DRenderContext &context )
override;
253 void makeEntity( Qt3DCore::QEntity *parent,
const Qgs3DRenderContext &context, QgsLineVertexData &out,
bool selected );
254 Qt3DExtras::QPhongMaterial *material(
const QgsLine3DSymbol &symbol )
const;
255 void processMaterialDatadefined( uint verticesCount,
const QgsExpressionContext &context, QgsLineVertexData &out );
258 std::unique_ptr< QgsLine3DSymbol > mSymbol;
263 QgsLineVertexData outNormal;
264 QgsLineVertexData outSelected;
269bool QgsThickLine3DSymbolHandler::prepare(
const Qgs3DRenderContext &context, QSet<QString> &attributeNames )
271 Q_UNUSED( attributeNames )
273 outNormal.withAdjacency =
true;
274 outSelected.withAdjacency =
true;
275 outNormal.init( mSymbol->altitudeClamping(), mSymbol->altitudeBinding(), mSymbol->offset(), &context.map() );
276 outSelected.init( mSymbol->altitudeClamping(), mSymbol->altitudeBinding(), mSymbol->offset(), &context.map() );
278 QSet<QString> attrs = mSymbol->dataDefinedProperties().referencedFields( context.expressionContext() );
279 attributeNames.unite( attrs );
280 attrs = mSymbol->materialSettings()->dataDefinedProperties().referencedFields( context.expressionContext() );
281 attributeNames.unite( attrs );
285 processMaterialDatadefined( outNormal.vertices.size(), context.expressionContext(), outNormal );
286 processMaterialDatadefined( outSelected.vertices.size(), context.expressionContext(), outSelected );
292void QgsThickLine3DSymbolHandler::processFeature(
const QgsFeature &f,
const Qgs3DRenderContext &context )
298 QgsLineVertexData &out = mSelectedIds.contains( f.
id() ) ? outSelected : outNormal;
300 const int oldVerticesCount = out.vertices.size();
312 if (
const QgsLineString *ls = qgsgeometry_cast<const QgsLineString *>( g ) )
314 out.addLineString( *ls );
316 else if (
const QgsMultiLineString *mls = qgsgeometry_cast<const QgsMultiLineString *>( g ) )
318 for (
int nGeom = 0; nGeom < mls->numGeometries(); ++nGeom )
321 out.addLineString( *ls );
326 processMaterialDatadefined( out.vertices.size() - oldVerticesCount, context.expressionContext(), out );
331void QgsThickLine3DSymbolHandler::finalize( Qt3DCore::QEntity *parent,
const Qgs3DRenderContext &context )
334 makeEntity( parent, context, outNormal,
false );
335 makeEntity( parent, context, outSelected,
true );
337 updateZRangeFromPositions( outNormal.vertices );
338 updateZRangeFromPositions( outSelected.vertices );
342void QgsThickLine3DSymbolHandler::makeEntity( Qt3DCore::QEntity *parent,
const Qgs3DRenderContext &context, QgsLineVertexData &out,
bool selected )
344 if ( out.indexes.isEmpty() )
358 if ( QgsLineMaterial *lineMaterial =
dynamic_cast< QgsLineMaterial *
>( mat ) )
359 lineMaterial->setLineWidth( mSymbol->width() );
361 Qt3DCore::QEntity *entity =
new Qt3DCore::QEntity;
364 Qt3DRender::QGeometryRenderer *renderer =
new Qt3DRender::QGeometryRenderer;
365 renderer->setPrimitiveType( Qt3DRender::QGeometryRenderer::LineStripAdjacency );
369 mSymbol->materialSettings()->applyDataDefinedToGeometry( geometry, out.vertices.size(), out.materialDataDefined );
371 renderer->setGeometry( geometry );
373 renderer->setVertexCount( out.indexes.count() );
374 renderer->setPrimitiveRestartEnabled(
true );
375 renderer->setRestartIndexValue( 0 );
378 entity->addComponent( renderer );
379 entity->addComponent( mat );
380 entity->setParent( parent );
383void QgsThickLine3DSymbolHandler::processMaterialDatadefined( uint verticesCount,
const QgsExpressionContext &context, QgsLineVertexData &out )
385 const QByteArray bytes = mSymbol->materialSettings()->dataDefinedVertexColorsAsByte( context );
386 out.materialDataDefined.append( bytes.repeated( verticesCount ) );
393namespace Qgs3DSymbolImpl
410 QgsFeature3DHandler *handler = handlerForLine3DSymbol( layer, &symbol );
411 Qt3DCore::QEntity *e = entityFromHandler( handler, map, layer );
JoinStyle
Join styles for buffers.
@ Round
Use rounded joins.
EndCapStyle
End cap styles for buffers.
@ MultiPolygon
MultiPolygon.
@ Main3DRenderer
Renderer for normal entities.
static const char * PROP_NAME_3D_RENDERER_FLAG
Qt property name to hold the 3D geometry renderer flag.
static void clampAltitudes(QgsLineString *lineString, Qgis::AltitudeClamping altClamp, Qgis::AltitudeBinding altBind, const QgsPoint ¢roid, float offset, const Qgs3DMapSettings &map)
Clamps altitude of vertices of a linestring according to the settings.
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...
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, exception handling*.
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.
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 line string geometry collection.
Multi polygon geometry collection.
QgsPolygon * polygonN(int index)
Returns the polygon with the specified index.
bool requiresTextureCoordinates() const
Returns true if the material requires texture coordinates to be generated during triangulation....
Qt3DRender::QMaterial * toMaterial(QgsMaterialSettingsRenderingTechnique technique, const QgsMaterialContext &context) const override
Creates a new QMaterial object representing the material settings.
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.
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.
@ 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)
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