Skip to main content
Computational geometry deals with algorithms for solving geometric problems. This section covers essential 2D geometry primitives and algorithms commonly used in competitive programming.

Overview

Geometric algorithms are fundamental for solving problems involving:
  • Points, lines, and polygons
  • Distances and angles
  • Area and perimeter calculations
  • Convex hulls
  • Intersection detection
  • Closest pair problems

Core Components

Point

2D point with arithmetic operations and distance metrics

Polygon

Collection of points forming a polygon

Convex Hull

Find the smallest convex polygon containing all points

Area & Perimeter

Calculate geometric properties of polygons

Point Structure

The fundamental building block for all geometry algorithms is the Point structure.

Implementation

typedef long double floating_t;

template<typename T>
struct Point {
    T x;
    T y;

    // Arithmetic operators
    Point<T> operator + (Point<T> p) { return {x+p.x, y+p.y}; }
    Point<T> operator - (Point<T> p) { return {x-p.x, y-p.y}; }
    Point<T> operator * (Point<T> p) { return {x*p.x-y*p.y, x*p.y+y*p.x}; }
    Point<T> operator * (T p) { return {x*p, y*p}; }
    Point<T> operator / (T p) { return {x/p, y/p}; } // floating point only
    
    // Comparison operators
    bool operator == (const Point<T> &p) const { return x==p.x && y == p.y; }
    bool operator != (const Point<T> &p) const { return !(*this == p); }
    bool operator <  (const Point<T> &p) const { return x < p.x || (x == p.x && y < p.y); }
    bool operator >  (const Point<T> &p) const { return x > p.x || (x == p.x && y > p.y); }
    
    // Dot and cross products
    T dot(Point<T> p) { return x*p.x + y*p.y; }
    T cross(Point<T> p) { return x*p.y - y*p.x; }
    T orient(Point<T> b, Point<T> c) { return (b-*this).cross(c-*this); }
    
    // Norms and distances
    T norm() { return x*x + y*y; }
    floating_t eucl_dist() { return sqrt(norm()); }
    T man_dist() { return abs(x) + abs(y); }
    T ch_dist() { return max(abs(x), abs(y)); }
};

template<typename T>
using point = Point<T>;

Key Operations

Dot Product

The dot product measures the projection of one vector onto another.
T dot(Point<T> p) { 
    return x*p.x + y*p.y; 
}
Properties:
  • If a · b > 0: vectors point in similar direction
  • If a · b = 0: vectors are perpendicular
  • If a · b < 0: vectors point in opposite directions
Point<int> a = {3, 4};
Point<int> b = {1, 0};
int dotProduct = a.dot(b);  // 3

Cross Product

The cross product (in 2D, returns scalar) determines orientation.
T cross(Point<T> p) { 
    return x*p.y - y*p.x; 
}
Properties:
  • If a × b > 0: b is counter-clockwise from a
  • If a × b = 0: vectors are collinear
  • If a × b < 0: b is clockwise from a
Point<int> a = {1, 0};
Point<int> b = {0, 1};
int crossProduct = a.cross(b);  // 1 (counter-clockwise)

Orientation

Determine the orientation of three points (a, b, c).
T orient(Point<T> b, Point<T> c) { 
    return (b-*this).cross(c-*this); 
}
Returns:
  • Positive: counter-clockwise turn
  • Zero: collinear
  • Negative: clockwise turn
Point<int> a = {0, 0};
Point<int> b = {1, 0};
Point<int> c = {1, 1};
int orientation = a.orient(b, c);  // 1 (CCW)

Distance Metrics

Euclidean Distance

Standard straight-line distance.
floating_t eucl_dist() { 
    return sqrt(norm()); 
}

floating_t eucl_dist(Point<T> p) { 
    return sqrt(norm(p)); 
}
Point<int> a = {0, 0};
Point<int> b = {3, 4};
double dist = a.eucl_dist(b);  // 5.0

Manhattan Distance

Sum of absolute differences (taxicab geometry).
T man_dist() { 
    return abs(x) + abs(y); 
}

T man_dist(Point<T> p) { 
    return abs(x-p.x) + abs(y-p.y); 
}
Point<int> a = {1, 2};
Point<int> b = {4, 6};
int dist = a.man_dist(b);  // |4-1| + |6-2| = 7

Chebyshev Distance

Maximum of absolute differences.
T ch_dist() { 
    return max(abs(x), abs(y)); 
}

T ch_dist(Point<T> p) { 
    return max(abs(x-p.x), abs(y-p.y)); 
}
Point<int> a = {1, 2};
Point<int> b = {4, 6};
int dist = a.ch_dist(b);  // max(|4-1|, |6-2|) = 4

Polygon Structure

A polygon is represented as a collection of points.
template<typename T>
class Polygon {
    vector<Point<T>> points;
public:
    Polygon() {}
    Polygon(int n) : points(n) {}
    Polygon(vector<Point<T>> pts) : points(pts.begin(), pts.end()) {}
    
    typename vector<Point<T>>::iterator begin() { return points.begin(); }
    typename vector<Point<T>>::iterator end() { return points.end(); }
    int size() { return (int) points.size(); }
    Point<T>& operator [] (int i) { return points[i]; }
    
