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