20#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 
   21#include <Qt3DRender/QAttribute> 
   22#include <Qt3DRender/QBuffer> 
   23#include <Qt3DRender/QAbstractFunctor> 
   28#include <Qt3DCore/QAttribute> 
   29#include <Qt3DCore/QBuffer> 
   30#include <Qt3DCore/QAbstractFunctor> 
   44static QByteArray createPlaneVertexData( 
int res, 
float side, 
float vertScale, 
float skirtHeight, 
const QByteArray &heights )
 
   47  Q_ASSERT( heights.count() == res * res * 
static_cast<int>( 
sizeof( 
float ) ) );
 
   49  const float *zData = ( 
const float * ) heights.constData();
 
   50  const float *zBits = zData;
 
   52  const int nVerts = ( res + 2 ) * ( res + 2 );
 
   56  const quint32 elementSize = 3 + 2 + 3;
 
   57  const quint32 stride = elementSize * 
sizeof( float );
 
   58  QByteArray bufferBytes;
 
   59  bufferBytes.resize( stride * nVerts );
 
   60  float *fptr = 
reinterpret_cast<float *
>( bufferBytes.data() );
 
   63  QSize resolution( res, res );
 
   64  const float x0 = -w / 2.0f;
 
   65  const float z0 = -h / 2.0f;
 
   66  const float dx = w / ( resolution.width() - 1 );
 
   67  const float dz = h / ( resolution.height() - 1 );
 
   68  const float du = 1.0 / ( resolution.width() - 1 );
 
   69  const float dv = 1.0 / ( resolution.height() - 1 );
 
   73  const float noDataHeight = 0;
 
   75  const int iMax = resolution.width() - 1;
 
   76  const int jMax = resolution.height() - 1;
 
   79  for ( 
int j = -1; j <= resolution.height(); ++j )
 
   81    int jBound = std::clamp( j, 0, jMax );
 
   82    const float z = z0 + 
static_cast<float>( jBound ) * dz;
 
   83    const float v = 
static_cast<float>( jBound ) * dv;
 
   86    for ( 
int i = -1; i <= resolution.width(); ++i )
 
   88      int iBound = std::clamp( i, 0, iMax );
 
   89      const float x = x0 + 
static_cast<float>( iBound ) * dx;
 
   90      const float u = 
static_cast<float>( iBound ) * du;
 
   93      if ( i == iBound && j == jBound )
 
   96        height = zData[ jBound * resolution.width() + iBound ] - skirtHeight;
 
   98      if ( std::isnan( height ) )
 
   99        height = noDataHeight;
 
  103      *fptr++ = height / side * vertScale;
 
  111#define zAt( ii, jj )  zData[ jj * resolution.width() + ii ] * vertScale 
  112      float zi0 = zAt( std::clamp( i - 1, 0, iMax ), jBound );
 
  113      float zi1 = zAt( std::clamp( i + 1, 0, iMax ), jBound );
 
  114      float zj0 = zAt( iBound, std::clamp( j - 1, 0, jMax ) );
 
  115      float zj1 = zAt( iBound, std::clamp( j + 1, 0, jMax ) );
 
  118      if ( std::isnan( zi0 ) || std::isnan( zi1 ) || std::isnan( zj0 ) || std::isnan( zj1 ) )
 
  119        n = QVector3D( 0, 1, 0 );
 
  123        float zij = height * vertScale;
 
  126          di = 2 * ( zij - zi1 );
 
  127        else if ( i == iMax )
 
  128          di = 2 * ( zi0 - zij );
 
  133          dj = 2 * ( zij - zj1 );
 
  134        else if ( j == jMax )
 
  135          dj = 2 * ( zj0 - zij );
 
  139        n = QVector3D( di, 2 * side / res, dj );
 
  152inline int ijToHeightMapIndex( 
int i, 
int j, 
int resX, 
int resZ )
 
  154  i = std::clamp( i, 1, resX ) - 1;
 
  155  j = std::clamp( j, 1, resZ ) - 1;
 
  159static bool hasNoData( 
int i, 
int j, 
const float *heightMap, 
int resX, 
int resZ )
 
  161  return std::isnan( heightMap[ ijToHeightMapIndex( i, j, resX, resZ ) ] ) ||
 
  162         std::isnan( heightMap[ ijToHeightMapIndex( i + 1, j, resX, resZ ) ] ) ||
 
  163         std::isnan( heightMap[ ijToHeightMapIndex( i, j + 1, resX, resZ ) ] ) ||
 
  164         std::isnan( heightMap[ ijToHeightMapIndex( i + 1, j + 1, resX, resZ ) ] );
 
  167static QByteArray createPlaneIndexData( 
int res, 
const QByteArray &heightMap )
 
  169  QSize resolution( res, res );
 
  170  int numVerticesX = resolution.width() + 2;
 
  171  int numVerticesZ = resolution.height() + 2;
 
  174  const int faces = 2 * ( numVerticesX - 1 ) * ( numVerticesZ - 1 );
 
  175  const quint32 indices = 3 * faces;
 
  176  Q_ASSERT( indices < std::numeric_limits<quint32>::max() );
 
  177  QByteArray indexBytes;
 
  178  indexBytes.resize( indices * 
sizeof( quint32 ) );
 
  179  quint32 *indexPtr = 
reinterpret_cast<quint32 *
>( indexBytes.data() );
 
  181  const float *heightMapFloat = 
reinterpret_cast<const float *
>( heightMap.constData() );
 
  184  for ( 
int j = 0; j < numVerticesZ - 1; ++j )
 
  186    const int rowStartIndex = j * numVerticesX;
 
  187    const int nextRowStartIndex = ( j + 1 ) * numVerticesX;
 
  190    for ( 
int i = 0; i < numVerticesX - 1; ++i )
 
  192      if ( hasNoData( i, j, heightMapFloat, res, res ) )
 
  196        *indexPtr++ = rowStartIndex + i;
 
  197        *indexPtr++ = rowStartIndex + i;
 
  198        *indexPtr++ = rowStartIndex + i;
 
  200        *indexPtr++ = rowStartIndex + i;
 
  201        *indexPtr++ = rowStartIndex + i;
 
  202        *indexPtr++ = rowStartIndex + i;
 
  207      *indexPtr++ = rowStartIndex + i;
 
  208      *indexPtr++ = nextRowStartIndex + i;
 
  209      *indexPtr++ = rowStartIndex + i + 1;
 
  211      *indexPtr++ = nextRowStartIndex + i;
 
  212      *indexPtr++ = nextRowStartIndex + i + 1;
 
  213      *indexPtr++ = rowStartIndex + i + 1;
 
  227    explicit PlaneVertexBufferFunctor( 
int resolution, 
float side, 
float vertScale, 
float skirtHeight, 
const QByteArray &heightMap )
 
  228      : mResolution( resolution )
 
  230      , mVertScale( vertScale )
 
  231      , mSkirtHeight( skirtHeight )
 
  232      , mHeightMap( heightMap )
 
  235    QByteArray operator()()
 
  237      return createPlaneVertexData( mResolution, mSide, mVertScale, mSkirtHeight, mHeightMap );
 
  242      const PlaneVertexBufferFunctor *otherFunctor = functor_cast<PlaneVertexBufferFunctor>( &other );
 
  243      if ( otherFunctor != 
nullptr )
 
  244        return ( otherFunctor->mResolution == mResolution &&
 
  245                 otherFunctor->mSide == mSide &&
 
  246                 otherFunctor->mVertScale == mVertScale &&
 
  247                 otherFunctor->mSkirtHeight == mSkirtHeight &&
 
  248                 otherFunctor->mHeightMap == mHeightMap );
 
  252    QT3D_FUNCTOR( PlaneVertexBufferFunctor )
 
  259    QByteArray mHeightMap;
 
  267    explicit PlaneIndexBufferFunctor( 
int resolution, 
const QByteArray &heightMap )
 
  268      : mResolution( resolution )
 
  269      , mHeightMap( heightMap )
 
  272    QByteArray operator()()
 
  274      return createPlaneIndexData( mResolution, mHeightMap );
 
  279      const PlaneIndexBufferFunctor *otherFunctor = functor_cast<PlaneIndexBufferFunctor>( &other );
 
  280      if ( otherFunctor != 
nullptr )
 
  281        return ( otherFunctor->mResolution == mResolution );
 
  285    QT3D_FUNCTOR( PlaneIndexBufferFunctor )
 
  289    QByteArray mHeightMap;
 
  297DemTerrainTileGeometry::DemTerrainTileGeometry( 
int resolution, 
float side, 
float vertScale, 
float skirtHeight, 
const QByteArray &heightMap, DemTerrainTileGeometry::QNode *parent )
 
  298  : QGeometry( parent )
 
  299  , mResolution( resolution )
 
  301  , mVertScale( vertScale )
 
  302  , mSkirtHeight( skirtHeight )
 
  303  , mHeightMap( heightMap )
 
  308static bool intersectionDemTriangles( 
const QByteArray &vertexBuf, 
const QByteArray &indexBuf, 
const QgsRayCastingUtils::Ray3D &r, 
const QMatrix4x4 &worldTransform, QVector3D &intPt )
 
  313  const float *vertices = 
reinterpret_cast<const float *
>( vertexBuf.constData() );
 
  314  const uint *indices = 
reinterpret_cast<const uint *
>( indexBuf.constData() );
 
  316  int vertexCnt = vertexBuf.count() / 
sizeof( float );
 
  317  Q_ASSERT( vertexCnt % 8 == 0 );
 
  319  int indexCnt = indexBuf.count() / 
sizeof( uint );
 
  320  Q_ASSERT( indexCnt % 3 == 0 );
 
  321  int triangleCount = indexCnt / 3;
 
  323  QVector3D intersectionPt, minIntersectionPt;
 
  325  float minDistance = -1;
 
  327  for ( 
int i = 0; i < triangleCount; ++i )
 
  329    int v0 = indices[i * 3], v1 = indices[i * 3 + 1], v2 = indices[i * 3 + 2];
 
  330    QVector3D a( vertices[v0 * 8], vertices[v0 * 8 + 1], vertices[v0 * 8 + 2] );
 
  331    QVector3D b( vertices[v1 * 8], vertices[v1 * 8 + 1], vertices[v1 * 8 + 2] );
 
  332    QVector3D 
