Skip to main content

brep_kernel/blending/blend/
mod.rs

1//! General rolling-ball blends (Golovanov §4.9 + §6.9 surgery).
2//!
3//! The blend surface is the rational surface (4.9.1) built from three
4//! curves: the two support curves cr(t) ⊂ F1 and cs(t) ⊂ F2 where a
5//! sphere of radius ρ touches both faces, and the middle curve at the
6//! intersection of the two tangent planes, weighted w(t) = cos(α/2)
7//! (4.9.3).  The tangency system (4.9.2) + the section-plane constraint
8//! (4.9.5) — the sphere center pinned to the normal plane of the edge —
9//! is solved per station by Newton with a finite-difference Jacobian.
10//!
11//! Topology is rebuilt the §6.9 way, with NO tool solid and NO boolean:
12//! each mating face's loop swaps the blended edge's coedge for a coedge
13//! on its support curve (trimming the adjacent seam edge when the face
14//! is a closed carrier with seam-in-one-loop topology), and the blend
15//! face is inserted with its own seam.  Open edges take the same route
16//! (`edge/open.rs`), and a whole SELECTION goes through `network.rs`, which
17//! marches every stripe against the original solid and solves each shared
18//! corner from its ball before anything is cut.
19
20mod carve;
21mod chain;
22mod collapse;
23mod corner;
24mod edge;
25mod fold;
26mod miter;
27mod network;
28mod planar_chart;
29mod restrict;
30mod runout;
31mod stations;
32mod rows;
33mod track_fit;
34
35thread_local! {
36    static REFINE_OFF_FOR_TEST: std::cell::Cell<bool> = const { std::cell::Cell::new(false) };
37}
38
39/// Whether the open march's local station refinement runs. Escape hatch
40/// `BREP_BLEND_REFINE=0` restores the uniform ladder exactly; a test turns it
41/// off for its own thread with `set_refinement_off_for_test`.
42pub(crate) fn station_refinement_on() -> bool {
43    std::env::var("BREP_BLEND_REFINE").as_deref() != Ok("0")
44        && !REFINE_OFF_FOR_TEST.with(|off| off.get())
45}
46
47thread_local! {
48    static BLEND_NOTES: std::cell::RefCell<Vec<String>> = const { std::cell::RefCell::new(Vec::new()) };
49}
50
51/// Record what a blend that SHIPS needs its feature to say about it — today,
52/// a march whose rails still stand off their carriers after its station
53/// ladder and local refinement ran out. Drained per feature by the history
54/// loop ([`take_blend_notes`]), beside the soundness acceptance's repairs.
55pub(crate) fn record_blend_note(note: String) {
56    BLEND_NOTES.with(|notes| notes.borrow_mut().push(note));
57}
58
59/// Take every blend note recorded on this thread since the last call.
60/// Blending runs on the feature's own thread (no parallel march), so the
61/// history loop's drain sees every note its feature recorded.
62pub fn take_blend_notes() -> Vec<String> {
63    BLEND_NOTES.with(|notes| std::mem::take(&mut *notes.borrow_mut()))
64}
65
66/// The ledger's length, and a way back to it: a lane that refuses takes back
67/// the notes it recorded, so a note never describes a wall that did not ship.
68pub(crate) fn blend_notes_mark() -> usize {
69    BLEND_NOTES.with(|notes| notes.borrow().len())
70}
71
72pub(crate) fn blend_notes_truncate(mark: usize) {
73    BLEND_NOTES.with(|notes| notes.borrow_mut().truncate(mark));
74}
75
76
77pub use chain::{blend_smooth_chain, blend_smooth_chain_if_closed};
78pub(crate) use corner::round_concave_chain_corner;
79pub use corner::round_convex_corner;
80pub use edge::{blend_closed_edge, blend_edge_variable, blend_open_edge};
81pub(crate) use collapse::is_full_width_collapse;
82pub(crate) use planar_chart::{
83    fit_planar_charts_to_trims, is_planar_chart_refusal,
84};
85pub(crate) use track_fit::PCURVE_OFF_FLOOR;
86pub(crate) use edge::{consumed_band, is_consumed_snap, is_rail_collapse};
87pub(crate) use network::{
88    blend_star_network, degenerate_corner_setbacks, mixed_convexity_corner, DegenerateSetback,
89    MixedCorner,
90};
91pub(crate) use miter::is_marched_fit_off_carriers;
92pub(crate) use runout::{plan_runout, RunoutPlan};
93pub(crate) use fold::{is_wall_fold, WALL_FOLDS};
94pub(crate) use stations::is_ball_off_carrier;