QGIS API Documentation 3.39.0-Master (47f7b3a4989)
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 "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;
523 {
524 block = pc->nodeData( n, request );
525 }
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 = context.map().mapToWorldCoordinates( QgsVector3D( x, y, z ) );
611 outNormal.positions.push_back( QVector3D( static_cast<float>( point.x() ), static_cast<float>( point.y() ), static_cast<float>( point.z() ) ) );
612 }
613}
614
615void QgsSingleColorPointCloud3DSymbolHandler::finalize( Qt3DCore::QEntity *parent, const QgsPointCloud3DRenderContext &context )
616{
617 makeEntity( parent, context, outNormal, false );
618}
619
620Qt3DQGeometry *QgsSingleColorPointCloud3DSymbolHandler::makeGeometry( Qt3DCore::QNode *parent, const QgsPointCloud3DSymbolHandler::PointData &data, unsigned int byteStride )
621{
622 return new QgsSingleColorPointCloud3DGeometry( parent, data, byteStride );
623}
624
625QgsColorRampPointCloud3DSymbolHandler::QgsColorRampPointCloud3DSymbolHandler()
626 : QgsPointCloud3DSymbolHandler()
627{
628
629}
630
631bool QgsColorRampPointCloud3DSymbolHandler::prepare( const QgsPointCloud3DRenderContext &context )
632{
633 Q_UNUSED( context )
634 return true;
635}
636
637void QgsColorRampPointCloud3DSymbolHandler::processNode( QgsPointCloudIndex *pc, const IndexedPointCloudNode &n, const QgsPointCloud3DRenderContext &context )
638{
640 const int xOffset = 0;
641 attributes.push_back( QgsPointCloudAttribute( QStringLiteral( "X" ), QgsPointCloudAttribute::Int32 ) );
642 const int yOffset = attributes.pointRecordSize();
643 attributes.push_back( QgsPointCloudAttribute( QStringLiteral( "Y" ), QgsPointCloudAttribute::Int32 ) );
644 const int zOffset = attributes.pointRecordSize();
645 attributes.push_back( QgsPointCloudAttribute( QStringLiteral( "Z" ), QgsPointCloudAttribute::Int32 ) );
646
647 QString attributeName;
648 bool attrIsX = false;
649 bool attrIsY = false;
650 bool attrIsZ = false;
652 int attributeOffset = 0;
653 const double zValueScale = context.zValueScale();
654 const double zValueOffset = context.zValueFixedOffset();
655 const QgsCoordinateTransform coordinateTransform = context.coordinateTransform();
656 bool alreadyPrintedDebug = false;
657
658 QgsColorRampPointCloud3DSymbol *symbol = dynamic_cast<QgsColorRampPointCloud3DSymbol *>( context.symbol() );
659 if ( symbol )
660 {
661 int offset = 0;
662 const QgsPointCloudAttributeCollection collection = context.attributes();
663
664 if ( symbol->attribute() == QLatin1String( "X" ) )
665 {
666 attrIsX = true;
667 }
668 else if ( symbol->attribute() == QLatin1String( "Y" ) )
669 {
670 attrIsY = true;
671 }
672 else if ( symbol->attribute() == QLatin1String( "Z" ) )
673 {
674 attrIsZ = true;
675 }
676 else
677 {
678 const QgsPointCloudAttribute *attr = collection.find( symbol->attribute(), offset );
679 if ( attr )
680 {
681 attributeType = attr->type();
682 attributeName = attr->name();
683 attributeOffset = attributes.pointRecordSize();
684 attributes.push_back( *attr );
685 }
686 }
687 }
688
689 if ( attributeName.isEmpty() && !attrIsX && !attrIsY && !attrIsZ )
690 return;
691
692 QgsPointCloudRequest request;
693 request.setAttributes( attributes );
694 request.setFilterRect( context.extent() );
695 std::unique_ptr<QgsPointCloudBlock> block( pointCloudBlock( pc, n, request, context ) );
696 if ( !block )
697 return;
698
699 const char *ptr = block->data();
700 const int count = block->pointCount();
701 const std::size_t recordSize = block->attributes().pointRecordSize();
702
703 const QgsVector3D blockScale = block->scale();
704 const QgsVector3D blockOffset = block->offset();
705
706 for ( int i = 0; i < count; ++i )
707 {
708 if ( context.isCanceled() )
709 break;
710
711 const qint32 ix = *( qint32 * )( ptr + i * recordSize + xOffset );
712 const qint32 iy = *( qint32 * )( ptr + i * recordSize + yOffset );
713 const qint32 iz = *( qint32 * )( ptr + i * recordSize + zOffset );
714
715 double x = blockOffset.x() + blockScale.x() * ix;
716 double y = blockOffset.y() + blockScale.y() * iy;
717 double z = ( blockOffset.z() + blockScale.z() * iz ) * zValueScale + zValueOffset;
718 try
719 {
720 coordinateTransform.transformInPlace( x, y, z );
721 }
722 catch ( QgsCsException & )
723 {
724 if ( !alreadyPrintedDebug )
725 {
726 QgsDebugError( QStringLiteral( "Error transforming point coordinate" ) );
727 alreadyPrintedDebug = true;
728 }
729 }
730 const QgsVector3D point = context.map().mapToWorldCoordinates( QgsVector3D( x, y, z ) );
731 outNormal.positions.push_back( QVector3D( static_cast<float>( point.x() ), static_cast<float>( point.y() ), static_cast<float>( point.z() ) ) );
732
733 if ( attrIsX )
734 outNormal.parameter.push_back( x );
735 else if ( attrIsY )
736 outNormal.parameter.push_back( y );
737 else if ( attrIsZ )
738 outNormal.parameter.push_back( z );
739 else
740 {
741 float iParam = 0.0f;
742 context.getAttribute( ptr, i * recordSize + attributeOffset, attributeType, iParam );
743 outNormal.parameter.push_back( iParam );
744 }
745 }
746}
747
748void QgsColorRampPointCloud3DSymbolHandler::finalize( Qt3DCore::QEntity *parent, const QgsPointCloud3DRenderContext &context )
749{
750 makeEntity( parent, context, outNormal, false );
751}
752
753Qt3DQGeometry *QgsColorRampPointCloud3DSymbolHandler::makeGeometry( Qt3DCore::QNode *parent, const QgsPointCloud3DSymbolHandler::PointData &data, unsigned int byteStride )
754{
755 return new QgsColorRampPointCloud3DGeometry( parent, data, byteStride );
756}
757
758QgsRGBPointCloud3DSymbolHandler::QgsRGBPointCloud3DSymbolHandler()
759 : QgsPointCloud3DSymbolHandler()
760{
761
762}
763
764bool QgsRGBPointCloud3DSymbolHandler::prepare( const QgsPointCloud3DRenderContext &context )
765{
766 Q_UNUSED( context )
767 return true;
768}
769
770void QgsRGBPointCloud3DSymbolHandler::processNode( QgsPointCloudIndex *pc, const IndexedPointCloudNode &n, const QgsPointCloud3DRenderContext &context )
771{
773 attributes.push_back( QgsPointCloudAttribute( QStringLiteral( "X" ), QgsPointCloudAttribute::Int32 ) );
774 attributes.push_back( QgsPointCloudAttribute( QStringLiteral( "Y" ), QgsPointCloudAttribute::Int32 ) );
775 attributes.push_back( QgsPointCloudAttribute( QStringLiteral( "Z" ), QgsPointCloudAttribute::Int32 ) );
776
777 QgsRgbPointCloud3DSymbol *symbol = dynamic_cast<QgsRgbPointCloud3DSymbol *>( context.symbol() );
778
779 // we have to get the RGB attributes using their real data types -- they aren't always short! (sometimes unsigned short)
780 int attrOffset = 0 ;
781
782 const int redOffset = attributes.pointRecordSize();
783 const QgsPointCloudAttribute *colorAttribute = context.attributes().find( symbol->redAttribute(), attrOffset );
784 attributes.push_back( *colorAttribute );
785 const QgsPointCloudAttribute::DataType redType = colorAttribute->type();
786
787 const int greenOffset = attributes.pointRecordSize();
788 colorAttribute = context.attributes().find( symbol->greenAttribute(), attrOffset );
789 attributes.push_back( *colorAttribute );
790 const QgsPointCloudAttribute::DataType greenType = colorAttribute->type();
791
792 const int blueOffset = attributes.pointRecordSize();
793 colorAttribute = context.attributes().find( symbol->blueAttribute(), attrOffset );
794 attributes.push_back( *colorAttribute );
795 const QgsPointCloudAttribute::DataType blueType = colorAttribute->type();
796
797 QgsPointCloudRequest request;
798 request.setAttributes( attributes );
799 request.setFilterRect( context.extent() );
800 std::unique_ptr<QgsPointCloudBlock> block( pointCloudBlock( pc, n, request, context ) );
801 if ( !block )
802 return;
803
804 const char *ptr = block->data();
805 const int count = block->pointCount();
806 const std::size_t recordSize = block->attributes().pointRecordSize();
807
808 const QgsVector3D blockScale = block->scale();
809 const QgsVector3D blockOffset = block->offset();
810 const double zValueScale = context.zValueScale();
811 const double zValueOffset = context.zValueFixedOffset();
812 const QgsCoordinateTransform coordinateTransform = context.coordinateTransform();
813 bool alreadyPrintedDebug = false;
814
815 QgsContrastEnhancement *redContrastEnhancement = symbol->redContrastEnhancement();
816 QgsContrastEnhancement *greenContrastEnhancement = symbol->greenContrastEnhancement();
817 QgsContrastEnhancement *blueContrastEnhancement = symbol->blueContrastEnhancement();
818
819 const bool useRedContrastEnhancement = redContrastEnhancement && redContrastEnhancement->contrastEnhancementAlgorithm() != QgsContrastEnhancement::NoEnhancement;
820 const bool useBlueContrastEnhancement = blueContrastEnhancement && blueContrastEnhancement->contrastEnhancementAlgorithm() != QgsContrastEnhancement::NoEnhancement;
821 const bool useGreenContrastEnhancement = greenContrastEnhancement && greenContrastEnhancement->contrastEnhancementAlgorithm() != QgsContrastEnhancement::NoEnhancement;
822
823 int ir = 0;
824 int ig = 0;
825 int ib = 0;
826 for ( int i = 0; i < count; ++i )
827 {
828 if ( context.isCanceled() )
829 break;
830
831 const qint32 ix = *( qint32 * )( ptr + i * recordSize + 0 );
832 const qint32 iy = *( qint32 * )( ptr + i * recordSize + 4 );
833 const qint32 iz = *( qint32 * )( ptr + i * recordSize + 8 );
834 double x = blockOffset.x() + blockScale.x() * ix;
835 double y = blockOffset.y() + blockScale.y() * iy;
836 double z = ( blockOffset.z() + blockScale.z() * iz ) * zValueScale + zValueOffset;
837 try
838 {
839 coordinateTransform.transformInPlace( x, y, z );
840 }
841 catch ( QgsCsException & )
842 {
843 if ( !alreadyPrintedDebug )
844 {
845 QgsDebugError( QStringLiteral( "Error transforming point coordinate" ) );
846 alreadyPrintedDebug = true;
847 }
848 }
849 const QgsVector3D point = context.map().mapToWorldCoordinates( QgsVector3D( x, y, z ) );
850
851 QVector3D color( 0.0f, 0.0f, 0.0f );
852
853 context.getAttribute( ptr, i * recordSize + redOffset, redType, ir );
854 context.getAttribute( ptr, i * recordSize + greenOffset, greenType, ig );
855 context.getAttribute( ptr, i * recordSize + blueOffset, blueType, ib );
856
857 //skip if red, green or blue not in displayable range
858 if ( ( useRedContrastEnhancement && !redContrastEnhancement->isValueInDisplayableRange( ir ) )
859 || ( useGreenContrastEnhancement && !greenContrastEnhancement->isValueInDisplayableRange( ig ) )
860 || ( useBlueContrastEnhancement && !blueContrastEnhancement->isValueInDisplayableRange( ib ) ) )
861 {
862 continue;
863 }
864
865 //stretch color values
866 if ( useRedContrastEnhancement )
867 {
868 ir = redContrastEnhancement->enhanceContrast( ir );
869 }
870 if ( useGreenContrastEnhancement )
871 {
872 ig = greenContrastEnhancement->enhanceContrast( ig );
873 }
874 if ( useBlueContrastEnhancement )
875 {
876 ib = blueContrastEnhancement->enhanceContrast( ib );
877 }
878
879 color.setX( ir / 255.0f );
880 color.setY( ig / 255.0f );
881 color.setZ( ib / 255.0f );
882
883 outNormal.positions.push_back( QVector3D( static_cast<float>( point.x() ), static_cast<float>( point.y() ), static_cast<float>( point.z() ) ) );
884 outNormal.colors.push_back( color );
885 }
886}
887
888void QgsRGBPointCloud3DSymbolHandler::finalize( Qt3DCore::QEntity *parent, const QgsPointCloud3DRenderContext &context )
889{
890 makeEntity( parent, context, outNormal, false );
891}
892
893Qt3DQGeometry *QgsRGBPointCloud3DSymbolHandler::makeGeometry( Qt3DCore::QNode *parent, const QgsPointCloud3DSymbolHandler::PointData &data, unsigned int byteStride )
894{
895 return new QgsRGBPointCloud3DGeometry( parent, data, byteStride );
896}
897
898QgsClassificationPointCloud3DSymbolHandler::QgsClassificationPointCloud3DSymbolHandler()
899 : QgsPointCloud3DSymbolHandler()
900{
901
902}
903
904bool QgsClassificationPointCloud3DSymbolHandler::prepare( const QgsPointCloud3DRenderContext &context )
905{
906 Q_UNUSED( context )
907 return true;
908}
909
910void QgsClassificationPointCloud3DSymbolHandler::processNode( QgsPointCloudIndex *pc, const IndexedPointCloudNode &n, const QgsPointCloud3DRenderContext &context )
911{
913 const int xOffset = 0;
914 attributes.push_back( QgsPointCloudAttribute( QStringLiteral( "X" ), QgsPointCloudAttribute::Int32 ) );
915 const int yOffset = attributes.pointRecordSize();
916 attributes.push_back( QgsPointCloudAttribute( QStringLiteral( "Y" ), QgsPointCloudAttribute::Int32 ) );
917 const int zOffset = attributes.pointRecordSize();
918 attributes.push_back( QgsPointCloudAttribute( QStringLiteral( "Z" ), QgsPointCloudAttribute::Int32 ) );
919
920 QString attributeName;
921 bool attrIsX = false;
922 bool attrIsY = false;
923 bool attrIsZ = false;
925 int attributeOffset = 0;
927 if ( symbol )
928 {
929 int offset = 0;
930 const QgsPointCloudAttributeCollection collection = context.attributes();
931
932 if ( symbol->attribute() == QLatin1String( "X" ) )
933 {
934 attrIsX = true;
935 }
936 else if ( symbol->attribute() == QLatin1String( "Y" ) )
937 {
938 attrIsY = true;
939 }
940 else if ( symbol->attribute() == QLatin1String( "Z" ) )
941 {
942 attrIsZ = true;
943 }
944 else
945 {
946 const QgsPointCloudAttribute *attr = collection.find( symbol->attribute(), offset );
947 if ( attr )
948 {
949 attributeType = attr->type();
950 attributeName = attr->name();
951 attributeOffset = attributes.pointRecordSize();
952 attributes.push_back( *attr );
953 }
954 }
955 }
956
957 if ( attributeName.isEmpty() && !attrIsX && !attrIsY && !attrIsZ )
958 return;
959
960 QgsPointCloudRequest request;
961 request.setAttributes( attributes );
962 request.setFilterRect( context.extent() );
963 std::unique_ptr<QgsPointCloudBlock> block( pointCloudBlock( pc, n, request, context ) );
964 if ( !block )
965 return;
966
967 const char *ptr = block->data();
968 const int count = block->pointCount();
969 const std::size_t recordSize = block->attributes().pointRecordSize();
970
971 const QgsVector3D blockScale = block->scale();
972 const QgsVector3D blockOffset = block->offset();
973 const double zValueScale = context.zValueScale();
974 const double zValueOffset = context.zValueFixedOffset();
975 const QgsCoordinateTransform coordinateTransform = context.coordinateTransform();
976 bool alreadyPrintedDebug = false;
977
978 QList<QgsPointCloudCategory> categoriesList = symbol->categoriesList();
979 QVector<int> categoriesValues;
980 QHash<int, double> categoriesPointSizes;
981 for ( QgsPointCloudCategory &c : categoriesList )
982 {
983 categoriesValues.push_back( c.value() );
984 categoriesPointSizes.insert( c.value(), c.pointSize() > 0 ? c.pointSize() :
985 context.symbol() ? context.symbol()->pointSize() : 1.0 );
986 }
987
988 const QSet<int> filteredOutValues = context.getFilteredOutValues();
989 for ( int i = 0; i < count; ++i )
990 {
991 if ( context.isCanceled() )
992 break;
993
994 const qint32 ix = *( qint32 * )( ptr + i * recordSize + xOffset );
995 const qint32 iy = *( qint32 * )( ptr + i * recordSize + yOffset );
996 const qint32 iz = *( qint32 * )( ptr + i * recordSize + zOffset );
997
998 double x = blockOffset.x() + blockScale.x() * ix;
999 double y = blockOffset.y() + blockScale.y() * iy;
1000 double z = ( blockOffset.z() + blockScale.z() * iz ) * zValueScale + zValueOffset;
1001 try
1002 {
1003 coordinateTransform.transformInPlace( x, y, z );
1004 }
1005 catch ( QgsCsException & )
1006 {
1007 if ( !alreadyPrintedDebug )
1008 {
1009 QgsDebugError( QStringLiteral( "Error transforming point coordinate" ) );
1010 alreadyPrintedDebug = true;
1011 }
1012 }
1013 const QgsVector3D point = context.map().mapToWorldCoordinates( QgsVector3D( x, y, z ) );
1014 float iParam = 0.0f;
1015 if ( attrIsX )
1016 iParam = x;
1017 else if ( attrIsY )
1018 iParam = y;
1019 else if ( attrIsZ )
1020 iParam = z;
1021 else
1022 context.getAttribute( ptr, i * recordSize + attributeOffset, attributeType, iParam );
1023
1024 if ( filteredOutValues.contains( ( int ) iParam ) ||
1025 ! categoriesValues.contains( ( int ) iParam ) )
1026 continue;
1027 outNormal.positions.push_back( QVector3D( static_cast<float>( point.x() ), static_cast<float>( point.y() ), static_cast<float>( point.z() ) ) );
1028
1029 // find iParam actual index in the categories list
1030 float iParam2 = categoriesValues.indexOf( ( int )iParam ) + 1;
1031 outNormal.parameter.push_back( iParam2 );
1032 outNormal.pointSizes.push_back( categoriesPointSizes.value( ( int ) iParam ) );
1033 }
1034}
1035
1036void QgsClassificationPointCloud3DSymbolHandler::finalize( Qt3DCore::QEntity *parent, const QgsPointCloud3DRenderContext &context )
1037{
1038 makeEntity( parent, context, outNormal, false );
1039}
1040
1041Qt3DQGeometry *QgsClassificationPointCloud3DSymbolHandler::makeGeometry( Qt3DCore::QNode *parent, const QgsPointCloud3DSymbolHandler::PointData &data, unsigned int byteStride )
1042{
1043 return new QgsClassificationPointCloud3DGeometry( parent, data, byteStride );
1044}
1045
Represents a indexed point cloud node in octree.
int d() const
Returns d.
IndexedPointCloudNode parentNode() const
Returns the parent of the node.
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.
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.
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