fix: restore visibility for large-coordinate DXF files after world_offset regression
Three root causes caused all geometry and UCS arrows to disappear: 1. TruckObject::Lines and TruckObject::Text variants returned world-space f32 coordinates without applying world_offset, so fit_all() computed bounds spanning from local space to UTM world space (~4 M m), placing the camera impossibly far from all visible geometry. 2. Ray/XLine entities with unnormalized direction vectors (common in some DXF exporters) produced astronomically large far-point coordinates (up to 1e28) that overwhelmed the camera fit even after the offset fix. Fixed by normalizing the direction vector before multiplying by DISPLAY_EXTENT. 3. Origin-stuck corrupted entities (coordinates ≈ 0 in world space become ≈ -world_offset in local space) pulled the fit_all() bounds far from the actual drawing. Fixed by computing local_extent_max from EXTMIN/EXTMAX (10× safety margin) and skipping points outside that range in fit_all(). Additional hardening: wire_gpu.rs now skips ±inf segments (not just NaN), and snap_pts/key_vertices in all TruckObject variants are offset-corrected. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
a2fb334966
commit
e191315713
4 changed files with 115 additions and 43 deletions
|
|
@ -65,8 +65,11 @@ pub fn tessellate(
|
|||
match te.object {
|
||||
// ── Text / MText: pre-tessellated glyph strokes ───────────────
|
||||
TruckObject::Text(strokes_2d) => {
|
||||
// Elevation comes from the entity's Z coordinate.
|
||||
let elev = entity_z(entity);
|
||||
// Glyph strokes come from acad_to_truck in world-space f32.
|
||||
// Subtract world_offset (f32 subtraction — acceptable precision
|
||||
// for text rendering; the anchor was already cast to f32 there).
|
||||
let [ox, oy, oz] = world_offset;
|
||||
let elev = entity_z(entity) - oz as f32;
|
||||
|
||||
// Pack all strokes into one flat point list, separated by
|
||||
// NaN sentinels so wire_gpu.rs skips disconnected segments.
|
||||
|
|
@ -81,10 +84,11 @@ pub fn tessellate(
|
|||
points.push([f32::NAN, f32::NAN, f32::NAN]);
|
||||
}
|
||||
for &[x, y] in stroke {
|
||||
points.push([x, y, elev]);
|
||||
points.push([x - ox as f32, y - oy as f32, elev]);
|
||||
}
|
||||
}
|
||||
|
||||
let snap_pts = offset_snap_pts(te.snap_pts, world_offset);
|
||||
return WireModel {
|
||||
name,
|
||||
points,
|
||||
|
|
@ -93,7 +97,7 @@ pub fn tessellate(
|
|||
pattern_length: 0.0,
|
||||
pattern: [0.0; 8],
|
||||
line_weight_px,
|
||||
snap_pts: te.snap_pts,
|
||||
snap_pts,
|
||||
tangent_geoms: te.tangent_geoms,
|
||||
aci: 0,
|
||||
key_vertices: te.key_vertices,
|
||||
|
|
@ -107,6 +111,7 @@ pub fn tessellate(
|
|||
match result {
|
||||
TruckTessResult::Point([x, y, z]) => {
|
||||
let s = 0.1_f32;
|
||||
let snap_pts = offset_snap_pts(te.snap_pts, world_offset);
|
||||
return WireModel {
|
||||
name,
|
||||
points: vec![
|
||||
|
|
@ -120,11 +125,11 @@ pub fn tessellate(
|
|||
pattern_length: 0.0,
|
||||
pattern: [0.0; 8],
|
||||
line_weight_px: 1.0,
|
||||
snap_pts: te.snap_pts,
|
||||
snap_pts,
|
||||
tangent_geoms: te.tangent_geoms,
|
||||
aci: 0,
|
||||
key_vertices: te.key_vertices,
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
key_vertices: te.key_vertices,
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
};
|
||||
}
|
||||
_ => {}
|
||||
|
|
@ -133,6 +138,11 @@ pub fn tessellate(
|
|||
|
||||
TruckObject::Curve(e) => {
|
||||
if let TruckTessResult::Lines(points) = tessellate_edge(&e, world_offset) {
|
||||
let [ox, oy, oz] = world_offset;
|
||||
let snap_pts = offset_snap_pts(te.snap_pts, 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,
|
||||
|
|
@ -141,17 +151,22 @@ pub fn tessellate(
|
|||
pattern_length,
|
||||
pattern,
|
||||
line_weight_px,
|
||||
snap_pts: te.snap_pts,
|
||||
snap_pts,
|
||||
tangent_geoms: te.tangent_geoms,
|
||||
aci: 0,
|
||||
key_vertices: te.key_vertices,
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
key_vertices,
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
TruckObject::Contour(w) => {
|
||||
if let TruckTessResult::Lines(points) = tessellate_wire(&w, world_offset) {
|
||||
let [ox, oy, oz] = world_offset;
|
||||
let snap_pts = offset_snap_pts(te.snap_pts, 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,
|
||||
|
|
@ -160,29 +175,41 @@ pub fn tessellate(
|
|||
pattern_length,
|
||||
pattern,
|
||||
line_weight_px,
|
||||
snap_pts: te.snap_pts,
|
||||
snap_pts,
|
||||
tangent_geoms: te.tangent_geoms,
|
||||
aci: 0,
|
||||
key_vertices: te.key_vertices,
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
key_vertices,
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
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.
|
||||
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] }
|
||||
else { [x - ox as f32, y - oy as f32, z - oz as f32] }
|
||||
}).collect();
|
||||
let snap_pts = offset_snap_pts(te.snap_pts, 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,
|
||||
points: local_pts,
|
||||
color,
|
||||
selected,
|
||||
pattern_length: 0.0,
|
||||
pattern: [0.0; 8],
|
||||
line_weight_px,
|
||||
snap_pts: te.snap_pts,
|
||||
snap_pts,
|
||||
tangent_geoms: te.tangent_geoms,
|
||||
aci: 0,
|
||||
key_vertices: te.key_vertices,
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
key_vertices,
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -956,6 +983,13 @@ fn vec3_local(v: Vector3, off: [f64; 3]) -> Vec3 {
|
|||
Vec3::new((v.x - off[0]) as f32, (v.y - off[1]) as f32, (v.z - off[2]) as f32)
|
||||
}
|
||||
|
||||
fn offset_snap_pts(pts: Vec<(Vec3, SnapHint)>, off: [f64; 3]) -> Vec<(Vec3, SnapHint)> {
|
||||
let [ox, oy, oz] = off;
|
||||
pts.into_iter()
|
||||
.map(|(p, h)| (Vec3::new(p.x - ox as f32, p.y - oy as f32, p.z - oz as f32), h))
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Returns the text position of a dimension in DXF world-space (f64, no offset applied).
|
||||
/// Used when building a synthetic Text entity so tessellate() can apply world_offset itself.
|
||||
fn dimension_text_pos_f64(dim: &Dimension) -> Vector3 {
|
||||
|
|
|
|||
Loading…
Reference in a new issue