// // SPDX-License-Identifier: BSD-3-Clause // Copyright Contributors to the OpenEXR Project. // // // A 3D plane class template // #ifndef INCLUDED_IMATHPLANE_H #define INCLUDED_IMATHPLANE_H #include "ImathExport.h" #include "ImathNamespace.h" #include "ImathLine.h" #include "ImathVec.h" IMATH_INTERNAL_NAMESPACE_HEADER_ENTER /// /// The `Plane3` class represents a half space in 3D, so the normal /// may point either towards or away from origin. The plane `P` can /// be represented by Plane3 as either `p` or `-p` corresponding to /// the two half-spaces on either side of the plane. Any function /// which computes a distance will return either negative or positive /// values for the distance indicating which half-space the point is /// in. Note that reflection, and intersection functions will operate /// as expected. template class IMATH_EXPORT_TEMPLATE_TYPE Plane3 { public: /// @{ /// @name Direct access to member fields /// The normal to the plane Vec3 normal; /// The distance from the origin to the plane T distance; /// @} /// @{ /// @name Constructors /// Uninitialized by default IMATH_HOSTDEVICE Plane3() IMATH_NOEXCEPT {} /// Initialize with a normal and distance IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Plane3 (const Vec3& normal, T distance) IMATH_NOEXCEPT; /// Initialize with a point and a normal IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Plane3 (const Vec3& point, const Vec3& normal) IMATH_NOEXCEPT; /// Initialize with three points IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Plane3 (const Vec3& point1, const Vec3& point2, const Vec3& point3) IMATH_NOEXCEPT; /// @} /// @{ /// @name Manipulation /// Set via a given normal and distance IMATH_HOSTDEVICE void set (const Vec3& normal, T distance) IMATH_NOEXCEPT; /// Set via a given point and normal IMATH_HOSTDEVICE void set (const Vec3& point, const Vec3& normal) IMATH_NOEXCEPT; /// Set via three points IMATH_HOSTDEVICE void set (const Vec3& point1, const Vec3& point2, const Vec3& point3) IMATH_NOEXCEPT; /// @} /// @{ /// @name Utility Methods /// Determine if a line intersects the plane. /// @param line The line /// @param[out] intersection The point of intersection /// @return True if the line intersects the plane. IMATH_HOSTDEVICE IMATH_CONSTEXPR14 bool intersect (const Line3& line, Vec3& intersection) const IMATH_NOEXCEPT; /// Determine if a line intersects the plane. /// @param line The line /// @param[out] parameter The parametric value of the point of intersection /// @return True if the line intersects the plane. IMATH_HOSTDEVICE IMATH_CONSTEXPR14 bool intersectT (const Line3& line, T& parameter) const IMATH_NOEXCEPT; /// Return the distance from a point to the plane. IMATH_HOSTDEVICE constexpr T distanceTo (const Vec3& point) const IMATH_NOEXCEPT; /// Reflect the given point around the plane. IMATH_HOSTDEVICE constexpr Vec3 reflectPoint (const Vec3& point) const IMATH_NOEXCEPT; /// Reflect the direction vector around the plane IMATH_HOSTDEVICE constexpr Vec3 reflectVector (const Vec3& vec) const IMATH_NOEXCEPT; /// @} }; /// Plane of type float typedef Plane3 Plane3f; /// Plane of type double typedef Plane3 Plane3d; //--------------- // Implementation //--------------- template IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Plane3::Plane3 (const Vec3& p0, const Vec3& p1, const Vec3& p2) IMATH_NOEXCEPT { set (p0, p1, p2); } template IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Plane3::Plane3 (const Vec3& n, T d) IMATH_NOEXCEPT { set (n, d); } template IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Plane3::Plane3 (const Vec3& p, const Vec3& n) IMATH_NOEXCEPT { set (p, n); } template IMATH_HOSTDEVICE inline void Plane3::set (const Vec3& point1, const Vec3& point2, const Vec3& point3) IMATH_NOEXCEPT { normal = (point2 - point1) % (point3 - point1); normal.normalize(); distance = normal ^ point1; } template IMATH_HOSTDEVICE inline void Plane3::set (const Vec3& point, const Vec3& n) IMATH_NOEXCEPT { normal = n; normal.normalize(); distance = normal ^ point; } template IMATH_HOSTDEVICE inline void Plane3::set (const Vec3& n, T d) IMATH_NOEXCEPT { normal = n; normal.normalize(); distance = d; } template IMATH_HOSTDEVICE constexpr inline T Plane3::distanceTo (const Vec3& point) const IMATH_NOEXCEPT { return (point ^ normal) - distance; } template IMATH_HOSTDEVICE constexpr inline Vec3 Plane3::reflectPoint (const Vec3& point) const IMATH_NOEXCEPT { return normal * distanceTo (point) * -2.0 + point; } template IMATH_HOSTDEVICE constexpr inline Vec3 Plane3::reflectVector (const Vec3& v) const IMATH_NOEXCEPT { return normal * (normal ^ v) * 2.0 - v; } template IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline bool Plane3::intersect (const Line3& line, Vec3& point) const IMATH_NOEXCEPT { T d = normal ^ line.dir; if (d == 0.0) return false; T t = -((normal ^ line.pos) - distance) / d; point = line (t); return true; } template IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline bool Plane3::intersectT (const Line3& line, T& t) const IMATH_NOEXCEPT { T d = normal ^ line.dir; if (d == 0.0) return false; t = -((normal ^ line.pos) - distance) / d; return true; } /// Stream output, as "(normal distance)" template std::ostream& operator<< (std::ostream& o, const Plane3& plane) { return o << "(" << plane.normal << ", " << plane.distance << ")"; } /// Transform a plane by a matrix template IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Plane3 operator* (const Plane3& plane, const Matrix44& M) IMATH_NOEXCEPT { // T // -1 // Could also compute M but that would suck. // Vec3 dir1 = Vec3 (1, 0, 0) % plane.normal; T dir1Len = dir1 ^ dir1; Vec3 tmp = Vec3 (0, 1, 0) % plane.normal; T tmpLen = tmp ^ tmp; if (tmpLen > dir1Len) { dir1 = tmp; dir1Len = tmpLen; } tmp = Vec3 (0, 0, 1) % plane.normal; tmpLen = tmp ^ tmp; if (tmpLen > dir1Len) { dir1 = tmp; } Vec3 dir2 = dir1 % plane.normal; Vec3 point = plane.distance * plane.normal; return Plane3 (point * M, (point + dir2) * M, (point + dir1) * M); } /// Reflect the pla template IMATH_HOSTDEVICE constexpr inline Plane3 operator- (const Plane3& plane) IMATH_NOEXCEPT { return Plane3 (-plane.normal, -plane.distance); } IMATH_INTERNAL_NAMESPACE_HEADER_EXIT #endif // INCLUDED_IMATHPLANE_H