31 #include <Qt3DRender/QGeometryRenderer> 
   32 #include <Qt3DRender/QAttribute> 
   33 #include <Qt3DRender/QTechnique> 
   34 #include <Qt3DRender/QShaderProgram> 
   35 #include <Qt3DRender/QGraphicsApiFilter> 
   36 #include <Qt3DRender/QEffect> 
   40 #include <delaunator.hpp> 
   42 QgsPointCloud3DGeometry::QgsPointCloud3DGeometry( Qt3DCore::QNode *parent, 
const QgsPointCloud3DSymbolHandler::PointData &data, 
unsigned int byteStride )
 
   44   , mPositionAttribute( new 
Qt3DRender::QAttribute( this ) )
 
   45   , mParameterAttribute( new 
Qt3DRender::QAttribute( this ) )
 
   46   , mColorAttribute( new 
Qt3DRender::QAttribute( this ) )
 
   47   , mTriangleIndexAttribute( new 
Qt3DRender::QAttribute( this ) )
 
   48   , mNormalsAttribute( new 
Qt3DRender::QAttribute( this ) )
 
   49   , mVertexBuffer( new  
Qt3DRender::QBuffer( this ) )
 
   50   , mByteStride( byteStride )
 
   52   if ( !data.triangles.isEmpty() )
 
   54     mTriangleBuffer = 
new  Qt3DRender::QBuffer( 
this );
 
   55     mTriangleIndexAttribute->setAttributeType( Qt3DRender::QAttribute::IndexAttribute );
 
   56     mTriangleIndexAttribute->setBuffer( mTriangleBuffer );
 
   57     mTriangleIndexAttribute->setVertexBaseType( Qt3DRender::QAttribute::UnsignedInt );
 
   58     mTriangleBuffer->setData( data.triangles );
 
   59     mTriangleIndexAttribute->setCount( data.triangles.size() / 
sizeof( quint32 ) );
 
   60     addAttribute( mTriangleIndexAttribute );
 
   63   if ( !data.normals.isEmpty() )
 
   65     mNormalsBuffer = 
new Qt3DRender::QBuffer( 
this );
 
   66     mNormalsAttribute->setName( Qt3DRender::QAttribute::defaultNormalAttributeName() );
 
   67     mNormalsAttribute->setVertexBaseType( Qt3DRender::QAttribute::Float );
 
   68     mNormalsAttribute->setVertexSize( 3 );
 
   69     mNormalsAttribute->setAttributeType( Qt3DRender::QAttribute::VertexAttribute );
 
   70     mNormalsAttribute->setBuffer( mNormalsBuffer );
 
   71     mNormalsBuffer->setData( data.normals );
 
   72     mNormalsAttribute->setCount( data.normals.size() / ( 3 * 
sizeof( 
float ) ) );
 
   73     addAttribute( mNormalsAttribute );
 
   77 QgsSingleColorPointCloud3DGeometry::QgsSingleColorPointCloud3DGeometry( Qt3DCore::QNode *parent, 
const QgsPointCloud3DSymbolHandler::PointData &data, 
unsigned int byteStride )
 
   78   : QgsPointCloud3DGeometry( parent, data, byteStride )
 
   80   mPositionAttribute->setAttributeType( Qt3DRender::QAttribute::VertexAttribute );
 
   81   mPositionAttribute->setBuffer( mVertexBuffer );
 
   82   mPositionAttribute->setVertexBaseType( Qt3DRender::QAttribute::Float );
 
   83   mPositionAttribute->setVertexSize( 3 );
 
   84   mPositionAttribute->setName( Qt3DRender::QAttribute::defaultPositionAttributeName() );
 
   85   mPositionAttribute->setByteOffset( 0 );
 
   86   mPositionAttribute->setByteStride( mByteStride );
 
   87   addAttribute( mPositionAttribute );
 
   88   makeVertexBuffer( data );
 
   91 void QgsSingleColorPointCloud3DGeometry::makeVertexBuffer( 
const QgsPointCloud3DSymbolHandler::PointData &data )
 
   93   QByteArray vertexBufferData;
 
   94   vertexBufferData.resize( data.positions.size() * mByteStride );
 
   95   float *rawVertexArray = 
