Kernel: variable rounds are the union of their balls by default; retire fillet_gn_section_generator (moved from solidcore#2936) (#13945)

* test: the default kernel's variable rounds are the union of their balls (failing, #2273)

On main the default kernel sweeps great circles: the 20 cube's top front
edge rounded by the linear law 3, 2, 4, 2, 3 comes back with a round whose
net doubles back (check_brep #5), and the folded law 2, 2, 40, 3, 2 fails
in the surface (1001) with no reason, where it is a fold of the balls
(NoRoom, BallsFold, naming 19.63563).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* blend: the G^n section and the generic blend's checks are the default; their flags are retired (WR-685, WR-696, #2273)

`fillet_gn_section_generator` is removed and every read site takes its
side: a blend-curve round is the G^n section, a variable round is the
union of its balls (touch circles, law corners), the ease takes the
order-2 G^n section, and BallIsRegular, BandCutsThePart, the collapsed
offset and the refusals' fit sizes run on every kernel.

Retired with it, each now dead or a prerequisite of the G^n path:
- fillet_refuse_ball_not_fitting (WR-462): BallIsRegular replaced
  BallFitsItsFaces, which never ran with it; ball_fit.rs is removed.
- the executive's blend_curve_at_thirds option (WR-525), which the fork
  removed with its G^n section, and the ease's at-thirds target.
- fillet_blend_curve_revolved_on_arc (WR-581): only a blend-curve
  generator took it, and the executive builds none now.
- fillet_surface_plane_curve_on_plane_equation (WR-682): without it a
  variable round's side-face curve is not found (1001).
- fillet_corner_face_curve_halves (WR-659): an eased corner's patch does
  not close against the G^n ease without the halves.

The ExecutiveAccess adapter (the orchestration mocks, which hold no
solver geometry) reports nothing to judge, as its rail check already did.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* blend tests: the default kernel's rounds re-derived (WR-685, WR-696, WR-581, WR-659, WR-682, #2273)

The tests that set the retired flags drop the setting and keep their
on halves. Values pinned to the great-circle sweep are re-derived from
the union of the balls: wr646 against a quadrature of the envelope
(64.15953 removed; the round 64.1638, 6.7e-5 off), wr609 likewise
(5831.254415), wr631 against the fork's G^n builds. The refusals that
BallIsRegular now finds first name the same sizes (BallDoesNotFit).
The blend curve's own tests (at thirds, the revolved dome, the
great-circle marks) are removed with it. Known failures, recorded:
wr643's mirrored r 2 knife edge (#2963) and the r 9.99 G2 rim (#2964).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* blend: the surface-plane trace stays on its surface and is bounded (WR-682, #2273)

With its flag retired the trace runs on every kernel, and the goldens'
generated blend.fillet_geom_p2 cases showed two defects it carried from
the fork:
- gen0014: the march left the surface's domain (u = -6e5 on [0, 1]),
  marching the B-spline's extrapolation, and the refinement doubled
  its stations each pass until the allocation aborted (4.9 GB). A
  station off the domain, in a direction the surface isn't closed in,
  is the curve leaving the surface: refused (1001, as main's golden).
  The trace also holds at most MAX_STATIONS (the march's own 100 000).
- gen0123: start and end coincide, no curve between two points; it is
  not the trace's event, and the intersectors refuse it as before (1007).

(gen0015 and gen0170, whose spans at an end never met the check while
the curve ended at the given points, build since main's #2907 ends the
curve on the crossing.)

gen0014_the_trace_stays_on_its_surface aborts without the domain event.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* style: clippy's items_after_statements and field_reassign_with_default (#2273)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* blend: a band on a sheet has no part to cut (WR-696, #2273)

BandCutsThePart and the break-through check ask sm_BlendAddsMaterial,
whose IsConcaveEdge looks for a use of the edge on a material side and
fails (SM_ERR from fillet_solver::p5) where there is none: a sheet's
edges bound no material. The fillet failed with it on every open sheet,
on SolidCraft's set and, with the generic blend's checks now the
default, on the default kernel (the goldens' stubs4 rounds of
upstream's test8, shell_fillet, shell_fillet2, sphere_plane,
coons_01_03_29, test5 and open_shell, which main's default built).
An edge that bounds no material is its own event: nothing to judge
(edge_bounds_material). Not the fork's, which fails there.

a_round_on_a_sheet_has_no_part_to_cut fails without it with the same
"Fillet Surface Computation Failure: blend::fillet_solver::p5".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test: one half of #880's rim chamfers to a valid solid on the default kernel (#2273)

The issue's own pick, one half-ellipse rim edge chamfered by the offsets
of setbacks 1 and 2, was refused with 1001 on main's default kernel; with
the generic blend's sections and checks the default it builds a closed
solid (4 faces to 7) whose check_brep is clean.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* records: the trace's and the band check's fixes, and the known failing rollover case (WR-682, WR-685, #2273)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* blend: the gn flag's uses main added since are retired too (WR-685, WR-696, #2273)

- fillet_corner::topology::join: the unequal-blend test needs only the
  round's definition.
- session::finish: the refusal of great circles over a law corner
  (#2727) ran only without the G^n section; every kernel now builds the
  round as the union of its balls there, so it is removed, and its test
  keeps the union half.
- trim_at_creases: the strip's fit is noted on every kernel.
- Tests drop the setting; fillet_variable_radius_closes_onto_vertex's
  default kernel removes the balls' union (22.594877) as every fix does.
- The WR-682 record drops the span-end fix, superseded by #2907.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* style: cargo fmt (#2273)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* blend: the move to SolidCraft's kernel (#2273)

- The kernel's own later uses of fillet_gn_section_generator and
  fillet_surface_plane_curve_on_plane_equation (exact_pieces'
  certified-lift test, issue_2972's bare-net kernel) are dropped.
- The rollover case cyl_on_box1 edge 12 r 2 is known failing again in
  blend.fillet_executive_p3 (lost in the last rebase), and its golden
  line is dropped. Its issue moved to tangency-labs/solidcraft#13694.
- fillet_law_face_owned_drop_point pins what kernel builds: one face,
  not the law corner's three it built on solidcore main 99ed57c4d. Why
  the split no longer happens is still open.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* blend: the blend-curve generator is deleted with its flag (WR-685, #2273)

SmBlendCurveCrossSectionFSG was reachable only from a caller that
builds it directly: every blend-curve request is the G^n section since
fillet_gn_section_generator is retired, and nothing in solidcore, the
ops or SolidCraft builds the old generator. docs/generic-blend.md
deletes the old path in the same change, so it goes here (review of
tangency-labs/solidcore#2936, point 3):
- BlendCurveCrossSectionFsg, its CreateSurface and CreateSurfaceFromCurves,
  FilletSurfaceGenerator::BlendCurve, blend_curve, blend_curve_default and
  blend_scale.
- The corners' copies of a blend-curve generator take the G^n section
  only (fillet_corner p1 and p2); sm_SectionContactOrder refuses a
  blend-curve type, whose order gn_section_contact_order gives.
- Goldens runners: blend.fillet_standard_solver_p1's blend-curve generator
  cases are still drawn (so the cases after them stay as they were) and
  dropped; blend.fillet_solver_p1, blend.fillet_corner_p1 and
  blend.fillet_corner_p3 build the G^n section where they built a blend
  curve.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test: the variable rounds are their definitions; stale flag mentions (#2273)

Review of tangency-labs/solidcore#2936, points 2 and 4:
- wr696_default_variable_rounds: with SolidCraft's fix set every face the
  law-cornered rounds make (6 for 3, 2, 4, 2, 3; 3 for 4, 2, 4: the
  pieces and the corner balls' zones) is a procedural blend, and
  definition_check finds none bare. The default kernel builds the same
  faces as their nets, since fillet_round_as_definition is a fix of its
  own and stays off by default.
- wr_659 and issue_2704's headers point at the WR-685 addendum for the
  retired flags.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test: a smooth law's round is one face (#2273)

The law 4, 2, 4 of fillet_law_face_owned_drop_point is a quadratic
Bezier, smooth, with no corner: its round has no C0 knot to be split at,
so it adds one face. The rebased commit's +3 was wrong, and kernel's
expectation is kept.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* smlib: drop the retired fillet flags from SolidCraft's preset

UpstreamFixes no longer has fillet_refuse_ball_not_fitting,
fillet_corner_face_curve_halves, fillet_blend_curve_revolved_on_arc,
fillet_surface_plane_curve_on_plane_equation or
fillet_gn_section_generator: their behaviour is the kernel's default, so
the preset stops setting them (it did not build: E0609). The comments
that named the flag as the condition now read as the default.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* blend: review points (comments, gen0014's test builds only its case)

- fillet_corner p1: the face-curve-halves comment says what an easing
  corner does, and no longer calls the halves opt-in.
- fillet_executive p3: why the adapter over ExecutiveAccess passes the
  ball, fit and band checks (upstream's executive, the goldens' runners).
- goldens fillet_geom_p2: gen0014's test draws that case from its own
  seed instead of generating the unit's 1100 cases.
- WR-659 addendum: "the 40 mm box".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* goldens: fillet_geom_p2's Rng is in scope (clippy unused_qualifications)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* goldens: bless the five blend units the retirement moves (#2273)

Blessed on Ubuntu 24.04 (CI's glibc) at 39548d6e49. The counts match
CI's goldens on that head exactly; every other unit passes. Only the
cases that move past the tolerance take new lines: the other cases a
bless rewrites differ by about 1e-15 (another CPU's last digits) and
keep main's lines, which CI passes.

- fillet_executive_p3, 67 past the tolerance (69 lines):
  - six law-cornered rounds and issue-880's rim, refused before, build,
    each check_brep clean: the round is the union of its balls (WR-696);
  - law rounds that built move 1e-6 to 7e-5 in volume, the same union
    of balls in place of great circles (WR-685, WR-696);
  - constant rounds move 1e-10 to 1.3e-7: their side curves come from
    the surface-plane trace on the plane's equation (WR-682) and their
    corners' face curves are those curves' halves (WR-659);
  - blend-curve requests with G1 or thumbweight 1 are invalid input,
    1007 (WR-685 addendum): attributed-box-edge0-blend-g2, the eight
    issue919 rim cases, law-cube20-e0-deg2-smooth-xsect-blend-curve;
  - two rounds that built bodies check_brep rejects (bad loop
    orientation) are refused with a fit size: sweep4-brepForFillet2-
    all-r0.1 (CutsThePart) and stubs4-degenerate-caps_coons-e5-r0.5
    (BallDoesNotFit);
  - refused on both sides, the body left after the refusal or the
    retry step moves (corner3x2, stubs3, nurb_cone, sphere_diff).
- fillet_executive_p2, 1: set_params_single_fsg_3's blend curve is
  invalid input (WR-685 addendum).
- fillet_geom_p2, 12: the surface-plane trace runs on every kernel
  (WR-682); gen0014 refuses its station off the surface.
- fillet_solver_p1, 3: the runner's blend-curve kind builds the G^n
  section, which takes its thumbweight, not the old generator's scale.
- fillet_standard_solver_p1, 220 removed: the retired blend-curve
  generator's cases (their seeds are still drawn).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Karl Von Richter
2026-11-10 06:42:48 +00:00
committed by GitHub
parent e6789d881d
commit 52ea418a2a
125 changed files with 1573 additions and 3115 deletions
-5
View File
@@ -153,7 +153,6 @@ pub(crate) fn fixes() -> UpstreamFixes {
f.offset_stitch_at_body_tolerance = true;
f.curve_contacts_at_curve_ends = true;
f.shell_empty_cavity_fails = true;
f.fillet_refuse_ball_not_fitting = true;
f.boolean_lists_virtual_surface_copies = true;
f.ssi_tangent_contact_points = true;
f.ssi_trace_tangent_curves_once = true;
@@ -236,7 +235,6 @@ pub(crate) fn fixes() -> UpstreamFixes {
f.fillet_trim_status = true;
f.perspective_sphere_offsets = true;
f.plane_recognition_origin_after_axes = true;
f.fillet_corner_face_curve_halves = true;
f.brep_edit_statuses_pass_on = true;
f.fillet_run_on_bspline_trims = true;
f.query_statuses_pass_on = true;
@@ -249,7 +247,6 @@ pub(crate) fn fixes() -> UpstreamFixes {
f.offset_keep_cavity_regions = true;
f.gap_samples_non_bspline_v_stride = true;
f.imprint_skips_collapsed_definition = true;
f.fillet_blend_curve_revolved_on_arc = true;
f.temporary_radius_setup_errors = true;
f.ellipse_step_interval_checks = true;
f.corner_patch_face_side_twist = true;
@@ -326,8 +323,6 @@ pub(crate) fn fixes() -> UpstreamFixes {
f.is_topological_vertex_rejects_cusps_and_tangent_errors = true;
f.cone_create_canonical_preserves_inside_out_and_checks_height = true;
f.point_class_gap_3d_propagates_no_drop_error = true;
f.fillet_surface_plane_curve_on_plane_equation = true;
f.fillet_gn_section_generator = true;
f.offset_updates_result_tolerances = true;
f.cone_iso_circle_at_axial_height = true;
f.boolean_coincident_strip_drops_crossing = true;
+6 -6
View File
@@ -259,8 +259,8 @@ enum Section<'a> {
/// such rounds at a side edge as the [`Turn`] says (`SetSweptTurns`).
Round(Turn),
/// The curvature-continuous section (`SM_FSG_BLEND_CURVE`): the Gⁿ generator's order 2 at the
/// equal-area thumbweight (`SMLIB_BLEND_THUMBWEIGHT`, fork 6148773; solidcore#2261 under
/// `fillet_gn_section_generator`), which takes off what the ball's circle does.
/// equal-area thumbweight (`SMLIB_BLEND_THUMBWEIGHT`, fork 6148773; solidcore#2261, the
/// kernel's default since WR-685), which takes off what the ball's circle does.
Curvature,
Chord,
/// A chamfer of the sizes asked: one for all the edges or one per edge, and for each edge
@@ -296,8 +296,8 @@ fn face_set(b: &Brep) -> solidcore::Result<HashSet<FaceId>> {
/// reason) are [`Error::NoRoom`] like the fork's.
///
/// A blend too large that solidcore sizes (the session's fit, as the fork's capi reads it with
/// `smlib_blend_fit_size`, or [`SolidError::FilletRefused`] carrying it; under
/// `fixes.fillet_gn_section_generator`) is [`Error::TooLarge`] with that size, its edge's point
/// `smlib_blend_fit_size`, or [`SolidError::FilletRefused`] carrying it) is
/// [`Error::TooLarge`] with that size, its edge's point
/// filled in by the caller from the edge returned with it ([`sized_on`]); a corner solidcore
/// refuses as not supported (the mixed corner whose rails cross, solidcore#2256) is
/// [`Error::Unported`] naming it.
@@ -1394,8 +1394,8 @@ pub(crate) fn fillet_variable(
if law_has_corner(degree, knots, radii) {
return Ok(Err(Error::Unsupported));
}
// The round is the union of its balls (smlib#78, solidcore#2262 with
// `fillet_gn_section_generator`): each ball touches it along the circle shifted
// The round is the union of its balls (smlib#78, solidcore#2262):
// each ball touches it along the circle shifted
// -r r'/|c'| from its great circle. A law whose balls fold over one another is refused
// (`NoRoomReason::BallsFold`), [`Error::NoRoom`].
let solid_in = brep_p2::is_manifold_solid(&w)?;
+2 -2
View File
@@ -333,7 +333,7 @@ fn fork_only_blends_are_not_supported_yet() {
/// #199's bar, 14 x 6 x 10, its four upright edges rounded: past r 3 (a full round of the 6 mm
/// ends) the two rounds on each end would cross. solidcore refuses it with the largest radius that
/// builds and its edge (`SolidError::FilletRefused`, `fixes.fillet_gn_section_generator`): 3, and a
/// builds and its edge (`SolidError::FilletRefused`): 3, and a
/// point halfway up an upright edge; an equal chamfer of the 4 mm rib's top edges past 2, as its
/// distance.
#[test]
@@ -674,7 +674,7 @@ fn a_curvature_round_takes_its_wedges_equal_area_and_mixed_wedges_are_refused()
assert_eq!(blend(&chamfered, Blend::Curvature, &[[90.0; 3]], &[r], TOL, &[], &[], Corners::Filled).err(), Some(Error::NoMatch { point: 0 }));
}
/// A variable round is the union of its balls (solidcore#2262, `fillet_gn_section_generator`).
/// A variable round is the union of its balls (solidcore#2262).
/// Along the 30 mm top front edge: a law of one radius 2 takes the constant round's
/// (1 - π/4) 4 · 30 = 25.752220; 1 to 3, the balls' union's 27.857434 (the great circles would take
/// 27.898239), either way along the edge. Both come out 5.3e-5 of that over, as on the C++
+2 -2
View File
@@ -352,8 +352,8 @@ nice -n 10 cargo run -p goldens -- --solidcraft-cases '3526-*' # ids (<fi
defect and defers the case, here it is the right answer (a blend too large for its
faces, for example `199-*/round_past_the_end_face_is_refused`). `refused.fit_size`
(`value`, `tol`, `kind` `radius` (default), `scale` or `chord`, `source`) also requires the
largest size that builds, which a refusal reports with `fillet_gn_section_generator`
(`SolidError::FilletRefused`, WR-696): a refusal without a size fails it, and a refusal
largest size that builds, which a refusal reports (`SolidError::FilletRefused`,
WR-696): a refusal without a size fails it, and a refusal
with one is still an `ERROR` in a case that expects none.
* **Verdicts**: `PASS`, `FAIL`, `UNCHECKED` (no expectations were supplied, or no check
failed but one cannot be measured
@@ -271,7 +271,7 @@
{"case":"set_params_single_fsg_0","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":[1007.0,0.0,0.0,1.0,0.0,1.0,1.0,1.0,0.0,2.0]}}
{"case":"set_params_single_fsg_1","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":[0.0,1.0,0.0,1.0,0.0,1.0,1.0,1.0,2.0,0.0]}}
{"case":"set_params_single_fsg_2","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":[0.0,1.0,0.0,1.0,0.0,1.0,1.0,1.0,2.0,0.0]}}
{"case":"set_params_single_fsg_3","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":[0.0,1.0,0.0,1.0,0.0,1.0,1.0,1.0,2.0,0.0]}}
{"case":"set_params_single_fsg_3","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":[1007.0,0.0,0.0,1.0,0.0,1.0,1.0,1.0,0.0,2.0]}}
{"case":"set_params_vr_laws","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":[1007.0,0.0,0.0,1.0,0.0,1.0,1.0,1.0,1.0,2.0]}}
{"case":"set_params_vr_null_laws","deferred":null,"error":"null_deref","ints":{},"topology":null,"values":{}}
{"case":"temp_radius_const","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":[0.0]}}
@@ -25,7 +25,7 @@
{"case":"attributed-box-edge0-behavior2","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,10,15,7]},"topology":null,"values":{"attributes":{"blocks":[[352197.98228521127,352197.98228521127,21633766.503961973]],"n":114},"fillet_point_step":[0.00001]}}
{"case":"attributed-box-edge0-behavior3","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,10,15,7]},"topology":null,"values":{"attributes":{"blocks":[[352224.98228521127,352224.98228521127,21635290.503961973]],"n":114},"fillet_point_step":[0.00001]}}
{"case":"attributed-box-edge0-behavior4","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,10,15,7]},"topology":null,"values":{"attributes":{"blocks":[[250097.98228521127,250097.98228521127,14027686.309617518]],"n":94},"fillet_point_step":[0.00001]}}
{"case":"attributed-box-edge0-blend-g2","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,10,15,7]},"topology":null,"values":{"attributes":{"blocks":[[352176.7742276252,352176.7742276252,21632226.862624083]],"n":114},"fillet_point_step":[0.00001]}}
{"case":"attributed-box-edge0-blend-g2","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1007,8,12,6]},"topology":null,"values":{"attributes":{"blocks":[[373188.0,373188.0,21348048.0]],"n":110},"fillet_point_step":[0.00001]}}
{"case":"attributed-box-edge0-linear","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,10,15,7]},"topology":null,"values":{"attributes":{"blocks":[[352167.94112549693,352167.94112549693,21632085.156420976]],"n":114},"fillet_point_step":[0.00001]}}
{"case":"attributed-box-edge0-r2","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,10,15,7]},"topology":null,"values":{"attributes":{"blocks":[[352173.98228521127,352173.98228521127,21632188.503961973]],"n":114},"fillet_point_step":[0.00001]}}
{"case":"attributed-box-edge11-r2","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,10,15,7]},"topology":null,"values":{"attributes":{"blocks":[[352151.982351003,352151.982351003,21630261.106998987]],"n":114},"fillet_point_step":[0.00001]}}
@@ -54,23 +54,23 @@
{"case":"attributed-step-edge14-r1","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,14,21,9]},"topology":null,"values":{"attributes":{"blocks":[[518850.8495699078,518850.8495699078,44575383.487311214]],"n":162},"fillet_point_step":[0.00001]}}
{"case":"attributed-step-edge4-r1","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,14,21,9]},"topology":null,"values":{"attributes":{"blocks":[[518868.4203519453,518868.4203519453,44577819.05749922]],"n":162},"fillet_point_step":[0.00001]}}
{"case":"attributed-step-edge9-r1","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,14,21,9]},"topology":null,"values":{"attributes":{"blocks":[[518859.2787837579,518859.2787837579,44576274.79263492]],"n":162},"fillet_point_step":[0.00001]}}
{"case":"attributed-variable-box-edge0-1-to-2","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,10,15,7]},"topology":null,"values":{"attributes":{"blocks":[[352177.3113621633,352177.3113621633,21632479.023976]],"n":114},"fillet_point_step":[0.00001]}}
{"case":"attributed-variable-box-edge6-2-to-1","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,10,15,7]},"topology":null,"values":{"attributes":{"blocks":[[352165.3113621633,352165.3113621633,21631500.641614806]],"n":114},"fillet_point_step":[0.00001]}}
{"case":"attributed-variable-box-edge0-1-to-2","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,10,15,7]},"topology":null,"values":{"attributes":{"blocks":[[352177.32757815527,352177.32757815527,21632479.252438188]],"n":114},"fillet_point_step":[0.00001]}}
{"case":"attributed-variable-box-edge6-2-to-1","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,10,15,7]},"topology":null,"values":{"attributes":{"blocks":[[352165.32757815527,352165.32757815527,21631500.771934386]],"n":114},"fillet_point_step":[0.00001]}}
{"case":"big-rad-filleted_box-r1.0-top-edges","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,20,36,18],"mass_status":[0],"result_topology":{"blocks":[[281291,35318792],[285980,37333166],[211429,16888283]],"n":668}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[564.2389452228086,983.5015547299164,983.5015547299164,5.038410057395567,5.000000000000008,4.999999925784339,65212.87037306669,65652.9430384423,65652.94978056221,24587.53852411164,24776.42022262525,24776.42062407697],"result_geometry":{"blocks":[[1043.909543499877,1043.909543499877,132577.34831244644],[786.6137295003684,786.6137295003684,92148.64887494127],[548.8554048175436,548.8554048175436,83452.93188722905],[707.0839096994997,708.6839096994996,71698.2621958255],[75.48697566657789,75.48697566657789,960.1950347119924]],"n":1052},"selected_edge_before":{"blocks":[[112569.0,112569.0,7262465.274761933]],"n":136}}}
{"case":"big-rad-filleted_box-r2.0-top-edges","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,16,24,10],"mass_status":[0],"result_topology":{"blocks":[[281261,35311820],[207173,18894579]],"n":440}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[581.1150528699195,991.4160344161737,991.4160344161737,5.000000000000002,4.999999999999986,4.999999975615006,65845.15814429456,65969.77702349689,65969.78339230167,24785.400739525885,24785.40073952599,24785.400860155278],"result_geometry":{"blocks":[[1222.4097832140656,1222.4097832140656,168084.19656315702],[857.5286065323797,857.5286065323797,123935.48067211709],[580.7960876026176,593.5960876026177,48777.44680852571]],"n":676},"selected_edge_before":{"blocks":[[112569.0,112569.0,7262465.274761933]],"n":136}}}
{"case":"big-rad-filleted_box-r3.0-top-edges","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,16,24,10],"mass_status":[0],"result_topology":{"blocks":[[281261,35311820],[207173,18894579]],"n":440}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[581.1150528699195,991.4160344161737,991.4160344161737,5.000000000000002,4.999999999999986,4.999999975615006,65845.15814429456,65969.77702349689,65969.78339230167,24785.400739525885,24785.40073952599,24785.400860155278],"result_geometry":{"blocks":[[1222.4097832140656,1222.4097832140656,168084.19656315702],[857.5286065323797,857.5286065323797,123935.48067211709],[580.7960876026176,593.5960876026177,48777.44680852571]],"n":676},"selected_edge_before":{"blocks":[[112569.0,112569.0,7262465.274761933]],"n":136}}}
{"case":"big-radius-box_diff_cyl_big_rad-r28-edge12","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,5,7,3],"mass_status":[1007],"result_topology":{"blocks":[[143392,7604201]],"n":110}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[],"result_geometry":{"blocks":[[3031.090154314973,4114.496412117744,280772.74380950886]],"n":200},"selected_edge_before":{"blocks":[[14306.057758366,14306.057758366,72955.84024483882]],"n":17}}}
{"case":"corner3x2-union-inset-side-step-edges1-14-r1","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,20,30,12],"mass_status":[0],"result_topology":{"blocks":[[281013,35283637],[276706,34655270],[45373,682235]],"n":548}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[1260.0,2600.0,2600.0,10.0,5.615384615384614,6.538461538461538,259133.3333333333,483333.3333333333,439133.3333333333,102000.0,170000.0,145999.99999999997],"result_geometry":{"blocks":[[1317.5503,1317.5503,154679.4246],[1199.6401399999997,1199.6401399999997,162824.11708],[1385.4301499999997,1385.4301499999997,167142.79905000003],[425.15002999999996,425.15002999999996,14567.40099]],"n":836},"selected_edge_before":{"blocks":[[28276.809999999998,28276.809999999998,382664.51]],"n":34}}}
{"case":"corner3x2-union-inset-side-step-edges1-18-r1","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,20,30,12],"mass_status":[0],"result_topology":{"blocks":[[281013,35283637],[276706,34655270],[45373,682235]],"n":548}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[1260.0,2600.0,2600.0,10.0,5.615384615384614,6.538461538461538,259133.3333333333,483333.3333333333,439133.3333333333,102000.0,170000.0,145999.99999999997],"result_geometry":{"blocks":[[1317.5503,1317.5503,154679.4246],[1199.6401399999997,1199.6401399999997,162824.11708],[1384.4301499999997,1384.4301499999997,167016.79905000003],[425.15002999999996,425.15002999999996,14567.40099]],"n":836},"selected_edge_before":{"blocks":[[28287.0,28287.0,382874.85000000003]],"n":34}}}
{"case":"corner3x2-union-inset-side-step-edges12-13-r1","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,20,30,12],"mass_status":[0],"result_topology":{"blocks":[[281013,35283637],[276706,34655270],[45373,682235]],"n":548}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[1260.0,2600.0,2600.0,10.0,5.615384615384614,6.538461538461538,259133.3333333333,483333.3333333333,439133.3333333333,102000.0,170000.0,145999.99999999997],"result_geometry":{"blocks":[[1317.5503,1317.5503,154679.4246],[1202.6401399999997,1202.6401399999997,163412.11708],[1381.43015,1381.43015,166926.79905000003],[425.15002999999996,425.15002999999996,14567.40099]],"n":836},"selected_edge_before":{"blocks":[[28183.89,28183.89,381265.58999999997]],"n":34}}}
{"case":"corner3x2-union-inset-side-step-edges12-17-r1","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,20,30,12],"mass_status":[0],"result_topology":{"blocks":[[281013,35283637],[276706,34655270],[45373,682235]],"n":548}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[1260.0,2600.0,2600.0,10.0,5.615384615384614,6.538461538461538,259133.3333333333,483333.3333333333,439133.3333333333,102000.0,170000.0,145999.99999999997],"result_geometry":{"blocks":[[1317.5503,1317.5503,154679.4246],[1201.6401399999997,1201.6401399999997,163300.11708],[1381.43015,1381.43015,166926.79905000003],[425.15002999999996,425.15002999999996,14567.40099]],"n":836},"selected_edge_before":{"blocks":[[28190.699999999997,28190.699999999997,381445.24999999994]],"n":34}}}
{"case":"corner3x2-union-inset-side-step-edges13-19-r1","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,20,30,12],"mass_status":[0],"result_topology":{"blocks":[[281013,35283637],[276706,34655270],[45373,682235]],"n":548}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[1260.0,2600.0,2600.0,10.0,5.615384615384614,6.538461538461538,259133.3333333333,483333.3333333333,439133.3333333333,102000.0,170000.0,145999.99999999997],"result_geometry":{"blocks":[[1317.5503,1317.5503,154679.4246],[1203.6401399999997,1203.6401399999997,163632.11708],[1383.4301499999997,1383.4301499999997,167142.79905000003],[425.15002999999996,425.15002999999996,14567.40099]],"n":836},"selected_edge_before":{"blocks":[[28191.89,28191.89,381423.05999999994]],"n":34}}}
{"case":"corner3x2-union-inset-side-step-edges12-13-r1","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,20,30,12],"mass_status":[0],"result_topology":{"blocks":[[281013,35283637],[276706,34655270],[45373,682235]],"n":548}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[1260.0,2600.0,2600.0,10.0,5.615384615384614,6.538461538461538,259133.3333333333,483333.3333333333,439133.3333333333,102000.0,170000.0,145999.99999999997],"result_geometry":{"blocks":[[1317.5503,1317.5503,154679.4246],[1203.6401399999997,1203.6401399999997,163650.11708],[1385.4301499999997,1385.4301499999997,167106.79905000003],[425.15002999999996,425.15002999999996,14567.40099]],"n":836},"selected_edge_before":{"blocks":[[28183.89,28183.89,381265.58999999997]],"n":34}}}
{"case":"corner3x2-union-inset-side-step-edges12-17-r1","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,20,30,12],"mass_status":[0],"result_topology":{"blocks":[[281013,35283637],[276706,34655270],[45373,682235]],"n":548}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[1260.0,2600.0,2600.0,10.0,5.615384615384614,6.538461538461538,259133.3333333333,483333.3333333333,439133.3333333333,102000.0,170000.0,145999.99999999997],"result_geometry":{"blocks":[[1317.5503,1317.5503,154679.4246],[1202.6401399999997,1202.6401399999997,163484.11708],[1385.4301499999997,1385.4301499999997,167106.79905000003],[425.15002999999996,425.15002999999996,14567.40099]],"n":836},"selected_edge_before":{"blocks":[[28190.699999999997,28190.699999999997,381445.24999999994]],"n":34}}}
{"case":"corner3x2-union-inset-side-step-edges13-19-r1","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,20,30,12],"mass_status":[0],"result_topology":{"blocks":[[281013,35283637],[276706,34655270],[45373,682235]],"n":548}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[1260.0,2600.0,2600.0,10.0,5.615384615384614,6.538461538461538,259133.3333333333,483333.3333333333,439133.3333333333,102000.0,170000.0,145999.99999999997],"result_geometry":{"blocks":[[1317.5503,1317.5503,154679.4246],[1203.6401399999997,1203.6401399999997,163632.11708],[1388.43015,1388.43015,167394.79905000003],[425.15002999999996,425.15002999999996,14567.40099]],"n":836},"selected_edge_before":{"blocks":[[28191.89,28191.89,381423.05999999994]],"n":34}}}
{"case":"corner3x2-union-inset-side-step-edges14-27-r1","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,20,30,12],"mass_status":[0],"result_topology":{"blocks":[[281013,35283637],[276706,34655270],[45373,682235]],"n":548}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[1260.0,2600.0,2600.0,10.0,5.615384615384614,6.538461538461538,259133.3333333333,483333.3333333333,439133.3333333333,102000.0,170000.0,145999.99999999997],"result_geometry":{"blocks":[[1317.5503,1317.5503,154679.4246],[1200.6401399999997,1200.6401399999997,163008.11708],[1389.43015,1389.43015,167448.79905000003],[425.15002999999996,425.15002999999996,14567.40099]],"n":836},"selected_edge_before":{"blocks":[[28258.809999999998,28258.809999999998,382755.33999999997]],"n":34}}}
{"case":"corner3x2-union-inset-side-step-edges15-19-r1","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,20,30,12],"mass_status":[0],"result_topology":{"blocks":[[281013,35283637],[276706,34655270],[45373,682235]],"n":548}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[1260.0,2600.0,2600.0,10.0,5.615384615384614,6.538461538461538,259133.3333333333,483333.3333333333,439133.3333333333,102000.0,170000.0,145999.99999999997],"result_geometry":{"blocks":[[1317.5503,1317.5503,154679.4246],[1203.6401399999997,1203.6401399999997,163632.11708],[1385.4301499999997,1385.4301499999997,167286.79905000003],[425.15002999999996,425.15002999999996,14567.40099]],"n":836},"selected_edge_before":{"blocks":[[28194.55,28194.55,381466.79999999993]],"n":34}}}
{"case":"corner3x2-union-inset-side-step-edges15-19-r1","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,20,30,12],"mass_status":[0],"result_topology":{"blocks":[[281013,35283637],[276706,34655270],[45373,682235]],"n":548}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[1260.0,2600.0,2600.0,10.0,5.615384615384614,6.538461538461538,259133.3333333333,483333.3333333333,439133.3333333333,102000.0,170000.0,145999.99999999997],"result_geometry":{"blocks":[[1317.5503,1317.5503,154679.4246],[1203.6401399999997,1203.6401399999997,163632.11708],[1388.43015,1388.43015,167394.79905000003],[425.15002999999996,425.15002999999996,14567.40099]],"n":836},"selected_edge_before":{"blocks":[[28194.55,28194.55,381466.79999999993]],"n":34}}}
{"case":"corner3x2-union-inset-side-step-edges15-27-r1","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,20,30,12],"mass_status":[0],"result_topology":{"blocks":[[281013,35283637],[276706,34655270],[45373,682235]],"n":548}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[1260.0,2600.0,2600.0,10.0,5.615384615384614,6.538461538461538,259133.3333333333,483333.3333333333,439133.3333333333,102000.0,170000.0,145999.99999999997],"result_geometry":{"blocks":[[1317.5503,1317.5503,154679.4246],[1201.6401399999997,1201.6401399999997,163192.11708],[1389.43015,1389.43015,167448.79905000003],[425.15002999999996,425.15002999999996,14567.40099]],"n":836},"selected_edge_before":{"blocks":[[28232.55,28232.55,382450.79999999993]],"n":34}}}
{"case":"corner3x2-union-overhang-corner-edges6-12-r1","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,18,28,12],"mass_status":[0],"result_topology":{"blocks":[[281023,35286268],[293738,38199925],[27,29]],"n":514}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[1376.0,2600.0,2600.0,8.384615384615385,4.076923076923075,7.3076923076923075,275733.3333333333,483733.3333333334,346133.33333333326,58999.99999999996,127000.0,101799.99999999991],"result_geometry":{"blocks":[[1184.6602899999998,1216.6602899999998,148214.94477],[924.40014,995.1601399999998,124016.35848],[1077.1601400000002,1144.7601399999999,137516.89791999996],[116.02001000000001,125.98001000000002,1627.62007]],"n":792},"selected_edge_before":{"blocks":[[28103.18,28103.18,379900.98]],"n":34}}}
{"case":"corner3x2-union-overhang-corner-edges6-13-r1","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,18,28,12],"mass_status":[0],"result_topology":{"blocks":[[281023,35286268],[293738,38199925],[27,29]],"n":514}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[1376.0,2600.0,2600.0,8.384615384615385,4.076923076923075,7.3076923076923075,275733.3333333333,483733.3333333334,346133.33333333326,58999.99999999996,127000.0,101799.99999999991],"result_geometry":{"blocks":[[1184.6602899999998,1216.6602899999998,148214.94477],[924.40014,995.1601399999998,123908.35848],[1077.1601400000002,1144.7601399999999,137516.89791999996],[116.02001000000001,125.98001000000002,1627.62007]],"n":792},"selected_edge_before":{"blocks":[[28113.66,28113.66,380157.5]],"n":34}}}
{"case":"corner3x2-union-overhang-front-edges15-22-r1","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,18,28,12],"mass_status":[0],"result_topology":{"blocks":[[281021,35286730],[293739,38200282],[28,30]],"n":514}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[1360.0,2600.0,2600.0,10.0,4.076923076923075,7.3076923076923075,275733.3333333333,538333.3333333334,400733.33333333326,58999.99999999996,190000.0,105999.99999999993],"result_geometry":{"blocks":[[1256.5502899999997,1272.5502899999997,154725.82477000004],[1119.51014,1158.51014,153266.73848000006],[1285.6801400000004,1324.6401399999997,162101.61791999996],[144.02001,153.98001000000002,2033.6200699999997]],"n":792},"selected_edge_before":{"blocks":[[28220.4,28220.4,381917.5]],"n":34}}}
{"case":"corner3x2-union-overhang-front-edges15-22-r1","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,18,28,12],"mass_status":[0],"result_topology":{"blocks":[[281021,35286730],[293739,38200282],[28,30]],"n":514}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[1360.0,2600.0,2600.0,10.0,4.076923076923075,7.3076923076923075,275733.3333333333,538333.3333333334,400733.33333333326,58999.99999999996,190000.0,105999.99999999993],"result_geometry":{"blocks":[[1256.5502899999997,1272.5502899999997,154725.82477000004],[1120.51014,1159.51014,153406.73848000006],[1287.6801400000004,1326.64014,162211.61791999996],[144.02001,153.98001000000002,2033.6200699999997]],"n":792},"selected_edge_before":{"blocks":[[28220.4,28220.4,381917.5]],"n":34}}}
{"case":"corner3x2-union-overhang-front-edges15-24-r1","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,18,28,12],"mass_status":[0],"result_topology":{"blocks":[[281021,35286730],[293739,38200282],[28,30]],"n":514}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[1360.0,2600.0,2600.0,10.0,4.076923076923075,7.3076923076923075,275733.3333333333,538333.3333333334,400733.33333333326,58999.99999999996,190000.0,105999.99999999993],"result_geometry":{"blocks":[[1256.5502899999997,1272.5502899999997,154725.82477000004],[1118.51014,1157.51014,153018.73848000006],[1288.6801400000004,1327.6401400000002,162257.61791999996],[144.02001,153.98001000000002,2033.6200699999997]],"n":792},"selected_edge_before":{"blocks":[[28252.4,28252.4,382793.5]],"n":34}}}
{"case":"curve-sih-box-all-edges","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,24,48,26],"mass_status":[0],"result_topology":{"blocks":[[282511,35465257],[281766,36472829],[339653,48699707],[166360,10490369]],"n":896}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[2148.212368310088,5987.291690455043,5987.291690455043,4.999999888541479,10.000000001645898,15.000000196509284,2593031.078814224,1994679.8755745068,997175.0943071063,898093.7835769122,449046.86731624947,299364.5777750768],"result_geometry":{"blocks":[[2123.3366725419296,2123.3366725419296,288781.46047742834],[938.3747812310314,938.3747812310314,137777.47516100298],[1483.8363119707344,1483.8363119707344,163838.02754450816],[1277.5762707564274,1277.5762707564274,199242.87380139728],[1443.3103315619726,1443.3103315619726,178608.7258789652],[628.4921945649447,628.4921945649447,49464.034860716456]],"n":1428},"selected_edge_before":{"blocks":[[169486.80000000005,169486.80000000005,16693632.500000002]],"n":204}}}
{"case":"curve-sih-box-edge0","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,10,15,7],"mass_status":[0],"result_topology":{"blocks":[[300940,39985608],[15125,181474]],"n":278}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[595.2787636237798,997.8539825841174,997.8539825841174,4.989727306396368,4.999999999999999,4.989727193201295,66389.93507843695,66256.27346488538,66389.93722538959,24895.095758720912,24794.923030052472,24895.09632348168],"result_geometry":{"blocks":[[872.9203699999999,872.9203699999999,116451.73917000002],[684.0507236370267,684.0507236370267,60968.991387464666]],"n":436},"selected_edge_before":{"blocks":[[14094.7,14094.7,70994.8]],"n":17}}}
@@ -347,7 +347,7 @@
{"case":"issue-2349-teardrop-first_vertex_geometry-r3","deferred":null,"error":null,"ints":{"before_direct_topology":[0,1,1,0,0,9,0,0,0,2,2,1,-1,-1],"calculated_vertex_state":[0,1,1,1,0,0],"offsets_after_state":{"blocks":[[121693,2432078]],"n":27},"offsets_before_state":{"blocks":[[121693,2432078]],"n":27},"prefix_state":{"blocks":[[32282,597320]],"n":65},"prefix_statuses":[0,0,0,0]},"topology":null,"values":{"actual_solver_corner_parameters":[0.00004,0.17453292519943295,3.0,3.0,0.00004,0.3490658503988659,0.17453292519943295],"calculated_vertices":[0.0,0.0,7.0,0.0,0.3],"fillet_point_step":[0.00001],"offsets_after_distances":[-3.0,-3.0,-3.0,-3.0],"offsets_before_distances":[-3.0,-3.0,-3.0,-3.0],"selected_edge_before":{"blocks":[[14094.099820000001,14103.323740000002,70902.63008000002]],"n":17}}}
{"case":"issue-2349-teardrop-solver_geometry-r0.5","deferred":null,"error":null,"ints":{"all_corner_vertex_state":[0,0,1,1,0,1,0,0,0,2,1,1,0,3,1,1],"before_direct_topology":[0,1,1,0,0,9,0,0,0,2,2,1,-1,-1],"corner_adjustment_flags":[0,0,0],"corner_calculation_flags":[0,0,0,0],"generated_geometry_state":{"blocks":[[100185,3085371]],"n":60},"offsets_after_state":{"blocks":[[243388,7784818]],"n":51},"offsets_before_state":{"blocks":[[121693,2432078]],"n":27},"prefix_state":{"blocks":[[32543,608275]],"n":117},"prefix_statuses":[0,0,0,0,0,0]},"topology":null,"values":{"actual_solver_corner_parameters":[0.00004,0.17453292519943295,0.5,0.5,0.00004,0.3490658503988659,0.17453292519943295],"all_corner_vertices":[0.0,0.0,9.5,0.0,0.05,14.999999999999996,-4.440892098500626e-16,9.5,0.0,0.0,14.499999999999996,0.0,9.999999999999998,0.0,0.0],"fillet_point_step":[0.00001],"generated_geometry_samples":{"blocks":[[46.04710955768702,4e+20,-2e+20]],"n":125},"offsets_after_distances":[-0.5,-0.5,-0.5,-0.5,-0.5,-0.5,-0.5,-0.5],"offsets_before_distances":[-0.5,-0.5,-0.5,-0.5],"selected_edge_before":{"blocks":[[14094.099820000001,14103.323740000002,70902.63008000002]],"n":17}}}
{"case":"issue-880-half-arc-rim-0-setbacks-1-1","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,4,6,4],"mass_status":[0],"result_topology":{"blocks":[[144470,8713890]],"n":116},"rim_edge":[4],"setup":[0]},"topology":null,"values":{"chamfer_offsets":[1.4437306849540357,1.4437306849540357],"fillet_point_step":[0.00001],"mass_properties":[868.8314428537713,1756.2033588861154,1756.2033588861154,5.1406239673806295,4.430195919708666e-7,-0.031250984879630295,70614.02210308611,131898.1623457232,83236.70205428473,-0.003982157098254664,26800.38482713169,-0.002784112013812924],"result_geometry":{"blocks":[[550.9483263084367,990.3232199753255,79577.82092895848]],"n":196},"selected_edge_before":{"blocks":[[14100.080101853804,14118.806431353158,70780.7744061843]],"n":17}}}
{"case":"issue-880-half-arc-rim-0-setbacks-1-2","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,4,6,4],"mass_status":[0],"result_topology":{"blocks":[[144470,8713890]],"n":116},"rim_edge":[4],"setup":[0]},"topology":null,"values":{"chamfer_offsets":[2.5119210070209403,1.8192710478411664],"fillet_point_step":[0.00001],"mass_properties":[868.8314428537713,1756.2033588861154,1756.2033588861154,5.1406239673806295,4.430195919708666e-7,-0.031250984879630295,70614.02210308611,131898.1623457232,83236.70205428473,-0.003982157098254664,26800.38482713169,-0.002784112013812924],"result_geometry":{"blocks":[[550.9483263084367,990.3232199753255,79577.82092895848]],"n":196},"selected_edge_before":{"blocks":[[14100.080101853804,14118.806431353158,70780.7744061843]],"n":17}}}
{"case":"issue-880-half-arc-rim-0-setbacks-1-2","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,9,14,7],"mass_status":[0],"result_topology":{"blocks":[[302247,39913679],[24,76]],"n":261},"rim_edge":[4],"setup":[0]},"topology":null,"values":{"chamfer_offsets":[2.5119210070209403,1.8192710478411664],"fillet_point_step":[0.00001],"mass_properties":[845.1011491601702,1722.3667130798356,1722.3667130798356,5.048045338465755,0.04904460393596756,-0.21219415613396264,67368.30639808509,125395.94997855989,79215.27386378373,766.0762509536285,23745.600889792255,923.4436721725422],"result_geometry":{"blocks":[[975.4334886240416,1299.0378651209226,152604.22677027778],[834.1536847267798,1401.7425790221985,73391.22309175294]],"n":414},"selected_edge_before":{"blocks":[[14100.080101853804,14118.806431353158,70780.7744061843]],"n":17}}}
{"case":"issue-880-half-arc-rim-1-setbacks-1-1","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,4,6,4],"mass_status":[0],"result_topology":{"blocks":[[144470,8713890]],"n":116},"rim_edge":[5],"setup":[0]},"topology":null,"values":{"chamfer_offsets":[0.692649959179774,0.692649959179774],"fillet_point_step":[0.00001],"mass_properties":[868.8314428537713,1756.2033588861154,1756.2033588861154,5.1406239673806295,4.430195919708666e-7,-0.031250984879630295,70614.02210308611,131898.1623457232,83236.70205428473,-0.003982157098254664,26800.38482713169,-0.002784112013812924],"result_geometry":{"blocks":[[550.9483263084367,990.3232199753255,79577.82092895848]],"n":196},"selected_edge_before":{"blocks":[[14130.206460974816,14134.26974146202,71106.08528230156]],"n":17}}}
{"case":"issue-880-half-arc-rim-1-setbacks-1-2","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,4,6,4],"mass_status":[0],"result_topology":{"blocks":[[144470,8713890]],"n":116},"rim_edge":[5],"setup":[0]},"topology":null,"values":{"chamfer_offsets":[1.760840281246679,0.317109596292643],"fillet_point_step":[0.00001],"mass_properties":[868.8314428537713,1756.2033588861154,1756.2033588861154,5.1406239673806295,4.430195919708666e-7,-0.031250984879630295,70614.02210308611,131898.1623457232,83236.70205428473,-0.003982157098254664,26800.38482713169,-0.002784112013812924],"result_geometry":{"blocks":[[550.9483263084367,990.3232199753255,79577.82092895848]],"n":196},"selected_edge_before":{"blocks":[[14130.206460974816,14134.26974146202,71106.08528230156]],"n":17}}}
{"case":"issue-880-half-arc-rim-whole-offsets-1-1","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,6,10,6],"mass_status":[0],"result_topology":{"blocks":[[230851,22693540]],"n":190},"rim_edge":[4],"setup":[0]},"topology":null,"values":{"chamfer_offsets":[1.0,1.0],"fillet_point_step":[0.00001],"mass_properties":[843.4419706790258,1738.1708203041167,1738.1708203041167,5.071898289522079,5.235915880056969e-7,-0.1311527752890811,68762.11609619971,127566.73426940473,80379.45221552197,-0.004814865449686092,24768.944053818526,-0.006242712399236042],"result_geometry":{"blocks":[[595.5463822099409,1035.540078248152,86521.00135792041],[402.04428850228663,469.81396000806734,8114.348635575327]],"n":312},"selected_edge_before":{"blocks":[[14100.080101853804,14118.806431353158,70780.7744061843]],"n":17}}}
@@ -357,14 +357,14 @@
{"case":"issue-880-tilted-cylinder-rim-offsets-1-2","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,3,5,4],"mass_status":[0],"result_topology":{"blocks":[[130325,6420775]],"n":96},"rim_edge":[2],"setup":[0]},"topology":null,"values":{"chamfer_offsets":[1.0,2.0],"fillet_point_step":[0.00001],"mass_properties":[832.6483281009271,1720.140144361541,1720.140144361541,4.99767929190448,-2.1495585946764914e-7,-0.22570844007896562,67144.19086501349,123390.6309136572,77443.59644690811,0.0023345658723708806,22819.558958865095,0.0036109593469996204],"result_geometry":{"blocks":[[761.388603251321,1031.7361103537396,81273.63627947638]],"n":174},"selected_edge_before":{"blocks":[[14091.086294227582,14099.912699473927,70863.2943339659]],"n":17}}}
{"case":"issue-880-tilted-cylinder-rim-setbacks-1-1","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,3,5,4],"mass_status":[0],"result_topology":{"blocks":[[130325,6420775]],"n":96},"rim_edge":[2],"setup":[0]},"topology":null,"values":{"chamfer_offsets":[1.618033988749895,1.618033988749895],"fillet_point_step":[0.00001],"mass_properties":[826.1525474624167,1711.0809846736806,1711.0809846736806,4.9739626385500815,-1.7501575275512943e-7,-0.27845834850821183,66226.44903074687,121627.79467856979,76478.36337449068,0.0024680885887856246,21987.543441791786,0.0033055287285083113],"result_geometry":{"blocks":[[751.0025497731101,1019.8835624116716,80259.94614143898]],"n":174},"selected_edge_before":{"blocks":[[14091.086294227582,14099.912699473927,70863.2943339659]],"n":17}}}
{"case":"issue-880-tilted-cylinder-rim-setbacks-1-2","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,3,5,4],"mass_status":[0],"result_topology":{"blocks":[[130325,6420775]],"n":96},"rim_edge":[2],"setup":[0]},"topology":null,"values":{"chamfer_offsets":[2.118033988749895,2.73606797749979],"fillet_point_step":[0.00001],"mass_properties":[801.3331464208445,1660.057682126296,1660.057682126296,4.796573894345614,-1.7742447450618502e-7,-0.5492357686349448,62038.17343277012,111629.46761706655,69784.52447658317,0.002076350062359178,17348.968117547665,-0.0028464287422895196],"result_geometry":{"blocks":[[717.4767337778484,986.7173908186829,77521.35641370741]],"n":174},"selected_edge_before":{"blocks":[[14091.086294227582,14099.912699473927,70863.2943339659]],"n":17}}}
{"case":"issue919-cylinder-rim-edge1-blend-curve-g1-r10.0","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,2,3,3],"mass_status":[0],"result_topology":{"blocks":[[87159,2825806]],"n":60}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[1884.9556065113175,6283.18500796372,6283.18500796372,-1.4726672827265266e-8,1.4726670363343151e-8,9.999999999999998,994837.7456252411,994837.7456252411,314159.4891268237,0.011249309873292779,0.009398701749560834,-0.07608134049405635],"result_geometry":{"blocks":[[527.7040579753087,702.5531233622659,26658.127877841434]],"n":116},"selected_edge_before":{"blocks":[[14095.70132599177,14127.020009198175,70343.74995626012]],"n":17}}}
{"case":"issue919-cylinder-rim-edge1-blend-curve-g1-r9.99","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,3,5,4],"mass_status":[0],"result_topology":{"blocks":[[130319,6510830]],"n":96}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[1583.7685523019493,5300.271864268011,5300.271864268011,-1.8399005431793888e-6,2.1780758612647477e-7,11.406050174100162,950756.3822965294,950756.0703586438,244604.87304485095,0.016529236446639395,-0.04075782618448476,-0.0374183859802286],"result_geometry":{"blocks":[[594.1419734376818,786.7897690162058,38954.76979280044]],"n":174},"selected_edge_before":{"blocks":[[14095.70132599177,14127.020009198175,70343.74995626012]],"n":17}}}
{"case":"issue919-cylinder-rim-edge1-blend-curve-g2-r10.0","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,2,3,3],"mass_status":[0],"result_topology":{"blocks":[[87159,2825806]],"n":60}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[1884.9556065113175,6283.18500796372,6283.18500796372,-1.4726672827265266e-8,1.4726670363343151e-8,9.999999999999998,994837.7456252411,994837.7456252411,314159.4891268237,0.011249309873292779,0.009398701749560834,-0.07608134049405635],"result_geometry":{"blocks":[[527.7040579753087,702.5531233622659,26658.127877841434]],"n":116},"selected_edge_before":{"blocks":[[14095.70132599177,14127.020009198175,70343.74995626012]],"n":17}}}
{"case":"issue919-cylinder-rim-edge1-blend-curve-g2-r9.99","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,3,5,4],"mass_status":[0],"result_topology":{"blocks":[[130319,6510830]],"n":96}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[1644.3111130959878,5587.653678925119,5587.653678925119,-2.383818682443563e-6,2.1253783186845673e-7,10.99708332866578,964322.2023825841,964321.8530237549,262457.1988077855,0.016656203422202892,-0.05532857123535695,-0.03711301151031612],"result_geometry":{"blocks":[[593.4456665831377,787.2102238119991,38823.937164018214]],"n":174},"selected_edge_before":{"blocks":[[14095.70132599177,14127.020009198175,70343.74995626012]],"n":17}}}
{"case":"issue919-cylinder-rim-edge2-blend-curve-g1-r10.0","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,2,3,3],"mass_status":[0],"result_topology":{"blocks":[[87159,2825806]],"n":60}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[1884.9556065113175,6283.18500796372,6283.18500796372,-1.4726672827265266e-8,1.4726670363343151e-8,9.999999999999998,994837.7456252411,994837.7456252411,314159.4891268237,0.011249309873292779,0.009398701749560834,-0.07608134049405635],"result_geometry":{"blocks":[[527.7040579753087,702.5531233622659,26658.127877841434]],"n":116},"selected_edge_before":{"blocks":[[14156.70132599177,14188.020009198175,71124.74995626012]],"n":17}}}
{"case":"issue919-cylinder-rim-edge2-blend-curve-g1-r9.99","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,3,5,4],"mass_status":[0],"result_topology":{"blocks":[[130325,6420775]],"n":96}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[1583.7685966525378,5300.271266766072,5300.271266766072,-1.8712879855189476e-6,-1.7845850849284518e-7,8.593948525313555,652658.0601936308,652658.2056045898,244604.88575198458,-0.004212599712758974,-0.14141780285386873,-0.0378434190316843],"result_geometry":{"blocks":[[623.4162163020915,822.7421160371163,53950.62840185845]],"n":174},"selected_edge_before":{"blocks":[[14156.70132599177,14188.020009198175,71124.74995626012]],"n":17}}}
{"case":"issue919-cylinder-rim-edge2-blend-curve-g2-r10.0","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,2,3,3],"mass_status":[0],"result_topology":{"blocks":[[87159,2825806]],"n":60}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[1884.9556065113175,6283.18500796372,6283.18500796372,-1.4726672827265266e-8,1.4726670363343151e-8,9.999999999999998,994837.7456252411,994837.7456252411,314159.4891268237,0.011249309873292779,0.009398701749560834,-0.07608134049405635],"result_geometry":{"blocks":[[527.7040579753087,702.5531233622659,26658.127877841434]],"n":116},"selected_edge_before":{"blocks":[[14156.70132599177,14188.020009198175,71124.74995626012]],"n":17}}}
{"case":"issue919-cylinder-rim-edge2-blend-curve-g2-r9.99","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,3,5,4],"mass_status":[0],"result_topology":{"blocks":[[130325,6420775]],"n":96}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[1644.311119363348,5587.651975489321,5587.651975489321,-6.234700638422752e-6,-3.5185337940224953e-9,9.002917878731221,741467.7154116915,741467.6248444314,262456.83476519614,0.009604081397480868,-0.5074030190417189,-0.029600705227578187],"result_geometry":{"blocks":[[626.8552154158378,827.3897624597272,54376.46793556074]],"n":174},"selected_edge_before":{"blocks":[[14156.70132599177,14188.020009198175,71124.74995626012]],"n":17}}}
{"case":"issue919-cylinder-rim-edge1-blend-curve-g1-r10.0","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1007,2,3,3],"mass_status":[0],"result_topology":{"blocks":[[87159,2825806]],"n":60}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[1884.9556065113175,6283.18500796372,6283.18500796372,-1.4726672827265266e-8,1.4726670363343151e-8,9.999999999999998,994837.7456252411,994837.7456252411,314159.4891268237,0.011249309873292779,0.009398701749560834,-0.07608134049405635],"result_geometry":{"blocks":[[527.7040579753087,702.5531233622659,26658.127877841434]],"n":116},"selected_edge_before":{"blocks":[[14095.70132599177,14127.020009198175,70343.74995626012]],"n":17}}}
{"case":"issue919-cylinder-rim-edge1-blend-curve-g1-r9.99","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1007,2,3,3],"mass_status":[0],"result_topology":{"blocks":[[87159,2825806]],"n":60}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[1884.9556065113175,6283.18500796372,6283.18500796372,-1.4726672827265266e-8,1.4726670363343151e-8,9.999999999999998,994837.7456252411,994837.7456252411,314159.4891268237,0.011249309873292779,0.009398701749560834,-0.07608134049405635],"result_geometry":{"blocks":[[527.7040579753087,702.5531233622659,26658.127877841434]],"n":116},"selected_edge_before":{"blocks":[[14095.70132599177,14127.020009198175,70343.74995626012]],"n":17}}}
{"case":"issue919-cylinder-rim-edge1-blend-curve-g2-r10.0","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1007,2,3,3],"mass_status":[0],"result_topology":{"blocks":[[87159,2825806]],"n":60}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[1884.9556065113175,6283.18500796372,6283.18500796372,-1.4726672827265266e-8,1.4726670363343151e-8,9.999999999999998,994837.7456252411,994837.7456252411,314159.4891268237,0.011249309873292779,0.009398701749560834,-0.07608134049405635],"result_geometry":{"blocks":[[527.7040579753087,702.5531233622659,26658.127877841434]],"n":116},"selected_edge_before":{"blocks":[[14095.70132599177,14127.020009198175,70343.74995626012]],"n":17}}}
{"case":"issue919-cylinder-rim-edge1-blend-curve-g2-r9.99","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1007,2,3,3],"mass_status":[0],"result_topology":{"blocks":[[87159,2825806]],"n":60}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[1884.9556065113175,6283.18500796372,6283.18500796372,-1.4726672827265266e-8,1.4726670363343151e-8,9.999999999999998,994837.7456252411,994837.7456252411,314159.4891268237,0.011249309873292779,0.009398701749560834,-0.07608134049405635],"result_geometry":{"blocks":[[527.7040579753087,702.5531233622659,26658.127877841434]],"n":116},"selected_edge_before":{"blocks":[[14095.70132599177,14127.020009198175,70343.74995626012]],"n":17}}}
{"case":"issue919-cylinder-rim-edge2-blend-curve-g1-r10.0","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1007,2,3,3],"mass_status":[0],"result_topology":{"blocks":[[87159,2825806]],"n":60}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[1884.9556065113175,6283.18500796372,6283.18500796372,-1.4726672827265266e-8,1.4726670363343151e-8,9.999999999999998,994837.7456252411,994837.7456252411,314159.4891268237,0.011249309873292779,0.009398701749560834,-0.07608134049405635],"result_geometry":{"blocks":[[527.7040579753087,702.5531233622659,26658.127877841434]],"n":116},"selected_edge_before":{"blocks":[[14156.70132599177,14188.020009198175,71124.74995626012]],"n":17}}}
{"case":"issue919-cylinder-rim-edge2-blend-curve-g1-r9.99","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1007,2,3,3],"mass_status":[0],"result_topology":{"blocks":[[87159,2825806]],"n":60}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[1884.9556065113175,6283.18500796372,6283.18500796372,-1.4726672827265266e-8,1.4726670363343151e-8,9.999999999999998,994837.7456252411,994837.7456252411,314159.4891268237,0.011249309873292779,0.009398701749560834,-0.07608134049405635],"result_geometry":{"blocks":[[527.7040579753087,702.5531233622659,26658.127877841434]],"n":116},"selected_edge_before":{"blocks":[[14156.70132599177,14188.020009198175,71124.74995626012]],"n":17}}}
{"case":"issue919-cylinder-rim-edge2-blend-curve-g2-r10.0","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1007,2,3,3],"mass_status":[0],"result_topology":{"blocks":[[87159,2825806]],"n":60}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[1884.9556065113175,6283.18500796372,6283.18500796372,-1.4726672827265266e-8,1.4726670363343151e-8,9.999999999999998,994837.7456252411,994837.7456252411,314159.4891268237,0.011249309873292779,0.009398701749560834,-0.07608134049405635],"result_geometry":{"blocks":[[527.7040579753087,702.5531233622659,26658.127877841434]],"n":116},"selected_edge_before":{"blocks":[[14156.70132599177,14188.020009198175,71124.74995626012]],"n":17}}}
{"case":"issue919-cylinder-rim-edge2-blend-curve-g2-r9.99","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1007,2,3,3],"mass_status":[0],"result_topology":{"blocks":[[87159,2825806]],"n":60}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[1884.9556065113175,6283.18500796372,6283.18500796372,-1.4726672827265266e-8,1.4726670363343151e-8,9.999999999999998,994837.7456252411,994837.7456252411,314159.4891268237,0.011249309873292779,0.009398701749560834,-0.07608134049405635],"result_geometry":{"blocks":[[527.7040579753087,702.5531233622659,26658.127877841434]],"n":116},"selected_edge_before":{"blocks":[[14156.70132599177,14188.020009198175,71124.74995626012]],"n":17}}}
{"case":"issue920-cylinder-rim-edge1-constant-r10.0","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,3,4,3],"mass_status":[0],"result_topology":{"blocks":[[101236,3961388]],"n":77}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[1570.7963760973983,5235.988291000227,5235.988291000227,1.8833101490165886e-7,2.059948257914543e-7,11.500000235372113,947714.0853077865,947713.8663011974,240855.69263077818,0.01617878124484213,0.014791470053185648,-0.03804027228670748],"result_geometry":{"blocks":[[590.9590566994827,737.60927109562,34353.41686048178]],"n":138},"selected_edge_before":{"blocks":[[14095.70132599177,14127.020009198175,70343.74995626012]],"n":17}}}
{"case":"issue920-cylinder-rim-edge1-constant-r9.99","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,3,5,4],"mass_status":[0],"result_topology":{"blocks":[[130313,6525256]],"n":96}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[1571.1549739407485,5237.781041311214,5237.781041311214,1.882665543057572e-7,2.0592431928935601e-7,11.497487105531828,947809.066019011,947808.8470124219,240963.9868810795,0.016178781243650686,0.014791470064092968,-0.03804027240533144],"result_geometry":{"blocks":[[596.9287052557129,789.048870953054,40056.385280241884]],"n":174},"selected_edge_before":{"blocks":[[14095.70132599177,14127.020009198175,70343.74995626012]],"n":17}}}
{"case":"issue920-cylinder-rim-edge1-variable-constant-law-r10.0","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,3,4,3],"mass_status":[0],"result_topology":{"blocks":[[101236,3961388]],"n":77}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[1570.7963760973983,5235.988291000227,5235.988291000227,1.8833101490165886e-7,2.059948257914543e-7,11.500000235372113,947714.0853077865,947713.8663011974,240855.69263077818,0.01617878124484213,0.014791470053185648,-0.03804027228670748],"result_geometry":{"blocks":[[590.9590566994827,737.60927109562,34353.41686048178]],"n":138},"selected_edge_before":{"blocks":[[14095.70132599177,14127.020009198175,70343.74995626012]],"n":17}}}
@@ -380,24 +380,24 @@
{"case":"issue_2020_mitred_put_back_d9_full","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,8,12,6],"mass_status":[0],"result_topology":{"blocks":[[258750,29224039]],"n":224}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[2539.999999999998,1200.0000000000011,1200.0000000000011,19.999999999999982,14.999999999999996,0.5000000000000004,360400.00000000023,640400.0,1000000.0000000002,9000.000000000015,12000.000000000004,359999.99999999994],"result_geometry":{"blocks":[[1861.3361707476251,1861.3361707476251,225473.40608729987],[1541.6800249999997,1968.4000250000001,88228.20117500001]],"n":356},"selected_edge_before":{"blocks":[[56502.00000000001,56502.00000000001,1722373.9091997326]],"n":68}}}
{"case":"issue_2020_mitred_put_back_d9_solver_geometry","deferred":null,"error":null,"ints":{"all_corner_vertex_state":{"blocks":[[52,908]],"n":32},"before_direct_topology":{"blocks":[[78,1076]],"n":41},"corner_adjustment_flags":[0,0,0,1,0,0,2,0,0,3,0,0],"corner_calculation_flags":[0,0,0,0,1,0,0,0,2,0,0,0,3,0,0,0],"generated_geometry_state":{"blocks":[[57068,1042802]],"n":66},"offsets_after_state":{"blocks":[[486632,29434852]],"n":108},"offsets_before_state":{"blocks":[[486632,29434852]],"n":108},"prefix_state":{"blocks":[[129520,6117777]],"n":245},"prefix_statuses":[0,0,0,0,0,0]},"topology":null,"values":{"actual_solver_corner_parameters":{"blocks":[[26.792846803190923,26.792846803190923,453.0330947014537]],"n":28},"all_corner_vertices":{"blocks":[[144.00000000000006,144.00000000000006,952.000000000001]],"n":20},"fillet_point_step":[0.00001],"generated_geometry_samples":{"blocks":[[139.50000000000009,4e+20,-2e+20]],"n":68},"offsets_after_distances":[-3.0,-3.0,-3.0,-3.0,-3.0,-3.0,-3.0,-3.0,-3.0,-3.0,-3.0,-3.0,-3.0,-3.0,-3.0,-3.0],"offsets_before_distances":[-3.0,-3.0,-3.0,-3.0,-3.0,-3.0,-3.0,-3.0,-3.0,-3.0,-3.0,-3.0,-3.0,-3.0,-3.0,-3.0],"selected_edge_before":{"blocks":[[56502.00000000001,56502.00000000001,1722373.9091997326]],"n":68}}}
{"case":"issue_2176_tabbed_plate_corner_arc_r0_5","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,16,25,11],"mass_status":[0],"result_topology":{"blocks":[[281128,35285668],[236437,24427509]],"n":460}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[4398.8425857072025,4054.888816833887,4054.888816833887,-0.00012669975810349513,0.9115221713707169,0.9999652696452712,726504.4940266546,619661.9460832218,1335354.1129348162,3691.566425403889,-0.9648562485615326,-16.865770119157276],"result_geometry":{"blocks":[[1401.1712384785255,1737.8960095130597,174917.61539001222],[1565.4826234656139,1654.1854956478237,213041.33663008222],[1371.046719799316,3505.834581774351,181490.89801207467]],"n":712},"selected_edge_before":{"blocks":[[14154.967002424684,14154.967002424684,71530.48607805041]],"n":17}}}
{"case":"issue_2176_tabbed_plate_disc_wall_r0_5","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,14,21,9],"mass_status":[0],"result_topology":{"blocks":[[281171,35300367],[149816,9440034]],"n":386}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[4367.449401610503,4047.089262579409,4047.089262579409,-5.718562397197714e-7,0.9171896532273762,0.998253555517983,724309.0114324422,617039.5731092782,1330592.0072751264,3721.435702636294,-0.0015413574392603045,-0.36290622697270075],"result_geometry":{"blocks":[[1499.7510999505373,1706.073485467804,190709.01430381104],[1124.3803374815031,1525.7473994426227,144254.99284007528],[92.0299790391458,546.4989415529162,1060.0310174505425]],"n":596},"selected_edge_before":{"blocks":[[14027.437365722679,14144.47975123995,70257.10597694984]],"n":17}}}
{"case":"issue_2176_tabbed_plate_tab_side_r0_5","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,14,21,9],"mass_status":[0],"result_topology":{"blocks":[[281168,35290808],[149786,9405196]],"n":386}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[4397.942625660986,4054.67199430081,4054.67199430081,-0.0003610268152069641,0.9102246530893696,0.9999174589769523,726369.267726605,619657.2031776452,1335215.7030253154,3681.2173403955694,-2.7621752457740785,-41.57405779972847],"result_geometry":{"blocks":[[1364.7334764622403,1687.0849033256527,173832.5300393556],[1306.519620068148,1551.5720848838248,152881.19830835846],[342.34265676509955,550.6800654765135,15689.434055981344]],"n":596},"selected_edge_before":{"blocks":[[14127.847240556588,14127.847240556588,71293.15049706593]],"n":17}}}
{"case":"issue_2176_tabbed_plate_disc_wall_r0_5","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,14,21,9],"mass_status":[0],"result_topology":{"blocks":[[281171,35300367],[149816,9440034]],"n":386}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[4367.4493841856,4047.08926324806,4047.08926324806,-5.722796489689114e-7,0.9171896570905997,0.9982535555912998,724309.0118538848,617039.5730984351,1330592.0076828557,3721.4357261314526,-0.001543880814352094,-0.362947223855391],"result_geometry":{"blocks":[[1499.7509972439477,1706.0733827612144,190709.00916024353],[1124.3840510315765,1525.7511129926966,144255.5624676332],[92.0299790391458,546.4989415529162,1060.0310174505425]],"n":596},"selected_edge_before":{"blocks":[[14027.437365722679,14144.47975123995,70257.10597694984]],"n":17}}}
{"case":"issue_2176_tabbed_plate_tab_side_r0_5","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,14,21,9],"mass_status":[0],"result_topology":{"blocks":[[281168,35290808],[149786,9405196]],"n":386}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[4397.942625648389,4054.6719942882105,4054.6719942882105,-0.0003610268268599808,0.9102246530153764,0.9999174589753982,726369.2677188747,619657.203177439,1335215.7030174378,3681.2173399283347,-2.7621753166411542,-41.57405896780808],"result_geometry":{"blocks":[[1364.7339089054826,1687.085383710163,173832.58252326763],[1306.519620068148,1551.5720848838248,152881.19830835846],[342.34265676509955,550.6800654765135,15689.434055981344]],"n":596},"selected_edge_before":{"blocks":[[14127.847240556588,14127.847240556588,71293.15049706593]],"n":17}}}
{"case":"issue_2176_tabbed_plate_tab_top_r0_5","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,14,21,9],"mass_status":[0],"result_topology":{"blocks":[[281173,35304862],[149809,9411572]],"n":386}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[4398.24789430247,4054.7700191549548,4054.7700191549548,-5.519696972583106e-7,0.9105559203160607,0.9999386973404744,726367.8278701666,619662.5859111449,1335218.9522227664,3683.8919571192355,-0.0014270210124071687,-0.38100715225499243],"result_geometry":{"blocks":[[1343.8836492187402,1694.2856076554463,170184.63134580562],[1222.6211531467227,1579.5921858261206,136868.16581951614],[454.2585480681608,560.2564243430301,22246.496666459294]],"n":596},"selected_edge_before":{"blocks":[[14125.853333333334,14128.493333333334,71330.16]],"n":17}}}
{"case":"law-box10x20x30-e0-deg1-edge-map-degenerate","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,8,12,6],"mass_status":[0],"result_topology":{"blocks":[[258750,29222574]],"n":224}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[2200.0,6000.0,6000.0,4.999999999999999,9.999999999999998,15.0,2599999.9999999995,2000000.0,999999.9999999998,900000.0,450000.0,299999.99999999994],"result_geometry":{"blocks":[[1647.5002099999995,1647.5002099999995,195450.61977000008],[700.90005,700.90005,37411.60235000001]],"n":356},"selected_edge_before":{"blocks":[[14178.4,14178.4,71995.6]],"n":17}}}
{"case":"law-box10x20x30-e0-deg1-half-to-two","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,10,15,7],"mass_status":[0],"result_topology":{"blocks":[[301010,39996947],[15115,181394]],"n":278}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[2188.3674474157324,5992.48853957649,5992.48853957649,4.994157608510577,9.995523290115148,14.98162281481101,2591831.4171556165,1992689.1735775196,997738.7122607909,896979.2761741072,447847.900894425,299018.1010418324],"result_geometry":{"blocks":[[1712.6198010155663,1712.6198010155663,231574.67960448173],[1426.473888882551,1426.473888882551,128894.10446293742]],"n":436},"selected_edge_before":{"blocks":[[14178.4,14178.4,71995.6]],"n":17}}}
{"case":"law-box10x20x30-e0-deg2-edge-map-reversed","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,10,15,7],"mass_status":[0],"result_topology":{"blocks":[[301010,39996947],[15115,181394]],"n":278}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[2184.180175698155,5986.9976678385165,5986.9976678385165,4.989993955467209,9.998832177512746,14.968276339345405,2586777.675553807,1987399.2327326292,996975.3215489592,895944.4403663032,446302.34047020564,298684.7401142383],"result_geometry":{"blocks":[[1707.9022939654758,1707.9022939654758,230701.67833728326],[1423.3612665404362,1423.3612665404362,128633.06288725826]],"n":436},"selected_edge_before":{"blocks":[[14178.4,14178.4,71995.6]],"n":17}}}
{"case":"law-box10x20x30-e0-deg2-edge-map-sub-range","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,10,15,7],"mass_status":[0],"result_topology":{"blocks":[[301010,39996947],[15115,181394]],"n":278}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[2184.180175698155,5986.9976678385165,5986.9976678385165,4.989993955467209,9.998832177512746,14.968276339345405,2586777.675553807,1987399.2327326292,996975.3215489592,895944.4403663032,446302.34047020564,298684.7401142383],"result_geometry":{"blocks":[[1707.9022939654758,1707.9022939654758,230701.67833728326],[1423.3612665404362,1423.3612665404362,128633.06288725826]],"n":436},"selected_edge_before":{"blocks":[[14178.4,14178.4,71995.6]],"n":17}}}
{"case":"law-cube20-e0-deg1-4-2-4-c0-corner","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,8,12,6],"mass_status":[0],"result_topology":{"blocks":[[258750,29222574]],"n":224}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[2400.0,8000.0,8000.0,10.0,9.999999999999998,10.0,2133333.3333333335,2133333.3333333335,2133333.333333333,800000.0,800000.0,799999.9999999999],"result_geometry":{"blocks":[[1661.2002100000002,1661.2002100000002,200391.61977000005],[687.2000499999999,687.2000499999999,36709.60235]],"n":356},"selected_edge_before":{"blocks":[[14178.4,14178.4,71935.6]],"n":17}}}
{"case":"law-cube20-e0-deg1-linear-2-4","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,10,15,7],"mass_status":[0],"result_topology":{"blocks":[[301010,39996947],[15115,181394]],"n":278}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[2369.9971787052127,7959.938882612059,7959.938882612059,9.953285199050185,9.989215337883838,9.95328519345956,2111326.690672705,2103513.1316486103,2111326.692728949,790646.7232970882,785113.6838063456,790646.7238552927],"result_geometry":{"blocks":[[1684.018495036592,1684.018495036592,227164.9371211881],[1416.2116096133489,1416.2116096133489,127118.7631173969]],"n":436},"selected_edge_before":{"blocks":[[14178.4,14178.4,71935.6]],"n":17}}}
{"case":"law-cube20-e0-deg1-two-corners","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,8,12,6],"mass_status":[0],"result_topology":{"blocks":[[258750,29222574]],"n":224}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[2400.0,8000.0,8000.0,10.0,9.999999999999998,10.0,2133333.3333333335,2133333.3333333335,2133333.333333333,800000.0,800000.0,799999.9999999999],"result_geometry":{"blocks":[[1661.2002100000002,1661.2002100000002,200391.61977000005],[687.2000499999999,687.2000499999999,36709.60235]],"n":356},"selected_edge_before":{"blocks":[[14178.4,14178.4,71935.6]],"n":17}}}
{"case":"law-cube20-e0-deg2-c0-knot","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,8,12,6],"mass_status":[0],"result_topology":{"blocks":[[258750,29222574]],"n":224}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[2400.0,8000.0,8000.0,10.0,9.999999999999998,10.0,2133333.3333333335,2133333.3333333335,2133333.333333333,800000.0,800000.0,799999.9999999999],"result_geometry":{"blocks":[[1661.2002100000002,1661.2002100000002,200391.61977000005],[687.2000499999999,687.2000499999999,36709.60235]],"n":356},"selected_edge_before":{"blocks":[[14178.4,14178.4,71935.6]],"n":17}}}
{"case":"law-cube20-e0-deg2-smooth-4-2-4","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,10,15,7],"mass_status":[0],"result_topology":{"blocks":[[301010,39996947],[15115,181394]],"n":278}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[2364.5833884274725,7951.91872318908,7951.91872318908,9.944111161405383,10.000005764537047,9.944111153248919,2108837.4039038876,2097684.753829117,2108837.406896777,790748.4975647425,782206.8019289235,790748.4988280658],"result_geometry":{"blocks":[[1670.253816213491,1670.253816213491,225228.5723356151],[1414.9556478317274,1414.9556478317274,127060.02643786014]],"n":436},"selected_edge_before":{"blocks":[[14178.4,14178.4,71935.6]],"n":17}}}
{"case":"law-cube20-e0-deg2-smooth-g2","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,10,15,7],"mass_status":[0],"result_topology":{"blocks":[[301010,39996947],[15115,181394]],"n":278}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[2364.5833884274725,7951.91872318908,7951.91872318908,9.944111161405383,10.000005764537047,9.944111153248919,2108837.4039038876,2097684.753829117,2108837.406896777,790748.4975647425,782206.8019289235,790748.4988280658],"result_geometry":{"blocks":[[1670.253816213491,1670.253816213491,225228.5723356151],[1414.9556478317274,1414.9556478317274,127060.02643786014]],"n":436},"selected_edge_before":{"blocks":[[14178.4,14178.4,71935.6]],"n":17}}}
{"case":"law-cube20-e0-deg2-smooth-xsect-blend-curve","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,10,15,7],"mass_status":[0],"result_topology":{"blocks":[[301010,39996947],[15115,181394]],"n":278}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[2366.040386968263,7955.184176847979,7955.184176847979,9.947796765177388,10.00000958630715,9.947796714801624,2110462.0971337496,2100026.5067630815,2110462.129319577,791366.9884133905,783374.6307631921,791366.9930133581],"result_geometry":{"blocks":[[1670.2537675467788,1670.2537675467788,225228.5706809419],[1415.6238739668058,1415.6238739668058,127113.12984460121]],"n":436},"selected_edge_before":{"blocks":[[14178.4,14178.4,71935.6]],"n":17}}}
{"case":"law-box10x20x30-e0-deg1-edge-map-degenerate","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,12,19,9],"mass_status":[0],"result_topology":{"blocks":[[282157,35576428],[120532,5819260]],"n":352}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[2189.4571321942976,5993.757830244743,5993.757830244743,4.995128743296258,9.99576399430375,14.984714385317083,2593120.0621477054,1993916.5627755052,998033.2216380293,897396.7155170026,448207.4930860293,299152.9358938397],"result_geometry":{"blocks":[[1701.0562764837757,1701.0562764837757,218574.36419563327],[2163.3047039546013,2163.3047039546013,264144.8149702068],[411.8899398166186,411.8899398166186,8683.560350439691]],"n":552},"selected_edge_before":{"blocks":[[14178.4,14178.4,71995.6]],"n":17}}}
{"case":"law-box10x20x30-e0-deg1-half-to-two","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,10,15,7],"mass_status":[0],"result_topology":{"blocks":[[301010,39996947],[15115,181394]],"n":278}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[2188.379059506886,5992.5024348219395,5992.5024348219395,4.994168080003675,9.995531581842778,14.98165650073571,2591846.4037425597,1992702.533432261,997742.8556230384,896984.8330717636,447851.79925926693,299019.88656110596],"result_geometry":{"blocks":[[1712.6197407180512,1712.6197407180512,231574.67750033643],[1426.5305177374519,1426.5305177374519,128903.03470253291]],"n":436},"selected_edge_before":{"blocks":[[14178.4,14178.4,71995.6]],"n":17}}}
{"case":"law-box10x20x30-e0-deg2-edge-map-reversed","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,10,15,7],"mass_status":[0],"result_topology":{"blocks":[[301010,39996947],[15115,181394]],"n":278}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[2184.177950137648,5986.989082687177,5986.989082687177,4.989987686761873,9.998828224467495,14.968255698696115,2586769.088084993,1987391.0761068994,996973.3832900701,895941.2224802802,446299.9819602802,298683.71182376845],"result_geometry":{"blocks":[[1707.9022102028764,1707.9022102028764,230701.6755331708],[1423.3839279343283,1423.3839279343283,128635.76521585687]],"n":436},"selected_edge_before":{"blocks":[[14178.4,14178.4,71995.6]],"n":17}}}
{"case":"law-box10x20x30-e0-deg2-edge-map-sub-range","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,10,15,7],"mass_status":[0],"result_topology":{"blocks":[[301010,39996947],[15115,181394]],"n":278}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[2184.177950137648,5986.989082687177,5986.989082687177,4.989987686761873,9.998828224467495,14.968255698696115,2586769.088084993,1987391.0761068994,996973.3832900701,895941.2224802802,446299.9819602802,298683.71182376845],"result_geometry":{"blocks":[[1707.9022102028764,1707.9022102028764,230701.6755331708],[1423.3839279343283,1423.3839279343283,128635.76521585687]],"n":436},"selected_edge_before":{"blocks":[[14178.4,14178.4,71995.6]],"n":17}}}
{"case":"law-cube20-e0-deg1-4-2-4-c0-corner","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,12,19,9],"mass_status":[0],"result_topology":{"blocks":[[282157,35576940],[120532,5819421]],"n":352}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[2367.7996614875187,7960.455928310661,7960.455928310661,9.953870525840316,9.999999997907073,9.9538703640245,2112903.7903727363,2103885.510988785,2112903.8332586014,792373.4632352736,785299.4272634687,792373.4760973271],"result_geometry":{"blocks":[[1667.4392845374782,1667.4392845374782,214661.96286498918],[2130.612662111822,2130.612662111822,258072.04376489055],[407.39315200462664,407.39315200462664,8411.53509509764]],"n":552},"selected_edge_before":{"blocks":[[14178.4,14178.4,71935.6]],"n":17}}}
{"case":"law-cube20-e0-deg1-linear-2-4","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,10,15,7],"mass_status":[0],"result_topology":{"blocks":[[301010,39996947],[15115,181394]],"n":278}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[2370.05343059626,7960.0703182385405,7960.0703182385405,9.953433966158121,9.989250903639954,9.953433959735772,2111397.299919089,2103607.7826821413,2111397.302168263,790676.8629049206,785160.8967532889,790676.8637430049],"result_geometry":{"blocks":[[1684.0183897533257,1684.0183897533257,227164.9335056153],[1416.321913289498,1416.321913289498,127135.08601081748]],"n":436},"selected_edge_before":{"blocks":[[14178.4,14178.4,71935.6]],"n":17}}}
{"case":"law-cube20-e0-deg1-two-corners","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,16,26,12],"mass_status":[0],"result_topology":{"blocks":[[281248,35332030],[265557,31558171]],"n":480}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[2373.3343744605127,7967.5230234923765,7967.5230234923765,9.961877713267905,9.999999996732752,9.961877061901808,2116953.5053326106,2108985.6211141036,2116953.674365011,793714.8480985892,787842.1588430898,793714.8998877916],"result_geometry":{"blocks":[[1721.86233,1721.86233,208393.97133000006],[2488.8687436992404,2488.8687436992404,339912.5795379509],[1960.2108747484733,1960.2108747484733,252841.19884302327]],"n":748},"selected_edge_before":{"blocks":[[14178.4,14178.4,71935.6]],"n":17}}}
{"case":"law-cube20-e0-deg2-c0-knot","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,12,19,9],"mass_status":[0],"result_topology":{"blocks":[[282157,35576940],[120532,5819421]],"n":352}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[2367.799661484149,7960.455928301491,7960.455928301491,9.953870525830228,9.99999999790696,9.953870364013838,2112903.7903681034,2103885.51098218,2112903.83325414,792373.463233477,785299.4272601776,792373.4760956196],"result_geometry":{"blocks":[[1667.4392845374782,1667.4392845374782,214661.96286498918],[2130.6126621107524,2130.6126621107524,258072.04376462527],[407.39315200381,407.39315200381,8411.535095089917]],"n":552},"selected_edge_before":{"blocks":[[14178.4,14178.4,71935.6]],"n":17}}}
{"case":"law-cube20-e0-deg2-smooth-4-2-4","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,10,15,7],"mass_status":[0],"result_topology":{"blocks":[[301010,39996947],[15115,181394]],"n":278}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[2364.7321244967366,7952.15814556463,7952.15814556463,9.944378654908855,10.000003665020474,9.944378642827475,2108961.1939941524,2097854.778922764,2108961.198033214,790793.2619558896,782291.5574736597,790793.2635737617],"result_geometry":{"blocks":[[1670.2536924877857,1670.2536924877857,225228.56812894478],[1414.9286449728686,1414.9286449728686,127042.44116635519]],"n":436},"selected_edge_before":{"blocks":[[14178.4,14178.4,71935.6]],"n":17}}}
{"case":"law-cube20-e0-deg2-smooth-g2","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,10,15,7],"mass_status":[0],"result_topology":{"blocks":[[301010,39996947],[15115,181394]],"n":278}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[2364.7321244967366,7952.15814556463,7952.15814556463,9.944378654908855,10.000003665020474,9.944378642827475,2108961.1939941524,2097854.778922764,2108961.198033214,790793.2619558896,782291.5574736597,790793.2635737617],"result_geometry":{"blocks":[[1670.2536924877857,1670.2536924877857,225228.56812894478],[1414.9286449728686,1414.9286449728686,127042.44116635519]],"n":436},"selected_edge_before":{"blocks":[[14178.4,14178.4,71935.6]],"n":17}}}
{"case":"law-cube20-e0-deg2-smooth-xsect-blend-curve","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1007,8,12,6],"mass_status":[0],"result_topology":{"blocks":[[258750,29222574]],"n":224}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[2400.0,8000.0,8000.0,10.0,9.999999999999998,10.0,2133333.3333333335,2133333.3333333335,2133333.333333333,800000.0,800000.0,799999.9999999999],"result_geometry":{"blocks":[[1661.2002100000002,1661.2002100000002,200391.61977000005],[687.2000499999999,687.2000499999999,36709.60235]],"n":356},"selected_edge_before":{"blocks":[[14178.4,14178.4,71935.6]],"n":17}}}
{"case":"law-cube20-e0-deg2-smooth-xsect-linear","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,10,15,7],"mass_status":[0],"result_topology":{"blocks":[[301010,39996947],[15115,181394]],"n":278}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[2345.276012289922,7887.948288474076,7887.948288474076,9.87399069179629,10.000026673334782,9.873990690535063,2077813.4007131397,2053384.4728764938,2077813.4011334046,778859.1282175718,760133.6865919796,778859.1288435383],"result_geometry":{"blocks":[[1670.2536924877463,1670.2536924877463,225228.5681289348],[1403.4605734751906,1403.4605734751906,126222.68861420908]],"n":436},"selected_edge_before":{"blocks":[[14178.4,14178.4,71935.6]],"n":17}}}
{"case":"law-cube20-e0-deg3-asymmetric","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,10,15,7],"mass_status":[0],"result_topology":{"blocks":[[301010,39996947],[15115,181394]],"n":278}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[2369.4069855466732,7953.332363264005,7953.332363264005,9.945810598624647,9.991863206952454,9.945810527933006,2108787.386729554,2098759.629798661,2108787.405279481,789795.7339939832,782744.2624439899,789795.7389614069],"result_geometry":{"blocks":[[1689.9810388469928,1689.9810388469928,227825.14340855274],[1415.55332979773,1415.55332979773,127035.16611002201]],"n":436},"selected_edge_before":{"blocks":[[14178.4,14178.4,71935.6]],"n":17}}}
{"case":"law-cube20-e3-deg1-4-2-4-c0-corner","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,8,12,6],"mass_status":[0],"result_topology":{"blocks":[[258750,29222574]],"n":224}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[2400.0,8000.0,8000.0,10.0,9.999999999999998,10.0,2133333.3333333335,2133333.3333333335,2133333.333333333,800000.0,800000.0,799999.9999999999],"result_geometry":{"blocks":[[1661.2002100000002,1661.2002100000002,200391.61977000005],[687.2000499999999,687.2000499999999,36709.60235]],"n":356},"selected_edge_before":{"blocks":[[14121.4,14121.4,71278.6]],"n":17}}}
{"case":"law-cube20-e7-deg3-asymmetric","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,10,15,7],"mass_status":[0],"result_topology":{"blocks":[[301016,39999287],[15109,181340]],"n":278}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[2369.4069856233546,7953.332369523572,7953.332369523572,9.991863218874535,10.054189495131984,10.054189461763025,2133238.5615324583,2126026.848754881,2126026.8487130217,799983.7305187095,799576.4464642706,799576.4456593441],"result_geometry":{"blocks":[[1699.017989833037,1699.017989833037,200943.09722632947],[988.5405250895623,988.5405250895623,96611.78197634013]],"n":436},"selected_edge_before":{"blocks":[[14065.4,14065.4,70475.2]],"n":17}}}
{"case":"law-cube20-e0-deg3-asymmetric","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,10,15,7],"mass_status":[0],"result_topology":{"blocks":[[301010,39996947],[15115,181394]],"n":278}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[2369.5735936719675,7953.638073486443,7953.638073486443,9.946157645131114,9.991924935375478,9.946157573448264,2108951.5281389835,2098980.0399434315,2108951.5467260107,789862.8508648482,782854.2156875631,789862.856497768],"result_geometry":{"blocks":[[1689.9809462060066,1689.9809462060066,227825.14024817996],[1416.5087046699075,1416.5087046699075,127186.2367228824]],"n":436},"selected_edge_before":{"blocks":[[14178.4,14178.4,71935.6]],"n":17}}}
{"case":"law-cube20-e3-deg1-4-2-4-c0-corner","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,12,19,9],"mass_status":[0],"result_topology":{"blocks":[[282159,35577151],[120530,5819190]],"n":352}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[2367.7996627945695,7960.455895279177,7960.455895279177,10.046129513187235,10.000000001524032,9.953870348732204,2112903.7816744195,2118573.9699743497,2127592.2959717903,792373.4591729318,799447.4994214177,799717.7091340713],"result_geometry":{"blocks":[[1670.69928453716,1670.69928453716,194295.84286490816],[1718.582995385231,1718.582995385231,223908.79625261773],[286.68131240652457,286.68131240652457,5815.128836080283]],"n":552},"selected_edge_before":{"blocks":[[14121.4,14121.4,71278.6]],"n":17}}}
{"case":"law-cube20-e7-deg3-asymmetric","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,10,15,7],"mass_status":[0],"result_topology":{"blocks":[[301016,39999287],[15109,181340]],"n":278}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[2369.5735937803856,7953.638078975719,7953.638078975719,9.991924946708583,10.0538424503107,10.053842417282297,2133239.4747884185,2126081.2410895796,2126081.2408184493,799983.9353458919,799580.241198749,799580.239501653],"result_geometry":{"blocks":[[1699.017897191417,1699.017897191417,200943.09406580182],[989.3796673300916,989.3796673300916,96759.96075129857]],"n":436},"selected_edge_before":{"blocks":[[14065.4,14065.4,70475.2]],"n":17}}}
{"case":"negative-default-magnitude","deferred":null,"error":null,"ints":{"comment_bytes":{"blocks":[[4138,96800]],"n":44},"comment_lengths":[36,8],"corner_types":[0,0],"status_error_flags":[1007,1,0,5,0,0,0,0,0]},"topology":null,"values":{"fillet_point_step":[0.00001],"tolerances":[9876543.21,-1.0]}}
{"case":"negative-tiny-tolerance","deferred":null,"error":null,"ints":{"comment_bytes":{"blocks":[[4138,96800]],"n":44},"comment_lengths":[36,8],"corner_types":[0,0],"status_error_flags":[1007,1,0,5,0,0,0,0,0]},"topology":null,"values":{"fillet_point_step":[0.00001],"tolerances":[1e-300,-1.0]}}
{"case":"negative-tolerance","deferred":null,"error":null,"ints":{"comment_bytes":{"blocks":[[4138,96800]],"n":44},"comment_lengths":[36,8],"corner_types":[0,0],"status_error_flags":[1007,1,0,5,0,0,0,0,0]},"topology":null,"values":{"fillet_point_step":[0.00001],"tolerances":[0.25,-1.0]}}
@@ -546,7 +546,6 @@
{"case":"preview0061","deferred":null,"error":null,"ints":{},"topology":null,"values":{"fillet_point_step":[0.00001],"preview":{"blocks":[[45708.850906473286,45867.088827948755,5159845.554286335],[259.2656166503355,259.2656166503355,11181.180574793818]],"n":323}}}
{"case":"preview0062","deferred":null,"error":null,"ints":{},"topology":null,"values":{"fillet_point_step":[0.00001],"preview":{"blocks":[[15707.104275792228,15811.546808077857,156776.84514288738]],"n":111}}}
{"case":"preview0063","deferred":null,"error":null,"ints":{},"topology":null,"values":{"fillet_point_step":[0.00001],"preview":{"blocks":[[15067.106082946868,15069.68595539249,106968.37695126716]],"n":111}}}
{"case":"private-upstream-rollover-404-cyl-on-box1-edge12-r2","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,19,29,12],"mass_status":[0],"result_topology":{"blocks":[[281240,35192864],[292891,36509496],[15110,45867]],"n":529}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[784.3420546903735,1425.0743965207253,1425.0743965207253,-2.372719284956573,2.7275880338822544e-11,-6.023649318818151e-9,20338.870154912518,52089.060009610745,52089.06426280264,-0.001278539456174066,-2.0113133581935666e-6,-1.3431922272541398e-7],"result_geometry":{"blocks":[[-34.77306382013805,729.1101422050003,-4925.62104420249],[221.39336932498534,663.1080229595183,24580.72817061312],[243.26460990468183,607.0663390760005,28262.537647373454],[7.620079999999994,167.78008,117.96160000000003]],"n":814},"selected_edge_before":{"blocks":[[14074.721314240567,14093.08993703976,70279.39541078194]],"n":17}}}
{"case":"radius-supported-8x-tolerance-accepted","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,10,15,7],"mass_status":[0],"result_topology":{"blocks":[[300940,39985608],[15125,181474]],"n":278}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[2199.9993132312175,5999.999999673101,5999.999999673101,4.9999999997275895,9.999999999999998,14.999999999557046,2599999.9997744923,1999999.9997853898,999999.9999237241,899999.9999243879,449999.9999243887,299999.9999673104],"result_geometry":{"blocks":[[1693.7990515999995,1693.7990515999995,225027.37822280003],[1354.199456040291,1354.199456040291,122170.018586127]],"n":436},"selected_edge_before":{"blocks":[[14178.4,14178.4,71995.6]],"n":17}}}
{"case":"radius-supported-at-limit-accepted","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,10,15,7],"mass_status":[0],"result_topology":{"blocks":[[300940,39985611],[15125,181502]],"n":278}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[2199.999313231904,5999.999999673101,5999.999999673101,4.999999999727591,9.999999999999998,14.999999999557046,2599999.9997744923,1999999.99978539,999999.9999237244,899999.9999243879,449999.99992438895,299999.99996731046],"result_geometry":{"blocks":[[1693.7990516013183,1693.7990516013183,225196.57796860224],[1354.1994560410544,1354.1994560410544,121583.21692993311]],"n":436},"selected_edge_before":{"blocks":[[14178.4,14178.4,71995.6]],"n":17}}}
{"case":"radius-supported-just-below-limit-rejected","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1007,8,12,6],"mass_status":[0],"result_topology":{"blocks":[[258750,29222574]],"n":224}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[2200.0,6000.0,6000.0,4.999999999999999,9.999999999999998,15.0,2599999.9999999995,2000000.0,999999.9999999998,900000.0,450000.0,299999.99999999994],"result_geometry":{"blocks":[[1647.5002099999995,1647.5002099999995,195450.61977000008],[700.90005,700.90005,37411.60235000001]],"n":356},"selected_edge_before":{"blocks":[[14178.4,14178.4,71995.6]],"n":17}}}
@@ -576,8 +575,8 @@
{"case":"real-box-prepared-actual-session","deferred":null,"error":null,"ints":{"before_direct_topology":[],"prefix_state":[0,1,0,0,0,2,2,1,-1,-1],"prefix_statuses":[0,-1,-1]},"topology":null,"values":{"actual_solver_corner_parameters":[0.5,0.5,0.00004,0.3490658503988659,0.17453292519943295],"fillet_point_step":[0.00001],"selected_edge_before":{"blocks":[[14178.4,14178.4,71995.6]],"n":17}}}
{"case":"real-box-prepared-native-unknown-xsect-default","deferred":null,"error":null,"ints":{"before_direct_topology":[],"prefix_state":[0,1,0,0,0,2,2,1,-1,-1],"prefix_statuses":[0,-1,-1]},"topology":null,"values":{"actual_solver_corner_parameters":[0.5,0.5,0.00004,0.3490658503988659,0.17453292519943295],"fillet_point_step":[0.00001],"selected_edge_before":{"blocks":[[14178.4,14178.4,71995.6]],"n":17}}}
{"case":"real-box-select-original-surfaces-true-context","deferred":null,"error":null,"ints":{"insertion_geometry_present":[1],"insertion_intermediate_topology":{"blocks":[[71312,1969398]],"n":131},"insertion_passive_after":{"blocks":[[78297,6368843]],"n":109},"insertion_passive_before":{"blocks":[[78251,6059271]],"n":101},"insertion_statuses":[0,0,0,0,0],"insertion_target_topology":{"blocks":[[281081,37242562],[152555,9692685],[4923,666125],[7642,1020365],[70,2752]],"n":1104},"original_surface_selection":{"blocks":[[681,70568],[52,1229]],"n":302}},"topology":null,"values":{"fillet_point_step":[0.00001],"insertion_intermediate_geometry":{"blocks":[[955.0433105307864,955.0433105307864,49914.06908733248]],"n":107},"insertion_raw_intervals_after":[1e+20,-1e+20,1e+20,-1e+20,0.0,1.0,0.0,1.0],"insertion_raw_intervals_before":[1e+20,-1e+20,1e+20,-1e+20,0.0,1.0,0.0,1.0],"insertion_target_geometry":{"blocks":[[1800.4003699999996,1800.4003699999996,210259.69629],[2083.3170945456754,2083.3170945456754,247475.8961127575],[607.10004,607.10004,23454.501319999996]],"n":589},"selected_edge_before":{"blocks":[[14178.4,14178.4,71995.6]],"n":17}}}
{"case":"real-box-single-edge-linear-radius-half-to-two","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,10,15,7],"mass_status":[0],"result_topology":{"blocks":[[301015,39997847],[15110,181356]],"n":278}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[2188.3674474159525,5992.488539577527,5992.488539577527,5.005842391488697,9.995523290116662,15.018377185187576,2598438.9214541474,1999996.887156554,998438.9215420525,899962.4867185809,449999.465532101,299962.4865890335],"result_geometry":{"blocks":[[1674.7298010206996,1674.7298010206996,192959.62960575984],[969.0664608896851,969.0664608896851,97936.25034520043]],"n":436},"selected_edge_before":{"blocks":[[14060.4,14060.4,70497.6]],"n":17}}}
{"case":"real-box-single-edge-linear-radius-two-to-half","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,10,15,7],"mass_status":[0],"result_topology":{"blocks":[[301015,39997847],[15110,181356]],"n":278}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[2188.3674474158306,5992.488539805106,5992.488539805106,5.005842391317437,10.00447671026473,15.01837718490055,2599511.9868692076,1999996.8871735756,999511.9869401818,899986.5766212373,449999.4655329486,299986.57665178337],"result_geometry":{"blocks":[[1675.1198010216012,1675.1198010216012,192753.1694979272],[969.5982743111803,969.5982743111803,98158.87217277495]],"n":436},"selected_edge_before":{"blocks":[[14060.4,14060.4,70497.6]],"n":17}}}
{"case":"real-box-single-edge-linear-radius-half-to-two","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,10,15,7],"mass_status":[0],"result_topology":{"blocks":[[301015,39997847],[15110,181356]],"n":278}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[2188.3790595075548,5992.502434822855,5992.502434822855,5.005831919995653,9.995531581843263,15.018343499262066,2598441.811582999,1999996.8971680799,998441.8115187659,899962.5871742155,449999.46774264105,299962.58685422613],"result_geometry":{"blocks":[[1674.7297407231845,1674.7297407231845,192959.6275016145],[969.1201841429577,969.1201841429577,97945.42135616866]],"n":436},"selected_edge_before":{"blocks":[[14060.4,14060.4,70497.6]],"n":17}}}
{"case":"real-box-single-edge-linear-radius-two-to-half","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,10,15,7],"mass_status":[0],"result_topology":{"blocks":[[301015,39997847],[15110,181356]],"n":278}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[2188.37905950708,5992.5024351703705,5992.5024351703705,5.005831919753527,10.004468418462348,15.018343498820116,2599512.891982251,1999996.8971940402,999512.8918926076,899986.612591794,449999.467744817,299986.61252612213],"result_geometry":{"blocks":[[1675.1197407240861,1675.1197407240861,192753.16750184147],[969.5304929228423,969.5304929228423,98146.54225164212]],"n":436},"selected_edge_before":{"blocks":[[14060.4,14060.4,70497.6]],"n":17}}}
{"case":"real-box-single-edge-radius-half","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,10,15,7],"mass_status":[0],"result_topology":{"blocks":[[300940,39985608],[15125,181474]],"n":278}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[2195.600665117102,5998.927028706208,5998.927028706208,4.999125706075708,9.999999999999998,14.997337012941149,2598898.4137618863,1998936.5572224115,999752.0177821805,899679.3036554868,449682.8953314206,299893.9031807757],"result_geometry":{"blocks":[[1685.56037,1685.56037,223771.65917],[1349.4254718185134,1349.4254718185134,121881.22809373235]],"n":436},"selected_edge_before":{"blocks":[[14178.4,14178.4,71995.6]],"n":17}}}
{"case":"real-box-solver-geometry-actual-session","deferred":null,"error":null,"ints":{"all_corner_vertex_state":[0,0,1,1,0,1,1,1,1,0,1,1,1,1,1,1],"before_direct_topology":{"blocks":[[28,219]],"n":18},"corner_adjustment_flags":[0,0,0,1,0,0],"corner_calculation_flags":[0,0,0,0,1,0,0,0],"generated_geometry_state":{"blocks":[[57050,1041898]],"n":33},"offsets_after_state":{"blocks":[[121655,2431489]],"n":27},"offsets_before_state":{"blocks":[[121655,2431489]],"n":27},"prefix_state":{"blocks":[[64691,1812226]],"n":96},"prefix_statuses":[0,0,0,0,0,0]},"topology":null,"values":{"actual_solver_corner_parameters":[0.00004,0.17453292519943295,0.00004,0.17453292519943295,0.5,0.5,0.00004,0.3490658503988659,0.17453292519943295],"all_corner_vertices":{"blocks":[[276.0,276.0,3136.0]],"n":20},"fillet_point_step":[0.00001],"generated_geometry_samples":{"blocks":[[143.29999999999998,4e+20,-2e+20]],"n":68},"offsets_after_distances":[-0.5,-0.5,-0.5,-0.5],"offsets_before_distances":[-0.5,-0.5,-0.5,-0.5],"selected_edge_before":{"blocks":[[14178.4,14178.4,71995.6]],"n":17}}}
{"case":"real-box-trihedral-equal-radius-analytic-corner","deferred":null,"error":null,"ints":{"all_corner_vertex_state":{"blocks":[[36,763]],"n":36},"before_direct_topology":{"blocks":[[64,836]],"n":36},"classification_adjusted_corners":[],"corner_adjustment_flags":[0,0,0,1,0,0,2,0,0,3,0,0],"corner_calculation_flags":[0,1,0,1,1,0,0,0,2,0,0,0,3,0,0,0],"corner_edge_geometry_state":{"blocks":[[84219,2863601]],"n":68},"generated_geometry_state":{"blocks":[[171153,8773812]],"n":99},"intermediate_face_topology":{"blocks":[[271161,24861150],[2091,216230]],"n":464},"offsets_after_state":{"blocks":[[364971,17148807]],"n":81},"offsets_before_state":{"blocks":[[364971,17148807]],"n":81},"prefix_state":{"blocks":[[145644,7454631]],"n":249},"prefix_statuses":[0,0,0,0,0,0,0,0,0,0],"rails_after_classification_state":{"blocks":[[85906,11131838],[389,10101]],"n":298},"rails_after_trim_state":{"blocks":[[168343,8669959]],"n":100},"rails_before_classification_state":[1,0,2,0,1,0,4,0,3,0,0,0,5,0,8,12],"rails_before_trim_state":{"blocks":[[84127,3112722]],"n":70},"source_surface_binding":{"blocks":[[48030,528324]],"n":19}},"topology":null,"values":{"actual_solver_corner_parameters":{"blocks":[[5.269208027592628,5.269208027592628,74.2203548351002]],"n":23},"all_corner_vertices":{"blocks":[[129.0,129.0,3586.9999999999995]],"n":45},"corner_edge_geometry_samples":{"blocks":[[332.0494963629734,332.0494963629734,27135.19503359692]],"n":114},"fillet_point_step":[0.00001],"generated_geometry_samples":{"blocks":[[16.014999999999997,1.2e+21,-6.000000000000063e+20]],"n":204},"intermediate_face_geometry":{"blocks":[[490.53423335000787,490.53423335000787,70078.61248090953],[230.35143230614906,230.35143230614906,20221.081045102743]],"n":403},"offsets_after_distances":[-0.5,-0.5,-0.5,-0.5,-0.5,-0.5,-0.5,-0.5,-0.5,-0.5,-0.5,-0.5],"offsets_before_distances":[-0.5,-0.5,-0.5,-0.5,-0.5,-0.5,-0.5,-0.5,-0.5,-0.5,-0.5,-0.5],"rails_after_classification_parameters":{"blocks":[[1.2e+21,1.2e+21,9.24e+22]],"n":170},"rails_after_trim_geometry":{"blocks":[[1.5799999999999998,1.2e+21,-6e+20]],"n":72},"rails_before_classification_parameters":{"blocks":[[0.0002,0.0002,0.0021]],"n":20},"rails_before_trim_geometry":{"blocks":[[0.0,1.2e+21,-6e+20]],"n":24},"selected_edge_before":{"blocks":[[42190.2,42190.2,928444.6999999998]],"n":51}}}
@@ -602,7 +601,7 @@
{"case":"source-file-6_sided_corner-all-edges","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,64,123,61],"mass_status":[0],"result_topology":{"blocks":[[283769,35625538],[284512,36854725],[271386,34511400],[283411,35234493],[283627,36460301],[284751,37713997],[317833,43291061],[379719,49063301],[291464,33609125]],"n":2276}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[443.57161208134835,499.7447300414471,499.7447300414471,3.7497908779919875,3.749790877773721,3.7497908289015354,20817.125863491718,20817.125862303645,20817.12621504385,6246.289830074854,6246.289830269708,6246.289838178357],"result_geometry":{"blocks":[[854.4026556874678,854.4026556874678,105906.88311377533],[652.9932935269093,652.9932935269093,79077.6380755091],[692.9636103127021,692.9636103127021,91567.1202726605],[710.6397240066963,710.6397240066963,99706.69560795111],[598.727168373193,598.727168373193,80875.36910312623],[789.7601196767238,789.7601196767238,98004.34388144124],[656.3525599999998,656.3525599999998,91883.41504],[703.7445600000002,703.7445600000002,84588.89279999997],[654.6685600000003,654.6685600000003,79355.21455999996],[737.6578215009914,737.6578215009914,99070.59417896462],[589.2541911978551,649.2541911978551,72667.3402175583],[628.7594708197214,628.7594708197214,79550.4713972267],[645.4472177996703,645.4472177996703,82756.16234741977],[555.2016673599245,555.2016673599245,65289.5210960636]],"n":3568},"selected_edge_before":{"blocks":[[210963.7,210993.7,26171168.299999997],[168881.69999999998,168881.69999999998,16471199.399999999]],"n":459}}}
{"case":"source-file-bague-all-edges","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1007,4,8,4],"mass_status":[0],"result_topology":{"blocks":[[172450,12382265]],"n":146}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[514.6144027764909,225.66889284512877,225.66889284512877,-0.32303313010240103,6.889210187890638,-0.011379984931174108,18666.065838694758,10297.324325608877,28464.959061288333,-24.85414539881951,828.174064739097,-147.40253326904755],"result_geometry":{"blocks":[[270.59669473184863,660.8580131060972,19448.783514605828]],"n":232},"selected_edge_before":{"blocks":[[112359.55380710229,112557.74097961737,7247299.932758997]],"n":136}}}
{"case":"source-file-box1x1x2-all-edges","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,24,48,26],"mass_status":[0],"result_topology":{"blocks":[[282438,35461867],[281833,36474637],[339672,48701575],[166359,10491477]],"n":896}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[9.30194679671521,1.967003035932106,1.967003035932106,0.4999999757117343,0.5000000023283077,0.9999999889308744,3.2649512274482504,3.264951206130462,1.3042573024426076,0.9835015156673806,0.9835014821193659,0.49175073738537434],"result_geometry":{"blocks":[[193.45328884506165,193.45328884506165,28524.37936223593],[179.29069059146556,179.29069059146556,22031.704113554475],[208.6282635135972,208.6282635135972,25886.052475647815],[173.76843999999997,173.76843999999997,20884.368399999996],[134.73424774389622,134.73424774389622,18338.414562728045],[61.053229673345314,61.053229673345314,4403.841015076887]],"n":1428},"selected_edge_before":{"blocks":[[168284.96,168284.96,16577552.679999998]],"n":204}}}
{"case":"source-file-box_diff_cyl-all-edges","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,40,76,39],"mass_status":[0],"result_topology":{"blocks":[[282968,35506431],[283306,36675721],[267997,34055548],[286635,36037087],[363794,46577535],[182367,11241908]],"n":1412}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[627.2445952960352,950.6480780898113,950.6480780898113,3.874229357624231e-7,-0.20348974894456356,-5.1273783328422957e-8,15796.350695368727,16477.785461091597,15770.881590554309,-0.00017876692180651655,0.00012837259525750306,0.002077941171128243],"result_geometry":{"blocks":[[101.80636461627789,738.9318467782412,9456.940915297566],[166.5223208278985,749.569643880143,174.0511836522894],[227.53131622584206,633.676346889963,32510.402839190807],[222.14304894282054,619.34014427219,20893.24810129172],[46.956599999999966,638.1885999999996,-5833.451799999998],[322.00404754597434,506.68324235738874,39816.754597131956],[183.06527535819862,687.7092247739835,15422.008222770968],[130.94855197044683,544.5533077951053,17062.23070724576],[49.83296952498982,321.82783529968515,8374.348779660057]],"n":2230},"selected_edge_before":{"blocks":[[210463.65,210951.14999999988,26100092.299999993],[42210.47554043498,42255.6588015408,887040.2068456289]],"n":306}}}
{"case":"source-file-box_diff_cyl-all-edges","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,40,76,39],"mass_status":[0],"result_topology":{"blocks":[[282968,35506431],[283306,36675721],[267997,34055548],[286635,36037087],[363794,46577535],[182367,11241908]],"n":1412}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[627.2445954438153,950.6480778500087,950.6480778500087,3.8681753268088295e-7,-0.2034897502471257,-5.127772759603743e-8,15796.350688959315,16477.78545920116,15770.88158327281,-0.00017878552153312372,0.00012836359683495287,0.0020750864227059196],"result_geometry":{"blocks":[[101.80636461627789,738.9318467782412,9456.940915297566],[166.5223208278985,749.569643880143,174.0511836522894],[227.53131622584206,633.676346889963,32510.402839190807],[222.14304894282054,619.34014427219,20893.24810129172],[46.956599999999966,638.1885999999996,-5833.451799999998],[322.00404754597434,506.68324235738874,39816.754597131956],[183.06527535819862,687.7092247739835,15422.008222770968],[130.94855198031493,544.5533077996846,17062.230707804065],[49.83296952498982,321.82783529968515,8374.348779660057]],"n":2230},"selected_edge_before":{"blocks":[[210463.65,210951.14999999988,26100092.299999993],[42210.47554043498,42255.6588015408,887040.2068456289]],"n":306}}}
{"case":"source-file-box_diff_cyl_big_rad-all-edges","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1007,10,15,8],"mass_status":[0],"result_topology":{"blocks":[[300941,39928054],[30140,436784]],"n":280}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[115701.57332932904,1529494.006088955,1529494.006088955,-1.9135584797029415,-0.9649556748141885,-20.196266212587595,5974683452.46898,5954746195.646731,10270218574.735401,21646449.702618986,42926048.37740503,-76746621.4952533],"result_geometry":{"blocks":[[-835.3370606549072,8861.943417708128,-69336.09320817562],[290.1855502820211,4120.9768623089985,18165.86668339754]],"n":454},"selected_edge_before":{"blocks":[[210074.23415639185,218071.58566231982,26199180.985749345]],"n":255}}}
{"case":"source-file-box_diff_cyl_big_rad-r0.5-edge0","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,12,18,9],"mass_status":[0],"result_topology":{"blocks":[[283042,35515244],[105415,3872496]],"n":334}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[115658.54500464804,1529483.2669139523,1529483.2669139523,-1.9135700511377813,-0.965658602729514,-20.196407174514672,5974578259.796264,5954710532.699816,10270077722.078049,21646593.51282997,42926019.86020304,-76746711.70642623],"result_geometry":{"blocks":[[-1086.7132865397618,8472.006052945404,2631.947454673734],[1805.4349864584499,6513.36393457421,89104.03714407628],[80.92179765060668,562.8039448839702,3634.2290520674287]],"n":534},"selected_edge_before":{"blocks":[[14283.33334350586,14467.33334350586,73867.00012207031]],"n":17}}}
{"case":"source-file-box_diff_cyl_big_rad-r0.5-edge12","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,11,17,9],"mass_status":[0],"result_topology":{"blocks":[[284006,35772464],[90337,2396667]],"n":316}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[115668.36032337094,1529485.625870541,1529485.625870541,-1.913851462520626,-0.9651063712230051,-20.19637618225457,5974675051.201358,5954721097.62766,10270185078.983196,21646503.825274553,42926066.14128061,-76758128.55637008],"result_geometry":{"blocks":[[-632.4899827508547,8853.96826401428,-42712.70867640931],[1059.4761147998504,5172.565062028881,121758.26037236492]],"n":512},"selected_edge_before":{"blocks":[[14306.057758366,14306.057758366,72955.84024483882]],"n":17}}}
@@ -619,13 +618,13 @@
{"case":"source-file-box_with_large_fillet-edge1","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,12,18,8],"mass_status":[0],"result_topology":{"blocks":[[283055,35769646],[90395,2941752]],"n":332}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[537.7892904707323,862.6333644994273,862.6333644994273,4.488553303431224,5.0,4.488305634749131,52512.0721502345,47517.389874625085,52514.2086910191,19358.810953026907,15917.28115076158,19359.879189369483],"result_geometry":{"blocks":[[891.5671436602103,895.5671436602103,114231.151843292],[739.4048150194856,781.4408829969855,104609.36018334082],[17.6280532824558,17.6280532824558,62.80591234152895]],"n":516},"selected_edge_before":{"blocks":[[14068.3,14068.3,70644.2]],"n":17}}}
{"case":"source-file-box_with_large_fillet-edge12","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,12,18,8],"mass_status":[0],"result_topology":{"blocks":[[283001,35763294],[90433,3182624]],"n":332}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[537.789288998816,862.633375414687,862.633375414687,4.488429477447291,4.999876226379959,4.488553275115147,52512.788612319404,47518.81145382394,52512.073629490464,19359.87703985492,15917.283677892132,19358.811495927468],"result_geometry":{"blocks":[[814.1471436602104,838.1471436602104,102086.04287006857],[817.0508150194859,839.2868829969856,105455.30626572031],[17.6280532824558,17.6280532824558,45.18731024151452]],"n":516},"selected_edge_before":{"blocks":[[14079.3,14079.3,70608.90000000001]],"n":17}}}
{"case":"source-file-box_with_large_fillet-edge3","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1007,10,15,7],"mass_status":[0],"result_topology":{"blocks":[[285974,36222515],[30109,196175]],"n":278}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[538.2227848355478,862.6548251277313,862.6548251277313,4.488442197530397,5.0,4.488442195368608,52514.9239920041,47519.52638034829,52514.92406352628,19359.881585708183,15917.28595139585,19359.881595032577],"result_geometry":{"blocks":[[836.8070036602104,860.8070036602104,109173.87673372879],[579.5625666519293,601.798634629429,53541.36266599871]],"n":436},"selected_edge_before":{"blocks":[[14073.7,14073.7,70733.8]],"n":17}}}
{"case":"source-file-box_with_large_fillet-edge4","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,14,22,10],"mass_status":[0],"result_topology":{"blocks":[[281072,35291981],[178915,13605766]],"n":406}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[537.6713681733381,862.6278019474744,862.6278019474744,4.4883606306776915,5.000155928734892,4.488361746015738,52513.413335757876,47516.4933148329,52513.40160755154,19359.8773096077,15916.084162061892,19359.877275191542],"result_geometry":{"blocks":[[799.0440642911826,823.0440642911827,104507.0314889016],[812.724625289367,812.724625289367,106890.94023063482],[468.6658614414983,788.9868891549937,29856.61705782051]],"n":632},"selected_edge_before":{"blocks":[[14093.39629864484,14093.39629864484,70722.41447070886]],"n":17}}}
{"case":"source-file-box_with_large_fillet-edge4","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,14,22,10],"mass_status":[0],"result_topology":{"blocks":[[281072,35291981],[178915,13605766]],"n":406}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[537.6713657971693,862.6278053807719,862.6278053807719,4.488360653514321,5.00015590893774,4.488361741554979,52513.41337518746,47516.49370558227,52513.40195888178,19359.877309894164,15916.084284170542,19359.877276138737],"result_geometry":{"blocks":[[799.0440642911826,823.0440642911827,104507.03148890159],[812.72656830248,812.72656830248,106891.25215767618],[468.6658617490525,788.9868894625481,29856.617092731067]],"n":632},"selected_edge_before":{"blocks":[[14093.39629864484,14093.39629864484,70722.41447070886]],"n":17}}}
{"case":"source-file-box_with_large_fillet-edge5","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,12,18,8],"mass_status":[0],"result_topology":{"blocks":[[283036,35797270],[90396,3181663]],"n":332}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[537.7892891318179,862.6333649079133,862.6333649079133,4.488553303366396,5.000123832149973,4.488429469054802,52514.20863309225,47518.8110214335,52514.92402701891,19359.879188951414,15917.283554602647,19359.881588763506],"result_geometry":{"blocks":[[904.7211436602104,908.7211436602104,116607.89469317145],[618.3254587823888,640.5615267598887,89890.88291748935],[7.778247505838322,7.778247505838322,31.031592123367925]],"n":516},"selected_edge_before":{"blocks":[[14022.3,14042.3,70224.49999999999]],"n":17}}}
{"case":"source-file-brick-all-edges","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,56,104,50],"mass_status":[0],"result_topology":{"blocks":[[283437,35582898],[284022,36793899],[269944,34257554],[282676,35219757],[283555,36459123],[300887,43254006],[364092,46997335],[168409,10956390]],"n":1922}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[45087.097356758284,294964.3199128682,294964.3199128682,-2.12586480104287e-7,-12.70000023091666,25.40000002519063,496890207.7037177,819341741.9567833,808769897.7395835,-95149592.01315638,-2.7294360084613807,2.009157348746312],"result_geometry":{"blocks":[[682.9159729130314,6469.332409331139,119614.069780444],[727.2342346188091,5599.034162126886,-85341.93999259676],[990.2035095182382,5329.573957726606,184111.94959729872],[1330.4777803813379,4452.9505916878525,213174.52419417165],[241.5755629187879,3070.211362857953,219988.74315370314],[745.3445599999999,4452.784560000004,151948.24544],[389.4746000000004,4902.618600000001,105458.91540000004],[-98.27544000000188,3086.6845599999974,-38792.386960000236],[606.5103873971287,4737.820285189023,47825.679529197114],[423.41640674594356,4611.124366611683,41107.82944020807],[719.5812262674056,4362.155122099491,66988.19644875487],[317.6744279557803,2190.2145269698954,32856.72041913519]],"n":2996},"selected_edge_before":{"blocks":[[210965.98799999992,215163.59199999983,26141024.892426357],[126512.41199999995,128217.76800000013,9114019.36327905]],"n":408}}}
{"case":"source-file-corner_box-all-edges","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,30,60,32],"mass_status":[0],"result_topology":{"blocks":[[282676,35474753],[282571,36546502],[268276,34104339],[377289,49090592],[121300,5521860]],"n":1118}},"topology":null,"values":{"fillet_point_step":[0.001],"mass_properties":[360.29209466681806,455.9756674389535,455.9756674389535,-9.947249594502017,-10.031825910832763,3.463268966990351,54538.8963750908,56986.23408775473,96917.83501977609,-15883.823388473917,-15770.718486677864,45447.85683704582],"result_geometry":{"blocks":[[-805.3974759351756,1350.1282618853186,-96714.56379870111],[-597.1018663980398,1142.8047524259769,-78725.93067317118],[-432.07127447306203,1017.6364952602705,-72439.80627987147],[-635.3233999999995,1115.9246,-81890.29980000002],[-400.9597964901252,1002.4997617744377,-61854.22584627409],[-597.4315544061686,1057.2474890890628,-76312.4557029995],[-528.0638871103888,960.7335957063232,-51309.83745566855]],"n":1776},"selected_edge_before":{"blocks":[[209673.0980374654,211388.39390688544,26022406.58689605]],"n":255}}}
{"case":"source-file-corner_box-edge0","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,12,18,8],"mass_status":[0],"result_topology":{"blocks":[[283057,35770414],[90424,3092074]],"n":332}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[363.9406719490671,456.15627618925765,456.15627618925765,-9.947136643738995,-10.031783733055972,3.463209983290329,54561.75598005027,57010.49995063887,96957.38069528942,-15889.873840625996,-15776.64004565751,45464.79744018813],"result_geometry":{"blocks":[[-579.2715841839394,1117.6045067796938,-56209.91726906953],[-722.0686221779266,1220.101373126479,-89890.00293704089],[-26.711752494161882,29.931752494161888,-63.200354594176744]],"n":516},"selected_edge_before":{"blocks":[[13936.390000000001,14106.789999999999,69223.95000000001]],"n":17}}}
{"case":"source-file-corner_box-edge12","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,12,18,8],"mass_status":[0],"result_topology":{"blocks":[[283042,35773102],[90447,3153323]],"n":332}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[363.9901858099912,456.158710736926,456.158710736926,-9.947246038969011,-10.031963779171155,3.4631142989969326,54563.298092592995,57011.69320166166,96960.8502331014,-15889.939636021341,-15776.35412358989,45466.69356591667],"result_geometry":{"blocks":[[-638.8659474060853,1151.8293546174543,-64078.97542240601],[-503.15705923954346,1116.2021733001106,-68269.30948983079],[-10.880133051987993,24.729938828605444,-14.913610721505506]],"n":516},"selected_edge_before":{"blocks":[[13987.304798590523,14102.695201409477,69670.95850947798]],"n":17}}}
{"case":"source-file-corner_box-edge13","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,12,18,8],"mass_status":[0],"result_topology":{"blocks":[[283080,35781316],[90446,2972660]],"n":332}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[364.2272493659107,456.1703547750584,456.1703547750584,-9.947321904359725,-10.031886995544761,3.4632073811926407,54564.45819588373,57014.224249506144,96963.37009574973,-15890.521086233734,-15777.413878347905,45467.75008941774],"result_geometry":{"blocks":[[-664.9428242630895,1163.5703196410234,-70994.08315622927],[-381.64930763461274,1069.8322420370655,-56767.527443859675],[-7.374517673164047,17.516115097495174,-11.62494518930691]],"n":516},"selected_edge_before":{"blocks":[[14020.825764045085,14108.501160624766,69909.54567576876]],"n":17}}}
{"case":"source-file-corner_box-edge13","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,12,18,8],"mass_status":[0],"result_topology":{"blocks":[[283080,35781316],[90446,2972660]],"n":332}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[364.2272506060781,456.17035825951467,456.17035825951467,-9.947321901583718,-10.031886975139605,3.4632073948675517,54564.458488912154,57014.224669164774,96963.37060900849,-15890.52122097045,-15777.414053765477,45467.75033520464],"result_geometry":{"blocks":[[-664.9428545349724,1163.5702893691405,-70994.08448819212],[-381.6486986136518,1069.8328636887682,-56767.47473665325],[-7.374517673164047,17.516115097495174,-11.62494518930691]],"n":516},"selected_edge_before":{"blocks":[[14020.825764045085,14108.501160624766,69909.54567576876]],"n":17}}}
{"case":"source-file-corner_box-edge4","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,12,18,8],"mass_status":[0],"result_topology":{"blocks":[[283069,35773881],[90418,3002127]],"n":332}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[363.983592467881,456.158425559022,456.158425559022,-9.947162230434246,-10.03188164306579,3.4631120134445137,54562.57868783208,57010.62677367141,96959.09307670097,-15889.657938087537,-15776.06728754059,45465.81580871488],"result_geometry":{"blocks":[[-581.0714000830117,1110.116690880621,-55656.65675254168],[-638.009140251699,1236.0316155507205,-79701.07828505017],[-19.948053282455803,33.9417524941619,-37.52240735320551]],"n":516},"selected_edge_before":{"blocks":[[13960.02,14113.98,69472.28]],"n":17}}}
{"case":"source-file-corner_box-edge8","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,12,18,8],"mass_status":[0],"result_topology":{"blocks":[[283047,35769331],[90438,3032180]],"n":332}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[363.98359210162636,456.1584212419636,456.1584212419636,-9.947471417717937,-10.03188164336174,3.463308325646969,54563.20501587127,57014.04556590021,96961.88465148144,-15890.553283217172,-15777.447269205213,45467.22576310702],"result_geometry":{"blocks":[[-648.6341095132417,1201.6219814503913,-64987.67663951199],[-516.5702058831656,913.1039541801722,-72525.76861829401],[-12.708053282455813,12.858247505838145,-33.64591234152929]],"n":516},"selected_edge_before":{"blocks":[[13977.580000000002,14062.419999999998,69553.32]],"n":17}}}
{"case":"source-file-corner_box-edge9","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,12,18,8],"mass_status":[0],"result_topology":{"blocks":[[283047,35771705],[90442,3152895]],"n":332}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[364.0659464915135,456.16248932760504,456.16248932760504,-9.947422146044385,-10.031863071812262,3.4631433392357085,54563.03450950577,57013.69630442404,96962.22254136101,-15889.883349628268,-15777.176745516368,45467.36878614208],"result_geometry":{"blocks":[[-649.5885887174849,1142.8199107816008,-67345.77311642219],[-439.7115565364036,1071.8016505066296,-62451.94824216498],[-7.269913067113686,21.26361227881965,-10.337792483796804]],"n":516},"selected_edge_before":{"blocks":[[13996.453421716695,14087.546578283305,69794.86496653156]],"n":17}}}
@@ -646,7 +645,7 @@
{"case":"source-file-l_shaped_box-edge9","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,14,21,9],"mass_status":[0],"result_topology":{"blocks":[[281068,35288477],[149719,9044585]],"n":386}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[349.7811062317758,374.98927015385635,374.98927015385635,4.166500389217454,4.166785251797895,2.49999999920373,12499.910574002057,12498.842367350786,18748.931775107827,3906.24940098058,3905.9823485919383,5468.747607060301],"result_geometry":{"blocks":[[508.37637999999987,838.5763799999996,70854.33892],[459.8262599999998,859.6262599999995,42972.407166245626],[165.71995834998762,275.7199583499875,7724.274577487095]],"n":596},"selected_edge_before":{"blocks":[[14061.85,14061.85,70510.25]],"n":17}}}
{"case":"source-file-nurb_box-all-edges","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,24,48,26],"mass_status":[0],"result_topology":{"blocks":[[282226,35421086],[282589,36601181],[339410,48660087],[166265,10478814]],"n":896}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[565.6943113580346,899.6446846812103,899.6446846812103,5.713967038727894,5.01271209885463,5.000000014944847,58797.9919009819,66936.65703049491,65763.8079687946,22548.29909362344,25702.700376835124,26594.84197423397],"result_geometry":{"blocks":[[903.3411763052158,903.3916875552603,101831.8108836121],[997.6242345805495,997.6242345805495,119146.39005303221],[659.90400335089,659.90400335089,66738.41235240281],[794.2132823273336,838.7566169670148,91370.70001484721],[838.5989483337613,849.5495481979834,104789.38471239748],[430.7902027950342,430.7902027950342,34116.777710186456]],"n":1428},"selected_edge_before":{"blocks":[[169032.6654823264,169043.61886874458,16648301.88372158]],"n":204}}}
{"case":"source-file-nurb_box-edge0","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,10,15,7],"mass_status":[0],"result_topology":{"blocks":[[301253,40025295],[15109,181353]],"n":278}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[572.4611287528566,899.9779678007586,899.9779678007586,5.712886504074863,5.013361304656215,4.999877774324869,58830.753877779935,66957.11900233416,65792.26914757398,22558.527569030848,25706.812795760317,26599.28819472051],"result_geometry":{"blocks":[[929.2194676026754,929.2222541565895,118180.13714103615],[700.4080540822067,755.9019885861094,64020.31462765113]],"n":436},"selected_edge_before":{"blocks":[[14104.996570127067,14115.94716999129,71057.26314783939]],"n":17}}}
{"case":"source-file-nurb_box-edge5","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,10,15,7],"mass_status":[0],"result_topology":{"blocks":[[301286,40027343],[15099,181228]],"n":278}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[569.7588850791489,899.8472765073033,899.8472765073033,5.7138219088686375,5.012641741714142,4.999999933671896,58814.88347910324,66954.96057370566,65780.02681269194,22553.057774592267,25707.83554508174,26600.199116965323],"result_geometry":{"blocks":[[898.0602577914484,909.2865639640687,110212.47341333186],[582.8805059244625,638.3744404283655,52037.96804120446]],"n":436},"selected_edge_before":{"blocks":[[14069.7,14069.7,70653.50000000001]],"n":17}}}
{"case":"source-file-nurb_box-edge5","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,10,15,7],"mass_status":[0],"result_topology":{"blocks":[[301286,40027343],[15099,181228]],"n":278}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[569.7588916871713,899.8473095474152,899.8473095474152,5.713821704540132,5.012641919137385,4.999999933671881,58814.887782726066,66954.96167584042,65780.03001577573,22553.05940109776,25707.83556963998,26600.199165865935],"result_geometry":{"blocks":[[898.0601641169002,909.2864702895205,110212.47022839721],[582.8843327904801,638.3782672943831,52038.08527198644]],"n":436},"selected_edge_before":{"blocks":[[14069.7,14069.7,70653.50000000001]],"n":17}}}
{"case":"source-file-rollover_corner-all-edges","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1007,8,13,8],"mass_status":[0],"result_topology":{"blocks":[[303125,39214224]],"n":246}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[59976.30307521032,722078.2000379532,722078.2000379532,10.540752583281975,-13.778401533609816,18.995464529867505,1140089817.7788453,2517103972.440378,2923125629.5269446,-192153882.8381955,184340650.93294954,-316935712.89333946],"result_geometry":{"blocks":[[2825.108377907571,6355.055184388725,417585.2368753811],[1827.981803796895,4629.830501917736,170216.6812474922]],"n":410},"selected_edge_before":{"blocks":[[185160.28379451932,188092.0097841937,19878878.33564891]],"n":221}}}
{"case":"stubs3-overhang-union-nx1-multi-neighbour-end-face-edge12-r0.5","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,18,28,12],"mass_status":[0],"result_topology":{"blocks":[[281021,35286730],[293739,38200282],[28,30]],"n":514}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[1360.0,2600.0,2600.0,10.0,4.076923076923075,7.3076923076923075,275733.3333333333,538333.3333333334,400733.33333333326,58999.99999999996,190000.0,105999.99999999993],"result_geometry":{"blocks":[[1256.5502899999997,1272.5502899999997,154725.82477000004],[1116.51014,1155.51014,152504.73848000006],[1283.6801400000004,1322.6401399999997,162081.61791999996],[144.02001,153.98001000000002,2033.6200699999997]],"n":792},"selected_edge_before":{"blocks":[[14064.85,14064.85,70559.55]],"n":17}}}
{"case":"stubs3-overhang-union-nx1-multi-neighbour-end-face-edge12-r1.0","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,18,28,12],"mass_status":[0],"result_topology":{"blocks":[[281021,35286730],[293739,38200282],[28,30]],"n":514}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[1360.0,2600.0,2600.0,10.0,4.076923076923075,7.3076923076923075,275733.3333333333,538333.3333333334,400733.33333333326,58999.99999999996,190000.0,105999.99999999993],"result_geometry":{"blocks":[[1256.5502899999997,1272.5502899999997,154725.82477000004],[1116.51014,1155.51014,152504.73848000006],[1283.6801400000004,1322.6401399999997,162081.61791999996],[144.02001,153.98001000000002,2033.6200699999997]],"n":792},"selected_edge_before":{"blocks":[[14064.85,14064.85,70559.55]],"n":17}}}
@@ -660,12 +659,12 @@
{"case":"stubs3-overhang-union-nx1-multi-neighbour-end-face-edge16-r0.5","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,18,28,12],"mass_status":[0],"result_topology":{"blocks":[[281021,35286730],[293739,38200282],[28,30]],"n":514}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[1360.0,2600.0,2600.0,10.0,4.076923076923075,7.3076923076923075,275733.3333333333,538333.3333333334,400733.33333333326,58999.99999999996,190000.0,105999.99999999993],"result_geometry":{"blocks":[[1256.5502899999997,1272.5502899999997,154725.82477000004],[1116.51014,1155.51014,152432.73848000006],[1285.6801400000004,1324.6401399999997,162101.61791999996],[144.02001,153.98001000000002,2033.6200699999997]],"n":792},"selected_edge_before":{"blocks":[[14115.48,14115.48,71053.31999999999]],"n":17}}}
{"case":"stubs3-overhang-union-nx1-multi-neighbour-end-face-edge16-r1.0","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,18,28,12],"mass_status":[0],"result_topology":{"blocks":[[281021,35286730],[293739,38200282],[28,30]],"n":514}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[1360.0,2600.0,2600.0,10.0,4.076923076923075,7.3076923076923075,275733.3333333333,538333.3333333334,400733.33333333326,58999.99999999996,190000.0,105999.99999999993],"result_geometry":{"blocks":[[1256.5502899999997,1272.5502899999997,154725.82477000004],[1116.51014,1155.51014,152432.73848000006],[1285.6801400000004,1324.6401399999997,162101.61791999996],[144.02001,153.98001000000002,2033.6200699999997]],"n":792},"selected_edge_before":{"blocks":[[14115.48,14115.48,71053.31999999999]],"n":17}}}
{"case":"stubs3-overhang-union-nx1-multi-neighbour-end-face-edge16-r2.0","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,18,28,12],"mass_status":[0],"result_topology":{"blocks":[[281021,35286730],[293739,38200282],[28,30]],"n":514}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[1360.0,2600.0,2600.0,10.0,4.076923076923075,7.3076923076923075,275733.3333333333,538333.3333333334,400733.33333333326,58999.99999999996,190000.0,105999.99999999993],"result_geometry":{"blocks":[[1256.5502899999997,1272.5502899999997,154725.82477000004],[1116.51014,1155.51014,152432.73848000006],[1285.6801400000004,1324.6401399999997,162101.61791999996],[144.02001,153.98001000000002,2033.6200699999997]],"n":792},"selected_edge_before":{"blocks":[[14115.48,14115.48,71053.31999999999]],"n":17}}}
{"case":"stubs3-overhang-union-nx1-multi-neighbour-end-face-edge17-r0.5","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,18,28,12],"mass_status":[0],"result_topology":{"blocks":[[281021,35286730],[293739,38200282],[28,30]],"n":514}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[1360.0,2600.0,2600.0,10.0,4.076923076923075,7.3076923076923075,275733.3333333333,538333.3333333334,400733.33333333326,58999.99999999996,190000.0,105999.99999999993],"result_geometry":{"blocks":[[1256.5502899999997,1272.5502899999997,154725.82477000004],[1118.51014,1157.51014,152748.73848000006],[1284.6801400000004,1323.6401399999997,162145.61791999996],[144.02001,153.98001000000002,2033.6200699999997]],"n":792},"selected_edge_before":{"blocks":[[14101.74,14108.26,70928.16]],"n":17}}}
{"case":"stubs3-overhang-union-nx1-multi-neighbour-end-face-edge17-r1.0","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,18,28,12],"mass_status":[0],"result_topology":{"blocks":[[281021,35286730],[293739,38200282],[28,30]],"n":514}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[1360.0,2600.0,2600.0,10.0,4.076923076923075,7.3076923076923075,275733.3333333333,538333.3333333334,400733.33333333326,58999.99999999996,190000.0,105999.99999999993],"result_geometry":{"blocks":[[1256.5502899999997,1272.5502899999997,154725.82477000004],[1118.51014,1157.51014,152748.73848000006],[1284.6801400000004,1323.6401399999997,162145.61791999996],[144.02001,153.98001000000002,2033.6200699999997]],"n":792},"selected_edge_before":{"blocks":[[14101.74,14108.26,70928.16]],"n":17}}}
{"case":"stubs3-overhang-union-nx1-multi-neighbour-end-face-edge17-r2.0","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,18,28,12],"mass_status":[0],"result_topology":{"blocks":[[281021,35286730],[293739,38200282],[28,30]],"n":514}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[1360.0,2600.0,2600.0,10.0,4.076923076923075,7.3076923076923075,275733.3333333333,538333.3333333334,400733.33333333326,58999.99999999996,190000.0,105999.99999999993],"result_geometry":{"blocks":[[1256.5502899999997,1272.5502899999997,154725.82477000004],[1118.51014,1157.51014,152748.73848000006],[1284.6801400000004,1323.6401399999997,162145.61791999996],[144.02001,153.98001000000002,2033.6200699999997]],"n":792},"selected_edge_before":{"blocks":[[14101.74,14108.26,70928.16]],"n":17}}}
{"case":"stubs3-overhang-union-nx1-multi-neighbour-end-face-edge19-r0.5","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,18,28,12],"mass_status":[0],"result_topology":{"blocks":[[281021,35286730],[293739,38200282],[28,30]],"n":514}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[1360.0,2600.0,2600.0,10.0,4.076923076923075,7.3076923076923075,275733.3333333333,538333.3333333334,400733.33333333326,58999.99999999996,190000.0,105999.99999999993],"result_geometry":{"blocks":[[1256.5502899999997,1272.5502899999997,154725.82477000004],[1119.51014,1158.51014,153014.73848000006],[1283.6801400000004,1322.6401399999997,162081.61791999996],[144.02001,153.98001000000002,2033.6200699999997]],"n":792},"selected_edge_before":{"blocks":[[14073.74,14080.26,70600.16]],"n":17}}}
{"case":"stubs3-overhang-union-nx1-multi-neighbour-end-face-edge19-r1.0","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,18,28,12],"mass_status":[0],"result_topology":{"blocks":[[281021,35286730],[293739,38200282],[28,30]],"n":514}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[1360.0,2600.0,2600.0,10.0,4.076923076923075,7.3076923076923075,275733.3333333333,538333.3333333334,400733.33333333326,58999.99999999996,190000.0,105999.99999999993],"result_geometry":{"blocks":[[1256.5502899999997,1272.5502899999997,154725.82477000004],[1119.51014,1158.51014,153014.73848000006],[1283.6801400000004,1322.6401399999997,162081.61791999996],[144.02001,153.98001000000002,2033.6200699999997]],"n":792},"selected_edge_before":{"blocks":[[14073.74,14080.26,70600.16]],"n":17}}}
{"case":"stubs3-overhang-union-nx1-multi-neighbour-end-face-edge19-r2.0","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,18,28,12],"mass_status":[0],"result_topology":{"blocks":[[281021,35286730],[293739,38200282],[28,30]],"n":514}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[1360.0,2600.0,2600.0,10.0,4.076923076923075,7.3076923076923075,275733.3333333333,538333.3333333334,400733.33333333326,58999.99999999996,190000.0,105999.99999999993],"result_geometry":{"blocks":[[1256.5502899999997,1272.5502899999997,154725.82477000004],[1119.51014,1158.51014,153014.73848000006],[1283.6801400000004,1322.6401399999997,162081.61791999996],[144.02001,153.98001000000002,2033.6200699999997]],"n":792},"selected_edge_before":{"blocks":[[14073.74,14080.26,70600.16]],"n":17}}}
{"case":"stubs3-overhang-union-nx1-multi-neighbour-end-face-edge17-r0.5","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,18,28,12],"mass_status":[0],"result_topology":{"blocks":[[281021,35286730],[293739,38200282],[28,30]],"n":514}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[1360.0,2600.0,2600.0,10.0,4.076923076923075,7.3076923076923075,275733.3333333333,538333.3333333334,400733.33333333326,58999.99999999996,190000.0,105999.99999999993],"result_geometry":{"blocks":[[1256.5502899999997,1272.5502899999997,154725.82477000004],[1119.51014,1158.51014,152924.73848000006],[1286.6801400000004,1325.64014,162201.61791999996],[144.02001,153.98001000000002,2033.6200699999997]],"n":792},"selected_edge_before":{"blocks":[[14101.74,14108.26,70928.16]],"n":17}}}
{"case":"stubs3-overhang-union-nx1-multi-neighbour-end-face-edge17-r1.0","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,18,28,12],"mass_status":[0],"result_topology":{"blocks":[[281021,35286730],[293739,38200282],[28,30]],"n":514}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[1360.0,2600.0,2600.0,10.0,4.076923076923075,7.3076923076923075,275733.3333333333,538333.3333333334,400733.33333333326,58999.99999999996,190000.0,105999.99999999993],"result_geometry":{"blocks":[[1256.5502899999997,1272.5502899999997,154725.82477000004],[1119.51014,1158.51014,152924.73848000006],[1286.6801400000004,1325.64014,162201.61791999996],[144.02001,153.98001000000002,2033.6200699999997]],"n":792},"selected_edge_before":{"blocks":[[14101.74,14108.26,70928.16]],"n":17}}}
{"case":"stubs3-overhang-union-nx1-multi-neighbour-end-face-edge17-r2.0","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,18,28,12],"mass_status":[0],"result_topology":{"blocks":[[281021,35286730],[293739,38200282],[28,30]],"n":514}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[1360.0,2600.0,2600.0,10.0,4.076923076923075,7.3076923076923075,275733.3333333333,538333.3333333334,400733.33333333326,58999.99999999996,190000.0,105999.99999999993],"result_geometry":{"blocks":[[1256.5502899999997,1272.5502899999997,154725.82477000004],[1119.51014,1158.51014,152924.73848000006],[1286.6801400000004,1325.64014,162201.61791999996],[144.02001,153.98001000000002,2033.6200699999997]],"n":792},"selected_edge_before":{"blocks":[[14101.74,14108.26,70928.16]],"n":17}}}
{"case":"stubs3-overhang-union-nx1-multi-neighbour-end-face-edge19-r0.5","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,18,28,12],"mass_status":[0],"result_topology":{"blocks":[[281021,35286730],[293739,38200282],[28,30]],"n":514}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[1360.0,2600.0,2600.0,10.0,4.076923076923075,7.3076923076923075,275733.3333333333,538333.3333333334,400733.33333333326,58999.99999999996,190000.0,105999.99999999993],"result_geometry":{"blocks":[[1256.5502899999997,1272.5502899999997,154725.82477000004],[1121.51014,1160.51014,153294.73848000006],[1286.6801400000004,1325.64014,162201.61791999996],[144.02001,153.98001000000002,2033.6200699999997]],"n":792},"selected_edge_before":{"blocks":[[14073.74,14080.26,70600.16]],"n":17}}}
{"case":"stubs3-overhang-union-nx1-multi-neighbour-end-face-edge19-r1.0","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,18,28,12],"mass_status":[0],"result_topology":{"blocks":[[281021,35286730],[293739,38200282],[28,30]],"n":514}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[1360.0,2600.0,2600.0,10.0,4.076923076923075,7.3076923076923075,275733.3333333333,538333.3333333334,400733.33333333326,58999.99999999996,190000.0,105999.99999999993],"result_geometry":{"blocks":[[1256.5502899999997,1272.5502899999997,154725.82477000004],[1121.51014,1160.51014,153294.73848000006],[1286.6801400000004,1325.64014,162201.61791999996],[144.02001,153.98001000000002,2033.6200699999997]],"n":792},"selected_edge_before":{"blocks":[[14073.74,14080.26,70600.16]],"n":17}}}
{"case":"stubs3-overhang-union-nx1-multi-neighbour-end-face-edge19-r2.0","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,18,28,12],"mass_status":[0],"result_topology":{"blocks":[[281021,35286730],[293739,38200282],[28,30]],"n":514}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[1360.0,2600.0,2600.0,10.0,4.076923076923075,7.3076923076923075,275733.3333333333,538333.3333333334,400733.33333333326,58999.99999999996,190000.0,105999.99999999993],"result_geometry":{"blocks":[[1256.5502899999997,1272.5502899999997,154725.82477000004],[1121.51014,1160.51014,153294.73848000006],[1286.6801400000004,1325.64014,162201.61791999996],[144.02001,153.98001000000002,2033.6200699999997]],"n":792},"selected_edge_before":{"blocks":[[14073.74,14080.26,70600.16]],"n":17}}}
{"case":"stubs3-overhang-union-nx1-multi-neighbour-end-face-edge9-r0.5","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,18,28,12],"mass_status":[0],"result_topology":{"blocks":[[281021,35286730],[293739,38200282],[28,30]],"n":514}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[1360.0,2600.0,2600.0,10.0,4.076923076923075,7.3076923076923075,275733.3333333333,538333.3333333334,400733.33333333326,58999.99999999996,190000.0,105999.99999999993],"result_geometry":{"blocks":[[1256.5502899999997,1272.5502899999997,154725.82477000004],[1116.51014,1155.51014,152432.73848000006],[1283.6801400000004,1322.6401399999997,162081.61791999996],[144.02001,153.98001000000002,2033.6200699999997]],"n":792},"selected_edge_before":{"blocks":[[14136.85,14136.85,71126.55]],"n":17}}}
{"case":"stubs3-overhang-union-nx1-multi-neighbour-end-face-edge9-r1.0","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,18,28,12],"mass_status":[0],"result_topology":{"blocks":[[281021,35286730],[293739,38200282],[28,30]],"n":514}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[1360.0,2600.0,2600.0,10.0,4.076923076923075,7.3076923076923075,275733.3333333333,538333.3333333334,400733.33333333326,58999.99999999996,190000.0,105999.99999999993],"result_geometry":{"blocks":[[1256.5502899999997,1272.5502899999997,154725.82477000004],[1116.51014,1155.51014,152432.73848000006],[1283.6801400000004,1322.6401399999997,162081.61791999996],[144.02001,153.98001000000002,2033.6200699999997]],"n":792},"selected_edge_before":{"blocks":[[14136.85,14136.85,71126.55]],"n":17}}}
{"case":"stubs3-overhang-union-nx1-multi-neighbour-end-face-edge9-r2.0","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,18,28,12],"mass_status":[0],"result_topology":{"blocks":[[281021,35286730],[293739,38200282],[28,30]],"n":514}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[1360.0,2600.0,2600.0,10.0,4.076923076923075,7.3076923076923075,275733.3333333333,538333.3333333334,400733.33333333326,58999.99999999996,190000.0,105999.99999999993],"result_geometry":{"blocks":[[1256.5502899999997,1272.5502899999997,154725.82477000004],[1116.51014,1155.51014,152432.73848000006],[1283.6801400000004,1322.6401399999997,162081.61791999996],[144.02001,153.98001000000002,2033.6200699999997]],"n":792},"selected_edge_before":{"blocks":[[14136.85,14136.85,71126.55]],"n":17}}}
@@ -687,14 +686,14 @@
{"case":"stubs3-union-inset-side-step-edges14-18-r1","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,24,37,15],"mass_status":[0],"result_topology":{"blocks":[[281056,35289640],[284861,37175483],[181588,15482546]],"n":676}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[1254.9607549820776,2602.865112334212,2602.865112334212,10.005746974849712,5.617671762969949,6.541395558326957,259574.37164218113,484247.20406901406,439988.2637119952,102195.48149883584,170401.3372400946,146335.45679332208],"result_geometry":{"blocks":[[1379.7805400000002,1379.7805400000002,160263.72484999997],[1205.63015,1205.83015,166710.25935],[1576.719906362974,1576.719906362974,196238.60222964824],[1280.4432346184394,1342.9432346184394,176026.89946556705],[65.32963269221808,65.32963269221808,305.43284887561816]],"n":1032},"selected_edge_before":{"blocks":[[28246.11,28246.11,382576.94000000006]],"n":34}}}
{"case":"stubs3-union-inset-side-step-edges16-17-r1","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,24,37,15],"mass_status":[0],"result_topology":{"blocks":[[281117,35298145],[284838,37173051],[181588,14997215]],"n":676}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[1254.1023607787463,2603.294352389973,2603.294352389973,9.99769543760855,5.621213102977465,6.537353996483302,259590.96106096555,483705.38794386643,439736.335688461,102190.74609986568,170142.65403258588,146275.44802578553],"result_geometry":{"blocks":[[1337.15054,1337.15054,155841.24484999996],[1319.8851499999998,1320.1351499999998,185129.13934999995],[1241.1035754543243,1241.1035754543243,150547.64664998057],[1235.7899471859705,1304.8899471859709,163237.0127980429],[45.65311769881384,45.65311769881384,237.98758817186825]],"n":1032},"selected_edge_before":{"blocks":[[28200.149999999998,28200.149999999998,381471.6]],"n":34}}}
{"case":"stubs3-union-inset-side-step-edges16-18-r1","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,24,37,15],"mass_status":[0],"result_topology":{"blocks":[[281057,35290503],[284842,37170448],[181588,15809418]],"n":676}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[1254.1023610605782,2603.294358781255,2603.294358781255,10.00230461554488,5.62121307963151,6.53735400363592,259590.96106938046,483945.371292859,439976.3179308092,102190.74593132226,170230.4825780024,146397.99860124188],"result_geometry":{"blocks":[[1363.7805400000002,1363.7805400000002,158664.72484999997],[1261.9151499999998,1262.31515,177867.36435000002],[1435.9556244085259,1435.9556244085259,181486.25365849392],[1281.1652075800687,1347.7652075800686,174419.46355477662],[65.32963269221808,65.32963269221808,305.43284887561816]],"n":1032},"selected_edge_before":{"blocks":[[28232.45,28232.45,382342.20000000007]],"n":34}}}
{"case":"stubs3-union-inset-side-step-edges16-22-r1","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,20,30,12],"mass_status":[0],"result_topology":{"blocks":[[281013,35283637],[276706,34655270],[45373,682235]],"n":548}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[1260.0,2600.0,2600.0,10.0,5.615384615384614,6.538461538461538,259133.3333333333,483333.3333333333,439133.3333333333,102000.0,170000.0,145999.99999999997],"result_geometry":{"blocks":[[1317.5503,1317.5503,154679.4246],[1204.6401399999997,1204.6401399999997,164032.11708],[1383.4301499999997,1383.4301499999997,166962.79905000003],[425.15002999999996,425.15002999999996,14567.40099]],"n":836},"selected_edge_before":{"blocks":[[28218.04,28218.04,381759.6400000001]],"n":34}}}
{"case":"stubs3-union-inset-side-step-edges17-22-r1","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,20,30,12],"mass_status":[0],"result_topology":{"blocks":[[281013,35283637],[276706,34655270],[45373,682235]],"n":548}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[1260.0,2600.0,2600.0,10.0,5.615384615384614,6.538461538461538,259133.3333333333,483333.3333333333,439133.3333333333,102000.0,170000.0,145999.99999999997],"result_geometry":{"blocks":[[1317.5503,1317.5503,154679.4246],[1205.6401399999997,1205.6401399999997,164216.11708],[1382.4301499999997,1382.4301499999997,166944.79905000003],[425.15002999999996,425.15002999999996,14567.40099]],"n":836},"selected_edge_before":{"blocks":[[28209.59,28209.59,381709.99000000005]],"n":34}}}
{"case":"stubs3-union-inset-side-step-edges16-22-r1","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,20,30,12],"mass_status":[0],"result_topology":{"blocks":[[281013,35283637],[276706,34655270],[45373,682235]],"n":548}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[1260.0,2600.0,2600.0,10.0,5.615384615384614,6.538461538461538,259133.3333333333,483333.3333333333,439133.3333333333,102000.0,170000.0,145999.99999999997],"result_geometry":{"blocks":[[1317.5503,1317.5503,154679.4246],[1205.6401399999997,1205.6401399999997,164216.11708],[1386.43015,1386.43015,167124.79905000003],[425.15002999999996,425.15002999999996,14567.40099]],"n":836},"selected_edge_before":{"blocks":[[28218.04,28218.04,381759.6400000001]],"n":34}}}
{"case":"stubs3-union-inset-side-step-edges17-22-r1","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,20,30,12],"mass_status":[0],"result_topology":{"blocks":[[281013,35283637],[276706,34655270],[45373,682235]],"n":548}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[1260.0,2600.0,2600.0,10.0,5.615384615384614,6.538461538461538,259133.3333333333,483333.3333333333,439133.3333333333,102000.0,170000.0,145999.99999999997],"result_geometry":{"blocks":[[1317.5503,1317.5503,154679.4246],[1205.6401399999997,1205.6401399999997,164216.11708],[1386.43015,1386.43015,167124.79905000003],[425.15002999999996,425.15002999999996,14567.40099]],"n":836},"selected_edge_before":{"blocks":[[28209.59,28209.59,381709.99000000005]],"n":34}}}
{"case":"stubs3-union-overhang-corner-edges12-13-r1","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,18,28,12],"mass_status":[0],"result_topology":{"blocks":[[281023,35286268],[293738,38199925],[27,29]],"n":514}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[1376.0,2600.0,2600.0,8.384615384615385,4.076923076923075,7.3076923076923075,275733.3333333333,483733.3333333334,346133.33333333326,58999.99999999996,127000.0,101799.99999999991],"result_geometry":{"blocks":[[1184.6602899999998,1216.6602899999998,148214.94477],[926.40014,997.1601399999998,124260.35848],[1077.1601400000002,1144.7601399999999,137516.89791999996],[116.02001000000001,125.98001000000002,1627.62007]],"n":792},"selected_edge_before":{"blocks":[[28135.44,28135.44,380407.32]],"n":34}}}
{"case":"stubs3-union-overhang-corner-edges14-15-r1","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,18,28,12],"mass_status":[0],"result_topology":{"blocks":[[281023,35286268],[293738,38199925],[27,29]],"n":514}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[1376.0,2600.0,2600.0,8.384615384615385,4.076923076923075,7.3076923076923075,275733.3333333333,483733.3333333334,346133.33333333326,58999.99999999996,127000.0,101799.99999999991],"result_geometry":{"blocks":[[1184.6602899999998,1216.6602899999998,148214.94477],[928.40014,999.1601399999998,124720.35848],[1077.1601400000002,1144.7601399999999,137516.89791999996],[116.02001000000001,125.98001000000002,1627.62007]],"n":792},"selected_edge_before":{"blocks":[[28183.44,28183.44,381188.16]],"n":34}}}
{"case":"stubs3-union-overhang-corner-edges14-22-r1","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,18,28,12],"mass_status":[0],"result_topology":{"blocks":[[281023,35286268],[293738,38199925],[27,29]],"n":514}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[1376.0,2600.0,2600.0,8.384615384615385,4.076923076923075,7.3076923076923075,275733.3333333333,483733.3333333334,346133.33333333326,58999.99999999996,127000.0,101799.99999999991],"result_geometry":{"blocks":[[1184.6602899999998,1216.6602899999998,148214.94477],[927.40014,998.1601399999998,124688.35848],[1079.1601400000002,1146.7601399999999,137572.89791999996],[116.02001000000001,125.98001000000002,1627.62007]],"n":792},"selected_edge_before":{"blocks":[[28212.66,28212.66,381972.08]],"n":34}}}
{"case":"stubs3-union-overhang-corner-edges15-22-r1","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,18,28,12],"mass_status":[0],"result_topology":{"blocks":[[281023,35286268],[293738,38199925],[27,29]],"n":514}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[1376.0,2600.0,2600.0,8.384615384615385,4.076923076923075,7.3076923076923075,275733.3333333333,483733.3333333334,346133.33333333326,58999.99999999996,127000.0,101799.99999999991],"result_geometry":{"blocks":[[1184.6602899999998,1216.6602899999998,148214.94477],[927.40014,998.1601399999998,124580.35848],[1079.1601400000002,1146.7601399999999,137572.89791999996],[116.02001000000001,125.98001000000002,1627.62007]],"n":792},"selected_edge_before":{"blocks":[[28216.18,28216.18,382015.72000000003]],"n":34}}}
{"case":"stubs3-union-overhang-corner-edges14-22-r1","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,18,28,12],"mass_status":[0],"result_topology":{"blocks":[[281023,35286268],[293738,38199925],[27,29]],"n":514}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[1376.0,2600.0,2600.0,8.384615384615385,4.076923076923075,7.3076923076923075,275733.3333333333,483733.3333333334,346133.33333333326,58999.99999999996,127000.0,101799.99999999991],"result_geometry":{"blocks":[[1184.6602899999998,1216.6602899999998,148214.94477],[929.40014,1000.1601399999998,125004.35848],[1080.1601400000002,1147.7601399999999,137636.89791999996],[116.02001000000001,125.98001000000002,1627.62007]],"n":792},"selected_edge_before":{"blocks":[[28212.66,28212.66,381972.08]],"n":34}}}
{"case":"stubs3-union-overhang-corner-edges15-22-r1","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,18,28,12],"mass_status":[0],"result_topology":{"blocks":[[281023,35286268],[293738,38199925],[27,29]],"n":514}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[1376.0,2600.0,2600.0,8.384615384615385,4.076923076923075,7.3076923076923075,275733.3333333333,483733.3333333334,346133.33333333326,58999.99999999996,127000.0,101799.99999999991],"result_geometry":{"blocks":[[1184.6602899999998,1216.6602899999998,148214.94477],[929.40014,1000.1601399999998,124950.35848],[1080.1601400000002,1147.7601399999999,137636.89791999996],[116.02001000000001,125.98001000000002,1627.62007]],"n":792},"selected_edge_before":{"blocks":[[28216.18,28216.18,382015.72000000003]],"n":34}}}
{"case":"stubs3-union-overhang-front-edges14-15-r1","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,18,28,12],"mass_status":[0],"result_topology":{"blocks":[[281021,35286730],[293739,38200282],[28,30]],"n":514}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[1360.0,2600.0,2600.0,10.0,4.076923076923075,7.3076923076923075,275733.3333333333,538333.3333333334,400733.33333333326,58999.99999999996,190000.0,105999.99999999993],"result_geometry":{"blocks":[[1256.5502899999997,1272.5502899999997,154725.82477000004],[1117.51014,1156.51014,152734.73848000006],[1285.6801400000004,1324.6401399999997,162101.61791999996],[144.02001,153.98001000000002,2033.6200699999997]],"n":792},"selected_edge_before":{"blocks":[[28190.18,28190.18,381510.31999999995]],"n":34}}}
{"case":"stubs3-union-overhang-front-edges14-22-r1","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,18,28,12],"mass_status":[0],"result_topology":{"blocks":[[281021,35286730],[293739,38200282],[28,30]],"n":514}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[1360.0,2600.0,2600.0,10.0,4.076923076923075,7.3076923076923075,275733.3333333333,538333.3333333334,400733.33333333326,58999.99999999996,190000.0,105999.99999999993],"result_geometry":{"blocks":[[1256.5502899999997,1272.5502899999997,154725.82477000004],[1120.51014,1159.51014,153442.73848000006],[1283.6801400000004,1322.6401399999997,162081.61791999996],[144.02001,153.98001000000002,2033.6200699999997]],"n":792},"selected_edge_before":{"blocks":[[28197.18,28197.18,381663.72000000003]],"n":34}}}
{"case":"stubs3-union-overhang-front-edges14-22-r1","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,18,28,12],"mass_status":[0],"result_topology":{"blocks":[[281021,35286730],[293739,38200282],[28,30]],"n":514}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[1360.0,2600.0,2600.0,10.0,4.076923076923075,7.3076923076923075,275733.3333333333,538333.3333333334,400733.33333333326,58999.99999999996,190000.0,105999.99999999993],"result_geometry":{"blocks":[[1256.5502899999997,1272.5502899999997,154725.82477000004],[1121.51014,1160.51014,153582.73848000006],[1287.6801400000004,1326.64014,162211.61791999996],[144.02001,153.98001000000002,2033.6200699999997]],"n":792},"selected_edge_before":{"blocks":[[28197.18,28197.18,381663.72000000003]],"n":34}}}
{"case":"stubs3-union-overhang-front-edges15-16-r1","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,18,28,12],"mass_status":[0],"result_topology":{"blocks":[[281021,35286730],[293739,38200282],[28,30]],"n":514}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[1360.0,2600.0,2600.0,10.0,4.076923076923075,7.3076923076923075,275733.3333333333,538333.3333333334,400733.33333333326,58999.99999999996,190000.0,105999.99999999993],"result_geometry":{"blocks":[[1256.5502899999997,1272.5502899999997,154725.82477000004],[1117.51014,1156.51014,152662.73848000006],[1285.6801400000004,1324.6401399999997,162101.61791999996],[144.02001,153.98001000000002,2033.6200699999997]],"n":792},"selected_edge_before":{"blocks":[[28222.18,28222.18,381991.57999999996]],"n":34}}}
{"case":"stubs4-Heart-all-edges-r0.1","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,14,26,14],"mass_status":[0],"result_topology":{"blocks":[[281737,35365098],[295416,35149904]],"n":486}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[341.00305461458044,326.05802248658284,326.05802248658284,-0.04333396881304957,-2.5400257481565296,1.4999999973056695,5829.692509369144,4432.611755201721,8306.479082431522,-1242.2936597141088,-21.194074421043915,-0.11234678165543954],"result_geometry":{"blocks":[[26.803340595013452,568.056036137871,2971.8226614271207],[138.13394087019168,409.53123598152973,28655.61567725731],[54.07463694017612,557.3946077304216,11394.295597343118],[-16.32284748606198,23.52515333612606,-75.37077475844747]],"n":776},"selected_edge_before":{"blocks":[[84159.70543140007,84325.95274255969,3994513.133952511]],"n":102}}}
{"case":"stubs4-blade_hub-e13-r0.5","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,26,38,12],"mass_status":[1007],"result_topology":{"blocks":[[309560,38443985],[316103,39330976],[90813,2868792]],"n":588}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[],"result_geometry":{"blocks":[[96.95915602112353,304.44876579386323,10878.923281274361],[197.73624177468605,286.48891505225697,22246.937573391897],[174.3952617567553,284.582713318473,12670.807139693003],[95.00859139076509,214.62402605591367,10169.539988509488]],"n":1004},"selected_edge_before":{"blocks":[[14062.0744632926,14064.875069357513,70348.00893265601]],"n":17}}}
@@ -708,18 +707,18 @@
{"case":"stubs4-degenerate-bottle-e10-r0.5","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,26,40,16],"mass_status":[0],"result_topology":{"blocks":[[281457,35341216],[282271,36580789],[241977,24565779]],"n":730}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[33.11819078265203,11.06683396778218,11.06683396778218,-1.760928723326559e-6,-3.0260239843351257e-6,2.0788625844461937,64.79258473459024,66.6733018328832,5.277123465358535,-0.00010373432038354095,-0.00006130940949992112,0.000020822473328764406],"result_geometry":{"blocks":[[912.7406198383134,996.1574227558623,139865.57295882053],[1710.5690534181747,1900.7696584750158,195545.28934387196],[536.122128285832,587.7649824357395,53296.94403726827],[1116.695548284241,1296.7760762038654,136279.5389856879],[81.3031298885769,99.10219410214427,4292.377944642321]],"n":1112},"selected_edge_before":{"blocks":[[14124.027919677248,14129.830196394449,70404.16195467954]],"n":17}}}
{"case":"stubs4-degenerate-bottle-e13-r0.5","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,26,40,16],"mass_status":[0],"result_topology":{"blocks":[[281457,35341216],[282271,36580789],[241977,24565779]],"n":730}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[33.11819078265203,11.06683396778218,11.06683396778218,-1.760928723326559e-6,-3.0260239843351257e-6,2.0788625844461937,64.79258473459024,66.6733018328832,5.277123465358535,-0.00010373432038354095,-0.00006130940949992112,0.000020822473328764406],"result_geometry":{"blocks":[[912.7406198383134,996.1574227558623,139865.57295882053],[1710.5690534181747,1900.7696584750158,195545.28934387196],[536.122128285832,587.7649824357395,53296.94403726827],[1116.695548284241,1296.7760762038654,136279.5389856879],[81.3031298885769,99.10219410214427,4292.377944642321]],"n":1112},"selected_edge_before":{"blocks":[[14127.137890774764,14132.830196425228,70408.49505041902]],"n":17}}}
{"case":"stubs4-degenerate-bottle-e2-r0.5","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,26,40,16],"mass_status":[0],"result_topology":{"blocks":[[281457,35341216],[282271,36580789],[241977,24565779]],"n":730}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[33.11819078265203,11.06683396778218,11.06683396778218,-1.760928723326559e-6,-3.0260239843351257e-6,2.0788625844461937,64.79258473459024,66.6733018328832,5.277123465358535,-0.00010373432038354095,-0.00006130940949992112,0.000020822473328764406],"result_geometry":{"blocks":[[912.7406198383134,996.1574227558623,139865.57295882053],[1710.5690534181747,1900.7696584750158,195545.28934387196],[536.122128285832,587.7649824357395,53296.94403726827],[1116.695548284241,1296.7760762038654,136279.5389856879],[81.3031298885769,99.10219410214427,4292.377944642321]],"n":1112},"selected_edge_before":{"blocks":[[14121.830195910168,14121.830195910168,70458.47793958586]],"n":17}}}
{"case":"stubs4-degenerate-brepForFillet2-e5-r0.5","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,11,17,8],"mass_status":[0],"result_topology":{"blocks":[[284319,36121624],[75249,2183309]],"n":315}},"topology":null,"values":{"fillet_point_step":[0.001],"mass_properties":[1440.2511996650014,3616.2280220562025,3616.2280220562025,3.4572522748046746,6.96874549228937,11.462739999314897,855608.6386815243,741301.669406042,324387.4096625861,303890.9415636773,98588.81658529793,79222.61281029524],"result_geometry":{"blocks":[[977.9608984708158,1132.1585928908567,112679.82119098869],[1036.8272771466466,1132.6767094240176,128906.90468346755]],"n":494},"selected_edge_before":{"blocks":[[14104.237249363965,14104.237249363965,70989.17788508131]],"n":17}}}
{"case":"stubs4-degenerate-brepForFillet2-e7-r0.5","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,11,17,8],"mass_status":[0],"result_topology":{"blocks":[[284315,36028144],[75276,1943882]],"n":315}},"topology":null,"values":{"fillet_point_step":[0.001],"mass_properties":[1434.446813164844,3614.981530005013,3614.981530005013,3.4584871444027425,6.968101813802694,11.45680832778133,854576.7185460968,740358.8792442408,324305.3758619639,303605.7773882215,98562.20533431886,79209.84256232821],"result_geometry":{"blocks":[[914.9820844486778,1052.869998903444,105507.89478294902],[1124.5291907867822,1268.0925544771662,136640.38485087125]],"n":494},"selected_edge_before":{"blocks":[[14135.395411755704,14135.395411755704,71369.33404886544]],"n":17}}}
{"case":"stubs4-degenerate-brepForFillet2-e9-r0.5","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,11,17,8],"mass_status":[0],"result_topology":{"blocks":[[284315,36122025],[75252,2183684]],"n":315}},"topology":null,"values":{"fillet_point_step":[0.001],"mass_properties":[1440.2671115013059,3616.2323751508984,3616.2323751508984,3.4572615358535645,6.968145280660813,11.462733703496507,855582.2394479593,741302.3756518327,324361.4475208473,303878.3631816101,98589.1192548503,79198.80899947563],"result_geometry":{"blocks":[[941.8465165097493,1095.7344309645155,106272.86754210842],[1191.512938604236,1287.07630229462,145508.029385938]],"n":494},"selected_edge_before":{"blocks":[[14144.237249363965,14144.237249363965,71425.17788508131]],"n":17}}}
{"case":"stubs4-degenerate-caps_coons-e5-r0.5","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,9,13,5],"mass_status":[1007],"result_topology":{"blocks":[[258037,28685683]],"n":231}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[],"result_geometry":{"blocks":[[143.0401012469903,605.3942128690559,29578.99054563839],[243.63028218245358,825.498020792821,17264.887226412124]],"n":360},"selected_edge_before":{"blocks":[[14037.1094889089,14070.282001512544,70183.14505475634]],"n":17}}}
{"case":"stubs4-degenerate-nurb_cone-e1-r0.5","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,16,24,10],"mass_status":[0],"result_topology":{"blocks":[[281552,35353171],[207130,17929604]],"n":440}},"topology":null,"values":{"fillet_point_step":[0.001],"mass_properties":[314.8325246121948,213.7213448689033,213.7213448689033,-25.256791575512928,-20.641446371057185,-48.78070940849276,602531.7041465972,647001.3562174569,230178.1359116786,215876.09028929376,263548.4756783311,111869.03168332015],"result_geometry":{"blocks":[[-4492.250713961271,4649.51618583184,-535943.3213095476],[-4052.741456601031,4286.165134468015,-516235.4603248068],[-2714.7015550832602,2771.3320313018985,-230085.89935783745]],"n":676},"selected_edge_before":{"blocks":[[13749.737417808685,14322.262582191315,66614.77086913426]],"n":17}}}
{"case":"stubs4-degenerate-brepForFillet2-e5-r0.5","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,11,17,8],"mass_status":[0],"result_topology":{"blocks":[[284319,36121624],[75249,2183309]],"n":315}},"topology":null,"values":{"fillet_point_step":[0.001],"mass_properties":[1440.251382399228,3616.2287392776343,3616.2287392776343,3.4572511465510822,6.968744461180699,11.462741043541195,855608.855668429,741301.9055838867,324387.43394161284,303890.9644437594,98588.77681659971,79222.607589154],"result_geometry":{"blocks":[[977.9593770006319,1132.1570714206728,112679.78113225622],[1036.8269527019722,1132.676977089866,128906.89583019743]],"n":494},"selected_edge_before":{"blocks":[[14104.237249363965,14104.237249363965,70989.17788508131]],"n":17}}}
{"case":"stubs4-degenerate-brepForFillet2-e7-r0.5","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,11,17,8],"mass_status":[0],"result_topology":{"blocks":[[284315,36028144],[75276,1943882]],"n":315}},"topology":null,"values":{"fillet_point_step":[0.001],"mass_properties":[1434.4468178092154,3614.981530019566,3614.981530019566,3.4584871443580627,6.968101813879907,11.456808327808165,854576.7185569978,740358.879251663,324305.3758709199,303605.77739610383,98562.20533199854,79209.84255974233],"result_geometry":{"blocks":[[914.9820844486778,1052.869998903444,105507.89478294902],[1124.5310920443023,1268.0944557346863,136640.50315810967]],"n":494},"selected_edge_before":{"blocks":[[14135.395411755704,14135.395411755704,71369.33404886544]],"n":17}}}
{"case":"stubs4-degenerate-brepForFillet2-e9-r0.5","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,11,17,8],"mass_status":[0],"result_topology":{"blocks":[[284315,36122025],[75252,2183684]],"n":315}},"topology":null,"values":{"fillet_point_step":[0.001],"mass_properties":[1440.2672883975677,3616.2328421904776,3616.2328421904776,3.4572612606052133,6.9681461322979805,11.462734289594529,855582.4555680463,741302.518071291,324361.5460918078,303878.46584145265,98589.12059706918,79198.81581812014],"result_geometry":{"blocks":[[941.8468663093593,1095.7347807641254,106272.87711605163],[1191.514712250541,1287.078075940925,145508.17923556283]],"n":494},"selected_edge_before":{"blocks":[[14144.237249363965,14144.237249363965,71425.17788508131]],"n":17}}}
{"case":"stubs4-degenerate-caps_coons-e5-r0.5","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,5,6,2],"mass_status":[1007],"result_topology":{"blocks":[[114369,5170962]],"n":103}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[],"result_geometry":{"blocks":[[33.20006041930303,362.35023081673893,6668.477882377478]],"n":164},"selected_edge_before":{"blocks":[[14037.1094889089,14070.282001512544,70183.14505475634]],"n":17}}}
{"case":"stubs4-degenerate-nurb_cone-e1-r0.5","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,16,24,10],"mass_status":[0],"result_topology":{"blocks":[[281552,35353171],[207130,17929604]],"n":440}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[314.8325246121948,213.7213448689033,213.7213448689033,-25.256791575512928,-20.641446371057185,-48.78070940849276,602531.7041465972,647001.3562174569,230178.1359116786,215876.09028929376,263548.4756783311,111869.03168332015],"result_geometry":{"blocks":[[-4492.250713961271,4649.51618583184,-535943.3213095476],[-4052.741456601031,4286.165134468015,-516235.4603248068],[-2714.7015550832602,2771.3320313018985,-230085.89935783745]],"n":676},"selected_edge_before":{"blocks":[[13749.737417808685,14322.262582191315,66614.77086913426]],"n":17}}}
{"case":"stubs4-degenerate-nurb_cone-e11-r0.5","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,16,24,10],"mass_status":[0],"result_topology":{"blocks":[[281552,35353171],[207130,17929604]],"n":440}},"topology":null,"values":{"fillet_point_step":[0.001],"mass_properties":[314.8325246121948,213.7213448689033,213.7213448689033,-25.256791575512928,-20.641446371057185,-48.78070940849276,602531.7041465972,647001.3562174569,230178.1359116786,215876.09028929376,263548.4756783311,111869.03168332015],"result_geometry":{"blocks":[[-4492.250713961271,4649.51618583184,-535943.3213095476],[-4052.741456601031,4286.165134468015,-516235.4603248068],[-2714.7015550832602,2771.3320313018985,-230085.89935783745]],"n":676},"selected_edge_before":{"blocks":[[13738.84427117878,14353.15572882122,66458.77782534131]],"n":17}}}
{"case":"stubs4-degenerate-nurb_cone-e20-r0.5","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,16,24,10],"mass_status":[0],"result_topology":{"blocks":[[281552,35353171],[207130,17929604]],"n":440}},"topology":null,"values":{"fillet_point_step":[0.001],"mass_properties":[314.8325246121948,213.7213448689033,213.7213448689033,-25.256791575512928,-20.641446371057185,-48.78070940849276,602531.7041465972,647001.3562174569,230178.1359116786,215876.09028929376,263548.4756783311,111869.03168332015],"result_geometry":{"blocks":[[-4492.250713961271,4649.51618583184,-535943.3213095476],[-4052.741456601031,4286.165134468015,-516235.4603248068],[-2714.7015550832602,2771.3320313018985,-230085.89935783745]],"n":676},"selected_edge_before":{"blocks":[[13760.523416202164,14349.476583797836,66616.77589881746]],"n":17}}}
{"case":"stubs4-degenerate-nurb_cone-e3-r0.5","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,16,24,10],"mass_status":[0],"result_topology":{"blocks":[[281552,35353171],[207130,17929604]],"n":440}},"topology":null,"values":{"fillet_point_step":[0.001],"mass_properties":[314.8325246121948,213.7213448689033,213.7213448689033,-25.256791575512928,-20.641446371057185,-48.78070940849276,602531.7041465972,647001.3562174569,230178.1359116786,215876.09028929376,263548.4756783311,111869.03168332015],"result_geometry":{"blocks":[[-4492.250713961271,4649.51618583184,-535943.3213095476],[-4052.741456601031,4286.165134468015,-516235.4603248068],[-2714.7015550832602,2771.3320313018985,-230085.89935783745]],"n":676},"selected_edge_before":{"blocks":[[13744.700724671131,14331.299275328869,66625.11707259771]],"n":17}}}
{"case":"stubs4-degenerate-nurb_cone-e5-r0.5","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,16,24,10],"mass_status":[0],"result_topology":{"blocks":[[281552,35353171],[207130,17929604]],"n":440}},"topology":null,"values":{"fillet_point_step":[0.001],"mass_properties":[314.8325246121948,213.7213448689033,213.7213448689033,-25.256791575512928,-20.641446371057185,-48.78070940849276,602531.7041465972,647001.3562174569,230178.1359116786,215876.09028929376,263548.4756783311,111869.03168332015],"result_geometry":{"blocks":[[-4492.250713961271,4649.51618583184,-535943.3213095476],[-4052.741456601031,4286.165134468015,-516235.4603248068],[-2714.7015550832602,2771.3320313018985,-230085.89935783745]],"n":676},"selected_edge_before":{"blocks":[[13746.484192903254,14333.515807096746,66632.79245387115]],"n":17}}}
{"case":"stubs4-degenerate-nurb_cone-e5-r0.5","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,16,24,10],"mass_status":[0],"result_topology":{"blocks":[[281552,35353171],[207130,17929604]],"n":440}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[314.8325246121948,213.7213448689033,213.7213448689033,-25.256791575512928,-20.641446371057185,-48.78070940849276,602531.7041465972,647001.3562174569,230178.1359116786,215876.09028929376,263548.4756783311,111869.03168332015],"result_geometry":{"blocks":[[-4492.250713961271,4649.51618583184,-535943.3213095476],[-4052.741456601031,4286.165134468015,-516235.4603248068],[-2714.7015550832602,2771.3320313018985,-230085.89935783745]],"n":676},"selected_edge_before":{"blocks":[[13746.484192903254,14333.515807096746,66632.79245387115]],"n":17}}}
{"case":"stubs4-degenerate-nurb_cone-e8-r0.5","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,16,24,10],"mass_status":[0],"result_topology":{"blocks":[[281552,35353171],[207130,17929604]],"n":440}},"topology":null,"values":{"fillet_point_step":[0.001],"mass_properties":[314.8325246121948,213.7213448689033,213.7213448689033,-25.256791575512928,-20.641446371057185,-48.78070940849276,602531.7041465972,647001.3562174569,230178.1359116786,215876.09028929376,263548.4756783311,111869.03168332015],"result_geometry":{"blocks":[[-4492.250713961271,4649.51618583184,-535943.3213095476],[-4052.741456601031,4286.165134468015,-516235.4603248068],[-2714.7015550832602,2771.3320313018985,-230085.89935783745]],"n":676},"selected_edge_before":{"blocks":[[13736.67714277342,14349.32285722658,66464.01751703939]],"n":17}}}
{"case":"stubs4-degenerate-test5-e2-r0.5","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,11,15,5],"mass_status":[1007],"result_topology":{"blocks":[[286149,29279394]],"n":224}},"topology":null,"values":{"fillet_point_step":[0.001],"mass_properties":[],"result_geometry":{"blocks":[[85.68069370920375,378.2896333964196,18376.163437456027],[88.63410644750252,173.94741069992628,4988.627395117301]],"n":404},"selected_edge_before":{"blocks":[[14033.1235,14049.423499999999,70158.1555]],"n":17}}}
{"case":"stubs4-degenerate-test5-e3-r0.5","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,11,15,5],"mass_status":[1007],"result_topology":{"blocks":[[286141,29613358]],"n":224}},"topology":null,"values":{"fillet_point_step":[0.001],"mass_properties":[],"result_geometry":{"blocks":[[92.59199377804839,371.6016589249071,21582.091027855142],[81.40347940591737,180.63538517143874,3655.9784312442325]],"n":404},"selected_edge_before":{"blocks":[[14034.1235,14050.423499999999,70167.3055]],"n":17}}}
{"case":"stubs4-degenerate-test5-e2-r0.5","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,11,15,5],"mass_status":[1007],"result_topology":{"blocks":[[286149,29279394]],"n":224}},"topology":null,"values":{"fillet_point_step":[0.001],"mass_properties":[],"result_geometry":{"blocks":[[85.68069370908455,378.2896333963004,18376.163437450778],[88.63410633731786,173.9474106777953,4988.627378713014]],"n":404},"selected_edge_before":{"blocks":[[14033.1235,14049.423499999999,70158.1555]],"n":17}}}
{"case":"stubs4-degenerate-test5-e3-r0.5","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,11,15,5],"mass_status":[1007],"result_topology":{"blocks":[[286141,29613358]],"n":224}},"topology":null,"values":{"fillet_point_step":[0.001],"mass_properties":[],"result_geometry":{"blocks":[[92.59199377788534,371.60165892474396,21582.091027841445],[81.40347929557224,180.63538514935178,3655.9784148967733]],"n":404},"selected_edge_before":{"blocks":[[14034.1235,14050.423499999999,70167.3055]],"n":17}}}
{"case":"stubs4-degenerate-test5-e5-r0.5","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,11,15,5],"mass_status":[1007],"result_topology":{"blocks":[[286142,29613638]],"n":224}},"topology":null,"values":{"fillet_point_step":[0.001],"mass_properties":[],"result_geometry":{"blocks":[[102.47687191071579,382.38944963985637,23475.249887640803],[126.0876792211174,197.33148803796084,7072.337733722035]],"n":404},"selected_edge_before":{"blocks":[[14052.4235,14052.4235,70331.6555]],"n":17}}}
{"case":"stubs4-degenerate-test5-e9-r0.5","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,11,15,5],"mass_status":[1007],"result_topology":{"blocks":[[286145,29532836]],"n":224}},"topology":null,"values":{"fillet_point_step":[0.001],"mass_properties":[],"result_geometry":{"blocks":[[136.43078937915638,400.93935510972034,31560.319786924018],[92.02938725003246,178.78158256809684,7363.735412086718]],"n":404},"selected_edge_before":{"blocks":[[14056.4235,14056.4235,70328.8055]],"n":17}}}
{"case":"stubs4-delete-edge-bottle-e16-r0.5","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,26,40,16],"mass_status":[0],"result_topology":{"blocks":[[281457,35341216],[282271,36580789],[241977,24565779]],"n":730}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[33.11819078265203,11.06683396778218,11.06683396778218,-1.760928723326559e-6,-3.0260239843351257e-6,2.0788625844461937,64.79258473459024,66.6733018328832,5.277123465358535,-0.00010373432038354095,-0.00006130940949992112,0.000020822473328764406],"result_geometry":{"blocks":[[912.7406198383134,996.1574227558623,139865.57295882053],[1710.5690534181747,1900.7696584750158,195545.28934387196],[536.122128285832,587.7649824357395,53296.94403726827],[1116.695548284241,1296.7760762038654,136279.5389856879],[81.3031298885769,99.10219410214427,4292.377944642321]],"n":1112},"selected_edge_before":{"blocks":[[14131.330290252932,14137.869747404748,70425.4044659795]],"n":17}}}
@@ -734,13 +733,13 @@
{"case":"stubs4-delete-edge-bottle-e4-r0.5","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,26,40,16],"mass_status":[0],"result_topology":{"blocks":[[281457,35341216],[282271,36580789],[241977,24565779]],"n":730}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[33.11819078265203,11.06683396778218,11.06683396778218,-1.760928723326559e-6,-3.0260239843351257e-6,2.0788625844461937,64.79258473459024,66.6733018328832,5.277123465358535,-0.00010373432038354095,-0.00006130940949992112,0.000020822473328764406],"result_geometry":{"blocks":[[912.7406198383134,996.1574227558623,139865.57295882053],[1710.5690534181747,1900.7696584750158,195545.28934387196],[536.122128285832,587.7649824357395,53296.94403726827],[1116.695548284241,1296.7760762038654,136279.5389856879],[81.3031298885769,99.10219410214427,4292.377944642321]],"n":1112},"selected_edge_before":{"blocks":[[14115.988369117867,14125.869745985985,70373.30141174888]],"n":17}}}
{"case":"stubs4-delete-edge-bottle-e6-r0.5","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,26,40,16],"mass_status":[0],"result_topology":{"blocks":[[281457,35341216],[282271,36580789],[241977,24565779]],"n":730}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[33.11819078265203,11.06683396778218,11.06683396778218,-1.760928723326559e-6,-3.0260239843351257e-6,2.0788625844461937,64.79258473459024,66.6733018328832,5.277123465358535,-0.00010373432038354095,-0.00006130940949992112,0.000020822473328764406],"result_geometry":{"blocks":[[912.7406198383134,996.1574227558623,139865.57295882053],[1710.5690534181747,1900.7696584750158,195545.28934387196],[536.122128285832,587.7649824357395,53296.94403726827],[1116.695548284241,1296.7760762038654,136279.5389856879],[81.3031298885769,99.10219410214427,4292.377944642321]],"n":1112},"selected_edge_before":{"blocks":[[14124.527826269632,14127.869745985985,70447.23544041828]],"n":17}}}
{"case":"stubs4-delete-edge-bottle-e7-r0.1","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,32,48,18],"mass_status":[0],"result_topology":{"blocks":[[281583,35350890],[282351,36588122],[294279,38824292],[91461,4774055]],"n":872}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[33.11819066864763,11.066833774243449,11.066833774243449,-1.7609970442209088e-6,-3.0145034465592655e-6,2.0788625673081946,64.79258279032975,66.67329997242163,5.27712338101959,-0.00010334434039349798,-0.00006131172417492086,0.00002082299859421369],"result_geometry":{"blocks":[[833.5707049620322,895.1351249113155,137999.2209386839],[1507.7213444082386,1726.6978152454299,178940.40957328162],[720.5582406522839,767.5180483610025,61237.294110141964],[612.3207478661566,666.0523183050288,105921.17922875834],[863.0311361989676,1040.848076285573,63995.86690405079],[175.61357670612227,184.89374697004763,3885.136455295182]],"n":1316},"selected_edge_before":{"blocks":[[14051.529624477327,14057.561884221679,70319.4561279686]],"n":17}}}
{"case":"stubs4-delete-edge-bottle-e8-r0.1","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,30,46,18],"mass_status":[0],"result_topology":{"blocks":[[281565,35348141],[282248,36573784],[281433,35534770],[75941,2465056]],"n":838}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[33.09218738036034,11.065538052737455,11.065538052737455,0.00006226900094534471,0.00007280938078398392,2.078648279985114,64.77224264488694,66.65299102444386,5.276061894487162,0.003176116617600669,0.0027074806423888487,-0.0004192744764841643],"result_geometry":{"blocks":[[1012.7277596295393,1074.9335289046544,177512.69222574067],[1573.7785858342172,1755.7148736295153,178792.22878692462],[496.58950478253786,552.5215294143144,49503.18261364769],[770.3289339125942,856.5764767892705,131486.68153052227],[665.6843192898722,880.6526434703991,60627.911057078214]],"n":1272},"selected_edge_before":{"blocks":[[14038.722642146662,14068.791020398014,70258.3923721516]],"n":17}}}
{"case":"stubs4-delete-edge-bottle-e8-r0.1","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,30,46,18],"mass_status":[0],"result_topology":{"blocks":[[281565,35348141],[282248,36573784],[281433,35534770],[75941,2465056]],"n":838}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[33.092185871331075,11.065538052689323,11.065538052689323,0.00006226900094508103,0.0000728093838209039,2.078648279980933,64.77224264440687,66.65299102398727,5.276061894463687,0.0031761167197739597,0.002707480642381785,-0.0004192744764813645],"result_geometry":{"blocks":[[1012.7277596295393,1074.9335289046544,177512.6922257407],[1573.7785858342172,1755.7148736295153,178792.22878692462],[496.58950478253786,552.5215294143144,49503.18261364769],[770.3300304795544,856.5775565669239,131486.84339172163],[665.6843192898722,880.6526434703991,60627.911057078214]],"n":1272},"selected_edge_before":{"blocks":[[14038.722642146662,14068.791020398014,70258.3923721516]],"n":17}}}
{"case":"stubs4-delete-edge-bottle-e8-r0.5","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,26,40,16],"mass_status":[0],"result_topology":{"blocks":[[281457,35341216],[282271,36580789],[241977,24565779]],"n":730}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[33.11819078265203,11.06683396778218,11.06683396778218,-1.760928723326559e-6,-3.0260239843351257e-6,2.0788625844461937,64.79258473459024,66.6733018328832,5.277123465358535,-0.00010373432038354095,-0.00006130940949992112,0.000020822473328764406],"result_geometry":{"blocks":[[912.7406198383134,996.1574227558623,139865.57295882053],[1710.5690534181747,1900.7696584750158,195545.28934387196],[536.122128285832,587.7649824357395,53296.94403726827],[1116.695548284241,1296.7760762038654,136279.5389856879],[81.3031298885769,99.10219410214427,4292.377944642321]],"n":1112},"selected_edge_before":{"blocks":[[14038.722642146662,14068.791020398014,70258.3923721516]],"n":17}}}
{"case":"stubs4-delete-edge-sphere_diff_3cylinders-e1-r0.1","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,27,42,10],"mass_status":[0],"result_topology":{"blocks":[[281419,35082812],[281727,35941052],[180344,21182036]],"n":746}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[38227.39465582545,169498.77448635045,169498.77448635045,-6.537525605147451e-8,-0.00003553376850025953,0.00009270360956735411,200903772.64810207,200903772.35709706,200904532.7059085,244.22697528035508,5.232474176472877,0.24150269600857283],"result_geometry":{"blocks":[[-58.23628471091258,3250.9242591803145,29063.76962559144],[393.33231003009774,2283.686082563766,-7485.558712097773],[54.3322308528417,2638.6291261731308,-12862.653024015211],[86.16140240035178,6653.955394479132,135560.40545350235],[307.8777734698095,601.1564711167173,-374.55356794298245]],"n":1044},"selected_edge_before":{"blocks":[[13958.23095813032,14252.330774181872,68955.23539952865]],"n":17}}}
{"case":"stubs4-delete-edge-sphere_diff_3cylinders-e1-r0.5","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,27,42,10],"mass_status":[0],"result_topology":{"blocks":[[281419,35082812],[281727,35941052],[180344,21182036]],"n":746}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[38192.714026053916,169488.16337915658,169488.16337915658,-6.49394807046738e-8,-0.0009202478323694004,0.0027440685728641985,200882126.63477087,200882126.33792478,200899304.1981722,6594.234045343594,5.230885517988218,0.2414435699373052],"result_geometry":{"blocks":[[-55.04275585407373,3250.542102971599,29403.507339166164],[393.33231003009774,2283.686082563766,-7485.558712097773],[59.80457242487494,2637.390611484507,-11679.935762591926],[95.41311227246591,6655.501398807934,136003.33567879105],[310.7895637987017,601.8413267460317,-341.49978482958437]],"n":1044},"selected_edge_before":{"blocks":[[13958.23095813032,14252.330774181872,68955.23539952865]],"n":17}}}
{"case":"stubs4-delete-edge-sphere_diff_3cylinders-e1-r0.1","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,27,42,10],"mass_status":[0],"result_topology":{"blocks":[[281419,35082812],[281727,35941052],[180344,21182036]],"n":746}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[38227.394651122726,169498.77448635048,169498.77448635048,-6.537525566494148e-8,-0.00003553376850025952,0.00009270360956635606,200903772.6481021,200903772.35709706,200904532.7059085,244.22697528035508,5.2324741750780115,0.24150269600857283],"result_geometry":{"blocks":[[-58.23628471091258,3250.9242591803145,29063.76962559144],[393.33231003009774,2283.686082563766,-7485.558712097773],[54.3322308528417,2638.6291261731308,-12862.653024015211],[86.163552215806,6653.958166169308,135560.55789919852],[307.87777346981505,601.1564711167052,-374.5535679426274]],"n":1044},"selected_edge_before":{"blocks":[[13958.23095813032,14252.330774181872,68955.23539952865]],"n":17}}}
{"case":"stubs4-delete-edge-sphere_diff_3cylinders-e1-r0.5","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,27,42,10],"mass_status":[0],"result_topology":{"blocks":[[281419,35082812],[281727,35941052],[180344,21182036]],"n":746}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[38192.71401748579,169488.1633791566,169488.1633791566,-6.493948067082315e-8,-0.0009202478323694002,0.002744068572863554,200882126.63477087,200882126.33792478,200899304.1981722,6594.234045343594,5.230885517868269,0.2414435699373052],"result_geometry":{"blocks":[[-55.04275585407373,3250.542102971599,29403.507339166164],[393.33231003009774,2283.686082563766,-7485.558712097773],[59.80457242487494,2637.390611484507,-11679.935762591926],[95.41555286717242,6655.504459040125,136003.51224835293],[310.7895637987094,601.8413267460139,-341.49978482907227]],"n":1044},"selected_edge_before":{"blocks":[[13958.23095813032,14252.330774181872,68955.23539952865]],"n":17}}}
{"case":"stubs4-delete-edge-sphere_diff_3cylinders-e2-r0.1","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,25,39,8],"mass_status":[0],"result_topology":{"blocks":[[281287,35309495],[282813,36661718],[106749,9735716]],"n":689}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[38236.6064675432,169497.36934847521,169497.36934847521,-0.00024424347049823786,0.0002497767560673066,0.00008722033752664724,200904177.28570384,200904009.3586459,200903635.36792448,-219.8534982362868,211.7087893819528,802.8540378054577],"result_geometry":{"blocks":[[-270.3531330514662,3209.2965625494535,-61978.30896168256],[843.8053053338348,2629.357987451512,142865.50468114667],[-241.66997710761865,2297.9845592191455,-3820.746445578192],[-187.22231839074738,2183.8077466814675,-34648.73480807489]],"n":946},"selected_edge_before":{"blocks":[[13858.829248638478,14254.330768459826,68064.0472827436]],"n":17}}}
{"case":"stubs4-delete-edge-sphere_diff_3cylinders-e4-r0.1","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,27,42,10],"mass_status":[0],"result_topology":{"blocks":[[281352,35067373],[281728,35993813],[180344,22405812]],"n":746}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[38227.39416546525,169498.76851886226,169498.76851886226,2.602435771072326e-6,-0.00004068506621873948,-0.00012394772679052185,200903766.42554796,200903766.13482884,200904522.8685967,-272.50563367162266,5.22287303543402,0.2423491064599717],"result_geometry":{"blocks":[[178.65343403658443,3199.193276601,-10792.272973688872],[836.4691645295133,2411.465829505752,28928.316368092885],[557.8207081571363,2556.207707436294,134325.61177020936],[1817.449839319484,6341.336524020602,283989.26408746134],[570.3190851865097,608.3810936297443,3725.69112691614]],"n":1044},"selected_edge_before":{"blocks":[[14217.170757083568,14255.330774181872,72285.45278592095]],"n":17}}}
{"case":"stubs4-delete-edge-sphere_diff_3cylinders-e4-r0.5","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,27,42,10],"mass_status":[0],"result_topology":{"blocks":[[281353,35067637],[281729,35994049],[180344,22405839]],"n":746}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[38192.7135277132,169488.15651010408,169488.15651010408,2.6031870471965998e-6,-0.0009260662010646446,-0.0027752441450355028,200882118.22410485,200882117.92750245,200899285.3610431,-6625.286283460682,5.224549480711518,0.24218961673591433],"result_geometry":{"blocks":[[175.4642895640224,3198.8068229269074,-10836.351438469621],[835.6467220106982,2410.6433869869375,28870.044915666193],[560.4920595330373,2558.8790588121956,134983.0654784917],[1813.7752374651673,6339.865905808016,283835.56809906283],[571.0792708623438,609.8443121368729,3722.787788100186]],"n":1044},"selected_edge_before":{"blocks":[[14217.170757083568,14255.330774181872,72285.45278592095]],"n":17}}}
{"case":"stubs4-delete-edge-sphere_diff_3cylinders-e4-r0.1","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,27,42,10],"mass_status":[0],"result_topology":{"blocks":[[281352,35067373],[281728,35993813],[180344,22405812]],"n":746}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[38227.39416076445,169498.76851886226,169498.76851886226,2.6024357712026087e-6,-0.00004068506621873948,-0.00012394772678974916,200903766.42554796,200903766.13482884,200904522.8685967,-272.50563367162266,5.222873035903951,0.2423491064599717],"result_geometry":{"blocks":[[178.65343403658443,3199.193276601,-10792.272973688872],[836.4691645295133,2411.465829505752,28928.316368092885],[557.8207081571363,2556.207707436294,134325.61177020936],[1817.4532133323096,6341.339295710777,283989.51550117915],[570.3190851865119,608.3810936297399,3725.6911269162733]],"n":1044},"selected_edge_before":{"blocks":[[14217.170757083568,14255.330774181872,72285.45278592095]],"n":17}}}
{"case":"stubs4-delete-edge-sphere_diff_3cylinders-e4-r0.5","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,27,42,10],"mass_status":[0],"result_topology":{"blocks":[[281353,35067637],[281729,35994049],[180344,22405839]],"n":746}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[38192.71351914587,169488.15651010408,169488.15651010408,2.6031870468429546e-6,-0.0009260662010646446,-0.0027752441450349446,200882118.22410485,200882117.92750245,200899285.3610431,-6625.286283460682,5.224549479446177,0.24218961673591433],"result_geometry":{"blocks":[[175.4642895640224,3198.8068229269074,-10836.351438469621],[835.6467220106982,2410.6433869869375,28870.044915666193],[560.4920595330373,2558.8790588121956,134983.0654784917],[1813.779115857511,6339.868966040209,283835.8595316402],[571.0792708623519,609.8443121368555,3722.787788100698]],"n":1044},"selected_edge_before":{"blocks":[[14217.170757083568,14255.330774181872,72285.45278592095]],"n":17}}}
{"case":"stubs4-delete-edge-sphere_diff_3cylinders-e5-r0.1","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,25,39,8],"mass_status":[0],"result_topology":{"blocks":[[281287,35309495],[282813,36661718],[106749,9735716]],"n":689}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[38236.60642715864,169497.36934847521,169497.36934847521,-0.0002442434704982385,0.0002497767560673066,0.00008722033752664748,200904177.28570384,200904009.3586459,200903635.36792448,-219.85349823628636,211.70878938195298,802.8540378054586],"result_geometry":{"blocks":[[-270.3531330514662,3209.2965625494535,-61870.30896168256],[843.8053053338348,2629.357987451512,142865.50468114667],[-241.66997710761865,2297.9845592191455,-3820.746445578192],[-187.22231839074738,2183.8077466814675,-34648.73480807489]],"n":946},"selected_edge_before":{"blocks":[[14117.769047591726,14257.330768459826,71394.2646691359]],"n":17}}}
{"case":"stubs4-delete-edge-sphere_diff_3cylinders-e5-r0.5","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,25,39,8],"mass_status":[0],"result_topology":{"blocks":[[281287,35309495],[282813,36661718],[106749,9735716]],"n":689}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[38236.60642715864,169497.36934847521,169497.36934847521,-0.0002442434704982385,0.0002497767560673066,0.00008722033752664748,200904177.28570384,200904009.3586459,200903635.36792448,-219.85349823628636,211.70878938195298,802.8540378054586],"result_geometry":{"blocks":[[-270.3531330514662,3209.2965625494535,-61870.30896168256],[843.8053053338348,2629.357987451512,142865.50468114667],[-241.66997710761865,2297.9845592191455,-3820.746445578192],[-187.22231839074738,2183.8077466814675,-34648.73480807489]],"n":946},"selected_edge_before":{"blocks":[[14117.769047591726,14257.330768459826,71394.2646691359]],"n":17}}}
{"case":"stubs4-open_shell-e0-r0.5","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,16,21,6],"mass_status":[1007],"result_topology":{"blocks":[[325212,41883600],[60327,1599127]],"n":311}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[],"result_geometry":{"blocks":[[-1097.5615101691037,19602.9089607915,-184867.1316369425],[1582.0715457351475,17732.074813669384,255090.98593747205],[186.0159067879023,2930.3497457866056,6127.925961962178]],"n":550},"selected_edge_before":{"blocks":[[14053.433886125349,15365.754072155007,69967.22438595541]],"n":17}}}
@@ -771,18 +770,18 @@
{"case":"surface-surface-tiny-scale","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,4,4,1],"result_topology":{"blocks":[[71196,1456742]],"n":49}},"topology":null,"values":{"fillet_point_step":[0.00001],"result_geometry":{"blocks":[[20.252789536396897,20.255989536396896,1222.956513078754]],"n":106}}}
{"case":"surface-surface-unequal-radii","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1006]},"topology":null,"values":{"fillet_point_step":[0.00001]}}
{"case":"sweep4-bottle-e29-r0.1","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,26,40,16],"mass_status":[0],"result_topology":{"blocks":[[281457,35341216],[282271,36580789],[241977,24565779]],"n":730}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[33.11819078265203,11.06683396778218,11.06683396778218,-1.760928723326559e-6,-3.0260239843351257e-6,2.0788625844461937,64.79258473459024,66.6733018328832,5.277123465358535,-0.00010373432038354095,-0.00006130940949992112,0.000020822473328764406],"result_geometry":{"blocks":[[912.7406198383134,996.1574227558623,139865.57295882053],[1710.5690534181747,1900.7696584750158,195545.28934387196],[536.122128285832,587.7649824357395,53296.94403726827],[1116.695548284241,1296.7760762038654,136279.5389856879],[81.3031298885769,99.10219410214427,4292.377944642321]],"n":1112},"selected_edge_before":{"blocks":[[14056.32667686996,14056.532787646805,70289.10626586332]],"n":17}}}
{"case":"sweep4-brepForFillet2-all-r0.1","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,27,54,29],"mass_status":[0],"result_topology":{"blocks":[[282431,35459571],[282747,36619670],[288327,38735549],[347659,40038696]],"n":1007}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[1433.5192463313542,3616.0405226883913,3616.0405226883913,3.4579059647300046,6.968375606377352,11.46240873792781,855495.534560286,741228.249798683,324372.0511927991,303856.4935370433,98605.77159074086,79222.04705902988],"result_geometry":{"blocks":[[1127.5160335706753,1324.8666698370162,142482.42042283315],[1093.5699136951846,1266.486899506838,134059.6611106791],[611.5849243612906,698.4154589068847,93409.70379481115],[1183.8268835956392,1328.4597652999796,159120.4923411866],[845.30368590946,993.911398669886,101988.38788842077],[1073.3400862763394,1193.2675707736205,151117.25120041918],[168.42025275745684,206.57267920715915,5497.535339183709]],"n":1602},"selected_edge_before":{"blocks":[[211488.93573851514,211626.8236529697,26222606.564571798]],"n":255}}}
{"case":"sweep4-brepForFillet2-all-r0.1","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,10,15,7],"mass_status":[0],"result_topology":{"blocks":[[286213,36387994],[30108,196385]],"n":278}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[1440.9799345699366,3616.4117197382475,3616.4117197382475,3.4576417013586815,6.968403815007568,11.462456451394527,855617.9720066136,741334.0091506396,324410.44028196693,303891.37025483977,98600.05653986205,79223.04263413792],"result_geometry":{"blocks":[[1058.0112074993297,1200.4221207267126,134552.7622124501],[576.414142594088,675.4997380276822,62041.95297490219]],"n":436},"selected_edge_before":{"blocks":[[211488.93573851514,211626.8236529697,26222606.564571798]],"n":255}}}
{"case":"sweep4-native-crash-extrusion1002-all-r0.1","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,2,3,3],"mass_status":[0],"result_topology":{"blocks":[[87211,2632979]],"n":60}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[1828.3123418766857,4539.209557183511,4539.209557183511,-23.164276352530862,6.718006159263185,5.0,625550.1252623487,2775651.333995856,3098587.4887793036,152472.18881672568,-525737.5230232404,-851367.1886541296],"result_geometry":{"blocks":[[-265.93930395024375,984.5940213531953,-16331.908320443214]],"n":116},"selected_edge_before":{"blocks":[[41993.3485266974,42459.791701173235,923773.8634014014]],"n":51}}}
{"case":"sweep4-native-crash-sphere_diff_3cylinders-e30-r0.1","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,25,39,8],"mass_status":[0],"result_topology":{"blocks":[[281287,35309495],[282813,36661718],[106749,9735716]],"n":689}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[38236.0056036591,169499.5090554143,169499.5090554143,-2.2094098477279254e-7,5.8265357802372995e-6,0.00002320605524413402,200905056.55061626,200904890.31614494,200905240.27096927,-13.638909241246566,5.240051047217421,0.21252878573347037],"result_geometry":{"blocks":[[-272.31843466683495,3207.3312609340846,-62265.18690566959],[850.805323294692,2636.3580016381707,143897.50768906018],[-234.65262462943934,2305.0019116973244,-2850.5084735099554],[-187.22231839074738,2183.8077466814675,-34648.73480807489]],"n":946},"selected_edge_before":{"blocks":[[14043.344676254792,14208.387727110645,69814.76280349465]],"n":17}}}
{"case":"sweep4-native-crash-sphere_diff_3cylinders-e30-r0.1","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,25,39,8],"mass_status":[0],"result_topology":{"blocks":[[281287,35309495],[282813,36661718],[106749,9735716]],"n":689}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[38236.60646754423,169497.36934847521,169497.36934847521,-0.0002442434704982383,0.0002497767560673066,0.00008722033752664722,200904177.28570384,200904009.3586459,200903635.36792448,-219.85349823628647,211.7087893819534,802.8540378054577],"result_geometry":{"blocks":[[-270.31843466683495,3209.3312609340846,-61975.18690566959],[850.805323294692,2636.3580016381707,143897.50768906018],[-234.65262462943934,2305.0019116973244,-2850.5084735099554],[-187.22231839074738,2183.8077466814675,-34648.73480807489]],"n":946},"selected_edge_before":{"blocks":[[14043.344676254792,14208.387727110645,69814.76280349465]],"n":17}}}
{"case":"sweep4-sphere_diff_3cylinders-all-r0.1","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1007,25,39,8],"mass_status":[0],"result_topology":{"blocks":[[281287,35309495],[282813,36661718],[106749,9735716]],"n":689}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[38236.60646754423,169497.36934847521,169497.36934847521,-0.0002442434704982383,0.0002497767560673066,0.00008722033752664722,200904177.28570384,200904009.3586459,200903635.36792448,-219.85349823628647,211.7087893819534,802.8540378054577],"result_geometry":{"blocks":[[-272.3531330514662,3207.2965625494535,-62268.30896168256],[843.8053053338348,2629.357987451512,142865.50468114667],[-241.66997710761865,2297.9845592191455,-3820.746445578192],[-187.22231839074738,2183.8077466814675,-34648.73480807489]],"n":946},"selected_edge_before":{"blocks":[[210500.9244698742,213738.57714575977,26159842.25571068],[210998.88080540716,213017.77850297175,25928388.234741364],[126612.02279058412,128034.1177995765,8997007.19306596]],"n":663}}}
{"case":"sweep5-bague-e4-r1.0","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,4,8,4],"mass_status":[0],"result_topology":{"blocks":[[172450,12382265]],"n":146}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[514.6144027764909,225.66889284512877,225.66889284512877,-0.32303313010240103,6.889210187890638,-0.011379984931174108,18666.065838694758,10297.324325608877,28464.959061288333,-24.85414539881951,828.174064739097,-147.40253326904755],"result_geometry":{"blocks":[[270.59669473184863,660.8580131060972,19448.783514605828]],"n":232},"selected_edge_before":{"blocks":[[14036.56915572996,14077.922178408788,70220.03171369614]],"n":17}}}
{"case":"sweep5-bottle-e29-r1.0","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,26,40,16],"mass_status":[0],"result_topology":{"blocks":[[281457,35341216],[282271,36580789],[241977,24565779]],"n":730}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[33.11819078265203,11.06683396778218,11.06683396778218,-1.760928723326559e-6,-3.0260239843351257e-6,2.0788625844461937,64.79258473459024,66.6733018328832,5.277123465358535,-0.00010373432038354095,-0.00006130940949992112,0.000020822473328764406],"result_geometry":{"blocks":[[912.7406198383134,996.1574227558623,139865.57295882053],[1710.5690534181747,1900.7696584750158,195545.28934387196],[536.122128285832,587.7649824357395,53296.94403726827],[1116.695548284241,1296.7760762038654,136279.5389856879],[81.3031298885769,99.10219410214427,4292.377944642321]],"n":1112},"selected_edge_before":{"blocks":[[14056.32667686996,14056.532787646805,70289.10626586332]],"n":17}}}
{"case":"sweep5-ext_w_hole-e14-r1.0","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,16,24,10],"mass_status":[0],"result_topology":{"blocks":[[281265,35232906],[207181,19279604]],"n":440}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[284.98981133796997,233.92041218558995,233.92041218558995,4.121235785968235,3.3787490092953405,2.503170966827912,5809.813379408206,7087.081330486026,8992.812613690214,1976.9990940072303,2415.986012872389,3117.945568427183],"result_geometry":{"blocks":[[615.0139314107776,692.0181326716923,77614.46178832269],[553.4290978015259,574.8568236138705,71081.83901310955],[320.69517748498475,440.66148084137205,29369.56517126522]],"n":676},"selected_edge_before":{"blocks":[[14078.987775637732,14078.987775637732,70515.81832691318]],"n":17}}}
{"case":"sweep5-ext_w_hole-e15-r1.0","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,16,24,10],"mass_status":[0],"result_topology":{"blocks":[[281364,35247007],[207253,17810494]],"n":440}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[285.615150041505,234.29251510208664,234.29251510208664,4.127216303163789,3.3759513795077902,2.5000002478287437,5811.2864401681645,7110.652141803485,9017.06274962601,1977.4003647584098,2417.440213955953,3122.6486515526303],"result_geometry":{"blocks":[[557.802249015592,634.806450276507,65898.16751197066],[663.2574029302206,703.19053637927,88061.37442961268],[342.49702111005485,426.55033057019,31076.560961980325]],"n":676},"selected_edge_before":{"blocks":[[14067.85,14067.85,70523.75]],"n":17}}}
{"case":"sweep5-letter_g-e1-r1.0","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,22,33,13],"mass_status":[0],"result_topology":{"blocks":[[281269,35110418],[273706,35051752],[105878,4647860]],"n":602}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[859.163972176194,573.7959066160405,573.7959066160405,4.107533609006593,1.0328822173610015,1.0089011284794234,37903.47418701175,22576.85812690601,58933.808309440785,564.146139589189,2367.7020206242178,2148.3466295602084],"result_geometry":{"blocks":[[410.9033091576359,934.6948026222198,36540.549458268455],[523.9494009864142,872.1294547530237,69254.79224726776],[162.0350247187872,776.6408974164383,-2105.8909792905865],[195.33484732271341,644.7109172576087,11314.339475611954]],"n":916},"selected_edge_before":{"blocks":[[14012.150359744432,14071.96337274414,70007.57227090707]],"n":17}}}
{"case":"sweep5-letter_g-e10-r1.0","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,23,35,14],"mass_status":[0],"result_topology":{"blocks":[[281451,35195912],[271658,33821865],[151262,8469425]],"n":639}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[855.4845914943479,572.1866897469198,572.1866897469198,4.06209189207417,1.0718503855003707,0.9889089728175036,37554.08820632737,22226.41926963534,58285.03871091736,657.6087108586083,2288.4820353941905,2332.4894401451043],"result_geometry":{"blocks":[[366.9326699433314,889.7222385174488,40965.30671942545],[461.5924976248298,805.912969168919,52003.376920442846],[373.92872500534145,801.5254759869886,19904.77041026007],[348.62678218741655,1150.221972495881,41503.201140263234]],"n":974},"selected_edge_before":{"blocks":[[14000.017695808663,14139.892654430238,70165.97445144223]],"n":17}}}
{"case":"sweep5-ext_w_hole-e15-r1.0","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,16,24,10],"mass_status":[0],"result_topology":{"blocks":[[281364,35247007],[207253,17810494]],"n":440}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[285.61514002877186,234.29249007025385,234.29249007025385,4.127215937385101,3.3759514713802043,2.50000024782731,5811.286072814312,7110.650505969625,9017.06116363893,1977.4002064668946,2417.4397416853244,3122.6481762179046],"result_geometry":{"blocks":[[557.802249015592,634.806450276507,65898.16751197066],[663.2591239081229,703.1922573571724,88061.72349742928],[342.49702111005485,426.55033057019,31076.560961980325]],"n":676},"selected_edge_before":{"blocks":[[14067.85,14067.85,70523.75]],"n":17}}}
{"case":"sweep5-letter_g-e1-r1.0","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,22,33,13],"mass_status":[0],"result_topology":{"blocks":[[281269,35110418],[273706,35051752],[105878,4647860]],"n":602}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[859.1640101795887,573.7959270334253,573.7959270334253,4.107533440435279,1.0328822054385756,1.0089011104215657,37903.4742191604,22576.85814328094,58933.80834430048,564.1461465109314,2367.702014145944,2148.3466221053473],"result_geometry":{"blocks":[[410.9003920176803,934.6923177929822,36540.264544020014],[523.9494009864142,872.1294547530237,69254.79224726776],[162.03816578813058,776.6438390962456,-2105.4582212146775],[195.33484732271341,644.7109172576087,11314.339475611954]],"n":916},"selected_edge_before":{"blocks":[[14012.150359744432,14071.96337274414,70007.57227090707]],"n":17}}}
{"case":"sweep5-letter_g-e10-r1.0","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,23,35,14],"mass_status":[0],"result_topology":{"blocks":[[281451,35195912],[271658,33821865],[151262,8469425]],"n":639}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[855.4845929157715,572.1866899865429,572.1866899865429,4.062091888673557,1.0718503809116826,0.9889089729890397,37554.08823024624,22226.41927403144,58285.03873826522,657.608707549181,2288.482034038245,2332.489449763097],"result_geometry":{"blocks":[[366.9326348999855,889.7222034741029,40965.30377578439],[461.5924976248298,805.912969168919,52003.376920442846],[373.934517585421,801.5314610845561,19905.789541504462],[348.62678218741655,1150.221972495881,41503.201140263234]],"n":974},"selected_edge_before":{"blocks":[[14000.017695808663,14139.892654430238,70165.97445144223]],"n":17}}}
{"case":"sweep5-nurb_box1-all-r0.5","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[0,18,36,20],"mass_status":[0],"result_topology":{"blocks":[[281929,35373612],[285845,37305406],[241320,17629072]],"n":674}},"topology":null,"values":{"fillet_point_step":[0.001],"mass_properties":[1572.3515269962566,3793.110529773754,3793.110529773754,-2.156788380403075,23.563811523220245,3.9131205145753625,2294394.663519221,289144.8203365313,2426078.0496002086,350419.7571754788,-32655.37897308264,-192296.92366204038],"result_geometry":{"blocks":[[1097.5449746593674,2112.6442446539977,119601.48287439081],[806.8239395556377,1810.1771079212701,108163.19830857524],[1358.345574864562,1765.0662855596179,190578.11774205492],[922.4544112275546,1753.743797329686,106963.71519502944],[401.36696963680475,447.3281591380738,11726.830217950148]],"n":1080},"selected_edge_before":{"blocks":[[126990.00055073624,127451.28851121065,9289622.563160447]],"n":153}}}
{"case":"sweep5-sphere_diff_3cylinders-e29-r1.0","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,25,39,8],"mass_status":[0],"result_topology":{"blocks":[[281287,35309495],[282813,36661718],[106749,9735716]],"n":689}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[38236.0056036591,169499.5090554143,169499.5090554143,-2.2094098477279254e-7,5.8265357802372995e-6,0.00002320605524413402,200905056.55061626,200904890.31614494,200905240.27096927,-13.638909241246566,5.240051047217421,0.21252878573347037],"result_geometry":{"blocks":[[-272.31843466683495,3207.3312609340846,-62265.18690566959],[850.805323294692,2636.3580016381707,143897.50768906018],[-234.65262462943934,2305.0019116973244,-2850.5084735099554],[-187.22231839074738,2183.8077466814675,-34648.73480807489]],"n":946},"selected_edge_before":{"blocks":[[14089.869197752294,14207.754380872619,70438.50520744263]],"n":17}}}
{"case":"sweep5-sphere_diff_3cylinders-e29-r1.0","deferred":null,"error":null,"ints":{"api_status_vertex_edge_face_counts":[1001,25,39,8],"mass_status":[0],"result_topology":{"blocks":[[281287,35309495],[282813,36661718],[106749,9735716]],"n":689}},"topology":null,"values":{"fillet_point_step":[0.00001],"mass_properties":[38236.606568268166,169497.36934847521,169497.36934847521,-0.0002442434704982382,0.0002497767560673066,0.0000872203375266473,200904177.28570384,200904009.3586459,200903635.36792448,-219.85349823628644,211.70878938195352,802.854037805458],"result_geometry":{"blocks":[[-270.31843466683495,3209.3312609340846,-61867.18690566959],[850.805323294692,2636.3580016381707,143897.50768906018],[-234.65262462943934,2305.0019116973244,-2850.5084735099554],[-187.22231839074738,2183.8077466814675,-34648.73480807489]],"n":946},"selected_edge_before":{"blocks":[[14089.869197752294,14207.754380872619,70438.50520744263]],"n":17}}}
{"case":"two-faces-one-body-x0","deferred":null,"error":null,"ints":{"api_status_result_vertex_edge_face_counts":[0,1,4,4,1],"body0_topology":{"blocks":[[256990,21318399]],"n":180},"body0_vertex_edge_face_counts":[12,14,4],"result_topology":{"blocks":[[71196,1456742]],"n":49}},"topology":null,"values":{"body0_geometry":{"blocks":[[524.74019,594.8001899999997,69442.36691000001],[236.72004999999996,259.94005,12502.132969999997]],"n":372},"fillet_point_step":[0.00001],"result_geometry":{"blocks":[[273.09000000000003,276.2900000000001,15193.250000000005]],"n":106}}}
{"case":"two-faces-one-body-x2","deferred":null,"error":null,"ints":{"api_status_result_vertex_edge_face_counts":[0,1,4,4,1],"body0_topology":{"blocks":[[256990,21318399]],"n":180},"body0_vertex_edge_face_counts":[12,14,4],"result_topology":{"blocks":[[71196,1456742]],"n":49}},"topology":null,"values":{"body0_geometry":{"blocks":[[524.74019,594.8001899999997,69442.36691000001],[236.72004999999996,259.94005,12502.132969999997]],"n":372},"fillet_point_step":[0.00001],"result_geometry":{"blocks":[[272.7895363968895,275.98953639688955,15165.51307875397]],"n":106}}}
{"case":"two-faces-two-bodies-x0","deferred":null,"error":null,"ints":{"api_status_result_vertex_edge_face_counts":[0,1,4,4,1],"body0_topology":{"blocks":[[128403,5122478]],"n":91},"body0_vertex_edge_face_counts":[6,7,2],"body1_topology":{"blocks":[[128403,5122478]],"n":91},"body1_vertex_edge_face_counts":[6,7,2],"result_topology":{"blocks":[[71196,1456742]],"n":49}},"topology":null,"values":{"body0_geometry":{"blocks":[[357.93012000000004,357.93012000000004,34368.9378]],"n":186},"body1_geometry":{"blocks":[[403.53011999999995,496.81012000000004,38642.6178]],"n":186},"fillet_point_step":[0.00001],"result_geometry":{"blocks":[[273.09000000000003,276.2900000000001,15193.250000000005]],"n":106}}}
File diff suppressed because one or more lines are too long
@@ -63,7 +63,7 @@
{"case":"gen0041","deferred":null,"error":null,"ints":{},"topology":null,"values":{"flat":{"blocks":[[16066.889940157345,16110.889940157345,210888.3161509578]],"n":164}}}
{"case":"gen0042","deferred":null,"error":null,"ints":{},"topology":null,"values":{"flat":[0.0,0.0,1.0,0.0,0.0]}}
{"case":"gen0043","deferred":null,"error":null,"ints":{},"topology":null,"values":{"flat":{"blocks":[[16050.663272654156,16066.663272654156,208831.9112877131]],"n":73}}}
{"case":"gen0044","deferred":null,"error":null,"ints":{},"topology":null,"values":{"flat":[3.0,0.0,0.0,0.0,0.0,1.5,1.0,-1.0]}}
{"case":"gen0044","deferred":null,"error":null,"ints":{},"topology":null,"values":{"flat":[3.0,0.0,0.0,0.0,0.0,2.0,2.0,-1.0]}}
{"case":"gen0045","deferred":null,"error":null,"ints":{},"topology":null,"values":{"flat":{"blocks":[[16059.994469370078,16078.284659067667,209125.32106494086]],"n":60}}}
{"case":"gen0046","deferred":null,"error":null,"ints":{},"topology":null,"values":{"flat":[0.0,0.0,1.9114974191740313,2.4114974191740313,-0.5,0.0,0.0,-0.5,0.0,0.0]}}
{"case":"gen0047","deferred":null,"error":null,"ints":{},"topology":null,"values":{"flat":[0.0,0.0,1.0,0.0,71.94187139121505,5.0,-0.0,-2e-16,15.764717677796499,-8.209884922133655e-17,-0.44163273813250237,5.000000000000001,-0.0,-1e-15]}}
@@ -83,7 +83,7 @@
{"case":"gen0061","deferred":null,"error":null,"ints":{},"topology":null,"values":{"flat":[0.0,1.0]}}
{"case":"gen0062","deferred":null,"error":null,"ints":{},"topology":null,"values":{"flat":[0.0,0.0,1.0,-0.8284217819241004,0.43292179750948834,1.8522205459305647,-1.3769180634100657,0.8402576012717681,2.0888308602385637,-1.197189696088099,0.283966149344422,2.325441174546562,-1.0174613287661323,-0.2723253025829241]}}
{"case":"gen0063","deferred":null,"error":null,"ints":{},"topology":null,"values":{"flat":{"blocks":[[8.275128487894733,29.201324475157012,141.952399429247]],"n":28}}}
{"case":"gen0064","deferred":null,"error":null,"ints":{},"topology":null,"values":{"flat":[3.0,0.0,0.0,0.0,0.0,1.5,1.0,-1.0]}}
{"case":"gen0064","deferred":null,"error":null,"ints":{},"topology":null,"values":{"flat":[3.0,0.0,0.0,0.0,0.0,2.0,2.0,-1.0]}}
{"case":"gen0065","deferred":null,"error":null,"ints":{},"topology":null,"values":{"flat":[0.0,0.0]}}
{"case":"gen0066","deferred":null,"error":null,"ints":{},"topology":null,"values":{"flat":[0.0,1.0,0.0,0.0,0.00027590763455902554,-0.16515059118185427,-0.05901421955206665,0.001451417030048013,-1.0,0.0,0.0005482189258053823,0.0,-1.0,-0.5,1.0,0.0]}}
{"case":"gen0067","deferred":null,"error":null,"ints":{},"topology":null,"values":{"flat":[0.0,-1e-6,-1e-6,1.000001,1.000001]}}
@@ -211,7 +211,7 @@
{"case":"gen0189","deferred":null,"error":null,"ints":{},"topology":null,"values":{"flat":{"blocks":[[2.6114590395929467,128.94440462009777,159.7742114683003]],"n":28}}}
{"case":"gen0190","deferred":null,"error":null,"ints":{},"topology":null,"values":{"flat":[0.0,-200000.0,-1000000.0,200001.0,1000001.0]}}
{"case":"gen0191","deferred":null,"error":null,"ints":{},"topology":null,"values":{"flat":{"blocks":[[16050.470576946233,16054.470576946233,208720.15584916165]],"n":34}}}
{"case":"gen0192","deferred":null,"error":null,"ints":{},"topology":null,"values":{"flat":[3.0,0.0,0.0,0.0,0.0,1.5,1.0,-1.0]}}
{"case":"gen0192","deferred":null,"error":null,"ints":{},"topology":null,"values":{"flat":[3.0,0.0,0.0,0.0,0.0,2.0,2.0,-1.0]}}
{"case":"gen0193","deferred":null,"error":null,"ints":{},"topology":null,"values":{"flat":{"blocks":[[16044.917021896174,16060.716939116952,208545.10024707197]],"n":47}}}
{"case":"gen0194","deferred":null,"error":null,"ints":{},"topology":null,"values":{"flat":[0.0,0.0,1.0,1.0,0.0]}}
{"case":"gen0195","deferred":null,"error":null,"ints":{},"topology":null,"values":{"flat":[0.0,0.0,999.0]}}
@@ -2,10 +2,6 @@
{"case":"base_curve_extension_both_ends","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":147},"status":[0.0]}}
{"case":"base_curve_line","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":81},"status":[0.0]}}
{"case":"base_curve_line_and_hermite","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[18840.5,18844.5,279468.5]],"n":43},"status":[0.0]}}
{"case":"blend_box_edge_cont1","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":119},"status":[0.0]}}
{"case":"blend_box_edge_cont2","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":139},"status":[0.0]}}
{"case":"blend_box_edge_cont3","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":159},"status":[0.0]}}
{"case":"blend_curved_edge_skin","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":225},"status":[0.0]}}
{"case":"cd_init_distance_only","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[27.707106781186546,31.12132034355964,395.92766952966366]],"n":28},"status":[0.0]}}
{"case":"cd_setup_half_sqrt2","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[18499.707106781185,18501.121320343562,180790.0]],"n":43},"status":[0.0]}}
{"case":"circ_box_edge_r1_approx0_g10","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":109},"status":[0.0]}}
@@ -18,7 +14,6 @@
{"case":"circ_curved_edge_skin_g11","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"],["-inf","inf","-inf"]],"n":511},"status":[0.0]}}
{"case":"cr_assisted_radii","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[17296.5,19300.5,264872.5]],"n":46},"status":[0.0]}}
{"case":"cr_box_faces_setup","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[18297.5,18301.5,265877.5]],"n":46},"status":[0.0]}}
{"case":"gen0000","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"],[-1.7976931348623157e+308,1.7976931348623157e+308,"-inf"]],"n":279},"status":[0.0]}}
{"case":"gen0001","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[18258.1,18262.9,136993.1]],"n":30},"status":[0.0]}}
{"case":"gen0002","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[18258.149066467322,18258.587331141483,136988.8300019166]],"n":30},"status":[0.0]}}
{"case":"gen0003","deferred":null,"error":null,"ints":{"status":[0]},"topology":null,"values":{"out":{"blocks":[[16.0,"inf","NaN"]],"n":110}}}
@@ -28,7 +23,6 @@
{"case":"gen0007","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[176.92774115795436,369.0388833450123,15312.668988551046]],"n":168},"status":[0.0]}}
{"case":"gen0008","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[18258.1,18258.5,136988.5]],"n":30},"status":[0.0]}}
{"case":"gen0009","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[17293.5,19299.460958433294,264857.57808313344]],"n":47},"status":[0.0]}}
{"case":"gen0010","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[126.83123020765609,126.83159298977614,10824.064430671238]],"n":209},"status":[0.0]}}
{"case":"gen0011","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[18258.1,18258.5,136988.5]],"n":30},"status":[0.0]}}
{"case":"gen0012","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[17778.25647549236,18189.02950909302,303194.6772075217]],"n":46},"status":[0.0]}}
{"case":"gen0013","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"],[3.0,3.0,6.0]],"n":259},"status":[0.0]}}
@@ -39,10 +33,8 @@
{"case":"gen0018","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":[1.3541615435193872,1.3541615435193872,1.3541615435193872],"status":[0.0]}}
{"case":"gen0019","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[17.283041808141412,24.37771503116736,197.65873363323075]],"n":22},"status":[0.0]}}
{"case":"gen0020","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":40},"status":[0.0]}}
{"case":"gen0021","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":233},"status":[0.0]}}
{"case":"gen0022","deferred":null,"error":null,"ints":{"status":[0]},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":92}}}
{"case":"gen0023","deferred":null,"error":null,"ints":{"status":[1001]},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"],["-inf","inf","-inf"],["-inf","inf","-inf"],[487.8787327413357,487.8787327413357,9189.294416911122]],"n":821}}}
{"case":"gen0024","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"],["-inf","inf","-inf"]],"n":301},"status":[0.0]}}
{"case":"gen0025","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[11.712440782849885,95.88092478455148,-13.639899071830776]],"n":58},"status":[0.0]}}
{"case":"gen0026","deferred":null,"error":null,"ints":{"status":[0]},"topology":null,"values":{"out":{"blocks":[[49.0,"inf","NaN"]],"n":80}}}
{"case":"gen0027","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":59},"status":[0.0]}}
@@ -58,7 +50,6 @@
{"case":"gen0037","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[18293.408195167394,18301.040975836975,265858.1426338282]],"n":47},"status":[0.0]}}
{"case":"gen0038","deferred":null,"error":null,"ints":{"status":[0]},"topology":null,"values":{"out":{"blocks":[[46.0,"inf","NaN"]],"n":110}}}
{"case":"gen0039","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":89},"status":[0.0]}}
{"case":"gen0040","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"],[2.0,2.0,3.0]],"n":258},"status":[0.0]}}
{"case":"gen0041","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[18498.5,18498.5,180788.0]],"n":44},"status":[0.0]}}
{"case":"gen0042","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":59},"status":[0.0]}}
{"case":"gen0043","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":114},"status":[0.0]}}
@@ -76,13 +67,10 @@
{"case":"gen0055","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[18258.1,18258.5,136988.5]],"n":30},"status":[0.0]}}
{"case":"gen0056","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":174},"status":[0.0]}}
{"case":"gen0057","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":[0.4448608426642609,-0.4448608426642609,-0.4448608426642609],"status":[0.0]}}
{"case":"gen0058","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"],[7.0,7.0,44.0]],"n":267},"status":[0.0]}}
{"case":"gen0059","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[180.52314804869428,727.4701086713328,22889.883738527882],[101.34956990500041,180.28695899580202,1997.5269778119787]],"n":327},"status":[0.0]}}
{"case":"gen0060","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[18498.0,18498.0,180786.0]],"n":44},"status":[0.0]}}
{"case":"gen0061","deferred":null,"error":null,"ints":{"status":[0]},"topology":null,"values":{"out":{"blocks":[[64.0,"inf","NaN"]],"n":80}}}
{"case":"gen0062","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[18296.386389867665,18301.103019278762,265872.72591078083]],"n":47},"status":[0.0]}}
{"case":"gen0063","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":59},"status":[0.0]}}
{"case":"gen0064","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":225},"status":[0.0]}}
{"case":"gen0065","deferred":null,"error":null,"ints":{"status":[1001]},"topology":null,"values":{"out":{"blocks":[[140.41479924178725,"inf","NaN"]],"n":44}}}
{"case":"gen0066","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[18299.280639286935,18303.69842846746,265888.7320397126]],"n":47},"status":[0.0]}}
{"case":"gen0067","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":106},"status":[1001.0]}}
@@ -90,23 +78,16 @@
{"case":"gen0069","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[18298.45069942339,18302.502097289725,265880.24930253753]],"n":47},"status":[0.0]}}
{"case":"gen0070","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[18259.043267188274,18259.043267188274,173648.1730687531]],"n":32},"status":[0.0]}}
{"case":"gen0071","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[18255.0,18255.0,173635.0]],"n":32},"status":[0.0]}}
{"case":"gen0072","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":104},"status":[1001.0]}}
{"case":"gen0073","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"],["-inf","inf","-inf"]],"n":335},"status":[0.0]}}
{"case":"gen0074","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":73},"status":[1001.0]}}
{"case":"gen0075","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[18256.0,18256.0,173636.0]],"n":32},"status":[0.0]}}
{"case":"gen0076","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"],["-inf","inf","-inf"],["-inf","inf","-inf"]],"n":634},"status":[0.0]}}
{"case":"gen0077","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[19498.5,19499.5,184788.0]],"n":44},"status":[0.0]}}
{"case":"gen0078","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":[5.0,7.0,0.0,0.14992348372985442,1.489780265193806,3.6256183665669064,-0.9776618977240588,12.572303153107473,0.0,0.0],"status":[1001.0]}}
{"case":"gen0079","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"],[5.0,5.0,31.0]],"n":265},"status":[0.0]}}
{"case":"gen0080","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[17.374848318098287,25.47004619210916,235.84813598861228]],"n":24},"status":[0.0]}}
{"case":"gen0081","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":231},"status":[0.0]}}
{"case":"gen0082","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"],[5.0,5.0,31.0]],"n":265},"status":[0.0]}}
{"case":"gen0083","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[6.715535605583199,65.5075423778336,-147.87701430125787]],"n":58},"status":[1001.0]}}
{"case":"gen0084","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"],[7.024780289766348,7.024780289766348,44.049560579532695]],"n":267},"status":[0.0]}}
{"case":"gen0085","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[74.37030640831864,74.49785900699979,3450.632788337989]],"n":106},"status":[1001.0]}}
{"case":"gen0086","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[14.457686141043885,22.595861080860114,222.9265373106561]],"n":26},"status":[0.0]}}
{"case":"gen0087","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":124},"status":[0.0]}}
{"case":"gen0088","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"],["-inf","inf","-inf"]],"n":401},"status":[0.0]}}
{"case":"gen0089","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":225},"status":[0.0]}}
{"case":"gen0090","deferred":null,"error":null,"ints":{"status":[1001]},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"],["-inf","inf","-inf"],["-inf","inf","-inf"],[398.1287327413357,402.1287327413357,5988.14328772177]],"n":821}}}
{"case":"gen0091","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":88},"status":[0.0]}}
@@ -127,7 +108,6 @@
{"case":"gen0106","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[18293.475573343152,18300.171726055603,265860.08326791826]],"n":47},"status":[0.0]}}
{"case":"gen0107","deferred":null,"error":"null_deref","ints":{},"topology":null,"values":{}}
{"case":"gen0108","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":51},"status":[0.0]}}
{"case":"gen0109","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"],["-inf","inf","-inf"]],"n":301},"status":[0.0]}}
{"case":"gen0110","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[18258.0,18258.0,136988.0]],"n":30},"status":[0.0]}}
{"case":"gen0111","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":116},"status":[0.0]}}
{"case":"gen0112","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[18255.484286696625,18261.258288097968,173636.82414748718]],"n":32},"status":[0.0]}}
@@ -139,27 +119,21 @@
{"case":"gen0118","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[17834.501804220665,17836.20801599369,250576.96815663532]],"n":43},"status":[0.0]}}
{"case":"gen0119","deferred":null,"error":null,"ints":{"status":[1001]},"topology":null,"values":{"out":{"blocks":[[45.0,"inf","NaN"]],"n":74}}}
{"case":"gen0120","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[54.03346495646362,125.40554318276561,1386.7049026892987]],"n":59},"status":[0.0]}}
{"case":"gen0121","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":225},"status":[0.0]}}
{"case":"gen0122","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":119},"status":[0.0]}}
{"case":"gen0123","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"],["-inf","inf","-inf"],["-inf","inf","-inf"],["-inf","inf","-inf"],["-inf","inf","-inf"],["-inf","inf","-inf"],["-inf","inf","-inf"],["-inf","inf","-inf"],["-inf","inf","-inf"],["-inf","inf","-inf"],["-inf","inf","-inf"],["-inf","inf","-inf"],["-inf","inf","-inf"],["-inf","inf","-inf"],["-inf","inf","-inf"],["-inf","inf","-inf"],["-inf","inf","-inf"]],"n":4269},"status":[0.0]}}
{"case":"gen0124","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"],[29758114.28720932,36618241.209518485,325703573.1060371]],"n":297},"status":[0.0]}}
{"case":"gen0125","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":231},"status":[0.0]}}
{"case":"gen0126","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":138},"status":[0.0]}}
{"case":"gen0127","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[18294.439150561375,18304.7317641347,265853.8539234147]],"n":47},"status":[0.0]}}
{"case":"gen0128","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":225},"status":[0.0]}}
{"case":"gen0129","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[34.352571870725555,40.1511693087871,428.6214850978325]],"n":22},"status":[0.0]}}
{"case":"gen0130","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[18296.5,18296.5,265882.5]],"n":47},"status":[0.0]}}
{"case":"gen0131","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":69},"status":[0.0]}}
{"case":"gen0132","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[18258.1,18262.9,136993.1]],"n":30},"status":[0.0]}}
{"case":"gen0133","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"],[5.0,5.0,31.0]],"n":265},"status":[0.0]}}
{"case":"gen0134","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[18258.0,18259.0,136989.0]],"n":30},"status":[0.0]}}
{"case":"gen0135","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[18297.26794451958,18303.3701564394,265892.4419345177]],"n":47},"status":[0.0]}}
{"case":"gen0136","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":231},"status":[0.0]}}
{"case":"gen0137","deferred":null,"error":null,"ints":{"status":[0]},"topology":null,"values":{"out":{"blocks":[[46.0,"inf","NaN"]],"n":110}}}
{"case":"gen0138","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[18299.21991486233,18304.36652477055,265885.51313467877]],"n":47},"status":[0.0]}}
{"case":"gen0139","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[41.247625762346374,55.512668932265655,574.7876670849153]],"n":30},"status":[0.0]}}
{"case":"gen0140","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":149},"status":[0.0]}}
{"case":"gen0141","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"],[5.0,5.0,31.0]],"n":265},"status":[0.0]}}
{"case":"gen0142","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[18257.194949509405,18258.426686288803,173639.39566642733]],"n":32},"status":[0.0]}}
{"case":"gen0143","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[19499.0,19501.0,184788.0]],"n":44},"status":[0.0]}}
{"case":"gen0144","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":[0.700727257950955,-0.700727257950955,0.700727257950955],"status":[0.0]}}
@@ -172,7 +146,6 @@
{"case":"gen0151","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":108},"status":[0.0]}}
{"case":"gen0152","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":129},"status":[0.0]}}
{"case":"gen0153","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[18290.68238137255,18305.576836022785,265862.7048956015]],"n":47},"status":[0.0]}}
{"case":"gen0154","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":189},"status":[0.0]}}
{"case":"gen0155","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":[0.7492542102451745,-0.7492542102451745,-0.7492542102451745],"status":[0.0]}}
{"case":"gen0156","deferred":null,"error":null,"ints":{"status":[1001]},"topology":null,"values":{"out":[1.0,-1.0,-1.0,0.0,0.0,0.0,0.0,1.0,-1.0,-1.0,0.0,0.0,0.0,0.0]}}
{"case":"gen0157","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":120},"status":[0.0]}}
@@ -182,22 +155,17 @@
{"case":"gen0161","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[18258.067034453845,18258.421547433558,136988.6670659214]],"n":30},"status":[0.0]}}
{"case":"gen0162","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[18256.0,18256.0,173636.0]],"n":32},"status":[0.0]}}
{"case":"gen0163","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":[1.6937956274921293,-1.6937956274921293,1.6937956274921293],"status":[0.0]}}
{"case":"gen0164","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[119.60670574677694,119.60699008450412,9105.603909279405]],"n":183},"status":[0.0]}}
{"case":"gen0165","deferred":null,"error":"null_deref","ints":{},"topology":null,"values":{}}
{"case":"gen0166","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":169},"status":[0.0]}}
{"case":"gen0167","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"],["-inf","inf","-inf"]],"n":333},"status":[0.0]}}
{"case":"gen0168","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[75506.90733211041,550724.141835963,15931147.809042787],[4.0,4.0,22.0]],"n":263},"status":[0.0]}}
{"case":"gen0169","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":124},"status":[0.0]}}
{"case":"gen0170","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":[4.0,2.0,5.0,2.0,0.0,0.8759016206147161,4.227562371146,3.144278826281761,1.762484532912571,0.9172368893574865,-0.11292459211567629,0.0,-1.400495296273657],"status":[0.0]}}
{"case":"gen0171","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":216},"status":[0.0]}}
{"case":"gen0172","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":[1.249613322626349,-1.249613322626349,1.249613322626349],"status":[0.0]}}
{"case":"gen0173","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"],["-inf","inf","-inf"]],"n":289},"status":[0.0]}}
{"case":"gen0174","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[18256.94009695229,18257.408853835866,173642.99476625095]],"n":32},"status":[0.0]}}
{"case":"gen0175","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[8.071619130343828,98.38787571281117,24.68864117833072]],"n":57},"status":[0.0]}}
{"case":"gen0176","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":111},"status":[1001.0]}}
{"case":"gen0177","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":189},"status":[0.0]}}
{"case":"gen0178","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"],[1.0,1.0,1.0]],"n":257},"status":[0.0]}}
{"case":"gen0179","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[-2.2766585842512246,270.96654121489047,-1430.937423237151]],"n":155},"status":[0.0]}}
{"case":"gen0180","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":111},"status":[1001.0]}}
{"case":"gen0181","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":211},"status":[0.0]}}
{"case":"gen0182","deferred":null,"error":null,"ints":{"status":[1001]},"topology":null,"values":{"out":{"blocks":[[-1.1381891465141285,"inf","NaN"]],"n":44}}}
@@ -206,7 +174,6 @@
{"case":"gen0185","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[18255.0,18255.0,173635.0]],"n":32},"status":[0.0]}}
{"case":"gen0186","deferred":null,"error":null,"ints":{"status":[0]},"topology":null,"values":{"out":{"blocks":[[157.7141379525543,189.7141379525543,1520.4217885462094]],"n":50}}}
{"case":"gen0187","deferred":null,"error":null,"ints":{"status":[0]},"topology":null,"values":{"out":{"blocks":[[-3.0,"inf","NaN"]],"n":110}}}
{"case":"gen0188","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[275.0685299938543,577.1295534630912,31860.15517280302]],"n":253},"status":[0.0]}}
{"case":"gen0189","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":250},"status":[0.0]}}
{"case":"gen0190","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[18257.0,18257.0,173638.0]],"n":32},"status":[0.0]}}
{"case":"gen0191","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[18257.5,18259.5,136988.0]],"n":30},"status":[0.0]}}
@@ -220,53 +187,40 @@
{"case":"gen0199","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[18258.1,18260.6,136990.8]],"n":30},"status":[0.0]}}
{"case":"gen0200","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[416149.42252508324,440414.7138257905,56433022.27637162],[4.0,4.0,10.0]],"n":260},"status":[0.0]}}
{"case":"gen0201","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":68},"status":[0.0]}}
{"case":"gen0202","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":225},"status":[0.0]}}
{"case":"gen0203","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[9.422974016846638,116.75291678011979,-133.8324127155483]],"n":71},"status":[0.0]}}
{"case":"gen0204","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[18257.5,18259.5,136988.0]],"n":30},"status":[0.0]}}
{"case":"gen0205","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":235},"status":[0.0]}}
{"case":"gen0206","deferred":null,"error":null,"ints":{"status":[0]},"topology":null,"values":{"out":{"blocks":[[151.8,165.0,2183.6000000000004]],"n":50}}}
{"case":"gen0207","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":129},"status":[0.0]}}
{"case":"gen0208","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[17.237422340126837,88.49804693690186,219.75316897700202]],"n":57},"status":[0.0]}}
{"case":"gen0209","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":129},"status":[0.0]}}
{"case":"gen0210","deferred":null,"error":null,"ints":{"status":[1001]},"topology":null,"values":{"out":{"blocks":[[4.5,"inf","NaN"]],"n":44}}}
{"case":"gen0211","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":216},"status":[0.0]}}
{"case":"gen0212","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"],["-inf","inf","-inf"],["-inf","inf","-inf"],["-inf","inf","-inf"],["-inf","inf","-inf"],["-inf","inf","-inf"],["-inf","inf","-inf"],["-inf","inf","-inf"],["-inf","inf","-inf"],["-inf","inf","-inf"],["-inf","inf","-inf"],[23.93333333333333,23.93333333333333,352.44444444444446]],"n":2843},"status":[0.0]}}
{"case":"gen0213","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[16.816576573850238,33.14331414123698,66.21164946340744]],"n":70},"status":[0.0]}}
{"case":"gen0214","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"],[13.1064721038207,13.106482016785705,291.24532320588946]],"n":290},"status":[0.0]}}
{"case":"gen0215","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":250},"status":[0.0]}}
{"case":"gen0216","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[18256.0,18256.0,173636.0]],"n":32},"status":[0.0]}}
{"case":"gen0217","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[18256.152972406002,18256.24856857762,173637.65968770982]],"n":32},"status":[0.0]}}
{"case":"gen0218","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"],["-inf","inf","-inf"]],"n":339},"status":[0.0]}}
{"case":"gen0219","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":123},"status":[0.0]}}
{"case":"gen0220","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[18258.1,18262.9,136993.1]],"n":30},"status":[0.0]}}
{"case":"gen0221","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[-57.47759641180761,431.18408494827537,-4836.202581136356]],"n":155},"status":[0.0]}}
{"case":"gen0222","deferred":null,"error":null,"ints":{"status":[1001]},"topology":null,"values":{"out":{"blocks":[[68.88301782571615,"inf","NaN"]],"n":44}}}
{"case":"gen0223","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"],["-inf","inf","-inf"]],"n":395},"status":[0.0]}}
{"case":"gen0224","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[-81219.33710753745,408754.7756673256,-10009913.548529286],[4.0,4.0,22.0]],"n":263},"status":[0.0]}}
{"case":"gen0225","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":235},"status":[0.0]}}
{"case":"gen0226","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[10723.286506043167,12146.20980605266,178603.41050716396]],"n":27},"status":[0.0]}}
{"case":"gen0227","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":69},"status":[0.0]}}
{"case":"gen0228","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[6.499065816668671,30.98831768355978,-84.91468393063364]],"n":72},"status":[0.0]}}
{"case":"gen0229","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":77},"status":[0.0]}}
{"case":"gen0230","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":[0.4204765514268215,-0.4204765514268215,-0.4204765514268215],"status":[0.0]}}
{"case":"gen0231","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"],[7.889624359119243,7.889624359119243,33.88962435911924]],"n":265},"status":[0.0]}}
{"case":"gen0232","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[17839.994703779477,17839.994703779477,197096.34125525088]],"n":40},"status":[0.0]}}
{"case":"gen0233","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[17887.367537482154,17964.75035123513,251159.01564335014]],"n":43},"status":[0.0]}}
{"case":"gen0234","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":89},"status":[1001.0]}}
{"case":"gen0235","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[18259.624224479143,18259.624224479143,173650.49689791657]],"n":32},"status":[0.0]}}
{"case":"gen0236","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[54120151.63594405,330931152.36450464,12949256167.586412],[4.0,4.0,22.0]],"n":263},"status":[0.0]}}
{"case":"gen0237","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"],["-inf","inf","-inf"]],"n":301},"status":[0.0]}}
{"case":"gen0238","deferred":null,"error":null,"ints":{"status":[1001]},"topology":null,"values":{"out":{"blocks":[[66.0,"inf","NaN"]],"n":44}}}
{"case":"gen0239","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":[5.0,3.0,0.0,-0.3669098818748153,2.7911032128555315,1.126695186549174,-0.8330652944227346,-999988.097181181,0.10464627405470939,-0.5136936038178358,-0.5136936038178358],"status":[0.0]}}
{"case":"gen0240","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[18257.803732229702,18257.803732229702,136987.15105604386]],"n":30},"status":[0.0]}}
{"case":"gen0241","deferred":null,"error":null,"ints":{"status":[1001]},"topology":null,"values":{"out":[1.0,-1.0,-1.0,0.0,0.0,0.0,0.0,1.0,-1.0,-1.0,0.0,0.0,0.0,0.0]}}
{"case":"gen0242","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[18498.5,18498.5,180788.0]],"n":44},"status":[0.0]}}
{"case":"gen0243","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[18259.14381534973,18263.70631744776,136996.16650659664]],"n":30},"status":[0.0]}}
{"case":"gen0244","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":129},"status":[0.0]}}
{"case":"gen0245","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[18256.92032379099,18256.92032379099,173639.27635434334]],"n":32},"status":[0.0]}}
{"case":"gen0246","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[18498.5,18501.5,180791.0]],"n":44},"status":[0.0]}}
{"case":"gen0247","deferred":null,"error":null,"ints":{"status":[0]},"topology":null,"values":{"out":{"blocks":[[66.0,"inf","NaN"]],"n":110}}}
{"case":"gen0248","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":144},"status":[0.0]}}
{"case":"gen0249","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[18257.815829370153,18258.439653316884,136988.0236249891]],"n":30},"status":[0.0]}}
{"case":"gen0250","deferred":null,"error":null,"ints":{"status":[0]},"topology":null,"values":{"out":{"blocks":[[58.0,"inf","NaN"]],"n":110}}}
{"case":"gen0251","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":83},"status":[0.0]}}
@@ -276,18 +230,14 @@
{"case":"gen0255","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[18499.0,18500.0,180790.0]],"n":44},"status":[0.0]}}
{"case":"gen0256","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"],["-inf","inf","-inf"]],"n":330},"status":[0.0]}}
{"case":"gen0257","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[37.84649764403495,43.20826890431039,499.63262428216814]],"n":23},"status":[0.0]}}
{"case":"gen0258","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":124},"status":[0.0]}}
{"case":"gen0259","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[18296.5,18296.5,265882.5]],"n":47},"status":[0.0]}}
{"case":"gen0260","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":124},"status":[0.0]}}
{"case":"gen0261","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"],["-inf","inf","-inf"]],"n":412},"status":[0.0]}}
{"case":"gen0262","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":147},"status":[0.0]}}
{"case":"gen0263","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":225},"status":[0.0]}}
{"case":"gen0264","deferred":null,"error":null,"ints":{"status":[1001]},"topology":null,"values":{"out":[1.0,-1.0,-1.0,0.0,0.0,0.0,0.0,1.0,-1.0,-1.0,0.0,0.0,0.0,0.0]}}
{"case":"gen0265","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":69},"status":[0.0]}}
{"case":"gen0266","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[18257.0,18257.0,173638.0]],"n":32},"status":[0.0]}}
{"case":"gen0267","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[18258.942148490045,18258.942148490045,173647.76859396018]],"n":32},"status":[0.0]}}
{"case":"gen0268","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[18299.15572129129,18301.711330999227,265885.355944458]],"n":47},"status":[0.0]}}
{"case":"gen0269","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[129.09482759896758,129.09535620195328,11074.677641166782]],"n":209},"status":[0.0]}}
{"case":"gen0270","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[155.1938764479588,155.582474680747,15338.275417589317],[40.40371742624278,40.56053267151692,3594.403682189122]],"n":408},"status":[0.0]}}
{"case":"gen0271","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"],["-inf","inf","-inf"]],"n":310},"status":[0.0]}}
{"case":"gen0272","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":69},"status":[0.0]}}
@@ -295,29 +245,20 @@
{"case":"gen0274","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[18256.38001394367,18260.16444795651,173639.4122727811]],"n":32},"status":[0.0]}}
{"case":"gen0275","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":111},"status":[1001.0]}}
{"case":"gen0276","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[18304.26293993151,18304.26293993151,265911.99917173974]],"n":47},"status":[0.0]}}
{"case":"gen0277","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[20.514142578877617,708.4652188159666,-11401.654370290515],[4.0,4.0,22.0]],"n":263},"status":[0.0]}}
{"case":"gen0278","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[295748971.23875046,439401727.47217244,46608384294.30595],[-3814701.3749021823,83034823.7115323,-294874050.3363173]],"n":321},"status":[0.0]}}
{"case":"gen0279","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":225},"status":[0.0]}}
{"case":"gen0280","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":253},"status":[0.0]}}
{"case":"gen0281","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[38.78441515490289,85.5557055243537,1349.8101520631574]],"n":70},"status":[0.0]}}
{"case":"gen0282","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[18257.0,18257.0,173638.0]],"n":32},"status":[0.0]}}
{"case":"gen0283","deferred":null,"error":null,"ints":{"status":[0]},"topology":null,"values":{"out":{"blocks":[[121.0,133.0,1199.0]],"n":50}}}
{"case":"gen0284","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":225},"status":[0.0]}}
{"case":"gen0285","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":225},"status":[0.0]}}
{"case":"gen0286","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[72.01916756870285,170.16251593311634,541.1657774252519]],"n":77},"status":[0.0]}}
{"case":"gen0287","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":71},"status":[1001.0]}}
{"case":"gen0288","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":101},"status":[0.0]}}
{"case":"gen0289","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"],[6.0,6.0,27.0]],"n":263},"status":[0.0]}}
{"case":"gen0290","deferred":null,"error":null,"ints":{"status":[1001]},"topology":null,"values":{"out":{"blocks":[[692.202403549369,"inf","NaN"]],"n":44}}}
{"case":"gen0291","deferred":null,"error":null,"ints":{"status":[0]},"topology":null,"values":{"out":{"blocks":[[65.0,"inf","NaN"]],"n":80}}}
{"case":"gen0292","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[18827.47638555042,18838.211821210596,222892.94546787982]],"n":41},"status":[0.0]}}
{"case":"gen0293","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[152.21127853627863,152.410561877325,15010.31255792543],[21.143722555962277,21.2253579234608,844.6201357045676]],"n":321},"status":[0.0]}}
{"case":"gen0294","deferred":null,"error":null,"ints":{"status":[0]},"topology":null,"values":{"out":{"blocks":[[96.0,"inf","NaN"]],"n":80}}}
{"case":"gen0295","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":169},"status":[0.0]}}
{"case":"gen0296","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[18293.018259295866,18300.266808365017,265858.5211611576]],"n":47},"status":[0.0]}}
{"case":"gen0297","deferred":null,"error":null,"ints":{"status":[0]},"topology":null,"values":{"out":{"blocks":[[71.0,"inf","NaN"]],"n":110}}}
{"case":"gen0298","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[18498.999999999,18499.000000002998,180789.99999999598]],"n":44},"status":[0.0]}}
{"case":"gen0299","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":71},"status":[1001.0]}}
{"case":"gen0300","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[18498.0,18502.0,180786.0]],"n":44},"status":[0.0]}}
{"case":"gen0301","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":73},"status":[1007.0]}}
{"case":"gen0302","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":[4.0,2.0,4.0,0.0,0.0,-0.8386061494079766,-1.4375489894865572,-2.5298613515556365,2.4448218499082772,0.44412328382130783,1.555746770941871,-0.8369237095419888],"status":[0.0]}}
@@ -331,7 +272,6 @@
{"case":"gen0310","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[-61558373.93168993,223094052.63812837,-4482071623.009551]],"n":126},"status":[1001.0]}}
{"case":"gen0311","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[18256.625235823158,18256.625235823158,173638.00171866466]],"n":32},"status":[0.0]}}
{"case":"gen0312","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[150164336.01745173,511781980.7910377,20360737778.6063],[-23938616.51299342,146479950.87323606,-843588799.0751429]],"n":329},"status":[0.0]}}
{"case":"gen0313","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":124},"status":[0.0]}}
{"case":"gen0314","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[18258.0,18260.0,136990.0]],"n":30},"status":[0.0]}}
{"case":"gen0315","deferred":null,"error":null,"ints":{"status":[0]},"topology":null,"values":{"out":{"blocks":[[-4.0,"inf","NaN"]],"n":80}}}
{"case":"gen0316","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[12.447564456846914,35.17424681971284,-52.49356933015319]],"n":59},"status":[0.0]}}
@@ -345,13 +285,9 @@
{"case":"gen0324","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[18254.357920063776,18257.725136463916,173632.11528845518]],"n":32},"status":[0.0]}}
{"case":"gen0325","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":59},"status":[0.0]}}
{"case":"gen0326","deferred":null,"error":null,"ints":{"status":[0]},"topology":null,"values":{"out":{"blocks":[[74.0,"inf","NaN"]],"n":80}}}
{"case":"gen0327","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":129},"status":[0.0]}}
{"case":"gen0328","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"],["-inf","inf","-inf"]],"n":318},"status":[0.0]}}
{"case":"gen0329","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"],["-inf","inf","-inf"]],"n":310},"status":[0.0]}}
{"case":"gen0330","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"],["-inf","inf","-inf"],["-inf","inf","-inf"]],"n":656},"status":[0.0]}}
{"case":"gen0331","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":119},"status":[0.0]}}
{"case":"gen0332","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[41.21304491191255,788.3534105840207,-676.4274077530732],[143.21120941769567,181.925358794706,3401.5579178433522]],"n":327},"status":[0.0]}}
{"case":"gen0333","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[123.4691622860927,596.7474267784772,3308.801542974873]],"n":253},"status":[0.0]}}
{"case":"gen0334","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":31},"status":[0.0]}}
{"case":"gen0335","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":230},"status":[0.0]}}
{"case":"gen0336","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[344.71903929841693,344.7197570019045,36025.36251893895],[63.99974134916124,64.00033501272898,8127.971353809305],[56.84344504932075,56.844084106495494,7090.306698122426],[57.10387587855283,57.104327125375136,7403.909158697731],[64.00003936924709,64.00041227968383,8128.007289509658],[59.966714724547195,59.9669720560851,7349.565106083112],[55.67294585057379,55.67304622449565,7070.467669620981],[62.30901978345994,62.309036433898804,8085.775529230678],[62.809939490679234,62.809939490679234,7818.933509325813],[54.190476190476204,54.190476190476204,2995.52380952381]],"n":2393},"status":[0.0]}}
@@ -363,7 +299,6 @@
{"case":"gen0342","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[18498.000000001,18498.000000002998,180786.0]],"n":44},"status":[0.0]}}
{"case":"gen0343","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[18257.360675552052,18260.08202665615,136988.57699432565]],"n":30},"status":[0.0]}}
{"case":"gen0344","deferred":null,"error":null,"ints":{"status":[1001]},"topology":null,"values":{"out":[1.0,-1.0,-1.0,0.0,0.0,0.0,0.0,1.0,-1.0,-1.0,0.0,0.0,0.0,0.0]}}
{"case":"gen0345","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":230},"status":[0.0]}}
{"case":"gen0346","deferred":null,"error":null,"ints":{"status":[0]},"topology":null,"values":{"out":{"blocks":[[50.0,"inf","NaN"]],"n":80}}}
{"case":"gen0347","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[186.27461581506793,186.27470995890937,18299.667001817088],[54.0299784915577,54.03006405881243,7143.32480747954],[65.84168357144193,65.84216369614728,9692.66950699445]],"n":755},"status":[0.0]}}
{"case":"gen0348","deferred":null,"error":null,"ints":{"status":[1001]},"topology":null,"values":{"out":{"blocks":[[-1.2606361610308987,"inf","NaN"]],"n":44}}}
@@ -373,11 +308,8 @@
{"case":"gen0352","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":[1.1097433346864831,-1.1097433346864831,-1.1097433346864831],"status":[0.0]}}
{"case":"gen0353","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":256},"status":[0.0]}}
{"case":"gen0354","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[106.8742903192942,107.2540203581474,7503.197485484877]],"n":168},"status":[0.0]}}
{"case":"gen0355","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"],[5.0,5.0,31.0]],"n":265},"status":[0.0]}}
{"case":"gen0356","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":68},"status":[1001.0]}}
{"case":"gen0357","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"],[4.666666666666666,4.666666666666666,14.666666666666666]],"n":261},"status":[0.0]}}
{"case":"gen0358","deferred":null,"error":null,"ints":{"status":[1001]},"topology":null,"values":{"out":{"blocks":[[690.202403549369,"inf","NaN"]],"n":44}}}
{"case":"gen0359","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":101},"status":[1001.0]}}
{"case":"gen0360","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[18258.0,18258.5,136988.5]],"n":30},"status":[0.0]}}
{"case":"gen0361","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[35.01121929268353,44.409888783953484,412.42966873004235]],"n":23},"status":[0.0]}}
{"case":"gen0362","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[19833.46173873513,19847.798039383822,299241.4758173968]],"n":45},"status":[0.0]}}
@@ -398,14 +330,11 @@
{"case":"gen0377","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"],["-inf","inf","-inf"],["-inf","inf","-inf"]],"n":689},"status":[0.0]}}
{"case":"gen0378","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":209},"status":[0.0]}}
{"case":"gen0379","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":127},"status":[0.0]}}
{"case":"gen0380","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[148.86920947275829,148.86945339524334,14886.899629102365]],"n":253},"status":[0.0]}}
{"case":"gen0381","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":79},"status":[0.0]}}
{"case":"gen0382","deferred":null,"error":null,"ints":{"status":[0]},"topology":null,"values":{"out":{"blocks":[[51.0,"inf","NaN"]],"n":110}}}
{"case":"gen0383","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":124},"status":[0.0]}}
{"case":"gen0384","deferred":null,"error":null,"ints":{"status":[1001]},"topology":null,"values":{"out":[1.0,-1.0,-1.0,0.0,0.0,0.0,0.0,1.0,-1.0,-1.0,0.0,0.0,0.0,0.0]}}
{"case":"gen0385","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":116},"status":[0.0]}}
{"case":"gen0386","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[29.020004517250847,167.74973678247162,-295.90368728443195]],"n":70},"status":[0.0]}}
{"case":"gen0387","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[146.82799066498552,147.4464670311385,13731.375754329967],[17.029387024300174,17.03270478355391,438.7708047631735]],"n":297},"status":[0.0]}}
{"case":"gen0388","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":73},"status":[1007.0]}}
{"case":"gen0389","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[18255.790660769228,18257.22055117476,173635.87758827966]],"n":32},"status":[0.0]}}
{"case":"gen0390","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"],[37.142922950097656,42.80241665207909,701.0809046257526]],"n":299},"status":[0.0]}}
@@ -418,18 +347,12 @@
{"case":"gen0397","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"],["-inf","inf","-inf"]],"n":335},"status":[0.0]}}
{"case":"gen0398","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[18299.24442232531,18305.224871307324,265878.7723690119]],"n":47},"status":[0.0]}}
{"case":"gen0399","deferred":null,"error":null,"ints":{"status":[0]},"topology":null,"values":{"out":{"blocks":[[50.0,"inf","NaN"]],"n":80}}}
{"case":"gen0400","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"],["-inf","inf","-inf"]],"n":320},"status":[0.0]}}
{"case":"gen0401","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":101},"status":[0.0]}}
{"case":"gen0402","deferred":null,"error":null,"ints":{"status":[0]},"topology":null,"values":{"out":{"blocks":[[39.0,"inf","NaN"]],"n":110}}}
{"case":"gen0403","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"],[17.696305551609246,17.696305551609246,65.39261110321848]],"n":267},"status":[0.0]}}
{"case":"gen0404","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[18257.768271876805,18259.536543753613,136989.21518567338]],"n":30},"status":[0.0]}}
{"case":"gen0405","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":230},"status":[0.0]}}
{"case":"gen0406","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":119},"status":[0.0]}}
{"case":"gen0407","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":124},"status":[0.0]}}
{"case":"gen0408","deferred":null,"error":null,"ints":{"status":[1001]},"topology":null,"values":{"out":{"blocks":[[55.63518285869904,"inf","NaN"]],"n":44}}}
{"case":"gen0409","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[18255.310482131157,18256.952819974613,173637.06309744634]],"n":32},"status":[0.0]}}
{"case":"gen0410","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":49},"status":[0.0]}}
{"case":"gen0411","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"],["-inf","inf","-inf"]],"n":321},"status":[0.0]}}
{"case":"gen0412","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[18259.71973224573,18259.71973224573,173648.87892898291]],"n":32},"status":[0.0]}}
{"case":"gen0413","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":[1.5486024527900069,-1.5486024527900069,-1.5486024527900069],"status":[0.0]}}
{"case":"gen0414","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[18501.000001,18501.000001,180792.000004]],"n":44},"status":[0.0]}}
@@ -438,7 +361,6 @@
{"case":"gen0417","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":96},"status":[0.0]}}
{"case":"gen0418","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[17296.345128672714,19299.9058008047,264886.84698762756]],"n":47},"status":[0.0]}}
{"case":"gen0419","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":109},"status":[0.0]}}
{"case":"gen0420","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":119},"status":[0.0]}}
{"case":"gen0421","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[18258.0,18259.0,136989.0]],"n":30},"status":[0.0]}}
{"case":"gen0422","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":231},"status":[0.0]}}
{"case":"gen0423","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"],[36011.88385152597,139044.1318124444,2546019.8901707316]],"n":402},"status":[0.0]}}
@@ -462,16 +384,13 @@
{"case":"gen0441","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":230},"status":[0.0]}}
{"case":"gen0442","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":[0.22588794268292206,-0.22588794268292206,0.22588794268292206],"status":[0.0]}}
{"case":"gen0443","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"],[24072.125539473585,51221.53031680138,342053.86742064875]],"n":302},"status":[0.0]}}
{"case":"gen0444","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":129},"status":[0.0]}}
{"case":"gen0445","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":78},"status":[1001.0]}}
{"case":"gen0446","deferred":null,"error":null,"ints":{"status":[0]},"topology":null,"values":{"out":{"blocks":[[115.5,133.5,1233.0]],"n":50}}}
{"case":"gen0447","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[19499.0,19501.0,184786.0]],"n":44},"status":[0.0]}}
{"case":"gen0448","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[72345915.98753832,451653978.03782314,16988537705.896158],[11405406.824168082,26951396.838783585,124754925.44691914]],"n":292},"status":[0.0]}}
{"case":"gen0449","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[18499.000000002998,18499.000000002998,180790.000000006]],"n":44},"status":[0.0]}}
{"case":"gen0450","deferred":null,"error":null,"ints":{"status":[0]},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":92}}}
{"case":"gen0451","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":134},"status":[1001.0]}}
{"case":"gen0452","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[18258.20792960636,18258.20792960636,136987.84097308016]],"n":30},"status":[0.0]}}
{"case":"gen0453","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"],[5.540743695421119,5.540743695421119,31.54074369542112]],"n":265},"status":[0.0]}}
{"case":"gen0454","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":86},"status":[1001.0]}}
{"case":"gen0455","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":77},"status":[0.0]}}
{"case":"gen0456","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[18498.000000001,18498.000000002998,180786.0]],"n":44},"status":[0.0]}}
@@ -479,11 +398,9 @@
{"case":"gen0458","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[18294.291779222636,18302.617676318063,265857.6399850318]],"n":47},"status":[0.0]}}
{"case":"gen0459","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":209},"status":[0.0]}}
{"case":"gen0460","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[18258.0,18258.0,136988.0]],"n":30},"status":[0.0]}}
{"case":"gen0461","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":83},"status":[1001.0]}}
{"case":"gen0462","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[18256.121124323174,18258.049632323113,173637.44875129266]],"n":32},"status":[0.0]}}
{"case":"gen0463","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[18297.21406688747,18301.023444812454,265880.8328227374]],"n":47},"status":[0.0]}}
{"case":"gen0464","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":96},"status":[0.0]}}
{"case":"gen0465","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[-138323233.7222958,485188202.3332747,-28041455489.83091],[4.0,4.0,22.0]],"n":263},"status":[0.0]}}
{"case":"gen0466","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[18498.5,18500.5,180789.0]],"n":44},"status":[0.0]}}
{"case":"gen0467","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":86},"status":[0.0]}}
{"case":"gen0468","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":41},"status":[0.0]}}
@@ -494,8 +411,6 @@
{"case":"gen0473","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[18258.0,18260.0,136990.0]],"n":30},"status":[0.0]}}
{"case":"gen0474","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":129},"status":[1001.0]}}
{"case":"gen0475","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[18498.5,18498.5,180788.0]],"n":44},"status":[0.0]}}
{"case":"gen0476","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":124},"status":[0.0]}}
{"case":"gen0477","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":53},"status":[1001.0]}}
{"case":"gen0478","deferred":null,"error":null,"ints":{"status":[0]},"topology":null,"values":{"out":{"blocks":[[95.0,"inf","NaN"]],"n":80}}}
{"case":"gen0479","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[18257.78563004376,18257.78563004376,136986.20493328886]],"n":30},"status":[0.0]}}
{"case":"linear_box_edge_chamfer","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":31},"status":[0.0]}}
@@ -511,114 +426,6 @@
{"case":"rev_base_line1","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":119},"status":[0.0]}}
{"case":"rev_base_line2","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":111},"status":[0.0]}}
{"case":"rev_base_line3","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":100},"status":[0.0]}}
{"case":"rev_blend_c1_sc0.7_side0_s0.001","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":235},"status":[0.0]}}
{"case":"rev_blend_c1_sc0.7_side0_s1.0","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":235},"status":[0.0]}}
{"case":"rev_blend_c1_sc0.7_side0_s1000.0","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":235},"status":[0.0]}}
{"case":"rev_blend_c1_sc0.7_side1_s0.001","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":235},"status":[0.0]}}
{"case":"rev_blend_c1_sc0.7_side1_s1.0","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":235},"status":[0.0]}}
{"case":"rev_blend_c1_sc0.7_side1_s1000.0","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":235},"status":[0.0]}}
{"case":"rev_blend_c1_sc0.7_side2_s0.001","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":235},"status":[0.0]}}
{"case":"rev_blend_c1_sc0.7_side2_s1.0","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":235},"status":[0.0]}}
{"case":"rev_blend_c1_sc0.7_side2_s1000.0","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":235},"status":[0.0]}}
{"case":"rev_blend_c1_sc1.5_side0_s0.001","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":235},"status":[0.0]}}
{"case":"rev_blend_c1_sc1.5_side0_s1.0","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":235},"status":[0.0]}}
{"case":"rev_blend_c1_sc1.5_side0_s1000.0","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":235},"status":[0.0]}}
{"case":"rev_blend_c1_sc1.5_side1_s0.001","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":235},"status":[0.0]}}
{"case":"rev_blend_c1_sc1.5_side1_s1.0","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":235},"status":[0.0]}}
{"case":"rev_blend_c1_sc1.5_side1_s1000.0","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":235},"status":[0.0]}}
{"case":"rev_blend_c1_sc1.5_side2_s0.001","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":235},"status":[0.0]}}
{"case":"rev_blend_c1_sc1.5_side2_s1.0","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":235},"status":[0.0]}}
{"case":"rev_blend_c1_sc1.5_side2_s1000.0","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":235},"status":[0.0]}}
{"case":"rev_blend_c1_sc2.5_side0_s0.001","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":235},"status":[0.0]}}
{"case":"rev_blend_c1_sc2.5_side0_s1.0","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":235},"status":[0.0]}}
{"case":"rev_blend_c1_sc2.5_side0_s1000.0","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":235},"status":[0.0]}}
{"case":"rev_blend_c1_sc2.5_side1_s0.001","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":235},"status":[0.0]}}
{"case":"rev_blend_c1_sc2.5_side1_s1.0","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":235},"status":[0.0]}}
{"case":"rev_blend_c1_sc2.5_side1_s1000.0","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":235},"status":[0.0]}}
{"case":"rev_blend_c1_sc2.5_side2_s0.001","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":235},"status":[0.0]}}
{"case":"rev_blend_c1_sc2.5_side2_s1.0","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":235},"status":[0.0]}}
{"case":"rev_blend_c1_sc2.5_side2_s1000.0","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":235},"status":[0.0]}}
{"case":"rev_blend_c2_sc0.7_side0_s0.001","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":235},"status":[0.0]}}
{"case":"rev_blend_c2_sc0.7_side0_s1.0","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":235},"status":[0.0]}}
{"case":"rev_blend_c2_sc0.7_side0_s1000.0","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":235},"status":[0.0]}}
{"case":"rev_blend_c2_sc0.7_side1_s0.001","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"],["-inf","inf","-inf"]],"n":287},"status":[0.0]}}
{"case":"rev_blend_c2_sc0.7_side1_s1.0","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"],["-inf","inf","-inf"]],"n":287},"status":[0.0]}}
{"case":"rev_blend_c2_sc0.7_side1_s1000.0","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"],["-inf","inf","-inf"]],"n":287},"status":[0.0]}}
{"case":"rev_blend_c2_sc0.7_side2_s0.001","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"],["-inf","inf","-inf"]],"n":287},"status":[0.0]}}
{"case":"rev_blend_c2_sc0.7_side2_s1.0","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"],["-inf","inf","-inf"]],"n":287},"status":[0.0]}}
{"case":"rev_blend_c2_sc0.7_side2_s1000.0","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"],["-inf","inf","-inf"]],"n":287},"status":[0.0]}}
{"case":"rev_blend_c2_sc1.5_side0_s0.001","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":235},"status":[0.0]}}
{"case":"rev_blend_c2_sc1.5_side0_s1.0","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":235},"status":[0.0]}}
{"case":"rev_blend_c2_sc1.5_side0_s1000.0","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":235},"status":[0.0]}}
{"case":"rev_blend_c2_sc1.5_side1_s0.001","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"],["-inf","inf","-inf"]],"n":287},"status":[0.0]}}
{"case":"rev_blend_c2_sc1.5_side1_s1.0","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"],["-inf","inf","-inf"]],"n":287},"status":[0.0]}}
{"case":"rev_blend_c2_sc1.5_side1_s1000.0","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"],["-inf","inf","-inf"]],"n":287},"status":[0.0]}}
{"case":"rev_blend_c2_sc1.5_side2_s0.001","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"],["-inf","inf","-inf"]],"n":287},"status":[0.0]}}
{"case":"rev_blend_c2_sc1.5_side2_s1.0","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"],["-inf","inf","-inf"]],"n":287},"status":[0.0]}}
{"case":"rev_blend_c2_sc1.5_side2_s1000.0","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"],["-inf","inf","-inf"]],"n":287},"status":[0.0]}}
{"case":"rev_blend_c2_sc2.5_side0_s0.001","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":235},"status":[0.0]}}
{"case":"rev_blend_c2_sc2.5_side0_s1.0","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":235},"status":[0.0]}}
{"case":"rev_blend_c2_sc2.5_side0_s1000.0","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":235},"status":[0.0]}}
{"case":"rev_blend_c2_sc2.5_side1_s0.001","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"],["-inf","inf","-inf"]],"n":287},"status":[0.0]}}
{"case":"rev_blend_c2_sc2.5_side1_s1.0","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"],["-inf","inf","-inf"]],"n":287},"status":[0.0]}}
{"case":"rev_blend_c2_sc2.5_side1_s1000.0","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"],["-inf","inf","-inf"]],"n":287},"status":[0.0]}}
{"case":"rev_blend_c2_sc2.5_side2_s0.001","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"],["-inf","inf","-inf"]],"n":287},"status":[0.0]}}
{"case":"rev_blend_c2_sc2.5_side2_s1.0","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"],["-inf","inf","-inf"]],"n":287},"status":[0.0]}}
{"case":"rev_blend_c2_sc2.5_side2_s1000.0","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"],["-inf","inf","-inf"]],"n":287},"status":[0.0]}}
{"case":"rev_blend_c3_sc0.7_side0_s0.001","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":235},"status":[0.0]}}
{"case":"rev_blend_c3_sc0.7_side0_s1.0","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":235},"status":[0.0]}}
{"case":"rev_blend_c3_sc0.7_side0_s1000.0","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":235},"status":[0.0]}}
{"case":"rev_blend_c3_sc0.7_side1_s0.001","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"],["-inf","inf","-inf"]],"n":339},"status":[0.0]}}
{"case":"rev_blend_c3_sc0.7_side1_s1.0","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"],["-inf","inf","-inf"]],"n":339},"status":[0.0]}}
{"case":"rev_blend_c3_sc0.7_side1_s1000.0","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"],["-inf","inf","-inf"]],"n":339},"status":[0.0]}}
{"case":"rev_blend_c3_sc0.7_side2_s0.001","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"],["-inf","inf","-inf"]],"n":339},"status":[0.0]}}
{"case":"rev_blend_c3_sc0.7_side2_s1.0","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"],["-inf","inf","-inf"]],"n":339},"status":[0.0]}}
{"case":"rev_blend_c3_sc0.7_side2_s1000.0","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"],["-inf","inf","-inf"]],"n":339},"status":[0.0]}}
{"case":"rev_blend_c3_sc1.5_side0_s0.001","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":235},"status":[0.0]}}
{"case":"rev_blend_c3_sc1.5_side0_s1.0","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":235},"status":[0.0]}}
{"case":"rev_blend_c3_sc1.5_side0_s1000.0","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":235},"status":[0.0]}}
{"case":"rev_blend_c3_sc1.5_side1_s0.001","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"],["-inf","inf","-inf"]],"n":339},"status":[0.0]}}
{"case":"rev_blend_c3_sc1.5_side1_s1.0","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"],["-inf","inf","-inf"]],"n":339},"status":[0.0]}}
{"case":"rev_blend_c3_sc1.5_side1_s1000.0","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"],["-inf","inf","-inf"]],"n":339},"status":[0.0]}}
{"case":"rev_blend_c3_sc1.5_side2_s0.001","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"],["-inf","inf","-inf"]],"n":339},"status":[0.0]}}
{"case":"rev_blend_c3_sc1.5_side2_s1.0","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"],["-inf","inf","-inf"]],"n":339},"status":[0.0]}}
{"case":"rev_blend_c3_sc1.5_side2_s1000.0","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"],["-inf","inf","-inf"]],"n":339},"status":[0.0]}}
{"case":"rev_blend_c3_sc2.5_side0_s0.001","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":235},"status":[0.0]}}
{"case":"rev_blend_c3_sc2.5_side0_s1.0","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":235},"status":[0.0]}}
{"case":"rev_blend_c3_sc2.5_side0_s1000.0","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":235},"status":[0.0]}}
{"case":"rev_blend_c3_sc2.5_side1_s0.001","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"],["-inf","inf","-inf"]],"n":339},"status":[0.0]}}
{"case":"rev_blend_c3_sc2.5_side1_s1.0","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"],["-inf","inf","-inf"]],"n":339},"status":[0.0]}}
{"case":"rev_blend_c3_sc2.5_side1_s1000.0","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"],["-inf","inf","-inf"]],"n":339},"status":[0.0]}}
{"case":"rev_blend_c3_sc2.5_side2_s0.001","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"],["-inf","inf","-inf"]],"n":339},"status":[0.0]}}
{"case":"rev_blend_c3_sc2.5_side2_s1.0","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"],["-inf","inf","-inf"]],"n":339},"status":[0.0]}}
{"case":"rev_blend_c3_sc2.5_side2_s1000.0","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"],["-inf","inf","-inf"]],"n":339},"status":[0.0]}}
{"case":"rev_blend_c4_sc0.7_side0_s0.001","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":235},"status":[0.0]}}
{"case":"rev_blend_c4_sc0.7_side0_s1.0","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":235},"status":[0.0]}}
{"case":"rev_blend_c4_sc0.7_side0_s1000.0","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":235},"status":[0.0]}}
{"case":"rev_blend_c4_sc0.7_side1_s0.001","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":235},"status":[0.0]}}
{"case":"rev_blend_c4_sc0.7_side1_s1.0","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":235},"status":[0.0]}}
{"case":"rev_blend_c4_sc0.7_side1_s1000.0","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":235},"status":[0.0]}}
{"case":"rev_blend_c4_sc0.7_side2_s0.001","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":235},"status":[0.0]}}
{"case":"rev_blend_c4_sc0.7_side2_s1.0","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":235},"status":[0.0]}}
{"case":"rev_blend_c4_sc0.7_side2_s1000.0","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":235},"status":[0.0]}}
{"case":"rev_blend_c4_sc1.5_side0_s0.001","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":235},"status":[0.0]}}
{"case":"rev_blend_c4_sc1.5_side0_s1.0","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":235},"status":[0.0]}}
{"case":"rev_blend_c4_sc1.5_side0_s1000.0","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":235},"status":[0.0]}}
{"case":"rev_blend_c4_sc1.5_side1_s0.001","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":235},"status":[0.0]}}
{"case":"rev_blend_c4_sc1.5_side1_s1.0","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":235},"status":[0.0]}}
{"case":"rev_blend_c4_sc1.5_side1_s1000.0","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":235},"status":[0.0]}}
{"case":"rev_blend_c4_sc1.5_side2_s0.001","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":235},"status":[0.0]}}
{"case":"rev_blend_c4_sc1.5_side2_s1.0","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":235},"status":[0.0]}}
{"case":"rev_blend_c4_sc1.5_side2_s1000.0","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":235},"status":[0.0]}}
{"case":"rev_blend_c4_sc2.5_side0_s0.001","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":235},"status":[0.0]}}
{"case":"rev_blend_c4_sc2.5_side0_s1.0","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":235},"status":[0.0]}}
{"case":"rev_blend_c4_sc2.5_side0_s1000.0","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":235},"status":[0.0]}}
{"case":"rev_blend_c4_sc2.5_side1_s0.001","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":235},"status":[0.0]}}
{"case":"rev_blend_c4_sc2.5_side1_s1.0","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":235},"status":[0.0]}}
{"case":"rev_blend_c4_sc2.5_side1_s1000.0","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":235},"status":[0.0]}}
{"case":"rev_blend_c4_sc2.5_side2_s0.001","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":235},"status":[0.0]}}
{"case":"rev_blend_c4_sc2.5_side2_s1.0","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":235},"status":[0.0]}}
{"case":"rev_blend_c4_sc2.5_side2_s1000.0","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":235},"status":[0.0]}}
{"case":"rev_cr_jac_planes","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[5.199999999999999,13.200000000000001,-9.600000000000001]],"n":59},"status":[0.0]}}
{"case":"rev_skip0_a0","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":96},"status":[1001.0]}}
{"case":"rev_skip0_a1","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[["-inf","inf","-inf"]],"n":96},"status":[1001.0]}}
@@ -1220,33 +1027,6 @@
{"case":"rv2_base_ratoob0_nq3","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[17834.95018899467,18006.75236827312,2175106.8919628914]],"n":150},"status":[0.0]}}
{"case":"rv2_base_ratoob1_nq1","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[17865.535254678056,17892.525804468292,1233154.7909143355]],"n":97},"status":[0.0]}}
{"case":"rv2_base_ratoob1_nq3","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[17923.381224403303,17950.345352797267,1591941.8264536485]],"n":117},"status":[0.0]}}
{"case":"rv2_blend_closed_nq3_s0.001_g0_c1","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[148.62290070767153,148.869936692375,14608.580085768319],[11.496,11.504000000000001,169.488]],"n":280},"status":[0.0]}}
{"case":"rv2_blend_closed_nq3_s0.001_g0_c2","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[157.27778257845725,157.4542552655581,15789.457056393006],[28.83999346348281,28.99468462806257,1569.5593278857236]],"n":348},"status":[0.0]}}
{"case":"rv2_blend_closed_nq3_s0.001_g0_c3","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[165.76579168193524,165.88924458278166,16946.919673076918],[46.351060641056634,46.635480454806284,4240.003290226028]],"n":416},"status":[0.0]}}
{"case":"rv2_blend_closed_nq3_s1.0_g0_c1","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[164.9055915910216,411.9415762945698,11340.856210120473],[7.5,15.5,157.5]],"n":280},"status":[0.0]}}
{"case":"rv2_blend_closed_nq3_s1.0_g0_c2","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[242.58681116028305,419.05949826587266,27155.6998452107],[-45.30588537593507,109.3852793528693,-866.1493228275606]],"n":348},"status":[0.0]}}
{"case":"rv2_blend_closed_nq3_s1.0_g0_c3","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[299.6955348498878,423.1485189854002,39599.33709198946],[-77.33888784176195,207.08226280685935,-4815.508619172537]],"n":416},"status":[0.0]}}
{"case":"rv2_blend_closed_nq3_s1000.0_g0_c1","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[16447.596474941114,263483.5811784891,-3256383.019437706],[-3988.5,4011.5,-11830.5]],"n":280},"status":[0.0]}}
{"case":"rv2_blend_closed_nq3_s1000.0_g0_c2","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[85551.46024469017,262024.21259742544,11393369.147489568],[-74191.27278569883,80500.06801201137,-2436577.023170184]],"n":348},"status":[0.0]}}
{"case":"rv2_blend_closed_nq3_s1000.0_g0_c3","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[134394.90335227104,257922.3803018193,22729502.55597207],[-124486.29794026718,161353.3332747026,-9127893.44943911]],"n":416},"status":[0.0]}}
{"case":"rv2_blend_closed_nq4_s0.001_g0_c1","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[168.3802722064217,168.57806888018212,18116.430998267027],[30.799434694325154,30.92417733288832,1922.5226760139858]],"n":361},"status":[0.0]}}
{"case":"rv2_blend_closed_nq4_s0.001_g0_c2","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[176.87367691295063,177.0110380688279,19513.27292576587],[54.30597551322232,54.59438398438952,6043.478502556922]],"n":453},"status":[0.0]}}
{"case":"rv2_blend_closed_nq4_s0.001_g0_c3","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[185.03580189031211,185.1572912707306,20837.0012883709],[62.14406248558705,62.552380824005176,8022.420111076967],[16.0,16.0,332.375]],"n":545},"status":[0.0]}}
{"case":"rv2_blend_closed_nq4_s1.0_g0_c1","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[234.87741593599253,432.67408969637984,25017.867406458667],[1.835996703709199,126.57863526687456,2104.5044115063965]],"n":361},"status":[0.0]}}
{"case":"rv2_blend_closed_nq4_s1.0_g0_c2","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[297.3816340625535,434.74278994049826,39128.99250299076],[-28.7226958306437,259.6857749201664,2926.9229602230525]],"n":453},"status":[0.0]}}
{"case":"rv2_blend_closed_nq4_s1.0_g0_c3","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[321.20727092672223,442.69673463955723,44206.21629167928],[-36.33802364142846,371.9873191762016,-1192.6369252334312],[16.0,16.0,332.375]],"n":545},"status":[0.0]}}
{"case":"rv2_blend_closed_nq4_s1000.0_g0_c1","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[66732.0211455067,264528.69490589376,6926454.275598097],[-28961.60199391224,95781.03656925306,184086.23990391666]],"n":361},"status":[0.0]}}
{"case":"rv2_blend_closed_nq4_s1000.0_g0_c2","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[120805.62599506765,258166.61872195575,19654915.876567025],[-83057.38178589642,205351.03917801924,-3113635.3436347167]],"n":453},"status":[0.0]}}
{"case":"rv2_blend_closed_nq4_s1000.0_g0_c3","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[137349.9133906786,258932.66925725146,23613899.90390819],[-100967.41210257604,314357.9097169076,-9814728.951004185],[16.0,16.0,332.375]],"n":545},"status":[0.0]}}
{"case":"rv2_blend_torus_nq1_dz0.0","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[237.28749391142122,237.28749391142122,16936.41278842023]],"n":155},"status":[0.0]}}
{"case":"rv2_blend_torus_nq1_dz0.001","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[237.29510005770362,237.29986496460674,16936.7039009136]],"n":155},"status":[0.0]}}
{"case":"rv2_blend_torus_nq1_dz1e-07","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[237.28749467327737,237.2874951490134,16936.412817676835]],"n":155},"status":[0.0]}}
{"case":"rv2_blend_torus_nq2_dz0.0","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[225.3111831820431,331.5660171779823,18611.840360249204]],"n":209},"status":[0.0]}}
{"case":"rv2_blend_torus_nq2_dz0.001","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[225.32013989422308,331.5783934855552,18612.281497686876]],"n":209},"status":[0.0]}}
{"case":"rv2_blend_torus_nq2_dz1e-07","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[225.3111840790992,331.56601841645977,18611.84040455846]],"n":209},"status":[0.0]}}
{"case":"rv2_blend_torus_nq3_dz0.0","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[166.95584412271577,423.47770542341425,12063.614247755517],[4.0,4.0,22.0]],"n":263},"status":[0.0]}}
{"case":"rv2_blend_torus_nq3_dz0.001","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[166.9664088708869,423.4919568106105,12064.304124780665],[4.0,4.0,22.0]],"n":263},"status":[0.0]}}
{"case":"rv2_blend_torus_nq3_dz1e-07","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[166.95584518043205,423.4777068497593,12063.61431693587],[4.0,4.0,22.0]],"n":263},"status":[0.0]}}
{"case":"rv2_circ_closed_nq3_s0.001_g0_a0_m0","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[144.77704695754844,144.9841303207931,14265.734006771956]],"n":246},"status":[0.0]}}
{"case":"rv2_circ_closed_nq3_s0.001_g0_a0_m1","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[144.78270381179794,144.9967403917243,14266.603571336122]],"n":246},"status":[0.0]}}
{"case":"rv2_circ_closed_nq3_s0.001_g0_a1_m0","deferred":null,"error":null,"ints":{},"topology":null,"values":{"out":{"blocks":[[155.46313113923583,155.6096292496892,15559.030538299665],[36.16397238777566,36.39754601913158,2547.4297078129484]],"n":379},"status":[0.0]}}
+1
View File
@@ -2,6 +2,7 @@
"blend.fillet_executive_p3": {
"issue-2349-teardrop-full-r0.5": "tangency-labs/solidcore#2349: the closed round's first span is off the true round by 7.9e-4 against a 4e-5 edge tolerance; the curved-spine mitre and both exact pcurves remain unimplemented",
"issue-2349-teardrop-full-r3": "tangency-labs/solidcore#2349: the closed-angle mitre is not certified; tangency-labs/solidcore#2404 tracks the refusal size whose fresh build fails validity",
"private-upstream-rollover-404-cyl-on-box1-edge12-r2": "tangency-labs/solidcraft#13694: fails in the rollover (1001) once the WR-682 surface-plane trace is taken; main's default built it, and the trace's curves agree with the two-points intersector's to the tolerance, so the cause is not found yet",
"stubs4-delete-edge-sphere_diff_3cylinders-e2-r0.5": "tangency-labs/solidcore#3053: with every fix off the round builds a body that is not closed (29 vertices, 44 edges, 9 faces, mass status 1007), where it was refused with status 1001"
},
"intersect.topology_solver_p2": {
+3 -6
View File
@@ -519,7 +519,7 @@ pub struct RefusedExpect {
/// Text the step's error contains. Empty or whitespace-only text is invalid.
pub error: String,
/// The largest size that builds, which the refusal must report
/// (`SolidError::FilletRefused`'s `fit`; needs `fillet_gn_section_generator`).
/// (`SolidError::FilletRefused`'s `fit`).
#[serde(default)]
pub fit_size: Option<FitSizeExpect>,
}
@@ -987,7 +987,7 @@ pub enum Run {
/// A step returned an error other than `Unported`.
Error(String),
/// A fillet or chamfer step was refused as too large, with the largest size that
/// builds it (`SolidError::FilletRefused`, opt-in `fillet_gn_section_generator`).
/// builds it (`SolidError::FilletRefused`, WR-696).
/// Scored as an `ERROR`, except by a case that expects the refusal.
Refused {
/// The error, prefixed with the step as for [`Run::Error`].
@@ -1753,7 +1753,6 @@ fn enable_fix(k: &mut Kernel, name: &str) -> Result<(), String> {
"cover_wraps_across_closed_seam" => &mut k.fixes.cover_wraps_across_closed_seam,
"fillet_refuse_non_manifold_result" => &mut k.fixes.fillet_refuse_non_manifold_result,
"fillet_refuse_crossing_rails" => &mut k.fixes.fillet_refuse_crossing_rails,
"fillet_refuse_ball_not_fitting" => &mut k.fixes.fillet_refuse_ball_not_fitting,
"fillet_torus_rail_on_axis" => &mut k.fixes.fillet_torus_rail_on_axis,
"cone_parallel_line_midpoint" => &mut k.fixes.cone_parallel_line_midpoint,
"fillet_trace_from_tangent_point_toward_next" => {
@@ -2508,11 +2507,9 @@ mod tests {
enable_fix(&mut k, "sweep_frame_on_planar_path_normal").unwrap();
enable_fix(&mut k, "cover_refuses_folded_continuation").unwrap();
enable_fix(&mut k, "fillet_refuse_non_manifold_result").unwrap();
enable_fix(&mut k, "fillet_refuse_ball_not_fitting").unwrap();
assert!(k.fixes.sweep_frame_on_planar_path_normal);
assert!(k.fixes.cover_refuses_folded_continuation);
assert!(k.fixes.fillet_refuse_non_manifold_result);
assert!(k.fixes.fillet_refuse_ball_not_fitting);
assert!(enable_fix(&mut k, "no_such_fix").is_err());
}
@@ -2727,7 +2724,7 @@ mod tests {
// blend's checks the refusal reports the largest radius that builds, 3.
let case: Case = serde_json::from_value(json!({
"name": "bar-round-too-large",
"fixes": ["fillet_refuse_overlapping_bands", "fillet_gn_section_generator"],
"fixes": ["fillet_refuse_overlapping_bands"],
"steps": [
{"op": "box", "id": "bar", "origin": [14.0, 0.0, 0.0], "size": [14.0, 6.0, 10.0]},
{"op": "fillet", "id": "result", "body": "bar",
@@ -39,6 +39,7 @@ use solidcore::blend::fillet_corner::p3::{
CornerEnv, FilletCorner, FilletCornerKind, FilletExecutiveData,
};
use solidcore::blend::fillet_geom::p1::{FilStatus, FilletEdgeType, FilletSolverId};
use solidcore::blend::fillet_section::section::{GnSectionFsg, GN_THUMBWEIGHT_EQUAL_AREA};
use solidcore::blend::fillet_solver::p1::{FilletSolver, FilletSurfaceGenerator};
use solidcore::curve::curve::Curve;
use solidcore::geom::extent2d::Extent2d;
@@ -321,7 +322,8 @@ struct SolverRegIn {
}
/// The fillet solver of a model geometry in a `const_rad` case: `kind` -1 none, 0
/// `SmCircularCrossSectionFSG()`, 1 `SmBlendCurveCrossSectionFSG(scale, continuity)`, 2
/// `SmCircularCrossSectionFSG()`, 1 a blend curve: the G^n section of order `continuity`
/// (at least 2; `scale` was the retired `SmBlendCurveCrossSectionFSG`'s, WR-685), 2
/// `SmLinearCrossSectionFSG`, 3 the base `SmFilletSurfaceGenerator`, 4 no generator.
#[derive(Debug, Clone, Serialize, Deserialize)]
struct FsgIn {
@@ -2086,7 +2088,12 @@ fn corner_rust(i: &Inputs) -> Result<Output, HarnessError> {
let mut fs = FilletSolver::new(1e-3, EFF_ZERO_RAD, 1e-2);
fs.set_fillet_surface_generator(match f.kind {
0 => Some(FilletSurfaceGenerator::circular_default()),
1 => Some(FilletSurfaceGenerator::blend_curve(f.scale, f.continuity)),
// a blend-curve request is the G^n section (the old generator is
// retired, WR-685): its order the continuity, at least 2
1 => Some(FilletSurfaceGenerator::GnSection(GnSectionFsg::new(
(f.continuity as usize).max(2),
GN_THUMBWEIGHT_EQUAL_AREA,
))),
2 => Some(FilletSurfaceGenerator::Linear),
3 => Some(FilletSurfaceGenerator::Base),
_ => None,
@@ -429,7 +429,11 @@ fn fsg_of(kind: u8) -> FilletSurfaceGenerator {
match kind {
1 => FilletSurfaceGenerator::Linear,
2 => FilletSurfaceGenerator::circular_default(),
3 => FilletSurfaceGenerator::blend_curve_default(),
// a blend curve is the G^n section (the old generator is retired, WR-685)
3 => FilletSurfaceGenerator::GnSection(solidcore::blend::fillet_section::section::GnSectionFsg::new(
2,
solidcore::blend::fillet_section::section::GN_DEFAULT_THUMBWEIGHT,
)),
_ => FilletSurfaceGenerator::Base,
}
}
@@ -1563,7 +1563,6 @@ fn executive(target: Option<Handle>) -> FilletExecutive<Handle> {
vertex_corner_map: BTreeMap::new(),
edgeuse_solver_map: BTreeMap::new(),
self_intersection_handler: None,
blend_curve_at_thirds: false,
mark_corner_patches: false,
cliff_overflow: false,
open_ends: Vec::new(),
@@ -869,7 +869,6 @@ fn rust(input: &Inputs) -> Result<Output, HarnessError> {
vertex_corner_map: BTreeMap::new(),
edgeuse_solver_map: BTreeMap::new(),
self_intersection_handler: None,
blend_curve_at_thirds: false,
mark_corner_patches: false,
cliff_overflow: false,
open_ends: Vec::new(),
@@ -1508,6 +1508,27 @@ mod tests {
}
}
/// `gen0014`: the surface-and-plane trace (WR-682, on every kernel since its flag was
/// retired) between two points of a surface whose curve runs off its domain. The march
/// went on along the B-spline's extrapolation to u = -6e5 on a domain of [0, 1], and each
/// refining pass split every span that missed, doubling the stations until the
/// allocation failed (an abort, 4.9 GB). The trace refuses a station off the domain
/// (status 1001, as the golden), and holds at most `MAX_STATIONS` in any case.
#[test]
fn gen0014_the_trace_stays_on_its_surface() {
// only `gen0014`, from its own seed, as `CaseContext::generated_cases` draws it
let seed = CaseContext::seed_for("blend.fillet_geom_p2", 14);
let inputs = Runner.generate(&mut Rng::new(seed)).unwrap();
let case = Case {
unit: "blend.fillet_geom_p2".into(),
name: "gen0014".into(),
source: crate::case::CaseSource::Generated { seed },
inputs,
};
let out = Runner.run_rust(&case).unwrap();
assert_eq!(out.values["status"], [1001.0], "{out:?}");
}
/// Tallies the Rust outcome of every case per query (status `0`, an upstream error
/// status, a deferral): with no failed case, the passes' success-path / error-path
/// split. `CASE_SEEDS` sets the generated count.
@@ -48,6 +48,7 @@ use serde_json::Value;
use solidcore::blend::fillet_custom_solver::{JacobianLoad, OffsetSurface, SurfaceId};
use solidcore::blend::fillet_geom::p1::{FilletBrep, FilletSolverId};
use solidcore::blend::fillet_section::section::{GnSectionFsg, GN_DEFAULT_THUMBWEIGHT};
use solidcore::blend::fillet_solver::p1::{
check_edge_curve_domains, compute_uv_vectors, find_next_good_interval, test_analytic_surface,
test_manifold_tangent_rollover, test_side_edge_convexity, tol_ang_tol_rad, trim_rail,
@@ -1290,9 +1291,10 @@ fn rust(k: &Kernel, i: &Inputs) -> Result<Output, HarnessError> {
1 => FilletSurfaceGenerator::Linear,
2 => FilletSurfaceGenerator::circular_default(),
3 => FilletSurfaceGenerator::circular(a != 0.0, bb, c != 0.0, d != 0.0),
4 => FilletSurfaceGenerator::blend_curve_default(),
// (the shim's `(ULONG)b`)
_ => FilletSurfaceGenerator::blend_curve(a, bb as u32),
// a blend curve is the G^n section (the old generator is retired, WR-685):
// the default order 2, or order `b` (at least 2) at thumbweight `a`
4 => FilletSurfaceGenerator::GnSection(GnSectionFsg::new(2, GN_DEFAULT_THUMBWEIGHT)),
_ => FilletSurfaceGenerator::GnSection(GnSectionFsg::new((bb as usize).max(2), a)),
};
o.push(f64::from(g.fillet_surface_generator_type() as i32));
match g {
@@ -1304,7 +1306,7 @@ fn rust(k: &Kernel, i: &Inputs) -> Result<Output, HarnessError> {
]),
_ => o.extend([0.0; 4]),
}
o.push(g.blend_scale().unwrap_or(0.0));
o.push(g.thumbweight().unwrap_or(0.0));
o.push(g.continuity().map_or(0.0, f64::from));
if *kind == 0 {
let k = Kernel::default();
@@ -35,12 +35,13 @@ use serde_json::Value;
use solidcore::blend::fillet_custom_solver::{OffsetSurface, SurfaceId};
use solidcore::blend::fillet_geom::p1::{FilletBrep, FilletSolverId};
use solidcore::blend::fillet_section::section::{GnSectionFsg, GN_DEFAULT_THUMBWEIGHT};
use solidcore::blend::fillet_solver::p1::{FilletSurfaceGenerator, OffsetSurfaceSlot};
use solidcore::blend::fillet_standard_solver::p1::{
constant_radius_from_edgeuse, constant_radius_is_kind_of, BlendCurveCrossSectionFsg,
constant_radius_from_edgeuse, constant_radius_is_kind_of,
BoundaryTrimmingType, CircularCrossSectionFsg, ConstantDistanceFs, ConstantRadiusFs,
CurveBasedFs, FilletLaw, FilletLawKind, FilletSolver, InitialSurface, LinearCrossSectionFsg,
RailSurface, SurfaceSurfaceFs, VariableRadiusFs, CONSTANT_RADIUS_FS_TYPE,
SurfaceSurfaceFs, VariableRadiusFs, CONSTANT_RADIUS_FS_TYPE,
CONSTANT_RADIUS_FS_TYPE_STRING,
};
use solidcore::curve::curve::{Curve, CurveKind};
@@ -592,58 +593,9 @@ fn rust_generator(i: &Inputs) -> Result<Rec, HarnessError> {
};
(res, [c, r1, r2])
}
Inputs::Blend {
cont,
scale,
tol,
g1,
center,
rail1,
rail2,
sides,
} => {
let fsg = BlendCurveCrossSectionFsg {
continuity: *cont as u32,
blend_scale: *scale,
at_thirds: false,
};
let mut c = bcurve_of(center)?;
let mut r1 = bcurve_of(rail1)?;
let mut r2 = bcurve_of(rail2)?;
let built = match sides {
Some(s) => Some((
surface_of(&s.s1)?,
bcurve_of(&s.uv1)?,
surface_of(&s.s2)?,
bcurve_of(&s.uv2)?,
)),
None => None,
};
let (side1, side2) = match &built {
Some((s1, uv1, s2, uv2)) => (
RailSurface {
surface: Some(s1),
uv_curve: Some(uv1),
},
RailSurface {
surface: Some(s2),
uv_curve: Some(uv2),
},
),
None => (
RailSurface {
surface: None,
uv_curve: None,
},
RailSurface {
surface: None,
uv_curve: None,
},
),
};
let res = fsg
.create_surface_from_curves(&k, &mut c, &mut r1, &mut r2, *tol, *g1, side1, side2);
(res, [c, r1, r2])
Inputs::Blend { .. } => {
// the blend-curve generator is retired (WR-685): `cases` drops these
return Err(harness("the blend-curve generator is retired (WR-685)"));
}
_ => return Err(harness("not a generator op")),
};
@@ -765,7 +717,8 @@ fn vr_of(k: &Kernel, s: &VrIn) -> Result<VariableRadiusFs, HarnessError> {
.set_fillet_surface_generator(Some(match s.fsg {
1 => FilletSurfaceGenerator::Linear,
2 => FilletSurfaceGenerator::circular_default(),
_ => FilletSurfaceGenerator::blend_curve_default(),
// a blend curve is the G^n section (the old generator is retired, WR-685)
_ => FilletSurfaceGenerator::GnSection(GnSectionFsg::new(2, GN_DEFAULT_THUMBWEIGHT)),
}));
curve_based.original = Some(center);
let law = match &s.law {
@@ -2172,7 +2125,11 @@ impl UnitDiff for Runner {
seeds: ctx.seeds.max(MIN_GENERATED),
..ctx.clone()
};
default_cases(self, &ctx)
let mut cases = default_cases(self, &ctx)?;
// The blend-curve generator is retired (WR-685, #2273): its cases are still drawn,
// so the generated cases after them stay as they were, and dropped here.
cases.retain(|c| !matches!(c.parse::<Inputs>(), Ok(Inputs::Blend { .. })));
Ok(cases)
}
fn run_rust(&self, case: &Case) -> Result<Output, HarnessError> {
@@ -2192,6 +2149,10 @@ mod tests {
for seed in 0..400u64 {
let mut rng = Rng::new(0x5eed_0000 + seed);
let i = gen_case(&mut rng);
// (the retired blend-curve generator's cases are dropped, WR-685)
if matches!(i, Inputs::Blend { .. }) {
continue;
}
let op = i.label();
let out = rust(&i).expect("harness");
let kind = if let Some(d) = &out.deferred {
@@ -2224,7 +2185,6 @@ mod tests {
.unwrap_or(0)
};
assert!(ok("Circ") > 40, "too few successful Circ cases");
assert!(ok("Blend") > 20, "too few successful Blend cases");
assert!(ok("CrEu") > 10, "too few successful CrEu cases");
}
+8 -21
View File
@@ -2443,9 +2443,10 @@ impl FilletCorner {
// arrive here when building an N-sided patch
// Not upstream (WR-659, opt-in `fillet_corner_face_curve_halves`; the fork's
// tangency-labs/smlib 4702889): at a corner whose rounds ease
let face_curve_halves = env.k.fixes.fillet_corner_face_curve_halves && self.ease_dist > 0.0;
// Not upstream (WR-659; the fork's tangency-labs/smlib 4702889): at a corner whose
// rounds ease (m_dEaseDist > 0), the patch's sides on the corner's face curves are
// those curves' own halves (below)
let face_curve_halves = self.ease_dist > 0.0;
// for every m_Surfaces->Surface - build 1 face with natural edge boundaries
for surface in self.surfaces.clone() {
@@ -2467,7 +2468,7 @@ impl FilletCorner {
curve_orients.push(orient);
}
// Not upstream (WR-659, opt-in; the fork's 4702889): at a corner whose rounds
// Not upstream (WR-659; the fork's 4702889): at a corner whose rounds
// ease into their curvature-continuous sections (m_dEaseDist), a side of this
// face on one of the corner's face curves is that curve's own half
// (sm_FaceCurveHalfAlong), not the patch's iso-curve, which N_FillNSidedHole fits
@@ -2755,17 +2756,15 @@ impl FilletCorner {
let fsg0 = fsg_of(env, fg0)?;
let fsg1 = fsg_of(env, fg1)?;
let fsg_type = fsg0.fillet_surface_generator_type();
let mut blend_scale = 1.5; // For use in SmBlendCurveCrossSectionFSG cases only
let mut max_continuity = 0u32;
// the fork's SmGnSectionFSG (WR-685, fixes.fillet_gn_section_generator): its
// a blend-curve generator is the fork's SmGnSectionFSG (WR-685): its
// thumbweight, and its order as the continuity
let gn = matches!(fsg0, FilletSurfaceGenerator::GnSection(_));
let mut thumbweight = GN_DEFAULT_THUMBWEIGHT;
if fsg_type != fsg1.fillet_surface_generator_type() {
return Err(sm_err());
}
if fsg_type == FilletSurfaceGeneratorType::BlendCurve && gn {
if fsg_type == FilletSurfaceGeneratorType::BlendCurve {
thumbweight = fsg0.thumbweight().unwrap_or(thumbweight);
let first_order = fsg0.continuity();
if (thumbweight - fsg1.thumbweight().unwrap_or(f64::NAN)).abs() > EFF_ZERO
@@ -2777,15 +2776,6 @@ impl FilletCorner {
if continuity > max_continuity {
max_continuity = continuity;
}
} else if fsg_type == FilletSurfaceGeneratorType::BlendCurve {
blend_scale = fsg0.blend_scale().unwrap_or(blend_scale);
if (blend_scale - fsg1.blend_scale().unwrap_or(blend_scale)).abs() > EFF_ZERO {
return Err(sm_err()); // Unable to convert
}
let continuity = fsg1.continuity().unwrap_or(0);
if continuity > max_continuity {
max_continuity = continuity;
}
}
// Make a constant radius fillet solver
@@ -2795,7 +2785,7 @@ impl FilletCorner {
let approx = !env.k.fixes.fillet_exact_arc_sections;
FilletSurfaceGenerator::circular(approx, 1.0e-3, false, false)
}
FilletSurfaceGeneratorType::BlendCurve if gn => {
FilletSurfaceGeneratorType::BlendCurve => {
FilletSurfaceGenerator::GnSection(GnSectionFsg::new(
if max_continuity > 1 {
max_continuity as usize
@@ -2805,9 +2795,6 @@ impl FilletCorner {
thumbweight,
))
}
FilletSurfaceGeneratorType::BlendCurve => {
FilletSurfaceGenerator::blend_curve(blend_scale, max_continuity)
}
FilletSurfaceGeneratorType::Linear => return Err(sm_err()),
// no solver is made: pNewFS->SetFilletExecutive on NULL
FilletSurfaceGeneratorType::Unknown => return Err(deref()),
+8 -27
View File
@@ -1245,11 +1245,9 @@ impl FilletCorner {
let mut start_rad = 0.0;
let mut end_rad = 0.0;
let mut fsg_type = FilletSurfaceGeneratorType::Unknown;
let mut blend_scale = 1.0; // For use in SmBlendCurveCrossSectionFSG cases only
let mut max_continuity = 0u32;
// the fork's SmGnSectionFSG (WR-685, fixes.fillet_gn_section_generator): its
// a blend-curve generator is the fork's SmGnSectionFSG (WR-685): its
// thumbweight, and its order as the continuity
let mut gn = false;
let mut thumbweight = GN_DEFAULT_THUMBWEIGHT;
let mut start_axis = Vec3::UNDEF;
let mut end_axis = Vec3::UNDEF;
@@ -1275,33 +1273,20 @@ impl FilletCorner {
if ii == 0 {
fsg_type = fsg.fillet_surface_generator_type();
gn = matches!(fsg, FilletSurfaceGenerator::GnSection(_));
if fsg_type == FilletSurfaceGeneratorType::BlendCurve && gn {
if fsg_type == FilletSurfaceGeneratorType::BlendCurve {
thumbweight = fsg.thumbweight().unwrap_or(thumbweight);
let continuity = fsg.continuity().unwrap_or(0);
if continuity > max_continuity {
max_continuity = continuity;
}
} else if fsg_type == FilletSurfaceGeneratorType::BlendCurve {
blend_scale = fsg.blend_scale().unwrap_or(blend_scale);
let continuity = fsg.continuity().unwrap_or(0);
if continuity > max_continuity {
max_continuity = continuity;
}
}
} else if fsg_type != fsg.fillet_surface_generator_type() {
return Err(sm_err()); // Unable to convert - two different types
} else if fsg_type == FilletSurfaceGeneratorType::BlendCurve && gn {
if (thumbweight - fsg.thumbweight().unwrap_or(f64::NAN)).abs() > EFF_ZERO
|| fsg.continuity() != Some(max_continuity)
{
return Err(sm_err()); // Unable to convert
}
} else if fsg_type == FilletSurfaceGeneratorType::BlendCurve {
let other_scale = fsg.blend_scale().unwrap_or(blend_scale);
if (blend_scale - other_scale).abs() > EFF_ZERO {
return Err(sm_err()); // Unable to convert
}
} else if fsg_type == FilletSurfaceGeneratorType::BlendCurve
&& ((thumbweight - fsg.thumbweight().unwrap_or(f64::NAN)).abs() > EFF_ZERO
|| fsg.continuity() != Some(max_continuity))
{
return Err(sm_err()); // Unable to convert
}
// Drop pE's end points to center line to compute radius, axis & origin of
@@ -1568,7 +1553,7 @@ impl FilletCorner {
false,
)),
FilletSurfaceGeneratorType::Linear => Some(FilletSurfaceGenerator::Linear),
FilletSurfaceGeneratorType::BlendCurve if gn => {
FilletSurfaceGeneratorType::BlendCurve => {
Some(FilletSurfaceGenerator::GnSection(GnSectionFsg::new(
if max_continuity > 1 {
max_continuity as usize
@@ -1578,10 +1563,6 @@ impl FilletCorner {
thumbweight,
)))
}
FilletSurfaceGeneratorType::BlendCurve => Some(FilletSurfaceGenerator::blend_curve(
blend_scale,
max_continuity,
)),
FilletSurfaceGeneratorType::Unknown => None,
};
if fsg.is_some() {
@@ -106,9 +106,8 @@ fn live(solvers: &[Option<SolverObject>], id: Option<FilletSolverId>) -> Result<
/// loop's gap closes ([`LOOP_GAP_ZONES`] of the body's tolerance), the blend with the larger
/// and the other's offset. Each blend's rails are on its own offsets, which
/// `SM_FE_CROSS_SECTION` cannot end both of. `None` for anything else: other solvers (a
/// law's rails are the law's to meet), without `fixes.fillet_gn_section_generator` and
/// `fixes.fillet_round_as_definition` (a blend not by its definition bends its rails to the
/// section), or one closed blend.
/// law's rails are the law's to meet), without `fixes.fillet_round_as_definition` (a blend
/// not by its definition bends its rails to the section), or one closed blend.
fn unequal_blends(
k: &Kernel,
target: &Brep,
@@ -116,7 +115,7 @@ fn unequal_blends(
ids: &[Option<FilletSolverId>],
faces: [Option<FaceId>; 2],
) -> Result<Option<(usize, f64)>> {
if !(k.fixes.fillet_gn_section_generator && k.fixes.fillet_round_as_definition) {
if !k.fixes.fillet_round_as_definition {
return Ok(None);
}
let mut offsets = Vec::new();
+1 -1
View File
@@ -1880,7 +1880,7 @@ pub struct CollapsedOffset {
pub partial: bool,
}
/// Not the fork's (#2401; with `fixes.fillet_gn_section_generator`): for a constant ball of
/// Not the fork's (#2401): for a constant ball of
/// `radius` (`None`: the solver's own) whose offset of one of its faces collapses (the face
/// a cylinder or sphere as wide as the ball, the ball inside it: its offset is the axis or
/// the centre, [`QuadricKind::Line`] or [`QuadricKind::Point`]), the radius of that face
@@ -220,8 +220,8 @@ pub fn fillet_edges_per_edge(
/// (`SmLinearFilletLaw`) and one cross-section (`xsect_type` 0 linear, 2 blend
/// curve, any other value circular), then `StitchAndOrient` with its defaults.
/// `continuity` (1, 2 or 3 for G1-G3) applies to blend-curve cross-sections, whose
/// thumbweight is the `SetFilletParameters` default (`1.0`; the fork's
/// `SM_GN_DEFAULT_THUMBWEIGHT` with `fixes.fillet_gn_section_generator`).
/// thumbweight is the `SetFilletParameters` default with the G^n section, the fork's
/// `SM_GN_DEFAULT_THUMBWEIGHT` (upstream's `1.0`, which the G^n section refuses).
///
/// # Errors
/// `SM_ERR_INVALID_INPUT` for an empty edge list or a start or end radius below 8
@@ -47,7 +47,7 @@
//! | [`FilletExecutive::add_fillet_surface_generator`] | `AddFilletSurfaceGenerator` |
//! | [`FilletExecutive::remove_from_topo_edges`] | `RemoveFromTopoEdges` |
//! | [`FilletExecutive::set_do_global_merge`], [`FilletExecutive::set_do_trimming`], [`FilletExecutive::set_self_intersection_handler`] | `SetDoGlobalMerge`, `SetDoTrimming`, `SetSelfIntersectionHandler` |
//! | [`FilletExecutive::set_blend_curve_at_thirds`], [`FilletExecutive::set_mark_corner_patches`] | the fork's `SetBlendCurveAtThirds` (tangency-labs/smlib `fd3b6a7`), `SetMarkCornerPatches` (`60af574`); off by default |
//! | [`FilletExecutive::set_mark_corner_patches`] | the fork's `SetMarkCornerPatches` (`60af574`); off by default |
//! | [`is_radius_supported`] | `SmFilletExecutive::IsRadiusSupported` (static) |
//! | fields `fillet`, `pseudo_brep`, `corners`, `solvers`, `error` | `GetFilletBrep`, `GetPseudoBrep`, `GetFilletCorners`, `GetFilletSolvers`, `GetFilletErrorInfo` |
//! | [`FilletExecutive::fillet_corner_of_vertex`] | `GetFilletCornerOfVertex` |
@@ -804,7 +804,6 @@ impl<O: ClassObject + SolutionObject + Ord> FilletExecutive<O> {
vertex_corner_map: BTreeMap::new(),
edgeuse_solver_map: BTreeMap::new(),
self_intersection_handler: None,
blend_curve_at_thirds: false,
mark_corner_patches: false,
cliff_overflow: false,
open_ends: Vec::new(),
@@ -952,12 +951,6 @@ impl<O: ClassObject + SolutionObject + Ord> FilletExecutive<O> {
self.options.trimming = value;
}
/// `SetBlendCurveAtThirds` (the fork's, tangency-labs/smlib `fd3b6a7`): before
/// `SetFilletParameters`, which creates the section generators with it.
pub fn set_blend_curve_at_thirds(&mut self, value: bool) {
self.blend_curve_at_thirds = value;
}
/// `SetMarkCornerPatches` (the fork's, tangency-labs/smlib `60af574`): before
/// `DoFilleting`.
pub fn set_mark_corner_patches(&mut self, value: bool) {
+5 -14
View File
@@ -722,13 +722,11 @@ impl<O: ClassObject + SolutionObject + Ord> FilletExecutive<O> {
.ok_or_else(|| first("no radius"))?;
let mut generator: Option<O> = None;
let at_thirds = self.blend_curve_at_thirds;
// the fork's SmGnSectionFSG in place of the blend curve (WR-685)
let gn = k.fixes.fillet_gn_section_generator;
let exact_arcs = k.fixes.fillet_exact_arc_sections;
// the fork's SmGnSectionFSG in place of the blend curve (WR-685)
let gn_order = params.continuity as usize;
let gn_invalid = |kind: FilletSurfaceGeneratorType| {
gn && kind == FilletSurfaceGeneratorType::BlendCurve
kind == FilletSurfaceGeneratorType::BlendCurve
&& !GnSectionFsg::is_valid(gn_order, params.thumbweight)
};
let generator_spec = |kind: FilletSurfaceGeneratorType, circular_tol: f64| match kind {
@@ -740,16 +738,9 @@ impl<O: ClassObject + SolutionObject + Ord> FilletExecutive<O> {
false,
false,
)),
FilletSurfaceGeneratorType::BlendCurve if gn => Some(
FilletSurfaceGenerator::GnSection(GnSectionFsg::new(gn_order, params.thumbweight)),
),
FilletSurfaceGeneratorType::BlendCurve => {
Some(FilletSurfaceGenerator::blend_curve_at_thirds(
params.thumbweight,
params.continuity,
at_thirds,
))
}
FilletSurfaceGeneratorType::BlendCurve => Some(FilletSurfaceGenerator::GnSection(
GnSectionFsg::new(gn_order, params.thumbweight),
)),
FilletSurfaceGeneratorType::Unknown => None,
};
+99 -136
View File
@@ -95,10 +95,9 @@ fn ignore<T>(result: Result<T>) -> Result<Option<T>> {
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum NoRoomReason {
/// A rolling ball does not fit a face it rolls on: its rail turns back on itself
/// (`fixes.fillet_refuse_ball_not_fitting`, WR-462). With
/// `fixes.fillet_gn_section_generator`, `BallIsRegular`'s station where a face does
/// not enclose the ball (the fork's 410dfe1, WR-696).
/// A rolling ball does not fit a face it rolls on, whose rail would turn back on itself
/// (WR-462): `BallIsRegular`'s station where a face does not enclose the ball (the
/// fork's 410dfe1, WR-696).
BallDoesNotFit,
/// A rail leaves the face it rolls on between its ends (the fork's
/// `RailsFitTheirFaces`; `fixes.fillet_refuse_rails_leaving_faces`, WR-302).
@@ -126,19 +125,18 @@ pub enum NoRoomReason {
/// hold its radius law (the fork's `sm_HoldsItsLaw`, WR-631).
CliffLawNotHeld,
/// A variable round's balls fold over one another: its radius changes faster than a
/// rolling ball can follow (the fork's `sm_BallsFold` in its circular section;
/// `fixes.fillet_gn_section_generator`, WR-685). With that flag, since the fork's
/// tangency-labs/smlib#79 (410dfe1, WR-696), `BallIsRegular`'s regressive station:
/// a round's balls, or a constant ball, folding over themselves along the edge.
/// rolling ball can follow (the fork's `sm_BallsFold` in its circular section, WR-685),
/// since the fork's tangency-labs/smlib#79 (410dfe1, WR-696) `BallIsRegular`'s
/// regressive station: a round's balls, or a constant ball, folding over themselves
/// along the edge.
BallsFold,
/// Two unequal offsets (a chamfer of two distances) where a face curves tighter than
/// the offset along it, which folds there (the fork's `BallIsRegular`, 410dfe1;
/// `fixes.fillet_gn_section_generator`, WR-696).
/// WR-696).
OffsetFolds,
/// A convex blend (one that removes material) would take all of the part between its
/// rails somewhere along its edge and cut it into pieces (the fork's `BandCutsThePart`,
/// tangency-labs/smlib#79 862971f, e568e45 and aac4288;
/// `fixes.fillet_gn_section_generator`, WR-696).
/// tangency-labs/smlib#79 862971f, e568e45 and aac4288; WR-696).
CutsThePart,
/// A convex blend's section would leave the part between its rails and come back into
/// it through an inner face: the blend would break through a wall into the hollow
@@ -183,8 +181,7 @@ pub enum NoRoomReason {
/// A constant ball as wide as a face it rolls on (a cylinder or sphere of its radius,
/// the ball inside): its offset of that face collapses onto the axis or the centre, so
/// its centre does not move along the edge, and the zone it sweeps has no section of the
/// ball at an end of the edge, so no round ends there (not the fork's, #2401;
/// `fixes.fillet_gn_section_generator`).
/// ball at an end of the edge, so no round ends there (not the fork's, #2401).
OffsetCollapses,
/// A rail of a constant ball's round or chamfer along an arc would have its ends
/// within the part's resolution of each other (two vertex tolerances) without closing
@@ -649,10 +646,6 @@ pub struct FilletExecutive<O> {
pub edgeuse_solver_map: BTreeMap<O, O>,
/// `m_pSelfIntersectionHandler` (added by `blend.fillet_executive_p1`).
pub self_intersection_handler: Option<O>,
/// `m_bBlendCurveAtThirds` (the fork's, tangency-labs/smlib `fd3b6a7`; `FALSE` from
/// the constructor): `SetFilletParameters` builds its blend-curve generators with
/// their sections at thirds of the way to the corner.
pub blend_curve_at_thirds: bool,
/// `m_bMarkCornerPatches` (the fork's, tangency-labs/smlib `60af574`; `FALSE` from
/// the constructor): `DoFilleting` tags each face of a set-back corner's patch with
/// an `SM_AI_FILLET_CORNER_FACE` mark naming the corner before the merge.
@@ -704,8 +697,7 @@ pub struct FilletExecutive<O> {
/// `m_dFitRadius` (the fork's, tangency-labs/smlib a3d6d81; `-1` from the
/// constructor): with a refusal as too large ([`FilletErrorType::NoRoom`]), the largest
/// size that builds, of kind [`Self::fit_kind`]: `> 0`, `0` when none does, `< 0` when
/// not known (a radius law, a cause with no size). Set only with
/// `fixes.fillet_gn_section_generator`. Read it with [`Self::fit_size`].
/// not known (a radius law, a cause with no size). Read it with [`Self::fit_size`].
pub fit_radius: f64,
/// `m_pFitEdge`: the blended edge [`Self::fit_radius`] is for.
pub fit_edge: Option<O>,
@@ -2029,15 +2021,6 @@ pub trait BrepCreationAccess<O: ClassObject + SolutionObject + Ord>:
fn creation_smooth(&mut self, k: &mut Kernel, executive: &mut FilletExecutive<O>)
-> Result<()>;
/// `SmFilletSolver::BallFitsItsFaces` (SolidCraft change, WR-462, #1172) on this
/// solver: whether its rolling ball fits the faces it rolls on. Only a live session
/// has solvers to judge.
///
/// # Errors
/// The judging's own errors; the adapter over [`ExecutiveAccess`] has no solver
/// geometry to judge.
fn creation_ball_fits(&mut self, k: &mut Kernel, solver: O) -> Result<bool>;
/// `sm_ExtendTraceToItsRails` (fork tangency-labs/smlib@a9277fd, WR-609; called
/// before the corners since @6e77631, WR-610) on this solver: let its trace reach
/// as far as its rails can lie from the filleted edge. Only a live session has
@@ -2051,11 +2034,11 @@ pub trait BrepCreationAccess<O: ClassObject + SolutionObject + Ord>:
/// `SmFilletSolver::BallIsRegular` (the fork's, tangency-labs/smlib#79 410dfe1 to
/// a34b5e8) on this solver: its rolling ball's local regularity along its edge and the
/// radius that works, with whether it is a constant-radius solver
/// (`GetSolverType() == SM_FS_CONST_RADIUS`). Only a live session has solvers to judge.
/// (`GetSolverType() == SM_FS_CONST_RADIUS`); regular from the adapter over
/// [`ExecutiveAccess`], which holds no solver geometry.
///
/// # Errors
/// The judging's own errors; the adapter over [`ExecutiveAccess`] has no solver
/// geometry to judge.
/// The judging's own errors.
fn creation_ball_is_regular(
&mut self,
k: &mut Kernel,
@@ -2064,10 +2047,11 @@ pub trait BrepCreationAccess<O: ClassObject + SolutionObject + Ord>:
/// What `NoteOpenFit` and `FitMargin` (the fork's, a3d6d81 and 49f393d) read of this
/// solver: its first edge use's edge, that edge's fit margin and its two offsets;
/// `None` without the edge.
/// `None` without the edge, and from the adapter over [`ExecutiveAccess`], which holds no
/// solvers.
///
/// # Errors
/// Topology lookups; the adapter over [`ExecutiveAccess`] has no solvers.
/// Topology lookups.
fn creation_solver_fit(&self, solver: O) -> Result<Option<SolverFit<O>>>;
/// The fork's `SmBlendCorner::FitOfEndPastSideEdges` (smlib 41a39ec) on `corner`
@@ -2090,11 +2074,10 @@ pub trait BrepCreationAccess<O: ClassObject + SolutionObject + Ord>:
/// (tangency-labs/smlib#79 862971f, e568e45, aac4288) on this solver: `None` for a
/// concave blend (one that adds material) or one that keeps the part whole; otherwise
/// where it would cut the part, with its edge and whether it is a chamfer (its
/// generator `SM_FSG_LINEAR`). Only a live session has solvers to judge.
/// generator `SM_FSG_LINEAR`). `None` from the adapter over [`ExecutiveAccess`], which holds no solver geometry, nothing to judge.
///
/// # Errors
/// The judging's own errors; the adapter over [`ExecutiveAccess`] has no solver
/// geometry to judge.
/// The judging's own errors.
fn creation_band_cuts_the_part(
&mut self,
k: &mut Kernel,
@@ -2104,10 +2087,10 @@ pub trait BrepCreationAccess<O: ClassObject + SolutionObject + Ord>:
/// Not the fork's (WR-707, #2299): `None` for a concave blend or one whose sections
/// do not break through the part; otherwise where its section would break through
/// into a hollow behind a wall, with the largest size at which no section does
/// (`session::band_cuts::band_breaks_through_the_part`).
/// (`session::band_cuts::band_breaks_through_the_part`). `None` from the adapter over [`ExecutiveAccess`], which holds no solver geometry, nothing to judge.
///
/// # Errors
/// The judging's own errors; the adapter over [`ExecutiveAccess`] has no solvers.
/// The judging's own errors.
fn creation_band_breaks_through(
&mut self,
k: &mut Kernel,
@@ -2117,10 +2100,10 @@ pub trait BrepCreationAccess<O: ClassObject + SolutionObject + Ord>:
/// `SmFilletSolver::LargestSizeOnItsFaces(pOnly, ...)` (the fork's, 49f393d and
/// 5e8c9c1) on this solver: the largest size at which its rails stay on its faces
/// (`only`: that face's boundary only), with what it sizes; `None` where nothing bounds
/// it.
/// it, and from the adapter over [`ExecutiveAccess`], which holds no solvers.
///
/// # Errors
/// The search's own errors; the adapter over [`ExecutiveAccess`] has no solvers.
/// The search's own errors.
fn creation_largest_size_on_its_faces(
&mut self,
k: &mut Kernel,
@@ -2132,10 +2115,11 @@ pub trait BrepCreationAccess<O: ClassObject + SolutionObject + Ord>:
/// the blends of `solvers` (constant balls) roll on, in face order, where it is a
/// polygon with every edge blended, the radius that leaves some of it, the first
/// solver on it and the least radius of the blends on it (not the fork's: what the
/// face's taken-whole event compares, #2401).
/// face's taken-whole event compares, #2401). None from the adapter over
/// [`ExecutiveAccess`], which holds no solvers.
///
/// # Errors
/// The sizing's own errors; the adapter over [`ExecutiveAccess`] has no solvers.
/// The sizing's own errors.
fn creation_polygons_taken_whole(
&mut self,
k: &mut Kernel,
@@ -2144,10 +2128,11 @@ pub trait BrepCreationAccess<O: ClassObject + SolutionObject + Ord>:
/// The circle-top fit of `CreateFilletBrep` (the fork's, a3d6d81 and 5e8c9c1) for
/// `solver`: for each planar face its closed edge bounds alone, the radius of the ball
/// touching it at the circle's centre less the fit margin, with the edge.
/// touching it at the circle's centre less the fit margin, with the edge. None from the
/// adapter over [`ExecutiveAccess`], which holds no solvers.
///
/// # Errors
/// The sizing's own errors; the adapter over [`ExecutiveAccess`] has no solvers.
/// The sizing's own errors.
fn creation_circle_tops(&mut self, k: &mut Kernel, solver: O) -> Result<Vec<(f64, O)>>;
/// Not the fork's (#2401): for a constant ball of `radius` (`None`: its own) whose
@@ -2155,10 +2140,11 @@ pub trait BrepCreationAccess<O: ClassObject + SolutionObject + Ord>:
/// open at an end of the edge, or (solidcore #2652) where the face is as wide as the ball
/// along part of the edge only
/// ([`ball_zone_open_at_an_end`](crate::blend::fillet_exact::ball_zone_open_at_an_end));
/// `None` otherwise, and for a solver that rolls no constant ball.
/// `None` otherwise, for a solver that rolls no constant ball, and from the adapter over
/// [`ExecutiveAccess`], which holds no solvers.
///
/// # Errors
/// The judging's own errors; the adapter over [`ExecutiveAccess`] has no solvers.
/// The judging's own errors.
fn creation_ball_zone_open(
&mut self,
k: &mut Kernel,
@@ -2183,10 +2169,10 @@ pub trait BrepCreationAccess<O: ClassObject + SolutionObject + Ord>:
/// `SmFilletSolver::BandsMeetAt` (the fork's, a3d6d81) over the executive's pairs of
/// `solvers` sharing a face, in its loop order (`a`, `b`, then each's face index): the
/// radius where their bands meet, with the first solver's edge, for each pair that
/// has one.
/// has one. None from the adapter over [`ExecutiveAccess`], which holds no solvers.
///
/// # Errors
/// The sizing's own errors; the adapter over [`ExecutiveAccess`] has no solvers.
/// The sizing's own errors.
fn creation_bands_meet(&mut self, k: &mut Kernel, solvers: &[O]) -> Result<Vec<(f64, O)>>;
/// Not the fork's (#3190's finding): the band refusal's fit as a scale of both blends,
@@ -2239,10 +2225,6 @@ where
ExecutiveAccess::process_smooth_edge_sequences(self, k, executive)
}
fn creation_ball_fits(&mut self, _k: &mut Kernel, _solver: O) -> Result<bool> {
Err(invalid("the ball-fit rule needs a live fillet session"))
}
fn creation_extend_trace_to_its_rails(&mut self, _k: &mut Kernel, _solver: O) -> Result<()> {
Err(invalid("the trace reach needs a live fillet session"))
}
@@ -2252,11 +2234,21 @@ where
_k: &mut Kernel,
_solver: O,
) -> Result<(BallStation, bool)> {
Err(invalid("the ball's regularity needs a live fillet session"))
// The adapter over ExecutiveAccess drives upstream's CreateFilletBrep (the goldens'
// executive runners) and holds no solver geometry. The ball, fit and band checks
// are not upstream's, so it passes them as upstream does, here and below; an error
// would refuse every round it builds. A live session judges them.
Ok((
BallStation {
check: BallCheck::Regular,
..BallStation::default()
},
false,
))
}
fn creation_solver_fit(&self, _solver: O) -> Result<Option<SolverFit<O>>> {
Err(invalid("a refusal's fit needs a live fillet session"))
Ok(None)
}
fn creation_band_cuts_the_part(
@@ -2264,7 +2256,7 @@ where
_k: &mut Kernel,
_solver: O,
) -> Result<Option<SolverCut<O>>> {
Err(invalid("the band's cut needs a live fillet session"))
Ok(None)
}
fn creation_band_breaks_through(
@@ -2272,9 +2264,7 @@ where
_k: &mut Kernel,
_solver: O,
) -> Result<Option<SolverCut<O>>> {
Err(invalid(
"the band's break-through needs a live fillet session",
))
Ok(None)
}
fn creation_largest_size_on_its_faces(
@@ -2283,7 +2273,7 @@ where
_solver: O,
_only: Option<O>,
) -> Result<Option<(f64, FitKind)>> {
Err(invalid("a refusal's fit needs a live fillet session"))
Ok(None)
}
fn creation_polygons_taken_whole(
@@ -2291,7 +2281,7 @@ where
_k: &mut Kernel,
_solvers: &[O],
) -> Result<Vec<(f64, O, f64)>> {
Err(invalid("a refusal's fit needs a live fillet session"))
Ok(Vec::new())
}
fn creation_ball_zone_open(
@@ -2300,7 +2290,7 @@ where
_solver: O,
_radius: Option<f64>,
) -> Result<Option<crate::blend::fillet_exact::CollapsedOffset>> {
Err(invalid("the ball's zone needs a live fillet session"))
Ok(None)
}
fn creation_rail_below_resolution(
@@ -2313,11 +2303,11 @@ where
}
fn creation_circle_tops(&mut self, _k: &mut Kernel, _solver: O) -> Result<Vec<(f64, O)>> {
Err(invalid("a refusal's fit needs a live fillet session"))
Ok(Vec::new())
}
fn creation_bands_meet(&mut self, _k: &mut Kernel, _solvers: &[O]) -> Result<Vec<(f64, O)>> {
Err(invalid("a refusal's fit needs a live fillet session"))
Ok(Vec::new())
}
fn creation_band_scale(&mut self, _k: &mut Kernel, _solvers: &[O]) -> Result<Option<(f64, O)>> {
@@ -3061,19 +3051,17 @@ impl<O: ClassObject + SolutionObject + Ord> FilletExecutive<O> {
None
};
if let Some((reason, why)) = why {
// the fork's 49f393d (`fixes.fillet_gn_section_generator`): the largest radius at
// which the overflowing blends' rails stay on their faces (where a boundary of a
// face first meets a rail): open, so less the fit margin (NoteOpenFit)
if k.fixes.fillet_gn_section_generator {
for &edge in &overflowing {
let mut index = 0;
while let Some(solver) = self.solvers.get(index).copied() {
index += 1;
if access.geometry_overflow_edge(solver)? != Some(edge) {
continue;
}
self.note_fit_on_its_faces(k, access, solver)?;
// the fork's 49f393d (WR-696): the largest radius at which the overflowing
// blends' rails stay on their faces (where a boundary of a face first meets a
// rail): open, so less the fit margin (NoteOpenFit)
for &edge in &overflowing {
let mut index = 0;
while let Some(solver) = self.solvers.get(index).copied() {
index += 1;
if access.geometry_overflow_edge(solver)? != Some(edge) {
continue;
}
self.note_fit_on_its_faces(k, access, solver)?;
}
}
return self.record_no_room(reason, why);
@@ -3103,20 +3091,18 @@ impl<O: ClassObject + SolutionObject + Ord> FilletExecutive<O> {
if k.fixes.fillet_refuse_face_consuming_blends
&& !access.geometry_faces_outlast(k, &self.solvers)?
{
// the fork's 49f393d, a3d6d81 and 5e8c9c1 (`fixes.fillet_gn_section_generator`): the
// largest radius that leaves some of the face, for a polygon with every edge blended
// the fork's 49f393d, a3d6d81 and 5e8c9c1 (WR-696): the largest radius that leaves
// some of the face, for a polygon with every edge blended
// (NoteFitOfPolygonsTakenWhole) and a plane bounded by one blended circle (the ball
// touching it at the centre); open, so less the fit margin
if k.fixes.fillet_gn_section_generator {
let solvers = self.solvers.clone();
for (best, solver, _) in access.creation_polygons_taken_whole(k, &solvers)? {
self.note_open_fit(access, true, best, FitKind::Radius, solver)?;
}
for solver in solvers {
for (fit, edge) in access.creation_circle_tops(k, solver)? {
if self.fit_radius < 0.0 || fit < self.fit_radius {
self.note_fit_radius(fit, Some(edge), FitKind::Radius);
}
let solvers = self.solvers.clone();
for (best, solver, _) in access.creation_polygons_taken_whole(k, &solvers)? {
self.note_open_fit(access, true, best, FitKind::Radius, solver)?;
}
for solver in solvers {
for (fit, edge) in access.creation_circle_tops(k, solver)? {
if self.fit_radius < 0.0 || fit < self.fit_radius {
self.note_fit_radius(fit, Some(edge), FitKind::Radius);
}
}
}
@@ -3128,8 +3114,7 @@ impl<O: ClassObject + SolutionObject + Ord> FilletExecutive<O> {
Ok(())
}
/// Not the fork's (#2401, `fixes.fillet_gn_section_generator` with
/// `fixes.fillet_refuse_face_consuming_blends`): a plane face bounded by straight edges,
/// Not the fork's (#2401, with `fixes.fillet_refuse_face_consuming_blends`): a plane face bounded by straight edges,
/// each blended with a constant ball, is taken whole once the least of its balls reaches
/// the radius that leaves some of it (`NoteFitOfPolygonsTakenWhole`'s bound, the deepest
/// point of the face in the balls' terms), to within the blended edge's tolerance (a face
@@ -3200,14 +3185,12 @@ impl<O: ClassObject + SolutionObject + Ord> FilletExecutive<O> {
if k.fixes.fillet_refuse_overlapping_bands
&& !access.geometry_bands_clear_other_rails(k, &self.solvers)?
{
// the fork's a3d6d81 (`fixes.fillet_gn_section_generator`): the largest common radius
// at which the bands stay apart, where they meet (closed), the least over the pairs
if k.fixes.fillet_gn_section_generator {
let solvers = self.solvers.clone();
for (meet, edge) in access.creation_bands_meet(k, &solvers)? {
if self.fit_radius < 0.0 || meet < self.fit_radius {
self.note_fit_radius(meet, Some(edge), FitKind::Radius);
}
// the fork's a3d6d81 (WR-696): the largest common radius at which the bands stay
// apart, where they meet (closed), the least over the pairs
let solvers = self.solvers.clone();
for (meet, edge) in access.creation_bands_meet(k, &solvers)? {
if self.fit_radius < 0.0 || meet < self.fit_radius {
self.note_fit_radius(meet, Some(edge), FitKind::Radius);
}
}
// (not the fork's, #3190's finding) where no radius is common to both, the scale
@@ -3944,24 +3927,6 @@ impl<O: ClassObject + SolutionObject + Ord> FilletExecutive<O> {
})?;
ignore(access.creation_smooth(k, self))?;
// Opt-in, not upstream (`fixes.fillet_refuse_ball_not_fitting`, WR-462, #1172):
// a blend whose rolling ball does not fit a face it rolls on has a rail turned
// back on itself; a corner where it ends looks for it where it cannot be.
// (the fork's 410dfe1 replaced `BallFitsItsFaces` by `BallIsRegular`, below, with
// `fixes.fillet_gn_section_generator`)
if k.fixes.fillet_refuse_ball_not_fitting && !k.fixes.fillet_gn_section_generator {
let mut index = 0;
while let Some(solver) = self.solvers.get(index).copied() {
if !access.creation_ball_fits(k, solver)? {
self.error.code = FilletErrorType::NoRoom as i32;
self.error.comment = "Fillet Error: a rail turns back on itself: the blend is wider than the face's curve allows (its rolling ball does not fit)".into();
self.error.no_room = Some(NoRoomReason::BallDoesNotFit);
return Err(failure());
}
index += 1;
}
}
// Opt-in, not upstream (`fixes.fillet_trace_reaches_rails`, WR-609/WR-610; the
// fork's tangency-labs/smlib@a9277fd and @6e77631): each solver's base surfaces
// reach as far as its rails can lie from the edge before the corners look for
@@ -3975,27 +3940,25 @@ impl<O: ClassObject + SolutionObject + Ord> FilletExecutive<O> {
}
}
// Opt-in, not upstream (`fixes.fillet_gn_section_generator`; the fork's
// tangency-labs/smlib#79, 410dfe1 to a34b5e8 and a3d6d81): the rolling ball's local
// regularity along each blend's edge, refused naming the radius that works.
if k.fixes.fillet_gn_section_generator {
self.refuse_irregular_balls(k, access)?;
// not the fork's (#2401): a ball as wide as a face, whose zone has no section at
// an end of its edge
self.refuse_collapsed_offsets(k, access)?;
// the fork's 862971f, e568e45 and aac4288: a convex blend that would cut the part
// into pieces, refused naming the largest size that keeps it whole
self.refuse_blends_cutting_the_part(k, access)?;
// not the fork's (WR-707, #2299): a convex blend whose section would break through
// a wall into the hollow behind, refused naming the largest size that does not
if k.fixes.fillet_refuse_rounds_breaking_through {
self.refuse_blends_breaking_through(k, access)?;
}
// not the fork's (#2401): a polygon face its blends take whole, refused before
// the trace that its rails of no length would fail
if k.fixes.fillet_refuse_face_consuming_blends {
self.refuse_polygons_taken_whole(k, access)?;
}
// Not upstream (WR-696; the fork's tangency-labs/smlib#79, 410dfe1 to a34b5e8 and
// a3d6d81, which replaced its `BallFitsItsFaces`): the rolling ball's local regularity
// along each blend's edge, refused naming the radius that works.
self.refuse_irregular_balls(k, access)?;
// not the fork's (#2401): a ball as wide as a face, whose zone has no section at an
// end of its edge
self.refuse_collapsed_offsets(k, access)?;
// the fork's 862971f, e568e45 and aac4288: a convex blend that would cut the part
// into pieces, refused naming the largest size that keeps it whole
self.refuse_blends_cutting_the_part(k, access)?;
// not the fork's (WR-707, #2299): a convex blend whose section would break through a
// wall into the hollow behind, refused naming the largest size that does not
if k.fixes.fillet_refuse_rounds_breaking_through {
self.refuse_blends_breaking_through(k, access)?;
}
// not the fork's (#2401): a polygon face its blends take whole, refused before the
// trace that its rails of no length would fail
if k.fixes.fillet_refuse_face_consuming_blends {
self.refuse_polygons_taken_whole(k, access)?;
}
// Not the fork's (#2546, WR-739): a rail whose ends would be one vertex, or that
@@ -748,7 +748,6 @@ fn state() -> FilletExecutive<Handle> {
vertex_corner_map: BTreeMap::new(),
edgeuse_solver_map: BTreeMap::new(),
self_intersection_handler: None,
blend_curve_at_thirds: false,
mark_corner_patches: false,
cliff_overflow: false,
open_ends: Vec::new(),
@@ -1977,8 +1977,8 @@ impl<'target> FilletSession<'target> {
/// overload with `SM_FS_VARIABLE_RADIUS`, as `SmApiVariableRadiusFillet` does:
/// one cross-section type for every edge, `radius` as the (unused) solver
/// distance, `law` shared by every edge's solver and default tolerances. The
/// thumbweight is `SetFilletParameters`' default: upstream's `1.0`, or with
/// `fixes.fillet_gn_section_generator` the fork's `SM_GN_DEFAULT_THUMBWEIGHT`.
/// thumbweight is `SetFilletParameters`' default with the G^n section, the fork's
/// `SM_GN_DEFAULT_THUMBWEIGHT` (upstream's `1.0`, which the G^n section refuses).
///
/// Zero selects linear, two blend-curve, every other cross-section code circular.
///
@@ -2029,13 +2029,10 @@ impl<'target> FilletSession<'target> {
tan_tol_deg: -1.0,
xsect_tol: -1.0,
continuity,
// SetFilletParameters' default thumbweight: upstream's 1.0, the fork's
// SM_GN_DEFAULT_THUMBWEIGHT with its G^n section (WR-685), which refuses 1.0
thumbweight: if k.fixes.fillet_gn_section_generator {
crate::blend::fillet_section::section::GN_DEFAULT_THUMBWEIGHT
} else {
1.0
},
// SetFilletParameters' default thumbweight: the fork's
// SM_GN_DEFAULT_THUMBWEIGHT with its G^n section (WR-685), which refuses
// upstream's 1.0
thumbweight: crate::blend::fillet_section::section::GN_DEFAULT_THUMBWEIGHT,
second_radii: None,
},
);
@@ -2813,8 +2810,7 @@ impl<'target> FilletSession<'target> {
/// `GetFitRadius`, `GetFitEdge`, `GetFitKind` (the fork's, tangency-labs/smlib#79
/// a3d6d81): with a refusal as too large ([`ErrorInfo::no_room_reason`]), the largest
/// size that builds the refused blend and its edge, computed from the refusal's cause;
/// `None` when its cause has no size (a radius law) or no refusal noted one. Only with
/// `fixes.fillet_gn_section_generator`.
/// `None` when its cause has no size (a radius law) or no refusal noted one.
#[must_use]
pub fn fit_size(&self) -> Option<crate::blend::fillet_executive::FitSize<EdgeId>> {
let fit = self.executive.fit_size()?;
@@ -3616,23 +3612,6 @@ impl BrepCreationAccess<FilletObject> for SessionObjects<'_> {
executive.process_smooth_edge_sequences_narrow(k, self)
}
fn creation_ball_fits(&mut self, k: &mut Kernel, solver: FilletObject) -> Result<bool> {
let FilletObject::Solver(id) = solver else {
return Err(invalid("object is not a solver"));
};
let index = id.0 as usize;
let current = self
.solvers
.get_mut(index)
.and_then(Option::as_mut)
.ok_or_else(|| invalid("solver is not live in this session"))?;
crate::blend::fillet_solver::ball_fit::ball_fits_its_faces(
live_solver_ops(current),
k,
self.target,
)
}
fn creation_extend_trace_to_its_rails(
&mut self,
k: &mut Kernel,
@@ -3772,7 +3751,11 @@ impl BrepCreationAccess<FilletObject> for SessionObjects<'_> {
None => None,
};
let edge = edge.ok_or_else(|| SolidError::null_pointer(OP))?;
if crate::blend::fillet_solver::p5::is_concave_edge(k, self.target, edge)? {
// a sheet's edge bounds no material: there is no part for the band to cut (not the
// fork's, whose `sm_BlendAddsMaterial` fails there, and the fillet with it)
if !crate::blend::fillet_solver::p5::edge_bounds_material(self.target, edge)?
|| crate::blend::fillet_solver::p5::is_concave_edge(k, self.target, edge)?
{
return Ok(None);
}
let Some(cut) = band_cuts::band_cuts_the_part_cached(
@@ -3817,7 +3800,11 @@ impl BrepCreationAccess<FilletObject> for SessionObjects<'_> {
None => None,
};
let edge = edge.ok_or_else(|| SolidError::null_pointer(OP))?;
if crate::blend::fillet_solver::p5::is_concave_edge(k, self.target, edge)? {
// a sheet's edge bounds no material: there is no part for the band to cut (not the
// fork's, whose `sm_BlendAddsMaterial` fails there, and the fillet with it)
if !crate::blend::fillet_solver::p5::edge_bounds_material(self.target, edge)?
|| crate::blend::fillet_solver::p5::is_concave_edge(k, self.target, edge)?
{
return Ok(None);
}
let Some(cut) = band_cuts::band_breaks_through_the_part_cached(
@@ -7,8 +7,7 @@
//! `BallIsRegular` (`SmFilletSolver.cpp`, `SmFilletSolver.h`) and the virtuals
//! `GetBallLaw`, `SetBallRadius` and `RollsABall` (`SmFilletStandardSolver.h/.cpp`) in
//! commits 410dfe1, 20ba5a9, 8c40818 and a34b5e8 (the last deletes the transversality check
//! 410dfe1 added, so it has no port). They run only with the opt-in
//! `Kernel::fixes.fillet_gn_section_generator`.
//! 410dfe1 added, so it has no port).
//!
//! | Rust | Upstream (fork) |
//! |----------------------------|---------------------------------------------------|
@@ -5,8 +5,7 @@
//! merged at 5e8c9c1) adds `SmFilletSolver::BandCutsThePart` with `sm_EdgesCrossingPlane`
//! and `sm_KeepsMaterialBehind` (`SmFilletSolver.cpp`, `SmFilletSolver.h`) in commits
//! 862971f, e568e45 (the section intersected with every face, not sampled) and aac4288 (a
//! run of cutting sections reaching an end of the edge is no cut). They run only with the
//! opt-in `Kernel::fixes.fillet_gn_section_generator`.
//! run of cutting sections reaching an end of the edge is no cut).
//!
//! | Rust | Upstream (fork) |
//! |-------------------------------|------------------------------------------|
@@ -1030,8 +1029,7 @@ pub(crate) fn band_cuts_the_part_cached(
Ok(cut)
}
/// Not the fork's (WR-707, #2299; `fixes.fillet_refuse_rounds_breaking_through` with
/// `fixes.fillet_gn_section_generator`): whether this convex blend's section breaks
/// Not the fork's (WR-707, #2299; `fixes.fillet_refuse_rounds_breaking_through`): whether this convex blend's section breaks
/// through the part somewhere along its edge (it leaves the part and comes back into it
/// through an inner face, one sharing no edge with the blended faces: a hollow behind a
/// wall, `section_breaks_through`), and where it would, the largest size that keeps every
@@ -94,19 +94,18 @@ impl FilletSession<'_> {
/// The fork's `sm_HoldsItsLaw`: whether a variable round on planar faces holds its
/// radius law between the filleted edge's ends.
///
/// A rolling ball of radius r between two planes meeting at the interior angle a stands
/// off the edge by `r (1 / sin(a/2) - 1)` where its section crosses the wedge's
/// bisector. That point must lie on the fillet surface, at seven points along the edge,
/// to twenty times the solver's tolerance and a ten-thousandth of the radius; of the two
/// angles the planes make, and the bisector either way, the one that fits. Rounds of
/// other solvers, with other than a circular section, on faces that are not both
/// planes, with other than one fillet geometry, or along an edge that is not straight,
/// pass.
/// The round's point on the touch circle of the ball at each of seven points along the
/// edge, in the wedge's bisector plane, must lie on the fillet surface, to twenty times
/// the solver's tolerance and a ten-thousandth of the radius; of the two angles the
/// planes make, and the bisector either way, the one that fits. Rounds of other solvers,
/// with other than a circular section, on faces that are not both planes, with other
/// than one fillet geometry, or along an edge that is not straight, pass.
///
/// With `fixes.fillet_gn_section_generator` (the fork's tangency-labs/smlib@8bedf89 =
/// d01d7b0's 6007a3d, WR-685) the point is on the round's touch circle, not the great
/// circle: the ball's centre `r / sin(a/2)` off the edge on the bisector, the circle
/// square to the centres' line, its centre moved along that line by `-r dr/ds` (`s` the
/// The point is on the round's touch circle, not the great circle (the fork's
/// tangency-labs/smlib@8bedf89 = d01d7b0's 6007a3d, WR-685; its first `sm_HoldsItsLaw`
/// took the great circle's point `r (1 / sin(a/2) - 1)` off the edge): the ball's
/// centre `r / sin(a/2)` off the edge on the bisector, the circle square to the
/// centres' line, its centre moved along that line by `-r dr/ds` (`s` the
/// centres' arc length) and its radius `r sqrt(1 - (dr/ds)^2)`, its point in the
/// bisector plane on the edge's side; the law's value and slope are read with `SER`.
pub(super) fn holds_its_law(&self, k: &Kernel, solver: FilletObject) -> Result<bool> {
@@ -160,78 +159,22 @@ impl FilletSession<'_> {
let mut law = vr.law.clone();
// the fork's tangency-labs/smlib@8bedf89 (= d01d7b0's 6007a3d; WR-685): the round
// touches each ball along its touch circle, not its great circle
let touch_circle = k.fixes.fillet_gn_section_generator;
let mut holds = true;
let mut i = 1;
while i < 8 && holds {
let t = interval.evaluate(f64::from(i) / 8.0);
i += 1;
if touch_circle {
let edge_pv = curve.evaluate(k, t, 1, true, false)?;
let [pnt, edge_d, ..] = *edge_pv.as_slice() else {
return Err(SolidError::sm_err(OP));
};
let [r, dr, _] = law.evaluate(t, &vr.law_interval, vr.law_orientation)?;
let radius = r.abs();
let slope = if r < 0.0 { -dr } else { dr }; // d|r|/dT
// The ball's centre on the wedge's bisector, r / sin(a/2) off the edge, and
// the touch circle's point on the bisector plane toward the edge. The planes'
// normals are both outward (or inward), the bisector along their sum and the
// angle pi less theirs, or one of each, the bisector along their difference.
let mut fits = false;
let mut c = 0;
while c < 4 && !fits {
let bisector = if c < 2 { n0 + n1 } else { n0 - n1 };
let angle = if c < 2 { PI - phi } else { phi };
let sign = if c % 2 == 1 { -1.0 } else { 1.0 };
c += 1;
let len = bisector.length();
if len <= EFF_ZERO_SQRT || angle <= EFF_ZERO_SQRT {
continue;
}
let out = bisector * (sign / len); // edge to centre
let off = 1.0 / (angle / 2.0).sin();
let centre = pnt + out * (radius * off);
let along = edge_d + out * (slope * off); // dC/dT
let speed = along.length();
if speed <= EFF_ZERO {
continue;
}
let along = along / speed;
let rate = slope / speed; // dr/ds
if rate.abs() >= 1.0 {
continue;
}
let to_edge = -out - along * (-out).dot(along);
let to_edge_len = to_edge.length();
if to_edge_len <= EFF_ZERO {
continue;
}
let middle = centre
+ along * (-radius * rate)
+ to_edge * (radius * (1.0 - rate * rate).sqrt() / to_edge_len);
let dropped = fillet.drop_point::<NoObject>(
k,
middle,
&domain,
&DropPointOptions::default(),
)?;
fits = dropped.success && dropped.gap <= tol + 1.0e-4 * radius;
}
holds = fits;
continue;
}
let pnt = curve.evaluate_point(k, t)?;
// SmVariableRadiusFS::GetFilletRadius: SER inside a `double` function, but a law
// continued past its curve to an unusable radius stays refused (a corner may
// have narrowed the law to its setback, putting this station past its curve)
let radius = law
.fillet_radius(t, &vr.law_interval, vr.law_orientation)?
.abs();
// The section's middle: along the wedge's bisector, r (1 / sin(a/2) - 1) off the
// edge. The planes' normals are both outward (or inward), the bisector along
// their sum and the angle pi less theirs, or one of each, the bisector along
// their difference.
let edge_pv = curve.evaluate(k, t, 1, true, false)?;
let [pnt, edge_d, ..] = *edge_pv.as_slice() else {
return Err(SolidError::sm_err(OP));
};
let [r, dr, _] = law.evaluate(t, &vr.law_interval, vr.law_orientation)?;
let radius = r.abs();
let slope = if r < 0.0 { -dr } else { dr }; // d|r|/dT
// The ball's centre on the wedge's bisector, r / sin(a/2) off the edge, and the
// touch circle's point on the bisector plane toward the edge. The planes' normals
// are both outward (or inward), the bisector along their sum and the angle pi
// less theirs, or one of each, the bisector along their difference.
let mut fits = false;
let mut c = 0;
while c < 4 && !fits {
@@ -243,16 +186,33 @@ impl FilletSession<'_> {
if len <= EFF_ZERO_SQRT || angle <= EFF_ZERO_SQRT {
continue;
}
let stand_off = radius * (1.0 / (angle / 2.0).sin() - 1.0);
let middle = pnt + bisector * (sign * stand_off / len);
let out = bisector * (sign / len); // edge to centre
let off = 1.0 / (angle / 2.0).sin();
let centre = pnt + out * (radius * off);
let along = edge_d + out * (slope * off); // dC/dT
let speed = along.length();
if speed <= EFF_ZERO {
continue;
}
let along = along / speed;
let rate = slope / speed; // dr/ds
if rate.abs() >= 1.0 {
continue;
}
let to_edge = -out - along * (-out).dot(along);
let to_edge_len = to_edge.length();
if to_edge_len <= EFF_ZERO {
continue;
}
let middle = centre
+ along * (-radius * rate)
+ to_edge * (radius * (1.0 - rate * rate).sqrt() / to_edge_len);
let dropped = fillet.drop_point::<NoObject>(
k,
middle,
&domain,
&DropPointOptions::default(),
)?;
// the solver's tolerance, and its circular sections' relative accuracy (a
// non-rational cubic across the round, within about 2e-5 of the radius)
fits = dropped.success && dropped.gap <= tol + 1.0e-4 * radius;
}
holds = fits;
@@ -1,19 +1,19 @@
//! The fork's section placement and corner-patch marks of the live session.
//! The fork's corner-patch marks of the live session.
//!
//! Upstream: the fork tangency-labs/smlib `fd3b6a7` (`SmFilletExecutive::SetBlendCurveAtThirds`)
//! and `60af574` (`SmFilletExecutive::SetMarkCornerPatches`, `SmFilletCorner::GetPatchFaces`,
//! the marking loop of `DoFilleting`); neither is in SMLib at the pin.
//! Upstream: the fork tangency-labs/smlib `60af574` (`SmFilletExecutive::SetMarkCornerPatches`,
//! `SmFilletCorner::GetPatchFaces`, the marking loop of `DoFilleting`); not in SMLib at the
//! pin. The fork's `SetBlendCurveAtThirds` (`fd3b6a7`) went when the G^n section replaced the
//! blend curve (WR-685 addendum 2026-11-06).
//!
//! | Rust | Upstream (fork) |
//! |------|-----------------|
//! | [`FilletSession::set_blend_curve_at_thirds`] | `SmFilletExecutive::SetBlendCurveAtThirds` |
//! | [`FilletSession::set_mark_corner_patches`] | `SmFilletExecutive::SetMarkCornerPatches` |
//! | `mark_corner_patches` (private) | the `m_bMarkCornerPatches` loop of `DoFilleting` |
//! | `patch_faces` (private) | `SmFilletCorner::GetPatchFaces` |
//! | [`FilletSession::corner_patch_faces`] | `round_edges` reading the `SM_AI_FILLET_CORNER_FACE` marks |
//!
//! Deviations: both settings are per session and off by default, so a session that
//! does not set them is the pinned C++'s. The marks live in the session's attribute
//! Deviations: the setting is per session and off by default, so a session that
//! does not set it is the pinned C++'s. The marks live in the session's attribute
//! store (keyed by the intermediate faces, then by the target copies the merge makes,
//! as the fork's attributes travel with the copy); [`FilletSession::corner_patch_faces`]
//! reads them from the target faces, and they go with the session. No recursion.
@@ -27,18 +27,6 @@ use crate::topology::FaceId;
const OP: &str = "blend::fillet_executive::session::corner_marks";
impl FilletSession<'_> {
/// `SetBlendCurveAtThirds` (the fork's, tangency-labs/smlib `fd3b6a7`; off by
/// default): the blend-curve generators the prepare calls create
/// (`SetFilletParameters`) place each section's inner control points a third and
/// two thirds of the way from each contact to where the contacts' tangent lines
/// meet (the end derivatives scaled to `n/3` of that distance for degree `n`, the
/// second and third derivatives by its square and cube). Set it before preparing
/// the edges. Off, the sections are the pinned C++'s faired Hermite scaled by the
/// thumbweight.
pub fn set_blend_curve_at_thirds(&mut self, at_thirds: bool) {
self.executive.set_blend_curve_at_thirds(at_thirds);
}
/// `SetMarkCornerPatches` (the fork's, tangency-labs/smlib `60af574`; off by
/// default): before the merge, `do_filleting` marks each face of every set-back
/// corner's patch (the faces on the surfaces the corner made) with an
@@ -29,10 +29,7 @@ use super::{live_solver_ops, SessionObjects};
use crate::blend::blend_setback::{ease_surface_of, interval_in, uv_at, EaseRamp};
use crate::blend::fillet_geom::p1::{FilletGeomId, FilletVertexType, SurfaceHandle};
use crate::blend::fillet_section::section::{GnFaces, GnSectionFsg};
use crate::blend::fillet_solver::p1::{
FilletSolverOps, FilletSolverType, FilletSurfaceGeneratorType,
};
use crate::blend::fillet_standard_solver::p1::{BlendCurveCrossSectionFsg, RailSurface};
use crate::blend::fillet_solver::p1::{FilletSolverOps, FilletSurfaceGeneratorType};
use crate::curve::curve::{Curve, CurveKind};
use crate::error::{EntityRef, Result, SolidError};
use crate::geom::extent2d::Extent2d;
@@ -105,9 +102,10 @@ impl SessionObjects<'_> {
/// `SM_FV_SETBACK` vertex of a corner with an ease (in `corners`' order), the round's
/// surface is replaced, over the rail parameter from where the plane square to the edge
/// at the setback plus the ease cuts the rail to where the setback's section meets it,
/// by the C2 blend of its own surface into the one `SmBlendCurveCrossSectionFSG` (`G2`,
/// at thirds) builds on the same rails. A round whose sections are already that
/// (`SM_FSG_BLEND_CURVE`) keeps them; ramps on both ends of one round go into one
/// by the C2 blend of its own surface into the order-2 G^n section at thumbweight 0 on
/// the same rails (the fork's 11ea2d9 and 22d258a; its first version, `e74bbd3`, took
/// `SmBlendCurveCrossSectionFSG`'s `G2` at thirds). A round whose sections are already
/// curvature-continuous (`SM_FSG_BLEND_CURVE`) keeps them; ramps on both ends of one round go into one
/// blend. Without an eased corner nothing changes.
///
/// # Errors
@@ -425,57 +423,29 @@ impl SessionObjects<'_> {
// the curvature-continuous surface on the same rails (CreateSurfaceFromCurves
// changes the curves' knots: it is given copies)
let mut c0 = center;
let c0 = center;
let mut c1 = bspline_curve(rail0).ok_or_else(null)?.clone();
let mut c2 = bspline_curve(rail1).ok_or_else(null)?.clone();
let g2_generator = BlendCurveCrossSectionFsg {
continuity: 2,
blend_scale: 1.0,
at_thirds: true,
};
let solver = self.solver_mut(solver_id)?;
let need_g1 = live_solver_ops(solver).solver_type()? == FilletSolverType::ConstRadius;
let (Some(surf0), Some(surf1)) = (face_surfs.first(), face_surfs.get(1)) else {
return Err(sm_err());
};
let g2 = if k.fixes.fillet_gn_section_generator {
// the fork's order-2 G^n section (WR-685, tangency-labs/smlib@11ea2d9):
// the faces' curvature across the rails. Its thumbweight stays 0, not the
// equal area default: it is the corner's transition, not the blend's own
// section (the fork's 22d258a = d01d7b0's adb9854)
let (Some(uv0), Some(uv1)) = (uvs.first(), uvs.get(1)) else {
return Err(null());
};
GnSectionFsg::new(2, 0.0).create_surface_from_curves(
k,
&c0,
[&mut c1, &mut c2],
tol,
GnFaces {
surfaces: [surf0, surf1],
uv: [uv0, uv1],
},
)?
} else {
g2_generator
.create_surface_from_curves(
k,
&mut c0,
&mut c1,
&mut c2,
tol,
need_g1,
RailSurface {
surface: Some(surf0),
uv_curve: uvs.first(),
},
RailSurface {
surface: Some(surf1),
uv_curve: uvs.get(1),
},
)
.map(Surface::from)?
// the fork's order-2 G^n section (WR-685, tangency-labs/smlib@11ea2d9): the
// faces' curvature across the rails. Its thumbweight stays 0, not the equal area
// default: it is the corner's transition, not the blend's own section (the fork's
// 22d258a = d01d7b0's adb9854)
let (Some(uv0), Some(uv1)) = (uvs.first(), uvs.get(1)) else {
return Err(null());
};
let g2 = GnSectionFsg::new(2, 0.0).create_surface_from_curves(
k,
&c0,
[&mut c1, &mut c2],
tol,
GnFaces {
surfaces: [surf0, surf1],
uv: [uv0, uv1],
},
)?;
// (the fork's EaseSurface takes the G^n target, a blend by its definition with
// `fillet_round_as_definition`, and the round's own surface as they are)
@@ -39,13 +39,12 @@
//! No recursion.
use super::original_trim::OriginalSurfaceDeletion;
use super::{invalid, FilletBody, FilletObject, FilletSession, SessionObjects, SolverObject};
use super::{invalid, FilletBody, FilletObject, FilletSession, SessionObjects};
use crate::blend::fillet_cliff_overflow::Refusal;
use crate::blend::fillet_executive::p3::{
ErrorInfo, FilletExecutive, FilletFinishAccess, StitchAttempt, StitchSettings,
};
use crate::blend::fillet_geom::p1::FilletErrorType;
use crate::blend::fillet_solver::p1::FilletSurfaceGeneratorType;
use crate::error::{EntityRef, Result, SolidError};
use crate::geom::object::NotifyOperation;
use crate::geom::tol::approx_tol3d;
@@ -537,8 +536,8 @@ impl FilletSession<'_> {
self.executive.error = note;
}
}
// Opt-in (`fixes.fillet_gn_section_generator`, WR-696): a refusal with a size that
// builds carries it on the error, its status unchanged.
// Not upstream (WR-696): a refusal with a size that builds carries it on the error,
// its status unchanged.
if let Err(SolidError::Upstream {
operation,
code,
@@ -656,48 +655,6 @@ impl FilletSession<'_> {
}
}
/// Not the fork's (#2727): great circles have no corner of a radius law to stop at. Swept
/// over one, the surface's net doubles back on itself (`check_brep` #5): the 20 cube's
/// law 4, 2, 4 builds such a net, and 3, 2, 4, 2, 3 one over 140 mm across. A circular
/// variable round whose law has a corner inside its edge is built only as its balls'
/// union (`fixes.fillet_gn_section_generator`, WR-696), which splits it there; without
/// it the round is refused before the target is touched.
fn refuse_great_circles_over_a_law_corner(&mut self, k: &Kernel) -> Result<()> {
if k.fixes.fillet_gn_section_generator {
return Ok(());
}
let mut crossed = false;
for solver in self.objects.solvers.iter().flatten() {
let SolverObject::VariableRadius(vr) = solver else {
continue;
};
let circular = vr
.curve_based
.solver
.fillet_surface_generator()
.is_some_and(|fsg| {
fsg.fillet_surface_generator_type() == FilletSurfaceGeneratorType::Circular
});
if circular
&& !vr
.law
.corner_parameters(&vr.law_interval, vr.law_orientation)?
.is_empty()
{
crossed = true;
}
}
if !crossed {
return Ok(());
}
self.note_refusal(Refusal {
code: FilletErrorType::CornerUnsupported,
reason: None,
comment: "Fillet Error: a variable round's radius law has a corner inside its edge, which a sweep of great circles cannot follow: its net would double back on itself",
});
Err(failure())
}
/// `JoinBlendedVertexFans` (the fork's, tangency-labs/smlib@e418750, WR-665): the
/// inverse of the fan split after the blends: the target's vertices still at a split
/// point (within their own tolerance of it), joined into the first of them
@@ -769,7 +726,6 @@ impl FilletSession<'_> {
});
return Err(failure());
}
self.refuse_great_circles_over_a_law_corner(k)?;
// (not the fork, #2933) a corner at a vertex marked set back is classified now, where
// the setback set on it is first read: the Setback where it is one
self.set_back_marked_corners(k)?;
@@ -1050,7 +1006,8 @@ mod stitch_identity_tests {
}
}
/// `fixes.fillet_refuse_ball_not_fitting` (WR-462, tangency-labs/solidcore#1172): a
/// A ball that does not fit a face it rolls on (WR-462, tangency-labs/solidcore#1172; since the
/// retirement of `fillet_refuse_ball_not_fitting`, judged by `BallIsRegular`, WR-696): a
/// 60 x 40 x 20 box, its top edge at x = 60 rounded r3, then the round's end arc on the face
/// y = 40 with the two edges tangent to it (the top edge at y = 40, the vertical edge at
/// x = 60, y = 40): the ball rolls on the r3 round, so one of radius over 3 does not fit it.
@@ -1094,9 +1051,9 @@ mod ball_fit_tests {
nearest.1.unwrap()
}
/// The executive's error code after the round of `radius` on the r3 round's end with the
/// fix on or off, and its result.
fn end_round(radius: f64, fix: bool) -> (i32, Result<()>) {
/// The executive's error code after the round of `radius` on the r3 round's end, and its
/// result.
fn end_round(radius: f64) -> (i32, Result<()>) {
let mut k = Kernel::default();
let mut body =
crate::primitive::api_primitives::create_box(&mut k, Point3::ZERO, 60.0, 40.0, 20.0)
@@ -1114,7 +1071,6 @@ mod ball_fit_tests {
.into_iter()
.map(|p| edge_near(&k, &body, p))
.collect();
k.fixes.fillet_refuse_ball_not_fitting = fix;
let mut session = FilletSession::new(&mut k, &mut body).unwrap();
session
.prepare_constant_radius_edges(&mut k, &edges, radius, 1, 1, 1.0)
@@ -1125,34 +1081,25 @@ mod ball_fit_tests {
#[test]
fn a_ball_that_does_not_fit_is_no_room_before_the_corners() {
// without the ball-fit rule: a ball of 3.1 beside the R3 round's end arc fails (the
// blend corner refuses it); one of 7 is refused before the corners (#2546, WR-739),
// its rail past the R3 round's axis (radius 3 - 7 < 0), naming 3
let (_, result) = end_round(3.1, false);
assert!(result.is_err(), "r3.1");
let (code, result) = end_round(7.0, false);
let Err(SolidError::FilletRefused { reason, fit, .. }) = result else {
panic!("r7: {result:?}");
};
assert_eq!(
reason,
Some(crate::blend::fillet_executive::NoRoomReason::RailPastAxis)
);
assert!((fit.size - 3.0).abs() < 1e-12, "r7: {}", fit.size);
assert_eq!(code, NO_ROOM);
for radius in [3.1, 7.0] {
let (code, result) = end_round(radius, true);
assert!(matches!(
result,
Err(SolidError::Upstream { code: 1001, .. })
));
let (code, result) = end_round(radius);
eprintln!("r{radius}: code {code} {result:?}");
let Err(SolidError::FilletRefused { reason, fit, .. }) = result else {
panic!("r{radius}: {result:?}");
};
assert_eq!(
reason,
Some(crate::blend::fillet_executive::NoRoomReason::BallDoesNotFit),
"r{radius}"
);
assert!(fit.size > 0.0 && fit.size <= 3.0, "r{radius}: {}", fit.size);
assert_eq!(code, NO_ROOM, "r{radius}: NoRoom");
}
}
#[test]
fn a_ball_that_fits_is_not_refused() {
let (code, result) = end_round(2.0, true);
let (code, result) = end_round(2.0);
result.unwrap();
assert_ne!(code, NO_ROOM);
}
@@ -7,8 +7,7 @@
//! `LargestSizeOnItsFaces` and `BandsMeetAt` (`SmFilletSolver.cpp`, `SmFilletSolver.h`) and
//! the executive's `NoteFitOfPolygonsTakenWhole` and the circle-top fit of
//! `CreateFilletBrep` (`SmFilletExecutive.cpp`) in commits a3d6d81 and 49f393d; 5e8c9c1
//! brackets each bound strictly inside its search (twice the blend's own size). They run
//! only with the opt-in `Kernel::fixes.fillet_gn_section_generator`.
//! brackets each bound strictly inside its search (twice the blend's own size).
//!
//! | Rust | Upstream (fork) |
//! |-------------------------------|--------------------------------------------------|
@@ -85,7 +85,7 @@ impl FilletSession<'_> {
// `GetRadiusCornerParameters` (virtual): the variable radius solver's
let geoms = match self.objects.solvers.get(index).and_then(Option::as_ref) {
Some(SolverObject::VariableRadius(vr)) => {
if vr.radius_corner_parameters(k)?.is_empty() {
if vr.radius_corner_parameters()?.is_empty() {
continue;
}
vr.curve_based.solver.fillet_geoms()
@@ -22,8 +22,7 @@
//! fork's in address order).
//! - **Fit sizes.** The three refusals step 5 sizes (`NoteFitOnFace` after the tangent
//! edge and the extension, `NoteFitRadius` from `sm_CornerTakesPerRadius` after the
//! whole edge; tangency-labs/smlib a3d6d81, 49f393d) note them with
//! `fixes.fillet_gn_section_generator` (WR-696, #2278).
//! whole edge; tangency-labs/smlib a3d6d81, 49f393d) note them (WR-696, #2278).
//! - **Section ends (not the fork's).** A round with WR-674's section ends is trimmed here
//! only with `fixes.fillet_section_end_trim_at_creases` (WR-706, #2223): each such end is
//! cut by its section's plane and closed by the section's flat face, and a side of that
@@ -661,10 +660,10 @@ impl FilletSession<'_> {
for (slot, f) in entry.iter_mut().zip(faces) {
slot.1 = f;
}
// not the fork's (#2401; with `fixes.fillet_gn_section_generator`, WR-696): an
// open end the end face does not cut is an overflow's, absent below the size at
// which the end's blend stays on its faces: that size (open)
if note.is_some() && cut.is_err() && k.fixes.fillet_gn_section_generator {
// not the fork's (#2401, WR-696): an open end the end face does not cut is an
// overflow's, absent below the size at which the end's blend stays on its
// faces: that size (open)
if note.is_some() && cut.is_err() {
self.executive
.note_fit_on_its_faces(k, &mut self.objects, end.solver)?;
}
@@ -750,9 +749,7 @@ impl FilletSession<'_> {
// Not the fork's (#2404): the strip a blend leaves on an edge of the body, thinner than
// the part resolves, has no topology to build
if self.strip_below_resolution(k, &sheet, blended_edges, tol)? {
if k.fixes.fillet_gn_section_generator {
self.note_fit_of_the_strip(solvers, blended_edges)?;
}
self.note_fit_of_the_strip(solvers, blended_edges)?;
return refuse(
note,
refusal(
@@ -905,16 +902,11 @@ impl FilletSession<'_> {
&& rolled_on.contains(&g)
&& is_tangent_edge(k, self.objects.target, e, tangency)?
{
// the fork's NoteFitOnFace(g) (49f393d; with
// `fixes.fillet_gn_section_generator`, WR-696)
if k.fixes.fillet_gn_section_generator {
let face = FilletObject::Topology(
FilletBody::Target,
EntityRef::Face(g),
);
self.executive
.note_fit_on_face(k, &mut self.objects, face)?;
}
// the fork's NoteFitOnFace(g) (49f393d, WR-696)
let face =
FilletObject::Topology(FilletBody::Target, EntityRef::Face(g));
self.executive
.note_fit_on_face(k, &mut self.objects, face)?;
return refuse(
note,
refusal(
@@ -995,12 +987,10 @@ impl FilletSession<'_> {
if has && !kept_rounds.contains(&i) {
// the largest radius that keeps a length of the edge: its corners take
// r <u, e> at each end (sm_CornerTakesPerRadius), the edge's length L in all
// at r = L / (s0 + s1); open, so less the fit margin (the fork's a3d6d81;
// with `fixes.fillet_gn_section_generator`, WR-696)
if k.fixes.fillet_gn_section_generator {
if let Some(&solver) = solvers.get(i) {
self.note_fit_of_corners_taking_the_edge(k, solver, solvers)?;
}
// at r = L / (s0 + s1); open, so less the fit margin (the fork's a3d6d81,
// WR-696)
if let Some(&solver) = solvers.get(i) {
self.note_fit_of_corners_taking_the_edge(k, solver, solvers)?;
}
return refuse(
note,
@@ -1062,13 +1052,10 @@ impl FilletSession<'_> {
let outcome = extend(k, self.objects.target, f, &rails, blended_edges, tol)?;
match outcome {
ExtendOutcome::Refused(why) => {
// the fork's NoteFitOnFace(f) (49f393d; with
// `fixes.fillet_gn_section_generator`, WR-696)
if k.fixes.fillet_gn_section_generator {
let face = FilletObject::Topology(FilletBody::Target, EntityRef::Face(f));
self.executive
.note_fit_on_face(k, &mut self.objects, face)?;
}
// the fork's NoteFitOnFace(f) (49f393d, WR-696)
let face = FilletObject::Topology(FilletBody::Target, EntityRef::Face(f));
self.executive
.note_fit_on_face(k, &mut self.objects, face)?;
return refuse(
note,
refusal(
@@ -250,8 +250,8 @@ impl FilletSession<'_> {
/// wedge of its edges between planes, else at the narrowest of its wedges at which no
/// station folds ([`unfolded_wedge`]), so their rails meet where they run on into each
/// other. Then prepared as [`Self::prepare_per_edge_two_offsets`] with the linear
/// section, and the solver keeps the sizes: with `fixes.fillet_gn_section_generator` and
/// `fixes.fillet_round_as_definition` the chamfer's surface is its definition, the
/// section, and the solver keeps the sizes: with `fixes.fillet_round_as_definition` the
/// chamfer's surface is its definition, the
/// chord of order 0, and keeps them too. A distance is along the edge's blend edge
/// use's face (support 1) or its radial mate's (support 2); an angle is to support 1.
/// Between planes the sizes hold all along the edge; on a curved face, where the wedge
+4 -4
View File
@@ -1071,9 +1071,7 @@ pub fn srf_srf_intersection_with_context(
// analytic intersector gives exactly. Points off a surface, and an end where the surface
// touches the plane, are met by the intersectors below. A round of touch circles needs it
// (#2704): its end section leaves the end face's plane, so its side curve is this one.
if (k.fixes.fillet_surface_plane_curve_on_plane_equation || k.fixes.fillet_gn_section_generator)
&& curves_3d.is_empty()
{
if curves_3d.is_empty() {
let plane_first = matches!(surf1.kind(), SurfaceKind::Plane(_));
if let (Some(start_pnt), Some(end_pnt), true) = (
start,
@@ -1085,7 +1083,9 @@ pub fn srf_srf_intersection_with_context(
} else {
(surf1, surf2)
};
if !surface.is_planar(k, approx_tol)?.is_planar
// a curve between two points: ends that coincide are no such curve
if start_pnt.distance(end_pnt) > approx_tol
&& !surface.is_planar(k, approx_tol)?.is_planar
&& ends_on_both(k, [surf1, surf2], [start_pnt, end_pnt], approx_tol)?
{
let c = surface_plane_curve(
@@ -2,8 +2,7 @@
//! plane's equation.
//!
//! Upstream: the SolidCraft fork's `source/SMLib/src/SmFilletGeom.cpp`
//! (tangency-labs/smlib@5bdcddf, with @14a6daa's quarter points and start direction), under
//! WR-682's `fillet_surface_plane_curve_on_plane_equation`.
//! (tangency-labs/smlib@5bdcddf, with @14a6daa's quarter points and start direction; WR-682).
//!
//! | Rust | Upstream |
//! |-----------------------|------------------------|
@@ -15,7 +14,16 @@
//! net's bound is within the tenth of `tol` the curve is held to (#2510). An end goes onto
//! the crossing by the least 3D step, not `OntoPlane`'s least uv step, and the curve ends
//! there, not at the given point (#2907): a point within `tol` of both surfaces is what the
//! vertices are, and the curve is held to the crossing itself.
//! vertices are, and the curve is held to the crossing itself. Not the fork's: a station off
//! the surface's domain in a direction the surface is not closed in is the curve leaving the
//! surface, and the trace refuses it (`SM_ERR`), where the fork marches on along the
//! B-spline's extrapolation (the goldens' generated `blend.fillet_geom_p2` case `gen0014`
//! reached u = -6e5 on a surface of domain [0, 1]). Bounds: the march
//! and the refinement together hold at most [`MAX_STATIONS`] stations; a curve whose spans
//! still miss the exact curve when refining would pass it can't be fitted (`SM_ERR`), as when
//! its 20 passes run out. Each pass splits every span that misses, so without the bound a
//! curve that never fits doubles its stations each pass (the goldens' generated
//! `blend.fillet_geom_p2` case `gen0014` ran out of memory).
#![allow(clippy::neg_cmp_op_on_partial_ord)] // a NaN must take the failing branch, as upstream
@@ -26,6 +34,7 @@ use crate::kernel::Kernel;
use crate::math::{Point3, Vec3};
use crate::nurbs::b_spline_curve::p1::{BSplineCurveForm, CanonicalData, KnotType};
use crate::nurbs::b_spline_curve::BSplineCurve;
use crate::nurbs::b_spline_surface::SurfParamType;
use crate::nurbs::b_spline_surface_n_lib::p2::EvaluateFlags;
use crate::nurbs::knots::Side;
use crate::surface::procedural_blend::NetScope;
@@ -35,6 +44,9 @@ use crate::surface::surface::Surface;
const OP: &str = "blend::fillet_geom::surface_plane_curve::surface_plane_curve";
/// The most stations the trace holds, marched and refined.
const MAX_STATIONS: usize = 100_000;
/// The three curves of [`surface_plane_curve`].
#[derive(Debug)]
pub struct SurfacePlaneCurves {
@@ -221,8 +233,8 @@ fn hermite(dim: u64, control: &[Point3], mult: &[usize], knots: &[f64]) -> Resul
/// # Errors
///
/// `SM_ERR` for an end off the surface or the plane, a surface that touches the plane, a
/// curve that turns back before its end, a step that vanishes, or curves that can't be
/// fitted; those of the evaluations and the point drops.
/// curve that turns back before its end or leaves the surface's domain, a step that
/// vanishes, or curves that can't be fitted; those of the evaluations and the point drops.
#[allow(clippy::too_many_arguments, clippy::too_many_lines)] // one upstream routine
pub fn surface_plane_curve(
k: &Kernel,
@@ -289,6 +301,17 @@ pub fn surface_plane_curve(
}
let [start_uv, stop_uv] = end_uv;
let [start_x, stop_x] = end_x;
// the curve stays on the surface: within its domain, but across a seam it is closed over
let closed =
|param| -> Result<bool> { Ok(surf.is_closed(k, &dom, param, Some(tol), false)?.0) };
let (closed_u, closed_v) = (closed(SurfParamType::U)?, closed(SurfParamType::V)?);
let on_domain = |uv: Point2| {
let (lo, hi) = (dom.min(), dom.max());
let pad = |a: f64, b: f64| 1.0e-12 * (1.0 + a.abs() + b.abs());
let (pu, pv) = (pad(lo.x, hi.x), pad(lo.y, hi.y));
(closed_u || (uv.x >= lo.x - pu && uv.x <= hi.x + pu))
&& (closed_v || (uv.y >= lo.y - pv && uv.y <= hi.y + pv))
};
// the stations: from the start, along the level line, to the end
let (t0, r0) = tr.tangent(start_uv, start_dir.unwrap_or(end - start))?;
@@ -299,7 +322,7 @@ pub fn surface_plane_curve(
rate: r0,
}];
let mut h = 0.0625 * start.distance(end);
for _ in 0..100_000 {
for _ in 0..MAX_STATIONS {
let last = *st.last().ok_or_else(fail)?;
if last.x.distance(end) <= 1.5 * h {
// the last step: onto the end itself
@@ -333,6 +356,10 @@ pub fn surface_plane_curve(
turned = Some((tn, rn, tn.angle_between(last.t)?));
}
match turned {
Some(_) if !on_domain(next) => {
// the curve leaves the surface
return Err(fail());
}
Some((tn, rn, turn)) if turn <= ang_tol => {
let x = surf.evaluate_point(k, next)?;
st.push(Station {
@@ -439,6 +466,10 @@ pub fn surface_plane_curve(
});
}
// insert those middles as stations
if st.len() + off.len() > MAX_STATIONS {
// the curves could not be fitted within the tolerance
return Err(fail());
}
let mut refined = Vec::with_capacity(st.len() + off.len());
let mut pending = off.iter().peekable();
for (j, station) in st.iter().enumerate() {
@@ -16,9 +16,7 @@
//! Newton solve takes at most 40 steps.
use crate::blend::fillet_section::section::GnSectionFsg;
use crate::blend::fillet_solver::p1::{
FilletSolver, FilletSurfaceGenerator, FilletSurfaceGeneratorType,
};
use crate::blend::fillet_solver::p1::{FilletSolver, FilletSurfaceGeneratorType};
use crate::curve::curve::Curve;
use crate::error::{Result, SolidError};
use crate::geom::global_solver::SolverOperation;
@@ -47,7 +45,7 @@ fn smax(a: f64, b: f64) -> f64 {
/// `sm_SectionContactOrder`: the order of contact `k` of a fillet's cross-section with
/// the faces it meets: 1 for a chamfer's straight section, 2 for a round's circular
/// one, `n + 1` for a blend curve of Gn continuity. The section stands off its face as
/// one; a G^n section's is [`gn_section_contact_order`]'s. The section stands off its face as
/// `c s^k` at distance `s` from the contact line; where the face runs tangent into an
/// end face whose normal curvature across the seam differs by `dk`, the end rib leaves
/// the tangent end as `a ~ s^(k/2)` along the rail.
@@ -62,20 +60,16 @@ pub fn section_contact_order(solver: &FilletSolver) -> Result<u32> {
match fsg.fillet_surface_generator_type() {
FilletSurfaceGeneratorType::Linear => Ok(1),
FilletSurfaceGeneratorType::Circular => Ok(2),
// ((SmBlendCurveCrossSectionFSG*)pFSG)->GetContinuity() + 1
FilletSurfaceGeneratorType::BlendCurve => match fsg {
FilletSurfaceGenerator::BlendCurve(g) => g
.continuity
.checked_add(1)
.ok_or_else(|| SolidError::sm_err(OP_ORDER)),
_ => Err(SolidError::sm_err(OP_ORDER)),
},
FilletSurfaceGeneratorType::Unknown => Err(SolidError::sm_err(OP_ORDER)),
// ((SmBlendCurveCrossSectionFSG*)pFSG)->GetContinuity() + 1: that generator is
// retired (WR-685); a G^n section's order is [`gn_section_contact_order`]'s
FilletSurfaceGeneratorType::BlendCurve | FilletSurfaceGeneratorType::Unknown => {
Err(SolidError::sm_err(OP_ORDER))
}
}
}
/// The fork's `sm_SectionContactOrder` for a G^n section (`SM_FSG_BLEND_CURVE` with
/// `fixes.fillet_gn_section_generator`, WR-685; tangency-labs/smlib@11ea2d9): the order of
/// The fork's `sm_SectionContactOrder` for a G^n section (`SM_FSG_BLEND_CURVE`, WR-685;
/// tangency-labs/smlib@11ea2d9): the order of
/// contact k of the section with the face it meets at `at`, a point of one of its rails:
/// `n + 1`, or `n + 2` where its jets make the `t^(n+1)` term vanish (two planes), found at
/// that rail's station (`SmGnSectionFSG::ContactOrderAt`). The rail through `at` is the one
+13 -14
View File
@@ -303,19 +303,19 @@ pub trait FilletSolverOps {
/// # Errors
///
/// The solver's failure.
fn radius_corner_parameters(&mut self, _k: &Kernel) -> Result<Vec<f64>> {
fn radius_corner_parameters(&mut self) -> Result<Vec<f64>> {
Ok(Vec::new())
}
/// `IsAtRadiusCorner(crTsectPnt)` (virtual, the fork's 6eecf04): whether the point lies
/// where the radius has a corner. `false` by default.
fn is_at_radius_corner(&mut self, _k: &Kernel, _point: &TsectPnt) -> bool {
fn is_at_radius_corner(&mut self, _point: &TsectPnt) -> bool {
false
}
/// `GetRadiusParameter(crTsectPnt, rdParam)` (virtual, the fork's 6eecf04): the point's
/// edge parameter, `None` where the solver has no radius corners (the default).
fn radius_parameter(&mut self, _k: &Kernel, _point: &TsectPnt) -> Option<f64> {
fn radius_parameter(&mut self, _point: &TsectPnt) -> Option<f64> {
None
}
@@ -1281,16 +1281,16 @@ impl<'s, 't, O: SolutionObject + 't, G: Clone> FilletIntersector<'s, 't, O, G> {
) -> Result<()> {
let si = &self.base.base;
let (Some(from_param), Some(to_param)) = (
solver.radius_parameter(k, tsect),
solver.radius_parameter(k, next_tsp),
solver.radius_parameter(tsect),
solver.radius_parameter(next_tsp),
) else {
return Ok(());
};
let Ok(corners) = solver.radius_corner_parameters(k) else {
let Ok(corners) = solver.radius_corner_parameters() else {
return Ok(());
};
for &corner in &corners {
if solver.is_at_radius_corner(k, tsect)
if solver.is_at_radius_corner(tsect)
|| (corner - from_param) * (corner - to_param) >= 0.0
{
continue;
@@ -1317,7 +1317,7 @@ impl<'s, 't, O: SolutionObject + 't, G: Clone> FilletIntersector<'s, 't, O, G> {
&mut on_corner,
)?;
let param = if flags.found_answer {
solver.radius_parameter(k, &on_corner)
solver.radius_parameter(&on_corner)
} else {
None
};
@@ -1328,7 +1328,7 @@ impl<'s, 't, O: SolutionObject + 't, G: Clone> FilletIntersector<'s, 't, O, G> {
param0 = param1;
step1 = d_step;
param1 = param;
landed = solver.is_at_radius_corner(k, &on_corner);
landed = solver.is_at_radius_corner(&on_corner);
}
if landed {
*next_tsp = on_corner;
@@ -1379,11 +1379,10 @@ impl<'s, 't, O: SolutionObject + 't, G: Clone> FilletIntersector<'s, 't, O, G> {
// rescaled and every later use below sees the new value.
let mut step_size = step_size;
// SolidCraft (the fork's 6eecf04; a radius corner exists only under
// `fillet_gn_section_generator`): where the radius has a corner the curves turn. A
// SolidCraft (the fork's 6eecf04): where the radius has a corner the curves turn. A
// step from a point at a corner starts along the tangents after it
// (ComputePointValues averages the two sides).
if solver.is_at_radius_corner(k, tsect) {
if solver.is_at_radius_corner(tsect) {
let mut after = tsect.clone();
if one_sided_tangents(solver, k, &si.uv_domains, 1.0, &mut after)? {
take_tangents(tsect, &after);
@@ -1445,7 +1444,7 @@ impl<'s, 't, O: SolutionObject + 't, G: Clone> FilletIntersector<'s, 't, O, G> {
// SolidCraft (the fork's 6eecf04): a step that ends at a radius corner arrives
// along the tangents before it
if solver.is_at_radius_corner(k, next_tsp) {
if solver.is_at_radius_corner(next_tsp) {
let mut before = next_tsp.clone();
if one_sided_tangents(solver, k, &si.uv_domains, -1.0, &mut before)? {
take_tangents(next_tsp, &before);
@@ -1915,7 +1914,7 @@ impl<'s, 't, O: SolutionObject + 't, G: Clone> FilletIntersector<'s, 't, O, G> {
let count = pnts.len();
for (kk, slot) in pnts.iter_mut().enumerate() {
let mut point_in = None;
if kk > 0 && kk + 1 < count && solver.is_at_radius_corner(k, slot) {
if kk > 0 && kk + 1 < count && solver.is_at_radius_corner(slot) {
let mut point_out = slot.clone();
let mut before = slot.clone();
let b_in = one_sided_tangents(solver, k, &uv_domains, -1.0, &mut before)?;
-1
View File
@@ -4,7 +4,6 @@
//!
//! Upstream: `source/SMLib/src/SmFilletSolver.cpp`, `source/SMLib/inc/SmFilletSolver.h`.
pub mod ball_fit;
pub mod curve_blend_sih;
pub mod p1;
pub mod p2;
@@ -1,238 +0,0 @@
//! Whether a fillet solver's rolling ball fits the faces it rolls on.
//!
//! Upstream: not in SMLib at the pinned commit. SolidCraft's fork adds
//! `SmFilletSolver::BallFitsItsFaces` (`SmFilletSolver.cpp`) and its call before the
//! corners in `SmFilletExecutive::CreateFilletBrep`, with the error type
//! `FilletErrorType::NoRoom` (not an upstream code); the source is the diff
//! `2c5baae..e5696ca` quoted in
//! tangency-labs/solidcore#1172.
//!
//! | Rust | Upstream (fork) |
//! |----------------------|---------------------------------------|
//! | [`ball_fits_its_faces`] | `SmFilletSolver::BallFitsItsFaces` |
//!
//! Deviations: a solver without an edge use judges nothing (the fork's `NER` fails the
//! fillet with a null pointer); the fork's evaluation order `[1] = Dv, [2] = Du` is
//! Rust's `(P, Du, Dv)`, which gives the same determinant and trace.
use super::p1::FilletSolverOps;
use crate::blend::fillet_custom_solver::offset_evaluate_1st;
use crate::error::{Result, SolidError};
use crate::geom::vector2d::Point2;
use crate::intersect::surface_intersector::p1::{SrfIndex, TsectPnt};
use crate::kernel::Kernel;
use crate::math::{Vec3, EFF_ZERO};
use crate::surface::surface::p4::NoObject;
use crate::surface::surface::p5::DropPointOptions;
use crate::topology::edgeuse::p1 as eu;
use crate::topology::{edge, Brep};
const OP: &str = "blend::fillet_solver::ball_fit::ball_fits_its_faces";
/// A stretch this far below zero is still a fit (a ball as wide as the face's curve).
const FIT_TOL: f64 = 1.0e-6;
/// Sections judged along the filleted edge.
const NUM_SAMPLES: usize = 9;
/// `SmFilletSolver::BallFitsItsFaces`: `false` where, at one of nine sections along the
/// solver's edge, a face curves tighter than the rolling ball.
///
/// The ball touches a face where the face's offset surface (moved along the normal by
/// the ball's radius) passes through the ball's centre. Along a direction in which the
/// face curves toward the ball by `k` the offset is stretched by `1 - r k`; past the
/// face's centre of curvature that is negative, the ball cuts through the face and
/// the blend passes through itself. The stretches are the eigenvalues of `M = H G^-1`
/// (`G = [Bi.Bj]` of the base surface, `H = [Oi.Bj]` of the offset against it); both are
/// at least zero when `det M` and `trace M` are. A stretch of zero fits (a pin's
/// hemispherical end as wide as the round), by `FIT_TOL`. A section the solve does
/// not find, or a pole of a surface, judges nothing: the check refuses only what it can
/// solve for, so a refusal is never a false positive but a miss is possible. The nine
/// sections sit at `(j + 0.5) / 9` and never test the ends of the edge.
///
/// `brep` is the target holding the solver's edge use.
///
/// # Errors
///
/// Those of the drops, the section solves and the evaluations; `SM_ERR_NULL_POINTER`
/// for an edge without a curve.
pub fn ball_fits_its_faces(
ops: &mut dyn FilletSolverOps,
k: &Kernel,
brep: &mut Brep,
) -> Result<bool> {
let (Some(first), Some(second)) = (ops.solver().surface(0)?, ops.solver().surface(1)?) else {
return Ok(true);
};
let domains = [
first
.surface
.base_surface()
.natural_uv_domain_with_nurb(k)?,
second
.surface
.base_surface()
.natural_uv_domain_with_nurb(k)?,
];
let Some(edgeuse) = ops.solver().edgeuse(0)? else {
return Ok(true);
};
let Some(edge_id) = eu::edge(brep, edgeuse)? else {
return Err(SolidError::null_pointer(OP));
};
let interval = edge::interval(brep, edge_id)?;
let curve = edge::curve(brep, edge_id)?
.ok_or_else(|| SolidError::null_pointer(OP))?
.clone();
for j in 0..NUM_SAMPLES {
let t = interval.evaluate((j as f64 + 0.5) / NUM_SAMPLES as f64);
let pv = curve.evaluate(k, t, 1, true, false)?;
let (Some(&point), Some(&tangent)) = (pv.first(), pv.get(1)) else {
continue;
};
let moves = tangent.length() > EFF_ZERO;
if !moves {
continue;
}
let normal = tangent.unitize()?;
// the edge point on each face's surface: the section's guess
let mut guess: Vec<Point2> = Vec::with_capacity(2);
let mut dropped = true;
for (rail, domain) in domains.iter().enumerate() {
if !dropped {
break;
}
let Some(slot) = ops.solver().surface(rail)? else {
return Ok(true);
};
let drop = slot.surface.base_surface().drop_point::<NoObject>(
k,
point,
domain,
&DropPointOptions::default(),
)?;
dropped = drop.success;
guess.push(drop.result_uv);
}
if !dropped {
continue;
}
let [g0, g1] = *guess.as_slice() else {
continue;
};
// the section through it
let mut section = TsectPnt::new();
if !ops.point_on_plane_solve(
k,
Some(&mut *brep),
point,
normal,
&domains[0],
&domains[1],
g0,
g1,
&mut section,
)? {
continue;
}
let radii_change = ops.offset_radii_can_change()?;
if radii_change {
ops.setup_offset_values(&section, None)?;
}
// the derivatives of the offset (O) and base (B) surfaces there
let derivs = (|| -> Result<Vec<([Vec3; 2], [Vec3; 2])>> {
let mut derivs = Vec::with_capacity(2);
for (rail, srf) in [SrfIndex::First, SrfIndex::Second].into_iter().enumerate() {
let uv = section.uv_pos(srf);
let slot = ops
.solver_mut()
.surface_mut(rail)?
.ok_or_else(|| SolidError::null_pointer(OP))?;
let (_, ou, ov) = offset_evaluate_1st(k, &mut slot.surface, uv)?;
let (_, bu, bv) = slot
.surface
.base_surface()
.evaluate_1st_derivatives(k, uv, true, true)?;
derivs.push(([ou, ov], [bu, bv]));
}
Ok(derivs)
})();
// restored whether or not the evaluations failed
if radii_change {
ops.solver_mut().reload_surface_offsets()?;
}
let derivs = derivs?;
for ([o1, o2], [b1, b2]) in derivs {
if !stretches_fit(o1, o2, b1, b2) {
return Ok(false);
}
}
}
Ok(true)
}
/// Whether both stretches of the offset `(o1, o2)` against its base `(b1, b2)` are at
/// least zero, by [`FIT_TOL`]: `M = H G^-1`, `G = [Bi.Bj]`, `H = [Oi.Bj]`.
fn stretches_fit(o1: Vec3, o2: Vec3, b1: Vec3, b2: Vec3) -> bool {
let (g11, g12, g22) = (b1.dot(b1), b1.dot(b2), b2.dot(b2));
let det_g = g11 * g22 - g12 * g12;
// a pole (a parameter direction that does not move) has no stretch to judge
let moves = det_g > EFF_ZERO * g11 * g22;
if !moves {
return true;
}
let (h11, h12, h21, h22) = (o1.dot(b1), o1.dot(b2), o2.dot(b1), o2.dot(b2));
let det_m = (h11 * h22 - h12 * h21) / det_g;
let trace_m = (h11 * g22 - h12 * g12 - h21 * g12 + h22 * g11) / det_g;
!(det_m < -FIT_TOL || trace_m < -FIT_TOL)
}
#[cfg(test)]
mod tests {
use super::*;
fn v(x: f64, y: f64, z: f64) -> Vec3 {
Vec3::new(x, y, z)
}
/// A cylinder of radius 5 about z, at (5, 0, 0) with unit parameter speeds: its
/// inward offset by `r` stretches the angular direction by `1 - r/5`.
fn stretch_of_inward_offset(r: f64) -> bool {
let b1 = v(0.0, 5.0, 0.0);
let b2 = v(0.0, 0.0, 1.0);
let o1 = v(0.0, 5.0 - r, 0.0);
stretches_fit(o1, b2, b1, b2)
}
#[test]
fn a_ball_over_the_faces_radius_does_not_fit() {
assert!(stretch_of_inward_offset(2.0));
assert!(stretch_of_inward_offset(5.0), "a zero stretch fits");
assert!(!stretch_of_inward_offset(7.0));
}
/// An offset that stretches the two parameter directions of an orthonormal base by
/// `s1` and `s2`.
fn stretches(s1: f64, s2: f64) -> bool {
let (b1, b2) = (v(1.0, 0.0, 0.0), v(0.0, 1.0, 0.0));
stretches_fit(b1 * s1, b2 * s2, b1, b2)
}
#[test]
fn a_doubly_curved_face_is_judged_by_both_det_and_trace() {
// a sphere of radius 5 offset inward by 7 stretches both ways by -0.4: det is
// positive, only the trace refuses it
assert!(!stretches(-0.4, -0.4));
assert!(stretches(0.6, 0.6));
// a saddle-like offset (one direction past its centre): the trace is positive,
// only the determinant refuses it
assert!(!stretches(2.0, -0.5));
assert!(stretches(2.0, 0.5));
}
}
+40 -92
View File
@@ -31,7 +31,7 @@
//! | [`FilletSolver::TYPE`], [`FilletSolver::type_string`], [`FilletSolver::is_kind_of`] | `GetType`, `GetTypeString` (`SM_COMMON`), `IsKindOf` |
//! | [`FilletSolverOps`] (trait, base methods) | the virtuals `GetJacobianSize`, `SetupOffsetValues`, `CanMakeAnalytic`, `OffsetRadiiCanChange`, `LoadJacobian`, `LoadInitialValues`; `GetSolverType`, `PointOnPlaneSolve` and the `SmConstantDistanceFS::GetDistance` read of `SmFindClippedRadiusEFO` (added by `blend.fillet_solver_p3`) |
//! | [`FilStatus`] (re-export of `blend.fillet_geom_p1`'s), [`FilletSolverType`], [`FilletSurfaceGeneratorType`] | `SmFilStatus`, `SmFilletSolverType`, `SmFilletSurfaceGeneratorType` |
//! | [`FilletSurfaceGenerator`] | `SmFilletSurfaceGenerator`, `SmLinearCrossSectionFSG`, `SmCircularCrossSectionFSG`, `SmBlendCurveCrossSectionFSG` (constructors, `GetFilletSurfaceGeneratorType`, `GetBlendScale`, `GetContinuity`; `Drop` is each destructor); the circular and blend-curve variants hold `blend.fillet_standard_solver_p1`'s [`CircularCrossSectionFsg`] / [`BlendCurveCrossSectionFsg`] (one type per class) |
//! | [`FilletSurfaceGenerator`] | `SmFilletSurfaceGenerator`, `SmLinearCrossSectionFSG`, `SmCircularCrossSectionFSG` (constructors, `GetFilletSurfaceGeneratorType`, `GetContinuity`; `Drop` is each destructor); the circular variant holds `blend.fillet_standard_solver_p1`'s [`CircularCrossSectionFsg`]; a blend-curve request is the G^n section ([`GnSectionFsg`]; `SmBlendCurveCrossSectionFSG` is retired, WR-685) |
//! | [`FilletSurfaceGenerator::create_surface`] | `SmFilletSurfaceGenerator::CreateSurface` (base; the linear one dispatches to [`LinearCrossSectionFsg::create_surface`]) |
//! | [`FilletSphereSolveEnfo`] | `SmFilletSphereSolveENFO` (constructor, `SetPlaneAdjusts`, `Evaluate`) |
//! | [`RailUvCurveIntersectEnfo`] | `SmRailUVCurveIntersectENFO` (constructor, `Evaluate`) |
@@ -126,7 +126,7 @@ use crate::blend::fillet_geom::p3::SplitCorners;
use crate::blend::fillet_intersector::HandlingAlgorithmType;
use crate::blend::fillet_section::section::GnSectionFsg;
use crate::blend::fillet_standard_solver::p1::{
BlendCurveCrossSectionFsg, CircularCrossSectionFsg, LinearCrossSectionFsg, VariableRadiusFs,
CircularCrossSectionFsg, LinearCrossSectionFsg, VariableRadiusFs,
};
use crate::curve::curve::{Curve, CurveKind};
use crate::curve::iso_curve::IsoCurve;
@@ -242,12 +242,9 @@ pub enum FilletSurfaceGenerator {
Circular(CircularCrossSectionFsg),
/// `SmEiffelTowerCrossSectionFSG` (unit `blend.fillet_custom_solver`).
EiffelTower,
/// `SmBlendCurveCrossSectionFSG` (its members and `CreateSurfaceFromCurves`:
/// [`BlendCurveCrossSectionFsg`] of `blend.fillet_standard_solver_p1`).
BlendCurve(BlendCurveCrossSectionFsg),
/// The fork's `SmGnSectionFSG` (tangency-labs/smlib@11ea2d9; [`GnSectionFsg`]), of
/// type `SM_FSG_BLEND_CURVE`: built in place of the blend curve with
/// `fixes.fillet_gn_section_generator` (WR-685).
/// type `SM_FSG_BLEND_CURVE`: every blend-curve request is built by it.
/// `SmBlendCurveCrossSectionFSG` is retired with its flag (WR-685, #2273).
GnSection(GnSectionFsg),
}
@@ -276,42 +273,17 @@ impl FilletSurfaceGenerator {
Self::circular(true, 0.05, false, false)
}
/// `SmBlendCurveCrossSectionFSG(dBlendScale, lContinuity)`.
#[must_use]
pub const fn blend_curve(blend_scale: f64, continuity: u32) -> Self {
Self::blend_curve_at_thirds(blend_scale, continuity, false)
}
/// `SmBlendCurveCrossSectionFSG(dBlendScale, lContinuity, bAtThirds)` (the fork's,
/// tangency-labs/smlib `fd3b6a7`): with `at_thirds`, each section's inner control
/// points sit a third and two thirds of the way from each contact to where the
/// contacts' tangent lines meet.
#[must_use]
pub const fn blend_curve_at_thirds(blend_scale: f64, continuity: u32, at_thirds: bool) -> Self {
Self::BlendCurve(BlendCurveCrossSectionFsg {
continuity,
blend_scale,
at_thirds,
})
}
/// `SmBlendCurveCrossSectionFSG()` with its default arguments (`1.5, 1`).
#[must_use]
pub const fn blend_curve_default() -> Self {
Self::blend_curve(1.5, 1)
}
/// `MeetsItsFacesTangentially` (virtual; the fork's, tangency-labs/smlib `8bffb23`):
/// whether each cross section is tangent, at its ends on the rails, to the faces the
/// fillet rolls on. The linear section cuts across both faces, an arc about the ball's
/// centre is square to the faces at each rail unless mirrored about the rails' chord,
/// and a blend curve takes its end tangents from that arc; the base generator and any
/// and a G^n section takes its end tangents from that arc; the base generator and any
/// custom one are not known to.
#[must_use]
pub const fn meets_its_faces_tangentially(&self) -> bool {
match self {
Self::Circular(g) => !g.mirror,
Self::BlendCurve(_) | Self::GnSection(_) => true,
Self::GnSection(_) => true,
Self::Base | Self::Linear | Self::EiffelTower => false,
}
}
@@ -323,16 +295,7 @@ impl FilletSurfaceGenerator {
Self::Base | Self::EiffelTower => FilletSurfaceGeneratorType::Unknown,
Self::Linear => FilletSurfaceGeneratorType::Linear,
Self::Circular(_) => FilletSurfaceGeneratorType::Circular,
Self::BlendCurve(_) | Self::GnSection(_) => FilletSurfaceGeneratorType::BlendCurve,
}
}
/// `SmBlendCurveCrossSectionFSG::GetBlendScale` (`None` for the other kinds).
#[must_use]
pub const fn blend_scale(&self) -> Option<f64> {
match self {
Self::BlendCurve(g) => Some(g.blend_scale),
_ => None,
Self::GnSection(_) => FilletSurfaceGeneratorType::BlendCurve,
}
}
@@ -345,12 +308,10 @@ impl FilletSurfaceGenerator {
}
}
/// `SmBlendCurveCrossSectionFSG::GetContinuity`, `SmGnSectionFSG::GetOrder` (`None`
/// for the other kinds).
/// `SmGnSectionFSG::GetOrder` (`None` for the other kinds).
#[must_use]
pub const fn continuity(&self) -> Option<u32> {
match self {
Self::BlendCurve(g) => Some(g.continuity),
#[allow(clippy::cast_possible_truncation)]
Self::GnSection(g) => Some(g.order as u32),
_ => None,
@@ -368,9 +329,9 @@ impl FilletSurfaceGenerator {
/// `SM_ERR` for [`FilletSurfaceGenerator::Base`]; those of
/// `SmEiffelTowerCrossSectionFSG::CreateSurface`,
/// `SmLinearCrossSectionFSG::CreateSurface` ([`LinearCrossSectionFsg::create_surface`])
/// and the circular and blend-curve generators' `CreateSurface`;
/// and the circular and G^n generators' `CreateSurface`;
/// [`SolidError::InvalidInput`] for a missing centre line of the circular and
/// blend-curve generators (upstream dereferences `NULL`).
/// G^n generators (upstream dereferences `NULL`).
#[allow(clippy::too_many_arguments)]
pub fn create_surface(
&self,
@@ -401,16 +362,6 @@ impl FilletSurfaceGenerator {
rail1,
rail2,
),
Self::BlendCurve(g) => g.create_surface(
k,
approx_tol_3d,
solver_type,
center_line.ok_or_else(no_center)?,
rail1,
rail2,
side1,
side2,
),
Self::GnSection(g) => {
// the uv curves rebuilt on the stations are dropped: a caller that owns
// them uses `create_surface_replacing_uv` (which also keeps the equal area
@@ -452,7 +403,7 @@ impl FilletSurfaceGenerator {
/// has no such solver); with it and `fixes.fillet_round_as_definition` a constant
/// round between NURBS faces is its definition, the rails and uv curves rebuilt on its
/// stations ([`CircularCrossSectionFsg::definition_surface`], the fork's cc08236).
/// With it and `fixes.fillet_gn_section_generator`, a round whose centre line or a
/// With it, a round whose centre line or a
/// rail turns at a knot (a corner of its radius law) is skinned piece by piece between
/// the turns and the pieces joined there
/// ([`CircularCrossSectionFsg::piecewise_surface`], the fork's 6eecf04); for a ball
@@ -473,6 +424,9 @@ impl FilletSurfaceGenerator {
ball: Option<&crate::blend::fillet_standard_solver::p2::CircleBall>,
) -> Result<(Surface, Option<crate::blend::law_corners::LawCornerPieces>)> {
use crate::blend::fillet_standard_solver::p1::RailSurface;
use crate::blend::fillet_standard_solver::touch_circle::{
corner_angle, fillet_curve_corners,
};
if let Self::GnSection(g) = self {
let center =
center_line.ok_or_else(|| SolidError::invalid_input(OP, "NULL centre line"))?;
@@ -500,33 +454,27 @@ impl FilletSurfaceGenerator {
}
// the fork's `SmGnSectionFSG::CircleSurface` (6eecf04, 5fbffc9): where the
// centre line or a rail turns, the round skinned piece by piece and joined
if k.fixes.fillet_gn_section_generator {
use crate::blend::fillet_standard_solver::touch_circle::{
corner_angle, fillet_curve_corners,
let corners =
fillet_curve_corners(center, rail1, rail2, corner_angle(ball.ang_tol_rad))?;
if !corners.is_empty() {
// (each piece by its definition where it is one, #430)
let definition = crate::blend::fillet_standard_solver::p2::PieceDefinitionInputs {
points,
surfaces,
uv: [&mut *uv1, &mut *uv2],
ball,
};
let corners =
fillet_curve_corners(center, rail1, rail2, corner_angle(ball.ang_tol_rad))?;
if !corners.is_empty() {
// (each piece by its definition where it is one, #430)
let definition =
crate::blend::fillet_standard_solver::p2::PieceDefinitionInputs {
points,
surfaces,
uv: [&mut *uv1, &mut *uv2],
ball,
};
let (s, kept) = g.piecewise_surface(
k,
approx_tol_3d,
solver_type,
center,
rail1,
rail2,
&corners,
Some(definition),
)?;
return Ok((Surface::from(s), kept));
}
let (s, kept) = g.piecewise_surface(
k,
approx_tol_3d,
solver_type,
center,
rail1,
rail2,
&corners,
Some(definition),
)?;
return Ok((Surface::from(s), kept));
}
}
// (a chamfer between NURBS faces is its definition, the chord: #2486)
@@ -2237,26 +2185,26 @@ pub trait FilletSolverOps: AsFilletSolverOps {
/// # Errors
///
/// Those of the variable radius solver's law.
fn radius_corner_parameters(&mut self, k: &Kernel) -> Result<Vec<f64>> {
fn radius_corner_parameters(&mut self) -> Result<Vec<f64>> {
match self.variable_radius_mut() {
// (the inherent methods: a method call on `vr` would resolve to this trait's)
Some(vr) => VariableRadiusFs::radius_corner_parameters(vr, k),
Some(vr) => VariableRadiusFs::radius_corner_parameters(vr),
None => Ok(Vec::new()),
}
}
/// `IsAtRadiusCorner` (virtual, the fork's 6eecf04): whether `point` lies where the
/// radius has a corner. `false` for the base.
fn is_at_radius_corner(&mut self, k: &Kernel, point: &TsectPnt) -> bool {
fn is_at_radius_corner(&mut self, point: &TsectPnt) -> bool {
self.variable_radius_mut()
.is_some_and(|vr| VariableRadiusFs::is_at_radius_corner(vr, k, point))
.is_some_and(|vr| VariableRadiusFs::is_at_radius_corner(vr, point))
}
/// `GetRadiusParameter` (virtual, the fork's 6eecf04): the edge parameter of `point`,
/// `None` where the solver has no radius corners (and for the base).
fn radius_parameter(&mut self, k: &Kernel, point: &TsectPnt) -> Option<f64> {
fn radius_parameter(&mut self, point: &TsectPnt) -> Option<f64> {
self.variable_radius_mut()
.and_then(|vr| VariableRadiusFs::radius_parameter(vr, k, point))
.and_then(|vr| VariableRadiusFs::radius_parameter(vr, point))
}
/// `((SmConstantDistanceFS*)this)->GetDistance()`: the rail distance of a
+3 -109
View File
@@ -62,11 +62,6 @@
//! - **Iteration.** `sm_FindRolloverSideEdge`'s `while (TRUE)` advances its interval
//! index on every pass that does not return, so it runs at most `pCC.len()` times;
//! there is no recursion.
//! - **Revolved blend curves (WR-581, #919).** With
//! `fixes.fillet_blend_curve_revolved_on_arc`, `CalcTorusFilletGeom` also takes a
//! blend-curve section whose centre line is a point on the arc's axis and revolves the
//! blend curve of `CreateSurfaceFromCurves` (shared:
//! `BlendCurveCrossSectionFsg::cross_section_through`) at the start point.
//! - **Side edge run on (WR-610, #960).** With `fixes.fillet_trace_reaches_rails`,
//! `RailEdgeuseIntersect` widens a straight side edge's parameter interval on a planar
//! base surface past both ends (`run_side_edge_on_along_its_line`, the fork's
@@ -109,7 +104,6 @@ use crate::blend::fillet_solver::p1::{
FilletSolver, FilletSolverOps, FilletSphereSolveEnfo, FilletSurfaceGenerator,
FilletSurfaceGeneratorType, RailRailIntersectEnfo, RailUvCurveIntersectEnfo,
};
use crate::blend::fillet_standard_solver::p1::SectionUv;
use crate::curve::curve::p1::GlobalPointSolveOptions;
use crate::curve::curve::Curve;
use crate::curve::line::Line;
@@ -383,84 +377,6 @@ fn fsg_type(s: &FilletSolver) -> Result<FilletSurfaceGeneratorType> {
.ok_or_else(|| invalid("no fillet surface generator"))
}
/// Not upstream (WR-581): whether every centre-line point lies on the axis of `frame`, to
/// `dAnalyticTol` scaled by one plus the arc's radius `arc_radius`. Each point is the
/// first offset surface's point at the fillet point's first UV position
/// (`GetSurface(0)->EvaluatePoint`, as the section's centre `sArcCenter` is taken), an
/// evaluation that keeps no extension, so a blend that is refused here leaves the solver
/// as it was; a point that does not evaluate is not on the axis.
///
/// # Errors
///
/// `SM_ERR_INVALID_INPUT` from `Unitize` of a zero axis; [`SolidError::InvalidInput`]
/// without the offset surface; [`SolidError::Unported`] from the evaluation.
fn centre_line_on_axis(
k: &Kernel,
s: &FilletSolver,
frame: &Axis2Placement,
arc_radius: f64,
tsects: &[TsectPnt],
) -> Result<bool> {
let axis = frame.z_axis().unitize()?;
let origin = frame.origin();
let tol = ANALYTIC_TOL * (1.0 + arc_radius);
let slot = s.surface(0)?.ok_or_else(|| invalid("no offset surface"))?;
for t in tsects {
let centre = match slot
.surface
.surface
.evaluate_point(k, t.uv_pos(SrfIndex::First))
{
Ok(p) => p,
Err(e @ (SolidError::Unported { .. } | SolidError::Cancelled { .. })) => return Err(e),
Err(_) => return Ok(false),
};
let off = centre - origin;
if (off - axis * off.dot(axis)).length() >= tol {
return Ok(false);
}
}
Ok(true)
}
/// Not upstream (WR-581): the blend curve cross section of the solver's
/// `SmBlendCurveCrossSectionFSG` about `centre` through the rail points `rails`, whose UV
/// positions on the offset surfaces `GetSurface(0)`, `GetSurface(1)` are `uvs`
/// (`BlendCurveCrossSectionFsg::cross_section_through`, as `CreateSurfaceFromCurves`
/// builds each section of a marched blend).
///
/// # Errors
///
/// [`SolidError::InvalidInput`] for a solver without a blend-curve generator or an
/// offset surface; those of the section.
fn blend_curve_section(
k: &Kernel,
s: &FilletSolver,
centre: Point3,
rails: [Point3; 2],
uvs: [Point2; 2],
) -> Result<BSplineCurve> {
let Some(FilletSurfaceGenerator::BlendCurve(fsg)) = s.fsg.as_ref() else {
return Err(invalid("no blend-curve surface generator"));
};
let offset = |rail: usize| -> Result<Surface> {
let slot = s
.surface(rail)?
.ok_or_else(|| invalid("no offset surface"))?;
Ok(Surface::from(slot.surface.surface.clone()))
};
let (sur0, sur1) = (offset(0)?, offset(1)?);
let [uv0, uv1] = uvs;
fsg.cross_section_through(
k,
centre,
rails,
s.approx_tol_3d,
[Some(&sur0), Some(&sur1)],
SectionUv::Points(uv0, uv1),
)
}
/// `sm_TurnIntoHalfPlane` (fork addition): turns `point` about the axis (through `origin`,
/// unit direction `axis`) into the half-plane, bounded by the axis, through `target`. A
/// point on the axis, or a target on it (within `tol`), stays.
@@ -1343,15 +1259,6 @@ impl FilletSolver {
let section = fsg_type(s)?;
let linear_section =
k.fixes.fillet_chamfer_cone_on_arc && section == FilletSurfaceGeneratorType::Linear;
// Not upstream (WR-581, #919), opt-in `fixes.fillet_blend_curve_revolved_on_arc`: a
// blend-curve section whose centre line is a point on the arc's axis (a blend as
// wide as the face it uses up, whose marched centre line has no length to march)
// is revolved too; any other blend-curve section is still refused here
// (the G^n section of WR-685 has no section to revolve: it is marched)
let blend_section = class.is_none()
&& k.fixes.fillet_blend_curve_revolved_on_arc
&& section == FilletSurfaceGeneratorType::BlendCurve
&& !matches!(s.fsg.as_ref(), Some(FilletSurfaceGenerator::GnSection(_)));
let (ref_frame, start_ang) = if let Some(class) = class {
// WR-669: the circular or linear cross-section turned about the faces' common
// axis (the class's); the frame's origin: the centre of the edge's circle, where
@@ -1370,18 +1277,14 @@ impl FilletSolver {
frame.set_canonical(centre, x, z.cross(x))?;
(frame, 0.0)
} else {
if section != FilletSurfaceGeneratorType::Circular && !linear_section && !blend_section
{
if section != FilletSurfaceGeneratorType::Circular && !linear_section {
return Err(sm_err());
}
let Some((ref_frame, arc_radius, start_ang, _end_ang)) =
let Some((ref_frame, _arc_radius, start_ang, _end_ang)) =
curve.is_arc(k, 11, ANALYTIC_TOL)?
else {
return Err(sm_err());
};
if blend_section && !centre_line_on_axis(k, s, &ref_frame, arc_radius, tsects)? {
return Err(sm_err());
}
(ref_frame, start_ang)
};
@@ -1455,18 +1358,9 @@ impl FilletSolver {
}
// allocate the arc from the points [centerPoint, sP0, sP1] (a linear section: the
// line from rail to rail; WR-581's blend-curve section: the blend curve the
// marched surface has at each of its sections, here at the start point)
// line from rail to rail)
let mut arc = if linear_section {
BSplineCurve::create_line_segment(3, p0, p1)?
} else if blend_section {
blend_curve_section(
k,
ops.solver(),
arc_center,
[p0, p1],
[start_uv0, start_uv1],
)?
} else {
BSplineCurve::create_arc_from_points(arc_center, p0, p1, NurbCircleParam::Quadratic)?
};
+11 -13
View File
@@ -791,10 +791,10 @@ fn c1_collect_points(
// Now, compute 'through points' from all internal G1 knots
// (the size is re-read every iteration, as upstream's GetSize())
// SolidCraft (the fork's 6eecf04, under `fillet_gn_section_generator`): the corners of
// SolidCraft (the fork's 6eecf04): the corners of
// the radius law are through points too, after the G1 knots, so the trace has a point
// where the fillet turns (a failed one fails the trace, as a G1 knot's does).
let corner_knots = ops.radius_corner_parameters(cx.k)?;
let corner_knots = ops.radius_corner_parameters()?;
let mut k = 0;
while k < ops.solver().g1_knots.len() + corner_knots.len() {
// get position and tangent at G1 knot (status checked, values unused)
@@ -4671,18 +4671,18 @@ impl crate::blend::fillet_intersector::FilletSolverOps for IntersectorSolver<'_>
}
/// The solver's virtual `GetRadiusCornerParameters` (the fork's 6eecf04).
fn radius_corner_parameters(&mut self, k: &Kernel) -> Result<Vec<f64>> {
self.ops.radius_corner_parameters(k)
fn radius_corner_parameters(&mut self) -> Result<Vec<f64>> {
self.ops.radius_corner_parameters()
}
/// The solver's virtual `IsAtRadiusCorner` (the fork's 6eecf04).
fn is_at_radius_corner(&mut self, k: &Kernel, point: &TsectPnt) -> bool {
self.ops.is_at_radius_corner(k, point)
fn is_at_radius_corner(&mut self, point: &TsectPnt) -> bool {
self.ops.is_at_radius_corner(point)
}
/// The solver's virtual `GetRadiusParameter` (the fork's 6eecf04).
fn radius_parameter(&mut self, k: &Kernel, point: &TsectPnt) -> Option<f64> {
self.ops.radius_parameter(k, point)
fn radius_parameter(&mut self, point: &TsectPnt) -> Option<f64> {
self.ops.radius_parameter(point)
}
/// `GetSurface(rail)->Evaluate1stDerivatives(uv, TRUE, TRUE, ..)` on the solver's
@@ -4791,8 +4791,7 @@ impl crate::blend::fillet_intersector::FilletSolverOps for IntersectorSolver<'_>
let radii = self.ops.constant_radii();
// (a variable round between NURBS faces is its definition too, the fork's 0d43b4c;
// read only where the circle generator may take it)
let law = if k.fixes.fillet_gn_section_generator
&& k.fixes.fillet_round_as_definition
let law = if k.fixes.fillet_round_as_definition
&& solver_type == crate::blend::fillet_solver::p1::FilletSolverType::VariableRadius
{
let has_edgeuse = matches!(self.ops.solver().edgeuse(0), Ok(Some(_)));
@@ -4824,9 +4823,8 @@ impl crate::blend::fillet_intersector::FilletSolverOps for IntersectorSolver<'_>
.fillet_surface_generator_mut()
.ok_or_else(|| SolidError::null_pointer(OP))?;
// The fork's `SmGnSectionFSG::CircleSurface` folded-balls check (`sm_BallsFold`,
// WR-685, d01d7b0's 2714d37) is gone since tangency-labs/smlib#79's 410dfe1: with
// `fixes.fillet_gn_section_generator` a round whose balls fold is refused before the
// corners by `BallIsRegular` (`blend::fillet_executive::session::ball_regular`).
// WR-685, d01d7b0's 2714d37) is gone since tangency-labs/smlib#79's 410dfe1: a round
// whose balls fold is refused before the corners by `BallIsRegular` (`blend::fillet_executive::session::ball_regular`).
// (a constant round between NURBS faces is its definition, the fork's cc08236)
let ball = crate::blend::fillet_standard_solver::p2::CircleBall {
radii,
+3 -1
View File
@@ -44,7 +44,9 @@ mod end_sections_fit;
#[path = "p5/rails_fit.rs"]
mod rails_fit;
pub use rails_fit::{inside_material, is_concave_edge, is_knife_edge, RailsFit};
pub use rails_fit::{
edge_bounds_material, inside_material, is_concave_edge, is_knife_edge, RailsFit,
};
const OP: &str = "blend::fillet_solver::p5";
@@ -110,6 +110,24 @@ pub fn is_knife_edge(
/// `SM_ERR` for an edge with no loop edge use on the material side; those of the
/// sector test.
pub fn is_concave_edge(k: &Kernel, target: &mut Brep, edge_id: EdgeId) -> Result<bool> {
match material_use(target, edge_id)? {
Some(use_) => eu2::is_convex_radial_sector(k, target, use_, 10, false, 0.0),
None => Err(SolidError::sm_err(OP)),
}
}
/// Whether the edge bounds material: a use of it in a loop of a shell of a region that is
/// not a void (where [`is_concave_edge`] judges it). A sheet's edges bound none.
///
/// # Errors
///
/// Those of the topology queries.
pub fn edge_bounds_material(target: &Brep, edge_id: EdgeId) -> Result<bool> {
Ok(material_use(target, edge_id)?.is_some())
}
/// The first use of the edge in a loop of a shell of a region that is not a void.
fn material_use(target: &Brep, edge_id: EdgeId) -> Result<Option<crate::topology::EdgeuseId>> {
for use_ in edge::edgeuses(target, edge_id, None, None)? {
if !eu::is_loop_edgeuse(target, use_)? {
continue;
@@ -124,9 +142,9 @@ pub fn is_concave_edge(k: &Kernel, target: &mut Brep, edge_id: EdgeId) -> Result
if target.region(region)?.is_void() != 0 {
continue;
}
return eu2::is_convex_radial_sector(k, target, use_, 10, false, 0.0);
return Ok(Some(use_));
}
Err(SolidError::sm_err(OP))
Ok(None)
}
/// `sm_InsideMaterial` (fork, WR-631): whether a rail that leaves `face` near `point`
@@ -46,7 +46,6 @@
//! | [`VariableRadiusFs::type_code`], [`VariableRadiusFs::type_string`] | `SmVariableRadiusFS::GetType`, `GetTypeString` |
//! | [`LinearCrossSectionFsg::create_surface`] | `SmLinearCrossSectionFSG::CreateSurface` |
//! | [`CircularCrossSectionFsg`], [`CircularCrossSectionFsg::create_surface_from_curves`] | `SmCircularCrossSectionFSG`, `CreateSurfaceFromCurves` |
//! | [`BlendCurveCrossSectionFsg`], [`BlendCurveCrossSectionFsg::create_surface_from_curves`] | `SmBlendCurveCrossSectionFSG`, `CreateSurfaceFromCurves` |
//! | [`GuessSphereSolve::new`] | `SmGuessSphereSolveENFO::SmGuessSphereSolveENFO` (file-local class) |
//! | [`FilletSolver`] (re-exported from `blend.fillet_solver_p1`) | the `SmFilletSolver` base of the solvers (`FilletSolver::is_kind_of` is `SmFilletSolver::IsKindOf`) |
//! | [`FilletSolverType`], [`FilletSurfaceGeneratorType`] (re-exported from `blend.fillet_solver_p1`), [`BoundaryTrimmingType`] (re-exported from `blend.fillet_geom_p1`) | `SmFilletSolverType`, `SmFilletSurfaceGeneratorType`, `SmBoundaryTrimmingType` |
@@ -64,12 +63,6 @@
//! tangency-labs/smlib `b7ec55b`, not in SMLib at the pin) the edge-use constructors
//! orient their offsets by `sector_sides` (`sm_SectorSides`), which also sides a
//! cusp's faces; off, they keep upstream's tangency refusal.
//! - **Sections at thirds.** [`BlendCurveCrossSectionFsg::at_thirds`] is the fork's
//! `m_bAtThirds` (tangency-labs/smlib `fd3b6a7`, not in SMLib at the pin; off unless
//! the executive's `SetBlendCurveAtThirds` is set, so the default is the pinned C++).
//! - **Shared section.** The body of `CreateSurfaceFromCurves`' section loop is
//! `BlendCurveCrossSectionFsg::cross_section_through`, which (not upstream, WR-581)
//! `blend::fillet_solver::p2`'s revolved blend-curve section also builds from.
//! - **Object model.** `SmConstantRadiusFS` is the co-ported [`ConstantRadiusAssistedFs`]
//! of `blend.fillet_custom_solver` (the members of `SmFilletSolver`,
//! `SmConstantRadiusFS` and `SmConstantRadiusAssistedFS` are the same), aliased as
@@ -116,12 +109,10 @@
//! `Evaluate` / `GetNaturalInterval` dispatch on its kind as upstream's virtual calls
//! on `rCenterLine` do (an `SmLine` centre line, `SmOffsetGeometryCreation.cpp:2717-2751`,
//! answers degree 1 and `SmLine::IsLine` even after `MakeCurvesCompatible` raised its
//! NURB to degree 3); the knot synchronisation edits its NURB part. The blend
//! generator still takes the centre line's B-spline data (no caller passes an
//! analytic one).
//! `BlendCurveCrossSectionFsg::continuity` is `u32` where `m_lContinuity` is `ULONG`
//! (64 bits in the reference build); the FFI guard bounds it to 32 bits, so no compared
//! value differs.
//! NURB to degree 3); the knot synchronisation edits its NURB part.
//! - **No blend curve.** `SmBlendCurveCrossSectionFSG` is not ported any more: every
//! blend-curve request is the G^n section (`blend::fillet_section`), and the old
//! generator was retired with `fillet_gn_section_generator` (WR-685, #2273).
//! - **Indexing.** `rF`, the Jacobian, `crX`, `rGuessT`, `rIntervals` and the cross
//! section array of `CreateSurfaceFromCurves` are indexed with checks: an index
//! upstream would read or write out of bounds is [`SolidError::InvalidInput`]
@@ -143,7 +134,6 @@ use crate::blend::fillet_solver::p1::{
ExtensionCorners, FilletSolverOps, FilletSphereSolveEnfo, FilletSurfaceGenerator,
};
use crate::curve::curve::p1::GlobalPointSolveOptions;
use crate::curve::curve::p4::is_closed_base;
use crate::curve::curve::p5::is_arc_base;
use crate::curve::curve::{Curve, CurveKind};
use crate::error::{ignore_status, ignored, Result, SolidError};
@@ -167,7 +157,6 @@ use crate::surface::offset_surface::SS_UNKNOWN;
use crate::surface::surface::p1::zone_tol_3d;
use crate::surface::surface::p3::{out_of_bounds_enabled, set_out_of_bounds_enabled};
use crate::surface::surface::p5::{SS_UMAX, SS_UMIN};
use crate::surface::surface::p7::{compute_higher_order_derivs, drop_vectors_at};
use crate::surface::surface::{Surface, SurfaceKind};
use crate::topology::edgeuse::p1 as edgeuse;
use crate::topology::edgeuse::p3 as edgeuse_p3;
@@ -183,8 +172,6 @@ const OP_CD_INIT: &str =
const OP_BASE: &str = "blend::fillet_standard_solver::p1::CurveBasedFs::evaluate_base_curve";
const OP_CIRC: &str =
"blend::fillet_standard_solver::p1::CircularCrossSectionFsg::create_surface_from_curves";
const OP_BLEND: &str =
"blend::fillet_standard_solver::p1::BlendCurveCrossSectionFsg::create_surface_from_curves";
const OP_VR: &str = "blend::fillet_standard_solver::p1::VariableRadiusFs";
/// `dAnalyticTol` of the surface generators and `SetExtensionFlags`.
@@ -2084,17 +2071,12 @@ impl VariableRadiusFs {
/// `GetRadiusCornerParameters` (the fork's 6eecf04, not upstream): the edge parameters
/// where the radius law has a corner, ascending ([`FilletLaw::corner_parameters`] over
/// the law's interval and orientation). Under `fixes.fillet_gn_section_generator` (the
/// law corners of WR-685); none without it, so that the trace, its flush and the
/// executive see no corner and are as before.
/// the law's interval and orientation): the law corners of WR-685.
///
/// # Errors
///
/// Those of [`FilletLaw::corner_parameters`].
pub fn radius_corner_parameters(&self, k: &Kernel) -> Result<Vec<f64>> {
if !k.fixes.fillet_gn_section_generator {
return Ok(Vec::new());
}
pub fn radius_corner_parameters(&self) -> Result<Vec<f64>> {
self.law
.corner_parameters(&self.law_interval, self.law_orientation)
}
@@ -2104,8 +2086,8 @@ impl VariableRadiusFs {
/// [`Self::radius_corner_parameters`], within `1e-9` of the law interval's size;
/// `false` where those fail.
#[must_use]
pub fn is_at_radius_corner(&self, k: &Kernel, point: &TsectPnt) -> bool {
let Ok(corners) = self.radius_corner_parameters(k) else {
pub fn is_at_radius_corner(&self, point: &TsectPnt) -> bool {
let Ok(corners) = self.radius_corner_parameters() else {
return false;
};
let tol = 1.0e-9 * (1.0 + self.law_interval.min().abs() + self.law_interval.max().abs());
@@ -2117,8 +2099,8 @@ impl VariableRadiusFs {
/// parameter, `m_adUserDoubles[0]`) where the law has corners; `None` where it has none
/// or they fail.
#[must_use]
pub fn radius_parameter(&self, k: &Kernel, point: &TsectPnt) -> Option<f64> {
match self.radius_corner_parameters(k) {
pub fn radius_parameter(&self, point: &TsectPnt) -> Option<f64> {
match self.radius_corner_parameters() {
Ok(corners) if !corners.is_empty() => {
Some(point.user_doubles.first().copied().unwrap_or(f64::NAN))
}
@@ -2883,9 +2865,9 @@ impl CircularCrossSectionFsg {
/// [`CircularCrossSectionFsg::create_surface_from_curves`] as the fork's
/// `SmGnSectionFSG::CircleSurfaceFromCurves` (tangency-labs/smlib d2a6125, f2ec002,
/// e9560e3; `fixes.fillet_gn_section_generator`, WR-685): `ball_radius_varies`, the
/// solver's ball changes its radius along the centre line (a radius law, or a constant
/// chord between faces whose angle changes). With the flag each section is the circle
/// e9560e3; WR-685): `ball_radius_varies`, the solver's ball changes its radius along
/// the centre line (a radius law, or a constant chord between faces whose angle
/// changes). Each section is the circle
/// along which the balls' envelope touches the ball, square to the centre line: where
/// the ball's radius varies, its centre is the ball's centre moved along the centre
/// line by `-r r'/|c'|` (the envelope's condition `<p - c, c'> = -r r'` on the ball
@@ -3193,41 +3175,32 @@ impl CircularCrossSectionFsg {
.first()
.copied()
.ok_or_else(|| SolidError::sm_err(OP))?;
let (p1, p2, v1, v2) = if k.fixes.fillet_gn_section_generator {
// the fork's `CircleSurfaceFromCurves` (WR-685): the rails' points and
// tangents, and the section the circle along which the balls' envelope
// touches the ball, square to the centre line
let tangent = |pv: &[Vec3]| match *pv {
[p, d, ..] => Ok((p, d)),
_ => Err(SolidError::sm_err(OP)),
};
let (_, cent_d) = tangent(&cent_pv)?;
let (p1, d1) = tangent(&rail1.evaluate(t, 1, true, false)?)?;
let (p2, d2) = tangent(&rail2.evaluate(t, 1, true, false)?)?;
let mut v1 = p1 - cent;
let mut v2 = p2 - cent;
let speed = cent_d.length();
if ball_radius_varies
&& speed > EFF_ZERO
&& v1.length() > EFF_ZERO
&& v2.length() > EFF_ZERO
{
let r1 = v1.length();
let r2 = v2.length();
let rate = 0.5 * (v1.dot(d1 - cent_d) / r1 + v2.dot(d2 - cent_d) / r2);
let along = cent_d / speed;
cent += along * (-0.5 * (r1 + r2) * rate / speed);
v1 = p1 - cent;
v2 = p2 - cent;
}
(p1, p2, v1, v2)
} else {
let p1 = rail1.evaluate_point(t)?;
let p2 = rail2.evaluate_point(t)?;
// get sample Point gaps
(p1, p2, p1 - cent, p2 - cent)
// the fork's `CircleSurfaceFromCurves` (WR-685): the rails' points and tangents,
// and the section the circle along which the balls' envelope touches the ball,
// square to the centre line
let tangent = |pv: &[Vec3]| match *pv {
[p, d, ..] => Ok((p, d)),
_ => Err(SolidError::sm_err(OP)),
};
let (_, cent_d) = tangent(&cent_pv)?;
let (p1, d1) = tangent(&rail1.evaluate(t, 1, true, false)?)?;
let (p2, d2) = tangent(&rail2.evaluate(t, 1, true, false)?)?;
let mut v1 = p1 - cent;
let mut v2 = p2 - cent;
let speed = cent_d.length();
if ball_radius_varies
&& speed > EFF_ZERO
&& v1.length() > EFF_ZERO
&& v2.length() > EFF_ZERO
{
let r1 = v1.length();
let r2 = v2.length();
let rate = 0.5 * (v1.dot(d1 - cent_d) / r1 + v2.dot(d2 - cent_d) / r2);
let along = cent_d / speed;
cent += along * (-0.5 * (r1 + r2) * rate / speed);
v1 = p1 - cent;
v2 = p2 - cent;
}
// when railCurve samplePoints are close together - make a degenerate cross section curve
if p1.distance(p2) < approx_tol_3d {
@@ -3467,53 +3440,8 @@ impl CircularCrossSectionFsg {
}
}
/// The fillet surface generator with a blend curve cross section
/// (`SmBlendCurveCrossSectionFSG`): `G1`, `G2` or `G3` blend curves between the rails.
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct BlendCurveCrossSectionFsg {
/// `m_lContinuity`: 1, 2 or 3 for `G1`, `G2` or `G3`.
pub continuity: u32,
/// `m_dBlendScale`: the scale of the end derivatives.
pub blend_scale: f64,
/// `m_bAtThirds` (the fork's, tangency-labs/smlib `fd3b6a7`): the sections' inner
/// control points sit a third and two thirds of the way from each contact to
/// where the contacts' tangent lines meet, instead of the faired Hermite scaled
/// by the blend scale.
pub at_thirds: bool,
}
impl Default for BlendCurveCrossSectionFsg {
/// `SmBlendCurveCrossSectionFSG()`: blend scale `1.5`, `G1`, not at thirds.
fn default() -> Self {
Self {
continuity: 1,
blend_scale: 1.5,
at_thirds: false,
}
}
}
/// Where a blend curve cross section reads its rail points' UV positions
/// ([`BlendCurveCrossSectionFsg::cross_section_through`]).
#[derive(Debug, Clone, Copy)]
pub(crate) enum SectionUv<'a> {
/// No UV curves (`pUV1` or `pUV2` `NULL`): no higher-order derivatives.
None,
/// The UV curves `pUV1`, `pUV2` at `t` (`CreateSurfaceFromCurves`).
Curves {
/// The rails' parameter.
t: f64,
/// The first rail's UV curve.
uv1: &'a BSplineCurve,
/// The second rail's UV curve.
uv2: &'a BSplineCurve,
},
/// The rail points' UV positions themselves (not upstream, WR-581).
Points(Point2, Point2),
}
/// A surface and its UV curve along a rail (`pSurf1`, `pUV1` of
/// `SmBlendCurveCrossSectionFSG::CreateSurfaceFromCurves`).
/// A surface and its UV curve along a rail (`pSurf1`, `pUV1` of a generator's
/// `CreateSurface`).
#[derive(Debug, Clone, Copy)]
pub struct RailSurface<'a> {
/// The surface the rail lies on.
@@ -3522,471 +3450,6 @@ pub struct RailSurface<'a> {
pub uv_curve: Option<&'a BSplineCurve>,
}
impl BlendCurveCrossSectionFsg {
/// `GetFilletSurfaceGeneratorType`.
#[must_use]
pub const fn generator_type(&self) -> FilletSurfaceGeneratorType {
FilletSurfaceGeneratorType::BlendCurve
}
/// `GetBlendScale`.
#[must_use]
pub const fn blend_scale(&self) -> f64 {
self.blend_scale
}
/// `GetContinuity`.
#[must_use]
pub const fn continuity(&self) -> u32 {
self.continuity
}
/// `SmBlendCurveCrossSectionFSG::CreateSurfaceFromCurves`: a blend curve from
/// `rail1` to `rail2` at every unique knot of `rail1` (the rails first get knots
/// until they have four; their knot counts must agree), with the end tangents of
/// the approximated arc about the centre line, faired and scaled by the blend scale
/// (for continuity 2 or 3 and both UV curves, also the second (and third)
/// directional derivatives of the surfaces along the dropped tangents, raising the
/// degree to 5 (7)); a point curve where the rails meet within `approx_tol_3d`.
/// The surface is the ruled surface between the end sections when the centre line
/// is a degree 1 line and no rail is a line in another direction, the surface of
/// revolution of the first section when all three curves are arcs, else a skin
/// through all sections along both rails (with cross boundary derivative surfaces
/// from the rail 1 and centre line tangents for `need_g1_continuity`; closed rails
/// close the skin with a copy of the first section).
///
/// # Errors
///
/// `SM_ERR` when the rails' knot counts differ, for a zero radius or a zero or
/// straight arc angle; `SM_ERR_INVALID_INPUT` from `Unitize`; those of the curve and
/// surface constructions and the surface queries; [`SolidError::InvalidInput`]
/// for continuity above 1 with both UV curves but a missing surface (upstream
/// dereferences `NULL`), or a knot insertion that adds no knot (upstream loops
/// forever).
pub fn create_surface_from_curves(
&self,
k: &Kernel,
center_line: &mut BSplineCurve,
rail1: &mut BSplineCurve,
rail2: &mut BSplineCurve,
approx_tol_3d: f64,
need_g1_continuity: bool,
side1: RailSurface<'_>,
side2: RailSurface<'_>,
) -> Result<BSplineSurface> {
const OP: &str = OP_BLEND;
let knots = rail1.knots(None)?.0;
let knots2 = rail2.knots(None)?.0;
if knots2.len() != knots.len() {
return Err(SolidError::sm_err(OP)); // Curves not compatible
}
let mut cross_sections: Vec<BSplineCurve> = Vec::new();
let mut parameters_of_cross_sections: Vec<f64> = Vec::new();
// Surface creation requires 4 or more cross sections so add
// some extra knots if needed.
let knots = add_section_knots(
rail1,
rail2,
knots,
false,
OP,
k.fixes.fillet_statuses_pass_on,
)?;
for i in 1..knots.len() {
let num_between: usize = 0;
for j in 0..=num_between + 1 {
let k0 = knot(&knots, i - 1, OP)?;
let k1 = knot(&knots, i, OP)?;
let mut t = k0 + j as f64 * (k1 - k0) / (num_between as f64 + 1.0);
if j == 0 {
t = k0;
}
if j == num_between + 1 {
t = k1;
}
if j == 0 && i != 1 {
continue; // Only do first point first time through
}
let section = self.cross_section_at(
k,
t,
center_line,
rail1,
rail2,
approx_tol_3d,
side1,
side2,
)?;
parameters_of_cross_sections.push(t);
cross_sections.push(section);
}
}
let mut is_line = center_line.is_line(ANALYTIC_SAMPLES, ANALYTIC_TOL)?;
if center_line.degree()? != 1 && is_line.is_some() {
is_line = None;
}
let mut sweep = false;
if let Some((_, line_vector)) = is_line {
sweep = true;
if line_is_off(line_vector, rail1)? {
sweep = false;
}
if line_is_off(line_vector, rail2)? {
sweep = false;
}
}
if sweep {
let (Some(start), Some(end)) = (cross_sections.first(), cross_sections.last()) else {
return Err(SolidError::invalid_input(OP, "no cross sections"));
};
let mut surface = BSplineSurface::create_ruled_surface(start, end, SurfParamType::U)?;
reparameterize_to_rail(&mut surface, rail1)?;
return Ok(surface);
}
let arc = bspline_is_arc(k, center_line)?;
let mut revolve = false;
if arc.is_some() {
revolve = true;
if bspline_is_arc(k, rail1)?.is_none() {
revolve = false;
}
if bspline_is_arc(k, rail2)?.is_none() {
revolve = false;
}
}
if let (true, Some((ref_frame, _, _, end_ang))) = (revolve, &arc) {
let gen_curve = cross_sections
.first()
.ok_or_else(|| SolidError::invalid_input(OP, "no cross sections"))?;
let mut surface = BSplineSurface::create_surf_of_revolution(
k,
gen_curve,
ref_frame.origin(),
ref_frame.z_axis(),
*end_ang,
false,
None,
)?;
reparameterize_to_rail(&mut surface, rail1)?;
return Ok(surface);
}
let mut deriv_surfs: [Option<BSplineSurface>; 2] = [None, None];
if need_g1_continuity {
let ivl = center_line.natural_interval();
for (i, slot) in deriv_surfs.iter_mut().enumerate() {
// We need to provide cross-boundary derivative surface
// for skinned-surface creation.
// Create rulled surface using end cross-section
// curve and the tangent vectors of rails
let (gen_curve, t) = if i == 1 {
(cross_sections.last(), ivl.max())
} else {
(cross_sections.first(), ivl.min())
};
let gen_curve =
gen_curve.ok_or_else(|| SolidError::invalid_input(OP, "no cross sections"))?;
let st = tangent_at(rail1, t, OP)?;
let end = tangent_at(center_line, t, OP)?;
*slot = Some(deriv_surface(
gen_curve,
st,
end,
k.fixes.fillet_statuses_pass_on,
)?);
}
insert_end_span_knots(rail1, rail2, OP, k.fixes.fillet_statuses_pass_on)?;
}
if is_closed_base(k, &*rail1, &rail1.natural_interval(), 0.0)?
&& is_closed_base(k, &*rail2, &rail2.natural_interval(), 0.0)?
{
let copy_first = cross_sections
.first()
.ok_or_else(|| SolidError::invalid_input(OP, "no cross sections"))?
.copy();
cross_sections.pop();
cross_sections.push(copy_first);
}
let [d0, d1] = &deriv_surfs;
let opts = SkinnedSurfaceOptions {
synchronized: true,
cross_section_surf_param: SurfParamType::U,
approx_tol: approx_tol_3d,
rail1: Some(rail1),
rail2: Some(rail2),
rail1_used_as_spine_curve: false,
intersections_with_rails: Some(&parameters_of_cross_sections),
deriv_surfs: Some([d0.as_ref(), d1.as_ref()]),
degree: 3,
};
BSplineSurface::create_skinned_surface(k, &cross_sections, opts)
}
/// The blend curve cross section at `t` (the body of the loops of
/// `CreateSurfaceFromCurves`): [`BlendCurveCrossSectionFsg::cross_section_through`]
/// the centre line's and the rails' points at `t`, with the UV curves' points at `t`.
fn cross_section_at(
&self,
k: &Kernel,
t: f64,
center_line: &BSplineCurve,
rail1: &BSplineCurve,
rail2: &BSplineCurve,
approx_tol_3d: f64,
side1: RailSurface<'_>,
side2: RailSurface<'_>,
) -> Result<BSplineCurve> {
const OP: &str = OP_BLEND;
let cent = center_line
.evaluate(t, 1, true, false)?
.first()
.copied()
.ok_or_else(|| SolidError::sm_err(OP))?;
let p1 = rail1.evaluate_point(t)?;
let p2 = rail2.evaluate_point(t)?;
let uv = match (side1.uv_curve, side2.uv_curve) {
(Some(uv1), Some(uv2)) => SectionUv::Curves { t, uv1, uv2 },
_ => SectionUv::None,
};
self.cross_section_through(
k,
cent,
[p1, p2],
approx_tol_3d,
[side1.surface, side2.surface],
uv,
)
}
/// The blend curve cross section about `cent` from `p1` to `p2` (on the rails'
/// surfaces `surfaces`): the end tangents of the arc about `cent`, faired and scaled
/// by the blend scale, for continuity 2 or 3 with `uv` points also the second (and
/// third) directional derivatives of the surfaces along the dropped tangents; a
/// point curve where the points meet within `approx_tol_3d`. Shared by
/// `CreateSurfaceFromCurves` and (not upstream, WR-581) the revolved section of
/// `CalcTorusFilletGeom` (`blend::fillet_solver::p2`).
///
/// # Errors
///
/// `SM_ERR` for a zero radius or a zero or straight arc angle; `SM_ERR_INVALID_INPUT`
/// from `Unitize`; [`SolidError::InvalidInput`] for continuity above 1 with `uv`
/// points but a missing surface (upstream dereferences `NULL`); those of the curve
/// constructions and the surface queries.
pub(crate) fn cross_section_through(
&self,
k: &Kernel,
cent: Point3,
[p1, p2]: [Point3; 2],
approx_tol_3d: f64,
surfaces: [Option<&Surface>; 2],
uv: SectionUv<'_>,
) -> Result<BSplineCurve> {
const OP: &str = OP_BLEND;
let v1 = p1 - cent;
let v2 = p2 - cent;
if p1.distance(p2) < approx_tol_3d {
// Create a point curve.
return BSplineCurve::create_point_curve(p1); /* parameterized from 0 to 1 */
}
let radius = v1.length();
let radius2 = v2.length();
// Check for case of zero radius on interior of surface
// We do allow it on the ends of the surface - however it
// may not be allowed in the creation - we'll see.
if radius < EFF_ZERO || radius2 < EFF_ZERO {
// (an error at interior and end knots alike: "Someday we will handle this
// at the ends")
return Err(SolidError::sm_err(OP));
}
let v1 = v1.unitize()?;
let v2 = v2.unitize()?;
let mut z_vec = v1.cross(v2).unitize()?;
let angle = z_vec.ccw_angle_between(v1, v2)?;
if angle.abs() < EFF_ZERO_SQRT {
return Err(SolidError::sm_err(OP)); // Degenerate case here
}
if angle.abs() > PI - EFF_ZERO_SQRT {
return Err(SolidError::sm_err(OP)); // Nearly 180 degree case here
}
if angle < 0.0 {
z_vec = -z_vec;
}
let angle = z_vec.ccw_angle_between(v1, v2)?;
if angle < EFF_ZERO {
return Err(SolidError::sm_err(OP)); // Can't happen ??
}
let y_vec = z_vec.cross(v1);
let x_vec = y_vec.cross(z_vec);
let x_vec = x_vec.unitize()?;
let y_vec = y_vec.unitize()?;
let mut placement = Axis2Placement::default();
placement.set_canonical(cent, x_vec, y_vec)?;
let arc = BSplineCurve::approximate_arc(
3,
None,
&placement,
radius,
0.0,
angle * 180.0 / PI,
approx_tol_3d * 100.0,
)?;
let ivl = arc.natural_interval();
let tan_1 = tangent_at(&arc, ivl.min(), OP)?.unitize()?;
let points = [p1, p2];
let tan_2 = tangent_at(&arc, ivl.max(), OP)?.unitize()?;
let mut vectors = [tan_1, tan_2];
let tan_3d_1 = tan_1;
let tan_3d_2 = tan_2.unitize()? * tan_3d_1.length();
// Create a blend curve instead using tangent vectors of the curve
let mut higher_order_vecs: Option<Vec<Vec3>> = None;
if self.continuity > 1 && !matches!(uv, SectionUv::None) {
let null = || SolidError::invalid_input(OP, "UV curves without their surfaces");
let [surf1, surf2] = surfaces;
let surf1 = surf1.ok_or_else(null)?;
let surf2 = surf2.ok_or_else(null)?;
let (uv1, uv2) = match uv {
SectionUv::Curves { t, uv1, uv2 } => {
let uv_pnt1 = uv1.evaluate_point(t)?;
let uv_pnt2 = uv2.evaluate_point(t)?;
(
Point2::new(uv_pnt1.x, uv_pnt1.y),
Point2::new(uv_pnt2.x, uv_pnt2.y),
)
}
SectionUv::Points(uv1, uv2) => (uv1, uv2),
SectionUv::None => return Err(SolidError::invalid_input(OP, "no UV points")),
};
let drop1 = |s: &Surface, uv: Point2, v: Vec3| -> Result<Vec2> {
drop_vectors_at(k, s, uv, Side::Left, Side::Left, &[v])?
.first()
.copied()
.ok_or_else(|| SolidError::sm_err(OP))
};
let uv_tan1 = drop1(surf1, uv1, tan_3d_1)?;
let uv_tan2 = drop1(surf2, uv2, tan_3d_2)?;
let mut vecs = Vec::new();
if self.continuity == 2 {
let g2 = compute_higher_order_derivs(k, surf1, uv1, uv_tan1, false, false)?.g2;
surf1.evaluate_point(k, uv1)?;
vecs.push(g2);
let g2b = compute_higher_order_derivs(k, surf2, uv2, uv_tan2, false, false)?.g2;
vecs.push(g2b);
surf2.evaluate_point(k, uv2)?;
}
if self.continuity == 3 {
let d1 = compute_higher_order_derivs(k, surf1, uv1, uv_tan1, true, false)?;
surf1.evaluate_point(k, uv1)?;
vecs.push(d1.g2);
let d2 = compute_higher_order_derivs(k, surf2, uv2, uv_tan2, true, false)?;
vecs.push(d2.g2);
surf2.evaluate_point(k, uv2)?;
vecs.push(d1.g3.ok_or_else(|| SolidError::sm_err(OP))?);
vecs.push(d2.g3.ok_or_else(|| SolidError::sm_err(OP))?);
}
higher_order_vecs = Some(vecs);
}
BSplineCurve::fair_blend_curve_derivatives(
&points,
&mut vectors,
higher_order_vecs.as_deref_mut(),
false,
)?;
let s = self.blend_scale;
for v in &mut vectors {
*v *= s;
}
let mut degree = 3;
if let Some(h) = higher_order_vecs.as_mut() {
if h.len() == 2 {
for v in h.iter_mut() {
*v = *v * s * s;
}
degree = 5;
}
if h.len() == 4 {
for (n, v) in h.iter_mut().enumerate() {
*v = if n < 2 { *v * s * s } else { *v * s * s * s };
}
degree = 7;
}
}
// At thirds (fork fd3b6a7): the Hermite's inner control points (P0 + D0/n,
// P1 - D1/n for degree n) a third of the way from each contact to where the two
// contact tangent lines meet, so D_i is n/3 of that distance; the higher
// derivatives keep their curvature with it.
if self.at_thirds {
let [d0, d1] = vectors;
let l0 = d0.length();
let l1 = d1.length();
let w = p1 - p2;
if l0 > EFF_ZERO && l1 > EFF_ZERO {
let d0 = d0 / l0;
let d1 = d1 / l1;
// Lines P0 + u d0 and P1 - v d1 (u, v > 0 run towards the corner).
let b = -d0.dot(d1);
let den = 1.0 - b * b;
if den > 1.0e-10 {
let dd = d0.dot(w);
let e = -d1.dot(w);
let u = (b * e - dd) / den;
let v = (e - b * dd) / den;
if u > EFF_ZERO && v > EFF_ZERO {
let n = degree as f64;
let k0 = (n / 3.0) * u / l0;
let k1 = (n / 3.0) * v / l1;
let [v0, v1] = &mut vectors;
*v0 *= k0;
*v1 *= k1;
if let Some(h) = higher_order_vecs.as_mut() {
let len = h.len();
for (index, vec) in h.iter_mut().enumerate() {
*vec = match index {
0 => *vec * (k0 * k0),
1 => *vec * (k1 * k1),
2 if len == 4 => *vec * (k0 * k0 * k0),
3 if len == 4 => *vec * (k1 * k1 * k1),
_ => *vec,
};
}
}
}
}
}
}
BSplineCurve::create_interpolating_curve(
ParamMethod::Uniform,
3,
degree,
&points,
&vectors,
higher_order_vecs.as_deref(),
false,
)
}
}
#[cfg(test)]
mod tests {
use super::*;
@@ -4407,25 +3870,6 @@ mod tests {
));
}
#[test]
fn blend_needs_matching_knot_counts() {
let k = Kernel::default();
let mut c = line(p(0.0, 1.0, 1.0), p(5.0, 1.0, 1.0));
let mut a = line(p(0.0, 0.0, 1.0), p(5.0, 0.0, 1.0));
let mut b = line(p(0.0, 1.0, 0.0), p(5.0, 1.0, 0.0));
b.insert_one_knot(0.5, 1).expect("knot");
let none = RailSurface {
surface: None,
uv_curve: None,
};
let r = BlendCurveCrossSectionFsg::default()
.create_surface_from_curves(&k, &mut c, &mut a, &mut b, 1e-6, false, none, none);
assert!(matches!(r, Err(SolidError::Upstream { .. })));
let fsg = BlendCurveCrossSectionFsg::default();
assert_eq!((fsg.continuity(), fsg.blend_scale()), (1, 1.5));
assert_eq!(fsg.generator_type(), FilletSurfaceGeneratorType::BlendCurve);
}
#[test]
fn guess_sphere_solve_starts_from_the_sphere() {
let mut fs = cr();
@@ -26,7 +26,6 @@
//! | `impl FilletSolverOps for VariableRadiusFs` | the `SmVariableRadiusFS` virtuals (`GetJacobianSize`, `SetupOffsetValues`, `OffsetRadiiCanChange`, `LoadJacobian`, `LoadInitialValues`, `GetType`, `IsKindOf`, `GetSolverType`) |
//! | `impl FilletSolverOps for ConstantDistanceFs` | the `SmConstantDistanceFS` virtuals (`CanMakeAnalytic`, `GetJacobianSize`, `GetSolverType`, `LoadJacobian`, `LoadInitialValues`, `SetupOffsetValues`, `GetType`, `IsKindOf`) and `GetDistance` |
//! | [`CircularCrossSectionFsg::create_surface`] | `SmCircularCrossSectionFSG::CreateSurface` |
//! | [`BlendCurveCrossSectionFsg::create_surface`] | `SmBlendCurveCrossSectionFSG::CreateSurface` |
//! | [`SurfaceSurfaceFs::new`] | `SmSurfaceSurfaceFS::SmSurfaceSurfaceFS` |
//! | [`SurfaceSurfaceFs::calc_fillet_geom`], [`SurfaceSurfaceFs::calc_fillet_start`], [`SurfaceSurfaceStart`] | `SmSurfaceSurfaceFS::CalcFilletGeom` (up to `GetPseudoBrep`; the rest is `surface_surface`'s) |
//! | [`SurfaceSurfaceFs::is_kind_of`] | `SmSurfaceSurfaceFS::IsKindOf` |
@@ -128,10 +127,10 @@ use crate::blend::fillet_solver::p3::StepSolveOutcome;
use crate::blend::fillet_solver::p4::IntersectorSolver;
use crate::blend::fillet_standard_solver::p1::SolverRails;
use crate::blend::fillet_standard_solver::p1::{
constant_radius_is_kind_of, BlendCurveCrossSectionFsg, BoundaryTrimmingType,
CircularCrossSectionFsg, ConstantDistanceFs, ConstantRadiusFs, CurveBasedFs,
DistanceInitialValues, FilletLaw, FilletSolverType, JacobianSurfaces, RailSurface,
SurfaceSurfaceFs, VariableRadiusFs, CONSTANT_RADIUS_ASSISTED_FS_TYPE, CURVE_BASED_FS_TYPE,
constant_radius_is_kind_of, BoundaryTrimmingType, CircularCrossSectionFsg, ConstantDistanceFs,
ConstantRadiusFs, CurveBasedFs, DistanceInitialValues, FilletLaw, FilletSolverType,
JacobianSurfaces, SurfaceSurfaceFs, VariableRadiusFs, CONSTANT_RADIUS_ASSISTED_FS_TYPE,
CURVE_BASED_FS_TYPE,
};
use crate::blend::law_corners::{ArcApproximation, LawCornerPieces};
use crate::curve::curve::p1::GlobalPointSolveOptions;
@@ -2479,9 +2478,8 @@ impl CircularCrossSectionFsg {
/// pRail1Curve, pRail2Curve, crFilletPoints, pSurf1, pUV1, pSurf2, pUV2,
/// rpFilletSurface)`: [`CircularCrossSectionFsg::create_surface_from_curves`] at the
/// solver's tolerance, without `G1` continuity (upstream keeps it off for every
/// solver type). The fillet points and surfaces are not used. With
/// `fixes.fillet_gn_section_generator` a variable-radius or constant-distance
/// solver's sections are the balls' touch circles
/// solver type). The fillet points and surfaces are not used. A variable-radius or
/// constant-distance solver's sections are the balls' touch circles
/// ([`CircularCrossSectionFsg::create_surface_from_curves_of_balls`]; WR-685).
///
/// # Errors
@@ -2503,11 +2501,10 @@ impl CircularCrossSectionFsg {
// ball changes its radius along the round (a radius law, or a constant chord
// between faces whose angle changes); the others' balls touch the round along
// their great circles.
let ball_radius_varies = k.fixes.fillet_gn_section_generator
&& matches!(
solver_type,
FilletSolverType::VariableRadius | FilletSolverType::ConstDist
);
let ball_radius_varies = matches!(
solver_type,
FilletSolverType::VariableRadius | FilletSolverType::ConstDist
);
// the centre line is a plain SmBSplineCurve here, so its virtuals are the
// B-spline ones
let mut cl = Curve::from(core::mem::take(center_line));
@@ -2976,8 +2973,7 @@ fn rolled_on(offset: &crate::surface::offset_surface::OffsetSurface) -> Cow<'_,
impl CircularCrossSectionFsg {
/// The fork's `SmGnSectionFSG::CircleSurface` gate (cc08236, 308cc40, c596548; with
/// `fixes.fillet_gn_section_generator` and `fixes.fillet_round_as_definition`,
/// WR-698): a ball of one radius between faces that are NURBS surfaces is the round by
/// `fixes.fillet_round_as_definition`, WR-698): a ball of one radius between faces that are NURBS surfaces is the round by
/// its definition, the order-1 section's `Build` with the rails and uv curves
/// replaced ([`GnSectionFsg::build_given_ball`]), unless the rails or the centre line
/// turn at a knot (`sm_FilletCurveCorners`: the pieces are built as before), a face is
@@ -3021,7 +3017,7 @@ impl CircularCrossSectionFsg {
corner_angle, fillet_curve_corners,
};
use crate::surface::surface::SurfaceKind;
if !(k.fixes.fillet_gn_section_generator && k.fixes.fillet_round_as_definition) {
if !k.fixes.fillet_round_as_definition {
return Ok(None);
}
let [rail1, rail2] = rails;
@@ -3282,7 +3278,7 @@ impl CircularCrossSectionFsg {
impl super::p1::LinearCrossSectionFsg {
/// A chamfer by its definition (solidcore's, #2486; with
/// `fixes.fillet_gn_section_generator` and `fixes.fillet_round_as_definition`): the
/// `fixes.fillet_round_as_definition`): the
/// section generator's chord, order 0, between the feet of the point at the solver's
/// offsets off the two faces ([`GnSectionFsg::build_chord`]), keeping the chamfer's
/// sizes: those the solver was made for, else its two offsets' setbacks at the wedge
@@ -3314,7 +3310,7 @@ impl super::p1::LinearCrossSectionFsg {
};
use crate::surface::procedural_blend::chamfer::{ChamferDefinition, ChamferSize};
use crate::surface::surface::SurfaceKind;
if !(k.fixes.fillet_gn_section_generator && k.fixes.fillet_round_as_definition) {
if !k.fixes.fillet_round_as_definition {
return Ok(None);
}
let [rail1, rail2] = rails;
@@ -3582,46 +3578,6 @@ fn chord_between_planes(
const OP_LINEAR_DEF: &str =
"blend::fillet_standard_solver::p2::LinearCrossSectionFsg::definition_surface";
impl BlendCurveCrossSectionFsg {
/// `SmBlendCurveCrossSectionFSG::CreateSurface(rFilletSolver, pCenterLine,
/// pRail1Curve, pRail2Curve, crFilletPoints, pSurf1, pUV1, pSurf2, pUV2,
/// rpFilletSurface)`:
/// [`BlendCurveCrossSectionFsg::create_surface_from_curves`] at the solver's
/// tolerance, with `G1` continuity for a constant-radius solver
/// (`SM_FS_CONST_RADIUS`). The fillet points are not used.
///
/// # Errors
///
/// Those of [`BlendCurveCrossSectionFsg::create_surface_from_curves`].
#[allow(clippy::too_many_arguments)]
pub fn create_surface(
&self,
k: &Kernel,
approx_tol_3d: f64,
solver_type: FilletSolverType,
center_line: &mut BSplineCurve,
rail1: &mut BSplineCurve,
rail2: &mut BSplineCurve,
side1: RailSurface<'_>,
side2: RailSurface<'_>,
) -> Result<BSplineSurface> {
let mut need_g1_continuity = false;
if solver_type == FilletSolverType::ConstRadius {
need_g1_continuity = true;
}
self.create_surface_from_curves(
k,
center_line,
rail1,
rail2,
approx_tol_3d,
need_g1_continuity,
side1,
side2,
)
}
}
// ---- SmSurfaceSurfaceFS ---------------------------------------------------------------------------
impl SurfaceSurfaceFs {
@@ -4217,23 +4173,5 @@ mod tests {
.expect("circular");
let corner = s.evaluate_point(Point2::new(0.0, 0.0)).expect("point");
assert!(corner.distance(p(0.0, 0.0, 1.0)) < 1e-6);
let none = RailSurface {
surface: None,
uv_curve: None,
};
let mut c = line(p(0.0, 1.0, 1.0), p(5.0, 1.0, 1.0));
let (mut a, mut b) = (r1.copy(), r2.copy());
b.insert_one_knot(0.5, 1).expect("knot");
let r = BlendCurveCrossSectionFsg::default().create_surface(
&k,
1e-6,
FilletSolverType::VariableRadius,
&mut c,
&mut a,
&mut b,
none,
none,
);
assert!(matches!(r, Err(SolidError::Upstream { .. })));
}
}
@@ -3,8 +3,7 @@
//!
//! Not in the pinned upstream: the SolidCraft fork's `source/SMLib/src/SmFilletSection.cpp`
//! (`sm_FilletCurveCorners`, from tangency-labs/smlib@6eecf04), called by
//! `SmGnSectionFSG::CircleSurface`, the fork's circular section, under
//! `fixes.fillet_gn_section_generator` (WR-685, #2250).
//! `SmGnSectionFSG::CircleSurface`, the fork's circular section (WR-685, #2250).
//!
//! | Rust | Fork (`SmFilletSection.cpp`) |
//! |---------------------------|------------------------------|
+2 -3
View File
@@ -4,8 +4,7 @@
//! between rail points at a peak.
//!
//! Not in the pinned upstream: the SolidCraft fork's law corners (tangency-labs/smlib#79,
//! 7babe17, 58d03ef and 62fcc82), for `fixes.fillet_gn_section_generator` (WR-685's
//! law-corner addendum, #2273). The round is the union of its balls: each side of a law
//! 7babe17, 58d03ef and 62fcc82; WR-685's law-corner addendum, #2273). The round is the union of its balls: each side of a law
//! corner is skinned on its own and ends on the corner ball's touch circle of its own
//! side, through the same two rail points. Where the law dips the circle after lies ahead
//! of the one before and the ball's own sphere fills the zone between them; where it
@@ -22,7 +21,7 @@
//! | [`sphere_zone`] | `sm_SphereZone` (`SmFilletExecutive.cpp`) |
//! | [`curve_between`] | `sm_CurveBetween` (`SmFilletExecutive.cpp`) |
//!
//! What is in, under `fixes.fillet_gn_section_generator`: 6eecf04's trace (the law's
//! What is in: 6eecf04's trace (the law's
//! corners, [`FilletLaw::corner_parameters`](crate::blend::fillet_standard_solver::p1::FilletLaw::corner_parameters),
//! are through points, and the fillet intersector steps onto them and flushes each span
//! with its own side's tangents, so the round's curves turn there), and its piecewise skin
+2 -2
View File
@@ -354,8 +354,8 @@ pub enum SolidError {
operation: &'static str,
},
/// A fillet refused as too large, with the largest size that builds it (opt-in
/// `fixes.fillet_gn_section_generator`; the fork's `GetFitRadius`, `GetFitEdge` and
/// A fillet refused as too large, with the largest size that builds it (the fork's
/// `GetFitRadius`, `GetFitEdge` and
/// `GetFitKind`, which its capi's `smlib_blend_fit_size` reads, tangency-labs/smlib#79,
/// WR-696). Returned in place of [`SolidError::Upstream`] with the same `code` (so
/// [`SolidError::sm_status`] is unchanged) only when the refusal's cause has a size; a
+2 -19
View File
@@ -384,8 +384,6 @@ pub struct UpstreamFixes {
pub fillet_chamfer_cone_on_arc: bool,
/// With `fillet_chamfer_cone_on_arc`, `CalcTorusFilletGeom` stores a linear section's revolution as the `SmCone` it is: the revolution's NURBS form is copied (`SmBSplineSurface::Copy`) and passed through `CopyAndAddAnalytics`, and when that gives a cone it is the fillet surface and the rails are made on it (as a straight edge's round is stored as its cylinder); anything else stays the surface of revolution. Without it a chamfer round a hole's rim is a surface of revolution, which reads back as a rational B-spline, not the cone it is (WR-572, #1503; the fork's tangency-labs/smlib@b5743ec).
pub fillet_chamfer_cone_stored_as_cone: bool,
/// `CalcTorusFilletGeom` also revolves a blend-curve (G1/G2/G3) section when the fillet's centre line is a point on the arc's axis (a blend as wide as the face it uses up, such as an R10 cylinder's rim at 10): upstream takes only circular sections there, so such a blend is marched along a centre line of no length and `TrimRails` fails (`SM_ERR`), leaving the body as it was; the revolved section is the blend curve `CreateSurfaceFromCurves` builds for each section of a marched blend, and every other blend is marched as upstream (WR-581, #919).
pub fillet_blend_curve_revolved_on_arc: bool,
/// `CreateCornerBlend`'s four-sided (not bilinear) corner patch is made tangent to the surfaces along its sides: a bicubic Coons patch meets its cross-boundary derivatives only where their twists agree at the corners, and where two rounds of different curvature meet `sm_CreateCoonsSrf`'s mean twist left both rounds at an angle along whole sides (15.6 degrees off a bar's round at r 2, rig fillets/1207). A copy is refined to 8 up to 64 spans each way and the control points next to each side are moved into that side's tangent planes until every side is within `SM_CONTINUITY_ANGLE` (WR-547; the fork's tangency-labs/smlib@cae8618). The patch's normal at each measured station is made unit by its own length, not by `Unitize`, whose absolute floor (1e-12) refused a small patch's normal near its collapsed side, so a variable-radius corner on a box of 0.01 failed (tangency-labs/smlib@701da4b).
pub corner_blend_coons_patch_tangent_to_sides: bool,
/// `SmFilletCorner::CreateCornerPatch` marks the patch sides that lie on a face of the body (a fillet edge with an original face) and `sm_CreateCoonsSrf` gives a corner between such a side and a blend's side the blend side's twist instead of the mean of the two: a bicubic Coons patch meets a side's cross-boundary derivative only where the corner twists are the other sides' own, so the mean tilted the patch off the face's tangent plane beside that side and it crossed the face (0.037 out of a bar's side face where the bar's top-edge round meets the concave round at a cylinder it runs tangent into, r 2). Corners between two face sides or two blend sides keep the mean (WR-613, #1836; the fork's tangency-labs/smlib@7fd9fb0 (commit not in fork history at 26cc451), from the issue's diff).
@@ -396,8 +394,6 @@ pub struct UpstreamFixes {
pub fillet_torus_rail_on_axis: bool,
/// The fillet solver decides whether a constant round is exact by one classification of its spine (the curve the ball's centre runs on) from its faces' kinds and placement, read as the natural quadrics they lie on (plane, sphere, circular cylinder or cone, an offset of one): a line (two planes; a plane or cylinder parallel to a cylinder's axis) is built as the cylinder, a circle about a common axis (coaxial quadrics, a plane square to the axis, a sphere's centre on it) as the section turned about that axis, a point (two cylinders as wide as the ball, axes meeting) as the ball's piece; every other round is traced. This replaces upstream's try-and-fall-through chain (`CanMakeAnalytic`, planes and cones only, then cylinder, torus and with `fillet_corner_ball_patch` the sphere, each deciding from the edge's shape) at `CalcFilletGeom` and at `ReCalcFilletGeom` (where a line round is rebuilt as its cylinder, not the cone), and a builder's failure is then an error, not a trace. So a round on a sphere is exact, and a circular round's frame comes from the faces' axis, not the edge's `IsArc` (WR-669; the fork's tangency-labs/smlib@b5f2867 and 7ac037e). The torus and ball builders' own flags still apply inside them: the fork's behaviour is this with `fillet_torus_span_from_start_section`, `fillet_chamfer_cone_on_arc`, `fillet_chamfer_cone_stored_as_cone`, `fillet_torus_center_on_axis`, `fillet_torus_rail_on_axis` and `fillet_corner_ball_center_from_axes` on (a chamfer round a circle is traced without `fillet_chamfer_cone_on_arc`). A conic spine (a plane with a cylinder or cone at any other angle; two cylinders or cones touching a common ball the same way round) is built as the exact rational surface of the ball's arcs, checked against the ball before it is kept (the fork's tangency-labs/smlib@0061c41 and 1b5f1e7); the fork's nodal-quartic rounds are classified but still traced here. A line round's cylinder is built on its exact spine, the line its offsets meet in, its rails on the faces' feet of it, and keeps that frame instead of the stations' centres and a frame refitted from its net (#2405, solidcore-native).
pub fillet_exact_round_classes: bool,
/// `sm_SrfSrfIntersection` traces the curve of a surface and a plane between two points on both, where the surface is not flat and they cross at both, on the plane's equation (`sm_SurfacePlaneCurve`): the plane, unbounded, does not end the curve, where upstream's analytic intersector stops at the plane's domain, the face it was made for, and its two-points intersector marches both surfaces in their domains. Its three curves are cubic Hermite interpolants of the stations, a span split where a quarter point is off the exact curve by more than a tenth of the tolerance (WR-682; the fork's tangency-labs/smlib@5bdcddf, 14a6daa and 4c6571b).
pub fillet_surface_plane_curve_on_plane_equation: bool,
/// `SmFilletExecutive::CreateFilletBrep` stitches the fillet body keeping a fillet's own edge where an edge of corner-patch faces only meets an edge of other fillet faces only (`SmFilletPatchStitchCallback`): an N-sided corner patch is bounded by its surfaces' isoparametric curves, the approximations it was fitted to, and the default choice between the two near-equal distances left one half of a set-back section the exact arc and the other the polynomial approximation, off the round (WR-546, #1377; the fork's tangency-labs/smlib@1072d1b).
pub fillet_patch_keeps_fillet_edges: bool,
/// `SmFilletGeom::TrimOriginalSurfaces` takes the piece of an original face 'inside' a fillet's rail (the one to delete) as the piece whose binormal along the rail makes the largest positive dot with the fillet's (above `SM_EFF_ZERO_SQRT`), not any piece above a fixed 0.2: the pieces' binormals are opposite, and 0.2 refused any fillet meeting its face at more than 78 degrees. A knife edge's chamfer meets the flat face at 81 degrees at d 0.5 (dot 0.15): nothing was deleted and the chamfer face was left apart from the body (WR-611, #1809; the fork's tangency-labs/smlib@de4dae6).
@@ -426,8 +422,6 @@ pub struct UpstreamFixes {
pub offset_excess_faces_after_merge: bool,
/// `SmFilletEdge::FindFilletBrepEdge`, looking for both edges of a fillet edge split in two (a corner's face curve split at the side's middle), keeps the second half when the first half's midpoint matched the curve to scaled zero and the other's only to the edges' tolerance, provided its ends lie on the curve too. Upstream kept such a near edge only for when nothing matched at all, so the second half was never merged into its face and the corner's sheet came out with two free edges (`SMLIB_ERR_NOT_SOLID` for some set-back, eased G2 corners) (WR-612, #1819; the fork's tangency-labs/smlib@ceb3272).
pub fillet_split_edge_keeps_near_half: bool,
/// At a set-back corner whose rounds ease (`SmFilletCorner::m_dEaseDist`, the fork's `e74bbd3`), `SmFilletCorner::MakeFaceBrep` bounds each face of the N-sided patch on one of the corner's face curves (`SM_FE_RAIL_RAIL_INTERPOLATION`) by that curve's own half, the curve trimmed to half its interval (one quintic span, curvature-continuous with its contact line and with the other half), instead of the patch surface's iso-curve, which `N_FillNSidedHole` fits to the half only to tolerance in its surfaces' degree and knots (a quintic face curve's half came back degree 6 over 7 spans) (WR-659; the fork's tangency-labs/smlib@4702889). Corners without an ease are unchanged; not reachable in the pinned C++, which has no ease.
pub fillet_corner_face_curve_halves: bool,
/// The extended offset (`SmOffsetExecutive::DoExtendedOffset`, which shells and offsets with extended convex edges) caps each vertex of the original with one edge (a cone's apex, the tip of a drilled hole) with the sphere `BuildOffsetOfVertex` builds for it, a face of the whole sphere zone the merge joins to the cone's offset; upstream builds no vertex offsets there, so the cone's offset ends open on the circle the apex's normals sweep out and the shell fails (WR-531; the fork's tangency-labs/smlib@d5dadaa).
pub offset_point_vertex_caps: bool,
/// `BuildOffsetOfFaceuse` clips a face to its offset domain from its counterclockwise loops (an inset is not turned inside out) (WR-342, #974).
@@ -1171,8 +1165,6 @@ pub struct UpstreamFixes {
pub curve_contacts_at_curve_ends: bool,
/// `SmOffsetExecutive::ShellBrep` of a solid inward fails when the inset leaves no cavity (an empty offset, `SM_ERR_INVALID_INPUT`) or the offset is not a closed solid (`SM_ERR`), instead of handing the input back unhollowed as a success (WR-454, #380; the fork's tangency-labs/smlib@1fc0d8f (was fbe43bb)).
pub shell_empty_cavity_fails: bool,
/// `create_fillet_brep` refuses a blend whose rolling ball does not fit the faces it rolls on (a face curves tighter than the ball at a section of the edge: `BallFitsItsFaces`) before the corners, with `FilletErrorType::NoRoom` (error info code 8, not an upstream code), where the corners fail with the generic status looking for a rail end that is not there (WR-462, #1172; SolidCraft change, diff `2c5baae..e5696ca` in the issue, in the fork as tangency-labs/smlib@a15b5a2).
pub fillet_refuse_ball_not_fitting: bool,
/// `CreateFilletBrep` sets each solver's trace reach before the corners (`sm_ExtendTraceToItsRails`): where the base surfaces' domains extended by the solver's factor (half their size) do not reach as far as a rail can lie from the edge (`r / tan(t/2)`, `t` the smallest angle between the faces' planes along it, `r` the largest radius over the trace, a variable round's law included), they reach twice that and `r` more, in the parameter directions that run across the edge (`GetDomainExtension`), so a blend wider than its faces is traced to its rails instead of being clamped at the extended domain's border; and `RailEdgeuseIntersect` runs a straight side edge on a plane on along its line as far, so a rail meeting the side edge's line past the edge's end is found (WR-609, WR-610, #960; the fork's tangency-labs/smlib@a9277fd and @6e77631). It runs such an edge on along its line on a cylinder or cone too, a ruling of it, so a disc's rim rounded past its wall meets the seam's line below the wall at its closed corner (the fork's @779cb9b).
pub fillet_trace_reaches_rails: bool,
/// `SmFilletVertex::CalcRailIntEdgeuse` places a rail's end found on a side edge at the rail's base surface evaluated with out-of-bounds evaluation on (the surface continued, as `RailEdgeuseIntersect`'s solve over the extended domain found it), not clamped to the surface's own domain, where a rail meeting a side edge's line just past the edge's end (a cliff overflow, with `fillet_trace_reaches_rails`) was put on the edge's end vertex, off the rail by the square of that distance over twice the radius, and taken as meeting the side edge (WR-630, #960/#1467; the fork's tangency-labs/smlib@3f22e97).
@@ -1323,16 +1315,7 @@ pub struct UpstreamFixes {
pub ascii_doubles_round_trip: bool,
/// A round whose filleted edge runs on tangentially at a vertex into an edge of its own convexity that its rail on that face runs alongside and never meets (an R2 corner arc of a plate's outline between straight sides, picked alone) ends at its section through the vertex: the round is cut there by the plane normal to the filleted edge, and the region between the round, its faces and the end sections is subtracted from the body, a flat end face (the section's corner) left on each such end. With `fillet_nx1_end_rib_global_merge` the end rib was deleted for the global merge, which cannot cut a round lying along the continued edge, and `DoFilleting` left an open body (`fillet_edges` refused it as not closed with `fillet_refuse_non_manifold_result`); pinned SMLib fails the corner (`SM_FILERR_VERTEX_PROBLEM`, 1001). Only a single round whose both ends are such ends is built; any other combination is refused with `FilletErrorType::NoRoom` (WR-674, #2176; own design, not in the fork, whose `CalcCornerEdgeGeom` takes the global merge as WR-303 does).
pub fillet_round_ends_at_tangent_continuation: bool,
/// A blend-curve fillet (`SM_FSG_BLEND_CURVE`) is built by the G^n section generator ([`crate::blend::fillet_section::section::GnSectionFsg`], the fork's `SmGnSectionFSG`) in place of `SmBlendCurveCrossSectionFSG`: the section of order n = continuity (2 to 4) and thumbweight w (below 1, the fork's b9d6a72, or `GN_THUMBWEIGHT_EQUAL_AREA` = 2, the default: the w at which the section takes off the area the ball's circle does, the fork's 6148773 = d01d7b0's 1947a45, resolved at every station from that station's own wedge, with its s-derivative, so that w varies along the blend: the surface interpolates the section's homogeneous rows, each a cubic Hermite curve of its values and s-derivatives, and the certificate bounds their remainder too, the fork's 7102bc5), `S(t) = f T1(1 - p1) + (1 - f) T2(p2)` over the faces' order-n jets along the rails, a rational Bezier section times the jets' cubic Hermite curves along the rails, certified span by span within a tenth of the fillet's tolerance; its contact with each face is of order n + 1 (n + 2 between planes). `SetFilletParameters` refuses another order or thumbweight (`SM_ERR_INVALID_INPUT`), the corners build theirs with the same order and thumbweight (and refuse to convert two that differ), the tangent end's rib takes the order of contact found at its rail (`ContactOrderAt`), and a round's ease before a setback blends into the order-2 section at thumbweight 0, not the equal area default (the fork's 22d258a = d01d7b0's adb9854). With it the `blend_curve_at_thirds` executive option is not used: the fork removed `SetBlendCurveAtThirds` when this generator replaced the blend curve, the ease's at-thirds G2 target among it; `fillet_blend_curve_revolved_on_arc` does not revolve it (the fork's `AdjustCrossSection` change, which refuses an order above 3, has no port: the function is not ported) (WR-685, #2250; the fork's tangency-labs/smlib@11ea2d9 = d01d7b0's 0bd3f4d, smlib#78).
///
/// With it a variable round is the union of its balls (the fork's d2a6125, f2ec002, e9560e3, 2714d37 and 6007a3d, rebased from 6b346f6, 5db8feb, fb5c060, d622107 and 8bedf89): a variable-radius or constant-distance solver's circle section is the circle along which the balls' envelope touches the ball, square to the centre line and moved along it by `-r r'/|c'|`, not the great circle through the rails; a round whose balls fold over one another is refused (`FilletErrorType::NoRoom`, `NoRoomReason::BallsFold`, naming the radius there); a cliff overflow's law check (`sm_HoldsItsLaw`) tests the touch circle; and `SmApiVariableRadiusFillet` takes the G^n section's default thumbweight (WR-685 addendum 2026-11-01).
///
/// With it, since the fork's tangency-labs/smlib#79 (410dfe1, 20ba5a9, 8c40818, a34b5e8, a3d6d81; merged at 5e8c9c1), `CreateFilletBrep` judges the rolling ball's local regularity along every blend after the trace reach and before the corners (`SmFilletSolver::BallIsRegular`, [`crate::blend::fillet_executive::session::ball_regular`]): each face encloses the ball (`1 - r k > 0`) and every point of its section is progressive (`f_tt > 0`). A blend that is not regular is refused with `FilletErrorType::NoRoom` (`NoRoomReason::BallDoesNotFit`, `BallsFold` or `OffsetFolds`) naming the radius that works, and the largest size that builds is noted ([`crate::blend::fillet_executive::session::FilletSession::fit_size`]). This replaces `BallFitsItsFaces` (`fillet_refuse_ball_not_fitting` is not run) and the circular section's `sm_BallsFold` (WR-696).
/// Then a convex blend (one that removes material) that would take all of the part between its rails somewhere along its edge, cutting it into pieces, is refused (`NoRoomReason::CutsThePart`) naming the largest size that keeps it whole, the fit noted less the fit margin (`SmFilletSolver::BandCutsThePart` with `sm_EdgesCrossingPlane` and `sm_KeepsMaterialBehind`, the fork's 862971f, e568e45 and aac4288; [`crate::blend::fillet_executive::session::band_cuts`]).
/// A blend refused as larger than its faces notes its largest size that builds too: where its rails stay on their faces (`LargestSizeOnItsFaces`, `BallThrough`), where a band reaches a circular top's centre, a polygon face's deepest point (`NoteFitOfPolygonsTakenWhole`), or where two bands on a face meet (`BandsMeetAt`; the fork's a3d6d81, 49f393d and 5e8c9c1, [`crate::blend::fillet_executive::session::fit_size`]). A refusal with a size returns [`crate::SolidError::FilletRefused`] (same status) carrying it, from `FilletSession::do_fillet` and the public fillet API.
/// Not the fork's (#2401): the refusals that had no size name one from their own geometry too. A polygon face its blends take whole (their balls reaching its deepest point, to the edge's tolerance) is refused (`NoRoomReason::FaceConsumed`) before the corners and the trace, which its rails of no length failed. A constant ball as wide as a face it rolls on (a cylinder or sphere of its radius, the ball inside) has its centre fixed; where the plane through an end of the edge square to it misses that centre, the zone the ball sweeps has no section there and the blend is refused (`NoRoomReason::OffsetCollapses`) naming that radius less the fit margin, and a ball past it that does not fit (`BallDoesNotFit`) names it open the same way; where every end's plane holds it (a tray's seam, a cornered block's rim) it builds as before ([`crate::blend::fillet_exact::ball_zone_open_at_an_end`]). The open ends of an overflow's trim that the end face does not cut (`CliffEndFaceNotPlanar`, `CliffEndNotCut`), and a trimmed blend that keeps no length where no corner takes any, name where the blend stays on its faces (`LargestSizeOnItsFaces`, open).
pub fillet_gn_section_generator: bool,
/// With [`Self::fillet_gn_section_generator`] also on (a no-op otherwise): constant and variable-radius rounds between NURBS faces are built as their definition, a [`crate::surface::procedural_blend::ProceduralBlend`] (the fork's `SmProceduralBlend`): the two faces the ball rolls on, its radius or radius law, the section's order and thumbweight rule and the leader, which evaluate exactly; its net, the certified B-spline approximation within the certificate's bound (the radius law in the certificate), is what the surface cache and tessellation use (`SmBlendNetScope`), the cache's node boxes grown by the net's bound. With it the file reader reads a definition (`SmProceduralBlend_TYPE`, `SURF_BASE_TYPE + 41`); without it that type is refused as the pinned reader refuses it (WR-698, #2273; the fork's tangency-labs/smlib@014f66f to 729f893, smlib#79 step 7, merged at 5e8c9c1).
/// Constant and variable-radius rounds between NURBS faces are built as their definition, a [`crate::surface::procedural_blend::ProceduralBlend`] (the fork's `SmProceduralBlend`): the two faces the ball rolls on, its radius or radius law, the section's order and thumbweight rule and the leader, which evaluate exactly; its net, the certified B-spline approximation within the certificate's bound (the radius law in the certificate), is what the surface cache and tessellation use (`SmBlendNetScope`), the cache's node boxes grown by the net's bound. With it the file reader reads a definition (`SmProceduralBlend_TYPE`, `SURF_BASE_TYPE + 41`); without it that type is refused as the pinned reader refuses it (WR-698, #2273; the fork's tangency-labs/smlib@014f66f to 729f893, smlib#79 step 7, merged at 5e8c9c1).
///
/// Not the fork's (#2486): a chamfer (the linear section) of a constant-radius solver's two offsets between NURBS faces, or of a constant-distance solver's chord between planes, is built as its definition too, the section generator's order 0: the straight chord between the feet of the point at the two offsets off the faces, certified as any section; between planes it is the exact plane through the feet, a `Plane` at a bound of 0 carrying its definition ([`crate::surface::procedural_blend::exact::ExactClass::Chord`], reached through [`crate::surface::surface::Surface::procedural_blend`]); either way keeping the chamfer's sizes (two distances, a distance and an angle, or a chord, with the wedge angle they were converted at; [`crate::surface::procedural_blend::chamfer`], [`crate::blend::fillet_executive::session::FilletSession::prepare_chamfers`]). The record and the database carry the sizes.
pub fillet_round_as_definition: bool,
@@ -1368,7 +1351,7 @@ pub struct UpstreamFixes {
pub fillet_section_end_trim_at_creases: bool,
/// With `fillet_overflow_trim_at_creases`, a crease of a blend past its faces that runs along an edge of the face it crosses, within the trim's tolerance, is taken as that edge: the sheet is split along it, its piece past the face is deleted, and the body's edge stands as the imprint where the material taken off stops and the sheet is sewn (as an extension's edges along the body do). The fork's `TrimAtCreases` (tangency-labs/smlib#79 step 6 at 5e8c9c1) keeps only the crease's runs inside the face (`sm_PiecesInFace`), so such a crease is dropped, the sheet keeps its piece past the face, the face is taken off with the rest, and the sewing is refused (`SM_FILERR_BAD_MERGE`): a disc 13 in radius and 2 high rounded 2.0001 to 2.01 on its top edge (the crease runs (r - 2)^2/4 inside the bottom edge) fails where r 2 and r 2.02 build. Not the fork's (WR-717, #2385).
pub fillet_overflow_crease_along_edge: bool,
/// With `fillet_gn_section_generator`, a convex blend whose section between its rails would break through the part (leave its material through a face and come back into it, where one of the faces it crosses there shares no edge with the blended faces: a hollow behind a wall, such as a round on a wall thinner than it reaches into the hollow behind, or a blind pocket or cavity under a blended face, which the pinned construction builds into a body that intersects itself or has the wrong volume) is refused with `FilletErrorType::NoRoom` (`NoRoomReason::BreaksThrough`), naming the largest size whose sections do not break through, and that size less the fit margin is the refusal's fit (`SolidError::FilletRefused`). A section that runs off its face (past a cliff, into a hole or an opening: the part beyond it reaches a rail) or through a hole in a blended face does not break through. The same 32 sections as `BandCutsThePart` are judged; the faces at the blended edge's ends, which the corners trim, are not ([`crate::blend::fillet_executive::session::band_cuts::band_breaks_through_the_part`]). Not the fork's: fork 5e8c9c1 segfaults in `DoFilleting` on #2299's case (WR-707, #2299; addendum `plan/upstream-issues/WR-707--addendum-2026-11-02-rounds-running-off-their-faces.md`).
/// A convex blend whose section between its rails would break through the part (leave its material through a face and come back into it, where one of the faces it crosses there shares no edge with the blended faces: a hollow behind a wall, such as a round on a wall thinner than it reaches into the hollow behind, or a blind pocket or cavity under a blended face, which the pinned construction builds into a body that intersects itself or has the wrong volume) is refused with `FilletErrorType::NoRoom` (`NoRoomReason::BreaksThrough`), naming the largest size whose sections do not break through, and that size less the fit margin is the refusal's fit (`SolidError::FilletRefused`). A section that runs off its face (past a cliff, into a hole or an opening: the part beyond it reaches a rail) or through a hole in a blended face does not break through. The same 32 sections as `BandCutsThePart` are judged; the faces at the blended edge's ends, which the corners trim, are not ([`crate::blend::fillet_executive::session::band_cuts::band_breaks_through_the_part`]). Not the fork's: fork 5e8c9c1 segfaults in `DoFilleting` on #2299's case (WR-707, #2299; addendum `plan/upstream-issues/WR-707--addendum-2026-11-02-rounds-running-off-their-faces.md`).
pub fillet_refuse_rounds_breaking_through: bool,
/// `SmPlane::GlobalSurfaceIntersect` with a torus as the other surface takes the torus's own plane section (`SmSurfOfRevolution::IntersectWithPlane` with the torus's iso circles: the circles of a plane square to the axis, the meridians of a plane through it), the orders and UV curves swapped as for a surface of revolution, where upstream has no torus case and marches it (circles 1.4e-6 off, meridians 3.5e-6 off); a meridian keeps its generator's circle kind (WR-721, #2405; solidcore-native, no fork commit).
pub plane_first_torus_section_exact: bool,
@@ -1570,7 +1570,6 @@ mod tests {
use crate::nurbs::b_spline_curve::BSplineCurve;
use crate::surface::procedural_blend::{BlendDefinitionInput, ProceduralBlend};
let mut k = Kernel::default();
k.fixes.fillet_gn_section_generator = true;
k.fixes.fillet_round_as_definition = true;
let bilinear = |p: [Point3; 4]| {
BSplineSurface::create_bilinear_surface(p[0], p[1], p[2], p[3]).unwrap()
@@ -1355,7 +1355,6 @@ fn round_blend_with(order: u32, certified: bool, thumbweight: f64) -> (Kernel, P
use crate::nurbs::b_spline_curve::BSplineCurve;
use crate::surface::procedural_blend::BlendDefinitionInput;
let mut kk = k();
kk.fixes.fillet_gn_section_generator = true;
kk.fixes.fillet_round_as_definition = true;
let (l, r) = (10.0, 2.0);
let bilinear =
@@ -2702,7 +2702,6 @@ mod tests {
use crate::surface::procedural_blend::{BlendDefinitionInput, ProceduralBlend};
let mut k = Kernel::default();
k.fixes.fillet_gn_section_generator = true;
k.fixes.fillet_round_as_definition = true;
let (l, r) = (10.0, 2.0);
+1 -3
View File
@@ -3857,9 +3857,7 @@ impl Surface {
STEP_SURFACE_TYPE => Ok(Self::from(StepSurface::read_from_db(k, db, version)?)),
// the fork's SmProceduralBlend (014f66f), read only with its flag: the pinned
// reader refuses the type
PROCEDURAL_BLEND_TYPE
if k.fixes.fillet_round_as_definition && k.fixes.fillet_gn_section_generator =>
{
PROCEDURAL_BLEND_TYPE if k.fixes.fillet_round_as_definition => {
Ok(Self::from(ProceduralBlend::read_from_db(k, db, version)?))
}
// the fork's SmBallPatch (f8e6709), which the pinned reader refuses
@@ -143,7 +143,9 @@ fn cross_section_on_the_original_face_drops_points_with_the_face() {
/// top face past each round's axis (radius 1 - r < 0): its section turned about the axis
/// would be a spindle torus through its own axis. Refused, naming 1. Upstream and the
/// port before built an 18-face body whose corner faces cross themselves (the difftest's
/// `big-rad-filleted_box-r2.0-top-edges` and `-r3.0-`, parked on WR-739).
/// `big-rad-filleted_box-r2.0-top-edges` and `-r3.0-`, parked on WR-739). The ball's
/// regularity (`BallIsRegular`, WR-696) finds it first: the R1 rounds curve tighter than
/// the ball, which does not fit them (`BallDoesNotFit`), naming the same 1.
#[test]
fn a_round_wider_than_the_r1_rounds_is_refused_naming_1() {
for r in [1.01, 2.0, 3.0] {
@@ -153,7 +155,7 @@ fn a_round_wider_than_the_r1_rounds_is_refused_naming_1() {
let Err(SolidError::FilletRefused { reason, fit, .. }) = result else {
panic!("r {r}: {result:?}");
};
assert_eq!(reason, Some(NoRoomReason::RailPastAxis), "r {r}");
assert_eq!(reason, Some(NoRoomReason::BallDoesNotFit), "r {r}");
assert!((fit.size - 1.0).abs() < 1e-12, "r {r}: {}", fit.size);
}
}
@@ -1,6 +1,7 @@
//! A B-spline radius law round on a cube edge (golden `law-cube20-e0-deg2-smooth-4-2-4`,
//! `prog_test` `smFilletTest.cpp:399`; the law is smooth, as a law with a corner inside its
//! edge is refused on this kernel, #2727, `variable_round_law_corner_refused.rs`).
//! `prog_test` `smFilletTest.cpp:399`; the law is smooth. A law with a corner inside its
//! edge is built as the union of its balls, split at the corner, #2727,
//! `wr696_default_variable_rounds.rs`).
//!
//! `SmFilletEdge::CalcFilletIntSideFace` and `CalcCrossSection` work on upstream's
//! pointers to the faces' surfaces, which keep their face as owner; the port's copies
@@ -54,6 +55,7 @@ fn bspline_law_round_drops_points_on_face_owned_surfaces_without_point_test() {
.unwrap();
session.do_fillet(&mut k).unwrap();
}
// the round adds its face
// the round adds its face: the law (a quadratic Bezier through 4, 2, 4) is smooth, with
// no corner, so the round has no C0 knot to be split at (WR-685's law corners)
assert_eq!(p1::faces(&body, None).unwrap().len(), faces_before + 1);
}
@@ -18,15 +18,13 @@
//! quadrilateral (40, 0), (0, 20), (0, 30), (40, 30) from z = -15 to 30, joined; the edge
//! lies between the wedge's front face y = 0 and its top face z = 15.
//! - A box edge whose radius runs linearly from 4 to 0 (and 0 to 4): the round closes to the
//! box corner as before. What it removes depends on its construction:
//! - without `fillet_gn_section_generator` its sections are the balls' great circles, and
//! it removes `(1 - pi/4) L r0^2 / 3 = 22.8909` (the integral of the corner's
//! `(1 - pi/4) r^2` along the edge, exact for a round of great circles);
//! - with it, its sections are the circles each ball touches the round along, shifted
//! `-r r' / |c'|` from the great circle, and it removes the balls' union. Its volume
//! 22.594877 is not a closed form but SolidCraft's numerical integration of that union
//! (`removed_by_balls` in its `variable_radius_down_to_zero_at_one_end`, which checks it
//! to 1e-5).
//! box corner as before. Its sections are the circles each ball touches the round along,
//! shifted `-r r' / |c'|` from the great circle, on every kernel (the G^n section's flag,
//! `fillet_gn_section_generator`, is retired: WR-685 addendum 2026-11-06), and it removes
//! the balls' union. Its volume 22.594877 is not a closed form but SolidCraft's numerical
//! integration of that union (`removed_by_balls` in its
//! `variable_radius_down_to_zero_at_one_end`, which checks it to 1e-5). The great circles
//! removed `(1 - pi/4) L r0^2 / 3 = 22.8909`.
//!
//! Each is checked to 1e-4 relative, as SolidCraft checks it.
//!
@@ -367,17 +365,14 @@ fn taper_closing_to_a_point_rounds_the_wedge() {
}
/// A box edge's radius running linearly from 4 to 0 (and 0 to 4) closes the round to the box
/// corner: 7 faces, the corner kept. What it removes depends on the round's construction
/// (module docs): its sections the balls' great circles without `fillet_gn_section_generator`,
/// `(1 - pi/4) L r0^2 / 3` (exact for a round of great circles); the balls' touch circles with
/// it, their union's volume (SolidCraft's numerical reference). Checked to 1e-4 relative.
/// corner: 7 faces, the corner kept, removing the balls' union (module docs; SolidCraft's
/// numerical reference), with no fixes and with every fix. Checked to 1e-4 relative.
#[test]
fn linear_radius_to_zero_closes_a_box_round_to_the_corner() {
let great_circles = (1.0 - std::f64::consts::FRAC_PI_4) * 20.0 * 16.0 / 3.0;
// the union of the balls, integrated numerically (module docs)
let balls = 22.594_877;
let mut wrong = Vec::new();
for (fixes, want) in [(Fixes::None, great_circles), (Fixes::All, balls)] {
for (fixes, want) in [(Fixes::None, balls), (Fixes::All, balls)] {
for (r0, r1) in [(4.0, 0.0), (0.0, 4.0)] {
let mut k = kernel(fixes);
let b = create_box(&mut k, Point3::new(0.0, 0.0, 0.0), 10.0, 20.0, 30.0).unwrap();
@@ -1,6 +1,6 @@
//! The SolidCraft fork's tangency-labs/smlib@64e5632 and 8f145ee (#2273, smlib#79 step 7):
//! a variable round whose balls exist over the variable radius solver's stations is its
//! definition (`fillet_round_as_definition`, WR-698, on `fillet_gn_section_generator`).
//! definition (`fillet_round_as_definition`, WR-698).
//!
//! The capi's `variable_round_on_a_cone_is_its_definition` and
//! `variable_round_quadratic_law_is_its_definition`: the top back edge (y = 30, z = 20) of a
@@ -457,7 +457,6 @@ fn solidcraft_kernel() -> Kernel {
/// each end of the edge.
fn fork_kernel() -> Kernel {
let mut k = Kernel::new(&KernelOptions::default());
k.fixes.fillet_gn_section_generator = true;
k.fixes.fillet_round_as_definition = true;
k.fixes.fillet_exact_arc_sections = true;
k.fixes.fillet_variable_span_follows_fillet = true;
@@ -13,7 +13,7 @@
//! box (0, 0, 0) .. (48, 16, 20), to the blends' tolerance 4e-5. Drafted 5 degrees inward,
//! the front face runs tangent into a cone instead.
//!
//! [`TANGENT_END_CASES`] holds the fork's thirteen cases with its reason for each that fails
//! [`TANGENT_END_CASES`] holds twelve of the fork's thirteen cases with its reason for each that fails
//! (`TANGENT_END_CASES` in capi `tests/ops_kernel.cpp`) at cd47efd, kept as they are. cd47efd's are 6d73e4f's: `concave_chamfer_d2`, `drafted_front_round_r2` and
//! `front_chamfer_d2` pass, and `chamfers_together_d2` fails at the 3x2 mixed corner where the
//! chamfers meet; 0cc48bd and b34d61b change no mark. Each case checks, as the fork's
@@ -24,23 +24,30 @@
//!
//! The marks run under [`solidcraft_kernel`], the fork's profile at cd47efd as far as solidcore
//! models it: every fix SolidCraft turns on but `geometric_g2_continuity` (as
//! `issue_2174_cap_rim_two_edges.rs`) and the two that are not the fork's at cd47efd, WR-685's
//! G^n section (its 11ea2d9 is later) and WR-710's refusal. At 9bebf34 the fork had neither the
//! `issue_2174_cap_rim_two_edges.rs`) and WR-710's refusal, not the fork's at cd47efd. The G^n
//! section and the generic blend's regularity and fit checks (WR-685, WR-696; the fork's
//! later 11ea2d9 and smlib#79) are on, as solidcore builds them always. At 9bebf34 the fork had neither the
//! tangent end of the trace (its later 6d73e4f/0cc48bd/b34d61b, WR-600) nor the blend corner
//! (its later smlib#79 step 4); solidcore builds both always (#2400), so 9bebf34's marks are
//! not run. At 5e8c9c1, with both, the fork's marks of the thirteen cases are cd47efd's, and
//! solidcore's are too.
//!
//! Four of the cases have tests already:
//! `fork_856b54e_tangent_end.rs` (front chamfer, concave chamfer, front round, against closed
//! forms) and `fork_cd47efd_tangent_end_rib_sqrt_s.rs` (the curvature round's rib). They stay
//! in the table for the fork's marks. The fork's twins on its `smlib-tangent-ends` branch,
//! The thirteenth, `front_curvature_round_r2` (the front top edge rounded 2 by the G2 blend
//! curve at thirds, the fork's `SetBlendCurveAtThirds`), is not run: solidcore's
//! curvature-continuous round is the G^n section (WR-685; the blend curve and its at-thirds
//! option went with `fillet_gn_section_generator`, WR-685 addendum 2026-11-06), the fork's
//! later 11ea2d9. That round on the same edge is graded against its own quadrature in
//! `fork_cd47efd_tangent_end_rib_sqrt_s.rs`.
//!
//! Three of the cases have tests already: `fork_856b54e_tangent_end.rs` (front chamfer,
//! concave chamfer, front round, against closed forms). They stay in the table for the
//! fork's marks. The fork's twins on its `smlib-tangent-ends` branch,
//! c5ea180 and 169adea, have the same diffs as 9bebf34 and a87c502, and on its `replay/1.0.1`
//! 6d73e4f, 0cc48bd and b34d61b are 856b54e, 4ee7d3a and cd47efd (the same trees).
//!
//! Differences from the fork's capi, all in how the test drives the kernel: blends go
//! through [`FilletSession`] per edge (constant radius; `Linear` for the chamfer, without
//! the capi's bevelled corners; `BlendCurve` G2 at thirds for the curvature round), edges
//! the capi's bevelled corners), edges
//! are picked as the nearest within 0.1 of each point; the drafted peg is a taper extrude
//! with `LinearExtension` corners, because `CurveExtension` (the fork's
//! `SMLIB_DRAFT_CORNER_CURVATURE`) refuses the half disc's 180-degree wall here (`NotExact`
@@ -73,18 +80,14 @@ use solidcore::{Brep, Kernel};
const PI: f64 = core::f64::consts::PI;
/// Every fix SolidCraft turns on: all but `geometric_g2_continuity`, and but WR-685's
/// `fillet_gn_section_generator`, the fork's later 11ea2d9 (= 0bd3f4d), which smlib#76 does
/// not have (its section refuses the curvature round's thumbweight 1), and but WR-710's
/// Every fix SolidCraft turns on: all but `geometric_g2_continuity`, and but WR-710's
/// `fillet_refuse_mixed_corner_crossing_rails`, not the fork's (it refuses the rounds
/// together where no Mixed corner takes the corner). The fork's profile at cd47efd.
fn solidcraft_kernel() -> Kernel {
let mut k = Kernel::default();
let mut f = UpstreamFixes::default();
for &name in UpstreamFixes::NAMES {
if name != "geometric_g2_continuity"
&& name != "fillet_gn_section_generator"
&& name != "fillet_refuse_mixed_corner_crossing_rails"
if name != "geometric_g2_continuity" && name != "fillet_refuse_mixed_corner_crossing_rails"
{
*f.flag_mut(name).unwrap() = true;
}
@@ -129,7 +132,6 @@ fn tangent_peg(k: &mut Kernel, draft_deg: f64) -> Brep {
#[derive(Clone, Copy)]
enum Kind {
Round,
Curvature,
Chamfer,
}
@@ -180,13 +182,11 @@ fn blend(
}
let (xsect, continuity) = match kind {
Kind::Round => (FilletSurfaceGeneratorType::Circular, 1),
Kind::Curvature => (FilletSurfaceGeneratorType::BlendCurve, 2),
Kind::Chamfer => (FilletSurfaceGeneratorType::Linear, 1),
};
let xsects = vec![xsect; edges.len()];
{
let mut s = FilletSession::new(k, b).map_err(|e| e.to_string())?;
s.set_blend_curve_at_thirds(matches!(kind, Kind::Curvature));
s.prepare_per_edge_constant_radius(k, &edges, &radii, &xsects, continuity, 1.0)
.and_then(|()| s.do_fillet(k))
.map_err(|e| format!("status: {e}"))?;
@@ -207,7 +207,6 @@ fn volume(k: &Kernel, b: &mut Brep) -> f64 {
// The fork's quadratures of the rig's expected answers (tanh-sinh, converged to 1e-13).
const PEG_V0: f64 = 6400.0 + 960.0 * PI;
const PEG_FRONT_ROUND_R2: f64 = 32.306_475_043_873_16;
const PEG_FRONT_CURVATURE_R2: f64 = 22.621_011_133_536_857;
const PEG_FRONT_CHAMFER_D2: f64 = 74.130_570_575_311_6;
const PEG_CONCAVE_CHAMFER_D2: f64 = 41.656_784_248_897_58;
@@ -338,10 +337,6 @@ fn front_chamfer_d2(k: &mut Kernel) -> Outcome {
let want = PEG_V0 - PEG_FRONT_CHAMFER_D2;
one(k, 0.0, Kind::Chamfer, &[PEG_FRONT], &[2.0], want, true)
}
fn front_curvature_round_r2(k: &mut Kernel) -> Outcome {
let want = PEG_V0 - PEG_FRONT_CURVATURE_R2;
one(k, 0.0, Kind::Curvature, &[PEG_FRONT], &[2.0], want, true)
}
fn front_round_r1_5_then_concave_round_r3(k: &mut Kernel) -> Outcome {
rounds_in_turn(k, 1.5, 3.0, true)
}
@@ -423,7 +418,7 @@ const ROUNDS_R2_HERE: &str = "the rounds together build within the box and check
const ROUNDS_R5_HERE: &str = "the blend corner's Mixed corner (built in solidcore from smlib#82) builds the rounds together within the box";
const CHAMFERS_HERE: &str = "the blend corner's Mixed corner (built in solidcore from smlib#82) builds the chamfers together at the tangent seam";
const TANGENT_END_CASES: [TangentEndCase; 13] = [
const TANGENT_END_CASES: [TangentEndCase; 12] = [
TangentEndCase {
name: "chamfers_together_d2",
run: chamfers_together_d2,
@@ -465,11 +460,6 @@ const TANGENT_END_CASES: [TangentEndCase; 13] = [
run: front_chamfer_d2,
at_cd47efd: PASSES,
},
TangentEndCase {
name: "front_curvature_round_r2",
run: front_curvature_round_r2,
at_cd47efd: PASSES,
},
TangentEndCase {
name: "front_round_r1_5_then_concave_round_r3",
run: front_round_r1_5_then_concave_round_r3,
@@ -73,14 +73,6 @@ use solidcore::topology::face::p2 as face;
use solidcore::topology::{EdgeId, FaceId};
use solidcore::{Brep, Kernel};
/// The G^n section's flag and the one its plane rails need, nothing else.
fn gn_kernel() -> Kernel {
let mut k = Kernel::default();
k.fixes.fillet_gn_section_generator = true;
k.fixes.fillet_surface_plane_curve_on_plane_equation = true;
k
}
/// The kernel SolidCraft runs: every fix on but `geometric_g2_continuity`.
fn solidcraft_kernel() -> Kernel {
let mut k = Kernel::new(&KernelOptions::default());
@@ -159,7 +151,10 @@ fn sharp_wedge(k: &mut Kernel) -> (f64, bool) {
#[test]
fn the_sharp_wedge_takes_off_the_circle_s_area() {
let want = 10.0 * 9.0 * (3f64.sqrt() - PI / 3.0);
for (name, mut k) in [("gn", gn_kernel()), ("solidcraft", solidcraft_kernel())] {
for (name, mut k) in [
("gn", Kernel::default()),
("solidcraft", solidcraft_kernel()),
] {
let (removed, sound) = sharp_wedge(&mut k);
println!("{name}: sharp wedge: removed {removed:.9}, want {want:.9}");
assert!(
@@ -15,13 +15,12 @@
//! curve on no edge (tests 3 and 14)" (with WR-668's `curve_check_zero_speed_tangent_end`,
//! the fork's ecf1963).
//!
//! The fork's "volume 9393.307931047 against the quadrature's 9393.307936313" matches a
//! G2 section whose quintic control points are evenly spaced on the faces (2, 4/3, 2/3
//! from the edge; section area 0.597884, swept and cut at the cylinder as in
//! `fork_856b54e_tangent_end.rs`). solidcore's blend-curve section removes less here:
//! 9395.419893021, about the same with or without this change. That difference is not
//! the rib's, so the volume is checked against the same blend with the rib marched into
//! the tangent end.
//! The curvature-continuous round is the G^n section (WR-685; the executive's blend-curve
//! section, which the fork's cd47efd built and whose rib this case was first written for,
//! went with `fillet_gn_section_generator`: WR-685 addendum 2026-11-06). Its order n takes
//! contact k = n + 2 between the peg's two planes: at n = 2 the end rib is regular in `s`,
//! at n = 3 (k = 5, odd) it is fitted in `t = sqrt(s)` with zero speed at P, as above. The
//! volumes are graded against the quadrature of the section swept and cut at the cylinder.
#![allow(
clippy::unwrap_used,
clippy::expect_used,
@@ -30,7 +29,6 @@
clippy::cast_precision_loss
)] // test helpers
use solidcore::blend::fillet_executive::api::fillet_edges;
use solidcore::blend::fillet_executive::session::FilletSession;
use solidcore::blend::fillet_section::section::{GnSectionFsg, GN_THUMBWEIGHT_EQUAL_AREA};
use solidcore::boolean::api_brep::boolean_union;
use solidcore::curve::curve::{Curve, CurveKind};
@@ -40,7 +38,6 @@ use solidcore::math::{Point3, Vec3};
use solidcore::primitive::api_curves as curves;
use solidcore::query::api_queries::get_edges;
use solidcore::sweep::api_brep::create_linear_sweep;
use solidcore::topology::brep::p5::{stitch_and_orient, StitchAndOrientOptions};
use solidcore::topology::brep::validation::{check_brep, CheckLevel};
use solidcore::topology::{edge, EdgeId};
use solidcore::{Brep, Kernel};
@@ -126,76 +123,6 @@ fn kernel() -> Kernel {
k
}
#[test]
fn g2_front_round_end_rib_has_zero_speed_at_its_tangent_end() {
let mut k = kernel();
let mut b = peg(&mut k);
let e = front_top(&b);
fillet_edges(&mut k, &mut b, &[e], 2.0, 2, 2, 1.0).unwrap();
// the end rib: the B-spline edge at P = (40, 0, 8) climbing the cylinder
let p = Point3::new(40.0, 0.0, 8.0);
let at_p = |q: Point3| q.distance(p) < 1e-6;
let ribs: Vec<EdgeId> = find_edges(&b, |s, t| (at_p(s) || at_p(t)) && s.z.max(t.z) > 9.0)
.into_iter()
.filter(|&e| {
matches!(
b.edge(e).unwrap().curve.as_ref().map(Curve::kind),
Some(CurveKind::BSpline(_))
)
})
.collect();
assert_eq!(ribs.len(), 1, "end ribs at P: {ribs:?}");
let rib = b.edge(ribs[0]).unwrap().curve.clone().unwrap();
let ivl = rib.natural_interval();
let (t0, t1) = (ivl.min(), ivl.max());
let t_p = if rib.evaluate_point(&k, t0).unwrap().distance(p) < 1e-6 {
t0
} else {
t1
};
let d = rib.evaluate(&k, t_p, 2, t_p == t1, false).unwrap();
// zero speed at P (the first two control points coincide), a non-zero second
// derivative along the seam T (z)
assert!(d[1].length() < 1e-9, "speed at P {:?}", d[1]);
let d2 = d[2];
assert!(d2.length() > 1e-3, "second derivative at P {d2:?}");
let off_t = (d2.x * d2.x + d2.y * d2.y).sqrt() / d2.length();
assert!(off_t < 1e-9, "second derivative off T: {d2:?}");
// SMLib's check passes (tests 3 and 14 on the zero-speed end with WR-668)
let lines = check_brep(&mut k, &mut b, CheckLevel::Level2)
.unwrap()
.lines();
assert!(lines.is_empty(), "{lines:#?}");
let v = volume(&k, &mut b);
// 9395.419893021 here, 9395.419890495 with the rib fitted in s (before cd47efd)
assert!((v - 9395.419893021).abs() < 1e-6, "V {v}");
}
/// The fork's 9393.307931047 (tangency-labs/smlib `cd47efd`) is the G2 round with the
/// blend curve's quintic control points at thirds (the fork-only `SetBlendCurveAtThirds`,
/// `fd3b6a7`, ported as `FilletSession::set_blend_curve_at_thirds`, #1438), which
/// `fillet_edges` never turns on. Built as `fillet_edges` does internally, with the mode
/// on, solidcore measures 9393.307938954; the off path stays pinned above (9395.419893021).
#[test]
fn g2_front_round_at_thirds_matches_the_fork_volume() {
let mut k = kernel();
let mut b = peg(&mut k);
let e = front_top(&b);
{
let mut s = FilletSession::new(&mut k, &mut b).unwrap();
s.set_blend_curve_at_thirds(true);
s.prepare_constant_radius_edges(&mut k, &[e], 2.0, 2, 2, 1.0)
.unwrap();
s.do_fillet(&mut k).unwrap();
}
stitch_and_orient(&mut k, &mut b, &StitchAndOrientOptions::default()).unwrap();
let v = volume(&k, &mut b);
assert!((v - 9393.307931047).abs() < 1e-5, "V {v}");
}
/// Quadrature volume (composite Simpson's rule) of the peg after cutting the order-`n` section
/// `(y(t), d(t))` of radius 2 and thumbweight `w` along the front top edge up to the cylinder
/// `(40 - x)^2 + (8 - y)^2 = 64`.
@@ -232,7 +159,7 @@ fn front_gn_quadrature_volume(n: usize, w: f64) -> f64 {
peg_v - removed
}
/// smlib#78 (`7268cee`, #2250): with `fillet_gn_section_generator` on, between the peg's two
/// smlib#78 (`7268cee`, #2250): with the G^n section (WR-685), between the peg's two
/// perpendicular planes `gn_section_contact_order` gives `k = n + 2`:
/// - at `n = 2` (`k = 4`, even), the end rib at `P = (40, 0, 8)` is regular in `s` along `T`;
/// - at `n = 3` (`k = 5`, odd), the end rib is fitted in `t = sqrt(s)` with zero speed at `P`
@@ -251,7 +178,6 @@ fn g2_and_g3_front_round_gn_section_end_rib_and_quadrature_volumes() {
(3u32, 0.0, 0.0, true),
] {
let mut k = kernel();
k.fixes.fillet_gn_section_generator = true;
let mut b = peg(&mut k);
let e = front_top(&b);
fillet_edges(&mut k, &mut b, &[e], 2.0, 2, cont, w_arg).unwrap();
@@ -1,7 +1,6 @@
//! The SolidCraft fork's tangency-labs/smlib@d305e69 (#2273, smlib#79 step 5): the top edge
//! of #851's arc wall rounded and chamfered into the wall's tip, the knife edge where the
//! wall runs out tangent into the back face, builds (`BandCutsThePart`, aac4288, on
//! `fixes.fillet_gn_section_generator`, WR-696). Near the tip the part is thinner than the
//! wall runs out tangent into the back face, builds (`BandCutsThePart`, aac4288, WR-696). Near the tip the part is thinner than the
//! blend's band, so the blend takes all of the part between its rails there and ends: the
//! part is not cut in two, the tip is blended away.
//!
@@ -15,8 +14,8 @@
//!
//! How this test drives the kernel differs from the capi: the edges are picked as the
//! nearest within 0.1 of the capi's points, and the blend is `fillet_edges` with the
//! neighbouring step 5 tests' fixes (`wr696_band_cuts`, `wr696_fit_sizes`: every fix, with
//! `fillet_gn_section_generator`) and their continuity 2.
//! neighbouring step 5 tests' fixes (`wr696_band_cuts`, `wr696_fit_sizes`: every fix) and
//! their continuity 2.
#![allow(
clippy::unwrap_used,
@@ -44,13 +43,12 @@ use solidcore::topology::face::p2 as face;
use solidcore::topology::EdgeId;
use solidcore::{Brep, Kernel, SolidError};
/// Every fix, with `fillet_gn_section_generator`.
/// Every fix.
fn kernel() -> Kernel {
let mut k = Kernel::default();
let mut fixes = UpstreamFixes::all();
fixes.fillet_gn_section_generator = true;
k.fixes = fixes;
k
Kernel {
fixes: UpstreamFixes::all(),
..Kernel::default()
}
}
fn pick(k: &Kernel, b: &Brep, q: Point3) -> EdgeId {
@@ -9,8 +9,8 @@
//! (degree-7 fits through seven points each side): the order at 1e-9, 1e-7 / mm, 1e-5 / mm^2
//! and 1e-3 / mm^3, and not the next at Continuity Analysis's tolerances.
//!
//! The six order-2 cases run on the port of the fork's 11ea2d9 (#2260,
//! `fillet_gn_section_generator`), under the same grading: the surface against the section
//! The six order-2 cases run on the port of the fork's 11ea2d9 (#2260, WR-685), under the
//! same grading: the surface against the section
//! worked out apart from the kernel in `gn_section`, the volume, the check at level 2 and the
//! order of contact along each seam, which the G^n tests in `wr685_gn_section.rs` leave out.
//!
@@ -793,19 +793,6 @@ fn assert_passes(case: &Case, k: &mut Kernel) {
);
}
/// The fork's mark: "the round's sections are the balls' great circles, not the circles the
/// balls' envelope touches them along: 0.0166 off the cone, volume 11955.6466 against
/// 11956.2224".
fn assert_variable_mark(k: &mut Kernel) {
let g = grade(&named(VARIABLE), k);
println!("{VARIABLE}: {g:?}");
assert!(g.failed.is_none(), "{g:?}");
assert!((g.off - 0.0166).abs() <= 0.0001, "{g:?}");
assert!((g.volume - 11955.6466).abs() <= 1e-4, "{g:?}");
assert_eq!(g.problems.len(), 2, "{g:?}");
assert_eq!(g.seams, [(1, 1), (1, 1)], "{g:?}");
}
#[test]
fn with_solidcraft_s_fixes_the_chords_and_circles_have_the_fork_s_marks() {
for case in running_cases().iter().filter(|c| c.name != VARIABLE) {
@@ -813,18 +800,6 @@ fn with_solidcraft_s_fixes_the_chords_and_circles_have_the_fork_s_marks() {
}
}
/// The mark is the fork's at ea59e9c, the great circles of approximated arcs.
/// `fillet_gn_section_generator` brings the fork's later touch circles and
/// `fillet_exact_arc_sections` its later exact circles (523bc25), tested with those ports
/// (`wr685_variable_round_touch_circle`, `wr708_exact_arc_sections`), so both stay off here.
#[test]
fn with_solidcraft_s_fixes_the_variable_round_has_the_fork_s_mark() {
let mut k = solidcraft_kernel();
k.fixes.fillet_gn_section_generator = false;
k.fixes.fillet_exact_arc_sections = false;
assert_variable_mark(&mut k);
}
#[test]
fn on_the_default_kernel_the_chords_and_circles_pass_but_the_boss_root_s_chord() {
for case in running_cases()
@@ -835,9 +810,13 @@ fn on_the_default_kernel_the_chords_and_circles_pass_but_the_boss_root_s_chord()
}
}
/// The fork's mark at ea59e9c for the variable round was its great circles' ("0.0166 off the
/// cone, volume 11955.6466 against 11956.2224"). Since the G^n section's flag is retired
/// (WR-685 addendum 2026-11-06) every kernel builds its touch circles: the default kernel's
/// round lies on its balls' cone, passes `Level2` and is G1 along both seams.
#[test]
fn on_the_default_kernel_the_variable_round_has_the_fork_s_mark() {
assert_variable_mark(&mut Kernel::default());
fn on_the_default_kernel_the_variable_round_lies_on_its_cone() {
assert_passes(&named(VARIABLE), &mut Kernel::default());
}
/// Upstream traces a chord round a circle: 3.07e-5 off the cone it should lie on, where the
@@ -1060,17 +1039,9 @@ fn boss_g2() -> Case {
}
}
/// The G^n section's flag and the one its plane rails need, nothing else.
fn gn_kernel() -> Kernel {
let mut k = Kernel::default();
k.fixes.fillet_gn_section_generator = true;
k.fixes.fillet_surface_plane_curve_on_plane_equation = true;
k
}
/// Each order-2 case on the G^n section's own flags and with SolidCraft's fixes.
fn assert_order_2(case: &Case) {
assert_passes(case, &mut gn_kernel());
assert_passes(case, &mut Kernel::default());
assert_passes(case, &mut solidcraft_kernel());
}
@@ -1181,12 +1152,11 @@ fn the_box_edge_at_gn_equal_area_default_is_g2_and_at_most_g3_with_its_planes()
assert_order_2(&case);
}
/// `4af4349`: with `fillet_gn_section_generator` on, `variable_round_on_its_cone` lies on the
/// exact cone of its balls' envelope, passes `Level2`, and is G1 along both seams.
/// `4af4349`: `variable_round_on_its_cone` lies on the exact cone of its balls' envelope, passes `Level2`, and is G1 along both seams.
#[test]
fn the_linear_variable_round_lies_on_its_cone_and_is_g1() {
let case = named(VARIABLE);
assert_passes(&case, &mut gn_kernel());
assert_passes(&case, &mut Kernel::default());
assert_passes(&case, &mut solidcraft_kernel());
}
@@ -1315,7 +1285,7 @@ fn holds_case() -> Case {
#[test]
fn the_progressive_cubic_variable_round_lies_on_its_balls_union_and_is_g1() {
let case = holds_case();
assert_passes(&case, &mut gn_kernel());
assert_passes(&case, &mut Kernel::default());
assert_passes(&case, &mut solidcraft_kernel());
}
@@ -1354,10 +1324,11 @@ fn wr711_exact_circles_of_one_arc_count_keep_the_progressive_round_on_its_balls(
);
}
/// `cf1c08b` + `0389af2`: the folded cubic law `[2, 2, 40, 3, 2]` builds folded (far off the
/// union of its balls) when `fillet_gn_section_generator` is off, and is refused when on.
/// `cf1c08b` + `0389af2`: the folded cubic law `[2, 2, 40, 3, 2]` is refused (the great
/// circles built it folded, far off the union of its balls, before the G^n section's flag was
/// retired).
#[test]
fn the_folded_cubic_variable_round_leaves_its_balls_union_without_fix_and_is_refused_with_fix() {
fn the_folded_cubic_variable_round_is_refused() {
let folds_law = [2.0, 2.0, 40.0, 3.0, 2.0];
let folds_curve = greville_cubic_curve(folds_law);
let case = Case {
@@ -1376,19 +1347,6 @@ fn the_folded_cubic_variable_round_leaves_its_balls_union_without_fix_and_is_ref
fitted: true,
size: 1.0,
};
// the fork before its G^n section had upstream's approximated arcs, not 523bc25's exact
// circle (`fillet_exact_arc_sections`, WR-708), which comes after it
let mut k_off = solidcraft_kernel();
k_off.fixes.fillet_gn_section_generator = false;
k_off.fixes.fillet_exact_arc_sections = false;
let g_off = grade(&case, &mut k_off);
assert!(g_off.failed.is_none(), "{g_off:?}");
assert!(
g_off.off > 1.0,
"expected folded surface far off balls union: {g_off:?}"
);
assert!(!g_off.problems.is_empty(), "{g_off:?}");
let g_on = grade(&case, &mut solidcraft_kernel());
assert!(
g_on.failed.is_some(),
@@ -12,6 +12,7 @@
#![allow(clippy::unwrap_used, clippy::expect_used, clippy::indexing_slicing)] // test helpers
use solidcore::blend::fillet_executive::session::FilletSession;
use solidcore::blend::fillet_section::section::GN_DEFAULT_THUMBWEIGHT;
use solidcore::geom::attribute::{AttributeStore, ObjectKey};
use solidcore::geom::global_solver::{SolutionRequested, SolverOperation};
use solidcore::geom::vector2d::Point2;
@@ -41,7 +42,8 @@ struct Spec {
ease: Option<f64>,
/// Every edge rounded and every corner set back and eased, else the three at `CORNER`.
all: bool,
/// The curvature-continuous blend (`G2` blend curve at thirds), else the round.
/// The curvature-continuous blend (the order-2 G^n section at its default, equal area
/// thumbweight), else the round.
g2_blend: bool,
}
@@ -73,13 +75,12 @@ fn build(spec: Spec) -> (Kernel, Brep, Vec<FaceId>) {
{
let mut s = FilletSession::new(&mut k, &mut b).unwrap();
s.set_mark_corner_patches(true);
let (xsect, continuity) = if spec.g2_blend {
s.set_blend_curve_at_thirds(true);
(2, 2)
let (xsect, continuity, w) = if spec.g2_blend {
(2, 2, GN_DEFAULT_THUMBWEIGHT)
} else {
(1, 1)
(1, 1, 1.0)
};
s.prepare_constant_radius_edges(&mut k, &edges, 8.0, xsect, continuity, 1.0)
s.prepare_constant_radius_edges(&mut k, &edges, 8.0, xsect, continuity, w)
.unwrap();
// the corners set back (`AddSetBackVertex`): no Ball is built there
let set_back: Vec<_> = s
@@ -1,142 +0,0 @@
//! tangency-labs/solidcore#1438: `FilletSession::set_blend_curve_at_thirds` (the fork's
//! `SmFilletExecutive::SetBlendCurveAtThirds`, tangency-labs/smlib `fd3b6a7`). A G2
//! (`SM_FSG_BLEND_CURVE`, continuity 2) round r = 2 of one edge of a 30 x 20 x 10 box.
//! With the option each section is the quintic whose control points sit at 0, 1/3 and
//! 2/3 of the way from each contact to the corner, so the body loses exactly that
//! section's area to the corner times the edge length. Off (the default), the sections
//! are the pinned C++'s faired Hermite and the volume differs.
#![allow(clippy::unwrap_used, clippy::indexing_slicing)] // test helpers
use solidcore::blend::fillet_executive::session::FilletSession;
use solidcore::blend::fillet_solver::p1::FilletSurfaceGeneratorType;
use solidcore::geom::attribute::{AttributeStore, ObjectKey};
use solidcore::mass::integrator::properties::{brep_volume, PropertyAttributes};
use solidcore::math::Point3;
use solidcore::primitive::api_primitives::create_box;
use solidcore::topology::brep::p5::{stitch_and_orient, StitchAndOrientOptions};
use solidcore::topology::{edge, vertex, Brep, EdgeId};
use solidcore::Kernel;
const R: f64 = 2.0;
const L: f64 = 30.0;
/// The box's top front edge, along X at y = 0, z = 10.
fn top_front_edge(b: &Brep) -> EdgeId {
let found: Vec<_> = b
.edges()
.ids()
.filter(|&e| {
let (s, t) = edge::start_end_vertices(b, e).unwrap();
let (p, q) = (
vertex::point(b, s.unwrap()).unwrap(),
vertex::point(b, t.unwrap()).unwrap(),
);
p.y.abs() < 1e-9 && q.y.abs() < 1e-9 && p.z == 10.0 && q.z == 10.0
})
.collect();
assert_eq!(found.len(), 1);
found[0]
}
fn volume(k: &Kernel, b: &mut Brep) -> f64 {
let store = AttributeStore::default();
let attrs = PropertyAttributes {
store: &store,
key_of: &|_| ObjectKey(0),
};
brep_volume(k, b, 1e-9, &attrs).unwrap()
}
/// The box with its top front edge rounded G2, sections at thirds or not.
fn rounded(at_thirds: Option<bool>) -> f64 {
let mut k = Kernel::default();
let mut b = create_box(&mut k, Point3::new(0.0, 0.0, 0.0), L, 20.0, 10.0).unwrap();
let e = top_front_edge(&b);
{
let mut s = FilletSession::new(&mut k, &mut b).unwrap();
if let Some(on) = at_thirds {
s.set_blend_curve_at_thirds(on);
}
s.prepare_per_edge_constant_radius(
&mut k,
&[e],
&[R],
&[FilletSurfaceGeneratorType::BlendCurve],
2,
1.0,
)
.unwrap();
s.create_corners(&k, None).unwrap();
s.do_filleting(&mut k, None).unwrap();
}
stitch_and_orient(&mut k, &mut b, &StitchAndOrientOptions::default()).unwrap();
volume(&k, &mut b)
}
/// The area between the corner (the origin) and the quintic Bezier from (1, 0) to
/// (0, 1) with control points at thirds along each side: ½∮(x dy − y dx), which is zero
/// along the two sides through the corner, by 8-point Gauss–Legendre (exact for the
/// degree 9 integrand).
fn quintic_area_to_corner() -> f64 {
let p = [
(1.0, 0.0),
(2.0 / 3.0, 0.0),
(1.0 / 3.0, 0.0),
(0.0, 1.0 / 3.0),
(0.0, 2.0 / 3.0),
(0.0, 1.0),
];
let binom = [1.0, 5.0, 10.0, 10.0, 5.0, 1.0];
let eval = |t: f64| {
let (mut x, mut y, mut dx, mut dy) = (0.0, 0.0, 0.0, 0.0);
for i in 0..6 {
let b = binom[i] * t.powi(i as i32) * (1.0 - t).powi(5 - i as i32);
let db = binom[i]
* (if i > 0 {
i as f64 * t.powi(i as i32 - 1) * (1.0 - t).powi(5 - i as i32)
} else {
0.0
} - if i < 5 {
(5 - i) as f64 * t.powi(i as i32) * (1.0 - t).powi(4 - i as i32)
} else {
0.0
});
x += b * p[i].0;
y += b * p[i].1;
dx += db * p[i].0;
dy += db * p[i].1;
}
x * dy - y * dx
};
let nodes = [
(0.183_434_642_495_649_8, 0.362_683_783_378_362_0),
(0.525_532_409_916_329_0, 0.313_706_645_877_887_3),
(0.796_666_477_413_626_7, 0.222_381_034_453_374_5),
(0.960_289_856_497_536_3, 0.101_228_536_290_376_3),
];
let mut integral = 0.0;
for (x, w) in nodes {
for s in [-x, x] {
integral += w * eval(0.5 * (s + 1.0)) * 0.5;
}
}
0.5 * integral
}
#[test]
fn g2_sections_at_thirds_remove_the_quintic_area() {
let full = L * 20.0 * 10.0;
let expected = full - quintic_area_to_corner() * R * R * L;
let v = rounded(Some(true));
assert!((v - expected).abs() < 1e-9 * full, "{v} vs {expected}");
}
#[test]
fn off_by_default_and_off_keeps_the_faired_hermite() {
let full = L * 20.0 * 10.0;
let at_thirds = full - quintic_area_to_corner() * R * R * L;
let default = rounded(None);
let off = rounded(Some(false));
assert_eq!(default.to_bits(), off.to_bits());
assert!((off - at_thirds).abs() > 1e-3, "{off} vs {at_thirds}");
}
@@ -146,7 +146,6 @@ fn solidcraft_fixes() -> UpstreamFixes {
f.offset_stitch_at_body_tolerance = true;
f.curve_contacts_at_curve_ends = true;
f.shell_empty_cavity_fails = true;
f.fillet_refuse_ball_not_fitting = true;
f.boolean_lists_virtual_surface_copies = true;
f.ssi_tangent_contact_points = true;
f.ssi_trace_tangent_curves_once = true;
@@ -373,7 +373,6 @@ fn solidcraft_fixes() -> UpstreamFixes {
f.offset_stitch_at_body_tolerance = true;
f.curve_contacts_at_curve_ends = true;
f.shell_empty_cavity_fails = true;
f.fillet_refuse_ball_not_fitting = true;
f.boolean_lists_virtual_surface_copies = true;
f.ssi_tangent_contact_points = true;
f.ssi_trace_tangent_curves_once = true;
@@ -162,7 +162,6 @@ fn sc_fixes(k: &mut Kernel) {
k.fixes.offset_stitch_at_body_tolerance = true;
k.fixes.curve_contacts_at_curve_ends = true;
k.fixes.shell_empty_cavity_fails = true;
k.fixes.fillet_refuse_ball_not_fitting = true;
k.fixes.fillet_trace_reaches_rails = true;
k.fixes.fillet_rail_end_on_continued_surface = true;
k.fixes.boolean_lists_virtual_surface_copies = true;
@@ -264,7 +263,6 @@ fn run_memo(nd_fix: bool, memo: Option<bool>) -> (usize, usize, usize, f64, Vec<
);
{
let mut s = FilletSession::new(&mut k, &mut b).unwrap();
s.set_blend_curve_at_thirds(false);
s.prepare_per_edge_constant_radius(
&mut k,
&[top, section],
@@ -148,7 +148,6 @@ fn solidcraft_fixes() -> UpstreamFixes {
f.offset_stitch_at_body_tolerance = true;
f.curve_contacts_at_curve_ends = true;
f.shell_empty_cavity_fails = true;
f.fillet_refuse_ball_not_fitting = true;
f.boolean_lists_virtual_surface_copies = true;
f.ssi_tangent_contact_points = true;
f.ssi_trace_tangent_curves_once = true;
@@ -270,7 +270,6 @@ fn solidcraft_flags(k: &mut Kernel) {
k.fixes.fillet_rail_end_on_continued_surface = true;
k.fixes.fillet_rail_rim_on_face = true;
k.fixes.fillet_rails_meet_at_one_end_point = true;
k.fixes.fillet_refuse_ball_not_fitting = true;
k.fixes.fillet_refuse_crossing_rails = true;
k.fixes.fillet_refuse_face_consuming_blends = true;
k.fixes.fillet_refuse_non_manifold_result = true;
@@ -162,7 +162,6 @@ use solidcore::topology::edgeuse::p1 as eu1;
/// The section generator and rounds (and chamfers) as their definitions.
fn definition_kernel() -> Kernel {
let mut k = Kernel::default();
k.fixes.fillet_gn_section_generator = true;
k.fixes.fillet_round_as_definition = true;
k
}
@@ -88,7 +88,6 @@ fn round(k: &mut Kernel, b: &mut Brep, points: &[[f64; 3]], r: f64) -> i32 {
let edges = pick(k, b, points);
let code = {
let mut s = FilletSession::new(k, b).unwrap();
s.set_blend_curve_at_thirds(false);
s.prepare_per_edge_constant_radius(
k,
&edges,
@@ -23,6 +23,7 @@ use std::thread;
use std::time::Duration;
use solidcore::blend::fillet_executive::api::fillet_edges;
use solidcore::blend::fillet_section::section::GN_DEFAULT_THUMBWEIGHT;
use solidcore::boolean::api_brep::boolean_difference;
use solidcore::geom::attribute::{AttributeStore, ObjectKey};
use solidcore::geom::global_solver::{
@@ -243,7 +244,15 @@ fn fillet_g2_traced_corner_parity_and_cancellation() {
let mut setup_copy = Kernel::default();
let mut body = copy_brep(&mut setup_copy, &box_template, 1);
let target_edges = corner_edges_at(&body, Point3::new(0.0, 0.0, 10.0));
fillet_edges(k, &mut body, &target_edges, 1.5, 2, 2, 1.0)?;
fillet_edges(
k,
&mut body,
&target_edges,
1.5,
2,
2,
GN_DEFAULT_THUMBWEIGHT,
)?;
Ok(fingerprint_brep(&mut body))
});
}
@@ -588,7 +597,15 @@ fn worker_thread_and_group_cancel_in_flight_via_cancel_token() {
let mut sc = Kernel::default();
let mut body = copy_brep(&mut sc, &box_w2, 1);
let target_edges = corner_edges_at(&body, Point3::new(0.0, 0.0, 10.0));
fillet_edges(&mut k, &mut body, &target_edges, 1.5, 2, 2, 1.0)?;
fillet_edges(
&mut k,
&mut body,
&target_edges,
1.5,
2,
2,
GN_DEFAULT_THUMBWEIGHT,
)?;
}
});
@@ -1,5 +1,5 @@
//! The #2252 pipe-on-plate G2 round (r 2, order 2, w 0) by WR-685's G^n section
//! (`fillet_gn_section_generator`) on SolidCraft's flag profile (tangency-labs/solidcraft#8526
//! The #2252 pipe-on-plate G2 round (r 2, order 2, w 0) by WR-685's G^n section on
//! SolidCraft's flag profile (tangency-labs/solidcraft#8526
//! at c494a18, `crates/smlib/src/core.rs` `fixes()`, 292 flags), reported on #2260.
//!
//! With `query_statuses_pass_on` (tangency-labs/smlib 8311f8e) `sm_RefineCCSolutions`
@@ -120,7 +120,6 @@ const SOLIDCRAFT_C494A18: &[&str] = &[
"face_tight_box_searches_trim",
"fillet_3x2_mixed_concave_side_edge",
"fillet_3x2_tangent_side_edge_roles",
"fillet_blend_curve_revolved_on_arc",
"fillet_chamfer_cone_on_arc",
"fillet_chamfer_cone_stored_as_cone",
"fillet_cleanup_keeps_target_faces",
@@ -128,7 +127,6 @@ const SOLIDCRAFT_C494A18: &[&str] = &[
"fillet_cliff_overflow",
"fillet_corner_ball_center_from_axes",
"fillet_corner_ball_patch",
"fillet_corner_face_curve_halves",
"fillet_corner_per_vertex_fan",
"fillet_corner_sphere_from_four_arcs",
"fillet_corner_variable_radius_rail_on_opposite_fillet",
@@ -147,7 +145,6 @@ const SOLIDCRAFT_C494A18: &[&str] = &[
"fillet_rail_rim_on_face",
"fillet_rails_meet_at_one_end_point",
"fillet_rail_trim_at_near_knot",
"fillet_refuse_ball_not_fitting",
"fillet_refuse_crossing_rails",
"fillet_refuse_face_consuming_blends",
"fillet_refuse_non_manifold_result",
@@ -312,8 +309,6 @@ fn kernel(names: &[&str]) -> Kernel {
.flag_mut(name)
.unwrap_or_else(|| panic!("no flag {name}")) = true;
}
k.fixes.fillet_gn_section_generator = true;
k.fixes.fillet_surface_plane_curve_on_plane_equation = true;
k
}
@@ -244,7 +244,6 @@ fn closed_angle_is_the_blend_corners_mitred_turn() {
#[ignore = "#2404: the fold refusal names its closed bound 1.875 (less rounding), where the round does not build"]
fn closed_angle_round_builds_validly_or_refuses_with_a_fit_size() {
let mut k = Kernel::default();
k.fixes.fillet_gn_section_generator = true;
let mut b = teardrop(&mut k);
let rim = top_rim(&k, &b);
let mut s = FilletSession::new(&mut k, &mut b).unwrap();
@@ -53,7 +53,6 @@ fn fixture(curved: bool) -> (Kernel, ProceduralBlend) {
fn fixture_order(curved: bool, order: u32) -> (Kernel, ProceduralBlend) {
let mut k = Kernel::default();
k.fixes.fillet_gn_section_generator = true;
k.fixes.fillet_round_as_definition = true;
let wall = Surface::from(
BSplineSurface::create_bilinear_surface(
@@ -1,9 +1,8 @@
//! #2371: the G^n section round (`fixes.fillet_gn_section_generator`, the curvature
//! fillet) polls the kernel's [`CancelToken`] (#2136) in the loops it spends its time in:
//! #2371: the G^n section round (the curvature fillet, WR-685) polls the kernel's [`CancelToken`] (#2136) in the loops it spends its time in:
//! the stations, the certificate's spans, pieces and Krawczyk steps, and the skin.
//!
//! - A token that never fires leaves every result bit for bit as without one (the
//! volume, every vertex and the faces' points), with the flag on and off.
//! volume, every vertex and the faces' points).
//! - A token fired before the call, or from another thread while the boss root's
//! order-2 round certifies its spans (4 min uncancelled in the difftest profile, a
//! 227-span certificate), turns the call into `Err(Cancelled)`, never `Ok`, and the call
@@ -36,14 +35,6 @@ use solidcore::topology::face::p2 as face;
use solidcore::topology::{vertex, EdgeId, FaceId};
use solidcore::{Brep, CancelToken, Kernel, Result};
/// The G^n section's flag and the one its plane rails need (as `fork_ea59e9c_section_orders`).
fn gn_kernel(gn: bool) -> Kernel {
let mut k = Kernel::default();
k.fixes.fillet_gn_section_generator = gn;
k.fixes.fillet_surface_plane_curve_on_plane_equation = true;
k
}
fn box_40_30_20(k: &mut Kernel) -> Result<Brep> {
create_box(k, Point3::new(0.0, 0.0, 0.0), 40.0, 30.0, 20.0)
}
@@ -129,14 +120,13 @@ const ROUND: Blend = (1, 1, 1.0);
/// The case's model, built without a token, and its blend's result with `token`.
fn round(
gn: bool,
build: Build,
at: [f64; 3],
r: f64,
blend: Blend,
token: Option<CancelToken>,
) -> (Kernel, Brep, Result<()>) {
let mut k = gn_kernel(gn);
let mut k = Kernel::default();
let mut b = build(&mut k).unwrap();
let e = pick(&k, &b, at);
if let Some(t) = token {
@@ -153,21 +143,17 @@ fn is_cancelled(r: &Result<()>) -> bool {
/// Without a token and with one that never fires: the same status, and for a built blend
/// the same result, bit for bit.
fn assert_unfired_is_identical(gn: bool, build: Build, at: [f64; 3], r: f64, blend: Blend) {
let (k0, mut b0, made0) = round(gn, build, at, r, blend, None);
let (k1, mut b1, made1) = round(gn, build, at, r, blend, Some(CancelToken::new()));
fn assert_unfired_is_identical(build: Build, at: [f64; 3], r: f64, blend: Blend) {
let (k0, mut b0, made0) = round(build, at, r, blend, None);
let (k1, mut b1, made1) = round(build, at, r, blend, Some(CancelToken::new()));
assert_eq!(made0, made1, "the statuses differ");
if std::env::var_os("ISSUE_2371_PRINT").is_some() {
eprintln!("ISSUE_2371 gn={gn} at={at:?} blend={blend:?} status={made0:?}");
}
if made0.is_err() {
// the blend curve at continuity 2 without the G^n generator: refused alike
assert!(!gn, "the G^n round failed: {made0:?}");
return;
eprintln!("ISSUE_2371 at={at:?} blend={blend:?} status={made0:?}");
}
made0.expect("the round builds");
let (f0, f1) = (fingerprint(&k0, &mut b0), fingerprint(&k1, &mut b1));
if std::env::var_os("ISSUE_2371_PRINT").is_some() {
eprintln!("ISSUE_2371 gn={gn} at={at:?} blend={blend:?} bits={f0:x?}");
eprintln!("ISSUE_2371 at={at:?} blend={blend:?} bits={f0:x?}");
}
assert_eq!(f0, f1, "an unfired token changed the result");
}
@@ -175,31 +161,25 @@ fn assert_unfired_is_identical(gn: bool, build: Build, at: [f64; 3], r: f64, ble
#[test]
fn an_unfired_token_leaves_the_box_edge_rounds_bit_for_bit() {
let edge = [20.0, 30.0, 20.0];
for gn in [true, false] {
for blend in [GN2, GN3, ROUND] {
assert_unfired_is_identical(gn, box_40_30_20, edge, 3.0, blend);
}
for blend in [GN2, GN3, ROUND] {
assert_unfired_is_identical(box_40_30_20, edge, 3.0, blend);
}
}
#[test]
fn an_unfired_token_leaves_the_pipe_root_rounds_bit_for_bit() {
let edge = [30.0, 28.0, 10.0];
for gn in [true, false] {
for blend in [GN2, ROUND] {
assert_unfired_is_identical(gn, pipe_on_plate, edge, 2.0, blend);
}
for blend in [GN2, ROUND] {
assert_unfired_is_identical(pipe_on_plate, edge, 2.0, blend);
}
}
#[test]
fn a_token_fired_before_the_call_cancels_the_gn_round() {
for gn in [true, false] {
let token = CancelToken::new();
token.cancel();
let (_, _, made) = round(gn, box_40_30_20, [20.0, 30.0, 20.0], 3.0, GN2, Some(token));
assert!(is_cancelled(&made), "gn={gn}: {made:?}");
}
let token = CancelToken::new();
token.cancel();
let (_, _, made) = round(box_40_30_20, [20.0, 30.0, 20.0], 3.0, GN2, Some(token));
assert!(is_cancelled(&made), "{made:?}");
}
/// The boss root's order-2 round, cancelled from another thread `delay` into the call:
@@ -210,7 +190,7 @@ fn cancel_boss_root_after(
delay: std::time::Duration,
) -> Option<(std::time::Duration, &'static str)> {
use std::time::Instant;
let mut k = gn_kernel(true);
let mut k = Kernel::default();
let mut b = boss_on_plate(&mut k).unwrap();
let e = pick(&k, &b, BOSS_ROOT);
let token = CancelToken::new();
+17 -40
View File
@@ -1,6 +1,6 @@
//! #2401 (carried over from tangency-labs/smlib#91; the generic blend, hub #2243): the
//! refusals that had no size through the fit name the largest size that builds, each decided
//! from its own geometry, with `fixes.fillet_gn_section_generator` (WR-685/WR-696):
//! from its own geometry (WR-685/WR-696):
//!
//! - **An open end of an overflow** (`CutFilletAtOpenEnd`'s refusals, and a blend the trim
//! keeps no length of where no corner takes any): the overflow is absent below the size at
@@ -40,13 +40,12 @@ use solidcore::topology::brep::validation::{check_brep, CheckLevel};
use solidcore::topology::{edge, EdgeId};
use solidcore::{Brep, Kernel, SolidError};
/// SolidCraft's set of fixes, `fillet_gn_section_generator` as given.
fn kernel(gn: bool) -> Kernel {
let mut k = Kernel::default();
let mut fixes = UpstreamFixes::all();
fixes.fillet_gn_section_generator = gn;
k.fixes = fixes;
k
/// SolidCraft's set of fixes.
fn kernel() -> Kernel {
Kernel {
fixes: UpstreamFixes::all(),
..Kernel::default()
}
}
fn pick(k: &Kernel, b: &Brep, q: Point3) -> EdgeId {
@@ -173,7 +172,7 @@ const TOP_EDGE: Point3 = Point3::new(10.0, 9.0, 30.0);
#[test]
fn an_overflow_past_a_cylindrical_end_names_where_it_stays_on_its_faces() {
for r in [12.0, 10.01] {
let mut k = kernel(true);
let mut k = kernel();
let mut b = arc_ended_box(&mut k);
let m = margin(&k, &b, TOP_EDGE);
let got = blend(&mut k, &mut b, &[TOP_EDGE], r, 1);
@@ -187,7 +186,7 @@ fn an_overflow_past_a_cylindrical_end_names_where_it_stays_on_its_faces() {
/// is 3.5e-4 off).
#[test]
fn an_overflow_past_a_cylindrical_end_builds_at_its_named_size() {
let mut k = kernel(true);
let mut k = kernel();
let mut b = arc_ended_box(&mut k);
let fit = 10.0 - margin(&k, &b, TOP_EDGE);
blend(&mut k, &mut b, &[TOP_EDGE], fit, 1).unwrap();
@@ -222,7 +221,7 @@ fn chamfered_top_volume(w: f64, h: f64, d: f64) -> f64 {
#[test]
fn chamfers_taking_a_square_top_name_its_depth() {
for d in [5.0, 5.01] {
let mut k = kernel(true);
let mut k = kernel();
let mut b = create_box(&mut k, Point3::ZERO, 10.0, 10.0, 10.0).unwrap();
let m = margin(&k, &b, top_edges(10.0, 10.0)[0]);
let got = blend(&mut k, &mut b, &top_edges(10.0, 10.0), d, 0);
@@ -233,7 +232,7 @@ fn chamfers_taking_a_square_top_name_its_depth() {
/// The named size builds: the fork's closed form, `100 d - d (100 + s^2 + 10 s) / 3` off.
#[test]
fn chamfers_taking_a_square_top_build_at_the_named_size() {
let mut k = kernel(true);
let mut k = kernel();
let mut b = create_box(&mut k, Point3::ZERO, 10.0, 10.0, 10.0).unwrap();
let fit = 5.0 - margin(&k, &b, top_edges(10.0, 10.0)[0]);
blend(&mut k, &mut b, &top_edges(10.0, 10.0), fit, 0).unwrap();
@@ -246,12 +245,12 @@ fn chamfers_taking_a_square_top_build_at_the_named_size() {
/// margin, and that builds.
#[test]
fn chamfers_taking_a_rectangular_top_name_its_depth_and_build_there() {
let mut k = kernel(true);
let mut k = kernel();
let mut b = create_box(&mut k, Point3::ZERO, 10.0, 6.0, 10.0).unwrap();
let m = margin(&k, &b, top_edges(10.0, 6.0)[0]);
let got = blend(&mut k, &mut b, &top_edges(10.0, 6.0), 3.5, 0);
let fit = assert_refused(got, NoRoomReason::FaceConsumed, 3.0 - m);
let mut k = kernel(true);
let mut k = kernel();
let mut b = create_box(&mut k, Point3::ZERO, 10.0, 6.0, 10.0).unwrap();
blend(&mut k, &mut b, &top_edges(10.0, 6.0), fit, 0).unwrap();
assert_one_sound_solid(&mut k, &mut b, chamfered_top_volume(10.0, 6.0, fit), 1e-9);
@@ -293,7 +292,7 @@ const MIDDLE: Point3 = Point3::new(41.17486688363082, -20.413218067968561, 9.415
/// margin (open: below 2 the round's offset is a cylinder again).
#[test]
fn the_middle_edge_at_its_round_s_radius_is_refused_as_a_collapsed_offset() {
let mut k = kernel(true);
let mut k = kernel();
let mut b = arc_wall_plate_rounded(&mut k);
let m = margin(&k, &b, MIDDLE);
let got = blend(&mut k, &mut b, &[MIDDLE], 2.0, 1);
@@ -304,7 +303,7 @@ fn the_middle_edge_at_its_round_s_radius_is_refused_as_a_collapsed_offset() {
/// round's radius, which closed would be 2 itself, refused above; open, 2 less the margin.
#[test]
fn the_middle_edge_past_its_round_s_radius_names_that_radius_open() {
let mut k = kernel(true);
let mut k = kernel();
let mut b = arc_wall_plate_rounded(&mut k);
let m = margin(&k, &b, MIDDLE);
let got = blend(&mut k, &mut b, &[MIDDLE], 2.5, 1);
@@ -319,7 +318,7 @@ fn the_middle_edge_past_its_round_s_radius_names_that_radius_open() {
/// crossing (16/3) less the corner ball's (4 pi / 3).
#[test]
fn the_tray_s_seams_at_their_rounds_radius_build() {
let mut k = kernel(true);
let mut k = kernel();
let mut b = create_box(&mut k, Point3::ZERO, 25.0, 25.0, 10.0).unwrap();
let bottom = [
Point3::new(12.5, 0.0, 0.0),
@@ -354,7 +353,7 @@ fn the_tray_s_seams_at_their_rounds_radius_build() {
/// (1 - pi/4) 25 along 287 or 90, each corner (pi/2) (62.5 - 125/3).
#[test]
fn the_cornered_block_s_rim_at_its_corners_radius_builds() {
let mut k = kernel(true);
let mut k = kernel();
let mut b = create_box(&mut k, Point3::ZERO, 297.0, 100.0, 60.0).unwrap();
let corners = [(0.0, 0.0), (297.0, 0.0), (0.0, 100.0), (297.0, 100.0)]
.map(|(x, y)| Point3::new(x, y, 30.0));
@@ -375,25 +374,3 @@ fn the_cornered_block_s_rim_at_its_corners_radius_builds() {
let removed = 754.0 * 25.0 * (1.0 - PI / 4.0) + 4.0 * (PI / 2.0) * (62.5 - 125.0 / 3.0);
assert_one_sound_solid(&mut k, &mut b, before - removed, 1e-7);
}
// ---- without the flag ------------------------------------------------------------------
/// Without `fillet_gn_section_generator` none of these is sized or judged early: the square
/// top's chamfers fail as before (`SM_ERR`, no refusal), as does the middle edge at r2.
#[test]
fn without_the_flag_the_classes_fail_as_before() {
let mut k = kernel(false);
let mut b = create_box(&mut k, Point3::ZERO, 10.0, 10.0, 10.0).unwrap();
let got = blend(&mut k, &mut b, &top_edges(10.0, 10.0), 5.0, 0);
assert!(
matches!(got, Err(SolidError::Upstream { code: 1001, .. })),
"{got:?}"
);
let mut k = kernel(false);
let mut b = arc_wall_plate_rounded(&mut k);
let got = blend(&mut k, &mut b, &[MIDDLE], 2.0, 1);
assert!(
matches!(got, Err(SolidError::Upstream { code: 1001, .. })),
"{got:?}"
);
}
@@ -288,8 +288,6 @@ fn cases() -> Vec<Case> {
// #2388's own fix set: the offset of this body with every fix on is refused
// (`offset_brep`, status 1001)
let mut k = Kernel::new(&KernelOptions::default());
k.fixes.fillet_gn_section_generator = true;
k.fixes.fillet_surface_plane_curve_on_plane_equation = true;
k.fixes.fillet_round_as_definition = true;
k.blend_face_log = Some(BlendFaceLog::default());
let mut b = chamfered_box(&mut k);
@@ -98,7 +98,6 @@ fn kernel(on: bool) -> Kernel {
memoize_curve_caches: on,
..Kernel::default()
};
k.fixes.fillet_gn_section_generator = true;
k.fixes.fillet_round_as_definition = true;
k
}
@@ -1,8 +1,10 @@
//! #2704: with `fillet_gn_section_generator` alone, a variable box round failed at one end
//! ("failure to calculate intersection of fillet surface with side face", 1001) for laws such
//! as 4 to 0, 2 to 0, 4 to 2, 0.5 to 4 and 8 to 4, and not for 4 to 3 or 0 to 4. The touch
//! circle's section leaves the end face's plane at an end, so the side curve must come from
//! the plane's equation (WR-682), not the plane's domain or the surfaces' domains.
//! #2704: with the G^n section's touch circles alone (the default kernel since its flag,
//! `fillet_gn_section_generator`, was retired: WR-685 addendum 2026-11-06), a variable box
//! round failed at one end ("failure to calculate intersection of fillet surface with side
//! face", 1001) for laws such as 4 to 0, 2 to 0, 4 to 2, 0.5 to 4 and 8 to 4, and not for
//! 4 to 3 or 0 to 4. The touch circle's section leaves the end face's plane at an end, so
//! the side curve must come from the plane's equation (WR-682), not the plane's domain or
//! the surfaces' domains.
#![allow(
clippy::unwrap_used,
clippy::expect_used,
@@ -43,7 +45,6 @@ fn pick(k: &Kernel, b: &Brep, q: Point3) -> EdgeId {
/// to `to` at (10, 20, 30): the volume it removes.
fn removed(from: f64, to: f64) -> f64 {
let mut k = Kernel::default();
k.fixes.fillet_gn_section_generator = true;
let mut b = create_box(&mut k, Point3::ZERO, 10.0, 20.0, 30.0).unwrap();
let e = pick(&k, &b, Point3::new(10.0, 10.0, 30.0));
let ivl = edge::interval(&b, e).unwrap();
@@ -51,7 +51,6 @@ fn nearest(k: &Kernel, b: &Brep, p: Point3) -> EdgeId {
/// A kernel with the chamfer's definition on.
fn kernel() -> Kernel {
let mut k = Kernel::default();
k.fixes.fillet_gn_section_generator = true;
k.fixes.fillet_round_as_definition = true;
k
}
@@ -251,10 +251,8 @@ fn solids_touching_along_an_edge_pair_their_sides() {
#[test]
fn a_g2_round_decides_around_its_volume() {
// the G^n section's flag and the one its plane rails need: the round a bare net
let mut bare = Kernel::default();
bare.fixes.fillet_gn_section_generator = true;
bare.fixes.fillet_surface_plane_curve_on_plane_equation = true;
// the default kernel: the round a bare net
let bare = Kernel::default();
let v = 24000.0 - 40.0 * 9.0 * (1.0 - PI / 4.0);
for (name, mut k, certified) in [
("bare net", bare, false),
@@ -92,7 +92,6 @@ use solidcore::SolidError;
/// The section generator and rounds (and chamfers) as their definitions.
fn definition_kernel() -> Kernel {
let mut k = Kernel::default();
k.fixes.fillet_gn_section_generator = true;
k.fixes.fillet_round_as_definition = true;
k
}
@@ -310,7 +309,9 @@ fn issue_2546_chamfers_within_the_resolution_of_the_rounds_are_refused_naming_th
/// axis, the section through the axis. That is no chamfer of the corner, whether the part
/// resolves the arc or not (just past 5, within the resolution; at 5.1, beyond it, where a
/// body of more volume than at 5 was built). Refused, naming 5, the largest size on the
/// edge's side of the axis, which builds.
/// edge's side of the axis, which builds. The chamfer's regularity (`BallIsRegular`,
/// WR-696) finds it first: the R5 rounds curve tighter than its offset of d, which does not
/// fit them (`BallDoesNotFit`), naming the same 5.
#[test]
fn issue_2546_chamfers_past_the_rounds_radius_are_refused_naming_it() {
for d in [5.0001, 5.0002, 5.1] {
@@ -319,7 +320,7 @@ fn issue_2546_chamfers_past_the_rounds_radius_are_refused_naming_it() {
let SolidError::FilletRefused { reason, fit, .. } = err else {
panic!("d {d}: {err:?}");
};
assert_eq!(reason, Some(NoRoomReason::RailPastAxis), "d {d}");
assert_eq!(reason, Some(NoRoomReason::BallDoesNotFit), "d {d}");
assert_eq!(fit.kind, FitKind::Radius, "d {d}");
assert!((fit.size - 5.0).abs() < 1e-12, "d {d}: {}", fit.size);
}
@@ -14,9 +14,10 @@
//! linear cross section and bevel corners, at the default fixes.
//!
//! One half edge alone (the issue's pick: offsets from setbacks 1 on the cut face and 2
//! down the wall, as the fork's `sides_offsets` derives them) is refused with 1001. The
//! whole chain, both halves in one session, builds a closed solid (4 faces to 6), so a
//! caller chamfers the whole tangent chain.
//! down the wall, as the fork's `sides_offsets` derives them) builds a closed solid with a
//! clean check (4 faces to 7), since the generic blend's sections and checks are the
//! default (WR-685 addendum 2026-11-06); main's default kernel refused it with 1001. The
//! whole chain, both halves in one session, builds a closed solid (4 faces to 6).
#![allow(
clippy::unwrap_used,
clippy::expect_used,
@@ -36,6 +37,7 @@ use solidcore::sweep::api_brep::create_linear_sweep;
use solidcore::topology::brep::p1;
use solidcore::topology::brep::p2::is_manifold_solid;
use solidcore::topology::brep::p5::{stitch_and_orient, transform, StitchAndOrientOptions};
use solidcore::topology::brep::validation::{check_brep, CheckLevel};
use solidcore::topology::{edge, EdgeId, EdgeuseId};
use solidcore::{Brep, Kernel};
@@ -155,3 +157,20 @@ fn issue_880_whole_rim_chamfers() {
);
}
}
/// The issue's own pick: one rim half chamfered by the offsets of setbacks 1 on the cut face
/// and 2 down the wall builds a closed solid (4 faces to 7) that SMLib's check passes.
#[test]
fn issue_880_one_half_chamfers() {
let mut k = Kernel::default();
let mut b = cut_cylinder(&mut k);
let before = p1::faces(&b, None).unwrap().len();
let e = rims(&k, &b)[0];
let u = edge::blend_edgeuse(&k, &mut b, e).unwrap().unwrap();
chamfer(&mut k, &mut b, &[(e, u)], (1.0, 2.0)).unwrap();
assert_eq!(finish(&mut k, &mut b, before), (4, 7, true));
let lines = check_brep(&mut k, &mut b, CheckLevel::Level2)
.unwrap()
.lines();
assert!(lines.is_empty(), "{lines:?}");
}
@@ -1,18 +1,18 @@
//! tangency-labs/solidcore#919 (WR-581): a blend-curve (G2 or G1) round on an R10
//! cylinder's rim at the full width 10 fails in SMLib (`SmApiFilletEdges` returns
//! `SM_ERR`, 1001, and leaves the cylinder as it was; at 9.99 it builds). At the full
//! width the fillet's centre line is the single point at the dome's centre on the axis,
//! and `CalcTorusFilletGeom`, which builds the circular round's hemisphere there, takes
//! only circular sections, so the blend is marched along a centre line of no length and
//! `TrimRails` fails. The difftest fixtures
//! `issue919-cylinder-rim-edge{1,2}-blend-curve-g{1,2}-r10.0`
//! (`fixtures/blend.fillet_executive_p3/issue_919_920_full_width.json`) show the pinned
//! C++ failing the same way, bit-identical to the port.
//! tangency-labs/solidcore#919 (WR-581): a curvature-continuous round on an R10 cylinder's
//! rim at the full width 10. SMLib's blend curve fails there (`SmApiFilletEdges` returns
//! `SM_ERR`, 1001, and leaves the cylinder as it was): the fillet's centre line is the single
//! point at the dome's centre on the axis, and `CalcTorusFilletGeom`, which builds the
//! circular round's hemisphere there, takes only circular sections, so the blend is marched
//! along a centre line of no length and `TrimRails` fails (the goldens' cases
//! `issue919-cylinder-rim-edge{1,2}-blend-curve-g{1,2}-r10.0`,
//! `fixtures/blend.fillet_executive_p3/issue_919_920_full_width.json`).
//!
//! With the opt-in `Kernel::fixes.fillet_blend_curve_revolved_on_arc` the blend curve of
//! the section is revolved about the axis there, as the circular section is: the round
//! closes the top as a dome. Every blend whose centre line is not on the axis is marched
//! as before (r 9.99 builds bit-identically with the fix on and off).
//! The executive's curvature-continuous round is the G^n section on every kernel (WR-685;
//! its flag, `fillet_gn_section_generator`, is retired: WR-685 addendum 2026-11-06), and
//! WR-581's revolved blend curve went with the blend curve it revolved
//! (`fillet_blend_curve_revolved_on_arc`, WR-581 addendum 2026-11-07). The G^n section is
//! marched, so the full-width round is refused as the blend curve was, the cylinder as it
//! was; and it takes orders 2 to 4 only, so a G1 request is invalid input.
#![allow(
clippy::unwrap_used,
clippy::expect_used,
@@ -21,15 +21,11 @@
)] // test helpers
use solidcore::blend::fillet_executive::api::fillet_edges;
use solidcore::error::SM_ERR;
use solidcore::geom::attribute::{AttributeStore, ObjectKey};
use solidcore::geom::vector2d::Point2;
use solidcore::mass::integrator::properties::{brep_volume, PropertyAttributes};
use solidcore::blend::fillet_section::section::GN_DEFAULT_THUMBWEIGHT;
use solidcore::error::{SM_ERR, SM_ERR_INVALID_INPUT};
use solidcore::math::Point3;
use solidcore::primitive::api_primitives::create_cylinder;
use solidcore::surface::surface::{Surface, SurfaceKind};
use solidcore::topology::brep::p2::is_manifold_solid;
use solidcore::topology::brep::validation::{check_brep, CheckLevel};
use solidcore::surface::surface::SurfaceKind;
use solidcore::topology::edge;
use solidcore::{Brep, Kernel, SolidError};
@@ -40,10 +36,10 @@ const H: f64 = 20.0;
const BLEND_CURVE: u32 = 2;
/// The cylinder of radius 10 and height 20 with its top rim blended by `radius` at
/// `continuity` (1 G1, 2 G2), with the fix `on` or off: the API's result and the body.
fn blended(radius: f64, continuity: u32, on: bool) -> (Kernel, Result<(), SolidError>, Brep) {
/// `continuity` (1 G1, 2 G2) and the G^n section's default thumbweight: the API's result and
/// the body.
fn blended(radius: f64, continuity: u32) -> (Result<(), SolidError>, Brep) {
let mut k = Kernel::default();
k.fixes.fillet_blend_curve_revolved_on_arc = on;
let mut b = create_cylinder(&mut k, Point3::new(0.0, 0.0, 0.0), R, H).unwrap();
let rim = *b
.edge_list()
@@ -55,131 +51,54 @@ fn blended(radius: f64, continuity: u32, on: bool) -> (Kernel, Result<(), SolidE
(p.z - H).abs() < 1e-6 && (p.x.hypot(p.y) - R).abs() < 1e-6
})
.unwrap();
let result = fillet_edges(&mut k, &mut b, &[rim], radius, BLEND_CURVE, continuity, 1.0);
(k, result, b)
}
fn volume(k: &Kernel, b: &mut Brep) -> f64 {
let store = AttributeStore::default();
let attrs = PropertyAttributes {
store: &store,
key_of: &|_| ObjectKey(0),
};
brep_volume(k, b, 1e-6, &attrs).unwrap()
let result = fillet_edges(
&mut k,
&mut b,
&[rim],
radius,
BLEND_CURVE,
continuity,
GN_DEFAULT_THUMBWEIGHT,
);
(result, b)
}
/// The kinds of `b`'s face surfaces, as names.
fn kinds(b: &Brep) -> Vec<&'static str> {
b.face_list()
let mut got: Vec<_> = b
.face_list()
.iter()
.map(
|&f| match b.face(f).unwrap().surface.as_ref().unwrap().kind() {
SurfaceKind::Plane(_) => "plane",
SurfaceKind::Cone(_) => "cylinder",
SurfaceKind::SurfOfRevolution(_) => "revolution",
SurfaceKind::Sphere(_) => "sphere",
SurfaceKind::BSpline(_) => "bspline",
_ => "other",
},
)
.collect()
}
/// The volume of the cylinder under the dome surface `dome`, integrated along its
/// meridian independently of the mass properties: the cylinder up to where the meridian
/// starts, then the discs `pi r(z)^2 dz` up the meridian (trapezoids over 20000 steps).
fn volume_under(k: &Kernel, dome: &Surface) -> f64 {
let d = dome.natural_uv_domain_with_nurb(k).unwrap();
let (lo, hi) = (d.min(), d.max());
let at = |u: f64, v: f64| dome.evaluate_point(k, Point2::new(u, v)).unwrap();
let radius = |p: Point3| p.x.hypot(p.y);
let (mu, mv) = (0.5 * lo.x + 0.5 * hi.x, 0.5 * lo.y + 0.5 * hi.y);
// the meridian runs from the rim (r 10) to the apex (r 0); a parallel keeps its radius
let along_v = (radius(at(mu, lo.y)) - radius(at(mu, hi.y))).abs() > 1.0;
let n: u32 = 20_000;
let pts: Vec<Point3> = (0..=n)
.map(|i| {
let s = f64::from(i) / f64::from(n);
if along_v {
at(mu, lo.y + s * (hi.y - lo.y))
} else {
at(lo.x + s * (hi.x - lo.x), mv)
}
})
.collect();
let pi = std::f64::consts::PI;
let z0 = pts.iter().map(|p| p.z).fold(f64::INFINITY, f64::min);
let mut v = pi * R * R * z0;
for w in pts.windows(2) {
let (ra, rb) = (radius(w[0]), radius(w[1]));
v += pi * 0.5 * (ra * ra + rb * rb) * (w[1].z - w[0].z).abs();
}
v
got.sort_unstable();
got
}
#[test]
fn issue_919_full_width_blend_curve_is_refused_without_the_fix() {
for continuity in [2, 1] {
let (_, result, b) = blended(R, continuity, false);
assert!(
matches!(result, Err(SolidError::Upstream { code, .. }) if code == SM_ERR),
"G{continuity}: {result:?}"
);
// the cylinder as it was: its wall and two caps
let mut got = kinds(&b);
got.sort_unstable();
assert_eq!(got, ["cylinder", "plane", "plane"], "G{continuity}");
}
fn issue_919_full_width_g2_round_is_refused() {
let (result, b) = blended(R, 2);
assert!(
matches!(result, Err(SolidError::Upstream { code, .. }) if code == SM_ERR),
"{result:?}"
);
// the cylinder as it was: its wall and two caps
assert_eq!(kinds(&b), ["cylinder", "plane", "plane"]);
}
#[test]
fn issue_919_full_width_blend_curve_closes_the_top_with_the_fix() {
for continuity in [2, 1] {
let (mut k, result, mut b) = blended(R, continuity, true);
result.unwrap_or_else(|e| panic!("G{continuity}: {e:?}"));
fn issue_919_a_g1_round_is_not_a_gn_section() {
for radius in [R, 9.99] {
let (result, b) = blended(radius, 1);
assert!(
is_manifold_solid(&b).unwrap(),
"G{continuity}: a closed solid"
matches!(result, Err(SolidError::Upstream { code, .. }) if code == SM_ERR_INVALID_INPUT),
"r {radius}: {result:?}"
);
let mut got = kinds(&b);
got.sort_unstable();
assert_eq!(got, ["cylinder", "plane", "revolution"], "G{continuity}");
let dome = b
.face_list()
.iter()
.map(|&f| b.face(f).unwrap().surface.as_ref().unwrap())
.find(|s| matches!(s.kind(), SurfaceKind::SurfOfRevolution(_)))
.unwrap();
let want = volume_under(&k, dome);
let c = check_brep(&mut k, &mut b, CheckLevel::Level2).unwrap();
assert_eq!(c.failure_count(), 0, "G{continuity}: {:?}", c.lines());
let v = volume(&k, &mut b);
// the dome lies between the cone and the cylinder on the top 10
let pi = std::f64::consts::PI;
assert!(
v > pi * R * R * (H - R) + pi * R * R * R / 3.0 && v < pi * R * R * H,
"G{continuity}: {v}"
);
assert!(
(v - want).abs() <= 1e-6 * want,
"G{continuity}: volume {v}, integrated {want}"
);
eprintln!("issue_919 G{continuity}: volume {v}, integrated {want}");
}
}
/// Below the full width the centre line is a circle, not a point on the axis: the blend
/// is marched with the fix on as with it off, bit for bit.
#[test]
fn issue_919_narrower_blend_curve_is_unchanged_by_the_fix() {
for continuity in [2, 1] {
let (k0, r0, mut b0) = blended(9.99, continuity, false);
let (k1, r1, mut b1) = blended(9.99, continuity, true);
r0.unwrap();
r1.unwrap();
assert_eq!(kinds(&b0), kinds(&b1), "G{continuity}");
assert_eq!(b0.edge_list().len(), b1.edge_list().len(), "G{continuity}");
let (v0, v1) = (volume(&k0, &mut b0), volume(&k1, &mut b1));
assert_eq!(v0.to_bits(), v1.to_bits(), "G{continuity}: {v0} vs {v1}");
assert_eq!(kinds(&b), ["cylinder", "plane", "plane"], "r {radius}");
}
}
@@ -24,13 +24,11 @@
"fillet_torus_span_from_start_section",
"fillet_chamfer_cone_on_arc",
"fillet_chamfer_cone_stored_as_cone",
"fillet_blend_curve_revolved_on_arc",
"corner_blend_coons_patch_tangent_to_sides",
"corner_patch_face_side_twist",
"fillet_torus_center_on_axis",
"fillet_torus_rail_on_axis",
"fillet_exact_round_classes",
"fillet_surface_plane_curve_on_plane_equation",
"fillet_patch_keeps_fillet_edges",
"fillet_trim_inside_by_best_dot",
"fillet_knife_edge_rounds",
@@ -38,7 +36,6 @@
"fillet_half_degree_crease",
"offset_excess_faces_after_merge",
"fillet_split_edge_keeps_near_half",
"fillet_corner_face_curve_halves",
"offset_point_vertex_caps",
"offset_clip_right_side_out",
"offset_edges_keep_source_tolerance",
@@ -219,7 +216,6 @@
"offset_stitch_at_body_tolerance",
"curve_contacts_at_curve_ends",
"shell_empty_cavity_fails",
"fillet_refuse_ball_not_fitting",
"fillet_trace_reaches_rails",
"fillet_rail_end_on_continued_surface",
"fillet_cliff_overflow",
@@ -260,7 +256,6 @@
"boolean_coincident_strip_drops_crossing",
"ascii_doubles_round_trip",
"fillet_round_ends_at_tangent_continuation",
"fillet_gn_section_generator",
"fillet_round_as_definition",
"fillet_exact_arc_sections",
"fillet_exact_arc_spans",
@@ -1,8 +1,8 @@
//! #2727: great circles have no corner of a radius law to stop at. The 20 cube's edge rounded
//! by the linear laws 4, 2, 4 and 3, 2, 4, 2, 3 is refused by name on the kernel that sweeps
//! them (the net of the first doubles back on itself, `check_brep` #5; the second's reaches
//! over 140 mm across), and built as the union of the balls with
//! `fixes.fillet_gn_section_generator` (WR-696), which #2936 makes the default.
//! #2727: great circles have no corner of a radius law to stop at (the 20 cube's edge rounded
//! by the linear law 4, 2, 4 built a net that doubles back on itself, `check_brep` #5, and
//! 3, 2, 4, 2, 3 one over 140 mm across). Every kernel now builds a variable round as the union
//! of its balls (WR-696; the flag `fillet_gn_section_generator` and the refusal of the great
//! circles over a law corner are retired with it): each side of a corner is its own piece.
#![allow(
clippy::unwrap_used,
@@ -69,18 +69,6 @@ fn volume(k: &Kernel, b: &mut Brep) -> f64 {
brep_volume(k, b, 1e-7, &attrs).unwrap()
}
#[test]
fn great_circles_over_a_law_corner_are_refused_by_name_and_the_cube_stays() {
for r in [&[4.0, 2.0, 4.0][..], &[3.0, 2.0, 4.0, 2.0, 3.0]] {
let mut k = Kernel::default();
let mut b = create_box(&mut k, Point3::ZERO, 20.0, 20.0, 20.0).unwrap();
let why = round(&mut k, &mut b, r).expect_err("refused");
assert!(why.contains("has a corner inside its edge"), "{why}");
assert_eq!(b.face_list().len(), 6);
assert!((volume(&k, &mut b) - 8000.0).abs() <= 1e-9 * 8000.0);
}
}
/// With the balls' union each side of a corner is its own piece: a sound body with less than
/// the cube's volume and area (the law peaks at 4, so at most the constant round 4 goes:
/// 20 x (1 - pi/4) x 16 = 68.7).
@@ -88,7 +76,6 @@ fn great_circles_over_a_law_corner_are_refused_by_name_and_the_cube_stays() {
fn the_union_of_the_balls_builds_them() {
for r in [&[4.0, 2.0, 4.0][..], &[3.0, 2.0, 4.0, 2.0, 3.0]] {
let mut k = Kernel::default();
k.fixes.fillet_gn_section_generator = true;
let mut b = create_box(&mut k, Point3::ZERO, 20.0, 20.0, 20.0).unwrap();
round(&mut k, &mut b, r).unwrap();
stitch_and_orient(&mut k, &mut b, &StitchAndOrientOptions::default()).unwrap();
@@ -92,11 +92,25 @@ fn variable_round_reach(fix: bool) -> Vec<(f64, [[bool; 2]; 2])> {
out
}
/// The box less the union of the 2 -> 10 round's balls (centred `(r, y, 30 - r)`): the
/// integral along the edge of the area each plane `y` cuts between the rails above the
/// union of the balls' discs (Gauss-Legendre, 16 points in each of 40 panels along the edge
/// and 8 across, the union's top over 20001 balls).
const ENVELOPE_VOLUME: f64 = 5_831.254_415;
/// Traced farther, the round is the same union of balls (WR-685): both within 5.5e-5 of the
/// 168.75 removed, to the approximated arcs' accuracy. The trace's stations differ, so the
/// two skins differ by 1.5e-4 in volume (2.5e-8 relative); before the round was the union
/// of its balls, the great circles' two skins agreed to 5e-6.
#[test]
fn variable_round_traced_farther_comes_out_the_same() {
for fix in [false, true] {
let v = variable_round_volume(fix);
assert!((v - 5822.58649).abs() < 5e-6, "flag {fix}: volume {v}");
eprintln!("flag {fix}: volume {v}");
assert!(
(v - ENVELOPE_VOLUME).abs() < 1e-4 * (6000.0 - ENVELOPE_VOLUME),
"flag {fix}: volume {v}"
);
}
}
@@ -289,33 +289,20 @@ fn variable_round(cliff: bool, r0: f64, r1: f64) -> Outcome {
}
}
/// The box less the variable round's section along the edge, by the midpoint rule (the
/// rolling ball's section across the edge is the circle of the radius there, to the
/// accuracy of the round's cubic sections).
fn variable_round_expected(r0: f64, r1: f64) -> f64 {
let n = 20_000;
let mut removed = 0.0;
for i in 0..n {
let t = (f64::from(i) + 0.5) / f64::from(n);
removed += removed_area(r0 + (r1 - r0) * t, 10.0, 30.0);
}
6000.0 - removed * 20.0 / f64::from(n)
}
#[test]
fn a_variable_round_past_a_box_top_is_subtracted() {
// the fork's 2 -> 11, 20, 30, 50 (5789.69878, 5391.54581, 4819.37775, 3546.18768), from
// either end, to 1e-4 (the variable round's cubic sections' accuracy)
// The round is the union of its balls (WR-685): the fork's d01d7b0 and 58d03ef builds of
// 2 -> 11, 20, 30, 50, the G^n section's touch circles of upstream's approximated arcs,
// as this kernel builds them (`wr685_variable_round_touch_circle`), from either end, to
// the subtraction's 1e-7. Its great circles took off up to 1147 more (2 -> 50: 3546.18768).
for (r1, fork) in [
(11.0, 5789.69878),
(20.0, 5391.54581),
(30.0, 4819.37775),
(50.0, 3546.18768),
(11.0, 5_802.427_752_997_301_5),
(20.0, 5_503.840_689_738_950_5),
(30.0, 5_184.010_536_341_764_2),
(50.0, 4_693.488_044_680_034_4),
] {
let expected = variable_round_expected(2.0, r1);
assert!((expected - fork).abs() < 1e-4, "{r1}: {expected}");
assert_builds(&variable_round(true, 2.0, r1), expected, 1e-4);
assert_builds(&variable_round(true, r1, 2.0), expected, 1e-4);
assert_builds(&variable_round(true, 2.0, r1), fork, 1e-7);
assert_builds(&variable_round(true, r1, 2.0), fork, 1e-7);
}
assert_no_room(&variable_round(false, 2.0, 11.0));
}
@@ -138,23 +138,36 @@ fn round(far_end_only: bool, s: f64, r: f64) -> Result<(usize, f64, bool), i32>
Ok((faces, volume(&k, &mut b), manifold))
}
/// The rounds of the knife edge (r 0.5, 2, 5, each mirrored) with the run-on behind the
/// corner cut off: 7 faces, a manifold solid, and WR-570's closed-form volume to 1e-9
/// relative, as the fork's test asserts them.
/// The round of the knife edge at `r` on side `s` with the run-on behind the corner cut off:
/// 7 faces, a manifold solid, and WR-570's closed-form volume to 1e-9 relative, as the fork's
/// test asserts them.
fn assert_knife_edge_round(r: f64, s: f64) {
let before = (TIP - R) * R * H + R * R * (1.0 - PI / 4.0) * H;
let (faces, v, manifold) = round(true, s, r)
.unwrap_or_else(|code| panic!("r {r}, side {s}: the round failed: {code}"));
let want = before - removed(r);
assert_eq!(faces, 7, "r {r}, side {s}: faces");
assert!(manifold, "r {r}, side {s}: not a manifold solid");
assert!(
(v - want).abs() <= 1e-9 * want,
"r {r}, side {s}: volume {v}, expected {want}"
);
}
/// The rounds of the knife edge (r 0.5, 2, 5, each mirrored) but the mirrored r 2's.
#[test]
fn wr643_knife_edge_rounds_with_the_run_on_past_the_far_end_only() {
let before = (TIP - R) * R * H + R * R * (1.0 - PI / 4.0) * H;
for r in [0.5, 2.0, 5.0] {
for s in [1.0, -1.0] {
let (faces, v, manifold) = round(true, s, r)
.unwrap_or_else(|code| panic!("r {r}, side {s}: the round failed: {code}"));
let want = before - removed(r);
assert_eq!(faces, 7, "r {r}, side {s}: faces");
assert!(manifold, "r {r}, side {s}: not a manifold solid");
assert!(
(v - want).abs() <= 1e-9 * want,
"r {r}, side {s}: volume {v}, expected {want}"
);
}
for (r, s) in [(0.5, 1.0), (0.5, -1.0), (2.0, 1.0), (5.0, 1.0), (5.0, -1.0)] {
assert_knife_edge_round(r, s);
}
}
/// The mirrored r 2 round: since the ball's regularity is judged on every kernel (WR-696,
/// WR-685 addendum 2026-11-06), `BallIsRegular` refuses it as a fold ("touch circles move
/// back", a radius below 1.6875 fits), a straight extruded edge whose sections are all the
/// same; the other side and r 0.5 and 5 on this one build. Known failing, tangency-labs/solidcore#2963.
#[test]
#[ignore = "BallIsRegular refuses it as a fold: tangency-labs/solidcore#2963"]
fn wr643_mirrored_knife_edge_round_r2() {
assert_knife_edge_round(2.0, -1.0);
}
@@ -6,9 +6,13 @@
//! traced points: the round removes the wrong volume and its surface leaves the law's
//! circles.
//!
//! The round of a cube's edge between two perpendicular planes with radius `r(s)` removes
//! `(1 - pi/4) r(s)^2` of each section, so the volume removed is `(1 - pi/4)` times the
//! integral of `r^2` along the edge, in closed form for a polynomial law.
//! The round of a cube's edge between two perpendicular planes is the union of its balls
//! (WR-685; since the G^n section's flag was retired, on every kernel: WR-685 addendum
//! 2026-11-06). Each ball touches the balls' envelope along its touch circle, square to the
//! centre line and moved along it by `-r r'/|c'|`, not along its great circle. The volume
//! removed is the corner less the union of the balls, by quadrature ([`ENVELOPE_REMOVED`]);
//! the great circles' `(1 - pi/4) r(s)^2` per section, integrated along the edge, removes
//! 65.6068, 2.3% more.
#![allow(
clippy::unwrap_used,
@@ -81,9 +85,32 @@ fn law(t: f64) -> f64 {
6.0 * s * s * s + 18.0 * t * s * s + 3.0 * t * t * s + t * t * t
}
/// The largest distance from the round's surface of the law's section points at
/// 45 degrees, `(x, 20 - r + r/sqrt 2, 20 - r + r/sqrt 2)`, `x = 20 t` (taking the
/// law from whichever end of the edge fits it).
/// The law's slope `dr/dt` at `t`.
fn law_slope(t: f64) -> f64 {
let s = 1.0 - t;
// 3 (6 - 6) s^2 + 6 (1 - 6) s t + 3 (1 - 1) t^2
-30.0 * s * t
}
/// The point of the ball at `x = 20 t` on its touch circle in the plane of symmetry
/// `y = z`, on the edge's side: the ball of radius `r` centred `c = (x, 20 - r, 20 - r)`
/// touches the balls' envelope along the circle where `<p - c, c'> = -r r'`
/// (`c' = (1, -r', -r')`, `r' = dr/dx`), of radius `r sqrt(1 - r'^2 / |c'|^2)` about
/// `c - (r r' / |c'|^2) c'`.
fn touch_point(x: f64, r: f64, dr_dx: f64) -> Point3 {
let c = Vec3::new(x, 20.0 - r, 20.0 - r);
let cd = Vec3::new(1.0, -dr_dx, -dr_dx);
let n2 = cd.dot(cd);
let centre = c - cd * (r * dr_dx / n2);
let radius = r * (1.0 - dr_dx * dr_dx / n2).sqrt();
let d = Vec3::new(0.0, 1.0, 1.0);
let d = d - cd * (d.dot(cd) / n2);
let p = centre + d * (radius / d.length());
Point3::new(p.x, p.y, p.z)
}
/// The largest distance from the round's surface of the balls' touch points
/// ([`touch_point`]) at `x = 20 t` (taking the law from whichever end of the edge fits it).
fn surface_off_law(k: &Kernel, b: &Brep) -> f64 {
let rounds: Vec<_> = b
.faces()
@@ -97,9 +124,10 @@ fn surface_off_law(k: &Kernel, b: &Brep) -> f64 {
(1..40)
.map(|i| {
let x = f64::from(i) * 0.5;
let r = law(if reversed { 1.0 - x / 20.0 } else { x / 20.0 });
let c = 20.0 - r + r * core::f64::consts::FRAC_1_SQRT_2;
let p = Point3::new(x, c, c);
let t = if reversed { 1.0 - x / 20.0 } else { x / 20.0 };
let r = law(t);
let sign = if reversed { -1.0 } else { 1.0 };
let p = touch_point(x, r, sign * law_slope(t) / 20.0);
let uv = surface_closest_point(k, s, p).unwrap().uvs[0];
s.evaluate_point(k, uv).unwrap().distance(p)
})
@@ -132,16 +160,16 @@ fn rounded_cube(fixed: bool) -> (f64, f64) {
(volume(&k, &mut b), off)
}
/// `(1 - pi/4)` times the integral of `r^2` over the 20 mm edge: the square of the cubic
/// Bezier law 6, 6, 1, 1 is the degree 6 Bezier whose mean control value, 107/7, is the
/// mean of `r^2` over the edge.
fn law_removed() -> f64 {
(1.0 - core::f64::consts::FRAC_PI_4) * 20.0 * 107.0 / 7.0
}
/// The volume the union of the balls of the law 6, 6, 1, 1 takes off the cube's edge: the
/// integral along the edge of the area each plane `x` cuts between the rails
/// (`y, z > 20 - r(x)`) above the union of the balls' discs (Gauss-Legendre, 16 points in
/// each of 40 panels along the edge and 8 across, the union's top over 20001 balls; 40001
/// balls agree to 1.1e-6).
const ENVELOPE_REMOVED: f64 = 64.159_535;
#[test]
fn variable_round_on_planes_removes_the_laws_volume() {
let expected = 8000.0 - law_removed();
let expected = 8000.0 - ENVELOPE_REMOVED;
let (v, off) = rounded_cube(true);
eprintln!(
"fixed: {v} expected {expected} diff {} off {off}",
@@ -149,25 +177,20 @@ fn variable_round_on_planes_removes_the_laws_volume() {
);
// the fork's bound: the law's volume to 1e-4 (here 5e-5 of the volume removed)
assert!(
(v - expected).abs() < 1e-4 * law_removed(),
(v - expected).abs() < 1e-4 * ENVELOPE_REMOVED,
"{v} vs {expected}"
);
// the round holds the law's sections (2.0e-4 here)
// the round holds its balls' touch circles
assert!(off < 3e-4, "{off}");
}
/// Without the fix the rails stray between the traced points: the surface is 8.0e-4 off the
/// balls' touch circles, against 2.0e-4 with it. (The union of the balls removes about the
/// same volume either way, within 3e-5 of the envelope's: before the round was the union of
/// its balls, the great circles' volume showed the stray rails too.)
#[test]
fn variable_round_on_planes_keeps_upstreams_volume_without_the_fix() {
let expected = 8000.0 - law_removed();
fn variable_round_on_planes_strays_off_its_balls_without_the_fix() {
let (v, off) = rounded_cube(false);
eprintln!(
"upstream: {v} expected {expected} diff {} off {off}",
v - expected
);
// 1.5e-4 of the volume removed short, the surface 6.1e-4 off the law's sections
assert!(
(v - expected).abs() > 1e-4 * law_removed(),
"{v} vs {expected}"
);
eprintln!("upstream: {v} off {off}");
assert!(off > 5e-4, "{off}");
}
@@ -215,7 +215,6 @@ fn round() -> (f64, Result<(bool, f64), i32>) {
k.fixes.fillet_rail_end_on_continued_surface = true;
k.fixes.fillet_rail_rim_on_face = true;
k.fixes.fillet_rails_meet_at_one_end_point = true;
k.fixes.fillet_refuse_ball_not_fitting = true;
k.fixes.fillet_refuse_crossing_rails = true;
k.fixes.fillet_refuse_face_consuming_blends = true;
k.fixes.fillet_refuse_non_manifold_result = true;
+55 -39
View File
@@ -1,5 +1,6 @@
//! WR-682 (`fixes.fillet_surface_plane_curve_on_plane_equation`, the SolidCraft fork's
//! tangency-labs/smlib@5bdcddf, 14a6daa and 4c6571b): `sm_SrfSrfIntersection` traces the
//! WR-682 (the SolidCraft fork's tangency-labs/smlib@5bdcddf, 14a6daa and 4c6571b; on every
//! kernel since its flag, `fillet_surface_plane_curve_on_plane_equation`, was retired: WR-682
//! addendum 2026-11-07): `sm_SrfSrfIntersection` traces the
//! curve of a surface and a plane between two points on both on the plane's equation, so
//! that the plane's own domain doesn't end it.
//!
@@ -28,12 +29,6 @@ use solidcore::Kernel;
const TOL: f64 = 1e-5;
const ANG_TOL: f64 = 0.2;
fn kernel(flag: bool) -> Kernel {
let mut k = Kernel::default();
k.fixes.fillet_surface_plane_curve_on_plane_equation = flag;
k
}
fn ellipse(deg: f64) -> Point3 {
let t = deg.to_radians();
Point3::new(10.0 * t.cos(), 10.0 * t.sin(), 20.0 + 5.0 * t.cos())
@@ -158,7 +153,7 @@ fn check_curves(
#[test]
fn the_curve_runs_past_the_plane_s_domain_to_its_end() {
let k = kernel(true);
let k = Kernel::default();
let (cyl, plane) = (cylinder(&k), patch());
let c = intersect(&k, &cyl, &plane, 45.0, 135.0, None).unwrap();
let curve = c.curve_3d.as_ref().unwrap();
@@ -194,7 +189,7 @@ fn the_curve_runs_past_the_plane_s_domain_to_its_end() {
#[test]
fn the_uv_curves_follow_the_order_of_the_surfaces() {
let k = kernel(true);
let k = Kernel::default();
let (cyl, plane) = (cylinder(&k), patch());
let c = intersect(&k, &plane, &cyl, 45.0, 135.0, None).unwrap();
check_curves(
@@ -210,7 +205,7 @@ fn the_uv_curves_follow_the_order_of_the_surfaces() {
/// 14a6daa: the curve leaves its start the way it's told, not towards the end.
#[test]
fn the_start_direction_chooses_the_way_round() {
let k = kernel(true);
let k = Kernel::default();
let (cyl, plane) = (cylinder(&k), patch());
let t = 45f64.to_radians();
// the way the angle grows at 45 degrees, and the other way
@@ -257,18 +252,15 @@ fn the_start_direction_chooses_the_way_round() {
);
}
/// Upstream's two-points and general intersectors stop at the plane's domain: status 1001.
#[test]
fn without_the_flag_the_curve_is_not_found() {
let k = kernel(false);
let (cyl, plane) = (cylinder(&k), patch());
let e = intersect(&k, &cyl, &plane, 45.0, 135.0, None).unwrap_err();
assert!(e.contains("code: 1001"), "{e}");
}
/// The three curves, in full, to compare the flag on and off.
fn curves_text(k: &Kernel, a: &Surface, b: &Surface, from: Point3, to: Point3) -> String {
let r = srf_srf_intersection(
/// The intersection between `from` and `to`, as `sm_SrfSrfIntersection` gives it.
fn curves(
k: &Kernel,
a: &Surface,
b: &Surface,
from: Point3,
to: Point3,
) -> solidcore::Result<SrfSrfCurves> {
srf_srf_intersection(
k,
Some(from),
Some(to),
@@ -279,26 +271,50 @@ fn curves_text(k: &Kernel, a: &Surface, b: &Surface, from: Point3, to: Point3) -
TOL,
ANG_TOL,
SrfSrfOptions::default(),
);
format!("{r:?}")
)
}
fn assert_flag_changes_nothing(a: &Surface, b: &Surface, from: Point3, to: Point3) {
let (on, off) = (kernel(true), kernel(false));
let (with, without) = (
curves_text(&on, a, b, from, to),
curves_text(&off, a, b, from, to),
/// Not traced on the plane's equation: the intersectors' own answer, the status 1001 they
/// give where the plane's domain or an end off a surface stops them.
fn assert_not_found(a: &Surface, b: &Surface, from: Point3, to: Point3) {
let r = curves(&Kernel::default(), a, b, from, to);
assert!(
matches!(r, Err(solidcore::SolidError::Upstream { code: 1001, .. })),
"{r:?}"
);
assert_eq!(with, without);
}
/// The analytic intersector's answer stands: the cylinder as itself, whose section it finds.
/// Not traced on the plane's equation: the intersectors' exact line from `from` to `to`
/// (every point of the curve on the segment), not the trace's Hermite spans.
fn assert_line(a: &Surface, b: &Surface, from: Point3, to: Point3) {
let k = Kernel::default();
let c = curves(&k, a, b, from, to).unwrap().curve_3d.unwrap();
let ivl = c.natural_interval();
let ends = [ivl.min(), ivl.max()].map(|t| c.evaluate_point(&k, t).unwrap());
let fits = |p: Point3, q: Point3| ends[0].distance(p) < 1e-9 && ends[1].distance(q) < 1e-9;
assert!(fits(from, to) || fits(to, from), "{ends:?}");
let along = (to - from) / (to - from).length();
for i in 1..16 {
let p = c
.evaluate_point(&k, ivl.evaluate(f64::from(i) / 16.0))
.unwrap();
let off = (p - from) - along * (p - from).dot(along);
assert!(
off.length() < 1e-9,
"{p:?} off the line by {}",
off.length()
);
}
}
/// The analytic intersector's answer stands for the cylinder as itself: its section ends at
/// the plane's domain, so between these points it finds none.
#[test]
fn an_analytic_answer_is_kept() {
let k = kernel(true);
let k = Kernel::default();
let cyl =
Surface::from(create_cylinder_surface(&k, Point3::new(0.0, 0.0, 0.0), 10.0, 40.0).unwrap());
assert_flag_changes_nothing(&cyl, &patch(), ellipse(45.0), ellipse(135.0));
assert_not_found(&cyl, &patch(), ellipse(45.0), ellipse(135.0));
}
/// 4c6571b: a flat B-spline surface meets the plane in a line, the analytic intersector's.
@@ -326,13 +342,13 @@ fn a_flat_surface_is_not_traced() {
let mut big = Extent2d::default();
big.set_min_max_coords(-30.0, -30.0, 30.0, 30.0).unwrap();
wide.adjust_step_uv_domain(&big).unwrap();
assert_flag_changes_nothing(&nurb, &Surface::from(wide), at(-10.0), at(10.0));
assert_line(&nurb, &Surface::from(wide), at(-10.0), at(10.0));
}
/// An end where the surface touches the plane is a singular point: not traced.
#[test]
fn a_surface_touching_the_plane_is_not_traced() {
let k = kernel(true);
let k = Kernel::default();
let cyl = cylinder(&k);
// the plane x = 10 touches the cylinder along the line x = 10, y = 0
let frame = Axis2Placement::new(
@@ -344,7 +360,7 @@ fn a_surface_touching_the_plane_is_not_traced() {
let mut d = Extent2d::default();
d.set_min_max_coords(-30.0, -30.0, 30.0, 60.0).unwrap();
touching.adjust_step_uv_domain(&d).unwrap();
assert_flag_changes_nothing(
assert_line(
&cyl,
&Surface::from(touching),
Point3::new(10.0, 0.0, 5.0),
@@ -355,8 +371,8 @@ fn a_surface_touching_the_plane_is_not_traced() {
/// An end off the surface isn't taken either.
#[test]
fn an_end_off_a_surface_is_not_traced() {
let k = kernel(true);
let k = Kernel::default();
let cyl = cylinder(&k);
let off = Point3::new(9.0, 0.0, 24.5);
assert_flag_changes_nothing(&cyl, &patch(), ellipse(45.0), off);
assert_not_found(&cyl, &patch(), ellipse(45.0), off);
}
@@ -1,6 +1,5 @@
//! WR-685 (#2250), completed by the fork's b9d6a72 and 7102bc5 (smlib#79, #2273; the
//! prerequisites of #2274): with `fixes.fillet_gn_section_generator` a G^n section's
//! thumbweight is any w below 1 (the equal area default moves to 2), and the equal area
//! prerequisites of #2274): a G^n section's thumbweight is any w below 1 (the equal area default moves to 2), and the equal area
//! thumbweight is resolved at every station from that station's own wedge, not once per
//! generator from the first blend's middle station. The surface then interpolates the
//! section's homogeneous rows, each a cubic Hermite curve of its values and
@@ -29,7 +28,7 @@ use solidcore::blend::fillet_executive::api::fillet_edges;
use solidcore::blend::fillet_section::section::GN_DEFAULT_THUMBWEIGHT;
use solidcore::boolean::api_brep::boolean_union;
use solidcore::geom::attribute::{AttributeStore, ObjectKey};
use solidcore::kernel::{KernelOptions, UpstreamFixes};
use solidcore::kernel::KernelOptions;
use solidcore::mass::integrator::properties::{brep_volume, PropertyAttributes};
use solidcore::math::Point3;
use solidcore::nurbs::b_spline_curve::ControlPointForm;
@@ -40,15 +39,6 @@ use solidcore::surface::surface::SurfaceKind;
use solidcore::topology::EdgeId;
use solidcore::{Brep, Kernel};
fn kernel(gn: bool) -> Kernel {
let mut fixes = UpstreamFixes::default();
fixes.fillet_gn_section_generator = gn;
fixes.fillet_surface_plane_curve_on_plane_equation = gn;
let mut k = Kernel::new(&KernelOptions::default());
k.fixes = fixes;
k
}
fn pick(k: &Kernel, b: &Brep, p: [f64; 3]) -> EdgeId {
let q = Point3::new(p[0], p[1], p[2]);
let mut best = (0.1f64, None);
@@ -335,7 +325,7 @@ fn box_edge_rounds_are_the_fork_s() {
];
let circle = 24000.0 - 40.0 * 9.0 * (1.0 - core::f64::consts::FRAC_PI_4);
for (n, w, want_v, net) in cases {
let mut k = kernel(true);
let mut k = Kernel::new(&KernelOptions::default());
let mut b = create_box(&mut k, Point3::new(0.0, 0.0, 0.0), 40.0, 30.0, 20.0).unwrap();
let e = pick(&k, &b, [20.0, 30.0, 20.0]);
fillet_edges(&mut k, &mut b, &[e], 3.0, 2, n as u32, w).unwrap();
@@ -353,7 +343,7 @@ fn box_edge_rounds_are_the_fork_s() {
}
}
// 1 and past are refused, before and after b9d6a72
let mut k = kernel(true);
let mut k = Kernel::new(&KernelOptions::default());
let mut b = create_box(&mut k, Point3::new(0.0, 0.0, 0.0), 40.0, 30.0, 20.0).unwrap();
let e = pick(&k, &b, [20.0, 30.0, 20.0]);
assert!(fillet_edges(&mut k, &mut b, &[e], 3.0, 2, 2, 1.0).is_err());
@@ -409,7 +399,7 @@ fn equal_area_thumbweight_is_each_station_s_own() {
(&[1], 23465.663708708671, vec![box_net]),
];
for (order, want_v, nets) in cases {
let mut k = kernel(true);
let mut k = Kernel::new(&KernelOptions::default());
let mut b = create_box(&mut k, Point3::new(0.0, 0.0, 0.0), 40.0, 30.0, 20.0).unwrap();
let c = pick(&k, &b, [20.0, 30.0, 20.0]);
fillet_edges(&mut k, &mut b, &[c], 5.0, 0, 2, 0.0).unwrap();
@@ -508,7 +498,7 @@ fn pipe_root_rounds_are_the_fork_s() {
),
];
for (n, w, want_v, net) in cases {
let mut k = kernel(true);
let mut k = Kernel::new(&KernelOptions::default());
let plate = create_box(&mut k, Point3::new(0.0, 0.0, 0.0), 60.0, 40.0, 10.0).unwrap();
let mut pipe = create_cylinder(&mut k, Point3::new(0.0, 0.0, 0.0), 10.0, 60.0).unwrap();
let pl = Axis2Placement::new(
@@ -528,19 +518,6 @@ fn pipe_root_rounds_are_the_fork_s() {
}
}
/// Without the flag the G^n generator is not used: no blend face of the order-2 section's
/// degree 7 across, whatever the thumbweight (upstream's blend curve, or its refusal).
#[test]
fn flag_off_builds_no_gn_section() {
for w in [0.0, -3.0, GN_DEFAULT_THUMBWEIGHT] {
let mut k = kernel(false);
let mut b = create_box(&mut k, Point3::new(0.0, 0.0, 0.0), 40.0, 30.0, 20.0).unwrap();
let e = pick(&k, &b, [20.0, 30.0, 20.0]);
let _ = fillet_edges(&mut k, &mut b, &[e], 3.0, 2, 2, w);
assert!(blend_nets(&b, 7).is_empty(), "w {w}");
}
}
/// smlib#109 (f9b133a, b8ec238): an equal area round solves each order and u once in its
/// operation, and its certificate sums I(w) once per point and per interval off its cells.
/// The counts over the blend are gated about 5% over today's (the fork's capi `rooted` and
@@ -594,7 +571,7 @@ fn equal_area_roots_and_sums_are_solved_once_each() {
most_sums,
} in cases
{
let mut k = kernel(true);
let mut k = Kernel::new(&KernelOptions::default());
let mut b = build(&mut k).unwrap();
let e = pick(&k, &b, p);
fillet_edges(&mut k, &mut b, &[e], r, 2, 2, GN_DEFAULT_THUMBWEIGHT).unwrap();

Some files were not shown because too many files have changed in this diff Show More