QGIS API Documentation 3.37.0-Master (fdefdf9c27f)
qgsvectorlayerelevationproperties.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsvectorlayerelevationproperties.cpp
3 ---------------
4 begin : February 2022
5 copyright : (C) 2022 by Nyall Dawson
6 email : nyall dot dawson dot com
7 ***************************************************************************/
8
9/***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17
19#include "qgslinesymbol.h"
20#include "qgsfillsymbol.h"
21#include "qgsmarkersymbol.h"
22#include "qgssymbollayerutils.h"
23#include "qgslinesymbollayer.h"
24#include "qgsfillsymbollayer.h"
26#include "qgsapplication.h"
28#include "qgsvectorlayer.h"
29
32{
34 setDefaultProfileLineSymbol( color );
35 setDefaultProfileFillSymbol( color );
36 setDefaultProfileMarkerSymbol( color );
37}
38
40
42{
43 // layer is always considered as having elevation -- even if no z values are present or any
44 // offset/extrusion etc is set, then we are still considering the features as sitting on the terrain
45 // height
46 return true;
47}
48
49QDomElement QgsVectorLayerElevationProperties::writeXml( QDomElement &parentElement, QDomDocument &document, const QgsReadWriteContext &context )
50{
51 QDomElement element = document.createElement( QStringLiteral( "elevation" ) );
52 writeCommonProperties( element, document, context );
53
54 element.setAttribute( QStringLiteral( "extrusionEnabled" ), mEnableExtrusion ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
55 element.setAttribute( QStringLiteral( "extrusion" ), qgsDoubleToString( mExtrusionHeight ) );
56 element.setAttribute( QStringLiteral( "clamping" ), qgsEnumValueToKey( mClamping ) );
57 element.setAttribute( QStringLiteral( "binding" ), qgsEnumValueToKey( mBinding ) );
58 element.setAttribute( QStringLiteral( "type" ), qgsEnumValueToKey( mType ) );
59 element.setAttribute( QStringLiteral( "symbology" ), qgsEnumValueToKey( mSymbology ) );
60 if ( !std::isnan( mElevationLimit ) )
61 element.setAttribute( QStringLiteral( "elevationLimit" ), qgsDoubleToString( mElevationLimit ) );
62
63 element.setAttribute( QStringLiteral( "respectLayerSymbol" ), mRespectLayerSymbology ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
64 element.setAttribute( QStringLiteral( "showMarkerSymbolInSurfacePlots" ), mShowMarkerSymbolInSurfacePlots ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
65
66 QDomElement profileLineSymbolElement = document.createElement( QStringLiteral( "profileLineSymbol" ) );
67 profileLineSymbolElement.appendChild( QgsSymbolLayerUtils::saveSymbol( QString(), mProfileLineSymbol.get(), document, context ) );
68 element.appendChild( profileLineSymbolElement );
69
70 QDomElement profileFillSymbolElement = document.createElement( QStringLiteral( "profileFillSymbol" ) );
71 profileFillSymbolElement.appendChild( QgsSymbolLayerUtils::saveSymbol( QString(), mProfileFillSymbol.get(), document, context ) );
72 element.appendChild( profileFillSymbolElement );
73
74 QDomElement profileMarkerSymbolElement = document.createElement( QStringLiteral( "profileMarkerSymbol" ) );
75 profileMarkerSymbolElement.appendChild( QgsSymbolLayerUtils::saveSymbol( QString(), mProfileMarkerSymbol.get(), document, context ) );
76 element.appendChild( profileMarkerSymbolElement );
77
78 parentElement.appendChild( element );
79 return element;
80}
81
82bool QgsVectorLayerElevationProperties::readXml( const QDomElement &element, const QgsReadWriteContext &context )
83{
84 const QDomElement elevationElement = element.firstChildElement( QStringLiteral( "elevation" ) ).toElement();
85 if ( elevationElement.isNull() )
86 return false;
87
88 readCommonProperties( elevationElement, context );
89
90 mClamping = qgsEnumKeyToValue( elevationElement.attribute( QStringLiteral( "clamping" ) ), Qgis::AltitudeClamping::Terrain );
91 mBinding = qgsEnumKeyToValue( elevationElement.attribute( QStringLiteral( "binding" ) ), Qgis::AltitudeBinding::Centroid );
92 mType = qgsEnumKeyToValue( elevationElement.attribute( QStringLiteral( "type" ) ), Qgis::VectorProfileType::IndividualFeatures );
93 mEnableExtrusion = elevationElement.attribute( QStringLiteral( "extrusionEnabled" ), QStringLiteral( "0" ) ).toInt();
94 mExtrusionHeight = elevationElement.attribute( QStringLiteral( "extrusion" ), QStringLiteral( "0" ) ).toDouble();
95 mSymbology = qgsEnumKeyToValue( elevationElement.attribute( QStringLiteral( "symbology" ) ), Qgis::ProfileSurfaceSymbology::Line );
96 if ( elevationElement.hasAttribute( QStringLiteral( "elevationLimit" ) ) )
97 mElevationLimit = elevationElement.attribute( QStringLiteral( "elevationLimit" ) ).toDouble();
98 else
99 mElevationLimit = std::numeric_limits< double >::quiet_NaN();
100
101 mShowMarkerSymbolInSurfacePlots = elevationElement.attribute( QStringLiteral( "showMarkerSymbolInSurfacePlots" ), QStringLiteral( "0" ) ).toInt();
102
103 mRespectLayerSymbology = elevationElement.attribute( QStringLiteral( "respectLayerSymbol" ), QStringLiteral( "1" ) ).toInt();
104
106
107 const QDomElement profileLineSymbolElement = elevationElement.firstChildElement( QStringLiteral( "profileLineSymbol" ) ).firstChildElement( QStringLiteral( "symbol" ) );
108 mProfileLineSymbol.reset( QgsSymbolLayerUtils::loadSymbol< QgsLineSymbol >( profileLineSymbolElement, context ) );
109 if ( !mProfileLineSymbol )
110 setDefaultProfileLineSymbol( color );
111
112 const QDomElement profileFillSymbolElement = elevationElement.firstChildElement( QStringLiteral( "profileFillSymbol" ) ).firstChildElement( QStringLiteral( "symbol" ) );
113 mProfileFillSymbol.reset( QgsSymbolLayerUtils::loadSymbol< QgsFillSymbol >( profileFillSymbolElement, context ) );
114 if ( !mProfileFillSymbol )
115 setDefaultProfileFillSymbol( color );
116
117 const QDomElement profileMarkerSymbolElement = elevationElement.firstChildElement( QStringLiteral( "profileMarkerSymbol" ) ).firstChildElement( QStringLiteral( "symbol" ) );
118 mProfileMarkerSymbol.reset( QgsSymbolLayerUtils::loadSymbol< QgsMarkerSymbol >( profileMarkerSymbolElement, context ) );
119 if ( !mProfileMarkerSymbol )
120 setDefaultProfileMarkerSymbol( color );
121
122 return true;
123}
124
126{
127 QgsVectorLayer *vlayer = qobject_cast< QgsVectorLayer * >( layer );
128 if ( !vlayer )
129 return;
130
131 mZOffset = 0;
132 mZScale = 1;
133
134 mEnableExtrusion = false;
135 mExtrusionHeight = 0;
136
138
140
141 if ( QgsWkbTypes::hasZ( vlayer->wkbType() ) )
142 {
144 }
145 else
146 {
148 }
149}
150
152{
153 std::unique_ptr< QgsVectorLayerElevationProperties > res = std::make_unique< QgsVectorLayerElevationProperties >( nullptr );
154 res->setClamping( mClamping );
155 res->setBinding( mBinding );
156 res->setType( mType );
157 res->setExtrusionEnabled( mEnableExtrusion );
158 res->setExtrusionHeight( mExtrusionHeight );
159 res->setProfileLineSymbol( mProfileLineSymbol->clone() );
160 res->setProfileFillSymbol( mProfileFillSymbol->clone() );
161 res->setProfileMarkerSymbol( mProfileMarkerSymbol->clone() );
162 res->setRespectLayerSymbology( mRespectLayerSymbology );
163 res->setProfileSymbology( mSymbology );
164 res->setElevationLimit( mElevationLimit );
165 res->setShowMarkerSymbolInSurfacePlots( mShowMarkerSymbolInSurfacePlots );
166 res->copyCommonProperties( this );
167 return res.release();
168}
169
171{
172 QStringList properties;
173
174 switch ( mClamping )
175 {
177 properties << tr( "Clamped to Terrain" );
178 break;
180 properties << tr( "Relative to Terrain" );
181 break;
183 properties << tr( "Absolute" );
184 break;
185 }
186
188 {
190 {
193 break;
195 properties << tr( "Offset: %1" ).arg( mDataDefinedProperties.property( Property::ZOffset ).field() );
196 break;
198 properties << tr( "Offset: %1" ).arg( mDataDefinedProperties.property( Property::ZOffset ).expressionString() );
199 break;
200 }
201 }
202 else
203 {
204 properties << tr( "Offset: %1" ).arg( mZOffset );
205 }
206
207 if ( mEnableExtrusion )
208 {
210 {
212 {
215 break;
217 properties << tr( "Extrusion: %1" ).arg( mDataDefinedProperties.property( Property::ExtrusionHeight ).field() );
218 break;
220 properties << tr( "Extrusion: %1" ).arg( mDataDefinedProperties.property( Property::ExtrusionHeight ).expressionString() );
221 break;
222 }
223 }
224 else
225 {
226 properties << tr( "Extrusion: %1" ).arg( mExtrusionHeight );
227 }
228 }
229
230 properties << tr( "Scale: %1" ).arg( mZScale );
231
232 return QStringLiteral( "<li>%1</li>" ).arg( properties.join( QLatin1String( "</li><li>" ) ) );
233}
234
236{
237 // TODO -- test actual layer z range
238 return true;
239}
240
242{
243 // TODO -- determine actual z range from layer statistics
244 return QgsDoubleRange();
245}
246
248{
249 // show by default if the features aren't just directly clamped onto the terrain with
250 // no other changes
251 return !qgsDoubleNear( mZOffset, 0 )
252 || !qgsDoubleNear( mZScale, 1 )
253 || mEnableExtrusion
254 || mClamping != Qgis::AltitudeClamping::Terrain;
255}
256
258{
259 if ( mClamping == clamping )
260 return;
261
262 mClamping = clamping;
263 emit changed();
265}
266
268{
269 if ( mBinding == binding )
270 return;
271
272 mBinding = binding;
273 emit changed();
275}
276
278{
279 if ( type == mType )
280 return;
281
282 mType = type;
283 emit changed();
285}
286
288{
289 if ( mEnableExtrusion == enabled )
290 return;
291
292 mEnableExtrusion = enabled;
293 emit changed();
295}
296
298{
299 if ( mExtrusionHeight == height )
300 return;
301
302 mExtrusionHeight = height;
303 emit changed();
305}
306
308{
309 if ( mRespectLayerSymbology == enabled )
310 return;
311
312 mRespectLayerSymbology = enabled;
313 emit changed();
315}
316
318{
319 return mProfileLineSymbol.get();
320}
321
323{
324 mProfileLineSymbol.reset( symbol );
325 emit changed();
327}
328
330{
331 return mProfileFillSymbol.get();
332}
333
335{
336 mProfileFillSymbol.reset( symbol );
337 emit changed();
339}
340
342{
343 return mProfileMarkerSymbol.get();
344}
345
347{
348 mProfileMarkerSymbol.reset( symbol );
349 emit changed();
351}
352
354{
355 if ( mSymbology == symbology )
356 return;
357
358 mSymbology = symbology;
359 emit changed();
361}
362
364{
365 return mElevationLimit;
366}
367
369{
370 if ( qgsDoubleNear( mElevationLimit, limit ) )
371 return;
372
373 mElevationLimit = limit;
374 emit changed();
376}
377
379{
380 if ( show == mShowMarkerSymbolInSurfacePlots )
381 return;
382
383 mShowMarkerSymbolInSurfacePlots = show;
384 emit changed();
386}
387
388void QgsVectorLayerElevationProperties::setDefaultProfileLineSymbol( const QColor &color )
389{
390 std::unique_ptr< QgsSimpleLineSymbolLayer > profileLineLayer = std::make_unique< QgsSimpleLineSymbolLayer >( color, 0.6 );
391 mProfileLineSymbol = std::make_unique< QgsLineSymbol>( QgsSymbolLayerList( { profileLineLayer.release() } ) );
392}
393
394void QgsVectorLayerElevationProperties::setDefaultProfileMarkerSymbol( const QColor &color )
395{
396 std::unique_ptr< QgsSimpleMarkerSymbolLayer > profileMarkerLayer = std::make_unique< QgsSimpleMarkerSymbolLayer >( Qgis::MarkerShape::Diamond, 3 );
397 profileMarkerLayer->setColor( color );
398 profileMarkerLayer->setStrokeWidth( 0.2 );
399 profileMarkerLayer->setStrokeColor( color.darker( 140 ) );
400 mProfileMarkerSymbol = std::make_unique< QgsMarkerSymbol>( QgsSymbolLayerList( { profileMarkerLayer.release() } ) );
401}
402
403void QgsVectorLayerElevationProperties::setDefaultProfileFillSymbol( const QColor &color )
404{
405 std::unique_ptr< QgsSimpleFillSymbolLayer > profileFillLayer = std::make_unique< QgsSimpleFillSymbolLayer >( color );
406 profileFillLayer->setStrokeWidth( 0.2 );
407 profileFillLayer->setStrokeColor( color.darker( 140 ) );
408 mProfileFillSymbol = std::make_unique< QgsFillSymbol>( QgsSymbolLayerList( { profileFillLayer.release() } ) );
409}
AltitudeClamping
Altitude clamping.
Definition: qgis.h:3238
@ Relative
Elevation is relative to terrain height (final elevation = terrain elevation + feature elevation)
@ Terrain
Elevation is clamped to terrain (final elevation = terrain elevation)
@ Absolute
Elevation is taken directly from feature and is independent of terrain height (final elevation = feat...
@ Invalid
Invalid (not set) property.
@ Field
Field based property.
@ Static
Static property.
@ Expression
Expression based property.
AltitudeBinding
Altitude binding.
Definition: qgis.h:3251
@ Centroid
Clamp just centroid of feature.
VectorProfileType
Types of elevation profiles to generate for vector sources.
Definition: qgis.h:3448
@ IndividualFeatures
Treat each feature as an individual object (eg buildings)
ProfileSurfaceSymbology
Surface symbology type for elevation profile plots.
Definition: qgis.h:3435
@ Line
The elevation surface will be rendered using a line symbol.
static QgsColorSchemeRegistry * colorSchemeRegistry()
Returns the application's color scheme registry, used for managing color schemes.
QColor fetchRandomStyleColor() const
Returns a random color for use with a new symbol style (e.g.
QgsRange which stores a range of double values.
Definition: qgsrange.h:231
A fill symbol type, for rendering Polygon and MultiPolygon geometries.
Definition: qgsfillsymbol.h:30
A line symbol type, for rendering LineString and MultiLineString geometries.
Definition: qgslinesymbol.h:30
Base class for storage of map layer elevation properties.
QgsPropertyCollection mDataDefinedProperties
Property collection for data defined elevation settings.
void writeCommonProperties(QDomElement &element, QDomDocument &doc, const QgsReadWriteContext &context)
Writes common class properties to a DOM element, to be used later with readXml().
void profileGenerationPropertyChanged()
Emitted when any of the elevation properties which relate solely to generation of elevation profiles ...
void readCommonProperties(const QDomElement &element, const QgsReadWriteContext &context)
Reads common class properties from a DOM element previously written by writeXml().
void changed()
Emitted when any of the elevation properties have changed.
void profileRenderingPropertyChanged()
Emitted when any of the elevation properties which relate solely to presentation of elevation results...
Base class for all map layer types.
Definition: qgsmaplayer.h:75
A marker symbol type, for rendering Point and MultiPoint geometries.
bool isActive(int key) const final
Returns true if the collection contains an active property with the specified key.
void clear() final
Removes all properties from the collection.
QgsProperty property(int key) const final
Returns a matching property from the collection, if one exists.
QString expressionString() const
Returns the expression used for the property value.
Qgis::PropertyType propertyType() const
Returns the property type.
QString field() const
Returns the current field name the property references.
The class is used as a container of context for various read/write operations on other objects.
static QDomElement saveSymbol(const QString &symbolName, const QgsSymbol *symbol, QDomDocument &doc, const QgsReadWriteContext &context)
Writes a symbol definition to XML.
Vector layer specific subclass of QgsMapLayerElevationProperties.
QString htmlSummary() const override
Returns a HTML formatted summary of the properties.
void setDefaultsFromLayer(QgsMapLayer *layer) override
Sets default properties based on sensible choices for the given map layer.
bool readXml(const QDomElement &element, const QgsReadWriteContext &context) override
Reads the elevation properties from a DOM element previously written by writeXml().
QgsFillSymbol * profileFillSymbol() const
Returns the symbol used to render polygons for the layer in elevation profile plots.
void setProfileFillSymbol(QgsFillSymbol *symbol)
Sets the fill symbol used to render polygons for the layer in elevation profile plots.
void setExtrusionHeight(double height)
Sets the feature extrusion height.
void setShowMarkerSymbolInSurfacePlots(bool show)
Sets whether the marker symbol should also be shown in continuous surface plots.
void setBinding(Qgis::AltitudeBinding binding)
Sets the altitude binding method, which determines how altitude is bound to individual vertices in fe...
QDomElement writeXml(QDomElement &element, QDomDocument &doc, const QgsReadWriteContext &context) override
Writes the properties to a DOM element, to be used later with readXml().
Qgis::VectorProfileType type() const
Returns the type of profile the layer represents.
double elevationLimit() const
Returns the elevation limit, which is used when profileSymbology() is Qgis::ProfileSurfaceSymbology::...
QgsDoubleRange calculateZRange(QgsMapLayer *layer) const override
Attempts to calculate the overall elevation or z range for the specified layer, using the settings de...
QgsLineSymbol * profileLineSymbol() const
Returns the symbol used to render lines for the layer in elevation profile plots.
void setProfileSymbology(Qgis::ProfileSurfaceSymbology symbology)
Sets the symbology option used to render the vector profile in elevation profile plots.
void setProfileMarkerSymbol(QgsMarkerSymbol *symbol)
Sets the marker symbol used to render points for the layer in elevation profile plots.
void setExtrusionEnabled(bool enabled)
Sets whether extrusion is enabled.
void setType(Qgis::VectorProfileType type)
Sets the type of profile the layer represents.
QgsVectorLayerElevationProperties * clone() const override
Creates a clone of the properties.
Qgis::AltitudeClamping clamping() const
Returns the altitude clamping method, which dictates how feature heights are interpreted with respect...
QgsVectorLayerElevationProperties(QObject *parent)
Constructor for QgsVectorLayerElevationProperties, with the specified parent object.
bool showByDefaultInElevationProfilePlots() const override
Returns true if the layer should be visible by default in newly created elevation profile plots.
QgsMarkerSymbol * profileMarkerSymbol() const
Returns the symbol used to render points for the layer in elevation profile plots.
Qgis::AltitudeBinding binding() const
Returns the altitude binding method, which determines how altitude is bound to individual vertices in...
void setProfileLineSymbol(QgsLineSymbol *symbol)
Sets the line symbol used to render lines for the layer in elevation profile plots.
bool isVisibleInZRange(const QgsDoubleRange &range, QgsMapLayer *layer=nullptr) const override
Returns true if the layer should be visible and rendered for the specified z range.
bool hasElevation() const override
Returns true if the layer has an elevation or z component.
void setRespectLayerSymbology(bool enabled)
Sets whether layer symbology should be respected when rendering elevation profile plots.
void setElevationLimit(double limit)
Sets the elevation limit, which is used when profileSymbology() is Qgis::ProfileSurfaceSymbology::Fil...
void setClamping(Qgis::AltitudeClamping clamping)
Sets the altitude clamping method, which dictates how feature heights are interpreted with respect to...
Represents a vector layer which manages a vector based data sets.
Q_INVOKABLE Qgis::WkbType wkbType() const FINAL
Returns the WKBType or WKBUnknown in case of error.
static bool hasZ(Qgis::WkbType type)
Tests whether a WKB type contains the z-dimension.
Definition: qgswkbtypes.h:973
T qgsEnumKeyToValue(const QString &key, const T &defaultValue, bool tryValueAsKey=true, bool *returnOk=nullptr)
Returns the value corresponding to the given key of an enum.
Definition: qgis.h:5417
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
Definition: qgis.h:5124
QString qgsEnumValueToKey(const T &value, bool *returnOk=nullptr)
Returns the value for the given key of an enum.
Definition: qgis.h:5398
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:5207
QList< QgsSymbolLayer * > QgsSymbolLayerList
Definition: qgssymbol.h:30