QGIS API Documentation 3.99.0-Master (b3fe4c4eded)
Loading...
Searching...
No Matches
qgspointcloudlayerelevationproperties.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgspointcloudlayerelevationproperties.cpp
3 ---------------
4 begin : November 2020
5 copyright : (C) 2020 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 "qgscolorutils.h"
23#include "qgsfillsymbol.h"
24#include "qgsfillsymbollayer.h"
25#include "qgslinesymbol.h"
26#include "qgslinesymbollayer.h"
27#include "qgspointcloudlayer.h"
28#include "qgssymbollayerutils.h"
29#include "qgsvirtualpointcloudprovider.h"
30
31#include <QString>
32
33#include "moc_qgspointcloudlayerelevationproperties.cpp"
34
35using namespace Qt::StringLiterals;
36
39{
41 setDefaultProfileLineSymbol( mPointColor );
42 setDefaultProfileFillSymbol( mPointColor );
43
44 if ( QgsPointCloudLayer *pcLayer = qobject_cast< QgsPointCloudLayer * >( parent ) )
45 {
46 connect( pcLayer, &QgsPointCloudLayer::rendererChanged, this, [this]
47 {
48 if ( mRespectLayerColors )
50 } );
51 }
52}
53
55{
56 return mProfileLineSymbol.get();
57}
58
60{
61 if ( !symbol )
62 return;
63
64 mProfileLineSymbol.reset( symbol );
65 emit changed();
67}
68
70{
71 return mProfileFillSymbol.get();
72}
73
75{
76 if ( !symbol )
77 return;
78
79 mProfileFillSymbol.reset( symbol );
80 emit changed();
82}
83
85{
86 if ( mSymbology == symbology )
87 return;
88
89 mSymbology = symbology;
90 emit changed();
92}
93
95{
96 return mElevationLimit;
97}
98
100{
101 if ( qgsDoubleNear( mElevationLimit, limit ) )
102 return;
103
104 mElevationLimit = limit;
105 emit changed();
107}
108
109void QgsPointCloudLayerElevationProperties::setDefaultProfileLineSymbol( const QColor &color )
110{
111 auto profileLineLayer = std::make_unique< QgsSimpleLineSymbolLayer >( color, 0.6 );
112 mProfileLineSymbol = std::make_unique< QgsLineSymbol>( QgsSymbolLayerList( { profileLineLayer.release() } ) );
113}
114
115void QgsPointCloudLayerElevationProperties::setDefaultProfileFillSymbol( const QColor &color )
116{
117 auto profileFillLayer = std::make_unique< QgsSimpleFillSymbolLayer >( color );
118 profileFillLayer->setStrokeWidth( 0.2 );
119 profileFillLayer->setStrokeColor( color.darker( 140 ) );
120 mProfileFillSymbol = std::make_unique< QgsFillSymbol>( QgsSymbolLayerList( { profileFillLayer.release() } ) );
121}
122
123
125{
126 return true;
127}
128
129QDomElement QgsPointCloudLayerElevationProperties::writeXml( QDomElement &parentElement, QDomDocument &document, const QgsReadWriteContext &context )
130{
131 QDomElement element = document.createElement( u"elevation"_s );
132 writeCommonProperties( element, document, context );
133
134 element.setAttribute( u"max_screen_error"_s, qgsDoubleToString( mMaximumScreenError ) );
135 element.setAttribute( u"max_screen_error_unit"_s, QgsUnitTypes::encodeUnit( mMaximumScreenErrorUnit ) );
136 element.setAttribute( u"point_size"_s, qgsDoubleToString( mPointSize ) );
137 element.setAttribute( u"point_size_unit"_s, QgsUnitTypes::encodeUnit( mPointSizeUnit ) );
138 element.setAttribute( u"point_symbol"_s, qgsEnumValueToKey( mPointSymbol ) );
139 element.setAttribute( u"symbology"_s, qgsEnumValueToKey( mSymbology ) );
140 element.setAttribute( u"point_color"_s, QgsColorUtils::colorToString( mPointColor ) );
141 element.setAttribute( u"respect_layer_colors"_s, mRespectLayerColors ? u"1"_s : u"0"_s );
142 element.setAttribute( u"opacity_by_distance"_s, mApplyOpacityByDistanceEffect ? u"1"_s : u"0"_s );
143 element.setAttribute( u"type"_s, qgsEnumValueToKey( mType ) );
144 if ( !std::isnan( mElevationLimit ) )
145 element.setAttribute( u"elevationLimit"_s, qgsDoubleToString( mElevationLimit ) );
146
147 QDomElement profileLineSymbolElement = document.createElement( u"profileLineSymbol"_s );
148 profileLineSymbolElement.appendChild( QgsSymbolLayerUtils::saveSymbol( QString(), mProfileLineSymbol.get(), document, context ) );
149 element.appendChild( profileLineSymbolElement );
150
151 QDomElement profileFillSymbolElement = document.createElement( u"profileFillSymbol"_s );
152 profileFillSymbolElement.appendChild( QgsSymbolLayerUtils::saveSymbol( QString(), mProfileFillSymbol.get(), document, context ) );
153 element.appendChild( profileFillSymbolElement );
154
155 parentElement.appendChild( element );
156 return element;
157}
158
159bool QgsPointCloudLayerElevationProperties::readXml( const QDomElement &element, const QgsReadWriteContext &context )
160{
161 const QDomElement elevationElement = element.firstChildElement( u"elevation"_s ).toElement();
162 readCommonProperties( elevationElement, context );
163
164 mMaximumScreenError = elevationElement.attribute( u"max_screen_error"_s, u"0.3"_s ).toDouble();
165 bool ok = false;
166 mMaximumScreenErrorUnit = QgsUnitTypes::decodeRenderUnit( elevationElement.attribute( u"max_screen_error_unit"_s ), &ok );
167 if ( !ok )
168 mMaximumScreenErrorUnit = Qgis::RenderUnit::Millimeters;
169 mPointSize = elevationElement.attribute( u"point_size"_s, u"0.6"_s ).toDouble();
170 mPointSizeUnit = QgsUnitTypes::decodeRenderUnit( elevationElement.attribute( u"point_size_unit"_s ), &ok );
171 if ( !ok )
172 mPointSizeUnit = Qgis::RenderUnit::Millimeters;
173 mPointSymbol = qgsEnumKeyToValue( elevationElement.attribute( u"point_symbol"_s ), Qgis::PointCloudSymbol::Square );
174 mSymbology = qgsEnumKeyToValue( elevationElement.attribute( u"symbology"_s ), Qgis::ProfileSurfaceSymbology::FillBelow );
175 const QString colorString = elevationElement.attribute( u"point_color"_s );
176 if ( !colorString.isEmpty() )
177 {
178 mPointColor = QgsColorUtils::colorFromString( elevationElement.attribute( u"point_color"_s ) );
179 }
180 else
181 {
183 }
184
185 mRespectLayerColors = elevationElement.attribute( u"respect_layer_colors"_s, u"1"_s ).toInt();
186 mApplyOpacityByDistanceEffect = elevationElement.attribute( u"opacity_by_distance"_s ).toInt();
187 mType = qgsEnumKeyToValue( elevationElement.attribute( u"type"_s ), Qgis::PointCloudProfileType::IndividualPoints );
188 if ( elevationElement.hasAttribute( u"elevationLimit"_s ) )
189 mElevationLimit = elevationElement.attribute( u"elevationLimit"_s ).toDouble();
190 else
191 mElevationLimit = std::numeric_limits< double >::quiet_NaN();
192
194
195 const QDomElement profileLineSymbolElement = elevationElement.firstChildElement( u"profileLineSymbol"_s ).firstChildElement( u"symbol"_s );
196 mProfileLineSymbol = QgsSymbolLayerUtils::loadSymbol< QgsLineSymbol >( profileLineSymbolElement, context );
197 if ( !mProfileLineSymbol )
198 setDefaultProfileLineSymbol( color );
199
200 const QDomElement profileFillSymbolElement = elevationElement.firstChildElement( u"profileFillSymbol"_s ).firstChildElement( u"symbol"_s );
201 mProfileFillSymbol = QgsSymbolLayerUtils::loadSymbol< QgsFillSymbol >( profileFillSymbolElement, context );
202 if ( !mProfileFillSymbol )
203 setDefaultProfileFillSymbol( color );
204
205 return true;
206}
207
209{
210 auto res = std::make_unique< QgsPointCloudLayerElevationProperties >( nullptr );
211 res->copyCommonProperties( this );
212
213 res->mMaximumScreenError = mMaximumScreenError;
214 res->mMaximumScreenErrorUnit = mMaximumScreenErrorUnit;
215 res->mPointSize = mPointSize;
216 res->mPointSizeUnit = mPointSizeUnit;
217 res->mPointSymbol = mPointSymbol;
218 res->mPointColor = mPointColor;
219 res->mRespectLayerColors = mRespectLayerColors;
220 res->mType = mType;
221 res->mApplyOpacityByDistanceEffect = mApplyOpacityByDistanceEffect;
222 res->mElevationLimit = mElevationLimit;
223 res->mSymbology = mSymbology;
224
225 res->setProfileLineSymbol( mProfileLineSymbol->clone() );
226 res->setProfileFillSymbol( mProfileFillSymbol->clone() );
227
228 return res.release();
229}
230
232{
233 QStringList properties;
234 properties << tr( "Scale: %1" ).arg( mZScale );
235 properties << tr( "Offset: %1" ).arg( mZOffset );
236 return u"<ul><li>%1</li></ul>"_s.arg( properties.join( "</li><li>"_L1 ) );
237}
238
240{
241 // TODO -- test actual point cloud z range
242 return true;
243}
244
246{
247 if ( QgsPointCloudLayer *pcLayer = qobject_cast< QgsPointCloudLayer * >( layer ) )
248 {
249 if ( pcLayer->dataProvider() )
250 {
251 double zMin = std::numeric_limits<double>::quiet_NaN();
252 double zMax = std::numeric_limits<double>::quiet_NaN();
253 const QgsPointCloudStatistics stats = pcLayer->statistics();
254 if ( !stats.statisticsMap().isEmpty() )
255 {
256 // try to fetch z range from provider metadata
257 zMin = stats.minimum( u"Z"_s );
258 zMax = stats.maximum( u"Z"_s );
259 }
260 // try to fetch the elevation properties from virtual point cloud metadata
261 else if ( QgsVirtualPointCloudProvider *virtualProvider = dynamic_cast< QgsVirtualPointCloudProvider * >( pcLayer->dataProvider() ) )
262 {
263 for ( QgsPointCloudSubIndex subIndex : virtualProvider->subIndexes() )
264 {
265 const QgsDoubleRange newRange = subIndex.zRange();
266 if ( newRange.isInfinite() ) continue;
267 zMin = std::isnan( zMin ) ? newRange.lower() : std::min( zMin, newRange.lower() );
268 zMax = std::isnan( zMax ) ? newRange.upper() : std::max( zMax, newRange.upper() );
269 }
270 }
271
272 if ( !std::isnan( zMin ) && !std::isnan( zMax ) )
273 {
274 return QgsDoubleRange( zMin * mZScale + mZOffset, zMax * mZScale + mZOffset );
275 }
276 }
277 }
278
279 return QgsDoubleRange();
280}
281
283{
284 const QgsDoubleRange range = calculateZRange( layer );
285 if ( !range.isInfinite() && range.lower() != range.upper() )
286 return {range.lower(), range.upper() };
287 else if ( !range.isInfinite() )
288 return {range.lower() };
289 else
290 return {};
291}
292
297
299{
300 if ( qgsDoubleNear( error, mMaximumScreenError ) )
301 return;
302
303 mMaximumScreenError = error;
304 emit changed();
306}
307
309{
310 if ( unit == mMaximumScreenErrorUnit )
311 return;
312
313 mMaximumScreenErrorUnit = unit;
314 emit changed();
316}
317
322
324{
325 if ( mPointSymbol == symbol )
326 return;
327
328 mPointSymbol = symbol;
329 emit changed();
331}
332
334{
335 if ( color == mPointColor )
336 return;
337
338 mPointColor = color;
339 emit changed();
341}
342
344{
345 if ( apply == mApplyOpacityByDistanceEffect )
346 return;
347
348 mApplyOpacityByDistanceEffect = apply;
349 emit changed();
350
351 // turning ON opacity by distance requires a profile regeneration, turning it off does not.
352 if ( mApplyOpacityByDistanceEffect )
354 else
356}
357
359{
360 if ( qgsDoubleNear( size, mPointSize ) )
361 return;
362
363 mPointSize = size;
364 emit changed();
366}
367
369{
370 if ( mPointSizeUnit == units )
371 return;
372
373 mPointSizeUnit = units;
374 emit changed();
376}
377
379{
380 if ( mRespectLayerColors == enabled )
381 return;
382
383 mRespectLayerColors = enabled;
384 emit changed();
385
386 // turning ON respect layer colors requires a profile regeneration, turning it off does not.
387 if ( mRespectLayerColors )
389 else
391}
PointCloudSymbol
Rendering symbols for point cloud points.
Definition qgis.h:4340
@ Square
Renders points as squares.
Definition qgis.h:4341
@ IndividualPoints
Sample individual points from the point cloud.
Definition qgis.h:4301
RenderUnit
Rendering size units.
Definition qgis.h:5290
@ Millimeters
Millimeters.
Definition qgis.h:5291
ProfileSurfaceSymbology
Surface symbology type for elevation profile plots.
Definition qgis.h:4275
@ FillBelow
The elevation surface will be rendered using a fill symbol below the surface level.
Definition qgis.h:4277
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.
static QColor colorFromString(const QString &string)
Decodes a string into a color value.
static QString colorToString(const QColor &color)
Encodes a color into a string value.
QgsRange which stores a range of double values.
Definition qgsrange.h:236
bool isInfinite() const
Returns true if the range consists of all possible values.
Definition qgsrange.h:290
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().
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
void rendererChanged()
Signal emitted when renderer is changed.
void setProfileFillSymbol(QgsFillSymbol *symbol)
Sets the fill symbol used to render polygons for the layer in elevation profile plots.
void setRespectLayerColors(bool enabled)
Sets whether layer coloring should be respected when rendering elevation profile plots.
QString htmlSummary() const override
Returns a HTML formatted summary of the properties.
void setProfileLineSymbol(QgsLineSymbol *symbol)
Sets the line symbol used to render lines for the layer in elevation profile plots.
void setPointColor(const QColor &color)
Sets the color used drawing points in elevation profile charts.
bool showByDefaultInElevationProfilePlots() const override
Returns true if the layer should be visible by default in newly created elevation profile plots.
bool hasElevation() const override
Returns true if the layer has an elevation or z component.
void setApplyOpacityByDistanceEffect(bool apply)
Sets whether a reduced opacity by distance from profile curve effect should be applied when drawing p...
QDomElement writeXml(QDomElement &element, QDomDocument &doc, const QgsReadWriteContext &context) override
Writes the properties to a DOM element, to be used later with readXml().
void setPointSize(double size)
Sets the point size used for drawing points in elevation profile charts.
double elevationLimit() const
Returns the elevation limit, which is used when profileSymbology() is Qgis::ProfileSurfaceSymbology::...
bool readXml(const QDomElement &element, const QgsReadWriteContext &context) override
Reads the elevation properties from a DOM element previously written by writeXml().
void setPointSymbol(Qgis::PointCloudSymbol symbol)
Sets the symbol used drawing points in elevation profile charts.
QgsDoubleRange calculateZRange(QgsMapLayer *layer) const override
Attempts to calculate the overall elevation or z range for the specified layer, using the settings de...
void setMaximumScreenError(double error)
Sets the maximum screen error allowed when generating elevation profiles for the point cloud.
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.
void setPointSizeUnit(const Qgis::RenderUnit units)
Sets the units used for the point size used for drawing points in elevation profile charts.
QgsPointCloudLayerElevationProperties * clone() const override
Creates a clone of the properties.
void setMaximumScreenErrorUnit(Qgis::RenderUnit unit)
Sets the unit for the maximum screen error allowed when generating elevation profiles for the point c...
QgsFillSymbol * profileFillSymbol() const
Returns the symbol used to render polygons for the layer in elevation profile plots.
QList< double > significantZValues(QgsMapLayer *layer) const override
Returns a list of significant elevation/z-values for the specified layer, using the settings defined ...
Qgis::PointCloudSymbol pointSymbol() const
Returns the symbol used drawing points in elevation profile charts.
void setProfileSymbology(Qgis::ProfileSurfaceSymbology symbology)
Sets the symbology option used to render the point cloud profile in elevation profile plots.
void setElevationLimit(double limit)
Sets the elevation limit, which is used when profileSymbology() is Qgis::ProfileSurfaceSymbology::Fil...
QgsPointCloudLayerElevationProperties(QObject *parent)
Constructor for QgsPointCloudLayerElevationProperties, with the specified parent object.
QgsLineSymbol * profileLineSymbol() const
Returns the symbol used to render lines for the layer in elevation profile plots.
Represents a map layer supporting display of point clouds.
Used to store statistics of a point cloud dataset.
double maximum(const QString &attribute) const
Returns the maximum value for the attribute attribute If no matching statistic is available then NaN ...
double minimum(const QString &attribute) const
Returns the minimum value for the attribute attribute If no matching statistic is available then NaN ...
QMap< QString, QgsPointCloudAttributeStatistics > statisticsMap() const
Returns a map object containing all the statistics.
T lower() const
Returns the lower bound of the range.
Definition qgsrange.h:81
T upper() const
Returns the upper bound of the range.
Definition qgsrange.h:88
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.
static Q_INVOKABLE Qgis::RenderUnit decodeRenderUnit(const QString &string, bool *ok=nullptr)
Decodes a render unit from a string.
static Q_INVOKABLE QString encodeUnit(Qgis::DistanceUnit unit)
Encodes a distance unit to a string.
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:7145
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
Definition qgis.h:6852
QString qgsEnumValueToKey(const T &value, bool *returnOk=nullptr)
Returns the value for the given key of an enum.
Definition qgis.h:7126
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference).
Definition qgis.h:6935
QList< QgsSymbolLayer * > QgsSymbolLayerList
Definition qgssymbol.h:30