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 Permalink 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