QGIS API Documentation 4.1.0-Master (ca2ac17535b)
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"
24#include "qgsreadwritecontext.h"
25#include "qgssymbollayerutils.h"
26#include "qgsvectorlayer.h"
28#include "qgsxmlutils.h"
29
30#include <QString>
31
32using namespace Qt::StringLiterals;
33
35{
36 return new QgsPoint3DSymbol( *this );
37}
38
43
49
51 : mAltClamping( other.altitudeClamping() )
52 , mMaterialSettings( other.materialSettings() ? other.materialSettings()->clone() : nullptr )
53 , mShape( other.shape() )
54 , mShapeProperties( other.shapeProperties() )
55 , mTransform( other.transform() )
56 , mBillboardSymbol( other.billboardSymbol() ? other.billboardSymbol()->clone() : nullptr )
57{
59}
60
62
63void QgsPoint3DSymbol::writeXml( QDomElement &elem, const QgsReadWriteContext &context ) const
64{
65 QDomDocument doc = elem.ownerDocument();
66
67 QDomElement elemDataProperties = doc.createElement( u"data"_s );
68 elemDataProperties.setAttribute( u"alt-clamping"_s, Qgs3DUtils::altClampingToString( mAltClamping ) );
69 elem.appendChild( elemDataProperties );
70
71 elem.setAttribute( u"material_type"_s, mMaterialSettings->type() );
72 QDomElement elemMaterial = doc.createElement( u"material"_s );
73 mMaterialSettings->writeXml( elemMaterial, context );
74 elem.appendChild( elemMaterial );
75
76 elem.setAttribute( u"shape"_s, shapeToString( mShape ) );
77
78 QVariantMap shapePropertiesCopy( mShapeProperties );
79 shapePropertiesCopy[u"model"_s] = QVariant( context.pathResolver().writePath( shapePropertiesCopy[u"model"_s].toString() ) );
80
81 QDomElement elemShapeProperties = doc.createElement( u"shape-properties"_s );
82 elemShapeProperties.appendChild( QgsXmlUtils::writeVariant( shapePropertiesCopy, doc ) );
83 elem.appendChild( elemShapeProperties );
84
85 QDomElement elemTransform = doc.createElement( u"transform"_s );
86 elemTransform.setAttribute( u"matrix"_s, Qgs3DUtils::matrix4x4toString( mTransform ) );
87 elem.appendChild( elemTransform );
88
89 QDomElement elemDDP = doc.createElement( u"data-defined-properties"_s );
90 mDataDefinedProperties.writeXml( elemDDP, propertyDefinitions() );
91 elem.appendChild( elemDDP );
92
93 if ( billboardSymbol() )
94 {
95 const QDomElement symbolElem = QgsSymbolLayerUtils::saveSymbol( u"symbol"_s, billboardSymbol(), doc, context );
96
97 elem.appendChild( symbolElem );
98 }
99}
100
101void QgsPoint3DSymbol::readXml( const QDomElement &elem, const QgsReadWriteContext &context )
102{
103 const QDomElement elemDataProperties = elem.firstChildElement( u"data"_s );
104 mAltClamping = Qgs3DUtils::altClampingFromString( elemDataProperties.attribute( u"alt-clamping"_s ) );
105
106 const QDomElement elemMaterial = elem.firstChildElement( u"material"_s );
107 const QString materialType = elem.attribute( u"material_type"_s, u"phong"_s );
108 mMaterialSettings = Qgs3D::materialRegistry()->createMaterialSettings( materialType );
109 if ( !mMaterialSettings )
110 mMaterialSettings = Qgs3D::materialRegistry()->createMaterialSettings( u"phong"_s );
111 mMaterialSettings->readXml( elemMaterial, context );
112
113 mShape = shapeFromString( elem.attribute( u"shape"_s ) );
114
115 const QDomElement elemShapeProperties = elem.firstChildElement( u"shape-properties"_s );
116 mShapeProperties = QgsXmlUtils::readVariant( elemShapeProperties.firstChildElement() ).toMap();
117 mShapeProperties[u"model"_s] = QVariant( context.pathResolver().readPath( mShapeProperties[u"model"_s].toString() ) );
118
119 const QDomElement elemTransform = elem.firstChildElement( u"transform"_s );
120 mTransform = Qgs3DUtils::stringToMatrix4x4( elemTransform.attribute( u"matrix"_s ) );
121
122 const QDomElement elemDDP = elem.firstChildElement( u"data-defined-properties"_s );
123 if ( !elemDDP.isNull() )
124 mDataDefinedProperties.readXml( elemDDP, propertyDefinitions() );
125
126 const QDomElement symbolElem = elem.firstChildElement( u"symbol"_s );
127
129}
130
131QList<Qgis::GeometryType> QgsPoint3DSymbol::compatibleGeometryTypes() const
132{
133 return QList<Qgis::GeometryType>() << Qgis::GeometryType::Point;
134}
135
137{
138 const QgsVectorLayerElevationProperties *props = qgis::down_cast<const QgsVectorLayerElevationProperties *>( const_cast<QgsVectorLayer *>( layer )->elevationProperties() );
139
140 mAltClamping = props->clamping();
141 mTransform.data()[13] = static_cast<float>( props->zOffset() );
142 mShapeProperties[u"length"_s] = props->extrusionEnabled() ? static_cast<float>( props->extrusionHeight() ) : 0.0f;
143}
144
146{
147 if ( shape == "sphere"_L1 )
149 else if ( shape == "cone"_L1 )
151 else if ( shape == "cube"_L1 )
153 else if ( shape == "torus"_L1 )
155 else if ( shape == "plane"_L1 )
157 else if ( shape == "extruded-text"_L1 )
159 else if ( shape == "model"_L1 )
161 else if ( shape == "billboard"_L1 )
163 else // "cylinder" (default)
165}
166
168{
169 switch ( shape )
170 {
172 return u"cylinder"_s;
174 return u"sphere"_s;
176 return u"cone"_s;
178 return u"cube"_s;
180 return u"torus"_s;
182 return u"plane"_s;
184 return u"extruded-text"_s;
186 return u"model"_s;
188 return u"billboard"_s;
189 default:
190 Q_ASSERT( false );
191 return QString();
192 }
193}
194
195QVariant QgsPoint3DSymbol::shapeProperty( const QString &property ) const
196{
197 switch ( mShape )
198 {
200 {
201 if ( property == "length"_L1 )
202 {
203 const float length = mShapeProperties.value( property ).toFloat();
204 if ( length == 0 )
205 return 10;
206 return length;
207 }
208 else if ( property == "radius"_L1 )
209 {
210 const float radius = mShapeProperties.value( property ).toFloat();
211 if ( radius == 0 )
212 return 10;
213 return radius;
214 }
215 break;
216 }
218 {
219 if ( property == "radius"_L1 )
220 {
221 const float radius = mShapeProperties.value( property ).toFloat();
222 if ( radius == 0 )
223 return 10;
224 return radius;
225 }
226 else if ( property == "rings"_L1 )
227 {
228 constexpr int DEFAULT_RINGS = 16;
229 const int rings = mShapeProperties.value( property, DEFAULT_RINGS ).toInt();
230 if ( rings == 0 )
231 return DEFAULT_RINGS;
232 return rings;
233 }
234 else if ( property == "slices"_L1 )
235 {
236 constexpr int DEFAULT_SLICES = 16;
237 const int slices = mShapeProperties.value( property, DEFAULT_SLICES ).toInt();
238 if ( slices == 0 )
239 return DEFAULT_SLICES;
240 return slices;
241 }
242 break;
243 }
245 {
246 if ( property == "length"_L1 )
247 {
248 const float length = mShapeProperties.value( property ).toFloat();
249 if ( length == 0 )
250 return 10;
251 return length;
252 }
253 break;
254 }
256 {
257 if ( property == "size"_L1 )
258 {
259 const float size = mShapeProperties.value( property ).toFloat();
260 if ( size == 0 )
261 return 10;
262 return size;
263 }
264 break;
265 }
267 {
268 if ( property == "radius"_L1 )
269 {
270 const float radius = mShapeProperties.value( property ).toFloat();
271 if ( radius == 0 )
272 return 10;
273 return radius;
274 }
275 else if ( property == "minorRadius"_L1 )
276 {
277 const float minorRadius = mShapeProperties.value( property ).toFloat();
278 if ( minorRadius == 0 )
279 return 5;
280 return minorRadius;
281 }
282 break;
283 }
285 {
286 if ( property == "size"_L1 )
287 {
288 const float size = mShapeProperties.value( property ).toFloat();
289 if ( size == 0 )
290 return 10;
291 return size;
292 }
293 break;
294 }
296 {
297 if ( property == "depth"_L1 )
298 {
299 const float depth = mShapeProperties.value( property ).toFloat();
300 if ( depth == 0 )
301 return 1;
302 return depth;
303 }
304 break;
305 }
306
308 {
309 // defaults are "z" up, "y" forward -- this ensures default rendering matches 3.x appearance
310 if ( property == "upAxis"_L1 )
311 {
312 return mShapeProperties.value( u"upAxis"_s, u"z"_s ).toString();
313 }
314 if ( property == "forwardAxis"_L1 )
315 {
316 return mShapeProperties.value( u"forwardAxis"_s, u"y"_s ).toString();
317 }
318 break;
319 }
320
322 break;
323 }
324 return mShapeProperties.value( property );
325}
326
328{
329 return mTransform.data()[14];
330}
331
333{
334 return mMaterialSettings.get();
335}
336
338{
339 if ( materialSettings == mMaterialSettings.get() )
340 return;
341
342 mMaterialSettings.reset( materialSettings );
343}
344
345bool QgsPoint3DSymbol::exportGeometries( Qgs3DSceneExporter *exporter, Qt3DCore::QEntity *entity, const QString &objectNamePrefix ) const
346{
348 {
349 Qt3DRender::QSceneLoader *sceneLoader = entity->findChild<Qt3DRender::QSceneLoader *>();
350 if ( sceneLoader )
351 {
352 const QVector<Qgs3DExportObject *> objects = exporter->processSceneLoaderGeometries( sceneLoader, objectNamePrefix );
353 for ( Qgs3DExportObject *obj : objects )
354 {
355 obj->setSmoothEdges( exporter->smoothEdges() );
356 obj->setupMaterial( materialSettings() );
357 }
358 exporter->mObjects << objects;
359 }
360 else
361 {
362 const QList<Qt3DRender::QMesh *> meshes = entity->findChildren<Qt3DRender::QMesh *>();
363 for ( Qt3DRender::QMesh *mesh : meshes )
364 {
365 Qgs3DExportObject *object = exporter->processGeometryRenderer( mesh, objectNamePrefix );
366 if ( !object )
367 continue;
368 object->setSmoothEdges( exporter->smoothEdges() );
369 object->setupMaterial( materialSettings() );
370 exporter->mObjects << object;
371 }
372 }
373 return true;
374 }
375 else if ( shape() == Qgis::Point3DShape::Billboard )
376 {
377 Qgs3DExportObject *obj = exporter->processPoints( entity, objectNamePrefix );
378 if ( obj )
379 {
380 exporter->mObjects << obj;
381 return true;
382 }
383 }
384 else
385 {
386 const QVector<Qgs3DExportObject *> objects = exporter->processInstancedPointGeometry( entity, objectNamePrefix );
387 for ( Qgs3DExportObject *obj : objects )
388 {
389 obj->setupMaterial( materialSettings() );
390 exporter->mObjects << obj;
391 }
392 return true;
393 }
394 return false;
395}
396
398{
399 return mBillboardSymbol.get();
400}
401
403{
404 mBillboardSymbol.reset( symbol );
405}
Point3DShape
3D point shape types.
Definition qgis.h:4320
@ Plane
Flat plane.
Definition qgis.h:4326
@ Cylinder
Cylinder.
Definition qgis.h:4321
@ Torus
Torus.
Definition qgis.h:4325
@ ExtrudedText
Extruded text.
Definition qgis.h:4327
@ Model
Model.
Definition qgis.h:4328
@ Sphere
Sphere.
Definition qgis.h:4322
@ Billboard
Billboard.
Definition qgis.h:4329
@ 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.
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.
Basic shading material used for rendering based on the Phong shading model with three color component...
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.