forked from 1b-agent/opencadstudio-upstream
refactor: drop truck, and evaluate every curve through the kernel
The last four truck crates are gone from the manifest. What they were doing falls into three parts, and each now has one answer instead of two. NURBS evaluation. truck was carrying B-spline curves and surfaces for the SPLINE entity, hatch boundaries, BLEND's endpoint frames, the spline preview and ACIS spline-surface faces. The kernel now has both, over one de Boor written across however many coordinates a control point holds — so a plane curve and a space curve cannot drift apart, and a surface is the same algorithm applied twice. The rational and the polynomial cases stop being separate types: weights absent means polynomial. The entity conversion. Every LINE, ARC, ELLIPSE, SPLINE and polyline was built into truck topology purely so it could be sampled back into points. They are sampled through `entities::curve` now, which is where each one's geometry is already defined once and what EXTRUDE and REVOLVE read — so a circle drawn on screen and a circle handed to the Model tab come from the same definition. That retires four of TruckObject's variants and the module is renamed for what it does. SWEEP and LOFT. Both only ever produced a mesh, so both are built from point lists: a band of quads per span, and a lid where a profile closes. Lofting profiles of different densities resamples them by distance rather than by index, so a circle lofted to a square no longer twists. Two things worth noting for anyone reading the old comments. The tolerance globals that lived in the tessellation module were never about truck at all — they are the per-frame chord height, and they move to `curve_tol`. And the rule that a profile handed over as `Lines` silently broke EXTRUDE and REVOLVE no longer holds: those read the curve directly and never look at this channel. The two `automation` test failures are unchanged from before this and are not caused by it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
1f642bb40a
commit
8c7ebdc9f1
58 files changed
+947
-1761
No files matched your search
+33
-124
@@ -2,15 +2,15 @@
|
||||
//
|
||||
// Flow:
|
||||
// EntityType
|
||||
// ↓ acad_to_truck::convert()
|
||||
// TruckEntity { object: TruckObject, snap_pts, tangent_geoms, key_vertices }
|
||||
// ↓ truck_tess::tessellate_*()
|
||||
// TruckTessResult::Lines → WireModel
|
||||
// TruckTessResult::Point → WireModel (small cross)
|
||||
// TruckTessResult::Mesh → MeshModel
|
||||
// TruckObject::Text → one WireModel per glyph stroke (elevation from entity Z)
|
||||
// ↓ acad_to_render::convert()
|
||||
// RenderEntity { object: RenderObject, snap_pts, tangent_geoms, key_vertices }
|
||||
// ↓ curve_tol::tessellate_*()
|
||||
// RenderObject::Lines → WireModel
|
||||
// RenderObject::Dot → WireModel (a dot sized in pixels)
|
||||
// RenderObject::Text → WireModel (glyph strokes) + SDF quads
|
||||
// RenderObject::Text → one WireModel per glyph stroke (elevation from entity Z)
|
||||
//
|
||||
// Entities not handled by acad_to_truck (Viewport, Insert, Hatch, Ole2Frame)
|
||||
// Entities not handled by acad_to_render (Viewport, Insert, Hatch, Ole2Frame)
|
||||
// are tessellated by the FallbackTess fallback_geometry() path.
|
||||
|
||||
use crate::entities::leader::LeaderTess;
|
||||
@@ -18,10 +18,7 @@ use acadrust::types::Color as AcadColor;
|
||||
use acadrust::{CadDocument, EntityType, Handle};
|
||||
use glam::Vec3;
|
||||
|
||||
use crate::scene::convert::acad_to_truck::{convert, TruckObject};
|
||||
use crate::scene::convert::truck_tess::{
|
||||
tessellate_edge, tessellate_vertex, tessellate_wire, TruckTessResult,
|
||||
};
|
||||
use crate::scene::convert::acad_to_render::{convert, RenderObject};
|
||||
use crate::scene::model::wire_model::{SnapHint, WireModel};
|
||||
|
||||
/// Split an f64 offset-relative coordinate into the double-single (high, low)
|
||||
@@ -190,7 +187,7 @@ pub fn tessellate(
|
||||
// MLINE emits one WireModel per style element so each parallel line keeps
|
||||
// its own colour and linetype — a red Continuous line under a yellow dashed
|
||||
// line reads as the two-tone multiline the style defines. Handled here, like
|
||||
// Leader, because the single-colour truck `Lines` path can't carry
|
||||
// Leader, because the single-colour the kernel `Lines` path can't carry
|
||||
// per-element colour.
|
||||
if let EntityType::MLine(m) = entity {
|
||||
let lines = crate::entities::mline::mline_lines(m, document);
|
||||
@@ -422,11 +419,11 @@ pub fn tessellate(
|
||||
return out;
|
||||
}
|
||||
|
||||
// ── Try the truck path first ───────────────────────────────────────────
|
||||
// ── Try the kernel path first ───────────────────────────────────────────
|
||||
// Relative-PDSIZE points size their glyph from the current zoom so they
|
||||
// stay a roughly constant on-screen size; otherwise the header-driven path.
|
||||
let te = crate::entities::point::relative_truck(entity, document, world_per_pixel)
|
||||
.or_else(|| crate::entities::light::relative_truck(entity, document, world_per_pixel))
|
||||
let te = crate::entities::point::relative_render(entity, document, world_per_pixel)
|
||||
.or_else(|| crate::entities::light::relative_render(entity, document, world_per_pixel))
|
||||
.or_else(|| convert(entity, document));
|
||||
if let Some(te) = te {
|
||||
match te.object {
|
||||
@@ -438,7 +435,7 @@ pub fn tessellate(
|
||||
// groups by override colour and emit one WireModel per bin so a
|
||||
// single MTEXT can hand back N colour-distinct wires when the
|
||||
// value mixes inline colours.
|
||||
TruckObject::Text(stroke_groups) => {
|
||||
RenderObject::Text(stroke_groups) => {
|
||||
let entity_zf = entity_z(entity) as f64;
|
||||
let elev_v = entity_zf;
|
||||
|
||||
@@ -990,10 +987,22 @@ pub fn tessellate(
|
||||
}
|
||||
|
||||
// ── Standard topology objects ─────────────────────────────────
|
||||
TruckObject::Point(v) => {
|
||||
let result = tessellate_vertex(&v);
|
||||
match result {
|
||||
TruckTessResult::Point([x, y, z], [xl, yl, zl]) => {
|
||||
RenderObject::Dot(position) => {
|
||||
{
|
||||
{
|
||||
// Split into a coarse float and a fine correction, so
|
||||
// a point at survey coordinates keeps its last
|
||||
// millimetres instead of losing them to f32.
|
||||
let [x, y, z] = [
|
||||
position[0] as f32,
|
||||
position[1] as f32,
|
||||
position[2] as f32,
|
||||
];
|
||||
let [xl, yl, zl] = [
|
||||
(position[0] - x as f64) as f32,
|
||||
(position[1] - y as f64) as f32,
|
||||
(position[2] - z as f64) as f32,
|
||||
];
|
||||
// A PDMODE=0 point is a single dot. Size its marker to
|
||||
// ~1 px so it reads as a dot rather than a large
|
||||
// world-space "+" in small drawings — otherwise the
|
||||
@@ -1048,97 +1057,12 @@ pub fn tessellate(
|
||||
fill_tris_low: Vec::new(),
|
||||
}];
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
TruckObject::Curve(e) => {
|
||||
if let TruckTessResult::Lines(points, points_low) =
|
||||
tessellate_edge(&e)
|
||||
{
|
||||
let snap_pts = te.snap_pts;
|
||||
let key_vertices: Vec<[f64; 3]> = te
|
||||
.key_vertices
|
||||
.into_iter()
|
||||
.map(|[x, y, z]| [x, y, z])
|
||||
.collect();
|
||||
return vec![WireModel {
|
||||
taper_widths: Vec::new(),
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
pick_tris: Vec::new(),
|
||||
pick_tris_low: Vec::new(),
|
||||
dash_from_start: false,
|
||||
dash_align_end: None,
|
||||
text_verts: Vec::new(),
|
||||
name,
|
||||
points,
|
||||
points_low,
|
||||
color,
|
||||
selected,
|
||||
pattern_length,
|
||||
pattern,
|
||||
line_weight_px,
|
||||
snap_pts,
|
||||
tangent_geoms: te.tangent_geoms,
|
||||
aci: 0,
|
||||
key_vertices,
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
fill_tris: vec![],
|
||||
fill_tris_low: Vec::new(),
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
TruckObject::Contour(w) => {
|
||||
if let TruckTessResult::Lines(points, points_low) =
|
||||
tessellate_wire(&w)
|
||||
{
|
||||
let snap_pts = te.snap_pts;
|
||||
let key_vertices: Vec<[f64; 3]> = te
|
||||
.key_vertices
|
||||
.into_iter()
|
||||
.map(|[x, y, z]| [x, y, z])
|
||||
.collect();
|
||||
// A wide polyline arrives here: the shader expands this
|
||||
// centre-line to `world_width` so the band IS the wire (the
|
||||
// linetype dashes it); the band also backs pick.
|
||||
let (pick_tris, pick_tris_low) = points_to_ds(te.pick_tris);
|
||||
return vec![WireModel {
|
||||
taper_widths: Vec::new(),
|
||||
world_width: polyline_band_width(entity),
|
||||
depth_override: None,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
pick_tris,
|
||||
pick_tris_low,
|
||||
dash_from_start: false,
|
||||
dash_align_end: None,
|
||||
text_verts: Vec::new(),
|
||||
name,
|
||||
points,
|
||||
points_low,
|
||||
color,
|
||||
selected,
|
||||
pattern_length,
|
||||
pattern,
|
||||
line_weight_px,
|
||||
snap_pts,
|
||||
tangent_geoms: te.tangent_geoms,
|
||||
aci: 0,
|
||||
key_vertices,
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
fill_tris: vec![],
|
||||
fill_tris_low: Vec::new(),
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
TruckObject::Lines(points) => {
|
||||
RenderObject::Lines(points) => {
|
||||
// Points are world-space f64 from entity converters (polyline,
|
||||
// leader, mesh, solid2d, etc.). Subtract world_offset in f64
|
||||
// and split into double-single (high, low) f32 buffers — the
|
||||
@@ -1312,7 +1236,7 @@ pub fn tessellate(
|
||||
return out;
|
||||
}
|
||||
|
||||
TruckObject::SegmentedLines(points) => {
|
||||
RenderObject::SegmentedLines(points) => {
|
||||
let (local_pts, local_pts_low) = points_to_ds(points);
|
||||
let snap_pts = te.snap_pts;
|
||||
let key_vertices: Vec<[f64; 3]> = te
|
||||
@@ -1353,7 +1277,7 @@ pub fn tessellate(
|
||||
}];
|
||||
}
|
||||
|
||||
TruckObject::TaperedLines(points, widths) => {
|
||||
RenderObject::TaperedLines(points, widths) => {
|
||||
// A wide polyline whose width varies: one continuous band wire
|
||||
// carrying a per-point width; the shader interpolates each
|
||||
// segment's two endpoint widths. `world_width` (the widest edge)
|
||||
@@ -1398,21 +1322,6 @@ pub fn tessellate(
|
||||
}];
|
||||
}
|
||||
|
||||
TruckObject::Volume(_) => {
|
||||
// Solid3D / Region / Body → mesh tessellation lives in
|
||||
// `solid3d_tess`. As a wire fallback, render the pre-computed
|
||||
// edge wires stored in the entity when present (e.g. from
|
||||
// SOLVIEW output or when the SAT kernel cannot parse the
|
||||
// ACIS data).
|
||||
let wire_pts = solid_wire_fallback(entity);
|
||||
let mut wm = WireModel::solid_f64(name, wire_pts, color, selected);
|
||||
// Add insertion snap at point_of_reference.
|
||||
if let Some(p) = crate::entities::solid3d::point_of_reference(entity) {
|
||||
let sp = glam::DVec3::new(p.x, p.y, p.z);
|
||||
wm.snap_pts.push((sp, SnapHint::Insertion));
|
||||
}
|
||||
return vec![wm];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user