axiolid_construct/trimmed_intersection_types.rs
1use axiolid_brep::{Curve2Id, ExactBRep};
2use axiolid_core::{Interval, Scalar};
3use axiolid_nurbs::{
4 CertifiedSurfaceSurfaceIntersection3, CertifiedSurfaceSurfaceIntersectionOptions,
5 TransverseSurfaceSurfaceTrace3,
6};
7use axiolid_topology::{EdgeId, FaceId};
8
9/// Explicit resource and residual policy for certified topology integration.
10#[derive(Debug, Clone, Copy, PartialEq)]
11pub struct CertifiedSurfacePairSplitOptions {
12 /// Policy for the underlying certified surface/surface query.
13 intersection: CertifiedSurfaceSurfaceIntersectionOptions,
14 /// Largest certified surface/carrier residual accepted by the B-rep handoff.
15 max_surface_residual: Scalar,
16}
17
18impl CertifiedSurfacePairSplitOptions {
19 /// Validate and construct a split policy.
20 pub fn new(
21 intersection: CertifiedSurfaceSurfaceIntersectionOptions,
22 max_surface_residual: Scalar,
23 ) -> Result<Self, axiolid_contracts::GeomError> {
24 if !max_surface_residual.is_finite() || max_surface_residual <= 0.0 {
25 return Err(axiolid_contracts::GeomError::InvalidInput(
26 "surface-pair split residual must be finite and positive".into(),
27 ));
28 }
29 Ok(Self {
30 intersection,
31 max_surface_residual,
32 })
33 }
34
35 pub(super) fn intersection_options(self) -> CertifiedSurfaceSurfaceIntersectionOptions {
36 self.intersection
37 }
38
39 pub(super) fn max_surface_residual(self) -> Scalar {
40 self.max_surface_residual
41 }
42}
43
44impl Default for CertifiedSurfacePairSplitOptions {
45 fn default() -> Self {
46 Self {
47 intersection: CertifiedSurfaceSurfaceIntersectionOptions::default(),
48 max_surface_residual: 1.0e-7,
49 }
50 }
51}
52
53/// Which input surface is partitioned by the certified chord.
54#[derive(Debug, Clone, Copy, PartialEq, Eq)]
55pub enum SurfacePairMember {
56 /// The first function argument.
57 First,
58 /// The second function argument.
59 Second,
60}
61
62/// A certified edge embedded in a face without pretending it is a closed trim.
63#[derive(Debug, Clone, Copy, PartialEq)]
64pub struct EmbeddedFaceCurve {
65 /// Unsplit face that contains the intersection chord.
66 pub face: FaceId,
67 /// Shared model-space intersection edge.
68 pub edge: EdgeId,
69 /// Surface-parameter image from edge start to edge end.
70 pub pcurve: Curve2Id,
71 /// Native pcurve interval, oriented from edge start to edge end.
72 pub interval: Interval,
73}
74
75/// Validated analytic B-rep arrangement for one certified finite trace.
76#[derive(Debug, Clone, PartialEq)]
77pub struct CertifiedTrimmedSurfacePair3 {
78 /// Strict analytic B-rep containing three closed faces.
79 pub brep: ExactBRep,
80 /// The same edge used by the two split-face loops and embedded in the other face.
81 pub intersection_edge: EdgeId,
82 /// Input member whose rectangular face was split.
83 pub split_surface: SurfacePairMember,
84 /// Two deterministic trimmed faces on `split_surface`.
85 pub split_faces: [FaceId; 2],
86 /// Rectangular face that the finite chord does not partition.
87 pub unsplit_face: FaceId,
88 /// Explicit interior attachment on `unsplit_face`.
89 pub embedded_curve: EmbeddedFaceCurve,
90 /// Original certified bounded trace; no endpoint is widened by construction.
91 pub trace: TransverseSurfaceSurfaceTrace3,
92 /// Conservative global carrier-to-surface residual bound.
93 pub max_surface_residual_upper_bound: Scalar,
94 /// Certified patch pairs processed by the intersection query.
95 pub visited_patch_pairs: u32,
96 /// Bounded boundary queries used by the intersection query.
97 pub boundary_queries: u32,
98}
99
100/// Why valid geometry could not be promoted to a closed trimmed arrangement.
101#[derive(Debug, Clone, Copy, PartialEq, Eq)]
102pub enum SurfacePairSplitUnresolvedReason {
103 /// The underlying certified query retained uncertainty.
104 IntersectionUnresolved,
105 /// The query did not produce exactly one finite trace.
106 UnsupportedTraceCount,
107 /// Endpoint ownership did not identify exactly one partitioned rectangle.
108 UnsupportedEndpointOwnership,
109 /// The certified carrier residual exceeded explicit policy.
110 ResidualExceedsPolicy,
111 /// Representative parameters or carrier were finite but degenerate for topology.
112 DegenerateRepresentative,
113}
114
115/// Certified topology-integration outcome.
116///
117/// The success payload stays inline deliberately: boxing it would add an
118/// infallible allocation after all certified construction allocations have
119/// already been made fallible and bounded.
120#[allow(clippy::large_enum_variant)]
121#[derive(Debug, Clone, PartialEq)]
122#[non_exhaustive]
123pub enum CertifiedSurfacePairSplit3 {
124 /// Conservative proof that the bounded patches do not intersect.
125 Empty {
126 /// Certified patch pairs processed.
127 visited_patch_pairs: u32,
128 /// Bounded boundary queries used.
129 boundary_queries: u32,
130 },
131 /// One finite trace integrated into a strict trimmed arrangement.
132 Split(CertifiedTrimmedSurfacePair3),
133 /// Geometry remains usable, but no B-rep split was invented.
134 Unresolved {
135 /// Original intersection evidence retained without widening.
136 intersection: CertifiedSurfaceSurfaceIntersection3,
137 /// Topology-specific refusal reason.
138 reason: SurfacePairSplitUnresolvedReason,
139 },
140}