QGIS API Documentation 3.39.0-Master (d85f3c2a281)
Loading...
Searching...
No Matches
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 "qgsapplication.h"
61#include "qgsvectorlayer.h"
62#include "qgs3dutils.h"
65#include "qgssourcecache.h"
66
68
69
70//* INSTANCED RENDERING *//
71
72
73class QgsInstancedPoint3DSymbolHandler : public QgsFeature3DHandler
74{
75 public:
76 QgsInstancedPoint3DSymbolHandler( const QgsPoint3DSymbol *symbol, const QgsFeatureIds &selectedIds )
77 : mSymbol( static_cast< QgsPoint3DSymbol *>( symbol->clone() ) )
78 , mSelectedIds( selectedIds ) {}
79
80 bool prepare( const Qgs3DRenderContext &context, QSet<QString> &attributeNames ) override;
81 void processFeature( const QgsFeature &feature, const Qgs3DRenderContext &context ) override;
82 void finalize( Qt3DCore::QEntity *parent, const Qgs3DRenderContext &context ) override;
83
84 private:
85
86 static Qt3DRender::QMaterial *material( const QgsPoint3DSymbol *symbol, const QgsMaterialContext &materialContext );
87 static Qt3DRender::QGeometryRenderer *renderer( const QgsPoint3DSymbol *symbol, const QVector<QVector3D> &positions );
88 static Qt3DQGeometry *symbolGeometry( const QgsPoint3DSymbol *symbol );
89
91 struct PointData
92 {
93 QVector<QVector3D> positions; // contains triplets of float x,y,z for each point
94 };
95
96 void makeEntity( Qt3DCore::QEntity *parent, const Qgs3DRenderContext &context, PointData &out, bool selected );
97
98 // input specific for this class
99 std::unique_ptr< QgsPoint3DSymbol > mSymbol;
100 // inputs - generic
101 QgsFeatureIds mSelectedIds;
102
103 // outputs
104 PointData outNormal;
105 PointData outSelected;
106};
107
108
109bool QgsInstancedPoint3DSymbolHandler::prepare( const Qgs3DRenderContext &context, QSet<QString> &attributeNames )
110{
111 Q_UNUSED( context )
112 Q_UNUSED( attributeNames )
113 return true;
114}
115
116void QgsInstancedPoint3DSymbolHandler::processFeature( const QgsFeature &feature, const Qgs3DRenderContext &context )
117{
118 PointData &out = mSelectedIds.contains( feature.id() ) ? outSelected : outNormal;
119
120 if ( feature.geometry().isNull() )
121 return;
122
123 Qgs3DUtils::extractPointPositions( feature, context, mSymbol->altitudeClamping(), out.positions );
124 mFeatureCount++;
125}
126
127void QgsInstancedPoint3DSymbolHandler::finalize( Qt3DCore::QEntity *parent, const Qgs3DRenderContext &context )
128{
129 makeEntity( parent, context, outNormal, false );
130 makeEntity( parent, context, outSelected, true );
131
132 updateZRangeFromPositions( outNormal.positions );
133 updateZRangeFromPositions( outSelected.positions );
134
135 // the elevation offset is applied in the vertex shader so let's account for it as well
136 const float symbolOffset = mSymbol->transform().data()[13];
137
138 // also account for the actual height of the objects themselves
139 // NOTE -- these calculations are naive, and assume no rotation or scaling of the symbol!
140 switch ( mSymbol->shape() )
141 {
143 {
144 const float length = mSymbol->shapeProperty( QStringLiteral( "length" ) ).toFloat();
145 mZMin -= length * 0.5f;
146 mZMax += length * 0.5f;
147 break;
148 }
149
151 {
152 const float radius = mSymbol->shapeProperty( QStringLiteral( "radius" ) ).toFloat();
153 mZMin -= radius;
154 mZMax += radius;
155 break;
156 }
157
159 {
160 const float length = mSymbol->shapeProperty( QStringLiteral( "length" ) ).toFloat();
161 mZMin -= length * 0.5f;
162 mZMax += length * 0.5f;
163 break;
164 }
165
167 {
168 const float size = mSymbol->shapeProperty( QStringLiteral( "size" ) ).toFloat();
169 mZMin -= size * 0.5f;
170 mZMax += size * 0.5f;
171 break;
172 }
173
175 {
176 const float radius = mSymbol->shapeProperty( QStringLiteral( "radius" ) ).toFloat();
177 mZMin -= radius;
178 mZMax += radius;
179 break;
180 }
181
183 {
184 // worst case scenario -- even though planes are usually rotated so that they are flat,
185 // let's account for possible overridden rotation
186 const float size = mSymbol->shapeProperty( QStringLiteral( "size" ) ).toFloat();
187 mZMin -= size * 0.5f;
188 mZMax += size * 0.5f;
189 break;
190 }
191
195 break;
196 }
197
198 mZMin += symbolOffset;
199 mZMax += symbolOffset;
200}
201
202void QgsInstancedPoint3DSymbolHandler::makeEntity( Qt3DCore::QEntity *parent, const Qgs3DRenderContext &context, PointData &out, bool selected )
203{
204 // build the default material
205 QgsMaterialContext materialContext;
206 materialContext.setIsSelected( selected );
207 materialContext.setSelectionColor( context.selectionColor() );
208 Qt3DRender::QMaterial *mat = material( mSymbol.get(), materialContext );
209
210 // build the entity
211 Qt3DCore::QEntity *entity = new Qt3DCore::QEntity;
212 entity->addComponent( renderer( mSymbol.get(), out.positions ) );
213 entity->addComponent( mat );
214 entity->setParent( parent );
215
216// cppcheck wrongly believes entity will leak
217// cppcheck-suppress memleak
218}
219
220
221
222Qt3DRender::QMaterial *QgsInstancedPoint3DSymbolHandler::material( const QgsPoint3DSymbol *symbol, const QgsMaterialContext &materialContext )
223{
224 Qt3DRender::QFilterKey *filterKey = new Qt3DRender::QFilterKey;
225 filterKey->setName( QStringLiteral( "renderingStyle" ) );
226 filterKey->setValue( "forward" );
227
228 Qt3DRender::QShaderProgram *shaderProgram = new Qt3DRender::QShaderProgram;
229 shaderProgram->setVertexShaderCode( Qt3DRender::QShaderProgram::loadSource( QUrl( QStringLiteral( "qrc:/shaders/instanced.vert" ) ) ) );
230 shaderProgram->setFragmentShaderCode( Qt3DRender::QShaderProgram::loadSource( QUrl( QStringLiteral( "qrc:/shaders/phong.frag" ) ) ) );
231
232 Qt3DRender::QRenderPass *renderPass = new Qt3DRender::QRenderPass;
233 renderPass->setShaderProgram( shaderProgram );
234
235 Qt3DRender::QTechnique *technique = new Qt3DRender::QTechnique;
236 technique->addFilterKey( filterKey );
237 technique->addRenderPass( renderPass );
238 technique->graphicsApiFilter()->setApi( Qt3DRender::QGraphicsApiFilter::OpenGL );
239 technique->graphicsApiFilter()->setProfile( Qt3DRender::QGraphicsApiFilter::CoreProfile );
240 technique->graphicsApiFilter()->setMajorVersion( 3 );
241 technique->graphicsApiFilter()->setMinorVersion( 2 );
242
243 const QMatrix4x4 transformMatrix = symbol->transform();
244 QMatrix3x3 normalMatrix = transformMatrix.normalMatrix(); // transponed inverse of 3x3 sub-matrix
245
246 // QMatrix3x3 is not supported for passing to shaders, so we pass QMatrix4x4
247 float *n = normalMatrix.data();
248 const QMatrix4x4 normalMatrix4(
249 n[0], n[3], n[6], 0,
250 n[1], n[4], n[7], 0,
251 n[2], n[5], n[8], 0,
252 0, 0, 0, 0 );
253
254 Qt3DRender::QParameter *paramInst = new Qt3DRender::QParameter;
255 paramInst->setName( QStringLiteral( "inst" ) );
256 paramInst->setValue( transformMatrix );
257
258 Qt3DRender::QParameter *paramInstNormal = new Qt3DRender::QParameter;
259 paramInstNormal->setName( QStringLiteral( "instNormal" ) );
260 paramInstNormal->setValue( normalMatrix4 );
261
262 Qt3DRender::QEffect *effect = new Qt3DRender::QEffect;
263 effect->addTechnique( technique );
264 effect->addParameter( paramInst );
265 effect->addParameter( paramInstNormal );
266
267 symbol->materialSettings()->addParametersToEffect( effect, materialContext );
268
269 Qt3DRender::QMaterial *material = new Qt3DRender::QMaterial;
270 material->setEffect( effect );
271
272 return material;
273}
274
275Qt3DRender::QGeometryRenderer *QgsInstancedPoint3DSymbolHandler::renderer( const QgsPoint3DSymbol *symbol, const QVector<QVector3D> &positions )
276{
277 const int count = positions.count();
278 const int byteCount = positions.count() * sizeof( QVector3D );
279 QByteArray ba;
280 ba.resize( byteCount );
281 memcpy( ba.data(), positions.constData(), byteCount );
282
283 Qt3DQBuffer *instanceBuffer = new Qt3DQBuffer();
284 instanceBuffer->setData( ba );
285
286 Qt3DQAttribute *instanceDataAttribute = new Qt3DQAttribute;
287 instanceDataAttribute->setName( QStringLiteral( "pos" ) );
288 instanceDataAttribute->setAttributeType( Qt3DQAttribute::VertexAttribute );
289 instanceDataAttribute->setVertexBaseType( Qt3DQAttribute::Float );
290 instanceDataAttribute->setVertexSize( 3 );
291 instanceDataAttribute->setByteOffset( 0 );
292 instanceDataAttribute->setDivisor( 1 );
293 instanceDataAttribute->setBuffer( instanceBuffer );
294 instanceDataAttribute->setCount( count );
295 instanceDataAttribute->setByteStride( 3 * sizeof( float ) );
296
297 Qt3DQGeometry *geometry = symbolGeometry( symbol );
298 geometry->addAttribute( instanceDataAttribute );
299 geometry->setBoundingVolumePositionAttribute( instanceDataAttribute );
300
301 Qt3DRender::QGeometryRenderer *renderer = new Qt3DRender::QGeometryRenderer;
302 renderer->setGeometry( geometry );
303 renderer->setInstanceCount( count );
304
305 return renderer;
306}
307
308Qt3DQGeometry *QgsInstancedPoint3DSymbolHandler::symbolGeometry( const QgsPoint3DSymbol *symbol )
309{
310 switch ( symbol->shape() )
311 {
313 {
314 const float radius = symbol->shapeProperty( QStringLiteral( "radius" ) ).toFloat();
315 const float length = symbol->shapeProperty( QStringLiteral( "length" ) ).toFloat();
316 Qt3DExtras::QCylinderGeometry *g = new Qt3DExtras::QCylinderGeometry;
317 //g->setRings(2); // how many vertices vertically
318 //g->setSlices(8); // how many vertices on circumference
319 g->setRadius( radius );
320 g->setLength( length );
321 return g;
322 }
323
325 {
326 const float radius = symbol->shapeProperty( QStringLiteral( "radius" ) ).toFloat();
327 Qt3DExtras::QSphereGeometry *g = new Qt3DExtras::QSphereGeometry;
328 g->setRadius( radius );
329 return g;
330 }
331
333 {
334 const float length = symbol->shapeProperty( QStringLiteral( "length" ) ).toFloat();
335 const float bottomRadius = symbol->shapeProperty( QStringLiteral( "bottomRadius" ) ).toFloat();
336 const float topRadius = symbol->shapeProperty( QStringLiteral( "topRadius" ) ).toFloat();
337
338 Qt3DExtras::QConeGeometry *g = new Qt3DExtras::QConeGeometry;
339 g->setLength( length );
340 g->setBottomRadius( bottomRadius );
341 g->setTopRadius( topRadius );
342 //g->setHasBottomEndcap(hasBottomEndcap);
343 //g->setHasTopEndcap(hasTopEndcap);
344 return g;
345 }
346
348 {
349 const float size = symbol->shapeProperty( QStringLiteral( "size" ) ).toFloat();
350 Qt3DExtras::QCuboidGeometry *g = new Qt3DExtras::QCuboidGeometry;
351 g->setXExtent( size );
352 g->setYExtent( size );
353 g->setZExtent( size );
354 return g;
355 }
356
358 {
359 const float radius = symbol->shapeProperty( QStringLiteral( "radius" ) ).toFloat();
360 const float minorRadius = symbol->shapeProperty( QStringLiteral( "minorRadius" ) ).toFloat();
361 Qt3DExtras::QTorusGeometry *g = new Qt3DExtras::QTorusGeometry;
362 g->setRadius( radius );
363 g->setMinorRadius( minorRadius );
364 return g;
365 }
366
368 {
369 const float size = symbol->shapeProperty( QStringLiteral( "size" ) ).toFloat();
370 Qt3DExtras::QPlaneGeometry *g = new Qt3DExtras::QPlaneGeometry;
371 g->setWidth( size );
372 g->setHeight( size );
373 return g;
374 }
375
377 {
378 const float depth = symbol->shapeProperty( QStringLiteral( "depth" ) ).toFloat();
379 const QString text = symbol->shapeProperty( QStringLiteral( "text" ) ).toString();
380 Qt3DExtras::QExtrudedTextGeometry *g = new Qt3DExtras::QExtrudedTextGeometry;
381 g->setDepth( depth );
382 g->setText( text );
383 return g;
384 }
385
388 break;
389 }
390 Q_ASSERT( false );
391 return nullptr;
392}
393
394//* 3D MODEL RENDERING *//
395
396
397class QgsModelPoint3DSymbolHandler : public QgsFeature3DHandler
398{
399 public:
400 QgsModelPoint3DSymbolHandler( const QgsPoint3DSymbol *symbol, const QgsFeatureIds &selectedIds )
401 : mSymbol( static_cast< QgsPoint3DSymbol * >( symbol->clone() ) )
402 , mSelectedIds( selectedIds ) {}
403
404 bool prepare( const Qgs3DRenderContext &context, QSet<QString> &attributeNames ) override;
405 void processFeature( const QgsFeature &feature, const Qgs3DRenderContext &context ) override;
406 void finalize( Qt3DCore::QEntity *parent, const Qgs3DRenderContext &context ) override;
407
408 private:
409
410 static void addSceneEntities( const Qgs3DRenderContext &context, const QVector<QVector3D> &positions, const QgsPoint3DSymbol *symbol, Qt3DCore::QEntity *parent );
411 static void addMeshEntities( const Qgs3DRenderContext &context, const QVector<QVector3D> &positions, const QgsPoint3DSymbol *symbol, Qt3DCore::QEntity *parent, bool are_selected );
412 static Qt3DCore::QTransform *transform( QVector3D position, const QgsPoint3DSymbol *symbol );
413
415 struct PointData
416 {
417 QVector<QVector3D> positions; // contains triplets of float x,y,z for each point
418 };
419
420 void makeEntity( Qt3DCore::QEntity *parent, const Qgs3DRenderContext &context, PointData &out, bool selected );
421
422 // input specific for this class
423 std::unique_ptr< QgsPoint3DSymbol > mSymbol;
424 // inputs - generic
425 QgsFeatureIds mSelectedIds;
426
427 // outputs
428 PointData outNormal;
429 PointData outSelected;
430};
431
432bool QgsModelPoint3DSymbolHandler::prepare( const Qgs3DRenderContext &context, QSet<QString> &attributeNames )
433{
434 Q_UNUSED( context )
435 Q_UNUSED( attributeNames )
436 return true;
437}
438
439void QgsModelPoint3DSymbolHandler::processFeature( const QgsFeature &feature, const Qgs3DRenderContext &context )
440{
441 PointData &out = mSelectedIds.contains( feature.id() ) ? outSelected : outNormal;
442
443 if ( feature.geometry().isNull() )
444 return;
445
446 Qgs3DUtils::extractPointPositions( feature, context, mSymbol->altitudeClamping(), out.positions );
447 mFeatureCount++;
448}
449
450void QgsModelPoint3DSymbolHandler::finalize( Qt3DCore::QEntity *parent, const Qgs3DRenderContext &context )
451{
452 makeEntity( parent, context, outNormal, false );
453 makeEntity( parent, context, outSelected, true );
454
455 updateZRangeFromPositions( outNormal.positions );
456 updateZRangeFromPositions( outSelected.positions );
457
458 // the elevation offset is applied separately in QTransform added to sub-entities
459 const float symbolHeight = mSymbol->transform().data()[13];
460 mZMin += symbolHeight;
461 mZMax += symbolHeight;
462}
463
464void QgsModelPoint3DSymbolHandler::makeEntity( Qt3DCore::QEntity *parent, const Qgs3DRenderContext &context, PointData &out, bool selected )
465{
466 if ( selected )
467 {
468 addMeshEntities( context, out.positions, mSymbol.get(), parent, true );
469 }
470 else
471 {
472 // "overwriteMaterial" is a legacy setting indicating that non-embedded material should be used
473 if ( mSymbol->shapeProperty( QStringLiteral( "overwriteMaterial" ) ).toBool()
474 || ( mSymbol->materialSettings() && mSymbol->materialSettings()->type() != QLatin1String( "null" ) ) )
475 {
476 addMeshEntities( context, out.positions, mSymbol.get(), parent, false );
477 }
478 else
479 {
480 addSceneEntities( context, out.positions, mSymbol.get(), parent );
481 }
482 }
483}
484
485
486
487void QgsModelPoint3DSymbolHandler::addSceneEntities( const Qgs3DRenderContext &, const QVector<QVector3D> &positions, const QgsPoint3DSymbol *symbol, Qt3DCore::QEntity *parent )
488{
489 for ( const QVector3D &position : positions )
490 {
491 const QString source = QgsApplication::sourceCache()->localFilePath( symbol->shapeProperty( QStringLiteral( "model" ) ).toString() );
492 // if the source is remote, the Qgs3DMapScene will take care of refreshing this 3D symbol when the source is fetched
493 if ( !source.isEmpty() )
494 {
495 // build the entity
496 Qt3DCore::QEntity *entity = new Qt3DCore::QEntity;
497
498 const QUrl url = QUrl::fromLocalFile( source );
499 Qt3DRender::QSceneLoader *modelLoader = new Qt3DRender::QSceneLoader;
500 modelLoader->setSource( url );
501
502 entity->addComponent( modelLoader );
503 entity->addComponent( transform( position, symbol ) );
504 entity->setParent( parent );
505
506// cppcheck wrongly believes entity will leak
507// cppcheck-suppress memleak
508 }
509 }
510}
511
512void QgsModelPoint3DSymbolHandler::addMeshEntities( const Qgs3DRenderContext &context, const QVector<QVector3D> &positions, const QgsPoint3DSymbol *symbol, Qt3DCore::QEntity *parent, bool are_selected )
513{
514 if ( positions.empty() )
515 return;
516
517 // build the default material
518 QgsMaterialContext materialContext;
519 materialContext.setIsSelected( are_selected );
520 materialContext.setSelectionColor( context.selectionColor() );
521 Qt3DRender::QMaterial *mat = symbol->materialSettings()->toMaterial( QgsMaterialSettingsRenderingTechnique::Triangles, materialContext );
522
523 // get nodes
524 for ( const QVector3D &position : positions )
525 {
526 const QString source = QgsApplication::sourceCache()->localFilePath( symbol->shapeProperty( QStringLiteral( "model" ) ).toString() );
527 if ( !source.isEmpty() )
528 {
529 // build the entity
530 Qt3DCore::QEntity *entity = new Qt3DCore::QEntity;
531
532 const QUrl url = QUrl::fromLocalFile( source );
533 Qt3DRender::QMesh *mesh = new Qt3DRender::QMesh;
534 mesh->setSource( url );
535
536 entity->addComponent( mesh );
537 entity->addComponent( mat );
538 entity->addComponent( transform( position, symbol ) );
539 entity->setParent( parent );
540
541// cppcheck wrongly believes entity will leak
542// cppcheck-suppress memleak
543 }
544 }
545}
546
547Qt3DCore::QTransform *QgsModelPoint3DSymbolHandler::transform( QVector3D position, const QgsPoint3DSymbol *symbol )
548{
549 Qt3DCore::QTransform *tr = new Qt3DCore::QTransform;
550 tr->setMatrix( symbol->transform() );
551 tr->setTranslation( position + tr->translation() );
552 return tr;
553}
554
555// --------------
556
557//* BILLBOARD RENDERING *//
558
559class QgsPoint3DBillboardSymbolHandler : public QgsFeature3DHandler
560{
561 public:
562 QgsPoint3DBillboardSymbolHandler( const QgsPoint3DSymbol *symbol, const QgsFeatureIds &selectedIds )
563 : mSymbol( static_cast< QgsPoint3DSymbol * >( symbol->clone() ) )
564 , mSelectedIds( selectedIds ) {}
565
566 bool prepare( const Qgs3DRenderContext &context, QSet<QString> &attributeNames ) override;
567 void processFeature( const QgsFeature &feature, const Qgs3DRenderContext &context ) override;
568 void finalize( Qt3DCore::QEntity *parent, const Qgs3DRenderContext &context ) override;
569
570 private:
571
573 struct PointData
574 {
575 QVector<QVector3D> positions; // contains triplets of float x,y,z for each point
576 };
577
578 void makeEntity( Qt3DCore::QEntity *parent, const Qgs3DRenderContext &context, PointData &out, bool selected );
579
580 // input specific for this class
581 std::unique_ptr< QgsPoint3DSymbol > mSymbol;
582 // inputs - generic
583 QgsFeatureIds mSelectedIds;
584
585 // outputs
586 PointData outNormal;
587 PointData outSelected;
588};
589
590bool QgsPoint3DBillboardSymbolHandler::prepare( const Qgs3DRenderContext &context, QSet<QString> &attributeNames )
591{
592 Q_UNUSED( context )
593 Q_UNUSED( attributeNames )
594 return true;
595}
596
597void QgsPoint3DBillboardSymbolHandler::processFeature( const QgsFeature &feature, const Qgs3DRenderContext &context )
598{
599 PointData &out = mSelectedIds.contains( feature.id() ) ? outSelected : outNormal;
600
601 if ( feature.geometry().isNull() )
602 return;
603
604 Qgs3DUtils::extractPointPositions( feature, context, mSymbol->altitudeClamping(), out.positions );
605 mFeatureCount++;
606}
607
608void QgsPoint3DBillboardSymbolHandler::finalize( Qt3DCore::QEntity *parent, const Qgs3DRenderContext &context )
609{
610 makeEntity( parent, context, outNormal, false );
611 makeEntity( parent, context, outSelected, true );
612
613 updateZRangeFromPositions( outNormal.positions );
614 updateZRangeFromPositions( outSelected.positions );
615
616 // the elevation offset is applied externally through a QTransform of QEntity so let's account for it
617 const float billboardHeight = mSymbol->transform().data()[13];
618 mZMin += billboardHeight;
619 mZMax += billboardHeight;
620}
621
622void QgsPoint3DBillboardSymbolHandler::makeEntity( Qt3DCore::QEntity *parent, const Qgs3DRenderContext &context, PointData &out, bool selected )
623{
624 // Billboard Geometry
625 QgsBillboardGeometry *billboardGeometry = new QgsBillboardGeometry();
626 billboardGeometry->setPoints( out.positions );
627
628 // Billboard Geometry Renderer
629 Qt3DRender::QGeometryRenderer *billboardGeometryRenderer = new Qt3DRender::QGeometryRenderer;
630 billboardGeometryRenderer->setPrimitiveType( Qt3DRender::QGeometryRenderer::Points );
631 billboardGeometryRenderer->setGeometry( billboardGeometry );
632 billboardGeometryRenderer->setVertexCount( billboardGeometry->count() );
633
634 // Billboard Material
636 QgsMarkerSymbol *symbol = mSymbol->billboardSymbol();
637
638 if ( symbol )
639 {
640 billboardMaterial->setTexture2DFromSymbol( symbol, context, selected );
641 }
642 else
643 {
644 billboardMaterial->useDefaultSymbol( context, selected );
645 }
646
647 // Billboard Transform
648 Qt3DCore::QTransform *billboardTransform = new Qt3DCore::QTransform();
649 billboardTransform->setMatrix( mSymbol->billboardTransform() );
650
651 // Build the entity
652 Qt3DCore::QEntity *entity = new Qt3DCore::QEntity;
653
654 entity->addComponent( billboardMaterial );
655 entity->addComponent( billboardTransform );
656 entity->addComponent( billboardGeometryRenderer );
657 entity->setParent( parent );
658
659// cppcheck wrongly believes entity will leak
660// cppcheck-suppress memleak
661}
662
663
664namespace Qgs3DSymbolImpl
665{
666
667 QgsFeature3DHandler *handlerForPoint3DSymbol( QgsVectorLayer *layer, const QgsAbstract3DSymbol *symbol )
668 {
669 const QgsPoint3DSymbol *pointSymbol = dynamic_cast< const QgsPoint3DSymbol * >( symbol );
670 if ( !pointSymbol )
671 return nullptr;
672
673 if ( pointSymbol->shape() == Qgis::Point3DShape::Model )
674 return new QgsModelPoint3DSymbolHandler( pointSymbol, layer->selectedFeatureIds() );
675 // Add proper handler for billboard
676 else if ( pointSymbol->shape() == Qgis::Point3DShape::Billboard )
677 return new QgsPoint3DBillboardSymbolHandler( pointSymbol, layer->selectedFeatureIds() );
678 else
679 return new QgsInstancedPoint3DSymbolHandler( pointSymbol, layer->selectedFeatureIds() );
680 }
681}
682
@ Plane
Flat plane.
@ Cylinder
Cylinder.
@ ExtrudedText
Extruded text.
@ Billboard
Billboard.
QColor selectionColor() const
Returns color used for selected features.
static void extractPointPositions(const QgsFeature &f, const Qgs3DRenderContext &context, Qgis::AltitudeClamping altClamp, QVector< QVector3D > &positions)
Calculates (x,y,z) positions of (multi)point from the given feature.
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 QgsMaterialContext &materialContext) 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:58
QgsFeatureId id
Definition qgsfeature.h:66
QgsGeometry geometry
Definition qgsfeature.h:69
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 Qgs3DRenderContext &context, bool selected=false)
Set default symbol for the texture with context and selected parameter for rendering.
void setTexture2DFromSymbol(QgsMarkerSymbol *markerSymbol, const Qgs3DRenderContext &context, bool selected=false)
Set markerSymbol for the texture with context and selected parameter for rendering.
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.
Qgis::Point3DShape shape() const
Returns 3D shape for points.
QgsAbstract3DSymbol * clone() const override
Returns a new instance of the symbol with the same settings.
QVariant shapeProperty(const QString &property) const
Returns the value for a specific shape property.
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
Qt3DCore::QBuffer Qt3DQBuffer
Qt3DCore::QGeometry Qt3DQGeometry
QSet< QgsFeatureId > QgsFeatureIds
Qt3DCore::QAttribute Qt3DQAttribute
Qt3DCore::QBuffer Qt3DQBuffer
Qt3DCore::QGeometry Qt3DQGeometry