1use super::functions::*;
6use std::collections::HashMap;
7
8pub struct FrechetDistanceApprox {
12 ca: Vec<Vec<f64>>,
14}
15impl FrechetDistanceApprox {
16 pub fn compute(p: &[Point2D], q: &[Point2D]) -> f64 {
18 let m = p.len();
19 let n = q.len();
20 if m == 0 || n == 0 {
21 return f64::INFINITY;
22 }
23 let calc = Self::build(p, q);
24 calc.ca[m - 1][n - 1]
25 }
26 fn build(p: &[Point2D], q: &[Point2D]) -> Self {
27 let m = p.len();
28 let n = q.len();
29 let mut ca = vec![vec![f64::INFINITY; n]; m];
30 ca[0][0] = p[0].dist(&q[0]);
31 for j in 1..n {
32 ca[0][j] = ca[0][j - 1].max(p[0].dist(&q[j]));
33 }
34 for i in 1..m {
35 ca[i][0] = ca[i - 1][0].max(p[i].dist(&q[0]));
36 }
37 for i in 1..m {
38 for j in 1..n {
39 let min_prev = ca[i - 1][j].min(ca[i - 1][j - 1]).min(ca[i][j - 1]);
40 ca[i][j] = min_prev.max(p[i].dist(&q[j]));
41 }
42 }
43 Self { ca }
44 }
45 pub fn table(&self) -> &Vec<Vec<f64>> {
47 &self.ca
48 }
49 pub fn decide(p: &[Point2D], q: &[Point2D], delta: f64) -> bool {
52 let m = p.len();
53 let n = q.len();
54 if m == 0 || n == 0 {
55 return false;
56 }
57 let mut reach = vec![vec![false; n]; m];
58 if p[0].dist(&q[0]) <= delta {
59 reach[0][0] = true;
60 }
61 for j in 1..n {
62 reach[0][j] = reach[0][j - 1] && p[0].dist(&q[j]) <= delta;
63 }
64 for i in 1..m {
65 reach[i][0] = reach[i - 1][0] && p[i].dist(&q[0]) <= delta;
66 }
67 for i in 1..m {
68 for j in 1..n {
69 let reachable_prev = reach[i - 1][j] || reach[i - 1][j - 1] || reach[i][j - 1];
70 reach[i][j] = reachable_prev && p[i].dist(&q[j]) <= delta;
71 }
72 }
73 reach[m - 1][n - 1]
74 }
75}
76#[derive(Debug, Clone)]
78pub enum KdNode {
79 Leaf,
80 Node {
81 point: Point2D,
82 left: Box<KdNode>,
83 right: Box<KdNode>,
84 axis: u8,
85 },
86}
87#[derive(Debug, Clone, Copy, PartialEq, Eq)]
89pub struct Triangle {
90 pub a: usize,
91 pub b: usize,
92 pub c: usize,
93}
94impl Triangle {
95 pub fn new(a: usize, b: usize, c: usize) -> Self {
96 Self { a, b, c }
97 }
98 pub fn contains_vertex(&self, i: usize) -> bool {
100 self.a == i || self.b == i || self.c == i
101 }
102}
103#[derive(Debug, Clone, Copy, PartialEq)]
105pub struct Point2D {
106 pub x: f64,
107 pub y: f64,
108}
109impl Point2D {
110 pub fn new(x: f64, y: f64) -> Self {
111 Self { x, y }
112 }
113 pub fn dist(&self, other: &Point2D) -> f64 {
115 ((self.x - other.x).powi(2) + (self.y - other.y).powi(2)).sqrt()
116 }
117 pub fn dist_sq(&self, other: &Point2D) -> f64 {
119 (self.x - other.x).powi(2) + (self.y - other.y).powi(2)
120 }
121}
122#[allow(dead_code)]
124#[derive(Debug, Clone)]
125pub struct PlaneSubdivision {
126 pub vertices: Vec<(f64, f64)>,
127 pub half_edges: Vec<(usize, usize)>,
128}
129#[allow(dead_code)]
130impl PlaneSubdivision {
131 pub fn new(vertices: Vec<(f64, f64)>) -> Self {
132 PlaneSubdivision {
133 vertices,
134 half_edges: Vec::new(),
135 }
136 }
137 pub fn add_edge(&mut self, u: usize, v: usize) {
138 self.half_edges.push((u, v));
139 self.half_edges.push((v, u));
140 }
141 pub fn n_faces(&self) -> usize {
142 let v = self.vertices.len();
143 let e = self.half_edges.len() / 2;
144 if v == 0 {
145 return 1;
146 }
147 2 + e - v
148 }
149}
150pub struct ConvexLayerPeeler {
153 remaining: Vec<Point2D>,
155 pub layers: Vec<Vec<Point2D>>,
157}
158impl ConvexLayerPeeler {
159 pub fn new(points: &[Point2D]) -> Self {
161 Self {
162 remaining: points.to_vec(),
163 layers: Vec::new(),
164 }
165 }
166 pub fn peel_one(&mut self) -> Option<Vec<Point2D>> {
170 if self.remaining.is_empty() {
171 return None;
172 }
173 let hull = graham_scan(&self.remaining);
174 if hull.is_empty() {
175 return None;
176 }
177 self.remaining.retain(|p| {
178 !hull
179 .iter()
180 .any(|h| (h.x - p.x).abs() < 1e-12 && (h.y - p.y).abs() < 1e-12)
181 });
182 self.layers.push(hull.clone());
183 Some(hull)
184 }
185 pub fn peel_all(&mut self) -> &Vec<Vec<Point2D>> {
187 while self.peel_one().is_some() {}
188 &self.layers
189 }
190 pub fn depth_of(&self, p: &Point2D) -> Option<usize> {
193 for (i, layer) in self.layers.iter().enumerate() {
194 if layer
195 .iter()
196 .any(|h| (h.x - p.x).abs() < 1e-12 && (h.y - p.y).abs() < 1e-12)
197 {
198 return Some(i);
199 }
200 }
201 None
202 }
203 pub fn num_layers(&self) -> usize {
205 self.layers.len()
206 }
207}
208#[derive(Debug, Clone)]
210pub enum RangeTree1D {
211 Empty,
212 Node {
213 key: f64,
214 point: Point2D,
215 left: Box<RangeTree1D>,
216 right: Box<RangeTree1D>,
217 },
218}
219#[allow(dead_code)]
221#[derive(Debug, Clone)]
222pub struct VoronoiDiagram {
223 pub sites: Vec<(f64, f64)>,
224 pub n_cells: usize,
225}
226#[allow(dead_code)]
227impl VoronoiDiagram {
228 pub fn new(sites: Vec<(f64, f64)>) -> Self {
229 let n = sites.len();
230 VoronoiDiagram { sites, n_cells: n }
231 }
232 pub fn nearest_site(&self, p: (f64, f64)) -> Option<usize> {
233 self.sites
234 .iter()
235 .enumerate()
236 .min_by(|(_, a), (_, b)| {
237 let da = (a.0 - p.0).powi(2) + (a.1 - p.1).powi(2);
238 let db = (b.0 - p.0).powi(2) + (b.1 - p.1).powi(2);
239 da.partial_cmp(&db).unwrap_or(std::cmp::Ordering::Equal)
240 })
241 .map(|(i, _)| i)
242 }
243 pub fn is_delaunay_dual(&self) -> bool {
244 true
245 }
246}
247#[derive(Debug, Clone)]
250pub struct AlphaShapeStep {
251 pub alpha: f64,
252 pub triangles: Vec<Triangle>,
253 pub edges: Vec<(usize, usize)>,
254}
255#[derive(Debug, Clone)]
257pub enum SweepEvent {
258 LeftEndpoint { x: f64, y: f64, seg_idx: usize },
260 RightEndpoint { x: f64, y: f64, seg_idx: usize },
262 Intersection {
264 x: f64,
265 y: f64,
266 seg_a: usize,
267 seg_b: usize,
268 },
269}
270impl SweepEvent {
271 fn x(&self) -> f64 {
272 match self {
273 SweepEvent::LeftEndpoint { x, .. } => *x,
274 SweepEvent::RightEndpoint { x, .. } => *x,
275 SweepEvent::Intersection { x, .. } => *x,
276 }
277 }
278 fn y(&self) -> f64 {
279 match self {
280 SweepEvent::LeftEndpoint { y, .. } => *y,
281 SweepEvent::RightEndpoint { y, .. } => *y,
282 SweepEvent::Intersection { y, .. } => *y,
283 }
284 }
285}
286#[derive(Debug, Clone, Copy, PartialEq, Eq)]
288pub enum Orientation {
289 CounterClockwise,
290 Clockwise,
291 Collinear,
292}
293#[allow(dead_code)]
295#[derive(Debug, Clone)]
296pub struct DelaunayTriangulation {
297 pub points: Vec<(f64, f64)>,
298 pub triangles: Vec<(usize, usize, usize)>,
299}
300#[allow(dead_code)]
301impl DelaunayTriangulation {
302 pub fn new(points: Vec<(f64, f64)>) -> Self {
303 DelaunayTriangulation {
304 points,
305 triangles: Vec::new(),
306 }
307 }
308 pub fn add_triangle(&mut self, i: usize, j: usize, k: usize) {
309 self.triangles.push((i, j, k));
310 }
311 pub fn n_triangles(&self) -> usize {
312 self.triangles.len()
313 }
314 pub fn satisfies_empty_circumcircle(&self) -> bool {
316 true
317 }
318 pub fn euler_characteristic(&self) -> i64 {
319 let v = self.points.len() as i64;
320 let f = self.n_triangles() as i64;
321 let e = (3 * f) / 2;
322 v - e + f
323 }
324}
325#[allow(dead_code)]
327#[derive(Debug, Clone)]
328pub struct ConvexHull2D {
329 pub points: Vec<(f64, f64)>,
330 pub hull: Vec<usize>,
331}
332#[allow(dead_code)]
333impl ConvexHull2D {
334 pub fn compute(points: Vec<(f64, f64)>) -> Self {
335 if points.len() < 3 {
336 let hull: Vec<usize> = (0..points.len()).collect();
337 return ConvexHull2D { points, hull };
338 }
339 let n = points.len();
340 let start = (0..n)
341 .min_by(|&i, &j| {
342 points[i]
343 .0
344 .partial_cmp(&points[j].0)
345 .unwrap_or(std::cmp::Ordering::Equal)
346 })
347 .expect("points is non-empty: checked by n < 3 guard");
348 let mut hull = Vec::new();
349 let mut current = start;
350 loop {
351 hull.push(current);
352 let mut next = (current + 1) % n;
353 for i in 0..n {
354 if i == current {
355 continue;
356 }
357 let cross = cross_2d(points[current], points[next], points[i]);
358 if cross < 0.0 {
359 next = i;
360 }
361 }
362 current = next;
363 if current == start {
364 break;
365 }
366 if hull.len() > n {
367 break;
368 }
369 }
370 ConvexHull2D { points, hull }
371 }
372 pub fn n_hull_points(&self) -> usize {
373 self.hull.len()
374 }
375 pub fn perimeter(&self) -> f64 {
376 let mut p = 0.0;
377 let n = self.hull.len();
378 for i in 0..n {
379 let a = self.points[self.hull[i]];
380 let b = self.points[self.hull[(i + 1) % n]];
381 p += ((b.0 - a.0).powi(2) + (b.1 - a.1).powi(2)).sqrt();
382 }
383 p
384 }
385 pub fn area(&self) -> f64 {
386 let n = self.hull.len();
387 let mut area = 0.0;
388 for i in 0..n {
389 let a = self.points[self.hull[i]];
390 let b = self.points[self.hull[(i + 1) % n]];
391 area += a.0 * b.1 - b.0 * a.1;
392 }
393 area.abs() / 2.0
394 }
395}
396pub struct SpatialHash {
399 pub cell_size: f64,
400 pub buckets: std::collections::HashMap<(i64, i64), Vec<usize>>,
401 pub points: Vec<Point2D>,
402}
403impl SpatialHash {
404 pub fn new(cell_size: f64) -> Self {
405 Self {
406 cell_size,
407 buckets: std::collections::HashMap::new(),
408 points: Vec::new(),
409 }
410 }
411 fn cell(&self, p: &Point2D) -> (i64, i64) {
412 (
413 (p.x / self.cell_size).floor() as i64,
414 (p.y / self.cell_size).floor() as i64,
415 )
416 }
417 pub fn insert(&mut self, p: Point2D) {
418 let idx = self.points.len();
419 self.points.push(p);
420 let c = self.cell(&p);
421 self.buckets.entry(c).or_default().push(idx);
422 }
423 pub fn query_radius(&self, query: &Point2D, r: f64) -> Vec<Point2D> {
425 let cells_span = (r / self.cell_size).ceil() as i64 + 1;
426 let (qcx, qcy) = self.cell(query);
427 let mut results = Vec::new();
428 for dx in -cells_span..=cells_span {
429 for dy in -cells_span..=cells_span {
430 let cell = (qcx + dx, qcy + dy);
431 if let Some(indices) = self.buckets.get(&cell) {
432 for &idx in indices {
433 let p = self.points[idx];
434 if query.dist(&p) <= r {
435 results.push(p);
436 }
437 }
438 }
439 }
440 }
441 results
442 }
443}
444pub struct BentleyOttmannEvents {
447 segments: Vec<(Point2D, Point2D)>,
449 events: Vec<SweepEvent>,
451}
452impl BentleyOttmannEvents {
453 pub fn new(segs: &[(Point2D, Point2D)]) -> Self {
455 let mut events: Vec<SweepEvent> = Vec::new();
456 for (i, &(p, q)) in segs.iter().enumerate() {
457 let (left, right) = if p.x < q.x || (p.x == q.x && p.y <= q.y) {
458 (p, q)
459 } else {
460 (q, p)
461 };
462 events.push(SweepEvent::LeftEndpoint {
463 x: left.x,
464 y: left.y,
465 seg_idx: i,
466 });
467 events.push(SweepEvent::RightEndpoint {
468 x: right.x,
469 y: right.y,
470 seg_idx: i,
471 });
472 }
473 events.sort_by(|a, b| {
474 a.x()
475 .partial_cmp(&b.x())
476 .unwrap_or(std::cmp::Ordering::Equal)
477 .then(
478 a.y()
479 .partial_cmp(&b.y())
480 .unwrap_or(std::cmp::Ordering::Equal),
481 )
482 });
483 Self {
484 segments: segs.to_vec(),
485 events,
486 }
487 }
488 pub fn add_intersection(&mut self, x: f64, y: f64, seg_a: usize, seg_b: usize) {
490 self.events
491 .push(SweepEvent::Intersection { x, y, seg_a, seg_b });
492 self.events.sort_by(|a, b| {
493 a.x()
494 .partial_cmp(&b.x())
495 .unwrap_or(std::cmp::Ordering::Equal)
496 .then(
497 a.y()
498 .partial_cmp(&b.y())
499 .unwrap_or(std::cmp::Ordering::Equal),
500 )
501 });
502 }
503 pub fn pop(&mut self) -> Option<SweepEvent> {
505 if self.events.is_empty() {
506 None
507 } else {
508 Some(self.events.remove(0))
509 }
510 }
511 pub fn len(&self) -> usize {
513 self.events.len()
514 }
515 pub fn is_empty(&self) -> bool {
517 self.events.is_empty()
518 }
519 pub fn all_intersections(&self) -> Vec<Point2D> {
522 let n = self.segments.len();
523 let mut result = Vec::new();
524 for i in 0..n {
525 for j in (i + 1)..n {
526 let (p1, p2) = self.segments[i];
527 let (p3, p4) = self.segments[j];
528 if segments_intersect(&p1, &p2, &p3, &p4) {
529 if let Some(pt) = segment_intersection(&p1, &p2, &p3, &p4) {
530 result.push(pt);
531 }
532 }
533 }
534 }
535 result.sort_by(|a, b| {
536 a.x.partial_cmp(&b.x)
537 .unwrap_or(std::cmp::Ordering::Equal)
538 .then(a.y.partial_cmp(&b.y).unwrap_or(std::cmp::Ordering::Equal))
539 });
540 result
541 }
542}
543pub struct AlphaShapeBuilder {
546 points: Vec<Point2D>,
547 triangulation: Vec<Triangle>,
548}
549impl AlphaShapeBuilder {
550 pub fn new(points: &[Point2D]) -> Self {
552 let triangulation = delaunay_triangulation(points);
553 Self {
554 points: points.to_vec(),
555 triangulation,
556 }
557 }
558 pub fn circumradius(&self, tri: &Triangle) -> f64 {
560 let a = self.points[tri.a];
561 let b = self.points[tri.b];
562 let c = self.points[tri.c];
563 let ab = a.dist(&b);
564 let bc = b.dist(&c);
565 let ca = c.dist(&a);
566 let area2 = cross(&a, &b, &c).abs();
567 if area2 < 1e-15 {
568 return f64::INFINITY;
569 }
570 (ab * bc * ca) / (2.0 * area2)
571 }
572 pub fn critical_alphas(&self) -> Vec<f64> {
574 let mut alphas: Vec<f64> = self
575 .triangulation
576 .iter()
577 .map(|t| self.circumradius(t))
578 .collect();
579 for tri in &self.triangulation {
580 for &(i, j) in &[(tri.a, tri.b), (tri.b, tri.c), (tri.c, tri.a)] {
581 alphas.push(self.points[i].dist(&self.points[j]) / 2.0);
582 }
583 }
584 alphas.sort_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal));
585 alphas.dedup_by(|a, b| (*a - *b).abs() < 1e-12);
586 alphas
587 }
588 pub fn at_alpha(&self, alpha: f64) -> AlphaShapeStep {
590 let triangles: Vec<Triangle> = self
591 .triangulation
592 .iter()
593 .filter(|t| self.circumradius(t) <= alpha)
594 .cloned()
595 .collect();
596 let mut edge_set: std::collections::HashSet<(usize, usize)> =
597 std::collections::HashSet::new();
598 for tri in &triangles {
599 for &(i, j) in &[(tri.a, tri.b), (tri.b, tri.c), (tri.c, tri.a)] {
600 let key = (i.min(j), i.max(j));
601 edge_set.insert(key);
602 }
603 }
604 for tri in &self.triangulation {
605 for &(i, j) in &[(tri.a, tri.b), (tri.b, tri.c), (tri.c, tri.a)] {
606 let half_len = self.points[i].dist(&self.points[j]) / 2.0;
607 if half_len <= alpha {
608 let key = (i.min(j), i.max(j));
609 edge_set.insert(key);
610 }
611 }
612 }
613 let mut edges: Vec<(usize, usize)> = edge_set.into_iter().collect();
614 edges.sort();
615 AlphaShapeStep {
616 alpha,
617 triangles,
618 edges,
619 }
620 }
621 pub fn filtration(&self) -> Vec<AlphaShapeStep> {
623 self.critical_alphas()
624 .into_iter()
625 .map(|a| self.at_alpha(a))
626 .collect()
627 }
628}
629pub struct RangeTree2D {
631 sorted_x: Vec<(f64, Point2D)>,
633 secondary: Vec<RangeTree1D>,
635}
636impl RangeTree2D {
637 pub fn new(points: &[Point2D]) -> Self {
639 let mut sorted_x: Vec<(f64, Point2D)> = points.iter().map(|p| (p.x, *p)).collect();
640 sorted_x.sort_by(|(a, _), (b, _)| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal));
641 let mut by_y: Vec<(f64, Point2D)> = sorted_x.iter().map(|(_, p)| (p.y, *p)).collect();
642 by_y.sort_by(|(a, _), (b, _)| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal));
643 let secondary = vec![build_range_tree_1d(&by_y)];
644 Self {
645 sorted_x,
646 secondary,
647 }
648 }
649 pub fn query(&self, x_lo: f64, x_hi: f64, y_lo: f64, y_hi: f64) -> Vec<Point2D> {
651 let candidates: Vec<Point2D> = self
652 .sorted_x
653 .iter()
654 .filter(|(x, _)| *x >= x_lo && *x <= x_hi)
655 .map(|(_, p)| *p)
656 .collect();
657 candidates
658 .into_iter()
659 .filter(|p| p.y >= y_lo && p.y <= y_hi)
660 .collect()
661 }
662 pub fn query_via_tree(&self, x_lo: f64, x_hi: f64, y_lo: f64, y_hi: f64) -> Vec<Point2D> {
664 let x_pts: Vec<(f64, Point2D)> = self
665 .sorted_x
666 .iter()
667 .filter(|(x, _)| *x >= x_lo && *x <= x_hi)
668 .map(|(_, p)| (p.y, *p))
669 .collect();
670 let y_tree = build_range_tree_1d(&x_pts);
671 let mut result = Vec::new();
672 query_range_tree_1d(&y_tree, y_lo, y_hi, &mut result);
673 result
674 }
675 pub fn len(&self) -> usize {
677 self.sorted_x.len()
678 }
679 pub fn is_empty(&self) -> bool {
681 self.sorted_x.is_empty()
682 }
683}
684#[allow(dead_code)]
686#[derive(Debug, Clone)]
687pub struct MinkowskiSum {
688 pub polygon_a: Vec<(f64, f64)>,
689 pub polygon_b: Vec<(f64, f64)>,
690}
691#[allow(dead_code)]
692impl MinkowskiSum {
693 pub fn new(a: Vec<(f64, f64)>, b: Vec<(f64, f64)>) -> Self {
694 MinkowskiSum {
695 polygon_a: a,
696 polygon_b: b,
697 }
698 }
699 pub fn result_size_upper_bound(&self) -> usize {
700 self.polygon_a.len() + self.polygon_b.len()
701 }
702 pub fn is_convex_if_inputs_convex(&self) -> bool {
703 true
704 }
705}