c( vertices[v2 * 8], vertices[v2 * 8 + 1], vertices[v2 * 8 + 2] );
 
  334    const QVector3D tA = worldTransform * a;
 
  335    const QVector3D tB = worldTransform * b;
 
  336    const QVector3D tC = worldTransform * 
c;
 
  340    if ( QgsRayCastingUtils::rayTriangleIntersection( r, tA, tB, tC, uvw, t ) )
 
  342      intersectionPt = r.point( t * r.distance() );
 
  343      distance = r.projectedDistance( intersectionPt );
 
  346      if ( minDistance == -1 || distance < minDistance )
 
  348        minDistance = distance;
 
  349        minIntersectionPt = intersectionPt;
 
  354  if ( minDistance != -1 )
 
  356    intPt = minIntersectionPt;
 
  363bool DemTerrainTileGeometry::rayIntersection( 
const QgsRayCastingUtils::Ray3D &ray, 
const QMatrix4x4 &worldTransform, QVector3D &intersectionPoint )
 
  365  return intersectionDemTriangles( mVertexBuffer->data(), mIndexBuffer->data(), ray, worldTransform, intersectionPoint );
 
  368void DemTerrainTileGeometry::init()
 
  377  int nVertsX = mResolution + 2;
 
  378  int nVertsZ = mResolution + 2;
 
  379  const int nVerts = nVertsX * nVertsZ;
 
  380  const int stride = ( 3 + 2 + 3 ) * 
sizeof( 
float );
 
  381  const int faces = 2 * ( nVertsX - 1 ) * ( nVertsZ - 1 );
 
  383  mPositionAttribute->setName( Qt3DQAttribute::defaultPositionAttributeName() );
 
  384  mPositionAttribute->setVertexBaseType( Qt3DQAttribute::Float );
 
  385  mPositionAttribute->setVertexSize( 3 );
 
  386  mPositionAttribute->setAttributeType( Qt3DQAttribute::VertexAttribute );
 
  387  mPositionAttribute->setBuffer( mVertexBuffer );
 
  388  mPositionAttribute->setByteStride( stride );
 
  389  mPositionAttribute->setCount( nVerts );
 
  391  mTexCoordAttribute->setName( Qt3DQAttribute::defaultTextureCoordinateAttributeName() );
 
  392  mTexCoordAttribute->setVertexBaseType( Qt3DQAttribute::Float );
 
  393  mTexCoordAttribute->setVertexSize( 2 );
 
  394  mTexCoordAttribute->setAttributeType( Qt3DQAttribute::VertexAttribute );
 
  395  mTexCoordAttribute->setBuffer( mVertexBuffer );
 
  396  mTexCoordAttribute->setByteStride( stride );
 
  397  mTexCoordAttribute->setByteOffset( 3 * 
sizeof( 
float ) );
 
  398  mTexCoordAttribute->setCount( nVerts );
 
  400  mNormalAttribute->setName( Qt3DQAttribute::defaultNormalAttributeName() );
 
  401  mNormalAttribute->setVertexBaseType( Qt3DQAttribute::Float );
 
  402  mNormalAttribute->setVertexSize( 3 );
 
  403  mNormalAttribute->setAttributeType( Qt3DQAttribute::VertexAttribute );
 
  404  mNormalAttribute->setBuffer( mVertexBuffer );
 
  405  mNormalAttribute->setByteStride( stride );
 
  406  mNormalAttribute->setByteOffset( 5 * 
sizeof( 
float ) );
 
  407  mNormalAttribute->setCount( nVerts );
 
  409  mIndexAttribute->setAttributeType( Qt3DQAttribute::IndexAttribute );
 
  410  mIndexAttribute->setVertexBaseType( Qt3DQAttribute::UnsignedInt );
 
  411  mIndexAttribute->setBuffer( mIndexBuffer );
 
  414  mIndexAttribute->setCount( faces * 3 );
 
  419  mVertexBuffer->setData( PlaneVertexBufferFunctor( mResolution, mSide, mVertScale, mSkirtHeight, mHeightMap )() );
 
  420  mIndexBuffer->setData( PlaneIndexBufferFunctor( mResolution, mHeightMap )() );
 
  422  addAttribute( mPositionAttribute );
 
  423  addAttribute( mTexCoordAttribute );
 
  424  addAttribute( mNormalAttribute );
 
  425  addAttribute( mIndexAttribute );
 
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 Q_NOWARN_DEPRECATED_POP
 
#define Q_NOWARN_DEPRECATED_PUSH
 
Qt3DCore::QAbstractFunctor Qt3DQAbstractFunctor
 
Qt3DCore::QAttribute Qt3DQAttribute
 
Qt3DCore::QBuffer Qt3DQBuffer
 
bool operator==(const QgsFeatureIterator &fi1, const QgsFeatureIterator &fi2)