24 #include <Qt3DCore/QTransform>
25 #include <Qt3DExtras/QPhongMaterial>
26 #include <Qt3DRender/QEffect>
27 #include <Qt3DRender/QTechnique>
28 #include <Qt3DRender/QCullFace>
29 #include <Qt3DRender/QGeometryRenderer>
41 class QgsPolygon3DSymbolHandler :
public QgsFeature3DHandler
45 : mSymbol( symbol ), mSelectedIds( selectedIds ) {}
47 bool prepare(
const Qgs3DRenderContext &context, QSet<QString> &attributeNames )
override;
48 void processFeature(
QgsFeature &feature,
const Qgs3DRenderContext &context )
override;
49 void finalize( Qt3DCore::QEntity *parent,
const Qgs3DRenderContext &context )
override;
56 std::unique_ptr<QgsTessellator> tessellator;
57 QVector<QgsFeatureId> triangleIndexFids;
58 QVector<uint> triangleIndexStartingIndices;
61 void processPolygon(
QgsPolygon *polyClone,
QgsFeatureId fid,
float height,
float extrusionHeight,
const Qgs3DRenderContext &context, PolygonData &out );
62 void makeEntity( Qt3DCore::QEntity *parent,
const Qgs3DRenderContext &context, PolygonData &out,
bool selected );
71 PolygonData outNormal;
72 PolygonData outSelected;
74 QgsLineVertexData outEdges;
78 bool QgsPolygon3DSymbolHandler::prepare(
const Qgs3DRenderContext &context, QSet<QString> &attributeNames )
80 outEdges.withAdjacency =
true;
81 outEdges.init( mSymbol.altitudeClamping(), mSymbol.altitudeBinding(), mSymbol.height(), &context.map() );
83 outNormal.tessellator.reset(
new QgsTessellator( context.map().origin().x(), context.map().origin().y(),
true, mSymbol.invertNormals(), mSymbol.addBackFaces() ) );
84 outSelected.tessellator.reset(
new QgsTessellator( context.map().origin().x(), context.map().origin().y(),
true, mSymbol.invertNormals(), mSymbol.addBackFaces() ) );
87 attributeNames.unite( attrs );
91 void QgsPolygon3DSymbolHandler::processPolygon(
QgsPolygon *polyClone,
QgsFeatureId fid,
float height,
float extrusionHeight,
const Qgs3DRenderContext &context, PolygonData &out )
93 if ( mSymbol.edgesEnabled() )
100 if ( extrusionHeight )
104 outEdges.addLineString( *exterior, extrusionHeight + height );
105 outEdges.addVerticalLines( *exterior, extrusionHeight, height );
109 outEdges.addLineString( *interior, extrusionHeight + height );
110 outEdges.addVerticalLines( *interior, extrusionHeight, height );
117 Q_ASSERT( out.tessellator->dataVerticesCount() % 3 == 0 );
118 uint startingTriangleIndex =
static_cast<uint
>( out.tessellator->dataVerticesCount() / 3 );
119 out.triangleIndexStartingIndices.append( startingTriangleIndex );
120 out.triangleIndexFids.append( fid );
121 out.tessellator->addPolygon( *polyClone, extrusionHeight );
125 void QgsPolygon3DSymbolHandler::processFeature(
QgsFeature &f,
const Qgs3DRenderContext &context )
130 PolygonData &out = mSelectedIds.contains( f.
id() ) ? outSelected : outNormal;
144 float height = mSymbol.height();
145 float extrusionHeight = mSymbol.extrusionHeight();
148 if ( hasDDExtrusion )
151 if (
const QgsPolygon *poly = qgsgeometry_cast< const QgsPolygon *>( g ) )
154 processPolygon( polyClone, f.
id(), height, extrusionHeight, context, out );
156 else if (
const QgsMultiPolygon *mpoly = qgsgeometry_cast< const QgsMultiPolygon *>( g ) )
158 for (
int i = 0; i < mpoly->numGeometries(); ++i )
163 processPolygon( polyClone, f.
id(), height, extrusionHeight, context, out );
168 for (
int i = 0; i < gc->numGeometries(); ++i )
174 processPolygon( polyClone, f.
id(), height, extrusionHeight, context, out );
179 qDebug() <<
"not a polygon";
183 void QgsPolygon3DSymbolHandler::finalize( Qt3DCore::QEntity *parent,
const Qgs3DRenderContext &context )
186 makeEntity( parent, context, outNormal,
false );
187 makeEntity( parent, context, outSelected,
true );
189 mZMin = std::min( outNormal.tessellator->zMinimum(), outSelected.tessellator->zMinimum() );
190 mZMax = std::max( outNormal.tessellator->zMaximum(), outSelected.tessellator->zMaximum() );
193 if ( mSymbol.edgesEnabled() && !outEdges.indexes.isEmpty() )
195 QgsLineMaterial *mat =
new QgsLineMaterial;
196 mat->setLineColor( mSymbol.edgeColor() );
197 mat->setLineWidth( mSymbol.edgeWidth() );
199 Qt3DCore::QEntity *entity =
new Qt3DCore::QEntity;
202 Qt3DRender::QGeometryRenderer *renderer =
new Qt3DRender::QGeometryRenderer;
203 renderer->setPrimitiveType( Qt3DRender::QGeometryRenderer::LineStripAdjacency );
204 renderer->setGeometry( outEdges.createGeometry( entity ) );
205 renderer->setVertexCount( outEdges.indexes.count() );
206 renderer->setPrimitiveRestartEnabled(
true );
207 renderer->setRestartIndexValue( 0 );
210 entity->addComponent( renderer );
211 entity->addComponent( mat );
212 entity->setParent( parent );
217 void QgsPolygon3DSymbolHandler::makeEntity( Qt3DCore::QEntity *parent,
const Qgs3DRenderContext &context, PolygonData &out,
bool selected )
219 if ( out.tessellator->dataVerticesCount() == 0 )
222 Qt3DExtras::QPhongMaterial *mat = material( mSymbol );
226 mat->setDiffuse( context.map().selectionColor() );
227 mat->setAmbient( context.map().selectionColor().darker() );
231 QByteArray data( (
const char * )out.tessellator->data().constData(), out.tessellator->data().count() *
sizeof(
float ) );
232 int nVerts = data.count() / out.tessellator->stride();
237 geometry->
setData( data, nVerts, out.triangleIndexFids, out.triangleIndexStartingIndices );
239 Qt3DRender::QGeometryRenderer *renderer =
new Qt3DRender::QGeometryRenderer;
240 renderer->setGeometry( geometry );
243 Qt3DCore::QEntity *entity =
new Qt3DCore::QEntity;
244 entity->addComponent( renderer );
245 entity->addComponent( mat );
246 entity->setParent( parent );
249 entity->findChild<Qt3DRender::QGeometryRenderer *>()->setObjectName( QStringLiteral(
"main" ) );
264 return Qt3DRender::QCullFace::NoCulling;
267 Qt3DExtras::QPhongMaterial *QgsPolygon3DSymbolHandler::material(
const QgsPolygon3DSymbol &symbol )
const
269 Qt3DExtras::QPhongMaterial *material =
new Qt3DExtras::QPhongMaterial;
272 auto techniques = material->effect()->techniques();
273 for (
auto tit = techniques.constBegin(); tit != techniques.constEnd(); ++tit )
275 auto renderPasses = ( *tit )->renderPasses();
276 for (
auto rpit = renderPasses.begin(); rpit != renderPasses.end(); ++rpit )
278 Qt3DRender::QCullFace *cullFace =
new Qt3DRender::QCullFace;
279 cullFace->setMode( _qt3DcullingMode( symbol.
cullingMode() ) );
280 ( *rpit )->addRenderState( cullFace );
295 namespace Qgs3DSymbolImpl
306 QgsFeature3DHandler *handler = handlerForPolygon3DSymbol( layer, symbol );
307 Qt3DCore::QEntity *e = entityFromHandler( handler, map, layer );