#pragma once #include <vector> #include "Mylib/Geometry/Float/distance_segment_point.cpp" #include "Mylib/Geometry/Float/geometry_template.cpp" namespace haar_lib { namespace intersect_circle_segment_impl { enum class status_t { INSIDE, OUTSIDE, TANGENT, ONE_CROSSPOINT, TWO_CROSSPOINTS }; template <typename T> struct result { status_t status; std::vector<point<T>> crosspoints; bool is_inside() const { return status == status_t::INSIDE; } bool is_outside() const { return status == status_t::OUTSIDE; } bool is_tangent() const { return status == status_t::TANGENT; } bool has_one_crosspoint() const { return status == status_t::ONE_CROSSPOINT; } bool has_two_crosspoints() const { return status == status_t::TWO_CROSSPOINTS; } }; } // namespace intersect_circle_segment_impl template <typename T> auto intersect_circle_segment(const circle<T> &cl, const line<T> &s) { using namespace intersect_circle_segment_impl; const T r = cl.radius; const auto &c = cl.center; const T d1 = abs(c - s.from); const T d2 = abs(c - s.to); const T v = distance_segment_point(s, c); const T m = sqrt(r * r - v * v); const auto n = normal(s); const auto k = s.from + diff(s) * cross(n, c + n - s.from) / cross(n, diff(s)); if (d1 < r and d2 < r) { return result<T>({status_t::INSIDE, {}}); } else if (v == r) { return result<T>({status_t::TANGENT, {k}}); } else if (v > r) { return result<T>({status_t::OUTSIDE, {}}); } else if (d1 >= r and d2 >= r) { return result<T>({status_t::TWO_CROSSPOINTS, {k - unit(s) * m, k + unit(s) * m}}); } const T b = dot(unit(s), s.from - c); const T a = abs_sq(s.from - c) - r * r; const T x = sqrt(b * b - a); return result<T>( {status_t::ONE_CROSSPOINT, {s.from + unit(s) * (-b - x >= 0 ? -b - x : -b + x)}}); } } // namespace haar_lib
#line 2 "Mylib/Geometry/Float/intersect_circle_segment.cpp" #include <vector> #line 2 "Mylib/Geometry/Float/geometry_template.cpp" #include <cmath> #include <iostream> #line 5 "Mylib/Geometry/Float/geometry_template.cpp" namespace haar_lib { template <typename T> struct vec { T x, y; vec() {} vec(T x, T y) : x(x), y(y) {} friend auto operator+(const vec &a, const vec &b) { return vec(a.x + b.x, a.y + b.y); } friend auto operator-(const vec &a, const vec &b) { return vec(a.x - b.x, a.y - b.y); } friend auto operator-(const vec &a) { return vec(-a.x, -a.y); } friend bool operator==(const vec &a, const vec &b) { return a.x == b.x and a.y == b.y; } friend bool operator!=(const vec &a, const vec &b) { return !(a == b); } friend bool operator<(const vec &a, const vec &b) { return a.x < b.x or (a.x == b.x and a.y < b.y); } friend std::istream &operator>>(std::istream &s, vec &a) { s >> a.x >> a.y; return s; } }; template <typename T, typename U> auto operator*(const vec<T> &a, const U &k) { return vec<T>(a.x * k, a.y * k); } template <typename T, typename U> auto operator*(const U &k, const vec<T> &a) { return vec<T>(a.x * k, a.y * k); } template <typename T, typename U> auto operator/(const vec<T> &a, const U &k) { return vec<T>(a.x / k, a.y / k); } template <typename T> using point = vec<T>; template <typename T> T abs(const vec<T> &a) { return sqrt(a.x * a.x + a.y * a.y); } template <typename T> T abs_sq(const vec<T> &a) { return a.x * a.x + a.y * a.y; } template <typename T> T dot(const vec<T> &a, const vec<T> &b) { return a.x * b.x + a.y * b.y; } template <typename T> T cross(const vec<T> &a, const vec<T> &b) { return a.x * b.y - a.y * b.x; } template <typename T> auto unit(const vec<T> &a) { return a / abs(a); } template <typename T> auto normal(const vec<T> &p) { return vec<T>(-p.y, p.x); } template <typename T> auto polar(const T &r, const T &ang) { return vec<T>(r * cos(ang), r * sin(ang)); } template <typename T> T angle(const vec<T> &a, const vec<T> &b) { return atan2(b.y - a.y, b.x - a.x); } template <typename T> T phase(const vec<T> &a) { return atan2(a.y, a.x); } template <typename T> T angle_diff(const vec<T> &a, const vec<T> &b) { T r = phase(b) - phase(a); if (r < -M_PI) return r + 2 * M_PI; else if (r > M_PI) return r - 2 * M_PI; return r; } template <typename T> struct line { point<T> from, to; line() : from(), to() {} line(const point<T> &from, const point<T> &to) : from(from), to(to) {} }; template <typename T> using segment = line<T>; template <typename T> auto unit(const line<T> &a) { return unit(a.to - a.from); } template <typename T> auto normal(const line<T> &a) { return normal(a.to - a.from); } template <typename T> auto diff(const segment<T> &a) { return a.to - a.from; } template <typename T> T abs(const segment<T> &a) { return abs(diff(a)); } template <typename T> T dot(const line<T> &a, const line<T> &b) { return dot(diff(a), diff(b)); } template <typename T> T cross(const line<T> &a, const line<T> &b) { return cross(diff(a), diff(b)); } template <typename T> using polygon = std::vector<point<T>>; template <typename T> struct circle { point<T> center; T radius; circle() : center(), radius(0) {} circle(const point<T> ¢er, T radius) : center(center), radius(radius) {} }; template <typename T> std::ostream &operator<<(std::ostream &s, const vec<T> &a) { s << "(" << a.x << ", " << a.y << ")"; return s; } template <typename T> std::ostream &operator<<(std::ostream &s, const line<T> &a) { s << "(" << a.from << " -> " << a.to << ")"; return s; } template <typename T> std::ostream &operator<<(std::ostream &s, const circle<T> &a) { s << "(" << "center: " << a.center << ", " << "radius: " << a.radius << ")"; return s; } } // namespace haar_lib #line 3 "Mylib/Geometry/Float/distance_segment_point.cpp" namespace haar_lib { template <typename T> T distance_segment_point(const segment<T> &l, const point<T> &p) { if (dot(diff(l), p - l.from) < 0) return abs(p - l.from); if (dot(-diff(l), p - l.to) < 0) return abs(p - l.to); return abs(cross(diff(l), p - l.from)) / abs(l); } } // namespace haar_lib #line 5 "Mylib/Geometry/Float/intersect_circle_segment.cpp" namespace haar_lib { namespace intersect_circle_segment_impl { enum class status_t { INSIDE, OUTSIDE, TANGENT, ONE_CROSSPOINT, TWO_CROSSPOINTS }; template <typename T> struct result { status_t status; std::vector<point<T>> crosspoints; bool is_inside() const { return status == status_t::INSIDE; } bool is_outside() const { return status == status_t::OUTSIDE; } bool is_tangent() const { return status == status_t::TANGENT; } bool has_one_crosspoint() const { return status == status_t::ONE_CROSSPOINT; } bool has_two_crosspoints() const { return status == status_t::TWO_CROSSPOINTS; } }; } // namespace intersect_circle_segment_impl template <typename T> auto intersect_circle_segment(const circle<T> &cl, const line<T> &s) { using namespace intersect_circle_segment_impl; const T r = cl.radius; const auto &c = cl.center; const T d1 = abs(c - s.from); const T d2 = abs(c - s.to); const T v = distance_segment_point(s, c); const T m = sqrt(r * r - v * v); const auto n = normal(s); const auto k = s.from + diff(s) * cross(n, c + n - s.from) / cross(n, diff(s)); if (d1 < r and d2 < r) { return result<T>({status_t::INSIDE, {}}); } else if (v == r) { return result<T>({status_t::TANGENT, {k}}); } else if (v > r) { return result<T>({status_t::OUTSIDE, {}}); } else if (d1 >= r and d2 >= r) { return result<T>({status_t::TWO_CROSSPOINTS, {k - unit(s) * m, k + unit(s) * m}}); } const T b = dot(unit(s), s.from - c); const T a = abs_sq(s.from - c) - r * r; const T x = sqrt(b * b - a); return result<T>( {status_t::ONE_CROSSPOINT, {s.from + unit(s) * (-b - x >= 0 ? -b - x : -b + x)}}); } } // namespace haar_lib