diff --git a/src/scene/model/underlay_vector/dgn7.rs b/src/scene/model/underlay_vector/dgn7.rs index f9be987e6..d5b8612d3 100644 --- a/src/scene/model/underlay_vector/dgn7.rs +++ b/src/scene/model/underlay_vector/dgn7.rs @@ -254,6 +254,11 @@ fn read_run(run: &[&[u8]], colors: &[[u8; 3]], d3: bool, depth: usize) -> Raw { if e[1] & 0x80 != 0 || e.len() < 36 { continue; } + // An element that is no component ends the complex elements still + // open. + if e[0] & 0x80 == 0 { + collect.close(); + } let symbology = uint16(e, 34).unwrap_or(0); let color = colors[(symbology >> 8) as usize]; let element = |geom: DgnGeom| DgnElement { diff --git a/src/scene/model/underlay_vector/dgn8.rs b/src/scene/model/underlay_vector/dgn8.rs index ca2f5f63b..fd03152f4 100644 --- a/src/scene/model/underlay_vector/dgn8.rs +++ b/src/scene/model/underlay_vector/dgn8.rs @@ -686,6 +686,11 @@ fn read_run(run: &[&[u8]], styles: &Styles, xf: &Xf) -> Raw { // An open B-spline curve: order, pole count, closure and its header. let mut spline: Option<(usize, usize, bool, DgnElement)> = None; for (index, e) in run.iter().enumerate() { + // An element that is no component ends the complex elements still + // open. + if !is_component(e) { + collect.close(); + } if e.len() < 104 || styles.hidden.contains(&u32_at(e, 12).unwrap_or(0)) { continue; } @@ -1007,12 +1012,17 @@ fn read_run(run: &[&[u8]], styles: &Styles, xf: &Xf) -> Raw { continue; }; let flags = u16::from_le_bytes([lo, hi]); - spline = Some(( + // A curve before it that never got its poles still takes + // its place in an open cell. + let unread = spline.replace(( ((flags & 0x0f) + 2) as usize, u32_at(e, 112).unwrap_or(0) as usize, flags & 0x0180 != 0, element(DgnGeom::Chain(Vec::new())), )); + if unread.is_some() { + collect.skip(); + } } 21 => { let n = u32_at(e, 104).unwrap_or(0) as usize; @@ -1042,6 +1052,8 @@ fn read_run(run: &[&[u8]], styles: &Styles, xf: &Xf) -> Raw { ); } collect.push(DgnElement { geom, ..header }); + } else { + collect.skip(); } } } diff --git a/src/scene/model/underlay_vector/model.rs b/src/scene/model/underlay_vector/model.rs index ea98c7d81..ed63a9163 100644 --- a/src/scene/model/underlay_vector/model.rs +++ b/src/scene/model/underlay_vector/model.rs @@ -728,26 +728,33 @@ impl DgnGeom { } /// Collects elements in file order, gathering the components of a complex -/// chain, shape or text node into their header's element. +/// chain, shape, text node or cell into their header's element. #[derive(Default)] pub struct DgnCollector { pub elements: Vec, - /// The open complex element and how many components it still takes. - open: Option<(usize, DgnElement)>, + /// The open complex elements, innermost last, each with how many + /// components it still takes. A complex element inside another is one + /// component of it once it is complete. + open: Vec<(usize, DgnElement)>, } impl DgnCollector { - /// A complex chain or shape (or a text node) header with `count` + /// A complex chain or shape, a text node or a cell header with `count` /// components. pub fn open(&mut self, count: usize, header: DgnElement) { - self.close(); if count > 0 { - self.open = Some((count, header)); + self.open.push((count, header)); + } else { + self.skip(); } } - pub fn push(&mut self, element: DgnElement) { - if let Some((left, header)) = self.open.as_mut() { + pub fn push(&mut self, mut element: DgnElement) { + loop { + let Some((left, header)) = self.open.last_mut() else { + self.elements.push(element); + return; + }; match &mut header.geom { DgnGeom::Chain(parts) | DgnGeom::TextNode { lines: parts, .. } => { parts.push(element.geom) @@ -756,18 +763,34 @@ impl DgnCollector { _ => {} } *left -= 1; - if *left == 0 { - self.close(); + if *left > 0 { + return; } - return; + let Some((_, done)) = self.open.pop() else { + return; + }; + element = done; } - self.elements.push(element); } - /// Ends a complex element cut short with the components it has. + /// A component that converts to nothing (a curve that could not be + /// read) still takes its place in the open complex element. + pub fn skip(&mut self) { + if let Some((left, _)) = self.open.last_mut() { + *left -= 1; + if *left == 0 { + if let Some((_, done)) = self.open.pop() { + self.push(done); + } + } + } + } + + /// Ends the complex elements cut short with the components they have + /// (an element that is no component ends them all). pub fn close(&mut self) { - if let Some((_, header)) = self.open.take() { - self.elements.push(header); + while let Some((_, header)) = self.open.pop() { + self.push(header); } } }