reinterpret_cast<float *
>( vertexBufferData.data() );
 
   97   for ( 
int i = 0; i < data.positions.size(); ++i )
 
   99     rawVertexArray[idx++] = data.positions.at( i ).x();
 
  100     rawVertexArray[idx++] = data.positions.at( i ).y();
 
  101     rawVertexArray[idx++] = data.positions.at( i ).z();
 
  104   mVertexCount = data.positions.size();
 
  105   mVertexBuffer->setData( vertexBufferData );
 
  108 QgsColorRampPointCloud3DGeometry::QgsColorRampPointCloud3DGeometry( Qt3DCore::QNode *parent, 
const QgsPointCloud3DSymbolHandler::PointData &data, 
unsigned int byteStride )
 
  109   : QgsPointCloud3DGeometry( parent, data, byteStride )
 
  111   mPositionAttribute->setAttributeType( Qt3DRender::QAttribute::VertexAttribute );
 
  112   mPositionAttribute->setBuffer( mVertexBuffer );
 
  113   mPositionAttribute->setVertexBaseType( Qt3DRender::QAttribute::Float );
 
  114   mPositionAttribute->setVertexSize( 3 );
 
  115   mPositionAttribute->setName( Qt3DRender::QAttribute::defaultPositionAttributeName() );
 
  116   mPositionAttribute->setByteOffset( 0 );
 
  117   mPositionAttribute->setByteStride( mByteStride );
 
  118   addAttribute( mPositionAttribute );
 
  119   mParameterAttribute->setAttributeType( Qt3DRender::QAttribute::VertexAttribute );
 
  120   mParameterAttribute->setBuffer( mVertexBuffer );
 
  121   mParameterAttribute->setVertexBaseType( Qt3DRender::QAttribute::Float );
 
  122   mParameterAttribute->setVertexSize( 1 );
 
  123   mParameterAttribute->setName( 
"vertexParameter" );
 
  124   mParameterAttribute->setByteOffset( 12 );
 
  125   mParameterAttribute->setByteStride( mByteStride );
 
  126   addAttribute( mParameterAttribute );
 
  127   makeVertexBuffer( data );
 
  130 void QgsColorRampPointCloud3DGeometry::makeVertexBuffer( 
const QgsPointCloud3DSymbolHandler::PointData &data )
 
  132   QByteArray vertexBufferData;
 
  133   vertexBufferData.resize( data.positions.size() * mByteStride );
 
  134   float *rawVertexArray = 
reinterpret_cast<float *
>( vertexBufferData.data() );
 
  136   Q_ASSERT( data.positions.size() == data.parameter.size() );
 
  137   for ( 
int i = 0; i < data.positions.size(); ++i )
 
  139     rawVertexArray[idx++] = data.positions.at( i ).x();
 
  140     rawVertexArray[idx++] = data.positions.at( i ).y();
 
  141     rawVertexArray[idx++] = data.positions.at( i ).z();
 
  142     rawVertexArray[idx++] = data.parameter.at( i );
 
  145   mVertexCount = data.positions.size();
 
  146   mVertexBuffer->setData( vertexBufferData );
 
  149 QgsRGBPointCloud3DGeometry::QgsRGBPointCloud3DGeometry( Qt3DCore::QNode *parent, 
const QgsPointCloud3DSymbolHandler::PointData &data, 
unsigned int byteStride )
 
  150   : QgsPointCloud3DGeometry( parent, data, byteStride )
 
  152   mPositionAttribute->setAttributeType( Qt3DRender::QAttribute::VertexAttribute );
 
  153   mPositionAttribute->setBuffer( mVertexBuffer );
 
  154   mPositionAttribute->setVertexBaseType( Qt3DRender::QAttribute::Float );
 
  155   mPositionAttribute->setVertexSize( 3 );
 
  156   mPositionAttribute->setName( Qt3DRender::QAttribute::defaultPositionAttributeName() );
 
  157   mPositionAttribute->setByteOffset( 0 );
 
  158   mPositionAttribute->setByteStride( mByteStride );
 
  159   addAttribute( mPositionAttribute );
 
  160   mColorAttribute->setAttributeType( Qt3DRender::QAttribute::VertexAttribute );
 
  161   mColorAttribute->setBuffer( mVertexBuffer );
 
  162   mColorAttribute->setVertexBaseType( Qt3DRender::QAttribute::Float );
 
  163   mColorAttribute->setVertexSize( 3 );
 
  164   mColorAttribute->setName( QStringLiteral( 
"vertexColor" ) );
 
  165   mColorAttribute->setByteOffset( 12 );
 
  166   mColorAttribute->setByteStride( mByteStride );
 
  167   addAttribute( mColorAttribute );
 
  168   makeVertexBuffer( data );
 
  171 void QgsRGBPointCloud3DGeometry::makeVertexBuffer( 
const QgsPointCloud3DSymbolHandler::PointData &data )
 
  173   QByteArray vertexBufferData;
 
  174   vertexBufferData.resize( data.positions.size() * mByteStride );
 
  175   float *rawVertexArray = 
reinterpret_cast<float *
>( vertexBufferData.data() );
 
  177   Q_ASSERT( data.positions.size() == data.colors.size() );
 
  178   for ( 
int i = 0; i < data.positions.size(); ++i )
 
  180     rawVertexArray[idx++] = data.positions.at( i ).x();
 
  181     rawVertexArray[idx++] = data.positions.at( i ).y();
 
  182     rawVertexArray[idx++] = data.positions.at( i ).z();
 
  183     rawVertexArray[idx++] = data.colors.at( i ).x();
 
  184     rawVertexArray[idx++] = data.colors.at( i ).y();
 
  185     rawVertexArray[idx++] = data.colors.at( i ).z();
 
  187   mVertexCount = data.positions.size();
 
  188   mVertexBuffer->setData( vertexBufferData );
 
  191 QgsPointCloud3DSymbolHandler::QgsPointCloud3DSymbolHandler()
 
  196 void QgsPointCloud3DSymbolHandler::makeEntity( Qt3DCore::QEntity *parent, 
const QgsPointCloud3DRenderContext &context, 
const QgsPointCloud3DSymbolHandler::PointData &out, 
bool selected )
 
  200   if ( out.positions.empty() )
 
  204   Qt3DRender::QGeometry *geom = makeGeometry( parent, out, context.
symbol()->
byteStride() );
 
  205   Qt3DRender::QGeometryRenderer *gr = 
new Qt3DRender::QGeometryRenderer;
 
  208     gr->setPrimitiveType( Qt3DRender::QGeometryRenderer::Triangles );
 
  209     gr->setVertexCount( out.triangles.size() /  
sizeof( quint32 ) );
 
  213     gr->setPrimitiveType( Qt3DRender::QGeometryRenderer::Points );
 
  214     gr->setVertexCount( out.positions.count() );
 
  216   gr->setGeometry( geom );
 
  219   Qt3DCore::QTransform *tr = 
new Qt3DCore::QTransform;
 
  222   Qt3DRender::QMaterial *mat = 
new Qt3DRender::QMaterial;
 
  226   Qt3DRender::QShaderProgram *shaderProgram = 
new Qt3DRender::QShaderProgram( mat );
 
  227   shaderProgram->setVertexShaderCode( Qt3DRender::QShaderProgram::loadSource( QUrl( QStringLiteral( 
"qrc:/shaders/pointcloud.vert" ) ) ) );
 
  228   shaderProgram->setFragmentShaderCode( Qt3DRender::QShaderProgram::loadSource( QUrl( QStringLiteral( 
"qrc:/shaders/pointcloud.frag" ) ) ) );
 
  230   Qt3DRender::QRenderPass *renderPass = 
new Qt3DRender::QRenderPass( mat );
 
  231   renderPass->setShaderProgram( shaderProgram );
 
  233   if ( out.triangles.isEmpty() )
 
  235     Qt3DRender::QPointSize *pointSize = 
new Qt3DRender::QPointSize( renderPass );
 
  236     pointSize->setSizeMode( Qt3DRender::QPointSize::Programmable );  
 
  238     renderPass->addRenderState( pointSize );
 
  242   Qt3DRender::QFilterKey *filterKey = 
new Qt3DRender::QFilterKey;
 
  243   filterKey->setName( QStringLiteral( 
"renderingStyle" ) );
 
  244   filterKey->setValue( 
"forward" );
 
  246   Qt3DRender::QTechnique *technique = 
new Qt3DRender::QTechnique;
 
  247   technique->addRenderPass( renderPass );
 
  248   technique->addFilterKey( filterKey );
 
  249   technique->graphicsApiFilter()->setApi( Qt3DRender::QGraphicsApiFilter::OpenGL );
 
  250   technique->graphicsApiFilter()->setProfile( Qt3DRender::QGraphicsApiFilter::CoreProfile );
 
  251   technique->graphicsApiFilter()->setMajorVersion( 3 );
 
  252   technique->graphicsApiFilter()->setMinorVersion( 1 );
 
  253   technique->addParameter( 
new Qt3DRender::QParameter( 
"triangulate", !out.triangles.isEmpty() ) );
 
  255   Qt3DRender::QEffect *eff = 
new Qt3DRender::QEffect;
 
  256   eff->addTechnique( technique );
 
  257   mat->setEffect( eff );
 
  260   Qt3DCore::QEntity *entity = 
new Qt3DCore::QEntity;
 
  261   entity->addComponent( gr );
 
  262   entity->addComponent( tr );
 
  263   entity->addComponent( mat );
 
  264   entity->setParent( parent );
 
  273   bool hasColorData = !outNormal.colors.empty();
 
  274   bool hasParameterData = !outNormal.parameter.empty();
 
  277   std::vector<double> vertices( outNormal.positions.size() * 2 );
 
  279   for ( 
int i = 0; i < outNormal.positions.size(); ++i )
 
  281     vertices[idx++] = outNormal.positions.at( i ).x();
 
  282     vertices[idx++] = outNormal.positions.at( i ).z();
 
  288   int properPointsCount = outNormal.positions.count();
 
  289   while ( parentNode.
d() >= 0 )
 
  291     processNode( pc, parentNode, context );
 
  295   PointData filteredExtraPointData;
 
  297   double span = pc->
span();
 
  300   double extraBoxFactor = 16 / span;
 
  301   double extraX = extraBoxFactor * bbox.
xExtent();
 
  302   double extraZ = extraBoxFactor * bbox.
