fix: world_offset precision fix for large-coordinate DXF files (e.g. Turkish UTM)

Subtracts the DXF header extents centroid (world_offset) from all coordinates
in f64 BEFORE casting to f32. This eliminates the ~0.5 m ULP error that occurs
at 4,000,000 m UTM coordinates and caused geometry to disappear on zoom-out.

- Scene: adds world_offset field + compute_and_set_world_offset() method
- tessellate.rs: threads world_offset through all f64→f32 conversions
  (legacy_geometry, dimension_geometry, solid_wire_fallback, multileader)
- truck_tess.rs: to_local() helper already in place from prior session
- mod.rs: tessellate_entity() and entity_aabb() apply world_offset
- update.rs: compute_and_set_world_offset() called after doc load
- cmd_result.rs / solid3d_cmds.rs: pass correct offset to truck tessellators

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Hakan Seven 2026-04-27 07:41:38 +03:00
commit a2fb334966
7 changed files with 200 additions and 112 deletions

View file

@ -954,6 +954,7 @@ impl H7CAD {
let entity_opt = self.tabs[i].scene.document.get_entity(handle).cloned();
if let Some(entity) = entity_opt {
let truck_entity = entity.to_truck_entity(&self.tabs[i].scene.document);
let woff = self.tabs[i].scene.world_offset;
let result = truck_entity.and_then(|te| {
match te.object {
TruckObject::Contour(wire) => {
@ -961,7 +962,7 @@ impl H7CAD {
let face = builder::try_attach_plane(&[wire]).ok()?;
// tsweep(Face) → Solid
let solid = builder::tsweep(&face, TruckVec3::new(0.0, 0.0, height as f64));
match truck_tess::tessellate_solid(&solid) {
match truck_tess::tessellate_solid(&solid, woff) {
truck_tess::TruckTessResult::Mesh { verts, normals, indices } => {
Some(crate::scene::mesh_model::MeshModel {
name: String::new(),
@ -1008,6 +1009,7 @@ impl H7CAD {
let entity_opt = self.tabs[i].scene.document.get_entity(handle).cloned();
if let Some(entity) = entity_opt {
let truck_entity = entity.to_truck_entity(&self.tabs[i].scene.document);
let woff = self.tabs[i].scene.world_offset;
let result = truck_entity.and_then(|te| {
let wire: Option<truck_modeling::Wire> = match te.object {
TruckObject::Contour(w) => Some(w),
@ -1023,7 +1025,7 @@ impl H7CAD {
let dir = (axis_end - axis_start).normalize();
let axis = TruckVec3::new(dir.x as f64, dir.z as f64, dir.y as f64);
let shell = builder::rsweep(&wire, origin, axis, Rad(angle_deg.to_radians() as f64));
match truck_tess::tessellate_shell(&shell) {
match truck_tess::tessellate_shell(&shell, woff) {
truck_tess::TruckTessResult::Mesh { verts, normals, indices } => {
Some(crate::scene::mesh_model::MeshModel {
name: String::new(),
@ -1066,6 +1068,7 @@ impl H7CAD {
let profile_ent = self.tabs[i].scene.document.get_entity(profile_handle).cloned();
let path_ent = self.tabs[i].scene.document.get_entity(path_handle).cloned();
let woff = self.tabs[i].scene.world_offset;
let result = profile_ent.zip(path_ent).and_then(|(prof_e, path_e)| {
let prof_truck = prof_e.to_truck_entity(&self.tabs[i].scene.document)?;
@ -1093,7 +1096,7 @@ impl H7CAD {
// wire we get a Solid, otherwise a Shell.
if let Ok(face) = builder::try_attach_plane(&[profile_wire.clone()]) {
let solid = builder::tsweep(&face, dir);
match truck_tess::tessellate_solid(&solid) {
match truck_tess::tessellate_solid(&solid, woff) {
truck_tess::TruckTessResult::Mesh { verts, normals, indices } =>
Some(crate::scene::mesh_model::MeshModel {
name: String::new(), verts, normals, indices, color, selected: false,
@ -1102,7 +1105,7 @@ impl H7CAD {
}
} else {
let shell = builder::tsweep(&profile_wire, dir);
match truck_tess::tessellate_shell(&shell) {
match truck_tess::tessellate_shell(&shell, woff) {
truck_tess::TruckTessResult::Mesh { verts, normals, indices } =>
Some(crate::scene::mesh_model::MeshModel {
name: String::new(), verts, normals, indices, color, selected: false,
@ -1126,7 +1129,7 @@ impl H7CAD {
);
if let Ok(face) = builder::try_attach_plane(&[profile_wire.clone()]) {
let solid = builder::tsweep(&face, dir);
match truck_tess::tessellate_solid(&solid) {
match truck_tess::tessellate_solid(&solid, woff) {
truck_tess::TruckTessResult::Mesh { verts, normals, indices } =>
Some(crate::scene::mesh_model::MeshModel {
name: String::new(), verts, normals, indices, color, selected: false,
@ -1135,7 +1138,7 @@ impl H7CAD {
}
} else {
let shell = builder::tsweep(&profile_wire, dir);
match truck_tess::tessellate_shell(&shell) {
match truck_tess::tessellate_shell(&shell, woff) {
truck_tess::TruckTessResult::Mesh { verts, normals, indices } =>
Some(crate::scene::mesh_model::MeshModel {
name: String::new(), verts, normals, indices, color, selected: false,
@ -1190,6 +1193,7 @@ impl H7CAD {
}
}
let woff = self.tabs[i].scene.world_offset;
let result: Option<crate::scene::mesh_model::MeshModel> = (|| {
if wires.len() < 2 { return None; }
@ -1210,7 +1214,7 @@ impl H7CAD {
}
let shell = truck_modeling::Shell::from(all_faces);
match truck_tess::tessellate_shell(&shell) {
match truck_tess::tessellate_shell(&shell, woff) {
truck_tess::TruckTessResult::Mesh { verts, normals, indices } =>
Some(crate::scene::mesh_model::MeshModel {
name: String::new(), verts, normals, indices, color, selected: false,

View file

@ -73,6 +73,7 @@ impl H7CAD {
}
}
self.tabs[i].scene.compute_and_set_world_offset();
self.tabs[i].scene.populate_hatches_from_document();
self.tabs[i].scene.populate_images_from_document();
self.tabs[i].scene.populate_meshes_from_document();