axiolid_mesh_section_contract/
contract.rs

1//! Portable mesh plane-section provider contract.
2
3use axiolid_contracts::{
4    Backend, CancellationGranularity, ExecutionOptions, GeomResult, ScratchRequirement,
5};
6use axiolid_core::{Frame3, Point2};
7use axiolid_mesh::TriMesh;
8
9/// Hard bounds for one mesh section request.
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11pub struct SectionLimits {
12    /// Maximum source positions inspected.
13    pub max_source_vertices: usize,
14    /// Maximum source triangles inspected.
15    pub max_source_triangles: usize,
16    /// Maximum vertices across all output contours.
17    pub max_output_vertices: usize,
18    /// Maximum output contours.
19    pub max_contours: usize,
20}
21
22impl SectionLimits {
23    /// Construct explicit source and output work limits.
24    pub const fn new(
25        max_source_vertices: usize,
26        max_source_triangles: usize,
27        max_output_vertices: usize,
28        max_contours: usize,
29    ) -> Self {
30        Self {
31            max_source_vertices,
32            max_source_triangles,
33            max_output_vertices,
34            max_contours,
35        }
36    }
37}
38
39/// One closed plane-local polyline.
40///
41/// The terminal point is implicit and must not duplicate the first point.
42#[derive(Debug, Clone, PartialEq)]
43pub struct SectionContour {
44    /// Plane-local points in traversal order.
45    pub points: Vec<Point2>,
46    /// Private invariant marker: every constructible contour is closed.
47    closed: bool,
48}
49
50impl SectionContour {
51    /// Construct a closed contour. Registry validation checks cardinality and
52    /// finite, non-duplicated coordinates after provider dispatch.
53    pub fn new(points: Vec<Point2>) -> Self {
54        Self {
55            points,
56            closed: true,
57        }
58    }
59
60    /// Whether this polyline closes from its last point back to its first.
61    pub const fn is_closed(&self) -> bool {
62        self.closed
63    }
64}
65
66/// Provenance of a plane-section approximation.
67#[derive(Debug, Clone, Copy, PartialEq, Eq)]
68#[non_exhaustive]
69pub enum SectionSource {
70    /// Contours were intersected with the supplied triangle mesh.
71    InputMesh,
72}
73
74/// Auditable counts for one section operation.
75#[derive(Debug, Clone, Copy, PartialEq, Eq)]
76pub struct SectionEvidence {
77    /// Approximation source.
78    pub source: SectionSource,
79    /// Source triangles inspected.
80    pub source_triangles: usize,
81    /// Output contour vertices.
82    pub output_vertices: usize,
83    /// Output contours.
84    pub output_contours: usize,
85}
86
87impl SectionEvidence {
88    /// Record evidence for a section derived from the input mesh.
89    pub const fn input_mesh(
90        source_triangles: usize,
91        output_vertices: usize,
92        output_contours: usize,
93    ) -> Self {
94        Self {
95            source: SectionSource::InputMesh,
96            source_triangles,
97            output_vertices,
98            output_contours,
99        }
100    }
101
102    /// Whether this result came from the discrete input mesh.
103    pub const fn is_derived_from_input_mesh(self) -> bool {
104        matches!(self.source, SectionSource::InputMesh)
105    }
106}
107
108/// Plane-local closed section contours plus approximation evidence.
109#[derive(Debug, Clone, PartialEq)]
110pub struct SectionOutcome {
111    /// Right-handed orthonormal mapping from local `(x,y,0)` to model space.
112    pub frame: Frame3,
113    /// Closed section contours. Empty means the plane misses the solid.
114    pub contours: Vec<SectionContour>,
115    /// Source and output counts.
116    pub evidence: SectionEvidence,
117}
118
119impl SectionOutcome {
120    /// Construct a provider result. Registries validate it before returning it.
121    pub fn new(frame: Frame3, contours: Vec<SectionContour>, evidence: SectionEvidence) -> Self {
122        Self {
123            frame,
124            contours,
125            evidence,
126        }
127    }
128}
129
130/// Provider for deterministic sections of closed oriented triangle solids.
131pub trait MeshPlaneSection: Backend {
132    /// Scratch needed beyond inputs and result.
133    fn scratch_requirement(&self) -> ScratchRequirement {
134        ScratchRequirement::Unbounded
135    }
136
137    /// How finely the provider polls cancellation.
138    fn cancellation_granularity(&self) -> CancellationGranularity {
139        CancellationGranularity::None
140    }
141
142    /// Intersect one validated closed oriented mesh with `frame`'s local XY
143    /// plane. Implementations must enforce `limits` before growing output.
144    fn section(
145        &self,
146        mesh: &TriMesh,
147        frame: Frame3,
148        limits: SectionLimits,
149        options: &ExecutionOptions,
150    ) -> GeomResult<SectionOutcome>;
151}