18 #include <Qt3DRender/qattribute.h>    19 #include <Qt3DRender/qbuffer.h>    20 #include <Qt3DRender/qbufferdatagenerator.h>    30 static QByteArray createPlaneVertexData( 
int res, 
float side, 
float vertScale, 
float skirtHeight, 
const QByteArray &heights )
    33   Q_ASSERT( heights.count() == res * res * 
static_cast<int>( 
sizeof( float ) ) );
    35   const float *zData = ( 
const float * ) heights.constData();
    36   const float *zBits = zData;
    38   const int nVerts = ( res + 2 ) * ( res + 2 );
    42   const quint32 elementSize = 3 + 2 + 3;
    43   const quint32 stride = elementSize * 
sizeof( float );
    44   QByteArray bufferBytes;
    45   bufferBytes.resize( stride * nVerts );
    46   float *fptr = 
reinterpret_cast<float *
>( bufferBytes.data() );
    49   QSize resolution( res, res );
    50   const float x0 = -w / 2.0f;
    51   const float z0 = -h / 2.0f;
    52   const float dx = w / ( resolution.width() - 1 );
    53   const float dz = h / ( resolution.height() - 1 );
    54   const float du = 1.0 / ( resolution.width() - 1 );
    55   const float dv = 1.0 / ( resolution.height() - 1 );
    59   const float noDataHeight = 0;
    61   const int iMax = resolution.width() - 1;
    62   const int jMax = resolution.height() - 1;
    65   for ( 
int j = -1; j <= resolution.height(); ++j )
    67     int jBound = qBound( 0, j, jMax );
    68     const float z = z0 + 
static_cast<float>( jBound ) * dz;
    69     const float v = 
static_cast<float>( jBound ) * dv;
    72     for ( 
int i = -1; i <= resolution.width(); ++i )
    74       int iBound = qBound( 0, i, iMax );
    75       const float x = x0 + 
static_cast<float>( iBound ) * dx;
    76       const float u = 
static_cast<float>( iBound ) * du;
    79       if ( i == iBound && j == jBound )
    82         height = zData[ jBound * resolution.width() + iBound ] - skirtHeight;
    84       if ( std::isnan( height ) )
    85         height = noDataHeight;
    89       *fptr++ = height / side * vertScale;
    97 #define zAt( ii, jj )  zData[ jj * resolution.width() + ii ] * vertScale    98       float zi0 = zAt( qBound( 0, i - 1, iMax ), jBound );
    99       float zi1 = zAt( qBound( 0, i + 1, iMax ), jBound );
   100       float zj0 = zAt( iBound, qBound( 0, j - 1, jMax ) );
   101       float zj1 = zAt( iBound, qBound( 0, j + 1, jMax ) );
   104       if ( std::isnan( zi0 ) || std::isnan( zi1 ) || std::isnan( zj0 ) || std::isnan( zj1 ) )
   105         n = QVector3D( 0, 1, 0 );
   109         float zij = height * vertScale;
   112           di = 2 * ( zij - zi1 );
   113         else if ( i == iMax )
   114           di = 2 * ( zi0 - zij );
   119           dj = 2 * ( zij - zj1 );
   120         else if ( j == jMax )
   121           dj = 2 * ( zj0 - zij );
   125         n = QVector3D( di, 2 * side / res, dj );
   138 inline int ijToHeightMapIndex( 
int i, 
int j, 
int resX, 
int resZ )
   140   i = qBound( 1, i, resX ) - 1;
   141   j = qBound( 1, j, resZ ) - 1;
   146 static bool hasNoData( 
int i, 
int j, 
const float *heightMap, 
int resX, 
int resZ )
   148   return std::isnan( heightMap[ ijToHeightMapIndex( i, j, resX, resZ ) ] ) ||
   149          std::isnan( heightMap[ ijToHeightMapIndex( i + 1, j, resX, resZ ) ] ) ||
   150          std::isnan( heightMap[ ijToHeightMapIndex( i, j + 1, resX, resZ ) ] ) ||
   151          std::isnan( heightMap[ ijToHeightMapIndex( i + 1, j + 1, resX, resZ ) ] );
   154 static QByteArray createPlaneIndexData( 
int res, 
const QByteArray &heightMap )
   156   QSize resolution( res, res );
   157   int numVerticesX = resolution.width() + 2;
   158   int numVerticesZ = resolution.height() + 2;
   161   const int faces = 2 * ( numVerticesX - 1 ) * ( numVerticesZ - 1 );
   162   const quint32 indices = 3 * faces;
   163   Q_ASSERT( indices < std::numeric_limits<quint32>::max() );
   164   QByteArray indexBytes;
   165   indexBytes.resize( indices * 
sizeof( quint32 ) );
   166   quint32 *indexPtr = 
reinterpret_cast<quint32 *
>( indexBytes.data() );
   168   const float *heightMapFloat = 
