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 ) /
147 m_direction.lengthSquared();
150 QVector3D Ray3D::project( QVector3D vector )
const
152 const QVector3D norm = m_direction.normalized();
153 return QVector3D::dotProduct( vector, norm ) * norm;
157 float Ray3D::distance( QVector3D point )
const
159 const float t = projectedDistance( point );
160 return ( point - ( m_origin + t * m_direction ) ).length();
163 QDebug
operator<<( QDebug dbg,
const Ray3D &ray )
165 const QDebugStateSaver saver( dbg );
166 dbg.nospace() <<
"QRay3D(origin("
167 << ray.origin().x() <<
", " << ray.origin().y() <<
", "
168 << ray.origin().z() <<
") - direction("
169 << ray.direction().x() <<
", " << ray.direction().y() <<
", "
170 << ray.direction().z() <<
"))";
193 ray(
double xO,
double yO,
double zO,
double xD,
double yD,
double zD )
195 origin[0] = xO; origin[1] = yO; origin[2] = zO;
196 dir[0] = xD; dir[1] = yD; dir[2] = zD;
197 dir_inv[0] = 1 / dir[0]; dir_inv[1] = 1 / dir[1]; dir_inv[2] = 1 / dir[2];
199 ray(
const QgsRayCastingUtils::Ray3D &r )
202 origin[0] = r.origin().x(); origin[1] = r.origin().y(); origin[2] = r.origin().z();
203 dir[0] = r.direction().x(); dir[1] = r.direction().y(); dir[2] = r.direction().z();
204 dir_inv[0] = 1 / dir[0]; dir_inv[1] = 1 / dir[1]; dir_inv[2] = 1 / dir[2];
214bool intersection(
const box &b,
const ray &r )
216 double t1 = ( b.min[0] - r.origin[0] ) * r.dir_inv[0];
217 double t2 = ( b.max[0] - r.origin[0] ) * r.dir_inv[0];
219 double tmin = std::min( t1, t2 );
220 double tmax = std::max( t1, t2 );
222 for (
int i = 1; i < 3; ++i )
224 t1 = ( b.min[i] - r.origin[i] ) * r.dir_inv[i];
225 t2 = ( b.max[i] - r.origin[i] ) * r.dir_inv[i];
227 tmin = std::max( tmin, std::min( std::min( t1, t2 ), tmax ) );
228 tmax = std::min( tmax, std::max( std::max( t1, t2 ), tmin ) );
231 return tmax > std::max( tmin, 0.0 );
238 bool rayBoxIntersection(
const Ray3D &r,
const QgsAABB &aabb )
243 if ( b.min[0] == b.max[0] ) b.max[0] += 0.1;
244 if ( b.min[1] == b.max[1] ) b.max[1] += 0.1;
245 if ( b.min[2] == b.max[2] ) b.max[2] += 0.1;
247 return intersection( b, ray( r ) );
252 bool rayTriangleIntersection(
const Ray3D &ray,
262 const QVector3D ab = b - a;
263 const QVector3D ac =
c - a;
264 const QVector3D qp = ( ray.origin() - ray.point( ray.distance() ) );
266 const QVector3D n = QVector3D::crossProduct( ab, ac );
267 const float d = QVector3D::dotProduct( qp, n );
269 if ( d <= 0.0f || std::isnan( d ) )
272 const QVector3D ap = ray.origin() - a;
273 t = QVector3D::dotProduct( ap, n );
275 if ( t < 0.0f || t > d )
278 const QVector3D e = QVector3D::crossProduct( qp, ap );
279 uvw.setY( QVector3D::dotProduct( ac, e ) );
281 if ( uvw.y() < 0.0f || uvw.y() > d )
284 uvw.setZ( -QVector3D::dotProduct( ab, e ) );
286 if ( uvw.z() < 0.0f || uvw.y() + uvw.z() > d )
289 const float ood = 1.0f / d;
291 uvw.setY( uvw.y() * ood );
292 uvw.setZ( uvw.z() * ood );
293 uvw.setX( 1.0f - uvw.y() - uvw.z() );
298 bool rayMeshIntersection( Qt3DRender::QGeometryRenderer *geometryRenderer,
299 const QgsRayCastingUtils::Ray3D &r,
300 const QMatrix4x4 &worldTransform,
304 if ( geometryRenderer->primitiveType() != Qt3DRender::QGeometryRenderer::Triangles )
306 QgsDebugError( QString(
"Unsupported primitive type for intersection: " ).arg( geometryRenderer->primitiveType() ) );
309 if ( geometryRenderer->instanceCount() != 1 || geometryRenderer->indexOffset() != 0 || geometryRenderer->indexBufferByteOffset() != 0 || geometryRenderer->firstVertex() != 0 || geometryRenderer->firstInstance() != 0 )
311 QgsDebugError( QString(
"Unsupported geometry renderer for intersection." ) );
321 if ( attr->name() == Qt3DQAttribute::defaultPositionAttributeName() )
325 else if ( attr->attributeType() == Qt3DQAttribute::IndexAttribute )
337 if ( positionAttr->vertexBaseType() != Qt3DQAttribute::Float || positionAttr->vertexSize() != 3 )
339 QgsDebugError( QString(
"Unsupported position attribute: base type %1, vertex size %2" ). arg( positionAttr->vertexBaseType() ).arg( positionAttr->vertexSize() ) );
343 const QByteArray vertexBuf = positionAttr->buffer()->data();
344 const char *vertexPtr = vertexBuf.constData();
345 vertexPtr += positionAttr->byteOffset();
346 int vertexByteStride = positionAttr->byteStride() == 0 ? 3 *
sizeof( float ) : positionAttr->byteStride();
348 const uchar *indexPtrUChar =
nullptr;
349 const ushort *indexPtrUShort =
nullptr;
350 const uint *indexPtrUInt =
nullptr;
353 if ( indexAttr->byteStride() != 0 || indexAttr->vertexSize() != 1 )
355 QgsDebugError( QString(
"Unsupported index attribute: stride %1, vertex size %2" ).arg( indexAttr->byteStride() ).arg( indexAttr->vertexSize() ) );
359 const QByteArray indexBuf = indexAttr->buffer()->data();
360 if ( indexAttr->vertexBaseType() == Qt3DQAttribute::UnsignedByte )
362 indexPtrUChar =
reinterpret_cast<const uchar *
>( indexBuf.constData() + indexAttr->byteOffset() );
364 else if ( indexAttr->vertexBaseType() == Qt3DQAttribute::UnsignedShort )
366 indexPtrUShort =
reinterpret_cast<const ushort *
>( indexBuf.constData() + indexAttr->byteOffset() );
368 else if ( indexAttr->vertexBaseType() == Qt3DQAttribute::UnsignedInt )
370 indexPtrUInt =
reinterpret_cast<const uint *
>( indexBuf.constData() + indexAttr->byteOffset() );
374 QgsDebugError( QString(
"Unsupported index attribute: base type %1" ).arg( indexAttr->vertexBaseType() ) );
379 int vertexCount = geometryRenderer->vertexCount();
380 if ( vertexCount == 0 && indexAttr )
382 vertexCount = indexAttr->count();
384 if ( vertexCount == 0 )
386 vertexCount = positionAttr->count();
389 QVector3D intersectionPt, minIntersectionPt;
390 float minDistance = -1;
392 for (
int i = 0; i < vertexCount; i += 3 )
394 int v0index = 0, v1index = 0, v2index = 0;
401 else if ( indexPtrUShort )
403 v0index = indexPtrUShort[i];
404 v1index = indexPtrUShort[i + 1];
405 v2index = indexPtrUShort[i + 2];
407 else if ( indexPtrUChar )
409 v0index = indexPtrUChar[i];
410 v1index = indexPtrUChar[i + 1];
411 v2index = indexPtrUChar[i + 2];
413 else if ( indexPtrUInt )
415 v0index = indexPtrUInt[i];
416 v1index = indexPtrUInt[i + 1];
417 v2index = indexPtrUInt[i + 2];
422 const float *v0ptr =
reinterpret_cast<const float *
>( vertexPtr + v0index * vertexByteStride );
423 const float *v1ptr =
reinterpret_cast<const float *
>( vertexPtr + v1index * vertexByteStride );
424 const float *v2ptr =
reinterpret_cast<const float *
>( vertexPtr + v2index * vertexByteStride );
426 const QVector3D a( v0ptr[0], v0ptr[1], v0ptr[2] );
427 const QVector3D b( v1ptr[0], v1ptr[1], v1ptr[2] );
428 const QVector3D
c( v2ptr[0], v2ptr[1], v2ptr[2] );
433 const QVector3D tA = worldTransform * a;
434 const QVector3D tB = worldTransform * b;
435 const QVector3D tC = worldTransform *
c;
443 if ( QgsRayCastingUtils::rayTriangleIntersection( r, tA, tB, tC, uvw, t ) ||
444 QgsRayCastingUtils::rayTriangleIntersection( r, tA, tC, tB, uvw, t ) )
446 intersectionPt = r.point( t * r.distance() );
447 const float distance = r.projectedDistance( intersectionPt );
450 if ( minDistance == -1 || distance < minDistance )
452 triangleIndex =
static_cast<int>( i / 3 );
453 minDistance = distance;
454 minIntersectionPt = intersectionPt;
459 if ( minDistance != -1 )
461 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