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