feat: extrude Arc and Circle thickness along WCS normal

Arc: tessellates bottom + top arcs (32 segs each) with 2 endpoint walls.
Circle: tessellates bottom + top circles (64 segs each) with 4 quadrant walls.
Both use TruckObject::Lines with NaN-separated segments.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
This commit is contained in:
Hakan SevenandClaude Sonnet 4.6 committed 2026-05-02 20:30:30 +03:00
1 parent ce17e8abdf
commit c51eeb4ad0
2 files changed
+105 -22

No files matched your search

+46 -5
View File
@@ -45,20 +45,61 @@ fn to_truck(arc: &Arc) -> TruckEntity {
)
};
let cv = Vec3::new(cwx as f32, cwy as f32, cwz as f32);
let tangent = TangentGeom::Circle {
center: [cwx as f32, cwy as f32, cwz as f32],
radius: r as f32,
};
if arc.thickness.abs() > 1e-10 {
let t = arc.thickness;
let (nx, ny, nz) = normal;
let n = 32usize;
let (start_a, end_a) = if arc.normal.z < 0.0 {
let cw_span = if sa >= ea { sa - ea } else { sa - ea + TAU };
(sa, sa - cw_span)
} else {
let ccw_end = if ea >= sa { ea } else { ea + TAU };
(sa, ccw_end)
};
let mut pts: Vec<[f32; 3]> = Vec::with_capacity((n + 1) * 2 + 8);
for i in 0..=n {
let a = start_a + (end_a - start_a) * (i as f64 / n as f64);
let p = arc_pt(a);
pts.push([p.x as f32, p.y as f32, p.z as f32]);
}
pts.push([f32::NAN; 3]);
for i in 0..=n {
let a = start_a + (end_a - start_a) * (i as f64 / n as f64);
let p = arc_pt(a);
pts.push([(p.x + t * nx) as f32, (p.y + t * ny) as f32, (p.z + t * nz) as f32]);
}
pts.push([f32::NAN; 3]);
let ps = arc_pt(sa);
pts.push([ps.x as f32, ps.y as f32, ps.z as f32]);
pts.push([(ps.x + t * nx) as f32, (ps.y + t * ny) as f32, (ps.z + t * nz) as f32]);
pts.push([f32::NAN; 3]);
let pe = arc_pt(ea);
pts.push([pe.x as f32, pe.y as f32, pe.z as f32]);
pts.push([(pe.x + t * nx) as f32, (pe.y + t * ny) as f32, (pe.z + t * nz) as f32]);
return TruckEntity {
object: TruckObject::Lines(pts),
snap_pts: vec![(cv, SnapHint::Center)],
tangent_geoms: vec![tangent],
key_vertices: vec![],
};
}
let p_start = arc_pt(sa);
let p_end = arc_pt(ea);
let p_mid = arc_pt(mid_a);
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);
let cv = Vec3::new(cwx as f32, cwy as f32, cwz as f32);
TruckEntity {
object: TruckObject::Curve(edge),
snap_pts: vec![(cv, SnapHint::Center)],
tangent_geoms: vec![TangentGeom::Circle {
center: [cwx as f32, cwy as f32, cwz as f32],
radius: r as f32,
}],
tangent_geoms: vec![tangent],
key_vertices: vec![],
}
}
+59 -17
View File
@@ -35,12 +35,6 @@ fn to_truck(circle: &Circle) -> TruckEntity {
let p_top = pt(ay, (0.0, 0.0, 0.0), r);
let p_bot = pt((ay.0 * -1.0, ay.1 * -1.0, ay.2 * -1.0), (0.0, 0.0, 0.0), r);
let right = builder::vertex(p_right);
let left = builder::vertex(p_left);
let upper = builder::circle_arc(&right, &left, p_top);
let lower = builder::circle_arc(&left, &right, p_bot);
let wire: Wire = [upper, lower].into_iter().collect();
let cv = Vec3::new(cwx as f32, cwy as f32, cwz as f32);
let rf = r as f32;
let q = |d: (f64, f64, f64)| Vec3::new(
@@ -48,19 +42,67 @@ fn to_truck(circle: &Circle) -> TruckEntity {
(cwy + r * d.1) as f32,
(cwz + r * d.2) as f32,
);
let snap_pts = vec![
(cv, SnapHint::Center),
(q(ax), SnapHint::Quadrant),
(q(ay), SnapHint::Quadrant),
(q((-ax.0, -ax.1, -ax.2)), SnapHint::Quadrant),
(q((-ay.0, -ay.1, -ay.2)), SnapHint::Quadrant),
];
let tangent = TangentGeom::Circle {
center: [cwx as f32, cwy as f32, cwz as f32],
radius: rf,
};
if circle.thickness.abs() > 1e-10 {
let t = circle.thickness;
let (nx, ny, nz) = normal;
let n = 64usize;
let tau = std::f64::consts::TAU;
let circ_pt = |a: f64| -> (f64, f64, f64) {
let (c, s) = (a.cos(), a.sin());
(
cwx + r * (c * ax.0 + s * ay.0),
cwy + r * (c * ax.1 + s * ay.1),
cwz + r * (c * ax.2 + s * ay.2),
)
};
let mut pts: Vec<[f32; 3]> = Vec::with_capacity((n + 1) * 2 + 4 * 3);
for i in 0..=n {
let (x, y, z) = circ_pt(i as f64 * tau / n as f64);
pts.push([x as f32, y as f32, z as f32]);
}
pts.push([f32::NAN; 3]);
for i in 0..=n {
let (x, y, z) = circ_pt(i as f64 * tau / n as f64);
pts.push([(x + t * nx) as f32, (y + t * ny) as f32, (z + t * nz) as f32]);
}
pts.push([f32::NAN; 3]);
for i in 0..4usize {
let (x, y, z) = circ_pt(i as f64 * std::f64::consts::FRAC_PI_2);
pts.push([x as f32, y as f32, z as f32]);
pts.push([(x + t * nx) as f32, (y + t * ny) as f32, (z + t * nz) as f32]);
if i < 3 {
pts.push([f32::NAN; 3]);
}
}
return TruckEntity {
object: TruckObject::Lines(pts),
snap_pts,
tangent_geoms: vec![tangent],
key_vertices: vec![],
};
}
let right = builder::vertex(p_right);
let left = builder::vertex(p_left);
let upper = builder::circle_arc(&right, &left, p_top);
let lower = builder::circle_arc(&left, &right, p_bot);
let wire: Wire = [upper, lower].into_iter().collect();
TruckEntity {
object: TruckObject::Contour(wire),
snap_pts: vec![
(cv, SnapHint::Center),
(q(ax), SnapHint::Quadrant),
(q(ay), SnapHint::Quadrant),
(q((-ax.0, -ax.1, -ax.2)), SnapHint::Quadrant),
(q((-ay.0, -ay.1, -ay.2)), SnapHint::Quadrant),
],
tangent_geoms: vec![TangentGeom::Circle {
center: [cwx as f32, cwy as f32, cwz as f32],
radius: rf,
}],
snap_pts,
tangent_geoms: vec![tangent],
key_vertices: vec![],
}
}