forked from 1b-agent/opencadstudio-upstream
Convert polyline bulge segments to analytical TangentGeom::Arc
- Add bulge_arc_to_tangent helper to convert 2D BulgeArc into a 3D TangentGeom::Arc preserving center, plane axes, radius, and CCW sweep angles. - Replace full TangentGeom::Circle emission with TangentGeom::Arc across LwPolyline and Polyline2D paths. - Enables single-arc polylines to be extracted and rendered as analytical GPU arcs with circle.wgsl. - Add unit test verifying single bulge polyline extracts as analytical GPU arc.
This commit is contained in:
1 parent
73cd759ca4
commit
822b0afce5
4 files changed
+67
-36
No files matched your search
@@ -702,6 +702,30 @@ pub fn parse_angle_deg(value: &str) -> Option<f64> {
|
|||||||
/// there is one obvious place to see that the maths moved out.
|
/// there is one obvious place to see that the maths moved out.
|
||||||
pub use cadkernel::geom2d::BulgeArc;
|
pub use cadkernel::geom2d::BulgeArc;
|
||||||
|
|
||||||
|
/// Convert a 2D BulgeArc into a 3D TangentGeom::Arc with its world center,
|
||||||
|
/// plane axes, radius, and counter-clockwise start/end sweep angles.
|
||||||
|
pub fn bulge_arc_to_tangent(
|
||||||
|
arc: &BulgeArc,
|
||||||
|
to_wcs: &dyn Fn(f64, f64) -> (f64, f64, f64),
|
||||||
|
normal: (f64, f64, f64),
|
||||||
|
) -> crate::scene::model::wire_model::TangentGeom {
|
||||||
|
let (cwx, cwy, cwz) = to_wcs(arc.center[0], arc.center[1]);
|
||||||
|
let (ax, ay) = crate::scene::view::transform::ocs_axes(normal);
|
||||||
|
let (sa, ea) = if arc.sweep >= 0.0 {
|
||||||
|
(arc.start_angle, arc.end_angle)
|
||||||
|
} else {
|
||||||
|
(arc.end_angle, arc.start_angle)
|
||||||
|
};
|
||||||
|
crate::scene::model::wire_model::TangentGeom::Arc {
|
||||||
|
center: [cwx, cwy, cwz],
|
||||||
|
axis_x: [ax.0, ax.1, ax.2],
|
||||||
|
axis_y: [ay.0, ay.1, ay.2],
|
||||||
|
radius: arc.radius,
|
||||||
|
start_angle: sa,
|
||||||
|
end_angle: ea,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Triangulate the solid bands a `wide_fills` returns into the flat WCS f64
|
/// Triangulate the solid bands a `wide_fills` returns into the flat WCS f64
|
||||||
/// triangle list `RenderEntity::pick_tris` carries, so a wide polyline is
|
/// triangle list `RenderEntity::pick_tris` carries, so a wide polyline is
|
||||||
/// selectable across the band it draws and not just along its centreline.
|
/// selectable across the band it draws and not just along its centreline.
|
||||||
|
|||||||
@@ -351,11 +351,7 @@ fn to_render(pline: &LwPolyline, fill_mode: bool) -> RenderEntity {
|
|||||||
} else if let Some(arc) =
|
} else if let Some(arc) =
|
||||||
crate::entities::common::BulgeArc::from_bulge([ox0, oy0], [ox1, oy1], bulge)
|
crate::entities::common::BulgeArc::from_bulge([ox0, oy0], [ox1, oy1], bulge)
|
||||||
{
|
{
|
||||||
let (wcx, wcy, wcz) = to_wcs(arc.center[0], arc.center[1]);
|
tgs.push(crate::entities::common::bulge_arc_to_tangent(&arc, &to_wcs, normal));
|
||||||
tgs.push(TangentGeom::Circle {
|
|
||||||
center: [wcx as f32, wcy as f32, wcz as f32],
|
|
||||||
radius: arc.radius as f32,
|
|
||||||
});
|
|
||||||
for s in arc
|
for s in arc
|
||||||
.tessellate_angle(cadkernel::tessellation::DEFAULT_ANGLE)
|
.tessellate_angle(cadkernel::tessellation::DEFAULT_ANGLE)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
@@ -407,11 +403,7 @@ fn to_render(pline: &LwPolyline, fill_mode: bool) -> RenderEntity {
|
|||||||
[v1.location.x, v1.location.y],
|
[v1.location.x, v1.location.y],
|
||||||
v0.bulge,
|
v0.bulge,
|
||||||
) {
|
) {
|
||||||
let (wcx, wcy, wcz) = to_wcs(arc.center[0], arc.center[1]);
|
tgs.push(crate::entities::common::bulge_arc_to_tangent(&arc, &to_wcs, normal));
|
||||||
tgs.push(TangentGeom::Circle {
|
|
||||||
center: [wcx as f32, wcy as f32, wcz as f32],
|
|
||||||
radius: arc.radius as f32,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let (pts, widths) = crate::entities::common::tapered_band_points(
|
let (pts, widths) = crate::entities::common::tapered_band_points(
|
||||||
@@ -470,11 +462,7 @@ fn to_render(pline: &LwPolyline, fill_mode: bool) -> RenderEntity {
|
|||||||
}
|
}
|
||||||
let (wx1, wy1, wz1) = to_wcs(ox1, oy1);
|
let (wx1, wy1, wz1) = to_wcs(ox1, oy1);
|
||||||
kv.push([wx1, wy1, wz1]);
|
kv.push([wx1, wy1, wz1]);
|
||||||
let (wcx, wcy, wcz) = to_wcs(arc.center[0], arc.center[1]);
|
tgs.push(crate::entities::common::bulge_arc_to_tangent(&arc, &to_wcs, normal));
|
||||||
tgs.push(TangentGeom::Circle {
|
|
||||||
center: [wcx as f32, wcy as f32, wcz as f32],
|
|
||||||
radius: arc.radius as f32,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
if i + 1 < seg_count {
|
if i + 1 < seg_count {
|
||||||
pts.push([f64::NAN; 3]);
|
pts.push([f64::NAN; 3]);
|
||||||
@@ -565,11 +553,8 @@ fn centerline_metadata(
|
|||||||
[end.location.x, end.location.y],
|
[end.location.x, end.location.y],
|
||||||
start.bulge,
|
start.bulge,
|
||||||
) {
|
) {
|
||||||
let center = to_wcs(arc.center[0], arc.center[1]);
|
let normal = (pline.normal.x, pline.normal.y, pline.normal.z);
|
||||||
tangents.push(TangentGeom::Circle {
|
tangents.push(crate::entities::common::bulge_arc_to_tangent(&arc, to_wcs, normal));
|
||||||
center: [center.0 as f32, center.1 as f32, center.2 as f32],
|
|
||||||
radius: arc.radius as f32,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
if index == 0 {
|
if index == 0 {
|
||||||
key_vertices.push([p0.0, p0.1, p0.2]);
|
key_vertices.push([p0.0, p0.1, p0.2]);
|
||||||
|
|||||||
@@ -248,7 +248,7 @@ fn tessellate_polyline2d(pl: &Polyline2D, fill_mode: bool) -> RenderEntity {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
let (tangent_geoms, key_vertices) =
|
let (tangent_geoms, key_vertices) =
|
||||||
centerline_metadata_2d(verts, pl.is_closed(), &to_wcs);
|
centerline_metadata_2d(verts, pl.is_closed(), &to_wcs, normal);
|
||||||
return RenderEntity {
|
return RenderEntity {
|
||||||
pick_tris: Vec::new(),
|
pick_tris: Vec::new(),
|
||||||
object: RenderObject::BoundaryLines {
|
object: RenderObject::BoundaryLines {
|
||||||
@@ -296,11 +296,7 @@ fn tessellate_polyline2d(pl: &Polyline2D, fill_mode: bool) -> RenderEntity {
|
|||||||
} else if let Some(arc) =
|
} else if let Some(arc) =
|
||||||
crate::entities::common::BulgeArc::from_bulge([ox0, oy0], [ox1, oy1], bulge)
|
crate::entities::common::BulgeArc::from_bulge([ox0, oy0], [ox1, oy1], bulge)
|
||||||
{
|
{
|
||||||
let (wcx, wcy, wcz) = to_wcs(arc.center[0], arc.center[1]);
|
tgs.push(crate::entities::common::bulge_arc_to_tangent(&arc, &to_wcs, normal));
|
||||||
tgs.push(TangentGeom::Circle {
|
|
||||||
center: [wcx as f32, wcy as f32, wcz as f32],
|
|
||||||
radius: arc.radius as f32,
|
|
||||||
});
|
|
||||||
for s in arc
|
for s in arc
|
||||||
.tessellate_angle(cadkernel::tessellation::DEFAULT_ANGLE)
|
.tessellate_angle(cadkernel::tessellation::DEFAULT_ANGLE)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
@@ -378,11 +374,7 @@ fn tessellate_polyline2d(pl: &Polyline2D, fill_mode: bool) -> RenderEntity {
|
|||||||
[v1.location.x, v1.location.y],
|
[v1.location.x, v1.location.y],
|
||||||
bulge,
|
bulge,
|
||||||
) {
|
) {
|
||||||
let (wcx, wcy, wcz) = to_wcs(arc.center[0], arc.center[1]);
|
tangents.push(crate::entities::common::bulge_arc_to_tangent(&arc, &to_wcs, normal));
|
||||||
tangents.push(TangentGeom::Circle {
|
|
||||||
center: [wcx as f32, wcy as f32, wcz as f32],
|
|
||||||
radius: arc.radius as f32,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
@@ -464,6 +456,7 @@ fn centerline_metadata_2d(
|
|||||||
verts: &[acadrust::entities::Vertex2D],
|
verts: &[acadrust::entities::Vertex2D],
|
||||||
closed: bool,
|
closed: bool,
|
||||||
to_wcs: &dyn Fn(f64, f64) -> (f64, f64, f64),
|
to_wcs: &dyn Fn(f64, f64) -> (f64, f64, f64),
|
||||||
|
normal: (f64, f64, f64),
|
||||||
) -> (Vec<TangentGeom>, Vec<[f64; 3]>) {
|
) -> (Vec<TangentGeom>, Vec<[f64; 3]>) {
|
||||||
let count = verts.len();
|
let count = verts.len();
|
||||||
let segment_count = if closed {
|
let segment_count = if closed {
|
||||||
@@ -488,11 +481,7 @@ fn centerline_metadata_2d(
|
|||||||
[end.location.x, end.location.y],
|
[end.location.x, end.location.y],
|
||||||
start.bulge,
|
start.bulge,
|
||||||
) {
|
) {
|
||||||
let center = to_wcs(arc.center[0], arc.center[1]);
|
tangents.push(crate::entities::common::bulge_arc_to_tangent(&arc, to_wcs, normal));
|
||||||
tangents.push(TangentGeom::Circle {
|
|
||||||
center: [center.0 as f32, center.1 as f32, center.2 as f32],
|
|
||||||
radius: arc.radius as f32,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
if index == 0 {
|
if index == 0 {
|
||||||
key_vertices.push([p0.0, p0.1, p0.2]);
|
key_vertices.push([p0.0, p0.1, p0.2]);
|
||||||
|
|||||||
@@ -11325,4 +11325,37 @@ mod layout_cache_tests {
|
|||||||
partitioned.circle_instances.len()
|
partitioned.circle_instances.len()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn single_bulge_polyline_extracts_as_analytical_gpu_arc() {
|
||||||
|
let mut s = Scene::new();
|
||||||
|
let mut pline = acadrust::entities::LwPolyline::new();
|
||||||
|
pline.vertices = vec![
|
||||||
|
acadrust::entities::LwVertex {
|
||||||
|
location: acadrust::types::Vector2::new(0.0, 0.0),
|
||||||
|
bulge: 1.0, // semicircle
|
||||||
|
start_width: 0.0,
|
||||||
|
end_width: 0.0,
|
||||||
|
vertex_id: 0,
|
||||||
|
},
|
||||||
|
acadrust::entities::LwVertex {
|
||||||
|
location: acadrust::types::Vector2::new(100.0, 0.0),
|
||||||
|
bulge: 0.0,
|
||||||
|
start_width: 0.0,
|
||||||
|
end_width: 0.0,
|
||||||
|
vertex_id: 0,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
let _ = s.add_entity(EntityType::LwPolyline(pline));
|
||||||
|
|
||||||
|
let wires = s.model_tile_wires_arc(0, &Camera::default(), 1.0, 1000.0);
|
||||||
|
let depths = rustc_hash::FxHashMap::default();
|
||||||
|
let partitioned = crate::scene::pipeline::wire_arena::partition_wires(&wires, &depths);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
partitioned.circle_instances.len(),
|
||||||
|
1,
|
||||||
|
"Single bulge arc polyline must be extracted as analytical GPU arc instance"
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user