Alex's Anthology of Algorithms Common Code for Contests in Concise C++
Geometry / Geometry Primitives

A circle in two dimensions with epsilon-aware operations. The circle centered at $(h, k)$ is represented by the relation $(x - h)^2 + (y - k)^2 = r^2$, where the radius $r$ is normalized to a nonnegative number.

This implementation stores and computes circle parameters in double. Point-accepting constructors and predicates are templated on the point type Pt and only read .x/.y, so they accept Point, PointD, or PointI from 7.1.1 or any struct with numeric .x and .y fields.

  • Circle() constructs the zero-radius circle centered at the origin.
  • Circle(r) constructs a circle of radius abs(r) centered at the origin.
  • Circle(h, k, r) constructs a circle of radius abs(r) centered at (h, k).
  • Circle(o, r) constructs a circle of radius abs(r) centered at point o.
  • Circle(a, b) constructs the circle whose diameter is segment a-b.
  • Circle(a, b, c) constructs the circumcircle through non-collinear points a, b, and c, throwing if the points are collinear.
  • Circle(a, b, r) constructs one circle of radius abs(r) passing through points a and b, throwing if no finite circle is determined by the inputs.
  • operator== and operator!= compare stored centers and radii exactly; EQ(a, b) compares them using EPS.
  • contains(p) returns whether point p lies inside or on the circle.
  • on_edge(p) returns whether point p lies on the circle boundary.
  • incircle(a, b, c) returns the circle inscribed in triangle abc.
  • in_circumcircle(a, b, c, d) returns $1$ if d lies strictly inside the circle through a, b, and c, $0$ if it lies on the circle, or $-1$ if it lies outside. This has exact reasoning for integral points by evaluating the determinant directly without constructing a Circle or taking square roots. Points a, b, and c must not be collinear. For integer inputs, the sign test is exact provided the chosen intermediate type does not overflow.

The floating-point constructors and predicates use an absolute tolerance EPS.

Overflow warning: the determinant in in_circumcircle() grows like the fourth power of the coordinate magnitude. For large integer coordinates, use a point or intermediate type wide enough for that determinant.

Implementation

#include <cmath>
#include <cstdint>
#include <ostream>
#include <stdexcept>
#include <type_traits>

const double EPS = 1e-9;

template<typename T, typename U, typename C = std::common_type_t<T, U>>
bool EQ(T a, U b) {
  if constexpr (std::is_floating_point_v<C>) return C(a) == C(b) || std::fabs(C(a) - C(b)) <= EPS;
  return C(a) == C(b);
}

template<typename T, typename U, typename C = std::common_type_t<T, U>>
bool LT(T a, U b) {
  if constexpr (std::is_floating_point_v<C>) return C(a) < C(b) - EPS;
  return C(a) < C(b);
}

template<typename T, typename U>
bool LE(T a, U b) {
  return !LT(b, a);
}

// SFINAE guard: valid only when Pt exposes numeric .x/.y members. This keeps the templated point
// constructors from hijacking calls like Circle(double, double, double).
template<typename Pt>
using if_point = decltype(std::declval<const Pt &>().x, std::declval<const Pt &>().y, void());

struct Circle {
  double h, k, r;

  Circle() : h(0), k(0), r(0) {}
  explicit Circle(double r) : h(0), k(0), r(fabs(r)) {}
  Circle(double h, double k, double r) : h(h), k(k), r(fabs(r)) {}

  template<typename Pt, typename = if_point<Pt>>
  Circle(const Pt &o, double r) : h(o.x), k(o.y), r(fabs(r)) {}

  template<typename Pt, typename = if_point<Pt>>
  Circle(const Pt &a, const Pt &b) {
    h = (a.x + b.x) / 2.0;
    k = (a.y + b.y) / 2.0;
    r = hypot(a.x - h, a.y - k);
  }

  template<typename Pt, typename = if_point<Pt>>
  Circle(const Pt &a, const Pt &b, const Pt &c) {
    double ax = a.x, ay = a.y, bx = b.x, by = b.y, cx = c.x, cy = c.y;
    double asq = ax * ax + ay * ay, bsq = bx * bx + by * by, csq = cx * cx + cy * cy;
    double d = 2.0 * (ax * (by - cy) + bx * (cy - ay) + cx * (ay - by));
    if (EQ(d, 0)) {
      throw std::runtime_error("No circumcircle from collinear points.");
    }
    h = (asq * (by - cy) + bsq * (cy - ay) + csq * (ay - by)) / d;
    k = (asq * (cx - bx) + bsq * (ax - cx) + csq * (bx - ax)) / d;
    r = hypot(ax - h, ay - k);
  }

  template<typename Pt, typename = if_point<Pt>>
  Circle(const Pt &a, const Pt &b, double r) : r(fabs(r)) {
    if (EQ(this->r, 0) && EQ(a.x, b.x) && EQ(a.y, b.y)) {
      h = a.x;
      k = a.y;
      return;
    }
    double d = hypot(b.x - a.x, b.y - a.y);
    if (EQ(d, 0)) {
      throw std::runtime_error("Identical points, infinite circles.");
    }
    if (LT(this->r * 2.0, d)) {
      throw std::runtime_error("Points too far away to make Circle.");
    }
    double z = this->r * this->r - d * d / 4.0;
    double v = sqrt(z < 0 ? 0 : z) / d;
    double mx = (a.x + b.x) / 2.0, my = (a.y + b.y) / 2.0;
    h = mx + v * (a.y - b.y);
    k = my + v * (b.x - a.x);
    // The other answer is (h, k) = (mx - v*(a.y - b.y), my - v*(b.x - a.x)).
  }

