QGIS API Documentation  3.18.1-Zürich (202f1bf7e5)
qgspointcloud3dsymbol_p.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgspointcloud3dsymbol_p.cpp
3  ------------------------------
4  Date : December 2020
5  Copyright : (C) 2020 by Nedjima Belgacem
6  Email : belgacem dot nedjima at gmail dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
17 
19 
20 #include "qgspointcloud3dsymbol.h"
21 #include "qgsapplication.h"
22 #include "qgs3dsymbolregistry.h"
23 #include "qgspointcloudattribute.h"
24 #include "qgspointcloudrequest.h"
25 #include "qgscolorramptexture.h"
26 #include "qgs3dmapsettings.h"
27 #include "qgspointcloudindex.h"
28 
29 #include <Qt3DRender/QGeometryRenderer>
30 #include <Qt3DRender/QAttribute>
31 #include <Qt3DRender/QTechnique>
32 #include <Qt3DRender/QShaderProgram>
33 #include <Qt3DRender/QGraphicsApiFilter>
34 #include <Qt3DRender/QEffect>
35 #include <QPointSize>
36 #include <QUrl>
37 
38 QgsPointCloud3DGeometry::QgsPointCloud3DGeometry( Qt3DCore::QNode *parent, unsigned int byteStride )
39  : Qt3DRender::QGeometry( parent )
40  , mPositionAttribute( new Qt3DRender::QAttribute( this ) )
41  , mParameterAttribute( new Qt3DRender::QAttribute( this ) )
42  , mColorAttribute( new Qt3DRender::QAttribute( this ) )
43 #if QT_VERSION < QT_VERSION_CHECK(5, 10, 0)
44  , mVertexBuffer( new Qt3DRender::QBuffer( Qt3DRender::QBuffer::VertexBuffer, this ) )
45 #else
46  , mVertexBuffer( new Qt3DRender::QBuffer( this ) )
47 #endif
48  , mByteStride( byteStride )
49 {
50 
51 }
52 
53 QgsSingleColorPointCloud3DGeometry::QgsSingleColorPointCloud3DGeometry( Qt3DCore::QNode *parent, const QgsPointCloud3DSymbolHandler::PointData &data, unsigned int byteStride )
54  : QgsPointCloud3DGeometry( parent, byteStride )
55 {
56  mPositionAttribute->setAttributeType( Qt3DRender::QAttribute::VertexAttribute );
57  mPositionAttribute->setBuffer( mVertexBuffer );
58  mPositionAttribute->setVertexBaseType( Qt3DRender::QAttribute::Float );
59  mPositionAttribute->setVertexSize( 3 );
60  mPositionAttribute->setName( Qt3DRender::QAttribute::defaultPositionAttributeName() );
61  mPositionAttribute->setByteOffset( 0 );
62  mPositionAttribute->setByteStride( mByteStride );
63  addAttribute( mPositionAttribute );
64  makeVertexBuffer( data );
65 }
66 
67 void QgsSingleColorPointCloud3DGeometry::makeVertexBuffer( const QgsPointCloud3DSymbolHandler::PointData &data )
68 {
69  QByteArray vertexBufferData;
70  vertexBufferData.resize( data.positions.size() * mByteStride );
71  float *rawVertexArray = reinterpret_cast<float *>( vertexBufferData.data() );
72  int idx = 0;
73  for ( int i = 0; i < data.positions.size(); ++i )
74  {
75  rawVertexArray[idx++] = data.positions.at( i ).x();
76  rawVertexArray[idx++] = data.positions.at( i ).y();
77  rawVertexArray[idx++] = data.positions.at( i ).z();
78  }
79 
80  mVertexCount = data.positions.size();
81  mVertexBuffer->setData( vertexBufferData );
82 }
83 
84 QgsColorRampPointCloud3DGeometry::QgsColorRampPointCloud3DGeometry( Qt3DCore::QNode *parent, const QgsPointCloud3DSymbolHandler::PointData &data, unsigned int byteStride )
85  : QgsPointCloud3DGeometry( parent, byteStride )
86 {
87  mPositionAttribute->setAttributeType( Qt3DRender::QAttribute::VertexAttribute );
88  mPositionAttribute->setBuffer( mVertexBuffer );
89  mPositionAttribute->setVertexBaseType( Qt3DRender::QAttribute::Float );
90  mPositionAttribute->setVertexSize( 3 );
91  mPositionAttribute->setName( Qt3DRender::QAttribute::defaultPositionAttributeName() );
92  mPositionAttribute->setByteOffset( 0 );
93  mPositionAttribute->setByteStride( mByteStride );
94  addAttribute( mPositionAttribute );
95  mParameterAttribute->setAttributeType( Qt3DRender::QAttribute::VertexAttribute );
96  mParameterAttribute->setBuffer( mVertexBuffer );
97  mParameterAttribute->setVertexBaseType( Qt3DRender::QAttribute::Float );
98  mParameterAttribute->setVertexSize( 1 );
99  mParameterAttribute->setName( "vertexParameter" );
100  mParameterAttribute->setByteOffset( 12 );
101  mParameterAttribute->setByteStride( mByteStride );
102  addAttribute( mParameterAttribute );
103  makeVertexBuffer( data );
104 }
105 
106 void QgsColorRampPointCloud3DGeometry::makeVertexBuffer( const QgsPointCloud3DSymbolHandler::PointData &data )
107 {
108  QByteArray vertexBufferData;
109  vertexBufferData.resize( data.positions.size() * mByteStride );
110  float *rawVertexArray = reinterpret_cast<float *>( vertexBufferData.data() );
111  int idx = 0;
112  Q_ASSERT( data.positions.size() == data.parameter.size() );
113  for ( int i = 0; i < data.positions.size(); ++i )
114  {
115  rawVertexArray[idx++] = data.positions.at( i ).x();
116  rawVertexArray[idx++] = data.positions.at( i ).y();
117  rawVertexArray[idx++] = data.positions.at( i ).z();
118  rawVertexArray[idx++] = data.parameter.at( i );
119  }
120 
121  mVertexCount = data.positions.size();
122  mVertexBuffer->setData( vertexBufferData );
123 }
124 
125 QgsRGBPointCloud3DGeometry::QgsRGBPointCloud3DGeometry( Qt3DCore::QNode *parent, const QgsPointCloud3DSymbolHandler::PointData &data, unsigned int byteStride )
126  : QgsPointCloud3DGeometry( parent, byteStride )
127 {
128  mPositionAttribute->setAttributeType( Qt3DRender::QAttribute::VertexAttribute );
129  mPositionAttribute->setBuffer( mVertexBuffer );
130  mPositionAttribute->setVertexBaseType( Qt3DRender::QAttribute::Float );
131  mPositionAttribute->setVertexSize( 3 );
132  mPositionAttribute->setName( Qt3DRender::QAttribute::defaultPositionAttributeName() );
133  mPositionAttribute->setByteOffset( 0 );
134  mPositionAttribute->setByteStride( mByteStride );
135  addAttribute( mPositionAttribute );
136  mColorAttribute->setAttributeType( Qt3DRender::QAttribute::VertexAttribute );
137  mColorAttribute->setBuffer( mVertexBuffer );
138  mColorAttribute->setVertexBaseType( Qt3DRender::QAttribute::Float );
139  mColorAttribute->setVertexSize( 3 );
140  mColorAttribute->setName( QStringLiteral( "vertexColor" ) );
141  mColorAttribute->setByteOffset( 12 );
142  mColorAttribute->setByteStride( mByteStride );
143  addAttribute( mColorAttribute );
144  makeVertexBuffer( data );
145 }
146 
147 void QgsRGBPointCloud3DGeometry::makeVertexBuffer( const QgsPointCloud3DSymbolHandler::PointData &data )
148 {
149  QByteArray vertexBufferData;
150  vertexBufferData.resize( data.positions.size() * mByteStride );
151  float *rawVertexArray = reinterpret_cast<float *>( vertexBufferData.data() );
152  int idx = 0;
153  Q_ASSERT( data.positions.size() == data.colors.size() );
154  for ( int i = 0; i < data.positions.size(); ++i )
155  {
156  rawVertexArray[idx++] = data.positions.at( i ).x();
157  rawVertexArray[idx++] = data.positions.at( i ).y();
158  rawVertexArray[idx++] = data.positions.at( i ).z();
159  rawVertexArray[idx++] = data.colors.at( i ).x();
160  rawVertexArray[idx++] = data.colors.at( i ).y();
161  rawVertexArray[idx++] = data.colors.at( i ).z();
162  }
163  mVertexCount = data.positions.size();
164  mVertexBuffer->setData( vertexBufferData );
165 }
166 
167 QgsPointCloud3DSymbolHandler::QgsPointCloud3DSymbolHandler()
168 {
169 }
170 
171 void QgsPointCloud3DSymbolHandler::makeEntity( Qt3DCore::QEntity *parent, const QgsPointCloud3DRenderContext &context, QgsPointCloud3DSymbolHandler::PointData &out, bool selected )
172 {
173  Q_UNUSED( selected )
174 
175  if ( out.positions.empty() )
176  return;
177 
178  // Geometry
179  Qt3DRender::QGeometry *geom = makeGeometry( parent, out, context.symbol()->byteStride() );
180  Qt3DRender::QGeometryRenderer *gr = new Qt3DRender::QGeometryRenderer;
181  gr->setPrimitiveType( Qt3DRender::QGeometryRenderer::Points );
182  gr->setVertexCount( out.positions.count() );
183  gr->setGeometry( geom );
184 
185  // Transform
186  Qt3DCore::QTransform *tr = new Qt3DCore::QTransform;
187 
188  // Material
189  Qt3DRender::QMaterial *mat = new Qt3DRender::QMaterial;
190  if ( context.symbol() )
191  context.symbol()->fillMaterial( mat );
192 
193  Qt3DRender::QShaderProgram *shaderProgram = new Qt3DRender::QShaderProgram( mat );
194  shaderProgram->setVertexShaderCode( Qt3DRender::QShaderProgram::loadSource( QUrl( QStringLiteral( "qrc:/shaders/pointcloud.vert" ) ) ) );
195  shaderProgram->setFragmentShaderCode( Qt3DRender::QShaderProgram::loadSource( QUrl( QStringLiteral( "qrc:/shaders/pointcloud.frag" ) ) ) );
196 
197  Qt3DRender::QRenderPass *renderPass = new Qt3DRender::QRenderPass( mat );
198  renderPass->setShaderProgram( shaderProgram );
199 
200  Qt3DRender::QPointSize *pointSize = new Qt3DRender::QPointSize( renderPass );
201  pointSize->setSizeMode( Qt3DRender::QPointSize::Programmable ); // supported since OpenGL 3.2
202  pointSize->setValue( context.symbol() ? context.symbol()->pointSize() : 1.0f );
203  renderPass->addRenderState( pointSize );
204 
205  // without this filter the default forward renderer would not render this
206  Qt3DRender::QFilterKey *filterKey = new Qt3DRender::QFilterKey;
207  filterKey->setName( QStringLiteral( "renderingStyle" ) );
208  filterKey->setValue( "forward" );
209 
210  Qt3DRender::QTechnique *technique = new Qt3DRender::QTechnique;
211  technique->addRenderPass( renderPass );
212  technique->addFilterKey( filterKey );
213  technique->graphicsApiFilter()->setApi( Qt3DRender::QGraphicsApiFilter::OpenGL );
214  technique->graphicsApiFilter()->setProfile( Qt3DRender::QGraphicsApiFilter::CoreProfile );
215  technique->graphicsApiFilter()->setMajorVersion( 3 );
216  technique->graphicsApiFilter()->setMinorVersion( 1 );
217 
218  Qt3DRender::QEffect *eff = new Qt3DRender::QEffect;
219  eff->addTechnique( technique );
220  mat->setEffect( eff );
221 
222  // All together
223  Qt3DCore::QEntity *entity = new Qt3DCore::QEntity;
224  entity->addComponent( gr );
225  entity->addComponent( tr );
226  entity->addComponent( mat );
227  entity->setParent( parent );
228  // cppcheck wrongly believes entity will leak
229  // cppcheck-suppress memleak
230 }
231 
232 QgsSingleColorPointCloud3DSymbolHandler::QgsSingleColorPointCloud3DSymbolHandler()
233  : QgsPointCloud3DSymbolHandler()
234 {
235 
236 }
237 
238 bool QgsSingleColorPointCloud3DSymbolHandler::prepare( const QgsPointCloud3DRenderContext &context )
239 {
240  Q_UNUSED( context )
241  return true;
242 }
243 
244 void QgsSingleColorPointCloud3DSymbolHandler::processNode( QgsPointCloudIndex *pc, const IndexedPointCloudNode &n, const QgsPointCloud3DRenderContext &context )
245 {
247  attributes.push_back( QgsPointCloudAttribute( QStringLiteral( "X" ), QgsPointCloudAttribute::Int32 ) );
248  attributes.push_back( QgsPointCloudAttribute( QStringLiteral( "Y" ), QgsPointCloudAttribute::Int32 ) );
249  attributes.push_back( QgsPointCloudAttribute( QStringLiteral( "Z" ), QgsPointCloudAttribute::Int32 ) );
250 
251  QgsPointCloudRequest request;
252  request.setAttributes( attributes );
253  std::unique_ptr<QgsPointCloudBlock> block( pc->nodeData( n, request ) );
254  if ( !block )
255  return;
256 
257  const char *ptr = block->data();
258  int count = block->pointCount();
259  const std::size_t recordSize = attributes.pointRecordSize();
260 
261  const QgsVector3D scale = pc->scale();
262  const QgsVector3D offset = pc->offset();
263  const double zValueScale = context.zValueScale();
264  const double zValueOffset = context.zValueFixedOffset();
265  QgsCoordinateTransform coordinateTransform = context.coordinateTransform();
266  bool alreadyPrintedDebug = false;
267 
268  for ( int i = 0; i < count; ++i )
269  {
270  if ( context.isCanceled() )
271  break;
272 
273  qint32 ix = *( qint32 * )( ptr + i * recordSize + 0 );
274  qint32 iy = *( qint32 * )( ptr + i * recordSize + 4 );
275  qint32 iz = *( qint32 * )( ptr + i * recordSize + 8 );
276 
277  double x = offset.x() + scale.x() * ix;
278  double y = offset.y() + scale.y() * iy;
279  double z = ( offset.z() + scale.z() * iz ) * zValueScale + zValueOffset;
280  try
281  {
282  coordinateTransform.transformInPlace( x, y, z );
283  }
284  catch ( QgsCsException &e )
285  {
286  if ( !alreadyPrintedDebug )
287  {
288  QgsDebugMsg( QStringLiteral( "Error transforming point coordinate" ) );
289  alreadyPrintedDebug = true;
290  }
291  }
292  QgsVector3D point( x, y, z );
293  QgsVector3D p = context.map().mapToWorldCoordinates( QgsVector3D( x, y, z ) );
294  outNormal.positions.push_back( QVector3D( p.x(), p.y(), p.z() ) );
295  }
296 }
297 
298 void QgsSingleColorPointCloud3DSymbolHandler::finalize( Qt3DCore::QEntity *parent, const QgsPointCloud3DRenderContext &context )
299 {
300  makeEntity( parent, context, outNormal, false );
301 }
302 
303 Qt3DRender::QGeometry *QgsSingleColorPointCloud3DSymbolHandler::makeGeometry( Qt3DCore::QNode *parent, const QgsPointCloud3DSymbolHandler::PointData &data, unsigned int byteStride )
304 {
305  return new QgsSingleColorPointCloud3DGeometry( parent, data, byteStride );
306 }
307 
308 QgsColorRampPointCloud3DSymbolHandler::QgsColorRampPointCloud3DSymbolHandler()
309  : QgsPointCloud3DSymbolHandler()
310 {
311 
312 }
313 
314 bool QgsColorRampPointCloud3DSymbolHandler::prepare( const QgsPointCloud3DRenderContext &context )
315 {
316  Q_UNUSED( context )
317  return true;
318 }
319 
320 void QgsColorRampPointCloud3DSymbolHandler::processNode( QgsPointCloudIndex *pc, const IndexedPointCloudNode &n, const QgsPointCloud3DRenderContext &context )
321 {
323  const int xOffset = 0;
324  attributes.push_back( QgsPointCloudAttribute( QStringLiteral( "X" ), QgsPointCloudAttribute::Int32 ) );
325  const int yOffset = attributes.pointRecordSize();
326  attributes.push_back( QgsPointCloudAttribute( QStringLiteral( "Y" ), QgsPointCloudAttribute::Int32 ) );
327  const int zOffset = attributes.pointRecordSize();
328  attributes.push_back( QgsPointCloudAttribute( QStringLiteral( "Z" ), QgsPointCloudAttribute::Int32 ) );
329 
330  QString attributeName;
331  bool attrIsX = false;
332  bool attrIsY = false;
333  bool attrIsZ = false;
335  int attributeOffset = 0;
336  const double zValueScale = context.zValueScale();
337  const double zValueOffset = context.zValueFixedOffset();
338  QgsCoordinateTransform coordinateTransform = context.coordinateTransform();
339  bool alreadyPrintedDebug = false;
340 
341  QgsColorRampPointCloud3DSymbol *symbol = dynamic_cast<QgsColorRampPointCloud3DSymbol *>( context.symbol() );
342  if ( symbol )
343  {
344  int offset = 0;
345  QgsPointCloudAttributeCollection collection = context.attributes();
346 
347  if ( symbol->attribute() == QLatin1String( "X" ) )
348  {
349  attrIsX = true;
350  }
351  else if ( symbol->attribute() == QLatin1String( "Y" ) )
352  {
353  attrIsY = true;
354  }
355  else if ( symbol->attribute() == QLatin1String( "Z" ) )
356  {
357  attrIsZ = true;
358  }
359  else
360  {
361  const QgsPointCloudAttribute *attr = collection.find( symbol->attribute(), offset );
362  if ( attr )
363  {
364  attributeType = attr->type();
365  attributeName = attr->name();
366  attributeOffset = attributes.pointRecordSize();
367  attributes.push_back( *attr );
368  }
369  }
370  }
371 
372  if ( attributeName.isEmpty() && !attrIsX && !attrIsY && !attrIsZ )
373  return;
374 
375  QgsPointCloudRequest request;
376  request.setAttributes( attributes );
377  std::unique_ptr<QgsPointCloudBlock> block( pc->nodeData( n, request ) );
378  if ( !block )
379  return;
380 
381  const char *ptr = block->data();
382  int count = block->pointCount();
383  const std::size_t recordSize = attributes.pointRecordSize();
384 
385  const QgsVector3D scale = pc->scale();
386  const QgsVector3D offset = pc->offset();
387 
388  for ( int i = 0; i < count; ++i )
389  {
390  if ( context.isCanceled() )
391  break;
392 
393  qint32 ix = *( qint32 * )( ptr + i * recordSize + xOffset );
394  qint32 iy = *( qint32 * )( ptr + i * recordSize + yOffset );
395  qint32 iz = *( qint32 * )( ptr + i * recordSize + zOffset );
396 
397  double x = offset.x() + scale.x() * ix;
398  double y = offset.y() + scale.y() * iy;
399  double z = ( offset.z() + scale.z() * iz ) * zValueScale + zValueOffset;
400  try
401  {
402  coordinateTransform.transformInPlace( x, y, z );
403  }
404  catch ( QgsCsException &e )
405  {
406  if ( !alreadyPrintedDebug )
407  {
408  QgsDebugMsg( QStringLiteral( "Error transforming point coordinate" ) );
409  alreadyPrintedDebug = true;
410  }
411  }
412  QgsVector3D point( x, y, z );
413  point = context.map().mapToWorldCoordinates( point );
414  outNormal.positions.push_back( QVector3D( point.x(), point.y(), point.z() ) );
415 
416  if ( attrIsX )
417  outNormal.parameter.push_back( x );
418  else if ( attrIsY )
419  outNormal.parameter.push_back( y );
420  else if ( attrIsZ )
421  outNormal.parameter.push_back( z );
422  else
423  {
424  float iParam = 0.0f;
425  context.getAttribute( ptr, i * recordSize + attributeOffset, attributeType, iParam );
426  outNormal.parameter.push_back( iParam );
427  }
428  }
429 }
430 
431 void QgsColorRampPointCloud3DSymbolHandler::finalize( Qt3DCore::QEntity *parent, const QgsPointCloud3DRenderContext &context )
432 {
433  makeEntity( parent, context, outNormal, false );
434 }
435 
436 Qt3DRender::QGeometry *QgsColorRampPointCloud3DSymbolHandler::makeGeometry( Qt3DCore::QNode *parent, const QgsPointCloud3DSymbolHandler::PointData &data, unsigned int byteStride )
437 {
438  return new QgsColorRampPointCloud3DGeometry( parent, data, byteStride );
439 }
440 
441 QgsRGBPointCloud3DSymbolHandler::QgsRGBPointCloud3DSymbolHandler()
442  : QgsPointCloud3DSymbolHandler()
443 {
444 
445 }
446 
447 bool QgsRGBPointCloud3DSymbolHandler::prepare( const QgsPointCloud3DRenderContext &context )
448 {
449  Q_UNUSED( context )
450  return true;
451 }
452 
453 void QgsRGBPointCloud3DSymbolHandler::processNode( QgsPointCloudIndex *pc, const IndexedPointCloudNode &n, const QgsPointCloud3DRenderContext &context )
454 {
456  attributes.push_back( QgsPointCloudAttribute( QStringLiteral( "X" ), QgsPointCloudAttribute::Int32 ) );
457  attributes.push_back( QgsPointCloudAttribute( QStringLiteral( "Y" ), QgsPointCloudAttribute::Int32 ) );
458  attributes.push_back( QgsPointCloudAttribute( QStringLiteral( "Z" ), QgsPointCloudAttribute::Int32 ) );
459 
460  QgsRgbPointCloud3DSymbol *symbol = dynamic_cast<QgsRgbPointCloud3DSymbol *>( context.symbol() );
461 
462  // we have to get the RGB attributes using their real data types -- they aren't always short! (sometimes unsigned short)
463  int attrOffset = 0 ;
464 
465  const int redOffset = attributes.pointRecordSize();
466  const QgsPointCloudAttribute *colorAttribute = context.attributes().find( symbol->redAttribute(), attrOffset );
467  attributes.push_back( *colorAttribute );
468  const QgsPointCloudAttribute::DataType redType = colorAttribute->type();
469 
470  const int greenOffset = attributes.pointRecordSize();
471  colorAttribute = context.attributes().find( symbol->greenAttribute(), attrOffset );
472  attributes.push_back( *colorAttribute );
473  const QgsPointCloudAttribute::DataType greenType = colorAttribute->type();
474 
475  const int blueOffset = attributes.pointRecordSize();
476  colorAttribute = context.attributes().find( symbol->blueAttribute(), attrOffset );
477  attributes.push_back( *colorAttribute );
478  const QgsPointCloudAttribute::DataType blueType = colorAttribute->type();
479 
480  QgsPointCloudRequest request;
481  request.setAttributes( attributes );
482  std::unique_ptr<QgsPointCloudBlock> block( pc->nodeData( n, request ) );
483  if ( !block )
484  return;
485 
486  const char *ptr = block->data();
487  int count = block->pointCount();
488  const std::size_t recordSize = attributes.pointRecordSize();
489 
490  const QgsVector3D scale = pc->scale();
491  const QgsVector3D offset = pc->offset();
492  const double zValueScale = context.zValueScale();
493  const double zValueOffset = context.zValueFixedOffset();
494  QgsCoordinateTransform coordinateTransform = context.coordinateTransform();
495  bool alreadyPrintedDebug = false;
496 
497  QgsContrastEnhancement *redContrastEnhancement = symbol->redContrastEnhancement();
498  QgsContrastEnhancement *greenContrastEnhancement = symbol->greenContrastEnhancement();
499  QgsContrastEnhancement *blueContrastEnhancement = symbol->blueContrastEnhancement();
500 
501  const bool useRedContrastEnhancement = redContrastEnhancement && redContrastEnhancement->contrastEnhancementAlgorithm() != QgsContrastEnhancement::NoEnhancement;
502  const bool useBlueContrastEnhancement = blueContrastEnhancement && blueContrastEnhancement->contrastEnhancementAlgorithm() != QgsContrastEnhancement::NoEnhancement;
503  const bool useGreenContrastEnhancement = greenContrastEnhancement && greenContrastEnhancement->contrastEnhancementAlgorithm() != QgsContrastEnhancement::NoEnhancement;
504 
505  int ir = 0;
506  int ig = 0;
507  int ib = 0;
508  for ( int i = 0; i < count; ++i )
509  {
510  if ( context.isCanceled() )
511  break;
512 
513  qint32 ix = *( qint32 * )( ptr + i * recordSize + 0 );
514  qint32 iy = *( qint32 * )( ptr + i * recordSize + 4 );
515  qint32 iz = *( qint32 * )( ptr + i * recordSize + 8 );
516  double x = offset.x() + scale.x() * ix;
517  double y = offset.y() + scale.y() * iy;
518  double z = ( offset.z() + scale.z() * iz ) * zValueScale + zValueOffset;
519  try
520  {
521  coordinateTransform.transformInPlace( x, y, z );
522  }
523  catch ( QgsCsException &e )
524  {
525  if ( !alreadyPrintedDebug )
526  {
527  QgsDebugMsg( QStringLiteral( "Error transforming point coordinate" ) );
528  alreadyPrintedDebug = true;
529  }
530  }
531  QgsVector3D point( x, y, z );
532  QgsVector3D p = context.map().mapToWorldCoordinates( point );
533 
534  QVector3D color( 0.0f, 0.0f, 0.0f );
535 
536  context.getAttribute( ptr, i * recordSize + redOffset, redType, ir );
537  context.getAttribute( ptr, i * recordSize + greenOffset, greenType, ig );
538  context.getAttribute( ptr, i * recordSize + blueOffset, blueType, ib );
539 
540  //skip if red, green or blue not in displayable range
541  if ( ( useRedContrastEnhancement && !redContrastEnhancement->isValueInDisplayableRange( ir ) )
542  || ( useGreenContrastEnhancement && !greenContrastEnhancement->isValueInDisplayableRange( ig ) )
543  || ( useBlueContrastEnhancement && !blueContrastEnhancement->isValueInDisplayableRange( ib ) ) )
544  {
545  continue;
546  }
547 
548  //stretch color values
549  if ( useRedContrastEnhancement )
550  {
551  ir = redContrastEnhancement->enhanceContrast( ir );
552  }
553  if ( useGreenContrastEnhancement )
554  {
555  ig = greenContrastEnhancement->enhanceContrast( ig );
556  }
557  if ( useBlueContrastEnhancement )
558  {
559  ib = blueContrastEnhancement->enhanceContrast( ib );
560  }
561 
562  color.setX( ir / 255.0f );
563  color.setY( ig / 255.0f );
564  color.setZ( ib / 255.0f );
565 
566  outNormal.positions.push_back( QVector3D( p.x(), p.y(), p.z() ) );
567  outNormal.colors.push_back( color );
568  }
569 }
570 
571 void QgsRGBPointCloud3DSymbolHandler::finalize( Qt3DCore::QEntity *parent, const QgsPointCloud3DRenderContext &context )
572 {
573  makeEntity( parent, context, outNormal, false );
574 }
575 
576 Qt3DRender::QGeometry *QgsRGBPointCloud3DSymbolHandler::makeGeometry( Qt3DCore::QNode *parent, const QgsPointCloud3DSymbolHandler::PointData &data, unsigned int byteStride )
577 {
578  return new QgsRGBPointCloud3DGeometry( parent, data, byteStride );
579 }
580 
581 QgsClassificationPointCloud3DSymbolHandler::QgsClassificationPointCloud3DSymbolHandler()
582  : QgsPointCloud3DSymbolHandler()
583 {
584 
585 }
586 
587 bool QgsClassificationPointCloud3DSymbolHandler::prepare( const QgsPointCloud3DRenderContext &context )
588 {
589  Q_UNUSED( context )
590  return true;
591 }
592 
593 void QgsClassificationPointCloud3DSymbolHandler::processNode( QgsPointCloudIndex *pc, const IndexedPointCloudNode &n, const QgsPointCloud3DRenderContext &context )
594 {
596  const int xOffset = 0;
597  attributes.push_back( QgsPointCloudAttribute( QStringLiteral( "X" ), QgsPointCloudAttribute::Int32 ) );
598  const int yOffset = attributes.pointRecordSize();
599  attributes.push_back( QgsPointCloudAttribute( QStringLiteral( "Y" ), QgsPointCloudAttribute::Int32 ) );
600  const int zOffset = attributes.pointRecordSize();
601  attributes.push_back( QgsPointCloudAttribute( QStringLiteral( "Z" ), QgsPointCloudAttribute::Int32 ) );
602 
603  QString attributeName;
604  bool attrIsX = false;
605  bool attrIsY = false;
606  bool attrIsZ = false;
608  int attributeOffset = 0;
610  if ( symbol )
611  {
612  int offset = 0;
613  QgsPointCloudAttributeCollection collection = context.attributes();
614 
615  if ( symbol->attribute() == QLatin1String( "X" ) )
616  {
617  attrIsX = true;
618  }
619  else if ( symbol->attribute() == QLatin1String( "Y" ) )
620  {
621  attrIsY = true;
622  }
623  else if ( symbol->attribute() == QLatin1String( "Z" ) )
624  {
625  attrIsZ = true;
626  }
627  else
628  {
629  const QgsPointCloudAttribute *attr = collection.find( symbol->attribute(), offset );
630  if ( attr )
631  {
632  attributeType = attr->type();
633  attributeName = attr->name();
634  attributeOffset = attributes.pointRecordSize();
635  attributes.push_back( *attr );
636  }
637  }
638  }
639 
640  if ( attributeName.isEmpty() && !attrIsX && !attrIsY && !attrIsZ )
641  return;
642 
643  QgsPointCloudRequest request;
644  request.setAttributes( attributes );
645  std::unique_ptr<QgsPointCloudBlock> block( pc->nodeData( n, request ) );
646  if ( !block )
647  return;
648 
649  const char *ptr = block->data();
650  int count = block->pointCount();
651  const std::size_t recordSize = attributes.pointRecordSize();
652 
653  const QgsVector3D scale = pc->scale();
654  const QgsVector3D offset = pc->offset();
655  const double zValueScale = context.zValueScale();
656  const double zValueOffset = context.zValueFixedOffset();
657  QgsCoordinateTransform coordinateTransform = context.coordinateTransform();
658  bool alreadyPrintedDebug = false;
659 
660  QSet<int> filteredOutValues = context.getFilteredOutValues();
661  for ( int i = 0; i < count; ++i )
662  {
663  if ( context.isCanceled() )
664  break;
665 
666  qint32 ix = *( qint32 * )( ptr + i * recordSize + xOffset );
667  qint32 iy = *( qint32 * )( ptr + i * recordSize + yOffset );
668  qint32 iz = *( qint32 * )( ptr + i * recordSize + zOffset );
669 
670  double x = offset.x() + scale.x() * ix;
671  double y = offset.y() + scale.y() * iy;
672  double z = ( offset.z() + scale.z() * iz ) * zValueScale + zValueOffset;
673  try
674  {
675  coordinateTransform.transformInPlace( x, y, z );
676  }
677  catch ( QgsCsException &e )
678  {
679  if ( !alreadyPrintedDebug )
680  {
681  QgsDebugMsg( QStringLiteral( "Error transforming point coordinate" ) );
682  alreadyPrintedDebug = true;
683  }
684  }
685  QgsVector3D point( x, y, z );
686  QgsVector3D p = context.map().mapToWorldCoordinates( point );
687  float iParam = 0.0f;
688  if ( attrIsX )
689  iParam = x;
690  else if ( attrIsY )
691  iParam = y;
692  else if ( attrIsZ )
693  iParam = z;
694  else
695  context.getAttribute( ptr, i * recordSize + attributeOffset, attributeType, iParam );
696 
697  if ( filteredOutValues.contains( ( int ) iParam ) )
698  continue;
699  outNormal.positions.push_back( QVector3D( p.x(), p.y(), p.z() ) );
700  outNormal.parameter.push_back( iParam );
701  }
702 }
703 
704 void QgsClassificationPointCloud3DSymbolHandler::finalize( Qt3DCore::QEntity *parent, const QgsPointCloud3DRenderContext &context )
705 {
706  makeEntity( parent, context, outNormal, false );
707 }
708 
709 
710 Qt3DRender::QGeometry *QgsClassificationPointCloud3DSymbolHandler::makeGeometry( Qt3DCore::QNode *parent, const QgsPointCloud3DSymbolHandler::PointData &data, unsigned int byteStride )
711 {
712  return new QgsColorRampPointCloud3DGeometry( parent, data, byteStride );
713 }
714 
715 
Represents a indexed point cloud node in octree.
QString attribute() const
Returns the attribute used to select the color of the point cloud.
QString attribute() const
Returns the attribute used to select the color of the point cloud.
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.
bool isValueInDisplayableRange(double value)
Returns true if a pixel value is in displayable range, false if pixel is outside of range (i....
int enhanceContrast(double value)
Applies the contrast enhancement to a value.
ContrastEnhancementAlgorithm contrastEnhancementAlgorithm() const
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...
Custom exception class for Coordinate Reference System related exceptions.
Definition: qgsexception.h:66
Encapsulates the render context for a 3D 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...
QSet< int > getFilteredOutValues() const
Returns a set containing the filtered out values.
double zValueScale() const
Returns any constant scaling factor which must be applied to z values taken from the point cloud inde...
QgsPointCloudAttributeCollection attributes() const
Returns the attributes associated with the rendered block.
bool isCanceled() const
Returns true if the rendering is canceled.
QgsCoordinateTransform coordinateTransform() const
Returns the coordinate transform used to transform points from layer CRS to the map CRS.
QgsPointCloud3DSymbol * symbol() const
Returns the symbol used for rendering the point cloud.
double zValueFixedOffset() const
Returns any constant offset which must be applied to z values taken from the point cloud index.
virtual unsigned int byteStride()=0
Returns the byte stride for the geometries used to for the vertex buffer.
virtual void fillMaterial(Qt3DRender::QMaterial *material)=0SIP_SKIP
Used to fill material object with necessary QParameters (and consequently opengl uniforms)
float pointSize() const
Returns the point size of the point cloud.
Collection of point cloud attributes.
void push_back(const QgsPointCloudAttribute &attribute)
Adds extra attribute.
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.
QString name() const
Returns name of the attribute.
DataType type() const
Returns the data type.
Represents a indexed point clouds data in octree.
QgsVector3D offset() const
Returns offset.
QgsVector3D scale() const
Returns scale.
virtual QgsPointCloudBlock * nodeData(const IndexedPointCloudNode &n, const QgsPointCloudRequest &request)=0
Returns node data block.
Point cloud data request.
void setAttributes(const QgsPointCloudAttributeCollection &attributes)
Set attributes filter in the request.
QString blueAttribute() const
Returns the attribute to use for the blue channel.
QString greenAttribute() const
Returns the attribute to use for the green channel.
QgsContrastEnhancement * blueContrastEnhancement()
Returns the contrast enhancement to use for the blue channel.
QString redAttribute() const
Returns the attribute to use for the red channel.
QgsContrastEnhancement * greenContrastEnhancement()
Returns the contrast enhancement to use for the green channel.
QgsContrastEnhancement * redContrastEnhancement()
Returns the contrast enhancement to use for the red channel.
double y() const
Returns Y coordinate.
Definition: qgsvector3d.h:51
double z() const
Returns Z coordinate.
Definition: qgsvector3d.h:53
double x() const
Returns X coordinate.
Definition: qgsvector3d.h:49
#define QgsDebugMsg(str)
Definition: qgslogger.h:38