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