diff --git a/src/3d/qgsvectorlayer3drenderer.cpp b/src/3d/qgsvectorlayer3drenderer.cpp index 45f059dfb415..882d07fe019c 100644 --- a/src/3d/qgsvectorlayer3drenderer.cpp +++ b/src/3d/qgsvectorlayer3drenderer.cpp @@ -86,7 +86,7 @@ Qt3DCore::QEntity *QgsVectorLayer3DRenderer::createEntity( const Qgs3DMapSetting else if ( mSymbol->type() == QLatin1String( "point" ) ) return new QgsPoint3DSymbolEntity( map, vl, *static_cast( mSymbol.get() ) ); else if ( mSymbol->type() == QLatin1String( "line" ) ) - return new QgsLine3DSymbolEntity( map, vl, *static_cast( mSymbol.get() ) ); + return Qgs3DSymbolImpl::entityForLine3DSymbol( map, vl, *static_cast( mSymbol.get() ) ); else return nullptr; } diff --git a/src/3d/symbols/qgsline3dsymbol_p.cpp b/src/3d/symbols/qgsline3dsymbol_p.cpp index 329de15d8efc..33081905d6be 100644 --- a/src/3d/symbols/qgsline3dsymbol_p.cpp +++ b/src/3d/symbols/qgsline3dsymbol_p.cpp @@ -26,19 +26,15 @@ #include "qgsmultipolygon.h" #include "qgsgeos.h" +#include #include #include +#include /// @cond PRIVATE -QgsLine3DSymbolEntity::QgsLine3DSymbolEntity( const Qgs3DMapSettings &map, QgsVectorLayer *layer, const QgsLine3DSymbol &symbol, Qt3DCore::QNode *parent ) - : Qt3DCore::QEntity( parent ) -{ - addEntityForSelectedLines( map, layer, symbol ); - addEntityForNotSelectedLines( map, layer, symbol ); -} -Qt3DExtras::QPhongMaterial *QgsLine3DSymbolEntity::material( const QgsLine3DSymbol &symbol ) const +static Qt3DExtras::QPhongMaterial *_material( const QgsLine3DSymbol &symbol ) { Qt3DExtras::QPhongMaterial *material = new Qt3DExtras::QPhongMaterial; @@ -50,169 +46,257 @@ Qt3DExtras::QPhongMaterial *QgsLine3DSymbolEntity::material( const QgsLine3DSymb return material; } -void QgsLine3DSymbolEntity::addEntityForSelectedLines( const Qgs3DMapSettings &map, QgsVectorLayer *layer, const QgsLine3DSymbol &symbol ) + +// ----------- + + +class QgsBufferedLine3DSymbolHandler : public QgsFeature3DHandler { - // build the default material - Qt3DExtras::QPhongMaterial *mat = material( symbol ); + public: + QgsBufferedLine3DSymbolHandler( const QgsLine3DSymbol &symbol, const QgsFeatureIds &selectedIds ) + : mSymbol( symbol ), mSelectedIds( selectedIds ) {} - // update the material with selection colors - mat->setDiffuse( map.selectionColor() ); - mat->setAmbient( map.selectionColor().darker() ); + bool prepare( const Qgs3DRenderContext &context, QSet &attributeNames ) override; + void processFeature( QgsFeature &feature, const Qgs3DRenderContext &context ) override; + void finalize( Qt3DCore::QEntity *parent, const Qgs3DRenderContext &context ) override; - // build the feature request to select features - QgsFeatureRequest req; - req.setDestinationCrs( map.crs(), map.transformContext() ); - req.setFilterFids( layer->selectedFeatureIds() ); + private: - // build the entity - QgsLine3DSymbolEntityNode *entity = new QgsLine3DSymbolEntityNode( map, layer, symbol, req ); - entity->addComponent( mat ); - entity->setParent( this ); + //! temporary data we will pass to the tessellator + struct LineData + { + QList polygons; + QList fids; + }; + + void makeEntity( Qt3DCore::QEntity *parent, const Qgs3DRenderContext &context, LineData &out, bool selected ); + + // input specific for this class + const QgsLine3DSymbol &mSymbol; + // inputs - generic + QgsFeatureIds mSelectedIds; + + // outputs + LineData outNormal; //!< Features that are not selected + LineData outSelected; //!< Features that are selected +}; + + + +bool QgsBufferedLine3DSymbolHandler::prepare( const Qgs3DRenderContext &context, QSet &attributeNames ) +{ + Q_UNUSED( context ); + Q_UNUSED( attributeNames ); + return true; } -void QgsLine3DSymbolEntity::addEntityForNotSelectedLines( const Qgs3DMapSettings &map, QgsVectorLayer *layer, const QgsLine3DSymbol &symbol ) +void QgsBufferedLine3DSymbolHandler::processFeature( QgsFeature &f, const Qgs3DRenderContext &context ) { - // build the default material - Qt3DExtras::QPhongMaterial *mat = material( symbol ); + if ( f.geometry().isNull() ) + return; - // build the feature request to select features - QgsFeatureRequest req; - req.setDestinationCrs( map.crs(), map.transformContext() ); + LineData &out = mSelectedIds.contains( f.id() ) ? outSelected : outNormal; - QgsFeatureIds notSelected = layer->allFeatureIds(); - notSelected.subtract( layer->selectedFeatureIds() ); - req.setFilterFids( notSelected ); + QgsGeometry geom = f.geometry(); - // build the entity - QgsLine3DSymbolEntityNode *entity = new QgsLine3DSymbolEntityNode( map, layer, symbol, req ); - entity->findChild()->setObjectName( QStringLiteral( "main" ) ); // temporary measure to distinguish between "selected" and "main" - entity->addComponent( mat ); - entity->setParent( this ); + // segmentize curved geometries if necessary + if ( QgsWkbTypes::isCurvedType( geom.constGet()->wkbType() ) ) + geom = QgsGeometry( geom.constGet()->segmentize() ); + + const QgsAbstractGeometry *g = geom.constGet(); + + // TODO: configurable + const int nSegments = 4; + const QgsGeometry::EndCapStyle endCapStyle = QgsGeometry::CapRound; + const QgsGeometry::JoinStyle joinStyle = QgsGeometry::JoinStyleRound; + const double mitreLimit = 0; + + QgsGeos engine( g ); + QgsAbstractGeometry *buffered = engine.buffer( mSymbol.width() / 2., nSegments, endCapStyle, joinStyle, mitreLimit ); // factory + + if ( QgsWkbTypes::flatType( buffered->wkbType() ) == QgsWkbTypes::Polygon ) + { + QgsPolygon *polyBuffered = static_cast( buffered ); + Qgs3DUtils::clampAltitudes( polyBuffered, mSymbol.altitudeClamping(), mSymbol.altitudeBinding(), mSymbol.height(), context.map() ); + out.polygons.append( polyBuffered ); + out.fids.append( f.id() ); + } + else if ( QgsWkbTypes::flatType( buffered->wkbType() ) == QgsWkbTypes::MultiPolygon ) + { + QgsMultiPolygon *mpolyBuffered = static_cast( buffered ); + for ( int i = 0; i < mpolyBuffered->numGeometries(); ++i ) + { + QgsAbstractGeometry *partBuffered = mpolyBuffered->geometryN( i ); + Q_ASSERT( QgsWkbTypes::flatType( partBuffered->wkbType() ) == QgsWkbTypes::Polygon ); + QgsPolygon *polyBuffered = static_cast( partBuffered )->clone(); // need to clone individual geometry parts + Qgs3DUtils::clampAltitudes( polyBuffered, mSymbol.altitudeClamping(), mSymbol.altitudeBinding(), mSymbol.height(), context.map() ); + out.polygons.append( polyBuffered ); + out.fids.append( f.id() ); + } + delete buffered; + } } -QgsLine3DSymbolEntityNode::QgsLine3DSymbolEntityNode( const Qgs3DMapSettings &map, QgsVectorLayer *layer, const QgsLine3DSymbol &symbol, const QgsFeatureRequest &req, Qt3DCore::QNode *parent ) - : Qt3DCore::QEntity( parent ) + +void QgsBufferedLine3DSymbolHandler::finalize( Qt3DCore::QEntity *parent, const Qgs3DRenderContext &context ) { - addComponent( symbol.renderAsSimpleLines() ? rendererSimple( map, symbol, layer, req ) : renderer( map, symbol, layer, req ) ); + // create entity for selected and not selected + makeEntity( parent, context, outNormal, false ); + makeEntity( parent, context, outSelected, true ); } -Qt3DRender::QGeometryRenderer *QgsLine3DSymbolEntityNode::renderer( const Qgs3DMapSettings &map, const QgsLine3DSymbol &symbol, const QgsVectorLayer *layer, const QgsFeatureRequest &request ) + +void QgsBufferedLine3DSymbolHandler::makeEntity( Qt3DCore::QEntity *parent, const Qgs3DRenderContext &context, LineData &out, bool selected ) { - QgsPointXY origin( map.origin().x(), map.origin().y() ); + if ( out.polygons.isEmpty() ) + return; // nothing to show - no need to create the entity - // TODO: configurable - int nSegments = 4; - QgsGeometry::EndCapStyle endCapStyle = QgsGeometry::CapRound; - QgsGeometry::JoinStyle joinStyle = QgsGeometry::JoinStyleRound; - double mitreLimit = 0; - - QList polygons; - QList fids; - QgsFeature f; - QgsFeatureIterator fi = layer->getFeatures( request ); - while ( fi.nextFeature( f ) ) + Qt3DExtras::QPhongMaterial *mat = _material( mSymbol ); + if ( selected ) { - if ( f.geometry().isNull() ) - continue; + // update the material with selection colors + mat->setDiffuse( context.map().selectionColor() ); + mat->setAmbient( context.map().selectionColor().darker() ); + } + + QgsPointXY origin( context.map().origin().x(), context.map().origin().y() ); + QgsTessellatedPolygonGeometry *geometry = new QgsTessellatedPolygonGeometry; + geometry->setPolygons( out.polygons, out.fids, origin, mSymbol.extrusionHeight() ); + + Qt3DRender::QGeometryRenderer *renderer = new Qt3DRender::QGeometryRenderer; + renderer->setGeometry( geometry ); + + // make entity + Qt3DCore::QEntity *entity = new Qt3DCore::QEntity; + entity->addComponent( renderer ); + entity->addComponent( mat ); + entity->setParent( parent ); - QgsGeometry geom = f.geometry(); + if ( !selected ) + entity->findChild()->setObjectName( QStringLiteral( "main" ) ); // temporary measure to distinguish between "selected" and "main" +} - // segmentize curved geometries if necessary - if ( QgsWkbTypes::isCurvedType( geom.constGet()->wkbType() ) ) - geom = QgsGeometry( geom.constGet()->segmentize() ); - const QgsAbstractGeometry *g = geom.constGet(); +// -------------- - QgsGeos engine( g ); - QgsAbstractGeometry *buffered = engine.buffer( symbol.width() / 2., nSegments, endCapStyle, joinStyle, mitreLimit ); // factory - if ( QgsWkbTypes::flatType( buffered->wkbType() ) == QgsWkbTypes::Polygon ) +class QgsSimpleLine3DSymbolHandler : public QgsFeature3DHandler +{ + public: + QgsSimpleLine3DSymbolHandler( const QgsLine3DSymbol &symbol, const QgsFeatureIds &selectedIds ) + : mSymbol( symbol ), mSelectedIds( selectedIds ) { - QgsPolygon *polyBuffered = static_cast( buffered ); - Qgs3DUtils::clampAltitudes( polyBuffered, symbol.altitudeClamping(), symbol.altitudeBinding(), symbol.height(), map ); - polygons.append( polyBuffered ); - fids.append( f.id() ); + // the first index is invalid, we use it for primitive restart + outNormal.vertices << QVector3D(); + outSelected.vertices << QVector3D(); } - else if ( QgsWkbTypes::flatType( buffered->wkbType() ) == QgsWkbTypes::MultiPolygon ) + + bool prepare( const Qgs3DRenderContext &context, QSet &attributeNames ) override; + void processFeature( QgsFeature &feature, const Qgs3DRenderContext &context ) override; + void finalize( Qt3DCore::QEntity *parent, const Qgs3DRenderContext &context ) override; + + private: + + //! temporary data we will pass to the tessellator + struct LineData { - QgsMultiPolygon *mpolyBuffered = static_cast( buffered ); - for ( int i = 0; i < mpolyBuffered->numGeometries(); ++i ) - { - QgsAbstractGeometry *partBuffered = mpolyBuffered->geometryN( i ); - Q_ASSERT( QgsWkbTypes::flatType( partBuffered->wkbType() ) == QgsWkbTypes::Polygon ); - QgsPolygon *polyBuffered = static_cast( partBuffered )->clone(); // need to clone individual geometry parts - Qgs3DUtils::clampAltitudes( polyBuffered, symbol.altitudeClamping(), symbol.altitudeBinding(), symbol.height(), map ); - polygons.append( polyBuffered ); - fids.append( f.id() ); - } - delete buffered; - } - } + QVector vertices; + QVector indexes; + }; - mGeometry = new QgsTessellatedPolygonGeometry; - mGeometry->setPolygons( polygons, fids, origin, symbol.extrusionHeight() ); + void makeEntity( Qt3DCore::QEntity *parent, const Qgs3DRenderContext &context, LineData &out, bool selected ); + Qt3DExtras::QPhongMaterial *material( const QgsLine3DSymbol &symbol ) const; - Qt3DRender::QGeometryRenderer *renderer = new Qt3DRender::QGeometryRenderer; - renderer->setGeometry( mGeometry ); + // input specific for this class + const QgsLine3DSymbol &mSymbol; + // inputs - generic + QgsFeatureIds mSelectedIds; + + // outputs + LineData outNormal; //!< Features that are not selected + LineData outSelected; //!< Features that are selected +}; - return renderer; -} -Qt3DRender::QGeometryRenderer *QgsLine3DSymbolEntityNode::rendererSimple( const Qgs3DMapSettings &map, const QgsLine3DSymbol &symbol, const QgsVectorLayer *layer, const QgsFeatureRequest &request ) +bool QgsSimpleLine3DSymbolHandler::prepare( const Qgs3DRenderContext &context, QSet &attributeNames ) { - QVector vertices; - vertices << QVector3D(); // the first index is invalid, we use it for primitive restart - QVector indexes; + Q_UNUSED( context ); + Q_UNUSED( attributeNames ); + return true; +} - QgsPoint centroid; - QgsPointXY origin( map.origin().x(), map.origin().y() ); - QgsFeature f; - QgsFeatureIterator fi = layer->getFeatures( request ); - while ( fi.nextFeature( f ) ) - { - if ( f.geometry().isNull() ) - continue; +void QgsSimpleLine3DSymbolHandler::processFeature( QgsFeature &f, const Qgs3DRenderContext &context ) +{ + if ( f.geometry().isNull() ) + return; - if ( symbol.altitudeBinding() == Qgs3DTypes::AltBindCentroid ) - centroid = QgsPoint( f.geometry().centroid().asPoint() ); + LineData &out = mSelectedIds.contains( f.id() ) ? outSelected : outNormal; - QgsGeometry geom = f.geometry(); - const QgsAbstractGeometry *g = geom.constGet(); - if ( const QgsLineString *ls = qgsgeometry_cast( g ) ) + QgsPoint centroid; + if ( mSymbol.altitudeBinding() == Qgs3DTypes::AltBindCentroid ) + centroid = QgsPoint( f.geometry().centroid().asPoint() ); + + QgsGeometry geom = f.geometry(); + const QgsAbstractGeometry *g = geom.constGet(); + if ( const QgsLineString *ls = qgsgeometry_cast( g ) ) + { + for ( int i = 0; i < ls->vertexCount(); ++i ) { - for ( int i = 0; i < ls->vertexCount(); ++i ) - { - QgsPoint p = ls->pointN( i ); - float z = Qgs3DUtils::clampAltitude( p, symbol.altitudeClamping(), symbol.altitudeBinding(), symbol.height(), centroid, map ); - vertices << QVector3D( p.x() - map.origin().x(), z, -( p.y() - map.origin().y() ) ); - indexes << vertices.count() - 1; - } + QgsPoint p = ls->pointN( i ); + float z = Qgs3DUtils::clampAltitude( p, mSymbol.altitudeClamping(), mSymbol.altitudeBinding(), mSymbol.height(), centroid, context.map() ); + out.vertices << QVector3D( p.x() - context.map().origin().x(), z, -( p.y() - context.map().origin().y() ) ); + out.indexes << out.vertices.count() - 1; } - else if ( const QgsMultiLineString *mls = qgsgeometry_cast( g ) ) + } + else if ( const QgsMultiLineString *mls = qgsgeometry_cast( g ) ) + { + for ( int nGeom = 0; nGeom < mls->numGeometries(); ++nGeom ) { - for ( int nGeom = 0; nGeom < mls->numGeometries(); ++nGeom ) + const QgsLineString *ls = qgsgeometry_cast( mls->geometryN( nGeom ) ); + for ( int i = 0; i < ls->vertexCount(); ++i ) { - const QgsLineString *ls = qgsgeometry_cast( mls->geometryN( nGeom ) ); - for ( int i = 0; i < ls->vertexCount(); ++i ) - { - QgsPoint p = ls->pointN( i ); - float z = Qgs3DUtils::clampAltitude( p, symbol.altitudeClamping(), symbol.altitudeBinding(), symbol.height(), centroid, map ); - vertices << QVector3D( p.x() - map.origin().x(), z, -( p.y() - map.origin().y() ) ); - indexes << vertices.count() - 1; - } - indexes << 0; // add primitive restart + QgsPoint p = ls->pointN( i ); + float z = Qgs3DUtils::clampAltitude( p, mSymbol.altitudeClamping(), mSymbol.altitudeBinding(), mSymbol.height(), centroid, context.map() ); + out.vertices << QVector3D( p.x() - context.map().origin().x(), z, -( p.y() - context.map().origin().y() ) ); + out.indexes << out.vertices.count() - 1; } + out.indexes << 0; // add primitive restart } + } + + out.indexes << 0; // add primitive restart +} + +void QgsSimpleLine3DSymbolHandler::finalize( Qt3DCore::QEntity *parent, const Qgs3DRenderContext &context ) +{ + // create entity for selected and not selected + makeEntity( parent, context, outNormal, false ); + makeEntity( parent, context, outSelected, true ); +} + + +void QgsSimpleLine3DSymbolHandler::makeEntity( Qt3DCore::QEntity *parent, const Qgs3DRenderContext &context, LineData &out, bool selected ) +{ + if ( out.indexes.isEmpty() ) + return; + + // material (only ambient color is used for the color) - indexes << 0; // add primitive restart + Qt3DExtras::QPhongMaterial *mat = _material( mSymbol ); + if ( selected ) + { + // update the material with selection colors + mat->setAmbient( context.map().selectionColor() ); } + // geometry renderer + QByteArray vertexBufferData; - vertexBufferData.resize( vertices.size() * 3 * sizeof( float ) ); + vertexBufferData.resize( out.vertices.size() * 3 * sizeof( float ) ); float *rawVertexArray = reinterpret_cast( vertexBufferData.data() ); int idx = 0; - for ( const auto &v : qgis::as_const( vertices ) ) + for ( const auto &v : qgis::as_const( out.vertices ) ) { rawVertexArray[idx++] = v.x(); rawVertexArray[idx++] = v.y(); @@ -220,28 +304,30 @@ Qt3DRender::QGeometryRenderer *QgsLine3DSymbolEntityNode::rendererSimple( const } QByteArray indexBufferData; - indexBufferData.resize( indexes.size() * sizeof( int ) ); + indexBufferData.resize( out.indexes.size() * sizeof( int ) ); unsigned int *rawIndexArray = reinterpret_cast( indexBufferData.data() ); idx = 0; - for ( unsigned int indexVal : qgis::as_const( indexes ) ) + for ( unsigned int indexVal : qgis::as_const( out.indexes ) ) { rawIndexArray[idx++] = indexVal; } - Qt3DRender::QBuffer *vertexBuffer = new Qt3DRender::QBuffer( Qt3DRender::QBuffer::VertexBuffer, this ); + Qt3DCore::QEntity *entity = new Qt3DCore::QEntity; + + Qt3DRender::QBuffer *vertexBuffer = new Qt3DRender::QBuffer( Qt3DRender::QBuffer::VertexBuffer, entity ); vertexBuffer->setData( vertexBufferData ); - Qt3DRender::QBuffer *indexBuffer = new Qt3DRender::QBuffer( Qt3DRender::QBuffer::IndexBuffer, this ); + Qt3DRender::QBuffer *indexBuffer = new Qt3DRender::QBuffer( Qt3DRender::QBuffer::IndexBuffer, entity ); indexBuffer->setData( indexBufferData ); - Qt3DRender::QAttribute *positionAttribute = new Qt3DRender::QAttribute( this ); + Qt3DRender::QAttribute *positionAttribute = new Qt3DRender::QAttribute( entity ); positionAttribute->setAttributeType( Qt3DRender::QAttribute::VertexAttribute ); positionAttribute->setBuffer( vertexBuffer ); positionAttribute->setVertexBaseType( Qt3DRender::QAttribute::Float ); positionAttribute->setVertexSize( 3 ); positionAttribute->setName( Qt3DRender::QAttribute::defaultPositionAttributeName() ); - Qt3DRender::QAttribute *indexAttribute = new Qt3DRender::QAttribute( this ); + Qt3DRender::QAttribute *indexAttribute = new Qt3DRender::QAttribute( entity ); indexAttribute->setAttributeType( Qt3DRender::QAttribute::IndexAttribute ); indexAttribute->setBuffer( indexBuffer ); indexAttribute->setVertexBaseType( Qt3DRender::QAttribute::UnsignedInt ); @@ -253,10 +339,38 @@ Qt3DRender::QGeometryRenderer *QgsLine3DSymbolEntityNode::rendererSimple( const Qt3DRender::QGeometryRenderer *renderer = new Qt3DRender::QGeometryRenderer; renderer->setPrimitiveType( Qt3DRender::QGeometryRenderer::LineStrip ); renderer->setGeometry( geom ); - renderer->setVertexCount( vertices.count() ); + renderer->setVertexCount( out.vertices.count() ); renderer->setPrimitiveRestartEnabled( true ); renderer->setRestartIndexValue( 0 ); - return renderer; + + // make entity + entity->addComponent( renderer ); + entity->addComponent( mat ); + entity->setParent( parent ); +} + + +// -------------- + + +namespace Qgs3DSymbolImpl +{ + + QgsFeature3DHandler *handlerForLine3DSymbol( QgsVectorLayer *layer, const QgsLine3DSymbol &symbol ) + { + if ( symbol.renderAsSimpleLines() ) + return new QgsSimpleLine3DSymbolHandler( symbol, layer->selectedFeatureIds() ); + else + return new QgsBufferedLine3DSymbolHandler( symbol, layer->selectedFeatureIds() ); + } + + Qt3DCore::QEntity *entityForLine3DSymbol( const Qgs3DMapSettings &map, QgsVectorLayer *layer, const QgsLine3DSymbol &symbol ) + { + QgsFeature3DHandler *handler = handlerForLine3DSymbol( layer, symbol ); + Qt3DCore::QEntity *e = entityFromHandler( handler, map, layer ); + delete handler; + return e; + } } /// @endcond diff --git a/src/3d/symbols/qgsline3dsymbol_p.h b/src/3d/symbols/qgsline3dsymbol_p.h index a49949f99e31..973a0e77275b 100644 --- a/src/3d/symbols/qgsline3dsymbol_p.h +++ b/src/3d/symbols/qgsline3dsymbol_p.h @@ -27,42 +27,19 @@ // version without notice, or even be removed. // -#include -#include -#include -class Qgs3DMapSettings; -class QgsTessellatedPolygonGeometry; -class QgsLine3DSymbol; - -class QgsVectorLayer; -class QgsFeatureRequest; - - -//! Entity that handles rendering of linestrings -class QgsLine3DSymbolEntity : public Qt3DCore::QEntity -{ - public: - QgsLine3DSymbolEntity( const Qgs3DMapSettings &map, QgsVectorLayer *layer, const QgsLine3DSymbol &symbol, Qt3DCore::QNode *parent = nullptr ); - - private: - void addEntityForSelectedLines( const Qgs3DMapSettings &map, QgsVectorLayer *layer, const QgsLine3DSymbol &symbol ); - void addEntityForNotSelectedLines( const Qgs3DMapSettings &map, QgsVectorLayer *layer, const QgsLine3DSymbol &symbol ); +#include "qgsfeature3dhandler_p.h" - Qt3DExtras::QPhongMaterial *material( const QgsLine3DSymbol &symbol ) const; -}; +class QgsLine3DSymbol; -class QgsLine3DSymbolEntityNode : public Qt3DCore::QEntity +namespace Qgs3DSymbolImpl { - public: - QgsLine3DSymbolEntityNode( const Qgs3DMapSettings &map, QgsVectorLayer *layer, const QgsLine3DSymbol &symbol, const QgsFeatureRequest &req, Qt3DCore::QNode *parent = nullptr ); - - private: - Qt3DRender::QGeometryRenderer *renderer( const Qgs3DMapSettings &map, const QgsLine3DSymbol &symbol, const QgsVectorLayer *layer, const QgsFeatureRequest &req ); - Qt3DRender::QGeometryRenderer *rendererSimple( const Qgs3DMapSettings &map, const QgsLine3DSymbol &symbol, const QgsVectorLayer *layer, const QgsFeatureRequest &request ); + //! factory method for QgsLine3DSymbol + QgsFeature3DHandler *handlerForLine3DSymbol( QgsVectorLayer *layer, const QgsLine3DSymbol &symbol ); - QgsTessellatedPolygonGeometry *mGeometry = nullptr; -}; + //! convenience function to create a complete entity from QgsPolygon3DSymbol (will run getFeatures() on the layer) + Qt3DCore::QEntity *entityForLine3DSymbol( const Qgs3DMapSettings &map, QgsVectorLayer *layer, const QgsLine3DSymbol &symbol ); +} /// @endcond