QGIS API Documentation 3.41.0-Master (fda2aa46e9a)
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#include "moc_qgspointcloud3dsymbol_p.cpp"
18
20
24#include "qgspointcloudindex.h"
26#include "qgsfeedback.h"
27#include "qgsaabb.h"
28
29#include <Qt3DCore/QEntity>
30#include <Qt3DRender/QGeometryRenderer>
31#include <Qt3DRender/QParameter>
32#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
33#include <Qt3DRender/QAttribute>
34#include <Qt3DRender/QBuffer>
35#include <Qt3DRender/QGeometry>
36
37typedef Qt3DRender::QAttribute Qt3DQAttribute;
38typedef Qt3DRender::QBuffer Qt3DQBuffer;
39typedef Qt3DRender::QGeometry Qt3DQGeometry;
40#else
41#include <Qt3DCore/QAttribute>
42#include <Qt3DCore/QBuffer>
43#include <Qt3DCore/QGeometry>
44
45typedef Qt3DCore::QAttribute Qt3DQAttribute;
46typedef Qt3DCore::QBuffer Qt3DQBuffer;
47typedef Qt3DCore::QGeometry Qt3DQGeometry;
48#endif
49#include <Qt3DRender/QTechnique>
50#include <Qt3DRender/QShaderProgram>
51#include <Qt3DRender/QGraphicsApiFilter>
52#include <Qt3DRender/QEffect>
53#include <QPointSize>
54#include <QUrl>
55
56#include <delaunator.hpp>
57
58// pick a point that we'll use as origin for coordinates for this node's points
59static QgsVector3D originFromNodeBounds( QgsPointCloudIndex *pc, const IndexedPointCloudNode &n, const QgsPointCloud3DRenderContext &context, const QgsPointCloudBlock *block )
60{
61 const QgsVector3D blockScale = block->scale();
62 const QgsVector3D blockOffset = block->offset();
63
64 QgsPointCloudDataBounds bounds = pc->nodeBounds( n );
65 double nodeOriginX = bounds.xMin() * blockScale.x() + blockOffset.x();
66 double nodeOriginY = bounds.yMin() * blockScale.y() + blockOffset.y();
67 double nodeOriginZ = ( bounds.zMin() * blockScale.z() + blockOffset.z() ) * 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 Qt3DCore::QTransform *tr = new Qt3DCore::QTransform;
311 QVector3D nodeTranslation = ( out.positionsOrigin - context.origin() ).toVector3D();
312 tr->setTranslation( nodeTranslation );
313
314 // Material
315 QgsMaterial *mat = new QgsMaterial;
316 if ( context.symbol() )
317 context.symbol()->fillMaterial( mat );
318
319 Qt3DRender::QShaderProgram *shaderProgram = new Qt3DRender::QShaderProgram( mat );
320 shaderProgram->setVertexShaderCode( Qt3DRender::QShaderProgram::loadSource( QUrl( QStringLiteral( "qrc:/shaders/pointcloud.vert" ) ) ) );
321 shaderProgram->setFragmentShaderCode( Qt3DRender::QShaderProgram::loadSource( QUrl( QStringLiteral( "qrc:/shaders/pointcloud.frag" ) ) ) );
322
323 Qt3DRender::QRenderPass *renderPass = new Qt3DRender::QRenderPass( mat );
324 renderPass->setShaderProgram( shaderProgram );
325
326 if ( out.triangles.isEmpty() )
327 {
328 Qt3DRender::QPointSize *pointSize = new Qt3DRender::QPointSize( renderPass );
329 pointSize->setSizeMode( Qt3DRender::QPointSize::Programmable ); // supported since OpenGL 3.2
330 renderPass->addRenderState( pointSize );
331 }
332
333 // without this filter the default forward renderer would not render this
334 Qt3DRender::QFilterKey *filterKey = new Qt3DRender::QFilterKey;
335 filterKey->setName( QStringLiteral( "renderingStyle" ) );
336 filterKey->setValue( "forward" );
337
338 Qt3DRender::QTechnique *technique = new Qt3DRender::QTechnique;
339 technique->addRenderPass( renderPass );
340 technique->addFilterKey( filterKey );
341 technique->graphicsApiFilter()->setApi( Qt3DRender::QGraphicsApiFilter::OpenGL );
342 technique->graphicsApiFilter()->setProfile( Qt3DRender::QGraphicsApiFilter::CoreProfile );
343 technique->graphicsApiFilter()->setMajorVersion( 3 );
344 technique->graphicsApiFilter()->setMinorVersion( 1 );
345 technique->addParameter( new Qt3DRender::QParameter( "triangulate", !out.triangles.isEmpty() ) );
346
347 Qt3DRender::QEffect *eff = new Qt3DRender::QEffect;
348 eff->addTechnique( technique );
349 mat->setEffect( eff );
350
351 // All together
352 Qt3DCore::QEntity *entity = new Qt3DCore::QEntity;
353 entity->addComponent( gr );
354 entity->addComponent( tr );
355 entity->addComponent( mat );
356 entity->setParent( parent );
357 // cppcheck wrongly believes entity will leak
358 // cppcheck-suppress memleak
359}
360
361
362std::vector<double> QgsPointCloud3DSymbolHandler::getVertices( QgsPointCloudIndex *pc, const IndexedPointCloudNode &n, const QgsPointCloud3DRenderContext &context, const QgsBox3D &box3D )
363{
364
365 bool hasColorData = !outNormal.colors.empty();
366 bool hasParameterData = !outNormal.parameter.empty();
367 bool hasPointSizeData = !outNormal.pointSizes.empty();
368
369 // first, get the points of the concerned node
370 std::vector<double> vertices( outNormal.positions.size() * 2 );
371 size_t idx = 0;
372 for ( int i = 0; i < outNormal.positions.size(); ++i )
373 {
374 vertices[idx++] = outNormal.positions.at( i ).x();
375 vertices[idx++] = -outNormal.positions.at( i ).y(); // flipping y to have correctly oriented triangles from delaunator
376 }
377
378 // next, we also need all points of all parents nodes to make the triangulation (also external points)
379 IndexedPointCloudNode parentNode = n.parentNode();
380
381 double span = pc->span();
382 //factor to take account of the density of the point to calculate extension of the bounding box
383 // with a usual value span = 128, bounding box is extended by 12.5 % on each side.
384 double extraBoxFactor = 16 / span;
385
386 // We keep all points in vertical direction to avoid odd triangulation if points are isolated on top
387 QgsRectangle rectRelativeToChunkOrigin = ( box3D - outNormal.positionsOrigin ).toRectangle();
388 rectRelativeToChunkOrigin.grow( extraBoxFactor * std::max( box3D.width(), box3D.height() ) );
389
390 PointData filteredExtraPointData;
391 while ( parentNode.d() >= 0 )
392 {
393 PointData outputParent;
394 processNode( pc, parentNode, context, &outputParent );
395
396 // the "main" chunk and each parent chunks have their origins
397 QVector3D originDifference = ( outputParent.positionsOrigin - outNormal.positionsOrigin ).toVector3D();
398
399 for ( int i = 0; i < outputParent.positions.count(); ++i )
400 {
401 const QVector3D pos = outputParent.positions.at( i ) + originDifference;
402 if ( rectRelativeToChunkOrigin.contains( pos.x(), pos.y() ) )
403 {
404 filteredExtraPointData.positions.append( pos );
405 vertices.push_back( pos.x() );
406 vertices.push_back( -pos.y() ); // flipping y to have correctly oriented triangles from delaunator
407
408 if ( hasColorData )
409 filteredExtraPointData.colors.append( outputParent.colors.at( i ) );
410 if ( hasParameterData )
411 filteredExtraPointData.parameter.append( outputParent.parameter.at( i ) );
412 if ( hasPointSizeData )
413 filteredExtraPointData.pointSizes.append( outputParent.pointSizes.at( i ) );
414 }
415 }
416
417 parentNode = parentNode.parentNode();
418 }
419
420 outNormal.positions.append( filteredExtraPointData.positions );
421 outNormal.colors.append( filteredExtraPointData.colors );
422 outNormal.parameter.append( filteredExtraPointData.parameter );
423 outNormal.pointSizes.append( filteredExtraPointData.pointSizes );
424
425 return vertices;
426}
427
428void QgsPointCloud3DSymbolHandler::calculateNormals( const std::vector<size_t> &triangles )
429{
430 QVector<QVector3D> normals( outNormal.positions.count(), QVector3D( 0.0, 0.0, 0.0 ) );
431 for ( size_t i = 0; i < triangles.size(); i += 3 )
432 {
433 QVector<QVector3D> triangleVertices( 3 );
434 for ( size_t j = 0; j < 3; ++j )
435 {
436 size_t vertIndex = triangles.at( i + j );
437 triangleVertices[j] = outNormal.positions.at( vertIndex );
438 }
439 //calculate normals
440 for ( size_t j = 0; j < 3; ++j )
441 normals[triangles.at( i + j )] += QVector3D::crossProduct(
442 triangleVertices.at( 1 ) - triangleVertices.at( 0 ),
443 triangleVertices.at( 2 ) - triangleVertices.at( 0 ) );
444 }
445
446 // Build now normals array
447 outNormal.normals.resize( ( outNormal.positions.count() ) * sizeof( float ) * 3 );
448 float *normPtr = reinterpret_cast<float *>( outNormal.normals.data() );
449 for ( int i = 0; i < normals.size(); ++i )
450 {
451 QVector3D normal = normals.at( i );
452 normal = normal.normalized();
453
454 *normPtr++ = normal.x();
455 *normPtr++ = normal.y();
456 *normPtr++ = normal.z();
457 }
458}
459
460void QgsPointCloud3DSymbolHandler::filterTriangles( const std::vector<size_t> &triangleIndexes, const QgsPointCloud3DRenderContext &context, const QgsBox3D &box3D )
461{
462 outNormal.triangles.resize( triangleIndexes.size() * sizeof( quint32 ) );
463 quint32 *indexPtr = reinterpret_cast<quint32 *>( outNormal.triangles.data() );
464 size_t effective = 0;
465
466 bool horizontalFilter = context.symbol()->horizontalTriangleFilter();
467 bool verticalFilter = context.symbol()->verticalTriangleFilter();
468 float horizontalThreshold = context.symbol()->horizontalFilterThreshold();
469 float verticalThreshold = context.symbol()->verticalFilterThreshold();
470
471 QgsBox3D boxRelativeToChunkOrigin = box3D - outNormal.positionsOrigin;
472
473 for ( size_t i = 0; i < triangleIndexes.size(); i += 3 )
474 {
475 bool atLeastOneInBox = false;
476 bool horizontalSkip = false;
477 bool verticalSkip = false;
478 for ( size_t j = 0; j < 3; j++ )
479 {
480 QVector3D pos = outNormal.positions.at( triangleIndexes.at( i + j ) );
481 atLeastOneInBox |= boxRelativeToChunkOrigin.contains( pos.x(), pos.y(), pos.z() );
482
483 if ( verticalFilter || horizontalFilter )
484 {
485 const QVector3D pos2 = outNormal.positions.at( triangleIndexes.at( i + ( j + 1 ) % 3 ) );
486
487 if ( verticalFilter )
488 verticalSkip |= std::fabs( pos.z() - pos2.z() ) > verticalThreshold;
489
490 if ( horizontalFilter && ! verticalSkip )
491 {
492 // filter only in the horizontal plan, it is a 2.5D triangulation.
493 horizontalSkip |= sqrt( std::pow( pos.x() - pos2.x(), 2 ) +
494 std::pow( pos.y() - pos2.y(), 2 ) ) > horizontalThreshold;
495 }
496
497 if ( horizontalSkip || verticalSkip )
498 break;
499 }
500 }
501 if ( atLeastOneInBox && !horizontalSkip && !verticalSkip )
502 {
503 for ( size_t j = 0; j < 3; j++ )
504 {
505 size_t vertIndex = triangleIndexes.at( i + j );
506 *indexPtr++ = quint32( vertIndex );
507 }
508 effective++;
509 }
510 }
511
512 if ( effective != 0 )
513 {
514 outNormal.triangles.resize( effective * 3 * sizeof( quint32 ) );
515 }
516 else
517 {
518 outNormal.triangles.clear();
519 outNormal.normals.clear();
520 }
521}
522
523void QgsPointCloud3DSymbolHandler::triangulate( QgsPointCloudIndex *pc, const IndexedPointCloudNode &n, const QgsPointCloud3DRenderContext &context, const QgsBox3D &box3D )
524{
525 if ( outNormal.positions.isEmpty() )
526 return;
527
528 // Triangulation happens here
529 std::unique_ptr<delaunator::Delaunator> triangulation;
530 try
531 {
532 std::vector<double> vertices = getVertices( pc, n, context, box3D );
533 triangulation.reset( new delaunator::Delaunator( vertices ) );
534 }
535 catch ( std::exception &e )
536 {
537 // something went wrong, better to retrieve initial state
538 QgsDebugMsgLevel( QStringLiteral( "Error with triangulation" ), 4 );
539 outNormal = PointData();
540 processNode( pc, n, context );
541 return;
542 }
543
544 const std::vector<size_t> &triangleIndexes = triangulation->triangles;
545
546 calculateNormals( triangleIndexes );
547 filterTriangles( triangleIndexes, context, box3D );
548}
549
550std::unique_ptr<QgsPointCloudBlock> QgsPointCloud3DSymbolHandler::pointCloudBlock( QgsPointCloudIndex *pc, const IndexedPointCloudNode &n, const QgsPointCloudRequest &request, const QgsPointCloud3DRenderContext &context )
551{
552 std::unique_ptr<QgsPointCloudBlock> block;
554 {
555 block = pc->nodeData( n, request );
556 }
558 {
559 if ( pc->nodePointCount( n ) < 1 )
560 return block;
561
562 bool loopAborted = false;
563 QEventLoop loop;
564 QgsPointCloudBlockRequest *req = pc->asyncNodeData( n, request );
565 QObject::connect( req, &QgsPointCloudBlockRequest::finished, &loop, &QEventLoop::quit );
566 QObject::connect( context.feedback(), &QgsFeedback::canceled, &loop, [ & ]()
567 {
568 loopAborted = true;
569 loop.quit();
570 } );
571 loop.exec();
572
573 if ( !loopAborted )
574 block = req->takeBlock();
575 }
576 return block;
577}
578
579//
580
581QgsSingleColorPointCloud3DSymbolHandler::QgsSingleColorPointCloud3DSymbolHandler()
582 : QgsPointCloud3DSymbolHandler()
583{
584
585}
586
587bool QgsSingleColorPointCloud3DSymbolHandler::prepare( const QgsPointCloud3DRenderContext &context )
588{
589 Q_UNUSED( context )
590 return true;
591}
592
593void QgsSingleColorPointCloud3DSymbolHandler::processNode( QgsPointCloudIndex *pc, const IndexedPointCloudNode &n, const QgsPointCloud3DRenderContext &context, PointData *output )
594{
596 attributes.push_back( QgsPointCloudAttribute( QStringLiteral( "X" ), QgsPointCloudAttribute::Int32 ) );
597 attributes.push_back( QgsPointCloudAttribute( QStringLiteral( "Y" ), QgsPointCloudAttribute::Int32 ) );
598 attributes.push_back( QgsPointCloudAttribute( QStringLiteral( "Z" ), QgsPointCloudAttribute::Int32 ) );
599
600 QgsPointCloudRequest request;
601 request.setAttributes( attributes );
602 request.setFilterRect( context.layerExtent() );
603 std::unique_ptr<QgsPointCloudBlock> block( pointCloudBlock( pc, n, request, context ) );
604 if ( !block )
605 return;
606
607 const char *ptr = block->data();
608 const int count = block->pointCount();
609 const std::size_t recordSize = block->attributes().pointRecordSize();
610 const QgsVector3D blockScale = block->scale();
611 const QgsVector3D blockOffset = block->offset();
612 const double zValueScale = context.zValueScale();
613 const double zValueOffset = context.zValueFixedOffset();
614 const QgsCoordinateTransform coordinateTransform = context.coordinateTransform();
615 bool alreadyPrintedDebug = false;
616
617 if ( !output )
618 output = &outNormal;
619
620 output->positionsOrigin = originFromNodeBounds( pc, n, context, block.get() );
621
622 for ( int i = 0; i < count; ++i )
623 {
624 if ( context.isCanceled() )
625 break;
626
627 const qint32 ix = *( qint32 * )( ptr + i * recordSize + 0 );
628 const qint32 iy = *( qint32 * )( ptr + i * recordSize + 4 );
629 const qint32 iz = *( qint32 * )( ptr + i * recordSize + 8 );
630
631 double x = blockOffset.x() + blockScale.x() * ix;
632 double y = blockOffset.y() + blockScale.y() * iy;
633 double z = ( blockOffset.z() + blockScale.z() * iz ) * zValueScale + zValueOffset;
634 try
635 {
636 coordinateTransform.transformInPlace( x, y, z );
637 }
638 catch ( QgsCsException &e )
639 {
640 if ( !alreadyPrintedDebug )
641 {
642 QgsDebugError( QStringLiteral( "Error transforming point coordinate" ) );
643 alreadyPrintedDebug = true;
644 }
645 }
646 const QgsVector3D point = QgsVector3D( x, y, z ) - output->positionsOrigin;
647 output->positions.push_back( point.toVector3D() );
648 }
649}
650
651void QgsSingleColorPointCloud3DSymbolHandler::finalize( Qt3DCore::QEntity *parent, const QgsPointCloud3DRenderContext &context )
652{
653 makeEntity( parent, context, outNormal, false );
654}
655
656Qt3DQGeometry *QgsSingleColorPointCloud3DSymbolHandler::makeGeometry( Qt3DCore::QNode *parent, const QgsPointCloud3DSymbolHandler::PointData &data, unsigned int byteStride )
657{
658 return new QgsSingleColorPointCloud3DGeometry( parent, data, byteStride );
659}
660
661QgsColorRampPointCloud3DSymbolHandler::QgsColorRampPointCloud3DSymbolHandler()
662 : QgsPointCloud3DSymbolHandler()
663{
664
665}
666
667bool QgsColorRampPointCloud3DSymbolHandler::prepare( const QgsPointCloud3DRenderContext &context )
668{
669 Q_UNUSED( context )
670 return true;
671}
672
673void QgsColorRampPointCloud3DSymbolHandler::processNode( QgsPointCloudIndex *pc, const IndexedPointCloudNode &n, const QgsPointCloud3DRenderContext &context, PointData *output )
674{
676 const int xOffset = 0;
677 attributes.push_back( QgsPointCloudAttribute( QStringLiteral( "X" ), QgsPointCloudAttribute::Int32 ) );
678 const int yOffset = attributes.pointRecordSize();
679 attributes.push_back( QgsPointCloudAttribute( QStringLiteral( "Y" ), QgsPointCloudAttribute::Int32 ) );
680 const int zOffset = attributes.pointRecordSize();
681 attributes.push_back( QgsPointCloudAttribute( QStringLiteral( "Z" ), QgsPointCloudAttribute::Int32 ) );
682
683 QString attributeName;
684 bool attrIsX = false;
685 bool attrIsY = false;
686 bool attrIsZ = false;
688 int attributeOffset = 0;
689 const double zValueScale = context.zValueScale();
690 const double zValueOffset = context.zValueFixedOffset();
691 const QgsCoordinateTransform coordinateTransform = context.coordinateTransform();
692 bool alreadyPrintedDebug = false;
693
694 QgsColorRampPointCloud3DSymbol *symbol = dynamic_cast<QgsColorRampPointCloud3DSymbol *>( context.symbol() );
695 if ( symbol )
696 {
697 int offset = 0;
698 const QgsPointCloudAttributeCollection collection = context.attributes();
699
700 if ( symbol->attribute() == QLatin1String( "X" ) )
701 {
702 attrIsX = true;
703 }
704 else if ( symbol->attribute() == QLatin1String( "Y" ) )
705 {
706 attrIsY = true;
707 }
708 else if ( symbol->attribute() == QLatin1String( "Z" ) )
709 {
710 attrIsZ = true;
711 }
712 else
713 {
714 const QgsPointCloudAttribute *attr = collection.find( symbol->attribute(), offset );
715 if ( attr )
716 {
717 attributeType = attr->type();
718 attributeName = attr->name();
719 attributeOffset = attributes.pointRecordSize();
720 attributes.push_back( *attr );
721 }
722 }
723 }
724
725 if ( attributeName.isEmpty() && !attrIsX && !attrIsY && !attrIsZ )
726 return;
727
728 QgsPointCloudRequest request;
729 request.setAttributes( attributes );
730 request.setFilterRect( context.layerExtent() );
731 std::unique_ptr<QgsPointCloudBlock> block( pointCloudBlock( pc, n, request, context ) );
732 if ( !block )
733 return;
734
735 const char *ptr = block->data();
736 const int count = block->pointCount();
737 const std::size_t recordSize = block->attributes().pointRecordSize();
738
739 const QgsVector3D blockScale = block->scale();
740 const QgsVector3D blockOffset = block->offset();
741
742 if ( !output )
743 output = &outNormal;
744
745 output->positionsOrigin = originFromNodeBounds( pc, n, context, block.get() );
746
747 for ( int i = 0; i < count; ++i )
748 {
749 if ( context.isCanceled() )
750 break;
751
752 const qint32 ix = *( qint32 * )( ptr + i * recordSize + xOffset );
753 const qint32 iy = *( qint32 * )( ptr + i * recordSize + yOffset );
754 const qint32 iz = *( qint32 * )( ptr + i * recordSize + zOffset );
755
756 double x = blockOffset.x() + blockScale.x() * ix;
757 double y = blockOffset.y() + blockScale.y() * iy;
758 double z = ( blockOffset.z() + blockScale.z() * iz ) * zValueScale + zValueOffset;
759 try
760 {
761 coordinateTransform.transformInPlace( x, y, z );
762 }
763 catch ( QgsCsException & )
764 {
765 if ( !alreadyPrintedDebug )
766 {
767 QgsDebugError( QStringLiteral( "Error transforming point coordinate" ) );
768 alreadyPrintedDebug = true;
769 }
770 }
771 const QgsVector3D point = QgsVector3D( x, y, z ) - output->positionsOrigin;
772 output->positions.push_back( point.toVector3D() );
773
774 if ( attrIsX )
775 output->parameter.push_back( x );
776 else if ( attrIsY )
777 output->parameter.push_back( y );
778 else if ( attrIsZ )
779 output->parameter.push_back( z );
780 else
781 {
782 float iParam = 0.0f;
783 context.getAttribute( ptr, i * recordSize + attributeOffset, attributeType, iParam );
784 output->parameter.push_back( iParam );
785 }
786 }
787}
788
789void QgsColorRampPointCloud3DSymbolHandler::finalize( Qt3DCore::QEntity *parent, const QgsPointCloud3DRenderContext &context )
790{
791 makeEntity( parent, context, outNormal, false );
792}
793
794Qt3DQGeometry *QgsColorRampPointCloud3DSymbolHandler::makeGeometry( Qt3DCore::QNode *parent, const QgsPointCloud3DSymbolHandler::PointData &data, unsigned int byteStride )
795{
796 return new QgsColorRampPointCloud3DGeometry( parent, data, byteStride );
797}
798
799QgsRGBPointCloud3DSymbolHandler::QgsRGBPointCloud3DSymbolHandler()
800 : QgsPointCloud3DSymbolHandler()
801{
802
803}
804
805bool QgsRGBPointCloud3DSymbolHandler::prepare( const QgsPointCloud3DRenderContext &context )
806{
807 Q_UNUSED( context )
808 return true;
809}
810
811void QgsRGBPointCloud3DSymbolHandler::processNode( QgsPointCloudIndex *pc, const IndexedPointCloudNode &n, const QgsPointCloud3DRenderContext &context, PointData *output )
812{
814 attributes.push_back( QgsPointCloudAttribute( QStringLiteral( "X" ), QgsPointCloudAttribute::Int32 ) );
815 attributes.push_back( QgsPointCloudAttribute( QStringLiteral( "Y" ), QgsPointCloudAttribute::Int32 ) );
816 attributes.push_back( QgsPointCloudAttribute( QStringLiteral( "Z" ), QgsPointCloudAttribute::Int32 ) );
817
818 QgsRgbPointCloud3DSymbol *symbol = dynamic_cast<QgsRgbPointCloud3DSymbol *>( context.symbol() );
819
820 // we have to get the RGB attributes using their real data types -- they aren't always short! (sometimes unsigned short)
821 int attrOffset = 0 ;
822
823 const int redOffset = attributes.pointRecordSize();
824 const QgsPointCloudAttribute *colorAttribute = context.attributes().find( symbol->redAttribute(), attrOffset );
825 attributes.push_back( *colorAttribute );
826 const QgsPointCloudAttribute::DataType redType = colorAttribute->type();
827
828 const int greenOffset = attributes.pointRecordSize();
829 colorAttribute = context.attributes().find( symbol->greenAttribute(), attrOffset );
830 attributes.push_back( *colorAttribute );
831 const QgsPointCloudAttribute::DataType greenType = colorAttribute->type();
832
833 const int blueOffset = attributes.pointRecordSize();
834 colorAttribute = context.attributes().find( symbol->blueAttribute(), attrOffset );
835 attributes.push_back( *colorAttribute );
836 const QgsPointCloudAttribute::DataType blueType = colorAttribute->type();
837
838 QgsPointCloudRequest request;
839 request.setAttributes( attributes );
840 request.setFilterRect( context.layerExtent() );
841 std::unique_ptr<QgsPointCloudBlock> block( pointCloudBlock( pc, n, request, context ) );
842 if ( !block )
843 return;
844
845 const char *ptr = block->data();
846 const int count = block->pointCount();
847 const std::size_t recordSize = block->attributes().pointRecordSize();
848
849 const QgsVector3D blockScale = block->scale();
850 const QgsVector3D blockOffset = block->offset();
851 const double zValueScale = context.zValueScale();
852 const double zValueOffset = context.zValueFixedOffset();
853 const QgsCoordinateTransform coordinateTransform = context.coordinateTransform();
854 bool alreadyPrintedDebug = false;
855
856 QgsContrastEnhancement *redContrastEnhancement = symbol->redContrastEnhancement();
857 QgsContrastEnhancement *greenContrastEnhancement = symbol->greenContrastEnhancement();
858 QgsContrastEnhancement *blueContrastEnhancement = symbol->blueContrastEnhancement();
859
860 const bool useRedContrastEnhancement = redContrastEnhancement && redContrastEnhancement->contrastEnhancementAlgorithm() != QgsContrastEnhancement::NoEnhancement;
861 const bool useBlueContrastEnhancement = blueContrastEnhancement && blueContrastEnhancement->contrastEnhancementAlgorithm() != QgsContrastEnhancement::NoEnhancement;
862 const bool useGreenContrastEnhancement = greenContrastEnhancement && greenContrastEnhancement->contrastEnhancementAlgorithm() != QgsContrastEnhancement::NoEnhancement;
863
864 if ( !output )
865 output = &outNormal;
866
867 output->positionsOrigin = originFromNodeBounds( pc, n, context, block.get() );
868
869 int ir = 0;
870 int ig = 0;
871 int ib = 0;
872 for ( int i = 0; i < count; ++i )
873 {
874 if ( context.isCanceled() )
875 break;
876
877 const qint32 ix = *( qint32 * )( ptr + i * recordSize + 0 );
878 const qint32 iy = *( qint32 * )( ptr + i * recordSize + 4 );
879 const qint32 iz = *( qint32 * )( ptr + i * recordSize + 8 );
880 double x = blockOffset.x() + blockScale.x() * ix;
881 double y = blockOffset.y() + blockScale.y() * iy;
882 double z = ( blockOffset.z() + blockScale.z() * iz ) * zValueScale + zValueOffset;
883 try
884 {
885 coordinateTransform.transformInPlace( x, y, z );
886 }
887 catch ( QgsCsException & )
888 {
889 if ( !alreadyPrintedDebug )
890 {
891 QgsDebugError( QStringLiteral( "Error transforming point coordinate" ) );
892 alreadyPrintedDebug = true;
893 }
894 }
895 const QgsVector3D point = QgsVector3D( x, y, z ) - output->positionsOrigin;
896
897 QVector3D color( 0.0f, 0.0f, 0.0f );
898
899 context.getAttribute( ptr, i * recordSize + redOffset, redType, ir );
900 context.getAttribute( ptr, i * recordSize + greenOffset, greenType, ig );
901 context.getAttribute( ptr, i * recordSize + blueOffset, blueType, ib );
902
903 //skip if red, green or blue not in displayable range
904 if ( ( useRedContrastEnhancement && !redContrastEnhancement->isValueInDisplayableRange( ir ) )
905 || ( useGreenContrastEnhancement && !greenContrastEnhancement->isValueInDisplayableRange( ig ) )
906 || ( useBlueContrastEnhancement && !blueContrastEnhancement->isValueInDisplayableRange( ib ) ) )
907 {
908 continue;
909 }
910
911 //stretch color values
912 if ( useRedContrastEnhancement )
913 {
914 ir = redContrastEnhancement->enhanceContrast( ir );
915 }
916 if ( useGreenContrastEnhancement )
917 {
918 ig = greenContrastEnhancement->enhanceContrast( ig );
919 }
920 if ( useBlueContrastEnhancement )
921 {
922 ib = blueContrastEnhancement->enhanceContrast( ib );
923 }
924
925 color.setX( ir / 255.0f );
926 color.setY( ig / 255.0f );
927 color.setZ( ib / 255.0f );
928
929 output->positions.push_back( point.toVector3D() );
930 output->colors.push_back( color );
931 }
932}
933
934void QgsRGBPointCloud3DSymbolHandler::finalize( Qt3DCore::QEntity *parent, const QgsPointCloud3DRenderContext &context )
935{
936 makeEntity( parent, context, outNormal, false );
937}
938
939Qt3DQGeometry *QgsRGBPointCloud3DSymbolHandler::makeGeometry( Qt3DCore::QNode *parent, const QgsPointCloud3DSymbolHandler::PointData &data, unsigned int byteStride )
940{
941 return new QgsRGBPointCloud3DGeometry( parent, data, byteStride );
942}
943
944QgsClassificationPointCloud3DSymbolHandler::QgsClassificationPointCloud3DSymbolHandler()
945 : QgsPointCloud3DSymbolHandler()
946{
947
948}
949
950bool QgsClassificationPointCloud3DSymbolHandler::prepare( const QgsPointCloud3DRenderContext &context )
951{
952 Q_UNUSED( context )
953 return true;
954}
955
956void QgsClassificationPointCloud3DSymbolHandler::processNode( QgsPointCloudIndex *pc, const IndexedPointCloudNode &n, const QgsPointCloud3DRenderContext &context, PointData *output )
957{
959 const int xOffset = 0;
960 attributes.push_back( QgsPointCloudAttribute( QStringLiteral( "X" ), QgsPointCloudAttribute::Int32 ) );
961 const int yOffset = attributes.pointRecordSize();
962 attributes.push_back( QgsPointCloudAttribute( QStringLiteral( "Y" ), QgsPointCloudAttribute::Int32 ) );
963 const int zOffset = attributes.pointRecordSize();
964 attributes.push_back( QgsPointCloudAttribute( QStringLiteral( "Z" ), QgsPointCloudAttribute::Int32 ) );
965
966 QString attributeName;
967 bool attrIsX = false;
968 bool attrIsY = false;
969 bool attrIsZ = false;
971 int attributeOffset = 0;
973 if ( symbol )
974 {
975 int offset = 0;
976 const QgsPointCloudAttributeCollection collection = context.attributes();
977
978 if ( symbol->attribute() == QLatin1String( "X" ) )
979 {
980 attrIsX = true;
981 }
982 else if ( symbol->attribute() == QLatin1String( "Y" ) )
983 {
984 attrIsY = true;
985 }
986 else if ( symbol->attribute() == QLatin1String( "Z" ) )
987 {
988 attrIsZ = true;
989 }
990 else
991 {
992 const QgsPointCloudAttribute *attr = collection.find( symbol->attribute(), offset );
993 if ( attr )
994 {
995 attributeType = attr->type();
996 attributeName = attr->name();
997 attributeOffset = attributes.pointRecordSize();
998 attributes.push_back( *attr );
999 }
1000 }
1001 }
1002
1003 if ( attributeName.isEmpty() && !attrIsX && !attrIsY && !attrIsZ )
1004 return;
1005
1006 QgsPointCloudRequest request;
1007 request.setAttributes( attributes );
1008 request.setFilterRect( context.layerExtent() );
1009 std::unique_ptr<QgsPointCloudBlock> block( pointCloudBlock( pc, n, request, context ) );
1010 if ( !block )
1011 return;
1012
1013 const char *ptr = block->data();
1014 const int count = block->pointCount();
1015 const std::size_t recordSize = block->attributes().pointRecordSize();
1016
1017 const QgsVector3D blockScale = block->scale();
1018 const QgsVector3D blockOffset = block->offset();
1019 const double zValueScale = context.zValueScale();
1020 const double zValueOffset = context.zValueFixedOffset();
1021 const QgsCoordinateTransform coordinateTransform = context.coordinateTransform();
1022 bool alreadyPrintedDebug = false;
1023
1024 QList<QgsPointCloudCategory> categoriesList = symbol->categoriesList();
1025 QVector<int> categoriesValues;
1026 QHash<int, double> categoriesPointSizes;
1027 for ( QgsPointCloudCategory &c : categoriesList )
1028 {
1029 categoriesValues.push_back( c.value() );
1030 categoriesPointSizes.insert( c.value(), c.pointSize() > 0 ? c.pointSize() :
1031 context.symbol() ? context.symbol()->pointSize() : 1.0 );
1032 }
1033
1034 if ( !output )
1035 output = &outNormal;
1036
1037 output->positionsOrigin = originFromNodeBounds( pc, n, context, block.get() );
1038
1039 const QSet<int> filteredOutValues = context.getFilteredOutValues();
1040 for ( int i = 0; i < count; ++i )
1041 {
1042 if ( context.isCanceled() )
1043 break;
1044
1045 const qint32 ix = *( qint32 * )( ptr + i * recordSize + xOffset );
1046 const qint32 iy = *( qint32 * )( ptr + i * recordSize + yOffset );
1047 const qint32 iz = *( qint32 * )( ptr + i * recordSize + zOffset );
1048
1049 double x = blockOffset.x() + blockScale.x() * ix;
1050 double y = blockOffset.y() + blockScale.y() * iy;
1051 double z = ( blockOffset.z() + blockScale.z() * iz ) * zValueScale + zValueOffset;
1052 try
1053 {
1054 coordinateTransform.transformInPlace( x, y, z );
1055 }
1056 catch ( QgsCsException & )
1057 {
1058 if ( !alreadyPrintedDebug )
1059 {
1060 QgsDebugError( QStringLiteral( "Error transforming point coordinate" ) );
1061 alreadyPrintedDebug = true;
1062 }
1063 }
1064 const QgsVector3D point = QgsVector3D( x, y, z ) - output->positionsOrigin;
1065 float iParam = 0.0f;
1066 if ( attrIsX )
1067 iParam = x;
1068 else if ( attrIsY )
1069 iParam = y;
1070 else if ( attrIsZ )
1071 iParam = z;
1072 else
1073 context.getAttribute( ptr, i * recordSize + attributeOffset, attributeType, iParam );
1074
1075 if ( filteredOutValues.contains( ( int ) iParam ) ||
1076 ! categoriesValues.contains( ( int ) iParam ) )
1077 continue;
1078 output->positions.push_back( point.toVector3D() );
1079
1080 // find iParam actual index in the categories list
1081 float iParam2 = categoriesValues.indexOf( ( int )iParam ) + 1;
1082 output->parameter.push_back( iParam2 );
1083 output->pointSizes.push_back( categoriesPointSizes.value( ( int ) iParam ) );
1084 }
1085}
1086
1087void QgsClassificationPointCloud3DSymbolHandler::finalize( Qt3DCore::QEntity *parent, const QgsPointCloud3DRenderContext &context )
1088{
1089 makeEntity( parent, context, outNormal, false );
1090}
1091
1092Qt3DQGeometry *QgsClassificationPointCloud3DSymbolHandler::makeGeometry( Qt3DCore::QNode *parent, const QgsPointCloud3DSymbolHandler::PointData &data, unsigned int byteStride )
1093{
1094 return new QgsClassificationPointCloud3DGeometry( parent, data, byteStride );
1095}
1096
Represents a indexed point cloud node in octree.
int d() const
Returns d.
IndexedPointCloudNode parentNode() const
Returns the parent of the node.
QgsVector3D origin() const
Returns coordinates in map CRS at which 3D scene has origin (0,0,0)
A 3-dimensional box composed of x, y, z coordinates.
Definition qgsbox3d.h:43
bool contains(const QgsBox3D &other) const
Returns true when box contains other box.
Definition qgsbox3d.cpp:161
double width() const
Returns the width of the box.
Definition qgsbox3d.h:293
double height() const
Returns the height of the box.
Definition qgsbox3d.h:300
QgsPointCloudCategoryList categoriesList() const
Returns the list of categories of the classification.
QString attribute() const
Returns the attribute used to select the color of the point cloud.
QString attribute() const
Returns the attribute used to select the color of the point cloud.
Manipulates raster or point cloud pixel values so that they enhanceContrast or clip into a specified ...
@ NoEnhancement
Default color scaling algorithm, no scaling is applied.
bool isValueInDisplayableRange(double value)
Returns true if a pixel value is in displayable range, false if pixel is outside of range (i....
int enhanceContrast(double value)
Applies the contrast enhancement to a value.
ContrastEnhancementAlgorithm contrastEnhancementAlgorithm() const
Class for doing transforms between two map coordinate systems.
void transformInPlace(double &x, double &y, double &z, Qgis::TransformDirection direction=Qgis::TransformDirection::Forward) const
Transforms an array of x, y and z double coordinates in place, from the source CRS to the destination...
Custom exception class for Coordinate Reference System related exceptions.
void canceled()
Internal routines can connect to this signal if they use event loop.
Encapsulates the render context for a 3D point cloud rendering operation.
void getAttribute(const char *data, std::size_t offset, QgsPointCloudAttribute::DataType type, T &value) const
Retrieves the attribute value from data at the specified offset, where type indicates the original da...
QSet< int > getFilteredOutValues() const
Returns a set containing the filtered out values.
QgsPointCloud3DSymbol * symbol() const
Returns the symbol used for rendering the point cloud.
double zValueScale() const
Returns any constant scaling factor which must be applied to z values taken from the point cloud inde...
QgsFeedback * feedback() const
Returns the feedback object used to cancel rendering and check if rendering was canceled.
QgsPointCloudAttributeCollection attributes() const
Returns the attributes associated with the rendered block.
bool isCanceled() const
Returns true if the rendering is canceled.
QgsCoordinateTransform coordinateTransform() const
Returns the coordinate transform used to transform points from layer CRS to the map CRS.
QgsRectangle layerExtent() const
Returns the 3D scene's extent in layer crs.
double zValueFixedOffset() const
Returns any constant offset which must be applied to z values taken from the point cloud index.
bool verticalTriangleFilter() const
Returns whether triangles are filtered by vertical height for rendering.
float verticalFilterThreshold() const
Returns the threshold vertical height value for filtering triangles.
virtual 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.
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.
Base class for storing raw data from point cloud nodes.
QgsVector3D scale() const
Returns the custom scale of the block.
QgsVector3D offset() const
Returns the custom offset of the block.
Represents an individual category (class) from a QgsPointCloudClassifiedRenderer.
Represents packaged data bounds.
qint64 xMin() const
Returns x min.
qint64 zMin() const
Returns z min.
qint64 yMin() const
Returns y min.
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...
QgsPointCloudDataBounds nodeBounds(const IndexedPointCloudNode &node) const
Returns bounds of particular node.
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.
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.
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
QVector3D toVector3D() const
Converts the current object to QVector3D.
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