zExtent();
 
  305   const QgsAABB extendedBBox( bbox.
xMin - extraX, -std::numeric_limits<float>::max(), bbox.
zMin - extraZ, bbox.
xMax + extraX, std::numeric_limits<float>::max(), bbox.
zMax + extraZ );
 
  307   for ( 
int i = properPointsCount; i < outNormal.positions.count(); ++i )
 
  309     const  QVector3D pos = outNormal.positions.at( i );
 
  310     if ( extendedBBox.intersects( pos.x(), pos.y(), pos.z() ) )
 
  312       filteredExtraPointData.positions.append( pos );
 
  313       vertices.push_back( pos.x() );
 
  314       vertices.push_back( pos.z() );
 
  317         filteredExtraPointData.colors.append( outNormal.colors.at( i ) );
 
  318       if ( hasParameterData )
 
  319         filteredExtraPointData.parameter.append( outNormal.parameter.at( i ) );
 
  323   outNormal.positions.resize( properPointsCount );
 
  325     outNormal.colors.resize( properPointsCount );
 
  326   if ( hasParameterData )
 
  327     outNormal.parameter.resize( properPointsCount );
 
  329   outNormal.positions.append( filteredExtraPointData.positions );
 
  330   outNormal.colors.append( filteredExtraPointData.colors );
 
  331   outNormal.parameter.append( filteredExtraPointData.parameter );
 
  336 void QgsPointCloud3DSymbolHandler::calculateNormals( 
const std::vector<size_t> &triangles )
 
  338   QVector<QVector3D> normals( outNormal.positions.count(), QVector3D( 0.0, 0.0, 0.0 ) );
 
  339   for ( 
size_t i = 0; i < triangles.size(); i += 3 )
 
  341     QVector<QVector3D> triangleVertices( 3 );
 
  342     for ( 
size_t j = 0; j < 3; ++j )
 
  344       size_t vertIndex = triangles.at( i + j );
 
  345       triangleVertices[j] = outNormal.positions.at( vertIndex );
 
  348     for ( 
size_t j = 0; j < 3; ++j )
 
  349       normals[triangles.at( i + j )] += QVector3D::crossProduct(
 
  350                                           triangleVertices.at( 1 ) - triangleVertices.at( 0 ),
 
  351                                           triangleVertices.at( 2 ) - triangleVertices.at( 0 ) );
 
  355   outNormal.normals.resize( ( outNormal.positions.count() ) * 
sizeof( 
float ) * 3 );
 
  356   float *normPtr = 
reinterpret_cast<float *
>( outNormal.normals.data() );
 
  357   for ( 
int i = 0; i < normals.size(); ++i )
 
  359     QVector3D normal = normals.at( i );
 
  360     normal = normal.normalized();
 
  362     *normPtr++ = normal.x();
 
  363     *normPtr++ = normal.y();
 
  364     *normPtr++ = normal.z();
 
  370   outNormal.triangles.resize( triangleIndexes.size() * 
sizeof( quint32 ) );
 
  371   quint32 *indexPtr = 
reinterpret_cast<quint32 *
>( outNormal.triangles.data() );
 
  372   size_t effective = 0;
 
  379   for ( 
size_t i = 0; i < triangleIndexes.size(); i += 3 )
 
  381     bool atLeastOneInBox = 
false;
 
  382     bool horizontalSkip = 
false;
 
  383     bool verticalSkip = 
false;
 
  384     for ( 
size_t j = 0; j < 3; j++ )
 
  386       QVector3D pos = outNormal.positions.at( triangleIndexes.at( i  + j ) );
 
  387       atLeastOneInBox |= bbox.
