พื้นฐาน Geometry
พื้นฐาน Computational Geometry สำหรับ Competitive Programming
พื้นฐาน Geometry
Basic Types
Point / Vector
struct Point {
double x, y;
Point() : x(0), y(0) {}
Point(double x, double y) : x(x), y(y) {}
Point operator+(const Point& p) const { return Point(x + p.x, y + p.y); }
Point operator-(const Point& p) const { return Point(x - p.x, y - p.y); }
Point operator*(double t) const { return Point(x * t, y * t); }
Point operator/(double t) const { return Point(x / t, y / t); }
double dot(const Point& p) const { return x * p.x + y * p.y; }
double cross(const Point& p) const { return x * p.y - y * p.x; }
double norm() const { return sqrt(x * x + y * y); }
double norm2() const { return x * x + y * y; }
Point rotate(double angle) const {
return Point(x * cos(angle) - y * sin(angle),
x * sin(angle) + y * cos(angle));
}
bool operator<(const Point& p) const {
if (x != p.x) return x < p.x;
return y < p.y;
}
bool operator==(const Point& p) const {
return abs(x - p.x) < EPS && abs(y - p.y) < EPS;
}
};
const double EPS = 1e-9;
Line
struct Line {
Point a, b; // line through points a and b
// หรือใช้ ax + by + c = 0
double A, B, C;
Line(Point a, Point b) : a(a), b(b) {
A = b.y - a.y;
B = a.x - b.x;
C = -(A * a.x + B * a.y);
}
// Distance from point to line
double dist(Point p) const {
return abs(A * p.x + B * p.y + C) / sqrt(A * A + B * B);
}
// Projection of point onto line
Point project(Point p) const {
Point v = b - a;
double t = (p - a).dot(v) / v.norm2();
return a + v * t;
}
// Reflection of point across line
Point reflect(Point p) const {
return project(p) * 2 - p;
}
};
Basic Operations
Cross Product และ Orientation
// cross(b-a, c-a) > 0: counter-clockwise
// cross(b-a, c-a) < 0: clockwise
// cross(b-a, c-a) = 0: collinear
int sign(double x) {
if (x > EPS) return 1;
if (x < -EPS) return -1;
return 0;
}
int orientation(Point a, Point b, Point c) {
return sign((b - a).cross(c - a));
}
Distance Functions
// Distance between two points
double dist(Point a, Point b) {
return (a - b).norm();
}
// Distance from point to line segment
double distToSegment(Point p, Point a, Point b) {
if ((p - a).dot(b - a) <= 0) return dist(p, a);
if ((p - b).dot(a - b) <= 0) return dist(p, b);
return abs((b - a).cross(p - a)) / dist(a, b);
}
Line Intersection
// Check if two lines intersect (not parallel)
bool lineIntersect(Line l1, Line l2, Point& result) {
double det = l1.A * l2.B - l2.A * l1.B;
if (abs(det) < EPS) return false; // parallel
result.x = (l1.B * l2.C - l2.B * l1.C) / det;
result.y = (l2.A * l1.C - l1.A * l2.C) / det;
return true;
}
// Alternative using parametric form
bool lineIntersect2(Point a, Point b, Point c, Point d, Point& result) {
Point ab = b - a, cd = d - c, ac = c - a;
double denom = ab.cross(cd);
if (abs(denom) < EPS) return false;
double t = ac.cross(cd) / denom;
result = a + ab * t;
return true;
}
Segment Intersection
bool onSegment(Point p, Point a, Point b) {
return min(a.x, b.x) <= p.x + EPS && p.x <= max(a.x, b.x) + EPS &&
min(a.y, b.y) <= p.y + EPS && p.y <= max(a.y, b.y) + EPS;
}
bool segmentIntersect(Point a, Point b, Point c, Point d) {
int d1 = orientation(c, d, a);
int d2 = orientation(c, d, b);
int d3 = orientation(a, b, c);
int d4 = orientation(a, b, d);
if (((d1 > 0 && d2 < 0) || (d1 < 0 && d2 > 0)) &&
((d3 > 0 && d4 < 0) || (d3 < 0 && d4 > 0)))
return true;
// Collinear cases
if (d1 == 0 && onSegment(a, c, d)) return true;
if (d2 == 0 && onSegment(b, c, d)) return true;
if (d3 == 0 && onSegment(c, a, b)) return true;
if (d4 == 0 && onSegment(d, a, b)) return true;
return false;
}
Polygon Operations
Area of Polygon (Shoelace Formula)
double polygonArea(vector<Point>& poly) {
double area = 0;
int n = poly.size();
for (int i = 0; i < n; i++) {
area += poly[i].cross(poly[(i + 1) % n]);
}
return abs(area) / 2;
}
Point in Polygon
// Ray casting algorithm
bool pointInPolygon(Point p, vector<Point>& poly) {
int n = poly.size();
int count = 0;
for (int i = 0; i < n; i++) {
Point a = poly[i], b = poly[(i + 1) % n];
if ((a.y <= p.y && p.y < b.y) || (b.y <= p.y && p.y < a.y)) {
double x = a.x + (p.y - a.y) * (b.x - a.x) / (b.y - a.y);
if (p.x < x) count++;
}
}
return count % 2 == 1;
}
// Winding number (handles edges)
int windingNumber(Point p, vector<Point>& poly) {
int n = poly.size();
int wn = 0;
for (int i = 0; i < n; i++) {
Point a = poly[i], b = poly[(i + 1) % n];
if (a.y <= p.y) {
if (b.y > p.y && orientation(a, b, p) > 0) wn++;
} else {
if (b.y <= p.y && orientation(a, b, p) < 0) wn--;
}
}
return wn; // != 0 means inside
}
Polygon Convexity Check
bool isConvex(vector<Point>& poly) {
int n = poly.size();
bool hasPos = false, hasNeg = false;
for (int i = 0; i < n; i++) {
int o = orientation(poly[i], poly[(i+1)%n], poly[(i+2)%n]);
if (o > 0) hasPos = true;
if (o < 0) hasNeg = true;
}
return !(hasPos && hasNeg);
}
Circle Operations
Circle
struct Circle {
Point c;
double r;
Circle() : r(0) {}
Circle(Point c, double r) : c(c), r(r) {}
// Check if point is inside
bool contains(Point p) const {
return dist(c, p) <= r + EPS;
}
// Circumference
double circumference() const {
return 2 * M_PI * r;
}
// Area
double area() const {
return M_PI * r * r;
}
};
Circle-Line Intersection
vector<Point> circleLineIntersect(Circle c, Line l) {
Point proj = l.project(c.c);
double d = dist(c.c, proj);
if (d > c.r + EPS) return {};
if (abs(d - c.r) < EPS) return {proj};
double h = sqrt(c.r * c.r - d * d);
Point v = (l.b - l.a) / (l.b - l.a).norm();
return {proj + v * h, proj - v * h};
}
Circle-Circle Intersection
vector<Point> circleCircleIntersect(Circle c1, Circle c2) {
double d = dist(c1.c, c2.c);
if (d > c1.r + c2.r + EPS) return {}; // too far
if (d < abs(c1.r - c2.r) - EPS) return {}; // one inside other
double a = (c1.r * c1.r - c2.r * c2.r + d * d) / (2 * d);
double h = sqrt(max(0.0, c1.r * c1.r - a * a));
Point p = c1.c + (c2.c - c1.c) * (a / d);
Point v = (c2.c - c1.c).rotate(M_PI / 2) * (h / d);
if (abs(h) < EPS) return {p};
return {p + v, p - v};
}
Tips
- Epsilon comparison - floating point ต้องใช้ epsilon
- Integer geometry - ถ้าทำได้ ใช้ integer และหลีกเลี่ยง division
- Cross product sign - สำคัญมากสำหรับ orientation tests
- Degenerate cases - จัดการ cases พิเศษเช่น parallel lines, coincident points