QGIS API Documentation 3.41.0-Master (d2aaa9c6e02)
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#include "moc_qgsvectorlayerelevationproperties.cpp"
20#include "qgslinesymbol.h"
21#include "qgsfillsymbol.h"
22#include "qgsmarkersymbol.h"
23#include "qgssymbollayerutils.h"
24#include "qgslinesymbollayer.h"
25#include "qgsfillsymbollayer.h"
27#include "qgsapplication.h"
29#include "qgsvectorlayer.h"
30
33{
35 setDefaultProfileLineSymbol( color );
36 setDefaultProfileFillSymbol( color );
37 setDefaultProfileMarkerSymbol( color );
38}
39
41
43{
44 // layer is always considered as having elevation -- even if no z values are present or any
45 // offset/extrusion etc is set, then we are still considering the features as sitting on the terrain
46 // height
47 return true;
48}
49
50QDomElement QgsVectorLayerElevationProperties::writeXml( QDomElement &parentElement, QDomDocument &document, const QgsReadWriteContext &context )
51{
52 QDomElement element = document.createElement( QStringLiteral( "elevation" ) );
53 writeCommonProperties( element, document, context );
54
55 element.setAttribute( QStringLiteral( "extrusionEnabled" ), mEnableExtrusion ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
56 element.setAttribute( QStringLiteral( "extrusion" ), qgsDoubleToString( mExtrusionHeight ) );
57 element.setAttribute( QStringLiteral( "customToleranceEnabled" ), mEnableCustomTolerance ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
58 element.setAttribute( QStringLiteral( "customTolerance" ), qgsDoubleToString( mCustomTolerance ) );
59 element.setAttribute( QStringLiteral( "clamping" ), qgsEnumValueToKey( mClamping ) );
60 element.setAttribute( QStringLiteral( "binding" ), qgsEnumValueToKey( mBinding ) );
61 element.setAttribute( QStringLiteral( "type" ), qgsEnumValueToKey( mType ) );
62 element.setAttribute( QStringLiteral( "symbology" ), qgsEnumValueToKey( mSymbology ) );
63 if ( !std::isnan( mElevationLimit ) )
64 element.setAttribute( QStringLiteral( "elevationLimit" ), qgsDoubleToString( mElevationLimit ) );
65
66 element.setAttribute( QStringLiteral( "respectLayerSymbol" ), mRespectLayerSymbology ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
67 element.setAttribute( QStringLiteral( "showMarkerSymbolInSurfacePlots" ), mShowMarkerSymbolInSurfacePlots ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
68
69 QDomElement profileLineSymbolElement = document.createElement( QStringLiteral( "profileLineSymbol" ) );
70 profileLineSymbolElement.appendChild( QgsSymbolLayerUtils::saveSymbol( QString(), mProfileLineSymbol.get(), document, context ) );
71 element.appendChild( profileLineSymbolElement );
72
73 QDomElement profileFillSymbolElement = document.createElement( QStringLiteral( "profileFillSymbol" ) );
74 profileFillSymbolElement.appendChild( QgsSymbolLayerUtils::saveSymbol( QString(), mProfileFillSymbol.get(), document, context ) );
75 element.appendChild( profileFillSymbolElement );
76
77 QDomElement profileMarkerSymbolElement = document.createElement( QStringLiteral( "profileMarkerSymbol" ) );
78 profileMarkerSymbolElement.appendChild( QgsSymbolLayerUtils::saveSymbol( QString(), mProfileMarkerSymbol.get(), document, context ) );
79 element.appendChild( profileMarkerSymbolElement );
80
81 parentElement.appendChild( element );
82 return element;
83}
84
85bool QgsVectorLayerElevationProperties::readXml( const QDomElement &element, const QgsReadWriteContext &context )
86{
87 const QDomElement elevationElement = element.firstChildElement( QStringLiteral( "elevation" ) ).toElement();
88 if ( elevationElement.isNull() )
89 return false;
90
91 readCommonProperties( elevationElement, context );
92
93 mClamping = qgsEnumKeyToValue( elevationElement.attribute( QStringLiteral( "clamping" ) ), Qgis::AltitudeClamping::Terrain );
94 mBinding = qgsEnumKeyToValue( elevationElement.attribute( QStringLiteral( "binding" ) ), Qgis::AltitudeBinding::Centroid );
95 mType = qgsEnumKeyToValue( elevationElement.attribute( QStringLiteral( "type" ) ), Qgis::VectorProfileType::IndividualFeatures );
96 mEnableExtrusion = elevationElement.attribute( QStringLiteral( "extrusionEnabled" ), QStringLiteral( "0" ) ).toInt();
97 mExtrusionHeight = elevationElement.attribute( QStringLiteral( "extrusion" ), QStringLiteral( "0" ) ).toDouble();
98 mEnableCustomTolerance = elevationElement.attribute( QStringLiteral( "customToleranceEnabled" ), QStringLiteral( "0" ) ).toInt();
99 mCustomTolerance = elevationElement.attribute( QStringLiteral( "customTolerance" ), QStringLiteral( "0" ) ).toDouble();
100 mSymbology = qgsEnumKeyToValue( elevationElement.attribute( QStringLiteral( "symbology" ) ), Qgis::ProfileSurfaceSymbology::Line );
101 if ( elevationElement.hasAttribute( QStringLiteral( "elevationLimit" ) ) )
102 mElevationLimit = elevationElement.attribute( QStringLiteral( "elevationLimit" ) ).toDouble();
103 else
104 mElevationLimit = std::numeric_limits< double >::quiet_NaN();
105
106 mShowMarkerSymbolInSurfacePlots = elevationElement.attribute( QStringLiteral( "showMarkerSymbolInSurfacePlots" ), QStringLiteral( "0" ) ).toInt();
107
108 mRespectLayerSymbology = elevationElement.attribute( QStringLiteral( "respectLayerSymbol" ), QStringLiteral( "1" ) ).toInt();
109
111
112 const QDomElement profileLineSymbolElement = elevationElement.firstChildElement( QStringLiteral( "profileLineSymbol" ) ).firstChildElement( QStringLiteral( "symbol" ) );
113 mProfileLineSymbol.reset( QgsSymbolLayerUtils::loadSymbol< QgsLineSymbol >( profileLineSymbolElement, context ) );
114 if ( !mProfileLineSymbol )
115 setDefaultProfileLineSymbol( color );
116
117 const QDomElement profileFillSymbolElement = elevationElement.firstChildElement( QStringLiteral( "profileFillSymbol" ) ).firstChildElement( QStringLiteral( "symbol" ) );
118 mProfileFillSymbol.reset( QgsSymbolLayerUtils::loadSymbol< QgsFillSymbol >( profileFillSymbolElement, context ) );
119 if ( !mProfileFillSymbol )
120 setDefaultProfileFillSymbol( color );
121
122 const QDomElement profileMarkerSymbolElement = elevationElement.firstChildElement( QStringLiteral( "profileMarkerSymbol" ) ).firstChildElement( QStringLiteral( "symbol" ) );
123 mProfileMarkerSymbol.reset( QgsSymbolLayerUtils::loadSymbol< QgsMarkerSymbol >( profileMarkerSymbolElement, context ) );
124 if ( !mProfileMarkerSymbol )
125 setDefaultProfileMarkerSymbol( color );
126
127 return true;
128}
129
131{
132 QgsVectorLayer *vlayer = qobject_cast< QgsVectorLayer * >( layer );
133 if ( !vlayer )
134 return;
135
136 mZOffset = 0;
137 mZScale = 1;
138
139 mEnableExtrusion = false;
140 mExtrusionHeight = 0;
141
142 // By default override default tolerance for Polygon and Line
143 // to avoid unexpected behaviors.
144 // For example, see: https://github.com/qgis/QGIS/issues/58016
145 mEnableCustomTolerance = vlayer->geometryType() != Qgis::GeometryType::Point;
146 mCustomTolerance = 0;
147
149
151
152 if ( QgsWkbTypes::hasZ( vlayer->wkbType() ) )
153 {
155 }
156 else
157 {
159 }
160}
161
163{
164 std::unique_ptr< QgsVectorLayerElevationProperties > res = std::make_unique< QgsVectorLayerElevationProperties >( nullptr );
165 res->setClamping( mClamping );
166 res->setBinding( mBinding );
167 res->setType( mType );
168 res->setExtrusionEnabled( mEnableExtrusion );
169 res->setExtrusionHeight( mExtrusionHeight );
170 res->setCustomToleranceEnabled( mEnableCustomTolerance );
171 res->setCustomTolerance( mCustomTolerance );
172 res->setProfileLineSymbol( mProfileLineSymbol->clone() );
173 res->setProfileFillSymbol( mProfileFillSymbol->clone() );
174 res->setProfileMarkerSymbol( mProfileMarkerSymbol->clone() );
175 res->setRespectLayerSymbology( mRespectLayerSymbology );
176 res->setProfileSymbology( mSymbology );
177 res->setElevationLimit( mElevationLimit );
178 res->setShowMarkerSymbolInSurfacePlots( mShowMarkerSymbolInSurfacePlots );
179 res->copyCommonProperties( this );
180 return res.release();
181}
182
184{
185 QStringList properties;
186
187 switch ( mClamping )
188 {
190 properties << tr( "Clamped to Terrain" );
191 break;
193 properties << tr( "Relative to Terrain" );
194 break;
196 properties << tr( "Absolute" );
197 break;
198 }
199
201 {
203 {
206 break;
208 properties << tr( "Offset: %1" ).arg( mDataDefinedProperties.property( Property::ZOffset ).field() );
209 break;
211 properties << tr( "Offset: %1" ).arg( mDataDefinedProperties.property( Property::ZOffset ).expressionString() );
212 break;
213 }
214 }
215 else
216 {
217 properties << tr( "Offset: %1" ).arg( mZOffset );
218 }
219
220 if ( mEnableExtrusion )
221 {
223 {
225 {
228 break;
230 properties << tr( "Extrusion: %1" ).arg( mDataDefinedProperties.property( Property::ExtrusionHeight ).field() );
231 break;
233 properties << tr( "Extrusion: %1" ).arg( mDataDefinedProperties.property( Property::ExtrusionHeight ).expressionString() );
234 break;
235 }
236 }
237 else
238 {
239 properties << tr( "Extrusion: %1" ).arg( mExtrusionHeight );
240 }
241 }
242
243 if ( mEnableCustomTolerance )
244 {
245 properties << tr( "CustomTolerance: %1" ).arg( mCustomTolerance );
246 }
247
248 properties << tr( "Scale: %1" ).arg( mZScale );
249
250 return QStringLiteral( "<li>%1</li>" ).arg( properties.join( QLatin1String( "</li><li>" ) ) );
251}
252
254{
255 // TODO -- test actual layer z range
256 return true;
257}
258
260{
261 // TODO -- determine actual z range from layer statistics
262 return QgsDoubleRange();
263}
264
266{
267 // show by default if the features aren't just directly clamped onto the terrain with
268 // no other changes
269 return !qgsDoubleNear( mZOffset, 0 )
270 || !qgsDoubleNear( mZScale, 1 )
271 || mEnableExtrusion
272 || mClamping != Qgis::AltitudeClamping::Terrain;
273}
274
276{
277 if ( mClamping == clamping )
278 return;
279
280 mClamping = clamping;
281 emit changed();
283}
284
286{
287 if ( mBinding == binding )
288 return;
289
290 mBinding = binding;
291 emit changed();
293}
294
296{
297 if ( type == mType )
298 return;
299
300 mType = type;
301 emit changed();
303}
304
306{
307 if ( mEnableExtrusion == enabled )
308 return;
309
310 mEnableExtrusion = enabled;
311 emit changed();
313}
314
316{
317 if ( mExtrusionHeight == height )
318 return;
319
320 mExtrusionHeight = height;
321 emit changed();
323}
324
326{
327 if ( mCustomTolerance == tolerance )
328 return;
329
330 mCustomTolerance = tolerance;
331 emit changed();
333}
334
336{
337 if ( mEnableCustomTolerance == enabled )
338 return;
339
340 mEnableCustomTolerance = enabled;
341 emit changed();
343}
344
346{
347 if ( mRespectLayerSymbology == enabled )
348 return;
349
350 mRespectLayerSymbology = enabled;
351 emit changed();
353}
354
356{
357 return mProfileLineSymbol.get();
358}
359
361{
362 mProfileLineSymbol.reset( symbol );
363 emit changed();
365}
366
368{
369 return mProfileFillSymbol.get();
370}
371
373{
374 mProfileFillSymbol.reset( symbol );
375 emit changed();
377}
378
380{
381 return mProfileMarkerSymbol.get();
382}
383
385{
386 mProfileMarkerSymbol.reset( symbol );
387 emit changed();
389}
390
392{
393 if ( mSymbology == symbology )
394 return;
395
396 mSymbology = symbology;
397 emit changed();
399}
400
402{
403 return mElevationLimit;
404}
405
407{
408 if ( qgsDoubleNear( mElevationLimit, limit ) )
409 return;
410
411 mElevationLimit = limit;
412 emit changed();
414}
415
417{
418 if ( show == mShowMarkerSymbolInSurfacePlots )
419 return;
420
421 mShowMarkerSymbolInSurfacePlots = show;
422 emit changed();
424}
425
426void QgsVectorLayerElevationProperties::setDefaultProfileLineSymbol( const QColor &color )
427{
428 std::unique_ptr< QgsSimpleLineSymbolLayer > profileLineLayer = std::make_unique< QgsSimpleLineSymbolLayer >( color, 0.6 );
429 mProfileLineSymbol = std::make_unique< QgsLineSymbol>( QgsSymbolLayerList( { profileLineLayer.release() } ) );
430}
431
432void QgsVectorLayerElevationProperties::setDefaultProfileMarkerSymbol( const QColor &color )
433{
434 std::unique_ptr< QgsSimpleMarkerSymbolLayer > profileMarkerLayer = std::make_unique< QgsSimpleMarkerSymbolLayer >( Qgis::MarkerShape::Diamond, 3 );
435 profileMarkerLayer->setColor( color );
436 profileMarkerLayer->setStrokeWidth( 0.2 );
437 profileMarkerLayer->setStrokeColor( color.darker( 140 ) );
438 mProfileMarkerSymbol = std::make_unique< QgsMarkerSymbol>( QgsSymbolLayerList( { profileMarkerLayer.release() } ) );
439}
440
441void QgsVectorLayerElevationProperties::setDefaultProfileFillSymbol( const QColor &color )
442{
443 std::unique_ptr< QgsSimpleFillSymbolLayer > profileFillLayer = std::make_unique< QgsSimpleFillSymbolLayer >( color );
444 profileFillLayer->setStrokeWidth( 0.2 );
445 profileFillLayer->setStrokeColor( color.darker( 140 ) );
446 mProfileFillSymbol = std::make_unique< QgsFillSymbol>( QgsSymbolLayerList( { profileFillLayer.release() } ) );
447}
AltitudeClamping
Altitude clamping.
Definition qgis.h:3762
@ 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:3775
@ Centroid
Clamp just centroid of feature.
VectorProfileType
Types of elevation profiles to generate for vector sources.
Definition qgis.h:3973
@ IndividualFeatures
Treat each feature as an individual object (eg buildings)
ProfileSurfaceSymbology
Surface symbology type for elevation profile plots.
Definition qgis.h:3960
@ 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:237
A fill symbol type, for rendering Polygon and MultiPolygon geometries.
A line symbol type, for rendering LineString and MultiLineString geometries.
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:76
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 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 data sets.
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 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:6301
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
Definition qgis.h:6008
QString qgsEnumValueToKey(const T &value, bool *returnOk=nullptr)
Returns the value for the given key of an enum.
Definition qgis.h:6282
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition qgis.h:6091
QList< QgsSymbolLayer * > QgsSymbolLayerList
Definition qgssymbol.h:30