QGIS API Documentation 4.1.0-Master (26185ffb827)
Loading...
Searching...
No Matches
qgspoint3dsymbol.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgspoint3dsymbol.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.h"
17
18#include "qgs3d.h"
19#include "qgs3dexportobject.h"
20#include "qgs3dsceneexporter.h"
21#include "qgs3dutils.h"
22#include "qgsmarkersymbol.h"
23#include "qgsmaterialregistry.h"
25#include "qgsreadwritecontext.h"
26#include "qgssymbollayerutils.h"
27#include "qgsvectorlayer.h"
29#include "qgsxmlutils.h"
30
31#include <QString>
32
33using namespace Qt::StringLiterals;
34
36{
37 return new QgsPoint3DSymbol( *this );
38}
39
44
50
52 : mAltClamping( other.altitudeClamping() )
53 , mMaterialSettings( other.materialSettings() ? other.materialSettings()->clone() : nullptr )
54 , mShape( other.shape() )
55 , mShapeProperties( other.shapeProperties() )
56 , mTransform( other.transform() )
57 , mBillboardSymbol( other.billboardSymbol() ? other.billboardSymbol()->clone() : nullptr )
58{
60}
61
63
64void QgsPoint3DSymbol::writeXml( QDomElement &elem, const QgsReadWriteContext &context ) const
65{
66 QDomDocument doc = elem.ownerDocument();
67
68 QDomElement elemDataProperties = doc.createElement( u"data"_s );
69 elemDataProperties.setAttribute( u"alt-clamping"_s, Qgs3DUtils::altClampingToString( mAltClamping ) );
70 elem.appendChild( elemDataProperties );
71
72 elem.setAttribute( u"material_type"_s, mMaterialSettings->type() );
73 QDomElement elemMaterial = doc.createElement( u"material"_s );
74 mMaterialSettings->writeXml( elemMaterial, context );
75 elem.appendChild( elemMaterial );
76
77 elem.setAttribute( u"shape"_s, shapeToString( mShape ) );
78
79 QVariantMap shapePropertiesCopy( mShapeProperties );
80 shapePropertiesCopy[u"model"_s] = QVariant( context.pathResolver().writePath( shapePropertiesCopy[u"model"_s].toString() ) );
81
82 QDomElement elemShapeProperties = doc.createElement( u"shape-properties"_s );
83 elemShapeProperties.appendChild( QgsXmlUtils::writeVariant( shapePropertiesCopy, doc ) );
84 elem.appendChild( elemShapeProperties );
85
86 QDomElement elemTransform = doc.createElement( u"transform"_s );
87 elemTransform.setAttribute( u"matrix"_s, Qgs3DUtils::matrix4x4toString( mTransform ) );
88 elem.appendChild( elemTransform );
89
90 QDomElement elemDDP = doc.createElement( u"data-defined-properties"_s );
91 mDataDefinedProperties.writeXml( elemDDP, propertyDefinitions() );
92 elem.appendChild( elemDDP );
93
94 if ( billboardSymbol() )
95 {
96 const QDomElement symbolElem = QgsSymbolLayerUtils::saveSymbol( u"symbol"_s, billboardSymbol(), doc, context );
97
98 elem.appendChild( symbolElem );
99 }
100}
101
102void QgsPoint3DSymbol::readXml( const QDomElement &elem, const QgsReadWriteContext &context )
103{
104 const QDomElement elemDataProperties = elem.firstChildElement( u"data"_s );
105 mAltClamping = Qgs3DUtils::altClampingFromString( elemDataProperties.attribute( u"alt-clamping"_s ) );
106
107 const QDomElement elemMaterial = elem.firstChildElement( u"material"_s );
108 const QString materialType = elem.attribute( u"material_type"_s, u"metalrough"_s );
109 mMaterialSettings = Qgs3D::materialRegistry()->createMaterialSettings( materialType );
110 if ( !mMaterialSettings )
111 mMaterialSettings = Qgs3D::materialRegistry()->createMaterialSettings( u"metalrough"_s );
112 mMaterialSettings->readXml( elemMaterial, context );
113
114 mShape = shapeFromString( elem.attribute( u"shape"_s ) );
115
116 const QDomElement elemShapeProperties = elem.firstChildElement( u"shape-properties"_s );
117 mShapeProperties = QgsXmlUtils::readVariant( elemShapeProperties.firstChildElement() ).toMap();
118 mShapeProperties[u"model"_s] = QVariant( context.pathResolver().readPath( mShapeProperties[u"model"_s].toString() ) );
119
120 const QDomElement elemTransform = elem.firstChildElement( u"transform"_s );
121 mTransform = Qgs3DUtils::stringToMatrix4x4( elemTransform.attribute( u"matrix"_s ) );
122
123 const QDomElement elemDDP = elem.firstChildElement( u"data-defined-properties"_s );
124 if ( !elemDDP.isNull() )
125 mDataDefinedProperties.readXml( elemDDP, propertyDefinitions() );
126
127 const QDomElement symbolElem = elem.firstChildElement( u"symbol"_s );
128
130}
131
132QList<Qgis::GeometryType> QgsPoint3DSymbol::compatibleGeometryTypes() const
133{
134 return QList<Qgis::GeometryType>() << Qgis::GeometryType::Point;
135}
136
138{
139 const QgsVectorLayerElevationProperties *props = qgis::down_cast<const QgsVectorLayerElevationProperties *>( const_cast<QgsVectorLayer *>( layer )->elevationProperties() );
140
141 mAltClamping = props->clamping();
142 mTransform.data()[13] = static_cast<float>( props->zOffset() );
143 mShapeProperties[u"length"_s] = props->extrusionEnabled() ? static_cast<float>( props->extrusionHeight() ) : 0.0f;
144}
145
147{
148 if ( shape == "sphere"_L1 )
150 else if ( shape == "cone"_L1 )
152 else if ( shape == "cube"_L1 )
154 else if ( shape == "torus"_L1 )
156 else if ( shape == "plane"_L1 )
158 else if ( shape == "extruded-text"_L1 )
160 else if ( shape == "model"_L1 )
162 else if ( shape == "billboard"_L1 )
164 else // "cylinder" (default)
166}
167
169{
170 switch ( shape )
171 {
173 return u"cylinder"_s;
175 return u"sphere"_s;
177 return u"cone"_s;
179 return u"cube"_s;
181 return u"torus"_s;
183 return u"plane"_s;
185 return u"extruded-text"_s;
187 return u"model"_s;
189 return u"billboard"_s;
190 default:
191 Q_ASSERT( false );
192 return QString();
193 }
194}
195
196QVariant QgsPoint3DSymbol::shapeProperty( const QString &property ) const
197{
198 switch ( mShape )
199 {
201 {
202 if ( property == "length"_L1 )
203 {
204 const float length = mShapeProperties.value( property ).toFloat();
205 if ( length == 0 )
206 return 10;
207 return length;
208 }
209 else if ( property == "radius"_L1 )
210 {
211 const float radius = mShapeProperties.value( property ).toFloat();
212 if ( radius == 0 )
213 return 10;
214 return radius;
215 }
216 break;
217 }
219 {
220 if ( property == "radius"_L1 )
221 {
222 const float radius = mShapeProperties.value( property ).toFloat();
223 if ( radius == 0 )
224 return 10;
225 return radius;
226 }
227 else if ( property == "rings"_L1 )
228 {
229 constexpr int DEFAULT_RINGS = 16;
230 const int rings = mShapeProperties.value( property, DEFAULT_RINGS ).toInt();
231 if ( rings == 0 )
232 return DEFAULT_RINGS;
233 return rings;
234 }
235 else if ( property == "slices"_L1 )
236 {
237 constexpr int DEFAULT_SLICES = 16;
238 const int slices = mShapeProperties.value( property, DEFAULT_SLICES ).toInt();
239 if ( slices == 0 )
240 return DEFAULT_SLICES;
241 return slices;
242 }
243 break;
244 }
246 {
247 if ( property == "length"_L1 )
248 {
249 const float length = mShapeProperties.value( property ).toFloat();
250 if ( length == 0 )
251 return 10;
252 return length;
253 }
254 break;
255 }
257 {
258 if ( property == "size"_L1 )
259 {
260 const float size = mShapeProperties.value( property ).toFloat();
261 if ( size == 0 )
262 return 10;
263 return size;
264 }
265 break;
266 }
268 {
269 if ( property == "radius"_L1 )
270 {
271 const float radius = mShapeProperties.value( property ).toFloat();
272 if ( radius == 0 )
273 return 10;
274 return radius;
275 }
276 else if ( property == "minorRadius"_L1 )
277 {
278 const float minorRadius = mShapeProperties.value( property ).toFloat();
279 if ( minorRadius == 0 )
280 return 5;
281 return minorRadius;
282 }
283 break;
284 }
286 {
287 if ( property == "size"_L1 )
288 {
289 const float size = mShapeProperties.value( property ).toFloat();
290 if ( size == 0 )
291 return 10;
292 return size;
293 }
294 break;
295 }
297 {
298 if ( property == "depth"_L1 )
299 {
300 const float depth = mShapeProperties.value( property ).toFloat();
301 if ( depth == 0 )
302 return 1;
303 return depth;
304 }
305 break;
306 }
307
309 {
310 // defaults are "z" up, "y" forward -- this ensures default rendering matches 3.x appearance
311 if ( property == "upAxis"_L1 )
312 {
313 return mShapeProperties.value( u"upAxis"_s, u"z"_s ).toString();
314 }
315 if ( property == "forwardAxis"_L1 )
316 {
317 return mShapeProperties.value( u"forwardAxis"_s, u"y"_s ).toString();
318 }
319 break;
320 }
321
323 break;
324 }
325 return mShapeProperties.value( property );
326}
327
329{
330 return mTransform.data()[14];
331}
332
334{
335 return mMaterialSettings.get();
336}
337
339{
340 if ( materialSettings == mMaterialSettings.get() )
341 return;
342
343 mMaterialSettings.reset( materialSettings );
344}
345
346bool QgsPoint3DSymbol::exportGeometries( Qgs3DSceneExporter *exporter, Qt3DCore::QEntity *entity, const QString &objectNamePrefix ) const
347{
349 {
350 Qt3DRender::QSceneLoader *sceneLoader = entity->findChild<Qt3DRender::QSceneLoader *>();
351 if ( sceneLoader )
352 {
353 const QVector<Qgs3DExportObject *> objects = exporter->processSceneLoaderGeometries( sceneLoader, objectNamePrefix );
354 for ( Qgs3DExportObject *obj : objects )
355 {
356 obj->setSmoothEdges( exporter->smoothEdges() );
357 obj->setupMaterial( materialSettings() );
358 }
359 exporter->mObjects << objects;
360 }
361 else
362 {
363 const QList<Qt3DRender::QMesh *> meshes = entity->findChildren<Qt3DRender::QMesh *>();
364 for ( Qt3DRender::QMesh *mesh : meshes )
365 {
366 Qgs3DExportObject *object = exporter->processGeometryRenderer( mesh, objectNamePrefix );
367 if ( !object )
368 continue;
369 object->setSmoothEdges( exporter->smoothEdges() );
370 object->setupMaterial( materialSettings() );
371 exporter->mObjects << object;
372 }
373 }
374 return true;
375 }
376 else if ( shape() == Qgis::Point3DShape::Billboard )
377 {
378 Qgs3DExportObject *obj = exporter->processPoints( entity, objectNamePrefix );
379 if ( obj )
380 {
381 exporter->mObjects << obj;
382 return true;
383 }
384 }
385 else
386 {
387 const QVector<Qgs3DExportObject *> objects = exporter->processInstancedPointGeometry( entity, objectNamePrefix );
388 for ( Qgs3DExportObject *obj : objects )
389 {
390 obj->setupMaterial( materialSettings() );
391 exporter->mObjects << obj;
392 }
393 return true;
394 }
395 return false;
396}
397
399{
400 return mBillboardSymbol.get();
401}
402
404{
405 mBillboardSymbol.reset( symbol );
406}
Point3DShape
3D point shape types.
Definition qgis.h:4340
@ Plane
Flat plane.
Definition qgis.h:4346
@ Cylinder
Cylinder.
Definition qgis.h:4341
@ Torus
Torus.
Definition qgis.h:4345
@ ExtrudedText
Extruded text.
Definition qgis.h:4347
@ Model
Model.
Definition qgis.h:4348
@ Sphere
Sphere.
Definition qgis.h:4342
@ Billboard
Billboard.
Definition qgis.h:4349
@ Point
Points.
Definition qgis.h:380
Manages the data of each object of the scene (positions, normals, texture coordinates ....
void setSmoothEdges(bool smoothEdges)
Sets whether triangles edges will look smooth.
Entity that handles the exporting of 3D scenes.
bool smoothEdges() const
Returns whether the triangles will look smooth.
static Qgis::AltitudeClamping altClampingFromString(const QString &str)
Converts a string to a value from AltitudeClamping enum.
static QString matrix4x4toString(const QMatrix4x4 &m)
Converts a 4x4 transform matrix to a string.
static QString altClampingToString(Qgis::AltitudeClamping altClamp)
Converts a value from AltitudeClamping enum to a string.
static QMatrix4x4 stringToMatrix4x4(const QString &str)
Convert a string to a 4x4 transform matrix.
static QgsMaterialRegistry * materialRegistry()
Returns the material registry, used for managing 3D materials.
Definition qgs3d.cpp:125
Abstract base class for 3D symbols that are used by VectorLayer3DRenderer objects.
static const QgsPropertiesDefinition & propertyDefinitions()
Returns the symbol layer property definitions.
void setDataDefinedProperties(const QgsPropertyCollection &collection)
Sets the symbol layer's property collection, used for data defined overrides.
QgsPropertyCollection mDataDefinedProperties
QgsPropertyCollection & dataDefinedProperties()
Returns a reference to the symbol layer's property collection, used for data defined overrides.
Abstract base class for material settings.
double zOffset() const
Returns the z offset, which is a fixed offset amount which should be added to z values from the layer...
A marker symbol type, for rendering Point and MultiPoint geometries.
std::unique_ptr< QgsAbstractMaterialSettings > createMaterialSettings(const QString &type) const
Creates a new instance of the material settings of the specified type.
A PBR metal rough shading material used for rendering.
QString writePath(const QString &filename) const
Prepare a filename to save it to the project file.
QString readPath(const QString &filename) const
Turn filename read from the project file to an absolute path.
static QString shapeToString(Qgis::Point3DShape shape)
Returns string from a shape enum value.
~QgsPoint3DSymbol() override
void setDefaultPropertiesFromLayer(const QgsVectorLayer *layer) override
Sets default properties for the symbol based on a layer's configuration.
static QgsAbstract3DSymbol * create()
Creates a new QgsPoint3DSymbol.
void writeXml(QDomElement &elem, const QgsReadWriteContext &context) const override
Writes symbol configuration to the given DOM element.
QgsPoint3DSymbol()
Constructor for QgsPoint3DSymbol with default QgsMarkerSymbol as the billboardSymbol.
QMatrix4x4 transform() const
Returns transform for individual objects represented by the symbol.
void setMaterialSettings(QgsAbstractMaterialSettings *materialSettings) override
Sets the material settings used for shading of the symbol.
QgsMarkerSymbol * billboardSymbol() const
Returns a symbol for billboard.
Qgis::Point3DShape shape() const
Returns 3D shape for points.
float billboardHeight() const
Returns how much the billboard should be elevated upwards.
QList< Qgis::GeometryType > compatibleGeometryTypes() const override
Returns the list of the vector layer geometry types which are compatible with this symbol.
bool exportGeometries(Qgs3DSceneExporter *exporter, Qt3DCore::QEntity *entity, const QString &objectNamePrefix) const override
Exports the geometries contained within the hierarchy of entity.
void setBillboardSymbol(QgsMarkerSymbol *symbol)
Set symbol for billboard and the ownership is transferred.
QgsAbstractMaterialSettings * materialSettings() const override
Returns material settings used for shading of the symbol.
QVariantMap shapeProperties() const
Returns a key-value dictionary of point shape properties.
Qgis::AltitudeClamping altitudeClamping() const
Returns method that determines altitude (whether to clamp to feature to terrain).
QgsAbstract3DSymbol * clone() const override
Returns a new instance of the symbol with the same settings.
void readXml(const QDomElement &elem, const QgsReadWriteContext &context) override
Reads symbol configuration from the given DOM element.
QVariant shapeProperty(const QString &property) const
Returns the value for a specific shape property.
static Qgis::Point3DShape shapeFromString(const QString &shape)
Returns shape enum value from a string.
A container for the context for various read/write operations on objects.
const QgsPathResolver & pathResolver() const
Returns path resolver for conversion between relative and absolute paths.
static std::unique_ptr< QgsSymbol > loadSymbol(const QDomElement &element, const QgsReadWriteContext &context)
Attempts to load a symbol from a DOM element.
static QDomElement saveSymbol(const QString &symbolName, const QgsSymbol *symbol, QDomDocument &doc, const QgsReadWriteContext &context)
Writes a symbol definition to XML.
static QgsSymbol * defaultSymbol(Qgis::GeometryType geomType)
Returns a new default symbol for the specified geometry type.
Vector layer specific subclass of QgsMapLayerElevationProperties.
double extrusionHeight() const
Returns the feature extrusion height.
Qgis::AltitudeClamping clamping() const
Returns the altitude clamping method, which dictates how feature heights are interpreted with respect...
bool extrusionEnabled() const
Returns true if extrusion is enabled.
Represents a vector layer which manages a vector based dataset.
static QDomElement writeVariant(const QVariant &value, QDomDocument &doc)
Write a QVariant to a QDomElement.
static QVariant readVariant(const QDomElement &element)
Read a QVariant from a QDomElement.