diff --git a/src/entities/dimension.rs b/src/entities/dimension.rs index dbceea692..e88295f9d 100644 --- a/src/entities/dimension.rs +++ b/src/entities/dimension.rs @@ -1120,12 +1120,13 @@ fn tessellate_dimension_inner( }; let snap_pts = dimension_snap_pts(dim, world_offset); - let key_vertices: Vec<[f32; 3]> = geom + let key_vertices: Vec<[f64; 3]> = geom .dim_lines .iter() .chain(geom.ext_lines.iter()) .copied() .filter(|p| !(p[0].is_nan() || p[1].is_nan() || p[2].is_nan())) + .map(|[x, y, z]| [x as f64, y as f64, z as f64]) .collect(); // DIMLWD (dim line + arrows) and DIMLWE (extension lines). Negative diff --git a/src/entities/leader.rs b/src/entities/leader.rs index 643a4dc56..c5b993bb9 100644 --- a/src/entities/leader.rs +++ b/src/entities/leader.rs @@ -623,7 +623,7 @@ impl LeaderTess for Leader { let mut points: Vec<[f32; 3]> = verts.iter().map(|v| p3(v)).collect(); let mut tangents: Vec = Vec::new(); - let key_vertices: Vec<[f32; 3]> = verts.iter().map(|v| p3(v)).collect(); + let key_vertices: Vec<[f64; 3]> = verts.iter().map(|v| [v.x, v.y, v.z]).collect(); let mut fill_tris: Vec<[f32; 3]> = Vec::new(); for i in 0..verts.len().saturating_sub(1) { diff --git a/src/entities/multileader.rs b/src/entities/multileader.rs index 4bc8646df..c2a8222e8 100644 --- a/src/entities/multileader.rs +++ b/src/entities/multileader.rs @@ -1161,7 +1161,7 @@ impl MultiLeaderTess for MultiLeader { // ── Leader / arrow / dogleg points ─────────────────────────────────────── let mut points: Vec<[f32; 3]> = 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<(glam::DVec3, SnapHint)> = Vec::new(); let mut tangents: Vec = Vec::new(); let mut arrow_fill: Vec<[f32; 3]> = Vec::new(); @@ -1209,7 +1209,7 @@ impl MultiLeaderTess for MultiLeader { ctrl.push(cp_f); } for &c in &ctrl { - key_verts.push(c); + key_verts.push([c[0] as f64, c[1] as f64, c[2] as f64]); snap_pts.push((Vec3::from(c).as_dvec3(), SnapHint::Node)); } diff --git a/src/scene/cache/block_cache.rs b/src/scene/cache/block_cache.rs index 2f73535e1..6c5dbff10 100644 --- a/src/scene/cache/block_cache.rs +++ b/src/scene/cache/block_cache.rs @@ -38,7 +38,7 @@ pub struct LocalWire { /// Low-bit residual paired with `points` so block-instance wires keep /// sub-f32 precision once the renderer translates them to world space. pub points_low: Vec<[f32; 3]>, - pub key_vertices: Vec<[f32; 3]>, + pub key_vertices: Vec<[f64; 3]>, pub snap_pts: Vec<(glam::DVec3, SnapHint)>, pub tangent_geoms: Vec, pub fill_tris: Vec<[f32; 3]>, @@ -1042,7 +1042,7 @@ struct BatchEntry { points: Vec<[f32; 3]>, points_low: Vec<[f32; 3]>, snap_pts: Vec<(glam::DVec3, SnapHint)>, - key_vertices: Vec<[f32; 3]>, + key_vertices: Vec<[f64; 3]>, tangent_geoms: Vec, fill_tris: Vec<[f32; 3]>, min_x: f32, @@ -1454,9 +1454,7 @@ fn emit_wire( p[1] as f64 + lo_y, p[2] as f64 + lo_z, )); - entry - .key_vertices - .push([(v.x - ox) as f32, (v.y - oy) as f32, (v.z - oz) as f32]); + entry.key_vertices.push([v.x - ox, v.y - oy, v.z - oz]); } for (p, hint) in &lw.snap_pts { let v = accum_xform.apply(Vector3::new( diff --git a/src/scene/convert/tessellate.rs b/src/scene/convert/tessellate.rs index fb859668e..d5064d566 100644 --- a/src/scene/convert/tessellate.rs +++ b/src/scene/convert/tessellate.rs @@ -213,10 +213,10 @@ pub fn tessellate( } let snap_pts = offset_snap_pts(te.snap_pts, world_offset); - let key_vertices: Vec<[f32; 3]> = te + let key_vertices: Vec<[f64; 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, y - oy, z - oz]) .collect(); // Empty input (no glyphs) → emit a single empty wire so the @@ -293,12 +293,10 @@ pub fn tessellate( 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 + let key_vertices: Vec<[f64; 3]> = te .key_vertices .into_iter() - .map(|[kx, ky, kz]| { - [(kx - ox) as f32, (ky - oy) as f32, (kz - oz) as f32] - }) + .map(|[kx, ky, kz]| [kx - ox, ky - oy, kz - oz]) .collect(); return vec![WireModel { name, @@ -339,10 +337,10 @@ pub fn tessellate( { let [ox, oy, oz] = world_offset; let snap_pts = offset_snap_pts(te.snap_pts, world_offset); - let key_vertices: Vec<[f32; 3]> = te + let key_vertices: Vec<[f64; 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, y - oy, z - oz]) .collect(); return vec![WireModel { name, @@ -372,10 +370,10 @@ pub fn tessellate( { let [ox, oy, oz] = world_offset; let snap_pts = offset_snap_pts(te.snap_pts, world_offset); - let key_vertices: Vec<[f32; 3]> = te + let key_vertices: Vec<[f64; 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, y - oy, z - oz]) .collect(); return vec![WireModel { name, @@ -409,10 +407,10 @@ pub fn tessellate( let [ox, oy, oz] = world_offset; let (local_pts, local_pts_low) = offset_to_ds(points, world_offset); let snap_pts = offset_snap_pts(te.snap_pts, world_offset); - let key_vertices: Vec<[f32; 3]> = te + let key_vertices: Vec<[f64; 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, y - oy, z - oz]) .collect(); let (fill_tris, fill_tris_low) = offset_to_ds(te.fill_tris, world_offset); return vec![WireModel { @@ -440,10 +438,10 @@ pub fn tessellate( let [ox, oy, oz] = world_offset; let (local_pts, local_pts_low) = offset_to_ds(points, world_offset); let snap_pts = offset_snap_pts(te.snap_pts, world_offset); - let key_vertices: Vec<[f32; 3]> = te + let key_vertices: Vec<[f64; 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, y - oy, z - oz]) .collect(); return vec![WireModel { name, @@ -491,6 +489,10 @@ pub fn tessellate( // f64 for the WireModel's double-single-era snap buffer. let snap_pts: Vec<(glam::DVec3, SnapHint)> = snap_pts.into_iter().map(|(p, h)| (p.as_dvec3(), h)).collect(); + let key_vertices: Vec<[f64; 3]> = key_vertices + .into_iter() + .map(|[x, y, z]| [x as f64, y as f64, z as f64]) + .collect(); vec![WireModel { name, points, diff --git a/src/scene/mod.rs b/src/scene/mod.rs index 831a76bcd..8bf7d5247 100644 --- a/src/scene/mod.rs +++ b/src/scene/mod.rs @@ -3270,14 +3270,14 @@ impl Scene { for &[x, y, z] in &wire.key_vertices { if x.is_finite() && y.is_finite() && z.is_finite() { min = min.min(glam::Vec3::new( - x + ox as f32, - y + oy as f32, - z + oz, + (x + ox) as f32, + (y + oy) as f32, + (z + oz as f64) as f32, )); max = max.max(glam::Vec3::new( - x + ox as f32, - y + oy as f32, - z + oz, + (x + ox) as f32, + (y + oy) as f32, + (z + oz as f64) as f32, )); any = true; } @@ -8593,7 +8593,7 @@ fn lod_stub_wire( line_weight_px: 1.0, snap_pts: vec![], tangent_geoms: vec![], - key_vertices: vec![[cx, cy, cz]], + key_vertices: vec![[cx as f64, cy as f64, cz as f64]], aabb, plinegen: true, vp_scissor: None, diff --git a/src/scene/model/wire_model.rs b/src/scene/model/wire_model.rs index 88528a627..dba9cd46a 100644 --- a/src/scene/model/wire_model.rs +++ b/src/scene/model/wire_model.rs @@ -64,7 +64,7 @@ pub struct WireModel { /// True polyline vertices used for Endpoint/Midpoint snap. /// Non-empty only for entities with distinct vertex positions (Line, LwPolyline). /// Empty for tessellated curves (Circle, Arc, Ellipse) which use snap_pts instead. - pub key_vertices: Vec<[f32; 3]>, + pub key_vertices: Vec<[f64; 3]>, /// World-space 2-D bounding box [min_x, min_y, max_x, max_y]. /// Set from acadrust `bounding_box()` in `tessellate_entity()`. /// Preview / interim wires use `UNBOUNDED_AABB` so they are never pre-rejected diff --git a/src/scene/pick/xclip.rs b/src/scene/pick/xclip.rs index 7ac225b05..98a5bff42 100644 --- a/src/scene/pick/xclip.rs +++ b/src/scene/pick/xclip.rs @@ -103,7 +103,7 @@ pub fn clip_wires(wires: &mut Vec, poly: &[[f32; 2]]) { w.fill_tris = clip_triangles(&w.fill_tris, poly); } w.key_vertices - .retain(|v| point_in_poly(v[0], v[1], poly)); + .retain(|v| point_in_poly(v[0] as f32, v[1] as f32, poly)); w.snap_pts.retain(|(p, _)| point_in_poly(p.x as f32, p.y as f32, poly)); w.aabb = recompute_aabb(&w.points, &w.fill_tris); } diff --git a/src/scene/pipeline/face3d_gpu.rs b/src/scene/pipeline/face3d_gpu.rs index 3515e1745..b9dc35e39 100644 --- a/src/scene/pipeline/face3d_gpu.rs +++ b/src/scene/pipeline/face3d_gpu.rs @@ -126,11 +126,21 @@ impl Face3DGpu { let fill_color = [r * 0.45, g * 0.45, b * 0.45, a]; let depth = depth_of(wire); let p = &wire.key_vertices; - let v = |i: usize| Face3DVertex { - position: p[i], - color: fill_color, - draw_depth: depth, - position_low: [0.0; 3], + // key_vertices are f64 (offset-relative); split into the + // double-single (high, low) pair the face3d shader expects. + let v = |i: usize| { + let [x, y, z] = p[i]; + let h = [x as f32, y as f32, z as f32]; + Face3DVertex { + position: h, + color: fill_color, + draw_depth: depth, + position_low: [ + (x - h[0] as f64) as f32, + (y - h[1] as f64) as f32, + (z - h[2] as f64) as f32, + ], + } }; verts_3d.push(v(0)); verts_3d.push(v(1)); diff --git a/src/snap/mod.rs b/src/snap/mod.rs index ef4803d26..5d70aa4c3 100644 --- a/src/snap/mod.rs +++ b/src/snap/mod.rs @@ -542,7 +542,10 @@ impl Snapper { if !wire.key_vertices.is_empty() { // Use explicit vertices (Line, LwPolyline): every vertex is an endpoint. for &p in &wire.key_vertices { - try_pt(Vec3::from(p), SnapType::Endpoint); + try_pt( + Vec3::new(p[0] as f32, p[1] as f32, p[2] as f32), + SnapType::Endpoint, + ); } } else { // Tessellated curves (Circle, Arc, Ellipse): only arc endpoints. @@ -571,8 +574,8 @@ impl Snapper { } if !wire.key_vertices.is_empty() { for seg in wire.key_vertices.windows(2) { - let a = Vec3::from(seg[0]); - let b = Vec3::from(seg[1]); + let a = Vec3::new(seg[0][0] as f32, seg[0][1] as f32, seg[0][2] as f32); + let b = Vec3::new(seg[1][0] as f32, seg[1][1] as f32, seg[1][2] as f32); if a.distance_squared(b) > 1e-12 { try_pt((a + b) * 0.5, SnapType::Midpoint); }