22#include <Qt3DCore/QAttribute>
23#include <Qt3DCore/QBuffer>
24#include <Qt3DCore/QGeometry>
25#include <Qt3DRender/QGeometryRenderer>
39 double boxXMax = nodeBbox.
xMax;
40 double boxYMax = nodeBbox.
yMax;
41 double boxZMax = nodeBbox.
zMax;
44 if ( boxXMax == nodeBbox.
xMin )
46 if ( boxYMax == nodeBbox.
yMin )
48 if ( boxZMax == nodeBbox.
zMin )
52 double t1 = ( nodeBbox.
xMin - ray.
origin().x() ) * dirInv.x();
53 double t2 = ( boxXMax - ray.
origin().x() ) * dirInv.x();
54 double tmin = std::min( t1, t2 );
55 double tmax = std::max( t1, t2 );
57 t1 = ( nodeBbox.
yMin - ray.
origin().y() ) * dirInv.y();
58 t2 = ( boxYMax - ray.
origin().y() ) * dirInv.y();
59 tmin = std::max( tmin, std::min( std::min( t1, t2 ), tmax ) );
60 tmax = std::min( tmax, std::max( std::max( t1, t2 ), tmin ) );
62 t1 = ( nodeBbox.
zMin - ray.
origin().z() ) * dirInv.z();
63 t2 = ( boxZMax - ray.
origin().z() ) * dirInv.z();
64 tmin = std::max( tmin, std::min( std::min( t1, t2 ), tmax ) );
65 tmax = std::min( tmax, std::max( std::max( t1, t2 ), tmin ) );
67 return tmax > std::max( tmin, 0.0 );
73 bool rayTriangleIntersection(
const QgsRay3D &ray,
float maxDist,
const QVector3D &a,
const QVector3D &b,
const QVector3D &
c, QVector3D &uvw,
float &t )
78 const QVector3D ab = b - a;
79 const QVector3D ac =
c - a;
80 const QVector3D qp = ( ray.
origin() - ray.
point( maxDist ) );
82 const QVector3D n = QVector3D::crossProduct( ab, ac );
83 const float d = QVector3D::dotProduct( qp, n );
85 if ( d <= 0.0f || std::isnan( d ) )
88 const QVector3D ap = ray.
origin() - a;
89 t = QVector3D::dotProduct( ap, n );
91 if ( t < 0.0f || t > d )
94 const QVector3D e = QVector3D::crossProduct( qp, ap );
95 uvw.setY( QVector3D::dotProduct( ac, e ) );
97 if ( uvw.y() < 0.0f || uvw.y() > d )
100 uvw.setZ( -QVector3D::dotProduct( ab, e ) );
102 if ( uvw.z() < 0.0f || uvw.y() + uvw.z() > d )
105 const float ood = 1.0f / d;
107 uvw.setY( uvw.y() * ood );
108 uvw.setZ( uvw.z() * ood );
109 uvw.setX( 1.0f - uvw.y() - uvw.z() );
114 bool rayMeshIntersection( Qt3DRender::QGeometryRenderer *geometryRenderer,
const QgsRay3D &r,
float maxDist,
const QMatrix4x4 &worldTransform, QVector3D &intPt,
int &triangleIndex )
116 if ( geometryRenderer->primitiveType() != Qt3DRender::QGeometryRenderer::Triangles )
118 QgsDebugError( QString(
"Unsupported primitive type for intersection: " ).arg( geometryRenderer->primitiveType() ) );
121 if ( geometryRenderer->instanceCount() != 1
122 || geometryRenderer->indexOffset() != 0
123 || geometryRenderer->indexBufferByteOffset() != 0
124 || geometryRenderer->firstVertex() != 0
125 || geometryRenderer->firstInstance() != 0 )
127 QgsDebugError( QString(
"Unsupported geometry renderer for intersection." ) );
131 Qt3DCore::QGeometry *geometry = geometryRenderer->geometry();
133 Qt3DCore::QAttribute *positionAttr =
nullptr;
134 Qt3DCore::QAttribute *indexAttr =
nullptr;
135 for ( Qt3DCore::QAttribute *attr : geometry->attributes() )
137 if ( attr->name() == Qt3DCore::QAttribute::defaultPositionAttributeName() )
141 else if ( attr->attributeType() == Qt3DCore::QAttribute::IndexAttribute )
153 if ( positionAttr->vertexBaseType() != Qt3DCore::QAttribute::Float || positionAttr->vertexSize() != 3 )
155 QgsDebugError( QString(
"Unsupported position attribute: base type %1, vertex size %2" ).arg( positionAttr->vertexBaseType() ).arg( positionAttr->vertexSize() ) );
159 const QByteArray vertexBuf = positionAttr->buffer()->data();
160 const char *vertexPtr = vertexBuf.constData();
161 vertexPtr += positionAttr->byteOffset();
162 int vertexByteStride = positionAttr->byteStride() == 0 ? 3 *
sizeof( float ) : positionAttr->byteStride();
164 const uchar *indexPtrUChar =
nullptr;
165 const ushort *indexPtrUShort =
nullptr;
166 const uint *indexPtrUInt =
nullptr;
169 if ( indexAttr->byteStride() != 0 || indexAttr->vertexSize() != 1 )
171 QgsDebugError( QString(
"Unsupported index attribute: stride %1, vertex size %2" ).arg( indexAttr->byteStride() ).arg( indexAttr->vertexSize() ) );
175 const QByteArray indexBuf = indexAttr->buffer()->data();
176 if ( indexAttr->vertexBaseType() == Qt3DCore::QAttribute::UnsignedByte )
178 indexPtrUChar =
reinterpret_cast<const uchar *
>( indexBuf.constData() + indexAttr->byteOffset() );
180 else if ( indexAttr->vertexBaseType() == Qt3DCore::QAttribute::UnsignedShort )
182 indexPtrUShort =
reinterpret_cast<const ushort *
>( indexBuf.constData() + indexAttr->byteOffset() );
184 else if ( indexAttr->vertexBaseType() == Qt3DCore::QAttribute::UnsignedInt )
186 indexPtrUInt =
reinterpret_cast<const uint *
>( indexBuf.constData() + indexAttr->byteOffset() );
190 QgsDebugError( QString(
"Unsupported index attribute: base type %1" ).arg( indexAttr->vertexBaseType() ) );
195 int vertexCount = geometryRenderer->vertexCount();
196 if ( vertexCount == 0 && indexAttr )
198 vertexCount = indexAttr->count();
200 if ( vertexCount == 0 )
202 vertexCount = positionAttr->count();
205 QVector3D intersectionPt, minIntersectionPt;
206 float minDistance = -1;
208 for (
int i = 0; i < vertexCount; i += 3 )
210 int v0index = 0, v1index = 0, v2index = 0;
217 else if ( indexPtrUShort )
219 v0index = indexPtrUShort[i];
220 v1index = indexPtrUShort[i + 1];
221 v2index = indexPtrUShort[i + 2];
223 else if ( indexPtrUChar )
225 v0index = indexPtrUChar[i];
226 v1index = indexPtrUChar[i + 1];
227 v2index = indexPtrUChar[i + 2];
229 else if ( indexPtrUInt )
231 v0index = indexPtrUInt[i];
232 v1index = indexPtrUInt[i + 1];
233 v2index = indexPtrUInt[i + 2];
238 const float *v0ptr =
reinterpret_cast<const float *
>( vertexPtr + v0index * vertexByteStride );
239 const float *v1ptr =
reinterpret_cast<const float *
>( vertexPtr + v1index * vertexByteStride );
240 const float *v2ptr =
reinterpret_cast<const float *
>( vertexPtr + v2index * vertexByteStride );
242 const QVector3D a( v0ptr[0], v0ptr[1], v0ptr[2] );
243 const QVector3D b( v1ptr[0], v1ptr[1], v1ptr[2] );
244 const QVector3D
c( v2ptr[0], v2ptr[1], v2ptr[2] );
249 const QVector3D tA = worldTransform * a;
250 const QVector3D tB = worldTransform * b;
251 const QVector3D tC = worldTransform *
c;
259 if (
QgsRayCastingUtils::rayTriangleIntersection( r, maxDist, tA, tB, tC, uvw, t ) ||
QgsRayCastingUtils::rayTriangleIntersection( r, maxDist, tA, tC, tB, uvw, t ) )
261 intersectionPt = r.
point( t * maxDist );
265 if ( minDistance == -1 || distance < minDistance )
267 triangleIndex =
static_cast<int>( i / 3 );
268 minDistance = distance;
269 minIntersectionPt = intersectionPt;
274 if ( minDistance != -1 )
276 intPt = minIntersectionPt;
float projectedDistance(const QVector3D &point) const
Returns the distance of the projection of a point to the ray.
QVector3D origin() const
Returns the origin of the ray.
QVector3D directionInversed() const
Returns a vector with the direction components inversed ( 1/x, 1/y, 1/z) This can be used as an optim...
QVector3D point(float distance) const
Returns the point along the ray with the specified distance from the ray's origin.
bool rayBoxIntersection(const QgsRay3D &ray, const QgsAABB &nodeBbox)
Tests whether an axis aligned box is intersected by a ray.
bool rayMeshIntersection(Qt3DRender::QGeometryRenderer *geometryRenderer, const QgsRay3D &r, float maxDist, const QMatrix4x4 &worldTransform, QVector3D &intPt, int &triangleIndex)
Tests whether a triangular mesh is intersected by 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 QgsDebugError(str)