QGIS API Documentation 3.37.0-Master (fdefdf9c27f)
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 "qgs3dutils.h"
19#include "qgsreadwritecontext.h"
20#include "qgsxmlutils.h"
21#include "qgssymbollayerutils.h"
22#include "qgs3d.h"
23#include "qgsmaterialregistry.h"
24#include "qgs3dexportobject.h"
25#include "qgs3dsceneexporter.h"
26#include "qgsmarkersymbol.h"
27#include "qgsvectorlayer.h"
29
31{
32 return new QgsPoint3DSymbol( *this );
33}
34
36{
37 return new QgsPoint3DSymbol();
38}
39
41 : mMaterialSettings( std::make_unique< QgsPhongMaterialSettings >() )
42{
44}
45
47 : mAltClamping( other.altitudeClamping() )
48 , mMaterialSettings( other.materialSettings() ? other.materialSettings()->clone() : nullptr )
49 , mShape( other.shape() )
50 , mShapeProperties( other.shapeProperties() )
51 , mTransform( other.transform() )
52 , mBillboardSymbol( other.billboardSymbol() ? other.billboardSymbol()->clone() : nullptr )
53{
55}
56
58
59void QgsPoint3DSymbol::writeXml( QDomElement &elem, const QgsReadWriteContext &context ) const
60{
61 QDomDocument doc = elem.ownerDocument();
62
63 QDomElement elemDataProperties = doc.createElement( QStringLiteral( "data" ) );
64 elemDataProperties.setAttribute( QStringLiteral( "alt-clamping" ), Qgs3DUtils::altClampingToString( mAltClamping ) );
65 elem.appendChild( elemDataProperties );
66
67 elem.setAttribute( QStringLiteral( "material_type" ), mMaterialSettings->type() );
68 QDomElement elemMaterial = doc.createElement( QStringLiteral( "material" ) );
69 mMaterialSettings->writeXml( elemMaterial, context );
70 elem.appendChild( elemMaterial );
71
72 elem.setAttribute( QStringLiteral( "shape" ), shapeToString( mShape ) );
73
74 QVariantMap shapePropertiesCopy( mShapeProperties );
75 shapePropertiesCopy[QStringLiteral( "model" )] = QVariant( context.pathResolver().writePath( shapePropertiesCopy[QStringLiteral( "model" )].toString() ) );
76
77 QDomElement elemShapeProperties = doc.createElement( QStringLiteral( "shape-properties" ) );
78 elemShapeProperties.appendChild( QgsXmlUtils::writeVariant( shapePropertiesCopy, doc ) );
79 elem.appendChild( elemShapeProperties );
80
81 QDomElement elemTransform = doc.createElement( QStringLiteral( "transform" ) );
82 elemTransform.setAttribute( QStringLiteral( "matrix" ), Qgs3DUtils::matrix4x4toString( mTransform ) );
83 elem.appendChild( elemTransform );
84
85 if ( billboardSymbol() )
86 {
87 const QDomElement symbolElem = QgsSymbolLayerUtils::saveSymbol( QStringLiteral( "symbol" ), billboardSymbol(), doc, context );
88
89 elem.appendChild( symbolElem );
90 }
91}
92
93void QgsPoint3DSymbol::readXml( const QDomElement &elem, const QgsReadWriteContext &context )
94{
95 const QDomElement elemDataProperties = elem.firstChildElement( QStringLiteral( "data" ) );
96 mAltClamping = Qgs3DUtils::altClampingFromString( elemDataProperties.attribute( QStringLiteral( "alt-clamping" ) ) );
97
98 const QDomElement elemMaterial = elem.firstChildElement( QStringLiteral( "material" ) );
99 const QString materialType = elem.attribute( QStringLiteral( "material_type" ), QStringLiteral( "phong" ) );
100 mMaterialSettings.reset( Qgs3D::materialRegistry()->createMaterialSettings( materialType ) );
101 if ( !mMaterialSettings )
102 mMaterialSettings.reset( Qgs3D::materialRegistry()->createMaterialSettings( QStringLiteral( "phong" ) ) );
103 mMaterialSettings->readXml( elemMaterial, context );
104
105 mShape = shapeFromString( elem.attribute( QStringLiteral( "shape" ) ) );
106
107 const QDomElement elemShapeProperties = elem.firstChildElement( QStringLiteral( "shape-properties" ) );
108 mShapeProperties = QgsXmlUtils::readVariant( elemShapeProperties.firstChildElement() ).toMap();
109 mShapeProperties[QStringLiteral( "model" )] = QVariant( context.pathResolver().readPath( mShapeProperties[QStringLiteral( "model" )].toString() ) );
110
111 const QDomElement elemTransform = elem.firstChildElement( QStringLiteral( "transform" ) );
112 mTransform = Qgs3DUtils::stringToMatrix4x4( elemTransform.attribute( QStringLiteral( "matrix" ) ) );
113
114 const QDomElement symbolElem = elem.firstChildElement( QStringLiteral( "symbol" ) );
115
116 setBillboardSymbol( QgsSymbolLayerUtils::loadSymbol< QgsMarkerSymbol >( symbolElem, context ) );
117}
118
119QList<Qgis::GeometryType> QgsPoint3DSymbol::compatibleGeometryTypes() const
120{
121 return QList< Qgis::GeometryType >() << Qgis::GeometryType::Point;
122}
123
125{
126 const QgsVectorLayerElevationProperties *props = qgis::down_cast< const QgsVectorLayerElevationProperties * >( const_cast< QgsVectorLayer *>( layer )->elevationProperties() );
127
128 mAltClamping = props->clamping();
129 mTransform.data()[13] = static_cast< float >( props->zOffset() );
130 mShapeProperties[QStringLiteral( "length" )] = props->extrusionEnabled() ? static_cast< float>( props->extrusionHeight() ) : 0.0f;
131}
132
134{
135 if ( shape == QStringLiteral( "sphere" ) )
137 else if ( shape == QLatin1String( "cone" ) )
139 else if ( shape == QLatin1String( "cube" ) )
141 else if ( shape == QLatin1String( "torus" ) )
143 else if ( shape == QLatin1String( "plane" ) )
145 else if ( shape == QLatin1String( "extruded-text" ) )
147 else if ( shape == QLatin1String( "model" ) )
149 else if ( shape == QLatin1String( "billboard" ) )
151 else // "cylinder" (default)
153}
154
156{
157 switch ( shape )
158 {
159 case Qgis::Point3DShape::Cylinder: return QStringLiteral( "cylinder" );
160 case Qgis::Point3DShape::Sphere: return QStringLiteral( "sphere" );
161 case Qgis::Point3DShape::Cone: return QStringLiteral( "cone" );
162 case Qgis::Point3DShape::Cube: return QStringLiteral( "cube" );
163 case Qgis::Point3DShape::Torus: return QStringLiteral( "torus" );
164 case Qgis::Point3DShape::Plane: return QStringLiteral( "plane" );
165 case Qgis::Point3DShape::ExtrudedText: return QStringLiteral( "extruded-text" );
166 case Qgis::Point3DShape::Model: return QStringLiteral( "model" );
167 case Qgis::Point3DShape::Billboard: return QStringLiteral( "billboard" );
168 default: Q_ASSERT( false ); return QString();
169 }
170}
171
172QVariant QgsPoint3DSymbol::shapeProperty( const QString &property ) const
173{
174 switch ( mShape )
175 {
177 {
178 if ( property == QLatin1String( "length" ) )
179 {
180 const float length = mShapeProperties.value( property ).toFloat();
181 if ( length == 0 )
182 return 10;
183 return length;
184 }
185 else if ( property == QLatin1String( "radius" ) )
186 {
187 const float radius = mShapeProperties.value( property ).toFloat();
188 if ( radius == 0 )
189 return 10;
190 return radius;
191 }
192 break;
193 }
195 {
196 if ( property == QLatin1String( "radius" ) )
197 {
198 const float radius = mShapeProperties.value( property ).toFloat();
199 if ( radius == 0 )
200 return 10;
201 return radius;
202 }
203 break;
204 }
206 {
207 if ( property == QLatin1String( "length" ) )
208 {
209 const float length = mShapeProperties.value( property ).toFloat();
210 if ( length == 0 )
211 return 10;
212 return length;
213 }
214 break;
215 }
217 {
218 if ( property == QLatin1String( "size" ) )
219 {
220 const float size = mShapeProperties.value( property ).toFloat();
221 if ( size == 0 )
222 return 10;
223 return size;
224 }
225 break;
226 }
228 {
229 if ( property == QLatin1String( "radius" ) )
230 {
231 const float radius = mShapeProperties.value( property ).toFloat();
232 if ( radius == 0 )
233 return 10;
234 return radius;
235 }
236 else if ( property == QLatin1String( "minorRadius" ) )
237 {
238 const float minorRadius = mShapeProperties.value( property ).toFloat();
239 if ( minorRadius == 0 )
240 return 5;
241 return minorRadius;
242 }
243 break;
244 }
246 {
247 if ( property == QLatin1String( "size" ) )
248 {
249 const float size = mShapeProperties.value( property ).toFloat();
250 if ( size == 0 )
251 return 10;
252 return size;
253 }
254 break;
255 }
257 {
258 if ( property == QLatin1String( "depth" ) )
259 {
260 const float depth = mShapeProperties.value( property ).toFloat();
261 if ( depth == 0 )
262 return 1;
263 return depth;
264 }
265 break;
266 }
267
270 break;
271 }
272 return mShapeProperties.value( property );
273}
274
276{
277 QMatrix4x4 billboardTransformMatrix;
278 billboardTransformMatrix.translate( QVector3D( 0, mTransform.data()[13], 0 ) );
279
280 return billboardTransformMatrix;
281}
282
284{
285 return mMaterialSettings.get();
286}
287
289{
290 if ( materialSettings == mMaterialSettings.get() )
291 return;
292
293 mMaterialSettings.reset( materialSettings );
294}
295
296bool QgsPoint3DSymbol::exportGeometries( Qgs3DSceneExporter *exporter, Qt3DCore::QEntity *entity, const QString &objectNamePrefix ) const
297{
299 {
300 Qt3DRender::QSceneLoader *sceneLoader = entity->findChild<Qt3DRender::QSceneLoader *>();
301 if ( sceneLoader != nullptr )
302 {
303 const QVector<Qgs3DExportObject *> objects = exporter->processSceneLoaderGeometries( sceneLoader, objectNamePrefix );
304 for ( Qgs3DExportObject *obj : objects )
305 {
306 obj->setSmoothEdges( exporter->smoothEdges() );
307 obj->setupMaterial( materialSettings() );
308 }
309 exporter->mObjects << objects;
310 }
311 else
312 {
313 const QList<Qt3DRender::QMesh *> meshes = entity->findChildren<Qt3DRender::QMesh *>();
314 for ( Qt3DRender::QMesh *mesh : meshes )
315 {
316 Qgs3DExportObject *object = exporter->processGeometryRenderer( mesh, objectNamePrefix );
317 if ( object == nullptr ) continue;
318 object->setSmoothEdges( exporter->smoothEdges() );
319 object->setupMaterial( materialSettings() );
320 exporter->mObjects << object;
321 }
322 }
323 return true;
324 }
325 else if ( shape() == Qgis::Point3DShape::Billboard )
326 {
327 Qgs3DExportObject *obj = exporter->processPoints( entity, objectNamePrefix );
328 if ( obj != nullptr )
329 {
330 exporter->mObjects << obj;
331 return true;
332 }
333 }
334 else
335 {
336 const QVector<Qgs3DExportObject *> objects = exporter->processInstancedPointGeometry( entity, objectNamePrefix );
337 for ( Qgs3DExportObject *obj : objects )
338 {
339 obj->setupMaterial( materialSettings() );
340 exporter->mObjects << obj;
341 }
342 return true;
343 }
344 return false;
345}
346
348{
349 return mBillboardSymbol.get();
350}
351
353{
354 mBillboardSymbol.reset( symbol );
355}
Point3DShape
3D point shape types.
Definition: qgis.h:3379
@ Plane
Flat plane.
@ Cylinder
Cylinder.
@ ExtrudedText
Extruded text.
@ Billboard
Billboard.
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 scene.
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.
Definition: qgs3dutils.cpp:294
static QString matrix4x4toString(const QMatrix4x4 &m)
Converts a 4x4 transform matrix to a string.
Definition: qgs3dutils.cpp:476
static QString altClampingToString(Qgis::AltitudeClamping altClamp)
Converts a value from AltitudeClamping enum to a string.
Definition: qgs3dutils.cpp:279
static QMatrix4x4 stringToMatrix4x4(const QString &str)
Convert a string to a 4x4 transform matrix.
Definition: qgs3dutils.cpp:486
static QgsMaterialRegistry * materialRegistry()
Returns the material registry, used for managing 3D materials.
Definition: qgs3d.cpp:95
void setDataDefinedProperties(const QgsPropertyCollection &collection)
Sets the symbol layer's property collection, used for data defined overrides.
QgsPropertyCollection & dataDefinedProperties()
Returns a reference to the symbol layer's property collection, used for data defined overrides.
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.
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.
QMatrix4x4 billboardTransform() const
Returns transform for billboards.
QgsAbstractMaterialSettings * materialSettings() const
Returns material settings used for shading of the symbol.
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.
QgsMarkerSymbol * billboardSymbol() const
Returns a symbol for billboard.
Qgis::Point3DShape shape() const
Returns 3D shape for points.
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.
QgsAbstract3DSymbol * clone() const override
Returns a new instance of the symbol with the same settings.
void setMaterialSettings(QgsAbstractMaterialSettings *materialSettings)
Sets the material settings used for shading of the symbol.
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.
The class is used as a container of context for various read/write operations on other objects.
const QgsPathResolver & pathResolver() const
Returns path resolver for conversion between relative and absolute paths.
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.
Definition: qgssymbol.cpp:705
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 data sets.
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.