Add AutoCAD MCP premium skill and backend APIs
Introduce the autocad-mcp-premium skill with workflow docs, examples, and references (.claude/skills/autocad-mcp-premium/*). Add PlanSpec/critique plumbing and engineering helpers (engineering/plan_spec.py, engineering/critique.py) plus tests and a smoke script. Extend backend API (backends/base.py) with corner operations and premium meta-tools (trim/extend/fillet/chamfer, drawing_plan, drawing_critique, point_from_snap, construction_xline/clear, drawing_apply_iso_layers, dimension_auto, entity_select_smart) and implement COM backend corner ops (backends/com_backend.py) with placeholders for meta-tools. Update CLAUDE.md to document the premium drawing rules and standard workflow. Misc: add examples, references, and tests for premium features, and minor server/backend adjustments.
This commit is contained in:
@@ -0,0 +1,107 @@
|
||||
# Example — Simple P&ID Flow Control Loop
|
||||
|
||||
ISA-5.1 tagged flow loop: pump P-101 → flow transmitter FT-101 → control valve
|
||||
FCV-101 → vessel V-201. Drawn on A3 with the `pid` layer set.
|
||||
|
||||
## Layout
|
||||
|
||||
```text
|
||||
┌────┐ ╭──╮ ┌────────┐
|
||||
│P101├──────────────────┤FT├────────╳──────│ V-201 │
|
||||
└────┘ PROCESS-MAIN ╰┬─╯ PROCESS │ │ │
|
||||
│ signal │FCV │ │
|
||||
↓ │101 │ │
|
||||
(FIC101) │ └────────┘
|
||||
controller │
|
||||
─┴─ control output
|
||||
```
|
||||
|
||||
## Full workflow
|
||||
|
||||
```python
|
||||
# 1. PLAN
|
||||
plan = await drawing_plan(
|
||||
intent="Flow control loop 101: P-101 → FT-101 → FCV-101 → V-201",
|
||||
sheet_size="A3",
|
||||
scale=1.0,
|
||||
layer_set_id="pid",
|
||||
dim_style="ordinate", # P&ID typically minimal dim
|
||||
notes=["ISA-5.1 tag conventions", "Pneumatic signal lines dashed"],
|
||||
)
|
||||
|
||||
# 2. P&ID LAYERS
|
||||
await drawing_apply_iso_layers("pid")
|
||||
|
||||
# 3. EQUIPMENT — pump (circle) and vessel (rectangle)
|
||||
pump = await entity_create_circle(40, 60, 6, layer="PROCESS-EQUIPMENT")
|
||||
await entity_create_text("P-101", 33, 50, height=3.0, layer="INSTRUMENT-TAG-TEXT")
|
||||
|
||||
vessel = await entity_create_rectangle(180, 40, 230, 80, layer="PROCESS-EQUIPMENT")
|
||||
await entity_create_text("V-201", 195, 60, height=3.5, layer="INSTRUMENT-TAG-TEXT")
|
||||
|
||||
# 4. PROCESS LINE — main horizontal (heavy)
|
||||
main_line_a = await entity_create_line(46, 60, 110, 60, layer="PROCESS-PIPING-MAIN")
|
||||
main_line_b = await entity_create_line(110, 60, 150, 60, layer="PROCESS-PIPING-MAIN")
|
||||
main_line_c = await entity_create_line(150, 60, 180, 60, layer="PROCESS-PIPING-MAIN")
|
||||
|
||||
# 5. INSTRUMENT BUBBLES — flow transmitter, control valve
|
||||
ft = await entity_create_circle(110, 60, 4, layer="INSTRUMENT-SYMBOL")
|
||||
await entity_create_text("FT", 107, 60.5, height=2.0, layer="INSTRUMENT-TAG-TEXT")
|
||||
await entity_create_text("101", 106, 57.5, height=2.0, layer="INSTRUMENT-TAG-TEXT")
|
||||
|
||||
# control valve symbol = bowtie (2 triangles) — built from lines for now
|
||||
fcv_top1 = await entity_create_line(150, 60, 154, 64, layer="PROCESS-VALVES")
|
||||
fcv_top2 = await entity_create_line(150, 60, 154, 56, layer="PROCESS-VALVES")
|
||||
fcv_bot1 = await entity_create_line(154, 64, 158, 60, layer="PROCESS-VALVES")
|
||||
fcv_bot2 = await entity_create_line(154, 56, 158, 60, layer="PROCESS-VALVES")
|
||||
await entity_create_text("FCV-101", 145, 70, height=2.5, layer="INSTRUMENT-TAG-TEXT")
|
||||
|
||||
# 6. SIGNAL LINES — FT bubble up to controller, then to FCV (dashed)
|
||||
sig1 = await entity_create_line(110, 64, 110, 90, layer="INSTRUMENT-LINE-SIGNAL")
|
||||
controller = await entity_create_circle(110, 95, 5, layer="INSTRUMENT-SYMBOL")
|
||||
await entity_create_text("FIC", 107, 95.5, height=2.0, layer="INSTRUMENT-TAG-TEXT")
|
||||
await entity_create_text("101", 106, 92.5, height=2.0, layer="INSTRUMENT-TAG-TEXT")
|
||||
sig2 = await entity_create_line(110, 90, 154, 90, layer="INSTRUMENT-LINE-SIGNAL")
|
||||
sig3 = await entity_create_line(154, 90, 154, 64, layer="INSTRUMENT-LINE-SIGNAL")
|
||||
|
||||
# 7. (no dimensions — P&ID is schematic, not dimensioned)
|
||||
|
||||
# 8. CRITIQUE — focus on what matters for P&ID
|
||||
issues = await drawing_critique(focus=["layer_color", "iso128", "construction_left"])
|
||||
assert issues == [], f"Premium gate failed: {issues}"
|
||||
|
||||
# 9. FINALIZE
|
||||
await titleblock_apply_iso_a3(
|
||||
title="P&ID — Flow Control Loop 101",
|
||||
drawing_number="ANK-PID-2026-001",
|
||||
revision="0",
|
||||
scale="NTS",
|
||||
drawn_by="UE",
|
||||
company="Anka-Makine",
|
||||
)
|
||||
|
||||
await drawing_finalize(
|
||||
save_path=r"C:\work\anka\pid-loop-101.dwg",
|
||||
screenshot_path=r"C:\work\anka\pid-loop-101.png",
|
||||
)
|
||||
```
|
||||
|
||||
## What this example demonstrates
|
||||
|
||||
- **`layer_set_id="pid"`** in `drawing_plan` triggers the P&ID layer bootstrap
|
||||
(PROCESS-PIPING-MAIN, INSTRUMENT-SYMBOL, INSTRUMENT-LINE-SIGNAL, etc).
|
||||
- **Layer-by-purpose**: process lines on PROCESS-PIPING-MAIN (heavy 0.7 mm),
|
||||
signal lines on INSTRUMENT-LINE-SIGNAL (dashed 0.18), tags on
|
||||
INSTRUMENT-TAG-TEXT.
|
||||
- **ISA-5.1 tags** in text: `FT-101`, `FCV-101`, `FIC-101`, `P-101`, `V-201`.
|
||||
- **No dimensions** — P&IDs are schematic. We pass a focused critique that
|
||||
doesn't run dimension overlap checks.
|
||||
- The same `drawing_finalize` infrastructure that handles mechanical drawings
|
||||
works for P&IDs without modification.
|
||||
|
||||
## Where to grow
|
||||
|
||||
V2/V3 features that would polish this example:
|
||||
- Symbol library blocks for pumps, valves, instruments (`block_insert`).
|
||||
- ISO 14617 graphic-symbol catalog as MCP tools.
|
||||
- Equipment-tag and line-tag auto-numbering.
|
||||
@@ -0,0 +1,125 @@
|
||||
# Example — Premium Shaft Drawing
|
||||
|
||||
A fully worked example: power-transmission shaft Ø30 × 200 mm with two keyway
|
||||
seats (10 × 4 × 50 mm each per DIN 6885), drawn at 1:2 on A4.
|
||||
|
||||
## Goal
|
||||
|
||||
```text
|
||||
50 100 50
|
||||
┌──┴──┬───┴───┬──┴──┐
|
||||
│ │ │ │ keyway both ends, M0.04 surface finish
|
||||
└─────┴───────┴─────┘ bearing seat in middle (Ø30 h7)
|
||||
────── 200 ──────
|
||||
```
|
||||
|
||||
## Full workflow
|
||||
|
||||
```python
|
||||
# 1. PLAN — commit intent first
|
||||
plan = await drawing_plan(
|
||||
intent="Power transmission shaft Ø30 x 200, 2× DIN 6885 keyway",
|
||||
sheet_size="A4",
|
||||
scale=0.5, # 1:2 (drawing is half real size)
|
||||
layer_set_id="mech",
|
||||
dim_style="chain",
|
||||
notes=[
|
||||
"Material: C45 normalized",
|
||||
"Surface finish Ra 1.6 µm overall",
|
||||
"Keyways: 10 x 4 x 50 mm per DIN 6885 A",
|
||||
],
|
||||
)
|
||||
|
||||
# 2. LAYERS — mech standard
|
||||
await drawing_apply_iso_layers("mech")
|
||||
|
||||
# 3. CONSTRUCTION — centerline as reference
|
||||
cl = await construction_xline(0, 0, 0) # horizontal centerline at y=0
|
||||
|
||||
# 4. GEOMETRY — front view (top half mirrored later)
|
||||
top_edge = await entity_create_line(0, 15, 200, 15, layer="GEOMETRY")
|
||||
right_edge = await entity_create_line(200, 15, 200, -15, layer="GEOMETRY")
|
||||
bot_edge = await entity_create_line(200, -15, 0, -15, layer="GEOMETRY")
|
||||
left_edge = await entity_create_line(0, -15, 0, 15, layer="GEOMETRY")
|
||||
|
||||
# 4b. KEYWAY LEFT — use the engineering primitive (per CLAUDE.md rule)
|
||||
keyway_l = await keyway_draw_section(
|
||||
bore_x=25, bore_y=0, bore_diameter=30,
|
||||
keyway_width=10, keyway_depth=4,
|
||||
)
|
||||
|
||||
# 4c. KEYWAY RIGHT — symmetric on the other end
|
||||
keyway_r = await keyway_draw_section(
|
||||
bore_x=175, bore_y=0, bore_diameter=30,
|
||||
keyway_width=10, keyway_depth=4,
|
||||
)
|
||||
|
||||
# 4d. Centerline (engineering layer, dashed)
|
||||
center = await entity_create_line(-10, 0, 210, 0, layer="CENTER")
|
||||
|
||||
# 5. CORNERS — small chamfer at each end (1×45°)
|
||||
await entity_chamfer(top_edge["handle"], left_edge["handle"], dist1=1)
|
||||
await entity_chamfer(top_edge["handle"], right_edge["handle"], dist1=1)
|
||||
await entity_chamfer(bot_edge["handle"], left_edge["handle"], dist1=1)
|
||||
await entity_chamfer(bot_edge["handle"], right_edge["handle"], dist1=1)
|
||||
|
||||
# 6. SELECT geometry for dim
|
||||
geometry = await entity_select_smart({
|
||||
"type": "LINE",
|
||||
"layer": "GEOMETRY",
|
||||
"length_range": [40, 220], # exclude small chamfer lines
|
||||
})
|
||||
|
||||
# 7. DIMENSIONS — chain dimensioning, 12 mm offset above the part
|
||||
dims = await dimension_auto(
|
||||
[e["handle"] for e in geometry],
|
||||
style="chain",
|
||||
offset=12.0,
|
||||
)
|
||||
|
||||
# 8. CRITIQUE — must be empty before finalize
|
||||
issues = await drawing_critique(focus=None)
|
||||
if issues:
|
||||
for i in issues:
|
||||
print(f" [{i['severity']}] {i['focus']}: {i['message']}")
|
||||
raise RuntimeError("Premium gate failed; fix before finalize")
|
||||
|
||||
# 9. CLEAR + TITLEBLOCK + FINALIZE
|
||||
await construction_clear()
|
||||
|
||||
await titleblock_apply_iso_a3(
|
||||
title="Transmission Shaft",
|
||||
drawing_number="ANK-SH-2026-001",
|
||||
revision="A",
|
||||
scale="1:2",
|
||||
material="C45 normalized",
|
||||
drawn_by="UE",
|
||||
company="Anka-Makine",
|
||||
)
|
||||
|
||||
result = await drawing_finalize(
|
||||
save_path=r"C:\work\anka\sh-2026-001.dwg",
|
||||
screenshot_path=r"C:\work\anka\sh-2026-001.png",
|
||||
expected={
|
||||
"part_type": "shaft",
|
||||
"must_have_keyway": True,
|
||||
"must_have_bore": False, # solid shaft, not bored
|
||||
},
|
||||
)
|
||||
```
|
||||
|
||||
## What this example demonstrates
|
||||
|
||||
- **Plan-first workflow** (rule 1)
|
||||
- **Engineering primitives** for the keyway, not hand-drawn (rule 8 + CLAUDE.md
|
||||
production drawing rule)
|
||||
- **Construction line** for the centerline reference, cleared before finalize
|
||||
- **Corner explicitness** via `entity_chamfer` (rule 5)
|
||||
- **`entity_select_smart`** with `length_range` to filter out the tiny chamfer
|
||||
lines (rule 8 — meta-tools over loops)
|
||||
- **`dimension_auto`** with chain style (rule 6)
|
||||
- **Critique gate** before finalize (rule 7)
|
||||
- **`titleblock_apply_iso_a3`** + `drawing_finalize` with `expected` contract
|
||||
|
||||
The whole drawing comes out reproducible: the same call sequence generates an
|
||||
identical DXF every time, suitable for `git diff` and ISO 9001 traceability.
|
||||
Reference in New Issue
Block a user