25 #include <Qt3DCore/QTransform> 
   26 #include <Qt3DRender/QMaterial> 
   27 #include <Qt3DExtras/QPhongMaterial> 
   29 #include <Qt3DExtras/QDiffuseMapMaterial> 
   30 #include <Qt3DRender/QAbstractTextureImage> 
   31 #include <Qt3DRender/QTexture> 
   33 #include <Qt3DRender/QEffect> 
   34 #include <Qt3DRender/QTechnique> 
   35 #include <Qt3DRender/QCullFace> 
   36 #include <Qt3DRender/QGeometryRenderer> 
   50 class QgsPolygon3DSymbolHandler : 
public QgsFeature3DHandler
 
   55       , mSelectedIds( selectedIds ) {}
 
   57     bool prepare( 
const Qgs3DRenderContext &context, QSet<QString> &attributeNames ) 
override;
 
   58     void processFeature( 
const QgsFeature &f, 
const Qgs3DRenderContext &context ) 
override;
 
   59     void finalize( Qt3DCore::QEntity *parent, 
const Qgs3DRenderContext &context ) 
override;
 
   66       std::unique_ptr<QgsTessellator> tessellator;
 
   67       QVector<QgsFeatureId> triangleIndexFids;
 
   68       QVector<uint> triangleIndexStartingIndices;
 
   69       QByteArray materialDataDefined;
 
   72     void processPolygon( 
QgsPolygon *polyClone, 
QgsFeatureId fid, 
float height, 
float extrusionHeight, 
const Qgs3DRenderContext &context, PolygonData &out );
 
   73     void processMaterialDatadefined( uint verticesCount, 
const QgsExpressionContext &context, PolygonData &out );
 
   74     void makeEntity( Qt3DCore::QEntity *parent, 
const Qgs3DRenderContext &context, PolygonData &out, 
bool selected );
 
   75     Qt3DRender::QMaterial *material( 
const QgsPolygon3DSymbol *symbol, 
bool isSelected, 
const Qgs3DRenderContext &context ) 
const;
 
   78     std::unique_ptr< QgsPolygon3DSymbol > mSymbol;
 
   83     PolygonData outNormal;  
 
   84     PolygonData outSelected;  
 
   86     QgsLineVertexData outEdges;  
 
   90 bool QgsPolygon3DSymbolHandler::prepare( 
const Qgs3DRenderContext &context, QSet<QString> &attributeNames )
 
   92   outEdges.withAdjacency = 
true;
 
   93   outEdges.init( mSymbol->altitudeClamping(), mSymbol->altitudeBinding(), 0, &context.map() );
 
   97   outNormal.tessellator.reset( 
new QgsTessellator( context.map().origin().x(), context.map().origin().y(), 
true, mSymbol->invertNormals(), mSymbol->addBackFaces(), 
false,
 
   99                                mSymbol->renderedFacade(),
 
  100                                texturedMaterialSettings ? texturedMaterialSettings->
textureRotation() : 0 ) );
 
  101   outSelected.tessellator.reset( 
new QgsTessellator( context.map().origin().x(), context.map().origin().y(), 
true, mSymbol->invertNormals(),
 
  102                                  mSymbol->addBackFaces(), 
false,
 
  104                                  mSymbol->renderedFacade(),
 
  105                                  texturedMaterialSettings ? texturedMaterialSettings->
textureRotation() : 0 ) );
 
  108   attributeNames.unite( attrs );
 
  109   attrs = mSymbol->material()->dataDefinedProperties().referencedFields( context.expressionContext() );
 
  110   attributeNames.unite( attrs );
 
  114 void QgsPolygon3DSymbolHandler::processPolygon( 
QgsPolygon *polyClone, 
QgsFeatureId fid, 
float height, 
float extrusionHeight, 
const Qgs3DRenderContext &context, PolygonData &out )
 
  116   uint oldVerticesCount = out.tessellator->dataVerticesCount();
 
  117   if ( mSymbol->edgesEnabled() )
 
  124     if ( extrusionHeight )
 
  128       outEdges.addLineString( *exterior, extrusionHeight + height );
 
  129       outEdges.addVerticalLines( *exterior, extrusionHeight, height );
 
  133         outEdges.addLineString( *interior, extrusionHeight + height );
 
  134         outEdges.addVerticalLines( *interior, extrusionHeight, height );
 
  141   Q_ASSERT( out.tessellator->dataVerticesCount() % 3 == 0 );
 
  142   uint startingTriangleIndex = 
