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....
float textureRotation() const
Returns the texture rotation, in degrees.
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