#ifndef FESA_MATH_VECTOR3_H_ #define FESA_MATH_VECTOR3_H_ // NOLINT(readability-identifier-naming) #include #include #include #include namespace fesa { /// @brief Represents an owning fixed-size three-dimensional value vector. class Vector3 { public: /// @brief Constructs the zero vector. constexpr Vector3() noexcept = default; /// @brief Constructs a vector from three Cartesian components. /// @param x First component in the caller-defined coordinate system. /// @param y Second component in the caller-defined coordinate system. /// @param z Third component in the caller-defined coordinate system. constexpr Vector3(double x, double y, double z) noexcept : components_{{x, y, z}} {} /// @brief Returns the first component. constexpr double X() const noexcept { return components_[0]; } /// @brief Returns the second component. constexpr double Y() const noexcept { return components_[1]; } /// @brief Returns the third component. constexpr double Z() const noexcept { return components_[2]; } /// @brief Returns a component by zero-based index. /// @pre index is less than three. constexpr double operator[](std::size_t index) const noexcept { return components_[index]; } /// @brief Adds corresponding vector components. constexpr Vector3 operator+(const Vector3& rhs) const noexcept { return Vector3{X() + rhs.X(), Y() + rhs.Y(), Z() + rhs.Z()}; } /// @brief Subtracts corresponding vector components. constexpr Vector3 operator-(const Vector3& rhs) const noexcept { return Vector3{X() - rhs.X(), Y() - rhs.Y(), Z() - rhs.Z()}; } /// @brief Multiplies every component by a scalar. constexpr Vector3 operator*(double scalar) const noexcept { return Vector3{X() * scalar, Y() * scalar, Z() * scalar}; } /// @brief Computes the Euclidean dot product with rhs. double Dot(const Vector3& rhs) const noexcept { return X() * rhs.X() + Y() * rhs.Y() + Z() * rhs.Z(); } /// @brief Computes the right-handed cross product with rhs. Vector3 Cross(const Vector3& rhs) const noexcept { return Vector3{Y() * rhs.Z() - Z() * rhs.Y(), Z() * rhs.X() - X() * rhs.Z(), X() * rhs.Y() - Y() * rhs.X()}; } /// @brief Computes the Euclidean norm. double Norm() const noexcept { return std::sqrt(Dot(*this)); } /// @brief Returns a unit vector when the norm is usable. /// @return Empty when the norm is exactly zero or nonfinite. std::optional Normalized() const noexcept { const double norm = Norm(); // NOLINT(readability-identifier-naming) if (norm == 0.0 || !std::isfinite(norm)) { return std::nullopt; } return Vector3{X() / norm, Y() / norm, Z() / norm}; } /// @brief Reports whether all components are finite. bool IsFinite() const noexcept { return std::isfinite(X()) && std::isfinite(Y()) && std::isfinite(Z()); } private: std::array components_{}; }; } // namespace fesa #endif // FESA_MATH_VECTOR3_H_