QGIS API Documentation 3.41.0-Master (af5edcb665c)
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( "clamping" ), qgsEnumValueToKey( mClamping ) );
58 element.setAttribute( QStringLiteral( "binding" ), qgsEnumValueToKey( mBinding ) );
59 element.setAttribute( QStringLiteral( "type" ), qgsEnumValueToKey( mType ) );
60 element.setAttribute( QStringLiteral( "symbology" ), qgsEnumValueToKey( mSymbology ) );
61 if ( !std::isnan( mElevationLimit ) )
62 element.setAttribute( QStringLiteral( "elevationLimit" ), qgsDoubleToString( mElevationLimit ) );
63
64 element.setAttribute( QStringLiteral( "respectLayerSymbol" ), mRespectLayerSymbology ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
65 element.setAttribute( QStringLiteral( "showMarkerSymbolInSurfacePlots" ), mShowMarkerSymbolInSurfacePlots ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
66
67 QDomElement profileLineSymbolElement = document.createElement( QStringLiteral( "profileLineSymbol" ) );
68 profileLineSymbolElement.appendChild( QgsSymbolLayerUtils::saveSymbol( QString(), mProfileLineSymbol.get(), document, context ) );
69 element.appendChild( profileLineSymbolElement );
70
71 QDomElement profileFillSymbolElement = document.createElement( QStringLiteral( "profileFillSymbol" ) );
72 profileFillSymbolElement.appendChild( QgsSymbolLayerUtils::saveSymbol( QString(), mProfileFillSymbol.get(), document, context ) );
73 element.appendChild( profileFillSymbolElement );
74
75 QDomElement profileMarkerSymbolElement = document.createElement( QStringLiteral( "profileMarkerSymbol" ) );
76 profileMarkerSymbolElement.appendChild( QgsSymbolLayerUtils::saveSymbol( QString(), mProfileMarkerSymbol.get(), document, context ) );
77 element.appendChild( profileMarkerSymbolElement );
78
79 parentElement.appendChild( element );
80 return element;
81}
82
83bool QgsVectorLayerElevationProperties::readXml( const QDomElement &element, const QgsReadWriteContext &context )
84{
85 const QDomElement elevationElement = element.firstChildElement( QStringLiteral( "elevation" ) ).toElement();
86 if ( elevationElement.isNull() )
87 return false;
88
89 readCommonProperties( elevationElement, context );
90
91 mClamping = qgsEnumKeyToValue( elevationElement.attribute( QStringLiteral( "clamping" ) ), Qgis::AltitudeClamping::Terrain );
92 mBinding = qgsEnumKeyToValue( elevationElement.attribute( QStringLiteral( "binding" ) ), Qgis::AltitudeBinding::Centroid );
93 mType = qgsEnumKeyToValue( elevationElement.attribute( QStringLiteral( "type" ) ), Qgis::VectorProfileType::IndividualFeatures );
94 mEnableExtrusion = elevationElement.attribute( QStringLiteral( "extrusionEnabled" ), QStringLiteral( "0" ) ).toInt();
95 mExtrusionHeight = elevationElement.attribute( QStringLiteral( "extrusion" ), QStringLiteral( "0" ) ).toDouble();
96 mSymbology = qgsEnumKeyToValue( elevationElement.attribute( QStringLiteral( "symbology" ) ), Qgis::ProfileSurfaceSymbology::Line );
97 if ( elevationElement.hasAttribute( QStringLiteral( "elevationLimit" ) ) )
98 mElevationLimit = elevationElement.attribute( QStringLiteral( "elevationLimit" ) ).toDouble();
99 else
100 mElevationLimit = std::numeric_limits< double >::quiet_NaN();
101
102 mShowMarkerSymbolInSurfacePlots = elevationElement.attribute( QStringLiteral( "showMarkerSymbolInSurfacePlots" ), QStringLiteral( "0" ) ).toInt();
103
104 mRespectLayerSymbology = elevationElement.attribute( QStringLiteral( "respectLayerSymbol" ), QStringLiteral( "1" ) ).toInt();
105
107
108 const QDomElement profileLineSymbolElement = elevationElement.firstChildElement( QStringLiteral( "profileLineSymbol" ) ).firstChildElement( QStringLiteral( "symbol" ) );
109 mProfileLineSymbol.reset( QgsSymbolLayerUtils::loadSymbol< QgsLineSymbol >( profileLineSymbolElement, context ) );
110 if ( !mProfileLineSymbol )
111 setDefaultProfileLineSymbol( color );
112
113 const QDomElement profileFillSymbolElement = elevationElement.firstChildElement( QStringLiteral( "profileFillSymbol" ) ).firstChildElement( QStringLiteral( "symbol" ) );
114 mProfileFillSymbol.reset( QgsSymbolLayerUtils::loadSymbol< QgsFillSymbol >( profileFillSymbolElement, context ) );
115 if ( !mProfileFillSymbol )
116 setDefaultProfileFillSymbol( color );
117
118 const QDomElement profileMarkerSymbolElement = elevationElement.firstChildElement( QStringLiteral( "profileMarkerSymbol" ) ).firstChildElement( QStringLiteral( "symbol" ) );
119 mProfileMarkerSymbol.reset( QgsSymbolLayerUtils::loadSymbol< QgsMarkerSymbol >( profileMarkerSymbolElement, context ) );
120 if ( !mProfileMarkerSymbol )
121 setDefaultProfileMarkerSymbol( color );
122
123 return true;
124}
125
127{
128 QgsVectorLayer *vlayer = qobject_cast< QgsVectorLayer * >( layer );
129 if ( !vlayer )
130 return;
131
132 mZOffset = 0;
133 mZScale = 1;
134
135 mEnableExtrusion = false;
136 mExtrusionHeight = 0;
137
139
141
142 if ( QgsWkbTypes::hasZ( vlayer->wkbType() ) )
143 {
145 }
146 else
147 {
149 }
150}
151
153{
154 std::unique_ptr< QgsVectorLayerElevationProperties > res = std::make_unique< QgsVectorLayerElevationProperties >( nullptr );
155 res->setClamping( mClamping );
156 res->setBinding( mBinding );
157 res->setType( mType );
158 res->setExtrusionEnabled( mEnableExtrusion );
159 res->setExtrusionHeight( mExtrusionHeight );
160 res->setProfileLineSymbol( mProfileLineSymbol->clone() );
161 res->setProfileFillSymbol( mProfileFillSymbol->clone() );
162 res->setProfileMarkerSymbol( mProfileMarkerSymbol->clone() );
163 res->setRespectLayerSymbology( mRespectLayerSymbology );
164 res->setProfileSymbology( mSymbology );
165 res->setElevationLimit( mElevationLimit );
166 res->setShowMarkerSymbolInSurfacePlots( mShowMarkerSymbolInSurfacePlots );
167 res->copyCommonProperties( this );
168 return res.release();
169}
170
172{
173 QStringList properties;
174
175 switch ( mClamping )
176 {
178 properties << tr( "Clamped to Terrain" );
179 break;
181 properties << tr( "Relative to Terrain" );
182 break;
184 properties << tr( "Absolute" );
185 break;
186 }
187
189 {
191 {
194 break;
196 properties << tr( "Offset: %1" ).arg( mDataDefinedProperties.property( Property::ZOffset ).field() );
197 break;
199 properties << tr( "Offset: %1" ).arg( mDataDefinedProperties.property( Property::ZOffset ).expressionString() );
200 break;
201 }
202 }
203 else
204 {
205 properties << tr( "Offset: %1" ).arg( mZOffset );
206 }
207
208 if ( mEnableExtrusion )
209 {
211 {
213 {
216 break;
218 properties << tr( "Extrusion: %1" ).arg( mDataDefinedProperties.property( Property::ExtrusionHeight ).field() );
219 break;
221 properties << tr( "Extrusion: %1" ).arg( mDataDefinedProperties.property( Property::ExtrusionHeight ).expressionString() );
222 break;
223 }
224 }
225 else
226 {
227 properties << tr( "Extrusion: %1" ).arg( mExtrusionHeight );
228 }
229 }
230
231 properties << tr( "Scale: %1" ).arg( mZScale );
232
233 return QStringLiteral( "<li>%1</li>" ).arg( properties.join( QLatin1String( "</li><li>" ) ) );
234}
235
237{
238 // TODO -- test actual layer z range
239 return true;
240}
241
243{
244 // TODO -- determine actual z range from layer statistics
245 return QgsDoubleRange();
246}
247
249{
250 // show by default if the features aren't just directly clamped onto the terrain with
251 // no other changes
252 return !qgsDoubleNear( mZOffset, 0 )
253 || !qgsDoubleNear( mZScale, 1 )
254 || mEnableExtrusion
255 || mClamping != Qgis::AltitudeClamping::Terrain;
256}
257
259{
260 if ( mClamping == clamping )
261 return;
262
263 mClamping = clamping;
264 emit changed();
266}
267
269{
270 if ( mBinding == binding )
271 return;
272
273 mBinding = binding;
274 emit changed();
276}
277
279{
280 if ( type == mType )
281 return;
282
283 mType = type;
284 emit changed();
286}
287
289{
290 if ( mEnableExtrusion == enabled )
291 return;
292
293 mEnableExtrusion = enabled;
294 emit changed();
296}
297
299{
300 if ( mExtrusionHeight == height )
301 return;
302
303 mExtrusionHeight = height;
304 emit changed();
306}
307
309{
310 if ( mRespectLayerSymbology == enabled )
311 return;
312
313 mRespectLayerSymbology = enabled;
314 emit changed();
316}
317
319{
320 return mProfileLineSymbol.get();
321}
322
324{
325 mProfileLineSymbol.reset( symbol );
326 emit changed();
328}
329
331{
332 return mProfileFillSymbol.get();
333}
334
336{
337 mProfileFillSymbol.reset( symbol );
338 emit changed();
340}
341
343{
344 return mProfileMarkerSymbol.get();
345}
346
348{
349 mProfileMarkerSymbol.reset( symbol );
350 emit changed();
352}
353
355{
356 if ( mSymbology == symbology )
357 return;
358
359 mSymbology = symbology;
360 emit changed();
362}
363
365{
366 return mElevationLimit;
367}
368
370{
371 if ( qgsDoubleNear( mElevationLimit, limit ) )
372 return;
373
374 mElevationLimit = limit;
375 emit changed();
377}
378
380{
381 if ( show == mShowMarkerSymbolInSurfacePlots )
382 return;
383
384 mShowMarkerSymbolInSurfacePlots = show;
385 emit changed();
387}
388
389void QgsVectorLayerElevationProperties::setDefaultProfileLineSymbol( const QColor &color )
390{
391 std::unique_ptr< QgsSimpleLineSymbolLayer > profileLineLayer = std::make_unique< QgsSimpleLineSymbolLayer >( color, 0.6 );
392 mProfileLineSymbol = std::make_unique< QgsLineSymbol>( QgsSymbolLayerList( { profileLineLayer.release() } ) );
393}
394
395void QgsVectorLayerElevationProperties::setDefaultProfileMarkerSymbol( const QColor &color )
396{
397 std::unique_ptr< QgsSimpleMarkerSymbolLayer > profileMarkerLayer = std::make_unique< QgsSimpleMarkerSymbolLayer >( Qgis::MarkerShape::Diamond, 3 );
398 profileMarkerLayer->setColor( color );
399 profileMarkerLayer->setStrokeWidth( 0.2 );
400 profileMarkerLayer->setStrokeColor( color.darker( 140 ) );
401 mProfileMarkerSymbol = std::make_unique< QgsMarkerSymbol>( QgsSymbolLayerList( { profileMarkerLayer.release() } ) );
402}
403
404void QgsVectorLayerElevationProperties::setDefaultProfileFillSymbol( const QColor &color )
405{
406 std::unique_ptr< QgsSimpleFillSymbolLayer > profileFillLayer = std::make_unique< QgsSimpleFillSymbolLayer >( color );
407 profileFillLayer->setStrokeWidth( 0.2 );
408 profileFillLayer->setStrokeColor( color.darker( 140 ) );
409 mProfileFillSymbol = std::make_unique< QgsFillSymbol>( QgsSymbolLayerList( { profileFillLayer.release() } ) );
410}
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:231
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 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.
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:6276
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
Definition qgis.h:5983
QString qgsEnumValueToKey(const T &value, bool *returnOk=nullptr)
Returns the value for the given key of an enum.
Definition qgis.h:6257
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition qgis.h:6066
QList< QgsSymbolLayer * > QgsSymbolLayerList
Definition qgssymbol.h:30