intersects( pos.x(), pos.y(), pos.z() );
 
  389       if ( verticalFilter || horizontalFilter )
 
  391         const QVector3D pos2 = outNormal.positions.at( triangleIndexes.at( i + ( j + 1 ) % 3 ) );
 
  393         if ( verticalFilter )
 
  394           verticalSkip |= std::fabs( pos.y() - pos2.y() ) > verticalThreshold;
 
  396         if ( horizontalFilter && ! verticalSkip )
 
  399           horizontalSkip |= sqrt( std::pow( pos.x() - pos2.x(), 2 ) +
 
  400                                   std::pow( pos.z() - pos2.z(), 2 ) ) > horizontalThreshold;
 
  403         if ( horizontalSkip || verticalSkip )
 
  407     if ( atLeastOneInBox && !horizontalSkip && !verticalSkip )
 
  409       for ( 
size_t j = 0; j < 3; j++ )
 
  411         size_t vertIndex = triangleIndexes.at( i + j );
 
  412         *indexPtr++ = quint32( vertIndex );
 
  418   if ( effective != 0 )
 
  420     outNormal.triangles.resize( effective * 3 * 
sizeof( quint32 ) );
 
  424     outNormal.triangles.clear();
 
  425     outNormal.normals.clear();
 
  431   if ( outNormal.positions.isEmpty() )
 
  435   std::unique_ptr<delaunator::Delaunator> triangulation;
 
  438     std::vector<double> vertices = getVertices( pc, n, context, bbox );
 
  439     triangulation.reset( 
new delaunator::Delaunator( vertices ) );
 
  441   catch ( std::exception &e )
 
  445     outNormal = PointData();
 
  446     processNode( pc, n, context );
 
  450   const std::vector<size_t> &triangleIndexes = triangulation->triangles;
 
  452   calculateNormals( triangleIndexes );
 
  453   filterTriangles( triangleIndexes, context, bbox );
 
  459   if ( pc->
accessType() == QgsPointCloudIndex::AccessType::Local )
 
  463   else if ( pc->
accessType() == QgsPointCloudIndex::AccessType::Remote )
 
  465     bool loopAborted = 
false;
 
  477       block = req->
block();
 
  484 QgsSingleColorPointCloud3DSymbolHandler::QgsSingleColorPointCloud3DSymbolHandler()
 
  485   : QgsPointCloud3DSymbolHandler()
 
  505   std::unique_ptr<QgsPointCloudBlock> block( pointCloudBlock( pc, n, request, context ) );
 
  509   const char *ptr = block->
data();
 
  517   bool alreadyPrintedDebug = 
false;
 
  519   for ( 
int i = 0; i < count; ++i )
 
  524     const qint32 ix = *( qint32 * )( ptr + i * recordSize + 0 );
 
  525     const qint32 iy = *( qint32 * )( ptr + i * recordSize + 4 );
 
  526     const qint32 iz = *( qint32 * )( ptr + i * recordSize + 8 );
 
  528     double x = blockOffset.
x() + blockScale.
x() * ix;
 
  529     double y = blockOffset.
y() + blockScale.
y() * iy;
 
  530     double z = ( blockOffset.
z() + blockScale.
z() * iz ) * zValueScale + zValueOffset;
 
  537       if ( !alreadyPrintedDebug )
 
  539         QgsDebugMsg( QStringLiteral( 
"Error transforming point coordinate" ) );
 
  540         alreadyPrintedDebug = 
true;
 
  545     outNormal.positions.push_back( QVector3D( p.
x(), p.
y(), p.
z() ) );
 
  551   makeEntity( parent, context, outNormal, 
false );
 
  554 Qt3DRender::QGeometry *QgsSingleColorPointCloud3DSymbolHandler::makeGeometry( Qt3DCore::QNode *parent, 
const QgsPointCloud3DSymbolHandler::PointData &data, 
unsigned int byteStride )
 
  556   return new QgsSingleColorPointCloud3DGeometry( parent, data, byteStride );
 
  559 QgsColorRampPointCloud3DSymbolHandler::QgsColorRampPointCloud3DSymbolHandler()
 
  560   : QgsPointCloud3DSymbolHandler()
 
  574   const int xOffset = 0;
 
  581   QString attributeName;
 
  582   bool attrIsX = 
false;
 
  583   bool attrIsY = 
false;
 
  584   bool attrIsZ = 
false;
 
  586   int attributeOffset = 0;
 
  590   bool alreadyPrintedDebug = 
false;
 
  598     if ( symbol->
attribute() == QLatin1String( 
"X" ) )
 
  602     else if ( symbol->
attribute() == QLatin1String( 
"Y" ) )
 
  606     else if ( symbol->
attribute() == QLatin1String( 
"Z" ) )
 
  615         attributeType = attr->
type();
 
  616         attributeName = attr->
