QGIS API Documentation 3.99.0-Master (26c88405ac0)
Loading...
Searching...
No Matches
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
20#include <memory>
21
23#include "qgspointcloudblock.h"
24
29
31{
32 return QStringLiteral( "rgb" );
33}
34
36{
37 auto res = std::make_unique< QgsPointCloudRgbRenderer >();
38 res->mRedAttribute = mRedAttribute;
39 res->mGreenAttribute = mGreenAttribute;
40 res->mBlueAttribute = mBlueAttribute;
41
42 if ( mRedContrastEnhancement )
43 {
44 res->setRedContrastEnhancement( new QgsContrastEnhancement( *mRedContrastEnhancement ) );
45 }
46 if ( mGreenContrastEnhancement )
47 {
48 res->setGreenContrastEnhancement( new QgsContrastEnhancement( *mGreenContrastEnhancement ) );
49 }
50 if ( mBlueContrastEnhancement )
51 {
52 res->setBlueContrastEnhancement( new QgsContrastEnhancement( *mBlueContrastEnhancement ) );
53 }
54
55 copyCommonProperties( res.get() );
56
57 return res.release();
58}
59
61{
62 QgsRectangle visibleExtent = context.renderContext().extent();
63 if ( renderAsTriangles() )
64 {
65 // we need to include also points slightly outside of the visible extent,
66 // otherwise the triangulation may be missing triangles near the edges and corners
67 visibleExtent.grow( std::max( visibleExtent.width(), visibleExtent.height() ) * 0.05 );
68 }
69
70 const char *ptr = block->data();
71 const int count = block->pointCount();
72 const QgsPointCloudAttributeCollection request = block->attributes();
73
74 const std::size_t recordSize = request.pointRecordSize();
75 int redOffset = 0;
76 const QgsPointCloudAttribute *attribute = request.find( mRedAttribute, redOffset );
77 if ( !attribute )
78 return;
79 const QgsPointCloudAttribute::DataType redType = attribute->type();
80
81 int greenOffset = 0;
82 attribute = request.find( mGreenAttribute, greenOffset );
83 if ( !attribute )
84 return;
85 const QgsPointCloudAttribute::DataType greenType = attribute->type();
86
87 int blueOffset = 0;
88 attribute = request.find( mBlueAttribute, blueOffset );
89 if ( !attribute )
90 return;
91 const QgsPointCloudAttribute::DataType blueType = attribute->type();
92
93 const bool useRedContrastEnhancement = mRedContrastEnhancement && mRedContrastEnhancement->contrastEnhancementAlgorithm() != QgsContrastEnhancement::NoEnhancement;
94 const bool useBlueContrastEnhancement = mBlueContrastEnhancement && mBlueContrastEnhancement->contrastEnhancementAlgorithm() != QgsContrastEnhancement::NoEnhancement;
95 const bool useGreenContrastEnhancement = mGreenContrastEnhancement && mGreenContrastEnhancement->contrastEnhancementAlgorithm() != QgsContrastEnhancement::NoEnhancement;
96
97 const bool renderElevation = context.renderContext().elevationMap();
98 const QgsDoubleRange zRange = context.renderContext().zRange();
99 const bool considerZ = !zRange.isInfinite() || renderElevation;
100
101 int rendered = 0;
102 double x = 0;
103 double y = 0;
104 double z = 0;
106 const bool reproject = ct.isValid();
107 for ( int i = 0; i < count; ++i )
108 {
109 if ( context.renderContext().renderingStopped() )
110 {
111 break;
112 }
113
114 if ( considerZ )
115 {
116 // z value filtering is cheapest, if we're doing it...
117 z = pointZ( context, ptr, i );
118 if ( !zRange.contains( z ) )
119 continue;
120 }
121
122 pointXY( context, ptr, i, x, y );
123 if ( visibleExtent.contains( x, y ) )
124 {
125 if ( reproject )
126 {
127 try
128 {
129 ct.transformInPlace( x, y, z );
130 }
131 catch ( QgsCsException & )
132 {
133 continue;
134 }
135 }
136
137 int red = 0;
138 context.getAttribute( ptr, i * recordSize + redOffset, redType, red );
139 int green = 0;
140 context.getAttribute( ptr, i * recordSize + greenOffset, greenType, green );
141 int blue = 0;
142 context.getAttribute( ptr, i * recordSize + blueOffset, blueType, blue );
143
144 //skip if red, green or blue not in displayable range
145 if ( ( useRedContrastEnhancement && !mRedContrastEnhancement->isValueInDisplayableRange( red ) )
146 || ( useGreenContrastEnhancement && !mGreenContrastEnhancement->isValueInDisplayableRange( green ) )
147 || ( useBlueContrastEnhancement && !mBlueContrastEnhancement->isValueInDisplayableRange( blue ) ) )
148 {
149 continue;
150 }
151
152 //stretch color values
153 if ( useRedContrastEnhancement )
154 {
155 red = mRedContrastEnhancement->enhanceContrast( red );
156 }
157 if ( useGreenContrastEnhancement )
158 {
159 green = mGreenContrastEnhancement->enhanceContrast( green );
160 }
161 if ( useBlueContrastEnhancement )
162 {
163 blue = mBlueContrastEnhancement->enhanceContrast( blue );
164 }
165
166 red = std::max( 0, std::min( 255, red ) );
167 green = std::max( 0, std::min( 255, green ) );
168 blue = std::max( 0, std::min( 255, blue ) );
169
170 if ( renderAsTriangles() )
171 {
172 addPointToTriangulation( x, y, z, QColor( red, green, blue ), context );
173
174 // We don't want to render any points if we're rendering triangles and there is no preview painter
175 if ( !context.renderContext().previewRenderPainter() )
176 continue;
177 }
178
179 drawPoint( x, y, QColor( red, green, blue ), context );
180 if ( renderElevation )
181 drawPointToElevationMap( x, y, z, context );
182
183 rendered++;
184 }
185 }
186 context.incrementPointsRendered( rendered );
187}
188
189
191{
192 auto r = std::make_unique< QgsPointCloudRgbRenderer >();
193
194 r->setRedAttribute( element.attribute( QStringLiteral( "red" ), QStringLiteral( "Red" ) ) );
195 r->setGreenAttribute( element.attribute( QStringLiteral( "green" ), QStringLiteral( "Green" ) ) );
196 r->setBlueAttribute( element.attribute( QStringLiteral( "blue" ), QStringLiteral( "Blue" ) ) );
197
198 r->restoreCommonProperties( element, context );
199
200 //contrast enhancements
202 const QDomElement redContrastElem = element.firstChildElement( QStringLiteral( "redContrastEnhancement" ) );
203 if ( !redContrastElem.isNull() )
204 {
206 redContrastEnhancement->readXml( redContrastElem );
207 r->setRedContrastEnhancement( redContrastEnhancement );
208 }
209
211 const QDomElement greenContrastElem = element.firstChildElement( QStringLiteral( "greenContrastEnhancement" ) );
212 if ( !greenContrastElem.isNull() )
213 {
215 greenContrastEnhancement->readXml( greenContrastElem );
216 r->setGreenContrastEnhancement( greenContrastEnhancement );
217 }
218
220 const QDomElement blueContrastElem = element.firstChildElement( QStringLiteral( "blueContrastEnhancement" ) );
221 if ( !blueContrastElem.isNull() )
222 {
224 blueContrastEnhancement->readXml( blueContrastElem );
225 r->setBlueContrastEnhancement( blueContrastEnhancement );
226 }
227
228 return r.release();
229}
230
231QDomElement QgsPointCloudRgbRenderer::save( QDomDocument &doc, const QgsReadWriteContext &context ) const
232{
233 QDomElement rendererElem = doc.createElement( QStringLiteral( "renderer" ) );
234
235 rendererElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "rgb" ) );
236
237 rendererElem.setAttribute( QStringLiteral( "red" ), mRedAttribute );
238 rendererElem.setAttribute( QStringLiteral( "green" ), mGreenAttribute );
239 rendererElem.setAttribute( QStringLiteral( "blue" ), mBlueAttribute );
240
241 saveCommonProperties( rendererElem, context );
242
243 //contrast enhancement
244 if ( mRedContrastEnhancement )
245 {
246 QDomElement redContrastElem = doc.createElement( QStringLiteral( "redContrastEnhancement" ) );
247 mRedContrastEnhancement->writeXml( doc, redContrastElem );
248 rendererElem.appendChild( redContrastElem );
249 }
250 if ( mGreenContrastEnhancement )
251 {
252 QDomElement greenContrastElem = doc.createElement( QStringLiteral( "greenContrastEnhancement" ) );
253 mGreenContrastEnhancement->writeXml( doc, greenContrastElem );
254 rendererElem.appendChild( greenContrastElem );
255 }
256 if ( mBlueContrastEnhancement )
257 {
258 QDomElement blueContrastElem = doc.createElement( QStringLiteral( "blueContrastEnhancement" ) );
259 mBlueContrastEnhancement->writeXml( doc, blueContrastElem );
260 rendererElem.appendChild( blueContrastElem );
261 }
262
263 return rendererElem;
264}
265
267{
268 QSet<QString> res;
269 res << mRedAttribute << mGreenAttribute << mBlueAttribute;
270 return res;
271}
272
273std::unique_ptr<QgsPreparedPointCloudRendererData> QgsPointCloudRgbRenderer::prepare()
274{
275 auto data = std::make_unique< QgsPointCloudRgbRendererPreparedData >();
276 data->redAttribute = mRedAttribute;
277 if ( mRedContrastEnhancement )
278 data->redContrastEnhancement = std::make_unique<QgsContrastEnhancement>( *mRedContrastEnhancement );
279 data->greenAttribute = mGreenAttribute;
280 if ( mGreenContrastEnhancement )
281 data->greenContrastEnhancement = std::make_unique<QgsContrastEnhancement>( *mGreenContrastEnhancement );
282 data->blueAttribute = mBlueAttribute;
283 if ( mBlueContrastEnhancement )
284 data->blueContrastEnhancement = std::make_unique<QgsContrastEnhancement>( *mBlueContrastEnhancement );
285
286 data->useRedContrastEnhancement = mRedContrastEnhancement && mRedContrastEnhancement->contrastEnhancementAlgorithm() != QgsContrastEnhancement::NoEnhancement;
287 data->useBlueContrastEnhancement = mBlueContrastEnhancement && mBlueContrastEnhancement->contrastEnhancementAlgorithm() != QgsContrastEnhancement::NoEnhancement;
288 data->useGreenContrastEnhancement = mGreenContrastEnhancement && mGreenContrastEnhancement->contrastEnhancementAlgorithm() != QgsContrastEnhancement::NoEnhancement;
289
290 return data;
291}
292
297
299{
300 const QgsPointCloudAttributeCollection request = block->attributes();
301 redOffset = 0;
302 const QgsPointCloudAttribute *attribute = request.find( redAttribute, redOffset );
303 if ( !attribute )
304 return false;
305 redType = attribute->type();
306
307 greenOffset = 0;
308 attribute = request.find( greenAttribute, greenOffset );
309 if ( !attribute )
310 return false;
311 greenType = attribute->type();
312
313 blueOffset = 0;
314 attribute = request.find( blueAttribute, blueOffset );
315 if ( !attribute )
316 return false;
317 blueType = attribute->type();
318 return true;
319}
320
322{
323 const char *ptr = block->data();
324 const int pointRecordSize = block->pointRecordSize();
325
326 int red = 0;
327 QgsPointCloudRenderContext::getAttribute( ptr, i * pointRecordSize + redOffset, redType, red );
328 int green = 0;
329 QgsPointCloudRenderContext::getAttribute( ptr, i * pointRecordSize + greenOffset, greenType, green );
330 int blue = 0;
331 QgsPointCloudRenderContext::getAttribute( ptr, i * pointRecordSize + blueOffset, blueType, blue );
332
333 //skip if red, green or blue not in displayable range
334 if ( ( useRedContrastEnhancement && !redContrastEnhancement->isValueInDisplayableRange( red ) )
335 || ( useGreenContrastEnhancement && !greenContrastEnhancement->isValueInDisplayableRange( green ) )
336 || ( useBlueContrastEnhancement && !blueContrastEnhancement->isValueInDisplayableRange( blue ) ) )
337 {
338 return QColor();
339 }
340
341 //stretch color values
343 {
344 red = redContrastEnhancement->enhanceContrast( red );
345 }
347 {
348 green = greenContrastEnhancement->enhanceContrast( green );
349 }
351 {
352 blue = blueContrastEnhancement->enhanceContrast( blue );
353 }
354
355 red = std::max( 0, std::min( 255, red ) );
356 green = std::max( 0, std::min( 255, green ) );
357 blue = std::max( 0, std::min( 255, blue ) );
358
359 return QColor( red, green, blue );
360}
361
363{
364 return mRedAttribute;
365}
366
368{
369 mRedAttribute = redAttribute;
370}
371
373{
374 return mGreenAttribute;
375}
376
378{
379 mGreenAttribute = greenAttribute;
380}
381
383{
384 return mBlueAttribute;
385}
386
388{
389 mBlueAttribute = blueAttribute;
390}
391
393{
394 return mRedContrastEnhancement.get();
395}
396
398{
399 mRedContrastEnhancement.reset( enhancement );
400}
401
403{
404 return mGreenContrastEnhancement.get();
405}
406
408{
409 mGreenContrastEnhancement.reset( enhancement );
410}
411
413{
414 return mBlueContrastEnhancement.get();
415}
416
418{
419 mBlueContrastEnhancement.reset( enhancement );
420}
@ UnknownDataType
Unknown or unspecified type.
Definition qgis.h:373
Handles contrast enhancement and clipping.
@ NoEnhancement
Default color scaling algorithm, no scaling is applied.
Handles coordinate transforms between two coordinate systems.
void transformInPlace(double &x, double &y, double &z, Qgis::TransformDirection direction=Qgis::TransformDirection::Forward) const
Transforms an array of x, y and z double coordinates in place, from the source CRS to the destination...
bool isValid() const
Returns true if the coordinate transform is valid, ie both the source and destination CRS have been s...
Custom exception class for Coordinate Reference System related exceptions.
QgsRange which stores a range of double values.
Definition qgsrange.h:233
bool isInfinite() const
Returns true if the range consists of all possible values.
Definition qgsrange.h:287
A 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...
bool renderAsTriangles() const
Returns whether points are triangulated to render solid surface.
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 addPointToTriangulation(double x, double y, double z, const QColor &color, QgsPointCloudRenderContext &context)
Adds a point to the list of points to be triangulated (only used when renderAsTriangles() is enabled)...
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:137
A container for the context for various read/write operations on objects.
A rectangle specified with double values.
bool contains(const QgsRectangle &rect) const
Returns true when rectangle contains other rectangle.
void grow(double delta)
Grows the rectangle in place by the specified amount.
QgsElevationMap * elevationMap() const
Returns the destination elevation map for the render operation.
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...
QPainter * previewRenderPainter()
Returns the const destination QPainter for temporary in-progress preview renders.
QgsCoordinateTransform coordinateTransform() const
Returns the current coordinate transform for the context.