QGIS API Documentation 3.99.0-Master (7d2ca374f2d)
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 "qgsunittypes.h"
30#include "qgsvirtualpointcloudprovider.h"
31
32#include <QString>
33
34#include "moc_qgspointcloudlayerelevationproperties.cpp"
35
36using namespace Qt::StringLiterals;
37
40{
42 setDefaultProfileLineSymbol( mPointColor );
43 setDefaultProfileFillSymbol( mPointColor );
44
45 if ( QgsPointCloudLayer *pcLayer = qobject_cast< QgsPointCloudLayer * >( parent ) )
46 {
47 connect( pcLayer, &QgsPointCloudLayer::rendererChanged, this, [this]
48 {
49 if ( mRespectLayerColors )
51 } );
52 }
53}
54
56{
57 return mProfileLineSymbol.get();
58}
59
61{
62 if ( !symbol )
63 return;
64
65 mProfileLineSymbol.reset( symbol );
66 emit changed();
68}
69
71{
72 return mProfileFillSymbol.get();
73}
74
76{
77 if ( !symbol )
78 return;
79
80 mProfileFillSymbol.reset( symbol );
81 emit changed();
83}
84
86{
87 if ( mSymbology == symbology )
88 return;
89
90 mSymbology = symbology;
91 emit changed();
93}
94
96{
97 return mElevationLimit;
98}
99
101{
102 if ( qgsDoubleNear( mElevationLimit, limit ) )
103 return;
104
105 mElevationLimit = limit;
106 emit changed();
108}
109
110void QgsPointCloudLayerElevationProperties::setDefaultProfileLineSymbol( const QColor &color )
111{
112 auto profileLineLayer = std::make_unique< QgsSimpleLineSymbolLayer >( color, 0.6 );
113 mProfileLineSymbol = std::make_unique< QgsLineSymbol>( QgsSymbolLayerList( { profileLineLayer.release() } ) );
114}
115
116void QgsPointCloudLayerElevationProperties::setDefaultProfileFillSymbol( const QColor &color )
117{
118 auto profileFillLayer = std::make_unique< QgsSimpleFillSymbolLayer >( color );
119 profileFillLayer->setStrokeWidth( 0.2 );
120 profileFillLayer->setStrokeColor( color.darker( 140 ) );
121 mProfileFillSymbol = std::make_unique< QgsFillSymbol>( QgsSymbolLayerList( { profileFillLayer.release() } ) );
122}
123
124
126{
127 return true;
128}
129
130QDomElement QgsPointCloudLayerElevationProperties::writeXml( QDomElement &parentElement, QDomDocument &document, const QgsReadWriteContext &context )
131{
132 QDomElement element = document.createElement( u"elevation"_s );
133 writeCommonProperties( element, document, context );
134
135 element.setAttribute( u"max_screen_error"_s, qgsDoubleToString( mMaximumScreenError ) );
136 element.setAttribute( u"max_screen_error_unit"_s, QgsUnitTypes::encodeUnit( mMaximumScreenErrorUnit ) );
137 element.setAttribute( u"point_size"_s, qgsDoubleToString( mPointSize ) );
138 element.setAttribute( u"point_size_unit"_s, QgsUnitTypes::encodeUnit( mPointSizeUnit ) );
139 element.setAttribute( u"point_symbol"_s, qgsEnumValueToKey( mPointSymbol ) );
140 element.setAttribute( u"symbology"_s, qgsEnumValueToKey( mSymbology ) );
141 element.setAttribute( u"point_color"_s, QgsColorUtils::colorToString( mPointColor ) );
142 element.setAttribute( u"respect_layer_colors"_s, mRespectLayerColors ? u"1"_s : u"0"_s );
143 element.setAttribute( u"opacity_by_distance"_s, mApplyOpacityByDistanceEffect ? u"1"_s : u"0"_s );
144 element.setAttribute( u"type"_s, qgsEnumValueToKey( mType ) );
145 if ( !std::isnan( mElevationLimit ) )
146 element.setAttribute( u"elevationLimit"_s, qgsDoubleToString( mElevationLimit ) );
147
148 QDomElement profileLineSymbolElement = document.createElement( u"profileLineSymbol"_s );
149 profileLineSymbolElement.appendChild( QgsSymbolLayerUtils::saveSymbol( QString(), mProfileLineSymbol.get(), document, context ) );
150 element.appendChild( profileLineSymbolElement );
151
152 QDomElement profileFillSymbolElement = document.createElement( u"profileFillSymbol"_s );
153 profileFillSymbolElement.appendChild( QgsSymbolLayerUtils::saveSymbol( QString(), mProfileFillSymbol.get(), document, context ) );
154 element.appendChild( profileFillSymbolElement );
155
156 parentElement.appendChild( element );
157 return element;
158}
159
160bool QgsPointCloudLayerElevationProperties::readXml( const QDomElement &element, const QgsReadWriteContext &context )
161{
162 const QDomElement elevationElement = element.firstChildElement( u"elevation"_s ).toElement();
163 readCommonProperties( elevationElement, context );
164
165 mMaximumScreenError = elevationElement.attribute( u"max_screen_error"_s, u"0.3"_s ).toDouble();
166 bool ok = false;
167 mMaximumScreenErrorUnit = QgsUnitTypes::decodeRenderUnit( elevationElement.attribute( u"max_screen_error_unit"_s ), &ok );
168 if ( !ok )
169 mMaximumScreenErrorUnit = Qgis::RenderUnit::Millimeters;
170 mPointSize = elevationElement.attribute( u"point_size"_s, u"0.6"_s ).toDouble();
171 mPointSizeUnit = QgsUnitTypes::decodeRenderUnit( elevationElement.attribute( u"point_size_unit"_s ), &ok );
172 if ( !ok )
173 mPointSizeUnit = Qgis::RenderUnit::Millimeters;
174 mPointSymbol = qgsEnumKeyToValue( elevationElement.attribute( u"point_symbol"_s ), Qgis::PointCloudSymbol::Square );
175 mSymbology = qgsEnumKeyToValue( elevationElement.attribute( u"symbology"_s ), Qgis::ProfileSurfaceSymbology::FillBelow );
176 const QString colorString = elevationElement.attribute( u"point_color"_s );
177 if ( !colorString.isEmpty() )
178 {
179 mPointColor = QgsColorUtils::colorFromString( elevationElement.attribute( u"point_color"_s ) );
180 }
181 else
182 {
184 }
185
186 mRespectLayerColors = elevationElement.attribute( u"respect_layer_colors"_s, u"1"_s ).toInt();
187 mApplyOpacityByDistanceEffect = elevationElement.attribute( u"opacity_by_distance"_s ).toInt();
188 mType = qgsEnumKeyToValue( elevationElement.attribute( u"type"_s ), Qgis::PointCloudProfileType::IndividualPoints );
189 if ( elevationElement.hasAttribute( u"elevationLimit"_s ) )
190 mElevationLimit = elevationElement.attribute( u"elevationLimit"_s ).toDouble();
191 else
192 mElevationLimit = std::numeric_limits< double >::quiet_NaN();
193
195
196 const QDomElement profileLineSymbolElement = elevationElement.firstChildElement( u"profileLineSymbol"_s ).firstChildElement( u"symbol"_s );
197 mProfileLineSymbol = QgsSymbolLayerUtils::loadSymbol< QgsLineSymbol >( profileLineSymbolElement, context );
198 if ( !mProfileLineSymbol )
199 setDefaultProfileLineSymbol( color );
200
201 const QDomElement profileFillSymbolElement = elevationElement.firstChildElement( u"profileFillSymbol"_s ).firstChildElement( u"symbol"_s );
202 mProfileFillSymbol = QgsSymbolLayerUtils::loadSymbol< QgsFillSymbol >( profileFillSymbolElement, context );
203 if ( !mProfileFillSymbol )
204 setDefaultProfileFillSymbol( color );
205
206 return true;
207}
208
210{
211 auto res = std::make_unique< QgsPointCloudLayerElevationProperties >( nullptr );
212 res->copyCommonProperties( this );
213
214 res->mMaximumScreenError = mMaximumScreenError;
215 res->mMaximumScreenErrorUnit = mMaximumScreenErrorUnit;
216 res->mPointSize = mPointSize;
217 res->mPointSizeUnit = mPointSizeUnit;
218 res->mPointSymbol = mPointSymbol;
219 res->mPointColor = mPointColor;
220 res->mRespectLayerColors = mRespectLayerColors;
221 res->mType = mType;
222 res->mApplyOpacityByDistanceEffect = mApplyOpacityByDistanceEffect;
223 res->mElevationLimit = mElevationLimit;
224 res->mSymbology = mSymbology;
225
226 res->setProfileLineSymbol( mProfileLineSymbol->clone() );
227 res->setProfileFillSymbol( mProfileFillSymbol->clone() );
228
229 return res.release();
230}
231
233{
234 QStringList properties;
235 properties << tr( "Scale: %1" ).arg( mZScale );
236 properties << tr( "Offset: %1" ).arg( mZOffset );
237 return u"<ul><li>%1</li></ul>"_s.arg( properties.join( "</li><li>"_L1 ) );
238}
239
241{
242 // TODO -- test actual point cloud z range
243 return true;
244}
245
247{
248 if ( QgsPointCloudLayer *pcLayer = qobject_cast< QgsPointCloudLayer * >( layer ) )
249 {
250 if ( pcLayer->dataProvider() )
251 {
252 double zMin = std::numeric_limits<double>::quiet_NaN();
253 double zMax = std::numeric_limits<double>::quiet_NaN();
254 const QgsPointCloudStatistics stats = pcLayer->statistics();
255 if ( !stats.statisticsMap().isEmpty() )
256 {
257 // try to fetch z range from provider metadata
258 zMin = stats.minimum( u"Z"_s );
259 zMax = stats.maximum( u"Z"_s );
260 }
261 // try to fetch the elevation properties from virtual point cloud metadata
262 else if ( QgsVirtualPointCloudProvider *virtualProvider = dynamic_cast< QgsVirtualPointCloudProvider * >( pcLayer->dataProvider() ) )
263 {
264 for ( QgsPointCloudSubIndex subIndex : virtualProvider->subIndexes() )
265 {
266 const QgsDoubleRange newRange = subIndex.zRange();
267 if ( newRange.isInfinite() ) continue;
268 zMin = std::isnan( zMin ) ? newRange.lower() : std::min( zMin, newRange.lower() );
269 zMax = std::isnan( zMax ) ? newRange.upper() : std::max( zMax, newRange.upper() );
270 }
271 }
272
273 if ( !std::isnan( zMin ) && !std::isnan( zMax ) )
274 {
275 return QgsDoubleRange( zMin * mZScale + mZOffset, zMax * mZScale + mZOffset );
276 }
277 }
278 }
279
280 return QgsDoubleRange();
281}
282
284{
285 const QgsDoubleRange range = calculateZRange( layer );
286 if ( !range.isInfinite() && range.lower() != range.upper() )
287 return {range.lower(), range.upper() };
288 else if ( !range.isInfinite() )
289 return {range.lower() };
290 else
291 return {};
292}
293
298
300{
301 if ( qgsDoubleNear( error, mMaximumScreenError ) )
302 return;
303
304 mMaximumScreenError = error;
305 emit changed();
307}
308
310{
311 if ( unit == mMaximumScreenErrorUnit )
312 return;
313
314 mMaximumScreenErrorUnit = unit;
315 emit changed();
317}
318
323
325{
326 if ( mPointSymbol == symbol )
327 return;
328
329 mPointSymbol = symbol;
330 emit changed();
332}
333
335{
336 if ( color == mPointColor )
337 return;
338
339 mPointColor = color;
340 emit changed();
342}
343
345{
346 if ( apply == mApplyOpacityByDistanceEffect )
347 return;
348
349 mApplyOpacityByDistanceEffect = apply;
350 emit changed();
351
352 // turning ON opacity by distance requires a profile regeneration, turning it off does not.
353 if ( mApplyOpacityByDistanceEffect )
355 else
357}
358
360{
361 if ( qgsDoubleNear( size, mPointSize ) )
362 return;
363
364 mPointSize = size;
365 emit changed();
367}
368
370{
371 if ( mPointSizeUnit == units )
372 return;
373
374 mPointSizeUnit = units;
375 emit changed();
377}
378
380{
381 if ( mRespectLayerColors == enabled )
382 return;
383
384 mRespectLayerColors = enabled;
385 emit changed();
386
387 // turning ON respect layer colors requires a profile regeneration, turning it off does not.
388 if ( mRespectLayerColors )
390 else
392}
PointCloudSymbol
Rendering symbols for point cloud points.
Definition qgis.h:4355
@ Square
Renders points as squares.
Definition qgis.h:4356
@ IndividualPoints
Sample individual points from the point cloud.
Definition qgis.h:4316
RenderUnit
Rendering size units.
Definition qgis.h:5305
@ Millimeters
Millimeters.
Definition qgis.h:5306
ProfileSurfaceSymbology
Surface symbology type for elevation profile plots.
Definition qgis.h:4290
@ FillBelow
The elevation surface will be rendered using a fill symbol below the surface level.
Definition qgis.h:4292
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:7160
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
Definition qgis.h:6867
QString qgsEnumValueToKey(const T &value, bool *returnOk=nullptr)
Returns the value for the given key of an enum.
Definition qgis.h:7141
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference).
Definition qgis.h:6950
QList< QgsSymbolLayer * > QgsSymbolLayerList
Definition qgssymbol.h:30