reinterpret_cast<const float *
>( heightMap.constData() );
   171   for ( 
int j = 0; j < numVerticesZ - 1; ++j )
   173     const int rowStartIndex = j * numVerticesX;
   174     const int nextRowStartIndex = ( j + 1 ) * numVerticesX;
   177     for ( 
int i = 0; i < numVerticesX - 1; ++i )
   179       if ( hasNoData( i, j, heightMapFloat, res, res ) )
   183         *indexPtr++ = rowStartIndex + i;
   184         *indexPtr++ = rowStartIndex + i;
   185         *indexPtr++ = rowStartIndex + i;
   187         *indexPtr++ = rowStartIndex + i;
   188         *indexPtr++ = rowStartIndex + i;
   189         *indexPtr++ = rowStartIndex + i;
   194       *indexPtr++ = rowStartIndex + i;
   195       *indexPtr++ = nextRowStartIndex + i;
   196       *indexPtr++ = rowStartIndex + i + 1;
   198       *indexPtr++ = nextRowStartIndex + i;
   199       *indexPtr++ = nextRowStartIndex + i + 1;
   200       *indexPtr++ = rowStartIndex + i + 1;
   210 class PlaneVertexBufferFunctor : 
public QBufferDataGenerator
   213     explicit PlaneVertexBufferFunctor( 
int resolution, 
float side, 
float vertScale, 
float skirtHeight, 
const QByteArray &heightMap )
   214       : mResolution( resolution )
   216       , mVertScale( vertScale )
   217       , mSkirtHeight( skirtHeight )
   218       , mHeightMap( heightMap )
   221     QByteArray operator()() final
   223       return createPlaneVertexData( mResolution, mSide, mVertScale, mSkirtHeight, mHeightMap );
   226     bool operator ==( 
const QBufferDataGenerator &other ) 
const final   228       const PlaneVertexBufferFunctor *otherFunctor = functor_cast<PlaneVertexBufferFunctor>( &other );
   229       if ( otherFunctor != 
nullptr )
   230         return ( otherFunctor->mResolution == mResolution &&
   231                  otherFunctor->mSide == mSide &&
   232                  otherFunctor->mVertScale == mVertScale &&
   233                  otherFunctor->mSkirtHeight == mSkirtHeight &&
   234                  otherFunctor->mHeightMap == mHeightMap );
   238     QT3D_FUNCTOR( PlaneVertexBufferFunctor )
   245     QByteArray mHeightMap;
   250 class PlaneIndexBufferFunctor : 
public QBufferDataGenerator
   253     explicit PlaneIndexBufferFunctor( 
int resolution, 
const QByteArray &heightMap )
   254       : mResolution( resolution )
   255       , mHeightMap( heightMap )
   258     QByteArray operator()() final
   260       return createPlaneIndexData( mResolution, mHeightMap );
   263     bool operator ==( 
const QBufferDataGenerator &other ) 
const final   265       const PlaneIndexBufferFunctor *otherFunctor = functor_cast<PlaneIndexBufferFunctor>( &other );
   266       if ( otherFunctor != 
nullptr )
   267         return ( otherFunctor->mResolution == mResolution );
   271     QT3D_FUNCTOR( PlaneIndexBufferFunctor )
   275     QByteArray mHeightMap;
   282 DemTerrainTileGeometry::DemTerrainTileGeometry( 
int resolution, 
float side, 
float vertScale, 
float skirtHeight, 
const QByteArray &heightMap, DemTerrainTileGeometry::QNode *parent )
   283   : QGeometry( parent )
   284   , mResolution( resolution )
   286   , mVertScale( vertScale )
   287   , mSkirtHeight( skirtHeight )
   288   , mHeightMap( heightMap )
   293 static bool intersectionDemTriangles( 
const QByteArray &vertexBuf, 
const QByteArray &indexBuf, 
const QgsRayCastingUtils::Ray3D &r, 
const QMatrix4x4 &worldTransform, QVector3D &intPt )
   298   const float *vertices = 
reinterpret_cast<const float *
>( vertexBuf.constData() );
   299   const uint *indices = 
reinterpret_cast<const uint *
>( indexBuf.constData() );
   301   int vertexCnt = vertexBuf.count() / 
sizeof( float );
   302   Q_ASSERT( vertexCnt % 8 == 0 );
   304   int indexCnt = indexBuf.count() / 
sizeof( uint );
   305   Q_ASSERT( indexCnt % 3 == 0 );
   306   int triangleCount = indexCnt / 3;
   308   QVector3D intersectionPt, minIntersectionPt;
   310   float minDistance = -1;
   312   for ( 
int i = 0; i < triangleCount; ++i )
   314     int v0 = indices[i * 3], v1 = indices[i * 3 + 1], v2 = indices[i * 3 + 2];
   315     QVector3D a( vertices[v0 * 8], vertices[v0 * 8 + 1], vertices[v0 * 8 + 2] );
   316     QVector3D b( vertices[v1 * 8], vertices[v1 * 8 + 1], vertices[v1 * 8 + 2] );
   317     QVector3D 
