📐 Geometría Computacional

Algoritmos fundamentales: convex hull, closest pair, Voronoi, sweep line y más.

↩ Volver al índice de módulos

📚 Contenido

🔺 4.1 Primitivas Geométricas

Cross Product (Producto Cruz 2D)

cross(O, A, B) = (A.x - O.x) × (B.y - O.y) - (A.y - O.y) × (B.x - O.x)

cross > 0

Giro a la izquierda (CCW)

cross < 0

Giro a la derecha (CW)

cross = 0

Puntos colineales

Visualización: Giro y Producto Cruz

Haz clic en el canvas para mover B y ver cómo cambia el signo del cross.

Implementación

double cross(Point O, Point A, Point B) {
    return (A.x - O.x) * (B.y - O.y) - (A.y - O.y) * (B.x - O.x);
}

// Orientación: >0 CCW, <0 CW, =0 colineal
int orient(Point a, Point b, Point c) {
    double v = cross(a, b, c);
    if (v > 0) return 1;   // CCW
    if (v < 0) return -1;  // CW
    return 0;              // colineal
}

// Test si segmentos AB y CD se intersectan
bool segmentsIntersect(Point A, Point B, Point C, Point D) {
    int o1 = orient(A, B, C), o2 = orient(A, B, D);
    int o3 = orient(C, D, A), o4 = orient(C, D, B);
    if (o1 * o2 < 0 && o3 * o4 < 0) return true;
    // Casos colineales...
    return false;
}
def cross(o, a, b):
    return (a[0] - o[0]) * (b[1] - o[1]) - (a[1] - o[1]) * (b[0] - o[0])

def orient(a, b, c):
    v = cross(a, b, c)
    if v > 0: return 1   # CCW
    if v < 0: return -1  # CW
    return 0             # colineal

def segments_intersect(a, b, c, d):
    o1, o2 = orient(a, b, c), orient(a, b, d)
    o3, o4 = orient(c, d, a), orient(c, d, b)
    if o1 * o2 < 0 and o3 * o4 < 0:
        return True
    # Casos colineales...
    return False

📍 4.2 Closest Pair Problem

Problema: Dado un conjunto P de n puntos, encontrar el par más cercano en O(n log n).

Divide & Conquer Approach

  1. Ordenar por coordenada x en O(n log n)
  2. Dividir P en mitades izquierda/derecha en la mediana xm
  3. Conquistar: Recursivamente encontrar δL, δR; sea δ = min(δL, δR)
  4. Combinar: Considerar la franja vertical |x - xm| < δ
    • Ordenar puntos en la franja por y (merge de dos listas ordenadas)
    • Cada punto revisa máximo 7 sucesores
T(n) = 2T(n/2) + O(n) = O(n log n)

Visualización: Closest Pair

Genera puntos y encuentra el par más cercano

Implementación

double closestPair(vector<Point>& Px, vector<Point>& Py) {
    int n = Px.size();
    if (n <= 3) return bruteForce(Px);
    
    int mid = n / 2;
    Point midPoint = Px[mid];
    
    vector<Point> Lx(Px.begin(), Px.begin() + mid);
    vector<Point> Rx(Px.begin() + mid, Px.end());
    vector<Point> Ly, Ry;
    for (auto& p : Py) {
        if (p.x <= midPoint.x) Ly.push_back(p);
        else Ry.push_back(p);
    }
    
    double dL = closestPair(Lx, Ly);
    double dR = closestPair(Rx, Ry);
    double d = min(dL, dR);
    
    // Franja
    vector<Point> strip;
    for (auto& p : Py)
        if (abs(p.x - midPoint.x) < d) strip.push_back(p);
    
    for (int i = 0; i < strip.size(); i++)
        for (int j = i + 1; j < strip.size() && strip[j].y - strip[i].y < d; j++)
            d = min(d, dist(strip[i], strip[j]));
    
    return d;
}

🧹 4.3 Line Sweep Algorithm

Bentley-Ottmann: Dado n segmentos en el plano, reportar todas las k intersecciones en O((n + k) log n).

Estructuras Clave

Procesamiento de Eventos

EventoAcción
Left endpointInsertar segmento en status; check con vecinos
Right endpointEliminar segmento; check nuevos vecinos entre sí
IntersectionSwap segmentos en status; check nuevos vecinos

