QGIS API Documentation 3.37.0-Master (fdefdf9c27f)
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
23#include "qgs3dmapsettings.h"
24#include "qgspointcloudindex.h"
26#include "qgsfeedback.h"
27
28#include <Qt3DRender/QGeometryRenderer>
29#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
30#include <Qt3DRender/QAttribute>
31#include <Qt3DRender/QBuffer>
32#include <Qt3DRender/QGeometry>
33
34typedef Qt3DRender::QAttribute Qt3DQAttribute;
35typedef Qt3DRender::QBuffer Qt3DQBuffer;
36typedef Qt3DRender::QGeometry Qt3DQGeometry;
37#else
38#include <Qt3DCore/QAttribute>
39#include <Qt3DCore/QBuffer>
40#include <Qt3DCore/QGeometry>
41
42typedef Qt3DCore::QAttribute Qt3DQAttribute;
43typedef Qt3DCore::QBuffer Qt3DQBuffer;
44typedef Qt3DCore::QGeometry Qt3DQGeometry;
45#endif
46#include <Qt3DRender/QTechnique>
47#include <Qt3DRender/QShaderProgram>
48#include <Qt3DRender/QGraphicsApiFilter>
49#include <Qt3DRender/QEffect>
50#include <QPointSize>
51#include <QUrl>
52
53#include <delaunator.hpp>
54
55QgsPointCloud3DGeometry::QgsPointCloud3DGeometry( Qt3DCore::QNode *parent, const QgsPointCloud3DSymbolHandler::PointData &data, unsigned int byteStride )
56 : Qt3DQGeometry( parent )
57 , mPositionAttribute( new Qt3DQAttribute( this ) )
58 , mParameterAttribute( new Qt3DQAttribute( this ) )
59 , mPointSizeAttribute( new Qt3DQAttribute( this ) )
60 , mColorAttribute( new Qt3DQAttribute( this ) )
61 , mTriangleIndexAttribute( new Qt3DQAttribute( this ) )
62 , mNormalsAttribute( new Qt3DQAttribute( this ) )
63 , mVertexBuffer( new Qt3DQBuffer( this ) )
64 , mByteStride( byteStride )
65{
66 if ( !data.triangles.isEmpty() )
67 {
68 mTriangleBuffer = new Qt3DQBuffer( this );
69 mTriangleIndexAttribute->setAttributeType( Qt3DQAttribute::IndexAttribute );
70 mTriangleIndexAttribute->setBuffer( mTriangleBuffer );
71 mTriangleIndexAttribute->setVertexBaseType( Qt3DQAttribute::UnsignedInt );
72 mTriangleBuffer->setData( data.triangles );
73 mTriangleIndexAttribute->setCount( data.triangles.size() / sizeof( quint32 ) );
74 addAttribute( mTriangleIndexAttribute );
75 }
76
77 if ( !data.normals.isEmpty() )
78 {
79 mNormalsBuffer = new Qt3DQBuffer( this );
80 mNormalsAttribute->setName( Qt3DQAttribute::defaultNormalAttributeName() );
81 mNormalsAttribute->setVertexBaseType( Qt3DQAttribute::Float );
82 mNormalsAttribute->setVertexSize( 3 );
83 mNormalsAttribute->setAttributeType( Qt3DQAttribute::VertexAttribute );
84 mNormalsAttribute->setBuffer( mNormalsBuffer );
85 mNormalsBuffer->setData( data.normals );
86 mNormalsAttribute->setCount( data.normals.size() / ( 3 * sizeof( float ) ) );
87 addAttribute( mNormalsAttribute );
88 }
89}
90
91QgsSingleColorPointCloud3DGeometry::QgsSingleColorPointCloud3DGeometry( Qt3DCore::QNode *parent, const QgsPointCloud3DSymbolHandler::PointData &data, unsigned int byteStride )
92 : QgsPointCloud3DGeometry( parent, data, byteStride )
93{
94 mPositionAttribute->setAttributeType( Qt3DQAttribute::VertexAttribute );
95 mPositionAttribute->setBuffer( mVertexBuffer );
96 mPositionAttribute->setVertexBaseType( Qt3DQAttribute::Float );
97 mPositionAttribute->setVertexSize( 3 );
98 mPositionAttribute->setName( Qt3DQAttribute::defaultPositionAttributeName() );
99 mPositionAttribute->setByteOffset( 0 );
100 mPositionAttribute->setByteStride( mByteStride );
101 addAttribute( mPositionAttribute );
102 makeVertexBuffer( data );
103}
104
105void QgsSingleColorPointCloud3DGeometry::makeVertexBuffer( const QgsPointCloud3DSymbolHandler::PointData &data )
106{
107 QByteArray vertexBufferData;
108 vertexBufferData.resize( data.positions.size() * mByteStride );
109 float *rawVertexArray = reinterpret_cast<float *>( vertexBufferData.data() );
110 int idx = 0;
111 for ( int i = 0; i < data.positions.size(); ++i )
112 {
113 rawVertexArray[idx++] = data.positions.at( i ).x();
114 rawVertexArray[idx++] = data.positions.at( i ).y();
115 rawVertexArray[idx++] = data.positions.at( i ).z();
116 }
117
118 mVertexCount = data.positions.size();
119 mVertexBuffer->setData( vertexBufferData );
120}
121
122QgsColorRampPointCloud3DGeometry::QgsColorRampPointCloud3DGeometry( Qt3DCore::QNode *parent, const QgsPointCloud3DSymbolHandler::PointData &data, unsigned int byteStride )
123 : QgsPointCloud3DGeometry( parent, data, byteStride )
124{
125 mPositionAttribute->setAttributeType( Qt3DQAttribute::VertexAttribute );
126 mPositionAttribute->setBuffer( mVertexBuffer );
127 mPositionAttribute->setVertexBaseType( Qt3DQAttribute::Float );
128 mPositionAttribute->setVertexSize( 3 );
129 mPositionAttribute->setName( Qt3DQAttribute::defaultPositionAttributeName() );
130 mPositionAttribute->setByteOffset( 0 );
131 mPositionAttribute->setByteStride( mByteStride );
132 addAttribute( mPositionAttribute );
133 mParameterAttribute->setAttributeType( Qt3DQAttribute::VertexAttribute );
134 mParameterAttribute->setBuffer( mVertexBuffer );
135 mParameterAttribute->setVertexBaseType( Qt3DQAttribute::Float );
136 mParameterAttribute->setVertexSize( 1 );
137 mParameterAttribute->setName( "vertexParameter" );
138 mParameterAttribute->setByteOffset( 12 );
139 mParameterAttribute->setByteStride( mByteStride );
140 addAttribute( mParameterAttribute );
141 makeVertexBuffer( data );
142}
143
144void QgsColorRampPointCloud3DGeometry::makeVertexBuffer( const QgsPointCloud3DSymbolHandler::PointData &data )
145{
146 QByteArray vertexBufferData;
147 vertexBufferData.resize( data.positions.size() * mByteStride );
148 float *rawVertexArray = reinterpret_cast<float *>( vertexBufferData.data() );
149 int idx = 0;
150 Q_ASSERT( data.positions.size() == data.parameter.size() );
151 for ( int i = 0; i < data.positions.size(); ++i )
152 {
153 rawVertexArray[idx++] = data.positions.at( i ).x();
154 rawVertexArray[idx++] = data.positions.at( i ).y();
155 rawVertexArray[idx++] = data.positions.at( i ).z();
156 rawVertexArray[idx++] = data.parameter.at( i );
157 }
158
159 mVertexCount = data.positions.size();
160 mVertexBuffer->setData( vertexBufferData );
161}
162
163QgsRGBPointCloud3DGeometry::QgsRGBPointCloud3DGeometry( Qt3DCore::QNode *parent, const QgsPointCloud3DSymbolHandler::PointData &data, unsigned int byteStride )
164 : QgsPointCloud3DGeometry( parent, data, byteStride )
165{
166 mPositionAttribute->setAttributeType( Qt3DQAttribute::VertexAttribute );
167 mPositionAttribute->setBuffer( mVertexBuffer );
168 mPositionAttribute->setVertexBaseType( Qt3DQAttribute::Float );
169 mPositionAttribute->setVertexSize( 3 );
170 mPositionAttribute->setName( Qt3DQAttribute::defaultPositionAttributeName() );
171 mPositionAttribute->setByteOffset( 0 );
172 mPositionAttribute->setByteStride( mByteStride );
173 addAttribute( mPositionAttribute );
174 mColorAttribute->setAttributeType( Qt3DQAttribute::VertexAttribute );
175 mColorAttribute->setBuffer( mVertexBuffer );
176 mColorAttribute->setVertexBaseType( Qt3DQAttribute::Float );
177 mColorAttribute->setVertexSize( 3 );
178 mColorAttribute->setName( QStringLiteral( "vertexColor" ) );
179 mColorAttribute->setByteOffset( 12 );
180 mColorAttribute->setByteStride( mByteStride );
181 addAttribute( mColorAttribute );
182 makeVertexBuffer( data );
183}
184
185void QgsRGBPointCloud3DGeometry::makeVertexBuffer( const QgsPointCloud3DSymbolHandler::PointData &data )
186{
187 QByteArray vertexBufferData;
188 vertexBufferData.resize( data.positions.size() * mByteStride );
189 float *rawVertexArray = reinterpret_cast<float *>( vertexBufferData.data() );
190 int idx = 0;
191 Q_ASSERT( data.positions.size() == data.colors.size() );
192 for ( int i = 0; i < data.positions.size(); ++i )
193 {
194 rawVertexArray[idx++] = data.positions.at( i ).x();
195 rawVertexArray[idx++] = data.positions.at( i ).y();
196 rawVertexArray[idx++] = data.positions.at( i ).z();
197 rawVertexArray[idx++] = data.colors.at( i ).x();
198 rawVertexArray[idx++] = data.colors.at( i ).y();
199 rawVertexArray[idx++] = data.colors.at( i ).z();
200 }
201 mVertexCount = data.positions.size();
202 mVertexBuffer->setData( vertexBufferData );
203}
204
205QgsClassificationPointCloud3DGeometry::QgsClassificationPointCloud3DGeometry( Qt3DCore::QNode *parent, const QgsPointCloud3DSymbolHandler::PointData &data, unsigned int byteStride )
206 : QgsPointCloud3DGeometry( parent, data, byteStride )
207{
208 mPositionAttribute->setAttributeType( Qt3DQAttribute::VertexAttribute );
209 mPositionAttribute->setBuffer( mVertexBuffer );
210 mPositionAttribute->setVertexBaseType( Qt3DQAttribute::Float );
211 mPositionAttribute->setVertexSize( 3 );
212 mPositionAttribute->setName( Qt3DQAttribute::defaultPositionAttributeName() );
213 mPositionAttribute->setByteOffset( 0 );
214 mPositionAttribute->setByteStride( mByteStride );
215 addAttribute( mPositionAttribute );
216 mParameterAttribute->setAttributeType( Qt3DQAttribute::VertexAttribute );
217 mParameterAttribute->setBuffer( mVertexBuffer );
218 mParameterAttribute->setVertexBaseType( Qt3DQAttribute::Float );
219 mParameterAttribute->setVertexSize( 1 );
220 mParameterAttribute->setName( "vertexParameter" );
221 mParameterAttribute->setByteOffset( 12 );
222 mParameterAttribute->setByteStride( mByteStride );
223 addAttribute( mParameterAttribute );
224 mPointSizeAttribute->setAttributeType( Qt3DQAttribute::VertexAttribute );
225 mPointSizeAttribute->setBuffer( mVertexBuffer );
226 mPointSizeAttribute->setVertexBaseType( Qt3DQAttribute::Float );
227 mPointSizeAttribute->setVertexSize( 1 );
228 mPointSizeAttribute->setName( "vertexSize" );
229 mPointSizeAttribute->setByteOffset( 16 );
230 mPointSizeAttribute->setByteStride( mByteStride );
231 addAttribute( mPointSizeAttribute );
232 makeVertexBuffer( data );
233}
234
235void QgsClassificationPointCloud3DGeometry::makeVertexBuffer( const QgsPointCloud3DSymbolHandler::PointData &data )
236{
237 QByteArray vertexBufferData;
238 vertexBufferData.resize( data.positions.size() * mByteStride );
239 float *rawVertexArray = reinterpret_cast<float *>( vertexBufferData.data() );
240 int idx = 0;
241 Q_ASSERT( data.positions.size() == data.parameter.size() );
242 for ( int i = 0; i < data.positions.size(); ++i )
243 {
244 rawVertexArray[idx++] = data.positions.at( i ).x();
245 rawVertexArray[idx++] = data.positions.at( i ).y();
246 rawVertexArray[idx++] = data.positions.at( i ).z();
247 rawVertexArray[idx++] = data.parameter.at( i );
248 rawVertexArray[idx++] = data.pointSizes.at( i );
249 }
250
251 mVertexCount = data.positions.size();
252 mVertexBuffer->setData( vertexBufferData );
253}
254
255QgsPointCloud3DSymbolHandler::QgsPointCloud3DSymbolHandler()
256{
257}
258
259
260void QgsPointCloud3DSymbolHandler::makeEntity( Qt3DCore::QEntity *parent, const QgsPointCloud3DRenderContext &context, const QgsPointCloud3DSymbolHandler::PointData &out, bool selected )
261{
262 Q_UNUSED( selected )
263
264 if ( out.positions.empty() )
265 return;
266
267 // Geometry
268 Qt3DQGeometry *geom = makeGeometry( parent, out, context.symbol()->byteStride() );
269 Qt3DRender::QGeometryRenderer *gr = new Qt3DRender::QGeometryRenderer;
270 if ( context.symbol()->renderAsTriangles() && ! out.triangles.isEmpty() )
271 {
272 gr->setPrimitiveType( Qt3DRender::QGeometryRenderer::Triangles );
273 gr->setVertexCount( out.triangles.size() / sizeof( quint32 ) );
274 }
275 else
276 {
277 gr->setPrimitiveType( Qt3DRender::QGeometryRenderer::Points );
278 gr->setVertexCount( out.positions.count() );
279 }
280 gr->setGeometry( geom );
281
282 // Transform
283 Qt3DCore::QTransform *tr = new Qt3DCore::QTransform;
284
285 // Material
286 Qt3DRender::QMaterial *mat = new Qt3DRender::QMaterial;
287 if ( context.symbol() )
288 context.symbol()->fillMaterial( mat );
289
290 Qt3DRender::QShaderProgram *shaderProgram = new Qt3DRender::QShaderProgram( mat );
291 shaderProgram->setVertexShaderCode( Qt3DRender::QShaderProgram::loadSource( QUrl( QStringLiteral( "qrc:/shaders/pointcloud.vert" ) ) ) );
292 shaderProgram->setFragmentShaderCode( Qt3DRender::QShaderProgram::loadSource( QUrl( QStringLiteral( "qrc:/shaders/pointcloud.frag" ) ) ) );
293
294 Qt3DRender::QRenderPass *renderPass = new Qt3DRender::QRenderPass( mat );
295 renderPass->setShaderProgram( shaderProgram );
296
297 if ( out.triangles.isEmpty() )
298 {
299 Qt3DRender::QPointSize *pointSize = new Qt3DRender::QPointSize( renderPass );
300 pointSize->setSizeMode( Qt3DRender::QPointSize::Programmable ); // supported since OpenGL 3.2
301 renderPass->addRenderState( pointSize );
302 }
303
304 // without this filter the default forward renderer would not render this
305 Qt3DRender::QFilterKey *filterKey = new Qt3DRender::QFilterKey;
306 filterKey->setName( QStringLiteral( "renderingStyle" ) );
307 filterKey->setValue( "forward" );
308
309 Qt3DRender::QTechnique *technique = new Qt3DRender::QTechnique;
310 technique->addRenderPass( renderPass );
311 technique->addFilterKey( filterKey );
312 technique->graphicsApiFilter()->setApi( Qt3DRender::QGraphicsApiFilter::OpenGL );
313 technique->graphicsApiFilter()->setProfile( Qt3DRender::QGraphicsApiFilter::CoreProfile );
314 technique->graphicsApiFilter()->setMajorVersion( 3 );
315 technique->graphicsApiFilter()->setMinorVersion( 1 );
316 technique->addParameter( new Qt3DRender::QParameter( "triangulate", !out.triangles.isEmpty() ) );
317
318 Qt3DRender::QEffect *eff = new Qt3DRender::QEffect;
319 eff->addTechnique( technique );
320 mat->setEffect( eff );
321
322 // All together
323 Qt3DCore::QEntity *entity = new Qt3DCore::QEntity;
324 entity->addComponent( gr );
325 entity->addComponent( tr );
326 entity->addComponent( mat );
327 entity->setParent( parent );
328 // cppcheck wrongly believes entity will leak
329 // cppcheck-suppress memleak
330}
331
332
333std::vector<double> QgsPointCloud3DSymbolHandler::getVertices( QgsPointCloudIndex *pc, const IndexedPointCloudNode &n, const QgsPointCloud3DRenderContext &context, const QgsAABB &bbox )
334{
335
336 bool hasColorData = !outNormal.colors.empty();
337 bool hasParameterData = !outNormal.parameter.empty();
338
339 // first, get the points of the concerned node
340 std::vector<double> vertices( outNormal.positions.size() * 2 );
341 size_t idx = 0;
342 for ( int i = 0; i < outNormal.positions.size(); ++i )
343 {
344 vertices[idx++] = outNormal.positions.at( i ).x();
345 vertices[idx++] = outNormal.positions.at( i ).z();
346 }
347
348 // next, we also need all points of all parents nodes to make the triangulation (also external points)
349 IndexedPointCloudNode parentNode = n.parentNode();
350
351 int properPointsCount = outNormal.positions.count();
352 while ( parentNode.d() >= 0 )
353 {
354 processNode( pc, parentNode, context );
355 parentNode = parentNode.parentNode();
356 }
357
358 PointData filteredExtraPointData;
359
360 double span = pc->span();
361 //factor to take account of the density of the point to calculate extension of the bounding box
362 // with a usual value span = 128, bounding box is extended by 12.5 % on each side.
363 double extraBoxFactor = 16 / span;
364 double extraX = extraBoxFactor * bbox.xExtent();
365 double extraZ = extraBoxFactor * bbox.zExtent();
366
367 // We keep all points in vertical direction to avoid odd triangulation if points are isolated on top
368 const QgsAABB extendedBBox( bbox.xMin - extraX, -std::numeric_limits<float>::max(), bbox.zMin - extraZ, bbox.xMax + extraX, std::numeric_limits<float>::max(), bbox.zMax + extraZ );
369
370 for ( int i = properPointsCount; i < outNormal.positions.count(); ++i )
371 {
372 const QVector3D pos = outNormal.positions.at( i );
373 if ( extendedBBox.intersects( pos.x(), pos.y(), pos.z() ) )
374 {
375 filteredExtraPointData.positions.append( pos );
376 vertices.push_back( pos.x() );
377 vertices.push_back( pos.z() );
378
379 if ( hasColorData )
380 filteredExtraPointData.colors.append( outNormal.colors.at( i ) );
381 if ( hasParameterData )
382 filteredExtraPointData.parameter.append( outNormal.parameter.at( i ) );
383 }
384 }
385
386 outNormal.positions.resize( properPointsCount );
387 if ( hasColorData )
388 outNormal.colors.resize( properPointsCount );
389 if ( hasParameterData )
390 outNormal.parameter.resize( properPointsCount );
391
392 outNormal.positions.append( filteredExtraPointData.positions );
393 outNormal.colors.append( filteredExtraPointData.colors );
394 outNormal.parameter.append( filteredExtraPointData.parameter );
395
396 return vertices;
397}
398
399void QgsPointCloud3DSymbolHandler::calculateNormals( const std::vector<size_t> &triangles )
400{
401 QVector<QVector3D> normals( outNormal.positions.count(), QVector3D( 0.0, 0.0, 0.0 ) );
402 for ( size_t i = 0; i < triangles.size(); i += 3 )
403 {
404 QVector<QVector3D> triangleVertices( 3 );
405 for ( size_t j = 0; j < 3; ++j )
406 {
407 size_t vertIndex = triangles.at( i + j );
408 triangleVertices[j] = outNormal.positions.at( vertIndex );
409 }
410 //calculate normals
411 for ( size_t j = 0; j < 3; ++j )
412 normals[triangles.at( i + j )] += QVector3D::crossProduct(
413 triangleVertices.at( 1 ) - triangleVertices.at( 0 ),
414 triangleVertices.at( 2 ) - triangleVertices.at( 0 ) );
415 }
416
417 // Build now normals array
418 outNormal.normals.resize( ( outNormal.positions.count() ) * sizeof( float ) * 3 );
419 float *normPtr = reinterpret_cast<float *>( outNormal.normals.data() );
420 for ( int i = 0; i < normals.size(); ++i )
421 {
422 QVector3D normal = normals.at( i );
423 normal = normal.normalized();
424
425 *normPtr++ = normal.x();
426 *normPtr++ = normal.y();
427 *normPtr++ = normal.z();
428 }
429}
430
431void QgsPointCloud3DSymbolHandler::filterTriangles( const std::vector<size_t> &triangleIndexes, const QgsPointCloud3DRenderContext &context, const QgsAABB &bbox )
432{
433 outNormal.triangles.resize( triangleIndexes.size() * sizeof( quint32 ) );
434 quint32 *indexPtr = reinterpret_cast<quint32 *>( outNormal.triangles.data() );
435 size_t effective = 0;
436
437 bool horizontalFilter = context.symbol()->horizontalTriangleFilter();
438 bool verticalFilter = context.symbol()->verticalTriangleFilter();
439 float horizontalThreshold = context.symbol()->horizontalFilterThreshold();
440 float verticalThreshold = context.symbol()->verticalFilterThreshold();
441
442 for ( size_t i = 0; i < triangleIndexes.size(); i += 3 )
443 {
444 bool atLeastOneInBox = false;
445 bool horizontalSkip = false;
446 bool verticalSkip = false;
447 for ( size_t j = 0; j < 3; j++ )
448 {
449 QVector3D pos = outNormal.positions.at( triangleIndexes.at( i + j ) );
450 atLeastOneInBox |= bbox.intersects( pos.x(), pos.y(), pos.z() );
451
452 if ( verticalFilter || horizontalFilter )
453 {
454 const QVector3D pos2 = outNormal.positions.at( triangleIndexes.at( i + ( j + 1 ) % 3 ) );
455
456 if ( verticalFilter )
457 verticalSkip |= std::fabs( pos.y() - pos2.y() ) > verticalThreshold;
458
459 if ( horizontalFilter && ! verticalSkip )
460 {
461 // filter only in the horizontal plan, it is a 2.5D triangulation.
462 horizontalSkip |= sqrt( std::pow( pos.x() - pos2.x(), 2 ) +
463 std::pow( pos.z() - pos2.z(), 2 ) ) > horizontalThreshold;
464 }
465
466 if ( horizontalSkip || verticalSkip )
467 break;
468 }
469 }
470 if ( atLeastOneInBox && !horizontalSkip && !verticalSkip )
471 {
472 for ( size_t j = 0; j < 3; j++ )
473 {
474 size_t vertIndex = triangleIndexes.at( i + j );
475 *indexPtr++ = quint32( vertIndex );
476 }
477 effective++;
478 }
479 }
480
481 if ( effective != 0 )
482 {
483 outNormal.triangles.resize( effective * 3 * sizeof( quint32 ) );
484 }
485 else
486 {
487 outNormal.triangles.clear();
488 outNormal.normals.clear();
489 }
490}
491
492void QgsPointCloud3DSymbolHandler::triangulate( QgsPointCloudIndex *pc, const IndexedPointCloudNode &n, const QgsPointCloud3DRenderContext &context, const QgsAABB &bbox )
493{
494 if ( outNormal.positions.isEmpty() )
495 return;
496
497 // Triangulation happens here
498 std::unique_ptr<delaunator::Delaunator> triangulation;
499 try
500 {
501 std::vector<double> vertices = getVertices( pc, n, context, bbox );
502 triangulation.reset( new delaunator::Delaunator( vertices ) );
503 }
504 catch ( std::exception &e )
505 {
506 // something went wrong, better to retrieve initial state
507 QgsDebugMsgLevel( QStringLiteral( "Error with triangulation" ), 4 );
508 outNormal = PointData();
509 processNode( pc, n, context );
510 return;
511 }
512
513 const std::vector<size_t> &triangleIndexes = triangulation->triangles;
514
515 calculateNormals( triangleIndexes );
516 filterTriangles( triangleIndexes, context, bbox );
517}
518
519std::unique_ptr<QgsPointCloudBlock> QgsPointCloud3DSymbolHandler::pointCloudBlock( QgsPointCloudIndex *pc, const IndexedPointCloudNode &n, const QgsPointCloudRequest &request, const QgsPointCloud3DRenderContext &context )
520{
521 std::unique_ptr<QgsPointCloudBlock> block;
522 if ( pc->accessType() == QgsPointCloudIndex::AccessType::Local )
523 {
524 block = pc->nodeData( n, request );
525 }
526 else if ( pc->accessType() == QgsPointCloudIndex::AccessType::Remote )
527 {
528 if ( pc->nodePointCount( n ) < 1 )
529 return block;
530
531 bool loopAborted = false;
532 QEventLoop loop;
533 QgsPointCloudBlockRequest *req = pc->asyncNodeData( n, request );
534 QObject::connect( req, &QgsPointCloudBlockRequest::finished, &loop, &QEventLoop::quit );
535 QObject::connect( context.feedback(), &QgsFeedback::canceled, &loop, [ & ]()
536 {
537 loopAborted = true;
538 loop.quit();
539 } );
540 loop.exec();
541
542 if ( !loopAborted )
543 block = req->takeBlock();
544 }
545 return block;
546}
547
548//
549
550QgsSingleColorPointCloud3DSymbolHandler::QgsSingleColorPointCloud3DSymbolHandler()
551 : QgsPointCloud3DSymbolHandler()
552{
553
554}
555
556bool QgsSingleColorPointCloud3DSymbolHandler::prepare( const QgsPointCloud3DRenderContext &context )
557{
558 Q_UNUSED( context )
559 return true;
560}
561
562void QgsSingleColorPointCloud3DSymbolHandler::processNode( QgsPointCloudIndex *pc, const IndexedPointCloudNode &n, const QgsPointCloud3DRenderContext &context )
563{
565 attributes.push_back( QgsPointCloudAttribute( QStringLiteral( "X" ), QgsPointCloudAttribute::Int32 ) );
566 attributes.push_back( QgsPointCloudAttribute( QStringLiteral( "Y" ), QgsPointCloudAttribute::Int32 ) );
567 attributes.push_back( QgsPointCloudAttribute( QStringLiteral( "Z" ), QgsPointCloudAttribute::Int32 ) );
568
569 QgsPointCloudRequest request;
570 request.setAttributes( attributes );
571 request.setFilterRect( context.extent() );
572 std::unique_ptr<QgsPointCloudBlock> block( pointCloudBlock( pc, n, request, context ) );
573 if ( !block )
574 return;
575
576 const char *ptr = block->data();
577 const int count = block->pointCount();
578 const std::size_t recordSize = block->attributes().pointRecordSize();
579 const QgsVector3D blockScale = block->scale();
580 const QgsVector3D blockOffset = block->offset();
581 const double zValueScale = context.zValueScale();
582 const double zValueOffset = context.zValueFixedOffset();
583 const QgsCoordinateTransform coordinateTransform = context.coordinateTransform();
584 bool alreadyPrintedDebug = false;
585
586 for ( int i = 0; i < count; ++i )
587 {
588 if ( context.isCanceled() )
589 break;
590
591 const qint32 ix = *( qint32 * )( ptr + i * recordSize + 0 );
592 const qint32 iy = *( qint32 * )( ptr + i * recordSize + 4 );
593 const qint32 iz = *( qint32 * )( ptr + i * recordSize + 8 );
594
595 double x = blockOffset.x() + blockScale.x() * ix;
596 double y = blockOffset.y() + blockScale.y() * iy;
597 double z = ( blockOffset.z() + blockScale.z() * iz ) * zValueScale + zValueOffset;
598 try
599 {
600 coordinateTransform.transformInPlace( x, y, z );
601 }
602 catch ( QgsCsException &e )
603 {
604 if ( !alreadyPrintedDebug )
605 {
606 QgsDebugError( QStringLiteral( "Error transforming point coordinate" ) );
607 alreadyPrintedDebug = true;
608 }
609 }
610 const QgsVector3D point( x, y, z );
611 const QgsVector3D p = context.map().mapToWorldCoordinates( QgsVector3D( x, y, z ) );
612 outNormal.positions.push_back( QVector3D( p.x(), p.y(), p.z() ) );
613 }
614}
615
616void QgsSingleColorPointCloud3DSymbolHandler::finalize( Qt3DCore::QEntity *parent, const QgsPointCloud3DRenderContext &context )
617{
618 makeEntity( parent, context, outNormal, false );
619}
620
621Qt3DQGeometry *QgsSingleColorPointCloud3DSymbolHandler::makeGeometry( Qt3DCore::QNode *parent, const QgsPointCloud3DSymbolHandler::PointData &data, unsigned int byteStride )
622{
623 return new QgsSingleColorPointCloud3DGeometry( parent, data, byteStride );
624}
625
626QgsColorRampPointCloud3DSymbolHandler::QgsColorRampPointCloud3DSymbolHandler()
627 : QgsPointCloud3DSymbolHandler()
628{
629
630}
631
632bool QgsColorRampPointCloud3DSymbolHandler::prepare( const QgsPointCloud3DRenderContext &context )
633{
634 Q_UNUSED( context )
635 return true;
636}
637
638void QgsColorRampPointCloud3DSymbolHandler::processNode( QgsPointCloudIndex *pc, const IndexedPointCloudNode &n, const QgsPointCloud3DRenderContext &context )
639{
641 const int xOffset = 0;
642 attributes.push_back( QgsPointCloudAttribute( QStringLiteral( "X" ), QgsPointCloudAttribute::Int32 ) );
643 const int yOffset = attributes.pointRecordSize();
644 attributes.push_back( QgsPointCloudAttribute( QStringLiteral( "Y" ), QgsPointCloudAttribute::Int32 ) );
645 const int zOffset = attributes.pointRecordSize();
646 attributes.push_back( QgsPointCloudAttribute( QStringLiteral( "Z" ), QgsPointCloudAttribute::Int32 ) );
647
648 QString attributeName;
649 bool attrIsX = false;
650 bool attrIsY = false;
651 bool attrIsZ = false;
653 int attributeOffset = 0;
654 const double zValueScale = context.zValueScale();
655 const double zValueOffset = context.zValueFixedOffset();
656 const QgsCoordinateTransform coordinateTransform = context.coordinateTransform();
657 bool alreadyPrintedDebug = false;
658
659 QgsColorRampPointCloud3DSymbol *symbol = dynamic_cast<QgsColorRampPointCloud3DSymbol *>( context.symbol() );
660 if ( symbol )
661 {
662 int offset = 0;
663 const QgsPointCloudAttributeCollection collection = context.attributes();
664
665 if ( symbol->attribute() == QLatin1String( "X" ) )
666 {
667 attrIsX = true;
668 }
669 else if ( symbol->attribute() == QLatin1String( "Y" ) )
670 {
671 attrIsY = true;
672 }
673 else if ( symbol->attribute() == QLatin1String( "Z" ) )
674 {
675 attrIsZ = true;
676 }
677 else
678 {
679 const QgsPointCloudAttribute *attr = collection.find( symbol->attribute(), offset );
680 if ( attr )
681 {
682 attributeType = attr->type();
683 attributeName = attr->name();
684 attributeOffset = attributes.pointRecordSize();
685 attributes.push_back( *attr );
686 }
687 }
688 }
689
690 if ( attributeName.isEmpty() && !attrIsX && !attrIsY && !attrIsZ )
691 return;
692
693 QgsPointCloudRequest request;
694 request.setAttributes( attributes );
695 request.setFilterRect( context.extent() );
696 std::unique_ptr<QgsPointCloudBlock> block( pointCloudBlock( pc, n, request, context ) );
697 if ( !block )
698 return;
699
700 const char *ptr = block->data();
701 const int count = block->pointCount();
702 const std::size_t recordSize = block->attributes().pointRecordSize();
703
704 const QgsVector3D blockScale = block->scale();
705 const QgsVector3D blockOffset = block->offset();
706
707 for ( int i = 0; i < count; ++i )
708 {
709 if ( context.isCanceled() )
710 break;
711
712 const qint32 ix = *( qint32 * )( ptr + i * recordSize + xOffset );
713 const qint32 iy = *( qint32 * )( ptr + i * recordSize + yOffset );
714 const qint32 iz = *( qint32 * )( ptr + i * recordSize + zOffset );
715
716 double x = blockOffset.x() + blockScale.x() * ix;
717 double y = blockOffset.y() + blockScale.y() * iy;
718 double z = ( blockOffset.z() + blockScale.z() * iz ) * zValueScale + zValueOffset;
719 try
720 {
721 coordinateTransform.transformInPlace( x, y, z );
722 }
723 catch ( QgsCsException & )
724 {
725 if ( !alreadyPrintedDebug )
726 {
727 QgsDebugError( QStringLiteral( "Error transforming point coordinate" ) );
728 alreadyPrintedDebug = true;
729 }
730 }
731 QgsVector3D point( x, y, z );
732 point = context.map().mapToWorldCoordinates( point );
733 outNormal.positions.push_back( QVector3D( point.x(), point.y(), point.z() ) );
734
735 if ( attrIsX )
736 outNormal.parameter.push_back( x );
737 else if ( attrIsY )
738 outNormal.parameter.push_back( y );
739 else if ( attrIsZ )
740 outNormal.parameter.push_back( z );
741 else
742 {
743 float iParam = 0.0f;
744 context.getAttribute( ptr, i * recordSize + attributeOffset, attributeType, iParam );
745 outNormal.parameter.push_back( iParam );
746 }
747 }
748}
749
750void QgsColorRampPointCloud3DSymbolHandler::finalize( Qt3DCore::QEntity *parent, const QgsPointCloud3DRenderContext &context )
751{
752 makeEntity( parent, context, outNormal, false );
753}
754
755Qt3DQGeometry *QgsColorRampPointCloud3DSymbolHandler::makeGeometry( Qt3DCore::QNode *parent, const QgsPointCloud3DSymbolHandler::PointData &data, unsigned int byteStride )
756{
757 return new QgsColorRampPointCloud3DGeometry( parent, data, byteStride );
758}
759
760QgsRGBPointCloud3DSymbolHandler::QgsRGBPointCloud3DSymbolHandler()
761 : QgsPointCloud3DSymbolHandler()
762{
763
764}
765
766bool QgsRGBPointCloud3DSymbolHandler::prepare( const QgsPointCloud3DRenderContext &context )
767{
768 Q_UNUSED( context )
769 return true;
770}
771
772void QgsRGBPointCloud3DSymbolHandler::processNode( QgsPointCloudIndex *pc, const IndexedPointCloudNode &n, const QgsPointCloud3DRenderContext &context )
773{
775 attributes.push_back( QgsPointCloudAttribute( QStringLiteral( "X" ), QgsPointCloudAttribute::Int32 ) );
776 attributes.push_back( QgsPointCloudAttribute( QStringLiteral( "Y" ), QgsPointCloudAttribute::Int32 ) );
777 attributes.push_back( QgsPointCloudAttribute( QStringLiteral( "Z" ), QgsPointCloudAttribute::Int32 ) );
778
779 QgsRgbPointCloud3DSymbol *symbol = dynamic_cast<QgsRgbPointCloud3DSymbol *>( context.symbol() );
780
781 // we have to get the RGB attributes using their real data types -- they aren't always short! (sometimes unsigned short)
782 int attrOffset = 0 ;
783
784 const int redOffset = attributes.pointRecordSize();
785 const QgsPointCloudAttribute *colorAttribute = context.attributes().find( symbol->redAttribute(), attrOffset );
786 attributes.push_back( *colorAttribute );
787 const QgsPointCloudAttribute::DataType redType = colorAttribute->type();
788
789 const int greenOffset = attributes.pointRecordSize();
790 colorAttribute = context.attributes().find( symbol->greenAttribute(), attrOffset );
791 attributes.push_back( *colorAttribute );
792 const QgsPointCloudAttribute::DataType greenType = colorAttribute->type();
793
794 const int blueOffset = attributes.pointRecordSize();
795 colorAttribute = context.attributes().find( symbol->blueAttribute(), attrOffset );
796 attributes.push_back( *colorAttribute );
797 const QgsPointCloudAttribute::DataType blueType = colorAttribute->type();
798
799 QgsPointCloudRequest request;
800 request.setAttributes( attributes );
801 request.setFilterRect( context.extent() );
802 std::unique_ptr<QgsPointCloudBlock> block( pointCloudBlock( pc, n, request, context ) );
803 if ( !block )
804 return;
805
806 const char *ptr = block->data();
807 const int count = block->pointCount();
808 const std::size_t recordSize = block->attributes().pointRecordSize();
809
810 const QgsVector3D blockScale = block->scale();
811 const QgsVector3D blockOffset = block->offset();
812 const double zValueScale = context.zValueScale();
813 const double zValueOffset = context.zValueFixedOffset();
814 const QgsCoordinateTransform coordinateTransform = context.coordinateTransform();
815 bool alreadyPrintedDebug = false;
816
817 QgsContrastEnhancement *redContrastEnhancement = symbol->redContrastEnhancement();
818 QgsContrastEnhancement *greenContrastEnhancement = symbol->greenContrastEnhancement();
819 QgsContrastEnhancement *blueContrastEnhancement = symbol->blueContrastEnhancement();
820
821 const bool useRedContrastEnhancement = redContrastEnhancement && redContrastEnhancement->contrastEnhancementAlgorithm() != QgsContrastEnhancement::NoEnhancement;
822 const bool useBlueContrastEnhancement = blueContrastEnhancement && blueContrastEnhancement->contrastEnhancementAlgorithm() != QgsContrastEnhancement::NoEnhancement;
823 const bool useGreenContrastEnhancement = greenContrastEnhancement && greenContrastEnhancement->contrastEnhancementAlgorithm() != QgsContrastEnhancement::NoEnhancement;
824
825 int ir = 0;
826 int ig = 0;
827 int ib = 0;
828 for ( int i = 0; i < count; ++i )
829 {
830 if ( context.isCanceled() )
831 break;
832
833 const qint32 ix = *( qint32 * )( ptr + i * recordSize + 0 );
834 const qint32 iy = *( qint32 * )( ptr + i * recordSize + 4 );
835 const qint32 iz = *( qint32 * )( ptr + i * recordSize + 8 );
836 double x = blockOffset.x() + blockScale.x() * ix;
837 double y = blockOffset.y() + blockScale.y() * iy;
838 double z = ( blockOffset.z() + blockScale.z() * iz ) * zValueScale + zValueOffset;
839 try
840 {
841 coordinateTransform.transformInPlace( x, y, z );
842 }
843 catch ( QgsCsException & )
844 {
845 if ( !alreadyPrintedDebug )
846 {
847 QgsDebugError( QStringLiteral( "Error transforming point coordinate" ) );
848 alreadyPrintedDebug = true;
849 }
850 }
851 const QgsVector3D point( x, y, z );
852 const QgsVector3D p = context.map().mapToWorldCoordinates( point );
853
854 QVector3D color( 0.0f, 0.0f, 0.0f );
855
856 context.getAttribute( ptr, i * recordSize + redOffset, redType, ir );
857 context.getAttribute( ptr, i * recordSize + greenOffset, greenType, ig );
858 context.getAttribute( ptr, i * recordSize + blueOffset, blueType, ib );
859
860 //skip if red, green or blue not in displayable range
861 if ( ( useRedContrastEnhancement && !redContrastEnhancement->isValueInDisplayableRange( ir ) )
862 || ( useGreenContrastEnhancement && !greenContrastEnhancement->isValueInDisplayableRange( ig ) )
863 || ( useBlueContrastEnhancement && !blueContrastEnhancement->isValueInDisplayableRange( ib ) ) )
864 {
865 continue;
866 }
867
868 //stretch color values
869 if ( useRedContrastEnhancement )
870 {
871 ir = redContrastEnhancement->enhanceContrast( ir );
872 }
873 if ( useGreenContrastEnhancement )
874 {
875 ig = greenContrastEnhancement->enhanceContrast( ig );
876 }
877 if ( useBlueContrastEnhancement )
878 {
879 ib = blueContrastEnhancement->enhanceContrast( ib );
880 }
881
882 color.setX( ir / 255.0f );
883 color.setY( ig / 255.0f );
884 color.setZ( ib / 255.0f );
885
886 outNormal.positions.push_back( QVector3D( p.x(), p.y(), p.z() ) );
887 outNormal.colors.push_back( color );
888 }
889}
890
891void QgsRGBPointCloud3DSymbolHandler::finalize( Qt3DCore::QEntity *parent, const QgsPointCloud3DRenderContext &context )
892{
893 makeEntity( parent, context, outNormal, false );
894}
895
896Qt3DQGeometry *QgsRGBPointCloud3DSymbolHandler::makeGeometry( Qt3DCore::QNode *parent, const QgsPointCloud3DSymbolHandler::PointData &data, unsigned int byteStride )
897{
898 return new QgsRGBPointCloud3DGeometry( parent, data, byteStride );
899}
900
901QgsClassificationPointCloud3DSymbolHandler::QgsClassificationPointCloud3DSymbolHandler()
902 : QgsPointCloud3DSymbolHandler()
903{
904
905}
906
907bool QgsClassificationPointCloud3DSymbolHandler::prepare( const QgsPointCloud3DRenderContext &context )
908{
909 Q_UNUSED( context )
910 return true;
911}
912
913void QgsClassificationPointCloud3DSymbolHandler::processNode( QgsPointCloudIndex *pc, const IndexedPointCloudNode &n, const QgsPointCloud3DRenderContext &context )
914{
916 const int xOffset = 0;
917 attributes.push_back( QgsPointCloudAttribute( QStringLiteral( "X" ), QgsPointCloudAttribute::Int32 ) );
918 const int yOffset = attributes.pointRecordSize();
919 attributes.push_back( QgsPointCloudAttribute( QStringLiteral( "Y" ), QgsPointCloudAttribute::Int32 ) );
920 const int zOffset = attributes.pointRecordSize();
921 attributes.push_back( QgsPointCloudAttribute( QStringLiteral( "Z" ), QgsPointCloudAttribute::Int32 ) );
922
923 QString attributeName;
924 bool attrIsX = false;
925 bool attrIsY = false;
926 bool attrIsZ = false;
928 int attributeOffset = 0;
930 if ( symbol )
931 {
932 int offset = 0;
933 const QgsPointCloudAttributeCollection collection = context.attributes();
934
935 if ( symbol->attribute() == QLatin1String( "X" ) )
936 {
937 attrIsX = true;
938 }
939 else if ( symbol->attribute() == QLatin1String( "Y" ) )
940 {
941 attrIsY = true;
942 }
943 else if ( symbol->attribute() == QLatin1String( "Z" ) )
944 {
945 attrIsZ = true;
946 }
947 else
948 {
949 const QgsPointCloudAttribute *attr = collection.find( symbol->attribute(), offset );
950 if ( attr )
951 {
952 attributeType = attr->type();
953 attributeName = attr->name();
954 attributeOffset = attributes.pointRecordSize();
955 attributes.push_back( *attr );
956 }
957 }
958 }
959
960 if ( attributeName.isEmpty() && !attrIsX && !attrIsY && !attrIsZ )
961 return;
962
963 QgsPointCloudRequest request;
964 request.setAttributes( attributes );
965 request.setFilterRect( context.extent() );
966 std::unique_ptr<QgsPointCloudBlock> block( pointCloudBlock( pc, n, request, context ) );
967 if ( !block )
968 return;
969
970 const char *ptr = block->data();
971 const int count = block->pointCount();
972 const std::size_t recordSize = block->attributes().pointRecordSize();
973
974 const QgsVector3D blockScale = block->scale();
975 const QgsVector3D blockOffset = block->offset();
976 const double zValueScale = context.zValueScale();
977 const double zValueOffset = context.zValueFixedOffset();
978 const QgsCoordinateTransform coordinateTransform = context.coordinateTransform();
979 bool alreadyPrintedDebug = false;
980
981 QList<QgsPointCloudCategory> categoriesList = symbol->categoriesList();
982 QVector<int> categoriesValues;
983 QHash<int, double> categoriesPointSizes;
984 for ( QgsPointCloudCategory &c : categoriesList )
985 {
986 categoriesValues.push_back( c.value() );
987 categoriesPointSizes.insert( c.value(), c.pointSize() > 0 ? c.pointSize() :
988 context.symbol() ? context.symbol()->pointSize() : 1.0 );
989 }
990
991 const QSet<int> filteredOutValues = context.getFilteredOutValues();
992 for ( int i = 0; i < count; ++i )
993 {
994 if ( context.isCanceled() )
995 break;
996
997 const qint32 ix = *( qint32 * )( ptr + i * recordSize + xOffset );
998 const qint32 iy = *( qint32 * )( ptr + i * recordSize + yOffset );
999 const qint32 iz = *( qint32 * )( ptr + i * recordSize + zOffset );
1000
1001 double x = blockOffset.x() + blockScale.x() * ix;
1002 double y = blockOffset.y() + blockScale.y() * iy;
1003 double z = ( blockOffset.z() + blockScale.z() * iz ) * zValueScale + zValueOffset;
1004 try
1005 {
1006 coordinateTransform.transformInPlace( x, y, z );
1007 }
1008 catch ( QgsCsException & )
1009 {
1010 if ( !alreadyPrintedDebug )
1011 {
1012 QgsDebugError( QStringLiteral( "Error transforming point coordinate" ) );
1013 alreadyPrintedDebug = true;
1014 }
1015 }
1016 const QgsVector3D point( x, y, z );
1017 const QgsVector3D p = context.map().mapToWorldCoordinates( point );
1018 float iParam = 0.0f;
1019 if ( attrIsX )
1020 iParam = x;
1021 else if ( attrIsY )
1022 iParam = y;
1023 else if ( attrIsZ )
1024 iParam = z;
1025 else
1026 context.getAttribute( ptr, i * recordSize + attributeOffset, attributeType, iParam );
1027
1028 if ( filteredOutValues.contains( ( int ) iParam ) ||
1029 ! categoriesValues.contains( ( int ) iParam ) )
1030 continue;
1031 outNormal.positions.push_back( QVector3D( p.x(), p.y(), p.z() ) );
1032
1033 // find iParam actual index in the categories list
1034 float iParam2 = categoriesValues.indexOf( ( int )iParam ) + 1;
1035 outNormal.parameter.push_back( iParam2 );
1036 outNormal.pointSizes.push_back( categoriesPointSizes.value( ( int ) iParam ) );
1037 }
1038}
1039
1040void QgsClassificationPointCloud3DSymbolHandler::finalize( Qt3DCore::QEntity *parent, const QgsPointCloud3DRenderContext &context )
1041{
1042 makeEntity( parent, context, outNormal, false );
1043}
1044
1045Qt3DQGeometry *QgsClassificationPointCloud3DSymbolHandler::makeGeometry( Qt3DCore::QNode *parent, const QgsPointCloud3DSymbolHandler::PointData &data, unsigned int byteStride )
1046{
1047 return new QgsClassificationPointCloud3DGeometry( parent, data, byteStride );
1048}
1049
Represents a indexed point cloud node in octree.
int d() const
Returns d.
IndexedPointCloudNode parentNode() const
Returns the parent of the node.
3
Definition: qgsaabb.h:33
float xMax
Definition: qgsaabb.h:89
float xExtent() const
Returns box width in X axis.
Definition: qgsaabb.h:42
float zExtent() const
Returns box width in Z axis.
Definition: qgsaabb.h:46
float xMin
Definition: qgsaabb.h:86
float zMax
Definition: qgsaabb.h:91
bool intersects(const QgsAABB &other) const
Determines whether the box intersects some other axis aligned box.
Definition: qgsaabb.cpp:35
float zMin
Definition: qgsaabb.h:88
QgsPointCloudCategoryList categoriesList() const
Returns the list of categories of the classification.
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, 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...
Custom exception class for Coordinate Reference System related exceptions.
Definition: qgsexception.h:67
void canceled()
Internal routines can connect to this signal if they use event loop.
Encapsulates the render context for a 3D point cloud rendering operation.
QgsRectangle extent() const
Returns the 3D scene's extent in layer crs.
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.
QgsPointCloud3DSymbol * symbol() const
Returns the symbol used for rendering the point cloud.
double zValueScale() const
Returns any constant scaling factor which must be applied to z values taken from the point cloud inde...
QgsFeedback * feedback() const
Returns the feedback object used to cancel rendering and check if rendering was canceled.
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.
double zValueFixedOffset() const
Returns any constant offset which must be applied to z values taken from the point cloud index.
bool verticalTriangleFilter() const
Returns whether triangles are filtered by vertical height for rendering.
float verticalFilterThreshold() const
Returns the threshold vertical height value for filtering triangles.
virtual unsigned int byteStride()=0
Returns the byte stride for the geometries used to for the vertex buffer.
float horizontalFilterThreshold() const
Returns the threshold horizontal size value for filtering triangles.
virtual void fillMaterial(Qt3DRender::QMaterial *material)=0SIP_SKIP
Used to fill material object with necessary QParameters (and consequently opengl uniforms)
bool renderAsTriangles() const
Returns whether points are triangulated to render solid surface.
float pointSize() const
Returns the point size of the point cloud.
bool horizontalTriangleFilter() const
Returns whether triangles are filtered by horizontal size for rendering.
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.
Base class for handling loading QgsPointCloudBlock asynchronously.
void finished()
Emitted when the request processing has finished.
std::unique_ptr< QgsPointCloudBlock > takeBlock()
Returns the requested block.
Represents an individual category (class) from a QgsPointCloudClassifiedRenderer.
Represents a indexed point clouds data in octree.
int span() const
Returns the number of points in one direction in a single node.
virtual qint64 nodePointCount(const IndexedPointCloudNode &n) const
Returns the number of points of a given node n.
virtual QgsPointCloudBlockRequest * asyncNodeData(const IndexedPointCloudNode &n, const QgsPointCloudRequest &request)=0
Returns a handle responsible for loading a node data block.
virtual AccessType accessType() const =0
Returns the access type of the data If the access type is Remote, data will be fetched from an HTTP s...
virtual std::unique_ptr< QgsPointCloudBlock > nodeData(const IndexedPointCloudNode &n, const QgsPointCloudRequest &request)=0
Returns node data block.
Point cloud data request.
void setFilterRect(QgsRectangle extent)
Sets the rectangle from which points will be taken, in point cloud's crs.
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.
Class for storage of 3D vectors similar to QVector3D, with the difference that it uses double precisi...
Definition: qgsvector3d.h:31
double y() const
Returns Y coordinate.
Definition: qgsvector3d.h:50
double z() const
Returns Z coordinate.
Definition: qgsvector3d.h:52
double x() const
Returns X coordinate.
Definition: qgsvector3d.h:48
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
Qt3DCore::QAttribute Qt3DQAttribute
Definition: qgs3daxis.cpp:28
Qt3DCore::QBuffer Qt3DQBuffer
Definition: qgs3daxis.cpp:30
Qt3DCore::QGeometry Qt3DQGeometry
Definition: qgs3daxis.cpp:29
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
#define QgsDebugError(str)
Definition: qgslogger.h:38