refactor(render): tessellate curved entities from their own curve

The point lists were built three different ways and none of them scaled
with the geometry. A full ellipse was cut into sixteen segments per half
and an elliptical arc into thirty-two, whatever its size, so anything
large read as a polygon; a circle worked out its own segment count from
the chord tolerance; an arc was handed to truck's arc-through-three-
points builder, which cancels at survey coordinates.

All three now sample the entity's curve at the render pass's chord
tolerance, so how round something looks follows how big it is and how
far in the view is zoomed. The ellipse also stops casting its local
coordinates to f32 on the way in — the vertex path splits f64 into a
double-single pair precisely so that precision survives to the shader,
and throwing it away first defeated that.

What does not change is the kind of object each entity hands over.
EXTRUDE, REVOLVE and SWEEP read their profile and path out of Contour or
Curve and have no arm for a bare point list, so an arc or an ellipse
given as Lines would quietly stop being usable as either. The arc keeps
its circle_arc edge for that reason; only the ellipse's control points
change, and they keep the same two-half-edge wire.

The ellipse now decides it is closed from its own endpoints rather than
from its stored parameters, so a file that writes an end a hair short of
a full turn still produces a wire a plane can attach to.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Hakan SevenandClaude Opus 5 committed 2026-08-09 00:55:29 +03:00
1 parent c2cc6fd7c4
commit 90abfc21a9
5 files changed
+116 -138

No files matched your search

+8 -5
View File
@@ -26,9 +26,6 @@ fn to_truck(arc: &Arc) -> TruckEntity {
// Compute OCS basis vectors for this entity's normal.
let (ax, ay) = crate::scene::view::transform::ocs_axes(normal);
let ccw_end = if ea >= sa { ea } else { ea + TAU };
let mid_a = sa + (ccw_end - sa) * 0.5;
// Arc centre in WCS.
let (cwx, cwy, cwz) = crate::scene::view::transform::ocs_point_to_wcs((cx, cy, cz), normal);
@@ -45,7 +42,8 @@ fn to_truck(arc: &Arc) -> TruckEntity {
// Centre, ends, arc-length midpoint and the quadrants the sweep actually
// covers, all from the entity's own curve. Circles and ellipses (closed
// curves) deliberately emit no midpoint; see #34.
let snap = crate::entities::curve::snap_from(&crate::entities::curve::arc_curve(arc));
let curve = crate::entities::curve::arc_curve(arc);
let snap = crate::entities::curve::snap_from(&curve);
let tangent = TangentGeom::Circle {
center: [cwx as f32, cwy as f32, cwz as f32],
radius: r as f32,
@@ -87,9 +85,14 @@ fn to_truck(arc: &Arc) -> TruckEntity {
};
}
// Kept as a truck edge rather than a point list: EXTRUDE, REVOLVE and
// SWEEP take their profile and path from `Curve` / `Contour` and have no
// arm for `Lines`, so handing them one would quietly stop an arc being
// usable as either.
let p_start = arc_pt(sa);
let p_end = arc_pt(ea);
let p_mid = arc_pt(mid_a);
let ccw_end = if ea >= sa { ea } else { ea + TAU };
let p_mid = arc_pt(sa + (ccw_end - sa) * 0.5);
let v_start = builder::vertex(p_start);
let v_end = builder::vertex(p_end);
let edge = builder::circle_arc(&v_start, &v_end, p_mid);