QGIS API Documentation 3.28.0-Firenze (ed3ad0430f)
qgspointcloudrgbrenderer.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgspointcloudrgbrenderer.h
3 --------------------
4 begin : October 2020
5 copyright : (C) 2020 by Nyall Dawson
6 email : nyall dot dawson at gmail 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 "qgspointcloudblock.h"
21
23{
24
25}
26
28{
29 return QStringLiteral( "rgb" );
30}
31
33{
34 std::unique_ptr< QgsPointCloudRgbRenderer > res = std::make_unique< QgsPointCloudRgbRenderer >();
35 res->mRedAttribute = mRedAttribute;
36 res->mGreenAttribute = mGreenAttribute;
37 res->mBlueAttribute = mBlueAttribute;
38
39 if ( mRedContrastEnhancement )
40 {
41 res->setRedContrastEnhancement( new QgsContrastEnhancement( *mRedContrastEnhancement ) );
42 }
43 if ( mGreenContrastEnhancement )
44 {
45 res->setGreenContrastEnhancement( new QgsContrastEnhancement( *mGreenContrastEnhancement ) );
46 }
47 if ( mBlueContrastEnhancement )
48 {
49 res->setBlueContrastEnhancement( new QgsContrastEnhancement( *mBlueContrastEnhancement ) );
50 }
51
52 copyCommonProperties( res.get() );
53
54 return res.release();
55}
56
58{
59 const QgsRectangle visibleExtent = context.renderContext().extent();
60
61 const char *ptr = block->data();
62 const int count = block->pointCount();
63 const QgsPointCloudAttributeCollection request = block->attributes();
64
65 const std::size_t recordSize = request.pointRecordSize();
66 int redOffset = 0;
67 const QgsPointCloudAttribute *attribute = request.find( mRedAttribute, redOffset );
68 if ( !attribute )
69 return;
70 const QgsPointCloudAttribute::DataType redType = attribute->type();
71
72 int greenOffset = 0;
73 attribute = request.find( mGreenAttribute, greenOffset );
74 if ( !attribute )
75 return;
76 const QgsPointCloudAttribute::DataType greenType = attribute->type();
77
78 int blueOffset = 0;
79 attribute = request.find( mBlueAttribute, blueOffset );
80 if ( !attribute )
81 return;
82 const QgsPointCloudAttribute::DataType blueType = attribute->type();
83
84 const bool useRedContrastEnhancement = mRedContrastEnhancement && mRedContrastEnhancement->contrastEnhancementAlgorithm() != QgsContrastEnhancement::NoEnhancement;
85 const bool useBlueContrastEnhancement = mBlueContrastEnhancement && mBlueContrastEnhancement->contrastEnhancementAlgorithm() != QgsContrastEnhancement::NoEnhancement;
86 const bool useGreenContrastEnhancement = mGreenContrastEnhancement && mGreenContrastEnhancement->contrastEnhancementAlgorithm() != QgsContrastEnhancement::NoEnhancement;
87
88 const bool renderElevation = context.elevationMap();
89 const QgsDoubleRange zRange = context.renderContext().zRange();
90 const bool considerZ = !zRange.isInfinite() || renderElevation;
91
92 int rendered = 0;
93 double x = 0;
94 double y = 0;
95 double z = 0;
97 const bool reproject = ct.isValid();
98 for ( int i = 0; i < count; ++i )
99 {
100 if ( context.renderContext().renderingStopped() )
101 {
102 break;
103 }
104
105 if ( considerZ )
106 {
107 // z value filtering is cheapest, if we're doing it...
108 z = pointZ( context, ptr, i );
109 if ( !zRange.contains( z ) )
110 continue;
111 }
112
113 pointXY( context, ptr, i, x, y );
114 if ( visibleExtent.contains( x, y ) )
115 {
116 if ( reproject )
117 {
118 try
119 {
120 ct.transformInPlace( x, y, z );
121 }
122 catch ( QgsCsException & )
123 {
124 continue;
125 }
126 }
127
128 int red = 0;
129 context.getAttribute( ptr, i * recordSize + redOffset, redType, red );
130 int green = 0;
131 context.getAttribute( ptr, i * recordSize + greenOffset, greenType, green );
132 int blue = 0;
133 context.getAttribute( ptr, i * recordSize + blueOffset, blueType, blue );
134
135 //skip if red, green or blue not in displayable range
136 if ( ( useRedContrastEnhancement && !mRedContrastEnhancement->isValueInDisplayableRange( red ) )
137 || ( useGreenContrastEnhancement && !mGreenContrastEnhancement->isValueInDisplayableRange( green ) )
138 || ( useBlueContrastEnhancement && !mBlueContrastEnhancement->isValueInDisplayableRange( blue ) ) )
139 {
140 continue;
141 }
142
143 //stretch color values
144 if ( useRedContrastEnhancement )
145 {
146 red = mRedContrastEnhancement->enhanceContrast( red );
147 }
148 if ( useGreenContrastEnhancement )
149 {
150 green = mGreenContrastEnhancement->enhanceContrast( green );
151 }
152 if ( useBlueContrastEnhancement )
153 {
154 blue = mBlueContrastEnhancement->enhanceContrast( blue );
155 }
156
157 red = std::max( 0, std::min( 255, red ) );
158 green = std::max( 0, std::min( 255, green ) );
159 blue = std::max( 0, std::min( 255, blue ) );
160
161 drawPoint( x, y, QColor( red, green, blue ), context );
162 if ( renderElevation )
163 drawPointToElevationMap( x, y, z, context );
164 rendered++;
165 }
166 }
167 context.incrementPointsRendered( rendered );
168}
169
170
172{
173 std::unique_ptr< QgsPointCloudRgbRenderer > r = std::make_unique< QgsPointCloudRgbRenderer >();
174
175 r->setRedAttribute( element.attribute( QStringLiteral( "red" ), QStringLiteral( "Red" ) ) );
176 r->setGreenAttribute( element.attribute( QStringLiteral( "green" ), QStringLiteral( "Green" ) ) );
177 r->setBlueAttribute( element.attribute( QStringLiteral( "blue" ), QStringLiteral( "Blue" ) ) );
178
179 r->restoreCommonProperties( element, context );
180
181 //contrast enhancements
183 const QDomElement redContrastElem = element.firstChildElement( QStringLiteral( "redContrastEnhancement" ) );
184 if ( !redContrastElem.isNull() )
185 {
187 redContrastEnhancement->readXml( redContrastElem );
188 r->setRedContrastEnhancement( redContrastEnhancement );
189 }
190
192 const QDomElement greenContrastElem = element.firstChildElement( QStringLiteral( "greenContrastEnhancement" ) );
193 if ( !greenContrastElem.isNull() )
194 {
196 greenContrastEnhancement->readXml( greenContrastElem );
197 r->setGreenContrastEnhancement( greenContrastEnhancement );
198 }
199
201 const QDomElement blueContrastElem = element.firstChildElement( QStringLiteral( "blueContrastEnhancement" ) );
202 if ( !blueContrastElem.isNull() )
203 {
205 blueContrastEnhancement->readXml( blueContrastElem );
206 r->setBlueContrastEnhancement( blueContrastEnhancement );
207 }
208
209 return r.release();
210}
211
212QDomElement QgsPointCloudRgbRenderer::save( QDomDocument &doc, const QgsReadWriteContext &context ) const
213{
214 QDomElement rendererElem = doc.createElement( QStringLiteral( "renderer" ) );
215
216 rendererElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "rgb" ) );
217
218 rendererElem.setAttribute( QStringLiteral( "red" ), mRedAttribute );
219 rendererElem.setAttribute( QStringLiteral( "green" ), mGreenAttribute );
220 rendererElem.setAttribute( QStringLiteral( "blue" ), mBlueAttribute );
221
222 saveCommonProperties( rendererElem, context );
223
224 //contrast enhancement
225 if ( mRedContrastEnhancement )
226 {
227 QDomElement redContrastElem = doc.createElement( QStringLiteral( "redContrastEnhancement" ) );
228 mRedContrastEnhancement->writeXml( doc, redContrastElem );
229 rendererElem.appendChild( redContrastElem );
230 }
231 if ( mGreenContrastEnhancement )
232 {
233 QDomElement greenContrastElem = doc.createElement( QStringLiteral( "greenContrastEnhancement" ) );
234 mGreenContrastEnhancement->writeXml( doc, greenContrastElem );
235 rendererElem.appendChild( greenContrastElem );
236 }
237 if ( mBlueContrastEnhancement )
238 {
239 QDomElement blueContrastElem = doc.createElement( QStringLiteral( "blueContrastEnhancement" ) );
240 mBlueContrastEnhancement->writeXml( doc, blueContrastElem );
241 rendererElem.appendChild( blueContrastElem );
242 }
243
244 return rendererElem;
245}
246
248{
249 QSet<QString> res;
250 res << mRedAttribute << mGreenAttribute << mBlueAttribute;
251 return res;
252}
253
254std::unique_ptr<QgsPreparedPointCloudRendererData> QgsPointCloudRgbRenderer::prepare()
255{
256 std::unique_ptr< QgsPointCloudRgbRendererPreparedData > data = std::make_unique< QgsPointCloudRgbRendererPreparedData >();
257 data->redAttribute = mRedAttribute;
258 if ( mRedContrastEnhancement )
259 data->redContrastEnhancement.reset( new QgsContrastEnhancement( *mRedContrastEnhancement ) );
260 data->greenAttribute = mGreenAttribute;
261 if ( mGreenContrastEnhancement )
262 data->greenContrastEnhancement.reset( new QgsContrastEnhancement( *mGreenContrastEnhancement ) );
263 data->blueAttribute = mBlueAttribute;
264 if ( mBlueContrastEnhancement )
265 data->blueContrastEnhancement.reset( new QgsContrastEnhancement( *mBlueContrastEnhancement ) );
266
267 data->useRedContrastEnhancement = mRedContrastEnhancement && mRedContrastEnhancement->contrastEnhancementAlgorithm() != QgsContrastEnhancement::NoEnhancement;
268 data->useBlueContrastEnhancement = mBlueContrastEnhancement && mBlueContrastEnhancement->contrastEnhancementAlgorithm() != QgsContrastEnhancement::NoEnhancement;
269 data->useGreenContrastEnhancement = mGreenContrastEnhancement && mGreenContrastEnhancement->contrastEnhancementAlgorithm() != QgsContrastEnhancement::NoEnhancement;
270
271 return data;
272}
273
275{
277}
278
280{
281 const QgsPointCloudAttributeCollection request = block->attributes();
282 redOffset = 0;
283 const QgsPointCloudAttribute *attribute = request.find( redAttribute, redOffset );
284 if ( !attribute )
285 return false;
286 redType = attribute->type();
287
288 greenOffset = 0;
289 attribute = request.find( greenAttribute, greenOffset );
290 if ( !attribute )
291 return false;
292 greenType = attribute->type();
293
294 blueOffset = 0;
295 attribute = request.find( blueAttribute, blueOffset );
296 if ( !attribute )
297 return false;
298 blueType = attribute->type();
299 return true;
300}
301
303{
304 const char *ptr = block->data();
305 const int pointRecordSize = block->pointRecordSize();
306
307 int red = 0;
308 QgsPointCloudRenderContext::getAttribute( ptr, i * pointRecordSize + redOffset, redType, red );
309 int green = 0;
310 QgsPointCloudRenderContext::getAttribute( ptr, i * pointRecordSize + greenOffset, greenType, green );
311 int blue = 0;
312 QgsPointCloudRenderContext::getAttribute( ptr, i * pointRecordSize + blueOffset, blueType, blue );
313
314 //skip if red, green or blue not in displayable range
315 if ( ( useRedContrastEnhancement && !redContrastEnhancement->isValueInDisplayableRange( red ) )
316 || ( useGreenContrastEnhancement && !greenContrastEnhancement->isValueInDisplayableRange( green ) )
317 || ( useBlueContrastEnhancement && !blueContrastEnhancement->isValueInDisplayableRange( blue ) ) )
318 {
319 return QColor();
320 }
321
322 //stretch color values
324 {
325 red = redContrastEnhancement->enhanceContrast( red );
326 }
328 {
329 green = greenContrastEnhancement->enhanceContrast( green );
330 }
332 {
333 blue = blueContrastEnhancement->enhanceContrast( blue );
334 }
335
336 red = std::max( 0, std::min( 255, red ) );
337 green = std::max( 0, std::min( 255, green ) );
338 blue = std::max( 0, std::min( 255, blue ) );
339
340 return QColor( red, green, blue );
341}
342
344{
345 return mRedAttribute;
346}
347
348void QgsPointCloudRgbRenderer::setRedAttribute( const QString &redAttribute )
349{
350 mRedAttribute = redAttribute;
351}
352
354{
355 return mGreenAttribute;
356}
357
358void QgsPointCloudRgbRenderer::setGreenAttribute( const QString &greenAttribute )
359{
360 mGreenAttribute = greenAttribute;
361}
362
364{
365 return mBlueAttribute;
366}
367
368void QgsPointCloudRgbRenderer::setBlueAttribute( const QString &blueAttribute )
369{
370 mBlueAttribute = blueAttribute;
371}
372
374{
375 return mRedContrastEnhancement.get();
376}
377
379{
380 mRedContrastEnhancement.reset( enhancement );
381}
382
384{
385 return mGreenContrastEnhancement.get();
386}
387
389{
390 mGreenContrastEnhancement.reset( enhancement );
391}
392
394{
395 return mBlueContrastEnhancement.get();
396}
397
399{
400 mBlueContrastEnhancement.reset( enhancement );
401}
@ UnknownDataType
Unknown or unspecified type.
Manipulates raster or point cloud pixel values so that they enhanceContrast or clip into a specified ...
@ NoEnhancement
Default color scaling algorithm, no scaling is applied.
void readXml(const QDomElement &elem)
Class for doing transforms between two map coordinate systems.
bool isValid() const
Returns true if the coordinate transform is valid, ie both the source and destination CRS have been s...
void transformInPlace(double &x, double &y, double &z, Qgis::TransformDirection direction=Qgis::TransformDirection::Forward) const SIP_THROW(QgsCsException)
Transforms an array of x, y and z double coordinates in place, from the source CRS to the destination...
Custom exception class for Coordinate Reference System related exceptions.
Definition: qgsexception.h:66
QgsRange which stores a range of double values.
Definition: qgsrange.h:203
bool isInfinite() const
Returns true if the range consists of all possible values.
Definition: qgsrange.h:247
Collection of point cloud attributes.
int pointRecordSize() const
Returns total size of record.
const QgsPointCloudAttribute * find(const QString &attributeName, int &offset) const
Finds the attribute with the name.
Attribute for point cloud data pair of name and size in bytes.
DataType
Systems of unit measurement.
DataType type() const
Returns the data type.
Base class for storing raw data from point cloud nodes.
const char * data() const
Returns raw pointer to data.
QgsPointCloudAttributeCollection attributes() const
Returns the attributes that are stored in the data block, along with their size.
int pointCount() const
Returns number of points that are stored in the block.
int pointRecordSize() const
Returns the total size of each individual point record.
Encapsulates the render context for a 2D point cloud rendering operation.
QgsRenderContext & renderContext()
Returns a reference to the context's render context.
void incrementPointsRendered(long count)
Increments the count of points rendered by the specified amount.
static void getAttribute(const char *data, std::size_t offset, QgsPointCloudAttribute::DataType type, T &value)
Retrieves the attribute value from data at the specified offset, where type indicates the original da...
QgsElevationMap * elevationMap()
Returns elevation map.
Abstract base class for 2d point cloud renderers.
void drawPointToElevationMap(double x, double y, double z, QgsPointCloudRenderContext &context) const
Draws a point at the elevation z using at the specified x and y (in map coordinates) on the elevation...
void saveCommonProperties(QDomElement &element, const QgsReadWriteContext &context) const
Saves common renderer properties (such as point size and screen error) to the specified DOM element.
void copyCommonProperties(QgsPointCloudRenderer *destination) const
Copies common point cloud properties (such as point size and screen error) to the destination rendere...
void drawPoint(double x, double y, const QColor &color, QgsPointCloudRenderContext &context) const
Draws a point using a color at the specified x and y (in map coordinates).
static double pointZ(QgsPointCloudRenderContext &context, const char *ptr, int i)
Retrieves the z value for the point at index i.
static void pointXY(QgsPointCloudRenderContext &context, const char *ptr, int i, double &x, double &y)
Retrieves the x and y coordinate for the point at index i.
std::unique_ptr< QgsContrastEnhancement > redContrastEnhancement
QSet< QString > usedAttributes() const override
Returns the set of attributes used by the prepared point cloud renderer.
std::unique_ptr< QgsContrastEnhancement > greenContrastEnhancement
bool prepareBlock(const QgsPointCloudBlock *block) override
Prepares the renderer for using the specified block.
QColor pointColor(const QgsPointCloudBlock *block, int i, double z) override
An optimised method of retrieving the color of a point from a point cloud block.
std::unique_ptr< QgsContrastEnhancement > blueContrastEnhancement
QgsPointCloudAttribute::DataType blueType
QgsPointCloudAttribute::DataType redType
QgsPointCloudAttribute::DataType greenType
std::unique_ptr< QgsPreparedPointCloudRendererData > prepare() override
Returns prepared data container for bulk point color retrieval.
void setRedContrastEnhancement(QgsContrastEnhancement *enhancement)
Sets the contrast enhancement to use for the red channel.
QString redAttribute() const
Returns the attribute to use for the red channel.
static QgsPointCloudRenderer * create(QDomElement &element, const QgsReadWriteContext &context)
Creates an RGB renderer from an XML element.
QString greenAttribute() const
Returns the attribute to use for the green channel.
QString type() const override
Returns the identifier of the renderer type.
QDomElement save(QDomDocument &doc, const QgsReadWriteContext &context) const override
Saves the renderer configuration to an XML element.
void setBlueContrastEnhancement(QgsContrastEnhancement *enhancement)
Sets the contrast enhancement to use for the blue channel.
void renderBlock(const QgsPointCloudBlock *block, QgsPointCloudRenderContext &context) override
Renders a block of point cloud data using the specified render context.
const QgsContrastEnhancement * greenContrastEnhancement() const
Returns the contrast enhancement to use for the green channel.
QString blueAttribute() const
Returns the attribute to use for the blue channel.
QgsPointCloudRgbRenderer()
Constructor for QgsPointCloudRgbRenderer.
void setGreenContrastEnhancement(QgsContrastEnhancement *enhancement)
Sets the contrast enhancement to use for the green channel.
void setBlueAttribute(const QString &attribute)
Sets the attribute to use for the blue channel.
const QgsContrastEnhancement * blueContrastEnhancement() const
Returns the contrast enhancement to use for the blue channel.
void setGreenAttribute(const QString &attribute)
Sets the attribute to use for the green channel.
void setRedAttribute(const QString &attribute)
Sets the attribute to use for the red channel.
QgsPointCloudRenderer * clone() const override
Create a deep copy of this renderer.
const QgsContrastEnhancement * redContrastEnhancement() const
Returns the contrast enhancement to use for the red channel.
QSet< QString > usedAttributes(const QgsPointCloudRenderContext &context) const override
Returns a list of attributes required by this renderer.
bool contains(const QgsRange< T > &other) const
Returns true if this range contains another range.
Definition: qgsrange.h:108
The class is used as a container of context for various read/write operations on other objects.
A rectangle specified with double values.
Definition: qgsrectangle.h:42
bool contains(const QgsRectangle &rect) const SIP_HOLDGIL
Returns true when rectangle contains other rectangle.
Definition: qgsrectangle.h:363
const QgsRectangle & extent() const
When rendering a map layer, calling this method returns the "clipping" extent for the layer (in the l...
QgsDoubleRange zRange() const
Returns the range of z-values which should be rendered.
bool renderingStopped() const
Returns true if the rendering operation has been stopped and any ongoing rendering should be canceled...
QgsCoordinateTransform coordinateTransform() const
Returns the current coordinate transform for the context.