diff --git a/Cargo.lock b/Cargo.lock index 548e2d2f7..7548727d1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -74,7 +74,7 @@ checksum = "366ffbaa4442f4684d91e2cd7c5ea7c4ed8add41959a31447066e279e432b618" [[package]] name = "acadrust" version = "0.4.0" -source = "git+https://github.com/OpenAEC-Foundation/acadifc?branch=main#3832a9b6f598405f057e6e4e6d49db65f4d68834" +source = "git+https://github.com/OpenAEC-Foundation/acadifc?branch=main#4ef83a122446504a988ed8ed7904b1c1b5f1b51f" dependencies = [ "ahash 0.8.12", "anyhow", diff --git a/src/entities/solid3d.rs b/src/entities/solid3d.rs index 152b7fa03..ef4b8eee3 100644 --- a/src/entities/solid3d.rs +++ b/src/entities/solid3d.rs @@ -263,6 +263,23 @@ pub fn fallback_wires(e: &EntityType) -> Option<&[acadrust::entities::Wire]> { } } +/// Whether the entity's ACIS payload parses into a SAT document. When it +/// does, the mesh pipeline (fill + feature edges + isolines, all body-placed) +/// is the authoritative render and the embedded display-cache wires must NOT +/// be drawn: they are body-local (unplaced), and for R2013+ AcDs-backed +/// solids the inline wire section misparses into garbage points near the +/// origin. The wires remain useful only as a last resort when the ACIS data +/// itself is unreadable. +pub fn acis_parses(e: &EntityType) -> bool { + match e { + EntityType::Solid3D(s) => s.acis_data.parse().is_some(), + EntityType::Region(r) => r.acis_data.parse().is_some(), + EntityType::Body(b) => b.acis_data.parse().is_some(), + EntityType::Surface(s) => s.acis_data.parse().is_some(), + _ => false, + } +} + /// Run the appropriate `solid3d_tess::tessellate_*` for the entity, /// returning `None` for non-volume entities or when the kernel fails. pub fn tessellate_volume( diff --git a/src/scene/convert/tessellate.rs b/src/scene/convert/tessellate.rs index 94679bcca..55cf95f3c 100644 --- a/src/scene/convert/tessellate.rs +++ b/src/scene/convert/tessellate.rs @@ -1706,6 +1706,13 @@ fn solid_wire_fallback(entity: &EntityType) -> Vec<[f64; 3]> { if wires.is_empty() { return vec![]; } + // Parseable ACIS → the mesh pipeline draws the body (placed); the embedded + // display-cache wires are body-local and would render unplaced at the + // origin (garbage for AcDs-backed solids). Only unreadable ACIS falls + // back to them. + if crate::entities::solid3d::acis_parses(entity) { + return vec![]; + } let mut pts: Vec<[f64; 3]> = Vec::new(); for wire in wires {