Skip to content

stl2step 1.3.0 + SolidOut 1.3.0 for macOS and Windows

Latest

Choose a tag to compare

@BlinkingSun BlinkingSun released this 05 Sep 05:07
· 7 commits to main since this release

Downloads

SolidOut 1.3.0 — the desktop app (same UI on both platforms, engine 1.3.0 built in; no separate install)

Platform File Notes
macOS (Apple silicon) SolidOut-macOS-AppleSilicon.dmg Developer ID signed, notarized and stapled.
Windows 10/11 (x64) SolidOut-Windows-x64-setup.exe (recommended) · SolidOut-Windows-x64.msi Not yet Authenticode-signed: SmartScreen warns on first launch — in Edge use the arrow next to DeleteKeep anyway, then More infoRun anyway; or fetch with curl.exe -L -o from PowerShell, which skips the browser prompt. Needs WebView2 (built into Windows 11).
Checksums SHA256SUMS.txt Windows files.

SolidOut is closed source; its binaries ship here as release assets. The engine it drives is this repository.

stl2step CLI 1.3.0 — build from source on macOS, Linux (Debian/Ubuntu fixed in 955a0e4) or Windows per the README; the CLI is what SolidOut bundles.

What 1.3.0 converts that 1.2.0 did not (measured on the linkage-plate sample shipped in tests/corpus): through-holes as closed cylinders, conical chamfers as real cone faces, outer profile arcs and slot ends as partial cylinders, intercepted bores — 22 cylinders, 2 cones and 49 true circles where 1.2.0 wrote 1,517 facets; watertight, deterministic, round-trip volume error 0.0004 %. Toroidal rounds and freeform (lofted) surfaces stay faceted by design — see Deferred below.


Engine changelog (1.3.0)

Added

  • Cones as a surface type: chamfer frustums (Origin::ChamferConeGeom_ConicalSurface; D-130-3). Detector C claims a ring adjacent to one accepted closed-360 cylinder and one cap, sharing the axis, with two rim radii and a constant slope, and ships it as a real cone face: the face is built on the same surface handle the bind site uses (SurfVar::ConeBase, from the fitted rims via coneFromRims), rim and seam pcurves are written explicitly (a seam needs two, at u0 and u0 + 2π), the seam is an explicit generator with both vertices snapped to it, and the apex is excluded by construction because the face's v-range runs between two positive-radius rims (b50328c, 49952bc). The taper sign is carried in a signed height and a signed SemiAngle, never by negating the axis, so both frusta of a hole-mouth pair build in one frame (30f67dd). Detector C runs a first pass right after the law bands and detector A — before B1 — so the exact frustum claims the ring before B1 can commit ~60° arcs of it as cylinders; the original post-B1 pass is kept (978ab69; D-130-3, D-130-8). General cones (apex inside the face, oblique sections) are not built (D-130-3).
  • Certified bind classes on conescircle-on-cone and line-on-cone (src/refit_cone_bind.{hpp,cpp}, cone_bind_unit; 10ce7cd; D-130-3's hard gate). A rim circle binds only when its pcurve is a v-iso line and the circle is coaxial with the cone, in which case |C3d(t) − S(pc(t))| is constant in t and the endpoint value is the supremum (proved, not sampled); a seam binds as an affine generator whose supremum is at an endpoint. Every other cone edge returns an unhandled-…-cone class and ships as the mesh polyline — tier 2, counted (D-130-2).
  • Cone math (src/refit_cone_math.{hpp,cpp}, cone_math_unit; b3114da, 7f4eb5f, 0d67eba): circleOnConeMax (exact for coaxial and perpendicular-plane circles, a provable upper bound otherwise, invariant under rigid placement), the exact pointConeDist, tier-1 IntAna cone cases (cone∩plane ⟂ axis, coaxial cone∩cylinder, coaxial cone∩cone; everything oblique returns false), and the frustum helpers. Kept in its own translation unit so the P1 include allowlist is neither touched nor widened (0d67eba).
  • Cone volume prediction (19ec800; D-130-11(2)): a ChamferCone region predicts its facet-to-surface volume in closed form — the circular-segment gap between each inscribed facet and the frustum, summed as an exact per-triangle density over the triangles it claims — so a built cone is no longer read as zero-area by the cascade budget and the D4 guard (I9 green on the plate). At equal rim radii the formula collapses to the cylinder's own.
  • Mesh quantization floor (src/stl_quant.{hpp,cpp}, DIAG_QUANTFLOOR, quant_floor_unit; 61fab1d; D-130-12): the resolution of the number format a mesh file was written in, at that mesh's own coordinate magnitude — for a binary STL the binary32 ulp at the largest |coordinate| in the file times √3/2; for an ASCII STL the printed-decimal grid at the same magnitude. Measured from the file; an unreadable file yields 0, which certifies nothing. It is the certificate the absorb below runs on.
  • Law-band extent — the absorb (4af42c2, 3d25757; D-130-9, D-130-12; supersedes D-130-11(1)): a recognised law band owns every adjacent unclaimed triangle whose vertices lie on the cylinder the band has already certified, admitted only inside max(the band's own residual, the mesh's quantization floor) — never a part-scale budget. After each round the band's cylinder is refit by least squares over its members with the axis direction among the unknowns, and a round whose refit leaves the certificate is rolled back whole. On the plate this closes the R 8.5 through-bore (6 → 139 triangles) and completes both R 30 profile arcs to exactly the sidecar's 75 and 80 triangles. The planar noise floor D-130-11(1) proposed as the certificate was measured (DIAG_NOISEFLOOR, a7f7b99) and refused: on the plate its median is 1.7e-15 mm and its max 0.019 mm — 105× looser than the budget it was meant to tighten.
  • Virtual generators (e2cf8f5; D-130-8): a law band's chain may be built on the lines where two adjacent facet planes meet rather than on the mesh edges the tessellation happened to draw, so a staggered strip chains at every fold the mesh resolves. The virtual path runs only where the mesh-edge chain refused. On the plate the four R 3 slot ends are recognised for the first time, the R 8.5 bore is claimed as a full 92-generator closed chain, and the cross bore reaches 214 of its 279 ground-truth triangles.
  • N-gon wall cylinders (Origin::NgonWall, detector A; 49952bc, ad5c814): closed unclaimed A2 walls (N ≥ 6, generators parallel) are claimed as right circular cylinders after the law bands and before B1. The accept test is the vertex residual against the fitted circle, with no chord-sagitta term (ad5c814): with the sagitta term the non-concyclic hex control S12-b was accepted at a 7 %-of-R residual; without it, refused. Detector A can certify a through hole: a link sharing exactly one mesh edge with its neighbour is no longer read as a turning-axis blend, and a single-cap ring (a chamfered through hole) is collected (ad5c814).
  • Planar CIRCLE loops (detector B; 49952bc, 88b14fd, 74f885c; D-130-2): LS-fit CIRCLE edges on already-analytic plane loops (N ≥ 6) where the two shipped surfaces yield no curve at all. A plane-loop CIRCLE replaces the polyline only when both sides of the chain are real regions that can share it (88b14fd), and it never replaces a curve derived from the shipped surfaces — two distinct planes meet along their line and nowhere else (74f885c, 47bdd57; DIAG_130_PLCKEEPLIN).
  • Edge-class census and gate (edgeClasses in RESULT; tests/gates/edge_class_gate.py + tests/gates/baseline/edge-class-ratchet.json; 9249ab0, 149564f, 082194b; D-130-2, D-130-5, D-130-7(c)). Every edge two analytic faces share is classified on the shipped shell: tier 1 (analytic) when the curve is a line, circle or ellipse and the closed-form bind-site supremum exists on both surfaces; tier 2 (polylineTier2) when it is a mesh polyline — counted, never absorbed; unhandled otherwise. Red lines unhandled*=0, dev>tol=0, tol>meshTolCap=0; the tier-2 count is a never-increase ceiling. Expected-red on 9 fixtures, recorded not relaxed (082194b): Body11 (overCap), Body28 (overCap,unhandled), S03 (overCap), S04 (overCap), S09 (overCap), S11-b (unhandled), S16-R1-explode-success (overCap,unhandled), handle-pickup (overCap,overTol,unhandled), linkage_bores_chamfer (overCap,overTol,unhandled).
  • Radius truth census (radiusDrift in RESULT, DIAG_RADIUS; 082194b; D-130-8) and torus-band census (DIAG_TORUSBAND, class filletStripOnTorusBand; D-130-7(c)): measurement only. Plate max |R_built−R_lsq| 1.55e-7 mm, torus-band count 0; S11-b's 12 fillets stay off-torus.
  • Fixtures and gates: the Mastercam linkage plate linkage_bores_chamfer (49952bc) with a sidecar measured from the mesh; synthetic battery B2–B6 (cross_bores, chamfer_straight_ring, boss_cone_chamfer, counterbore_chamfer, cyl_meets_chamfer) via the corpus generator (beb6322; D-130-5). Contract owned by gate_130 (tests/gates/gate_130.py; c49e169, 8a646f5; D-130-18(3)) — there is no gates/linkage_chamfer_gate.py. B2–B5 sidecars carry the generator's exactVolume; gate_130's volume cell reads it (9ccaf8d; D-130-15(1)). The coneNYI fixture-name heuristic and sidecar entries are retired (6952dcc; D-130-15(2)). Unit targets cone_math_unit, cone_bind_unit, quant_floor_unit.

Changed

  • Body28 builds (D-130-6; 0361889): main reverted the whole component; on this branch it is a valid closed solid of 499 planes + 263 cylinders (2533 fewer faces than main's faceted answer), enabled by the two plate heals (7a1c822, e7c00a8). Its sidecar cell smoothVolumeDeltaPctMax is re-derived from the built shell as the exact measured round-trip value, 0.0 → 0.0033. Its six analytic MakeEdge failed chains class as polylineTier2 (082194b; D-130-6 open).
  • Handle pickup heals, recorded (D-130-11(1), D-130-13(1)): under the quantization-certified absorb two R≈3 bands admit three triangles that lie inside their own already-certified residual — 918 → 916 faces (PLANE 797 → 795; CYLINDRICAL 121), |V_step − V_mesh| 10.309374 → 10.115732, both radii moving to the least-squares value (4af42c2). Virtual generators then ship two more rims as circles, CIRCLE 95 → 97, |V_step − V_mesh| 10.115732 → 9.732831 (e2cf8f5, b1da5e4). The control is 916 / 795 / 121 / 97, |dV| 9.732831 from b1da5e4 on; PRG, plane-census, nwcyl and hl ratchets untouched and green.
  • Cascade containment (66608dc; D-130-9(b)): a face that is not an analytic region explodes its own neighbourhood instead of escalating the component to the U2 blanket rung. RULE 1.5's 50 % test is unchanged.
  • RESULT warnings order (b94a094; D-130-10(2)): the list handed back is sorted, so the RESULT line is a property of the mesh rather than of the thread pool; the live log callback still sees each warning at the moment it is raised.
  • RESULT smoothBuiltCones (b94a094; D-130-10(1)): the conical faces a build actually shipped, counted off the written shape the way smoothBuiltCylinders is. Reads 0 on every part with no chamfer frustum. RESULT identity is compared modulo this key.
  • I7 loop closure (b53029b, e523298; D-130-21): a boundary walk that leaves a split vertex and returns to the same vertex is a cycle. If that vertex is incident to ≥ 3 regions/islands it is a chain endpoint (I8), so the cycle is split there. PARKED I-checker rows on Body11, Body28 (regions 538/775) and handle-pickup (region 171) are lifted (038aafb; D-130-21).
  • B2 cross_bores pierced bore (b8b3291, 488cce7; D-130-16, D-130-17, D-130-2): the R8 wall is one closed-360 cylinder face with two tier-2 inner wires (the R5 windows); the R5 surface is two faces (the larger bore severs every generator). gate_130 counts a tier-2 edge as shared when both faces reference one EDGE_CURVE (8dd2503; D-130-19) and counts distinct cylindrical surfaces, not faces (53c46f6; D-130-20).
  • G2 sagitta in archChainBand (75101e7; D-130-1): outside coarse, G2 accepts a cylinder commit only when the max vertex residual is within the exact deviation a correct fit of a counted N-gon can produce (N = ev.d2.nSides, only when N ≥ 6); never loosened for a region whose N was not counted. coarseFusionBand is not widened.
  • Plate fillet strips (D-130-9(a), D-130-10(3); 1a2343d, 3d25757): once the real R 10 cross bore is a recognised cylinder, 52 two-facet strips C1 had claimed are the chamfer frustum, and 13 two-facet slivers on the toroidal mouth rounds lose fillet status (triangles ship as the same facets). S11-b's 12 real fillets are byte-identical. The 1.4 torus item inherits the 13.
  • Cap plates carry their own measured planar residual (plateFaceTolCap = max(meshTolCap, Region::maxVertexDev); 7a1c822).
  • S03 builds (74f885c vs main 3e7636f): main reverted it whole; the branch ships 24 planes + 30 cylinders.

Fixed

  • A plane-loop CIRCLE never overrides the curve IntAna derived from the shipped surfaces (74f885c; D-130-2): detector B had replaced 42 exact plane|plane lines on Handle pickup with arcs lying on neither face.
  • Facet fill planes (0f065e7; D-130-9(b)): a mesh facet is filled on the plane of its own wire, so a shared vertex snapped onto a neighbouring region's curve no longer leaves the fill UnorientableShape.
  • One cone frame for both taper signs (30f67dd): detector C had negated the neighbour cylinder's axis for a frustum whose radius grows against it, which also negates YDirection on a right-handed gp_Ax3; the sign now lives in a signed height; both plate frusta reach valid=1.
  • B2 volume (9fa4eff; D-130-20): default BRepGProp::VolumeProperties under-integrated a cylindrical face whose inner wire is a 68-span polyline (37 mm³ / 0.0598 % vs the generator's exact volume). Adaptive 2D Gauss (Eps = Precision::Confusion()) recovers 1.70 mm³ / 0.00272 % — the D-130-2 tier-2 chord, counted not absorbed. Geometry unchanged; gate_130 B2 volume cell green.
  • Single-closed-edge inner loops keep their sense on the edge, not the wire (714a6af): closes the 1.2.0 registered limitation.
  • The plate ShapeFix_Face rung repairs orientation only, never wire geometry (e7c00a8).
  • An ellipse arc binds its vertices at the parameters they occupy (8c1498d): S11-b ships 12 cylinders / 12 fillets, one solid (1.2.0 re-read as 0 solids, volume 2.9674 % off).
  • Detector A never claimed a through hole (ad5c814): isGeneratorRidge read a cap-rim link as a generator ridge ⟂ the axis.
  • Sidecar semiAngleDeg 45.017° → 45.000004° on the plate (65d79a1): the recorded value was the facet-normal angle, not the surface's.

Deferred

  • Torus surfaces → 1.4 (D-130-7, amended by D-130-9(a) and D-130-10(3)): the plate's three toroidal rounds at the cross-bore mouths stay faceted; no lane builds Geom_ToroidalSurface in 1.3.0. The 13 two-facet fillet-strip slivers on those bands are the 1.4 item's inherited count.
  • Same-surface islands and the loop-level union → 1.4, with the tori (D-130-13(2), D-130-14, D-130-16, D-130-17 and the 2026-09-05 addendum). The island claiming landed and was reverted the same lane (228dfbc000c29f) because its per-piece emit shipped Handle pickup's single R 4 wall as eleven faces and partial_recovery_gate refused it — the instrument was not edited. The union is compiled-in behind STL2STEP_UNION, off by default (d3179af, 0477c72). 1.3.0 ships the seed piece(s) per surface: the plate's cross bore as 214 of 279 triangles in 2 faces; each R 3 slot-end top row stays facets (28 of 39 tris per wall in two faces). The plate sidecar's cross-bore entry is the mesh truth (255 on-surface + 24 off-surface, D-130-13(2)) and is not edited to match the shipped 214/279; the plate's gates_full SIDECAR row is expected-red by D-130-17.
  • B6 cyl_meets_chamfer (a cone cut by a second bore: non-coaxial cone∩cyl and a trimmed cone face) stays expected-red and may slip to 1.3.1 (D-130-5). gate_130 remains inverted on GATE_130_EXPECTED_RED while B6 is unmet.
  • Edge-class red lines on 9 fixtures (082194b; D-130-2): Body11, Body28, S03, S04, S09, S11-b, S16-R1-explode-success, handle-pickup, linkage_bores_chamfer — recorded in edge-class-ratchet.json expectedRed; widening that map is a defect.
  • Intersection edges (D-130-2): tier 1 analytic only where IntAna on the shipped surfaces yields a line, circle or ellipse; general cyl∩cyl and non-coaxial cyl∩cone ship as the mesh polyline, counted and ratcheted, never absorbed; free BSpline approximations and BRepAlgoAPI_Section curves are refused as shipped geometry (door D-130-2b).
  • Hand constants named, not moved (D-130-8): SegmentParams::thetaCylLoDeg = 5.0 still gates B1's seed and grow; kTurnDot = 0.7 is unchanged.
  • The tripwire's resolver (cd42b46, 8c1498d): reports but does not refuse until it is pass-aware.