QGIS API Documentation 3.41.0-Master (3440c17df1d)
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 "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
39
41 : mMaterialSettings( std::make_unique< QgsPhongMaterialSettings >() )
42{
44
45 // our built-in 3D geometries (e.g. cylinder, plane, ...) assume Y axis going "up",
46 // let's rotate them by default so that their Z axis goes "up" (like the rest of the scene)
47 mTransform.rotate( QQuaternion::fromAxisAndAngle( QVector3D( 1, 0, 0 ), 90 ) );
48}
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( QStringLiteral( "data" ) );
68 elemDataProperties.setAttribute( QStringLiteral( "alt-clamping" ), Qgs3DUtils::altClampingToString( mAltClamping ) );
69 elem.appendChild( elemDataProperties );
70
71 elem.setAttribute( QStringLiteral( "material_type" ), mMaterialSettings->type() );
72 QDomElement elemMaterial = doc.createElement( QStringLiteral( "material" ) );
73 mMaterialSettings->writeXml( elemMaterial, context );
74 elem.appendChild( elemMaterial );
75
76 elem.setAttribute( QStringLiteral( "shape" ), shapeToString( mShape ) );
77
78 QVariantMap shapePropertiesCopy( mShapeProperties );
79 shapePropertiesCopy[QStringLiteral( "model" )] = QVariant( context.pathResolver().writePath( shapePropertiesCopy[QStringLiteral( "model" )].toString() ) );
80
81 QDomElement elemShapeProperties = doc.createElement( QStringLiteral( "shape-properties" ) );
82 elemShapeProperties.appendChild( QgsXmlUtils::writeVariant( shapePropertiesCopy, doc ) );
83 elem.appendChild( elemShapeProperties );
84
85 QDomElement elemTransform = doc.createElement( QStringLiteral( "transform" ) );
86 elemTransform.setAttribute( QStringLiteral( "matrix" ), Qgs3DUtils::matrix4x4toString( mTransform ) );
87 elem.appendChild( elemTransform );
88
89 if ( billboardSymbol() )
90 {
91 const QDomElement symbolElem = QgsSymbolLayerUtils::saveSymbol( QStringLiteral( "symbol" ), billboardSymbol(), doc, context );
92
93 elem.appendChild( symbolElem );
94 }
95}
96
97void QgsPoint3DSymbol::readXml( const QDomElement &elem, const QgsReadWriteContext &context )
98{
99 const QDomElement elemDataProperties = elem.firstChildElement( QStringLiteral( "data" ) );
100 mAltClamping = Qgs3DUtils::altClampingFromString( elemDataProperties.attribute( QStringLiteral( "alt-clamping" ) ) );
101
102 const QDomElement elemMaterial = elem.firstChildElement( QStringLiteral( "material" ) );
103 const QString materialType = elem.attribute( QStringLiteral( "material_type" ), QStringLiteral( "phong" ) );
104 mMaterialSettings.reset( Qgs3D::materialRegistry()->createMaterialSettings( materialType ) );
105 if ( !mMaterialSettings )
106 mMaterialSettings.reset( Qgs3D::materialRegistry()->createMaterialSettings( QStringLiteral( "phong" ) ) );
107 mMaterialSettings->readXml( elemMaterial, context );
108
109 mShape = shapeFromString( elem.attribute( QStringLiteral( "shape" ) ) );
110
111 const QDomElement elemShapeProperties = elem.firstChildElement( QStringLiteral( "shape-properties" ) );
112 mShapeProperties = QgsXmlUtils::readVariant( elemShapeProperties.firstChildElement() ).toMap();
113 mShapeProperties[QStringLiteral( "model" )] = QVariant( context.pathResolver().readPath( mShapeProperties[QStringLiteral( "model" )].toString() ) );
114
115 const QDomElement elemTransform = elem.firstChildElement( QStringLiteral( "transform" ) );
116 mTransform = Qgs3DUtils::stringToMatrix4x4( elemTransform.attribute( QStringLiteral( "matrix" ) ) );
117
118 const QDomElement symbolElem = elem.firstChildElement( QStringLiteral( "symbol" ) );
119
120 setBillboardSymbol( QgsSymbolLayerUtils::loadSymbol< QgsMarkerSymbol >( symbolElem, context ) );
121}
122
123QList<Qgis::GeometryType> QgsPoint3DSymbol::compatibleGeometryTypes() const
124{
125 return QList< Qgis::GeometryType >() << Qgis::GeometryType::Point;
126}
127
129{
130 const QgsVectorLayerElevationProperties *props = qgis::down_cast< const QgsVectorLayerElevationProperties * >( const_cast< QgsVectorLayer *>( layer )->elevationProperties() );
131
132 mAltClamping = props->clamping();
133 mTransform.data()[13] = static_cast< float >( props->zOffset() );
134 mShapeProperties[QStringLiteral( "length" )] = props->extrusionEnabled() ? static_cast< float>( props->extrusionHeight() ) : 0.0f;
135}
136
138{
139 if ( shape == QStringLiteral( "sphere" ) )
141 else if ( shape == QLatin1String( "cone" ) )
143 else if ( shape == QLatin1String( "cube" ) )
145 else if ( shape == QLatin1String( "torus" ) )
147 else if ( shape == QLatin1String( "plane" ) )
149 else if ( shape == QLatin1String( "extruded-text" ) )
151 else if ( shape == QLatin1String( "model" ) )
153 else if ( shape == QLatin1String( "billboard" ) )
155 else // "cylinder" (default)
157}
158
160{
161 switch ( shape )
162 {
163 case Qgis::Point3DShape::Cylinder: return QStringLiteral( "cylinder" );
164 case Qgis::Point3DShape::Sphere: return QStringLiteral( "sphere" );
165 case Qgis::Point3DShape::Cone: return QStringLiteral( "cone" );
166 case Qgis::Point3DShape::Cube: return QStringLiteral( "cube" );
167 case Qgis::Point3DShape::Torus: return QStringLiteral( "torus" );
168 case Qgis::Point3DShape::Plane: return QStringLiteral( "plane" );
169 case Qgis::Point3DShape::ExtrudedText: return QStringLiteral( "extruded-text" );
170 case Qgis::Point3DShape::Model: return QStringLiteral( "model" );
171 case Qgis::Point3DShape::Billboard: return QStringLiteral( "billboard" );
172 default: Q_ASSERT( false ); return QString();
173 }
174}
175
176QVariant QgsPoint3DSymbol::shapeProperty( const QString &property ) const
177{
178 switch ( mShape )
179 {
181 {
182 if ( property == QLatin1String( "length" ) )
183 {
184 const float length = mShapeProperties.value( property ).toFloat();
185 if ( length == 0 )
186 return 10;
187 return length;
188 }
189 else if ( property == QLatin1String( "radius" ) )
190 {
191 const float radius = mShapeProperties.value( property ).toFloat();
192 if ( radius == 0 )
193 return 10;
194 return radius;
195 }
196 break;
197 }
199 {
200 if ( property == QLatin1String( "radius" ) )
201 {
202 const float radius = mShapeProperties.value( property ).toFloat();
203 if ( radius == 0 )
204 return 10;
205 return radius;
206 }
207 break;
208 }
210 {
211 if ( property == QLatin1String( "length" ) )
212 {
213 const float length = mShapeProperties.value( property ).toFloat();
214 if ( length == 0 )
215 return 10;
216 return length;
217 }
218 break;
219 }
221 {
222 if ( property == QLatin1String( "size" ) )
223 {
224 const float size = mShapeProperties.value( property ).toFloat();
225 if ( size == 0 )
226 return 10;
227 return size;
228 }
229 break;
230 }
232 {
233 if ( property == QLatin1String( "radius" ) )
234 {
235 const float radius = mShapeProperties.value( property ).toFloat();
236 if ( radius == 0 )
237 return 10;
238 return radius;
239 }
240 else if ( property == QLatin1String( "minorRadius" ) )
241 {
242 const float minorRadius = mShapeProperties.value( property ).toFloat();
243 if ( minorRadius == 0 )
244 return 5;
245 return minorRadius;
246 }
247 break;
248 }
250 {
251 if ( property == QLatin1String( "size" ) )
252 {
253 const float size = mShapeProperties.value( property ).toFloat();
254 if ( size == 0 )
255 return 10;
256 return size;
257 }
258 break;
259 }
261 {
262 if ( property == QLatin1String( "depth" ) )
263 {
264 const float depth = mShapeProperties.value( property ).toFloat();
265 if ( depth == 0 )
266 return 1;
267 return depth;
268 }
269 break;
270 }
271
274 break;
275 }
276 return mShapeProperties.value( property );
277}
278
280{
281 return mTransform.data()[14];
282}
283
285{
286 return mMaterialSettings.get();
287}
288
290{
291 if ( materialSettings == mMaterialSettings.get() )
292 return;
293
294 mMaterialSettings.reset( materialSettings );
295}
296
297bool QgsPoint3DSymbol::exportGeometries( Qgs3DSceneExporter *exporter, Qt3DCore::QEntity *entity, const QString &objectNamePrefix ) const
298{
300 {
301 Qt3DRender::QSceneLoader *sceneLoader = entity->findChild<Qt3DRender::QSceneLoader *>();
302 if ( sceneLoader )
303 {
304 const QVector<Qgs3DExportObject *> objects = exporter->processSceneLoaderGeometries( sceneLoader, objectNamePrefix );
305 for ( Qgs3DExportObject *obj : objects )
306 {
307 obj->setSmoothEdges( exporter->smoothEdges() );
308 obj->setupMaterial( materialSettings() );
309 }
310 exporter->mObjects << objects;
311 }
312 else
313 {
314 const QList<Qt3DRender::QMesh *> meshes = entity->findChildren<Qt3DRender::QMesh *>();
315 for ( Qt3DRender::QMesh *mesh : meshes )
316 {
317 Qgs3DExportObject *object = exporter->processGeometryRenderer( mesh, objectNamePrefix );
318 if ( !object )
319 continue;
320 object->setSmoothEdges( exporter->smoothEdges() );
321 object->setupMaterial( materialSettings() );
322 exporter->mObjects << object;
323 }
324 }
325 return true;
326 }
327 else if ( shape() == Qgis::Point3DShape::Billboard )
328 {
329 Qgs3DExportObject *obj = exporter->processPoints( entity, objectNamePrefix );
330 if ( obj )
331 {
332 exporter->mObjects << obj;
333 return true;
334 }
335 }
336 else
337 {
338 const QVector<Qgs3DExportObject *> objects = exporter->processInstancedPointGeometry( entity, objectNamePrefix );
339 for ( Qgs3DExportObject *obj : objects )
340 {
341 obj->setupMaterial( materialSettings() );
342 exporter->mObjects << obj;
343 }
344 return true;
345 }
346 return false;
347}
348
350{
351 return mBillboardSymbol.get();
352}
353
355{
356 mBillboardSymbol.reset( symbol );
357}
Point3DShape
3D point shape types.
Definition qgis.h:3841
@ 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.
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: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.
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.
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.
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.
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.