37#include <Qt3DCore/QAttribute>
38#include <Qt3DCore/QBuffer>
39#include <Qt3DCore/QTransform>
40#include <Qt3DExtras/QPhongMaterial>
41#include <Qt3DRender/QGeometryRenderer>
43using namespace Qt::StringLiterals;
50class QgsBufferedLine3DSymbolHandler :
public QgsFeature3DHandler
53 QgsBufferedLine3DSymbolHandler(
const QgsLine3DSymbol *symbol,
const QgsFeatureIds &selectedIds )
54 : mSymbol( static_cast<QgsLine3DSymbol *>( symbol->clone() ) )
55 , mSelectedIds( selectedIds ) {}
57 bool prepare(
const Qgs3DRenderContext &context, QSet<QString> &attributeNames,
const QgsBox3D &chunkExtent )
override;
58 void processFeature(
const QgsFeature &feature,
const Qgs3DRenderContext &context )
override;
59 void finalize( Qt3DCore::QEntity *parent,
const Qgs3DRenderContext &context )
override;
65 std::unique_ptr<QgsTessellator> tessellator;
66 QVector<QgsFeatureId> triangleIndexFids;
67 QVector<uint> triangleIndexStartingIndices;
70 void processPolygon( QgsPolygon *polyBuffered,
QgsFeatureId fid,
float height,
float extrusionHeight,
const Qgs3DRenderContext &context, LineData &lineData );
72 void makeEntity( Qt3DCore::QEntity *parent,
const Qgs3DRenderContext &context, LineData &lineData,
bool selected );
75 std::unique_ptr<QgsLine3DSymbol> mSymbol;
79 LineData mLineDataNormal;
80 LineData mLineDataSelected;
84bool QgsBufferedLine3DSymbolHandler::prepare(
const Qgs3DRenderContext &, QSet<QString> &attributeNames,
const QgsBox3D &chunkExtent )
86 Q_UNUSED( attributeNames )
88 mChunkOrigin = chunkExtent.
center();
89 mChunkOrigin.
setZ( 0. );
90 mChunkExtent = chunkExtent;
94 const float textureRotation = texturedMaterialSettings ?
static_cast<float>( texturedMaterialSettings->
textureRotation() ) : 0;
95 const bool requiresTextureCoordinates = texturedMaterialSettings ? texturedMaterialSettings->
requiresTextureCoordinates() :
false;
97 auto lineDataNormalTessellator = std::make_unique<QgsTessellator>();
98 lineDataNormalTessellator->setOrigin( mChunkOrigin );
99 lineDataNormalTessellator->setAddNormals(
true );
100 lineDataNormalTessellator->setAddTextureUVs( requiresTextureCoordinates );
102 lineDataNormalTessellator->setTextureRotation( textureRotation );
104 mLineDataNormal.tessellator = std::move( lineDataNormalTessellator );
106 auto lineDataSelectedTessellator = std::make_unique<QgsTessellator>();
107 lineDataSelectedTessellator->setOrigin( mChunkOrigin );
108 lineDataSelectedTessellator->setAddNormals(
true );
109 lineDataSelectedTessellator->setAddTextureUVs( requiresTextureCoordinates );
111 lineDataSelectedTessellator->setTextureRotation( textureRotation );
113 mLineDataSelected.tessellator = std::move( lineDataSelectedTessellator );
115 mLineDataNormal.tessellator->setOutputZUp(
true );
116 mLineDataSelected.tessellator->setOutputZUp(
true );
126 LineData &lineData = mSelectedIds.contains( feature.
id() ) ? mLineDataSelected : mLineDataNormal;
129 clipGeometryIfTooLarge( geom );
144 const int nSegments = 4;
147 const double mitreLimit = 0;
149 const QgsGeos engine( abstractGeom );
151 double width = mSymbol->width();
159 QgsAbstractGeometry *buffered = engine.buffer( width / 2., nSegments, endCapStyle, joinStyle, mitreLimit );
166 processPolygon( polyBuffered, feature.
id(), mSymbol->offset(), mSymbol->extrusionHeight(), context, lineData );
174 processPolygon( polyBuffered, feature.
id(), mSymbol->offset(), mSymbol->extrusionHeight(), context, lineData );
185 Q_ASSERT( lineData.tessellator->dataVerticesCount() % 3 == 0 );
186 const uint startingTriangleIndex =
static_cast<uint
>( lineData.tessellator->dataVerticesCount() / 3 );
187 lineData.triangleIndexStartingIndices.append( startingTriangleIndex );
188 lineData.triangleIndexFids.append( fid );
189 lineData.tessellator->addPolygon( *polyBuffered, extrusionHeight );
190 if ( !lineData.tessellator->error().isEmpty() )
198void QgsBufferedLine3DSymbolHandler::finalize( Qt3DCore::QEntity *parent,
const Qgs3DRenderContext &context )
201 makeEntity( parent, context, mLineDataNormal,
false );
202 makeEntity( parent, context, mLineDataSelected,
true );
204 mZMin = std::min( mLineDataNormal.tessellator->zMinimum(), mLineDataSelected.tessellator->zMinimum() );
205 mZMax = std::max( mLineDataNormal.tessellator->zMaximum(), mLineDataSelected.tessellator->zMaximum() );
209void QgsBufferedLine3DSymbolHandler::makeEntity( Qt3DCore::QEntity *parent,
const Qgs3DRenderContext &context, LineData &lineData,
bool selected )
211 if ( lineData.tessellator->dataVerticesCount() == 0 )
221 const QByteArray data( (
const char * ) lineData.tessellator->data().constData(),
static_cast<int>( lineData.tessellator->data().count() *
sizeof(
float ) ) );
222 const int nVerts = data.count() / lineData.tessellator->stride();
227 geometry->
setData( data, nVerts, lineData.triangleIndexFids, lineData.triangleIndexStartingIndices );
229 Qt3DRender::QGeometryRenderer *renderer =
new Qt3DRender::QGeometryRenderer;
230 renderer->setGeometry( geometry );
233 QgsGeoTransform *transform =
new QgsGeoTransform;
234 transform->setGeoTranslation( mChunkOrigin );
237 Qt3DCore::QEntity *entity =
new Qt3DCore::QEntity;
238 entity->addComponent( renderer );
239 entity->addComponent( material );
240 entity->addComponent( transform );
241 entity->setParent( parent );
254class QgsThickLine3DSymbolHandler :
public QgsFeature3DHandler
257 QgsThickLine3DSymbolHandler(
const QgsLine3DSymbol *symbol,
const QgsFeatureIds &selectedIds )
258 : mSymbol( static_cast<QgsLine3DSymbol *>( symbol->clone() ) )
259 , mSelectedIds( selectedIds )
263 bool prepare(
const Qgs3DRenderContext &context, QSet<QString> &attributeNames,
const QgsBox3D &chunkExtent )
override;
264 void processFeature(
const QgsFeature &feature,
const Qgs3DRenderContext &context )
override;
265 void finalize( Qt3DCore::QEntity *parent,
const Qgs3DRenderContext &context )
override;
268 void makeEntity( Qt3DCore::QEntity *parent,
const Qgs3DRenderContext &context, QgsLineVertexData &lineVertexData,
bool selected );
269 Qt3DExtras::QPhongMaterial *material(
const QgsLine3DSymbol &symbol )
const;
270 void processMaterialDatadefined( uint verticesCount,
const QgsExpressionContext &context, QgsLineVertexData &lineVertexData );
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.withAdjacency =
true;
290 mLineDataSelected.withAdjacency =
true;
291 mLineDataNormal.init( mSymbol->altitudeClamping(), mSymbol->altitudeBinding(), mSymbol->offset(), context, mChunkOrigin );
292 mLineDataSelected.init( mSymbol->altitudeClamping(), mSymbol->altitudeBinding(), mSymbol->offset(), context, mChunkOrigin );
294 QSet<QString> attrs = mSymbol->dataDefinedProperties().referencedFields( context.
expressionContext() );
295 attributeNames.unite( attrs );
296 attrs = mSymbol->materialSettings()->dataDefinedProperties().referencedFields( context.
expressionContext() );
297 attributeNames.unite( attrs );
301 processMaterialDatadefined( mLineDataNormal.vertices.size(), context.
expressionContext(), mLineDataNormal );
302 processMaterialDatadefined( mLineDataSelected.vertices.size(), context.
expressionContext(), mLineDataSelected );
314 QgsLineVertexData &lineVertexData = mSelectedIds.
contains( feature.
id() ) ? mLineDataSelected : mLineDataNormal;
316 const int oldVerticesCount = lineVertexData.vertices.size();
319 ( void ) clipGeometryIfTooLarge( geom );
335 lineVertexData.addLineString( *lineString );
339 for (
int nGeom = 0; nGeom < multiLineString->numGeometries(); ++nGeom )
341 const QgsLineString *lineString = multiLineString->lineStringN( nGeom );
342 lineVertexData.addLineString( *lineString );
347 processMaterialDatadefined( lineVertexData.vertices.size() - oldVerticesCount, context.
expressionContext(), lineVertexData );
352void QgsThickLine3DSymbolHandler::finalize( Qt3DCore::QEntity *parent,
const Qgs3DRenderContext &context )
355 makeEntity( parent, context, mLineDataNormal,
false );
356 makeEntity( parent, context, mLineDataSelected,
true );
358 updateZRangeFromPositions( mLineDataNormal.vertices );
359 updateZRangeFromPositions( mLineDataSelected.vertices );
363void QgsThickLine3DSymbolHandler::makeEntity( Qt3DCore::QEntity *parent,
const Qgs3DRenderContext &context, QgsLineVertexData &lineVertexData,
bool selected )
365 if ( lineVertexData.indexes.isEmpty() )
379 if ( QgsLineMaterial *lineMaterial =
dynamic_cast<QgsLineMaterial *
>( material ) )
381 float width = mSymbol->width();
382 if ( mHighlightingEnabled )
386 lineMaterial->setLineColor( color );
393 lineMaterial->setLineWidth( width );
396 Qt3DCore::QEntity *entity =
new Qt3DCore::QEntity;
399 Qt3DRender::QGeometryRenderer *renderer =
new Qt3DRender::QGeometryRenderer;
400 renderer->setPrimitiveType( Qt3DRender::QGeometryRenderer::LineStripAdjacency );
401 Qt3DCore::QGeometry *geometry = lineVertexData.createGeometry( entity );
404 mSymbol->materialSettings()->applyDataDefinedToGeometry( geometry, lineVertexData.vertices.size(), lineVertexData.materialDataDefined );
406 renderer->setGeometry( geometry );
408 renderer->setVertexCount( lineVertexData.indexes.count() );
409 renderer->setPrimitiveRestartEnabled(
true );
410 renderer->setRestartIndexValue( 0 );
413 QgsGeoTransform *transform =
new QgsGeoTransform;
414 transform->setGeoTranslation( mChunkOrigin );
417 entity->addComponent( renderer );
418 entity->addComponent( material );
419 entity->addComponent( transform );
420 entity->setParent( parent );
423void QgsThickLine3DSymbolHandler::processMaterialDatadefined( uint verticesCount,
const QgsExpressionContext &context, QgsLineVertexData &lineVertexData )
425 const QByteArray bytes = mSymbol->materialSettings()->dataDefinedVertexColorsAsByte( context );
426 lineVertexData.materialDataDefined.append( bytes.repeated(
static_cast<int>( verticesCount ) ) );
433namespace Qgs3DSymbolImpl
436 QgsFeature3DHandler *handlerForLine3DSymbol( QgsVectorLayer *layer,
const QgsAbstract3DSymbol *symbol )
438 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.
@ MultiPolygon
MultiPolygon.
Rendering context for preparation of 3D entities.
QColor selectionColor() const
Returns color used for selected features.
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.
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).
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 setSelectionColor(const QColor &color)
Sets the color for representing materials in a selected state.
void setIsHighlighted(bool isHighlighted)
Sets whether the material should represent a highlighted state.
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())
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.
A Phong shading model with diffuse texture map.
bool requiresTextureCoordinates() const
Returns true if the material requires texture coordinates to be generated during triangulation....
double textureRotation() const
Returns the texture rotation, in degrees.
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.
QgsMaterial * toMaterial(QgsMaterialSettingsRenderingTechnique technique, const QgsMaterialContext &context) const override
Creates a new QgsMaterial object representing the material settings.
Qt3DRender::QGeometry subclass that represents polygons tessellated into 3D geometry.
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.
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.
@ 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).
T qgsgeometry_cast(QgsAbstractGeometry *geom)
QSet< QgsFeatureId > QgsFeatureIds
qint64 QgsFeatureId
64 bit feature ids negative numbers are used for uncommitted/newly added features