static_cast<uint
>( out.tessellator->dataVerticesCount() / 3 );
 
  143   out.triangleIndexStartingIndices.append( startingTriangleIndex );
 
  144   out.triangleIndexFids.append( fid );
 
  145   out.tessellator->addPolygon( *polyClone, extrusionHeight );
 
  148   if ( mSymbol->material()->dataDefinedProperties().hasActiveProperties() )
 
  149     processMaterialDatadefined( out.tessellator->dataVerticesCount() - oldVerticesCount, context.expressionContext(), out );
 
  152 void QgsPolygon3DSymbolHandler::processMaterialDatadefined( uint verticesCount, 
const QgsExpressionContext &context, QgsPolygon3DSymbolHandler::PolygonData &out )
 
  154   const QByteArray bytes = mSymbol->material()->dataDefinedVertexColorsAsByte( context );
 
  155   out.materialDataDefined.append( bytes.repeated( verticesCount ) );
 
  158 void QgsPolygon3DSymbolHandler::processFeature( 
const QgsFeature &f, 
const Qgs3DRenderContext &context )
 
  163   PolygonData &out = mSelectedIds.contains( f.
id() ) ? outSelected : outNormal;
 
  179   float height = mSymbol->height();
 
  180   float extrusionHeight = mSymbol->extrusionHeight();
 
  183   if ( hasDDExtrusion )
 
  186   if ( 
const QgsPolygon *poly = qgsgeometry_cast< const QgsPolygon *>( g ) )
 
  189     processPolygon( polyClone, f.
id(), height, extrusionHeight, context, out );
 
  191   else if ( 
const QgsMultiPolygon *mpoly = qgsgeometry_cast< const QgsMultiPolygon *>( g ) )
 
  193     for ( 
int i = 0; i < mpoly->numGeometries(); ++i )
 
  196       processPolygon( polyClone, f.
id(), height, extrusionHeight, context, out );
 
  201     for ( 
int i = 0; i < gc->numGeometries(); ++i )
 
  207         processPolygon( polyClone, f.
id(), height, extrusionHeight, context, out );
 
  212     qWarning() << 
"not a polygon";
 
  216 void QgsPolygon3DSymbolHandler::finalize( Qt3DCore::QEntity *parent, 
const Qgs3DRenderContext &context )
 
  219   makeEntity( parent, context, outNormal, 
false );
 
  220   makeEntity( parent, context, outSelected, 
true );
 
  222   mZMin = std::min( outNormal.tessellator->zMinimum(), outSelected.tessellator->zMinimum() );
 
  223   mZMax = std::max( outNormal.tessellator->zMaximum(), outSelected.tessellator->zMaximum() );
 
  226   if ( mSymbol->edgesEnabled() && !outEdges.indexes.isEmpty() )
 
  228     QgsLineMaterial *mat = 
new QgsLineMaterial;
 
  229     mat->setLineColor( mSymbol->edgeColor() );
 
  230     mat->setLineWidth( mSymbol->edgeWidth() );
 
  232     Qt3DCore::QEntity *entity = 
new Qt3DCore::QEntity;
 
  235     Qt3DRender::QGeometryRenderer *renderer = 
new Qt3DRender::QGeometryRenderer;
 
  236     renderer->setPrimitiveType( Qt3DRender::QGeometryRenderer::LineStripAdjacency );
 
  237     renderer->setGeometry( outEdges.createGeometry( entity ) );
 
  238     renderer->setVertexCount( outEdges.indexes.count() );
 
  239     renderer->setPrimitiveRestartEnabled( 
true );
 
  240     renderer->setRestartIndexValue( 0 );
 
  243     entity->addComponent( renderer );
 
  244     entity->addComponent( mat );
 
  245     entity->setParent( parent );
 
  250 void QgsPolygon3DSymbolHandler::makeEntity( Qt3DCore::QEntity *parent, 
const Qgs3DRenderContext &context, PolygonData &out, 
bool selected )
 
  252   if ( out.tessellator->dataVerticesCount() == 0 )
 
  255   Qt3DRender::QMaterial *mat = material( mSymbol.get(), selected, context );
 
  258   QByteArray data( ( 
const char * )out.tessellator->data().constData(), out.tessellator->data().count() * 
sizeof( 
float ) );
 
  259   int nVerts = data.count() / out.tessellator->stride();
 
  265   geometry->
setData( data, nVerts, out.triangleIndexFids, out.triangleIndexStartingIndices );
 
  266   if ( mSymbol->material()->dataDefinedProperties().hasActiveProperties() )
 
  267     mSymbol->material()->applyDataDefinedToGeometry( geometry, nVerts, out.materialDataDefined );
 
  269   Qt3DRender::QGeometryRenderer *renderer = 
new Qt3DRender::QGeometryRenderer;
 
  270   renderer->setGeometry( geometry );
 
  273   Qt3DCore::QEntity *entity = 
