QGIS API Documentation 3.39.0-Master (47f7b3a4989)
Loading...
Searching...
No Matches
qgsmeshlayerelevationproperties.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsmeshlayerelevationproperties.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 "qgsmeshlayer.h"
20#include "qgslinesymbol.h"
21#include "qgsfillsymbol.h"
22#include "qgssymbollayerutils.h"
23#include "qgslinesymbollayer.h"
24#include "qgsfillsymbollayer.h"
25#include "qgsapplication.h"
27
30{
32 setDefaultProfileLineSymbol( color );
33 setDefaultProfileFillSymbol( color );
34}
35
37
39{
40 return true;
41}
42
43QDomElement QgsMeshLayerElevationProperties::writeXml( QDomElement &parentElement, QDomDocument &document, const QgsReadWriteContext &context )
44{
45 QDomElement element = document.createElement( QStringLiteral( "elevation" ) );
46 element.setAttribute( QStringLiteral( "mode" ), qgsEnumValueToKey( mMode ) );
47 element.setAttribute( QStringLiteral( "symbology" ), qgsEnumValueToKey( mSymbology ) );
48 if ( !std::isnan( mElevationLimit ) )
49 element.setAttribute( QStringLiteral( "elevationLimit" ), qgsDoubleToString( mElevationLimit ) );
50
51 writeCommonProperties( element, document, context );
52
53 switch ( mMode )
54 {
56 element.setAttribute( QStringLiteral( "lower" ), qgsDoubleToString( mFixedRange.lower() ) );
57 element.setAttribute( QStringLiteral( "upper" ), qgsDoubleToString( mFixedRange.upper() ) );
58 element.setAttribute( QStringLiteral( "includeLower" ), mFixedRange.includeLower() ? "1" : "0" );
59 element.setAttribute( QStringLiteral( "includeUpper" ), mFixedRange.includeUpper() ? "1" : "0" );
60 break;
61
63 {
64 QDomElement ranges = document.createElement( QStringLiteral( "ranges" ) );
65 for ( auto it = mRangePerGroup.constBegin(); it != mRangePerGroup.constEnd(); ++it )
66 {
67 QDomElement range = document.createElement( QStringLiteral( "range" ) );
68 range.setAttribute( QStringLiteral( "group" ), it.key() );
69 range.setAttribute( QStringLiteral( "lower" ), qgsDoubleToString( it.value().lower() ) );
70 range.setAttribute( QStringLiteral( "upper" ), qgsDoubleToString( it.value().upper() ) );
71 range.setAttribute( QStringLiteral( "includeLower" ), it.value().includeLower() ? "1" : "0" );
72 range.setAttribute( QStringLiteral( "includeUpper" ), it.value().includeUpper() ? "1" : "0" );
73 ranges.appendChild( range );
74 }
75 element.appendChild( ranges );
76 break;
77 }
78
80 break;
81 }
82
83 QDomElement profileLineSymbolElement = document.createElement( QStringLiteral( "profileLineSymbol" ) );
84 profileLineSymbolElement.appendChild( QgsSymbolLayerUtils::saveSymbol( QString(), mProfileLineSymbol.get(), document, context ) );
85 element.appendChild( profileLineSymbolElement );
86
87 QDomElement profileFillSymbolElement = document.createElement( QStringLiteral( "profileFillSymbol" ) );
88 profileFillSymbolElement.appendChild( QgsSymbolLayerUtils::saveSymbol( QString(), mProfileFillSymbol.get(), document, context ) );
89 element.appendChild( profileFillSymbolElement );
90
91 parentElement.appendChild( element );
92 return element;
93}
94
95bool QgsMeshLayerElevationProperties::readXml( const QDomElement &element, const QgsReadWriteContext &context )
96{
97 const QDomElement elevationElement = element.firstChildElement( QStringLiteral( "elevation" ) ).toElement();
98 mMode = qgsEnumKeyToValue( elevationElement.attribute( QStringLiteral( "mode" ) ), Qgis::MeshElevationMode::FromVertices );
99 mSymbology = qgsEnumKeyToValue( elevationElement.attribute( QStringLiteral( "symbology" ) ), Qgis::ProfileSurfaceSymbology::Line );
100 if ( elevationElement.hasAttribute( QStringLiteral( "elevationLimit" ) ) )
101 mElevationLimit = elevationElement.attribute( QStringLiteral( "elevationLimit" ) ).toDouble();
102 else
103 mElevationLimit = std::numeric_limits< double >::quiet_NaN();
104
105 readCommonProperties( elevationElement, context );
106
107 switch ( mMode )
108 {
110 {
111 const double lower = elevationElement.attribute( QStringLiteral( "lower" ) ).toDouble();
112 const double upper = elevationElement.attribute( QStringLiteral( "upper" ) ).toDouble();
113 const bool includeLower = elevationElement.attribute( QStringLiteral( "includeLower" ) ).toInt();
114 const bool includeUpper = elevationElement.attribute( QStringLiteral( "includeUpper" ) ).toInt();
115 mFixedRange = QgsDoubleRange( lower, upper, includeLower, includeUpper );
116 break;
117 }
118
120 {
121 mRangePerGroup.clear();
122
123 const QDomNodeList ranges = elevationElement.firstChildElement( QStringLiteral( "ranges" ) ).childNodes();
124 for ( int i = 0; i < ranges.size(); ++i )
125 {
126 const QDomElement rangeElement = ranges.at( i ).toElement();
127 const int group = rangeElement.attribute( QStringLiteral( "group" ) ).toInt();
128 const double lower = rangeElement.attribute( QStringLiteral( "lower" ) ).toDouble();
129 const double upper = rangeElement.attribute( QStringLiteral( "upper" ) ).toDouble();
130 const bool includeLower = rangeElement.attribute( QStringLiteral( "includeLower" ) ).toInt();
131 const bool includeUpper = rangeElement.attribute( QStringLiteral( "includeUpper" ) ).toInt();
132 mRangePerGroup.insert( group, QgsDoubleRange( lower, upper, includeLower, includeUpper ) );
133 }
134 break;
135 }
136
138 break;
139 }
140
141 const QColor defaultColor = QgsApplication::colorSchemeRegistry()->fetchRandomStyleColor();
142
143 const QDomElement profileLineSymbolElement = elevationElement.firstChildElement( QStringLiteral( "profileLineSymbol" ) ).firstChildElement( QStringLiteral( "symbol" ) );
144 mProfileLineSymbol.reset( QgsSymbolLayerUtils::loadSymbol< QgsLineSymbol >( profileLineSymbolElement, context ) );
145 if ( !mProfileLineSymbol )
146 setDefaultProfileLineSymbol( defaultColor );
147
148 const QDomElement profileFillSymbolElement = elevationElement.firstChildElement( QStringLiteral( "profileFillSymbol" ) ).firstChildElement( QStringLiteral( "symbol" ) );
149 mProfileFillSymbol.reset( QgsSymbolLayerUtils::loadSymbol< QgsFillSymbol >( profileFillSymbolElement, context ) );
150 if ( !mProfileFillSymbol )
151 setDefaultProfileFillSymbol( defaultColor );
152
153 return true;
154}
155
157{
158 QStringList properties;
159 switch ( mMode )
160 {
162 properties << tr( "Elevation range: %1 to %2" ).arg( mFixedRange.lower() ).arg( mFixedRange.upper() );
163 break;
164
166 {
167 for ( auto it = mRangePerGroup.constBegin(); it != mRangePerGroup.constEnd(); ++it )
168 {
169 properties << tr( "Elevation for group %1: %2 to %3" ).arg( it.key() ).arg( it.value().lower() ).arg( it.value().upper() );
170 }
171 break;
172 }
173
175 properties << tr( "Scale: %1" ).arg( mZScale );
176 properties << tr( "Offset: %1" ).arg( mZOffset );
177 break;
178 }
179 return QStringLiteral( "<li>%1</li>" ).arg( properties.join( QLatin1String( "</li><li>" ) ) );
180}
181
183{
184 std::unique_ptr< QgsMeshLayerElevationProperties > res = std::make_unique< QgsMeshLayerElevationProperties >( nullptr );
185 res->setMode( mMode );
186 res->setProfileLineSymbol( mProfileLineSymbol->clone() );
187 res->setProfileFillSymbol( mProfileFillSymbol->clone() );
188 res->setProfileSymbology( mSymbology );
189 res->setElevationLimit( mElevationLimit );
190 res->setFixedRange( mFixedRange );
191 res->setFixedRangePerGroup( mRangePerGroup );
192 res->copyCommonProperties( this );
193 return res.release();
194}
195
197{
198 switch ( mMode )
199 {
201 return mFixedRange.overlaps( range );
202
204 {
205 for ( auto it = mRangePerGroup.constBegin(); it != mRangePerGroup.constEnd(); ++it )
206 {
207 if ( it.value().overlaps( range ) )
208 return true;
209 }
210 return false;
211 }
212
214 // TODO -- test actual mesh z range
215 return true;
216 }
218}
219
221{
222 switch ( mMode )
223 {
225 return mFixedRange;
226
228 {
229 double lower = std::numeric_limits< double >::max();
230 double upper = std::numeric_limits< double >::min();
231 bool includeLower = true;
232 bool includeUpper = true;
233 for ( auto it = mRangePerGroup.constBegin(); it != mRangePerGroup.constEnd(); ++it )
234 {
235 if ( it.value().lower() < lower )
236 {
237 lower = it.value().lower();
238 includeLower = it.value().includeLower();
239 }
240 else if ( !includeLower && it.value().lower() == lower && it.value().includeLower() )
241 {
242 includeLower = true;
243 }
244 if ( it.value().upper() > upper )
245 {
246 upper = it.value().upper();
247 includeUpper = it.value().includeUpper();
248 }
249 else if ( !includeUpper && it.value().upper() == upper && it.value().includeUpper() )
250 {
251 includeUpper = true;
252 }
253 }
254 return QgsDoubleRange( lower, upper, includeLower, includeUpper );
255 }
256
258 // TODO -- determine actual z range from mesh statistics
259 return QgsDoubleRange();
260 }
262}
263
265{
266 switch ( mMode )
267 {
269 {
270 if ( !mFixedRange.isInfinite() && mFixedRange.lower() != mFixedRange.upper() )
271 return { mFixedRange.lower(), mFixedRange.upper() };
272 else if ( !mFixedRange.isInfinite() )
273 return { mFixedRange.lower() };
274
275 return {};
276 }
277
279 {
280 QList< double > res;
281 for ( auto it = mRangePerGroup.constBegin(); it != mRangePerGroup.constEnd(); ++it )
282 {
283 if ( it.value().isInfinite() )
284 continue;
285
286 if ( !res.contains( it.value().lower( ) ) )
287 res.append( it.value().lower() );
288 if ( !res.contains( it.value().upper( ) ) )
289 res.append( it.value().upper() );
290 }
291 std::sort( res.begin(), res.end() );
292 return res;
293 }
294
296 return {};
297 }
299}
300
305
319
324
326{
327 if ( mMode == mode )
328 return;
329
330 mMode = mode;
331 emit changed();
332}
333
335{
336 return mFixedRange;
337}
338
340{
341 if ( range == mFixedRange )
342 return;
343
344 mFixedRange = range;
345 emit changed();
346}
347
349{
350 return mRangePerGroup;
351}
352
353void QgsMeshLayerElevationProperties::setFixedRangePerGroup( const QMap<int, QgsDoubleRange> &ranges )
354{
355 if ( ranges == mRangePerGroup )
356 return;
357
358 mRangePerGroup = ranges;
359 emit changed();
360}
361
363{
364 return mProfileLineSymbol.get();
365}
366
368{
369 mProfileLineSymbol.reset( symbol );
370 emit changed();
372}
373
375{
376 return mProfileFillSymbol.get();
377}
378
380{
381 mProfileFillSymbol.reset( symbol );
382 emit changed();
384}
385
387{
388 if ( mSymbology == symbology )
389 return;
390
391 mSymbology = symbology;
392 emit changed();
394}
395
397{
398 return mElevationLimit;
399}
400
402{
403 if ( qgsDoubleNear( mElevationLimit, limit ) )
404 return;
405
406 mElevationLimit = limit;
407 emit changed();
409}
410
411void QgsMeshLayerElevationProperties::setDefaultProfileLineSymbol( const QColor &color )
412{
413 std::unique_ptr< QgsSimpleLineSymbolLayer > profileLineLayer = std::make_unique< QgsSimpleLineSymbolLayer >( color, 0.6 );
414 mProfileLineSymbol = std::make_unique< QgsLineSymbol>( QgsSymbolLayerList( { profileLineLayer.release() } ) );
415}
416
417void QgsMeshLayerElevationProperties::setDefaultProfileFillSymbol( const QColor &color )
418{
419 std::unique_ptr< QgsSimpleFillSymbolLayer > profileFillLayer = std::make_unique< QgsSimpleFillSymbolLayer >( color );
420 profileFillLayer->setStrokeStyle( Qt::NoPen );
421 mProfileFillSymbol = std::make_unique< QgsFillSymbol>( QgsSymbolLayerList( { profileFillLayer.release() } ) );
422}
MeshElevationMode
Mesh layer elevation modes.
Definition qgis.h:3461
@ FromVertices
Elevation should be taken from mesh vertices.
@ FixedRangePerGroup
Layer has a fixed (manually specified) elevation range per group.
@ FixedElevationRange
Layer has a fixed elevation range.
ProfileSurfaceSymbology
Surface symbology type for elevation profile plots.
Definition qgis.h:3606
@ 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
bool isInfinite() const
Returns true if the range consists of all possible values.
Definition qgsrange.h:285
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.
void writeCommonProperties(QDomElement &element, QDomDocument &doc, const QgsReadWriteContext &context)
Writes common class properties to a DOM element, to be used later with readXml().
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...
@ FlagDontInvalidateCachedRendersWhenRangeChanges
Any cached rendering will not be invalidated when z range context is modified.
Base class for all map layer types.
Definition qgsmaplayer.h:75
Mesh layer specific subclass of QgsMapLayerElevationProperties.
QDomElement writeXml(QDomElement &element, QDomDocument &doc, const QgsReadWriteContext &context) override
Writes the properties to a DOM element, to be used later with readXml().
QgsLineSymbol * profileLineSymbol() const
Returns the line symbol used to render the mesh profile in elevation profile plots.
QgsDoubleRange fixedRange() const
Returns the fixed elevation range for the mesh.
bool hasElevation() const override
Returns true if the layer has an elevation or z component.
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.
Qgis::MeshElevationMode mode() const
Returns the elevation mode.
void setFixedRangePerGroup(const QMap< int, QgsDoubleRange > &ranges)
Sets the fixed elevation range for each group.
QgsMeshLayerElevationProperties * clone() const override
Creates a clone of the properties.
void setElevationLimit(double limit)
Sets the elevation limit, which is used when profileSymbology() is Qgis::ProfileSurfaceSymbology::Fil...
QList< double > significantZValues(QgsMapLayer *layer) const override
Returns a list of significant elevation/z-values for the specified layer, using the settings defined ...
QgsFillSymbol * profileFillSymbol() const
Returns the fill symbol used to render the mesh profile in elevation profile plots.
void setProfileSymbology(Qgis::ProfileSurfaceSymbology symbology)
Sets the symbology option used to render the mesh profile in elevation profile plots.
void setProfileFillSymbol(QgsFillSymbol *symbol)
Sets the fill symbol used to render the mesh profile in elevation profile plots.
void setProfileLineSymbol(QgsLineSymbol *symbol)
Sets the line symbol used to render the mesh profile in elevation profile plots.
QgsMeshLayerElevationProperties(QObject *parent)
Constructor for QgsMeshLayerElevationProperties, with the specified parent object.
void setMode(Qgis::MeshElevationMode mode)
Sets the elevation mode.
QMap< int, QgsDoubleRange > fixedRangePerGroup() const
Returns the fixed elevation range for each group.
QString htmlSummary() const override
Returns a HTML formatted summary of the properties.
QgsMapLayerElevationProperties::Flags flags() const override
Returns flags associated to the elevation properties.
void setFixedRange(const QgsDoubleRange &range)
Sets the fixed elevation range for the mesh.
bool showByDefaultInElevationProfilePlots() const override
Returns true if the layer should be visible by default in newly created elevation profile plots.
bool readXml(const QDomElement &element, const QgsReadWriteContext &context) override
Reads the elevation properties from a DOM element previously written by writeXml().
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...
bool includeUpper() const
Returns true if the upper bound is inclusive, or false if the upper bound is exclusive.
Definition qgsrange.h:101
bool overlaps(const QgsRange< T > &other) const
Returns true if this range overlaps another range.
Definition qgsrange.h:176
T lower() const
Returns the lower bound of the range.
Definition qgsrange.h:78
bool includeLower() const
Returns true if the lower bound is inclusive, or false if the lower bound is exclusive.
Definition qgsrange.h:93
T upper() const
Returns the upper bound of the range.
Definition qgsrange.h:85
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.
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:5675
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
Definition qgis.h:5382
QString qgsEnumValueToKey(const T &value, bool *returnOk=nullptr)
Returns the value for the given key of an enum.
Definition qgis.h:5656
#define BUILTIN_UNREACHABLE
Definition qgis.h:6119
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition qgis.h:5465
QList< QgsSymbolLayer * > QgsSymbolLayerList
Definition qgssymbol.h:30