QGIS API Documentation 3.99.0-Master (21b3aa880ba)
Loading...
Searching...
No Matches
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
20#include "qgsapplication.h"
22#include "qgsfillsymbol.h"
23#include "qgsfillsymbollayer.h"
24#include "qgslinesymbol.h"
25#include "qgslinesymbollayer.h"
26#include "qgsmarkersymbol.h"
28#include "qgssymbollayerutils.h"
29#include "qgsvectorlayer.h"
30
31#include "moc_qgsvectorlayerelevationproperties.cpp"
32
35{
37 setDefaultProfileLineSymbol( color );
38 setDefaultProfileFillSymbol( color );
39 setDefaultProfileMarkerSymbol( color );
40}
41
43
45{
46 // layer is always considered as having elevation -- even if no z values are present or any
47 // offset/extrusion etc is set, then we are still considering the features as sitting on the terrain
48 // height
49 return true;
50}
51
52QDomElement QgsVectorLayerElevationProperties::writeXml( QDomElement &parentElement, QDomDocument &document, const QgsReadWriteContext &context )
53{
54 QDomElement element = document.createElement( QStringLiteral( "elevation" ) );
55 writeCommonProperties( element, document, context );
56
57 element.setAttribute( QStringLiteral( "extrusionEnabled" ), mEnableExtrusion ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
58 element.setAttribute( QStringLiteral( "extrusion" ), qgsDoubleToString( mExtrusionHeight ) );
59 element.setAttribute( QStringLiteral( "customToleranceEnabled" ), mEnableCustomTolerance ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
60 if ( mCustomTolerance != 0 )
61 element.setAttribute( QStringLiteral( "customTolerance" ), qgsDoubleToString( mCustomTolerance ) );
62 element.setAttribute( QStringLiteral( "clamping" ), qgsEnumValueToKey( mClamping ) );
63 element.setAttribute( QStringLiteral( "binding" ), qgsEnumValueToKey( mBinding ) );
64 element.setAttribute( QStringLiteral( "type" ), qgsEnumValueToKey( mType ) );
65 element.setAttribute( QStringLiteral( "symbology" ), qgsEnumValueToKey( mSymbology ) );
66 if ( !std::isnan( mElevationLimit ) )
67 element.setAttribute( QStringLiteral( "elevationLimit" ), qgsDoubleToString( mElevationLimit ) );
68
69 element.setAttribute( QStringLiteral( "respectLayerSymbol" ), mRespectLayerSymbology ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
70 element.setAttribute( QStringLiteral( "showMarkerSymbolInSurfacePlots" ), mShowMarkerSymbolInSurfacePlots ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
71
72 QDomElement profileLineSymbolElement = document.createElement( QStringLiteral( "profileLineSymbol" ) );
73 profileLineSymbolElement.appendChild( QgsSymbolLayerUtils::saveSymbol( QString(), mProfileLineSymbol.get(), document, context ) );
74 element.appendChild( profileLineSymbolElement );
75
76 QDomElement profileFillSymbolElement = document.createElement( QStringLiteral( "profileFillSymbol" ) );
77 profileFillSymbolElement.appendChild( QgsSymbolLayerUtils::saveSymbol( QString(), mProfileFillSymbol.get(), document, context ) );
78 element.appendChild( profileFillSymbolElement );
79
80 QDomElement profileMarkerSymbolElement = document.createElement( QStringLiteral( "profileMarkerSymbol" ) );
81 profileMarkerSymbolElement.appendChild( QgsSymbolLayerUtils::saveSymbol( QString(), mProfileMarkerSymbol.get(), document, context ) );
82 element.appendChild( profileMarkerSymbolElement );
83
84 parentElement.appendChild( element );
85 return element;
86}
87
88bool QgsVectorLayerElevationProperties::readXml( const QDomElement &element, const QgsReadWriteContext &context )
89{
90 const QDomElement elevationElement = element.firstChildElement( QStringLiteral( "elevation" ) ).toElement();
91 if ( elevationElement.isNull() )
92 return false;
93
94 readCommonProperties( elevationElement, context );
95
96 mClamping = qgsEnumKeyToValue( elevationElement.attribute( QStringLiteral( "clamping" ) ), Qgis::AltitudeClamping::Terrain );
97 mBinding = qgsEnumKeyToValue( elevationElement.attribute( QStringLiteral( "binding" ) ), Qgis::AltitudeBinding::Centroid );
98 mType = qgsEnumKeyToValue( elevationElement.attribute( QStringLiteral( "type" ) ), Qgis::VectorProfileType::IndividualFeatures );
99 mEnableExtrusion = elevationElement.attribute( QStringLiteral( "extrusionEnabled" ), QStringLiteral( "0" ) ).toInt();
100 mExtrusionHeight = elevationElement.attribute( QStringLiteral( "extrusion" ), QStringLiteral( "0" ) ).toDouble();
101 mEnableCustomTolerance = elevationElement.attribute( QStringLiteral( "customToleranceEnabled" ), QStringLiteral( "0" ) ).toInt();
102 mCustomTolerance = elevationElement.attribute( QStringLiteral( "customTolerance" ), QStringLiteral( "0" ) ).toDouble();
103 mSymbology = qgsEnumKeyToValue( elevationElement.attribute( QStringLiteral( "symbology" ) ), Qgis::ProfileSurfaceSymbology::Line );
104 if ( elevationElement.hasAttribute( QStringLiteral( "elevationLimit" ) ) )
105 mElevationLimit = elevationElement.attribute( QStringLiteral( "elevationLimit" ) ).toDouble();
106 else
107 mElevationLimit = std::numeric_limits< double >::quiet_NaN();
108
109 mShowMarkerSymbolInSurfacePlots = elevationElement.attribute( QStringLiteral( "showMarkerSymbolInSurfacePlots" ), QStringLiteral( "0" ) ).toInt();
110
111 mRespectLayerSymbology = elevationElement.attribute( QStringLiteral( "respectLayerSymbol" ), QStringLiteral( "1" ) ).toInt();
112
114
115 const QDomElement profileLineSymbolElement = elevationElement.firstChildElement( QStringLiteral( "profileLineSymbol" ) ).firstChildElement( QStringLiteral( "symbol" ) );
116 mProfileLineSymbol = QgsSymbolLayerUtils::loadSymbol< QgsLineSymbol >( profileLineSymbolElement, context );
117 if ( !mProfileLineSymbol )
118 setDefaultProfileLineSymbol( color );
119
120 const QDomElement profileFillSymbolElement = elevationElement.firstChildElement( QStringLiteral( "profileFillSymbol" ) ).firstChildElement( QStringLiteral( "symbol" ) );
121 mProfileFillSymbol = QgsSymbolLayerUtils::loadSymbol< QgsFillSymbol >( profileFillSymbolElement, context );
122 if ( !mProfileFillSymbol )
123 setDefaultProfileFillSymbol( color );
124
125 const QDomElement profileMarkerSymbolElement = elevationElement.firstChildElement( QStringLiteral( "profileMarkerSymbol" ) ).firstChildElement( QStringLiteral( "symbol" ) );
126 mProfileMarkerSymbol = QgsSymbolLayerUtils::loadSymbol< QgsMarkerSymbol >( profileMarkerSymbolElement, context );
127 if ( !mProfileMarkerSymbol )
128 setDefaultProfileMarkerSymbol( color );
129
130 return true;
131}
132
134{
135 QgsVectorLayer *vlayer = qobject_cast< QgsVectorLayer * >( layer );
136 if ( !vlayer )
137 return;
138
139 mZOffset = 0;
140 mZScale = 1;
141
142 mEnableExtrusion = false;
143 mExtrusionHeight = 0;
144
145 // By default override default tolerance for Polygon and Line
146 // to avoid unexpected behaviors.
147 // For example, see: https://github.com/qgis/QGIS/issues/58016
148 mEnableCustomTolerance = vlayer->geometryType() != Qgis::GeometryType::Point;
149 mCustomTolerance = 0;
150
152
154
155 if ( QgsWkbTypes::hasZ( vlayer->wkbType() ) )
156 {
158 }
159 else
160 {
162 }
163}
164
166{
167 auto res = std::make_unique< QgsVectorLayerElevationProperties >( nullptr );
168 res->setClamping( mClamping );
169 res->setBinding( mBinding );
170 res->setType( mType );
171 res->setExtrusionEnabled( mEnableExtrusion );
172 res->setExtrusionHeight( mExtrusionHeight );
173 res->setCustomToleranceEnabled( mEnableCustomTolerance );
174 res->setCustomTolerance( mCustomTolerance );
175 res->setProfileLineSymbol( mProfileLineSymbol->clone() );
176 res->setProfileFillSymbol( mProfileFillSymbol->clone() );
177 res->setProfileMarkerSymbol( mProfileMarkerSymbol->clone() );
178 res->setRespectLayerSymbology( mRespectLayerSymbology );
179 res->setProfileSymbology( mSymbology );
180 res->setElevationLimit( mElevationLimit );
181 res->setShowMarkerSymbolInSurfacePlots( mShowMarkerSymbolInSurfacePlots );
182 res->copyCommonProperties( this );
183 return res.release();
184}
185
187{
188 QStringList properties;
189
190 switch ( mClamping )
191 {
193 properties << tr( "Clamped to Terrain" );
194 break;
196 properties << tr( "Relative to Terrain" );
197 break;
199 properties << tr( "Absolute" );
200 break;
201 }
202
204 {
205 switch ( mDataDefinedProperties.property( Property::ZOffset ).propertyType() )
206 {
209 break;
211 properties << tr( "Offset: %1" ).arg( mDataDefinedProperties.property( Property::ZOffset ).field() );
212 break;
214 properties << tr( "Offset: %1" ).arg( mDataDefinedProperties.property( Property::ZOffset ).expressionString() );
215 break;
216 }
217 }
218 else
219 {
220 properties << tr( "Offset: %1" ).arg( mZOffset );
221 }
222
223 if ( mEnableExtrusion )
224 {
226 {
227 switch ( mDataDefinedProperties.property( Property::ExtrusionHeight ).propertyType() )
228 {
231 break;
233 properties << tr( "Extrusion: %1" ).arg( mDataDefinedProperties.property( Property::ExtrusionHeight ).field() );
234 break;
236 properties << tr( "Extrusion: %1" ).arg( mDataDefinedProperties.property( Property::ExtrusionHeight ).expressionString() );
237 break;
238 }
239 }
240 else
241 {
242 properties << tr( "Extrusion: %1" ).arg( mExtrusionHeight );
243 }
244 }
245
246 if ( mEnableCustomTolerance )
247 {
248 properties << tr( "CustomTolerance: %1" ).arg( mCustomTolerance );
249 }
250
251 properties << tr( "Scale: %1" ).arg( mZScale );
252
253 return QStringLiteral( "<li>%1</li>" ).arg( properties.join( QLatin1String( "</li><li>" ) ) );
254}
255
257{
258 // TODO -- test actual layer z range
259 return true;
260}
261
263{
264 // TODO -- determine actual z range from layer statistics
265 return QgsDoubleRange();
266}
267
269{
270 // show by default if the features aren't just directly clamped onto the terrain with
271 // no other changes
272 return !qgsDoubleNear( mZOffset, 0 )
273 || !qgsDoubleNear( mZScale, 1 )
274 || mEnableExtrusion
275 || mClamping != Qgis::AltitudeClamping::Terrain;
276}
277
279{
280 if ( mClamping == clamping )
281 return;
282
283 mClamping = clamping;
284 emit changed();
286}
287
289{
290 if ( mBinding == binding )
291 return;
292
293 mBinding = binding;
294 emit changed();
296}
297
299{
300 if ( type == mType )
301 return;
302
303 mType = type;
304 emit changed();
306}
307
309{
310 if ( mEnableExtrusion == enabled )
311 return;
312
313 mEnableExtrusion = enabled;
314 emit changed();
316}
317
319{
320 if ( mExtrusionHeight == height )
321 return;
322
323 mExtrusionHeight = height;
324 emit changed();
326}
327
329{
330 if ( mCustomTolerance == tolerance )
331 return;
332
333 mCustomTolerance = tolerance;
334 emit changed();
336}
337
339{
340 if ( mEnableCustomTolerance == enabled )
341 return;
342
343 mEnableCustomTolerance = enabled;
344 emit changed();
346}
347
349{
350 if ( mRespectLayerSymbology == enabled )
351 return;
352
353 mRespectLayerSymbology = enabled;
354 emit changed();
356}
357
359{
360 return mProfileLineSymbol.get();
361}
362
364{
365 mProfileLineSymbol.reset( symbol );
366 emit changed();
368}
369
371{
372 return mProfileFillSymbol.get();
373}
374
376{
377 mProfileFillSymbol.reset( symbol );
378 emit changed();
380}
381
383{
384 return mProfileMarkerSymbol.get();
385}
386
388{
389 mProfileMarkerSymbol.reset( symbol );
390 emit changed();
392}
393
395{
396 if ( mSymbology == symbology )
397 return;
398
399 mSymbology = symbology;
400 emit changed();
402}
403
405{
406 return mElevationLimit;
407}
408
410{
411 if ( qgsDoubleNear( mElevationLimit, limit ) )
412 return;
413
414 mElevationLimit = limit;
415 emit changed();
417}
418
420{
421 if ( show == mShowMarkerSymbolInSurfacePlots )
422 return;
423
424 mShowMarkerSymbolInSurfacePlots = show;
425 emit changed();
427}
428
429void QgsVectorLayerElevationProperties::setDefaultProfileLineSymbol( const QColor &color )
430{
431 auto profileLineLayer = std::make_unique< QgsSimpleLineSymbolLayer >( color, 0.6 );
432 mProfileLineSymbol = std::make_unique< QgsLineSymbol>( QgsSymbolLayerList( { profileLineLayer.release() } ) );
433}
434
435void QgsVectorLayerElevationProperties::setDefaultProfileMarkerSymbol( const QColor &color )
436{
437 auto profileMarkerLayer = std::make_unique< QgsSimpleMarkerSymbolLayer >( Qgis::MarkerShape::Diamond, 3 );
438 profileMarkerLayer->setColor( color );
439 profileMarkerLayer->setStrokeWidth( 0.2 );
440 profileMarkerLayer->setStrokeColor( color.darker( 140 ) );
441 mProfileMarkerSymbol = std::make_unique< QgsMarkerSymbol>( QgsSymbolLayerList( { profileMarkerLayer.release() } ) );
442}
443
444void QgsVectorLayerElevationProperties::setDefaultProfileFillSymbol( const QColor &color )
445{
446 auto profileFillLayer = std::make_unique< QgsSimpleFillSymbolLayer >( color );
447 profileFillLayer->setStrokeWidth( 0.2 );
448 profileFillLayer->setStrokeColor( color.darker( 140 ) );
449 mProfileFillSymbol = std::make_unique< QgsFillSymbol>( QgsSymbolLayerList( { profileFillLayer.release() } ) );
450}
AltitudeClamping
Altitude clamping.
Definition qgis.h:3982
@ Relative
Elevation is relative to terrain height (final elevation = terrain elevation + feature elevation).
Definition qgis.h:3984
@ Terrain
Elevation is clamped to terrain (final elevation = terrain elevation).
Definition qgis.h:3985
@ Absolute
Elevation is taken directly from feature and is independent of terrain height (final elevation = feat...
Definition qgis.h:3983
@ Invalid
Invalid (not set) property.
Definition qgis.h:683
@ Field
Field based property.
Definition qgis.h:685
@ Static
Static property.
Definition qgis.h:684
@ Expression
Expression based property.
Definition qgis.h:686
@ Diamond
Diamond.
Definition qgis.h:3082
@ Point
Points.
Definition qgis.h:359
AltitudeBinding
Altitude binding.
Definition qgis.h:3995
@ Centroid
Clamp just centroid of feature.
Definition qgis.h:3997
VectorProfileType
Types of elevation profiles to generate for vector sources.
Definition qgis.h:4206
@ IndividualFeatures
Treat each feature as an individual object (eg buildings).
Definition qgis.h:4207
ProfileSurfaceSymbology
Surface symbology type for elevation profile plots.
Definition qgis.h:4193
@ Line
The elevation surface will be rendered using a line symbol.
Definition qgis.h:4194
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:233
A fill symbol type, for rendering Polygon and MultiPolygon geometries.
A line symbol type, for rendering LineString and MultiLineString geometries.
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 ...
QgsMapLayerElevationProperties(QObject *parent)
Constructor for QgsMapLayerElevationProperties, with the specified parent object.
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:80
A marker symbol type, for rendering Point and MultiPoint geometries.
A container for the context for various read/write operations on objects.
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.
QString htmlSummary() const override
Returns a HTML formatted summary of the properties.
void setCustomToleranceEnabled(bool enabled)
Sets whether custom tolerance is enabled.
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().
void setCustomTolerance(double tolerance)
Sets the feature custom tolerance.
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 dataset.
Q_INVOKABLE Qgis::WkbType wkbType() const final
Returns the WKBType or WKBUnknown in case of error.
Q_INVOKABLE Qgis::GeometryType geometryType() const
Returns point, line or polygon.
static Q_INVOKABLE bool hasZ(Qgis::WkbType type)
Tests whether a WKB type contains the z-dimension.
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:6817
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
Definition qgis.h:6524
QString qgsEnumValueToKey(const T &value, bool *returnOk=nullptr)
Returns the value for the given key of an enum.
Definition qgis.h:6798
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference).
Definition qgis.h:6607
QList< QgsSymbolLayer * > QgsSymbolLayerList
Definition qgssymbol.h:30