mirror of
https://github.com/bherbruck/solidcraft.git
synced 2026-11-03 10:35:58 +00:00
kernel, doc: an overflowing round goes first; an edge it removes is gone, and the fillet says so
SMLib (smlib-batch-4-rulings 0e83cca, SMLIB_ABI_VERSION 5) rounds the edges whose rounds overflow their faces first and then what is left of the others; smlib_blend_dropping says which picks' edges the overflow removed whole. The smlib crate binds it (Brep::blend_dropping), the kernel returns those picks (fillet_removing), and a fillet notes them as its warning: "the edge at (0, 0, 10) was removed by the larger round, so it is not rounded" (a 50 x 50 x 20 block, R21 on its bottom front edge with the front left upright: the block is R21's alone, in closed form). Ruling d8: [21, 5, 5] on a 20 cube builds as R21 alone (6107.529370); the test is no longer ignored. R25 with R2 at a corner (blend_corner) builds the same way, R25's alone in closed form, where it was refused. The rig's 1080 notched block outline at R8 builds now and comes off the known-failing list. Needs SMLIB_REV at that SMLib once it is pushed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+23
-6
@@ -392,23 +392,37 @@ pub struct SolvedSketch {
|
||||
/// for each group of edges sharing a face; the radius per edge is returned. With
|
||||
/// [`FilletFit::Taper`](crate::FilletFit::Taper) it tapers along each edge it doesn't fit. With
|
||||
/// the exact fit a radius too large is refused, naming the largest that fits ([`with_largest_fit`]).
|
||||
/// Also the picks whose edges a round overflowing its faces removed whole ([`kernel::fillet_removing`]).
|
||||
fn fillet_fitted(
|
||||
body: &kernel::Body,
|
||||
edges: &[Vec3],
|
||||
r: f64,
|
||||
fit: crate::FilletFit,
|
||||
) -> std::result::Result<(kernel::Body, Option<Vec<f64>>), kernel::KernelError> {
|
||||
match kernel::fillet(body, edges, r) {
|
||||
) -> std::result::Result<(kernel::Body, Option<Vec<f64>>, Vec<Vec3>), kernel::KernelError> {
|
||||
match kernel::fillet_removing(body, edges, r) {
|
||||
Ok((b, gone)) => Ok((b, None, gone)),
|
||||
Err(kernel::KernelError::TooLarge(why)) if fit == crate::FilletFit::Exact => {
|
||||
Err(with_largest_fit(why, "radius", || kernel::fillet_max(body, edges, r)))
|
||||
}
|
||||
Err(kernel::KernelError::TooLarge(why)) if fit == crate::FilletFit::Reduce => match kernel::fillet_max_each(body, edges, r)? {
|
||||
// Built at the radius asked for after all (the groups apart): nothing reduced.
|
||||
Some((used, b)) => Ok((b, used.iter().any(|u| *u < r).then_some(used))),
|
||||
Some((used, b)) => Ok((b, used.iter().any(|u| *u < r).then_some(used), Vec::new())),
|
||||
None => Err(kernel::KernelError::TooLarge(why)),
|
||||
},
|
||||
Err(kernel::KernelError::TooLarge(_)) if fit == crate::FilletFit::Taper => kernel::fillet_tapered(body, edges, r).map(|(b, _)| (b, None)),
|
||||
other => other.map(|b| (b, None)),
|
||||
Err(kernel::KernelError::TooLarge(_)) if fit == crate::FilletFit::Taper => {
|
||||
kernel::fillet_tapered(body, edges, r).map(|(b, _)| (b, None, Vec::new()))
|
||||
}
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
|
||||
/// The warning of a fillet some of whose edges a larger round, overflowing its faces, removed
|
||||
/// whole: they are gone, so they are not rounded.
|
||||
fn removed_note(gone: &[Vec3]) -> String {
|
||||
let at = |p: &Vec3| format!("({}, {}, {})", show_mm(p.x), show_mm(p.y), show_mm(p.z));
|
||||
match gone {
|
||||
[one] => format!("the edge at {} was removed by the larger round, so it is not rounded", at(one)),
|
||||
_ => format!("the edges at {} were removed by the larger round, so they are not rounded", gone.iter().map(at).collect::<Vec<_>>().join(", ")),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3718,10 +3732,13 @@ fn blend_body(
|
||||
(b, input)
|
||||
}
|
||||
FeatureKind::Fillet { fit, .. } => {
|
||||
let (b, u) = fillet_fitted(&mb.body, edges, r, *fit)?;
|
||||
let (b, u, gone) = fillet_fitted(&mb.body, edges, r, *fit)?;
|
||||
if let Some(u) = &u {
|
||||
append_warning(warning, reduced_note(u, r));
|
||||
}
|
||||
if !gone.is_empty() {
|
||||
append_warning(warning, removed_note(&gone));
|
||||
}
|
||||
used = u;
|
||||
(b, input)
|
||||
}
|
||||
|
||||
@@ -4158,6 +4158,26 @@ fn a_design_saved_before_format_14_with_fewer_body_names_opens_and_names_every_b
|
||||
let _ = std::fs::remove_dir_all(&dir);
|
||||
}
|
||||
|
||||
/// R21 on the bottom front edge of a 50 x 50 x 20 block overflows the 20 mm front face (its circle
|
||||
/// about (y, z) = (21, 21) reaches the top only at y = 21 - sqrt(440)) and goes first; the front
|
||||
/// left upright, picked with it, lies wholly in what it removes (every (0, 0, z) is outside that
|
||||
/// circle), so it is gone: not rounded, and the feature says so. The block is R21's alone: the
|
||||
/// section loses 20 (21 - sqrt(440)) + int_0^sqrt(440) (21 - sqrt(441 - u^2)) du, along 50.
|
||||
#[test]
|
||||
fn fillet_edge_removed_by_a_larger_overflowing_round_is_noted() {
|
||||
let mut s = Session::default();
|
||||
run(&mut s, "solid.box", json!({"length": 50, "width": 50, "height": 20}));
|
||||
let out = run(&mut s, "solid.fillet", json!({"edges": [[25, 0, 0], [0, 0, 10]], "radius": 21, "tangent_chain": false, "name": "Round"}));
|
||||
let w = 440f64.sqrt();
|
||||
let f = 0.5 * (w * (441.0 - w * w).sqrt() + 441.0 * (w / 21.0).asin());
|
||||
let lost = 20.0 * (21.0 - w) + 21.0 * w - f;
|
||||
let want = 50.0 * 50.0 * 20.0 - 50.0 * lost;
|
||||
assert!(rel(volume(&mut s), want) < 1e-9, "{} vs {want}", volume(&mut s));
|
||||
let id = out["feature"].as_u64().unwrap();
|
||||
let warning = s.model.result(id).and_then(|r| r.warning.clone()).unwrap_or_default();
|
||||
assert_eq!(warning, "the edge at (0, 0, 10) was removed by the larger round, so it is not rounded");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fillet_fit_reduce_uses_the_largest_radius_that_fits() {
|
||||
// #293: 3.5 is too large for the 6 mm end faces of a 14 x 6 x 10 box; reduce gives 3 (a full
|
||||
|
||||
@@ -214,6 +214,16 @@ pub fn fillet(body: &Body, edges: &[Vec3], radius: f64) -> Result<Body> {
|
||||
crate::blend_smlib::fillet(body, edges, radius).and_then(|b| closed(body, b))
|
||||
}
|
||||
|
||||
/// [`fillet`], with the picks whose edges are gone: where some of the rounds overflow their
|
||||
/// faces, those are built first, and a picked edge one of them removes whole is not rounded (the
|
||||
/// others round what is left of their edges).
|
||||
pub fn fillet_removing(body: &Body, edges: &[Vec3], radius: f64) -> Result<(Body, Vec<Vec3>)> {
|
||||
let _span = solidcraft_profile::span("kernel", "fillet");
|
||||
body.require_brep("fillet")?;
|
||||
let (b, gone) = crate::blend_smlib::fillet_removing(body, edges, radius)?;
|
||||
Ok((closed(body, b)?, gone))
|
||||
}
|
||||
|
||||
/// [`fillet`] with corner setbacks: each `(at, distance)` sets back the corner at the vertex
|
||||
/// nearest `at`, a vertex where every edge is rounded, so its patch starts `distance` along
|
||||
/// each of its edges from the vertex (one distance for all of a corner's edges: SMLib keeps one
|
||||
|
||||
@@ -46,6 +46,13 @@ pub(crate) struct Later {
|
||||
seams: Vec<usize>,
|
||||
}
|
||||
|
||||
impl Later {
|
||||
/// How many of `edges`, the last ones, are the new edges.
|
||||
pub(crate) fn new_count(&self) -> usize {
|
||||
self.new.len()
|
||||
}
|
||||
}
|
||||
|
||||
/// The history of `body` over the body `levels` rounds back ([`Rounds::before`] taken that many
|
||||
/// times), composed; `None` when a step has no record or history, or for no levels.
|
||||
fn down(body: &Body, levels: usize) -> Option<History> {
|
||||
@@ -537,9 +544,17 @@ mod tests {
|
||||
#[test]
|
||||
fn corners_refuse_what_they_cannot_build() {
|
||||
let (bx, a, b, _) = setup();
|
||||
// Larger than the faces, or not a size: errors, no panic. Large but fitting is fine.
|
||||
// Not a size: errors, no panic. Large but fitting is fine.
|
||||
assert!(fillet_radii(&bx, &[(a, 15.0), (b, 2.0)]).is_ok_and(|r| r.unmeshed_faces() == 0));
|
||||
assert!(fillet_radii(&bx, &[(a, 25.0), (b, 2.0)]).is_err());
|
||||
// R25 on a overflows both its faces and goes first: its circle about (x, z) = (-5, -5)
|
||||
// takes all of the top, and with it b, which is gone. What is left is R25's alone: the
|
||||
// square [0, 20]² inside that circle, with t = x + 5, ∫₅^√600 √(625 − t²) dt − 5 (√600 − 5),
|
||||
// along 20.
|
||||
let g = |t: f64| 0.5 * (t * (625.0 - t * t).sqrt() + 625.0 * (t / 25.0).asin());
|
||||
let w = 600f64.sqrt();
|
||||
let want = 20.0 * (g(w) - g(5.0) - 5.0 * (w - 5.0));
|
||||
let r = fillet_radii(&bx, &[(a, 25.0), (b, 2.0)]).unwrap();
|
||||
assert!((vol(&r) - want).abs() < 1e-9 * want, "{} vs {want}", vol(&r));
|
||||
assert!(fillet_radii(&bx, &[(a, f64::NAN)]).is_err());
|
||||
assert!(fillet_radii(&bx, &[(a, 0.0)]).is_err());
|
||||
assert!(fillet_radii(&bx, &[]).is_err());
|
||||
|
||||
@@ -29,6 +29,12 @@ pub(crate) fn fillet(body: &Body, edges: &[Vec3], radius: f64) -> Result<Body> {
|
||||
imp::blend(body, "fillet", Kind::Round, edges, &vec![radius; edges.len()])
|
||||
}
|
||||
|
||||
/// [`fillet`], with the picks whose edges a larger, overflowing round removed whole.
|
||||
pub(crate) fn fillet_removing(body: &Body, edges: &[Vec3], radius: f64) -> Result<(Body, Vec<Vec3>)> {
|
||||
let (b, dropped) = imp::blend_dropping(body, "fillet", Kind::Round, edges, &vec![radius; edges.len()])?;
|
||||
Ok((b, edges.iter().zip(dropped).filter(|(_, d)| *d).map(|(p, _)| *p).collect()))
|
||||
}
|
||||
|
||||
/// Each edge rounded at its own radius ([`crate::fillet_each`]).
|
||||
pub(crate) fn fillet_each(body: &Body, edges: &[Vec3], radii: &[f64]) -> Result<Body> {
|
||||
if radii.len() != edges.len() {
|
||||
@@ -200,6 +206,12 @@ mod imp {
|
||||
}
|
||||
|
||||
pub(super) fn blend(body: &Body, what: &str, kind: Kind, edges: &[Vec3], sizes: &[f64]) -> Result<Body> {
|
||||
blend_dropping(body, what, kind, edges, sizes).map(|(b, _)| b)
|
||||
}
|
||||
|
||||
/// [`blend`], with whether each of `edges` picked an edge a larger round removed whole: a
|
||||
/// round overflowing its faces is built first, and an edge it takes away is gone.
|
||||
pub(super) fn blend_dropping(body: &Body, what: &str, kind: Kind, edges: &[Vec3], sizes: &[f64]) -> Result<(Body, Vec<bool>)> {
|
||||
body.require_brep(what)?;
|
||||
sizes_ok(what, sizes)?;
|
||||
let picked = resolve(body, edges)?;
|
||||
@@ -210,23 +222,29 @@ mod imp {
|
||||
let tol = pick_tolerance(body);
|
||||
let Kind::Round = kind else {
|
||||
let kind = blend_kind(kind);
|
||||
return run(body, what, &picked.edges, |b| b.blend(kind, &picked.points, sizes, tol))
|
||||
return run_with(body, what, &picked.edges, &[], |b| b.blend_dropping(kind, &picked.points, sizes, tol))
|
||||
.map(|(out, dropped, _)| (out, dropped))
|
||||
.map_err(|e| crate::blend::with_continuation(e, next));
|
||||
};
|
||||
// Constant-radius rounds: the body keeps what they were made on, and a later round at a
|
||||
// corner where they meet blends them again with it (crate::blend_corner).
|
||||
let out = match crate::blend_corner::later_corners(body, &picked.edges, sizes)? {
|
||||
Some((later, new)) => reblend(body, what, &later).map(|b| b.with_rounds(body, new)),
|
||||
None => run(body, what, &picked.edges, |b| b.blend(Blend::Round, &picked.points, sizes, tol))
|
||||
.map(|b| b.with_rounds(body, picked.edges.iter().copied().zip(sizes.iter().copied()).collect())),
|
||||
Some((later, new)) => reblend(body, what, &later).map(|(b, dropped_new)| {
|
||||
// A picked seam has no round of its own: only the new edges can be removed.
|
||||
let dropped = picked.edges.iter().map(|e| new.iter().position(|(n, _)| n == e).is_some_and(|j| dropped_new.get(j).copied().unwrap_or(false))).collect();
|
||||
(b.with_rounds(body, new), dropped)
|
||||
}),
|
||||
None => run_with(body, what, &picked.edges, &[], |b| b.blend_dropping(Blend::Round, &picked.points, sizes, tol))
|
||||
.map(|(out, dropped, _)| (out.with_rounds(body, picked.edges.iter().copied().zip(sizes.iter().copied()).collect()), dropped)),
|
||||
};
|
||||
out.map_err(|e| crate::blend::with_continuation(e, next))
|
||||
}
|
||||
|
||||
/// The blend `later` makes of its base, every round from the earliest meeting the new edges'
|
||||
/// corners on and the new edges in one, with its history over `body`, the body the later
|
||||
/// round was given ([`crate::blend_corner::rebase`]).
|
||||
fn reblend(body: &Body, what: &str, later: &crate::blend_corner::Later) -> Result<Body> {
|
||||
/// round was given ([`crate::blend_corner::rebase`]), and whether each new edge (in
|
||||
/// `later`'s order) was removed whole by a larger, overflowing round.
|
||||
fn reblend(body: &Body, what: &str, later: &crate::blend_corner::Later) -> Result<(Body, Vec<bool>)> {
|
||||
let base = &later.base;
|
||||
let mesh = base.mesh(&crate::MeshTolerance::chord((base.size() * 2e-3).max(1e-3)))?;
|
||||
let mut indices = Vec::with_capacity(later.edges.len());
|
||||
@@ -241,9 +259,11 @@ mod imp {
|
||||
}
|
||||
sizes_ok(what, &radii)?;
|
||||
let tol = pick_tolerance(base);
|
||||
let out = run(base, what, &indices, |b| b.blend(Blend::Round, &points, &radii, tol))?;
|
||||
let (out, dropped, _) = run_with(base, what, &indices, &[], |b| b.blend_dropping(Blend::Round, &points, &radii, tol))?;
|
||||
// The new edges are the last of `later.edges`.
|
||||
let dropped_new = dropped.get(dropped.len().saturating_sub(later.new_count())..).map(<[bool]>::to_vec).unwrap_or_default();
|
||||
let history = out.history().and_then(|h| crate::blend_corner::rebase(h, later, body));
|
||||
Ok(out.with_checked_history(history, &record::counts(&[body])).inherit_regularization_protection(body))
|
||||
Ok((out.with_checked_history(history, &record::counts(&[body])).inherit_regularization_protection(body), dropped_new))
|
||||
}
|
||||
|
||||
/// Rounds with corner setbacks: each corner point picks the body's nearest vertex (within
|
||||
|
||||
@@ -157,7 +157,7 @@ pub mod watch;
|
||||
|
||||
pub use blend::{
|
||||
ChamferSide, blend_edges, chamfer, chamfer_max, chamfer_sides, fillet, fillet_each, fillet_g2, fillet_g2_corners, fillet_g2_with_g2_corners,
|
||||
fillet_least_setback, fillet_max, fillet_max_each, fillet_setback, tangent_chain,
|
||||
fillet_least_setback, fillet_max, fillet_max_each, fillet_removing, fillet_setback, tangent_chain,
|
||||
};
|
||||
pub use blend_corner::fillet_radii;
|
||||
pub use blend_variable::{RadiusSpline, Taper, fillet_chord, fillet_tapered, fillet_variable, fillet_variable_points, fillet_variable_spline, taper};
|
||||
|
||||
@@ -394,14 +394,13 @@ fn a_round_wider_than_its_faces_overflows_onto_its_tangent_sides() {
|
||||
}
|
||||
|
||||
/// A corner's rounds with a radius per edge, one wider than its faces: R21 with R5 on the other
|
||||
/// two edges at the corner. The R21 takes both faces beside its edge, and with them the R5
|
||||
/// edges, which lie on them: the body is R21's alone
|
||||
/// two edges at the corner. The R21 overflows, so it goes first; it takes both faces beside its
|
||||
/// edge, and with them the R5 edges, which lie on them and are gone: the body is R21's alone
|
||||
/// ([`a_round_wider_than_its_faces_overflows_onto_its_tangent_sides`]). (The same corner at one
|
||||
/// radius as wide as the faces, and its fit, are the rig's
|
||||
/// fillets/477-fillet-cube-corner-rounds-as-wide-as-faces-* cases; no command takes a radius per
|
||||
/// edge.)
|
||||
#[test]
|
||||
#[ignore = "fails until SMLib blends the corner whole: status 1001, fillet error 4 (edge type 14), Unable to Trim Rail Curve"]
|
||||
fn a_corner_round_wider_than_its_faces_overflows_and_takes_the_corners_other_edges() {
|
||||
let b = box_solid(Vec3::ZERO, Vec3::new(20.0, 20.0, 20.0)).unwrap();
|
||||
let corner = [Vec3::new(10.0, 0.0, 0.0), Vec3::new(0.0, 10.0, 0.0), Vec3::new(0.0, 0.0, 10.0)];
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//! The operations block of `capi/include/smlib.h` (`smlib_boolean`, `smlib_boolean_union_all`, `smlib_boolean2d`, `smlib_fillet`,
|
||||
//! `smlib_chamfer`, `smlib_blend`, `smlib_blend_setback`, `smlib_blend_setback_open`, `smlib_fillet_variable`, `smlib_chamfer_sides`, `smlib_shell`, `smlib_offset_faces`,
|
||||
//! `smlib_chamfer`, `smlib_blend`, `smlib_blend_dropping`, `smlib_blend_setback`, `smlib_blend_setback_open`, `smlib_fillet_variable`, `smlib_chamfer_sides`, `smlib_shell`, `smlib_offset_faces`,
|
||||
//! `smlib_thicken`, `smlib_draft`, `smlib_merge_faces`, `smlib_brep_solid_count`, `smlib_imprint`; the fork's `capi/src/smlib_ops.cpp`), declared by
|
||||
//! hand. Part of the FFI boundary, like its parent: called only through
|
||||
//! [`crate::ops`].
|
||||
@@ -95,6 +95,17 @@ unsafe extern "C" {
|
||||
out: *mut *mut RawBrep,
|
||||
out_failed_point: *mut i64,
|
||||
) -> i32;
|
||||
fn smlib_blend_dropping(
|
||||
brep: *const RawBrep,
|
||||
kind: i32,
|
||||
points: *const f64,
|
||||
sizes: *const f64,
|
||||
n_points: i64,
|
||||
tolerance: f64,
|
||||
out: *mut *mut RawBrep,
|
||||
out_failed_point: *mut i64,
|
||||
out_dropped: *mut i64,
|
||||
) -> i32;
|
||||
fn smlib_blend_setback(
|
||||
brep: *const RawBrep,
|
||||
kind: i32,
|
||||
@@ -467,6 +478,31 @@ pub fn chamfer_sides(_: &Handle, _: &[[f64; 3]], _: f64, _: f64, _: f64, _: bool
|
||||
Err((NOT_BUILT, None))
|
||||
}
|
||||
|
||||
/// `smlib_blend_dropping`: `smlib_blend`, with whether each point picked an edge a larger,
|
||||
/// overflowing round removed whole (and so not rounded).
|
||||
#[cfg(feature = "native")]
|
||||
pub fn blend_dropping(kind: i32, b: &Handle, points: &[[f64; 3]], sizes: &[f64], tolerance: f64) -> Result<(Handle, Vec<bool>), PickError> {
|
||||
let n = i64::try_from(points.len()).map_err(|_| (ERR_ARG, None))?;
|
||||
if sizes.len() != points.len() {
|
||||
return Err((ERR_ARG, None));
|
||||
}
|
||||
let flat = points.as_ptr().cast::<f64>();
|
||||
let mut failed = -1i64;
|
||||
let mut dropped = vec![0i64; points.len()];
|
||||
let out =
|
||||
new_brep(|out| unsafe { smlib_blend_dropping(b.raw(), kind, flat, sizes.as_ptr(), n, tolerance, out, &mut failed, dropped.as_mut_ptr()) })
|
||||
.map_err(|s| {
|
||||
let at = (s == ERR_PICK_NONE || s == ERR_PICK_AMBIGUOUS).then(|| usize::try_from(failed).ok()).flatten();
|
||||
(s, at)
|
||||
})?;
|
||||
Ok((out, dropped.iter().map(|d| *d != 0).collect()))
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "native"))]
|
||||
pub fn blend_dropping(_: i32, _: &Handle, _: &[[f64; 3]], _: &[f64], _: f64) -> Result<(Handle, Vec<bool>), PickError> {
|
||||
Err((NOT_BUILT, None))
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "native"))]
|
||||
pub fn blend(_: i32, _: &Handle, _: &[[f64; 3]], _: &[f64], _: f64) -> Result<Handle, PickError> {
|
||||
Err((NOT_BUILT, None))
|
||||
|
||||
@@ -191,6 +191,23 @@ impl Brep {
|
||||
ffi::ops::blend(kind, &self.0, edges, sizes, tolerance).map(Brep).map_err(pick_error)
|
||||
}
|
||||
|
||||
/// [`Brep::blend`], with whether each point picked an edge that a larger round, overflowing
|
||||
/// its faces, removed whole: that edge is gone and not rounded (SMLib rounds the edges whose
|
||||
/// blends overflow first, then what is left of the others).
|
||||
pub fn blend_dropping(&self, kind: Blend, edges: &[[f64; 3]], sizes: &[f64], tolerance: f64) -> Result<(Brep, Vec<bool>)> {
|
||||
init()?;
|
||||
if edges.len() > MAX_POINTS || edges.is_empty() || sizes.len() != edges.len() {
|
||||
return Err(Error::Argument);
|
||||
}
|
||||
let kind = match kind {
|
||||
Blend::Round => ffi::ops::BLEND_ROUND,
|
||||
Blend::Curvature => ffi::ops::BLEND_CURVATURE,
|
||||
Blend::Chord => ffi::ops::BLEND_CHORD,
|
||||
Blend::Chamfer => ffi::ops::BLEND_CHAMFER,
|
||||
};
|
||||
ffi::ops::blend_dropping(kind, &self.0, edges, sizes, tolerance).map(|(b, d)| (Brep(b), d)).map_err(pick_error)
|
||||
}
|
||||
|
||||
/// [`Brep::blend`] with corner setbacks: each of `corners` picks the vertex nearest it
|
||||
/// (within `tolerance`), a corner where every edge is blended, and that corner's patch starts
|
||||
/// `setbacks[j]` along each of its edges from the vertex (one distance per corner, as SMLib
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
1080-chamfer-sloped-basin-1-mm-rim-3-past-the-rim SMLib refuses the chamfer past the rim as too large (SM_FILERR_NO_ROOM, CloseRemovalRegion): its sheet's boundary along the end wall's top edge line, past the rim, lies on the surfaces of two faces, where it should build cut by the front face
|
||||
1080-fillet-equal-slope-basin-1-mm-rim-loop-0-5 SMLib's check refuses the round: SmSurfOfRevolution Test #7, polar curve intervals do not match the surface's domain
|
||||
1080-fillet-equal-slope-basin-1-mm-rim-loop-4 not supported yet: a convex round past its face is not yet built by subtraction
|
||||
1080-fillet-notched-block-top-outline-r8 not supported yet: a convex round past its face is not yet built by subtraction (largest that fits named 7 mm)
|
||||
1080-fillet-sloped-basin-0-5-mm-rim-r4 not supported yet: a convex round past its face is not yet built by subtraction (largest that fits named 1.185 mm)
|
||||
1080-fillet-sloped-basin-0-5-mm-rim-r4-4-edges not supported yet: a convex round past its face is not yet built by subtraction
|
||||
1080-fillet-sloped-basin-1-mm-rim-r0-5-4-edges SMLib's check refuses the round: SmSurfOfRevolution Test #7, polar curve intervals do not match the surface's domain
|
||||
|
||||
Reference in New Issue
Block a user