QGIS API Documentation  3.21.0-Master (56b4176581)
qgspointcloudclassifiedrenderer.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgspointcloudclassifiedrenderer.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 "qgsstyle.h"
21 #include "qgscolorramp.h"
22 #include "qgssymbollayerutils.h"
25 
26 QgsPointCloudCategory::QgsPointCloudCategory( const int value, const QColor &color, const QString &label, bool render )
27  : mValue( value )
28  , mColor( color )
29  , mLabel( label )
30  , mRender( render )
31 {
32 }
33 
34 
35 //
36 // QgsPointCloudClassifiedRenderer
37 //
38 
40  : mCategories( defaultCategories() )
41 {
42 }
43 
45 {
46  return QStringLiteral( "classified" );
47 }
48 
50 {
51  std::unique_ptr< QgsPointCloudClassifiedRenderer > res = std::make_unique< QgsPointCloudClassifiedRenderer >();
52  res->mAttribute = mAttribute;
53  res->mCategories = mCategories;
54 
55  copyCommonProperties( res.get() );
56 
57  return res.release();
58 }
59 
61 {
62  const QgsRectangle visibleExtent = context.renderContext().extent();
63 
64  const char *ptr = block->data();
65  int count = block->pointCount();
66  const QgsPointCloudAttributeCollection request = block->attributes();
67 
68  const std::size_t recordSize = request.pointRecordSize();
69  int attributeOffset = 0;
70  const QgsPointCloudAttribute *attribute = request.find( mAttribute, attributeOffset );
71  if ( !attribute )
72  return;
73  const QgsPointCloudAttribute::DataType attributeType = attribute->type();
74 
75  const QgsDoubleRange zRange = context.renderContext().zRange();
76  const bool considerZ = !zRange.isInfinite();
77 
78  int rendered = 0;
79  double x = 0;
80  double y = 0;
81  double z = 0;
83  const bool reproject = ct.isValid();
84 
85  QHash< int, QColor > colors;
86  for ( const QgsPointCloudCategory &category : std::as_const( mCategories ) )
87  {
88  if ( !category.renderState() )
89  continue;
90 
91  colors.insert( category.value(), category.color() );
92  }
93 
94  for ( int i = 0; i < count; ++i )
95  {
96  if ( context.renderContext().renderingStopped() )
97  {
98  break;
99  }
100 
101  if ( considerZ )
102  {
103  // z value filtering is cheapest, if we're doing it...
104  z = pointZ( context, ptr, i );
105  if ( !zRange.contains( z ) )
106  continue;
107  }
108 
109  int attributeValue = 0;
110  context.getAttribute( ptr, i * recordSize + attributeOffset, attributeType, attributeValue );
111  const QColor color = colors.value( attributeValue );
112  if ( !color.isValid() )
113  continue;
114 
115  pointXY( context, ptr, i, x, y );
116  if ( visibleExtent.contains( x, y ) )
117  {
118  if ( reproject )
119  {
120  try
121  {
122  ct.transformInPlace( x, y, z );
123  }
124  catch ( QgsCsException & )
125  {
126  continue;
127  }
128  }
129 
130  drawPoint( x, y, color, context );
131  rendered++;
132  }
133  }
134  context.incrementPointsRendered( rendered );
135 }
136 
137 bool QgsPointCloudClassifiedRenderer::willRenderPoint( const QVariantMap &pointAttributes )
138 {
139  if ( !pointAttributes.contains( mAttribute ) )
140  return false;
141  bool parsedCorrectly;
142  int attributeInt = pointAttributes[ mAttribute ].toInt( &parsedCorrectly );
143  if ( !parsedCorrectly )
144  return false;
145  for ( const QgsPointCloudCategory &category : std::as_const( mCategories ) )
146  {
147  if ( category.value() == attributeInt )
148  return category.renderState();
149  }
150  return false;
151 }
152 
154 {
155  std::unique_ptr< QgsPointCloudClassifiedRenderer > r = std::make_unique< QgsPointCloudClassifiedRenderer >();
156 
157  r->setAttribute( element.attribute( QStringLiteral( "attribute" ), QStringLiteral( "Classification" ) ) );
158 
160  const QDomElement catsElem = element.firstChildElement( QStringLiteral( "categories" ) );
161  if ( !catsElem.isNull() )
162  {
163  QDomElement catElem = catsElem.firstChildElement();
164  while ( !catElem.isNull() )
165  {
166  if ( catElem.tagName() == QLatin1String( "category" ) )
167  {
168  const int value = catElem.attribute( QStringLiteral( "value" ) ).toInt();
169  const QString label = catElem.attribute( QStringLiteral( "label" ) );
170  const bool render = catElem.attribute( QStringLiteral( "render" ) ) != QLatin1String( "false" );
171  const QColor color = QgsSymbolLayerUtils::decodeColor( catElem.attribute( QStringLiteral( "color" ) ) );
172  categories.append( QgsPointCloudCategory( value, color, label, render ) );
173  }
174  catElem = catElem.nextSiblingElement();
175  }
176  r->setCategories( categories );
177  }
178 
179  r->restoreCommonProperties( element, context );
180 
181  return r.release();
182 }
183 
185 {
203  << QgsPointCloudCategory( 18, QColor( 100, 100, 100 ), QgsPointCloudDataProvider::translatedLasClassificationCodes().value( 18 ) );
204 }
205 
206 QDomElement QgsPointCloudClassifiedRenderer::save( QDomDocument &doc, const QgsReadWriteContext &context ) const
207 {
208  QDomElement rendererElem = doc.createElement( QStringLiteral( "renderer" ) );
209 
210  rendererElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "classified" ) );
211  rendererElem.setAttribute( QStringLiteral( "attribute" ), mAttribute );
212 
213  // categories
214  QDomElement catsElem = doc.createElement( QStringLiteral( "categories" ) );
215  for ( const QgsPointCloudCategory &category : mCategories )
216  {
217  QDomElement catElem = doc.createElement( QStringLiteral( "category" ) );
218  catElem.setAttribute( QStringLiteral( "value" ), QString::number( category.value() ) );
219  catElem.setAttribute( QStringLiteral( "label" ), category.label() );
220  catElem.setAttribute( QStringLiteral( "color" ), QgsSymbolLayerUtils::encodeColor( category.color() ) );
221  catElem.setAttribute( QStringLiteral( "render" ), category.renderState() ? "true" : "false" );
222  catsElem.appendChild( catElem );
223  }
224  rendererElem.appendChild( catsElem );
225 
226  saveCommonProperties( rendererElem, context );
227 
228  return rendererElem;
229 }
230 
232 {
233  QSet<QString> res;
234  res << mAttribute;
235  return res;
236 }
237 
238 QList<QgsLayerTreeModelLegendNode *> QgsPointCloudClassifiedRenderer::createLegendNodes( QgsLayerTreeLayer *nodeLayer )
239 {
240  QList<QgsLayerTreeModelLegendNode *> nodes;
241 
242  for ( const QgsPointCloudCategory &category : std::as_const( mCategories ) )
243  {
244  nodes << new QgsRasterSymbolLegendNode( nodeLayer, category.color(), category.label(), nullptr, true, QString::number( category.value() ) );
245  }
246 
247  return nodes;
248 }
249 
251 {
252  QStringList res;
253  for ( const QgsPointCloudCategory &category : std::as_const( mCategories ) )
254  {
255  res << QString::number( category.value() );
256  }
257  return res;
258 }
259 
261 {
262  bool ok = false;
263  const int value = key.toInt( &ok );
264  if ( !ok )
265  return false;
266 
267  for ( const QgsPointCloudCategory &category : std::as_const( mCategories ) )
268  {
269  if ( category.value() == value )
270  return category.renderState();
271  }
272  return false;
273 }
274 
275 void QgsPointCloudClassifiedRenderer::checkLegendItem( const QString &key, bool state )
276 {
277  bool ok = false;
278  const int value = key.toInt( &ok );
279  if ( !ok )
280  return;
281 
282  for ( auto it = mCategories.begin(); it != mCategories.end(); ++it )
283  {
284  if ( it->value() == value )
285  {
286  it->setRenderState( state );
287  return;
288  }
289  }
290 }
291 
293 {
294  return mAttribute;
295 }
296 
297 void QgsPointCloudClassifiedRenderer::setAttribute( const QString &attribute )
298 {
299  mAttribute = attribute;
300 }
301 
303 {
304  return mCategories;
305 }
306 
308 {
309  mCategories = categories;
310 }
311 
313 {
314  mCategories.append( category );
315 }
316 
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
Layer tree node points to a map layer.
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.
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.
Represents an individual category (class) from a QgsPointCloudClassifiedRenderer.
QgsPointCloudCategory()=default
Constructor for QgsPointCloudCategory.
void addCategory(const QgsPointCloudCategory &category)
Adds a category to the renderer.
QString attribute() const
Returns the attribute to use for the renderer.
bool willRenderPoint(const QVariantMap &pointAttributes) override
QDomElement save(QDomDocument &doc, const QgsReadWriteContext &context) const override
Saves the renderer configuration to an XML element.
void checkLegendItem(const QString &key, bool state=true) override
Called when the check state of the legend item with the specified key is changed.
QSet< QString > usedAttributes(const QgsPointCloudRenderContext &context) const override
Returns a list of attributes required by this renderer.
static QgsPointCloudRenderer * create(QDomElement &element, const QgsReadWriteContext &context)
Creates an RGB renderer from an XML element.
QgsPointCloudCategoryList categories() const
Returns the classification categories used for rendering.
static QgsPointCloudCategoryList defaultCategories()
Returns the default list of categories.
bool legendItemChecked(const QString &key) override
Returns true if the legend item with the specified key is checked.
QgsPointCloudRenderer * clone() const override
Create a deep copy of this renderer.
void setCategories(const QgsPointCloudCategoryList &categories)
Sets the classification categories used for rendering.
QList< QgsLayerTreeModelLegendNode * > createLegendNodes(QgsLayerTreeLayer *nodeLayer) override
Creates a set of legend nodes representing the renderer.
void renderBlock(const QgsPointCloudBlock *block, QgsPointCloudRenderContext &context) override
Renders a block of point cloud data using the specified render context.
QStringList legendRuleKeys() const override
Returns a list of all rule keys for legend nodes created by the renderer.
void setAttribute(const QString &attribute)
Sets the attribute to use for the renderer.
QString type() const override
Returns the identifier of the renderer type.
QgsPointCloudClassifiedRenderer()
Constructor for QgsPointCloudClassifiedRenderer.
static QMap< int, QString > translatedLasClassificationCodes()
Returns the map of LAS classification code to translated string value, corresponding to the ASPRS Sta...
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.
bool contains(const QgsRange< T > &other) const
Returns true if this range contains another range.
Definition: qgsrange.h:108
Implementation of legend node interface for displaying raster legend entries.
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...
static QColor decodeColor(const QString &str)
static QString encodeColor(const QColor &color)
QList< QgsPointCloudCategory > QgsPointCloudCategoryList