Commit Graph
6 Commits
Author SHA1 Message Date
Umut CANandClaude Opus 5 efcc8bbba1 fix(task-7): crossings test the exact arc, so a line through a jump's apex counts
flatten_bulges chops a semicircle into an even number of chords (36 for
r=50, 12 for r=5), so a flattened vertex lands exactly on the apex — the
axis of symmetry, the one place a P&ID line most plausibly meets a
crossing jump. segments_cross treats a vertex hit as a junction, so both
neighbouring chords dropped it and the arc contributed 0: the (45,0)->(55,0)
bulge -1 jump reported crossings 0 at x=50 and 1 at x=50.3 or x=49, the
plan's own (0,0)->(100,0) semicircle 0 at x=50, and the mirrored frame
(extrusion -Z) 0 at x=-50.

count_crossings now takes bulges= (per-chain DXF bulge lists, zero-padded)
and tests every bulged edge as its exact arc through the new
segment_arc_crossings — circle/segment intersection restricted to the
sweep — with the same junction rule as the straight case: a hit within
_EPS of the segment's ends, of the arc's own two ends, or a tangent, is
not a crossing. Nothing along the sweep is a vertex any more. The arc
parametrisation is factored into _arc_of_bulge and shared with
flatten_bulges, which keeps its promised signature and its ezdxf pin but
no longer feeds the crossing count. draw_line passes the vertices and
bulges through unflattened.

Pinned in tests: the apex case on the semicircle (x=50, y 20->60), the
r=5 jump at x=50 / 50.3 / 49 on +Z and -Z frames, the junction cases
(T-touch on the arc, through the arc's endpoint, chord side, tangent
along the apex, in-and-out at y=4.9 counts 2), and 4x400 seeded random
segment/arc pairs against ezdxf's ConstructionArc.intersect_line (a
20 000-case run in the worktree found 0 mismatches). The eight new
assertions fail on the flattened rule and pass on the exact one.

Headless finding, headless evidence; no new ActiveX call was written, so
the shared live AutoCAD was not touched.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FKFStjEFzpGyLq5bMpWxTd
2026-09-22 11:06:04 +03:00
Umut CANandClaude Opus 5 9cb4bee587 fix(pid): existing line payloads are read tolerantly and crossings follow arcs, not chords
A foreign or hand-edited ACADMCP_PID payload (from: 'garbage', seq: True)
made the next pid_line_draw raise TypeError; payload_port_refs /
payload_seq now accept only well-formed values and a reader result never
raises. An existing polyline with a bulge was tested as its chord, so a
line through the arc reported crossings 0; flatten_bulges (pure, pinned
against ezdxf.math's flattening) feeds count_crossings on both engines.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FKFStjEFzpGyLq5bMpWxTd
2026-09-21 23:05:54 +03:00
Umut CANandClaude Opus 5 3c0babfef1 fix(pid): signal lines carry no fabricated number; a bubble exits towards the first waypoint
An ISA-5.1 signal line has no pipe line number, yet every pneumatic /
electric line got the bare sequence as its number and a label, and ate a
process sequence number. Signal classes now leave line_number None (a
verbatim one is still honoured), seq None, no label. A radial port aimed
at the far end even with waypoints, so the first segment cut through the
bubble; aim_points (lines.py) aims at the first/last waypoint for both
draw_line and the dry run.

Merge note: benchmarks/adapters/autocad_mcp_pro.py (final group's file)
had its two _task_pid_roundtrip assertion lines moved to the new truth —
the signal row is unnumbered, the connector row is 3.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FKFStjEFzpGyLq5bMpWxTd
2026-09-21 22:24:03 +03:00
Umut CANandClaude Opus 5 6ad3734c47 fix(task-14): per-space resolution, mirrored inserts, tags above the box, per-axis scale
Closes the four verified BLOCKING findings on pid_graph.

1. scope="all" attached across layouts: the port grid, bbox candidates,
   vertex grid, junctions and text lookup were pooled from every space.
   The grid is now keyed by (space, cell) and every lookup filters by the
   edge's space; junctions carry `space`.
2. A mirrored INSERT (extrusion -Z, as MIRROR3D / foreign DXFs store it)
   got its catalogue ports on the unmirrored image at 1.0. Both engines
   report `mirrored` on INSERT properties (ezdxf: extrusion z < 0; COM:
   Normal z < 0; default False); transform_port takes `mirrored` and
   applies x -> -x about the WCS insertion point after rotation/scale,
   direction (180 - d) mod 360 — cross-checked against Insert.matrix44.
   resolve_endpoint passes it through too, so draw_line starts on the
   mirror image as well.
3. The text-tag fallback searched a full circle around the box top, so a
   line label or note below the symbol beat the tag above it. Candidates
   must now sit at or above top - height/2 (spec §9.2 step 6), nearest
   wins, and line-number texts are never equipment tags.
4. A non-uniform INSERT scale re-ran the transform with the X factor and
   set `inferred` (reserved for foreign-block ports). transform_port
   gains `strict=False` for the reader: point ports scale per axis
   exactly; a radial port keeps min(sx, sy)·r and the node drops to 0.6
   with notes ["non-uniform scale"]. Node dicts gain `y_scale`,
   `mirrored` and `notes` (default []).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FKFStjEFzpGyLq5bMpWxTd
2026-09-16 10:35:20 +03:00
Umut CANandClaude Opus 5 e924b5db99 fix(task-13): mirrored-symbol ports and COM-visible existing lines
Two review findings on pid_line_draw, both root-caused:

1. existing_pid_lines() filtered entity_list(type_filter="LWPOLYLINE") and
   tested info.type == "LWPOLYLINE". A live LWPOLYLINE's ActiveX ObjectName
   is AcDbPolyline (the repo's own 2026-08-06 measurement), which the COM
   engine reports as POLYLINE, so on live AutoCAD every auto-built number was
   seq 1, crossings always 0 and port_reuse always []. The reader now lists
   without a type filter and accepts {LWPOLYLINE, POLYLINE, 2DPOLYLINE} plus
   LINE — the same set the Task 14 graph reader keeps. The COM _entity_info
   polyline branch matched only the DXF-flavoured "AcDbLWPolyline", so a live
   LWPOLYLINE never got `points` either; it now accepts both spellings (with
   the OCS normalisation), which is what makes the crossing count real there.

2. resolve_endpoint() applied only x_scale, so a mirrored INSERT
   (entity_mirror writes y_scale = -1) resolved its port to a point off the
   symbol and the line was drawn through the pump body. transform_port takes
   an optional y_scale (default: uniform, signature unchanged) and applies the
   full reflect-then-rotate transform to point, direction and radius; a
   stretched symbol (|x_scale| != |y_scale|) has no circle for a radial port
   and is refused with a clear ValueError instead of a silent wrong number.

Tests: mirror about both axes resolves onto the real geometry, a stretched
copy is refused, and a fake-COM AcDbPolyline probe sees the existing line
with its seq, vertices and from-ref.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FKFStjEFzpGyLq5bMpWxTd
2026-09-15 23:48:35 +03:00
Umut CANandClaude Opus 5 e8f1a666f8 feat(pid): pid_line_draw — port-to-port orthogonal lines with class, number, markers
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FKFStjEFzpGyLq5bMpWxTd
2026-09-15 23:26:09 +03:00