cad-editor/docs/tessellation.md
Hakan Seven 273f482aee refactor: retire the solid3d feature — the web build gets solids too
The feature existed for one reason: truck's mesh and boolean crates reach
`vtkio → xz2 → lzma-sys`, a C library that cannot cross-compile to wasm32. So
the web build dropped it, and with it the Model tab, solid tessellation and
ACIS import — all of which quietly did nothing in the browser.

cadkernel is pure Rust and has no C dependency, so none of that holds any
more. The feature gated exactly two things by the end, `acis_export` and the
save-path sync that calls it, and both are as portable as everything around
them. Removing it means the web build makes primitives, runs booleans, draws
ACIS solids read from a file, and writes them back out as exact geometry — the
same as the desktop build.

Verified against all three: native, `--no-default-features`, and an actual
`wasm32-unknown-unknown` check rather than an assumption about one.

The docs claimed otherwise in four places and are corrected. `tessellation.md`
in particular was organised around whether an entity "goes through truck",
which is no longer a question anything can be asked — the three paths are now
a kernel B-rep mesh, a curve sampled through `entities::curve`, or geometry
emitted directly, and the per-entity table is updated to match.

`index.html` no longer passes `data-cargo-no-default-features`; there are no
features left to turn off.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-10 01:28:25 +03:00

6.5 KiB
Raw Blame History

Entity tessellation paths

How each acadrust EntityType becomes drawable geometry in OpenCADStudio.

There are three ways an entity gets there, and they must not be conflated:

  1. Kernel B-rep mesh — the ACIS document is lifted into a cadkernel Body and each face triangulated in its own surface's parameter space. The only path that produces filled mesh triangles from analytic surfaces.
  2. Curve-sampled — the entity's geometry is read through entities::curve::entity_curve, which is where each type's curve is defined once, and tessellated to a chord tolerance. Output is a polyline; no surface is involved.
  3. Direct — points, segments or triangles emitted straight from the entity's own fields.

The distinction between (2) and (3) is worth keeping because (2) is a single definition shared with everything else that needs an entity's geometry — snap candidates, EXTRUDE and REVOLVE profiles, hatch boundaries, clip outlines. A circle drawn on screen and a circle handed to the Model tab come from the same place and cannot disagree.

Entry points: src/scene/convert/tess.rs (tessellate_entity, the per-entity dispatcher) → src/scene/convert/tessellate.rs (tessellate, the RenderObject router), src/entities/curve.rs (curve definitions and sampling) and src/scene/convert/curve_tol.rs (the per-frame chord tolerance).

Summary

Path Entities
Kernel B-rep mesh (lift → per-face triangulation, with a direct per-surface fallback) Solid3D, Region, Body, Surface
Curve-sampled (entity_curve → chord-tolerance tessellation) Line, Arc, Circle, Ellipse, Spline, LwPolyline, Polyline, Polyline2D, Polyline3Dnon-thick variants only
Direct (segments/triangles emitted straight) everything else

The Model/Design-tab primitives (BOX, SPHERE, CYLINDER, CONE, WEDGE, TORUS, PYRAMID, EXTRUDE, REVOLVE) are true kernel B-reps too, cached on the Scene as Body and meshed the same way — but they are created as Solid3D placeholders carrying that body, not as their own EntityType. SWEEP and LOFT produce a mesh only, with no B-rep behind it.

ACIS solids dispatch through solid3d_tess::tessellate_acis, which lifts the document into the kernel first (acis_kernel::tessellate_sat) and falls back to a bespoke per-surface LOD sampler (tessellate_sat_lods) when the kernel cannot express a face — so their path is kernel-with-direct-fallback. The fallback is not silent: a mesh whose faces did not all lift is marked incomplete, because one missing wall looks exactly like a finished solid.

Curved-surface tessellation density is radius-relative (CURVE_REL_TOL, a fraction of the surface radius) so a cylinder's facet count matches the circle/arc wire tessellation instead of exploding on large radii.

Full table

Entity Output Path Notes
Arc wire curve-sampled non-thick: sampled from the arc's own curve; thick: direct Lines plus the swept wall
AttributeDefinition wire direct routes through the Text/MText LFF glyph stroke pipeline
AttributeEntity wire direct same as AttributeDefinition; values supplied per Insert
Block none n/a block-definition sentinel; not tessellated (referenced via Insert)
BlockEnd none n/a block-definition end marker; no output
Body mesh kernel-with-direct-fallback 3D ACIS body lifted into a kernel Body; fallback per-surface sampler
Circle wire curve-sampled non-thick: sampled from the circle's own curve; thick: direct Lines
Dimension wire direct baked-block path recurses on D### sub-entities; synthesis path emits lines/arrows/LFF text
Ellipse wire curve-sampled sampled from the ellipse's own curve
Face3D both direct edge Lines + direct fan-triangulated fill_tris; no B-rep
Hatch both direct boundary outline not emitted to the wire set (#131 OOM); fill rasterized on GPU
Insert wire direct expands block children and tessellates each via its own path; XCLIP filter applied
Leader wire direct leader path + arrowhead + landing, direct Lines
Line wire curve-sampled non-thick: its two ends; thick: direct Lines plus the swept wall
LwPolyline wire curve-sampled plinegen true: sampled from its own curve, bulges kept as arcs; else direct SegmentedLines
Mesh both direct SubD mesh: edge Lines + direct fan-triangulated fill_tris
MLine wire direct spine + offset lines + caps, direct Lines
MText wire direct wrap-aware multi-line LFF glyph layout; inline formatting codes
MultiLeader wire direct leader + landing + LFF text + frame + fill
Ole2Frame wire direct bounding rectangle + diagonal cross
Point wire direct a position → dot or cross marker sized by PDSIZE
PolyfaceMesh both direct face list: closed-polyline edges + direct fan-triangulated fill_tris
PolygonMesh both direct M×N grid wireframe + direct fan-triangulated fill_tris
Polyline wire curve-sampled heavy 3D polyline; sampled from its own curve, bulges kept as arcs
Polyline2D wire curve-sampled 2D polyline with bulge; sampled from its own curve
Polyline3D wire curve-sampled straight edges, no bulge or thickness
RasterImage wire direct boundary rectangle / clipping polygon
Ray wire direct two-point [base, base + dir×1e6], no sampling
Region mesh kernel-with-direct-fallback 2D planar ACIS body; same kernel path as Solid3D
Seqend none n/a vertex-sequence terminator sentinel; no output
Shape wire direct small diamond marker at the insertion point
Solid wire direct 2D SOLID: four quad edges as direct Lines
Solid3D mesh kernel-with-direct-fallback 3DSOLID: parse SAT/SAB → lift into a kernel Body; fallback sampler
Spline wire curve-sampled NURBS sampled through the kernel's space curve, refined where it bends
Table both direct cell fills (fill_tris) + LFF cell text + grid lines
Text wire direct LFF-font stroked glyph polylines
Tolerance wire direct feature-control frame grid + per-cell LFF symbols
Underlay wire direct boundary rectangle of the PDF/DWF reference
Unknown none n/a unrecognized-entity sentinel; no output
Viewport wire direct content-viewport frame rectangle (sheet viewport skipped)
Wipeout wire direct boundary rectangle / clipping polygon
XLine wire direct three-point infinite line, no sampling