name();
 
  623   if ( attributeName.isEmpty() && !attrIsX && !attrIsY && !attrIsZ )
 
  628   std::unique_ptr<QgsPointCloudBlock> block( pointCloudBlock( pc, n, request, context ) );
 
  632   const char *ptr = block->
data();
 
  639   for ( 
int i = 0; i < count; ++i )
 
  644     const qint32 ix = *( qint32 * )( ptr + i * recordSize + xOffset );
 
  645     const qint32 iy = *( qint32 * )( ptr + i * recordSize + yOffset );
 
  646     const qint32 iz = *( qint32 * )( ptr + i * recordSize + zOffset );
 
  648     double x = blockOffset.
x() + blockScale.
x() * ix;
 
  649     double y = blockOffset.
y() + blockScale.
y() * iy;
 
  650     double z = ( blockOffset.
z() + blockScale.
z() * iz ) * zValueScale + zValueOffset;
 
  657       if ( !alreadyPrintedDebug )
 
  659         QgsDebugMsg( QStringLiteral( 
"Error transforming point coordinate" ) );
 
  660         alreadyPrintedDebug = 
true;
 
  664     point = context.map().mapToWorldCoordinates( point );
 
  665     outNormal.positions.push_back( QVector3D( point.x(), point.y(), point.z() ) );
 
  668       outNormal.parameter.push_back( x );
 
  670       outNormal.parameter.push_back( y );
 
  672       outNormal.parameter.push_back( z );
 
  676       context.
getAttribute( ptr, i * recordSize + attributeOffset, attributeType, iParam );
 
  677       outNormal.parameter.push_back( iParam );
 
  684   makeEntity( parent, context, outNormal, 
false );
 
  687 Qt3DRender::QGeometry *QgsColorRampPointCloud3DSymbolHandler::makeGeometry( Qt3DCore::QNode *parent, 
const QgsPointCloud3DSymbolHandler::PointData &data, 
unsigned int byteStride )
 
  689   return new QgsColorRampPointCloud3DGeometry( parent, data, byteStride );
 
  692 QgsRGBPointCloud3DSymbolHandler::QgsRGBPointCloud3DSymbolHandler()
 
  693   : QgsPointCloud3DSymbolHandler()
 
  733   std::unique_ptr<QgsPointCloudBlock> block( pointCloudBlock( pc, n, request, context ) );
 
  737   const char *ptr = block->
data();
 
  746   bool alreadyPrintedDebug = 
false;
 
  759   for ( 
int i = 0; i < count; ++i )
 
  764     const qint32 ix = *( qint32 * )( ptr + i * recordSize + 0 );
 
  765     const qint32 iy = *( qint32 * )( ptr + i * recordSize + 4 );
 
  766     const qint32 iz = *( qint32 * )( ptr + i * recordSize + 8 );
 
  767     double x = blockOffset.
x() + blockScale.
x() * ix;
 
  768     double y = blockOffset.
y() + blockScale.
y() * iy;
 
  769     double z = ( blockOffset.
z() + blockScale.
z() * iz ) * zValueScale + zValueOffset;
 
  776       if ( !alreadyPrintedDebug )
 
  778         QgsDebugMsg( QStringLiteral( 
"Error transforming point coordinate" ) );
 
  779         alreadyPrintedDebug = 
true;
 
  783     const QgsVector3D p = context.map().mapToWorldCoordinates( point );
 
  785     QVector3D color( 0.0f, 0.0f, 0.0f );
 
  787     context.
getAttribute( ptr, i * recordSize + redOffset, redType, ir );
 
  788     context.
getAttribute( ptr, i * recordSize + greenOffset, greenType, ig );
 
  789     context.
