25 KiB
truck evaluation (2026-10-14)
Serves the operator's request to evaluate truck (https://github.com/ricosjp/truck), a Rust B-rep kernel, after the Aetheris evaluation (../aetheris-evaluation/), same method and cases. Campaign brush-tree, session self-2026-10-14-ag. Facts only, measured on Yggdrasil at truck 88ed0052.
Serves the operator's request to evaluate https://github.com/ricosjp/truck (Rust B-rep CAD kernel), campaign brush-tree, session self-2026-10-14-ag. Same method and cases as F:\Projects\GameCult.Geometry.Csg\docs\research\aetheris-evaluation\README.md. Facts only; no recommendation.
Measured at truck commit 88ed005249e5e3a6b07f62425399435905cd3ab6 (master, 2026-09-28, "Merge branch 'cargo-upgrade-20260928'"), cloned read-only to <scratch>\eyes-truck\repo. Nothing from truck was built or run on Starfire; every build/test/run was on Yggdrasil through ygg-verify.sh (image eureka-verify-rust, rustc/cargo 1.95.0, Debian 12, 4 CPUs, 6 GiB).
<scratch> = C:\Users\Meta\AppData\Local\Temp\claude\F--Projects-CultLib\5ea0b87f-66d0-4b24-8d36-45015e4cedc1\scratchpad.
Tags: [V] measured or read this pass; [S] stated by the repo's own docs only; [M] marketing claim.
Logs: eyes-truck\jobs\job1.log (truck's own tests), job2.log (first harness run, tol 0.05), job4.log (harness: 35 cases x tol 0.05/0.01/0.2, OCCT checks, truck reading OCCT STEP), job5.log (licences, wasm, determinism), job6.log (STEP entity census, case-25 stage timing, tolerance sweep). jobs\analyze.py digests job4.
Harness (mine, not truck's): eyes-truck\harness\ = local git repo (src\main.rs, check.py, cases.json copied unchanged from the Aetheris harness, job.sh, job5.sh, job6.sh); depends on truck by git rev 88ed0052. Built --release.
Q1 Shape
- [V] Repo: GitHub + GitLab (CI is
.gitlab-ci.yml); 2872 commits since 2020-05-18; 273.rsfiles, 71,555 lines of Rust (git ls-files). GitHub: 1621 stars, 41 open issues, not archived, Apache-2.0 (GitHub API). README: "Truck is a RUst Cad Kernel"; concept "Rust and WebGPU", "re-implementing the B-rep with NURBS". - [V] Maintainers: one organisation's staff. Commit authors (all history): Yoshinori Tanimura 2482 + alias "Tanimura Yoshinori" 110, "truck" 244, then Moritz Moeller 9, Greg Rauhoeft 5, Jinlei Li 3, others 1-3. Since 2025-10-14: 253 commits, by Tanimura (127+72), "truck" 52, thayashi-tech 1. Commits per calendar year: 2022 298, 2023 393, 2024 389, 2025 325, 2026 (to 09-28) 189. Many recent commits are titled "cargo upgrade" (git log -- truck-shapeops: the last five are all "cargo upgrade", 2026-05-25..2026-09-28).
- [V] Releases: 73 git tags; newest tag/crates.io release is 2024-09-20 (truck-modeling 0.6.0, shapeops 0.4.0, stepio 0.3.0, meshalgo 0.4.0, geometry 0.5.0...; crates.io API). master is two years of unreleased work: CHANGELOG "Unreleased" lists EdgeBlendSurface, Offset geometry, fillet for a single edge, truck-drafting (2D crate), truck-assembly (assembly read/write in STEP), higher-order derivatives, wgpu v26. The git-rev dependency I measured is this unreleased master, not the crates.io 0.4.0 shapeops. crates.io downloads: truck-geometry 130k, truck-modeling 127k, truck-stepio 103k, truck-meshalgo 60k, truck-shapeops 13k.
- [V] Crates (version, Rust lines): truck-base 0.5.0 (3,207), truck-geotrait 0.4.0 (2,211), truck-geometry 0.5.0 (15,200: B-spline/NURBS, knot vectors, decorators), truck-topology 0.6.0 (5,956: vertex/edge/wire/face/shell/solid), truck-polymesh 0.6.0 (2,901: mesh structs, OBJ/STL), truck-meshalgo 0.4.0 (6,617: tessellation via
spadeCDT, mesh filters/analyzers, VTK), truck-modeling 0.6.0 (3,878: builder, tsweep/rsweep/homotopy), truck-shapeops 0.4.0 (8,531: booleans, fillet, healing), truck-stepio 0.3.0 (10,537: STEP in/out viaruststep), truck-assembly 0.1.0 (1,740), truck-drafting 0.1.0 (1,883, 2D), truck-derivers 0.1.0 (1,344, derive macros), truck-platform 0.6.0 (2,981, wgpu), truck-rendimpl 0.6.0 (3,797, wgpu rendering), truck-js 0.2.0 (592, wasm-bindgen wrapper). Plus example-pages-generator and readme-generator in the workspace. - [V] Licence: repo
LICENSEis Apache-2.0; 13 crate manifests saylicense = "Apache-2.0";truck-assemblyandtruck-draftingmanifests carry nolicensefield (cargo metadata: truck-assembly licence null). Transitive dependency tree of the harness (truck-modeling+shapeops+meshalgo+stepio, 135 packages, cargo metadata, job5.log): MIT OR Apache-2.0 85, Apache-2.0 15, MIT 14, Apache-2.0 OR MIT 5, MIT/Apache-2.0 4, Unlicense OR MIT 3, Zlib OR Apache-2.0 OR MIT 2, BSD-2-Clause 1, Zlib 1, Unlicense/MIT 1, MIT OR Apache-2.0 OR LGPL-2.1-or-later 1 (r-efi, an OR), no licence field 2 (truck-assembly, my harness). No GPL/AGPL. Dependencies that matter: ruststep 0.4.0 (Apache-2.0, last published 2024-09-20), spade 2.15.1 (MIT OR Apache-2.0), cgmath (via truck-base), rayon, vtkio, nom 3.2.1 and quick-xml 0.22.0 (cargo prints a "future-incompat" warning for both, job4.log). - [V] MSRV: no
rust-versionin any Cargo.toml and no MSRV text anywhere (grep). Editions: 2021 for most crates, 2024 for truck-assembly and truck-drafting (so those need rustc >= 1.85). Builds on 1.95.0. - [V] CI: GitLab (
.gitlab-ci.yml) jobscpu-test(docker image,cargo make ci-cpu-test),cpu-nightly-test,meshalgo-features-buildcheck,gpu-test(artifacts: images),wasm-test(deno lint +cargo make wasm-test),page-build, deploy of example pages.Makefile.tomlcpu-test =cargo test -p truck-base -p truck-geotrait -p truck-geometry -p truck-topology -p truck-polymesh -p truck-meshalgo -p truck-modeling -p truck-shapeops -p truck-stepio --features derive --features polynomial. Tests that use sample data need the git submoduleresources(github.com/ricosjp/resources4truck). - [V] Surface/curve types. truck-geometry: Plane, Sphere, Torus (specifieds/), Circle, Line, Hyperbola, Parabola; BSplineCurve/Surface, NurbsCurve/Surface; decorators RevolutedCurve, ExtrudedCurve, Processor (matrix-transformed), PCurve, IntersectionCurve, TrimmedCurve, AfSurface, EdgeBlend, RbfSurface, Offset, homotopy. The ready-made enums in truck-modeling are narrower:
Surface= {Plane, BSplineSurface, NurbsSurface, RevolutedCurve(Processor<RevolutedCurve, Matrix4>)} (truck-modeling/src/geometry.rs:126-135);Curve= {Line, BSplineCurve, NurbsCurve, IntersectionCurve} (:24-32). So a cylinder, sphere or torus built with the modeling builder is a surface of revolution (Line or NURBS circle swept), not an analytic Cylinder/Sphere/Torus surface type. NURBS is first-class. - [V] How booleans work (truck-shapeops/src/transversal/integrate/mod.rs; entry points
and(solid0, solid1, tol)andor(...)returningOption<Solid>; there is no subtract, the examples invert the second solid withsolid.not()and calland): both shells are triangulated attol(shell.triangulation(tol)); triangle-triangle intersections give polylines (polyline_construction); polylines are re-fitted onto the two true surfaces by Newton iteration (IntersectionCurve,search_triple(..., 100), intersection_curve/mod.rs); faces are divided by the loops, classified and/or by crossing a ray against the other mesh; new edges are replaced by a quadratic B-spline approximation of the intersection curve withintol(BSplineCurve::quadratic_approximation(ic, range, tol, 100), integrate/mod.rs:altshell_to_shell). So it is a general surface-surface path through tessellation, not a table of special cases.tolis both the tessellation tolerance and the intersection-curve approximation tolerance; truck-baseTOLERANCE= 1e-6 (tolerance.rs:6) is the geometric coincidence tolerance (near). A non-positive tol hitsnonpositive_tolerance!. Failure isNonewith no message; some failures are panics (Q3). - [S] Documented limits (truck-shapeops/src/lib.rs:4-9): "Boolean operations are currently supported only for shapes where faces intersect transversally. Cases where faces are tangent to each other are not yet supported. ... performance optimization using BSP ... remains a future task." Fillet: "single edge whose end vertices are each adjacent to exactly three faces. Continuous edges are currently unsupported." truck-stepio lib.rs:1-6 states "Shapes created by set operations cannot be output yet" (contradicted by my measurement in Q4: 8 boolean results exported and read as valid by OCCT).
- [V] Also shipped in shapeops:
healing(SplitClosedEdgesAndFaces, RobustSplitClosedEdgesAndFaces) andfillet(simple_fillet,fillet_with_side).
Q2 Build and own tests on Linux
- [V] Job1 (job1.log), image rust 1.95.0, after
git submodule update --init resources(fetched resources4truck at 9bf9de14):cargo test --no-fail-fast -p truck-base -p truck-geotrait -p truck-geometry -p truck-topology -p truck-polymesh -p truck-meshalgo -p truck-modeling -p truck-shapeops -p truck-stepio -p truck-assembly -p truck-drafting -p truck-derivers --features derive --features polynomial(debug profile): exit 0, 745 passed, 0 failed, 6 ignored (unit + integration + doc-tests). - [V] Per crate (cargo prints crates alphabetically; the crate attribution below is inferred from that order and the test file names, passed counts unit+integration / doc-tests): assembly 2 / 39; base 28 / 55; derivers 0 / 0; drafting 20 / 25; geometry 82 / 139; geotrait 14 / 0; meshalgo 42 / 21; modeling 24 / 25; polymesh 13 / 15; shapeops 24 / 0 (21 unit + 3 in tests/fillet.rs); stepio 53 / 5 (3 unit + 39 tests/input + 3 tests/io + 8 tests/output); topology 7 / 112.
- [V] Not run: truck-platform, truck-rendimpl, truck-js tests (GPU/wasm CI jobs), nightly lane.
large-solid-torustest is#[ignore]d (1 ignored in topology). - [V] Compile times (4 CPUs, cold cache): my harness release build 1 m 06 s (job4.log);
truck-jswasm release build 1 m 18 s (job5.log). - [V]
cargo build --release --target wasm32-unknown-unknown -p truck-jssucceeds afterrustup target add wasm32-unknown-unknown:truck_js.wasm3,928,263 bytes (workspace sets opt-level "z" for truck-js). Not run in a browser. truck-js exports 12 builder fns, 20 shape, 5 polygon, 4 shapeops (and/or/not), 4 step_in wasm_bindgen items (grep counts).
Q3 Boolean torture (the Aetheris cases.json: 35 cases, same ops/geometry/expected volumes)
Method: harness\src\main.rs builds primitives with truck-modeling (box = 3 tsweeps then scaled; cylinder = rsweep circle + tsweep; sphere = rsweep semicircle + cone; torus = two rsweeps), centred as in the Aetheris harness, rotates about X by rx, translates, flips any primitive whose tessellated volume is negative with Solid::not(). union = or, intersect = and, subtract = and(a, not(b)), sequential for multi-step cases. Each case is its own process with a 150 s timeout. "refused" = None (no message exists in the API). Release build. Tolerance tol is truck's only knob, so I ran three: 0.05, 0.01, 0.2 (model sizes are 10-100 units). Reference volumes: the cases' analytic exp plus OCCT booleans on identical primitives (check.py ref).
Per-case outcome (S = succeeded, R = refused/None, P = panic; boolean time at tol 0.05 / 0.01 / 0.2 in ms; steps for case 21 in parentheses):
| # | case | tol 0.05 | tol 0.01 | tol 0.2 |
|---|---|---|---|---|
| 01 | coplanar face union | R 2 | R 2 | R 2 |
| 02 | flush slab subtract | R 3 | R 2 | R 2 |
| 03 | coplanar top pocket | P 3 | P 4 | P 3 |
| 04 | coincident-edge union | R 2 | R 2 | R 2 |
| 05 | coincident-edge subtract | R 4 | R 2 | R 2 |
| 06 | tangent cylinders union | R 21 | R 34 | R 18 |
| 07/08/09 | Steinmetz intersect / union / subtract | R 23/30/26 | R 41/40/42 | R 16/16/18 |
| 10 | sliver wall 1e-7 | R 4 | R 2 | R 2 |
| 11 | pocket leaving 1e-7 floor | S 2 | S 2 | S 2 |
| 12 | pocket leaving 1e-4 floor | S 2 | S 2 | S 2 |
| 13 | spheres exactly tangent, union | S 17 | S 90 | S 13 |
| 14 | spheres 1e-9 apart/overlap, union | S 17 | S 90 | S 15 |
| 15 | spheres overlap 1e-4 | R 59 | R 152 | R 44 |
| 16 | spheres overlap (6 apart) | R 306 | R 1044 | R 159 |
| 17 | box minus sphere on top face | R 13 | R 65 | R 11 |
| 18 | torus half cut by box | P 1311 | P 2320 | P 757 |
| 19 | torus union cylinder | R 105 | R 163 | R 52 |
| 20 | torus minus cylinder (tangent) | R 96 | R 151 | R 51 |
| 21 | 10x10 hole grid (100 steps) | P at step 3 (2940 ms) | R at step 1 | R at step 2 |
| 22 | two tangent holes | R 743 | R 1114 | R 193 |
| 23 | hole tangent to side wall | R 26 | R 61 | R 19 |
| 24 | two holes 1e-7 web | P (step 2) 3667 | R (step 2) 1039 | P (step 2) 913 |
| 25 | perpendicular cylinders union | S 12-14 s (see below) | R 7799 | S 1587 |
| 26 | coaxial tube (cyl minus coaxial cyl) | S 3384 | R 8089 | S 333 |
| 27 | blind hole from top | P 144 | R 178 | R 49 |
| 28 | oblique 30 deg through hole | S 3706 | R 3096 | S 299 |
| 29 | box intersect sphere | R 1711 | R 7098 | R 837 |
| 30 | offset corner union | S 2 | S 2 | S 2 |
| 31 | pocket leaving 1e-7 side wall | R 2 | R 2 | R 2 |
| 32 | union overlap by 1e-7 slab | R 4 | R 2 | R 5 |
| 33 | partial face contact union | R 2 | R 2 | R 2 |
| 34 | sphere fully inside box (void) | P 11 | P 15 | P 10 |
| 35 | cylinder minus enclosed sphere | P 28 | P 52 | P 14 |
- [V] Score per tolerance, 35 cases, succeeded / refused / panicked / timed out: tol 0.05: 8 / 20 / 7 / 0 (case 25 at 0.05: boolean returned S in ~12-14 s in 6 of 8 runs; in 2 of 8 runs the harness process hit the 150 s timeout later, see below); tol 0.01: 5 / 26 / 4 / 0; tol 0.2: 8 / 22 / 5 / 0. Union over the three tolerances: 8 distinct cases ever succeed (11, 12, 13, 14, 25, 26, 28, 30); 7 cases panic at least once (03, 18, 21, 24, 27, 34, 35); the other 20 are refused at every tol. Invalid STEP among the successes: 0 of 21 exported files (Q4).
- [V] Panic causes (message captured with a backtrace filter, job4.log): "This shell is not oriented and closed." at truck-topology/src/lib.rs:187 reached from
truck_shapeops::transversal::integrate::and(frame 6) for cases 03, 18, 24, 27, 34, 35: the boolean assembled a shell that failsSolid::new's closedness check. Andcalled Option::unwrap() on a None valueat truck-geometry/src/decorators/intersection_curve.rs:220:67 (IntersectionCurve::subs->search_triple(t,100).unwrap()) for case 21 at step 3 (tol 0.05) and in tessellation of results from cases 25/26/28 (below). Cases 34 and 35 (a solid wholly inside the other: no intersection curves) panic at every tol. - [V] Outcome depends on tol non-monotonically: case 25 succeeds at 0.5, 0.2, 0.1, 0.05 and is refused at 0.02, 0.01, 0.005; case 26 succeeds at 0.5, 0.2, 0.1, 0.05, 0.02 and is refused at 0.01 and 0.005; case 28 succeeds at 0.2 and 0.05, refused at 0.01 (job6.log sweep, job4.log). Case 27 is R at 0.5, P at 0.1/0.05/0.02, R at 0.2/0.01/0.005. Hole grid (21): never gets past 2 of 100 holes at any of 0.5, 0.2, 0.1, 0.05, 0.02, 0.01, 0.005 (P at 0.1 and 0.05, R otherwise). Coplanar union (01): R at 0.5, 0.1, 0.02, 0.005 as well. Box-minus-sphere dimple (17): R at 0.5, 0.1, 0.02, 0.005 as well.
- [V] Time per op (release, tol 0.05, boolean call only): planar box cases 2-4 ms; sphere/sphere 17 ms (13 at 0.2, 90 at 0.01); coaxial tube 3.4 s (0.33 s at 0.2, 4.2 s at 0.02); perpendicular cylinders 12-14 s (1.6 s at 0.2, 0.28 s at 0.5, 5.8 s at 0.1); oblique through hole 3.7 s (0.3 s at 0.2); box/sphere refusal 1.7 s; torus/box panic 1.3 s; 10x10 grid first two holes 2.9 s total. Cost grows as tol shrinks for the curved cases.
- [V] Determinism: three repeats at tol 0.05 of cases 11, 13, 26, 28, 30 gave identical face counts and mesh volumes to ~1e-12 (job5.log). Case 25 at 0.05: 2 of 8 runs ended at the 150 s timeout (job4.log rc=124, job5.log run 2) with the stderr of the job4 run holding ruststep "Lookup failed for #219 ..." lines (emitted when truck reads STEP); in 3 runs with stage timing (job6.log) boolean 13.3-14.6 s, meshes +1.0 s, STEP write, re-read +20 ms, no hang. Which stage hung in the 2 timeouts was not captured.
- [V] Against the Aetheris result on the same 35 cases (14 succeeded / 21 refused / 0 crashed): both succeed on 11, 12, 26, 28, 30. truck succeeds where Aetheris refused: 13, 14 (spheres), 25 (perpendicular cylinders, coarse tol only). Aetheris succeeded where truck refused or panicked at every tol: 01, 02, 03, 17, 21, 27, 32, 33, 34. Steinmetz (07-09), tangent cylinders (06), torus (18-20), 15, 16, 22-24, 29, 31, 35 fail in both.
Q4 STEP: export checked with OpenCASCADE; STEP import
Method: truck-stepio out::StepDisplay of solid.compress(); checked with cadquery-ocp (pip, Debian 12, Python 3.11, installed in the container) STEPControl_Reader + BRepCheck_Analyzer.IsValid + TopExp_Explorer counts + BRepGProp.VolumeProperties; each file in its own subprocess (job4.log "== check truck output"; reference volumes from OCCT booleans on identical primitives, "== ref").
- [V] Files: 21 STEP files exported (cases 11, 12, 13, 14, 30 at 3 tolerances; 25, 26, 28 at 0.05 and 0.2 where they succeeded). OCCT read 21/21,
IsValidTrue for 21/21, no crashes. HeaderFILE_SCHEMA(('ISO-10303-203')). - [V] Volumes (OCCT of truck's STEP vs OCCT boolean reference / analytic): 11: 840.0000016 vs 840.000001; 12: 840.0016 vs 840.0016; 13 and 14: 2 solids, 2 shells, 24 faces, 1047.19755 vs 1047.19755; 30: 1 solid, 12 faces, 1875.0 vs 1875.0; 25 (perpendicular cylinders): 10 faces, 1865.747 at tol 0.05 (-0.064% vs 1866.935), 1870.690 at 0.2 (+0.20%); 26 (tube): 6 faces, 502.303 at 0.05 (-0.07% vs 502.655), 504.539 at 0.2 (+0.38%); 28 (oblique hole): 8 faces, 3673.266 at 0.05 (-0.007% vs 3673.516), 3680.588 at 0.2 (+0.19%). So exact for planar/analytic-intersection results and tolerance-bound for results that need new intersection curves.
- [V] Entity census of the exports (job6.log): faces are
FACE_SURFACEoverPLANEorSURFACE_OF_REVOLUTION(spheres: 24 SURFACE_OF_REVOLUTION + AXIS1_PLACEMENT); new edges areINTERSECTION_CURVE+B_SPLINE_CURVE_WITH_KNOTS(case 11, a planar pocket with 1e-7 floor, still carries 4 INTERSECTION_CURVE + 4 B_SPLINE_CURVE_WITH_KNOTS; case 30 carries 6 of each). Solid isMANIFOLD_SOLID_BREP; case 13/14 (two disjoint shells in one Solid) is written asBREP_WITH_VOIDS+ORIENTED_CLOSED_SHELL, which OCCT reads as 2 solids and volume 1047.2 (a union of two spheres), so the second shell is not subtracted as a void. - [V] Truck's STEP writer supports (truck-stepio/src/out/geometry.rs): PLANE (:505), SPHERICAL_SURFACE (:537), TOROIDAL_SURFACE (:575), B_SPLINE_SURFACE_WITH_KNOTS (:621), rational B-spline (:677-680), SURFACE_OF_REVOLUTION (:741); no CYLINDRICAL_SURFACE writer line was found by that grep (cylinders from the builder are SURFACE_OF_REVOLUTION).
- [V] Truck reads STEP: yes (
truck_stepio::r#in,Table::from_step,step_assy,to_compressed_shell; tests read OCCT-written cube, cone, cylinder, sphere, torus and fourabc-*files from theresourcessubmodule, tests/input/tessellate_shape.rs:5-15; input handles CylindricalSurface, SphericalSurface, ToroidalSurface, BSpline, assemblies). My probe: I had OCCT write all 35 reference results (ref_NN.step) and read each with truck (Table::from_step, every shellto_compressed_shell,triangulation(0.01),put_together_same_attrs, volume; job4.log "== truck reads OCCT-written STEP"): no panic on any of 35 files; for 16 of them the tessellated shells are allClosedwith summed volume within 2% of OCCT's (01-05, 11, 12, 13, 17, 21, 26, 27, 30-33); for the rest the shell is Irregular/Regular/Oriented, or 0 triangles, or a wrong volume (06: 783+431 vs 1570.8; 07: 9.6 vs 666.7; 08: 1937 vs 2475; 09: 2 x 481.9 vs 904.1; 14, 16: 0 triangles; 25: 1370 vs 1867; 28: 3892.8 vs 3673.5); cases 18-20, 22-24 and 29 read with volumes within 0.4% but shells not Closed. Reading ref_21 (the 100-hole plate) took 25.8 s in release. These are reads of OCCT trimmed surfaces and intersection-curve edges, tessellated at the repo-test pattern; I did not separate reader faults from tessellation faults. - [V] Truck re-reading its own exported booleans (same probe,
step_rereadin job4.log): most results fail to come back as a closed mesh (11 and 12: shells "Oriented" with 2-10 triangles and volumes 0 / 750; 13 and 14: Irregular, negative volumes -1563.8 and -1648.7; 30 at 0.01: Oriented, 4 triangles, volume 10; 30 at 0.05 and 0.2: Closed with 0 triangles). Results vary between tolerance runs for the same geometry (case 30: 0 / 4 / 0 triangles at 0.05 / 0.01 / 0.2).
Q5 Tessellation (truck-meshalgo) of boolean results
Method: solid.triangulation(tol).to_polygon() then put_together_same_attrs(TOLERANCE*50).remove_degenerate_faces(); shell_condition() and volume() from meshalgo; plus an independent check of the written OBJ (check.py obj: weld at 1e-6, every directed edge must pair with its reverse; signed volume).
- [V] Planar results (cases 11, 12, 30): 28 / 28 / 36 triangles, identical at tol 0.1, 0.01, 0.001, 0.5-1 ms, Closed, independent OBJ check watertight and oriented, volumes exact (840.0000016, 840.0016, 1875.0).
- [V] Spheres (cases 13/14, two spheres r=5): tol 0.1: 992 triangles, 6 ms, Closed, volume 1015.59; tol 0.01: 12,656-12,684 triangles, 111-153 ms, volume 1044.54 (analytic 1047.20); tol 0.001: 78,928 triangles, 1.1-1.8 s, Closed, volume 1046.76. Case 14 is watertight by the independent check at 0.01; case 13 at 0.01 is
Regularby truck and by the independent check has 9 unmatched directed edges and 9 multi-used edges. - [V] Results with new intersection curves: case 26 (tube, boolean tol 0.05): mesh tol 0.1: 1,102 triangles, 33-39 ms, Closed, volume 500.06; tol 0.01: 8,219 triangles, 186-214 ms,
Irregular(independent: 17 unmatched directed edges, 6 multi-used edges), volume 501.79; tol 0.001: panic (intersection_curve.rs:220 unwrap). Case 25 (boolean tol 0.2): tol 0.1: 1,218 triangles, 57 ms Closed; tol 0.01: 11,172 triangles, 272 msRegular(independent: 7 unmatched, 7 multi); tol 0.001 panic. Case 28 (oblique hole, boolean tol 0.05): tol 0.1: 376 triangles, 25-30 msIrregular; tol 0.01 and 0.001: panic; the same case at boolean tol 0.2: tol 0.1 gives 318 trianglesIrregular, 0.01 and 0.001 panic. Case 26 at boolean tol 0.2 panics at all three mesh tolerances. - [V] Tessellating the bare primitives (tol 0.01): box 1000.0 exact; cylinder r5 h10 783.98 (analytic 785.40, -0.18%); sphere r5 522.28 (523.60, -0.25%); torus 10/3 1771.57 (1776.53, -0.28%) (job2.log prims).
- [V] The docs say the mesh of a Solid is not necessarily closed and recommend
put_together_same_attrs(tessellation/mod.rs docs onMeshableShape::triangulation);RobustMeshableShape"does not close the mesh of a solid". - [V] Output API:
PolygonMesh(positions/normals/uv + tri/quad/other faces), OBJ and STL writers in truck-polymesh, VTK in meshalgo. Triangles counted withfaces().triangle_iter().
Q6 Other things a consumer gets
- [V] WASM:
truck-js(wasm-bindgen) builds for wasm32-unknown-unknown, 3.9 MB; meshalgo has acfg(target_arch = "wasm32")path without rayon; CI runs wasm tests with deno (.gitlab-ci.ymljob wasm-test). Python bindings: none found (grep pyo3/python in manifests and READMEs). C ABI: none found. - [V] Rendering:
truck-platform(graphic utility on wgpu) andtruck-rendimpl(shape and polygon-mesh visualisation) with examples app.rs, simple-shape-viewer.rs, simple-obj-viewer.rs, textured-cube.rs, rotate-objects.rs, bsp-animation.rs; CI has agpu-testjob. Not run here (no GPU in the container). - [V] Modelling API (truck-modeling/examples/cylinder.rs, whole body of the cylinder):
Box =let vertex = builder::vertex(Point3::new(0.0, -height / 2.0, radius)); let circle = builder::rsweep(&vertex, Point3::origin(), Vector3::unit_y(), Rad(7.0), 2); let disk = builder::try_attach_plane(&[circle]).unwrap(); builder::tsweep(&disk, Vector3::new(0.0, height, 0.0))vertex->tsweepx/y/z. Punched cube (truck-shapeops/examples/punched-cube-shapeops.rs): buildcylinderthe same way,cylinder.not();thentruck_shapeops::and(&cube, &cylinder, 0.05).unwrap(). Other builder fns:line,circle_arc,bezier,homotopy,try_wire_homotopy,try_attach_plane,translated/rotated/scaled,rsweep,cone. The examples passRad(7.0)(a little over 2 pi) for a full revolution. - [V] Fillet: not reachable from
truck_modeling::Surface(no fillet variant). The fillet test (truck-shapeops/tests/fillet.rs:1-76) defines its ownCurveandSurfaceenums with seven derive macros andToSameGeometryimpls, builds two NURBS faces by hand, and callssimple_fillet(&face0, &face1, shared_edge_id, 0.3, 0.001); 3 such tests pass (job1.log). Limits per docs: a single edge whose end vertices each touch exactly three faces. I did not build "filleted box with a hole": it would need that custom enum pair plus a boolean on the result, and the measured boolean cannot subtract a blind hole from a box with a coplanar top (cases 03 and 27 panic). - [V] Serialisation:
Solid/Shellare serde types (examples writeserde_json::to_vec_pretty(&solid));CompressedSolidfor compact form (solid.compress()). - [V] Parallelism: rayon in meshalgo (non-wasm) and
Send + Syncbounds onShapeOpsSurface/ShapeOpsCurve. - [V] Panics are part of the surface:
Solid::new,buildercalls and tessellation panic on bad input (Q3), and there is noResultwith a reason onand/or.