QGIS API Documentation 3.32.0-Lima (311a8cb8a6)
qgspoint3dsymbol_p.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgspoint3dsymbol_p.cpp
3 --------------------------------------
4 Date : July 2017
5 Copyright : (C) 2017 by Martin Dobias
6 Email : wonder dot sk at gmail dot com
7 ***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15
16#include "qgspoint3dsymbol_p.h"
17
18#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
19#include <Qt3DRender/QAttribute>
20#include <Qt3DRender/QBuffer>
21#include <Qt3DRender/QGeometry>
22#include <Qt3DCore/QTransform>
23
24typedef Qt3DRender::QAttribute Qt3DQAttribute;
25typedef Qt3DRender::QBuffer Qt3DQBuffer;
26typedef Qt3DRender::QGeometry Qt3DQGeometry;
27#else
28#include <Qt3DCore/QAttribute>
29#include <Qt3DCore/QBuffer>
30#include <Qt3DCore/QGeometry>
31
32typedef Qt3DCore::QAttribute Qt3DQAttribute;
33typedef Qt3DCore::QBuffer Qt3DQBuffer;
34typedef Qt3DCore::QGeometry Qt3DQGeometry;
35#endif
36
37#include <Qt3DRender/QEffect>
38#include <Qt3DRender/QGraphicsApiFilter>
39#include <Qt3DRender/QParameter>
40#include <Qt3DRender/QTechnique>
41
42#include <Qt3DExtras/QCylinderGeometry>
43#include <Qt3DExtras/QConeGeometry>
44#include <Qt3DExtras/QCuboidGeometry>
45#include <Qt3DExtras/QPlaneGeometry>
46#include <Qt3DExtras/QSphereGeometry>
47#include <Qt3DExtras/QTorusGeometry>
48#include <Qt3DExtras/QPhongMaterial>
49#include <Qt3DRender/QSceneLoader>
50#include <Qt3DRender/QPaintedTextureImage>
51
52#include <Qt3DRender/QMesh>
53
54#include <Qt3DExtras/QExtrudedTextGeometry>
55
56#include <QUrl>
57#include <QVector3D>
58
59#include "qgspoint3dsymbol.h"
60#include "qgs3dmapsettings.h"
61
62#include "qgsapplication.h"
63#include "qgsvectorlayer.h"
64#include "qgs3dutils.h"
67#include "qgssourcecache.h"
68
70
71
72//* INSTANCED RENDERING *//
73
74
75class QgsInstancedPoint3DSymbolHandler : public QgsFeature3DHandler
76{
77 public:
78 QgsInstancedPoint3DSymbolHandler( const QgsPoint3DSymbol *symbol, const QgsFeatureIds &selectedIds )
79 : mSymbol( static_cast< QgsPoint3DSymbol *>( symbol->clone() ) )
80 , mSelectedIds( selectedIds ) {}
81
82 bool prepare( const Qgs3DRenderContext &context, QSet<QString> &attributeNames ) override;
83 void processFeature( const QgsFeature &feature, const Qgs3DRenderContext &context ) override;
84 void finalize( Qt3DCore::QEntity *parent, const Qgs3DRenderContext &context ) override;
85
86 private:
87
88 static Qt3DRender::QMaterial *material( const QgsPoint3DSymbol *symbol );
89 static Qt3DRender::QGeometryRenderer *renderer( const QgsPoint3DSymbol *symbol, const QVector<QVector3D> &positions );
90 static Qt3DQGeometry *symbolGeometry( QgsPoint3DSymbol::Shape shape, const QVariantMap &shapeProperties );
91
93 struct PointData
94 {
95 QVector<QVector3D> positions; // contains triplets of float x,y,z for each point
96 };
97
98 void makeEntity( Qt3DCore::QEntity *parent, const Qgs3DRenderContext &context, PointData &out, bool selected );
99
100 // input specific for this class
101 std::unique_ptr< QgsPoint3DSymbol > mSymbol;
102 // inputs - generic
103 QgsFeatureIds mSelectedIds;
104
105 // outputs
106 PointData outNormal;
107 PointData outSelected;
108};
109
110
111bool QgsInstancedPoint3DSymbolHandler::prepare( const Qgs3DRenderContext &context, QSet<QString> &attributeNames )
112{
113 Q_UNUSED( context )
114 Q_UNUSED( attributeNames )
115 return true;
116}
117
118void QgsInstancedPoint3DSymbolHandler::processFeature( const QgsFeature &feature, const Qgs3DRenderContext &context )
119{
120 PointData &out = mSelectedIds.contains( feature.id() ) ? outSelected : outNormal;
121
122 if ( feature.geometry().isNull() )
123 return;
124
125 Qgs3DUtils::extractPointPositions( feature, context.map(), mSymbol->altitudeClamping(), out.positions );
126 mFeatureCount++;
127}
128
129void QgsInstancedPoint3DSymbolHandler::finalize( Qt3DCore::QEntity *parent, const Qgs3DRenderContext &context )
130{
131 makeEntity( parent, context, outNormal, false );
132 makeEntity( parent, context, outSelected, true );
133
134 updateZRangeFromPositions( outNormal.positions );
135 updateZRangeFromPositions( outSelected.positions );
136
137 // the elevation offset is applied in the vertex shader so let's account for it as well
138 const float symbolHeight = mSymbol->transform().data()[13];
139 mZMin += symbolHeight;
140 mZMax += symbolHeight;
141}
142
143void QgsInstancedPoint3DSymbolHandler::makeEntity( Qt3DCore::QEntity *parent, const Qgs3DRenderContext &context, PointData &out, bool selected )
144{
145 // build the default material
146 Qt3DRender::QMaterial *mat = material( mSymbol.get() );
147
148 if ( selected )
149 {
150 // update the material with selection colors
151 for ( Qt3DRender::QParameter *param : mat->effect()->parameters() )
152 {
153 if ( param->name() == QLatin1String( "kd" ) ) // diffuse
154 param->setValue( context.map().selectionColor() );
155 else if ( param->name() == QLatin1String( "ka" ) ) // ambient
156 param->setValue( context.map().selectionColor().darker() );
157 }
158 }
159
160 // build the entity
161 Qt3DCore::QEntity *entity = new Qt3DCore::QEntity;
162 entity->addComponent( renderer( mSymbol.get(), out.positions ) );
163 entity->addComponent( mat );
164 entity->setParent( parent );
165
166// cppcheck wrongly believes entity will leak
167// cppcheck-suppress memleak
168}
169
170
171
172Qt3DRender::QMaterial *QgsInstancedPoint3DSymbolHandler::material( const QgsPoint3DSymbol *symbol )
173{
174 Qt3DRender::QFilterKey *filterKey = new Qt3DRender::QFilterKey;
175 filterKey->setName( QStringLiteral( "renderingStyle" ) );
176 filterKey->setValue( "forward" );
177
178 // the fragment shader implements a simplified version of phong shading that uses hardcoded light
179 // (instead of whatever light we have defined in the scene)
180 // TODO: use phong shading that respects lights from the scene
181 Qt3DRender::QShaderProgram *shaderProgram = new Qt3DRender::QShaderProgram;
182 shaderProgram->setVertexShaderCode( Qt3DRender::QShaderProgram::loadSource( QUrl( QStringLiteral( "qrc:/shaders/instanced.vert" ) ) ) );
183 shaderProgram->setFragmentShaderCode( Qt3DRender::QShaderProgram::loadSource( QUrl( QStringLiteral( "qrc:/shaders/instanced.frag" ) ) ) );
184
185 Qt3DRender::QRenderPass *renderPass = new Qt3DRender::QRenderPass;
186 renderPass->setShaderProgram( shaderProgram );
187
188 Qt3DRender::QTechnique *technique = new Qt3DRender::QTechnique;
189 technique->addFilterKey( filterKey );
190 technique->addRenderPass( renderPass );
191 technique->graphicsApiFilter()->setApi( Qt3DRender::QGraphicsApiFilter::OpenGL );
192 technique->graphicsApiFilter()->setProfile( Qt3DRender::QGraphicsApiFilter::CoreProfile );
193 technique->graphicsApiFilter()->setMajorVersion( 3 );
194 technique->graphicsApiFilter()->setMinorVersion( 2 );
195
196 const QMatrix4x4 transformMatrix = symbol->transform();
197 QMatrix3x3 normalMatrix = transformMatrix.normalMatrix(); // transponed inverse of 3x3 sub-matrix
198
199 // QMatrix3x3 is not supported for passing to shaders, so we pass QMatrix4x4
200 float *n = normalMatrix.data();
201 const QMatrix4x4 normalMatrix4(
202 n[0], n[3], n[6], 0,
203 n[1], n[4], n[7], 0,
204 n[2], n[5], n[8], 0,
205 0, 0, 0, 0 );
206
207 Qt3DRender::QParameter *paramInst = new Qt3DRender::QParameter;
208 paramInst->setName( QStringLiteral( "inst" ) );
209 paramInst->setValue( transformMatrix );
210
211 Qt3DRender::QParameter *paramInstNormal = new Qt3DRender::QParameter;
212 paramInstNormal->setName( QStringLiteral( "instNormal" ) );
213 paramInstNormal->setValue( normalMatrix4 );
214
215 Qt3DRender::QEffect *effect = new Qt3DRender::QEffect;
216 effect->addTechnique( technique );
217 effect->addParameter( paramInst );
218 effect->addParameter( paramInstNormal );
219
220 symbol->materialSettings()->addParametersToEffect( effect );
221
222 Qt3DRender::QMaterial *material = new Qt3DRender::QMaterial;
223 material->setEffect( effect );
224
225 return material;
226}
227
228Qt3DRender::QGeometryRenderer *QgsInstancedPoint3DSymbolHandler::renderer( const QgsPoint3DSymbol *symbol, const QVector<QVector3D> &positions )
229{
230 const int count = positions.count();
231 const int byteCount = positions.count() * sizeof( QVector3D );
232 QByteArray ba;
233 ba.resize( byteCount );
234 memcpy( ba.data(), positions.constData(), byteCount );
235
236 Qt3DQBuffer *instanceBuffer = new Qt3DQBuffer();
237 instanceBuffer->setData( ba );
238
239 Qt3DQAttribute *instanceDataAttribute = new Qt3DQAttribute;
240 instanceDataAttribute->setName( QStringLiteral( "pos" ) );
241 instanceDataAttribute->setAttributeType( Qt3DQAttribute::VertexAttribute );
242 instanceDataAttribute->setVertexBaseType( Qt3DQAttribute::Float );
243 instanceDataAttribute->setVertexSize( 3 );
244 instanceDataAttribute->setByteOffset( 0 );
245 instanceDataAttribute->setDivisor( 1 );
246 instanceDataAttribute->setBuffer( instanceBuffer );
247 instanceDataAttribute->setCount( count );
248 instanceDataAttribute->setByteStride( 3 * sizeof( float ) );
249
250 Qt3DQGeometry *geometry = symbolGeometry( symbol->shape(), symbol->shapeProperties() );
251 geometry->addAttribute( instanceDataAttribute );
252 geometry->setBoundingVolumePositionAttribute( instanceDataAttribute );
253
254 Qt3DRender::QGeometryRenderer *renderer = new Qt3DRender::QGeometryRenderer;
255 renderer->setGeometry( geometry );
256 renderer->setInstanceCount( count );
257
258 return renderer;
259}
260
261Qt3DQGeometry *QgsInstancedPoint3DSymbolHandler::symbolGeometry( QgsPoint3DSymbol::Shape shape, const QVariantMap &shapeProperties )
262{
263 switch ( shape )
264 {
266 {
267 const float radius = shapeProperties[QStringLiteral( "radius" )].toFloat();
268 const float length = shapeProperties[QStringLiteral( "length" )].toFloat();
269 Qt3DExtras::QCylinderGeometry *g = new Qt3DExtras::QCylinderGeometry;
270 //g->setRings(2); // how many vertices vertically
271 //g->setSlices(8); // how many vertices on circumference
272 g->setRadius( radius ? radius : 10 );
273 g->setLength( length ? length : 10 );
274 return g;
275 }
276
278 {
279 const float radius = shapeProperties[QStringLiteral( "radius" )].toFloat();
280 Qt3DExtras::QSphereGeometry *g = new Qt3DExtras::QSphereGeometry;
281 g->setRadius( radius ? radius : 10 );
282 return g;
283 }
284
286 {
287 const float length = shapeProperties[QStringLiteral( "length" )].toFloat();
288 const float bottomRadius = shapeProperties[QStringLiteral( "bottomRadius" )].toFloat();
289 const float topRadius = shapeProperties[QStringLiteral( "topRadius" )].toFloat();
290 Qt3DExtras::QConeGeometry *g = new Qt3DExtras::QConeGeometry;
291 g->setLength( length ? length : 10 );
292 g->setBottomRadius( bottomRadius );
293 g->setTopRadius( topRadius );
294 //g->setHasBottomEndcap(hasBottomEndcap);
295 //g->setHasTopEndcap(hasTopEndcap);
296 return g;
297 }
298
300 {
301 const float size = shapeProperties[QStringLiteral( "size" )].toFloat();
302 Qt3DExtras::QCuboidGeometry *g = new Qt3DExtras::QCuboidGeometry;
303 g->setXExtent( size ? size : 10 );
304 g->setYExtent( size ? size : 10 );
305 g->setZExtent( size ? size : 10 );
306 return g;
307 }
308
310 {
311 const float radius = shapeProperties[QStringLiteral( "radius" )].toFloat();
312 const float minorRadius = shapeProperties[QStringLiteral( "minorRadius" )].toFloat();
313 Qt3DExtras::QTorusGeometry *g = new Qt3DExtras::QTorusGeometry;
314 g->setRadius( radius ? radius : 10 );
315 g->setMinorRadius( minorRadius ? minorRadius : 5 );
316 return g;
317 }
318
320 {
321 const float size = shapeProperties[QStringLiteral( "size" )].toFloat();
322 Qt3DExtras::QPlaneGeometry *g = new Qt3DExtras::QPlaneGeometry;
323 g->setWidth( size ? size : 10 );
324 g->setHeight( size ? size : 10 );
325 return g;
326 }
327
329 {
330 const float depth = shapeProperties[QStringLiteral( "depth" )].toFloat();
331 const QString text = shapeProperties[QStringLiteral( "text" )].toString();
332 Qt3DExtras::QExtrudedTextGeometry *g = new Qt3DExtras::QExtrudedTextGeometry;
333 g->setDepth( depth ? depth : 1 );
334 g->setText( text );
335 return g;
336 }
337
338 default:
339 Q_ASSERT( false );
340 return nullptr;
341 }
342}
343
344//* 3D MODEL RENDERING *//
345
346
347class QgsModelPoint3DSymbolHandler : public QgsFeature3DHandler
348{
349 public:
350 QgsModelPoint3DSymbolHandler( const QgsPoint3DSymbol *symbol, const QgsFeatureIds &selectedIds )
351 : mSymbol( static_cast< QgsPoint3DSymbol * >( symbol->clone() ) )
352 , mSelectedIds( selectedIds ) {}
353
354 bool prepare( const Qgs3DRenderContext &context, QSet<QString> &attributeNames ) override;
355 void processFeature( const QgsFeature &feature, const Qgs3DRenderContext &context ) override;
356 void finalize( Qt3DCore::QEntity *parent, const Qgs3DRenderContext &context ) override;
357
358 private:
359
360 static void addSceneEntities( const Qgs3DMapSettings &map, const QVector<QVector3D> &positions, const QgsPoint3DSymbol *symbol, Qt3DCore::QEntity *parent );
361 static void addMeshEntities( const Qgs3DMapSettings &map, const QVector<QVector3D> &positions, const QgsPoint3DSymbol *symbol, Qt3DCore::QEntity *parent, bool are_selected );
362 static Qt3DCore::QTransform *transform( QVector3D position, const QgsPoint3DSymbol *symbol );
363
365 struct PointData
366 {
367 QVector<QVector3D> positions; // contains triplets of float x,y,z for each point
368 };
369
370 void makeEntity( Qt3DCore::QEntity *parent, const Qgs3DRenderContext &context, PointData &out, bool selected );
371
372 // input specific for this class
373 std::unique_ptr< QgsPoint3DSymbol > mSymbol;
374 // inputs - generic
375 QgsFeatureIds mSelectedIds;
376
377 // outputs
378 PointData outNormal;
379 PointData outSelected;
380};
381
382bool QgsModelPoint3DSymbolHandler::prepare( const Qgs3DRenderContext &context, QSet<QString> &attributeNames )
383{
384 Q_UNUSED( context )
385 Q_UNUSED( attributeNames )
386 return true;
387}
388
389void QgsModelPoint3DSymbolHandler::processFeature( const QgsFeature &feature, const Qgs3DRenderContext &context )
390{
391 PointData &out = mSelectedIds.contains( feature.id() ) ? outSelected : outNormal;
392
393 if ( feature.geometry().isNull() )
394 return;
395
396 Qgs3DUtils::extractPointPositions( feature, context.map(), mSymbol->altitudeClamping(), out.positions );
397 mFeatureCount++;
398}
399
400void QgsModelPoint3DSymbolHandler::finalize( Qt3DCore::QEntity *parent, const Qgs3DRenderContext &context )
401{
402 makeEntity( parent, context, outNormal, false );
403 makeEntity( parent, context, outSelected, true );
404
405 updateZRangeFromPositions( outNormal.positions );
406 updateZRangeFromPositions( outSelected.positions );
407
408 // the elevation offset is applied separately in QTransform added to sub-entities
409 const float symbolHeight = mSymbol->transform().data()[13];
410 mZMin += symbolHeight;
411 mZMax += symbolHeight;
412}
413
414void QgsModelPoint3DSymbolHandler::makeEntity( Qt3DCore::QEntity *parent, const Qgs3DRenderContext &context, PointData &out, bool selected )
415{
416 if ( selected )
417 {
418 addMeshEntities( context.map(), out.positions, mSymbol.get(), parent, true );
419 }
420 else
421 {
422 // "overwriteMaterial" is a legacy setting indicating that non-embedded material should be used
423 if ( mSymbol->shapeProperties()[QStringLiteral( "overwriteMaterial" )].toBool()
424 || ( mSymbol->materialSettings() && mSymbol->materialSettings()->type() != QLatin1String( "null" ) ) )
425 {
426 addMeshEntities( context.map(), out.positions, mSymbol.get(), parent, false );
427 }
428 else
429 {
430 addSceneEntities( context.map(), out.positions, mSymbol.get(), parent );
431 }
432 }
433}
434
435
436
437void QgsModelPoint3DSymbolHandler::addSceneEntities( const Qgs3DMapSettings &map, const QVector<QVector3D> &positions, const QgsPoint3DSymbol *symbol, Qt3DCore::QEntity *parent )
438{
439 Q_UNUSED( map )
440 for ( const QVector3D &position : positions )
441 {
442 const QString source = QgsApplication::sourceCache()->localFilePath( symbol->shapeProperties()[QStringLiteral( "model" )].toString() );
443 // if the source is remote, the Qgs3DMapScene will take care of refreshing this 3D symbol when the source is fetched
444 if ( !source.isEmpty() )
445 {
446 // build the entity
447 Qt3DCore::QEntity *entity = new Qt3DCore::QEntity;
448
449 const QUrl url = QUrl::fromLocalFile( source );
450 Qt3DRender::QSceneLoader *modelLoader = new Qt3DRender::QSceneLoader;
451 modelLoader->setSource( url );
452
453 entity->addComponent( modelLoader );
454 entity->addComponent( transform( position, symbol ) );
455 entity->setParent( parent );
456
457// cppcheck wrongly believes entity will leak
458// cppcheck-suppress memleak
459 }
460 }
461}
462
463void QgsModelPoint3DSymbolHandler::addMeshEntities( const Qgs3DMapSettings &map, const QVector<QVector3D> &positions, const QgsPoint3DSymbol *symbol, Qt3DCore::QEntity *parent, bool are_selected )
464{
465 if ( positions.empty() )
466 return;
467
468 // build the default material
469 QgsMaterialContext materialContext;
470 materialContext.setIsSelected( are_selected );
471 materialContext.setSelectionColor( map.selectionColor() );
472 Qt3DRender::QMaterial *mat = symbol->materialSettings()->toMaterial( QgsMaterialSettingsRenderingTechnique::Triangles, materialContext );
473
474 // get nodes
475 for ( const QVector3D &position : positions )
476 {
477 const QString source = QgsApplication::sourceCache()->localFilePath( symbol->shapeProperties()[QStringLiteral( "model" )].toString() );
478 if ( !source.isEmpty() )
479 {
480 // build the entity
481 Qt3DCore::QEntity *entity = new Qt3DCore::QEntity;
482
483 const QUrl url = QUrl::fromLocalFile( source );
484 Qt3DRender::QMesh *mesh = new Qt3DRender::QMesh;
485 mesh->setSource( url );
486
487 entity->addComponent( mesh );
488 entity->addComponent( mat );
489 entity->addComponent( transform( position, symbol ) );
490 entity->setParent( parent );
491
492// cppcheck wrongly believes entity will leak
493// cppcheck-suppress memleak
494 }
495 }
496}
497
498Qt3DCore::QTransform *QgsModelPoint3DSymbolHandler::transform( QVector3D position, const QgsPoint3DSymbol *symbol )
499{
500 Qt3DCore::QTransform *tr = new Qt3DCore::QTransform;
501 tr->setMatrix( symbol->transform() );
502 tr->setTranslation( position + tr->translation() );
503 return tr;
504}
505
506// --------------
507
508//* BILLBOARD RENDERING *//
509
510class QgsPoint3DBillboardSymbolHandler : public QgsFeature3DHandler
511{
512 public:
513 QgsPoint3DBillboardSymbolHandler( const QgsPoint3DSymbol *symbol, const QgsFeatureIds &selectedIds )
514 : mSymbol( static_cast< QgsPoint3DSymbol * >( symbol->clone() ) )
515 , mSelectedIds( selectedIds ) {}
516
517 bool prepare( const Qgs3DRenderContext &context, QSet<QString> &attributeNames ) override;
518 void processFeature( const QgsFeature &feature, const Qgs3DRenderContext &context ) override;
519 void finalize( Qt3DCore::QEntity *parent, const Qgs3DRenderContext &context ) override;
520
521 private:
522
524 struct PointData
525 {
526 QVector<QVector3D> positions; // contains triplets of float x,y,z for each point
527 };
528
529 void makeEntity( Qt3DCore::QEntity *parent, const Qgs3DRenderContext &context, PointData &out, bool selected );
530
531 // input specific for this class
532 std::unique_ptr< QgsPoint3DSymbol > mSymbol;
533 // inputs - generic
534 QgsFeatureIds mSelectedIds;
535
536 // outputs
537 PointData outNormal;
538 PointData outSelected;
539};
540
541bool QgsPoint3DBillboardSymbolHandler::prepare( const Qgs3DRenderContext &context, QSet<QString> &attributeNames )
542{
543 Q_UNUSED( context )
544 Q_UNUSED( attributeNames )
545 return true;
546}
547
548void QgsPoint3DBillboardSymbolHandler::processFeature( const QgsFeature &feature, const Qgs3DRenderContext &context )
549{
550 PointData &out = mSelectedIds.contains( feature.id() ) ? outSelected : outNormal;
551
552 if ( feature.geometry().isNull() )
553 return;
554
555 Qgs3DUtils::extractPointPositions( feature, context.map(), mSymbol->altitudeClamping(), out.positions );
556 mFeatureCount++;
557}
558
559void QgsPoint3DBillboardSymbolHandler::finalize( Qt3DCore::QEntity *parent, const Qgs3DRenderContext &context )
560{
561 makeEntity( parent, context, outNormal, false );
562 makeEntity( parent, context, outSelected, true );
563
564 updateZRangeFromPositions( outNormal.positions );
565 updateZRangeFromPositions( outSelected.positions );
566
567 // the elevation offset is applied externally through a QTransform of QEntity so let's account for it
568 const float billboardHeight = mSymbol->transform().data()[13];
569 mZMin += billboardHeight;
570 mZMax += billboardHeight;
571}
572
573void QgsPoint3DBillboardSymbolHandler::makeEntity( Qt3DCore::QEntity *parent, const Qgs3DRenderContext &context, PointData &out, bool selected )
574{
575 // Billboard Geometry
576 QgsBillboardGeometry *billboardGeometry = new QgsBillboardGeometry();
577 billboardGeometry->setPoints( out.positions );
578
579 // Billboard Geometry Renderer
580 Qt3DRender::QGeometryRenderer *billboardGeometryRenderer = new Qt3DRender::QGeometryRenderer;
581 billboardGeometryRenderer->setPrimitiveType( Qt3DRender::QGeometryRenderer::Points );
582 billboardGeometryRenderer->setGeometry( billboardGeometry );
583 billboardGeometryRenderer->setVertexCount( billboardGeometry->count() );
584
585 // Billboard Material
587 QgsMarkerSymbol *symbol = mSymbol->billboardSymbol();
588
589 if ( symbol )
590 {
591 billboardMaterial->setTexture2DFromSymbol( symbol, context.map(), selected );
592 }
593 else
594 {
595 billboardMaterial->useDefaultSymbol( context.map(), selected );
596 }
597
598 // Billboard Transform
599 Qt3DCore::QTransform *billboardTransform = new Qt3DCore::QTransform();
600 billboardTransform->setMatrix( mSymbol->billboardTransform() );
601
602 // Build the entity
603 Qt3DCore::QEntity *entity = new Qt3DCore::QEntity;
604
605 entity->addComponent( billboardMaterial );
606 entity->addComponent( billboardTransform );
607 entity->addComponent( billboardGeometryRenderer );
608 entity->setParent( parent );
609
610// cppcheck wrongly believes entity will leak
611// cppcheck-suppress memleak
612}
613
614
615namespace Qgs3DSymbolImpl
616{
617
618 QgsFeature3DHandler *handlerForPoint3DSymbol( QgsVectorLayer *layer, const QgsAbstract3DSymbol *symbol )
619 {
620 const QgsPoint3DSymbol *pointSymbol = dynamic_cast< const QgsPoint3DSymbol * >( symbol );
621 if ( !pointSymbol )
622 return nullptr;
623
624 if ( pointSymbol->shape() == QgsPoint3DSymbol::Model )
625 return new QgsModelPoint3DSymbolHandler( pointSymbol, layer->selectedFeatureIds() );
626 // Add proper handler for billboard
627 else if ( pointSymbol->shape() == QgsPoint3DSymbol::Billboard )
628 return new QgsPoint3DBillboardSymbolHandler( pointSymbol, layer->selectedFeatureIds() );
629 else
630 return new QgsInstancedPoint3DSymbolHandler( pointSymbol, layer->selectedFeatureIds() );
631 }
632
633 Qt3DCore::QEntity *entityForPoint3DSymbol( const Qgs3DMapSettings &map, QgsVectorLayer *layer, const QgsPoint3DSymbol &symbol )
634 {
635 QgsFeature3DHandler *handler = handlerForPoint3DSymbol( layer, &symbol );
636 Qt3DCore::QEntity *e = entityFromHandler( handler, map, layer );
637 delete handler;
638 return e;
639 }
640}
641
QColor selectionColor() const
Returns color used for selected features.
static void extractPointPositions(const QgsFeature &f, const Qgs3DMapSettings &map, Qgis::AltitudeClamping altClamp, QVector< QVector3D > &positions)
Calculates (x,y,z) positions of (multi)point from the given feature.
Definition: qgs3dutils.cpp:471
virtual Qt3DRender::QMaterial * toMaterial(QgsMaterialSettingsRenderingTechnique technique, const QgsMaterialContext &context) const =0
Creates a new QMaterial object representing the material settings.
virtual void addParametersToEffect(Qt3DRender::QEffect *effect) const =0
Adds parameters from the material to a destination effect.
static QgsSourceCache * sourceCache()
Returns the application's source cache, used for caching embedded and remote source strings as local ...
void setPoints(const QVector< QVector3D > &vertices)
Set the points for the billboard with vertices.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition: qgsfeature.h:56
QgsGeometry geometry
Definition: qgsfeature.h:67
Q_GADGET QgsFeatureId id
Definition: qgsfeature.h:64
Q_GADGET bool isNull
Definition: qgsgeometry.h:166
A marker symbol type, for rendering Point and MultiPoint geometries.
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 useDefaultSymbol(const Qgs3DMapSettings &map, bool selected=false)
Set default symbol for the texture with map and selected parameter for rendering.
void setTexture2DFromSymbol(QgsMarkerSymbol *markerSymbol, const Qgs3DMapSettings &map, bool selected=false)
Set markerSymbol for the texture with map and selected parameter for rendering.
Shape
3D shape types supported by the symbol
@ ExtrudedText
Supported in Qt 5.9+.
QgsAbstractMaterialSettings * materialSettings() const
Returns material settings used for shading of the symbol.
QMatrix4x4 transform() const
Returns transform for individual objects represented by the symbol.
QgsMarkerSymbol * billboardSymbol() const
Returns a symbol for billboard.
QgsAbstract3DSymbol * clone() const override SIP_FACTORY
Shape shape() const
Returns 3D shape for points.
QVariantMap shapeProperties() const
Returns a key-value dictionary of point shape properties.
QString localFilePath(const QString &path, bool blocking=false)
Returns a local file path reflecting the content of a specified source path.
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.
@ Triangles
Triangle based rendering (default)
Qt3DCore::QAttribute Qt3DQAttribute
Definition: qgs3daxis.cpp:28
Qt3DCore::QBuffer Qt3DQBuffer
Definition: qgs3daxis.cpp:30
Qt3DCore::QGeometry Qt3DQGeometry
Definition: qgs3daxis.cpp:29
QSet< QgsFeatureId > QgsFeatureIds
Definition: qgsfeatureid.h:37
Qt3DCore::QAttribute Qt3DQAttribute
Qt3DCore::QBuffer Qt3DQBuffer
Qt3DCore::QGeometry Qt3DQGeometry