  bool operator==(const Circle &c) const { return h == c.h && k == c.k && r == c.r; }
  bool operator!=(const Circle &c) const { return !(*this == c); }

  friend bool EQ(const Circle &a, const Circle &b) {
    return EQ(a.h, b.h) && EQ(a.k, b.k) && EQ(a.r, b.r);
  }

  template<typename Pt>
  bool contains(const Pt &p) const {
    return LE(hypot(p.x - h, p.y - k), r);
  }

  template<typename Pt>
  bool on_edge(const Pt &p) const {
    return EQ(hypot(p.x - h, p.y - k), r);
  }

  friend std::ostream &operator<<(std::ostream &out, const Circle &c) {
    auto flags = out.flags();
    out << std::showpos << "(x" << -(fabs(c.h) < EPS ? 0 : c.h) << ")^2+"
        << "(y" << -(fabs(c.k) < EPS ? 0 : c.k) << ")^2" << std::noshowpos << "="
        << (fabs(c.r) < EPS ? 0 : c.r * c.r);
    out.flags(flags);
    return out;
  }
};

template<typename Pt>
Circle incircle(const Pt &a, const Pt &b, const Pt &c) {
  double al = hypot(b.x - c.x, b.y - c.y);
  double bl = hypot(a.x - c.x, a.y - c.y);
  double cl = hypot(a.x - b.x, a.y - b.y);
  double l = al + bl + cl;
  double px = a.x - c.x, py = a.y - c.y, qx = b.x - c.x, qy = b.y - c.y;
  return EQ(l, 0) ? Circle(a.x, a.y, 0)
                  : Circle(
                        (al * a.x + bl * b.x + cl * c.x) / l, (al * a.y + bl * b.y + cl * c.y) / l,
                        fabs(px * qy - py * qx) / l
                    );
}

template<typename Pt>
int in_circumcircle(const Pt &a, const Pt &b, const Pt &c, const Pt &d) {
  using T = decltype(a.x + a.x);
  using W = std::conditional_t<
      std::is_floating_point<T>::value, long double,
      std::conditional_t<std::is_integral<T>::value, int64_t, T>>;
  W adx = (W)a.x - d.x, ady = (W)a.y - d.y;
  W bdx = (W)b.x - d.x, bdy = (W)b.y - d.y;
  W cdx = (W)c.x - d.x, cdy = (W)c.y - d.y;
  // Overflow warning.
  W det = (adx * adx + ady * ady) * (bdx * cdy - cdx * bdy) +
          (bdx * bdx + bdy * bdy) * (cdx * ady - adx * cdy) +
          (cdx * cdx + cdy * cdy) * (adx * bdy - bdx * ady);
  W orient = ((W)b.x - a.x) * ((W)c.y - a.y) - ((W)b.y - a.y) * ((W)c.x - a.x);
  W val = W{0} < orient ? det : -det;
  return EQ(val, W{0}) ? 0 : (W{0} < val ? 1 : -1);
}

Example Usage

#include <cassert>

struct Point {
  double x, y;
  Point(double x = 0, double y = 0) : x(x), y(y) {}
};

struct PointI {
  int x, y;
  PointI(int x = 0, int y = 0) : x(x), y(y) {}
};

int main() {
  Circle c(-2, 5, sqrt(10));
  assert(EQ(c, Circle(Point(-2, 5), sqrt(10))));
  assert(EQ(c, Circle(Point(1, 6), Point(-5, 4))));
  assert(EQ(c, Circle(Point(-3, 2), Point(-3, 8), Point(-1, 8))));
  assert(EQ(Circle(Point(0, 0), Point(0, 2), -1), Circle(0, 1, 1)));
  assert(EQ(c, incircle(Point(-12, 5), Point(3, 0), Point(0, 9))));
  assert(c.contains(Point(-2, 8)) && !c.contains(Point(-2, 9)));
  assert(c.on_edge(Point(-1, 2)) && !c.on_edge(Point(-1.01, 2)));

  // Integer-coordinate points are accepted; the Circle is computed in double.
  assert(EQ(c, Circle(PointI(1, 6), PointI(-5, 4))));
  assert(EQ(c, Circle(PointI(-3, 2), PointI(-3, 8), PointI(-1, 8))));
  assert(EQ(c, incircle(PointI(-12, 5), PointI(3, 0), PointI(0, 9))));
  assert(c.contains(PointI(-2, 8)) && !c.contains(PointI(-2, 9)));
  assert(c.on_edge(PointI(-1, 2)));

  // Exact integer in-circle predicate: unit circle through (1,0), (0,1), (-1,0).
  assert(in_circumcircle(PointI(1, 0), PointI(0, 1), PointI(-1, 0), PointI(0, 0)) == 1);  // inside
  assert(
      in_circumcircle(PointI(1, 0), PointI(0, 1), PointI(-1, 0), PointI(2, 0)) == -1
  );  // outside
  assert(
      in_circumcircle(PointI(1, 0), PointI(0, 1), PointI(-1, 0), PointI(0, -1)) == 0
  );  // on edge
  // Orientation-independent: reversing a, b, c gives the same answer.
  assert(in_circumcircle(PointI(-1, 0), PointI(0, 1), PointI(1, 0), PointI(0, 0)) == 1);
  return 0;
}