getAttribute( ptr, i * recordSize + blueOffset, blueType, ib );
 
  800     if ( useRedContrastEnhancement )
 
  804     if ( useGreenContrastEnhancement )
 
  808     if ( useBlueContrastEnhancement )
 
  813     color.setX( ir / 255.0f );
 
  814     color.setY( ig / 255.0f );
 
  815     color.setZ( ib / 255.0f );
 
  817     outNormal.positions.push_back( QVector3D( p.
x(), p.
y(), p.
z() ) );
 
  818     outNormal.colors.push_back( color );
 
  824   makeEntity( parent, context, outNormal, 
false );
 
  827 Qt3DRender::QGeometry *QgsRGBPointCloud3DSymbolHandler::makeGeometry( Qt3DCore::QNode *parent, 
const QgsPointCloud3DSymbolHandler::PointData &data, 
unsigned int byteStride )
 
  829   return new QgsRGBPointCloud3DGeometry( parent, data, byteStride );
 
  832 QgsClassificationPointCloud3DSymbolHandler::QgsClassificationPointCloud3DSymbolHandler()
 
  833   : QgsPointCloud3DSymbolHandler()
 
  847   const int xOffset = 0;
 
  854   QString attributeName;
 
  855   bool attrIsX = 
false;
 
  856   bool attrIsY = 
false;
 
  857   bool attrIsZ = 
false;
 
  859   int attributeOffset = 0;
 
  866     if ( symbol->
attribute() == QLatin1String( 
"X" ) )
 
  870     else if ( symbol->
attribute() == QLatin1String( 
"Y" ) )
 
  874     else if ( symbol->
attribute() == QLatin1String( 
"Z" ) )
 
  883         attributeType = attr->
type();
 
  884         attributeName = attr->
name();
 
  891   if ( attributeName.isEmpty() && !attrIsX && !attrIsY && !attrIsZ )
 
  896   std::unique_ptr<QgsPointCloudBlock> block( pointCloudBlock( pc, n, request, context ) );
 
  900   const char *ptr = block->
data();
 
  909   bool alreadyPrintedDebug = 
false;
 
  911   QList<QgsPointCloudCategory> categoriesList = symbol->
categoriesList();
 
  912   QVector<int> categoriesValues;
 
  915     categoriesValues.push_back( 
c.value() );
 
  919   for ( 
int i = 0; i < count; ++i )
 
  924     const qint32 ix = *( qint32 * )( ptr + i * recordSize + xOffset );
 
  925     const qint32 iy = *( qint32 * )( ptr + i * recordSize + yOffset );
 
  926     const qint32 iz = *( qint32 * )( ptr + i * recordSize + zOffset );
 
  928     double x = blockOffset.
x() + blockScale.
x() * ix;
 
  929     double y = blockOffset.
y() + blockScale.
y() * iy;
 
  930     double z = ( blockOffset.
z() + blockScale.
z() * iz ) * zValueScale + zValueOffset;
 
  937       if ( !alreadyPrintedDebug )
 
  939         QgsDebugMsg( QStringLiteral( 
"Error transforming point coordinate" ) );
 
  940         alreadyPrintedDebug = 
true;
 
  944     const QgsVector3D p = context.map().mapToWorldCoordinates( point );
 
  953       context.
getAttribute( ptr, i * recordSize + attributeOffset, attributeType, iParam );
 
  955     if ( filteredOutValues.contains( ( 
int ) iParam ) ||
 
  956          ! categoriesValues.contains( ( 
int ) iParam ) )
 
  958     outNormal.positions.push_back( QVector3D( p.
x(), p.
y(), p.
z() ) );
 
  961     float iParam2 = categoriesValues.indexOf( ( 
int )iParam ) + 1;
 
  962     outNormal.parameter.push_back( iParam2 );
 
  968   makeEntity( parent, context, outNormal, 
false );
 
  971 Qt3DRender::QGeometry *QgsClassificationPointCloud3DSymbolHandler::makeGeometry( Qt3DCore::QNode *parent, 
const QgsPointCloud3DSymbolHandler::PointData &data, 
unsigned int byteStride )
 
  973   return new QgsColorRampPointCloud3DGeometry( parent, data, byteStride );