fix(task-2): block_explode keeps the ATTRIB frame and writes into the owner layout
Two silent wrong-place defects in the BURST path. An ATTRIB is an OCS entity, so the TEXT that replaces it now carries extrusion/thickness with insert/align_point; a mirrored reference (ATTRIB reflected to (0,0,-1), INSERT +Z with yscale=-1) put the tag 50 units across the mirror axis with a clean audit. Members and TEXTs now go into the INSERT's owner layout (ezdxf get_layout, COM ObjectIdToObject(OwnerID)) instead of the current space: a sheet title block exploded while Model was current duplicated geometry into model space and then died on delete_entity headless, and on COM landed the tag text in model space with ok: True. A reference nested in a block definition is refused before any write on both engines. Five regression tests (mirrored INSERT, sheet-owned INSERT with Model current, nested INSERT, and the COM owner-block / nested-refusal call shapes) fail on the previous commit and pass here. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FKFStjEFzpGyLq5bMpWxTd
This commit is contained in:
co-authored by
Claude Opus 5
parent
19610b8f05
commit
13851a3d20
+42
-2
@@ -193,6 +193,38 @@ def _msp():
|
||||
return doc.ModelSpace
|
||||
|
||||
|
||||
def _owner_layout_block(doc, ent, handle):
|
||||
"""The block table record that owns ``ent``, refused unless it is a layout.
|
||||
|
||||
``Explode()`` places the members in the owner space, so anything this
|
||||
method adds alongside them must go there too — never ``ActiveLayout``,
|
||||
which is whatever tab the user happens to have open. An owner that is a
|
||||
block definition means ``ent`` is a nested reference; exploding it in place
|
||||
would redefine the block under every other reference, so it is refused
|
||||
before any call is dispatched. An owner that cannot be read at all is
|
||||
refused too rather than guessed.
|
||||
"""
|
||||
try:
|
||||
owner = doc.ObjectIdToObject(ent.OwnerID)
|
||||
is_layout = bool(owner.IsLayout)
|
||||
except Exception as exc:
|
||||
raise RuntimeError(
|
||||
f"Entity {handle} has no resolvable owner layout ({exc}); refusing to "
|
||||
"explode into a guessed space"
|
||||
) from exc
|
||||
if not is_layout:
|
||||
try:
|
||||
name = str(owner.Name)
|
||||
except Exception:
|
||||
name = "?"
|
||||
raise RuntimeError(
|
||||
f"Entity {handle} is nested inside block definition {name!r}; explode the "
|
||||
"outer reference instead (exploding here would redefine the block under "
|
||||
"every other reference)"
|
||||
)
|
||||
return owner
|
||||
|
||||
|
||||
def _require_block_defined(doc, name):
|
||||
"""``doc.Blocks.Item(name)``, or a ``ValueError`` before ``InsertBlock`` runs.
|
||||
|
||||
@@ -3312,6 +3344,14 @@ class ComBackend(AutoCADBackend):
|
||||
surface; ``Explode()``'s return shape is the ActiveX documented one
|
||||
(an array of the new objects) and is exercised live by the settings
|
||||
smoke.
|
||||
|
||||
The TEXTs go into the reference's *owner* block
|
||||
(``ObjectIdToObject(OwnerID)``), which is where ``Explode()`` puts the
|
||||
members; ``HandleToObject`` resolves a handle in any layout, so a title
|
||||
block on a sheet exploded while Model was active used to get its tag
|
||||
text in model space with ``ok: True``. A reference nested inside a
|
||||
block definition (owner ``IsLayout`` false) is refused before the
|
||||
explode is dispatched.
|
||||
"""
|
||||
|
||||
def _sync():
|
||||
@@ -3319,6 +3359,7 @@ class ComBackend(AutoCADBackend):
|
||||
ent = doc.HandleToObject(handle)
|
||||
if ent.ObjectName != "AcDbBlockReference":
|
||||
raise RuntimeError(f"Entity {handle} is not a block reference (INSERT)")
|
||||
owner = _owner_layout_block(doc, ent, handle)
|
||||
captured = []
|
||||
try:
|
||||
attrs = ent.GetAttributes()
|
||||
@@ -3347,11 +3388,10 @@ class ComBackend(AutoCADBackend):
|
||||
obj.Delete() # the tag placeholder EXPLODE leaves; the value is below
|
||||
continue
|
||||
inserted.append(str(obj.Handle))
|
||||
mspace = _msp()
|
||||
attribute_texts = []
|
||||
for item in captured:
|
||||
ins = item["insertion"]
|
||||
text = mspace.AddText(
|
||||
text = owner.AddText(
|
||||
item["text"],
|
||||
_apoint(ins[0], ins[1], ins[2] if len(ins) > 2 else 0.0),
|
||||
item["height"],
|
||||
|
||||
Reference in New Issue
Block a user