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