39#include <Qt3DCore/QAttribute>
40#include <Qt3DCore/QBuffer>
41#include <Qt3DCore/QTransform>
42#include <Qt3DRender/QGeometryRenderer>
44using namespace Qt::StringLiterals;
51class QgsBufferedLine3DSymbolHandler :
public QgsFeature3DHandler
54 QgsBufferedLine3DSymbolHandler(
const QgsLine3DSymbol *symbol,
const QgsFeatureIds &selectedIds )
55 : mSymbol( static_cast<QgsLine3DSymbol *>( symbol->clone() ) )
56 , mSelectedIds( selectedIds )
59 bool prepare(
const Qgs3DRenderContext &context, QSet<QString> &attributeNames,
const QgsBox3D &chunkExtent )
override;
60 void processFeature(
const QgsFeature &feature,
const Qgs3DRenderContext &context )
override;
61 void finalize( Qt3DCore::QEntity *parent,
const Qgs3DRenderContext &context )
override;
67 std::unique_ptr<QgsTessellator> tessellator;
68 QVector<QgsFeatureId> triangleIndexFids;
69 QVector<uint> triangleIndexStartingIndices;
72 void processPolygon( QgsPolygon *polyBuffered,
QgsFeatureId fid,
float height,
float extrusionHeight,
const Qgs3DRenderContext &context, LineData &lineData );
74 void makeEntity( Qt3DCore::QEntity *parent,
const Qgs3DRenderContext &context, LineData &lineData,
bool selected );
77 std::unique_ptr<QgsLine3DSymbol> mSymbol;
81 LineData mLineDataNormal;
82 LineData mLineDataSelected;
86bool QgsBufferedLine3DSymbolHandler::prepare(
const Qgs3DRenderContext &, QSet<QString> &attributeNames,
const QgsBox3D &chunkExtent )
88 Q_UNUSED( attributeNames )
90 mChunkOrigin = chunkExtent.
center();
91 mChunkOrigin.
setZ( 0. );
92 mChunkExtent = chunkExtent;
94 const bool requiresTextureCoordinates = mSymbol->materialSettings() && mSymbol->materialSettings()->requiresTextureCoordinates();
95 const bool requiresTangents = mSymbol->materialSettings() && mSymbol->materialSettings()->requiresTangents();
97 auto lineDataNormalTessellator = std::make_unique<QgsTessellator>();
98 lineDataNormalTessellator->setOrigin( mChunkOrigin );
99 lineDataNormalTessellator->setAddNormals(
true );
100 lineDataNormalTessellator->setAddTextureUVs( requiresTextureCoordinates );
101 lineDataNormalTessellator->setAddTangents( requiresTangents );
105 mLineDataNormal.tessellator = std::move( lineDataNormalTessellator );
107 auto lineDataSelectedTessellator = std::make_unique<QgsTessellator>();
108 lineDataSelectedTessellator->setOrigin( mChunkOrigin );
109 lineDataSelectedTessellator->setAddNormals(
true );
110 lineDataSelectedTessellator->setAddTextureUVs( requiresTextureCoordinates );
111 lineDataSelectedTessellator->setAddTangents( requiresTangents );
115 mLineDataSelected.tessellator = std::move( lineDataSelectedTessellator );
125 LineData &lineData = mSelectedIds.contains( feature.
id() ) ? mLineDataSelected : mLineDataNormal;
128 clipGeometryIfTooLarge( geom );
143 const int nSegments = 4;
146 const double mitreLimit = 0;
148 const QgsGeos engine( abstractGeom );
150 double width = mSymbol->width();
158 QgsAbstractGeometry *buffered = engine.buffer( width / 2., nSegments, endCapStyle, joinStyle, mitreLimit );
165 processPolygon( polyBuffered, feature.
id(), mSymbol->offset(), mSymbol->extrusionHeight(), context, lineData );
173 processPolygon( polyBuffered, feature.
id(), mSymbol->offset(), mSymbol->extrusionHeight(), context, lineData );
184 Q_ASSERT( lineData.tessellator->dataVerticesCount() % 3 == 0 );
185 const uint startingTriangleIndex =
static_cast<uint
>( lineData.tessellator->dataVerticesCount() / 3 );
186 lineData.triangleIndexStartingIndices.append( startingTriangleIndex );
187 lineData.triangleIndexFids.append( fid );
188 lineData.tessellator->addPolygon( *polyBuffered, extrusionHeight );
189 if ( !lineData.tessellator->error().isEmpty() )
197void QgsBufferedLine3DSymbolHandler::finalize( Qt3DCore::QEntity *parent,
const Qgs3DRenderContext &context )
200 makeEntity( parent, context, mLineDataNormal,
false );
201 makeEntity( parent, context, mLineDataSelected,
true );
203 mZMin = std::min( mLineDataNormal.tessellator->zMinimum(), mLineDataSelected.tessellator->zMinimum() );
204 mZMax = std::max( mLineDataNormal.tessellator->zMaximum(), mLineDataSelected.tessellator->zMaximum() );
208void QgsBufferedLine3DSymbolHandler::makeEntity( Qt3DCore::QEntity *parent,
const Qgs3DRenderContext &context, LineData &lineData,
bool selected )
210 if ( lineData.tessellator->dataVerticesCount() == 0 )
220 const QByteArray vertexBuffer = lineData.tessellator->vertexBuffer();
221 const QByteArray indexBuffer = lineData.tessellator->indexBuffer();
222 const int vertexCount = vertexBuffer.count() / lineData.tessellator->stride();
223 const size_t indexCount = lineData.tessellator->dataVerticesCount();
226 true,
false,
false, mSymbol->materialSettings() && mSymbol->materialSettings()->requiresTextureCoordinates(), mSymbol->materialSettings() && mSymbol->materialSettings()->requiresTangents()
228 geometry->
setVertexBufferData( vertexBuffer, vertexCount, lineData.triangleIndexFids, lineData.triangleIndexStartingIndices );
231 Qt3DRender::QGeometryRenderer *renderer =
new Qt3DRender::QGeometryRenderer;
232 renderer->setGeometry( geometry );
235 QgsGeoTransform *transform =
new QgsGeoTransform;
236 transform->setGeoTranslation( mChunkOrigin );
239 Qt3DCore::QEntity *entity =
new Qt3DCore::QEntity;
240 entity->addComponent( renderer );
241 entity->addComponent( material );
242 entity->addComponent( transform );
243 entity->setParent( parent );
256class QgsThickLine3DSymbolHandler :
public QgsFeature3DHandler
259 QgsThickLine3DSymbolHandler(
const QgsLine3DSymbol *symbol,
const QgsFeatureIds &selectedIds )
260 : mSymbol( static_cast<QgsLine3DSymbol *>( symbol->clone() ) )
261 , mSelectedIds( selectedIds )
264 bool prepare(
const Qgs3DRenderContext &context, QSet<QString> &attributeNames,
const QgsBox3D &chunkExtent )
override;
265 void processFeature(
const QgsFeature &feature,
const Qgs3DRenderContext &context )
override;
266 void finalize( Qt3DCore::QEntity *parent,
const Qgs3DRenderContext &context )
override;
269 void makeEntity( Qt3DCore::QEntity *parent,
const Qgs3DRenderContext &context, QgsLineVertexData &lineVertexData,
bool selected );
270 void processMaterialDatadefined( uint count,
const QgsExpressionContext &context, QByteArray &target );
273 std::unique_ptr<QgsLine3DSymbol> mSymbol;
277 QgsLineVertexData mLineDataNormal;
278 QgsLineVertexData mLineDataSelected;
282bool QgsThickLine3DSymbolHandler::prepare(
const Qgs3DRenderContext &context, QSet<QString> &attributeNames,
const QgsBox3D &chunkExtent )
284 Q_UNUSED( attributeNames )
286 mChunkOrigin = chunkExtent.
center();
287 mChunkExtent = chunkExtent;
289 mLineDataNormal.init( mSymbol->altitudeClamping(), mSymbol->altitudeBinding(), mSymbol->offset(), context, mChunkOrigin );
290 mLineDataSelected.init( mSymbol->altitudeClamping(), mSymbol->altitudeBinding(), mSymbol->offset(), context, mChunkOrigin );
292 QSet<QString> attrs = mSymbol->dataDefinedProperties().referencedFields( context.
expressionContext() );
293 attributeNames.unite( attrs );
294 attrs = mSymbol->materialSettings()->dataDefinedProperties().referencedFields( context.
expressionContext() );
295 attributeNames.unite( attrs );
305 QgsLineVertexData &lineVertexData = mSelectedIds.
contains( feature.
id() ) ? mLineDataSelected : mLineDataNormal;
307 const int oldSegmentCount = lineVertexData.pointsA.size();
308 const int oldJoinCount = lineVertexData.joinPointA.size();
311 ( void ) clipGeometryIfTooLarge( geom );
327 lineVertexData.addLineString( *lineString );
331 for (
int nGeom = 0; nGeom < multiLineString->numGeometries(); ++nGeom )
333 const QgsLineString *lineString = multiLineString->lineStringN( nGeom );
334 lineVertexData.addLineString( *lineString );
340 processMaterialDatadefined( lineVertexData.pointsA.size() - oldSegmentCount, context.
expressionContext(), lineVertexData.materialDataDefined );
341 processMaterialDatadefined( lineVertexData.joinPointA.size() - oldJoinCount, context.
expressionContext(), lineVertexData.materialDataDefinedJoins );
347void QgsThickLine3DSymbolHandler::finalize( Qt3DCore::QEntity *parent,
const Qgs3DRenderContext &context )
350 makeEntity( parent, context, mLineDataNormal,
false );
351 makeEntity( parent, context, mLineDataSelected,
true );
353 updateZRangeFromPositions( mLineDataNormal.vertices );
354 updateZRangeFromPositions( mLineDataSelected.vertices );
358void QgsThickLine3DSymbolHandler::makeEntity( Qt3DCore::QEntity *parent,
const Qgs3DRenderContext &context, QgsLineVertexData &lineVertexData,
bool selected )
360 if ( lineVertexData.pointsA.isEmpty() )
374 QgsLineMaterial *lineMaterial =
dynamic_cast<QgsLineMaterial *
>( material );
377 float width = mSymbol->width();
378 if ( mHighlightingEnabled )
382 lineMaterial->setLineColor( color );
389 lineMaterial->setLineWidth( width );
395 Qt3DCore::QEntity *entity = lineVertexData.createSegmentEntity( material, hasDataDefinedColor ? mSymbol->materialSettings() :
nullptr, handler );
398 QgsGeoTransform *transform =
new QgsGeoTransform;
399 transform->setGeoTranslation( mChunkOrigin );
401 entity->addComponent( transform );
402 entity->setParent( parent );
406 if ( Qt3DCore::QEntity *joinEntity = lineVertexData.createJoinEntity( lineMaterial, hasDataDefinedColor ? mSymbol->materialSettings() :
nullptr, handler ) )
408 QgsGeoTransform *joinTransform =
new QgsGeoTransform;
409 joinTransform->setGeoTranslation( mChunkOrigin );
410 joinEntity->addComponent( joinTransform );
411 joinEntity->setParent( parent );
416void QgsThickLine3DSymbolHandler::processMaterialDatadefined( uint count,
const QgsExpressionContext &context, QByteArray &target )
423 target.append( bytes.repeated(
static_cast<int>( count ) ) );
429namespace Qgs3DSymbolImpl
432 QgsFeature3DHandler *handlerForLine3DSymbol(
const QgsVectorLayer *layer,
const QgsAbstract3DSymbol *symbol )
434 const QgsLine3DSymbol *lineSymbol =
dynamic_cast<const QgsLine3DSymbol *
>( symbol );
static const QColor DEFAULT_HIGHLIGHT_COLOR
Default highlight color.
JoinStyle
Join styles for buffers.
@ Round
Use rounded joins.
EndCapStyle
End cap styles for buffers.
@ Triangles
Triangle based rendering (default).
@ Lines
Line based rendering, requires line data.
@ MultiPolygon
MultiPolygon.
Rendering context for preparation of 3D entities.
QgsExpressionContext & expressionContext()
Gets the expression context.
@ 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 Qgs3DRenderContext &context)
Clamps altitude of vertices of a linestring according to the settings.
static QgsMaterial * toMaterial(const QgsAbstractMaterialSettings *settings, Qgis::MaterialRenderingTechnique technique, const QgsMaterialContext &context)
Creates a new QgsMaterial object representing the material settings.
static const QgsAbstractMaterial3DHandler * handlerForMaterialSettings(const QgsAbstractMaterialSettings *settings)
Returns the handler to use for a material 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.
Abstract base class for material 3D handlers.
virtual QByteArray dataDefinedVertexColorsAsByte(const QgsAbstractMaterialSettings *settings, const QgsExpressionContext &expressionContext) const
Returns byte array corresponding to the data defined colors depending of the expressionContext,...
@ Ambient
Ambient color (phong material).
A 3-dimensional box composed of x, y, z coordinates.
bool contains(const QgsBox3D &other) const
Returns true when box contains other box.
QgsVector3D center() const
Returns the center of the box as a vector.
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.
bool isEmpty() const
Returns true if the geometry is empty (eg a linestring with no vertices, or a collection with no geom...
Does vector analysis using the GEOS library and handles import, export, and exception handling.
static int silhouetteWidth()
Returns the width of the generated silhouette effect in pixels.
bool renderAsSimpleLines() const
Returns whether the renderer will render data with simple lines (otherwise it uses buffer).
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 setIsHighlighted(bool isHighlighted)
Sets whether the material should represent a highlighted state.
static QgsMaterialContext fromRenderContext(const Qgs3DRenderContext &context)
Constructs a material context from the settings in a 3D render context.
Base class for all materials used within QGIS 3D views.
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(), Qgis::StringFormat format=Qgis::StringFormat::PlainText)
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.
Stores settings for use within QGIS.
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
Basic shading material used for rendering simple lines as solid line components.
Qt3DRender::QGeometry subclass that represents polygons tessellated into 3D geometry.
void setVertexBufferData(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 setIndexBufferData(const QByteArray &indexBufferData, size_t indexCount)
Sets index buffer data.
void setZ(double z)
Sets Z coordinate.
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.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference).
T qgsgeometry_cast(QgsAbstractGeometry *geom)
QSet< QgsFeatureId > QgsFeatureIds
qint64 QgsFeatureId
64 bit feature ids negative numbers are used for uncommitted/newly added features