Skip to main content

geop_core_geometry/intersection/
mod.rs

1mod coincidence;
2pub mod curve_curve;
3pub mod curve_curve_bisect;
4pub mod curve_surface;
5pub mod curve_surface_bisect;
6
7pub use curve_curve::curve_curve_intersect;
8pub use curve_curve::refine_crossing as refine_curve_curve_crossing;
9pub use curve_surface::{curve_surface_intersect, refine_crossing};
10
11/// Result of a subdivision-based intersection search: either the complete,
12/// finite set of distinct solutions (fewer than the caller's requested
13/// `max_solutions`), or a signal that the two shapes coincide/overlap over a
14/// shared region rather than meeting at finitely many isolated points.
15///
16/// Reaching exactly `max_solutions` (`> 0`) is the established signal for
17/// coincidence throughout this module — see [`curve_curve::curve_curve_intersect`]'s
18/// own doc comment for why the search's breadth-first-by-level queue
19/// ordering specifically makes that reliable (an evenly-spread set of
20/// leaves across the *whole* shared region, not just a lucky cluster of
21/// adjacent ones). This enum makes that convention explicit and
22/// type-checked, in place of a `result.len() >= max_solutions` comparison
23/// every caller previously had to remember to make.
24///
25/// [`Intersections::Coincident`] still carries the (capped, evenly-spread)
26/// solutions found before the cap was hit — some callers detect coincidence
27/// some other way and just want every point regardless (see
28/// `geop-ops-booleans::remesh::remesh_edges_x_edges`); others want to reuse
29/// them for a follow-up geometric test instead of re-deriving them (see
30/// `remesh_edges_x_faces::find_coincident_pair`). Use [`Intersections::into_vec`]
31/// to get the solutions either way, or match to tell the two cases apart.
32#[derive(Debug, Clone)]
33pub enum Intersections<T> {
34    /// The complete set of distinct solutions — strictly fewer than the
35    /// requested `max_solutions` (or `max_solutions` was `0`).
36    Found(Vec<T>),
37    /// `max_solutions` (`> 0`) distinct solutions were found before the
38    /// search exhausted the domain: read as coincidence (or, for a partial
39    /// overlap, an extended shared region), not a finite crossing count.
40    Coincident(Vec<T>),
41}
42
43impl<T> Intersections<T> {
44    /// `true` for [`Intersections::Coincident`].
45    pub fn is_coincident(&self) -> bool {
46        matches!(self, Intersections::Coincident(_))
47    }
48
49    /// The solutions found, regardless of variant.
50    pub fn into_vec(self) -> Vec<T> {
51        match self {
52            Intersections::Found(v) | Intersections::Coincident(v) => v,
53        }
54    }
55
56    /// The solutions found, regardless of variant.
57    pub fn as_slice(&self) -> &[T] {
58        match self {
59            Intersections::Found(v) | Intersections::Coincident(v) => v,
60        }
61    }
62
63    pub fn len(&self) -> usize {
64        self.as_slice().len()
65    }
66
67    pub fn is_empty(&self) -> bool {
68        self.as_slice().is_empty()
69    }
70}