geop_core_topology/validation/parameters.rs
1use geop_core_math::scalars::Scalar;
2
3/// Shared tuning knobs for the whole-model validation checks — how many
4/// points to sample along a curve, and the budgets passed down to the
5/// underlying BFS/DFS geometric searches.
6#[derive(Clone, Copy, Debug)]
7pub struct ValidationParameters<S: Scalar> {
8 /// How many points to sample along a curve for sampling-based checks.
9 pub sample_count: usize,
10 /// Node budget for the BFS containment searches (see
11 /// `contains::curve::curve_could_contain`), and for the pairwise
12 /// `curve_curve_intersect`/`curve_surface_intersect` searches in
13 /// `disjointness_check` (which now error, rather than silently
14 /// returning a truncated result, if they exhaust it — see
15 /// `curve_surface_intersect`'s own doc comment).
16 pub max_nodes: usize,
17 /// Convergence tolerance for those same searches. Empirically, the
18 /// pairwise `curve_curve_intersect`/`curve_surface_intersect` searches
19 /// need a *much* looser tolerance than a single-curve
20 /// `curve_could_contain` query to reliably converge within `max_nodes`:
21 /// `1e-7` can fail to resolve a clean, unambiguous case at all; `1e-5`
22 /// resolves most cases but not a near-tangential edge/face pair (e.g.
23 /// two adjacent flat walls of an `extruded_cylinder`'s polygon
24 /// approximation meeting at a shallow dihedral angle, or an edge ending
25 /// exactly at a `revolve`d cap's own pole) — each halving of the
26 /// tolerance costs roughly one extra subdivision *level*, and a
27 /// near-tangential pair's hull-overlap pruning barely discriminates at
28 /// all (see `curve_surface_intersect`'s own doc comment), so that one
29 /// extra level can mean an order of magnitude more nodes. `1e-4` is
30 /// loose enough to resolve every case in this crate's own basic-shape
31 /// validations within `max_nodes`, while still being far tighter than
32 /// any genuine geometric feature these checks care about.
33 pub min_subdivision_size: S,
34 /// `max_solutions` passed to `curve_curve_intersect` for every edge x
35 /// edge pair: how many points to return at most. Coincidence is reported
36 /// directly (`Intersections::Coincident`), not inferred from reaching
37 /// this count.
38 pub max_edge_edge_intersection_samples: usize,
39 /// Same idea as `max_edge_edge_intersection_samples`, but for
40 /// `curve_surface_intersect` on every edge x face pair.
41 pub max_edge_face_intersection_samples: usize,
42 /// How many random (point-on-face-a, point-on-face-b) starting pairs
43 /// `face_face_numerical_intersection` tries per face pair.
44 pub face_face_sample_count: usize,
45 /// How many alternating-projection Newton rounds each of those starting
46 /// pairs gets to converge in.
47 pub face_face_newton_iterations: usize,
48 /// How many random points, and how many random ray directions per
49 /// point, `validate_manifold`'s ray-direction-consistency check tries
50 /// per shell.
51 pub manifold_ray_sample_count: usize,
52 /// Seeds every random draw in `validate_manifold`'s
53 /// ray-direction-consistency check.
54 pub manifold_seed: u64,
55}
56
57impl<S: Scalar> Default for ValidationParameters<S> {
58 fn default() -> Self {
59 Self {
60 sample_count: 17,
61 max_nodes: 5000,
62 min_subdivision_size: S::from_f64(1e-4),
63 max_edge_edge_intersection_samples: 17,
64 max_edge_face_intersection_samples: 7,
65 face_face_sample_count: 20,
66 face_face_newton_iterations: 20,
67 manifold_ray_sample_count: 10,
68 manifold_seed: 0x5EED_1234_5678_9ABC,
69 }
70 }
71}