forked from 1b-agent/opencadstudio-upstream
Group nested DGN complex elements under their own headers
The element collector keeps a stack of open complex elements instead of one. A chain, text node or cell inside a cell is gathered on its own and, once complete, counts as one component of the cell, rather than closing the cell early and leaving its remaining components at the top level. A B-spline curve whose poles cannot be read still takes its place in the open cell, so the cell does not absorb the element after it. An element that is not a component ends every complex element still open, so a header whose count overstates its components cannot swallow the rest of the model. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
11ef1efc43
commit
a5f965ead4
3 files changed
+56
-16
No files matched your search
@@ -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 {
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<DgnElement>,
|
||||
/// 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user