1use crate::{Cell, Grid};
4use std::collections::HashSet;
5
6#[derive(Debug, Clone, Copy, PartialEq)]
7pub struct Point {
8 pub x: f32,
9 pub y: f32,
10}
11
12impl Point {
13 pub fn new(x: f32, y: f32) -> Self {
14 Self { x, y }
15 }
16
17 pub fn distance_to(&self, other: &Point) -> f32 {
18 ((self.x - other.x).powi(2) + (self.y - other.y).powi(2)).sqrt()
19 }
20}
21
22#[derive(Debug, Clone, Copy, PartialEq)]
23pub struct Triangle {
24 pub a: usize,
25 pub b: usize,
26 pub c: usize,
27}
28
29impl Triangle {
30 pub fn new(a: usize, b: usize, c: usize) -> Self {
31 Self { a, b, c }
32 }
33
34 pub fn contains_vertex(&self, vertex: usize) -> bool {
35 self.a == vertex || self.b == vertex || self.c == vertex
36 }
37
38 pub fn circumcenter(&self, points: &[Point]) -> Point {
39 let pa = points[self.a];
40 let pb = points[self.b];
41 let pc = points[self.c];
42
43 let d = 2.0 * (pa.x * (pb.y - pc.y) + pb.x * (pc.y - pa.y) + pc.x * (pa.y - pb.y));
44
45 if d.abs() < f32::EPSILON {
46 return Point::new((pa.x + pb.x + pc.x) / 3.0, (pa.y + pb.y + pc.y) / 3.0);
48 }
49
50 let ux = (pa.x * pa.x + pa.y * pa.y) * (pb.y - pc.y)
51 + (pb.x * pb.x + pb.y * pb.y) * (pc.y - pa.y)
52 + (pc.x * pc.x + pc.y * pc.y) * (pa.y - pb.y);
53
54 let uy = (pa.x * pa.x + pa.y * pa.y) * (pc.x - pb.x)
55 + (pb.x * pb.x + pb.y * pb.y) * (pa.x - pc.x)
56 + (pc.x * pc.x + pc.y * pc.y) * (pb.x - pa.x);
57
58 Point::new(ux / d, uy / d)
59 }
60
61 pub fn circumradius(&self, points: &[Point]) -> f32 {
62 let center = self.circumcenter(points);
63 center.distance_to(&points[self.a])
64 }
65
66 pub fn in_circumcircle(&self, points: &[Point], point: &Point) -> bool {
67 let center = self.circumcenter(points);
68 let radius = self.circumradius(points);
69 center.distance_to(point) < radius + f32::EPSILON
70 }
71}
72
73#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
74pub struct Edge {
75 pub a: usize,
76 pub b: usize,
77}
78
79impl Edge {
80 pub fn new(a: usize, b: usize) -> Self {
81 if a < b {
82 Self { a, b }
83 } else {
84 Self { a: b, b: a }
85 }
86 }
87
88 pub fn length(&self, points: &[Point]) -> f32 {
89 points[self.a].distance_to(&points[self.b])
90 }
91}
92
93pub struct DelaunayTriangulation {
94 pub points: Vec<Point>,
95 pub triangles: Vec<Triangle>,
96 pub edges: Vec<Edge>,
97}
98
99impl DelaunayTriangulation {
100 pub fn new(points: Vec<Point>) -> Self {
101 let mut triangulation = Self {
102 points,
103 triangles: Vec::new(),
104 edges: Vec::new(),
105 };
106
107 if triangulation.points.len() >= 3 {
108 triangulation.triangulate();
109 }
110
111 triangulation
112 }
113
114 fn triangulate(&mut self) {
115 if self.points.len() < 3 {
116 return;
117 }
118
119 let (min_x, max_x, min_y, max_y) = self.bounding_box();
121 let dx = max_x - min_x;
122 let dy = max_y - min_y;
123 let delta_max = dx.max(dy);
124 let mid_x = (min_x + max_x) / 2.0;
125 let mid_y = (min_y + max_y) / 2.0;
126
127 let super_a = self.points.len();
128 let super_b = self.points.len() + 1;
129 let super_c = self.points.len() + 2;
130
131 self.points
132 .push(Point::new(mid_x - 20.0 * delta_max, mid_y - delta_max));
133 self.points
134 .push(Point::new(mid_x, mid_y + 20.0 * delta_max));
135 self.points
136 .push(Point::new(mid_x + 20.0 * delta_max, mid_y - delta_max));
137
138 self.triangles
139 .push(Triangle::new(super_a, super_b, super_c));
140
141 for i in 0..super_a {
143 let point = self.points[i];
144 let mut bad_triangles = Vec::new();
145 let mut polygon = Vec::new();
146
147 for (j, triangle) in self.triangles.iter().enumerate() {
149 if triangle.in_circumcircle(&self.points, &point) {
150 bad_triangles.push(j);
151 }
152 }
153
154 for &bad_idx in &bad_triangles {
156 let bad_tri = self.triangles[bad_idx];
157 let edges = [
158 Edge::new(bad_tri.a, bad_tri.b),
159 Edge::new(bad_tri.b, bad_tri.c),
160 Edge::new(bad_tri.c, bad_tri.a),
161 ];
162
163 for edge in edges {
164 let mut is_shared = false;
165 for &other_idx in &bad_triangles {
166 if other_idx != bad_idx {
167 let other_tri = self.triangles[other_idx];
168 let other_edges = [
169 Edge::new(other_tri.a, other_tri.b),
170 Edge::new(other_tri.b, other_tri.c),
171 Edge::new(other_tri.c, other_tri.a),
172 ];
173 if other_edges.contains(&edge) {
174 is_shared = true;
175 break;
176 }
177 }
178 }
179 if !is_shared {
180 polygon.push(edge);
181 }
182 }
183 }
184
185 bad_triangles.sort_by(|a, b| b.cmp(a));
187 for &idx in &bad_triangles {
188 self.triangles.remove(idx);
189 }
190
191 for edge in polygon {
193 self.triangles.push(Triangle::new(edge.a, edge.b, i));
194 }
195 }
196
197 self.triangles.retain(|tri| {
199 !tri.contains_vertex(super_a)
200 && !tri.contains_vertex(super_b)
201 && !tri.contains_vertex(super_c)
202 });
203
204 self.points.truncate(super_a);
206
207 let mut edge_set = HashSet::new();
209 for triangle in &self.triangles {
210 edge_set.insert(Edge::new(triangle.a, triangle.b));
211 edge_set.insert(Edge::new(triangle.b, triangle.c));
212 edge_set.insert(Edge::new(triangle.c, triangle.a));
213 }
214 self.edges = edge_set.into_iter().collect();
215 }
216
217 fn bounding_box(&self) -> (f32, f32, f32, f32) {
218 if self.points.is_empty() {
219 return (0.0, 0.0, 0.0, 0.0);
220 }
221
222 let mut min_x = self.points[0].x;
223 let mut max_x = self.points[0].x;
224 let mut min_y = self.points[0].y;
225 let mut max_y = self.points[0].y;
226
227 for point in &self.points {
228 min_x = min_x.min(point.x);
229 max_x = max_x.max(point.x);
230 min_y = min_y.min(point.y);
231 max_y = max_y.max(point.y);
232 }
233
234 (min_x, max_x, min_y, max_y)
235 }
236
237 pub fn minimum_spanning_tree(&self) -> Vec<Edge> {
238 if self.edges.is_empty() {
239 return Vec::new();
240 }
241
242 let mut mst_edges = Vec::new();
243 let mut edges = self.edges.clone();
244 edges.sort_by(|a, b| {
245 a.length(&self.points)
246 .partial_cmp(&b.length(&self.points))
247 .unwrap()
248 });
249
250 let mut parent: Vec<usize> = (0..self.points.len()).collect();
251
252 fn find(parent: &mut [usize], x: usize) -> usize {
253 if parent[x] != x {
254 parent[x] = find(parent, parent[x]);
255 }
256 parent[x]
257 }
258
259 fn union(parent: &mut [usize], x: usize, y: usize) {
260 let px = find(parent, x);
261 let py = find(parent, y);
262 if px != py {
263 parent[px] = py;
264 }
265 }
266
267 for edge in edges {
268 let root_a = find(&mut parent, edge.a);
269 let root_b = find(&mut parent, edge.b);
270
271 if root_a != root_b {
272 mst_edges.push(edge);
273 union(&mut parent, edge.a, edge.b);
274
275 if mst_edges.len() == self.points.len() - 1 {
276 break;
277 }
278 }
279 }
280
281 mst_edges
282 }
283}
284
285pub fn connect_rooms<C: Cell>(grid: &mut Grid<C>, room_centers: &[Point]) -> Vec<Edge> {
287 if room_centers.len() < 2 {
288 return Vec::new();
289 }
290
291 let triangulation = DelaunayTriangulation::new(room_centers.to_vec());
292 let mst = triangulation.minimum_spanning_tree();
293
294 for edge in &mst {
296 let start = triangulation.points[edge.a];
297 let end = triangulation.points[edge.b];
298 draw_line(grid, start, end);
299 }
300
301 mst
302}
303
304fn draw_line<C: Cell>(grid: &mut Grid<C>, start: Point, end: Point) {
305 let dx = (end.x - start.x).abs();
306 let dy = (end.y - start.y).abs();
307 let steps = (dx.max(dy) as usize).max(1);
308
309 for i in 0..=steps {
310 let t = i as f32 / steps as f32;
311 let x = (start.x + t * (end.x - start.x)) as i32;
312 let y = (start.y + t * (end.y - start.y)) as i32;
313
314 if let Some(cell) = grid.get_mut(x, y) {
315 if !cell.is_passable() {
316 }
319 }
320 }
321}