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