refactor(snap): widen key_vertices to f64 (world_offset removal P4)
WireModel/LocalWire/BatchEntry key_vertices are now Vec<[f64; 3]>; tessellation keeps them in f64 (no f32 cast at offset subtraction), producers (dimension, leader, multileader) build them from the acadrust f64 source, the block-cache transform keeps f64, and the face3d Face3D quad path splits them into the double-single (high, low) pair. Consumers (snap endpoint/midpoint, xclip) read via f32 at the leaf. Still offset-relative (inert); endpoint/midpoint snap is no longer f32-capped. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
cd1d3bb619
commit
cca1086696
10 changed files with 54 additions and 40 deletions
|
|
@ -1120,12 +1120,13 @@ fn tessellate_dimension_inner(
|
||||||
};
|
};
|
||||||
|
|
||||||
let snap_pts = dimension_snap_pts(dim, world_offset);
|
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
|
.dim_lines
|
||||||
.iter()
|
.iter()
|
||||||
.chain(geom.ext_lines.iter())
|
.chain(geom.ext_lines.iter())
|
||||||
.copied()
|
.copied()
|
||||||
.filter(|p| !(p[0].is_nan() || p[1].is_nan() || p[2].is_nan()))
|
.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();
|
.collect();
|
||||||
|
|
||||||
// DIMLWD (dim line + arrows) and DIMLWE (extension lines). Negative
|
// DIMLWD (dim line + arrows) and DIMLWE (extension lines). Negative
|
||||||
|
|
|
||||||
|
|
@ -623,7 +623,7 @@ impl LeaderTess for Leader {
|
||||||
|
|
||||||
let mut points: Vec<[f32; 3]> = verts.iter().map(|v| p3(v)).collect();
|
let mut points: Vec<[f32; 3]> = verts.iter().map(|v| p3(v)).collect();
|
||||||
let mut tangents: Vec<TangentGeom> = Vec::new();
|
let mut tangents: Vec<TangentGeom> = 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();
|
let mut fill_tris: Vec<[f32; 3]> = Vec::new();
|
||||||
|
|
||||||
for i in 0..verts.len().saturating_sub(1) {
|
for i in 0..verts.len().saturating_sub(1) {
|
||||||
|
|
|
||||||
|
|
@ -1161,7 +1161,7 @@ impl MultiLeaderTess for MultiLeader {
|
||||||
|
|
||||||
// ── Leader / arrow / dogleg points ───────────────────────────────────────
|
// ── Leader / arrow / dogleg points ───────────────────────────────────────
|
||||||
let mut points: Vec<[f32; 3]> = Vec::new();
|
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 snap_pts: Vec<(glam::DVec3, SnapHint)> = Vec::new();
|
||||||
let mut tangents: Vec<TangentGeom> = Vec::new();
|
let mut tangents: Vec<TangentGeom> = Vec::new();
|
||||||
let mut arrow_fill: Vec<[f32; 3]> = Vec::new();
|
let mut arrow_fill: Vec<[f32; 3]> = Vec::new();
|
||||||
|
|
@ -1209,7 +1209,7 @@ impl MultiLeaderTess for MultiLeader {
|
||||||
ctrl.push(cp_f);
|
ctrl.push(cp_f);
|
||||||
}
|
}
|
||||||
for &c in &ctrl {
|
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));
|
snap_pts.push((Vec3::from(c).as_dvec3(), SnapHint::Node));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
8
src/scene/cache/block_cache.rs
vendored
8
src/scene/cache/block_cache.rs
vendored
|
|
@ -38,7 +38,7 @@ pub struct LocalWire {
|
||||||
/// Low-bit residual paired with `points` so block-instance wires keep
|
/// Low-bit residual paired with `points` so block-instance wires keep
|
||||||
/// sub-f32 precision once the renderer translates them to world space.
|
/// sub-f32 precision once the renderer translates them to world space.
|
||||||
pub points_low: Vec<[f32; 3]>,
|
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 snap_pts: Vec<(glam::DVec3, SnapHint)>,
|
||||||
pub tangent_geoms: Vec<TangentGeom>,
|
pub tangent_geoms: Vec<TangentGeom>,
|
||||||
pub fill_tris: Vec<[f32; 3]>,
|
pub fill_tris: Vec<[f32; 3]>,
|
||||||
|
|
@ -1042,7 +1042,7 @@ struct BatchEntry {
|
||||||
points: Vec<[f32; 3]>,
|
points: Vec<[f32; 3]>,
|
||||||
points_low: Vec<[f32; 3]>,
|
points_low: Vec<[f32; 3]>,
|
||||||
snap_pts: Vec<(glam::DVec3, SnapHint)>,
|
snap_pts: Vec<(glam::DVec3, SnapHint)>,
|
||||||
key_vertices: Vec<[f32; 3]>,
|
key_vertices: Vec<[f64; 3]>,
|
||||||
tangent_geoms: Vec<TangentGeom>,
|
tangent_geoms: Vec<TangentGeom>,
|
||||||
fill_tris: Vec<[f32; 3]>,
|
fill_tris: Vec<[f32; 3]>,
|
||||||
min_x: f32,
|
min_x: f32,
|
||||||
|
|
@ -1454,9 +1454,7 @@ fn emit_wire(
|
||||||
p[1] as f64 + lo_y,
|
p[1] as f64 + lo_y,
|
||||||
p[2] as f64 + lo_z,
|
p[2] as f64 + lo_z,
|
||||||
));
|
));
|
||||||
entry
|
entry.key_vertices.push([v.x - ox, v.y - oy, v.z - oz]);
|
||||||
.key_vertices
|
|
||||||
.push([(v.x - ox) as f32, (v.y - oy) as f32, (v.z - oz) as f32]);
|
|
||||||
}
|
}
|
||||||
for (p, hint) in &lw.snap_pts {
|
for (p, hint) in &lw.snap_pts {
|
||||||
let v = accum_xform.apply(Vector3::new(
|
let v = accum_xform.apply(Vector3::new(
|
||||||
|
|
|
||||||
|
|
@ -213,10 +213,10 @@ pub fn tessellate(
|
||||||
}
|
}
|
||||||
|
|
||||||
let snap_pts = offset_snap_pts(te.snap_pts, 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
|
.key_vertices
|
||||||
.into_iter()
|
.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();
|
.collect();
|
||||||
|
|
||||||
// Empty input (no glyphs) → emit a single empty wire so the
|
// Empty input (no glyphs) → emit a single empty wire so the
|
||||||
|
|
@ -293,12 +293,10 @@ pub fn tessellate(
|
||||||
let s = 0.1_f32;
|
let s = 0.1_f32;
|
||||||
let snap_pts = offset_snap_pts(te.snap_pts, world_offset);
|
let snap_pts = offset_snap_pts(te.snap_pts, world_offset);
|
||||||
let [ox, oy, oz] = world_offset;
|
let [ox, oy, oz] = world_offset;
|
||||||
let key_vertices: Vec<[f32; 3]> = te
|
let key_vertices: Vec<[f64; 3]> = te
|
||||||
.key_vertices
|
.key_vertices
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|[kx, ky, kz]| {
|
.map(|[kx, ky, kz]| [kx - ox, ky - oy, kz - oz])
|
||||||
[(kx - ox) as f32, (ky - oy) as f32, (kz - oz) as f32]
|
|
||||||
})
|
|
||||||
.collect();
|
.collect();
|
||||||
return vec![WireModel {
|
return vec![WireModel {
|
||||||
name,
|
name,
|
||||||
|
|
@ -339,10 +337,10 @@ pub fn tessellate(
|
||||||
{
|
{
|
||||||
let [ox, oy, oz] = world_offset;
|
let [ox, oy, oz] = world_offset;
|
||||||
let snap_pts = offset_snap_pts(te.snap_pts, 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
|
.key_vertices
|
||||||
.into_iter()
|
.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();
|
.collect();
|
||||||
return vec![WireModel {
|
return vec![WireModel {
|
||||||
name,
|
name,
|
||||||
|
|
@ -372,10 +370,10 @@ pub fn tessellate(
|
||||||
{
|
{
|
||||||
let [ox, oy, oz] = world_offset;
|
let [ox, oy, oz] = world_offset;
|
||||||
let snap_pts = offset_snap_pts(te.snap_pts, 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
|
.key_vertices
|
||||||
.into_iter()
|
.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();
|
.collect();
|
||||||
return vec![WireModel {
|
return vec![WireModel {
|
||||||
name,
|
name,
|
||||||
|
|
@ -409,10 +407,10 @@ pub fn tessellate(
|
||||||
let [ox, oy, oz] = world_offset;
|
let [ox, oy, oz] = world_offset;
|
||||||
let (local_pts, local_pts_low) = offset_to_ds(points, 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 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
|
.key_vertices
|
||||||
.into_iter()
|
.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();
|
.collect();
|
||||||
let (fill_tris, fill_tris_low) = offset_to_ds(te.fill_tris, world_offset);
|
let (fill_tris, fill_tris_low) = offset_to_ds(te.fill_tris, world_offset);
|
||||||
return vec![WireModel {
|
return vec![WireModel {
|
||||||
|
|
@ -440,10 +438,10 @@ pub fn tessellate(
|
||||||
let [ox, oy, oz] = world_offset;
|
let [ox, oy, oz] = world_offset;
|
||||||
let (local_pts, local_pts_low) = offset_to_ds(points, 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 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
|
.key_vertices
|
||||||
.into_iter()
|
.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();
|
.collect();
|
||||||
return vec![WireModel {
|
return vec![WireModel {
|
||||||
name,
|
name,
|
||||||
|
|
@ -491,6 +489,10 @@ pub fn tessellate(
|
||||||
// f64 for the WireModel's double-single-era snap buffer.
|
// f64 for the WireModel's double-single-era snap buffer.
|
||||||
let snap_pts: Vec<(glam::DVec3, SnapHint)> =
|
let snap_pts: Vec<(glam::DVec3, SnapHint)> =
|
||||||
snap_pts.into_iter().map(|(p, h)| (p.as_dvec3(), h)).collect();
|
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 {
|
vec![WireModel {
|
||||||
name,
|
name,
|
||||||
points,
|
points,
|
||||||
|
|
|
||||||
|
|
@ -3270,14 +3270,14 @@ impl Scene {
|
||||||
for &[x, y, z] in &wire.key_vertices {
|
for &[x, y, z] in &wire.key_vertices {
|
||||||
if x.is_finite() && y.is_finite() && z.is_finite() {
|
if x.is_finite() && y.is_finite() && z.is_finite() {
|
||||||
min = min.min(glam::Vec3::new(
|
min = min.min(glam::Vec3::new(
|
||||||
x + ox as f32,
|
(x + ox) as f32,
|
||||||
y + oy as f32,
|
(y + oy) as f32,
|
||||||
z + oz,
|
(z + oz as f64) as f32,
|
||||||
));
|
));
|
||||||
max = max.max(glam::Vec3::new(
|
max = max.max(glam::Vec3::new(
|
||||||
x + ox as f32,
|
(x + ox) as f32,
|
||||||
y + oy as f32,
|
(y + oy) as f32,
|
||||||
z + oz,
|
(z + oz as f64) as f32,
|
||||||
));
|
));
|
||||||
any = true;
|
any = true;
|
||||||
}
|
}
|
||||||
|
|
@ -8593,7 +8593,7 @@ fn lod_stub_wire(
|
||||||
line_weight_px: 1.0,
|
line_weight_px: 1.0,
|
||||||
snap_pts: vec![],
|
snap_pts: vec![],
|
||||||
tangent_geoms: vec![],
|
tangent_geoms: vec![],
|
||||||
key_vertices: vec![[cx, cy, cz]],
|
key_vertices: vec![[cx as f64, cy as f64, cz as f64]],
|
||||||
aabb,
|
aabb,
|
||||||
plinegen: true,
|
plinegen: true,
|
||||||
vp_scissor: None,
|
vp_scissor: None,
|
||||||
|
|
|
||||||
|
|
@ -64,7 +64,7 @@ pub struct WireModel {
|
||||||
/// True polyline vertices used for Endpoint/Midpoint snap.
|
/// True polyline vertices used for Endpoint/Midpoint snap.
|
||||||
/// Non-empty only for entities with distinct vertex positions (Line, LwPolyline).
|
/// Non-empty only for entities with distinct vertex positions (Line, LwPolyline).
|
||||||
/// Empty for tessellated curves (Circle, Arc, Ellipse) which use snap_pts instead.
|
/// 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].
|
/// World-space 2-D bounding box [min_x, min_y, max_x, max_y].
|
||||||
/// Set from acadrust `bounding_box()` in `tessellate_entity()`.
|
/// Set from acadrust `bounding_box()` in `tessellate_entity()`.
|
||||||
/// Preview / interim wires use `UNBOUNDED_AABB` so they are never pre-rejected
|
/// Preview / interim wires use `UNBOUNDED_AABB` so they are never pre-rejected
|
||||||
|
|
|
||||||
|
|
@ -103,7 +103,7 @@ pub fn clip_wires(wires: &mut Vec<WireModel>, poly: &[[f32; 2]]) {
|
||||||
w.fill_tris = clip_triangles(&w.fill_tris, poly);
|
w.fill_tris = clip_triangles(&w.fill_tris, poly);
|
||||||
}
|
}
|
||||||
w.key_vertices
|
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.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);
|
w.aabb = recompute_aabb(&w.points, &w.fill_tris);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -126,11 +126,21 @@ impl Face3DGpu {
|
||||||
let fill_color = [r * 0.45, g * 0.45, b * 0.45, a];
|
let fill_color = [r * 0.45, g * 0.45, b * 0.45, a];
|
||||||
let depth = depth_of(wire);
|
let depth = depth_of(wire);
|
||||||
let p = &wire.key_vertices;
|
let p = &wire.key_vertices;
|
||||||
let v = |i: usize| Face3DVertex {
|
// key_vertices are f64 (offset-relative); split into the
|
||||||
position: p[i],
|
// double-single (high, low) pair the face3d shader expects.
|
||||||
color: fill_color,
|
let v = |i: usize| {
|
||||||
draw_depth: depth,
|
let [x, y, z] = p[i];
|
||||||
position_low: [0.0; 3],
|
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(0));
|
||||||
verts_3d.push(v(1));
|
verts_3d.push(v(1));
|
||||||
|
|
|
||||||
|
|
@ -542,7 +542,10 @@ impl Snapper {
|
||||||
if !wire.key_vertices.is_empty() {
|
if !wire.key_vertices.is_empty() {
|
||||||
// Use explicit vertices (Line, LwPolyline): every vertex is an endpoint.
|
// Use explicit vertices (Line, LwPolyline): every vertex is an endpoint.
|
||||||
for &p in &wire.key_vertices {
|
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 {
|
} else {
|
||||||
// Tessellated curves (Circle, Arc, Ellipse): only arc endpoints.
|
// Tessellated curves (Circle, Arc, Ellipse): only arc endpoints.
|
||||||
|
|
@ -571,8 +574,8 @@ impl Snapper {
|
||||||
}
|
}
|
||||||
if !wire.key_vertices.is_empty() {
|
if !wire.key_vertices.is_empty() {
|
||||||
for seg in wire.key_vertices.windows(2) {
|
for seg in wire.key_vertices.windows(2) {
|
||||||
let a = Vec3::from(seg[0]);
|
let a = Vec3::new(seg[0][0] as f32, seg[0][1] as f32, seg[0][2] as f32);
|
||||||
let b = Vec3::from(seg[1]);
|
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 {
|
if a.distance_squared(b) > 1e-12 {
|
||||||
try_pt((a + b) * 0.5, SnapType::Midpoint);
|
try_pt((a + b) * 0.5, SnapType::Midpoint);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue