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 )] )
154 || std::isnan( heightMap[ijToHeightMapIndex( i + 1, j, resX, resZ )] )
155 || std::isnan( heightMap[ijToHeightMapIndex( i, j + 1, resX, resZ )] )
156 || std::isnan( heightMap[ijToHeightMapIndex( i + 1, j + 1, resX, resZ )] );
159static QByteArray createPlaneIndexData(
int res,
const QByteArray &heightMap )
161 QSize resolution( res, res );
162 int numVerticesX = resolution.width() + 2;
163 int numVerticesZ = resolution.height() + 2;
166 const int faces = 2 * ( numVerticesX - 1 ) * ( numVerticesZ - 1 );
167 const quint32 indices = 3 * faces;
168 Q_ASSERT( indices < std::numeric_limits<quint32>::max() );
169 QByteArray indexBytes;
170 indexBytes.resize( indices *
sizeof( quint32 ) );
171 quint32 *indexPtr =
reinterpret_cast<quint32 *
>( indexBytes.data() );
173 const float *heightMapFloat =
reinterpret_cast<const float *
>( heightMap.constData() );
176 for (
int j = 0; j < numVerticesZ - 1; ++j )
178 const int rowStartIndex = j * numVerticesX;
179 const int nextRowStartIndex = ( j + 1 ) * numVerticesX;
182 for (
int i = 0; i < numVerticesX - 1; ++i )
184 if ( hasNoData( i, j, heightMapFloat, res, res ) )
188 *indexPtr++ = rowStartIndex + i;
189 *indexPtr++ = rowStartIndex + i;
190 *indexPtr++ = rowStartIndex + i;
192 *indexPtr++ = rowStartIndex + i;
193 *indexPtr++ = rowStartIndex + i;
194 *indexPtr++ = rowStartIndex + i;
199 *indexPtr++ = rowStartIndex + i;
200 *indexPtr++ = nextRowStartIndex + i;
201 *indexPtr++ = rowStartIndex + i + 1;
203 *indexPtr++ = nextRowStartIndex + i;
204 *indexPtr++ = nextRowStartIndex + i + 1;
205 *indexPtr++ = rowStartIndex + i + 1;
213class PlaneVertexBufferFunctor :
public Qt3DCore::QAbstractFunctor
216 explicit PlaneVertexBufferFunctor(
int resolution,
float side,
float vertScale,
float skirtHeight,
const QByteArray &heightMap )
217 : mResolution( resolution )
219 , mVertScale( vertScale )
220 , mSkirtHeight( skirtHeight )
221 , mHeightMap( heightMap )
224 QByteArray operator()() {
return createPlaneVertexData( mResolution, mSide, mVertScale, mSkirtHeight, mHeightMap ); }
226 qintptr id()
const override {
return reinterpret_cast<qintptr
>( &Qt3DCore::FunctorType<PlaneVertexBufferFunctor>::id ); }
228 bool operator==(
const Qt3DCore::QAbstractFunctor &other )
const
230 const PlaneVertexBufferFunctor *otherFunctor =
dynamic_cast<const PlaneVertexBufferFunctor *
>( &other );
233 otherFunctor->mResolution == mResolution && otherFunctor->mSide == mSide && otherFunctor->mVertScale == mVertScale && otherFunctor->mSkirtHeight == mSkirtHeight && otherFunctor->mHeightMap == mHeightMap
243 QByteArray mHeightMap;
247class PlaneIndexBufferFunctor :
public Qt3DCore::QAbstractFunctor
250 explicit PlaneIndexBufferFunctor(
int resolution,
const QByteArray &heightMap )
251 : mResolution( resolution )
252 , mHeightMap( heightMap )
255 QByteArray operator()() {
return createPlaneIndexData( mResolution, mHeightMap ); }
257 qintptr id()
const override {
return reinterpret_cast<qintptr
>( &Qt3DCore::FunctorType<PlaneIndexBufferFunctor>::id ); }
259 bool operator==(
const Qt3DCore::QAbstractFunctor &other )
const
261 const PlaneIndexBufferFunctor *otherFunctor =
dynamic_cast<const PlaneIndexBufferFunctor *
>( &other );
263 return ( otherFunctor->mResolution == mResolution );
269 QByteArray mHeightMap;
275DemTerrainTileGeometry::DemTerrainTileGeometry(
int resolution,
float side,
float vertScale,
float skirtHeight,
const QByteArray &heightMap, DemTerrainTileGeometry::QNode *parent )
276 : QGeometry( parent )
277 , mResolution( resolution )
279 , mVertScale( vertScale )
280 , mSkirtHeight( skirtHeight )
281 , mHeightMap( heightMap )
286static bool intersectionDemTriangles(
const QByteArray &vertexBuf,
const QByteArray &indexBuf,
const QgsRay3D &r,
const QgsRayCastContext &context,
const QMatrix4x4 &worldTransform, QVector3D &intPt )
291 const float *vertices =
reinterpret_cast<const float *
>( vertexBuf.constData() );
292 const uint *indices =
reinterpret_cast<const uint *
>( indexBuf.constData() );
294 int vertexCnt = vertexBuf.count() /
sizeof( float );
295 Q_ASSERT( vertexCnt % 8 == 0 );
297 int indexCnt = indexBuf.count() /
sizeof( uint );
298 Q_ASSERT( indexCnt % 3 == 0 );
299 int triangleCount = indexCnt / 3;
301 QVector3D intersectionPt, minIntersectionPt;
303 float minDistance = -1;
305 for (
int i = 0; i < triangleCount; ++i )
307 int v0 = indices[i * 3], v1 = indices[i * 3 + 1], v2 = indices[i * 3 + 2];
308 QVector3D a( vertices[v0 * 8], vertices[v0 * 8 + 1], vertices[v0 * 8 + 2] );
309 QVector3D b( vertices[v1 * 8], vertices[v1 * 8 + 1], vertices[v1 * 8 + 2] );
310 QVector3D
c( vertices[v2 * 8], vertices[v2 * 8 + 1], vertices[v2 * 8 + 2] );
312 const QVector3D tA = worldTransform * a;
313 const QVector3D tB = worldTransform * b;
314 const QVector3D tC = worldTransform *
c;
324 if ( minDistance == -1 || distance < minDistance )
326 minDistance = distance;
327 minIntersectionPt = intersectionPt;
332 if ( minDistance != -1 )
334 intPt = minIntersectionPt;
341bool DemTerrainTileGeometry::rayIntersection(
const QgsRay3D &ray,
const QgsRayCastContext &context,
const QMatrix4x4 &worldTransform, QVector3D &intersectionPoint )
343 return intersectionDemTriangles( mVertexBuffer->data(), mIndexBuffer->data(), ray, context, worldTransform, intersectionPoint );
346void DemTerrainTileGeometry::init()
348 mPositionAttribute =
new Qt3DCore::QAttribute(
this );
349 mNormalAttribute =
new Qt3DCore::QAttribute(
this );
350 mTexCoordAttribute =
new Qt3DCore::QAttribute(
this );
351 mIndexAttribute =
new Qt3DCore::QAttribute(
this );
352 mVertexBuffer =
new Qt3DCore::QBuffer(
this );
353 mIndexBuffer =
new Qt3DCore::QBuffer(
this );
355 int nVertsX = mResolution + 2;
356 int nVertsZ = mResolution + 2;
357 const int nVerts = nVertsX * nVertsZ;
358 const int stride = ( 3 + 2 + 3 ) *
sizeof(
float );
359 const int faces = 2 * ( nVertsX - 1 ) * ( nVertsZ - 1 );
361 mPositionAttribute->setName( Qt3DCore::QAttribute::defaultPositionAttributeName() );
362 mPositionAttribute->setVertexBaseType( Qt3DCore::QAttribute::Float );
363 mPositionAttribute->setVertexSize( 3 );
364 mPositionAttribute->setAttributeType( Qt3DCore::QAttribute::VertexAttribute );
365 mPositionAttribute->setBuffer( mVertexBuffer );
366 mPositionAttribute->setByteStride( stride );
367 mPositionAttribute->setCount( nVerts );
369 mTexCoordAttribute->setName( Qt3DCore::QAttribute::defaultTextureCoordinateAttributeName() );
370 mTexCoordAttribute->setVertexBaseType( Qt3DCore::QAttribute::Float );
371 mTexCoordAttribute->setVertexSize( 2 );
372 mTexCoordAttribute->setAttributeType( Qt3DCore::QAttribute::VertexAttribute );
373 mTexCoordAttribute->setBuffer( mVertexBuffer );
374 mTexCoordAttribute->setByteStride( stride );
375 mTexCoordAttribute->setByteOffset( 3 *
sizeof(
float ) );
376 mTexCoordAttribute->setCount( nVerts );
378 mNormalAttribute->setName( Qt3DCore::QAttribute::defaultNormalAttributeName() );
379 mNormalAttribute->setVertexBaseType( Qt3DCore::QAttribute::Float );
380 mNormalAttribute->setVertexSize( 3 );
381 mNormalAttribute->setAttributeType( Qt3DCore::QAttribute::VertexAttribute );
382 mNormalAttribute->setBuffer( mVertexBuffer );
383 mNormalAttribute->setByteStride( stride );
384 mNormalAttribute->setByteOffset( 5 *
sizeof(
float ) );
385 mNormalAttribute->setCount( nVerts );
387 mIndexAttribute->setAttributeType( Qt3DCore::QAttribute::IndexAttribute );
388 mIndexAttribute->setVertexBaseType( Qt3DCore::QAttribute::UnsignedInt );
389 mIndexAttribute->setBuffer( mIndexBuffer );
392 mIndexAttribute->setCount( faces * 3 );
397 mVertexBuffer->setData( PlaneVertexBufferFunctor( mResolution, mSide, mVertScale, mSkirtHeight, mHeightMap )() );
398 mIndexBuffer->setData( PlaneIndexBufferFunctor( mResolution, mHeightMap )() );
400 addAttribute( mPositionAttribute );
401 addAttribute( mTexCoordAttribute );
402 addAttribute( mNormalAttribute );
403 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)