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