From 2716bcbbd8ca92b13baf5eb9abb2348dd55e540b Mon Sep 17 00:00:00 2001 From: Hakan Seven Date: Fri, 15 May 2026 21:09:56 +0300 Subject: [PATCH] fix(scene): drop unknown-owner entities when the file enumerates ownership elsewhere MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit belongs_to_visible_block's reverse-map fallback returned `true` on a map miss, which let block-defn entities with a null owner_handle leak into model space whenever their owning BlockRecord also had an empty entity_handles list. The visible symptom was a stray HATCH (and formerly BLOCK / BLOCKEND) selectable far from the drawing. The legacy permissive default existed because some DXF files omit group-code 330 everywhere, and dropping unknown-owner entities would empty MSPACE. Detect that case explicitly: if the entity_block_map is empty, no BlockRecord enumerated its contents — keep the legacy permissive behavior. If the map has at least one entry, the file is capable of declaring ownership, so an unknown-owner entity is an orphan and must not leak into the queried block. Co-Authored-By: Claude Opus 4.7 --- src/scene/mod.rs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/scene/mod.rs b/src/scene/mod.rs index d4f348fee..d2f3645dc 100644 --- a/src/scene/mod.rs +++ b/src/scene/mod.rs @@ -1142,8 +1142,20 @@ impl Scene { // P: epoch-cached reverse map replaces O(B) block_records scan. let map = self.entity_block_map(); - map.get(&entity_handle) - .map_or(true, |&owner| owner == block_handle) + if let Some(&owner) = map.get(&entity_handle) { + return owner == block_handle; + } + // Map miss. Permissive only when NO BlockRecord enumerated its + // entity_handles — that's a legacy DXF that omits 330 group codes + // everywhere, where dropping unknown-owner entities would empty + // model space. When at least one block did enumerate, the file is + // capable of declaring ownership, so an unknown-owner entity is + // an orphan (typically a block-defn entity whose owner was lost on + // round-trip) and must not leak into the queried block. + if map.is_empty() { + return true; + } + false } /// Build (and epoch-cache) a reverse map: entity_handle → block_record_handle,