    void add(Point<T> point) {
        points.push_back(point);
    }
    
    void delete_repeated() {
        vector<Point<T>> aux;
        sort(points.begin(), points.end());
        for(Point<T> &pt : points) {
            if(aux.empty() || aux.back() != pt) {
                aux.push_back(pt);
            }
        }
        points.swap(aux);
    }
};

template<typename T>
using polygon = Polygon<T>;

Usage Example

// Create a polygon
Polygon<int> poly;
poly.add({0, 0});
poly.add({4, 0});
poly.add({4, 3});
poly.add({0, 3});

// Or initialize with vector
vector<Point<int>> points = {{0,0}, {4,0}, {4,3}, {0,3}};
Polygon<int> rect(points);

// Remove duplicate points
poly.delete_repeated();

Area and Perimeter

Area Calculation

Compute the area of a polygon using the Shoelace formula.
template<typename T>
floating_t area(Polygon<T> points, bool sign = false) {
    int n = points.size();
    floating_t ans = 0.0;
    
    for(int i = 0; i < n; ++i) {
        ans += points[i].cross(points[(i + 1) % n]);
    }
    
    ans /= 2.0;
    // ans >= 0: counter-clockwise
    // ans < 0: clockwise
    return (!sign) ? abs(ans) : ans;
}
Time Complexity: O(n)
Space Complexity: O(1)

Example

vector<Point<int>> square = {{0,0}, {4,0}, {4,4}, {0,4}};
Polygon<int> poly(square);

floating_t a = area(poly);
// Result: 16.0

// Check orientation
floating_t signedArea = area(poly, true);
if(signedArea > 0) {
    cout << "Counter-clockwise\n";
} else {
    cout << "Clockwise\n";
}

Perimeter Calculation

Compute the perimeter by summing edge lengths.
template<typename T>
floating_t perimeter(Polygon<T> points) {
    int n = points.size();
    floating_t ans = 0.0;
    
    for(int i = 0; i < n; ++i) {
        ans += points[i].eucl_dist(points[(i + 1) % n]);
    }
    
    return ans;
}
Time Complexity: O(n)
Space Complexity: O(1)

Example

vector<Point<int>> triangle = {{0,0}, {3,0}, {0,4}};
Polygon<int> poly(triangle);

floating_t p = perimeter(poly);
// Result: 3 + 4 + 5 = 12.0

Common Patterns

Check if Point is Inside Polygon

bool isInside(Polygon<int>& poly, Point<int> p) {
    int n = poly.size();
    int count = 0;
    
    for(int i = 0; i < n; i++) {
        Point<int> a = poly[i];
        Point<int> 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 + (double)(p.y - a.y) / (b.y - a.y) * (b.x - a.x);
            if(p.x < x) count++;
        }
    }
    
    return count % 2 == 1;
}

Find Centroid

template<typename T>
Point<floating_t> centroid(Polygon<T>& poly) {
    int n = poly.size();
    floating_t cx = 0, cy = 0, area = 0;
    
    for(int i = 0; i < n; i++) {
        int j = (i + 1) % n;
        floating_t cross = poly[i].x * poly[j].y - poly[j].x * poly[i].y;
        cx += (poly[i].x + poly[j].x) * cross;
        cy += (poly[i].y + poly[j].y) * cross;
        area += cross;
    }
    
    area /= 2.0;
    cx /= (6.0 * area);
    cy /= (6.0 * area);
    
    return {cx, cy};
}

Check if Polygon is Convex

template<typename T>
bool isConvex(Polygon<T>& poly) {
    int n = poly.size();
    if(n < 3) return false;
    
    int sign = 0;
    for(int i = 0; i < n; i++) {
        T cross = poly[i].orient(
            poly[(i + 1) % n], 
            poly[(i + 2) % n]
        );
        
        if(cross != 0) {
            if(sign == 0) {
                sign = (cross > 0) ? 1 : -1;
            } else if((cross > 0 ? 1 : -1) != sign) {
                return false;
            }
        }
    }
    
    return true;
}

Type Definitions

typedef long double floating_t;

using point_i = Point<int>;
using point_ll = Point<long long>;
using point_d = Point<double>;

using polygon_i = Polygon<int>;
using polygon_ll = Polygon<long long>;
using polygon_d = Polygon<double>;

Hash Support

For using points in unordered containers:
template<typename T>
struct hasher {
    size_t operator()(const Point<T> &p) const { 
        return hash<T>()(p.x) ^ hash<T>()(p.y);
    }
};

// Usage
unordered_map<Point<int>, int, hasher<int>> mp;
mp[{1, 2}] = 10;

Precision Considerations

Floating point errors: Use appropriate epsilon for comparisons
const double EPS = 1e-9;

bool equals(double a, double b) {
    return abs(a - b) < EPS;
}

bool less(double a, double b) {
    return a < b - EPS;
}
Integer coordinates: Use long long for intermediate calculations to avoid overflow

Next Steps

Explore advanced geometry algorithms:

Convex Hull

Monotone Chain algorithm for finding convex hull

Sweep Line Technique

Advanced algorithmic techniques for geometry

Build docs developers (and LLMs) love