library

This documentation is automatically generated by online-judge-tools/verification-helper

View the Project on GitHub maspypy/library

:heavy_check_mark: geo3d/cross_point.hpp

Depends on

Verified with

Code

#include "geo3d/base.hpp"

// 0: 交点なし
// 1: 一意な交点
// 2:2 つ以上の交点
template <typename T>
int count_cross(Line_3d<T> L1, Line_3d<T> L2) {
  static_assert(!std::is_floating_point<T>::value);
  if (L1.is_parallel(L2)) {
    if (L1.contain(L2.a)) return 2;
    return 0;
  }
  Point_3d<T> norm = L1.d.cross(L2.d);
  return ((L1.a - L2.a).dot(norm) == 0 ? 1 : 0);
}

// count_cross == 1 のときにだけ呼ぶこと
template <typename REAL, typename T>
Point_3d<REAL> cross_point(Line_3d<T> L1, Line_3d<T> L2) {
  Point_3d<T> d1 = L1.d;
  Point_3d<T> d2 = L2.d;
  Point_3d<T> a = L2.a - L1.a;
  REAL t1 = [&]() -> REAL {
    FOR(3) {
      d1 = {d1.y, d1.z, d1.x};
      d2 = {d2.y, d2.z, d2.x};
      a = {a.y, a.z, a.x};
      T det = d1.x * d2.y - d1.y * d2.x;
      if (det != 0) { return REAL(a.x * d2.y - a.y * d2.x) / REAL(det); }
    }
    assert(0);
  }();
  REAL x = REAL(L1.a.x) + t1 * REAL(L1.d.x);
  REAL y = REAL(L1.a.y) + t1 * REAL(L1.d.y);
  REAL z = REAL(L1.a.z) + t1 * REAL(L1.d.z);
  return {x, y, z};
}
#line 2 "geo3d/base.hpp"

template <typename T>
struct Point_3d {
  T x, y, z;

  Point_3d() = default;

  template <typename A, typename B, typename C>
  Point_3d(A x, B y, C z) : x(x), y(y), z(z) {}

  Point_3d operator+(Point_3d p) const { return {x + p.x, y + p.y, z + p.z}; }
  Point_3d operator-(Point_3d p) const { return {x - p.x, y - p.y, z - p.z}; }
  Point_3d operator*(T t) const { return {x * t, y * t, z * t}; }
  bool operator==(Point_3d p) const { return x == p.x && y == p.y && z == p.z; }
  bool operator!=(Point_3d p) const { return x != p.x || y != p.y || z == p.z; }
  Point_3d operator-() const { return {-x, -y, -z}; }

  bool is_parallel(Point_3d p) const {
    return x * p.y == y * p.x && y * p.z == z * p.y && z * p.x == x * p.z;
  }

  T dot(Point_3d other) { return x * other.x + y * other.y + z * other.z; }
  double norm() { return sqrt(x * x + y * y + z * z); }
  Point_3d cross(Point_3d other) {
    return Point_3d(y * other.z - z * other.y, z * other.x - x * other.z,
                    x * other.y - y * other.x);
  }
};

template <typename T>
struct Line_3d {
  // a + td
  Point_3d<T> a, d;

  Line_3d(Point_3d<T> A, Point_3d<T> B) : a(A), d(B - A) {
    assert(d.dot(d) != 0);
  }
  bool is_parallel(Line_3d<T> other) {
    Point_3d<T> n = d.cross(other.d);
    return (n.x == T(0) && n.y == T(0) && n.z == T(0));
  }
  bool contain(Point_3d<T> p) {
    p = p - a;
    p = p.cross(d);
    return (p.x == T(0) && p.y == T(0) && p.z == T(0));
  }
};
#line 2 "geo3d/cross_point.hpp"

// 0: 交点なし
// 1: 一意な交点
// 2:2 つ以上の交点
template <typename T>
int count_cross(Line_3d<T> L1, Line_3d<T> L2) {
  static_assert(!std::is_floating_point<T>::value);
  if (L1.is_parallel(L2)) {
    if (L1.contain(L2.a)) return 2;
    return 0;
  }
  Point_3d<T> norm = L1.d.cross(L2.d);
  return ((L1.a - L2.a).dot(norm) == 0 ? 1 : 0);
}

// count_cross == 1 のときにだけ呼ぶこと
template <typename REAL, typename T>
Point_3d<REAL> cross_point(Line_3d<T> L1, Line_3d<T> L2) {
  Point_3d<T> d1 = L1.d;
  Point_3d<T> d2 = L2.d;
  Point_3d<T> a = L2.a - L1.a;
  REAL t1 = [&]() -> REAL {
    FOR(3) {
      d1 = {d1.y, d1.z, d1.x};
      d2 = {d2.y, d2.z, d2.x};
      a = {a.y, a.z, a.x};
      T det = d1.x * d2.y - d1.y * d2.x;
      if (det != 0) { return REAL(a.x * d2.y - a.y * d2.x) / REAL(det); }
    }
    assert(0);
  }();
  REAL x = REAL(L1.a.x) + t1 * REAL(L1.d.x);
  REAL y = REAL(L1.a.y) + t1 * REAL(L1.d.y);
  REAL z = REAL(L1.a.z) + t1 * REAL(L1.d.z);
  return {x, y, z};
}
Back to top page