Visualización: Sweep Line

Sweep line encuentra intersecciones de segmentos

🔷 4.4 Convex Hull

Definición: El convex hull de un conjunto de puntos es el polígono convexo más pequeño que contiene todos los puntos.

Algoritmos Principales

AlgoritmoTiempoDescripción
Graham ScanO(n log n)Ordenar por ángulo polar, mantener stack
Jarvis MarchO(nh)Gift wrapping, output-sensitive
Chan's AlgorithmO(n log h)Combina Graham + Jarvis
QuickHullO(n log n) avgDivide & conquer, worst O(n²)

Visualización: Convex Hull

Selecciona un algoritmo para construir el Convex Hull

Graham Scan

vector<Point> grahamScan(vector<Point> pts) {
    int n = pts.size();
    if (n < 3) return pts;
    
    // Encontrar punto más bajo
    int pivot = 0;
    for (int i = 1; i < n; i++)
        if (pts[i].y < pts[pivot].y || 
           (pts[i].y == pts[pivot].y && pts[i].x < pts[pivot].x))
            pivot = i;
    swap(pts[0], pts[pivot]);
    Point p0 = pts[0];
    
    // Ordenar por ángulo polar
    sort(pts.begin() + 1, pts.end(), [&](Point a, Point b) {
        double v = cross(p0, a, b);
        if (v == 0) return dist(p0, a) < dist(p0, b);
        return v > 0;
    });
    
    // Construir hull
    vector<Point> hull;
    for (auto& p : pts) {
        while (hull.size() >= 2 && 
               cross(hull[hull.size()-2], hull[hull.size()-1], p) <= 0)
            hull.pop_back();
        hull.push_back(p);
    }
    return hull;
}
def graham_scan(pts):
    if len(pts) < 3:
        return pts
    
    # Encontrar punto más bajo
    p0 = min(pts, key=lambda p: (p[1], p[0]))
    pts = sorted(pts, key=lambda p: (
        math.atan2(p[1] - p0[1], p[0] - p0[0]),
        (p[0] - p0[0])**2 + (p[1] - p0[1])**2
    ))
    
    # Construir hull
    hull = []
    for p in pts:
        while len(hull) >= 2 and cross(hull[-2], hull[-1], p) <= 0:
            hull.pop()
        hull.append(p)
    return hull

🎯 4.5 Voronoi Diagrams & Delaunay

Voronoi Cell: Para sitios P = {pi}, la celda de pi es:
Vor(pᵢ) = {x ∈ ℝ² : ||x - pᵢ|| ≤ ||x - pⱼ|| ∀j ≠ i}

Propiedades

Voronoi Diagram

Divide el plano en regiones por cercanía

Fortune's sweep: O(n log n)

Delaunay Triangulation

Maximiza el ángulo mínimo

Ningún punto dentro del circumcírculo

Fortune's Algorithm

Aplicaciones

Visualización: Voronoi (Crecimiento de Regiones)

Las regiones crecen desde cada sitio hasta chocar con sus vecinos.

🎲 4.7 Algoritmos Randomizados

Seidel's Randomized 2D LP

Problema: min{c₁x + c₂y | aᵢ₁x + aᵢ₂y ≤ bᵢ}

Tiempo esperado: O(n)

Enfoque

  1. Permutar constraints aleatoriamente
  2. Agregar constraints incrementalmente
  3. Si nueva constraint viola solución actual → resolver LP 1D en la línea boundary

Cada constraint causa violación con probabilidad ≤ 2/i

RANSAC (Computer Vision)

Monte Carlo π Estimation

π ≈ 4 × (puntos dentro / puntos totales)

📝 Quiz - Geometría Computacional

1. ¿Cuál es la complejidad del algoritmo Closest Pair con divide & conquer?

2. Si cross(O, A, B) > 0, ¿qué indica sobre el giro O→A→B?

3. ¿Cuál algoritmo de convex hull es output-sensitive?

4. La triangulación de Delaunay es el grafo dual de:

5. ¿Cuál es la complejidad esperada de Seidel's 2D LP?

6. Bentley-Ottmann reporta k intersecciones de n segmentos en: