QGIS API Documentation 3.99.0-Master (21b3aa880ba)
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
20#include "qgsapplication.h"
22#include "qgsfillsymbol.h"
23#include "qgsfillsymbollayer.h"
24#include "qgslinesymbol.h"
25#include "qgslinesymbollayer.h"
26#include "qgsmeshlayer.h"
27#include "qgssymbollayerutils.h"
28
29#include "moc_qgsmeshlayerelevationproperties.cpp"
30
33{
35 setDefaultProfileLineSymbol( color );
36 setDefaultProfileFillSymbol( color );
37}
38
40
42{
43 return true;
44}
45
46QDomElement QgsMeshLayerElevationProperties::writeXml( QDomElement &parentElement, QDomDocument &document, const QgsReadWriteContext &context )
47{
48 QDomElement element = document.createElement( QStringLiteral( "elevation" ) );
49 element.setAttribute( QStringLiteral( "mode" ), qgsEnumValueToKey( mMode ) );
50 element.setAttribute( QStringLiteral( "symbology" ), qgsEnumValueToKey( mSymbology ) );
51 if ( !std::isnan( mElevationLimit ) )
52 element.setAttribute( QStringLiteral( "elevationLimit" ), qgsDoubleToString( mElevationLimit ) );
53
54 writeCommonProperties( element, document, context );
55
56 switch ( mMode )
57 {
59 element.setAttribute( QStringLiteral( "lower" ), qgsDoubleToString( mFixedRange.lower() ) );
60 element.setAttribute( QStringLiteral( "upper" ), qgsDoubleToString( mFixedRange.upper() ) );
61 element.setAttribute( QStringLiteral( "includeLower" ), mFixedRange.includeLower() ? "1" : "0" );
62 element.setAttribute( QStringLiteral( "includeUpper" ), mFixedRange.includeUpper() ? "1" : "0" );
63 break;
64
66 {
67 QDomElement ranges = document.createElement( QStringLiteral( "ranges" ) );
68 for ( auto it = mRangePerGroup.constBegin(); it != mRangePerGroup.constEnd(); ++it )
69 {
70 QDomElement range = document.createElement( QStringLiteral( "range" ) );
71 range.setAttribute( QStringLiteral( "group" ), it.key() );
72 range.setAttribute( QStringLiteral( "lower" ), qgsDoubleToString( it.value().lower() ) );
73 range.setAttribute( QStringLiteral( "upper" ), qgsDoubleToString( it.value().upper() ) );
74 range.setAttribute( QStringLiteral( "includeLower" ), it.value().includeLower() ? "1" : "0" );
75 range.setAttribute( QStringLiteral( "includeUpper" ), it.value().includeUpper() ? "1" : "0" );
76 ranges.appendChild( range );
77 }
78 element.appendChild( ranges );
79 break;
80 }
81
83 break;
84 }
85
86 QDomElement profileLineSymbolElement = document.createElement( QStringLiteral( "profileLineSymbol" ) );
87 profileLineSymbolElement.appendChild( QgsSymbolLayerUtils::saveSymbol( QString(), mProfileLineSymbol.get(), document, context ) );
88 element.appendChild( profileLineSymbolElement );
89
90 QDomElement profileFillSymbolElement = document.createElement( QStringLiteral( "profileFillSymbol" ) );
91 profileFillSymbolElement.appendChild( QgsSymbolLayerUtils::saveSymbol( QString(), mProfileFillSymbol.get(), document, context ) );
92 element.appendChild( profileFillSymbolElement );
93
94 parentElement.appendChild( element );
95 return element;
96}
97
98bool QgsMeshLayerElevationProperties::readXml( const QDomElement &element, const QgsReadWriteContext &context )
99{
100 const QDomElement elevationElement = element.firstChildElement( QStringLiteral( "elevation" ) ).toElement();
101 mMode = qgsEnumKeyToValue( elevationElement.attribute( QStringLiteral( "mode" ) ), Qgis::MeshElevationMode::FromVertices );
102 mSymbology = qgsEnumKeyToValue( elevationElement.attribute( QStringLiteral( "symbology" ) ), Qgis::ProfileSurfaceSymbology::Line );
103 if ( elevationElement.hasAttribute( QStringLiteral( "elevationLimit" ) ) )
104 mElevationLimit = elevationElement.attribute( QStringLiteral( "elevationLimit" ) ).toDouble();
105 else
106 mElevationLimit = std::numeric_limits< double >::quiet_NaN();
107
108 readCommonProperties( elevationElement, context );
109
110 switch ( mMode )
111 {
113 {
114 const double lower = elevationElement.attribute( QStringLiteral( "lower" ) ).toDouble();
115 const double upper = elevationElement.attribute( QStringLiteral( "upper" ) ).toDouble();
116 const bool includeLower = elevationElement.attribute( QStringLiteral( "includeLower" ) ).toInt();
117 const bool includeUpper = elevationElement.attribute( QStringLiteral( "includeUpper" ) ).toInt();
118 mFixedRange = QgsDoubleRange( lower, upper, includeLower, includeUpper );
119 break;
120 }
121
123 {
124 mRangePerGroup.clear();
125
126 const QDomNodeList ranges = elevationElement.firstChildElement( QStringLiteral( "ranges" ) ).childNodes();
127 for ( int i = 0; i < ranges.size(); ++i )
128 {
129 const QDomElement rangeElement = ranges.at( i ).toElement();
130 const int group = rangeElement.attribute( QStringLiteral( "group" ) ).toInt();
131 const double lower = rangeElement.attribute( QStringLiteral( "lower" ) ).toDouble();
132 const double upper = rangeElement.attribute( QStringLiteral( "upper" ) ).toDouble();
133 const bool includeLower = rangeElement.attribute( QStringLiteral( "includeLower" ) ).toInt();
134 const bool includeUpper = rangeElement.attribute( QStringLiteral( "includeUpper" ) ).toInt();
135 mRangePerGroup.insert( group, QgsDoubleRange( lower, upper, includeLower, includeUpper ) );
136 }
137 break;
138 }
139
141 break;
142 }
143
144 const QColor defaultColor = QgsApplication::colorSchemeRegistry()->fetchRandomStyleColor();
145
146 const QDomElement profileLineSymbolElement = elevationElement.firstChildElement( QStringLiteral( "profileLineSymbol" ) ).firstChildElement( QStringLiteral( "symbol" ) );
147 mProfileLineSymbol = QgsSymbolLayerUtils::loadSymbol< QgsLineSymbol >( profileLineSymbolElement, context );
148 if ( !mProfileLineSymbol )
149 setDefaultProfileLineSymbol( defaultColor );
150
151 const QDomElement profileFillSymbolElement = elevationElement.firstChildElement( QStringLiteral( "profileFillSymbol" ) ).firstChildElement( QStringLiteral( "symbol" ) );
152 mProfileFillSymbol = QgsSymbolLayerUtils::loadSymbol< QgsFillSymbol >( profileFillSymbolElement, context );
153 if ( !mProfileFillSymbol )
154 setDefaultProfileFillSymbol( defaultColor );
155
156 return true;
157}
158
160{
161 QStringList properties;
162 switch ( mMode )
163 {
165 properties << tr( "Elevation range: %1 to %2" ).arg( mFixedRange.lower() ).arg( mFixedRange.upper() );
166 break;
167
169 {
170 for ( auto it = mRangePerGroup.constBegin(); it != mRangePerGroup.constEnd(); ++it )
171 {
172 properties << tr( "Elevation for group %1: %2 to %3" ).arg( it.key() ).arg( it.value().lower() ).arg( it.value().upper() );
173 }
174 break;
175 }
176
178 properties << tr( "Scale: %1" ).arg( mZScale );
179 properties << tr( "Offset: %1" ).arg( mZOffset );
180 break;
181 }
182 return QStringLiteral( "<li>%1</li>" ).arg( properties.join( QLatin1String( "</li><li>" ) ) );
183}
184
186{
187 auto res = std::make_unique< QgsMeshLayerElevationProperties >( nullptr );
188 res->setMode( mMode );
189 res->setProfileLineSymbol( mProfileLineSymbol->clone() );
190 res->setProfileFillSymbol( mProfileFillSymbol->clone() );
191 res->setProfileSymbology( mSymbology );
192 res->setElevationLimit( mElevationLimit );
193 res->setFixedRange( mFixedRange );
194 res->setFixedRangePerGroup( mRangePerGroup );
195 res->copyCommonProperties( this );
196 return res.release();
197}
198
200{
201 switch ( mMode )
202 {
204 return mFixedRange.overlaps( range );
205
207 {
208 for ( auto it = mRangePerGroup.constBegin(); it != mRangePerGroup.constEnd(); ++it )
209 {
210 if ( it.value().overlaps( range ) )
211 return true;
212 }
213 return false;
214 }
215
217 // TODO -- test actual mesh z range
218 return true;
219 }
221}
222
224{
225 switch ( mMode )
226 {
228 return mFixedRange;
229
231 {
232 double lower = std::numeric_limits< double >::max();
233 double upper = std::numeric_limits< double >::min();
234 bool includeLower = true;
235 bool includeUpper = true;
236 for ( auto it = mRangePerGroup.constBegin(); it != mRangePerGroup.constEnd(); ++it )
237 {
238 if ( it.value().lower() < lower )
239 {
240 lower = it.value().lower();
241 includeLower = it.value().includeLower();
242 }
243 else if ( !includeLower && it.value().lower() == lower && it.value().includeLower() )
244 {
245 includeLower = true;
246 }
247 if ( it.value().upper() > upper )
248 {
249 upper = it.value().upper();
250 includeUpper = it.value().includeUpper();
251 }
252 else if ( !includeUpper && it.value().upper() == upper && it.value().includeUpper() )
253 {
254 includeUpper = true;
255 }
256 }
257 return QgsDoubleRange( lower, upper, includeLower, includeUpper );
258 }
259
261 // TODO -- determine actual z range from mesh statistics
262 return QgsDoubleRange();
263 }
265}
266
268{
269 switch ( mMode )
270 {
272 {
273 if ( !mFixedRange.isInfinite() && mFixedRange.lower() != mFixedRange.upper() )
274 return { mFixedRange.lower(), mFixedRange.upper() };
275 else if ( !mFixedRange.isInfinite() )
276 return { mFixedRange.lower() };
277
278 return {};
279 }
280
282 {
283 QList< double > res;
284 for ( auto it = mRangePerGroup.constBegin(); it != mRangePerGroup.constEnd(); ++it )
285 {
286 if ( it.value().isInfinite() )
287 continue;
288
289 if ( !res.contains( it.value().lower( ) ) )
290 res.append( it.value().lower() );
291 if ( !res.contains( it.value().upper( ) ) )
292 res.append( it.value().upper() );
293 }
294 std::sort( res.begin(), res.end() );
295 return res;
296 }
297
299 return {};
300 }
302}
303
308
322
327
329{
330 if ( mMode == mode )
331 return;
332
333 mMode = mode;
334 emit changed();
335}
336
338{
339 return mFixedRange;
340}
341
343{
344 if ( range == mFixedRange )
345 return;
346
347 mFixedRange = range;
348 emit changed();
349}
350
352{
353 return mRangePerGroup;
354}
355
356void QgsMeshLayerElevationProperties::setFixedRangePerGroup( const QMap<int, QgsDoubleRange> &ranges )
357{
358 if ( ranges == mRangePerGroup )
359 return;
360
361 mRangePerGroup = ranges;
362 emit changed();
363}
364
366{
367 return mProfileLineSymbol.get();
368}
369
371{
372 mProfileLineSymbol.reset( symbol );
373 emit changed();
375}
376
378{
379 return mProfileFillSymbol.get();
380}
381
383{
384 mProfileFillSymbol.reset( symbol );
385 emit changed();
387}
388
390{
391 if ( mSymbology == symbology )
392 return;
393
394 mSymbology = symbology;
395 emit changed();
397}
398
400{
401 return mElevationLimit;
402}
403
405{
406 if ( qgsDoubleNear( mElevationLimit, limit ) )
407 return;
408
409 mElevationLimit = limit;
410 emit changed();
412}
413
414void QgsMeshLayerElevationProperties::setDefaultProfileLineSymbol( const QColor &color )
415{
416 auto profileLineLayer = std::make_unique< QgsSimpleLineSymbolLayer >( color, 0.6 );
417 mProfileLineSymbol = std::make_unique< QgsLineSymbol>( QgsSymbolLayerList( { profileLineLayer.release() } ) );
418}
419
420void QgsMeshLayerElevationProperties::setDefaultProfileFillSymbol( const QColor &color )
421{
422 auto profileFillLayer = std::make_unique< QgsSimpleFillSymbolLayer >( color );
423 profileFillLayer->setStrokeStyle( Qt::NoPen );
424 mProfileFillSymbol = std::make_unique< QgsFillSymbol>( QgsSymbolLayerList( { profileFillLayer.release() } ) );
425}
MeshElevationMode
Mesh layer elevation modes.
Definition qgis.h:4035
@ FromVertices
Elevation should be taken from mesh vertices.
Definition qgis.h:4037
@ FixedRangePerGroup
Layer has a fixed (manually specified) elevation range per group.
Definition qgis.h:4038
@ FixedElevationRange
Layer has a fixed elevation range.
Definition qgis.h:4036
ProfileSurfaceSymbology
Surface symbology type for elevation profile plots.
Definition qgis.h:4193
@ Line
The elevation surface will be rendered using a line symbol.
Definition qgis.h:4194
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:233
A fill symbol type, for rendering Polygon and MultiPolygon geometries.
A line symbol type, for rendering LineString and MultiLineString geometries.
void writeCommonProperties(QDomElement &element, QDomDocument &doc, const QgsReadWriteContext &context)
Writes common class properties to a DOM element, to be used later with readXml().
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...
@ FlagDontInvalidateCachedRendersWhenRangeChanges
Any cached rendering will not be invalidated when z range context is modified.
Base class for all map layer types.
Definition qgsmaplayer.h:80
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...
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.
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:6817
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
Definition qgis.h:6524
QString qgsEnumValueToKey(const T &value, bool *returnOk=nullptr)
Returns the value for the given key of an enum.
Definition qgis.h:6798
#define BUILTIN_UNREACHABLE
Definition qgis.h:7208
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference).
Definition qgis.h:6607
QList< QgsSymbolLayer * > QgsSymbolLayerList
Definition qgssymbol.h:30