forked from 1b-agent/opencadstudio-upstream
fix(layers): honor layer off/freeze for block sub-entities
Block-internal entities ignored their own layer state: 2D subs were only filtered by the invisible flag in the block-defn cache, and 3D solids render through a separate mesh path that applied no layer filter at all. Both now skip subs on off/frozen layers, matching top-level entities. Caches rebuild on every toggle, so visibility updates live. Fixes #133 Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
1 parent
0dc537b669
commit
caafb9b99d
2 files changed
+58
-1
No files matched your search
Vendored
+15
@@ -253,6 +253,14 @@ fn collect_referenced_blocks(doc: &CadDocument) -> Vec<String> {
|
||||
seen.into_iter().collect()
|
||||
}
|
||||
|
||||
/// True when `layer` is turned off or frozen — entities on it never render.
|
||||
fn layer_hidden(doc: &CadDocument, layer: &str) -> bool {
|
||||
doc.layers
|
||||
.get(layer)
|
||||
.map(|l| l.flags.off || l.flags.frozen)
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
fn build_defn(
|
||||
doc: &CadDocument,
|
||||
block_name: &str,
|
||||
@@ -360,6 +368,13 @@ fn build_defn(
|
||||
if entity.common().invisible {
|
||||
continue;
|
||||
}
|
||||
// A sub-entity on a layer that is off or frozen must not render, same
|
||||
// as a top-level entity on that layer. The defn cache is rebuilt on
|
||||
// every layer off/freeze toggle (bump_geometry bumps block_epoch), so
|
||||
// baking the visibility here stays in sync.
|
||||
if layer_hidden(doc, &entity.common().layer) {
|
||||
continue;
|
||||
}
|
||||
match entity {
|
||||
EntityType::Block(_)
|
||||
| EntityType::BlockEnd(_)
|
||||
|
||||
+43
-1
@@ -2031,7 +2031,14 @@ impl Scene {
|
||||
}
|
||||
}
|
||||
}
|
||||
let mut all: Vec<MeshLodSet> = self.meshes.values().cloned().collect();
|
||||
// Top-level solids: drop those whose layer is off/frozen or that are
|
||||
// flagged invisible / isolated-hidden, mirroring the 2D wire path.
|
||||
let mut all: Vec<MeshLodSet> = self
|
||||
.meshes
|
||||
.iter()
|
||||
.filter(|(&h, _)| self.mesh_entity_visible(h))
|
||||
.map(|(_, set)| set.clone())
|
||||
.collect();
|
||||
// Block-definition solids are instanced per model-space INSERT so a
|
||||
// block placed at an INSERT scale renders at the right size. (#123)
|
||||
all.extend(self.instanced_block_meshes(self.model_space_block_handle()));
|
||||
@@ -2040,6 +2047,31 @@ impl Scene {
|
||||
arc
|
||||
}
|
||||
|
||||
/// True when `layer` is turned off or frozen — entities on it never render.
|
||||
fn layer_hidden(&self, layer: &str) -> bool {
|
||||
self.document
|
||||
.layers
|
||||
.get(layer)
|
||||
.map(|l| l.flags.off || l.flags.frozen)
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
/// Visibility test for a solid mesh entity, mirroring the 2D wire path:
|
||||
/// honour the invisible flag, the isolate/hide set, and the layer's
|
||||
/// off/frozen state.
|
||||
fn mesh_entity_visible(&self, handle: Handle) -> bool {
|
||||
let Some(c) = self.document.get_entity(handle).map(|e| e.common()) else {
|
||||
return false;
|
||||
};
|
||||
if c.invisible {
|
||||
return false;
|
||||
}
|
||||
if !self.hidden.is_empty() && self.hidden.contains(&handle) {
|
||||
return false;
|
||||
}
|
||||
!self.layer_hidden(&c.layer)
|
||||
}
|
||||
|
||||
/// One transformed mesh per block-definition solid instance reached from an
|
||||
/// INSERT owned by `layout_block`. Nested INSERTs accumulate their
|
||||
/// transform. Empty when no block solids exist. (#123)
|
||||
@@ -2054,6 +2086,11 @@ impl Scene {
|
||||
continue;
|
||||
}
|
||||
if let EntityType::Insert(ins) = e {
|
||||
// INSERT on an off/frozen (or invisible) layer hides the whole
|
||||
// instance, block-internal solids included.
|
||||
if !self.mesh_entity_visible(ins.common.handle) {
|
||||
continue;
|
||||
}
|
||||
self.expand_block_meshes(&ins.block_name, &ins.get_transform(), 0, woff, &mut out);
|
||||
}
|
||||
}
|
||||
@@ -2081,6 +2118,11 @@ impl Scene {
|
||||
let Some(e) = self.document.get_entity(h) else {
|
||||
continue;
|
||||
};
|
||||
// A block-internal solid / nested INSERT on an off/frozen layer
|
||||
// (or flagged invisible) must not render, same as a top-level one.
|
||||
if !self.mesh_entity_visible(h) {
|
||||
continue;
|
||||
}
|
||||
if let EntityType::Insert(ins) = e {
|
||||
let composed = ins.get_transform().then(accum);
|
||||
self.expand_block_meshes(&ins.block_name, &composed, depth + 1, woff, out);
|
||||
|
||||
Reference in new issue
Block a user