22#include <Qt3DRender/QCamera>
23#include <Qt3DRender/QGeometryRenderer>
25#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
26#include <Qt3DRender/QAttribute>
27#include <Qt3DRender/QBuffer>
28#include <Qt3DRender/QGeometry>
33#include <Qt3DCore/QAttribute>
34#include <Qt3DCore/QBuffer>
35#include <Qt3DCore/QGeometry>
52 : m_direction( 0.0f, 0.0f, 1.0f )
56 Ray3D::Ray3D( QVector3D origin, QVector3D direction,
float distance )
58 , m_direction( direction )
59 , m_distance( distance )
62 QVector3D Ray3D::origin()
const
67 void Ray3D::setOrigin( QVector3D value )
72 QVector3D Ray3D::direction()
const
77 void Ray3D::setDirection( QVector3D value )
85 float Ray3D::distance()
const
90 void Ray3D::setDistance(
float distance )
92 m_distance = distance;
95 QVector3D Ray3D::point(
float t )
const
97 return m_origin + t * m_direction;
100 Ray3D &Ray3D::transform(
const QMatrix4x4 &matrix )
102 m_origin = matrix * m_origin;
103 m_direction = matrix.mapVector( m_direction );
108 Ray3D Ray3D::transformed(
const QMatrix4x4 &matrix )
const
110 return Ray3D( matrix * m_origin, matrix.mapVector( m_direction ) );
113 bool Ray3D::operator==(
const Ray3D &other )
const
115 return m_origin == other.origin() && m_direction == other.direction();
118 bool Ray3D::operator!=(
const Ray3D &other )
const
120 return !( *
this == other );
123 bool Ray3D::contains( QVector3D point )
const
125 const QVector3D ppVec( point - m_origin );
126 if ( ppVec.isNull() )
128 const float dot = QVector3D::dotProduct( ppVec, m_direction );
129 if ( qFuzzyIsNull( dot ) )
131 return qFuzzyCompare( dot * dot, ppVec.lengthSquared() * m_direction.lengthSquared() );
134 bool Ray3D::contains(
const Ray3D &ray )
const
136 const float dot = QVector3D::dotProduct( m_direction, ray.direction() );
137 if ( !qFuzzyCompare( dot * dot, m_direction.lengthSquared() * ray.direction().lengthSquared() ) )
139 return contains( ray.origin() );
142 float Ray3D::projectedDistance( QVector3D point )
const
144 Q_ASSERT( !m_direction.isNull() );
146 return QVector3D::dotProduct( point - m_origin, m_direction ) / m_direction.lengthSquared();
149 QVector3D Ray3D::project( QVector3D vector )
const
151 const QVector3D norm = m_direction.normalized();
152 return QVector3D::dotProduct( vector, norm ) * norm;
156 float Ray3D::distance( QVector3D point )
const
158 const float t = projectedDistance( point );
159 return ( point - ( m_origin + t * m_direction ) ).length();
162 QDebug
operator<<( QDebug dbg,
const Ray3D &ray )
164 const QDebugStateSaver saver( dbg );
165 dbg.nospace() <<
"QRay3D(origin("
166 << ray.origin().x() <<
", " << ray.origin().y() <<
", "
167 << ray.origin().z() <<
") - direction("
168 << ray.direction().x() <<
", " << ray.direction().y() <<
", "
169 << ray.direction().z() <<
"))";
196 ray(
double xO,
double yO,
double zO,
double xD,
double yD,
double zD )
204 dir_inv[0] = 1 / dir[0];
205 dir_inv[1] = 1 / dir[1];
206 dir_inv[2] = 1 / dir[2];
208 ray(
const QgsRayCastingUtils::Ray3D &r )
211 origin[0] = r.origin().x();
212 origin[1] = r.origin().y();
213 origin[2] = r.origin().z();
214 dir[0] = r.direction().x();
215 dir[1] = r.direction().y();
216 dir[2] = r.direction().z();
217 dir_inv[0] = 1 / dir[0];
218 dir_inv[1] = 1 / dir[1];
219 dir_inv[2] = 1 / dir[2];
229bool intersection(
const box &b,
const ray &r )
231 double t1 = ( b.min[0] - r.origin[0] ) * r.dir_inv[0];
232 double t2 = ( b.max[0] - r.origin[0] ) * r.dir_inv[0];
234 double tmin = std::min( t1, t2 );
235 double tmax = std::max( t1, t2 );
237 for (
int i = 1; i < 3; ++i )
239 t1 = ( b.min[i] - r.origin[i] ) * r.dir_inv[i];
240 t2 = ( b.max[i] - r.origin[i] ) * r.dir_inv[i];
242 tmin = std::max( tmin, std::min( std::min( t1, t2 ), tmax ) );
243 tmax = std::min( tmax, std::max( std::max( t1, t2 ), tmin ) );
246 return tmax > std::max( tmin, 0.0 );
253 bool rayBoxIntersection(
const Ray3D &r,
const QgsAABB &aabb )
258 if ( b.min[0] == b.max[0] )
260 if ( b.min[1] == b.max[1] )
262 if ( b.min[2] == b.max[2] )
265 return intersection( b, ray( r ) );
270 bool rayTriangleIntersection(
const Ray3D &ray, QVector3D a, QVector3D b, QVector3D
c, QVector3D &uvw,
float &t )
275 const QVector3D ab = b - a;
276 const QVector3D ac =
c - a;
277 const QVector3D qp = ( ray.origin() - ray.point( ray.distance() ) );
279 const QVector3D n = QVector3D::crossProduct( ab, ac );
280 const float d = QVector3D::dotProduct( qp, n );
282 if ( d <= 0.0f || std::isnan( d ) )
285 const QVector3D ap = ray.origin() - a;
286 t = QVector3D::dotProduct( ap, n );
288 if ( t < 0.0f || t > d )
291 const QVector3D e = QVector3D::crossProduct( qp, ap );
292 uvw.setY( QVector3D::dotProduct( ac, e ) );
294 if ( uvw.y() < 0.0f || uvw.y() > d )
297 uvw.setZ( -QVector3D::dotProduct( ab, e ) );
299 if ( uvw.z() < 0.0f || uvw.y() + uvw.z() > d )
302 const float ood = 1.0f / d;
304 uvw.setY( uvw.y() * ood );
305 uvw.setZ( uvw.z() * ood );
306 uvw.setX( 1.0f - uvw.y() - uvw.z() );
311 bool rayMeshIntersection( Qt3DRender::QGeometryRenderer *geometryRenderer,
const QgsRayCastingUtils::Ray3D &r,
const QMatrix4x4 &worldTransform, QVector3D &intPt,
int &triangleIndex )
313 if ( geometryRenderer->primitiveType() != Qt3DRender::QGeometryRenderer::Triangles )
315 QgsDebugError( QString(
"Unsupported primitive type for intersection: " ).arg( geometryRenderer->primitiveType() ) );
318 if ( geometryRenderer->instanceCount() != 1 || geometryRenderer->indexOffset() != 0 || geometryRenderer->indexBufferByteOffset() != 0 || geometryRenderer->firstVertex() != 0 || geometryRenderer->firstInstance() != 0 )
320 QgsDebugError( QString(
"Unsupported geometry renderer for intersection." ) );
330 if ( attr->name() == Qt3DQAttribute::defaultPositionAttributeName() )
334 else if ( attr->attributeType() == Qt3DQAttribute::IndexAttribute )
346 if ( positionAttr->vertexBaseType() != Qt3DQAttribute::Float || positionAttr->vertexSize() != 3 )
348 QgsDebugError( QString(
"Unsupported position attribute: base type %1, vertex size %2" ).arg( positionAttr->vertexBaseType() ).arg( positionAttr->vertexSize() ) );
352 const QByteArray vertexBuf = positionAttr->buffer()->data();
353 const char *vertexPtr = vertexBuf.constData();
354 vertexPtr += positionAttr->byteOffset();
355 int vertexByteStride = positionAttr->byteStride() == 0 ? 3 *
sizeof( float ) : positionAttr->byteStride();
357 const uchar *indexPtrUChar =
nullptr;
358 const ushort *indexPtrUShort =
nullptr;
359 const uint *indexPtrUInt =
nullptr;
362 if ( indexAttr->byteStride() != 0 || indexAttr->vertexSize() != 1 )
364 QgsDebugError( QString(
"Unsupported index attribute: stride %1, vertex size %2" ).arg( indexAttr->byteStride() ).arg( indexAttr->vertexSize() ) );
368 const QByteArray indexBuf = indexAttr->buffer()->data();
369 if ( indexAttr->vertexBaseType() == Qt3DQAttribute::UnsignedByte )
371 indexPtrUChar =
reinterpret_cast<const uchar *
>( indexBuf.constData() + indexAttr->byteOffset() );
373 else if ( indexAttr->vertexBaseType() == Qt3DQAttribute::UnsignedShort )
375 indexPtrUShort =
reinterpret_cast<const ushort *
>( indexBuf.constData() + indexAttr->byteOffset() );
377 else if ( indexAttr->vertexBaseType() == Qt3DQAttribute::UnsignedInt )
379 indexPtrUInt =
reinterpret_cast<const uint *
>( indexBuf.constData() + indexAttr->byteOffset() );
383 QgsDebugError( QString(
"Unsupported index attribute: base type %1" ).arg( indexAttr->vertexBaseType() ) );
388 int vertexCount = geometryRenderer->vertexCount();
389 if ( vertexCount == 0 && indexAttr )
391 vertexCount = indexAttr->count();
393 if ( vertexCount == 0 )
395 vertexCount = positionAttr->count();
398 QVector3D intersectionPt, minIntersectionPt;
399 float minDistance = -1;
401 for (
int i = 0; i < vertexCount; i += 3 )
403 int v0index = 0, v1index = 0, v2index = 0;
410 else if ( indexPtrUShort )
412 v0index = indexPtrUShort[i];
413 v1index = indexPtrUShort[i + 1];
414 v2index = indexPtrUShort[i + 2];
416 else if ( indexPtrUChar )
418 v0index = indexPtrUChar[i];
419 v1index = indexPtrUChar[i + 1];
420 v2index = indexPtrUChar[i + 2];
422 else if ( indexPtrUInt )
424 v0index = indexPtrUInt[i];
425 v1index = indexPtrUInt[i + 1];
426 v2index = indexPtrUInt[i + 2];
431 const float *v0ptr =
reinterpret_cast<const float *
>( vertexPtr + v0index * vertexByteStride );
432 const float *v1ptr =
reinterpret_cast<const float *
>( vertexPtr + v1index * vertexByteStride );
433 const float *v2ptr =
reinterpret_cast<const float *
>( vertexPtr + v2index * vertexByteStride );
435 const QVector3D a( v0ptr[0], v0ptr[1], v0ptr[2] );
436 const QVector3D b( v1ptr[0], v1ptr[1], v1ptr[2] );
437 const QVector3D
c( v2ptr[0], v2ptr[1], v2ptr[2] );
442 const QVector3D tA = worldTransform * a;
443 const QVector3D tB = worldTransform * b;
444 const QVector3D tC = worldTransform *
c;
452 if ( QgsRayCastingUtils::rayTriangleIntersection( r, tA, tB, tC, uvw, t ) || QgsRayCastingUtils::rayTriangleIntersection( r, tA, tC, tB, uvw, t ) )
454 intersectionPt = r.point( t * r.distance() );
455 const float distance = r.projectedDistance( intersectionPt );
458 if ( minDistance == -1 || distance < minDistance )
460 triangleIndex =
static_cast<int>( i / 3 );
461 minDistance = distance;
462 minIntersectionPt = intersectionPt;
467 if ( minDistance != -1 )
469 intPt = minIntersectionPt;
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
Qt3DCore::QAttribute Qt3DQAttribute
Qt3DCore::QGeometry Qt3DQGeometry
QDataStream & operator<<(QDataStream &out, const QgsFeature &feature)
Writes the feature to stream out. QGIS version compatibility is not guaranteed.
#define QgsDebugError(str)
Qt3DCore::QAttribute Qt3DQAttribute
Qt3DCore::QBuffer Qt3DQBuffer
Qt3DCore::QGeometry Qt3DQGeometry