QGIS API Documentation 3.99.0-Master (e9821da5c6b)
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 <QString>
30
31#include "moc_qgsmeshlayerelevationproperties.cpp"
32
33using namespace Qt::StringLiterals;
34
37{
39 setDefaultProfileLineSymbol( color );
40 setDefaultProfileFillSymbol( color );
41}
42
44
46{
47 return true;
48}
49
50QDomElement QgsMeshLayerElevationProperties::writeXml( QDomElement &parentElement, QDomDocument &document, const QgsReadWriteContext &context )
51{
52 QDomElement element = document.createElement( u"elevation"_s );
53 element.setAttribute( u"mode"_s, qgsEnumValueToKey( mMode ) );
54 element.setAttribute( u"symbology"_s, qgsEnumValueToKey( mSymbology ) );
55 if ( !std::isnan( mElevationLimit ) )
56 element.setAttribute( u"elevationLimit"_s, qgsDoubleToString( mElevationLimit ) );
57
58 writeCommonProperties( element, document, context );
59
60 switch ( mMode )
61 {
63 element.setAttribute( u"lower"_s, qgsDoubleToString( mFixedRange.lower() ) );
64 element.setAttribute( u"upper"_s, qgsDoubleToString( mFixedRange.upper() ) );
65 element.setAttribute( u"includeLower"_s, mFixedRange.includeLower() ? "1" : "0" );
66 element.setAttribute( u"includeUpper"_s, mFixedRange.includeUpper() ? "1" : "0" );
67 break;
68
70 {
71 QDomElement ranges = document.createElement( u"ranges"_s );
72 for ( auto it = mRangePerGroup.constBegin(); it != mRangePerGroup.constEnd(); ++it )
73 {
74 QDomElement range = document.createElement( u"range"_s );
75 range.setAttribute( u"group"_s, it.key() );
76 range.setAttribute( u"lower"_s, qgsDoubleToString( it.value().lower() ) );
77 range.setAttribute( u"upper"_s, qgsDoubleToString( it.value().upper() ) );
78 range.setAttribute( u"includeLower"_s, it.value().includeLower() ? "1" : "0" );
79 range.setAttribute( u"includeUpper"_s, it.value().includeUpper() ? "1" : "0" );
80 ranges.appendChild( range );
81 }
82 element.appendChild( ranges );
83 break;
84 }
85
87 break;
88 }
89
90 QDomElement profileLineSymbolElement = document.createElement( u"profileLineSymbol"_s );
91 profileLineSymbolElement.appendChild( QgsSymbolLayerUtils::saveSymbol( QString(), mProfileLineSymbol.get(), document, context ) );
92 element.appendChild( profileLineSymbolElement );
93
94 QDomElement profileFillSymbolElement = document.createElement( u"profileFillSymbol"_s );
95 profileFillSymbolElement.appendChild( QgsSymbolLayerUtils::saveSymbol( QString(), mProfileFillSymbol.get(), document, context ) );
96 element.appendChild( profileFillSymbolElement );
97
98 parentElement.appendChild( element );
99 return element;
100}
101
102bool QgsMeshLayerElevationProperties::readXml( const QDomElement &element, const QgsReadWriteContext &context )
103{
104 const QDomElement elevationElement = element.firstChildElement( u"elevation"_s ).toElement();
105 mMode = qgsEnumKeyToValue( elevationElement.attribute( u"mode"_s ), Qgis::MeshElevationMode::FromVertices );
106 mSymbology = qgsEnumKeyToValue( elevationElement.attribute( u"symbology"_s ), Qgis::ProfileSurfaceSymbology::Line );
107 if ( elevationElement.hasAttribute( u"elevationLimit"_s ) )
108 mElevationLimit = elevationElement.attribute( u"elevationLimit"_s ).toDouble();
109 else
110 mElevationLimit = std::numeric_limits< double >::quiet_NaN();
111
112 readCommonProperties( elevationElement, context );
113
114 switch ( mMode )
115 {
117 {
118 const double lower = elevationElement.attribute( u"lower"_s ).toDouble();
119 const double upper = elevationElement.attribute( u"upper"_s ).toDouble();
120 const bool includeLower = elevationElement.attribute( u"includeLower"_s ).toInt();
121 const bool includeUpper = elevationElement.attribute( u"includeUpper"_s ).toInt();
122 mFixedRange = QgsDoubleRange( lower, upper, includeLower, includeUpper );
123 break;
124 }
125
127 {
128 mRangePerGroup.clear();
129
130 const QDomNodeList ranges = elevationElement.firstChildElement( u"ranges"_s ).childNodes();
131 for ( int i = 0; i < ranges.size(); ++i )
132 {
133 const QDomElement rangeElement = ranges.at( i ).toElement();
134 const int group = rangeElement.attribute( u"group"_s ).toInt();
135 const double lower = rangeElement.attribute( u"lower"_s ).toDouble();
136 const double upper = rangeElement.attribute( u"upper"_s ).toDouble();
137 const bool includeLower = rangeElement.attribute( u"includeLower"_s ).toInt();
138 const bool includeUpper = rangeElement.attribute( u"includeUpper"_s ).toInt();
139 mRangePerGroup.insert( group, QgsDoubleRange( lower, upper, includeLower, includeUpper ) );
140 }
141 break;
142 }
143
145 break;
146 }
147
148 const QColor defaultColor = QgsApplication::colorSchemeRegistry()->fetchRandomStyleColor();
149
150 const QDomElement profileLineSymbolElement = elevationElement.firstChildElement( u"profileLineSymbol"_s ).firstChildElement( u"symbol"_s );
151 mProfileLineSymbol = QgsSymbolLayerUtils::loadSymbol< QgsLineSymbol >( profileLineSymbolElement, context );
152 if ( !mProfileLineSymbol )
153 setDefaultProfileLineSymbol( defaultColor );
154
155 const QDomElement profileFillSymbolElement = elevationElement.firstChildElement( u"profileFillSymbol"_s ).firstChildElement( u"symbol"_s );
156 mProfileFillSymbol = QgsSymbolLayerUtils::loadSymbol< QgsFillSymbol >( profileFillSymbolElement, context );
157 if ( !mProfileFillSymbol )
158 setDefaultProfileFillSymbol( defaultColor );
159
160 return true;
161}
162
164{
165 QStringList properties;
166 switch ( mMode )
167 {
169 properties << tr( "Elevation range: %1 to %2" ).arg( mFixedRange.lower() ).arg( mFixedRange.upper() );
170 break;
171
173 {
174 for ( auto it = mRangePerGroup.constBegin(); it != mRangePerGroup.constEnd(); ++it )
175 {
176 properties << tr( "Elevation for group %1: %2 to %3" ).arg( it.key() ).arg( it.value().lower() ).arg( it.value().upper() );
177 }
178 break;
179 }
180
182 properties << tr( "Scale: %1" ).arg( mZScale );
183 properties << tr( "Offset: %1" ).arg( mZOffset );
184 break;
185 }
186 return u"<li>%1</li>"_s.arg( properties.join( "</li><li>"_L1 ) );
187}
188
190{
191 auto res = std::make_unique< QgsMeshLayerElevationProperties >( nullptr );
192 res->setMode( mMode );
193 res->setProfileLineSymbol( mProfileLineSymbol->clone() );
194 res->setProfileFillSymbol( mProfileFillSymbol->clone() );
195 res->setProfileSymbology( mSymbology );
196 res->setElevationLimit( mElevationLimit );
197 res->setFixedRange( mFixedRange );
198 res->setFixedRangePerGroup( mRangePerGroup );
199 res->copyCommonProperties( this );
200 return res.release();
201}
202
204{
205 switch ( mMode )
206 {
208 return mFixedRange.overlaps( range );
209
211 {
212 for ( auto it = mRangePerGroup.constBegin(); it != mRangePerGroup.constEnd(); ++it )
213 {
214 if ( it.value().overlaps( range ) )
215 return true;
216 }
217 return false;
218 }
219
221 // TODO -- test actual mesh z range
222 return true;
223 }
225}
226
228{
229 switch ( mMode )
230 {
232 return mFixedRange;
233
235 {
236 double lower = std::numeric_limits< double >::max();
237 double upper = std::numeric_limits< double >::min();
238 bool includeLower = true;
239 bool includeUpper = true;
240 for ( auto it = mRangePerGroup.constBegin(); it != mRangePerGroup.constEnd(); ++it )
241 {
242 if ( it.value().lower() < lower )
243 {
244 lower = it.value().lower();
245 includeLower = it.value().includeLower();
246 }
247 else if ( !includeLower && it.value().lower() == lower && it.value().includeLower() )
248 {
249 includeLower = true;
250 }
251 if ( it.value().upper() > upper )
252 {
253 upper = it.value().upper();
254 includeUpper = it.value().includeUpper();
255 }
256 else if ( !includeUpper && it.value().upper() == upper && it.value().includeUpper() )
257 {
258 includeUpper = true;
259 }
260 }
261 return QgsDoubleRange( lower, upper, includeLower, includeUpper );
262 }
263
265 // TODO -- determine actual z range from mesh statistics
266 return QgsDoubleRange();
267 }
269}
270
272{
273 switch ( mMode )
274 {
276 {
277 if ( !mFixedRange.isInfinite() && mFixedRange.lower() != mFixedRange.upper() )
278 return { mFixedRange.lower(), mFixedRange.upper() };
279 else if ( !mFixedRange.isInfinite() )
280 return { mFixedRange.lower() };
281
282 return {};
283 }
284
286 {
287 QList< double > res;
288 for ( auto it = mRangePerGroup.constBegin(); it != mRangePerGroup.constEnd(); ++it )
289 {
290 if ( it.value().isInfinite() )
291 continue;
292
293 if ( !res.contains( it.value().lower( ) ) )
294 res.append( it.value().lower() );
295 if ( !res.contains( it.value().upper( ) ) )
296 res.append( it.value().upper() );
297 }
298 std::sort( res.begin(), res.end() );
299 return res;
300 }
301
303 return {};
304 }
306}
307
312
326
331
333{
334 if ( mMode == mode )
335 return;
336
337 mMode = mode;
338 emit changed();
339}
340
342{
343 return mFixedRange;
344}
345
347{
348 if ( range == mFixedRange )
349 return;
350
351 mFixedRange = range;
352 emit changed();
353}
354
356{
357 return mRangePerGroup;
358}
359
360void QgsMeshLayerElevationProperties::setFixedRangePerGroup( const QMap<int, QgsDoubleRange> &ranges )
361{
362 if ( ranges == mRangePerGroup )
363 return;
364
365 mRangePerGroup = ranges;
366 emit changed();
367}
368
370{
371 return mProfileLineSymbol.get();
372}
373
375{
376 mProfileLineSymbol.reset( symbol );
377 emit changed();
379}
380
382{
383 return mProfileFillSymbol.get();
384}
385
387{
388 mProfileFillSymbol.reset( symbol );
389 emit changed();
391}
392
394{
395 if ( mSymbology == symbology )
396 return;
397
398 mSymbology = symbology;
399 emit changed();
401}
402
404{
405 return mElevationLimit;
406}
407
409{
410 if ( qgsDoubleNear( mElevationLimit, limit ) )
411 return;
412
413 mElevationLimit = limit;
414 emit changed();
416}
417
418void QgsMeshLayerElevationProperties::setDefaultProfileLineSymbol( const QColor &color )
419{
420 auto profileLineLayer = std::make_unique< QgsSimpleLineSymbolLayer >( color, 0.6 );
421 mProfileLineSymbol = std::make_unique< QgsLineSymbol>( QgsSymbolLayerList( { profileLineLayer.release() } ) );
422}
423
424void QgsMeshLayerElevationProperties::setDefaultProfileFillSymbol( const QColor &color )
425{
426 auto profileFillLayer = std::make_unique< QgsSimpleFillSymbolLayer >( color );
427 profileFillLayer->setStrokeStyle( Qt::NoPen );
428 mProfileFillSymbol = std::make_unique< QgsFillSymbol>( QgsSymbolLayerList( { profileFillLayer.release() } ) );
429}
MeshElevationMode
Mesh layer elevation modes.
Definition qgis.h:4106
@ FromVertices
Elevation should be taken from mesh vertices.
Definition qgis.h:4108
@ FixedRangePerGroup
Layer has a fixed (manually specified) elevation range per group.
Definition qgis.h:4109
@ FixedElevationRange
Layer has a fixed elevation range.
Definition qgis.h:4107
ProfileSurfaceSymbology
Surface symbology type for elevation profile plots.
Definition qgis.h:4264
@ Line
The elevation surface will be rendered using a line symbol.
Definition qgis.h:4265
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:236
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:83
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:7134
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
Definition qgis.h:6841
QString qgsEnumValueToKey(const T &value, bool *returnOk=nullptr)
Returns the value for the given key of an enum.
Definition qgis.h:7115
#define BUILTIN_UNREACHABLE
Definition qgis.h:7513
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference).
Definition qgis.h:6924
QList< QgsSymbolLayer * > QgsSymbolLayerList
Definition qgssymbol.h:30