new Qt3DCore::QEntity;
 
  274   entity->addComponent( renderer );
 
  275   entity->addComponent( mat );
 
  276   entity->setParent( parent );
 
  279     entity->findChild<Qt3DRender::QGeometryRenderer *>()->setObjectName( QStringLiteral( 
"main" ) ); 
 
  294   return Qt3DRender::QCullFace::NoCulling;
 
  300   auto techniques = material->effect()->techniques();
 
  301   for ( 
auto tit = techniques.constBegin(); tit != techniques.constEnd(); ++tit )
 
  303     auto renderPasses = ( *tit )->renderPasses();
 
  304     for ( 
auto rpit = renderPasses.begin(); rpit != renderPasses.end(); ++rpit )
 
  306       Qt3DRender::QCullFace *cullFace = 
new Qt3DRender::QCullFace;
 
  307       cullFace->setMode( _qt3DcullingMode( cullingMode ) );
 
  308       ( *rpit )->addRenderState( cullFace );
 
  313 Qt3DRender::QMaterial *QgsPolygon3DSymbolHandler::material( 
const QgsPolygon3DSymbol *symbol, 
bool isSelected, 
const Qgs3DRenderContext &context )
 const 
  319   bool dataDefined = mSymbol->material()->dataDefinedProperties().hasActiveProperties();
 
  323   applyCullingMode( symbol->
cullingMode(), material );
 
  331 namespace Qgs3DSymbolImpl
 
  338     if ( !polygonSymbol )
 
  346     QgsFeature3DHandler *handler = handlerForPolygon3DSymbol( layer, &symbol );
 
  347     Qt3DCore::QEntity *e = entityFromHandler( handler, map, layer );
 
CullingMode
Triangle culling mode.
@ FrontAndBack
Will not render anything.
@ NoCulling
Will render both front and back faces of triangles.
@ Front
Will render only back faces of triangles.
@ Back
Will render only front faces of triangles (recommended when input data are consistent)
static void clampAltitudes(QgsLineString *lineString, Qgs3DTypes::AltitudeClamping altClamp, Qgs3DTypes::AltitudeBinding altBind, const QgsPoint ¢roid, float height, const Qgs3DMapSettings &map)
Clamps altitude of vertices of a linestring according to the settings.
@ PropertyHeight
Height (altitude)
@ PropertyExtrusionHeight
Extrusion height (zero means no extrusion)
Abstract base class for all geometries.
virtual QgsAbstractGeometry * segmentize(double tolerance=M_PI/180., SegmentationToleranceType toleranceType=MaximumAngle) const
Returns a version of the geometry without curves.
virtual const QgsAbstractGeometry * simplifiedTypeRef() const SIP_HOLDGIL
Returns a reference to the simplest lossless representation of this geometry, e.g.
QgsWkbTypes::Type wkbType() const SIP_HOLDGIL
Returns the WKB type of the geometry.
virtual Qt3DRender::QMaterial * toMaterial(QgsMaterialSettingsRenderingTechnique technique, const QgsMaterialContext &context) const =0
Creates a new QMaterial object representing the material settings.
QgsPropertyCollection dataDefinedProperties() const
Returns the symbol material property collection, used for data defined overrides.
double valueAsDouble(int key, const QgsExpressionContext &context, double defaultValue=0.0, bool *ok=nullptr) const
Calculates the current value of the property with the specified key and interprets it as a double.
const QgsCurve * interiorRing(int i) const SIP_HOLDGIL
Retrieves an interior ring from the curve polygon.
const QgsCurve * exteriorRing() const SIP_HOLDGIL
Returns the curve polygon's exterior ring.
int numInteriorRings() const SIP_HOLDGIL
Returns the number of interior rings contained with the curve polygon.
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...
A geometry is the spatial representation of a feature.
const QgsAbstractGeometry * constGet() const SIP_HOLDGIL
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
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.
Multi polygon geometry collection.
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.
Qgs3DTypes::CullingMode cullingMode() const
Returns front/back culling mode.
QgsAbstractMaterialSettings * material() const
Returns material used for shading of the symbol.
QgsPolygon * clone() const override
Clones the geometry by performing a deep copy.
A grouped map of multiple QgsProperty objects, each referenced by a integer key value.
QSet< QString > referencedFields(const QgsExpressionContext &context=QgsExpressionContext(), bool ignoreContext=false) const override
Returns the set of any fields referenced by the active properties from the collection.
bool isActive(int key) const override
Returns true if the collection contains an active property with the specified key.
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(Type type) SIP_HOLDGIL
Returns true if the WKB type is a curved type or can contain curved geometries.
static Type flatType(Type type) SIP_HOLDGIL
Returns the flat type for a WKB type.
@ Triangles
Triangle based rendering (default)
@ TrianglesDataDefined
Triangle based rendering with possibility of datadefined color.
QSet< QgsFeatureId > QgsFeatureIds
qint64 QgsFeatureId
64 bit feature ids negative numbers are used for uncommitted/newly added features