1use crate::{
2 coord::{Line, Point, Vector},
3 series::{SNumber, Series},
4 TAU,
5};
6use approx::AbsDiffEq;
7use core::cmp::Ordering;
8pub const EMPTY: usize = usize::MAX;
9
10pub fn triangle(sx: Series, sy: Series) -> Triangulation {
11 let mut ax: SNumber = SNumber::new([].to_vec());
12 let mut ay: SNumber = SNumber::new([].to_vec());
13 let mut points: Vec<Point> = [].to_vec();
14 if let Series::Number(x) = sx {
15 ax = x;
16 }
17 if let Series::Number(y) = sy {
18 ay = y;
19 }
20
21 for (index, data) in ax.series().iter().enumerate() {
22 points.push(Point::new(*data, ay.series()[index]));
23 }
24 let slice = &points[..];
25
26 triangulate(slice)
27}
28
29pub fn next_halfedge(i: usize) -> usize {
31 if i % 3 == 2 {
32 i - 2
33 } else {
34 i + 1
35 }
36}
37
38pub fn prev_halfedge(i: usize) -> usize {
40 if i % 3 == 0 {
41 i + 2
42 } else {
43 i - 1
44 }
45}
46
47#[derive(Debug, Clone)]
49pub struct Triangulation {
50 pub triangles: Vec<usize>,
53
54 pub halfedges: Vec<usize>,
60
61 pub hull: Vec<usize>,
64
65 pub vertices: Vec<Point>,
67
68 pub voronois: Vec<Vec<usize>>,
69 pub voronoi_edges: Vec<Line>,
70
71 pub tuple_triangles: Vec<Vec<usize>>,
72 pub tuple_halfedges: Vec<Vec<usize>>,
73}
74
75impl Triangulation {
76 fn new(n: usize) -> Self {
77 let max_triangles = if n > 2 { 2 * n - 5 } else { 0 };
78
79 Self {
80 triangles: Vec::with_capacity(max_triangles * 3),
81 halfedges: Vec::with_capacity(max_triangles * 3),
82 hull: Vec::new(),
83 vertices: Vec::new(),
84 tuple_triangles: Vec::new(),
85 tuple_halfedges: Vec::new(),
86 voronois: Vec::new(),
87 voronoi_edges: Vec::new(),
88 }
89 }
90
91 pub fn len(&self) -> usize {
93 self.triangles.len() / 3
94 }
95
96 pub fn is_empty(&self) -> bool {
97 self.triangles.is_empty()
98 }
99
100 fn add_triangle(
101 &mut self,
102 i0: usize,
103 i1: usize,
104 i2: usize,
105 a: usize,
106 b: usize,
107 c: usize,
108 ) -> usize {
109 let t = self.triangles.len();
110
111 self.triangles.push(i0);
112 self.triangles.push(i1);
113 self.triangles.push(i2);
114
115 self.halfedges.push(a);
116 self.halfedges.push(b);
117 self.halfedges.push(c);
118
119 if a != EMPTY {
120 self.halfedges[a] = t;
121 }
122 if b != EMPTY {
123 self.halfedges[b] = t + 1;
124 }
125 if c != EMPTY {
126 self.halfedges[c] = t + 2;
127 }
128
129 t
130 }
131
132 fn legalize(&mut self, a: usize, points: &[Point], hull: &mut Hull) -> usize {
133 let b = self.halfedges[a];
134
135 let ar = prev_halfedge(a);
151
152 if b == EMPTY {
153 return ar;
154 }
155
156 let al = next_halfedge(a);
157 let bl = prev_halfedge(b);
158
159 let p0 = self.triangles[ar];
160 let pr = self.triangles[a];
161 let pl = self.triangles[al];
162 let p1 = self.triangles[bl];
163
164 let illegal = points[p0].in_circle(&points[pr], &points[pl], &points[p1]);
165 if illegal {
166 self.triangles[a] = p1;
167 self.triangles[b] = p0;
168
169 let hbl = self.halfedges[bl];
170 let har = self.halfedges[ar];
171
172 if hbl == EMPTY {
174 let mut e = hull.start;
175 loop {
176 if hull.tri[e] == bl {
177 hull.tri[e] = a;
178 break;
179 }
180 e = hull.prev[e];
181 if e == hull.start {
182 break;
183 }
184 }
185 }
186
187 self.halfedges[a] = hbl;
188 self.halfedges[b] = har;
189 self.halfedges[ar] = bl;
190
191 if hbl != EMPTY {
192 self.halfedges[hbl] = a;
193 }
194 if har != EMPTY {
195 self.halfedges[har] = b;
196 }
197 if bl != EMPTY {
198 self.halfedges[bl] = ar;
199 }
200
201 let br = next_halfedge(b);
202
203 self.legalize(a, points, hull);
204 return self.legalize(br, points, hull);
205 }
206 ar
207 }
208}
209
210#[derive(Debug)]
212struct Hull {
213 prev: Vec<usize>,
214 next: Vec<usize>,
215 tri: Vec<usize>,
216 hash: Vec<usize>,
217 start: usize,
218 center: Point,
219}
220
221impl Hull {
222 fn new(n: usize, center: Point, i0: usize, i1: usize, i2: usize, points: &[Point]) -> Self {
223 let hash_len = (n as f64).sqrt() as usize;
224
225 let mut hull = Self {
226 prev: vec![0; n], next: vec![0; n], tri: vec![0; n], hash: vec![EMPTY; hash_len], start: i0,
231 center,
232 };
233
234 hull.next[i0] = i1;
235 hull.prev[i2] = i1;
236 hull.next[i1] = i2;
237 hull.prev[i0] = i2;
238 hull.next[i2] = i0;
239 hull.prev[i1] = i0;
240
241 hull.tri[i0] = 0;
242 hull.tri[i1] = 1;
243 hull.tri[i2] = 2;
244
245 hull.hash_edge(&points[i0], i0);
246 hull.hash_edge(&points[i1], i1);
247 hull.hash_edge(&points[i2], i2);
248
249 hull
250 }
251
252 fn hash_key(&self, p: &Point) -> usize {
253 let dx = p.get_x() - self.center.get_x();
254 let dy = p.get_y() - self.center.get_y();
255
256 let p = dx / (dx.abs() + dy.abs());
257
258 let a = (if dy > 0.0 { 3.0 - p } else { 1.0 + p }) / 4.0; let len = self.hash.len();
261
262 (((len as f64) * a).floor() as usize) % len
263 }
264
265 fn hash_edge(&mut self, p: &Point, i: usize) {
266 let key = self.hash_key(p);
267
268 self.hash[key] = i;
269 }
270
271 fn find_visible_edge(&self, p: &Point, points: &[Point]) -> (usize, bool) {
272 let mut start: usize = 0;
273 let key = self.hash_key(p);
274 let len = self.hash.len();
275
276 for j in 0..len {
277 start = self.hash[(key + j) % len];
278 if start != EMPTY && self.next[start] != EMPTY {
279 break;
280 }
281 }
282
283 start = self.prev[start];
284
285 let mut e = start;
286
287 while p.orient(&points[e], &points[self.next[e]]) <= 0. {
288 e = self.next[e];
289 if e == start {
290 return (EMPTY, false);
291 }
292 }
293
294 (e, e == start)
295 }
296}
297
298fn calc_bbox_center(points: &[Point]) -> Point {
300 let mut min_x = f64::INFINITY;
301 let mut min_y = f64::INFINITY;
302 let mut max_x = f64::NEG_INFINITY;
303 let mut max_y = f64::NEG_INFINITY;
304 for p in points.iter() {
305 min_x = min_x.min(p.get_x());
306 min_y = min_y.min(p.get_y());
307 max_x = max_x.max(p.get_x());
308 max_y = max_y.max(p.get_y());
309 }
310 Point::new((min_x + max_x) / 2.0, (min_y + max_y) / 2.0)
311}
312
313fn find_closest_point(points: &[Point], p0: &Point) -> Option<usize> {
314 let mut min_dist = f64::INFINITY;
315 let mut k: usize = 0;
316 for (i, p) in points.iter().enumerate() {
317 let d = p0.dist2(p);
318 if d > 0.0 && d < min_dist {
319 k = i;
320 min_dist = d;
321 }
322 }
323 if min_dist == f64::INFINITY {
324 None
325 } else {
326 Some(k)
327 }
328}
329
330fn find_seed_triangle(points: &[Point]) -> Option<(usize, usize, usize)> {
331 let bbox_center = calc_bbox_center(points);
333
334 let i0 = find_closest_point(points, &bbox_center)?;
335 let p0 = &points[i0];
336
337 let i1 = find_closest_point(points, p0)?;
339
340 let p1 = &points[i1];
341 let mut min_radius = f64::INFINITY;
343 let mut i2: usize = 0;
344 for (i, p) in points.iter().enumerate() {
345 if i == i0 || i == i1 {
346 continue;
347 }
348 let r = p0.circumradius2(p1, p);
349 if r < min_radius {
350 i2 = i;
351 min_radius = r;
352 }
353 }
354
355 if min_radius == f64::INFINITY {
356 None
357 } else {
358 Some(if p0.orient(p1, &points[i2]) > 0. {
360 (i0, i2, i1)
361 } else {
362 (i0, i1, i2)
363 })
364 }
365}
366
367fn sortf(f: &mut [(usize, f64)]) {
368 f.sort_unstable_by(|&(_, da), &(_, db)| da.partial_cmp(&db).unwrap_or(Ordering::Equal));
369}
370
371fn handle_collinear_points(points: &[Point]) -> Triangulation {
373 let pf = points.first().cloned().unwrap_or_default();
374
375 let mut dist: Vec<_> = points
376 .iter()
377 .enumerate()
378 .map(|(i, p)| {
379 let mut d = p.get_x() - pf.get_x();
380 if d == 0.0 {
381 d = p.get_y() - pf.get_y();
382 }
383 (i, d)
384 })
385 .collect();
386 sortf(&mut dist);
387
388 let mut triangulation = Triangulation::new(0);
389 let mut d0 = f64::NEG_INFINITY;
390 for (i, distance) in dist {
391 if distance > d0 {
392 triangulation.hull.push(i);
393 d0 = distance;
394 }
395 }
396
397 triangulation
398}
399
400pub fn triangulate(points: &[Point]) -> Triangulation {
404 let seed_triangle = find_seed_triangle(points);
405
406 if seed_triangle.is_none() {
407 return handle_collinear_points(points);
408 }
409
410 let n = points.len();
411 let (i0, i1, i2) =
412 seed_triangle.expect("At this stage, points are guaranteed to yeild a seed triangle");
413 let center = points[i0].circumcenter(&points[i1], &points[i2]);
414
415 let mut triangulation = Triangulation::new(n);
416 triangulation.add_triangle(i0, i1, i2, EMPTY, EMPTY, EMPTY);
417
418 let mut dists: Vec<_> = points
420 .iter()
421 .enumerate()
422 .map(|(i, point)| (i, center.dist2(point)))
423 .collect();
424
425 sortf(&mut dists);
426
427 let mut hull = Hull::new(n, center, i0, i1, i2, points);
428
429 for (k, &(i, _)) in dists.iter().enumerate() {
430 let p = &points[i];
431
432 if k > 0 && p.abs_diff_eq(&points[dists[k - 1].0], Point::default_epsilon()) {
435 continue;
436 }
437 if i == i0 || i == i1 || i == i2 {
439 continue;
440 }
441
442 let (mut e, walk_back) = hull.find_visible_edge(p, points);
444 if e == EMPTY {
445 continue; }
447
448 let t = triangulation.add_triangle(e, i, hull.next[e], EMPTY, EMPTY, hull.tri[e]);
450
451 hull.tri[i] = triangulation.legalize(t + 2, points, &mut hull);
453 hull.tri[e] = t; let mut n = hull.next[e];
457 loop {
458 let q = hull.next[n];
459 if p.orient(&points[n], &points[q]) <= 0. {
460 break;
461 }
462 let t = triangulation.add_triangle(n, i, q, hull.tri[i], EMPTY, hull.tri[n]);
463 hull.tri[i] = triangulation.legalize(t + 2, points, &mut hull);
464 hull.next[n] = EMPTY; n = q;
466 }
467
468 if walk_back {
470 loop {
471 let q = hull.prev[e];
472 if p.orient(&points[q], &points[e]) <= 0. {
473 break;
474 }
475 let t = triangulation.add_triangle(q, i, e, EMPTY, hull.tri[e], hull.tri[q]);
476 triangulation.legalize(t + 2, points, &mut hull);
477 hull.tri[q] = t;
478 hull.next[e] = EMPTY; e = q;
480 }
481 }
482
483 hull.prev[i] = e;
485 hull.next[i] = n;
486 hull.prev[n] = i;
487 hull.next[e] = i;
488 hull.start = e;
489
490 hull.hash_edge(p, i);
492 hull.hash_edge(&points[e], e);
493 }
494
495 let mut e = hull.start;
497 loop {
498 triangulation.hull.push(e);
499 e = hull.next[e];
500 if e == hull.start {
501 break;
502 }
503 }
504
505 triangulation.triangles.shrink_to_fit();
506 triangulation.halfedges.shrink_to_fit();
507
508 for index in (0..triangulation.triangles.len()).step_by(3) {
510 let p0 = triangulation.triangles[index];
511 let p1 = triangulation.triangles[index + 1];
512 let p2 = triangulation.triangles[index + 2];
513 triangulation.tuple_triangles.push([p0, p1, p2].to_vec());
514
515 let center = &points[p0].circumcenter(&points[p1], &points[p2]);
516 triangulation.vertices.push(center.clone());
517
518 let e1_i = triangulation.halfedges[index];
519 let e2_i = triangulation.halfedges[index + 1];
520 let e3_i = triangulation.halfedges[index + 2];
521 triangulation
522 .tuple_halfedges
523 .push([e1_i, e2_i, e3_i].to_vec());
524 }
525
526 for index in 0..points.len() {
527 if !triangulation.hull.contains(&index) {
528 let mut voronoi_all: Vec<(usize, Vec<usize>)> = Vec::new();
529 for (pos, tri) in triangulation.tuple_triangles.iter().enumerate() {
530
531 if tri.contains(&index) {
532 let mut new = tri.clone();
533 if tri[1] == index {
534 new.reverse();
535 }
536 new.retain(|&x| x != index);
537
538 voronoi_all.push((pos, new));
539 }
540 }
541
542 let voronoi = sortv(voronoi_all);
543 triangulation.voronois.push(voronoi);
544 }
545 }
546
547 let mut temp = triangulation.hull.clone();
548 let f = triangulation.hull.first().unwrap();
549 temp.push(*f);
550
551 for pos in 1..temp.len() {
552 let pi0 = temp[pos - 1];
553 let pi1 = temp[pos];
554 let p0 = &points[pi0];
555 let p1 = &points[pi1];
556
557 let square = Vector::from((p0.clone(), p1.clone())).az_rotate_tau(0.25 * TAU);
558
559 for (pos, tri) in triangulation.tuple_triangles.iter().enumerate() {
560 if tri.contains(&pi0) && tri.contains(&pi1) {
561 triangulation.voronoi_edges.push(Line::new(
562 triangulation.vertices[pos].clone(),
563 square.clone(),
564 ))
565 }
566 }
567 }
568
569 triangulation
570}
571
572fn sortv(vec_voronoi: Vec<(usize, Vec<usize>)>) -> Vec<usize> {
573 let mut sort: Vec<(usize, Vec<usize>)> = Vec::new();
574 if vec_voronoi.len() <= 3 {
575 sort = vec_voronoi;
576 } else {
577 let mut slice = vec_voronoi.clone();
578 sort.push(slice[0].clone());
579 slice.remove(0);
580
581 while slice.len() != 0 {
582 let value = sort.last().unwrap();
583 let mut index = 0;
584 for (pos, data) in slice.iter().enumerate() {
585 if data.1[0] == value.1[1] {
586 sort.push(data.clone());
587 index = pos;
588 break;
589 }
590 }
591 slice.remove(index);
592 }
593 }
594 let mut result: Vec<usize> = Vec::new();
595 for data in sort.iter() {
596 result.push(data.0);
597 }
598 result
599}