QGIS API Documentation 3.41.0-Master (3440c17df1d)
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 "moc_qgsmeshlayerelevationproperties.cpp"
20#include "qgsmeshlayer.h"
21#include "qgslinesymbol.h"
22#include "qgsfillsymbol.h"
23#include "qgssymbollayerutils.h"
24#include "qgslinesymbollayer.h"
25#include "qgsfillsymbollayer.h"
26#include "qgsapplication.h"
28
31{
33 setDefaultProfileLineSymbol( color );
34 setDefaultProfileFillSymbol( color );
35}
36
38
40{
41 return true;
42}
43
44QDomElement QgsMeshLayerElevationProperties::writeXml( QDomElement &parentElement, QDomDocument &document, const QgsReadWriteContext &context )
45{
46 QDomElement element = document.createElement( QStringLiteral( "elevation" ) );
47 element.setAttribute( QStringLiteral( "mode" ), qgsEnumValueToKey( mMode ) );
48 element.setAttribute( QStringLiteral( "symbology" ), qgsEnumValueToKey( mSymbology ) );
49 if ( !std::isnan( mElevationLimit ) )
50 element.setAttribute( QStringLiteral( "elevationLimit" ), qgsDoubleToString( mElevationLimit ) );
51
52 writeCommonProperties( element, document, context );
53
54 switch ( mMode )
55 {
57 element.setAttribute( QStringLiteral( "lower" ), qgsDoubleToString( mFixedRange.lower() ) );
58 element.setAttribute( QStringLiteral( "upper" ), qgsDoubleToString( mFixedRange.upper() ) );
59 element.setAttribute( QStringLiteral( "includeLower" ), mFixedRange.includeLower() ? "1" : "0" );
60 element.setAttribute( QStringLiteral( "includeUpper" ), mFixedRange.includeUpper() ? "1" : "0" );
61 break;
62
64 {
65 QDomElement ranges = document.createElement( QStringLiteral( "ranges" ) );
66 for ( auto it = mRangePerGroup.constBegin(); it != mRangePerGroup.constEnd(); ++it )
67 {
68 QDomElement range = document.createElement( QStringLiteral( "range" ) );
69 range.setAttribute( QStringLiteral( "group" ), it.key() );
70 range.setAttribute( QStringLiteral( "lower" ), qgsDoubleToString( it.value().lower() ) );
71 range.setAttribute( QStringLiteral( "upper" ), qgsDoubleToString( it.value().upper() ) );
72 range.setAttribute( QStringLiteral( "includeLower" ), it.value().includeLower() ? "1" : "0" );
73 range.setAttribute( QStringLiteral( "includeUpper" ), it.value().includeUpper() ? "1" : "0" );
74 ranges.appendChild( range );
75 }
76 element.appendChild( ranges );
77 break;
78 }
79
81 break;
82 }
83
84 QDomElement profileLineSymbolElement = document.createElement( QStringLiteral( "profileLineSymbol" ) );
85 profileLineSymbolElement.appendChild( QgsSymbolLayerUtils::saveSymbol( QString(), mProfileLineSymbol.get(), document, context ) );
86 element.appendChild( profileLineSymbolElement );
87
88 QDomElement profileFillSymbolElement = document.createElement( QStringLiteral( "profileFillSymbol" ) );
89 profileFillSymbolElement.appendChild( QgsSymbolLayerUtils::saveSymbol( QString(), mProfileFillSymbol.get(), document, context ) );
90 element.appendChild( profileFillSymbolElement );
91
92 parentElement.appendChild( element );
93 return element;
94}
95
96bool QgsMeshLayerElevationProperties::readXml( const QDomElement &element, const QgsReadWriteContext &context )
97{
98 const QDomElement elevationElement = element.firstChildElement( QStringLiteral( "elevation" ) ).toElement();
99 mMode = qgsEnumKeyToValue( elevationElement.attribute( QStringLiteral( "mode" ) ), Qgis::MeshElevationMode::FromVertices );
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 readCommonProperties( elevationElement, context );
107
108 switch ( mMode )
109 {
111 {
112 const double lower = elevationElement.attribute( QStringLiteral( "lower" ) ).toDouble();
113 const double upper = elevationElement.attribute( QStringLiteral( "upper" ) ).toDouble();
114 const bool includeLower = elevationElement.attribute( QStringLiteral( "includeLower" ) ).toInt();
115 const bool includeUpper = elevationElement.attribute( QStringLiteral( "includeUpper" ) ).toInt();
116 mFixedRange = QgsDoubleRange( lower, upper, includeLower, includeUpper );
117 break;
118 }
119
121 {
122 mRangePerGroup.clear();
123
124 const QDomNodeList ranges = elevationElement.firstChildElement( QStringLiteral( "ranges" ) ).childNodes();
125 for ( int i = 0; i < ranges.size(); ++i )
126 {
127 const QDomElement rangeElement = ranges.at( i ).toElement();
128 const int group = rangeElement.attribute( QStringLiteral( "group" ) ).toInt();
129 const double lower = rangeElement.attribute( QStringLiteral( "lower" ) ).toDouble();
130 const double upper = rangeElement.attribute( QStringLiteral( "upper" ) ).toDouble();
131 const bool includeLower = rangeElement.attribute( QStringLiteral( "includeLower" ) ).toInt();
132 const bool includeUpper = rangeElement.attribute( QStringLiteral( "includeUpper" ) ).toInt();
133 mRangePerGroup.insert( group, QgsDoubleRange( lower, upper, includeLower, includeUpper ) );
134 }
135 break;
136 }
137
139 break;
140 }
141
142 const QColor defaultColor = QgsApplication::colorSchemeRegistry()->fetchRandomStyleColor();
143
144 const QDomElement profileLineSymbolElement = elevationElement.firstChildElement( QStringLiteral( "profileLineSymbol" ) ).firstChildElement( QStringLiteral( "symbol" ) );
145 mProfileLineSymbol.reset( QgsSymbolLayerUtils::loadSymbol< QgsLineSymbol >( profileLineSymbolElement, context ) );
146 if ( !mProfileLineSymbol )
147 setDefaultProfileLineSymbol( defaultColor );
148
149 const QDomElement profileFillSymbolElement = elevationElement.firstChildElement( QStringLiteral( "profileFillSymbol" ) ).firstChildElement( QStringLiteral( "symbol" ) );
150 mProfileFillSymbol.reset( QgsSymbolLayerUtils::loadSymbol< QgsFillSymbol >( profileFillSymbolElement, context ) );
151 if ( !mProfileFillSymbol )
152 setDefaultProfileFillSymbol( defaultColor );
153
154 return true;
155}
156
158{
159 QStringList properties;
160 switch ( mMode )
161 {
163 properties << tr( "Elevation range: %1 to %2" ).arg( mFixedRange.lower() ).arg( mFixedRange.upper() );
164 break;
165
167 {
168 for ( auto it = mRangePerGroup.constBegin(); it != mRangePerGroup.constEnd(); ++it )
169 {
170 properties << tr( "Elevation for group %1: %2 to %3" ).arg( it.key() ).arg( it.value().lower() ).arg( it.value().upper() );
171 }
172 break;
173 }
174
176 properties << tr( "Scale: %1" ).arg( mZScale );
177 properties << tr( "Offset: %1" ).arg( mZOffset );
178 break;
179 }
180 return QStringLiteral( "<li>%1</li>" ).arg( properties.join( QLatin1String( "</li><li>" ) ) );
181}
182
184{
185 std::unique_ptr< QgsMeshLayerElevationProperties > res = std::make_unique< QgsMeshLayerElevationProperties >( nullptr );
186 res->setMode( mMode );
187 res->setProfileLineSymbol( mProfileLineSymbol->clone() );
188 res->setProfileFillSymbol( mProfileFillSymbol->clone() );
189 res->setProfileSymbology( mSymbology );
190 res->setElevationLimit( mElevationLimit );
191 res->setFixedRange( mFixedRange );
192 res->setFixedRangePerGroup( mRangePerGroup );
193 res->copyCommonProperties( this );
194 return res.release();
195}
196
198{
199 switch ( mMode )
200 {
202 return mFixedRange.overlaps( range );
203
205 {
206 for ( auto it = mRangePerGroup.constBegin(); it != mRangePerGroup.constEnd(); ++it )
207 {
208 if ( it.value().overlaps( range ) )
209 return true;
210 }
211 return false;
212 }
213
215 // TODO -- test actual mesh z range
216 return true;
217 }
219}
220
222{
223 switch ( mMode )
224 {
226 return mFixedRange;
227
229 {
230 double lower = std::numeric_limits< double >::max();
231 double upper = std::numeric_limits< double >::min();
232 bool includeLower = true;
233 bool includeUpper = true;
234 for ( auto it = mRangePerGroup.constBegin(); it != mRangePerGroup.constEnd(); ++it )
235 {
236 if ( it.value().lower() < lower )
237 {
238 lower = it.value().lower();
239 includeLower = it.value().includeLower();
240 }
241 else if ( !includeLower && it.value().lower() == lower && it.value().includeLower() )
242 {
243 includeLower = true;
244 }
245 if ( it.value().upper() > upper )
246 {
247 upper = it.value().upper();
248 includeUpper = it.value().includeUpper();
249 }
250 else if ( !includeUpper && it.value().upper() == upper && it.value().includeUpper() )
251 {
252 includeUpper = true;
253 }
254 }
255 return QgsDoubleRange( lower, upper, includeLower, includeUpper );
256 }
257
259 // TODO -- determine actual z range from mesh statistics
260 return QgsDoubleRange();
261 }
263}
264
266{
267 switch ( mMode )
268 {
270 {
271 if ( !mFixedRange.isInfinite() && mFixedRange.lower() != mFixedRange.upper() )
272 return { mFixedRange.lower(), mFixedRange.upper() };
273 else if ( !mFixedRange.isInfinite() )
274 return { mFixedRange.lower() };
275
276 return {};
277 }
278
280 {
281 QList< double > res;
282 for ( auto it = mRangePerGroup.constBegin(); it != mRangePerGroup.constEnd(); ++it )
283 {
284 if ( it.value().isInfinite() )
285 continue;
286
287 if ( !res.contains( it.value().lower( ) ) )
288 res.append( it.value().lower() );
289 if ( !res.contains( it.value().upper( ) ) )
290 res.append( it.value().upper() );
291 }
292 std::sort( res.begin(), res.end() );
293 return res;
294 }
295
297 return {};
298 }
300}
301
306
320
325
327{
328 if ( mMode == mode )
329 return;
330
331 mMode = mode;
332 emit changed();
333}
334
336{
337 return mFixedRange;
338}
339
341{
342 if ( range == mFixedRange )
343 return;
344
345 mFixedRange = range;
346 emit changed();
347}
348
350{
351 return mRangePerGroup;
352}
353
354void QgsMeshLayerElevationProperties::setFixedRangePerGroup( const QMap<int, QgsDoubleRange> &ranges )
355{
356 if ( ranges == mRangePerGroup )
357 return;
358
359 mRangePerGroup = ranges;
360 emit changed();
361}
362
364{
365 return mProfileLineSymbol.get();
366}
367
369{
370 mProfileLineSymbol.reset( symbol );
371 emit changed();
373}
374
376{
377 return mProfileFillSymbol.get();
378}
379
381{
382 mProfileFillSymbol.reset( symbol );
383 emit changed();
385}
386
388{
389 if ( mSymbology == symbology )
390 return;
391
392 mSymbology = symbology;
393 emit changed();
395}
396
398{
399 return mElevationLimit;
400}
401
403{
404 if ( qgsDoubleNear( mElevationLimit, limit ) )
405 return;
406
407 mElevationLimit = limit;
408 emit changed();
410}
411
412void QgsMeshLayerElevationProperties::setDefaultProfileLineSymbol( const QColor &color )
413{
414 std::unique_ptr< QgsSimpleLineSymbolLayer > profileLineLayer = std::make_unique< QgsSimpleLineSymbolLayer >( color, 0.6 );
415 mProfileLineSymbol = std::make_unique< QgsLineSymbol>( QgsSymbolLayerList( { profileLineLayer.release() } ) );
416}
417
418void QgsMeshLayerElevationProperties::setDefaultProfileFillSymbol( const QColor &color )
419{
420 std::unique_ptr< QgsSimpleFillSymbolLayer > profileFillLayer = std::make_unique< QgsSimpleFillSymbolLayer >( color );
421 profileFillLayer->setStrokeStyle( Qt::NoPen );
422 mProfileFillSymbol = std::make_unique< QgsFillSymbol>( QgsSymbolLayerList( { profileFillLayer.release() } ) );
423}
MeshElevationMode
Mesh layer elevation modes.
Definition qgis.h:3752
@ 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:3897
@ 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:76
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:6168
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
Definition qgis.h:5875
QString qgsEnumValueToKey(const T &value, bool *returnOk=nullptr)
Returns the value for the given key of an enum.
Definition qgis.h:6149
#define BUILTIN_UNREACHABLE
Definition qgis.h:6612
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition qgis.h:5958
QList< QgsSymbolLayer * > QgsSymbolLayerList
Definition qgssymbol.h:30