27#include <Qt3DCore/QAbstractFunctor>
28#include <Qt3DCore/QAttribute>
29#include <Qt3DCore/QBuffer>
31#include "moc_qgsdemterraintilegeometry_p.cpp"
37static QByteArray createPlaneVertexData(
int res,
float side,
float vertScale,
float skirtHeight,
const QByteArray &heights )
40 Q_ASSERT( heights.count() == res * res *
static_cast<int>(
sizeof(
float ) ) );
42 const float *zData = (
const float * ) heights.constData();
43 const float *zBits = zData;
45 const int nVerts = ( res + 2 ) * ( res + 2 );
49 const quint32 elementSize = 3 + 2 + 3;
50 const quint32 stride = elementSize *
sizeof( float );
51 QByteArray bufferBytes;
52 bufferBytes.resize( stride * nVerts );
53 float *fptr =
reinterpret_cast<float *
>( bufferBytes.data() );
55 QSize resolution( res, res );
57 const float y0 = side;
58 const float dx = side /
static_cast<float>( resolution.width() - 1 );
59 const float dy = side /
static_cast<float>( resolution.height() - 1 );
60 const float du = 1.0f /
static_cast<float>( resolution.width() - 1 );
61 const float dv = 1.0f /
static_cast<float>( resolution.height() - 1 );
65 const float noDataHeight = 0;
67 const int iMax = resolution.width() - 1;
68 const int jMax = resolution.height() - 1;
71 for (
int j = -1; j <= resolution.height(); ++j )
73 int jBound = std::clamp( j, 0, jMax );
74 const float y = y0 -
static_cast<float>( jBound ) * dy;
75 const float v =
static_cast<float>( jBound ) * dv;
78 for (
int i = -1; i <= resolution.width(); ++i )
80 int iBound = std::clamp( i, 0, iMax );
81 const float x = x0 +
static_cast<float>( iBound ) * dx;
82 const float u =
static_cast<float>( iBound ) * du;
85 if ( i == iBound && j == jBound )
88 height = zData[jBound * resolution.width() + iBound] - skirtHeight;
90 if ( std::isnan( height ) )
91 height = noDataHeight;
96 *fptr++ = height * vertScale;
103#define zAt( ii, jj ) zData[jj * resolution.width() + ii] * vertScale
104 float zi0 = zAt( std::clamp( i - 1, 0, iMax ), jBound );
105 float zi1 = zAt( std::clamp( i + 1, 0, iMax ), jBound );
106 float zj0 = zAt( iBound, std::clamp( j - 1, 0, jMax ) );
107 float zj1 = zAt( iBound, std::clamp( j + 1, 0, jMax ) );
110 if ( std::isnan( zi0 ) || std::isnan( zi1 ) || std::isnan( zj0 ) || std::isnan( zj1 ) )
111 n = QVector3D( 0, 0, 1 );
115 float zij = height * vertScale;
118 di = 2 * ( zij - zi1 );
119 else if ( i == iMax )
120 di = 2 * ( zi0 - zij );
125 dj = 2 * ( zij - zj1 );
126 else if ( j == jMax )
127 dj = 2 * ( zj0 - zij );
131 n = QVector3D( di, -dj, 2 * side /
static_cast<float>( res ) );
144inline int ijToHeightMapIndex(
int i,
int j,
int resX,
int resZ )
146 i = std::clamp( i, 1, resX ) - 1;
147 j = std::clamp( j, 1, resZ ) - 1;
151static bool hasNoData(
int i,
int j,
const float *heightMap,
int resX,
int resZ )
153 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 )] );
156static QByteArray createPlaneIndexData(
int res,
const QByteArray &heightMap )
158 QSize resolution( res, res );
159 int numVerticesX = resolution.width() + 2;
160 int numVerticesZ = resolution.height() + 2;
163 const int faces = 2 * ( numVerticesX - 1 ) * ( numVerticesZ - 1 );
164 const quint32 indices = 3 * faces;
165 Q_ASSERT( indices < std::numeric_limits<quint32>::max() );
166 QByteArray indexBytes;
167 indexBytes.resize( indices *
sizeof( quint32 ) );
168 quint32 *indexPtr =
reinterpret_cast<quint32 *
>( indexBytes.data() );
170 const float *heightMapFloat =
reinterpret_cast<const float *
>( heightMap.constData() );
173 for (
int j = 0; j < numVerticesZ - 1; ++j )
175 const int rowStartIndex = j * numVerticesX;
176 const int nextRowStartIndex = ( j + 1 ) * numVerticesX;
179 for (
int i = 0; i < numVerticesX - 1; ++i )
181 if ( hasNoData( i, j, heightMapFloat, res, res ) )
185 *indexPtr++ = rowStartIndex + i;
186 *indexPtr++ = rowStartIndex + i;
187 *indexPtr++ = rowStartIndex + i;
189 *indexPtr++ = rowStartIndex + i;
190 *indexPtr++ = rowStartIndex + i;
191 *indexPtr++ = rowStartIndex + i;
196 *indexPtr++ = rowStartIndex + i;
197 *indexPtr++ = nextRowStartIndex + i;
198 *indexPtr++ = rowStartIndex + i + 1;
200 *indexPtr++ = nextRowStartIndex + i;
201 *indexPtr++ = nextRowStartIndex + i + 1;
202 *indexPtr++ = rowStartIndex + i + 1;
210class PlaneVertexBufferFunctor :
public Qt3DCore::QAbstractFunctor
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()()
223 return createPlaneVertexData( mResolution, mSide, mVertScale, mSkirtHeight, mHeightMap );
226 qintptr id()
const override
228 return reinterpret_cast<qintptr
>( &Qt3DCore::FunctorType<PlaneVertexBufferFunctor>::id );
231 bool operator==(
const Qt3DCore::QAbstractFunctor &other )
const
233 const PlaneVertexBufferFunctor *otherFunctor =
dynamic_cast<const PlaneVertexBufferFunctor *
>( &other );
235 return ( otherFunctor->mResolution == mResolution && otherFunctor->mSide == mSide && otherFunctor->mVertScale == mVertScale && otherFunctor->mSkirtHeight == mSkirtHeight && otherFunctor->mHeightMap == mHeightMap );
244 QByteArray mHeightMap;
248class PlaneIndexBufferFunctor :
public Qt3DCore::QAbstractFunctor
251 explicit PlaneIndexBufferFunctor(
int resolution,
const QByteArray &heightMap )
252 : mResolution( resolution )
253 , mHeightMap( heightMap )
256 QByteArray operator()()
258 return createPlaneIndexData( mResolution, mHeightMap );
261 qintptr id()
const override
263 return reinterpret_cast<qintptr
>( &Qt3DCore::FunctorType<PlaneIndexBufferFunctor>::id );
266 bool operator==(
const Qt3DCore::QAbstractFunctor &other )
const
268 const PlaneIndexBufferFunctor *otherFunctor =
dynamic_cast<const PlaneIndexBufferFunctor *
>( &other );
270 return ( otherFunctor->mResolution == mResolution );
276 QByteArray mHeightMap;
282DemTerrainTileGeometry::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 )
293static bool intersectionDemTriangles(
const QByteArray &vertexBuf,
const QByteArray &indexBuf,
const QgsRay3D &r,
const QgsRayCastContext &context,
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;
331 if ( minDistance == -1 || distance < minDistance )
333 minDistance = distance;
334 minIntersectionPt = intersectionPt;
339 if ( minDistance != -1 )
341 intPt = minIntersectionPt;
348bool DemTerrainTileGeometry::rayIntersection(
const QgsRay3D &ray,
const QgsRayCastContext &context,
const QMatrix4x4 &worldTransform, QVector3D &intersectionPoint )
350 return intersectionDemTriangles( mVertexBuffer->data(), mIndexBuffer->data(), ray, context, worldTransform, intersectionPoint );
353void DemTerrainTileGeometry::init()
355 mPositionAttribute =
new Qt3DCore::QAttribute(
this );
356 mNormalAttribute =
new Qt3DCore::QAttribute(
this );
357 mTexCoordAttribute =
new Qt3DCore::QAttribute(
this );
358 mIndexAttribute =
new Qt3DCore::QAttribute(
this );
359 mVertexBuffer =
new Qt3DCore::QBuffer(
this );
360 mIndexBuffer =
new Qt3DCore::QBuffer(
this );
362 int nVertsX = mResolution + 2;
363 int nVertsZ = mResolution + 2;
364 const int nVerts = nVertsX * nVertsZ;
365 const int stride = ( 3 + 2 + 3 ) *
sizeof(
float );
366 const int faces = 2 * ( nVertsX - 1 ) * ( nVertsZ - 1 );
368 mPositionAttribute->setName( Qt3DCore::QAttribute::defaultPositionAttributeName() );
369 mPositionAttribute->setVertexBaseType( Qt3DCore::QAttribute::Float );
370 mPositionAttribute->setVertexSize( 3 );
371 mPositionAttribute->setAttributeType( Qt3DCore::QAttribute::VertexAttribute );
372 mPositionAttribute->setBuffer( mVertexBuffer );
373 mPositionAttribute->setByteStride( stride );
374 mPositionAttribute->setCount( nVerts );
376 mTexCoordAttribute->setName( Qt3DCore::QAttribute::defaultTextureCoordinateAttributeName() );
377 mTexCoordAttribute->setVertexBaseType( Qt3DCore::QAttribute::Float );
378 mTexCoordAttribute->setVertexSize( 2 );
379 mTexCoordAttribute->setAttributeType( Qt3DCore::QAttribute::VertexAttribute );
380 mTexCoordAttribute->setBuffer( mVertexBuffer );
381 mTexCoordAttribute->setByteStride( stride );
382 mTexCoordAttribute->setByteOffset( 3 *
sizeof(
float ) );
383 mTexCoordAttribute->setCount( nVerts );
385 mNormalAttribute->setName( Qt3DCore::QAttribute::defaultNormalAttributeName() );
386 mNormalAttribute->setVertexBaseType( Qt3DCore::QAttribute::Float );
387 mNormalAttribute->setVertexSize( 3 );
388 mNormalAttribute->setAttributeType( Qt3DCore::QAttribute::VertexAttribute );
389 mNormalAttribute->setBuffer( mVertexBuffer );
390 mNormalAttribute->setByteStride( stride );
391 mNormalAttribute->setByteOffset( 5 *
sizeof(
float ) );
392 mNormalAttribute->setCount( nVerts );
394 mIndexAttribute->setAttributeType( Qt3DCore::QAttribute::IndexAttribute );
395 mIndexAttribute->setVertexBaseType( Qt3DCore::QAttribute::UnsignedInt );
396 mIndexAttribute->setBuffer( mIndexBuffer );
399 mIndexAttribute->setCount( faces * 3 );
404 mVertexBuffer->setData( PlaneVertexBufferFunctor( mResolution, mSide, mVertScale, mSkirtHeight, mHeightMap )() );
405 mIndexBuffer->setData( PlaneIndexBufferFunctor( mResolution, mHeightMap )() );
407 addAttribute( mPositionAttribute );
408 addAttribute( mTexCoordAttribute );
409 addAttribute( mNormalAttribute );
410 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
bool operator==(const QgsFeatureIterator &fi1, const QgsFeatureIterator &fi2)