forked from 1b-agent/opencadstudio-upstream
fix(render): preserve f64 precision until world_offset subtraction
Entity converters were casting WCS coordinates to f32 before the renderer subtracted world_offset, which destroyed sub-unit precision on drawings sitting at large coordinates (typical UTM-style CAD files). The multileader case made it visible — glyphs warped under rotation — but every entity that emits TruckObject::Lines/SegmentedLines/key_vertices/fill_tris was affected. Type changes (in src/scene/acad_to_truck.rs): - TruckObject::Lines / SegmentedLines: Vec<[f32; 3]> → Vec<[f64; 3]> - TruckEntity::key_vertices / fill_tris: f32 → f64 All ~17 producer files updated to keep WCS coordinates in f64 right up to the TruckEntity boundary. The consumer in scene/tessellate.rs now performs `(x - ox) as f32` (f64 subtract, then cast) for points, key_vertices, and fill_tris — preserving precision near the camera origin even when the drawing sits at million-unit coordinates. catmull_rom_pts (multileader spline) is now f64; the scene path widens its offset-relative f32 ctrl points to f64 around the call and narrows back at the output. Notes: - Table layout still uses glam::Vec3 (f32) internally; widened to f64 only at the TruckEntity boundary for type compatibility. Separate cleanup to switch its internal math to f64 is tracked. - snap_pts and tangent_geoms remain f32 — they are UI feedback (snap candidates, tangent hints) and the precision is sufficient there.
This commit is contained in:
1 parent
8bfa5088c4
commit
288ccff95a
20 files changed
+371
-360
No files matched your search
+10
-22
@@ -51,38 +51,26 @@ fn to_truck(arc: &Arc) -> TruckEntity {
|
||||
let n = 32usize;
|
||||
let ccw_end = if ea >= sa { ea } else { ea + TAU };
|
||||
let (start_a, end_a) = (sa, ccw_end);
|
||||
let mut pts: Vec<[f32; 3]> = Vec::with_capacity((n + 1) * 2 + 8);
|
||||
let mut pts: Vec<[f64; 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([p.x, p.y, p.z]);
|
||||
}
|
||||
pts.push([f32::NAN; 3]);
|
||||
pts.push([f64::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([p.x + t * nx, p.y + t * ny, p.z + t * nz]);
|
||||
}
|
||||
pts.push([f32::NAN; 3]);
|
||||
pts.push([f64::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]);
|
||||
pts.push([ps.x, ps.y, ps.z]);
|
||||
pts.push([ps.x + t * nx, ps.y + t * ny, ps.z + t * nz]);
|
||||
pts.push([f64::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,
|
||||
]);
|
||||
pts.push([pe.x, pe.y, pe.z]);
|
||||
pts.push([pe.x + t * nx, pe.y + t * ny, pe.z + t * nz]);
|
||||
return TruckEntity {
|
||||
object: TruckObject::Lines(pts),
|
||||
snap_pts: vec![(cv, SnapHint::Center)],
|
||||
|
||||
+8
-16
@@ -69,31 +69,23 @@ fn to_truck(circle: &Circle) -> TruckEntity {
|
||||
cwz + r * (c * ax.2 + s * ay.2),
|
||||
)
|
||||
};
|
||||
let mut pts: Vec<[f32; 3]> = Vec::with_capacity((n + 1) * 2 + 4 * 3);
|
||||
let mut pts: Vec<[f64; 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([x, y, z]);
|
||||
}
|
||||
pts.push([f32::NAN; 3]);
|
||||
pts.push([f64::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([x + t * nx, y + t * ny, z + t * nz]);
|
||||
}
|
||||
pts.push([f32::NAN; 3]);
|
||||
pts.push([f64::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,
|
||||
]);
|
||||
pts.push([x, y, z]);
|
||||
pts.push([x + t * nx, y + t * ny, z + t * nz]);
|
||||
if i < 3 {
|
||||
pts.push([f32::NAN; 3]);
|
||||
pts.push([f64::NAN; 3]);
|
||||
}
|
||||
}
|
||||
return TruckEntity {
|
||||
|
||||
@@ -125,9 +125,9 @@ fn to_truck(ell: &Ellipse) -> TruckEntity {
|
||||
let edge = Edge::new(&v_start, &v_end, Curve::BSplineCurve(bspline));
|
||||
let pt_start = ctrl_pts.first().unwrap();
|
||||
let pt_end = ctrl_pts.last().unwrap();
|
||||
let key_vertices = vec![
|
||||
[pt_start.x as f32, pt_start.y as f32, pt_start.z as f32],
|
||||
[pt_end.x as f32, pt_end.y as f32, pt_end.z as f32],
|
||||
let key_vertices: Vec<[f64; 3]> = vec![
|
||||
[pt_start.x, pt_start.y, pt_start.z],
|
||||
[pt_end.x, pt_end.y, pt_end.z],
|
||||
];
|
||||
TruckEntity {
|
||||
object: TruckObject::Curve(edge),
|
||||
|
||||
+16
-16
@@ -13,12 +13,15 @@ use crate::scene::wire_model::TangentGeom;
|
||||
|
||||
fn to_truck(leader: &Leader) -> TruckEntity {
|
||||
let verts = &leader.vertices;
|
||||
let nan = [f32::NAN; 3];
|
||||
let p3 = |v: &acadrust::types::Vector3| -> [f32; 3] { [v.x as f32, v.y as f32, v.z as f32] };
|
||||
let nan = [f64::NAN; 3];
|
||||
let p3 = |v: &acadrust::types::Vector3| -> [f64; 3] { [v.x, v.y, v.z] };
|
||||
let p3f = |v: &acadrust::types::Vector3| -> [f32; 3] {
|
||||
[v.x as f32, v.y as f32, v.z as f32]
|
||||
};
|
||||
|
||||
let mut points: Vec<[f32; 3]> = Vec::new();
|
||||
let mut points: Vec<[f64; 3]> = Vec::new();
|
||||
let mut tangents: Vec<TangentGeom> = Vec::new();
|
||||
let mut key_verts: Vec<[f32; 3]> = Vec::new();
|
||||
let mut key_verts: Vec<[f64; 3]> = Vec::new();
|
||||
|
||||
// Main leader path
|
||||
for v in verts {
|
||||
@@ -26,9 +29,10 @@ fn to_truck(leader: &Leader) -> TruckEntity {
|
||||
key_verts.push(p3(v));
|
||||
}
|
||||
for i in 0..verts.len().saturating_sub(1) {
|
||||
// TangentGeom uses f32 (UI-only); cast at construction.
|
||||
tangents.push(TangentGeom::Line {
|
||||
p1: p3(&verts[i]),
|
||||
p2: p3(&verts[i + 1]),
|
||||
p1: p3f(&verts[i]),
|
||||
p2: p3f(&verts[i + 1]),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -36,12 +40,12 @@ fn to_truck(leader: &Leader) -> TruckEntity {
|
||||
if leader.arrow_enabled && verts.len() >= 2 {
|
||||
let tip = &verts[0];
|
||||
let next = &verts[1];
|
||||
let dx = (next.x - tip.x) as f32;
|
||||
let dy = (next.y - tip.y) as f32;
|
||||
let dx = next.x - tip.x;
|
||||
let dy = next.y - tip.y;
|
||||
let len = (dx * dx + dy * dy).sqrt().max(1e-9);
|
||||
let (dx, dy) = (dx / len, dy / len);
|
||||
let sz = (leader.text_height as f32).max(1.0) * 0.8;
|
||||
let a = std::f32::consts::PI / 6.0;
|
||||
let sz = (leader.text_height).max(1.0) * 0.8;
|
||||
let a = std::f64::consts::PI / 6.0;
|
||||
let (s, c) = a.sin_cos();
|
||||
let tip_f = p3(tip);
|
||||
points.push(nan);
|
||||
@@ -62,12 +66,8 @@ fn to_truck(leader: &Leader) -> TruckEntity {
|
||||
if leader.hookline_enabled && verts.len() >= 2 {
|
||||
let last = verts.last().unwrap();
|
||||
let prev = &verts[verts.len() - 2];
|
||||
let sign = if (last.x - prev.x) >= 0.0 {
|
||||
1.0_f32
|
||||
} else {
|
||||
-1.0_f32
|
||||
};
|
||||
let len = leader.text_height as f32 * 1.5;
|
||||
let sign = if (last.x - prev.x) >= 0.0 { 1.0_f64 } else { -1.0_f64 };
|
||||
let len = leader.text_height * 1.5;
|
||||
let last_f = p3(last);
|
||||
points.push(nan);
|
||||
points.push(last_f);
|
||||
|
||||
+9
-20
@@ -21,38 +21,27 @@ fn to_truck(line: &Line) -> TruckEntity {
|
||||
crate::scene::transform::ocs_point_to_wcs((line.end.x, line.end.y, line.end.z), normal);
|
||||
let p0 = Point3::new(sx, sy, sz);
|
||||
let p1 = Point3::new(ex, ey, ez);
|
||||
let kv = vec![
|
||||
[p0.x as f32, p0.y as f32, p0.z as f32],
|
||||
[p1.x as f32, p1.y as f32, p1.z as f32],
|
||||
];
|
||||
let kv: Vec<[f64; 3]> = vec![[p0.x, p0.y, p0.z], [p1.x, p1.y, p1.z]];
|
||||
let tangent = TangentGeom::Line {
|
||||
p1: kv[0],
|
||||
p2: kv[1],
|
||||
p1: [kv[0][0] as f32, kv[0][1] as f32, kv[0][2] as f32],
|
||||
p2: [kv[1][0] as f32, kv[1][1] as f32, kv[1][2] as f32],
|
||||
};
|
||||
|
||||
if line.thickness.abs() > 1e-10 {
|
||||
let t = line.thickness;
|
||||
let (nx, ny, nz) = normal;
|
||||
let p0t = [
|
||||
(sx + t * nx) as f32,
|
||||
(sy + t * ny) as f32,
|
||||
(sz + t * nz) as f32,
|
||||
];
|
||||
let p1t = [
|
||||
(ex + t * nx) as f32,
|
||||
(ey + t * ny) as f32,
|
||||
(ez + t * nz) as f32,
|
||||
];
|
||||
let pts = vec![
|
||||
let p0t = [sx + t * nx, sy + t * ny, sz + t * nz];
|
||||
let p1t = [ex + t * nx, ey + t * ny, ez + t * nz];
|
||||
let pts: Vec<[f64; 3]> = vec![
|
||||
kv[0],
|
||||
kv[1],
|
||||
[f32::NAN; 3],
|
||||
[f64::NAN; 3],
|
||||
p0t,
|
||||
p1t,
|
||||
[f32::NAN; 3],
|
||||
[f64::NAN; 3],
|
||||
kv[0],
|
||||
p0t,
|
||||
[f32::NAN; 3],
|
||||
[f64::NAN; 3],
|
||||
kv[1],
|
||||
p1t,
|
||||
];
|
||||
|
||||
+33
-34
@@ -74,44 +74,40 @@ fn bulge_from_midpoint(p0: [f64; 2], p1: [f64; 2], mid: [f64; 2]) -> Option<f64>
|
||||
/// Shared by LwPolyline and Polyline2D thickness paths.
|
||||
fn thick_segments(
|
||||
seg_data: &[(f64, f64, f64, f64)], // (x0, y0, x1, y1) per seg — or use run of (x,y,bulge)
|
||||
path_pts: &[[f32; 3]],
|
||||
path_pts: &[[f64; 3]],
|
||||
thickness: f64,
|
||||
normal: (f64, f64, f64),
|
||||
key_verts: Vec<[f32; 3]>,
|
||||
key_verts: Vec<[f64; 3]>,
|
||||
tangents: Vec<TangentGeom>,
|
||||
) -> TruckEntity {
|
||||
let (nx, ny, nz) = normal;
|
||||
let t = thickness;
|
||||
let off = |p: [f32; 3]| -> [f32; 3] {
|
||||
[
|
||||
(p[0] as f64 + t * nx) as f32,
|
||||
(p[1] as f64 + t * ny) as f32,
|
||||
(p[2] as f64 + t * nz) as f32,
|
||||
]
|
||||
let off = |p: [f64; 3]| -> [f64; 3] {
|
||||
[p[0] + t * nx, p[1] + t * ny, p[2] + t * nz]
|
||||
};
|
||||
let mut pts: Vec<[f32; 3]> = Vec::with_capacity(path_pts.len() * 2 + seg_data.len() * 3 + 4);
|
||||
let mut pts: Vec<[f64; 3]> = Vec::with_capacity(path_pts.len() * 2 + seg_data.len() * 3 + 4);
|
||||
// Bottom path
|
||||
pts.extend_from_slice(path_pts);
|
||||
pts.push([f32::NAN; 3]);
|
||||
pts.push([f64::NAN; 3]);
|
||||
// Top path
|
||||
for &p in path_pts {
|
||||
pts.push(off(p));
|
||||
}
|
||||
// Walls at each vertex (seg_data.0/.1 = start x/y of each seg, last seg appends its end too)
|
||||
if !seg_data.is_empty() {
|
||||
pts.push([f32::NAN; 3]);
|
||||
pts.push([f64::NAN; 3]);
|
||||
for (k, &(x0, y0, _x1, _y1)) in seg_data.iter().enumerate() {
|
||||
let pb = key_verts[k];
|
||||
let _ = (x0, y0); // key_verts already has correct WCS
|
||||
pts.push(pb);
|
||||
pts.push(off(pb));
|
||||
if k + 1 < seg_data.len() {
|
||||
pts.push([f32::NAN; 3]);
|
||||
pts.push([f64::NAN; 3]);
|
||||
}
|
||||
}
|
||||
// Last wall at the final vertex
|
||||
if let Some(&last) = key_verts.last() {
|
||||
pts.push([f32::NAN; 3]);
|
||||
pts.push([f64::NAN; 3]);
|
||||
pts.push(last);
|
||||
pts.push(off(last));
|
||||
}
|
||||
@@ -143,7 +139,7 @@ fn to_truck(pline: &LwPolyline) -> TruckEntity {
|
||||
let seg_count = if pline.is_closed { count } else { count - 1 };
|
||||
let mut edges: Vec<Edge> = Vec::new();
|
||||
let mut tangents: Vec<TangentGeom> = Vec::new();
|
||||
let mut key_verts: Vec<[f32; 3]> = Vec::new();
|
||||
let mut key_verts: Vec<[f64; 3]> = Vec::new();
|
||||
|
||||
// Convert OCS (x, y, elevation) to WCS Point3.
|
||||
let to_wcs = |x: f64, y: f64| -> (f64, f64, f64) {
|
||||
@@ -155,14 +151,14 @@ fn to_truck(pline: &LwPolyline) -> TruckEntity {
|
||||
};
|
||||
|
||||
if pline.thickness.abs() > 1e-10 {
|
||||
let mut path: Vec<[f32; 3]> = Vec::new();
|
||||
let mut kv: Vec<[f32; 3]> = Vec::new();
|
||||
let mut path: Vec<[f64; 3]> = Vec::new();
|
||||
let mut kv: Vec<[f64; 3]> = Vec::new();
|
||||
let mut tgs: Vec<TangentGeom> = Vec::new();
|
||||
let mut seg_data: Vec<(f64, f64, f64, f64)> = Vec::new();
|
||||
// First vertex
|
||||
let (w0x, w0y, w0z) = to_wcs(verts[0].location.x, verts[0].location.y);
|
||||
path.push([w0x as f32, w0y as f32, w0z as f32]);
|
||||
kv.push([w0x as f32, w0y as f32, w0z as f32]);
|
||||
path.push([w0x, w0y, w0z]);
|
||||
kv.push([w0x, w0y, w0z]);
|
||||
for i in 0..seg_count {
|
||||
let va = &verts[i];
|
||||
let vb = &verts[(i + 1) % count];
|
||||
@@ -171,10 +167,12 @@ fn to_truck(pline: &LwPolyline) -> TruckEntity {
|
||||
let bulge = va.bulge;
|
||||
if bulge.abs() < 1e-9 {
|
||||
let (wx, wy, wz) = to_wcs(ox1, oy1);
|
||||
path.push([wx as f32, wy as f32, wz as f32]);
|
||||
path.push([wx, wy, wz]);
|
||||
let p1_pt = path[path.len() - 2];
|
||||
let p2_pt = *path.last().unwrap();
|
||||
tgs.push(TangentGeom::Line {
|
||||
p1: path[path.len() - 2],
|
||||
p2: *path.last().unwrap(),
|
||||
p1: [p1_pt[0] as f32, p1_pt[1] as f32, p1_pt[2] as f32],
|
||||
p2: [p2_pt[0] as f32, p2_pt[1] as f32, p2_pt[2] as f32],
|
||||
});
|
||||
} else {
|
||||
let angle = 4.0 * bulge.atan();
|
||||
@@ -209,11 +207,11 @@ fn to_truck(pline: &LwPolyline) -> TruckEntity {
|
||||
for j in 1..=16usize {
|
||||
let a = a0 + (a1 - a0) * (j as f64 / 16.0);
|
||||
let (wx, wy, wz) = to_wcs(ocx + r * a.cos(), ocy + r * a.sin());
|
||||
path.push([wx as f32, wy as f32, wz as f32]);
|
||||
path.push([wx, wy, wz]);
|
||||
}
|
||||
}
|
||||
let (wbx, wby, wbz) = to_wcs(ox1, oy1);
|
||||
kv.push([wbx as f32, wby as f32, wbz as f32]);
|
||||
kv.push([wbx, wby, wbz]);
|
||||
seg_data.push((ox0, oy0, ox1, oy1));
|
||||
}
|
||||
return thick_segments(&seg_data, &path, pline.thickness, normal, kv, tgs);
|
||||
@@ -221,9 +219,10 @@ fn to_truck(pline: &LwPolyline) -> TruckEntity {
|
||||
|
||||
// plinegen=false: NaN-separated segments so the linetype pattern restarts per vertex.
|
||||
if !pline.plinegen {
|
||||
let mut pts: Vec<[f32; 3]> = Vec::new();
|
||||
let mut pts: Vec<[f64; 3]> = Vec::new();
|
||||
let mut tgs: Vec<TangentGeom> = Vec::new();
|
||||
let mut kv: Vec<[f32; 3]> = Vec::new();
|
||||
let mut kv: Vec<[f64; 3]> = Vec::new();
|
||||
let to_f32 = |p: [f64; 3]| -> [f32; 3] { [p[0] as f32, p[1] as f32, p[2] as f32] };
|
||||
for i in 0..seg_count {
|
||||
let va = &verts[i];
|
||||
let vb = &verts[(i + 1) % count];
|
||||
@@ -231,19 +230,19 @@ fn to_truck(pline: &LwPolyline) -> TruckEntity {
|
||||
let (ox1, oy1) = (vb.location.x, vb.location.y);
|
||||
let bulge = va.bulge;
|
||||
let (wx0, wy0, wz0) = to_wcs(ox0, oy0);
|
||||
let p_start = [wx0 as f32, wy0 as f32, wz0 as f32];
|
||||
let p_start = [wx0, wy0, wz0];
|
||||
pts.push(p_start);
|
||||
if i == 0 {
|
||||
kv.push(p_start);
|
||||
}
|
||||
if bulge.abs() < 1e-9 {
|
||||
let (wx1, wy1, wz1) = to_wcs(ox1, oy1);
|
||||
let p_end = [wx1 as f32, wy1 as f32, wz1 as f32];
|
||||
let p_end = [wx1, wy1, wz1];
|
||||
pts.push(p_end);
|
||||
kv.push(p_end);
|
||||
tgs.push(TangentGeom::Line {
|
||||
p1: p_start,
|
||||
p2: p_end,
|
||||
p1: to_f32(p_start),
|
||||
p2: to_f32(p_end),
|
||||
});
|
||||
} else {
|
||||
let angle = 4.0 * bulge.atan();
|
||||
@@ -273,10 +272,10 @@ fn to_truck(pline: &LwPolyline) -> TruckEntity {
|
||||
for j in 1..=16usize {
|
||||
let a = a0 + (a1 - a0) * (j as f64 / 16.0);
|
||||
let (wx, wy, wz) = to_wcs(ocx + r * a.cos(), ocy + r * a.sin());
|
||||
pts.push([wx as f32, wy as f32, wz as f32]);
|
||||
pts.push([wx, wy, wz]);
|
||||
}
|
||||
let (wx1, wy1, wz1) = to_wcs(ox1, oy1);
|
||||
kv.push([wx1 as f32, wy1 as f32, wz1 as f32]);
|
||||
kv.push([wx1, wy1, wz1]);
|
||||
let (wcx, wcy, wcz) = to_wcs(ocx, ocy);
|
||||
tgs.push(TangentGeom::Circle {
|
||||
center: [wcx as f32, wcy as f32, wcz as f32],
|
||||
@@ -284,7 +283,7 @@ fn to_truck(pline: &LwPolyline) -> TruckEntity {
|
||||
});
|
||||
}
|
||||
if i + 1 < seg_count {
|
||||
pts.push([f32::NAN; 3]);
|
||||
pts.push([f64::NAN; 3]);
|
||||
}
|
||||
}
|
||||
return TruckEntity {
|
||||
@@ -351,9 +350,9 @@ fn to_truck(pline: &LwPolyline) -> TruckEntity {
|
||||
}
|
||||
|
||||
if i == 0 {
|
||||
key_verts.push([p0.x as f32, p0.y as f32, p0.z as f32]);
|
||||
key_verts.push([p0.x, p0.y, p0.z]);
|
||||
}
|
||||
key_verts.push([p1.x as f32, p1.y as f32, p1.z as f32]);
|
||||
key_verts.push([p1.x, p1.y, p1.z]);
|
||||
}
|
||||
|
||||
TruckEntity {
|
||||
|
||||
+33
-33
@@ -10,7 +10,11 @@ use crate::scene::wire_model::SnapHint;
|
||||
|
||||
// ── Face3D ────────────────────────────────────────────────────────────────────
|
||||
|
||||
fn v3(v: &acadrust::types::Vector3) -> [f32; 3] {
|
||||
fn v3(v: &acadrust::types::Vector3) -> [f64; 3] {
|
||||
[v.x, v.y, v.z]
|
||||
}
|
||||
|
||||
fn v3f32(v: &acadrust::types::Vector3) -> [f32; 3] {
|
||||
[v.x as f32, v.y as f32, v.z as f32]
|
||||
}
|
||||
|
||||
@@ -20,13 +24,17 @@ impl TruckConvertible for Face3D {
|
||||
let p1 = v3(&self.second_corner);
|
||||
let p2 = v3(&self.third_corner);
|
||||
let p3 = v3(&self.fourth_corner);
|
||||
let p0f = v3f32(&self.first_corner);
|
||||
let p1f = v3f32(&self.second_corner);
|
||||
let p2f = v3f32(&self.third_corner);
|
||||
let p3f = v3f32(&self.fourth_corner);
|
||||
let inv = self.invisible_edges;
|
||||
|
||||
// Add edge as a line segment (separated by NaN from previous edges).
|
||||
let mut pts: Vec<[f32; 3]> = Vec::new();
|
||||
let mut add_edge = |a: [f32; 3], b: [f32; 3]| {
|
||||
let mut pts: Vec<[f64; 3]> = Vec::new();
|
||||
let mut add_edge = |a: [f64; 3], b: [f64; 3]| {
|
||||
if !pts.is_empty() {
|
||||
pts.push([f32::NAN; 3]);
|
||||
pts.push([f64::NAN; 3]);
|
||||
}
|
||||
pts.push(a);
|
||||
pts.push(b);
|
||||
@@ -50,17 +58,17 @@ impl TruckConvertible for Face3D {
|
||||
let cx = (p0[0] + p1[0] + p2[0] + p3[0]) / 4.0;
|
||||
let cy = (p0[1] + p1[1] + p2[1] + p3[1]) / 4.0;
|
||||
let cz = (p0[2] + p1[2] + p2[2] + p3[2]) / 4.0;
|
||||
let s = 0.1_f32;
|
||||
let s = 0.1_f64;
|
||||
pts = vec![[cx - s, cy, cz], [cx + s, cy, cz]];
|
||||
}
|
||||
|
||||
Some(TruckEntity {
|
||||
object: TruckObject::Lines(pts),
|
||||
snap_pts: vec![
|
||||
(Vec3::from(p0), SnapHint::Node),
|
||||
(Vec3::from(p1), SnapHint::Node),
|
||||
(Vec3::from(p2), SnapHint::Node),
|
||||
(Vec3::from(p3), SnapHint::Node),
|
||||
(Vec3::from(p0f), SnapHint::Node),
|
||||
(Vec3::from(p1f), SnapHint::Node),
|
||||
(Vec3::from(p2f), SnapHint::Node),
|
||||
(Vec3::from(p3f), SnapHint::Node),
|
||||
],
|
||||
tangent_geoms: vec![],
|
||||
key_vertices: vec![p0, p1, p2, p3],
|
||||
@@ -72,10 +80,10 @@ impl TruckConvertible for Face3D {
|
||||
impl Grippable for Face3D {
|
||||
fn grips(&self) -> Vec<GripDef> {
|
||||
vec![
|
||||
square_grip(0, Vec3::from(v3(&self.first_corner))),
|
||||
square_grip(1, Vec3::from(v3(&self.second_corner))),
|
||||
square_grip(2, Vec3::from(v3(&self.third_corner))),
|
||||
square_grip(3, Vec3::from(v3(&self.fourth_corner))),
|
||||
square_grip(0, Vec3::from(v3f32(&self.first_corner))),
|
||||
square_grip(1, Vec3::from(v3f32(&self.second_corner))),
|
||||
square_grip(2, Vec3::from(v3f32(&self.third_corner))),
|
||||
square_grip(3, Vec3::from(v3f32(&self.fourth_corner))),
|
||||
]
|
||||
}
|
||||
|
||||
@@ -178,21 +186,17 @@ impl TruckConvertible for PolygonMesh {
|
||||
.flags
|
||||
.contains(acadrust::entities::PolygonMeshFlags::CLOSED_N);
|
||||
|
||||
let pt = |i: usize, j: usize| -> [f32; 3] {
|
||||
let pt = |i: usize, j: usize| -> [f64; 3] {
|
||||
let v = &self.vertices[i * n + j];
|
||||
[
|
||||
v.location.x as f32,
|
||||
v.location.y as f32,
|
||||
v.location.z as f32,
|
||||
]
|
||||
[v.location.x, v.location.y, v.location.z]
|
||||
};
|
||||
|
||||
let mut pts: Vec<[f32; 3]> = Vec::new();
|
||||
let mut fill_tris: Vec<[f32; 3]> = Vec::new();
|
||||
let mut pts: Vec<[f64; 3]> = Vec::new();
|
||||
let mut fill_tris: Vec<[f64; 3]> = Vec::new();
|
||||
|
||||
// Rows (M direction).
|
||||
for i in 0..m {
|
||||
pts.push([f32::NAN; 3]);
|
||||
pts.push([f64::NAN; 3]);
|
||||
for j in 0..n {
|
||||
pts.push(pt(i, j));
|
||||
}
|
||||
@@ -203,7 +207,7 @@ impl TruckConvertible for PolygonMesh {
|
||||
|
||||
// Columns (N direction).
|
||||
for j in 0..n {
|
||||
pts.push([f32::NAN; 3]);
|
||||
pts.push([f64::NAN; 3]);
|
||||
for i in 0..m {
|
||||
pts.push(pt(i, j));
|
||||
}
|
||||
@@ -309,23 +313,19 @@ impl TruckConvertible for PolyfaceMesh {
|
||||
return None;
|
||||
}
|
||||
|
||||
let get_v = |idx: i16| -> Option<[f32; 3]> {
|
||||
let get_v = |idx: i16| -> Option<[f64; 3]> {
|
||||
let i = (idx.abs() as usize).checked_sub(1)?;
|
||||
let v = self.vertices.get(i)?;
|
||||
Some([
|
||||
v.location.x as f32,
|
||||
v.location.y as f32,
|
||||
v.location.z as f32,
|
||||
])
|
||||
Some([v.location.x, v.location.y, v.location.z])
|
||||
};
|
||||
|
||||
let mut pts: Vec<[f32; 3]> = Vec::new();
|
||||
let mut fill_tris: Vec<[f32; 3]> = Vec::new();
|
||||
let mut pts: Vec<[f64; 3]> = Vec::new();
|
||||
let mut fill_tris: Vec<[f64; 3]> = Vec::new();
|
||||
|
||||
for face in &self.faces {
|
||||
// Indices: 0 means unused. Negative = invisible edge (still render for wireframe).
|
||||
let indices = [face.index1, face.index2, face.index3, face.index4];
|
||||
let verts: Vec<[f32; 3]> = indices
|
||||
let verts: Vec<[f64; 3]> = indices
|
||||
.iter()
|
||||
.filter(|&&i| i != 0)
|
||||
.filter_map(|&i| get_v(i))
|
||||
@@ -334,7 +334,7 @@ impl TruckConvertible for PolyfaceMesh {
|
||||
if verts.len() < 2 {
|
||||
continue;
|
||||
}
|
||||
pts.push([f32::NAN; 3]);
|
||||
pts.push([f64::NAN; 3]);
|
||||
for &p in &verts {
|
||||
pts.push(p);
|
||||
}
|
||||
|
||||
+29
-39
@@ -20,23 +20,19 @@ impl TruckConvertible for MLine {
|
||||
// Spine: center line connecting all vertex positions.
|
||||
// Also attempt to draw parallel offset lines (±scale/2 in miter direction)
|
||||
// when scale_factor is non-zero.
|
||||
let scale = self.scale_factor as f32;
|
||||
let scale = self.scale_factor;
|
||||
|
||||
let mut pts: Vec<[f32; 3]> = Vec::new();
|
||||
let mut pts: Vec<[f64; 3]> = Vec::new();
|
||||
|
||||
// Center spine.
|
||||
for v in &self.vertices {
|
||||
pts.push([
|
||||
v.position.x as f32,
|
||||
v.position.y as f32,
|
||||
v.position.z as f32,
|
||||
]);
|
||||
pts.push([v.position.x, v.position.y, v.position.z]);
|
||||
}
|
||||
if closed && n >= 2 {
|
||||
pts.push([
|
||||
self.vertices[0].position.x as f32,
|
||||
self.vertices[0].position.y as f32,
|
||||
self.vertices[0].position.z as f32,
|
||||
self.vertices[0].position.x,
|
||||
self.vertices[0].position.y,
|
||||
self.vertices[0].position.z,
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -44,28 +40,28 @@ impl TruckConvertible for MLine {
|
||||
// along each vertex's miter direction.
|
||||
if scale.abs() > 1e-6 {
|
||||
let half = scale * 0.5;
|
||||
for sign in [-1.0_f32, 1.0_f32] {
|
||||
for sign in [-1.0_f64, 1.0_f64] {
|
||||
let offset = half * sign;
|
||||
pts.push([f32::NAN; 3]);
|
||||
pts.push([f64::NAN; 3]);
|
||||
for v in &self.vertices {
|
||||
let mx = v.miter.x as f32;
|
||||
let my = v.miter.y as f32;
|
||||
let mz = v.miter.z as f32;
|
||||
let mx = v.miter.x;
|
||||
let my = v.miter.y;
|
||||
let mz = v.miter.z;
|
||||
pts.push([
|
||||
v.position.x as f32 + mx * offset,
|
||||
v.position.y as f32 + my * offset,
|
||||
v.position.z as f32 + mz * offset,
|
||||
v.position.x + mx * offset,
|
||||
v.position.y + my * offset,
|
||||
v.position.z + mz * offset,
|
||||
]);
|
||||
}
|
||||
if closed && n >= 2 {
|
||||
let v0 = &self.vertices[0];
|
||||
let mx = v0.miter.x as f32;
|
||||
let my = v0.miter.y as f32;
|
||||
let mz = v0.miter.z as f32;
|
||||
let mx = v0.miter.x;
|
||||
let my = v0.miter.y;
|
||||
let mz = v0.miter.z;
|
||||
pts.push([
|
||||
v0.position.x as f32 + mx * offset,
|
||||
v0.position.y as f32 + my * offset,
|
||||
v0.position.z as f32 + mz * offset,
|
||||
v0.position.x + mx * offset,
|
||||
v0.position.y + my * offset,
|
||||
v0.position.z + mz * offset,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -74,14 +70,14 @@ impl TruckConvertible for MLine {
|
||||
// at the first and last vertex of an open MLine.
|
||||
if !closed {
|
||||
let cap_v = |v: &acadrust::entities::MLineVertex| {
|
||||
let mx = v.miter.x as f32;
|
||||
let my = v.miter.y as f32;
|
||||
let mz = v.miter.z as f32;
|
||||
let px = v.position.x as f32;
|
||||
let py = v.position.y as f32;
|
||||
let pz = v.position.z as f32;
|
||||
let mx = v.miter.x;
|
||||
let my = v.miter.y;
|
||||
let mz = v.miter.z;
|
||||
let px = v.position.x;
|
||||
let py = v.position.y;
|
||||
let pz = v.position.z;
|
||||
[
|
||||
[f32::NAN; 3],
|
||||
[f64::NAN; 3],
|
||||
[px + mx * (-half), py + my * (-half), pz + mz * (-half)],
|
||||
[px + mx * half, py + my * half, pz + mz * half],
|
||||
]
|
||||
@@ -91,16 +87,10 @@ impl TruckConvertible for MLine {
|
||||
}
|
||||
}
|
||||
|
||||
let key_verts: Vec<[f32; 3]> = self
|
||||
let key_verts: Vec<[f64; 3]> = self
|
||||
.vertices
|
||||
.iter()
|
||||
.map(|v| {
|
||||
[
|
||||
v.position.x as f32,
|
||||
v.position.y as f32,
|
||||
v.position.z as f32,
|
||||
]
|
||||
})
|
||||
.map(|v| [v.position.x, v.position.y, v.position.z])
|
||||
.collect();
|
||||
|
||||
let snap_pts = self
|
||||
|
||||
+33
-23
@@ -39,7 +39,9 @@ use crate::scene::wire_model::{SnapHint, TangentGeom};
|
||||
// ── TruckConvertible ────────────────────────────────────────────────────────
|
||||
|
||||
/// Catmull-Rom spline tessellation through `ctrl` points, `segs_per_span` segments each.
|
||||
pub(crate) fn catmull_rom_pts(ctrl: &[[f32; 3]], segs_per_span: u32) -> Vec<[f32; 3]> {
|
||||
/// Operates in f64 so it can be applied to either WCS-direct coordinates (entity path)
|
||||
/// or offset-relative coordinates (scene path) without precision loss.
|
||||
pub(crate) fn catmull_rom_pts(ctrl: &[[f64; 3]], segs_per_span: u32) -> Vec<[f64; 3]> {
|
||||
let n = ctrl.len();
|
||||
let mut out = Vec::new();
|
||||
for i in 0..n.saturating_sub(1) {
|
||||
@@ -48,10 +50,10 @@ pub(crate) fn catmull_rom_pts(ctrl: &[[f32; 3]], segs_per_span: u32) -> Vec<[f32
|
||||
let p2 = ctrl[i + 1];
|
||||
let p3 = if i + 2 < n { ctrl[i + 2] } else { ctrl[n - 1] };
|
||||
for j in 0..=segs_per_span {
|
||||
let t = j as f32 / segs_per_span as f32;
|
||||
let t = j as f64 / segs_per_span as f64;
|
||||
let t2 = t * t;
|
||||
let t3 = t2 * t;
|
||||
let mut pt = [0.0_f32; 3];
|
||||
let mut pt = [0.0_f64; 3];
|
||||
for k in 0..3 {
|
||||
pt[k] = 0.5
|
||||
* ((2.0 * p1[k])
|
||||
@@ -66,20 +68,26 @@ pub(crate) fn catmull_rom_pts(ctrl: &[[f32; 3]], segs_per_span: u32) -> Vec<[f32
|
||||
}
|
||||
|
||||
fn to_truck(ml: &MultiLeader, document: &acadrust::CadDocument) -> Option<TruckEntity> {
|
||||
let nan = [f32::NAN; 3];
|
||||
let p3 = |v: &acadrust::types::Vector3| -> [f32; 3] { [v.x as f32, v.y as f32, v.z as f32] };
|
||||
let nan = [f64::NAN; 3];
|
||||
let p3 = |v: &acadrust::types::Vector3| -> [f64; 3] { [v.x, v.y, v.z] };
|
||||
|
||||
let arrow_size = ml.arrowhead_size as f32;
|
||||
let arrow_size = ml.arrowhead_size;
|
||||
let draw_arrow = arrow_size > 0.0;
|
||||
let invisible = ml.path_type == MultiLeaderPathType::Invisible;
|
||||
|
||||
let mut points: Vec<[f32; 3]> = Vec::new();
|
||||
let mut points: Vec<[f64; 3]> = Vec::new();
|
||||
let mut tangents: Vec<TangentGeom> = Vec::new();
|
||||
let mut key_verts: Vec<[f32; 3]> = Vec::new();
|
||||
let mut key_verts: Vec<[f64; 3]> = Vec::new();
|
||||
let mut snap_pts: Vec<(Vec3, SnapHint)> = Vec::new();
|
||||
let mut first = true;
|
||||
|
||||
let node = |arr: [f32; 3]| (Vec3::from(arr), SnapHint::Node);
|
||||
// snap_pts uses f32 (UI-only); cast at construction.
|
||||
let node = |arr: [f64; 3]| {
|
||||
(
|
||||
Vec3::new(arr[0] as f32, arr[1] as f32, arr[2] as f32),
|
||||
SnapHint::Node,
|
||||
)
|
||||
};
|
||||
|
||||
for root in &ml.context.leader_roots {
|
||||
let cp = &root.connection_point;
|
||||
@@ -98,7 +106,7 @@ fn to_truck(ml: &MultiLeader, document: &acadrust::CadDocument) -> Option<TruckE
|
||||
first = false;
|
||||
|
||||
// Build the full control-point list: line.points + connection_point
|
||||
let mut ctrl: Vec<[f32; 3]> = line.points.iter().map(|p| p3(p)).collect();
|
||||
let mut ctrl: Vec<[f64; 3]> = line.points.iter().map(|p| p3(p)).collect();
|
||||
let last_f = *ctrl.last().unwrap_or(&cp_f);
|
||||
let dist = ((last_f[0] - cp_f[0]).powi(2) + (last_f[1] - cp_f[1]).powi(2)).sqrt();
|
||||
if dist > 1e-9 {
|
||||
@@ -122,9 +130,11 @@ fn to_truck(ml: &MultiLeader, document: &acadrust::CadDocument) -> Option<TruckE
|
||||
}
|
||||
|
||||
for i in 0..ctrl.len().saturating_sub(1) {
|
||||
let a = ctrl[i];
|
||||
let b = ctrl[i + 1];
|
||||
tangents.push(TangentGeom::Line {
|
||||
p1: ctrl[i],
|
||||
p2: ctrl[i + 1],
|
||||
p1: [a[0] as f32, a[1] as f32, a[2] as f32],
|
||||
p2: [b[0] as f32, b[1] as f32, b[2] as f32],
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -138,11 +148,11 @@ fn to_truck(ml: &MultiLeader, document: &acadrust::CadDocument) -> Option<TruckE
|
||||
} else {
|
||||
*cp
|
||||
};
|
||||
let dx = (next.x - tip.x) as f32;
|
||||
let dy = (next.y - tip.y) as f32;
|
||||
let dx = next.x - tip.x;
|
||||
let dy = next.y - tip.y;
|
||||
let dl = (dx * dx + dy * dy).sqrt().max(1e-9);
|
||||
let (dx, dy) = (dx / dl, dy / dl);
|
||||
let a = std::f32::consts::PI / 6.0;
|
||||
let a = std::f64::consts::PI / 6.0;
|
||||
let (s, c) = a.sin_cos();
|
||||
points.push(nan);
|
||||
points.push([
|
||||
@@ -166,11 +176,7 @@ fn to_truck(ml: &MultiLeader, document: &acadrust::CadDocument) -> Option<TruckE
|
||||
let d = ml.dogleg_length;
|
||||
points.push(nan);
|
||||
points.push(cp_f);
|
||||
points.push([
|
||||
(cp.x + dir.x / dl * d) as f32,
|
||||
(cp.y + dir.y / dl * d) as f32,
|
||||
cp.z as f32,
|
||||
]);
|
||||
points.push([cp.x + dir.x / dl * d, cp.y + dir.y / dl * d, cp.z]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -192,7 +198,7 @@ fn to_truck(ml: &MultiLeader, document: &acadrust::CadDocument) -> Option<TruckE
|
||||
let ins = &ctx.text_location;
|
||||
let ins_x = ins.x;
|
||||
let ins_y = ins.y;
|
||||
let z = ins.z as f32;
|
||||
let z = ins.z;
|
||||
// Prefer text_direction (carries through rotations/mirrors); fall back
|
||||
// to text_rotation when no direction has been set.
|
||||
let td = ctx.text_direction;
|
||||
@@ -202,7 +208,7 @@ fn to_truck(ml: &MultiLeader, document: &acadrust::CadDocument) -> Option<TruckE
|
||||
ctx.text_rotation as f32
|
||||
};
|
||||
let (cos_r, sin_r) = (rot.cos(), rot.sin());
|
||||
snap_pts.push(node([ins_x as f32, ins_y as f32, z]));
|
||||
snap_pts.push(node([ins_x, ins_y, z]));
|
||||
|
||||
// Resolve text style via handle when available, falling back to STANDARD.
|
||||
let style_name = ctx
|
||||
@@ -267,6 +273,10 @@ fn to_truck(ml: &MultiLeader, document: &acadrust::CadDocument) -> Option<TruckE
|
||||
let h_shift_local = -line_w * h_anchor;
|
||||
let wcs_dx = h_shift_local * cos_r - line_y_local * sin_r;
|
||||
let wcs_dy = h_shift_local * sin_r + line_y_local * cos_r;
|
||||
// tessellate_text_ex emits f32 glyph points around `origin`.
|
||||
// For entity-level WCS output, we accept the f32 cast here since
|
||||
// glyph offsets are small relative to the insertion point and the
|
||||
// entity path doesn't apply a world_offset before render.
|
||||
let origin = [ins_x as f32 + wcs_dx, ins_y as f32 + wcs_dy];
|
||||
let strokes = crate::scene::cxf::tessellate_text_ex(
|
||||
origin,
|
||||
@@ -283,7 +293,7 @@ fn to_truck(ml: &MultiLeader, document: &acadrust::CadDocument) -> Option<TruckE
|
||||
}
|
||||
points.push(nan);
|
||||
for &[x, y] in stroke {
|
||||
points.push([x, y, z]);
|
||||
points.push([x as f64, y as f64, z]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,14 +9,14 @@ use crate::scene::object::{GripApply, GripDef, PropSection};
|
||||
use crate::scene::wire_model::SnapHint;
|
||||
|
||||
fn to_truck(ole: &Ole2Frame) -> TruckEntity {
|
||||
let x0 = ole.upper_left_corner.x as f32;
|
||||
let y0 = ole.lower_right_corner.y as f32;
|
||||
let x1 = ole.lower_right_corner.x as f32;
|
||||
let y1 = ole.upper_left_corner.y as f32;
|
||||
let z = ole.upper_left_corner.z as f32;
|
||||
let x0 = ole.upper_left_corner.x;
|
||||
let y0 = ole.lower_right_corner.y;
|
||||
let x1 = ole.lower_right_corner.x;
|
||||
let y1 = ole.upper_left_corner.y;
|
||||
let z = ole.upper_left_corner.z;
|
||||
|
||||
if (x1 - x0).abs() < 1e-6 && (y1 - y0).abs() < 1e-6 {
|
||||
let s = 0.5_f32;
|
||||
let s = 0.5_f64;
|
||||
return TruckEntity {
|
||||
object: TruckObject::Lines(vec![[-s, 0.0, z], [s, 0.0, z]]),
|
||||
snap_pts: vec![],
|
||||
@@ -28,7 +28,7 @@ fn to_truck(ole: &Ole2Frame) -> TruckEntity {
|
||||
|
||||
let cx = (x0 + x1) * 0.5;
|
||||
let cy = (y0 + y1) * 0.5;
|
||||
let pts = vec![
|
||||
let pts: Vec<[f64; 3]> = vec![
|
||||
// Rectangle
|
||||
[x0, y0, z],
|
||||
[x1, y0, z],
|
||||
@@ -41,11 +41,11 @@ fn to_truck(ole: &Ole2Frame) -> TruckEntity {
|
||||
// Diagonal X
|
||||
[x0, y0, z],
|
||||
[x1, y1, z],
|
||||
[f32::NAN; 3],
|
||||
[f64::NAN; 3],
|
||||
[x1, y0, z],
|
||||
[x0, y1, z],
|
||||
];
|
||||
let center = Vec3::new(cx, cy, z);
|
||||
let center = Vec3::new(cx as f32, cy as f32, z as f32);
|
||||
TruckEntity {
|
||||
object: TruckObject::Lines(pts),
|
||||
snap_pts: vec![(center, SnapHint::Center)],
|
||||
|
||||
+30
-39
@@ -14,16 +14,10 @@ use crate::scene::wire_model::TangentGeom;
|
||||
// ── Polyline (old-style 3D heavy polyline) ────────────────────────────────────
|
||||
|
||||
fn tessellate_polyline(pl: &Polyline) -> TruckEntity {
|
||||
let pts: Vec<[f32; 3]> = pl
|
||||
let pts: Vec<[f64; 3]> = pl
|
||||
.vertices
|
||||
.iter()
|
||||
.map(|v| {
|
||||
[
|
||||
v.location.x as f32,
|
||||
v.location.y as f32,
|
||||
v.location.z as f32,
|
||||
]
|
||||
})
|
||||
.map(|v| [v.location.x, v.location.y, v.location.z])
|
||||
.collect();
|
||||
|
||||
let mut points = pts.clone();
|
||||
@@ -148,7 +142,7 @@ fn tessellate_polyline2d(pl: &Polyline2D) -> TruckEntity {
|
||||
let seg_count = if pl.is_closed() { count } else { count - 1 };
|
||||
let mut edges: Vec<Edge> = Vec::new();
|
||||
let mut tangents: Vec<TangentGeom> = Vec::new();
|
||||
let mut key_verts: Vec<[f32; 3]> = Vec::new();
|
||||
let mut key_verts: Vec<[f64; 3]> = Vec::new();
|
||||
|
||||
let to_wcs = |x: f64, y: f64| -> (f64, f64, f64) {
|
||||
crate::scene::transform::ocs_point_to_wcs((x, y, elev), normal)
|
||||
@@ -161,19 +155,18 @@ fn tessellate_polyline2d(pl: &Polyline2D) -> TruckEntity {
|
||||
if pl.thickness.abs() > 1e-10 {
|
||||
let (nx, ny, nz) = normal;
|
||||
let t = pl.thickness;
|
||||
let off = |p: [f32; 3]| -> [f32; 3] {
|
||||
[
|
||||
(p[0] as f64 + t * nx) as f32,
|
||||
(p[1] as f64 + t * ny) as f32,
|
||||
(p[2] as f64 + t * nz) as f32,
|
||||
]
|
||||
let off = |p: [f64; 3]| -> [f64; 3] {
|
||||
[p[0] + t * nx, p[1] + t * ny, p[2] + t * nz]
|
||||
};
|
||||
let mut path: Vec<[f32; 3]> = Vec::new();
|
||||
let mut kv: Vec<[f32; 3]> = Vec::new();
|
||||
let to_f32 = |p: [f64; 3]| -> [f32; 3] {
|
||||
[p[0] as f32, p[1] as f32, p[2] as f32]
|
||||
};
|
||||
let mut path: Vec<[f64; 3]> = Vec::new();
|
||||
let mut kv: Vec<[f64; 3]> = Vec::new();
|
||||
let mut tgs: Vec<TangentGeom> = Vec::new();
|
||||
let (w0x, w0y, w0z) = to_wcs(verts[0].location.x, verts[0].location.y);
|
||||
path.push([w0x as f32, w0y as f32, w0z as f32]);
|
||||
kv.push([w0x as f32, w0y as f32, w0z as f32]);
|
||||
path.push([w0x, w0y, w0z]);
|
||||
kv.push([w0x, w0y, w0z]);
|
||||
for i in 0..seg_count {
|
||||
let va = &verts[i];
|
||||
let vb = &verts[(i + 1) % count];
|
||||
@@ -182,10 +175,12 @@ fn tessellate_polyline2d(pl: &Polyline2D) -> TruckEntity {
|
||||
let bulge = va.bulge;
|
||||
if bulge.abs() < 1e-9 {
|
||||
let (wx, wy, wz) = to_wcs(ox1, oy1);
|
||||
path.push([wx as f32, wy as f32, wz as f32]);
|
||||
path.push([wx, wy, wz]);
|
||||
let p1_pt = path[path.len() - 2];
|
||||
let p2_pt = *path.last().unwrap();
|
||||
tgs.push(TangentGeom::Line {
|
||||
p1: path[path.len() - 2],
|
||||
p2: *path.last().unwrap(),
|
||||
p1: to_f32(p1_pt),
|
||||
p2: to_f32(p2_pt),
|
||||
});
|
||||
} else {
|
||||
let angle = 4.0 * bulge.atan();
|
||||
@@ -219,25 +214,25 @@ fn tessellate_polyline2d(pl: &Polyline2D) -> TruckEntity {
|
||||
for j in 1..=16usize {
|
||||
let a = a0 + (a1 - a0) * (j as f64 / 16.0);
|
||||
let (wx, wy, wz) = to_wcs(ocx + r * a.cos(), ocy + r * a.sin());
|
||||
path.push([wx as f32, wy as f32, wz as f32]);
|
||||
path.push([wx, wy, wz]);
|
||||
}
|
||||
}
|
||||
let (wbx, wby, wbz) = to_wcs(ox1, oy1);
|
||||
kv.push([wbx as f32, wby as f32, wbz as f32]);
|
||||
kv.push([wbx, wby, wbz]);
|
||||
}
|
||||
let mut pts: Vec<[f32; 3]> = Vec::with_capacity(path.len() * 2 + kv.len() * 3 + 4);
|
||||
let mut pts: Vec<[f64; 3]> = Vec::with_capacity(path.len() * 2 + kv.len() * 3 + 4);
|
||||
pts.extend_from_slice(&path);
|
||||
pts.push([f32::NAN; 3]);
|
||||
pts.push([f64::NAN; 3]);
|
||||
for &p in &path {
|
||||
pts.push(off(p));
|
||||
}
|
||||
if !kv.is_empty() {
|
||||
pts.push([f32::NAN; 3]);
|
||||
pts.push([f64::NAN; 3]);
|
||||
for (i, &pb) in kv.iter().enumerate() {
|
||||
pts.push(pb);
|
||||
pts.push(off(pb));
|
||||
if i + 1 < kv.len() {
|
||||
pts.push([f32::NAN; 3]);
|
||||
pts.push([f64::NAN; 3]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -304,9 +299,9 @@ fn tessellate_polyline2d(pl: &Polyline2D) -> TruckEntity {
|
||||
}
|
||||
|
||||
if i == 0 {
|
||||
key_verts.push([p0.x as f32, p0.y as f32, p0.z as f32]);
|
||||
key_verts.push([p0.x, p0.y, p0.z]);
|
||||
}
|
||||
key_verts.push([p1.x as f32, p1.y as f32, p1.z as f32]);
|
||||
key_verts.push([p1.x, p1.y, p1.z]);
|
||||
}
|
||||
|
||||
TruckEntity {
|
||||
@@ -411,12 +406,8 @@ impl Transformable for Polyline2D {
|
||||
// ── Polyline3D ────────────────────────────────────────────────────────────────
|
||||
|
||||
fn tessellate_polyline3d(pl: &Polyline3D) -> TruckEntity {
|
||||
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 to_pt = |v: &acadrust::entities::Vertex3DPolyline| -> [f64; 3] {
|
||||
[v.position.x, v.position.y, v.position.z]
|
||||
};
|
||||
|
||||
// DXF vertex flags: 8 = spline-fit curve point, 16 = spline frame control point.
|
||||
@@ -426,11 +417,11 @@ fn tessellate_polyline3d(pl: &Polyline3D) -> TruckEntity {
|
||||
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();
|
||||
let wire: Vec<[f64; 3]> = spline_curve.iter().map(|v| to_pt(v)).collect();
|
||||
let ctrl: Vec<[f64; 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();
|
||||
let pts: Vec<[f64; 3]> = pl.vertices.iter().map(to_pt).collect();
|
||||
(pts.clone(), pts)
|
||||
};
|
||||
|
||||
|
||||
@@ -23,16 +23,16 @@ fn image_corners(
|
||||
v: &acadrust::types::Vector3,
|
||||
w: f64,
|
||||
h: f64,
|
||||
) -> [[f32; 3]; 4] {
|
||||
let ox = origin.x as f32;
|
||||
let oy = origin.y as f32;
|
||||
let oz = origin.z as f32;
|
||||
let ux = (u.x * w) as f32;
|
||||
let uy = (u.y * w) as f32;
|
||||
let uz = (u.z * w) as f32;
|
||||
let vx = (v.x * h) as f32;
|
||||
let vy = (v.y * h) as f32;
|
||||
let vz = (v.z * h) as f32;
|
||||
) -> [[f64; 3]; 4] {
|
||||
let ox = origin.x;
|
||||
let oy = origin.y;
|
||||
let oz = origin.z;
|
||||
let ux = u.x * w;
|
||||
let uy = u.y * w;
|
||||
let uz = u.z * w;
|
||||
let vx = v.x * h;
|
||||
let vy = v.y * h;
|
||||
let vz = v.z * h;
|
||||
|
||||
[
|
||||
[ox, oy, oz],
|
||||
@@ -42,15 +42,19 @@ fn image_corners(
|
||||
]
|
||||
}
|
||||
|
||||
fn to_f32_3(p: [f64; 3]) -> [f32; 3] {
|
||||
[p[0] as f32, p[1] as f32, p[2] as f32]
|
||||
}
|
||||
|
||||
/// Rectangle border + X diagonals — used as a placeholder for images.
|
||||
fn image_wire(corners: [[f32; 3]; 4], with_x: bool) -> Vec<[f32; 3]> {
|
||||
fn image_wire(corners: [[f64; 3]; 4], with_x: bool) -> Vec<[f64; 3]> {
|
||||
let [p0, p1, p2, p3] = corners;
|
||||
let mut pts = vec![p0, p1, p2, p3, p0];
|
||||
if with_x {
|
||||
pts.push([f32::NAN; 3]);
|
||||
pts.push([f64::NAN; 3]);
|
||||
pts.push(p0);
|
||||
pts.push(p2);
|
||||
pts.push([f32::NAN; 3]);
|
||||
pts.push([f64::NAN; 3]);
|
||||
pts.push(p1);
|
||||
pts.push(p3);
|
||||
}
|
||||
@@ -76,14 +80,14 @@ impl TruckConvertible for RasterImage {
|
||||
);
|
||||
|
||||
// Helper: pixel-space → world-space point.
|
||||
let ox = self.insertion_point.x as f32;
|
||||
let oy = self.insertion_point.y as f32;
|
||||
let oz = self.insertion_point.z as f32;
|
||||
let px_to_world = |px: f64, py: f64| -> [f32; 3] {
|
||||
let ox = self.insertion_point.x;
|
||||
let oy = self.insertion_point.y;
|
||||
let oz = self.insertion_point.z;
|
||||
let px_to_world = |px: f64, py: f64| -> [f64; 3] {
|
||||
[
|
||||
ox + (self.u_vector.x * px + self.v_vector.x * py) as f32,
|
||||
oy + (self.u_vector.y * px + self.v_vector.y * py) as f32,
|
||||
oz + (self.u_vector.z * px + self.v_vector.z * py) as f32,
|
||||
ox + self.u_vector.x * px + self.v_vector.x * py,
|
||||
oy + self.u_vector.y * px + self.v_vector.y * py,
|
||||
oz + self.u_vector.z * px + self.v_vector.z * py,
|
||||
]
|
||||
};
|
||||
|
||||
@@ -91,7 +95,7 @@ impl TruckConvertible for RasterImage {
|
||||
let cb = &self.clip_boundary;
|
||||
match cb.clip_type {
|
||||
acadrust::entities::ClipType::Polygonal if cb.vertices.len() >= 3 => {
|
||||
let mut poly: Vec<[f32; 3]> =
|
||||
let mut poly: Vec<[f64; 3]> =
|
||||
cb.vertices.iter().map(|v| px_to_world(v.x, v.y)).collect();
|
||||
if let Some(&first) = poly.first() {
|
||||
poly.push(first);
|
||||
@@ -135,10 +139,10 @@ impl Grippable for RasterImage {
|
||||
self.size.y,
|
||||
);
|
||||
vec![
|
||||
square_grip(0, Vec3::from(corners[0])),
|
||||
diamond_grip(1, Vec3::from(corners[1])),
|
||||
diamond_grip(2, Vec3::from(corners[2])),
|
||||
diamond_grip(3, Vec3::from(corners[3])),
|
||||
square_grip(0, Vec3::from(to_f32_3(corners[0]))),
|
||||
diamond_grip(1, Vec3::from(to_f32_3(corners[1]))),
|
||||
diamond_grip(2, Vec3::from(to_f32_3(corners[2]))),
|
||||
diamond_grip(3, Vec3::from(to_f32_3(corners[3]))),
|
||||
]
|
||||
}
|
||||
|
||||
@@ -254,19 +258,19 @@ impl TruckConvertible for Wipeout {
|
||||
) {
|
||||
// Convert pixel-space boundary vertices to world space:
|
||||
// world = insertion_point + u_vector * v.x * size.x + v_vector * v.y * size.y
|
||||
let ox = self.insertion_point.x as f32;
|
||||
let oy = self.insertion_point.y as f32;
|
||||
let oz = self.insertion_point.z as f32;
|
||||
let mut poly: Vec<[f32; 3]> = self
|
||||
let ox = self.insertion_point.x;
|
||||
let oy = self.insertion_point.y;
|
||||
let oz = self.insertion_point.z;
|
||||
let mut poly: Vec<[f64; 3]> = self
|
||||
.clip_boundary_vertices
|
||||
.iter()
|
||||
.map(|v| {
|
||||
let wx = (self.u_vector.x * v.x * self.size.x
|
||||
+ self.v_vector.x * v.y * self.size.y) as f32;
|
||||
let wy = (self.u_vector.y * v.x * self.size.x
|
||||
+ self.v_vector.y * v.y * self.size.y) as f32;
|
||||
let wz = (self.u_vector.z * v.x * self.size.x
|
||||
+ self.v_vector.z * v.y * self.size.y) as f32;
|
||||
let wx = self.u_vector.x * v.x * self.size.x
|
||||
+ self.v_vector.x * v.y * self.size.y;
|
||||
let wy = self.u_vector.y * v.x * self.size.x
|
||||
+ self.v_vector.y * v.y * self.size.y;
|
||||
let wz = self.u_vector.z * v.x * self.size.x
|
||||
+ self.v_vector.z * v.y * self.size.y;
|
||||
[ox + wx, oy + wy, oz + wz]
|
||||
})
|
||||
.collect();
|
||||
@@ -330,10 +334,10 @@ impl Grippable for Wipeout {
|
||||
self.size.y,
|
||||
);
|
||||
vec![
|
||||
square_grip(0, Vec3::from(corners[0])),
|
||||
diamond_grip(1, Vec3::from(corners[1])),
|
||||
diamond_grip(2, Vec3::from(corners[2])),
|
||||
diamond_grip(3, Vec3::from(corners[3])),
|
||||
square_grip(0, Vec3::from(to_f32_3(corners[0]))),
|
||||
diamond_grip(1, Vec3::from(to_f32_3(corners[1]))),
|
||||
diamond_grip(2, Vec3::from(to_f32_3(corners[2]))),
|
||||
diamond_grip(3, Vec3::from(to_f32_3(corners[3]))),
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
+14
-14
@@ -23,12 +23,12 @@ impl TruckConvertible for Ray {
|
||||
return None;
|
||||
}
|
||||
let (nx, ny, nz) = (dir.x / len, dir.y / len, dir.z / len);
|
||||
let far = [
|
||||
(bp.x + nx * DISPLAY_EXTENT) as f32,
|
||||
(bp.y + ny * DISPLAY_EXTENT) as f32,
|
||||
(bp.z + nz * DISPLAY_EXTENT) as f32,
|
||||
let far: [f64; 3] = [
|
||||
bp.x + nx * DISPLAY_EXTENT,
|
||||
bp.y + ny * DISPLAY_EXTENT,
|
||||
bp.z + nz * DISPLAY_EXTENT,
|
||||
];
|
||||
let start = [bp.x as f32, bp.y as f32, bp.z as f32];
|
||||
let start: [f64; 3] = [bp.x, bp.y, bp.z];
|
||||
Some(TruckEntity {
|
||||
object: TruckObject::Lines(vec![start, far]),
|
||||
snap_pts: vec![],
|
||||
@@ -159,21 +159,21 @@ impl TruckConvertible for XLine {
|
||||
return None;
|
||||
}
|
||||
let (nx, ny, nz) = (dir.x / len, dir.y / len, dir.z / len);
|
||||
let far_pos = [
|
||||
(bp.x + nx * DISPLAY_EXTENT) as f32,
|
||||
(bp.y + ny * DISPLAY_EXTENT) as f32,
|
||||
(bp.z + nz * DISPLAY_EXTENT) as f32,
|
||||
let far_pos: [f64; 3] = [
|
||||
bp.x + nx * DISPLAY_EXTENT,
|
||||
bp.y + ny * DISPLAY_EXTENT,
|
||||
bp.z + nz * DISPLAY_EXTENT,
|
||||
];
|
||||
let far_neg = [
|
||||
(bp.x - nx * DISPLAY_EXTENT) as f32,
|
||||
(bp.y - ny * DISPLAY_EXTENT) as f32,
|
||||
(bp.z - nz * DISPLAY_EXTENT) as f32,
|
||||
let far_neg: [f64; 3] = [
|
||||
bp.x - nx * DISPLAY_EXTENT,
|
||||
bp.y - ny * DISPLAY_EXTENT,
|
||||
bp.z - nz * DISPLAY_EXTENT,
|
||||
];
|
||||
Some(TruckEntity {
|
||||
object: TruckObject::Lines(vec![far_neg, far_pos]),
|
||||
snap_pts: vec![],
|
||||
tangent_geoms: vec![],
|
||||
key_vertices: vec![[bp.x as f32, bp.y as f32, bp.z as f32]],
|
||||
key_vertices: vec![[bp.x, bp.y, bp.z]],
|
||||
fill_tris: vec![],
|
||||
})
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ use crate::scene::wire_model::SnapHint;
|
||||
// ── Marker geometry ───────────────────────────────────────────────────────────
|
||||
|
||||
/// Small diamond marker at the shape insertion point.
|
||||
fn shape_marker(ox: f32, oy: f32, oz: f32, size: f32) -> Vec<[f32; 3]> {
|
||||
fn shape_marker(ox: f64, oy: f64, oz: f64, size: f64) -> Vec<[f64; 3]> {
|
||||
let s = size * 0.5;
|
||||
vec![
|
||||
[ox, oy + s, oz], // top
|
||||
@@ -26,7 +26,7 @@ fn shape_marker(ox: f32, oy: f32, oz: f32, size: f32) -> Vec<[f32; 3]> {
|
||||
[ox, oy - s, oz], // bottom
|
||||
[ox - s, oy, oz], // left
|
||||
[ox, oy + s, oz], // close
|
||||
[f32::NAN; 3],
|
||||
[f64::NAN; 3],
|
||||
]
|
||||
}
|
||||
|
||||
@@ -34,12 +34,12 @@ fn shape_marker(ox: f32, oy: f32, oz: f32, size: f32) -> Vec<[f32; 3]> {
|
||||
|
||||
impl TruckConvertible for Shape {
|
||||
fn to_truck(&self, _document: &acadrust::CadDocument) -> Option<TruckEntity> {
|
||||
let ox = self.insertion_point.x as f32;
|
||||
let oy = self.insertion_point.y as f32;
|
||||
let oz = self.insertion_point.z as f32;
|
||||
let size = (self.size as f32).abs().max(0.5);
|
||||
let ox = self.insertion_point.x;
|
||||
let oy = self.insertion_point.y;
|
||||
let oz = self.insertion_point.z;
|
||||
let size = self.size.abs().max(0.5);
|
||||
|
||||
let snap_pt = Vec3::new(ox, oy, oz);
|
||||
let snap_pt = Vec3::new(ox as f32, oy as f32, oz as f32);
|
||||
let pts = shape_marker(ox, oy, oz, size);
|
||||
|
||||
Some(TruckEntity {
|
||||
|
||||
+16
-12
@@ -14,7 +14,11 @@ use crate::scene::acad_to_truck::{TruckEntity, TruckObject};
|
||||
use crate::scene::object::{GripApply, GripDef, PropSection};
|
||||
use crate::scene::wire_model::SnapHint;
|
||||
|
||||
fn v3(v: &acadrust::types::Vector3) -> [f32; 3] {
|
||||
fn v3(v: &acadrust::types::Vector3) -> [f64; 3] {
|
||||
[v.x, v.y, v.z]
|
||||
}
|
||||
|
||||
fn v3f32(v: &acadrust::types::Vector3) -> [f32; 3] {
|
||||
[v.x as f32, v.y as f32, v.z as f32]
|
||||
}
|
||||
|
||||
@@ -31,22 +35,22 @@ impl TruckConvertible for Solid {
|
||||
let pts = vec![
|
||||
p0,
|
||||
p1,
|
||||
[f32::NAN; 3],
|
||||
[f64::NAN; 3],
|
||||
p1,
|
||||
p3,
|
||||
[f32::NAN; 3],
|
||||
[f64::NAN; 3],
|
||||
p3,
|
||||
p2,
|
||||
[f32::NAN; 3],
|
||||
[f64::NAN; 3],
|
||||
p2,
|
||||
p0,
|
||||
];
|
||||
|
||||
let snap = vec![
|
||||
(Vec3::from(p0), SnapHint::Node),
|
||||
(Vec3::from(p1), SnapHint::Node),
|
||||
(Vec3::from(p2), SnapHint::Node),
|
||||
(Vec3::from(p3), SnapHint::Node),
|
||||
(Vec3::from(v3f32(&self.first_corner)), SnapHint::Node),
|
||||
(Vec3::from(v3f32(&self.second_corner)), SnapHint::Node),
|
||||
(Vec3::from(v3f32(&self.third_corner)), SnapHint::Node),
|
||||
(Vec3::from(v3f32(&self.fourth_corner)), SnapHint::Node),
|
||||
];
|
||||
|
||||
Some(TruckEntity {
|
||||
@@ -62,10 +66,10 @@ impl TruckConvertible for Solid {
|
||||
impl Grippable for Solid {
|
||||
fn grips(&self) -> Vec<GripDef> {
|
||||
vec![
|
||||
square_grip(0, Vec3::from(v3(&self.first_corner))),
|
||||
square_grip(1, Vec3::from(v3(&self.second_corner))),
|
||||
square_grip(2, Vec3::from(v3(&self.third_corner))),
|
||||
square_grip(3, Vec3::from(v3(&self.fourth_corner))),
|
||||
square_grip(0, Vec3::from(v3f32(&self.first_corner))),
|
||||
square_grip(1, Vec3::from(v3f32(&self.second_corner))),
|
||||
square_grip(2, Vec3::from(v3f32(&self.third_corner))),
|
||||
square_grip(3, Vec3::from(v3f32(&self.fourth_corner))),
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
@@ -64,9 +64,9 @@ fn to_truck(spl: &Spline) -> TruckEntity {
|
||||
} else {
|
||||
&spl.control_points
|
||||
};
|
||||
let key_vertices: Vec<[f32; 3]> = snap_source
|
||||
let key_vertices: Vec<[f64; 3]> = snap_source
|
||||
.iter()
|
||||
.map(|p| [p.x as f32, p.y as f32, p.z as f32])
|
||||
.map(|p| [p.x, p.y, p.z])
|
||||
.collect();
|
||||
|
||||
let is_closed = spl.flags.closed || spl.flags.periodic;
|
||||
|
||||
+14
-1
@@ -139,8 +139,21 @@ impl TruckConvertible for Table {
|
||||
}
|
||||
}
|
||||
|
||||
// Table currently does its layout in glam::Vec3 (f32). The world_offset
|
||||
// subtraction in tessellate.rs needs f64, so widen at the boundary —
|
||||
// precision is already limited by the f32 math above (separate fix-up).
|
||||
let pts_f64: Vec<[f64; 3]> = pts
|
||||
.into_iter()
|
||||
.map(|[x, y, z]| {
|
||||
if x.is_nan() {
|
||||
[f64::NAN, f64::NAN, f64::NAN]
|
||||
} else {
|
||||
[x as f64, y as f64, z as f64]
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
Some(TruckEntity {
|
||||
object: TruckObject::Lines(pts),
|
||||
object: TruckObject::Lines(pts_f64),
|
||||
snap_pts: vec![(origin, SnapHint::Insertion)],
|
||||
tangent_geoms: vec![],
|
||||
key_vertices: vec![],
|
||||
|
||||
@@ -16,17 +16,21 @@ use crate::scene::wire_model::SnapHint;
|
||||
|
||||
// ── Helpers ───────────────────────────────────────────────────────────────────
|
||||
|
||||
fn v3(v: &acadrust::types::Vector3) -> [f32; 3] {
|
||||
fn v3(v: &acadrust::types::Vector3) -> [f64; 3] {
|
||||
[v.x, v.y, v.z]
|
||||
}
|
||||
|
||||
fn v3f32(v: &acadrust::types::Vector3) -> [f32; 3] {
|
||||
[v.x as f32, v.y as f32, v.z as f32]
|
||||
}
|
||||
|
||||
/// Small cross marker at the insertion point (used when no clip boundary).
|
||||
fn cross_wire(origin: [f32; 3], size: f32) -> Vec<[f32; 3]> {
|
||||
fn cross_wire(origin: [f64; 3], size: f64) -> Vec<[f64; 3]> {
|
||||
let [ox, oy, oz] = origin;
|
||||
vec![
|
||||
[ox - size, oy, oz],
|
||||
[ox + size, oy, oz],
|
||||
[f32::NAN; 3],
|
||||
[f64::NAN; 3],
|
||||
[ox, oy - size, oz],
|
||||
[ox, oy + size, oz],
|
||||
]
|
||||
@@ -37,23 +41,24 @@ fn cross_wire(origin: [f32; 3], size: f32) -> Vec<[f32; 3]> {
|
||||
impl TruckConvertible for Underlay {
|
||||
fn to_truck(&self, _document: &acadrust::CadDocument) -> Option<TruckEntity> {
|
||||
let origin = v3(&self.insertion_point);
|
||||
let origin_f32 = v3f32(&self.insertion_point);
|
||||
|
||||
if !self.clip_boundary_vertices.is_empty() {
|
||||
// Draw clip boundary polygon + close it.
|
||||
let world_verts = self.world_clip_boundary();
|
||||
let mut pts: Vec<[f32; 3]> = world_verts
|
||||
let mut pts: Vec<[f64; 3]> = world_verts
|
||||
.iter()
|
||||
.map(|v| [v.x as f32, v.y as f32, v.z as f32])
|
||||
.map(|v| [v.x, v.y, v.z])
|
||||
.collect();
|
||||
// Close polygon.
|
||||
if let Some(&first) = pts.first() {
|
||||
pts.push(first);
|
||||
}
|
||||
// Insertion grip.
|
||||
let key: Vec<[f32; 3]> = pts.clone();
|
||||
let key: Vec<[f64; 3]> = pts.clone();
|
||||
Some(TruckEntity {
|
||||
object: TruckObject::Lines(pts),
|
||||
snap_pts: vec![(Vec3::from(origin), SnapHint::Node)],
|
||||
snap_pts: vec![(Vec3::from(origin_f32), SnapHint::Node)],
|
||||
tangent_geoms: vec![],
|
||||
key_vertices: key,
|
||||
fill_tris: vec![],
|
||||
@@ -63,7 +68,7 @@ impl TruckConvertible for Underlay {
|
||||
let pts = cross_wire(origin, 1.0);
|
||||
Some(TruckEntity {
|
||||
object: TruckObject::Lines(pts),
|
||||
snap_pts: vec![(Vec3::from(origin), SnapHint::Node)],
|
||||
snap_pts: vec![(Vec3::from(origin_f32), SnapHint::Node)],
|
||||
tangent_geoms: vec![],
|
||||
key_vertices: vec![origin],
|
||||
fill_tris: vec![],
|
||||
@@ -76,7 +81,7 @@ impl TruckConvertible for Underlay {
|
||||
|
||||
impl Grippable for Underlay {
|
||||
fn grips(&self) -> Vec<GripDef> {
|
||||
let origin = Vec3::from(v3(&self.insertion_point));
|
||||
let origin = Vec3::from(v3f32(&self.insertion_point));
|
||||
let mut grips = vec![square_grip(0, origin)];
|
||||
|
||||
if !self.clip_boundary_vertices.is_empty() {
|
||||
|
||||
@@ -22,9 +22,13 @@ pub enum TruckObject {
|
||||
Contour(Wire),
|
||||
Text(Vec<TextStroke>),
|
||||
/// Pre-computed NaN-separated 3-D point list (leader lines, arrowheads, etc.).
|
||||
Lines(Vec<[f32; 3]>),
|
||||
/// Points are stored in WCS as **f64** so the large world_offset can be
|
||||
/// subtracted in full precision in tessellate.rs before the f32 cast.
|
||||
/// Casting WCS coordinates to f32 in the entity converters used to wreck
|
||||
/// rotated sub-glyph precision on drawings far from origin.
|
||||
Lines(Vec<[f64; 3]>),
|
||||
/// Like Lines but linetype pattern restarts at each NaN-separated segment (plinegen=false).
|
||||
SegmentedLines(Vec<[f32; 3]>),
|
||||
SegmentedLines(Vec<[f64; 3]>),
|
||||
Volume(Solid),
|
||||
}
|
||||
|
||||
@@ -32,10 +36,13 @@ pub struct TruckEntity {
|
||||
pub object: TruckObject,
|
||||
pub snap_pts: Vec<(Vec3, SnapHint)>,
|
||||
pub tangent_geoms: Vec<TangentGeom>,
|
||||
pub key_vertices: Vec<[f32; 3]>,
|
||||
/// Pre-triangulated fill geometry: flat list of [f32;3] vertices, 3 per triangle.
|
||||
/// Non-empty for mesh-like entities (PolyfaceMesh, PolygonMesh) that need solid fill.
|
||||
pub fill_tris: Vec<[f32; 3]>,
|
||||
/// Polyline vertex positions in WCS f64; converted to offset-relative f32
|
||||
/// at the wire-model boundary.
|
||||
pub key_vertices: Vec<[f64; 3]>,
|
||||
/// Pre-triangulated fill geometry: flat list of WCS f64 vertices, 3 per
|
||||
/// triangle. Non-empty for mesh-like entities (PolyfaceMesh, PolygonMesh)
|
||||
/// that need solid fill.
|
||||
pub fill_tris: Vec<[f64; 3]>,
|
||||
}
|
||||
|
||||
pub fn convert(entity: &EntityType, document: &CadDocument) -> Option<TruckEntity> {
|
||||
|
||||
+35
-16
@@ -142,6 +142,12 @@ pub fn tessellate(
|
||||
}
|
||||
|
||||
let snap_pts = offset_snap_pts(te.snap_pts, world_offset);
|
||||
let [ox, oy, oz] = world_offset;
|
||||
let key_vertices: Vec<[f32; 3]> = te
|
||||
.key_vertices
|
||||
.into_iter()
|
||||
.map(|[x, y, z]| [(x - ox) as f32, (y - oy) as f32, (z - oz) as f32])
|
||||
.collect();
|
||||
return WireModel {
|
||||
name,
|
||||
points,
|
||||
@@ -153,7 +159,7 @@ pub fn tessellate(
|
||||
snap_pts,
|
||||
tangent_geoms: te.tangent_geoms,
|
||||
aci: 0,
|
||||
key_vertices: te.key_vertices,
|
||||
key_vertices,
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
@@ -168,6 +174,14 @@ pub fn tessellate(
|
||||
TruckTessResult::Point([x, y, z]) => {
|
||||
let s = 0.1_f32;
|
||||
let snap_pts = offset_snap_pts(te.snap_pts, world_offset);
|
||||
let [ox, oy, oz] = world_offset;
|
||||
let key_vertices: Vec<[f32; 3]> = te
|
||||
.key_vertices
|
||||
.into_iter()
|
||||
.map(|[kx, ky, kz]| {
|
||||
[(kx - ox) as f32, (ky - oy) as f32, (kz - oz) as f32]
|
||||
})
|
||||
.collect();
|
||||
return WireModel {
|
||||
name,
|
||||
points: vec![
|
||||
@@ -184,7 +198,7 @@ pub fn tessellate(
|
||||
snap_pts,
|
||||
tangent_geoms: te.tangent_geoms,
|
||||
aci: 0,
|
||||
key_vertices: te.key_vertices,
|
||||
key_vertices,
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
@@ -202,7 +216,7 @@ pub fn tessellate(
|
||||
let key_vertices: Vec<[f32; 3]> = te
|
||||
.key_vertices
|
||||
.into_iter()
|
||||
.map(|[x, y, z]| [x - ox as f32, y - oy as f32, z - oz as f32])
|
||||
.map(|[x, y, z]| [(x - ox) as f32, (y - oy) as f32, (z - oz) as f32])
|
||||
.collect();
|
||||
return WireModel {
|
||||
name,
|
||||
@@ -231,7 +245,7 @@ pub fn tessellate(
|
||||
let key_vertices: Vec<[f32; 3]> = te
|
||||
.key_vertices
|
||||
.into_iter()
|
||||
.map(|[x, y, z]| [x - ox as f32, y - oy as f32, z - oz as f32])
|
||||
.map(|[x, y, z]| [(x - ox) as f32, (y - oy) as f32, (z - oz) as f32])
|
||||
.collect();
|
||||
return WireModel {
|
||||
name,
|
||||
@@ -254,17 +268,18 @@ pub fn tessellate(
|
||||
}
|
||||
|
||||
TruckObject::Lines(points) => {
|
||||
// Points are world-space f32 from entity converters (polyline,
|
||||
// leader, mesh, solid2d, etc.). Subtract world_offset so the
|
||||
// geometry lands in local space alongside Line/Arc/Circle.
|
||||
// Points are world-space f64 from entity converters (polyline,
|
||||
// leader, mesh, solid2d, etc.). Subtract world_offset in f64
|
||||
// before casting to f32 so drawings at large UTM-style
|
||||
// coordinates keep sub-unit precision in the wire model.
|
||||
let [ox, oy, oz] = world_offset;
|
||||
let local_pts: Vec<[f32; 3]> = points
|
||||
.into_iter()
|
||||
.map(|[x, y, z]| {
|
||||
if x.is_nan() {
|
||||
[x, y, z]
|
||||
[f32::NAN, f32::NAN, f32::NAN]
|
||||
} else {
|
||||
[x - ox as f32, y - oy as f32, z - oz as f32]
|
||||
[(x - ox) as f32, (y - oy) as f32, (z - oz) as f32]
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
@@ -272,12 +287,12 @@ pub fn tessellate(
|
||||
let key_vertices: Vec<[f32; 3]> = te
|
||||
.key_vertices
|
||||
.into_iter()
|
||||
.map(|[x, y, z]| [x - ox as f32, y - oy as f32, z - oz as f32])
|
||||
.map(|[x, y, z]| [(x - ox) as f32, (y - oy) as f32, (z - oz) as f32])
|
||||
.collect();
|
||||
let fill_tris: Vec<[f32; 3]> = te
|
||||
.fill_tris
|
||||
.into_iter()
|
||||
.map(|[x, y, z]| [x - ox as f32, y - oy as f32, z - oz as f32])
|
||||
.map(|[x, y, z]| [(x - ox) as f32, (y - oy) as f32, (z - oz) as f32])
|
||||
.collect();
|
||||
return WireModel {
|
||||
name,
|
||||
@@ -304,9 +319,9 @@ pub fn tessellate(
|
||||
.into_iter()
|
||||
.map(|[x, y, z]| {
|
||||
if x.is_nan() {
|
||||
[x, y, z]
|
||||
[f32::NAN, f32::NAN, f32::NAN]
|
||||
} else {
|
||||
[x - ox as f32, y - oy as f32, z - oz as f32]
|
||||
[(x - ox) as f32, (y - oy) as f32, (z - oz) as f32]
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
@@ -314,7 +329,7 @@ pub fn tessellate(
|
||||
let key_vertices: Vec<[f32; 3]> = te
|
||||
.key_vertices
|
||||
.into_iter()
|
||||
.map(|[x, y, z]| [x - ox as f32, y - oy as f32, z - oz as f32])
|
||||
.map(|[x, y, z]| [(x - ox) as f32, (y - oy) as f32, (z - oz) as f32])
|
||||
.collect();
|
||||
return WireModel {
|
||||
name,
|
||||
@@ -657,8 +672,12 @@ pub fn tessellate_multileader(
|
||||
}
|
||||
|
||||
if ml.path_type == MultiLeaderPathType::Spline && ctrl.len() >= 2 {
|
||||
for pt in catmull_rom_pts(&ctrl, 8) {
|
||||
points.push(pt);
|
||||
let ctrl_f64: Vec<[f64; 3]> = ctrl
|
||||
.iter()
|
||||
.map(|c| [c[0] as f64, c[1] as f64, c[2] as f64])
|
||||
.collect();
|
||||
for pt in catmull_rom_pts(&ctrl_f64, 8) {
|
||||
points.push([pt[0] as f32, pt[1] as f32, pt[2] as f32]);
|
||||
}
|
||||
} else {
|
||||
for &c in &ctrl {
|
||||
|
||||
Reference in new issue
Block a user