mirror of
https://github.com/bherbruck/solidcraft.git
synced 2026-11-03 18:45:55 +00:00
Audit the held flags against the fork's source; tabbed plate and mitred rounds parity
Reading the fork at SMLIB_REV finds `perspective_sphere_offsets` is there (709c5be: the cull projects each sphere's own radius from its centre), so it goes on. The new `gap_samples_use_trimmed_spans` and `twist_simple_duw_sign` are held: upstream's defects are still in the fork. The tabbed plate and #1997's rounded box are compared with the C++ kernel. `sweeps::List` is visible to the crate for that. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MNXLXkZLQ6T7TSi4wswcmk
This commit is contained in:
@@ -250,6 +250,7 @@ pub(crate) fn fixes() -> UpstreamFixes {
|
||||
f.planar_path_sweep_statuses = true;
|
||||
f.planar_path_profile_placement_statuses = true;
|
||||
f.fillet_trim_status = true;
|
||||
f.perspective_sphere_offsets = true;
|
||||
f
|
||||
}
|
||||
|
||||
@@ -258,8 +259,8 @@ pub(crate) fn fixes() -> UpstreamFixes {
|
||||
/// (solidcore#1664, WR-563), `bspline_trim_keeps_rational_end_spans` (solidcore#1711, WR-575) and
|
||||
/// `fillet_blend_curve_revolved_on_arc` (solidcore#1759, WR-581, an own design waiting for the
|
||||
/// fork's fix) have no fork commit. `temporary_radius_setup_errors` (solidcore#644, #458), `ellipse_step_interval_checks`
|
||||
/// (solidcore#686, #428) and `perspective_sphere_offsets` (solidcore#684, WR-608, #525) are the
|
||||
/// port's own fixes with no fork commit; the C++ build keeps upstream's behaviour there.
|
||||
/// (solidcore#686, #428) are the port's own fixes with no fork commit; the C++ build keeps
|
||||
/// upstream's behaviour there.
|
||||
/// `corner_patch_face_side_twist` (WR-613, fork 7fd9fb0) ports a fork commit that is not
|
||||
/// published.
|
||||
///
|
||||
@@ -290,7 +291,9 @@ pub(crate) fn fixes() -> UpstreamFixes {
|
||||
/// no tangent is no tangency), `fillet_edge_curve_domain_statuses` (`sm_CheckEdgeCurveDomains`: a
|
||||
/// failed trim keeps the edge's curve), `offset_tangent_gap_statuses` (`HaveTangentGaps`: a failed
|
||||
/// sample shows no gap) and `ssi_alignment_statuses` (`ALIGN_DIR_WITH_PREVIOUS_POINT`: no angle, no
|
||||
/// alignment). `translation_sweep_regularize` (solidcore#1937) has no fork commit.
|
||||
/// alignment). `translation_sweep_regularize` (solidcore#1937) has no fork commit, and the fork keeps
|
||||
/// upstream's `gap_samples_use_trimmed_spans` (WR-89: `BuildSampleSet` spans from the first knot) and
|
||||
/// `twist_simple_duw_sign` (WR-46: `EvaluateSimple`'s Duw y is -per cos).
|
||||
#[cfg(test)]
|
||||
const HELD_BACK: &[&str] = &[
|
||||
"precise_properties_trim_base_v",
|
||||
@@ -298,7 +301,6 @@ const HELD_BACK: &[&str] = &[
|
||||
"fillet_blend_curve_revolved_on_arc",
|
||||
"temporary_radius_setup_errors",
|
||||
"ellipse_step_interval_checks",
|
||||
"perspective_sphere_offsets",
|
||||
"corner_patch_face_side_twist",
|
||||
"boolean_union_refuses_solid_leak",
|
||||
"curve_loop_start_after_previous_end",
|
||||
@@ -316,6 +318,8 @@ const HELD_BACK: &[&str] = &[
|
||||
"offset_tangent_gap_statuses",
|
||||
"ssi_alignment_statuses",
|
||||
"translation_sweep_regularize",
|
||||
"gap_samples_use_trimmed_spans",
|
||||
"twist_simple_duw_sign",
|
||||
];
|
||||
|
||||
fn fresh() -> Kernel {
|
||||
|
||||
@@ -894,3 +894,72 @@ fn rounds_on_the_871_part() {
|
||||
assert!(crefused.is_err());
|
||||
}
|
||||
}
|
||||
|
||||
/// The fork's `tabbed_plate_rounds_mitred_on_the_arcs_continuation`: a plate 2 thick, its outline an
|
||||
/// R25 arc to the sides x = +-4 of a tab whose top is 4 wide with R2 corners, every top edge of the
|
||||
/// outline rounded r 0.5. The arc's round and the tab side's are mitred on the arc wall's
|
||||
/// continuation. Removed: the outline's area less the area of the outline moved in by
|
||||
/// d = r (1 - cos phi), at the height r sin phi into the round (midpoint rule, 8192 steps; the area
|
||||
/// by Green's theorem). With SMLib built, the C++ kernel gives the same.
|
||||
#[test]
|
||||
fn tabbed_plate_rounds_mitred_on_the_arcs_continuation() {
|
||||
use super::sweep::extrude;
|
||||
use crate::sweeps::{Curve, DraftCorner};
|
||||
const Z: [f64; 3] = [0.0, 0.0, 1.0];
|
||||
let theta = (4.0_f64 / 25.0).acos();
|
||||
let y = 609.0_f64.sqrt();
|
||||
let cy = 280.0 / 9.0;
|
||||
let line = |a: [f64; 2], b: [f64; 2]| Curve::Line { start: [a[0], a[1], 0.0], end: [b[0], b[1], 0.0] };
|
||||
let arc = |c: [f64; 2], radius, start, end| Curve::Arc { center: [c[0], c[1], 0.0], axis: Z, reference: [1.0, 0.0, 0.0], radius, start, end };
|
||||
let outline = [
|
||||
arc([0.0, 0.0], 25.0, PI - theta, 2.0 * PI + theta),
|
||||
line([4.0, y], [4.0, cy]),
|
||||
arc([2.0, cy], 2.0, 0.0, PI / 2.0),
|
||||
line([2.0, cy + 2.0], [-2.0, cy + 2.0]),
|
||||
arc([-2.0, cy], 2.0, PI / 2.0, PI),
|
||||
line([-4.0, cy], [-4.0, y]),
|
||||
];
|
||||
let area = |da: f64, dt: f64| {
|
||||
let (big, rho) = (25.0 - da, 2.0 - dt);
|
||||
let tab = rho * rho * PI + 2.0 * rho * (2.0 + cy) + 4.0 * (cy + rho);
|
||||
let yc = (big * big - (4.0 - dt) * (4.0 - dt)).sqrt();
|
||||
let at = yc.atan2(4.0 - dt);
|
||||
0.5 * (big * big * (PI + 2.0 * at) + tab) + (4.0 - dt) * (cy - yc)
|
||||
};
|
||||
let (r, dphi) = (0.5, (PI / 2.0) / 8192.0);
|
||||
let want: f64 = (0..8192)
|
||||
.map(|i| {
|
||||
let phi = (f64::from(i) + 0.5) * dphi;
|
||||
let d = r * (1.0 - phi.cos());
|
||||
(area(0.0, 0.0) - area(d, d)) * r * phi.cos() * dphi
|
||||
})
|
||||
.sum();
|
||||
let top = [
|
||||
[0.0, -25.0, 2.0],
|
||||
[4.0, 27.8945, 2.0],
|
||||
[3.41421356, 32.5253247, 2.0],
|
||||
[0.0, cy + 2.0, 2.0],
|
||||
[-3.41421356, 32.5253247, 2.0],
|
||||
[-4.0, 27.8945, 2.0],
|
||||
];
|
||||
let plate = extrude(&outline, Z, 2.0, 0.0, DraftCorner::default(), true).unwrap();
|
||||
assert!(rel(volume(&plate, 1e-8).unwrap(), 2.0 * area(0.0, 0.0)) < 1e-10);
|
||||
let round = blend(&plate, Blend::Round, &top, &[r; 6], TOL, &[], &[], Corners::Filled).unwrap();
|
||||
let removed = volume(&plate, 1e-8).unwrap() - volume(&round, 1e-8).unwrap();
|
||||
assert!(rel(removed, want) < 1e-6, "removed {removed}, expected {want}");
|
||||
let (rec, _) = native(&to_arrays(&round).unwrap()).unwrap();
|
||||
rec.validate().unwrap();
|
||||
assert!(super::is_manifold_solid(&round).unwrap());
|
||||
assert!(super::check(&round, crate::check::CheckLevel::All).unwrap().is_valid());
|
||||
#[cfg(feature = "native")]
|
||||
{
|
||||
use crate::{Brep, ffi};
|
||||
crate::init().unwrap();
|
||||
let list = crate::sweeps::List::of(&outline).unwrap();
|
||||
let cpp = ffi::sweeps::extrude(&list.raw(), &Z, 2.0, 0.0, ffi::sweeps::DRAFT_CORNER_CURVATURE, true, &mut [f64::NAN; 3]).unwrap();
|
||||
let cround = ffi::ops::blend(ffi::ops::BLEND_ROUND, Brep::made(cpp).cpp().unwrap(), &top, &[r; 6], TOL).unwrap();
|
||||
let cv = ffi::volume(&cround, 1e-8).unwrap();
|
||||
assert!(rel(volume(&round, 1e-8).unwrap(), cv) < 1e-9);
|
||||
assert_eq!(counts(&round).unwrap(), ffi::counts(&cround).unwrap().map(|x| usize::try_from(x).unwrap()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -834,3 +834,45 @@ fn offset_faces_close_a_step_wall() {
|
||||
assert!(rel(got, v) < 1e-9 && rel(area, a) < 1e-9, "d {d}: V {got} A {area}");
|
||||
}
|
||||
}
|
||||
|
||||
/// Rig case shell/4492's rounded box: four mitred rounds, r 3, come off a 40 x 30 x 10 box's top
|
||||
/// together and follow it. From height 0 the outline is the 34 x 24 top moved out by the round's
|
||||
/// w(z) = sqrt(9 - (z - axis)^2), or 3 below the axis. With the fork's values at +19, and a body
|
||||
/// whose rounds go all the way down at -7. With SMLib built, the C++ kernel gives the same.
|
||||
#[test]
|
||||
fn mitred_rounds_follow_a_moved_top() {
|
||||
use super::blend::{Corners, blend};
|
||||
use crate::Blend;
|
||||
let edges = [[20.0, 0.0, 10.0], [20.0, 30.0, 10.0], [0.0, 15.0, 10.0], [40.0, 15.0, 10.0]];
|
||||
let top = [20.0, 15.0, 10.0];
|
||||
let rounded = blend(&make_box([0.0; 3], [40.0, 30.0, 10.0]).unwrap(), Blend::Round, &edges, &[3.0; 4], TOL, &[], &[], Corners::Filled).unwrap();
|
||||
let analytic = |d: f64| {
|
||||
let (height, axis, n) = (10.0 + d, 7.0 + d, 20000);
|
||||
(0..n)
|
||||
.map(|i| {
|
||||
let z = height * (f64::from(i) + 0.5) / f64::from(n);
|
||||
let w = if z < axis { 3.0 } else { (9.0 - (z - axis) * (z - axis)).max(0.0).sqrt() };
|
||||
(34.0 + 2.0 * w) * (24.0 + 2.0 * w) * height / f64::from(n)
|
||||
})
|
||||
.sum::<f64>()
|
||||
};
|
||||
let moves = [(19.0, [10, 20, 12]), (1.0, [10, 20, 12]), (-1.0, [10, 20, 12]), (-6.9, [10, 20, 12]), (-7.0, [6, 12, 8])];
|
||||
for (d, n) in moves {
|
||||
let moved = offset_faces(&rounded, &[top], 0.1, d).unwrap();
|
||||
let v = volume(&moved, 1e-8).unwrap();
|
||||
assert_eq!(counts(&moved).unwrap(), n, "d {d}");
|
||||
assert!(rel(v, analytic(d)) < 1e-6, "d {d}: {v} vs {}", analytic(d));
|
||||
}
|
||||
#[cfg(feature = "native")]
|
||||
{
|
||||
use crate::ffi;
|
||||
crate::init().unwrap();
|
||||
let b = ffi::make_box(&[0.0; 3], &[40.0, 30.0, 10.0]).unwrap();
|
||||
let round = ffi::ops::blend(ffi::ops::BLEND_ROUND, &b, &edges, &[3.0; 4], TOL).unwrap();
|
||||
for (d, _) in moves {
|
||||
let cpp = ffi::ops::pick_op(ffi::ops::Pick::OffsetFaces, &round, &[top], 0.1, d).unwrap();
|
||||
let ours = offset_faces(&rounded, &[top], 0.1, d).unwrap();
|
||||
assert!(rel(volume(&ours, 1e-8).unwrap(), ffi::volume(&cpp, 1e-8).unwrap()) < 1e-9, "d {d}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,13 +99,13 @@ pub const MAX_CURVES: usize = ffi::sweeps::CURVE_MAX_CURVES;
|
||||
|
||||
/// The curves as the C API's curve list.
|
||||
#[derive(Default)]
|
||||
struct List {
|
||||
pub(crate) struct List {
|
||||
kinds: Vec<i64>,
|
||||
reals: Vec<f64>,
|
||||
}
|
||||
|
||||
impl List {
|
||||
fn of<'a>(curves: impl IntoIterator<Item = &'a Curve>) -> Result<List> {
|
||||
pub(crate) fn of<'a>(curves: impl IntoIterator<Item = &'a Curve>) -> Result<List> {
|
||||
let mut l = List::default();
|
||||
for c in curves {
|
||||
l.push(c)?;
|
||||
@@ -150,7 +150,7 @@ impl List {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn raw(&self) -> ffi::sweeps::List<'_> {
|
||||
pub(crate) fn raw(&self) -> ffi::sweeps::List<'_> {
|
||||
ffi::sweeps::List::new(&self.kinds, &self.reals)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user