/*! Returns true if \a ray lies on this ray; false otherwise. If true, this implies that the two rays are the actually the same, but with different origin() points or an inverted direction(). */ bool QRay3D::contains(const QRay3D &ray) const { qreal dot = QVector3D::dotProduct(m_direction, ray.direction()); if (!qFuzzyCompare(dot*dot, m_direction.lengthSquared() * ray.direction().lengthSquared())) return false; return contains(ray.origin()); }
/*! Finds the \a minimum_t and \a maximum_t values where \a ray intersects this sphere. Returns true if intersections were found; or false if there is no intersection. If \a minimum_t and \a maximum_t are set to the same value, then \a ray touches the surface of the sphere at a single point. If the t values are negative, then the intersection occurs before the ray's origin point in the reverse direction of the ray. The \a minimum_t and \a maximum_t values can be passed to QRay3D::point() to determine the actual intersection points, as shown in the following example: \code qreal minimum_t, maximum_t; if (sphere.intersection(ray, &minimum_t, &maximum_t)) { qDebug() << "intersections at" << ray.point(minimum_t) << "and" << ray.point(maximum_t); } \endcode \sa intersects(), QRay3D::point() */ bool QSphere3D::intersection(const QRay3D &ray, qreal *minimum_t, qreal *maximum_t) const { QVector3D centerToOrigin = ray.origin() - m_center; qreal term1 = ray.direction().lengthSquared(); qreal term2 = 2.0f * QVector3D::dotProduct(centerToOrigin, ray.direction()); qreal term3 = centerToOrigin.lengthSquared() - m_radius * m_radius; qreal det = term2 * term2 - (4.0f * term1 * term3); if (term1 == 0.0f || det < 0.0f) { *minimum_t = qSNaN(); *maximum_t = qSNaN(); return false; } else if (det == 0.0f) { *minimum_t = *maximum_t = -term2 / (2.0f * term1); } else { qreal sqrtDet = qSqrt(det); qreal t1 = (-term2 - sqrtDet) / (2.0f * term1); qreal t2 = (-term2 + sqrtDet) / (2.0f * term1); if (t1 < t2) { *minimum_t = t1; *maximum_t = t2; } else { *minimum_t = t2; *maximum_t = t1; } } return true; }
QDebug operator<<(QDebug dbg, const QRay3D &ray) { dbg.nospace() << "QRay3D(origin(" << ray.origin().x() << ", " << ray.origin().y() << ", " << ray.origin().z() << ") - direction(" << ray.direction().x() << ", " << ray.direction().y() << ", " << ray.direction().z() << "))"; return dbg.space(); }
/*! Returns the t value at which \a ray intersects this triangle, or not-a-number if there is no intersection. When the \a ray intersects this triangle, the return value is a parametric value that can be passed to QRay3D::point() to determine the actual intersection point, as shown in the following example: \code float t = triangle.intersection(ray); QVector3D pt; if (qIsNaN(t)) { qWarning("no intersection occurred"); else pt = ray.point(t); \endcode \sa intersects(), contains(), QRay3D::point() */ float QTriangle3D::intersection(const QRay3D &ray) const { float t = plane().intersection(ray); if (qIsNaN(t) || contains(ray.point(t))) return t; return qSNaN(); }
/*! Returns true if the \a ray intersects this triangle; false otherwise. This function will return false if the triangle is degenerate. \sa contains(), intersection() */ bool QTriangle3D::intersects(const QRay3D &ray) const { float t = plane().intersection(ray); if (qIsNaN(t)) return false; return uvInTriangle(uv(ray.point(t))); }
/*! Returns true if the \a ray intersects this triangle; false otherwise. This function will return false if the triangle is degenerate. \sa contains(), intersection() */ bool QTriangle3D::intersects(const QRay3D &ray) const { qreal t = plane().intersection(ray); if (qIsNaN(t)) return false; return contains(ray.point(t)); }
// Test getting and setting properties via the metaobject system. void tst_QRay3D::properties() { tst_QRay3DProperties obj; qRegisterMetaType<QRay3D>(); obj.setRay(QRay3D(QVector3D(1, 2, 3), QVector3D(4, 5, 6))); QRay3D r = qvariant_cast<QRay3D>(obj.property("ray")); QCOMPARE(r.origin(), QVector3D(1, 2, 3)); QCOMPARE(r.direction(), QVector3D(4, 5, 6)); obj.setProperty("ray", qVariantFromValue (QRay3D(QVector3D(-1, -2, -3), QVector3D(-4, -5, -6)))); r = qvariant_cast<QRay3D>(obj.property("ray")); QCOMPARE(r.origin(), QVector3D(-1, -2, -3)); QCOMPARE(r.direction(), QVector3D(-4, -5, -6)); }
QT_BEGIN_NAMESPACE /*! \class QSphere3D \brief The QSphere3D class represents a mathematical sphere in 3D space. \since 4.8 \ingroup qt3d \ingroup qt3d::math QSphere3D can be used to represent the bounding regions of objects in a 3D scene so that they can be easily culled if they are out of view. It can also be used to assist with collision testing. \sa QBox3D */ /*! \fn QSphere3D::QSphere3D() Constructs a default sphere with a center() of (0, 0, 0) and radius() of 1. */ /*! \fn QSphere3D::QSphere3D(const QVector3D ¢er, qreal radius) Constructs a sphere with the specified \a center and \a radius. */ /*! \fn QVector3D QSphere3D::center() const Returns the center of this sphere. \sa setCenter(), radius() */ /*! \fn void QSphere3D::setCenter(const QVector3D ¢er) Sets the \a center of this sphere. \sa center(), setRadius() */ /*! \fn qreal QSphere3D::radius() const Returns the radius of this sphere. \sa setRadius(), center() */ /*! \fn void QSphere3D::setRadius(qreal radius) Sets the \a radius of this sphere. \sa radius(), setCenter() */ /*! \fn bool QSphere3D::contains(const QVector3D &point) const Returns true if \a point is contained within the bounds of this sphere; false otherwise. */ /*! Returns true if this sphere intersects \a ray; false otherwise. \sa intersection() */ bool QSphere3D::intersects(const QRay3D &ray) const { QVector3D centerToOrigin = ray.origin() - m_center; qreal term1 = ray.direction().lengthSquared(); qreal term2 = 2.0f * QVector3D::dotProduct(centerToOrigin, ray.direction()); qreal term3 = centerToOrigin.lengthSquared() - m_radius * m_radius; qreal det = term2 * term2 - (4.0f * term1 * term3); return term1 != 0.0f && det >= 0.0f; }
qreal QGLBezierPatch::intersection (qreal result, int depth, const QRay3D& ray, bool anyIntersection, qreal xtex, qreal ytex, qreal wtex, qreal htex, QVector2D *tc) { // Check the convex hull of the patch for an intersection. // If no intersection with the convex hull, then there is // no point subdividing this patch further. QBox3D box; for (int point = 0; point < 16; ++point) box.unite(points[point]); if (!box.intersects(ray)) return result; // Are we at the lowest point of subdivision yet? if (depth <= 1) { // Divide the patch into two triangles and intersect with those. QTriangle3D triangle1(points[0], points[3], points[12]); qreal t = triangle1.intersection(ray); if (!qIsNaN(t)) { result = combineResults(result, t); if (result == t) { QVector2D uv = triangle1.uv(ray.point(t)); QVector2D tp(xtex, ytex); QVector2D tq(xtex + wtex, ytex); QVector2D tr(xtex, ytex + htex); *tc = uv.x() * tp + uv.y() * tq + (1 - uv.x() - uv.y()) * tr; } } else { QTriangle3D triangle2(points[3], points[15], points[12]); qreal t = triangle2.intersection(ray); if (!qIsNaN(t)) { result = combineResults(result, t); if (result == t) { QVector2D uv = triangle2.uv(ray.point(t)); QVector2D tp(xtex + wtex, ytex); QVector2D tq(xtex + wtex, ytex + htex); QVector2D tr(xtex, ytex + htex); *tc = uv.x() * tp + uv.y() * tq + (1 - uv.x() - uv.y()) * tr; } } } } else { // Subdivide the patch to find the point of intersection. QGLBezierPatch patch1, patch2, patch3, patch4; subDivide(patch1, patch2, patch3, patch4); --depth; qreal hwtex = wtex / 2.0f; qreal hhtex = htex / 2.0f; result = patch1.intersection (result, depth, ray, anyIntersection, xtex, ytex, hwtex, hhtex, tc); if (anyIntersection && !qIsNaN(result)) return result; result = patch2.intersection (result, depth, ray, anyIntersection, xtex + hwtex, ytex, hwtex, hhtex, tc); if (anyIntersection && !qIsNaN(result)) return result; result = patch3.intersection (result, depth, ray, anyIntersection, xtex, ytex + hhtex, hwtex, hhtex, tc); if (anyIntersection && !qIsNaN(result)) return result; result = patch4.intersection (result, depth, ray, anyIntersection, xtex + hwtex, ytex + hhtex, hwtex, hhtex, tc); } return result; }