Skip to content

Commit 6cba1b3

Browse files
Implement Delaunay Triangulation using Bowyer–Watson
This implementation uses the Bowyer–Watson algorithm for Delaunay triangulation, ensuring no point lies inside the circumcircle of any triangle. It includes methods for triangulating a set of points and managing triangle and edge relationships.
1 parent 87e79b7 commit 6cba1b3

1 file changed

Lines changed: 110 additions & 0 deletions

File tree

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
package com.thealgorithms.geometry;
2+
3+
import java.util.*;
4+
5+
/**
6+
* Delaunay Triangulation using the Bowyer–Watson algorithm.
7+
*
8+
* Delaunay triangulation ensures that no point lies inside the circumcircle
9+
* of any triangle in the triangulation.
10+
*
11+
* Time Complexity: O(n^2) average
12+
*
13+
* Reference: https://en.wikipedia.org/wiki/Bowyer%E2%80%93Watson_algorithm
14+
*/
15+
public final class DelaunayTriangulation {
16+
17+
private DelaunayTriangulation() {}
18+
19+
public static List<Triangle> triangulate(List<Point> points) {
20+
List<Triangle> triangles = new ArrayList<>();
21+
22+
// 1. Create super triangle large enough to encompass all points
23+
double minX = points.stream().mapToDouble(p -> p.x).min().orElse(0);
24+
double minY = points.stream().mapToDouble(p -> p.y).min().orElse(0);
25+
double maxX = points.stream().mapToDouble(p -> p.x).max().orElse(0);
26+
double maxY = points.stream().mapToDouble(p -> p.y).max().orElse(0);
27+
28+
double dx = maxX - minX;
29+
double dy = maxY - minY;
30+
double deltaMax = Math.max(dx, dy);
31+
double midx = (minX + maxX) / 2;
32+
double midy = (minY + maxY) / 2;
33+
34+
Point p1 = new Point(midx - 20 * deltaMax, midy - deltaMax);
35+
Point p2 = new Point(midx, midy + 20 * deltaMax);
36+
Point p3 = new Point(midx + 20 * deltaMax, midy - deltaMax);
37+
Triangle superTriangle = new Triangle(p1, p2, p3);
38+
triangles.add(superTriangle);
39+
40+
// 2. Add points one by one
41+
for (Point p : points) {
42+
List<Triangle> badTriangles = new ArrayList<>();
43+
44+
for (Triangle t : triangles) {
45+
if (t.isPointInsideCircumcircle(p)) {
46+
badTriangles.add(t);
47+
}
48+
}
49+
50+
List<Edge> polygon = new ArrayList<>();
51+
for (Triangle t : badTriangles) {
52+
for (Edge e : t.getEdges()) {
53+
boolean shared = false;
54+
for (Triangle t2 : badTriangles) {
55+
if (t2 != t && t2.hasEdge(e)) {
56+
shared = true;
57+
break;
58+
}
59+
}
60+
if (!shared) polygon.add(e);
61+
}
62+
}
63+
64+
triangles.removeAll(badTriangles);
65+
for (Edge e : polygon) {
66+
triangles.add(new Triangle(e.p1, e.p2, p));
67+
}
68+
}
69+
70+
// 3. Remove triangles that share vertices with super triangle
71+
triangles.removeIf(t -> t.hasVertex(p1) || t.hasVertex(p2) || t.hasVertex(p3));
72+
return triangles;
73+
}
74+
75+
/** Helper record for representing an Edge. */
76+
public record Edge(Point p1, Point p2) {}
77+
78+
/** Helper class for representing a Triangle. */
79+
public static class Triangle {
80+
final Point a, b, c;
81+
82+
public Triangle(Point a, Point b, Point c) {
83+
this.a = a;
84+
this.b = b;
85+
this.c = c;
86+
}
87+
88+
public boolean hasVertex(Point p) {
89+
return p.equals(a) || p.equals(b) || p.equals(c);
90+
}
91+
92+
public boolean hasEdge(Edge e) {
93+
return hasVertex(e.p1) && hasVertex(e.p2);
94+
}
95+
96+
public List<Edge> getEdges() {
97+
return List.of(new Edge(a, b), new Edge(b, c), new Edge(c, a));
98+
}
99+
100+
public boolean isPointInsideCircumcircle(Point p) {
101+
double ax = a.x - p.x, ay = a.y - p.y;
102+
double bx = b.x - p.x, by = b.y - p.y;
103+
double cx = c.x - p.x, cy = c.y - p.y;
104+
double det = (ax * ax + ay * ay) * (bx * cy - by * cx)
105+
- (bx * bx + by * by) * (ax * cy - ay * cx)
106+
+ (cx * cx + cy * cy) * (ax * by - ay * bx);
107+
return det > 0;
108+
}
109+
}
110+
}

0 commit comments

Comments
 (0)