#pragma once #include "base/math.hpp" #include #include #include namespace m3 { template class Point { public: constexpr Point() : x(T()), y(T()), z(T()) {} constexpr Point(T const & x, T const & y, T const & z) : x(x), y(y), z(z) {} T Length() const { return std::sqrt(x * x + y * y + z * z); } Point RotateAroundX(double angleDegree) const; Point RotateAroundY(double angleDegree) const; Point RotateAroundZ(double angleDegree) const; bool operator==(Point const & rhs) const; T x; T y; T z; }; template Point Point::RotateAroundX(double angleDegree) const { double const angleRad = base::DegToRad(angleDegree); Point res; res.x = x; res.y = y * cos(angleRad) - z * sin(angleRad); res.z = y * sin(angleRad) + z * cos(angleRad); return res; } template Point Point::RotateAroundY(double angleDegree) const { double const angleRad = base::DegToRad(angleDegree); Point res; res.x = x * cos(angleRad) + z * sin(angleRad); res.y = y; res.z = -x * sin(angleRad) + z * cos(angleRad); return res; } template Point Point::RotateAroundZ(double angleDegree) const { double const angleRad = base::DegToRad(angleDegree); Point res; res.x = x * cos(angleRad) - y * sin(angleRad); res.y = x * sin(angleRad) + y * cos(angleRad); res.z = z; return res; } template bool Point::operator==(m3::Point const & rhs) const { return x == rhs.x && y == rhs.y && z == rhs.z; } template T DotProduct(Point const & a, Point const & b) { return a.x * b.x + a.y * b.y + a.z * b.z; } template Point CrossProduct(Point const & a, Point const & b) { auto const x = a.y * b.z - a.z * b.y; auto const y = a.z * b.x - a.x * b.z; auto const z = a.x * b.y - a.y * b.x; return Point(x, y, z); } using PointD = Point; template std::string DebugPrint(Point const & p) { std::ostringstream out; out.precision(20); out << "m3::Point<" << typeid(T).name() << ">(" << p.x << ", " << p.y << ", " << p.z << ")"; return out.str(); } } // namespace m3 namespace base { template bool AlmostEqualAbs(m3::Point const & p1, m3::Point const & p2, double const & eps) { return base::AlmostEqualAbs(p1.x, p2.x, eps) && base::AlmostEqualAbs(p1.y, p2.y, eps) && base::AlmostEqualAbs(p1.z, p2.z, eps); } } // namespace base