QGIS API Documentation 4.0.0-Norrköping (1ddcee3d0e4)
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 <QString>
32
33#include "moc_qgsvectorlayerelevationproperties.cpp"
34
35using namespace Qt::StringLiterals;
36
39{
41 setDefaultProfileLineSymbol( color );
42 setDefaultProfileFillSymbol( color );
43 setDefaultProfileMarkerSymbol( color );
44}
45
47
49{
50 // layer is always considered as having elevation -- even if no z values are present or any
51 // offset/extrusion etc is set, then we are still considering the features as sitting on the terrain
52 // height
53 return true;
54}
55
56QDomElement QgsVectorLayerElevationProperties::writeXml( QDomElement &parentElement, QDomDocument &document, const QgsReadWriteContext &context )
57{
58 QDomElement element = document.createElement( u"elevation"_s );
59 writeCommonProperties( element, document, context );
60
61 element.setAttribute( u"extrusionEnabled"_s, mEnableExtrusion ? u"1"_s : u"0"_s );
62 element.setAttribute( u"extrusion"_s, qgsDoubleToString( mExtrusionHeight ) );
63 element.setAttribute( u"customToleranceEnabled"_s, mEnableCustomTolerance ? u"1"_s : u"0"_s );
64 if ( mCustomTolerance != 0 )
65 element.setAttribute( u"customTolerance"_s, qgsDoubleToString( mCustomTolerance ) );
66 element.setAttribute( u"clamping"_s, qgsEnumValueToKey( mClamping ) );
67 element.setAttribute( u"binding"_s, qgsEnumValueToKey( mBinding ) );
68 element.setAttribute( u"type"_s, qgsEnumValueToKey( mType ) );
69 element.setAttribute( u"symbology"_s, qgsEnumValueToKey( mSymbology ) );
70 if ( !std::isnan( mElevationLimit ) )
71 element.setAttribute( u"elevationLimit"_s, qgsDoubleToString( mElevationLimit ) );
72
73 element.setAttribute( u"respectLayerSymbol"_s, mRespectLayerSymbology ? u"1"_s : u"0"_s );
74 element.setAttribute( u"showMarkerSymbolInSurfacePlots"_s, mShowMarkerSymbolInSurfacePlots ? u"1"_s : u"0"_s );
75
76 QDomElement profileLineSymbolElement = document.createElement( u"profileLineSymbol"_s );
77 profileLineSymbolElement.appendChild( QgsSymbolLayerUtils::saveSymbol( QString(), mProfileLineSymbol.get(), document, context ) );
78 element.appendChild( profileLineSymbolElement );
79
80 QDomElement profileFillSymbolElement = document.createElement( u"profileFillSymbol"_s );
81 profileFillSymbolElement.appendChild( QgsSymbolLayerUtils::saveSymbol( QString(), mProfileFillSymbol.get(), document, context ) );
82 element.appendChild( profileFillSymbolElement );
83
84 QDomElement profileMarkerSymbolElement = document.createElement( u"profileMarkerSymbol"_s );
85 profileMarkerSymbolElement.appendChild( QgsSymbolLayerUtils::saveSymbol( QString(), mProfileMarkerSymbol.get(), document, context ) );
86 element.appendChild( profileMarkerSymbolElement );
87
88 parentElement.appendChild( element );
89 return element;
90}
91
92bool QgsVectorLayerElevationProperties::readXml( const QDomElement &element, const QgsReadWriteContext &context )
93{
94 const QDomElement elevationElement = element.firstChildElement( u"elevation"_s ).toElement();
95 if ( elevationElement.isNull() )
96 return false;
97
98 readCommonProperties( elevationElement, context );
99
100 mClamping = qgsEnumKeyToValue( elevationElement.attribute( u"clamping"_s ), Qgis::AltitudeClamping::Terrain );
101 mBinding = qgsEnumKeyToValue( elevationElement.attribute( u"binding"_s ), Qgis::AltitudeBinding::Centroid );
102 mType = qgsEnumKeyToValue( elevationElement.attribute( u"type"_s ), Qgis::VectorProfileType::IndividualFeatures );
103 mEnableExtrusion = elevationElement.attribute( u"extrusionEnabled"_s, u"0"_s ).toInt();
104 mExtrusionHeight = elevationElement.attribute( u"extrusion"_s, u"0"_s ).toDouble();
105 mEnableCustomTolerance = elevationElement.attribute( u"customToleranceEnabled"_s, u"0"_s ).toInt();
106 mCustomTolerance = elevationElement.attribute( u"customTolerance"_s, u"0"_s ).toDouble();
107 mSymbology = qgsEnumKeyToValue( elevationElement.attribute( u"symbology"_s ), Qgis::ProfileSurfaceSymbology::Line );
108 if ( elevationElement.hasAttribute( u"elevationLimit"_s ) )
109 mElevationLimit = elevationElement.attribute( u"elevationLimit"_s ).toDouble();
110 else
111 mElevationLimit = std::numeric_limits< double >::quiet_NaN();
112
113 mShowMarkerSymbolInSurfacePlots = elevationElement.attribute( u"showMarkerSymbolInSurfacePlots"_s, u"0"_s ).toInt();
114
115 mRespectLayerSymbology = elevationElement.attribute( u"respectLayerSymbol"_s, u"1"_s ).toInt();
116
118
119 const QDomElement profileLineSymbolElement = elevationElement.firstChildElement( u"profileLineSymbol"_s ).firstChildElement( u"symbol"_s );
120 mProfileLineSymbol = QgsSymbolLayerUtils::loadSymbol< QgsLineSymbol >( profileLineSymbolElement, context );
121 if ( !mProfileLineSymbol )
122 setDefaultProfileLineSymbol( color );
123
124 const QDomElement profileFillSymbolElement = elevationElement.firstChildElement( u"profileFillSymbol"_s ).firstChildElement( u"symbol"_s );
125 mProfileFillSymbol = QgsSymbolLayerUtils::loadSymbol< QgsFillSymbol >( profileFillSymbolElement, context );
126 if ( !mProfileFillSymbol )
127 setDefaultProfileFillSymbol( color );
128
129 const QDomElement profileMarkerSymbolElement = elevationElement.firstChildElement( u"profileMarkerSymbol"_s ).firstChildElement( u"symbol"_s );
130 mProfileMarkerSymbol = QgsSymbolLayerUtils::loadSymbol< QgsMarkerSymbol >( profileMarkerSymbolElement, context );
131 if ( !mProfileMarkerSymbol )
132 setDefaultProfileMarkerSymbol( color );
133
134 return true;
135}
136
138{
139 QgsVectorLayer *vlayer = qobject_cast< QgsVectorLayer * >( layer );
140 if ( !vlayer )
141 return;
142
143 mZOffset = 0;
144 mZScale = 1;
145
146 mEnableExtrusion = false;
147 mExtrusionHeight = 0;
148
149 // By default override default tolerance for Polygon and Line
150 // to avoid unexpected behaviors.
151 // For example, see: https://github.com/qgis/QGIS/issues/58016
152 mEnableCustomTolerance = vlayer->geometryType() != Qgis::GeometryType::Point;
153 mCustomTolerance = 0;
154
156
158
159 if ( QgsWkbTypes::hasZ( vlayer->wkbType() ) )
160 {
162 }
163 else
164 {
166 }
167}
168
170{
171 auto res = std::make_unique< QgsVectorLayerElevationProperties >( nullptr );
172 res->setClamping( mClamping );
173 res->setBinding( mBinding );
174 res->setType( mType );
175 res->setExtrusionEnabled( mEnableExtrusion );
176 res->setExtrusionHeight( mExtrusionHeight );
177 res->setCustomToleranceEnabled( mEnableCustomTolerance );
178 res->setCustomTolerance( mCustomTolerance );
179 res->setProfileLineSymbol( mProfileLineSymbol->clone() );
180 res->setProfileFillSymbol( mProfileFillSymbol->clone() );
181 res->setProfileMarkerSymbol( mProfileMarkerSymbol->clone() );
182 res->setRespectLayerSymbology( mRespectLayerSymbology );
183 res->setProfileSymbology( mSymbology );
184 res->setElevationLimit( mElevationLimit );
185 res->setShowMarkerSymbolInSurfacePlots( mShowMarkerSymbolInSurfacePlots );
186 res->copyCommonProperties( this );
187 return res.release();
188}
189
191{
192 QStringList properties;
193
194 switch ( mClamping )
195 {
197 properties << tr( "Clamped to Terrain" );
198 break;
200 properties << tr( "Relative to Terrain" );
201 break;
203 properties << tr( "Absolute" );
204 break;
205 }
206
208 {
209 switch ( mDataDefinedProperties.property( Property::ZOffset ).propertyType() )
210 {
213 break;
215 properties << tr( "Offset: %1" ).arg( mDataDefinedProperties.property( Property::ZOffset ).field() );
216 break;
218 properties << tr( "Offset: %1" ).arg( mDataDefinedProperties.property( Property::ZOffset ).expressionString() );
219 break;
220 }
221 }
222 else
223 {
224 properties << tr( "Offset: %1" ).arg( mZOffset );
225 }
226
227 if ( mEnableExtrusion )
228 {
230 {
231 switch ( mDataDefinedProperties.property( Property::ExtrusionHeight ).propertyType() )
232 {
235 break;
237 properties << tr( "Extrusion: %1" ).arg( mDataDefinedProperties.property( Property::ExtrusionHeight ).field() );
238 break;
240 properties << tr( "Extrusion: %1" ).arg( mDataDefinedProperties.property( Property::ExtrusionHeight ).expressionString() );
241 break;
242 }
243 }
244 else
245 {
246 properties << tr( "Extrusion: %1" ).arg( mExtrusionHeight );
247 }
248 }
249
250 if ( mEnableCustomTolerance )
251 {
252 properties << tr( "CustomTolerance: %1" ).arg( mCustomTolerance );
253 }
254
255 properties << tr( "Scale: %1" ).arg( mZScale );
256
257 return u"<li>%1</li>"_s.arg( properties.join( "</li><li>"_L1 ) );
258}
259
261{
262 // TODO -- test actual layer z range
263 return true;
264}
265
267{
268 // TODO -- determine actual z range from layer statistics
269 return QgsDoubleRange();
270}
271
273{
274 // show by default if the features aren't just directly clamped onto the terrain with
275 // no other changes
276 return !qgsDoubleNear( mZOffset, 0 ) || !qgsDoubleNear( mZScale, 1 ) || mEnableExtrusion || mClamping != Qgis::AltitudeClamping::Terrain;
277}
278
280{
281 if ( mClamping == clamping )
282 return;
283
284 mClamping = clamping;
285 emit changed();
287}
288
290{
291 if ( mBinding == binding )
292 return;
293
294 mBinding = binding;
295 emit changed();
297}
298
300{
301 if ( type == mType )
302 return;
303
304 mType = type;
305 emit changed();
307}
308
310{
311 if ( mEnableExtrusion == enabled )
312 return;
313
314 mEnableExtrusion = enabled;
315 emit changed();
317}
318
320{
321 if ( mExtrusionHeight == height )
322 return;
323
324 mExtrusionHeight = height;
325 emit changed();
327}
328
330{
331 if ( mCustomTolerance == tolerance )
332 return;
333
334 mCustomTolerance = tolerance;
335 emit changed();
337}
338
340{
341 if ( mEnableCustomTolerance == enabled )
342 return;
343
344 mEnableCustomTolerance = enabled;
345 emit changed();
347}
348
350{
351 if ( mRespectLayerSymbology == enabled )
352 return;
353
354 mRespectLayerSymbology = enabled;
355 emit changed();
357}
358
360{
361 return mProfileLineSymbol.get();
362}
363
365{
366 mProfileLineSymbol.reset( symbol );
367 emit changed();
369}
370
372{
373 return mProfileFillSymbol.get();
374}
375
377{
378 mProfileFillSymbol.reset( symbol );
379 emit changed();
381}
382
384{
385 return mProfileMarkerSymbol.get();
386}
387
389{
390 mProfileMarkerSymbol.reset( symbol );
391 emit changed();
393}
394
396{
397 if ( mSymbology == symbology )
398 return;
399
400 mSymbology = symbology;
401 emit changed();
403}
404
406{
407 return mElevationLimit;
408}
409
411{
412 if ( qgsDoubleNear( mElevationLimit, limit ) )
413 return;
414
415 mElevationLimit = limit;
416 emit changed();
418}
419
421{
422 if ( show == mShowMarkerSymbolInSurfacePlots )
423 return;
424
425 mShowMarkerSymbolInSurfacePlots = show;
426 emit changed();
428}
429
430void QgsVectorLayerElevationProperties::setDefaultProfileLineSymbol( const QColor &color )
431{
432 auto profileLineLayer = std::make_unique< QgsSimpleLineSymbolLayer >( color, 0.6 );
433 mProfileLineSymbol = std::make_unique< QgsLineSymbol>( QgsSymbolLayerList( { profileLineLayer.release() } ) );
434}
435
436void QgsVectorLayerElevationProperties::setDefaultProfileMarkerSymbol( const QColor &color )
437{
438 auto profileMarkerLayer = std::make_unique< QgsSimpleMarkerSymbolLayer >( Qgis::MarkerShape::Diamond, 3 );
439 profileMarkerLayer->setColor( color );
440 profileMarkerLayer->setStrokeWidth( 0.2 );
441 profileMarkerLayer->setStrokeColor( color.darker( 140 ) );
442 mProfileMarkerSymbol = std::make_unique< QgsMarkerSymbol>( QgsSymbolLayerList( { profileMarkerLayer.release() } ) );
443}
444
445void QgsVectorLayerElevationProperties::setDefaultProfileFillSymbol( const QColor &color )
446{
447 auto profileFillLayer = std::make_unique< QgsSimpleFillSymbolLayer >( color );
448 profileFillLayer->setStrokeWidth( 0.2 );
449 profileFillLayer->setStrokeColor( color.darker( 140 ) );
450 mProfileFillSymbol = std::make_unique< QgsFillSymbol>( QgsSymbolLayerList( { profileFillLayer.release() } ) );
451}
AltitudeClamping
Altitude clamping.
Definition qgis.h:4099
@ Relative
Elevation is relative to terrain height (final elevation = terrain elevation + feature elevation).
Definition qgis.h:4101
@ Terrain
Elevation is clamped to terrain (final elevation = terrain elevation).
Definition qgis.h:4102
@ Absolute
Elevation is taken directly from feature and is independent of terrain height (final elevation = feat...
Definition qgis.h:4100
@ Invalid
Invalid (not set) property.
Definition qgis.h:709
@ Field
Field based property.
Definition qgis.h:711
@ Static
Static property.
Definition qgis.h:710
@ Expression
Expression based property.
Definition qgis.h:712
@ Diamond
Diamond.
Definition qgis.h:3196
@ Point
Points.
Definition qgis.h:380
AltitudeBinding
Altitude binding.
Definition qgis.h:4112
@ Centroid
Clamp just centroid of feature.
Definition qgis.h:4114
VectorProfileType
Types of elevation profiles to generate for vector sources.
Definition qgis.h:4335
@ IndividualFeatures
Treat each feature as an individual object (eg buildings).
Definition qgis.h:4336
ProfileSurfaceSymbology
Surface symbology type for elevation profile plots.
Definition qgis.h:4322
@ Line
The elevation surface will be rendered using a line symbol.
Definition qgis.h:4323
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:217
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:83
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:7176
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
Definition qgis.h:6893
QString qgsEnumValueToKey(const T &value, bool *returnOk=nullptr)
Returns the value for the given key of an enum.
Definition qgis.h:7157
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference).
Definition qgis.h:6975
QList< QgsSymbolLayer * > QgsSymbolLayerList
Definition qgssymbol.h:30