smlib: an offset or other non-NURBS face surface exports through ApproximateSurface on solidcore (solidcore#1441), and the new fixes are on

`to_arrays` approximates a face surface that is not a B-spline kind as `FlatFromBrep` does:
`ApproximateSurface` within the curves' approximation tolerance (`approx_tol3d`), up to 5
subdivisions, B-splines copied; a failed status or no surface fails the export.

`fixes()` turns on fillet_3x2_mixed_concave_side_edge (#1475),
ssi_singular_start_inside_direction (#1522) and fillet_vertex_error_diagnostics (#1469).

offset_sheet_quarter_cylinder now exports and matches its closed form; its parity with the C++
kernel stays ignored on solidcore#1477 (the quarter arc sweeps to an SmSurfOfExtrusion, not the
fork's SmCylinder).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MNXLXkZLQ6T7TSi4wswcmk
This commit is contained in:
Brett Lawson
2026-10-30 03:35:44 +01:00
parent 2308fa5be7
commit f23aa76d34
3 changed files with 22 additions and 11 deletions
+3
View File
@@ -59,6 +59,7 @@ pub(crate) fn fixes() -> UpstreamFixes {
f.fillet_refuse_face_consuming_blends = true;
f.fillet_refuse_non_manifold_result = true;
f.fillet_refuse_crossing_rails = true;
f.fillet_vertex_error_diagnostics = true;
f.fillet_corner_ball_patch = true;
f.fillet_chamfer_cone_on_arc = true;
f.fillet_torus_center_on_axis = true;
@@ -138,6 +139,7 @@ pub(crate) fn fixes() -> UpstreamFixes {
f.corner_blend_stays_inside_neighbours = true;
f.fillet_cleanup_keeps_target_faces = true;
f.fillet_nx1_tangent_side_edge = true;
f.fillet_3x2_mixed_concave_side_edge = true;
f.offset_closed_curve_trim_arc = true;
f.offset_stitch_at_body_tolerance = true;
f.curve_contacts_at_curve_ends = true;
@@ -147,6 +149,7 @@ pub(crate) fn fixes() -> UpstreamFixes {
f.sphere_small_circle_not_touching = true;
f.ssi_tangent_contact_points = true;
f.ssi_trace_tangent_curves_once = true;
f.ssi_singular_start_inside_direction = true;
f.found_torus_sphere_keep_tested_nurb = true;
f
}
+18 -10
View File
@@ -11,9 +11,8 @@
//! from the edges' and vertices' own ([`own_tolerances`]). Each entity keeps its tolerance across
//! the kernels instead of every one taking the largest at each crossing.
//!
//! Where solidcore has no port of an SMLib call the C++ makes, the conversion fails with
//! "not supported yet" naming the call: `SmSurface::ApproximateSurface` (a face whose surface is
//! not a B-spline kind).
//! A face whose surface is not a B-spline kind (an offset) exports its approximation, as
//! `FlatFromBrep` does (`SmSurface::ApproximateSurface`).
//!
//! [`from_arrays`] also runs the capi's `PutEnclosingShellsFirst` ([`put_enclosing_shells_first`],
//! an addition to SmuConvert): a bounded region of several shells starts its list at the shell
@@ -34,6 +33,7 @@ use solidcore::geom::axis2_placement::Axis2Placement;
use solidcore::geom::extent1d::Extent1d;
use solidcore::geom::extent2d::Extent2d;
use solidcore::geom::object::ObjectRef;
use solidcore::geom::tol::approx_tol3d;
use solidcore::nurbs::b_spline_curve::{BSplineCurve, BSplineCurveForm, CanonicalData, KnotType};
use solidcore::nurbs::b_spline_surface::{BSplineSurface, BSplineSurfaceForm, CanonicalSurfaceData};
use solidcore::nurbs::crv_basic::Curve as NurbCurve;
@@ -75,11 +75,6 @@ fn bad(what: &str) -> Error {
Error::Solidcore(format!("flat arrays: {what}"))
}
/// A call solidcore has no port of.
fn unported(call: &str) -> Error {
Error::Solidcore(format!("not supported yet: solidcore has no {call}"))
}
fn get<T: Copy>(v: &[T], i: usize) -> Result<T> {
v.get(i).copied().ok_or_else(|| bad("index past its array"))
}
@@ -975,8 +970,21 @@ fn flat_from_brep(k: &mut Kernel, b: &mut Brep) -> Result<Arrays> {
}
if nurbs_form || ty == SURFACE_NURBS_I {
// Every analytic class is an SmBSplineSurface: its own NURBS, in face order with the
// NURBS faces' surfaces. Another surface would be approximated (ApproximateSurface).
let part = bspline_surface_part(k, surface)?.ok_or_else(|| unported("SmSurface::ApproximateSurface"))?;
// NURBS faces' surfaces. Another surface (an offset) is approximated within the
// curves' tolerance, splitting its spans up to 5 times; its status fails the export,
// as does no surface, which would leave the arrays without this face's NURBS.
let approximated;
let part = match bspline_surface_part(k, surface)? {
Some(part) => part,
None => {
approximated = surface
.approximate_surface(k, approx_tol3d(k, approx_tol), 5, true)
.map_err(sc("SmSurface::ApproximateSurface"))?
.surface
.ok_or_else(|| bad("a face surface SMLib could not convert to a B-spline"))?;
bspline_surface_part(k, &approximated)?.ok_or_else(|| bad("an approximated face surface that is not a B-spline"))?
}
};
add_bspline_surface(&mut o, part.gw_nurb().ok_or_else(|| bad("a B-spline surface without its NURB"))?)?;
}
}
+1 -1
View File
@@ -409,7 +409,7 @@ cases!(
thicken_plate_symmetric,
thicken_a_solid,
offset_sheet_plate,
offset_sheet_quarter_cylinder: ignore = "solidcore#1441: an offset surface does not export, no SmSurface::ApproximateSurface (solidcore#1441)",
offset_sheet_quarter_cylinder: ignore = "solidcore#1477: the quarter arc sweeps to an SmSurfOfExtrusion, whose offset exports as a spline, where the fork's 12918e9 sweeps an SmCylinder (solidcore#1477)",
offset_sheet_a_solid,
offset_faces_top_out: ignore = "no SmOffsetFacesExecutive, fork a96ce9f (solidcore#1060)",
offset_faces_through,