fix(task-22): ucs_list decides "world" from the frame, not the empty name — an unnamed UCS is its own current row
An unnamed UCS (UCS Origin / 3P without saving, the common kind) has an empty UCSNAME exactly like WCS does, so both engines answered `current: world` while the drawing was not in WCS — verified live on AutoCAD 2026 (`_.UCS _O 10,10,0` → UCSNAME="" WORLDUCS=0) and on the DXF it writes ($UCSNAME='' $UCSORG=(0,20,0)). A silent wrong value. - COM: a named match still wins; otherwise WORLDUCS (AutoCAD's own answer) decides, and WORLDUCS=0 appends a `name: None` row built from UCSORG/UCSXDIR/UCSYDIR. - ezdxf: the same rule against $UCSORG/$UCSXDIR/$UCSYDIR via the new `engineering.environment.ucs.is_world_axes`; a stale $UCSNAME falls back to the frame instead of leaving no row current. - Server `ucs_list` result: `current` is null for an unnamed UCS (never `world`), plus `current_unnamed: bool` so null is unambiguous. - Tests: helper, headless (unnamed row, stale name, and the exact AutoCAD DXF over the wire), and COM fake reading WORLDUCS + the frame variables. 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
4bf686e943
commit
64cec37cc7
@@ -2692,22 +2692,41 @@ class EzdxfBackend(AutoCADBackend):
|
||||
}
|
||||
|
||||
async def ucs_list(self) -> list[dict]:
|
||||
from engineering.environment.ucs import WORLD
|
||||
from engineering.environment.ucs import (
|
||||
WORLD,
|
||||
WORLD_ORIGIN,
|
||||
WORLD_X_AXIS,
|
||||
WORLD_Y_AXIS,
|
||||
is_world_axes,
|
||||
)
|
||||
|
||||
def _sync():
|
||||
doc = self._require_doc()
|
||||
current = str(doc.header.get("$UCSNAME", "") or "")
|
||||
rows = [self._ucs_row(WORLD, (0, 0, 0), (1, 0, 0), (0, 1, 0), current == "")]
|
||||
header = doc.header
|
||||
current = str(header.get("$UCSNAME", "") or "")
|
||||
origin = tuple(header.get("$UCSORG", WORLD_ORIGIN))
|
||||
x_axis = tuple(header.get("$UCSXDIR", WORLD_X_AXIS))
|
||||
y_axis = tuple(header.get("$UCSYDIR", WORLD_Y_AXIS))
|
||||
rows = [self._ucs_row(WORLD, WORLD_ORIGIN, WORLD_X_AXIS, WORLD_Y_AXIS, False)]
|
||||
named_current = False
|
||||
for ucs in doc.ucs:
|
||||
is_current = current != "" and ucs.dxf.name.lower() == current.lower()
|
||||
named_current = named_current or is_current
|
||||
rows.append(
|
||||
self._ucs_row(
|
||||
ucs.dxf.name,
|
||||
ucs.dxf.origin,
|
||||
ucs.dxf.xaxis,
|
||||
ucs.dxf.yaxis,
|
||||
current != "" and ucs.dxf.name.lower() == current.lower(),
|
||||
ucs.dxf.name, ucs.dxf.origin, ucs.dxf.xaxis, ucs.dxf.yaxis, is_current
|
||||
)
|
||||
)
|
||||
if named_current:
|
||||
return rows
|
||||
# No saved entry is current. An empty $UCSNAME is NOT "world": an
|
||||
# unnamed UCS (UCS Origin / 3P without saving) has an empty name
|
||||
# too, and AutoCAD writes exactly that. The frame decides, the way
|
||||
# WORLDUCS does live.
|
||||
if is_world_axes(origin, x_axis, y_axis):
|
||||
rows[0]["current"] = True
|
||||
else:
|
||||
rows.append(self._ucs_row(None, origin, x_axis, y_axis, True))
|
||||
return rows
|
||||
|
||||
return await self._async(_sync)
|
||||
|
||||
Reference in New Issue
Block a user