QGIS API Documentation  3.21.0-Master (909859188c)
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"
20 #include "qgscontrastenhancement.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 QgsDoubleRange zRange = context.renderContext().zRange();
89  const bool considerZ = !zRange.isInfinite();
90 
91  int rendered = 0;
92  double x = 0;
93  double y = 0;
94  double z = 0;
96  const bool reproject = ct.isValid();
97  for ( int i = 0; i < count; ++i )
98  {
99  if ( context.renderContext().renderingStopped() )
100  {
101  break;
102  }
103 
104  if ( considerZ )
105  {
106  // z value filtering is cheapest, if we're doing it...
107  z = pointZ( context, ptr, i );
108  if ( !zRange.contains( z ) )
109  continue;
110  }
111 
112  pointXY( context, ptr, i, x, y );
113  if ( visibleExtent.contains( x, y ) )
114  {
115  if ( reproject )
116  {
117  try
118  {
119  ct.transformInPlace( x, y, z );
120  }
121  catch ( QgsCsException & )
122  {
123  continue;
124  }
125  }
126 
127  int red = 0;
128  context.getAttribute( ptr, i * recordSize + redOffset, redType, red );
129  int green = 0;
130  context.getAttribute( ptr, i * recordSize + greenOffset, greenType, green );
131  int blue = 0;
132  context.getAttribute( ptr, i * recordSize + blueOffset, blueType, blue );
133 
134  //skip if red, green or blue not in displayable range
135  if ( ( useRedContrastEnhancement && !mRedContrastEnhancement->isValueInDisplayableRange( red ) )
136  || ( useGreenContrastEnhancement && !mGreenContrastEnhancement->isValueInDisplayableRange( green ) )
137  || ( useBlueContrastEnhancement && !mBlueContrastEnhancement->isValueInDisplayableRange( blue ) ) )
138  {
139  continue;
140  }
141 
142  //stretch color values
143  if ( useRedContrastEnhancement )
144  {
145  red = mRedContrastEnhancement->enhanceContrast( red );
146  }
147  if ( useGreenContrastEnhancement )
148  {
149  green = mGreenContrastEnhancement->enhanceContrast( green );
150  }
151  if ( useBlueContrastEnhancement )
152  {
153  blue = mBlueContrastEnhancement->enhanceContrast( blue );
154  }
155 
156  red = std::max( 0, std::min( 255, red ) );
157  green = std::max( 0, std::min( 255, green ) );
158  blue = std::max( 0, std::min( 255, blue ) );
159 
160  drawPoint( x, y, QColor( red, green, blue ), context );
161  rendered++;
162  }
163  }
164  context.incrementPointsRendered( rendered );
165 }
166 
167 
169 {
170  std::unique_ptr< QgsPointCloudRgbRenderer > r = std::make_unique< QgsPointCloudRgbRenderer >();
171 
172  r->setRedAttribute( element.attribute( QStringLiteral( "red" ), QStringLiteral( "Red" ) ) );
173  r->setGreenAttribute( element.attribute( QStringLiteral( "green" ), QStringLiteral( "Green" ) ) );
174  r->setBlueAttribute( element.attribute( QStringLiteral( "blue" ), QStringLiteral( "Blue" ) ) );
175 
176  r->restoreCommonProperties( element, context );
177 
178  //contrast enhancements
180  const QDomElement redContrastElem = element.firstChildElement( QStringLiteral( "redContrastEnhancement" ) );
181  if ( !redContrastElem.isNull() )
182  {
184  redContrastEnhancement->readXml( redContrastElem );
185  r->setRedContrastEnhancement( redContrastEnhancement );
186  }
187 
189  const QDomElement greenContrastElem = element.firstChildElement( QStringLiteral( "greenContrastEnhancement" ) );
190  if ( !greenContrastElem.isNull() )
191  {
193  greenContrastEnhancement->readXml( greenContrastElem );
194  r->setGreenContrastEnhancement( greenContrastEnhancement );
195  }
196 
198  const QDomElement blueContrastElem = element.firstChildElement( QStringLiteral( "blueContrastEnhancement" ) );
199  if ( !blueContrastElem.isNull() )
200  {
202  blueContrastEnhancement->readXml( blueContrastElem );
203  r->setBlueContrastEnhancement( blueContrastEnhancement );
204  }
205 
206  return r.release();
207 }
208 
209 QDomElement QgsPointCloudRgbRenderer::save( QDomDocument &doc, const QgsReadWriteContext &context ) const
210 {
211  QDomElement rendererElem = doc.createElement( QStringLiteral( "renderer" ) );
212 
213  rendererElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "rgb" ) );
214 
215  rendererElem.setAttribute( QStringLiteral( "red" ), mRedAttribute );
216  rendererElem.setAttribute( QStringLiteral( "green" ), mGreenAttribute );
217  rendererElem.setAttribute( QStringLiteral( "blue" ), mBlueAttribute );
218 
219  saveCommonProperties( rendererElem, context );
220 
221  //contrast enhancement
222  if ( mRedContrastEnhancement )
223  {
224  QDomElement redContrastElem = doc.createElement( QStringLiteral( "redContrastEnhancement" ) );
225  mRedContrastEnhancement->writeXml( doc, redContrastElem );
226  rendererElem.appendChild( redContrastElem );
227  }
228  if ( mGreenContrastEnhancement )
229  {
230  QDomElement greenContrastElem = doc.createElement( QStringLiteral( "greenContrastEnhancement" ) );
231  mGreenContrastEnhancement->writeXml( doc, greenContrastElem );
232  rendererElem.appendChild( greenContrastElem );
233  }
234  if ( mBlueContrastEnhancement )
235  {
236  QDomElement blueContrastElem = doc.createElement( QStringLiteral( "blueContrastEnhancement" ) );
237  mBlueContrastEnhancement->writeXml( doc, blueContrastElem );
238  rendererElem.appendChild( blueContrastElem );
239  }
240 
241  return rendererElem;
242 }
243 
245 {
246  QSet<QString> res;
247  res << mRedAttribute << mGreenAttribute << mBlueAttribute;
248  return res;
249 }
250 
252 {
253  return mRedAttribute;
254 }
255 
256 void QgsPointCloudRgbRenderer::setRedAttribute( const QString &redAttribute )
257 {
258  mRedAttribute = redAttribute;
259 }
260 
262 {
263  return mGreenAttribute;
264 }
265 
266 void QgsPointCloudRgbRenderer::setGreenAttribute( const QString &greenAttribute )
267 {
268  mGreenAttribute = greenAttribute;
269 }
270 
272 {
273  return mBlueAttribute;
274 }
275 
276 void QgsPointCloudRgbRenderer::setBlueAttribute( const QString &blueAttribute )
277 {
278  mBlueAttribute = blueAttribute;
279 }
280 
282 {
283  return mRedContrastEnhancement.get();
284 }
285 
287 {
288  mRedContrastEnhancement.reset( enhancement );
289 }
290 
292 {
293  return mGreenContrastEnhancement.get();
294 }
295 
297 {
298  mGreenContrastEnhancement.reset( enhancement );
299 }
300 
302 {
303  return mBlueContrastEnhancement.get();
304 }
305 
307 {
308  mBlueContrastEnhancement.reset( enhancement );
309 }
@ 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.
void transformInPlace(double &x, double &y, double &z, TransformDirection direction=ForwardTransform) const SIP_THROW(QgsCsException)
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.
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.
Encapsulates the render context for a 2D point cloud rendering operation.
void getAttribute(const char *data, std::size_t offset, QgsPointCloudAttribute::DataType type, T &value) const
Retrieves the attribute value from data at the specified offset, where type indicates the original da...
void incrementPointsRendered(long count)
Increments the count of points rendered by the specified amount.
QgsRenderContext & renderContext()
Returns a reference to the context's render context.
Abstract base class for 2d point cloud renderers.
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.
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
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.
const QgsRectangle & extent() const
When rendering a map layer, calling this method returns the "clipping" extent for the layer (in the l...