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:
parent
8bfa5088c4
commit
288ccff95a
20 changed files with 371 additions and 360 deletions
|
|
@ -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]))),
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue