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 Delete → Keep anyway, then More info → Run 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::ChamferCone→Geom_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 viaconeFromRims), rim and seam pcurves are written explicitly (a seam needs two, atu0andu0 + 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 signedSemiAngle, 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 cones —
circle-on-coneandline-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 intand 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 anunhandled-…-coneclass 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 exactpointConeDist, tier-1IntAnacone cases (cone∩plane ⟂ axis, coaxial cone∩cylinder, coaxial cone∩cone; everything oblique returnsfalse), 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
ChamferConeregion 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 controlS12-bwas 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 (
edgeClassesin 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;unhandledotherwise. Red linesunhandled*=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 (
radiusDriftin RESULT,DIAG_RADIUS; 082194b; D-130-8) and torus-band census (DIAG_TORUSBAND, classfilletStripOnTorusBand; 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 bygate_130(tests/gates/gate_130.py; c49e169, 8a646f5; D-130-18(3)) — there is nogates/linkage_chamfer_gate.py. B2–B5 sidecars carry the generator'sexactVolume;gate_130's volume cell reads it (9ccaf8d; D-130-15(1)). TheconeNYIfixture-name heuristic and sidecar entries are retired (6952dcc; D-130-15(2)). Unit targetscone_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
smoothVolumeDeltaPctMaxis re-derived from the built shell as the exact measured round-trip value, 0.0 → 0.0033. Its sixanalytic MakeEdge failedchains class aspolylineTier2(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
warningsorder (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 waysmoothBuiltCylindersis. 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_borespierced 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_130counts 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 whenN ≥ 6); never loosened for a region whose N was not counted.coarseFusionBandis 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
YDirectionon a right-handedgp_Ax3; the sign now lives in a signed height; both plate frusta reachvalid=1. - B2 volume (9fa4eff; D-130-20): default
BRepGProp::VolumePropertiesunder-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_130B2 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_Facerung repairs orientation only, never wire geometry (e7c00a8). - An ellipse arc binds its vertices at the parameters they occupy (8c1498d):
S11-bships 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):
isGeneratorRidgeread a cap-rim link as a generator ridge ⟂ the axis. - Sidecar
semiAngleDeg45.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_ToroidalSurfacein 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 (228dfbc → 000c29f) because its per-piece emit shipped Handle pickup's single R 4 wall as eleven faces and
partial_recovery_gaterefused it — the instrument was not edited. The union is compiled-in behindSTL2STEP_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'sgates_fullSIDECAR 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) staysexpected-redand may slip to 1.3.1 (D-130-5).gate_130remains inverted onGATE_130_EXPECTED_REDwhile 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.jsonexpectedRed; widening that map is a defect. - Intersection edges (D-130-2): tier 1 analytic only where
IntAnaon 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 andBRepAlgoAPI_Sectioncurves are refused as shipped geometry (door D-130-2b). - Hand constants named, not moved (D-130-8):
SegmentParams::thetaCylLoDeg = 5.0still gates B1's seed and grow;kTurnDot = 0.7is unchanged. - The tripwire's resolver (cd42b46, 8c1498d): reports but does not refuse until it is pass-aware.