20#include "moc_qgsdemterraintilegeometry_p.cpp"
22#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
23#include <Qt3DRender/QAttribute>
24#include <Qt3DRender/QBuffer>
25#include <Qt3DRender/QAbstractFunctor>
30#include <Qt3DCore/QAttribute>
31#include <Qt3DCore/QBuffer>
32#include <Qt3DCore/QAbstractFunctor>
48static QByteArray createPlaneVertexData(
int res,
float side,
float vertScale,
float skirtHeight,
const QByteArray &heights )
51 Q_ASSERT( heights.count() == res * res *
static_cast<int>(
sizeof(
float ) ) );
53 const float *zData = (
const float * ) heights.constData();
54 const float *zBits = zData;
56 const int nVerts = ( res + 2 ) * ( res + 2 );
60 const quint32 elementSize = 3 + 2 + 3;
61 const quint32 stride = elementSize *
sizeof( float );
62 QByteArray bufferBytes;
63 bufferBytes.resize( stride * nVerts );
64 float *fptr =
reinterpret_cast<float *
>( bufferBytes.data() );
66 QSize resolution( res, res );
68 const float y0 = side;
69 const float dx = side /
static_cast<float>( resolution.width() - 1 );
70 const float dy = side /
static_cast<float>( resolution.height() - 1 );
71 const float du = 1.0f /
static_cast<float>( resolution.width() - 1 );
72 const float dv = 1.0f /
static_cast<float>( resolution.height() - 1 );
76 const float noDataHeight = 0;
78 const int iMax = resolution.width() - 1;
79 const int jMax = resolution.height() - 1;
82 for (
int j = -1; j <= resolution.height(); ++j )
84 int jBound = std::clamp( j, 0, jMax );
85 const float y = y0 -
static_cast<float>( jBound ) * dy;
86 const float v =
static_cast<float>( jBound ) * dv;
89 for (
int i = -1; i <= resolution.width(); ++i )
91 int iBound = std::clamp( i, 0, iMax );
92 const float x = x0 +
static_cast<float>( iBound ) * dx;
93 const float u =
static_cast<float>( iBound ) * du;
96 if ( i == iBound && j == jBound )
99 height = zData[jBound * resolution.width() + iBound] - skirtHeight;
101 if ( std::isnan( height ) )
102 height = noDataHeight;
107 *fptr++ = height * vertScale;
114#define zAt( ii, jj ) zData[jj * resolution.width() + ii] * vertScale
115 float zi0 = zAt( std::clamp( i - 1, 0, iMax ), jBound );
116 float zi1 = zAt( std::clamp( i + 1, 0, iMax ), jBound );
117 float zj0 = zAt( iBound, std::clamp( j - 1, 0, jMax ) );
118 float zj1 = zAt( iBound, std::clamp( j + 1, 0, jMax ) );
121 if ( std::isnan( zi0 ) || std::isnan( zi1 ) || std::isnan( zj0 ) || std::isnan( zj1 ) )
122 n = QVector3D( 0, 0, 1 );
126 float zij = height * vertScale;
129 di = 2 * ( zij - zi1 );
130 else if ( i == iMax )
131 di = 2 * ( zi0 - zij );
136 dj = 2 * ( zij - zj1 );
137 else if ( j == jMax )
138 dj = 2 * ( zj0 - zij );
142 n = QVector3D( di, -dj, 2 * side /
static_cast<float>( res ) );
155inline int ijToHeightMapIndex(
int i,
int j,
int resX,
int resZ )
157 i = std::clamp( i, 1, resX ) - 1;
158 j = std::clamp( j, 1, resZ ) - 1;
162static bool hasNoData(
int i,
int j,
const float *heightMap,
int resX,
int resZ )
164 return std::isnan( heightMap[ijToHeightMapIndex( i, j, resX, resZ )] ) || std::isnan( heightMap[ijToHeightMapIndex( i + 1, j, resX, resZ )] ) || std::isnan( heightMap[ijToHeightMapIndex( i, j + 1, resX, resZ )] ) || 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 );
240 qintptr id()
const override
242#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
243 return reinterpret_cast<qintptr
>( &Qt3DRender::FunctorType<PlaneVertexBufferFunctor>::id );
245 return reinterpret_cast<qintptr
>( &Qt3DCore::FunctorType<PlaneVertexBufferFunctor>::id );
251 const PlaneVertexBufferFunctor *otherFunctor =
dynamic_cast<const PlaneVertexBufferFunctor *
>( &other );
253 return ( otherFunctor->mResolution == mResolution && otherFunctor->mSide == mSide && otherFunctor->mVertScale == mVertScale && otherFunctor->mSkirtHeight == mSkirtHeight && otherFunctor->mHeightMap == mHeightMap );
262 QByteArray mHeightMap;
274 explicit PlaneIndexBufferFunctor(
int resolution,
const QByteArray &heightMap )
275 : mResolution( resolution )
276 , mHeightMap( heightMap )
279 QByteArray operator()()
281 return createPlaneIndexData( mResolution, mHeightMap );
284 qintptr id()
const override
286#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
287 return reinterpret_cast<qintptr
>( &Qt3DRender::FunctorType<PlaneIndexBufferFunctor>::id );
289 return reinterpret_cast<qintptr
>( &Qt3DCore::FunctorType<PlaneIndexBufferFunctor>::id );
295 const PlaneIndexBufferFunctor *otherFunctor =
dynamic_cast<const PlaneIndexBufferFunctor *
>( &other );
297 return ( otherFunctor->mResolution == mResolution );
303 QByteArray mHeightMap;
311DemTerrainTileGeometry::DemTerrainTileGeometry(
int resolution,
float side,
float vertScale,
float skirtHeight,
const QByteArray &heightMap, DemTerrainTileGeometry::QNode *parent )
312 : QGeometry( parent )
313 , mResolution( resolution )
315 , mVertScale( vertScale )
316 , mSkirtHeight( skirtHeight )
317 , mHeightMap( heightMap )
322static bool intersectionDemTriangles(
const QByteArray &vertexBuf,
const QByteArray &indexBuf,
const QgsRay3D &r,
const QgsRayCastContext &context,
const QMatrix4x4 &worldTransform, QVector3D &intPt )
327 const float *vertices =
reinterpret_cast<const float *
>( vertexBuf.constData() );
328 const uint *indices =
reinterpret_cast<const uint *
>( indexBuf.constData() );
330 int vertexCnt = vertexBuf.count() /
sizeof( float );
331 Q_ASSERT( vertexCnt % 8 == 0 );
333 int indexCnt = indexBuf.count() /
sizeof( uint );
334 Q_ASSERT( indexCnt % 3 == 0 );
335 int triangleCount = indexCnt / 3;
337 QVector3D intersectionPt, minIntersectionPt;
339 float minDistance = -1;
341 for (
int i = 0; i < triangleCount; ++i )
343 int v0 = indices[i * 3], v1 = indices[i * 3 + 1], v2 = indices[i * 3 + 2];
344 QVector3D a( vertices[v0 * 8], vertices[v0 * 8 + 1], vertices[v0 * 8 + 2] );
345 QVector3D b( vertices[v1 * 8], vertices[v1 * 8 + 1], vertices[v1 * 8 + 2] );
346 QVector3D
c( vertices[v2 * 8], vertices[v2 * 8 + 1], vertices[v2 * 8 + 2] );
348 const QVector3D tA = worldTransform * a;
349 const QVector3D tB = worldTransform * b;
350 const QVector3D tC = worldTransform *
c;
360 if ( minDistance == -1 || distance < minDistance )
362 minDistance = distance;
363 minIntersectionPt = intersectionPt;
368 if ( minDistance != -1 )
370 intPt = minIntersectionPt;
377bool DemTerrainTileGeometry::rayIntersection(
const QgsRay3D &ray,
const QgsRayCastContext &context,
const QMatrix4x4 &worldTransform, QVector3D &intersectionPoint )
379 return intersectionDemTriangles( mVertexBuffer->data(), mIndexBuffer->data(), ray, context, worldTransform, intersectionPoint );
382void DemTerrainTileGeometry::init()
391 int nVertsX = mResolution + 2;
392 int nVertsZ = mResolution + 2;
393 const int nVerts = nVertsX * nVertsZ;
394 const int stride = ( 3 + 2 + 3 ) *
sizeof(
float );
395 const int faces = 2 * ( nVertsX - 1 ) * ( nVertsZ - 1 );
397 mPositionAttribute->setName( Qt3DQAttribute::defaultPositionAttributeName() );
398 mPositionAttribute->setVertexBaseType( Qt3DQAttribute::Float );
399 mPositionAttribute->setVertexSize( 3 );
400 mPositionAttribute->setAttributeType( Qt3DQAttribute::VertexAttribute );
401 mPositionAttribute->setBuffer( mVertexBuffer );
402 mPositionAttribute->setByteStride( stride );
403 mPositionAttribute->setCount( nVerts );
405 mTexCoordAttribute->setName( Qt3DQAttribute::defaultTextureCoordinateAttributeName() );
406 mTexCoordAttribute->setVertexBaseType( Qt3DQAttribute::Float );
407 mTexCoordAttribute->setVertexSize( 2 );
408 mTexCoordAttribute->setAttributeType( Qt3DQAttribute::VertexAttribute );
409 mTexCoordAttribute->setBuffer( mVertexBuffer );
410 mTexCoordAttribute->setByteStride( stride );
411 mTexCoordAttribute->setByteOffset( 3 *
sizeof(
float ) );
412 mTexCoordAttribute->setCount( nVerts );
414 mNormalAttribute->setName( Qt3DQAttribute::defaultNormalAttributeName() );
415 mNormalAttribute->setVertexBaseType( Qt3DQAttribute::Float );
416 mNormalAttribute->setVertexSize( 3 );
417 mNormalAttribute->setAttributeType( Qt3DQAttribute::VertexAttribute );
418 mNormalAttribute->setBuffer( mVertexBuffer );
419 mNormalAttribute->setByteStride( stride );
420 mNormalAttribute->setByteOffset( 5 *
sizeof(
float ) );
421 mNormalAttribute->setCount( nVerts );
423 mIndexAttribute->setAttributeType( Qt3DQAttribute::IndexAttribute );
424 mIndexAttribute->setVertexBaseType( Qt3DQAttribute::UnsignedInt );
425 mIndexAttribute->setBuffer( mIndexBuffer );
428 mIndexAttribute->setCount( faces * 3 );
433 mVertexBuffer->setData( PlaneVertexBufferFunctor( mResolution, mSide, mVertScale, mSkirtHeight, mHeightMap )() );
434 mIndexBuffer->setData( PlaneIndexBufferFunctor( mResolution, mHeightMap )() );
436 addAttribute( mPositionAttribute );
437 addAttribute( mTexCoordAttribute );
438 addAttribute( mNormalAttribute );
439 addAttribute( mIndexAttribute );
A representation of a ray in 3D.
float projectedDistance(const QVector3D &point) const
Returns the distance of the projection of a point to the ray.
QVector3D point(float distance) const
Returns the point along the ray with the specified distance from the ray's origin.
Responsible for defining parameters of the ray casting operations in 3D map canvases.
float maximumDistance() const
The maximum distance from ray origin to look for hits when casting a ray.
bool rayTriangleIntersection(const QgsRay3D &ray, float maxDist, const QVector3D &a, const QVector3D &b, const QVector3D &c, QVector3D &uvw, float &t)
Tests whether a triangle is intersected by a ray.
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::QAttribute Qt3DQAttribute
Qt3DCore::QBuffer Qt3DQBuffer
Qt3DCore::QAbstractFunctor Qt3DQAbstractFunctor
bool operator==(const QgsFeatureIterator &fi1, const QgsFeatureIterator &fi2)