32 #include <Qt3DExtras/QPhongMaterial>
33 #include <Qt3DRender/QAttribute>
34 #include <Qt3DRender/QBuffer>
35 #include <Qt3DRender/QGeometryRenderer>
40 static Qt3DExtras::QPhongMaterial *_material(
const QgsLine3DSymbol &symbol )
42 Qt3DExtras::QPhongMaterial *material =
new Qt3DExtras::QPhongMaterial;
56 class QgsBufferedLine3DSymbolHandler :
public QgsFeature3DHandler
60 : mSymbol( symbol ), mSelectedIds( selectedIds ) {}
62 bool prepare(
const Qgs3DRenderContext &context, QSet<QString> &attributeNames )
override;
63 void processFeature(
QgsFeature &feature,
const Qgs3DRenderContext &context )
override;
64 void finalize( Qt3DCore::QEntity *parent,
const Qgs3DRenderContext &context )
override;
71 std::unique_ptr<QgsTessellator> tessellator;
72 QVector<QgsFeatureId> triangleIndexFids;
73 QVector<uint> triangleIndexStartingIndices;
76 void processPolygon(
QgsPolygon *polyBuffered,
QgsFeatureId fid,
float height,
float extrusionHeight,
const Qgs3DRenderContext &context, LineData &out );
78 void makeEntity( Qt3DCore::QEntity *parent,
const Qgs3DRenderContext &context, LineData &out,
bool selected );
92 bool QgsBufferedLine3DSymbolHandler::prepare(
const Qgs3DRenderContext &context, QSet<QString> &attributeNames )
94 Q_UNUSED( attributeNames )
96 outNormal.tessellator.reset(
new QgsTessellator( context.map().origin().x(), context.map().origin().y(),
true ) );
97 outSelected.tessellator.reset(
new QgsTessellator( context.map().origin().x(), context.map().origin().y(),
true ) );
102 void QgsBufferedLine3DSymbolHandler::processFeature(
QgsFeature &f,
const Qgs3DRenderContext &context )
107 LineData &out = mSelectedIds.contains( f.
id() ) ? outSelected : outNormal;
118 const int nSegments = 4;
121 const double mitreLimit = 0;
124 QgsAbstractGeometry *buffered = engine.buffer( mSymbol.width() / 2., nSegments, endCapStyle, joinStyle, mitreLimit );
129 processPolygon( polyBuffered, f.
id(), mSymbol.height(), mSymbol.extrusionHeight(), context, out );
139 processPolygon( polyBuffered, f.
id(), mSymbol.height(), mSymbol.extrusionHeight(), context, out );
145 void QgsBufferedLine3DSymbolHandler::processPolygon(
QgsPolygon *polyBuffered,
QgsFeatureId fid,
float height,
float extrusionHeight,
const Qgs3DRenderContext &context, LineData &out )
149 Q_ASSERT( out.tessellator->dataVerticesCount() % 3 == 0 );
150 uint startingTriangleIndex =
static_cast<uint
>( out.tessellator->dataVerticesCount() / 3 );
151 out.triangleIndexStartingIndices.append( startingTriangleIndex );
152 out.triangleIndexFids.append( fid );
153 out.tessellator->addPolygon( *polyBuffered, extrusionHeight );
157 void QgsBufferedLine3DSymbolHandler::finalize( Qt3DCore::QEntity *parent,
const Qgs3DRenderContext &context )
160 makeEntity( parent, context, outNormal,
false );
161 makeEntity( parent, context, outSelected,
true );
163 mZMin = std::min( outNormal.tessellator->zMinimum(), outSelected.tessellator->zMinimum() );
164 mZMax = std::max( outNormal.tessellator->zMaximum(), outSelected.tessellator->zMaximum() );
168 void QgsBufferedLine3DSymbolHandler::makeEntity( Qt3DCore::QEntity *parent,
const Qgs3DRenderContext &context, LineData &out,
bool selected )
170 if ( out.tessellator->dataVerticesCount() == 0 )
173 Qt3DExtras::QPhongMaterial *mat = _material( mSymbol );
177 mat->setDiffuse( context.map().selectionColor() );
178 mat->setAmbient( context.map().selectionColor().darker() );
182 QByteArray data( (
const char * )out.tessellator->data().constData(), out.tessellator->data().count() *
sizeof(
float ) );
183 int nVerts = data.count() / out.tessellator->stride();
186 geometry->
setData( data, nVerts, out.triangleIndexFids, out.triangleIndexStartingIndices );
188 Qt3DRender::QGeometryRenderer *renderer =
new Qt3DRender::QGeometryRenderer;
189 renderer->setGeometry( geometry );
192 Qt3DCore::QEntity *entity =
new Qt3DCore::QEntity;
193 entity->addComponent( renderer );
194 entity->addComponent( mat );
195 entity->setParent( parent );
198 entity->findChild<Qt3DRender::QGeometryRenderer *>()->setObjectName( QStringLiteral(
"main" ) );
208 class QgsSimpleLine3DSymbolHandler :
public QgsFeature3DHandler
212 : mSymbol( symbol ), mSelectedIds( selectedIds )
216 bool prepare(
const Qgs3DRenderContext &context, QSet<QString> &attributeNames )
override;
217 void processFeature(
QgsFeature &feature,
const Qgs3DRenderContext &context )
override;
218 void finalize( Qt3DCore::QEntity *parent,
const Qgs3DRenderContext &context )
override;
222 void makeEntity( Qt3DCore::QEntity *parent,
const Qgs3DRenderContext &context, QgsLineVertexData &out,
bool selected );
223 Qt3DExtras::QPhongMaterial *material(
const QgsLine3DSymbol &symbol )
const;
231 QgsLineVertexData outNormal;
232 QgsLineVertexData outSelected;
237 bool QgsSimpleLine3DSymbolHandler::prepare(
const Qgs3DRenderContext &context, QSet<QString> &attributeNames )
239 Q_UNUSED( attributeNames )
241 outNormal.init( mSymbol.altitudeClamping(), mSymbol.altitudeBinding(), mSymbol.height(), &context.map() );
242 outSelected.init( mSymbol.altitudeClamping(), mSymbol.altitudeBinding(), mSymbol.height(), &context.map() );
247 void QgsSimpleLine3DSymbolHandler::processFeature(
QgsFeature &f,
const Qgs3DRenderContext &context )
253 QgsLineVertexData &out = mSelectedIds.contains( f.
id() ) ? outSelected : outNormal;
257 if (
const QgsLineString *ls = qgsgeometry_cast<const QgsLineString *>( g ) )
259 out.addLineString( *ls );
261 else if (
const QgsMultiLineString *mls = qgsgeometry_cast<const QgsMultiLineString *>( g ) )
263 for (
int nGeom = 0; nGeom < mls->numGeometries(); ++nGeom )
265 const QgsLineString *ls = qgsgeometry_cast<const QgsLineString *>( mls->geometryN( nGeom ) );
266 out.addLineString( *ls );
271 void QgsSimpleLine3DSymbolHandler::finalize( Qt3DCore::QEntity *parent,
const Qgs3DRenderContext &context )
274 makeEntity( parent, context, outNormal,
false );
275 makeEntity( parent, context, outSelected,
true );
277 updateZRangeFromPositions( outNormal.vertices );
278 updateZRangeFromPositions( outSelected.vertices );
282 void QgsSimpleLine3DSymbolHandler::makeEntity( Qt3DCore::QEntity *parent,
const Qgs3DRenderContext &context, QgsLineVertexData &out,
bool selected )
284 if ( out.indexes.isEmpty() )
289 Qt3DExtras::QPhongMaterial *mat = _material( mSymbol );
293 mat->setAmbient( context.map().selectionColor() );
298 Qt3DCore::QEntity *entity =
new Qt3DCore::QEntity;
300 Qt3DRender::QGeometry *geom = out.createGeometry( entity );
302 Qt3DRender::QGeometryRenderer *renderer =
new Qt3DRender::QGeometryRenderer;
303 renderer->setPrimitiveType( Qt3DRender::QGeometryRenderer::LineStrip );
304 renderer->setGeometry( geom );
305 renderer->setVertexCount( out.indexes.count() );
306 renderer->setPrimitiveRestartEnabled(
true );
307 renderer->setRestartIndexValue( 0 );
310 entity->addComponent( renderer );
311 entity->addComponent( mat );
312 entity->setParent( parent );
320 class QgsThickLine3DSymbolHandler :
public QgsFeature3DHandler
324 : mSymbol( symbol ), mSelectedIds( selectedIds )
328 bool prepare(
const Qgs3DRenderContext &context, QSet<QString> &attributeNames )
override;
329 void processFeature(
QgsFeature &feature,
const Qgs3DRenderContext &context )
override;
330 void finalize( Qt3DCore::QEntity *parent,
const Qgs3DRenderContext &context )
override;
335 void makeEntity( Qt3DCore::QEntity *parent,
const Qgs3DRenderContext &context, QgsLineVertexData &out,
bool selected );
336 Qt3DExtras::QPhongMaterial *material(
const QgsLine3DSymbol &symbol )
const;
344 QgsLineVertexData outNormal;
345 QgsLineVertexData outSelected;
350 bool QgsThickLine3DSymbolHandler::prepare(
const Qgs3DRenderContext &context, QSet<QString> &attributeNames )
352 Q_UNUSED( attributeNames )
354 outNormal.withAdjacency =
true;
355 outSelected.withAdjacency =
true;
356 outNormal.init( mSymbol.altitudeClamping(), mSymbol.altitudeBinding(), mSymbol.height(), &context.map() );
357 outSelected.init( mSymbol.altitudeClamping(), mSymbol.altitudeBinding(), mSymbol.height(), &context.map() );
362 void QgsThickLine3DSymbolHandler::processFeature(
QgsFeature &f,
const Qgs3DRenderContext &context )
368 QgsLineVertexData &out = mSelectedIds.contains( f.
id() ) ? outSelected : outNormal;
372 if (
const QgsLineString *ls = qgsgeometry_cast<const QgsLineString *>( g ) )
374 out.addLineString( *ls );
376 else if (
const QgsMultiLineString *mls = qgsgeometry_cast<const QgsMultiLineString *>( g ) )
378 for (
int nGeom = 0; nGeom < mls->numGeometries(); ++nGeom )
380 const QgsLineString *ls = qgsgeometry_cast<const QgsLineString *>( mls->geometryN( nGeom ) );
381 out.addLineString( *ls );
386 void QgsThickLine3DSymbolHandler::finalize( Qt3DCore::QEntity *parent,
const Qgs3DRenderContext &context )
389 makeEntity( parent, context, outNormal,
false );
390 makeEntity( parent, context, outSelected,
true );
392 updateZRangeFromPositions( outNormal.vertices );
393 updateZRangeFromPositions( outSelected.vertices );
397 void QgsThickLine3DSymbolHandler::makeEntity( Qt3DCore::QEntity *parent,
const Qgs3DRenderContext &context, QgsLineVertexData &out,
bool selected )
399 if ( out.indexes.isEmpty() )
404 QgsLineMaterial *mat =
new QgsLineMaterial;
405 mat->setLineColor( mSymbol.material().ambient() );
406 mat->setLineWidth( mSymbol.width() );
410 mat->setLineColor( context.map().selectionColor() );
413 Qt3DCore::QEntity *entity =
new Qt3DCore::QEntity;
416 Qt3DRender::QGeometryRenderer *renderer =
new Qt3DRender::QGeometryRenderer;
417 renderer->setPrimitiveType( Qt3DRender::QGeometryRenderer::LineStripAdjacency );
418 renderer->setGeometry( out.createGeometry( entity ) );
419 renderer->setVertexCount( out.indexes.count() );
420 renderer->setPrimitiveRestartEnabled(
true );
421 renderer->setRestartIndexValue( 0 );
424 entity->addComponent( renderer );
425 entity->addComponent( mat );
426 entity->setParent( parent );
433 namespace Qgs3DSymbolImpl
447 QgsFeature3DHandler *handler = handlerForLine3DSymbol( layer, symbol );
448 Qt3DCore::QEntity *e = entityFromHandler( handler, map, layer );