/*************************************************************************** * Copyright (c) 2005 Imetric 3D GmbH * * * * This file is part of the FreeCAD CAx development system. * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Library General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU Library General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this library; see the file COPYING.LIB. If not, * * write to the Free Software Foundation, Inc., 59 Temple Place, * * Suite 330, Boston, MA 02111-1307, USA * * * ***************************************************************************/ #ifndef BASE_VECTOR3D_H #define BASE_VECTOR3D_H #include #include #include namespace Base { template struct float_traits { }; // TODO: Remove these specializations and use the default implementation for all types. template<> struct float_traits { using float_type = float; [[nodiscard]] static consteval float_type pi() { return std::numbers::pi_v; } [[nodiscard]] static consteval float_type epsilon() { return std::numeric_limits::epsilon(); } [[nodiscard]] static consteval float_type maximum() { return std::numeric_limits::max(); } }; template<> struct float_traits { using float_type = double; [[nodiscard]] static consteval float_type pi() { return std::numbers::pi_v; } [[nodiscard]] static consteval float_type epsilon() { return std::numeric_limits::epsilon(); } [[nodiscard]] static consteval float_type maximum() { return std::numeric_limits::max(); } }; /** The Vector Base class. */ template class Vector3 { public: static const Vector3 UnitX; static const Vector3 UnitY; static const Vector3 UnitZ; using num_type = float_type; using traits_type = float_traits; [[nodiscard]] static constexpr num_type epsilon() { return traits_type::epsilon(); } /** @name Public data members */ //@{ float_type x; /**< x-coordinate */ float_type y; /**< y-coordinate */ float_type z; /**< z-coordinate */ //@} /// Construction explicit Vector3(float_type fx = 0.0, float_type fy = 0.0, float_type fz = 0.0); Vector3(const Vector3& v) = default; Vector3(Vector3&& v) noexcept = default; ~Vector3() = default; /** @name Operator */ //@{ /// Returns a reference to a coordinate. \a usIndex must be in the range [0,2] [[nodiscard]] float_type& operator[](unsigned short usIndex); /// Returns a const reference to a coordinate. \a usIndex must be in the range [0,2] [[nodiscard]] const float_type& operator[](unsigned short usIndex) const; /// Vector addition [[nodiscard]] Vector3 operator+(const Vector3& rcVct) const; [[nodiscard]] Vector3 operator&(const Vector3& rcVct) const; /// Vector subtraction [[nodiscard]] Vector3 operator-(const Vector3& rcVct) const; /// Negative vector [[nodiscard]] Vector3 operator-() const; /// Vector summation Vector3& operator+=(const Vector3& rcVct); /// Vector subtraction Vector3& operator-=(const Vector3& rcVct); /// Vector scaling [[nodiscard]] Vector3 operator*(float_type fScale) const; [[nodiscard]] Vector3 operator/(float_type fDiv) const; Vector3& operator*=(float_type fScale); Vector3& operator/=(float_type fDiv); /// Assignment Vector3& operator=(const Vector3& v) = default; Vector3& operator=(Vector3&& v) noexcept = default; /// Scalar product [[nodiscard]] float_type operator*(const Vector3& rcVct) const; /// Scalar product [[nodiscard]] float_type Dot(const Vector3& rcVct) const; /// Cross product [[nodiscard]] Vector3 operator%(const Vector3& rcVct) const; /// Cross product [[nodiscard]] Vector3 Cross(const Vector3& rcVct) const; /// Comparing for inequality [[nodiscard]] bool operator!=(const Vector3& rcVct) const; /// Comparing for equality [[nodiscard]] bool operator==(const Vector3& rcVct) const; //@} /// Check if Vector is on a line segment [[nodiscard]] bool IsOnLineSegment(const Vector3& startVct, const Vector3& endVct) const; /** @name Modification */ //@{ void ScaleX(float_type f); void ScaleY(float_type f); void ScaleZ(float_type f); void Scale(float_type fX, float_type fY, float_type fZ); void MoveX(float_type f); void MoveY(float_type f); void MoveZ(float_type f); void Move(float_type fX, float_type fY, float_type fZ); void RotateX(float_type f); void RotateY(float_type f); void RotateZ(float_type f); //@} void Set(float_type fX, float_type fY, float_type fZ); /** @name Mathematics */ //@{ /// Length of the vector. [[nodiscard]] float_type Length() const; /// Squared length of the vector. [[nodiscard]] float_type Sqr() const; /// Set length to 1. Vector3& Normalize(); /// Checks whether this is the null vector [[nodiscard]] bool IsNull() const; /// Get angle between both vectors. The returned value lies in the interval [0,pi]. [[nodiscard]] float_type GetAngle(const Vector3& rcVect) const; /// Get oriented angle between both vectors using a normal. The returned value lies in the /// interval [0,2*pi]. [[nodiscard]] float_type GetAngleOriented(const Vector3& rcVect, const Vector3& norm) const; /** Transforms this point to the coordinate system defined by origin \a rclBase, * vector \a vector rclDirX and vector \a vector rclDirY. * \note \a rclDirX must be perpendicular to \a rclDirY, i.e. \a rclDirX * \a rclDirY = 0.. */ void TransformToCoordinateSystem(const Vector3& rclBase, const Vector3& rclDirX, const Vector3& rclDirY); /** * @brief IsEqual * @param rclPnt * @param tol * @return true or false * If the distance to point \a rclPnt is within the tolerance \a tol both points are considered * equal. */ [[nodiscard]] bool IsEqual(const Vector3& rclPnt, float_type tol) const; /// Returns true if two vectors are parallel within the tol /// If one of the vectors is the null vector then false is returned. [[nodiscard]] bool IsParallel(const Vector3& rclDir, float_type tol) const; /// Returns true if two vectors are normal within the tol /// If one of the vectors is the null vector then false is returned. [[nodiscard]] bool IsNormal(const Vector3& rclDir, float_type tol) const; /// Projects this point onto the plane given by the base \a rclBase and the normal \a rclNorm. Vector3& ProjectToPlane(const Vector3& rclBase, const Vector3& rclNorm); /** * Projects this point onto the plane given by the base \a rclBase and the normal \a rclNorm * and stores the result in rclProj. */ void ProjectToPlane(const Vector3& rclBase, const Vector3& rclNorm, Vector3& rclProj) const; /// Projects this point onto the line given by the base \a rclPoint and the direction \a /// rclLine. /** * Projects a point \a rclPoint onto the line defined by the origin and the direction \a * rclLine. The result is a vector from \a rclPoint to the point on the line. The length of this * vector is the distance from \a rclPoint to the line. Note: The resulting vector does not * depend on the current vector. */ Vector3& ProjectToLine(const Vector3& rclPoint, const Vector3& rclLine); /** * Get the perpendicular of this point to the line defined by rclBase and rclDir. * Note: Do not mix up this method with ProjectToLine. */ [[nodiscard]] Vector3 Perpendicular(const Vector3& rclBase, const Vector3& rclDir) const; /** Computes the distance to the given plane. Depending on the side this point is located * the distance can also be negative. The distance is positive if the point is at the same * side the plane normal points to, negative otherwise. */ [[nodiscard]] float_type DistanceToPlane(const Vector3& rclBase, const Vector3& rclNorm) const; /// Computes the distance from this point to the line given by \a rclBase and \a rclDirect. [[nodiscard]] float_type DistanceToLine(const Vector3& rclBase, const Vector3& rclDirect) const; /** Computes the vector from this point to the point on the line segment with the shortest * distance. The line segment is defined by \a rclP1 and \a rclP2. * Note: If the projection of this point is outside the segment then the shortest distance * to \a rclP1 or \a rclP2 is computed. */ [[nodiscard]] Vector3 DistanceToLineSegment(const Vector3& rclP1, const Vector3& rclP2) const; //@} }; template Vector3 const Vector3::UnitX(1.0, 0.0, 0.0); template Vector3 const Vector3::UnitY(0.0, 1.0, 0.0); template Vector3 const Vector3::UnitZ(0.0, 0.0, 1.0); /// Returns the distance between two points template [[nodiscard]] inline float_type Distance(const Vector3& v1, const Vector3& v2) { float_type x = v1.x - v2.x; float_type y = v1.y - v2.y; float_type z = v1.z - v2.z; return static_cast(std::sqrt((x * x) + (y * y) + (z * z))); } /// Returns the squared distance between two points template [[nodiscard]] inline float_type DistanceP2(const Vector3& v1, const Vector3& v2) { float_type x = v1.x - v2.x; float_type y = v1.y - v2.y; float_type z = v1.z - v2.z; return x * x + y * y + z * z; } /// Multiplication of scalar with vector. template [[nodiscard]] inline Vector3 operator*(float_type fFac, const Vector3& rcVct) { return Vector3(rcVct.x * fFac, rcVct.y * fFac, rcVct.z * fFac); } template [[nodiscard]] inline Vector3 toVector(const Vector3& v) { return Vector3(static_cast(v.x), static_cast(v.y), static_cast(v.z)); } using Vector3f = Vector3; using Vector3d = Vector3; } // namespace Base #endif // BASE_VECTOR3D_H