diff --git a/src/entities/polyline.rs b/src/entities/polyline.rs index 523fe70e4..9bcfd38d6 100644 --- a/src/entities/polyline.rs +++ b/src/entities/polyline.rs @@ -298,18 +298,30 @@ impl Transformable for Polyline2D { // ── Polyline3D ──────────────────────────────────────────────────────────────── fn tessellate_polyline3d(pl: &Polyline3D) -> TruckEntity { - let pts: Vec<[f32; 3]> = pl - .vertices - .iter() - .map(|v| [v.position.x as f32, v.position.y as f32, v.position.z as f32]) - .collect(); + let to_pt = |v: &acadrust::entities::Vertex3DPolyline| -> [f32; 3] { + [v.position.x as f32, v.position.y as f32, v.position.z as f32] + }; - let mut points = pts.clone(); - if pl.is_closed() && pts.len() >= 2 { - points.push(pts[0]); + // DXF vertex flags: 8 = spline-fit curve point, 16 = spline frame control point. + // When spline-fit vertices are present use them for the wire and control points for snap; + // otherwise treat all vertices uniformly. + let spline_curve: Vec<_> = pl.vertices.iter().filter(|v| v.flags & 8 != 0).collect(); + let ctrl_pts: Vec<_> = pl.vertices.iter().filter(|v| v.flags & 16 != 0).collect(); + + let (wire_pts, key_verts) = if !spline_curve.is_empty() { + let wire: Vec<[f32; 3]> = spline_curve.iter().map(|v| to_pt(v)).collect(); + let ctrl: Vec<[f32; 3]> = ctrl_pts.iter().map(|v| to_pt(v)).collect(); + (wire, ctrl) + } else { + let pts: Vec<[f32; 3]> = pl.vertices.iter().map(to_pt).collect(); + (pts.clone(), pts) + }; + + let mut points = wire_pts.clone(); + if pl.is_closed() && wire_pts.len() >= 2 { + points.push(wire_pts[0]); } - let key_verts = pts.clone(); TruckEntity { object: TruckObject::Lines(points), snap_pts: vec![], diff --git a/src/io/mod.rs b/src/io/mod.rs index 26cd5ed64..6bef9e876 100644 --- a/src/io/mod.rs +++ b/src/io/mod.rs @@ -170,13 +170,22 @@ pub fn save_dxf(doc: &CadDocument, path: &Path) -> Result<(), String> { // ── DXF post-load fixups ────────────────────────────────────────────────── -/// The acadrust DXF reader stores LinearDimension.rotation directly from DXF -/// group code 50, which is in degrees. DWG and our own dimension-creation code -/// store it in radians. Convert so tessellation can call cos/sin uniformly. +/// The acadrust DXF reader stores several rotation fields directly from DXF +/// group code 50 in degrees, while DWG and our own creation code store radians. +/// Apply to_radians() on load so tessellation can call cos/sin uniformly. fn fix_dxf_dimension_rotations(doc: &mut CadDocument) { for entity in doc.entities_mut() { - if let EntityType::Dimension(Dimension::Linear(d)) = entity { - d.rotation = d.rotation.to_radians(); + match entity { + EntityType::Dimension(Dimension::Linear(d)) => { + d.rotation = d.rotation.to_radians(); + } + EntityType::AttributeDefinition(a) => { + a.rotation = a.rotation.to_radians(); + } + EntityType::AttributeEntity(a) => { + a.rotation = a.rotation.to_radians(); + } + _ => {} } } }