c( vertices[v2 * 8], vertices[v2 * 8 + 1], vertices[v2 * 8 + 2] );
   319     const QVector3D tA = worldTransform * a;
   320     const QVector3D tB = worldTransform * b;
   321     const QVector3D tC = worldTransform * 
c;
   325     if ( QgsRayCastingUtils::rayTriangleIntersection( r, tA, tB, tC, uvw, t ) )
   327       intersectionPt = r.point( t * r.distance() );
   328       distance = r.projectedDistance( intersectionPt );
   331       if ( minDistance == -1 || distance < minDistance )
   333         minDistance = distance;
   334         minIntersectionPt = intersectionPt;
   339   if ( minDistance != -1 )
   341     intPt = minIntersectionPt;
   348 bool DemTerrainTileGeometry::rayIntersection( 
const QgsRayCastingUtils::Ray3D &ray, 
const QMatrix4x4 &worldTransform, QVector3D &intersectionPoint )
   350   return intersectionDemTriangles( mVertexBuffer->data(), mIndexBuffer->data(), ray, worldTransform, intersectionPoint );
   353 void DemTerrainTileGeometry::init()
   355   mPositionAttribute = 
new QAttribute( 
this );
   356   mNormalAttribute = 
new QAttribute( 
this );
   357   mTexCoordAttribute = 
new QAttribute( 
this );
   358   mIndexAttribute = 
new QAttribute( 
this );
   359 #if QT_VERSION < QT_VERSION_CHECK(5, 10, 0)   360   mVertexBuffer = 
new Qt3DRender::QBuffer( Qt3DRender::QBuffer::VertexBuffer, 
this );
   361   mIndexBuffer = 
new Qt3DRender::QBuffer( Qt3DRender::QBuffer::IndexBuffer, 
this );
   363   mVertexBuffer = 
new Qt3DRender::QBuffer( 
this );
   364   mIndexBuffer = 
new Qt3DRender::QBuffer( 
this );
   368   int nVertsX = mResolution + 2;
   369   int nVertsZ = mResolution + 2;
   370   const int nVerts = nVertsX * nVertsZ;
   371   const int stride = ( 3 + 2 + 3 ) * 
sizeof( 
float );
   372   const int faces = 2 * ( nVertsX - 1 ) * ( nVertsZ - 1 );
   374   mPositionAttribute->setName( QAttribute::defaultPositionAttributeName() );
   375   mPositionAttribute->setVertexBaseType( QAttribute::Float );
   376   mPositionAttribute->setVertexSize( 3 );
   377   mPositionAttribute->setAttributeType( QAttribute::VertexAttribute );
   378   mPositionAttribute->setBuffer( mVertexBuffer );
   379   mPositionAttribute->setByteStride( stride );
   380   mPositionAttribute->setCount( nVerts );
   382   mTexCoordAttribute->setName( QAttribute::defaultTextureCoordinateAttributeName() );
   383   mTexCoordAttribute->setVertexBaseType( QAttribute::Float );
   384   mTexCoordAttribute->setVertexSize( 2 );
   385   mTexCoordAttribute->setAttributeType( QAttribute::VertexAttribute );
   386   mTexCoordAttribute->setBuffer( mVertexBuffer );
   387   mTexCoordAttribute->setByteStride( stride );
   388   mTexCoordAttribute->setByteOffset( 3 * 
sizeof( 
float ) );
   389   mTexCoordAttribute->setCount( nVerts );
   391   mNormalAttribute->setName( QAttribute::defaultNormalAttributeName() );
   392   mNormalAttribute->setVertexBaseType( QAttribute::Float );
   393   mNormalAttribute->setVertexSize( 3 );
   394   mNormalAttribute->setAttributeType( QAttribute::VertexAttribute );
   395   mNormalAttribute->setBuffer( mVertexBuffer );
   396   mNormalAttribute->setByteStride( stride );
   397   mNormalAttribute->setByteOffset( 5 * 
sizeof( 
float ) );
   398   mNormalAttribute->setCount( nVerts );
   400   mIndexAttribute->setAttributeType( QAttribute::IndexAttribute );
   401   mIndexAttribute->setVertexBaseType( QAttribute::UnsignedInt );
   402   mIndexAttribute->setBuffer( mIndexBuffer );
   405   mIndexAttribute->setCount( faces * 3 );
   409   mVertexBuffer->setData( PlaneVertexBufferFunctor( mResolution, mSide, mVertScale, mSkirtHeight, mHeightMap )() );
   410   mIndexBuffer->setData( PlaneIndexBufferFunctor( mResolution, mHeightMap )() );
   412   addAttribute( mPositionAttribute );
   413   addAttribute( mTexCoordAttribute );
   414   addAttribute( mNormalAttribute );
   415   addAttribute( mIndexAttribute );
 bool operator==(const QgsFeatureIterator &fi1, const QgsFeatureIterator &fi2)
 
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