mirror of
https://github.com/bherbruck/solidcraft.git
synced 2026-11-06 20:02:16 +00:00
Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2e8847512b | |||
| 0fc45a1b07 | |||
| 4ea1435f7c | |||
| 18c8e31397 | |||
| 180510cdf4 | |||
| 7da12cb981 | |||
| add3e2d2c1 | |||
| 5d8bd85b7d | |||
| f0645730d9 | |||
| ba2408d6f4 | |||
| 124aa4cccd | |||
| c47669d406 |
Generated
+3
-2
@@ -4051,15 +4051,16 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "solidcore"
|
||||
version = "1.0.1"
|
||||
source = "git+https://github.com/tangency-labs/solidcore?rev=8ddce901671f1cebd9214a31d21895d725e886c8#8ddce901671f1cebd9214a31d21895d725e886c8"
|
||||
source = "git+https://github.com/tangency-labs/solidcore?rev=9856ffee5ab778c6b49f24716e82305683eda1fb#9856ffee5ab778c6b49f24716e82305683eda1fb"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"thiserror 2.0.21",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "solidcore-record"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/tangency-labs/solidcore?rev=f5e8e9a29e0c9b7cf6c4040a5bc8878382b3c62f#f5e8e9a29e0c9b7cf6c4040a5bc8878382b3c62f"
|
||||
source = "git+https://github.com/tangency-labs/solidcore?rev=9856ffee5ab778c6b49f24716e82305683eda1fb#9856ffee5ab778c6b49f24716e82305683eda1fb"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
|
||||
+2
-2
@@ -36,10 +36,10 @@ solidcraft-3dx-client = { path = "crates/threedx-client" }
|
||||
# move the rev on its own commit. For a
|
||||
# local checkout, add `[patch."https://github.com/tangency-labs/solidcore"] solidcore = { path =
|
||||
# "../solidcore/crates/solidcore" }` to a `.cargo/config.toml` outside the repository.
|
||||
solidcore = { git = "https://github.com/tangency-labs/solidcore", rev = "8ddce901671f1cebd9214a31d21895d725e886c8" }
|
||||
solidcore = { git = "https://github.com/tangency-labs/solidcore", rev = "9856ffee5ab778c6b49f24716e82305683eda1fb" }
|
||||
# Geometry as data (solidcore's layers §1, "Record"): the B-rep record, its structural validation
|
||||
# and the native body file. Pinned like solidcore; for a local checkout, patch it as above.
|
||||
solidcore-record = { git = "https://github.com/tangency-labs/solidcore", rev = "f5e8e9a29e0c9b7cf6c4040a5bc8878382b3c62f" }
|
||||
solidcore-record = { git = "https://github.com/tangency-labs/solidcore", rev = "9856ffee5ab778c6b49f24716e82305683eda1fb" }
|
||||
# test tooling: a dev-dependency only (xtask/src/layers.rs)
|
||||
solidcraft-testkit = { path = "crates/testkit" }
|
||||
|
||||
|
||||
+32
-26
@@ -6,7 +6,6 @@
|
||||
//! fork fixed in its own sources; each one turned on here says which fork commit it matches.
|
||||
|
||||
use std::panic::{AssertUnwindSafe, catch_unwind};
|
||||
use std::sync::atomic::{AtomicU64, Ordering};
|
||||
use std::sync::{Mutex, PoisonError};
|
||||
|
||||
use solidcore::geom::attribute::{AttributeStore, ObjectKey};
|
||||
@@ -153,7 +152,6 @@ pub(crate) fn fixes() -> UpstreamFixes {
|
||||
f.fillet_point_step_per_point = true;
|
||||
f.analytic_copy_keeps_parameterization = true;
|
||||
f.fillet_point_bigger_step_retry = true;
|
||||
f.fillet_through_extended_rail_end = true;
|
||||
f.precise_properties_body_length_scale = true;
|
||||
f.offset_extension_from_base = true;
|
||||
f.corner_blend_stays_inside_neighbours = true;
|
||||
@@ -230,7 +228,6 @@ pub(crate) fn fixes() -> UpstreamFixes {
|
||||
f.fillet_cleanup_removes_input_slits = true;
|
||||
f.fillet_rail_end_on_continued_surface = true;
|
||||
f.glue_vertices_joins_every_region = true;
|
||||
f.fillet_nx1_tangent_side_edge_same_convexity = true;
|
||||
f.fillet_removal_takes_ring_fillets = true;
|
||||
// The fork's commits that reached `SMLIB_REV` at eaa998a (tangency-labs/smlib#68, #69, #70).
|
||||
f.fillet_trim_inside_by_best_dot = true;
|
||||
@@ -274,7 +271,6 @@ pub(crate) fn fixes() -> UpstreamFixes {
|
||||
f.offset_keep_cavity_regions = true;
|
||||
f.offset_four_face_vertex_split = true;
|
||||
f.gap_samples_non_bspline_v_stride = true;
|
||||
f.gap_array_append_updates_longest = true;
|
||||
f.imprint_skips_collapsed_definition = true;
|
||||
f.precise_properties_trim_base_v = true;
|
||||
f.fillet_blend_curve_revolved_on_arc = true;
|
||||
@@ -319,7 +315,6 @@ pub(crate) fn fixes() -> UpstreamFixes {
|
||||
f.circle_silhouette_perspective_center = true;
|
||||
f.ellipse_convert_to_2d_uses_both_axes = true;
|
||||
f.circle_offset_antiparallel_normal = true;
|
||||
f.masked_array_uses_bit_shift = true;
|
||||
f.global_solver_identical_prefers_larger_when_maximizing = true;
|
||||
f.surface_continuity_checks_last_v_knot = true;
|
||||
f.surface_point_solver_propagates_bbox_failure = true;
|
||||
@@ -346,7 +341,6 @@ pub(crate) fn fixes() -> UpstreamFixes {
|
||||
f.surface_parallel_to_vector_checks = true;
|
||||
f.fillet_round_ends_at_tangent_continuation = true;
|
||||
f.geometric_g2_continuity = true;
|
||||
f.hash_table_grow_preserves_removed_records = true;
|
||||
f.bend_volume_bbox_contains_wide_angle_and_inf_u = true;
|
||||
f.bend_volume_trim_param_box_across_period = true;
|
||||
f.point_set_tight_pbox_projects_points = true;
|
||||
@@ -377,7 +371,6 @@ pub(crate) fn fixes() -> UpstreamFixes {
|
||||
f.fillet_section_end_trim_at_creases = true;
|
||||
f.fillet_refuse_mixed_corner_crossing_rails = true;
|
||||
f.fillet_keep_features = true;
|
||||
f.fillet_blend_corner = true;
|
||||
f.fillet_exact_arc_sections = true;
|
||||
f.fillet_exact_arc_spans = true;
|
||||
// Held back: see `HELD_BACK`.
|
||||
@@ -385,11 +378,22 @@ pub(crate) fn fixes() -> UpstreamFixes {
|
||||
f.cone_unbounded_parameterized_as_nurb = true;
|
||||
f.ellipse_open_arc_keeps_end_angle = true;
|
||||
f.fillet_round_as_definition = true;
|
||||
f.fillet_round_on_round_as_definition = true;
|
||||
f.fillet_overflow_crease_along_edge = true;
|
||||
f.plane_first_torus_section_exact = true;
|
||||
f.keep_exact_pcurves = true;
|
||||
f.shell_one_construction = true;
|
||||
f.offset_extends_ball_patches_as_themselves = true;
|
||||
f.approximate_surface_checks_every_row = true;
|
||||
f.topological_vertex_has_only_edge_uses = true;
|
||||
f.planar_section_face_tolerance = true;
|
||||
f.face_swap_uv_transposes_trims = true;
|
||||
f.closed_smooth_pole_tangent_limit = true;
|
||||
// Held back: see `HELD_BACK`.
|
||||
f.fillet_round_ends_on_outline = false;
|
||||
f.fillet_setback_beside_curved_faces = true;
|
||||
f.fillet_chamfer_corner = true;
|
||||
f.brep_ray_classifies_current_trims = true;
|
||||
f.revolution_frame_from_profile_origin = true;
|
||||
f
|
||||
}
|
||||
|
||||
@@ -399,29 +403,31 @@ pub(crate) fn fixes() -> UpstreamFixes {
|
||||
/// the fork doesn't have stays on, and where solidcore builds what SMLib refuses, a result right
|
||||
/// against its closed form is a win.
|
||||
///
|
||||
/// `fillet_refuse_rounds_breaking_through` (WR-707, solidcore#2311): sound geometry refused. With it
|
||||
/// on, 11 rig cases that pass with it off, each graded against its closed form or invariants, are
|
||||
/// refused as breaking through the part (190-fillet-disc-rim-past-its-2mm-wall fails status 1001
|
||||
/// instead): every-hole-top-rim-r12-past-plate-bottom, 1080-chamfer-runs-into-openings-cut-by-them
|
||||
/// (3350, its closed form), 1080-fillet-notched-block-top-outline-r8,
|
||||
/// 324-fillet-over-hole-cut-by-overlong-cylinder, 324-fillet-over-hole-overlap,
|
||||
/// 5158-fillet-adjacent-plate-edges-as-thick-as-plate and the sloped and equal-slope basin rims of
|
||||
/// #1080 and #5835. A fix under the same flag is in progress on solidcore.
|
||||
/// `fillet_refuse_rounds_breaking_through` (WR-707, solidcore#2311): sound geometry refused. At
|
||||
/// solidcore 9856ffee5, with it on, the fillet rig's 1668-fillet-both-sides-of-thin-wall-r7 is
|
||||
/// refused as breaking through the wall into the hollow behind it ("the largest radius that fits is
|
||||
/// 6.828 mm"), where with it off it builds the closed form, 39509.938 (at 8ddce9016 it refused 11
|
||||
/// rig cases that pass with it off; at this pin the other 270 fillet rig cases come out as with it
|
||||
/// off).
|
||||
///
|
||||
/// `fillet_round_ends_on_outline` (WR-730, solidcore#2541): volumes wrong against their closed
|
||||
/// forms, and rounds too big for their faces built instead of refused. With it on, each of these
|
||||
/// passes with it off: `fillet_over_a_cliff` measures 721.832 against the closed form's 693.205;
|
||||
/// `a_round_wider_than_its_faces_overflows_onto_its_tangent_sides` 6125.719 against 6107.529;
|
||||
/// `taper_follows_the_room_along_the_edge` 4210.926 against 4195.579; the round larger than the
|
||||
/// cube in `hostile_inputs_are_errors` builds (4773.168 against the 1094.853 its refusal leaves),
|
||||
/// as do the fillets the CLI's `run_strict` and `json_out` tests need to fail; and
|
||||
/// `a_corner_round_wider_than_its_faces_overflows_and_takes_the_corners_other_edges`,
|
||||
/// `overflow_goes_first`, `corners_refuse_what_they_cannot_build` and
|
||||
/// `fillet_edge_removed_by_a_larger_overflowing_round_is_noted` are refused (too large, no room,
|
||||
/// status 1001), where with it off they build. Measured again at solidcore 9856ffee5: the same.
|
||||
#[cfg(test)]
|
||||
const HELD_BACK: &[&str] = &["fillet_refuse_rounds_breaking_through"];
|
||||
const HELD_BACK: &[&str] = &["fillet_refuse_rounds_breaking_through", "fillet_round_ends_on_outline"];
|
||||
|
||||
/// How far apart two kernels' procedural blend serials start. A body keeps the serials of the
|
||||
/// kernel that made it and may be used on any other, whose memo of solved stations is keyed by
|
||||
/// serial alone: the ranges keep one definition's stations from answering for another's. A serial
|
||||
/// only names a definition, so which range one comes from changes no answer.
|
||||
pub(crate) const BLEND_SERIALS_PER_KERNEL: u64 = 1 << 40;
|
||||
|
||||
/// A new kernel. Each takes the next range of blend serials, the first starting at 0.
|
||||
/// A new kernel, with this backend's fixes.
|
||||
fn fresh() -> Kernel {
|
||||
static MADE: AtomicU64 = AtomicU64::new(0);
|
||||
let mut k = Kernel::new(&KernelOptions::default());
|
||||
k.fixes = fixes();
|
||||
k.blend_last_serial.set(MADE.fetch_add(1, Ordering::Relaxed).wrapping_mul(BLEND_SERIALS_PER_KERNEL));
|
||||
k
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
|
||||
use solidcore::EntityRef;
|
||||
use solidcore::SolidError;
|
||||
use solidcore::error::offset::OffsetFailure;
|
||||
use solidcore::error::{ErrorKind, Reason};
|
||||
use solidcore::geom::attribute::{Attribute, Behavior, ids};
|
||||
use solidcore::geom::axis2_placement::Axis2Placement;
|
||||
use solidcore::geom::object::Shape;
|
||||
@@ -29,7 +31,6 @@ use solidcore::nurbs::b_spline_curve::ControlPointForm;
|
||||
use solidcore::nurbs::b_spline_surface::p1::SurfParamType;
|
||||
use solidcore::nurbs::b_spline_surface_n_lib::p2::OrientType;
|
||||
use solidcore::nurbs::knots::Side;
|
||||
use solidcore::offset::construction::ShellRefusal;
|
||||
use solidcore::offset::offset_executive::p2::{OffsetOptions, ShellOptions, local_operation_simple, offset_brep_simple, shell_brep_simple};
|
||||
use solidcore::offset::offset_faces::{OffsetFacesExecutive, OffsetFacesRefusal};
|
||||
use solidcore::query::api_queries::{face_bounding_box, face_classify_uv, face_closest_point_in_shape, face_internal_point};
|
||||
@@ -50,21 +51,23 @@ type Out<T> = std::result::Result<T, Error>;
|
||||
/// `SM_ERR_INVALID_INPUT`.
|
||||
const INVALID_INPUT: i32 = 1007;
|
||||
|
||||
/// `SM_ERR_OFFSET_WALLS_TOUCH` (fork a759622), which `status` (smlib_shim.h) reports as
|
||||
/// `SMLIB_ERR_WALLS_TOUCH`.
|
||||
const OFFSET_WALLS_TOUCH: i32 = 1042;
|
||||
|
||||
/// `status` (smlib_shim.h): an offset whose walls touch is [`Error::WallsTouch`]; a vertex moved
|
||||
/// past an edge's other end (`SM_ERR_OFFSET_EDGE_VANISHES`, fork 34318f4) is
|
||||
/// `SMLIB_ERR_UNSUPPORTED`; a wall whose face's offset folds, which solidcore's one construction
|
||||
/// refuses (`fixes.shell_one_construction`, solidcore#2367), is [`Error::WallFolds`] with the
|
||||
/// largest wall it names; any other status as the blends pass it on.
|
||||
/// largest wall it names; any other status as the blends pass it on. solidcore names an offset's
|
||||
/// refusals by their kind and reason (its errors in its own terms, solidcore#2654), whichever
|
||||
/// status the pinned C++ gives them.
|
||||
fn status(e: SolidError) -> Error {
|
||||
match e {
|
||||
SolidError::Upstream { code: OFFSET_WALLS_TOUCH, .. } => Error::WallsTouch,
|
||||
SolidError::ShellRefused { refusal: ShellRefusal::Fold, size, .. } => Error::WallFolds { largest: size },
|
||||
e if e.is_offset_edge_vanishes() => Error::Unsupported,
|
||||
e => blend_status(e),
|
||||
if let SolidError::Failed(f) = &e
|
||||
&& let Reason::Offset(OffsetFailure::Folds { largest, .. }) = f.reason
|
||||
{
|
||||
return Error::WallFolds { largest: Some(largest) };
|
||||
}
|
||||
match e.kind() {
|
||||
ErrorKind::OffsetWallsTouch => Error::WallsTouch,
|
||||
ErrorKind::OffsetEdgeVanishes => Error::Unsupported,
|
||||
_ => blend_status(e),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -546,9 +546,8 @@ fn offset_faces_close_a_step_wall() {
|
||||
/// 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 bodies
|
||||
/// whose rounds go all the way down from -7 and are cut short from -7.5 (solidcore#2027). At -9
|
||||
/// solidcore refuses to put the rounds back (solidcore#2020, open): SolidCraft says it does not
|
||||
/// make that move.
|
||||
/// whose rounds go all the way down from -7 and are cut short from -7.5 (solidcore#2027). At -9,
|
||||
/// which solidcore refused before 9856ffee5 (solidcore#2020), it builds the closed form too.
|
||||
#[test]
|
||||
fn mitred_rounds_follow_a_moved_top() {
|
||||
use super::blend::{Corners, blend};
|
||||
@@ -574,6 +573,7 @@ fn mitred_rounds_follow_a_moved_top() {
|
||||
(-7.0, [6, 12, 8]),
|
||||
(-7.5, [6, 12, 8]),
|
||||
(-8.0, [6, 12, 8]),
|
||||
(-9.0, [6, 12, 8]),
|
||||
(-9.5, [6, 12, 8]),
|
||||
];
|
||||
for (d, n) in moves {
|
||||
@@ -582,7 +582,6 @@ fn mitred_rounds_follow_a_moved_top() {
|
||||
assert_eq!(counts(&moved).unwrap(), n, "d {d}");
|
||||
assert!(rel(v, analytic(d)) < 1e-6, "d {d}: {v} vs {}", analytic(d));
|
||||
}
|
||||
assert!(matches!(offset_faces(&rounded, &[top], 0.1, -9.0), Err(Error::Unsupported)));
|
||||
}
|
||||
|
||||
/// `moved_faces`: drafts so small they leave a plane or cylinder where it was still moved a face
|
||||
|
||||
+23
-140
@@ -24,21 +24,20 @@
|
||||
|
||||
use std::sync::PoisonError;
|
||||
|
||||
use solidcore::EntityRef;
|
||||
use solidcore::curve::curve::Curve;
|
||||
use solidcore::geom::extent2d::Extent2d;
|
||||
use solidcore::geom::geom_utility::p2::ContinuityType;
|
||||
use solidcore::geom::object::Shape;
|
||||
use solidcore::geom::tol::USE_DEFAULT;
|
||||
use solidcore::geom::vector2d::Point2;
|
||||
use solidcore::geom::vector3d::{Point3, Vec3};
|
||||
use solidcore::kernel::Kernel;
|
||||
use solidcore::nurbs::b_spline_surface::p1::SurfParamType;
|
||||
use solidcore::nurbs::b_spline_surface_n_lib::p2::EvaluateFlags;
|
||||
use solidcore::nurbs::b_spline_surface_n_lib::p2::OrientType;
|
||||
use solidcore::query::api_queries::{edge_closest_point, face_closest_point_in_shape, face_internal_point};
|
||||
use solidcore::query::brep::{BrepQuery, LiveBrepObjects};
|
||||
use solidcore::surface::cone::p1::Cone;
|
||||
use solidcore::surface::extend::Continuity;
|
||||
use solidcore::surface::side::BoxSide;
|
||||
use solidcore::surface::surface::Surface;
|
||||
use solidcore::surface::surface::SurfaceKind;
|
||||
use solidcore::topology::brep::p1 as brep_p1;
|
||||
@@ -54,6 +53,7 @@ use solidcore::topology::face::{p1 as face_p1, p2 as face_p2, p4 as face_p4};
|
||||
use solidcore::topology::loopuse::{loop_edges, loop_loopuses, notify_ref};
|
||||
use solidcore::topology::topology_traverser::Marks;
|
||||
use solidcore::topology::{Brep, BrepId, EdgeId, FaceId, LoopId, edge};
|
||||
use solidcore::{EntityRef, SolidError};
|
||||
|
||||
use super::blend::{p3, status};
|
||||
use super::sweep::build_faces;
|
||||
@@ -454,17 +454,17 @@ pub(crate) fn untrim_face(body: &Body, point: [f64; 3], tol: f64, holes: Option<
|
||||
/// grows in u), and whether it is at the box's max.
|
||||
#[derive(Clone, Copy)]
|
||||
struct Side {
|
||||
which: SurfParamType,
|
||||
which: BoxSide,
|
||||
u: bool,
|
||||
high: bool,
|
||||
}
|
||||
|
||||
/// `SIDES`.
|
||||
const SIDES: [Side; 4] = [
|
||||
Side { which: SurfParamType::UMin, u: true, high: false },
|
||||
Side { which: SurfParamType::UMax, u: true, high: true },
|
||||
Side { which: SurfParamType::VMin, u: false, high: false },
|
||||
Side { which: SurfParamType::VMax, u: false, high: true },
|
||||
Side { which: BoxSide::UMin, u: true, high: false },
|
||||
Side { which: BoxSide::UMax, u: true, high: true },
|
||||
Side { which: BoxSide::VMin, u: false, high: false },
|
||||
Side { which: BoxSide::VMax, u: false, high: true },
|
||||
];
|
||||
|
||||
/// `SAMPLES`.
|
||||
@@ -546,55 +546,6 @@ fn side_edge(k: &Kernel, b: &Brep, surf: &Surface, dom: &Extent2d, s: Side, edge
|
||||
e.filter(|_| d <= on)
|
||||
}
|
||||
|
||||
/// `across`: how far `ext` (the face's surface extended past side `s` of its box `dom`, on the
|
||||
/// same parameters) runs past that side, measured across it through the side's middle, by
|
||||
/// 16-point Gauss-Legendre quadrature on 64 pieces. Negative when it can't be evaluated.
|
||||
fn across(k: &Kernel, ext: &Surface, dom: &Extent2d, s: Side) -> f64 {
|
||||
const X: [f64; 8] = [
|
||||
0.0950125098376374,
|
||||
0.2816035507792589,
|
||||
0.4580167776572274,
|
||||
0.6178762444026438,
|
||||
0.755404408355003,
|
||||
0.8656312023878318,
|
||||
0.9445750230732326,
|
||||
0.9894009349916499,
|
||||
];
|
||||
const W: [f64; 8] = [
|
||||
0.1894506104550685,
|
||||
0.1826034150449236,
|
||||
0.1691565193950025,
|
||||
0.1495959888165767,
|
||||
0.1246289712555339,
|
||||
0.0951585116824928,
|
||||
0.0622535239386479,
|
||||
0.0271524594117541,
|
||||
];
|
||||
const PIECES: usize = 64;
|
||||
let Ok(bx) = ext.natural_uv_domain_with_nurb(k) else { return -1.0 };
|
||||
let mid = on_side(dom, s, 0.5);
|
||||
let from = if s.u { mid.x } else { mid.y };
|
||||
let to = match (s.u, s.high) {
|
||||
(true, true) => bx.max().x,
|
||||
(true, false) => bx.min().x,
|
||||
(false, true) => bx.max().y,
|
||||
(false, false) => bx.min().y,
|
||||
};
|
||||
let h = (to - from) / PIECES as f64;
|
||||
let mut length = 0.0;
|
||||
for piece in 0..PIECES {
|
||||
let c = from + (piece as f64 + 0.5) * h;
|
||||
for i in 0..16 {
|
||||
let (x, w) = if i < 8 { (-X[i], W[i]) } else { (X[i - 8], W[i - 8]) };
|
||||
let t = c + 0.5 * h * x;
|
||||
let uv = if s.u { Point2::new(t, mid.y) } else { Point2::new(mid.x, t) };
|
||||
let Some((_, du, dv)) = eval(k, ext, uv) else { return -1.0 };
|
||||
length += 0.5 * h.abs() * w * if s.u { du } else { dv }.length();
|
||||
}
|
||||
}
|
||||
length
|
||||
}
|
||||
|
||||
/// `cone_continued`: a cone's or cylinder's face continued naturally `distance` past side `s` of
|
||||
/// its box `dom`, as the analytic itself over a wider STEP domain (degrees round the axis,
|
||||
/// height along it). `None` where the cone can't be widened so (more than a turn, or past the
|
||||
@@ -656,82 +607,16 @@ fn same_patch(k: &Kernel, p: &Surface, q: &Surface, tol: f64) -> bool {
|
||||
}
|
||||
|
||||
/// `extended_by`: the surface `surf` (whose face is its whole box `dom`) extended past side `s` as
|
||||
/// `ct` says, so that it runs `distance` past that side measured across it ([`across`]), within
|
||||
/// 1e-9 of it. `CreateExtendedSurface` takes its distance as an estimate, and how far it then runs
|
||||
/// is increasing in what it is asked: a bracketed solve on that (each ask scaled by the distance
|
||||
/// over what it gave until two asks fall either side, then Illinois false position). An extension
|
||||
/// that moves the face's side off its parameters, or a target not met, is [`Error::NotExact`],
|
||||
/// never the surface as it came out.
|
||||
fn extended_by(k: &Kernel, surf: &Surface, dom: &Extent2d, s: Side, ct: ContinuityType, distance: f64, model_tol: f64) -> Result<Surface> {
|
||||
const BRACKET_TRIES: usize = 40;
|
||||
const SOLVE_TRIES: usize = 100;
|
||||
let tol = 1e-9 * distance;
|
||||
// How far asking `ask` runs, and the surface it makes.
|
||||
let try_ask = |ask: f64| -> Result<(Surface, f64)> {
|
||||
let tried = surf.create_extended_surface_dir(k, s.which, ask, ct).map_err(status)?;
|
||||
// The face's side stays where it was on the extended surface's parameters.
|
||||
let mid = on_side(dom, s, 0.5);
|
||||
let stays = matches!((point_at(k, surf, mid), point_at(k, &tried, mid)), (Some(was), Some(now)) if (was - now).length() <= model_tol);
|
||||
if !stays {
|
||||
return Err(Error::NotExact);
|
||||
}
|
||||
let got = across(k, &tried, dom, s);
|
||||
if got.is_finite() && got > 0.0 { Ok((tried, got)) } else { Err(Error::NotExact) }
|
||||
};
|
||||
// Asks that run short of and past `distance`, by f = got - distance.
|
||||
let (mut short, mut past) = (None, None);
|
||||
let mut ask = distance;
|
||||
for _ in 0..BRACKET_TRIES {
|
||||
let (made, got) = try_ask(ask)?;
|
||||
let f = got - distance;
|
||||
if f.abs() <= tol {
|
||||
return Ok(made);
|
||||
}
|
||||
if f < 0.0 {
|
||||
short = Some((ask, f));
|
||||
} else {
|
||||
past = Some((ask, f));
|
||||
}
|
||||
if short.is_some() && past.is_some() {
|
||||
break;
|
||||
}
|
||||
ask *= distance / got;
|
||||
/// `how` says, so that it runs `distance` past that side measured across it, exactly: solidcore's
|
||||
/// one extension ([`Surface::extended_by_distance`]), which keeps the source's own part bit for bit
|
||||
/// and meets the distance within 1e-9 of it. A distance it cannot meet exactly is
|
||||
/// [`Error::NotExact`], never a surface that falls short or runs past.
|
||||
fn extended_by(k: &Kernel, surf: &Surface, dom: &Extent2d, s: Side, how: Continuity, distance: f64) -> Result<Surface> {
|
||||
match surf.extended_by_distance(k, dom, s.which, how, distance) {
|
||||
Ok(e) => Ok(e.surface),
|
||||
Err(SolidError::ExtendRefused { .. } | SolidError::NotConverged { .. }) => Err(Error::NotExact),
|
||||
Err(e) => Err(status(e)),
|
||||
}
|
||||
let (Some((mut lo, mut flo)), Some((mut hi, mut fhi))) = (short, past) else { return Err(Error::NotExact) };
|
||||
// Illinois: false position, halving the value at the end that stays when the same end moves
|
||||
// twice running.
|
||||
#[derive(PartialEq)]
|
||||
enum Moved {
|
||||
Neither,
|
||||
Lo,
|
||||
Hi,
|
||||
}
|
||||
let mut moved = Moved::Neither;
|
||||
for _ in 0..SOLVE_TRIES {
|
||||
let x = hi - fhi * (hi - lo) / (fhi - flo);
|
||||
if !(x > lo.min(hi) && x < lo.max(hi)) {
|
||||
break;
|
||||
}
|
||||
let (made, got) = try_ask(x)?;
|
||||
let f = got - distance;
|
||||
if f.abs() <= tol {
|
||||
return Ok(made);
|
||||
}
|
||||
if f < 0.0 {
|
||||
(lo, flo) = (x, f);
|
||||
if moved == Moved::Lo {
|
||||
fhi *= 0.5;
|
||||
}
|
||||
moved = Moved::Lo;
|
||||
} else {
|
||||
(hi, fhi) = (x, f);
|
||||
if moved == Moved::Hi {
|
||||
flo *= 0.5;
|
||||
}
|
||||
moved = Moved::Hi;
|
||||
}
|
||||
}
|
||||
Err(Error::NotExact)
|
||||
}
|
||||
|
||||
/// `smlib_extend_sheet`: the one-face sheet `sheet`, whose face is its surface's whole parameter
|
||||
@@ -787,15 +672,13 @@ pub(crate) fn extend_sheet(sheet: &Body, point: [f64; 3], tol: f64, distance: f6
|
||||
if (nl.x - dl.x).abs() > ptol || (nl.y - dl.y).abs() > ptol || (nh.x - dh.x).abs() > ptol || (nh.y - dh.y).abs() > ptol {
|
||||
return Ok(Err(Error::Unsupported));
|
||||
}
|
||||
let ct = match how {
|
||||
Continuation::Tangent => ContinuityType::G1,
|
||||
Continuation::Curvature => ContinuityType::G1G2,
|
||||
Continuation::Natural => ContinuityType::CInfinity,
|
||||
let continuity = match how {
|
||||
Continuation::Tangent => Continuity::Tangent,
|
||||
Continuation::Curvature => Continuity::Curvature,
|
||||
Continuation::Natural => Continuity::Natural,
|
||||
};
|
||||
// CreateExtendedSurface takes its distance as an estimate (a natural parabola falls 2.5%
|
||||
// short, a G2 run-off of a circle runs more than twice as far): the distance asked of it
|
||||
// is solved for until the extension measures `distance` across the side's middle.
|
||||
let extended = match extended_by(k, &surf, &dom, grow, ct, distance, model_tol) {
|
||||
// The extension runs `distance` across the side, exactly (solidcore's one extension).
|
||||
let extended = match extended_by(k, &surf, &dom, grow, continuity, distance) {
|
||||
Ok(e) => e,
|
||||
Err(e) => return Ok(Err(e)),
|
||||
};
|
||||
|
||||
@@ -55,7 +55,7 @@ pub enum Error {
|
||||
/// middle of the edge it was found for, and why there is no room, when the refusal names them.
|
||||
TooLarge { size: f64, kind: FitKind, at: Option<[f64; 3]>, why: Option<RoomReason> },
|
||||
/// A shell, offset or thicken whose wall is thicker than a face curves: the face's offset
|
||||
/// folds (solidcore's `ShellRefused`, `ShellRefusal::Fold`). The largest wall that works,
|
||||
/// folds (solidcore's `OffsetFailure::Folds`). The largest wall that works,
|
||||
/// when solidcore names one.
|
||||
WallFolds { largest: Option<f64> },
|
||||
/// SMLib cannot build this exactly yet (a variable radius whose law has a corner).
|
||||
|
||||
@@ -486,19 +486,6 @@ fn bodies_move_between_kernels_and_calls_run_side_by_side() {
|
||||
}
|
||||
}
|
||||
|
||||
/// Each kernel has its own range of blend serials: a body keeps the serials of the kernel that
|
||||
/// made it, and another kernel's memo of solved stations must not take them for its own.
|
||||
#[test]
|
||||
fn kernels_never_issue_the_same_blend_serial() {
|
||||
let range = core::BLEND_SERIALS_PER_KERNEL as usize;
|
||||
let ranges = core::run("outer", |outer| {
|
||||
let inner = core::run("inner", |inner| Ok(inner.blend_last_serial.get() as usize)).unwrap_or_default();
|
||||
Ok([outer.blend_last_serial.get() as usize / range, inner / range])
|
||||
});
|
||||
let [outer, inner] = ranges.unwrap();
|
||||
assert_ne!(outer, inner);
|
||||
}
|
||||
|
||||
/// A panic in a call running beside another costs neither: the panicking call's kernel is thrown
|
||||
/// away and the other call and later ones go on.
|
||||
#[test]
|
||||
|
||||
@@ -8,32 +8,39 @@
|
||||
# and junit-gpu-1..4), run `cargo xtask known-failing --junit <dir>`, then drop each FIXED line and
|
||||
# add each REGRESSION line with its cause, from the test's failure message.
|
||||
solidcraft-cli::action_matrix::action_matrix_sample 3 baseline actions fail, the same 3 as on C++: 2 shells (Bad Loop Orient on issue-616-lid-ribs; status 1001 on filleted-shelled-box), 1 fillet (SmSurfOfRevolution Test #7 on oblique_cut_of_cylinder)
|
||||
solidcraft-cli::model_cache::a_later_round_after_opening_blends_the_saved_rounds_again the later r3 round at the r2 mitre builds solidcore's 10-face corner (7928.743041), the test wants SMLib f916a8d's setback corner (smlib#104), which solidcore ports in solidcore#2310: 15 faces, 7928.142563938
|
||||
solidcraft-cli::model_cache::a_later_round_after_opening_blends_the_saved_rounds_again the later r3 round at the r2 mitre builds 7927.724283 since solidcore#2382 (a9ef4c707, the least-certifying setback scale); the test wants SMLib f916a8d's setback corner (smlib#104), 15 faces, 7928.142563938, which solidcore#2369 built (7928.142564)
|
||||
solidcraft-cli::naming_corpus::corpus_designs_name_alike_every_build_and_fail_where_a_reference_is_gone oracle/83-boundary-loop-thicken does not load: step 8, thicken status 1001, as on C++
|
||||
solidcraft-doc::eval::cost_tests::a_tap_marking_searches_only_the_bodies_near_it main's mesh-based version (#10303) not taken; the exact replacement is to come
|
||||
solidcraft-doc::eval::cost_tests::a_tap_marking_still_searches_the_bodies_within_its_reach main's mesh-based version (#10303) not taken; the exact replacement is to come
|
||||
solidcraft-engine::boolean_regression_tests::box_intersect_splits_the_end_off_a_raked_wedge_after_its_end_rounds the wedge's end rounds fail status 1001 since solidcore#2480 (819a5ad3a, the procedural blend record); passes at 7906d0d0c
|
||||
solidcraft-engine::cmd::edit::tests::inserting_variable_fillet_control_preserves_parameters_at_existing_positions solidcore refuses a variable fillet whose law has a corner (solidcore#430)
|
||||
solidcraft-engine::cmd::file::tests::each_format_has_an_export_command_of_its_own the box's planar faces are meshed into 124 triangles, not 12 (the STL is 6284 bytes, the test counts 84 + 50 x 12), as on SMLib
|
||||
solidcraft-engine::cmd::sketch_project::tests::whole_body_intersect_keeps_a_small_round_between_short_walls the whole-body intersection gives no closed outline (0 profiles, 1 wanted) on solidcore between 8ddce9016 and 5d2635d36: it fails at 5d2635d36 and at 9856ffee5
|
||||
solidcraft-engine::extent_tests::cut_to_the_far_side_of_a_curved_wall main's mesh-based version (#8634) not taken; the exact replacement is to come
|
||||
solidcraft-engine::face_name_tests::a_join_that_makes_the_body_bigger_leaves_round_walls_it_never_touched_alone main's edge lookup by a stored point (#11286) finds the edge on the display mesh (edge_near on the body's mesh), not taken; the exact replacement is to come
|
||||
solidcraft-engine::hole_face_tests::a_hole_wider_than_the_part_says_it_removes_all_of_it a 40 mm hole at (10, 10) touches the plate's edge y = 30 at one point; the kernel parts the plate there into 2 bodies, the test wants truck's 1, as on SMLib
|
||||
solidcraft-engine::measure_centre_tests::a_fillet_round_a_boss_reports_its_radius the round at the foot of a boss is not an analytic torus of minor radius 3, so no face of the body is (the test finds none to measure), as on SMLib
|
||||
solidcraft-engine::pleat_regressions::mirrored_pleat_joins_into_a_thick_case_wall FilletRearOuter and FilletRearInner fail status 1001 since solidcore#2480 (819a5ad3a, the procedural blend record); passes at 7906d0d0c
|
||||
solidcraft-engine::pleat_regressions::pleat_built_at_the_far_end_joins_the_finished_case FilletRearOuter and FilletRearInner fail status 1001 since solidcore#2480 (819a5ad3a, the procedural blend record); passes at 7906d0d0c
|
||||
solidcraft-engine::tests::a_later_round_at_a_mitred_corner_is_blended_with_the_rounds_there the later r3 round at the r2 mitre builds 7927.724283 since solidcore#2382 (a9ef4c707, the least-certifying setback scale); 7928.142564 at solidcore#2369 (the fork's setback corner, smlib#104); the test wants the old 10-face corner, 7928.743041
|
||||
solidcraft-engine::tests::chord_and_variable_fillets its 2 → 4 → 2 waist: solidcore refuses a variable fillet whose law has a corner (solidcore#430)
|
||||
solidcraft-engine::tests::fillet_fit_taper_closes_to_a_point fillet status 1001 on the taper fit (radius 16 closing to 0), as on C++
|
||||
solidcraft-engine::tests::mirror_placed::dragging_a_mirrored_part_meshes_its_copies_once a copy of a copy drawn from its first copy's triangles (#10101) is triangulated differently from a fresh mesh of it, where truck's meshes are the same under a rigid move, as on SMLib
|
||||
solidcraft-engine::tests::shell_tangent_chain_that_opens_every_face_explains_how_to_keep_walls the 2 mm shell of the box with every edge rounded r 1.5, its front face open, fails SM_ERR_INVALID_INPUT at solidcore 8ddce9016: the wall is thicker than the rounds and their Ball corners (BallPatch, fillet_blend_corner), whose inward offsets collapse
|
||||
solidcraft-engine::tests::pleat_join::the_pleats_join_at_every_wall_from_2_4_to_2_6_mm at 2.5 mm FilletRearOuter and FilletRearInner fail status 1001 since solidcore#2480 (819a5ad3a, the procedural blend record); passes at 7906d0d0c
|
||||
solidcraft-engine::tests::rim_cut::rim_cut_after_the_round_on_the_other_end the window cut after the far-end round adds 4 faces, not 3 (16, want 15), since solidcore's exact surface extension (a6314d4b3 or f4e0ec2d0, solidcore#2769); passes at the merge before, 9e343e179
|
||||
solidcraft-engine::tests::robustness::a_boundary_found_across_a_seam_is_not_used seed 20's fillet fails status 1001 since solidcore#2480 (819a5ad3a, the procedural blend record); passes at 7906d0d0c
|
||||
solidcraft-kernel::blend::corner_tests::a_round_ending_in_an_earlier_round_matches_both_together fillet status 1001 on the round that ends in the earlier one, as on C++
|
||||
solidcraft-kernel::blend::corner_tests::corner_blends_hold_at_any_scale at 0.01x the arc case's rounds remove 72.783 (scaled back) against 72.713 at 1x, as on C++
|
||||
solidcraft-kernel::blend_corner::tests::issue2422_vertical_after_separate_bottom_rounds the vertical edge after the separate bottom rounds is refused as smooth ("its faces meet tangentially, so there is nothing to round"): the rounds leave it tangent at solidcore 8ddce9016
|
||||
solidcraft-kernel::blend_corner::tests::three_rounds_at_a_corner the corner's variable-radius transition between rounds of different radii meets its neighbours at 0.144 degrees once its sections are the balls' touch circles (fillet_gn_section_generator, solidcore#2262; 0 with the great circles), as on SMLib d01d7b0; the corner step replaces that transition
|
||||
solidcraft-kernel::blend_variable::tests::variable_radius_on_a_box_edge the variable round r 2 to 5 along a box edge fails status 1001 at solidcore 8ddce9016
|
||||
solidcraft-kernel::blend_smlib::tests::smooth_edges_and_unfinished_tangent_chains_are_refused_saying_why the r1 top round alone measures 7957.723 against the closed form 7957.505 since solidcore#2364 (845bdb4e0, the smooth-vertex End); passes at fb937dd8d
|
||||
solidcraft-kernel::blend_variable::tests::variable_radius_with_a_corner_through_a_middle_point solidcore refuses a variable fillet whose law has a corner (solidcore#430)
|
||||
solidcraft-kernel::blend_wrong_way_tests::a_chamfer_that_would_grow_the_part_on_a_convex_edge_is_refused at solidcore 8ddce9016 the 0.5 chamfer of the ball cut's rim is no longer refused as too large: the session builds no face (made no change), its tangent chain running into an unblended edge
|
||||
solidcraft-kernel::corner_g2::tests::a_long_setback_keeps_the_g2_patch_inside_the_box at set backs 11 to 15 the G2 corner patch bulges past the box, as on C++
|
||||
solidcraft-kernel::corner_g2::tests::curvature_rounds_meet_at_a_g2_corner the corner between curvature rounds jumps 2.07 in curvature over 538 stations on solidcore; the test wants it curvature continuous, as SMLib f916a8d's setback corner (smlib#104), which solidcore ports in solidcore#2310 builds it
|
||||
solidcraft-kernel::corner_g2::tests::the_box_corner_g2_patch_is_a_closed_solid_curvature_continuous_to_its_neighbours the fitted G2 corner patch bulges 1.7e-5 past the box, as on C++
|
||||
solidcraft-kernel::fillet_setback_tests::a_setback_not_past_the_radius_is_refused_naming_the_least solidcore builds setback 5.5 (15 faces) where SMLib f916a8d's setback corner (smlib#104), which solidcore ports in solidcore#2310 refuses it naming the least that builds; nothing names the least setback on solidcore until then
|
||||
solidcraft-kernel::modify_history_tests::fillet_variable_and_chord the variable round r 2 to 5 along the cube's edge fails status 1001 at solidcore 8ddce9016, as variable_radius_on_a_box_edge
|
||||
solidcraft-kernel::native::tests::box_and_fillet_have_stable_wire_records the box-edge round's wire record differs from the fixture at solidcore 8ddce9016 (a value 3 is 5): the fixture is re-blessed (NATIVE_BREP_BLESS=1) once the change is shown right
|
||||
solidcraft-kernel::tests::fillet_partial_mixed_arc_and_line_perimeter_run the partial arc-and-line run fails status 1001 since solidcore#2480 (819a5ad3a, the procedural blend record); passes at 7906d0d0c
|
||||
solidcraft-kernel::tests::fillet_tabbed_plate_outer_loop_and_partial_selection_after_hole the tabbed plate's outer-loop rounds fail status 1001 since solidcore#2480 (819a5ad3a, the procedural blend record); passes at 7906d0d0c
|
||||
solidcraft-kernel::tests::shell_of_a_basin_past_its_rim_keeps_the_rim_solid the shell of the basin fails status 1001 since the offset's exact extension margin (4d2b4d35a or 95192d385, solidcore#2769); passes at a5de86aaf
|
||||
solidcraft-smlib::core::blend_tests::tabbed_plate_rounds_mitred_on_the_arcs_continuation the rounds fail status 1001 since solidcore#2480 (819a5ad3a, the procedural blend record); passes at 7906d0d0c
|
||||
solidcraft-smlib::ops::tests::a_variable_round_with_a_corner_in_its_law_is_its_balls_union solidcore refuses a variable fillet whose law has a corner (solidcore#430)
|
||||
solidcraft-ui-egui::preselect_tests::variable_fillet_round_trip the dialog's variable round fails status 1001 at solidcore 8ddce9016, as variable_radius_on_a_box_edge
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# The fillets cases that fail today on solidcore, one a line: `<case> <why it fails today>`. Sorted.
|
||||
# The kernel rig gate fails on a case that fails and is not listed, and on a listed case that passes.
|
||||
# Baseline: solidcore pin 8ddce9016, tests/kernel-cases run by `cargo xtask kernel-cases`, x86_64 Linux.
|
||||
# Baseline: solidcore pin 9856ffee5, tests/kernel-cases run by `cargo xtask kernel-cases`, x86_64 Linux.
|
||||
1080-fillet-equal-slope-basin-1-mm-rim-loop-4 [fail] continuity_order: got {'body': 'Slab', 'edges': 'blend', 'order': 'g0', want >= g1 at every blend seam
|
||||
1080-fillet-sloped-basin-1-mm-rim-r4-2-edges [fail] continuity_order: got {'body': 'Slab', 'edges': 'blend', 'order': 'g0', want >= g1 at every blend seam
|
||||
1080-fillet-sloped-basin-1-mm-rim-r4-4-edges [fail] continuity_order: got {'body': 'Slab', 'edges': 'blend', 'order': 'g0', want >= g1 at every blend seam
|
||||
@@ -16,9 +16,10 @@ cov-fillet-g2-mixed-corner [unsupported] refused as on SMLib d01d7b0: a G2 corne
|
||||
cov-fillet-g2-oblique-three-edge-corner [unsupported] refused on solidcore: its three edges meet at different wedge angles, and one curvature fillet takes the first edge's equal-area thumbweight for every edge (solidcore#2250, issuecomment-6563419897); SMLib d01d7b0 fails it too
|
||||
cov-fillet-g2-pocket-corner [fail] continuity_order: G1 at one seam where the corner patch meets a contact face (g2 wanted), as on SMLib d01d7b0
|
||||
cov-junction-boss-tilt-20-root-round [fail] fillet status 1001 on a cylinder tilted 20 degrees into the plate, as on SMLib
|
||||
cov-junction-boss-tilt-40-root-round [fail] fillet status 1001 on a cylinder tilted 40 degrees into the plate, as on SMLib
|
||||
cov-junction-tee-equal-round [fail] the result is not a closed solid, as on SMLib: equal pipes' intersection is two plane ellipses crossing, a corner the old corner code cannot join (the corner step)
|
||||
cov-junction-y-junction-120-round [unsupported] refused as on SMLib: the faces between the three intersection curves narrow to nothing at the two triple points, so the room check trips (the corner step)
|
||||
every-block-cylinder-tangent-concave-arc-r2-partial-chain [fail] continuity_order: g0, a contact seam meets at 90 degrees, want >= g1 at every blend seam since solidcore#2364 (845bdb4e0, the smooth-vertex End); passes at fb937dd8d
|
||||
report-drafted-peg-front-and-concave-rounds-together-r2 [unsupported] step 13 (solid.fillet): invalid input: not supported yet: the fillet meets a corner of this kind, which SMLib's blends do not handle yet (where its ed
|
||||
report-fillet-curvature-three-edges-at-bar-corner [fail] continuity_order: G1 at one seam where the corner patch meets a contact face (g2 wanted), as on SMLib d01d7b0 (see KNOWN_FAILING)
|
||||
report-fillet-curvature-three-edges-at-bar-corner-solver-residues [fail] continuity_order: G1 at one seam where the corner patch meets a contact face (g2 wanted), as on SMLib d01d7b0 (see KNOWN_FAILING)
|
||||
report-fillet-curvature-three-edges-at-bar-corner-solver-residues-outside-setback [unsupported] the corner fill is refused (misses its neighbours' curvature by 4.02e-3, tolerance 2.5e-3) since solidcore#2369 (23a97889b, the setback corner); built the closed form's 9526.705048 at 8ddce9016
|
||||
|
||||
+1
-1
@@ -4,5 +4,5 @@
|
||||
"source": "invariants",
|
||||
"method": "the cut cannot find its sketch there: the move breaks a feature that worked and is refused",
|
||||
"outcome": "refused",
|
||||
"refusal": "moving Notch there breaks Notch"
|
||||
"refusal": "breaks Notch"
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
{
|
||||
"source": "analytic",
|
||||
"known_failure": "the variable round r 2 to 5 along a box edge fails status 1001 at solidcore 8ddce9016 (as blend_variable::tests::variable_radius_on_a_box_edge in tests/KNOWN_FAILING_TESTS)",
|
||||
"method": "box 40x30x20 with its top front edge (y=0, z=20) rounded at a radius running straight from 2 (x=0) to 5 (x=40). The round is the union of the balls rolled along the edge, ball s touching both faces at r(s), the law continued past the edge's ends along its end slopes: each section loses the corner points no ball reaches, up to rho(x, t), the nearest entry into a ball along the ray from the edge at the angle t. V, moments and areas integrated by Gauss-Legendre panels in x and t (tools/oracle-analytic/cases_fillets.py)",
|
||||
"body_count": 1,
|
||||
"volume_mm3": 23888.613525715446,
|
||||
|
||||
Reference in New Issue
Block a user