Fusion - the Fusion 360 Bridge
Public Made by Adomby adom
Drive Autodesk Fusion 360 from the cloud via Adom Bridge: component libraries, IPC package generation, board layout, exports (STEP/Gerbers/BOM/CPL), fast APS cloud search, and parametric modeling.
2D drawings (drawing_create, drawing_export, drawing_status) #43
feature/mech-drawings → masterMechanical: 2D drawings (drawing_create, drawing_export, drawing_status)
The bridge could not make 2D drawings. Fusion's July 2026 API added adsk.drawing.DrawingManager (a preview API), which makes a complete automatic drawing of a saved cloud design. This PR wraps it in three typed mechanical operations, verified live on Fusion 2705.1.30, including end to end through a deployed bridge.
What changed
- New add-in module
commands/mechanical/drawings.py, registered in the package, with three schema entries. - Regenerated: goldens, and the contract
contracts/describe.json(thefusion_mechanicalop list). - New docs section "2D drawings" in
docs/MECHANICAL.md. drawing_create(journaled): draws the active saved design. Fusion lays out the sheets with a base view, projected views, an isometric view, center marks, a title block filled with title, author and date, and automatic dimensions. Options:standard,units,sheetSize,orientation,views,style,tangentEdges,dimensions,holeNotes,datum,content,sheets,omit,configuration,name,folderId,useSavedVersion.- Refused before any cloud write:
- a never-saved design (
design_not_saved); - unsaved changes (
unsaved_changes, unlessuseSavedVersion); - an upload still running (
design_upload_pending, retryable); - a sheet size from the other standard (
sheet_size_mismatch; Fusion would ignore it silently); - a project root as destination (
refused_root_upload).
- a never-saved design (
folderIdmoves the new.f2d. If the move fails, the drawing is deleted (drawing_move_failed).
- Refused before any cloud write:
drawing_export(journaled): PDF, DWG and DXF, staged and published likeexport(bytes, SHA-256, explicit overwrite). With a DXF, the reply also gives the scale the layout chose, read from the DXF's dimensions (1:1for the test part on A3).drawing_status(read): readiness, sheets and views.
Two traps, found live, each blocked Fusion's main thread for every caller
- A drawing that a script opens finishes loading only after the script returns, and opening an automatic drawing starts Fusion's interactive Edit Auto Dimensions command in its drawing engine (
AcCoreConsole.exe). An export sent while that command waits is fed to its prompt ("Invalid selection" in the engine log), andDrawingExportManager.executewaits for its 600 s timeout. PDF, DWG and DXF each waited the full 600 s. Documents.open(file, False)(invisible): Fusion's log shows the drawing opened in 0.8 s, but no drawing engine started, and the call returned only after 600.9 s.
So drawing_export takes several calls:
- The first call opens the drawing visibly and answers
drawing_not_ready(retryable,retryAfterSeconds). - A later call ends Edit Auto Dimensions with
ui.terminateActiveCommandif it runs on that drawing, and answersdrawing_not_readyagain. - A call after that exports, only when all of these hold:
- the sheets read;
ui.activeCommandis idle;- the drawing engine logged
opendocsince the open and has no unfinished command (FusionDrawing.log); - that log has been quiet for 5 s.
Between formats in one call, the engine log is read again; a busy engine returns the files written so far with drawing_not_ready.
Two more rules:
- A drawing open from elsewhere is refused (
drawing_open_elsewhere). close:truecloses the drawing, and also the design its open brought in (opening a drawing re-opens the referenced design) when that design was not open before and is unmodified. It then re-activates the previous front document.
Live evidence (Fusion 2705.1.30), an 80 x 50 x 40 mm bracket
| Step | Result |
|---|---|
createDrawing |
16.8 to 33.6 s over 8 runs; out of process; opens nothing |
| Sheet | A3 ISO, title block filled; front, top, right and isometric views; center marks; dimensions 80, 50 and 40 at 1:1 |
| Visible open | 4.8 to 9.0 s |
| Edit Auto Dimensions | Starts on open when dimensions are on, and ui.activeCommand reads FusionDrawingAutoDimensionEditCommand. One terminateActiveCommand took 0.45 s; the engine finished the command and the gate passed about 6 s later. With dimensions:"none" it never starts. |
| Exports | PDF 0.3 to 0.9 s (A3, about 99 KB); DWG 0.07 to 0.1 s (AutoCAD 2013, AC1027); DXF 0.16 to 0.2 s (AC1027, mm, real DIMENSION entities) |
Sheet.autoDimension (API, later call) |
3.8 s; adds the same dimensions without the interactive command |
| End to end, deployed bridge | drawing_create 18.5 s, then drawing_export three times: open (8.3 s), end Edit Auto Dimensions (3.2 s), export and close (3.8 s). 41.6 s from create to three files; every SHA-256 in the reply matched its file. Restore: session republished, capabilities session matched, readiness public 1.13.61. |
| Folder move | 0.56 s, file id unchanged; rename works |
View.type |
Raises InternalValidationError: pAsset on every view of a fully opened, idle drawing (Fusion's log: no base-model asset in the drawing document), so views are reported best-effort and are not used for readiness |
Gaps (API limits)
- No API places a view or sets a view's scale. The automatic layout picks it for the sheet size, and the reply reports it. Fusion's Edit View dialog changes it. The replay text commands (
Commands.Start FusionDrawingViewEditCommand,Commands.SetString,CommitCommand) are an untested non-UI candidate. - No API activates a sheet, so DXF is the active sheet.
Tests
- Python: 27 new tests in
tests/test_mechanical_drawings.py, covering:- options and refusals;
- the engine-log reader, on real log lines;
- the export rules: never in the opening call; the terminate call does not export; someone else's command is never ended; unreadable views do not block; a busy engine between formats returns the files so far;
- the DXF scale reader;
- staged publish and the reference-aware close. Two op-count pins updated (73 ops). Full discover: 598 tests OK, 5 skipped.
- Goldens: 69 new validation cases, none removed.
tools/rust-ship.shwith a private target dir: green, 310 Rust tests; the Windows build embeds thisschema.jsonanddescribe.jsonbyte for byte.- Generated files (goldens, contracts/describe.json) were regenerated on master 7c64629; if another of today's PRs merges first, they'll be regenerated again.
For the maintainers to decide
- Preview API.
adsk.drawing.DrawingManageris a Fusion preview API: Autodesk says preview APIs can change without notice and advises against shipping programs that depend on them. On a Fusion without it the ops refuse withunsupported_capabilityand do nothing. Whether to ship now or hold until the API leaves preview is your call. - Engine log. The export gate reads
FusionDrawing.log. If a Fusion update changes that log, a wrong gate can send an export into the 600 s wait, which blocks every bridge call for its duration. - Not covered yet. Scale can only be set in Fusion's Edit View dialog (no API). Live tests used one part; multi-sheet assembly drawings are untested, and a DXF holds only the active sheet.
Base: master e46bcf3 (1.13.79). Tests and builds ran on 7c64629; the commits since only publish 1.13.79. Rebased after #42 (assembly_layout, ray_cast) merged: __init__.py registers both
layout and drawings, schema.json keeps #42's two ops and adds the three drawing ops, and the op-count pins in
test_mechanical_exploded_view.py and #42's test_mechanical_layout.py read 73.
Suggested changelog: "drawing_create, drawing_export, drawing_status: 2D drawings with Fusion's automatic drawing (sheets, base and projected views, title block, automatic dimensions) and PDF, DWG and DXF export with the scale read back, built around two traps that block Fusion for 10 minutes."
🤖 Generated with Claude Code
Diff Skip to comments (1)
addin/AdomBridge/commands/mechanical/__init__.py+3−2@@ -14,7 +14,7 @@ import adsk.core from .core import SESSION_ID, MechanicalError, document_identity, require from .operations import OPERATIONS, WRITES from .journal import Journal, JournalError-from . import handoff, transactions, sketches, features, assemblies, purchased, bill_of_materials, geometry, sketch_edits, regular_joints, motion_links, configurations, render_scene, exploded_view, exploded_preview, efficiency, exploded_render, exploded_stills, render_image, cam, layout+from . import handoff, transactions, sketches, features, assemblies, purchased, bill_of_materials, geometry, sketch_edits, regular_joints, motion_links, configurations, render_scene, exploded_view, exploded_preview, efficiency, exploded_render, exploded_stills, render_image, cam, layout, drawings for _name, _handler in {**sketches.OPERATIONS, **features.OPERATIONS, **assemblies.OPERATIONS, **geometry.OPERATIONS, **sketch_edits.OPERATIONS, **regular_joints.OPERATIONS, **motion_links.OPERATIONS}.items():@@ -38,7 +38,8 @@ OPERATIONS.update(exploded_stills.OPERATIONS) OPERATIONS.update(render_image.OPERATIONS) OPERATIONS.update(cam.OPERATIONS) OPERATIONS.update(layout.OPERATIONS)-WRITES.update(purchased.WRITES | bill_of_materials.WRITES | efficiency.WRITES | exploded_render.WRITES | exploded_stills.WRITES | render_image.WRITES | cam.WRITES | layout.WRITES)+OPERATIONS.update(drawings.OPERATIONS)+WRITES.update(purchased.WRITES | bill_of_materials.WRITES | efficiency.WRITES | exploded_render.WRITES | exploded_stills.WRITES | render_image.WRITES | cam.WRITES | layout.WRITES | drawings.WRITES) OPERATIONS["transaction_probe"] = transactions.probe WRITES.add("transaction_probe")
addin/AdomBridge/commands/mechanical/drawings.pyadded+515@@ -0,0 +1,515 @@+"""2D drawings with Fusion's automatic drawing API (adsk.drawing.DrawingManager, a July 2026 preview).++drawing_create makes a drawing of the active, saved cloud design in one journaled call: Fusion lays+out the sheets itself, with a base view and its projected views, an optional isometric view, a+filled title block and automatic dimensions. The API cannot place a view or set a view's scale; the+layout picks the scale for the chosen sheet size. The drawing is a new cloud file (.f2d) in the+design's folder, or in folderId.++drawing_export writes PDF, DWG and DXF of a drawing, and drawing_status says whether one is ready.++Measured on Fusion 2705 (2026-11-03): createDrawing took 24.7 to 33.6 s for a small part (three+runs); it works out of process (a drawing engine, AcCoreConsole.exe, lays out, dimensions and saves,+then quits) and does not open the drawing. Moving the new file to another folder took 0.6 s and+kept its file id.++HARD RULES (both found live, each one blocked Fusion's main thread for every caller):+1. Never export in the call that opens a drawing. A drawing a script opens only finishes loading+ after that script returns, and opening an automatically created drawing starts the interactive+ Edit Auto Dimensions command (AUTODIMENSIONEDIT) in the drawing engine. An export sent while that+ command waits for input is fed to its prompt and rejected ("Invalid selection"), and+ DrawingExportManager.execute holds the main thread until its 600 s timeout ("3 : export timed+ out"); PDF, DWG and DXF each waited the full 600 s.+2. Never open a drawing invisibly. Documents.open(file, False) opened the drawing in 0.8 s by+ Fusion's log, but no drawing engine started for it and the call did not return.+So drawing_export opens visibly and answers drawing_not_ready (retryable); a later call exports only+once the sheets read, Fusion runs no command, the drawing engine that loaded the drawing has no+unfinished command and its log has been quiet for a few seconds. (View.type is no readiness signal:+it raised "pAsset" for every view of a fully opened, idle drawing.)+"""+import math+import os+from pathlib import Path+import re+import tempfile+import threading+import time++import adsk.core+import adsk.fusion+try:+ import adsk.drawing # always present inside Fusion 2705+; offline tests install a stand-in+except ImportError:+ pass++from .core import MechanicalError, require, target+from .exporting import publish_staged++STANDARDS = {"iso": "ISODrawingStandardType", "asme": "ASMEDrawingStandardType"}+UNITS = {"mm": "MillimeterDrawingUnitType", "in": "InchDrawingUnitType"}+ISO_SIZES = {"A4": "A4ISOSheetSize", "A3": "A3ISOSheetSize", "A2": "A2ISOSheetSize", "A1": "A1ISOSheetSize", "A0": "A0ISOSheetSize"}+ASME_SIZES = {"A": "AASMESheetSize", "B": "BASMESheetSize", "C": "CASMESheetSize", "D": "DASMESheetSize", "E": "EASMESheetSize"}+DEFAULTS = {"iso": {"units": "mm", "sheetSize": "A3"}, "asme": {"units": "in", "sheetSize": "B"}}+ORIENTATIONS = {"landscape": "LandscapeSheetOrientationType", "portrait": "PortraitSheetOrientationType"}+DIMENSIONS = {"overall": "OverallDimensionStrategyType", "automatic": "AutomaticDimensionStrategyType",+ "baseline": "BaselineDimensionStrategyType", "chain": "ChainDimensionStrategyType",+ "ordinate": "OrdinateDimensionStrategyType", "symmetric": "SymmetricDimensionStrategyType",+ "symmetric_baseline": "SymmetricWithBaselineDimensionStrategyType",+ "symmetric_ordinate": "SymmetricWithOrdinateDimensionStrategyType"}+HOLE_NOTES = {"hole_and_thread": "HoleAndThreadNoteHolePreferencesType", "hole": "HoleNoteOnlyHolePreferencesType",+ "thread": "ThreadNoteOnlyHolePreferencesType", "none": "NoHoleAnnotationsHolePreferencesType"}+DATUMS = {"model_origin": "ModelOriginDefaultOriginType", "bottom_left": "BottomLeftDefaultOriginType",+ "bottom_right": "BottomRightDefaultOriginType", "top_left": "TopLeftDefaultOriginType",+ "top_right": "TopRightDefaultOriginType"}+STYLES = {"visible": "VisibleEdgesDrawingViewStyleType", "visible_and_hidden": "VisibleAndHiddenEdgesDrawingViewStyleType",+ "shaded_and_hidden": "ShadedAndHiddenEdgesDrawingViewStyleType", "shaded": "ShadedVisibleEdgesDrawingViewStyleType"}+TANGENT_EDGES = {"off": "OffTangentEdgeDisplayType", "full": "FullLengthTangentEdgeDisplayType",+ "shortened": "ShortenedTangentEdgeDisplayType"}+CONTENT = {"full": "FullAssemblyDrawingContentType", "visible": "VisibleOnlyDrawingContentType"}+LEVELS = {"first": "FirstLevelOnlySheetCreationType", "all": "AllLevelsSheetCreationType"}+DWG_FORMATS = {"autocad": "AutoCADDWGFormat", "simplified": "SimplifiedDWGFormat"}+VIEW_TYPES = {0: "base", 1: "projected", 2: "section", 3: "detail", 4: "auxiliary", 5: "flat_pattern", 6: "unknown"}+EXTENSIONS = {"pdf": ".pdf", "dwg": ".dwg", "dxf": ".dxf"}+IDLE_COMMANDS = ("", "SelectCommand")+AUTO_DIMENSION_EDIT = "AUTODIMENSIONEDIT"++# file id -> {"at": time.time() when a call here opened that drawing (its engine log is read from then on),+# "previous": the document that was active then, active again when the drawing closes,+# "before": creationIds of the documents open then: opening a drawing also opens the design it+# references, and close closes that design only if it was not open before}+_opened = {}+++def _enum(cls_name, member):+ return getattr(getattr(adsk.drawing, cls_name), member)+++def _main_thread():+ require(threading.current_thread() is threading.main_thread(), "wrong_thread", "Drawings require Fusion's main thread.")+++def _drawing_api():+ manager = getattr(getattr(adsk, "drawing", None), "DrawingManager", None)+ require(manager is not None, "unsupported_capability",+ "This Fusion has no automatic drawing API (adsk.drawing.DrawingManager arrived in July 2026); update Fusion.")+ dm = manager.get()+ require(dm is not None, "unsupported_capability", "Fusion returned no DrawingManager.")+ return dm+++# ---------------------------------------------------------------- drawing_create++def resolve_options(args):+ """The caller's options with defaults filled in; refuses combinations Fusion would silently ignore."""+ standard = args.get("standard", "iso")+ defaults = DEFAULTS[standard]+ size = args.get("sheetSize", defaults["sheetSize"])+ sizes = ISO_SIZES if standard == "iso" else ASME_SIZES+ require(size in sizes, "sheet_size_mismatch",+ "Sheet %s is not a%s size; use %s." % (size, "n ISO" if standard == "iso" else "n ASME", ", ".join(sizes)),+ standard=standard, sheetSize=size)+ orientation = args.get("orientation", "landscape")+ require(not (orientation == "portrait" and size in ("A0", "E")), "invalid_input",+ "Fusion has no portrait %s sheet." % size)+ views = args.get("views") or {}+ sheets = args.get("sheets") or {}+ omit = args.get("omit") or {}+ return {"standard": standard, "units": args.get("units", defaults["units"]), "sheetSize": size, "orientation": orientation,+ "orthographic": views.get("orthographic", True), "isometric": views.get("isometric", True),+ "style": args.get("style", "visible"), "tangentEdges": args.get("tangentEdges", "off"),+ "dimensions": args.get("dimensions", "overall"), "holeNotes": args.get("holeNotes", "hole_and_thread"),+ "datum": args.get("datum", "model_origin"), "content": args.get("content", "full"),+ "levels": sheets.get("levels", "all"), "assembly": sheets.get("assembly", True),+ "subassemblies": sheets.get("subassemblies", True), "components": sheets.get("components", True),+ "sheetMetal": sheets.get("sheetMetal", True), "partsList": sheets.get("partsList", True),+ "omitKeywords": omit.get("keywords", "Bolt,Screw,Nut,Washer"), "omitFasteners": omit.get("fasteners", False),+ "configuration": args.get("configuration", "")}+++def apply_options(inp, o):+ """Copy resolved options onto a CreateDrawingInput (automatic mode)."""+ inp.standard = _enum("DrawingStandardTypes", STANDARDS[o["standard"]])+ inp.units = _enum("DrawingUnitTypes", UNITS[o["units"]])+ inp.sheetSize = _enum("SheetSizes", (ISO_SIZES if o["standard"] == "iso" else ASME_SIZES)[o["sheetSize"]])+ inp.orientationType = _enum("SheetOrientationTypes", ORIENTATIONS[o["orientation"]])+ inp.content = _enum("DrawingContentTypes", CONTENT[o["content"]])+ inp.sheetCreationType = _enum("SheetCreationTypes", LEVELS[o["levels"]])+ if o["configuration"]:+ inp.configuration = o["configuration"]+ prefs = inp.automationPreferences+ g = prefs.globalPreferences+ g.isMainAssemblySheetGenerated = bool(o["assembly"])+ g.isSubAssemblySheetGenerated = bool(o["subassemblies"])+ g.isComponentSheetGenerated = bool(o["components"])+ g.isFoldedModelSheetGenerated = bool(o["sheetMetal"])+ g.isFlatPatternSheetGenerated = bool(o["sheetMetal"])+ g.isAnimationSheetGenerated = False+ g.isAutoDimensionEnabled = o["dimensions"] != "none"+ g.omitComponentsWithKeywords = o["omitKeywords"]+ g.isDetectAndOmitFasteners = bool(o["omitFasteners"])+ for p in (prefs.componentPreferences, prefs.foldedModelPreferences):+ p.sheetViewPreferences.isOrthogonalViewAdded = bool(o["orthographic"])+ p.sheetViewPreferences.isIsometricViewAdded = bool(o["isometric"] and o["orthographic"])+ for asm in (prefs.mainAssemblyPreferences, prefs.subAssemblyPreferences):+ # the assembly's isometric sheet carries the parts list, so views.isometric leaves it alone+ asm.isoViewSheetPreferences.isSheetCreated = True+ asm.isoViewSheetPreferences.isPartsListIncluded = bool(o["partsList"])+ asm.orthogonalViewSheetPreferences.isSheetCreated = bool(o["orthographic"])+ for p in (prefs.componentPreferences, prefs.foldedModelPreferences, prefs.flatPatternPreferences,+ prefs.mainAssemblyPreferences, prefs.subAssemblyPreferences):+ dims = p.autoDimensionPreferences+ dims.isAutoDimensionEnabled = o["dimensions"] != "none"+ if o["dimensions"] != "none":+ dims.dimensionStrategyType = _enum("DimensionStrategyTypes", DIMENSIONS[o["dimensions"]])+ dims.holePreferencesType = _enum("HolePreferencesTypes", HOLE_NOTES[o["holeNotes"]])+ if hasattr(dims, "defaultOriginType"):+ dims.defaultOriginType = _enum("DefaultOriginTypes", DATUMS[o["datum"]])+ view = p.drawingViewPreferences+ view.style = _enum("DrawingViewStyleTypes", STYLES[o["style"]])+ view.tangentEdgesType = _enum("TangentEdgeDisplayTypes", TANGENT_EDGES[o["tangentEdges"]])+++def drawing_create(app, args):+ _main_thread()+ doc, design, value = target(app, args, True, model_write=False)+ options = resolve_options(args)+ source = doc.dataFile+ require(source is not None, "design_not_saved",+ "Fusion draws a design from its cloud file, and this design was never saved. Save it into an "+ "'Adom AI Workspace' subfolder (fusion_save_to_cloud), then call drawing_create again.")+ require(not doc.isModified or args.get("useSavedVersion", False), "unsaved_changes",+ "The drawing would show the last saved version, not the changes made since. Save a version first, "+ "or pass useSavedVersion:true to draw the saved one.", savedVersion=source.versionNumber)+ require(source.isComplete, "design_upload_pending", "The design's last save is still uploading; call again in a few seconds.",+ retryable=True)+ destination = None+ if args.get("folderId"):+ destination = app.data.findFolderById(args["folderId"])+ require(destination is not None, "folder_not_found", "No cloud folder with that folderId.")+ require(not destination.isRoot, "refused_root_upload", "Put drawings in a subfolder, never a project's root folder.")+ else:+ require(not source.parentFolder.isRoot, "refused_root_upload",+ "The design sits in its project's root folder, where Fusion would also put the drawing. Pass folderId "+ "of a subfolder (an 'Adom AI Workspace' task folder) for the drawing.")+ dm = _drawing_api()+ inp = dm.createDrawingInput(source, _enum("DrawingCreationModes", "AutomaticDrawingCreationMode"))+ require(inp is not None, "drawing_failed", "Fusion did not create a drawing input for this design.")+ apply_options(inp, options)+ started = time.perf_counter()+ drawing = dm.createDrawing(inp)+ seconds = round(time.perf_counter() - started, 1)+ require(drawing is not None, "drawing_failed", "Fusion's automatic drawing failed for this design.", seconds=seconds)+ moved = None+ if destination is not None:+ moved = bool(drawing.move(destination))+ if not moved:+ # a failed call changes nothing: the drawing it made is deleted, not left beside the design+ removed = bool(drawing.deleteMe())+ raise MechanicalError("drawing_move_failed", "Fusion made the drawing but could not move it to folderId.",+ drawingDeleted=removed, seconds=seconds)+ if args.get("name"):+ drawing.name = args["name"]+ return {"target": value, "drawing": file_data(drawing), "source": file_data(source), "options": options,+ "seconds": seconds, "movedToFolder": moved,+ "next": "drawing_export with drawing.fileId; it opens the drawing in one call and exports in the next."}+++def file_data(f):+ folder = f.parentFolder+ return {"fileId": f.id, "name": f.name, "version": f.versionNumber, "extension": f.fileExtension,+ "folder": folder.name if folder else None, "folderId": folder.id if folder else None,+ "project": f.parentProject.name if f.parentProject else None}+++# ---------------------------------------------------------------- readiness++def find_open(app, file_id):+ for i in range(app.documents.count):+ d = app.documents.item(i)+ try:+ if d.dataFile is not None and d.dataFile.id == file_id:+ return d+ except Exception:+ continue+ return None+++def engine_log_path():+ """Fusion's drawing-engine log: %LOCALAPPDATA%/Autodesk/Autodesk Fusion 360/<user>/logs/FusionDrawing.log."""+ root = Path(os.environ.get("LOCALAPPDATA", "")) / "Autodesk" / "Autodesk Fusion 360"+ logs = sorted(root.glob("*/logs/FusionDrawing.log"), key=lambda p: p.stat().st_mtime, reverse=True) if root.exists() else []+ return logs[0] if logs else None+++LOG_LINE = re.compile(r"^(\d{8}T\d{6}) \w \.(\d+) (.*)$")+++QUIET_SECONDS = 5+++def engine_state(since, path=None, now=None):+ """What Fusion's drawing engines logged at or after `since` (epoch seconds), from FusionDrawing.log:+ per engine process, its unfinished commands, whether it loaded a document (opendoc) and whether it+ closed; plus how long the log has been quiet. None when the log cannot be found."""+ path = path or engine_log_path()+ if path is None:+ return None+ stamp = time.strftime("%Y%m%dT%H%M%S", time.localtime(since))+ engines, last = {}, None+ with open(path, encoding="utf-8", errors="replace") as f:+ for raw in f:+ m = LOG_LINE.match(raw.rstrip("\n"))+ if not m or m.group(1) < stamp:+ continue+ last = m.group(1)+ e = engines.setdefault(m.group(2), {"open": [], "loaded": False, "closed": False})+ text = m.group(3)+ if text.startswith("cmd will Start: "):+ e["open"].append(text[16:].strip())+ elif text.startswith("cmd Finished: "):+ name = text[14:].split(" Reason")[0].strip()+ if name in e["open"]:+ e["open"].remove(name)+ elif '"action":"opendoc"' in text:+ e["loaded"] = True+ elif text.startswith("closing dwg") or text.startswith("unloading AcFusionService"):+ e["closed"] = True+ quiet = None+ if last is not None:+ quiet = round((now if now is not None else time.time()) - time.mktime(time.strptime(last, "%Y%m%dT%H%M%S")), 1)+ live = {pid: e for pid, e in engines.items() if not e["closed"]}+ return {"loaded": any(e["loaded"] for e in live.values()),+ "unfinished": {pid: e["open"] for pid, e in live.items() if e["open"]}, "quietSeconds": quiet}+++PAPER = {v: k for k, v in {**ISO_SIZES, **ASME_SIZES, "custom": "CustomSizeSheetSize"}.items()}+++def paper_name(sheet):+ for member, name in PAPER.items():+ if getattr(adsk.drawing.SheetSizes, member, None) == sheet.sheetSize:+ return name+ return str(sheet.sheetSize)+++def view_data(view):+ """A view's type and curve count. Fusion 2705's View.type raises "InternalValidationError: pAsset"+ on drawings it opened (its log: no base model asset in the drawing document), so a view that+ cannot be read is reported as such and is not taken as a sign that the drawing is still loading."""+ try:+ return {"type": VIEW_TYPES.get(view.type, str(view.type)), "curves": view.viewCurves.count}+ except Exception as error:+ return {"type": None, "unreadable": str(error)[:80]}+++def sheet_data(drawing):+ """Sheets and their views. Width and height are Fusion's own numbers (mm on an mm drawing: 420 x 297+ for A3 landscape, read live); units is the drawing's unit setting."""+ units = "mm" if drawing.documentSettings.units == adsk.drawing.DrawingUnitTypes.MillimeterDrawingUnitType else "in"+ out = []+ for i in range(drawing.sheets.count):+ sheet = drawing.sheets.item(i)+ views = [view_data(sheet.views.item(j)) for j in range(sheet.views.count)]+ out.append({"index": i + 1, "name": sheet.name, "paper": paper_name(sheet), "width": sheet.width, "height": sheet.height,+ "units": units, "views": views})+ return out+++def readiness(app, doc, file_id):+ """(ready, detail) for a drawing this session opened, without changing anything. Ready means its+ sheets read, Fusion runs no command, a drawing engine loaded the drawing since it was opened+ (opendoc in the engine's log) and has no unfinished command, and the engine log has been quiet for+ QUIET_SECONDS: in the live run Edit Auto Dimensions started in the same second the open finished,+ so a single instant is not enough."""+ detail = {"open": True, "active": doc.isActive, "visible": doc.isVisible,+ "activeCommand": app.userInterface.activeCommand}+ try:+ drawing = adsk.drawing.DrawingDocument.cast(doc).drawing+ detail["sheets"] = sheet_data(drawing)+ detail["loaded"] = True+ except Exception as error:+ detail["loaded"], detail["loadError"] = False, str(error)[:160]+ engine = engine_state(_opened[file_id]["at"])+ detail["engine"] = engine+ detail["ready"] = bool(detail["loaded"] and detail["activeCommand"] in IDLE_COMMANDS and engine is not None+ and engine["loaded"] and not engine["unfinished"]+ and engine["quietSeconds"] is not None and engine["quietSeconds"] >= QUIET_SECONDS)+ return detail["ready"], detail+++def drawing_status(app, args):+ _main_thread()+ file_id = args["drawing"]["fileId"]+ doc = find_open(app, file_id)+ if doc is None:+ return {"drawing": {"fileId": file_id}, "open": False, "ready": False,+ "next": "drawing_export opens it; the export follows in a later call."}+ if file_id not in _opened:+ return {"drawing": {"fileId": file_id, "name": doc.name}, "open": True, "ready": False, "openedHere": False,+ "next": "Open elsewhere (by a person or before the add-in restarted); drawing_export only exports drawings it opened."}+ ready, detail = readiness(app, doc, file_id)+ return {"drawing": {"fileId": file_id, "name": doc.name}, "openedHere": True, **detail}+++# ---------------------------------------------------------------- drawing_export++def not_ready(message, **details):+ raise MechanicalError("drawing_not_ready", message, retryable=True, retryAfterSeconds=details.pop("retryAfterSeconds", 3), **details)+++def drawing_export(app, args):+ _main_thread()+ file_id = args["drawing"]["fileId"]+ outputs = {k: args[k] for k in EXTENSIONS if args.get(k)}+ require(outputs, "invalid_input", "Name at least one of pdf, dwg or dxf (absolute paths on the PC).")+ overwrite = bool(args.get("overwrite", False))+ for kind, raw in outputs.items():+ path = Path(raw)+ require(path.is_absolute(), "invalid_path", "%s must be an absolute path on the PC." % kind)+ require(path.suffix.lower() == EXTENSIONS[kind], "extension_mismatch", "%s must end in %s." % (kind, EXTENSIONS[kind]))+ require(overwrite or not path.exists(), "destination_exists", "%s exists; pass overwrite:true to replace it." % path)+ doc = find_open(app, file_id)+ if doc is None:+ data_file = app.data.findFileById(file_id)+ require(data_file is not None, "drawing_not_found", "No cloud file with that fileId.")+ require(data_file.fileExtension == "f2d", "not_a_drawing", "That file is a %s, not a drawing (.f2d)." % data_file.fileExtension)+ _opened[file_id] = {"at": time.time(), "previous": app.activeDocument,+ "before": {app.documents.item(i).creationId for i in range(app.documents.count)}}+ # visible: an invisible open never returned (hard rule 2)+ opened = app.documents.open(data_file, True)+ require(opened is not None, "drawing_open_failed", "Fusion could not open the drawing.")+ not_ready("Opened the drawing; Fusion finishes loading it after this call returns. Call drawing_export again in a "+ "few seconds (a new operationId): exporting in the call that opens a drawing blocks Fusion for 10 minutes.",+ opened=True, retryAfterSeconds=5)+ require(file_id in _opened, "drawing_open_elsewhere",+ "This drawing is open in Fusion but was not opened by drawing_export in this add-in session, so its "+ "drawing engine's state is unknown and an export could block Fusion. Close it in Fusion, then call again.")+ ready, detail = readiness(app, doc, file_id)+ if not ready:+ unfinished = [c for cmds in ((detail.get("engine") or {}).get("unfinished") or {}).values() for c in cmds]+ if detail.get("activeCommand") not in IDLE_COMMANDS and doc.isActive and AUTO_DIMENSION_EDIT in unfinished:+ # Fusion starts Edit Auto Dimensions when an automatic drawing opens; end it like Esc would+ ended = app.userInterface.terminateActiveCommand()+ not_ready("Ended Fusion's Edit Auto Dimensions command on the drawing; export in the next call.",+ endedCommand=detail.get("activeCommand"), terminated=bool(ended), detail=detail)+ not_ready("The drawing is still loading or Fusion is busy with a command; call again shortly.", detail=detail)+ drawing = adsk.drawing.DrawingDocument.cast(doc).drawing+ manager = drawing.exportManager+ results, started = {}, time.perf_counter()+ for kind, raw in outputs.items():+ if results:+ # each export runs a command in the drawing engine; the next one goes only once that finished+ engine = engine_state(_opened[file_id]["at"])+ if engine is None or engine["unfinished"]:+ not_ready("The drawing engine is still busy after the %s export; call again for the rest." % ", ".join(results),+ outputs=results, engine=engine)+ results[kind] = export_one(manager, kind, Path(raw), overwrite, args)+ out = {"drawing": {"fileId": file_id, "name": doc.name}, "sheets": detail.get("sheets"), "outputs": results,+ "seconds": round(time.perf_counter() - started, 1)}+ if "dxf" in results:+ out["scale"] = dxf_scale(Path(outputs["dxf"]))+ if args.get("close", False):+ out["closed"] = close_drawing(app, doc, file_id)+ return out+++def close_drawing(app, doc, file_id):+ """Close the drawing without saving, then the designs its open brought in (only those that were not+ open before and are unmodified), and put the previously active document back in front."""+ record = _opened.pop(file_id, {})+ references = set()+ try:+ refs = doc.documentReferences+ references = {refs.item(i).dataFile.id for i in range(refs.count) if refs.item(i).dataFile is not None}+ except Exception:+ pass+ doc.close(False)+ closed = [file_id]+ before = record.get("before") or set()+ for i in reversed(range(app.documents.count)):+ d = app.documents.item(i)+ try:+ fid = d.dataFile.id if d.dataFile is not None else None+ except Exception:+ continue+ if fid in references and d.creationId not in before and not d.isModified:+ d.close(False)+ closed.append(fid)+ previous = record.get("previous")+ if previous is not None and previous.isValid:+ previous.activate()+ return closed+++def dxf_dimensions(path):+ """(measured value, length on the sheet) of every linear DIMENSION in an ASCII DXF: group 42 is the+ measured value, 13/23 and 14/24 the two definition points, 50 the angle of a rotated dimension."""+ lines = path.read_text(encoding="utf-8", errors="replace").splitlines()+ pairs = [(lines[i].strip(), lines[i + 1].strip()) for i in range(0, len(lines) - 1, 2)]+ found, current = [], None+ for code, value in pairs:+ if code == "0":+ if current is not None:+ found.append(current)+ current = {} if value == "DIMENSION" else None+ elif current is not None and code in ("13", "23", "14", "24", "42", "50", "70"):+ try:+ current[code] = float(value)+ except ValueError:+ pass+ if current is not None:+ found.append(current)+ out = []+ for d in found:+ if not {"13", "23", "14", "24", "42"} <= set(d) or int(d.get("70", 0)) & 15 not in (0, 1) or d["42"] <= 0:+ continue # linear (rotated, horizontal, vertical) and aligned dimensions only+ dx, dy = d["14"] - d["13"], d["24"] - d["23"]+ if int(d.get("70", 0)) & 15 == 0:+ a = math.radians(d.get("50", 0.0))+ length = abs(dx * math.cos(a) + dy * math.sin(a))+ else:+ length = math.hypot(dx, dy)+ out.append((d["42"], length))+ return out+++def dxf_scale(path):+ """The scale the layout chose, read from the exported DXF's dimensions (sheet length / measured+ value, median over the dimensions); None when the drawing has no linear dimensions."""+ try:+ ratios = sorted(length / value for value, length in dxf_dimensions(path) if value > 0 and length > 0)+ except OSError:+ return None+ if not ratios:+ return None+ r = ratios[len(ratios) // 2]+ text = ("%g:1" % round(r, 3)) if r >= 1 else ("1:%g" % round(1 / r, 3))+ return {"ratio": round(r, 4), "text": text, "dimensions": len(ratios), "source": "dxf dimensions"}+++def export_one(manager, kind, destination, overwrite, args):+ destination.parent.mkdir(parents=True, exist_ok=True)+ started = time.perf_counter()+ with tempfile.TemporaryDirectory(prefix=".adom-drawing-", dir=str(destination.parent)) as folder:+ staged = Path(folder) / ("drawing" + EXTENSIONS[kind])+ if kind == "pdf":+ options = manager.createPDFExportOptions(str(staged))+ options.openPDF = False+ options.useLineWeights = bool(args.get("pdfLineWeights", True))+ if args.get("pdfSheets"):+ options.sheetRange = args["pdfSheets"]+ elif kind == "dwg":+ options = manager.createDWGExportOptions(str(staged))+ options.format = _enum("DWGFormats", DWG_FORMATS[args.get("dwgFormat", "autocad")])+ else:+ options = manager.createDXFExportOptions(str(staged))+ options.exportSplinesAsSplines = bool(args.get("dxfSplines", True))+ require(options is not None, "export_preflight_failed", "Fusion did not create %s export options." % kind)+ require(bool(manager.execute(options)), "export_failed", "Fusion's %s export returned false." % kind)+ result = publish_staged(staged, destination, overwrite)+ result["seconds"] = round(time.perf_counter() - started, 1)+ return result+++OPERATIONS = {"drawing_create": drawing_create, "drawing_export": drawing_export, "drawing_status": drawing_status}+WRITES = {"drawing_create", "drawing_export"}
addin/AdomBridge/commands/mechanical/schema.json+274@@ -8150,5 +8150,279 @@ } }, "description": "Cast batches of rays against named occurrences, without changing anything (assembly planning: what a part seats on, what blocks its way in, whether a tool reaches a screw). Each ray is cast against each occurrence it names, in that occurrence's own component coordinates, about a millisecond on a part, where a ray against a big subassembly's component (thousands of bodies) took a quarter of a second. Returns hits: a row per ray answered, [[occurrence index, distance in mm rounded to 0.01], ...], one entry per occurrence the ray meets within length (its nearest hit), nearest first; a ray that starts inside a body meets that body's exit face. Also cast (rays answered, in order), complete, missing (indexes with no occurrence at that path), failed (casts Fusion refused) and seconds. Not journaled: it stops at budgetSeconds or before its reply passes 1 MiB (stopped: budget|reply_bytes) and the caller sends the remaining rays. Requests over the CLI's argument limit (128 KiB) go in several calls."+ },+ "drawing_create": {+ "type": "object",+ "description": "Make a 2D drawing of the active design with Fusion's automatic drawing: sheets laid out by Fusion, each with a base view and its projected views (front, top, right), an optional isometric view, a filled title block and automatic dimensions. The design must be saved to the cloud with no unsaved changes (or pass useSavedVersion); the drawing is a new cloud file next to the design, or in folderId, never in a project's root folder. Fusion picks the views' scale for the sheet size; the API cannot set it. Takes about 30 s for a part. Journaled. Follow with drawing_export.",+ "properties": {+ "operationId": {+ "type": "string"+ },+ "standard": {+ "type": "string",+ "enum": [+ "iso",+ "asme"+ ],+ "description": "Drawing standard; iso by default."+ },+ "units": {+ "type": "string",+ "enum": [+ "mm",+ "in"+ ],+ "description": "mm for iso, in for asme by default."+ },+ "sheetSize": {+ "type": "string",+ "enum": [+ "A4",+ "A3",+ "A2",+ "A1",+ "A0",+ "A",+ "B",+ "C",+ "D",+ "E"+ ],+ "description": "A4 to A0 with iso, A to E with asme; A3 or B by default."+ },+ "orientation": {+ "type": "string",+ "enum": [+ "landscape",+ "portrait"+ ]+ },+ "views": {+ "type": "object",+ "properties": {+ "orthographic": {+ "type": "boolean"+ },+ "isometric": {+ "type": "boolean"+ }+ },+ "additionalProperties": false,+ "description": "Base and projected views (default true) and an isometric view beside them (default true)."+ },+ "style": {+ "type": "string",+ "enum": [+ "visible",+ "visible_and_hidden",+ "shaded_and_hidden",+ "shaded"+ ]+ },+ "tangentEdges": {+ "type": "string",+ "enum": [+ "off",+ "full",+ "shortened"+ ]+ },+ "dimensions": {+ "type": "string",+ "enum": [+ "none",+ "overall",+ "automatic",+ "baseline",+ "chain",+ "ordinate",+ "symmetric",+ "symmetric_baseline",+ "symmetric_ordinate"+ ],+ "description": "Automatic dimension strategy; overall by default, none for views only."+ },+ "holeNotes": {+ "type": "string",+ "enum": [+ "hole_and_thread",+ "hole",+ "thread",+ "none"+ ]+ },+ "datum": {+ "type": "string",+ "enum": [+ "model_origin",+ "bottom_left",+ "bottom_right",+ "top_left",+ "top_right"+ ],+ "description": "Origin for baseline and ordinate dimensions on part sheets."+ },+ "content": {+ "type": "string",+ "enum": [+ "full",+ "visible"+ ],+ "description": "Draw every part, or only the visible ones."+ },+ "sheets": {+ "type": "object",+ "additionalProperties": false,+ "description": "Which sheets Fusion makes: the main assembly, subassemblies, one per part (component), sheet metal; levels first or all.",+ "properties": {+ "assembly": {+ "type": "boolean"+ },+ "subassemblies": {+ "type": "boolean"+ },+ "components": {+ "type": "boolean"+ },+ "sheetMetal": {+ "type": "boolean"+ },+ "partsList": {+ "type": "boolean"+ },+ "levels": {+ "type": "string",+ "enum": [+ "first",+ "all"+ ]+ }+ }+ },+ "omit": {+ "type": "object",+ "additionalProperties": false,+ "description": "Parts left out of part sheets: names containing these comma-separated keywords (Bolt,Screw,Nut,Washer by default) and, with fasteners, any part Fusion recognizes as a fastener.",+ "properties": {+ "keywords": {+ "type": "string"+ },+ "fasteners": {+ "type": "boolean"+ }+ }+ },+ "configuration": {+ "type": "string",+ "description": "Configuration name for a configured design; the active one by default."+ },+ "folderId": {+ "type": "string",+ "description": "Cloud folder to put the drawing in; the design's folder by default."+ },+ "name": {+ "type": "string",+ "description": "Name for the drawing file; Fusion's is '<design> Drawing'."+ },+ "useSavedVersion": {+ "type": "boolean",+ "description": "Draw the last saved version even though the design has unsaved changes."+ }+ },+ "required": [+ "op",+ "sessionId",+ "operationId",+ "target"+ ]+ },+ "drawing_export": {+ "type": "object",+ "description": "Export a drawing made by drawing_create to PDF, DWG and DXF (absolute paths on the PC), staged and published with byte counts and SHA-256. The first call opens the drawing in Fusion and answers drawing_not_ready (retryable, retryAfterSeconds); call again with a new operationId. Never in the call that opens it: an export sent while Fusion's Edit Auto Dimensions command runs on a newly opened drawing blocks Fusion's main thread for 10 minutes. A later call ends that command if it is running, and exports once the sheets read, Fusion runs no command and the drawing engine is idle and quiet. A drawing opened by someone else is refused (drawing_open_elsewhere). DXF holds the active sheet; with a DXF the reply also gives the scale Fusion chose, read from its dimensions. close:true closes the drawing and the design its open brought in. Journaled.",+ "properties": {+ "operationId": {+ "type": "string"+ },+ "drawing": {+ "type": "object",+ "description": "The drawing's cloud file, as drawing_create returned it.",+ "properties": {+ "fileId": {+ "type": "string"+ }+ },+ "required": [+ "fileId"+ ],+ "additionalProperties": false+ },+ "pdf": {+ "type": "string",+ "description": "Absolute .pdf path; one PDF of every sheet unless pdfSheets."+ },+ "dwg": {+ "type": "string",+ "description": "Absolute .dwg path."+ },+ "dxf": {+ "type": "string",+ "description": "Absolute .dxf path (the active sheet)."+ },+ "overwrite": {+ "type": "boolean"+ },+ "pdfSheets": {+ "type": "string",+ "description": "Sheets for the PDF, like \"1-3\" or \"1,4\"; every sheet by default."+ },+ "pdfLineWeights": {+ "type": "boolean",+ "description": "Print line weights (default true)."+ },+ "dwgFormat": {+ "type": "string",+ "enum": [+ "autocad",+ "simplified"+ ]+ },+ "dxfSplines": {+ "type": "boolean",+ "description": "Keep splines as splines (default true)."+ },+ "close": {+ "type": "boolean",+ "description": "Close the drawing in Fusion after exporting, with the design its open brought in when that was not open before and is unmodified, and put the previously active document back (default false)."+ }+ },+ "required": [+ "op",+ "sessionId",+ "operationId",+ "drawing"+ ]+ },+ "drawing_status": {+ "type": "object",+ "description": "Whether a drawing is open and ready for drawing_export: its sheets read, Fusion's active command, the drawing engine's unfinished commands and how long its log has been quiet, and the sheets with their views. Changes nothing.",+ "properties": {+ "drawing": {+ "type": "object",+ "description": "The drawing's cloud file, as drawing_create returned it.",+ "properties": {+ "fileId": {+ "type": "string"+ }+ },+ "required": [+ "fileId"+ ],+ "additionalProperties": false+ }+ },+ "required": [+ "op",+ "drawing"+ ] } }
contracts/describe.json+549−1@@ -5043,6 +5043,280 @@ ], "type": "object" },+ "drawing_create": {+ "description": "Make a 2D drawing of the active design with Fusion's automatic drawing: sheets laid out by Fusion, each with a base view and its projected views (front, top, right), an optional isometric view, a filled title block and automatic dimensions. The design must be saved to the cloud with no unsaved changes (or pass useSavedVersion); the drawing is a new cloud file next to the design, or in folderId, never in a project's root folder. Fusion picks the views' scale for the sheet size; the API cannot set it. Takes about 30 s for a part. Journaled. Follow with drawing_export.",+ "properties": {+ "configuration": {+ "description": "Configuration name for a configured design; the active one by default.",+ "type": "string"+ },+ "content": {+ "description": "Draw every part, or only the visible ones.",+ "enum": [+ "full",+ "visible"+ ],+ "type": "string"+ },+ "datum": {+ "description": "Origin for baseline and ordinate dimensions on part sheets.",+ "enum": [+ "model_origin",+ "bottom_left",+ "bottom_right",+ "top_left",+ "top_right"+ ],+ "type": "string"+ },+ "dimensions": {+ "description": "Automatic dimension strategy; overall by default, none for views only.",+ "enum": [+ "none",+ "overall",+ "automatic",+ "baseline",+ "chain",+ "ordinate",+ "symmetric",+ "symmetric_baseline",+ "symmetric_ordinate"+ ],+ "type": "string"+ },+ "folderId": {+ "description": "Cloud folder to put the drawing in; the design's folder by default.",+ "type": "string"+ },+ "holeNotes": {+ "enum": [+ "hole_and_thread",+ "hole",+ "thread",+ "none"+ ],+ "type": "string"+ },+ "name": {+ "description": "Name for the drawing file; Fusion's is '<design> Drawing'.",+ "type": "string"+ },+ "omit": {+ "additionalProperties": false,+ "description": "Parts left out of part sheets: names containing these comma-separated keywords (Bolt,Screw,Nut,Washer by default) and, with fasteners, any part Fusion recognizes as a fastener.",+ "properties": {+ "fasteners": {+ "type": "boolean"+ },+ "keywords": {+ "type": "string"+ }+ },+ "type": "object"+ },+ "operationId": {+ "type": "string"+ },+ "orientation": {+ "enum": [+ "landscape",+ "portrait"+ ],+ "type": "string"+ },+ "sheetSize": {+ "description": "A4 to A0 with iso, A to E with asme; A3 or B by default.",+ "enum": [+ "A4",+ "A3",+ "A2",+ "A1",+ "A0",+ "A",+ "B",+ "C",+ "D",+ "E"+ ],+ "type": "string"+ },+ "sheets": {+ "additionalProperties": false,+ "description": "Which sheets Fusion makes: the main assembly, subassemblies, one per part (component), sheet metal; levels first or all.",+ "properties": {+ "assembly": {+ "type": "boolean"+ },+ "components": {+ "type": "boolean"+ },+ "levels": {+ "enum": [+ "first",+ "all"+ ],+ "type": "string"+ },+ "partsList": {+ "type": "boolean"+ },+ "sheetMetal": {+ "type": "boolean"+ },+ "subassemblies": {+ "type": "boolean"+ }+ },+ "type": "object"+ },+ "standard": {+ "description": "Drawing standard; iso by default.",+ "enum": [+ "iso",+ "asme"+ ],+ "type": "string"+ },+ "style": {+ "enum": [+ "visible",+ "visible_and_hidden",+ "shaded_and_hidden",+ "shaded"+ ],+ "type": "string"+ },+ "tangentEdges": {+ "enum": [+ "off",+ "full",+ "shortened"+ ],+ "type": "string"+ },+ "units": {+ "description": "mm for iso, in for asme by default.",+ "enum": [+ "mm",+ "in"+ ],+ "type": "string"+ },+ "useSavedVersion": {+ "description": "Draw the last saved version even though the design has unsaved changes.",+ "type": "boolean"+ },+ "views": {+ "additionalProperties": false,+ "description": "Base and projected views (default true) and an isometric view beside them (default true).",+ "properties": {+ "isometric": {+ "type": "boolean"+ },+ "orthographic": {+ "type": "boolean"+ }+ },+ "type": "object"+ }+ },+ "required": [+ "op",+ "sessionId",+ "operationId",+ "target"+ ],+ "type": "object"+ },+ "drawing_export": {+ "description": "Export a drawing made by drawing_create to PDF, DWG and DXF (absolute paths on the PC), staged and published with byte counts and SHA-256. The first call opens the drawing in Fusion and answers drawing_not_ready (retryable, retryAfterSeconds); call again with a new operationId. Never in the call that opens it: an export sent while Fusion's Edit Auto Dimensions command runs on a newly opened drawing blocks Fusion's main thread for 10 minutes. A later call ends that command if it is running, and exports once the sheets read, Fusion runs no command and the drawing engine is idle and quiet. A drawing opened by someone else is refused (drawing_open_elsewhere). DXF holds the active sheet; with a DXF the reply also gives the scale Fusion chose, read from its dimensions. close:true closes the drawing and the design its open brought in. Journaled.",+ "properties": {+ "close": {+ "description": "Close the drawing in Fusion after exporting, with the design its open brought in when that was not open before and is unmodified, and put the previously active document back (default false).",+ "type": "boolean"+ },+ "drawing": {+ "additionalProperties": false,+ "description": "The drawing's cloud file, as drawing_create returned it.",+ "properties": {+ "fileId": {+ "type": "string"+ }+ },+ "required": [+ "fileId"+ ],+ "type": "object"+ },+ "dwg": {+ "description": "Absolute .dwg path.",+ "type": "string"+ },+ "dwgFormat": {+ "enum": [+ "autocad",+ "simplified"+ ],+ "type": "string"+ },+ "dxf": {+ "description": "Absolute .dxf path (the active sheet).",+ "type": "string"+ },+ "dxfSplines": {+ "description": "Keep splines as splines (default true).",+ "type": "boolean"+ },+ "operationId": {+ "type": "string"+ },+ "overwrite": {+ "type": "boolean"+ },+ "pdf": {+ "description": "Absolute .pdf path; one PDF of every sheet unless pdfSheets.",+ "type": "string"+ },+ "pdfLineWeights": {+ "description": "Print line weights (default true).",+ "type": "boolean"+ },+ "pdfSheets": {+ "description": "Sheets for the PDF, like \"1-3\" or \"1,4\"; every sheet by default.",+ "type": "string"+ }+ },+ "required": [+ "op",+ "sessionId",+ "operationId",+ "drawing"+ ],+ "type": "object"+ },+ "drawing_status": {+ "description": "Whether a drawing is open and ready for drawing_export: its sheets read, Fusion's active command, the drawing engine's unfinished commands and how long its log has been quiet, and the sheets with their views. Changes nothing.",+ "properties": {+ "drawing": {+ "additionalProperties": false,+ "description": "The drawing's cloud file, as drawing_create returned it.",+ "properties": {+ "fileId": {+ "type": "string"+ }+ },+ "required": [+ "fileId"+ ],+ "type": "object"+ }+ },+ "required": [+ "op",+ "drawing"+ ],+ "type": "object"+ }, "efficiency_report": { "description": "Read what makes the design slow to recompute, open and edit, held against the efficiency playbook (skills/fusion-design-efficiency): timeline make-up and health, Position snapshots, Move features, size, repeated definitions made by Paste New, instance-weighted faces, imported history, wires in a parametric design, big sketches, pattern compute options, modeled threads, meshes and empty components. Returns metrics and findings (rule, severity, measured, limit, fix). Read-only and needs no revision digest. It is journaled like bom_export, so a long report on a big design is followed with fusion_mech_operation_status after the relay's 60 s; passes past budgetSeconds are skipped and listed, with complete:false.", "properties": {@@ -12362,7 +12636,7 @@ "op": "inspect" }, "input": {- "op": "required enum: inspect|inspect_entity|new_design|parameter_set|parameter_create|health|export|transaction_probe|sketch_create|sketch_geometry|sketch_constraint|sketch_dimension|sketch_project|sketch_edit|plane_create|feature_create|feature_edit|entity_delete|parameter_batch|component_create|occurrence_insert|occurrence_update|occurrence_delete|component_metadata|joint_create|joint_edit|joint_delete|interference|bom|bom_export|cad_import|mcmaster_discover|mcmaster_open|material_list|material_assign|rigid_group_create|rigid_group_edit|rigid_group_delete|assembly_properties|geometry_query|measure|sketch_curve_edit|sketch_offset|construction_axis|sketch_diagnostics|joint_origin_create|joint_origin_edit|joint_origin_delete|regular_joint_create|regular_joint_edit|motion_link_create|motion_link_edit|motion_link_delete|configuration_inspect|render_scene_inspect|exploded_view_plan|exploded_preview_create|exploded_preview_sample|exploded_preview_show|exploded_preview_dispose|exploded_preview_inspect|efficiency_report|exploded_view_render|exploded_view_stills|render_image|cam_tools|cam_job|cam_inspect|assembly_layout|ray_cast",+ "op": "required enum: inspect|inspect_entity|new_design|parameter_set|parameter_create|health|export|transaction_probe|sketch_create|sketch_geometry|sketch_constraint|sketch_dimension|sketch_project|sketch_edit|plane_create|feature_create|feature_edit|entity_delete|parameter_batch|component_create|occurrence_insert|occurrence_update|occurrence_delete|component_metadata|joint_create|joint_edit|joint_delete|interference|bom|bom_export|cad_import|mcmaster_discover|mcmaster_open|material_list|material_assign|rigid_group_create|rigid_group_edit|rigid_group_delete|assembly_properties|geometry_query|measure|sketch_curve_edit|sketch_offset|construction_axis|sketch_diagnostics|joint_origin_create|joint_origin_edit|joint_origin_delete|regular_joint_create|regular_joint_edit|motion_link_create|motion_link_edit|motion_link_delete|configuration_inspect|render_scene_inspect|exploded_view_plan|exploded_preview_create|exploded_preview_sample|exploded_preview_show|exploded_preview_dispose|exploded_preview_inspect|efficiency_report|exploded_view_render|exploded_view_stills|render_image|cam_tools|cam_job|cam_inspect|assembly_layout|ray_cast|drawing_create|drawing_export|drawing_status", "operationId": "required unique write ID; reuse unchanged for retry", "operationSchemas": { "assembly_layout": {@@ -13235,6 +13509,280 @@ ], "type": "object" },+ "drawing_create": {+ "description": "Make a 2D drawing of the active design with Fusion's automatic drawing: sheets laid out by Fusion, each with a base view and its projected views (front, top, right), an optional isometric view, a filled title block and automatic dimensions. The design must be saved to the cloud with no unsaved changes (or pass useSavedVersion); the drawing is a new cloud file next to the design, or in folderId, never in a project's root folder. Fusion picks the views' scale for the sheet size; the API cannot set it. Takes about 30 s for a part. Journaled. Follow with drawing_export.",+ "properties": {+ "configuration": {+ "description": "Configuration name for a configured design; the active one by default.",+ "type": "string"+ },+ "content": {+ "description": "Draw every part, or only the visible ones.",+ "enum": [+ "full",+ "visible"+ ],+ "type": "string"+ },+ "datum": {+ "description": "Origin for baseline and ordinate dimensions on part sheets.",+ "enum": [+ "model_origin",+ "bottom_left",+ "bottom_right",+ "top_left",+ "top_right"+ ],+ "type": "string"+ },+ "dimensions": {+ "description": "Automatic dimension strategy; overall by default, none for views only.",+ "enum": [+ "none",+ "overall",+ "automatic",+ "baseline",+ "chain",+ "ordinate",+ "symmetric",+ "symmetric_baseline",+ "symmetric_ordinate"+ ],+ "type": "string"+ },+ "folderId": {+ "description": "Cloud folder to put the drawing in; the design's folder by default.",+ "type": "string"+ },+ "holeNotes": {+ "enum": [+ "hole_and_thread",+ "hole",+ "thread",+ "none"+ ],+ "type": "string"+ },+ "name": {+ "description": "Name for the drawing file; Fusion's is '<design> Drawing'.",+ "type": "string"+ },+ "omit": {+ "additionalProperties": false,+ "description": "Parts left out of part sheets: names containing these comma-separated keywords (Bolt,Screw,Nut,Washer by default) and, with fasteners, any part Fusion recognizes as a fastener.",+ "properties": {+ "fasteners": {+ "type": "boolean"+ },+ "keywords": {+ "type": "string"+ }+ },+ "type": "object"+ },+ "operationId": {+ "type": "string"+ },+ "orientation": {+ "enum": [+ "landscape",+ "portrait"+ ],+ "type": "string"+ },+ "sheetSize": {+ "description": "A4 to A0 with iso, A to E with asme; A3 or B by default.",+ "enum": [+ "A4",+ "A3",+ "A2",+ "A1",+ "A0",+ "A",+ "B",+ "C",+ "D",+ "E"+ ],+ "type": "string"+ },+ "sheets": {+ "additionalProperties": false,+ "description": "Which sheets Fusion makes: the main assembly, subassemblies, one per part (component), sheet metal; levels first or all.",+ "properties": {+ "assembly": {+ "type": "boolean"+ },+ "components": {+ "type": "boolean"+ },+ "levels": {+ "enum": [+ "first",+ "all"+ ],+ "type": "string"+ },+ "partsList": {+ "type": "boolean"+ },+ "sheetMetal": {+ "type": "boolean"+ },+ "subassemblies": {+ "type": "boolean"+ }+ },+ "type": "object"+ },+ "standard": {+ "description": "Drawing standard; iso by default.",+ "enum": [+ "iso",+ "asme"+ ],+ "type": "string"+ },+ "style": {+ "enum": [+ "visible",+ "visible_and_hidden",+ "shaded_and_hidden",+ "shaded"+ ],+ "type": "string"+ },+ "tangentEdges": {+ "enum": [+ "off",+ "full",+ "shortened"+ ],+ "type": "string"+ },+ "units": {+ "description": "mm for iso, in for asme by default.",+ "enum": [+ "mm",+ "in"+ ],+ "type": "string"+ },+ "useSavedVersion": {+ "description": "Draw the last saved version even though the design has unsaved changes.",+ "type": "boolean"+ },+ "views": {+ "additionalProperties": false,+ "description": "Base and projected views (default true) and an isometric view beside them (default true).",+ "properties": {+ "isometric": {+ "type": "boolean"+ },+ "orthographic": {+ "type": "boolean"+ }+ },+ "type": "object"+ }+ },+ "required": [+ "op",+ "sessionId",+ "operationId",+ "target"+ ],+ "type": "object"+ },+ "drawing_export": {+ "description": "Export a drawing made by drawing_create to PDF, DWG and DXF (absolute paths on the PC), staged and published with byte counts and SHA-256. The first call opens the drawing in Fusion and answers drawing_not_ready (retryable, retryAfterSeconds); call again with a new operationId. Never in the call that opens it: an export sent while Fusion's Edit Auto Dimensions command runs on a newly opened drawing blocks Fusion's main thread for 10 minutes. A later call ends that command if it is running, and exports once the sheets read, Fusion runs no command and the drawing engine is idle and quiet. A drawing opened by someone else is refused (drawing_open_elsewhere). DXF holds the active sheet; with a DXF the reply also gives the scale Fusion chose, read from its dimensions. close:true closes the drawing and the design its open brought in. Journaled.",+ "properties": {+ "close": {+ "description": "Close the drawing in Fusion after exporting, with the design its open brought in when that was not open before and is unmodified, and put the previously active document back (default false).",+ "type": "boolean"+ },+ "drawing": {+ "additionalProperties": false,+ "description": "The drawing's cloud file, as drawing_create returned it.",+ "properties": {+ "fileId": {+ "type": "string"+ }+ },+ "required": [+ "fileId"+ ],+ "type": "object"+ },+ "dwg": {+ "description": "Absolute .dwg path.",+ "type": "string"+ },+ "dwgFormat": {+ "enum": [+ "autocad",+ "simplified"+ ],+ "type": "string"+ },+ "dxf": {+ "description": "Absolute .dxf path (the active sheet).",+ "type": "string"+ },+ "dxfSplines": {+ "description": "Keep splines as splines (default true).",+ "type": "boolean"+ },+ "operationId": {+ "type": "string"+ },+ "overwrite": {+ "type": "boolean"+ },+ "pdf": {+ "description": "Absolute .pdf path; one PDF of every sheet unless pdfSheets.",+ "type": "string"+ },+ "pdfLineWeights": {+ "description": "Print line weights (default true).",+ "type": "boolean"+ },+ "pdfSheets": {+ "description": "Sheets for the PDF, like \"1-3\" or \"1,4\"; every sheet by default.",+ "type": "string"+ }+ },+ "required": [+ "op",+ "sessionId",+ "operationId",+ "drawing"+ ],+ "type": "object"+ },+ "drawing_status": {+ "description": "Whether a drawing is open and ready for drawing_export: its sheets read, Fusion's active command, the drawing engine's unfinished commands and how long its log has been quiet, and the sheets with their views. Changes nothing.",+ "properties": {+ "drawing": {+ "additionalProperties": false,+ "description": "The drawing's cloud file, as drawing_create returned it.",+ "properties": {+ "fileId": {+ "type": "string"+ }+ },+ "required": [+ "fileId"+ ],+ "type": "object"+ }+ },+ "required": [+ "op",+ "drawing"+ ],+ "type": "object"+ }, "efficiency_report": { "description": "Read what makes the design slow to recompute, open and edit, held against the efficiency playbook (skills/fusion-design-efficiency): timeline make-up and health, Position snapshots, Move features, size, repeated definitions made by Paste New, instance-weighted faces, imported history, wires in a parametric design, big sketches, pattern compute options, modeled threads, meshes and empty components. Returns metrics and findings (rule, severity, measured, limit, fix). Read-only and needs no revision digest. It is journaled like bom_export, so a long report on a big design is followed with fusion_mech_operation_status after the relay's 60 s; passes past budgetSeconds are skipped and listed, with complete:false.", "properties": {
docs/MECHANICAL.md+21@@ -374,6 +374,27 @@ A failed transactional typed model operation reports its abort result and a sema `fusion_save_to_cloud` handles an explicit cloud project/folder/name. The typed export operation creates a local archive or exchange file and does not itself create a Fusion Team version. +## 2D drawings++`drawing_create` makes a drawing of the active design with Fusion's automatic drawing (`adsk.drawing.DrawingManager`, a preview API since July 2026). Fusion lays out the sheets: for a part, one sheet with a base view (front), its projected views (top, right), an isometric view, center marks, a title block filled with the title, author and date, and dimensions by the chosen strategy (`overall` by default). For an assembly it also makes the main assembly and subassembly sheets, with a parts list on the isometric sheet. Options: `standard` (iso or asme), `units`, `sheetSize` (A4 to A0 with iso, A to E with asme; a size of the other standard is refused, since Fusion would ignore it silently), `orientation`, `views`, `style`, `tangentEdges`, `dimensions` (`none`, `overall`, `automatic`, `baseline`, `chain`, `ordinate`, the symmetric variants), `holeNotes`, `datum`, `content`, `sheets`, `omit`, `configuration`, `name` and `folderId`.++The design is drawn from its cloud file, so it must be saved, with no unsaved changes (`useSavedVersion:true` draws the last saved version anyway). Fusion puts the drawing (an `.f2d` file) in the design's folder; `folderId` moves it elsewhere, and a project's root folder is refused either way. The API cannot place a view or set a view's scale: the layout picks the scale for the sheet size (an 80 x 50 x 40 mm part came out at 1:1 on A3). Measured on Fusion 2705: 24.7 to 33.6 s per drawing of a small part, in a drawing engine (`AcCoreConsole.exe`) that Fusion starts and stops; the drawing is not opened.++`drawing_export` writes PDF, DWG and DXF of a drawing `drawing_create` made, staged and published like `export` (byte count, SHA-256, explicit `overwrite`). Two traps found live each blocked Fusion's main thread for every caller, so the operation is built around them:++- **Never export in the call that opens a drawing.** A drawing that a script opens finishes loading only after the script returns, and opening an automatically created drawing starts Fusion's interactive Edit Auto Dimensions command in the drawing engine. An export sent while that command waits for input is fed to its prompt and rejected, and `DrawingExportManager.execute` holds the main thread until its 600 s timeout; PDF, DWG and DXF each waited the full 600 s.+- **Never open a drawing invisibly.** `Documents.open(file, False)` opened the drawing in 0.8 s by Fusion's log, but no drawing engine started for it and the call did not return.++So the first `drawing_export` call opens the drawing (visibly; 9 s for the test part) and answers `drawing_not_ready` with `retryable` and `retryAfterSeconds`; call again with a new `operationId`. A later call ends Edit Auto Dimensions on that drawing if it is running (and answers `drawing_not_ready` again), and exports only when the sheets read, Fusion runs no command, the drawing engine that loaded the drawing has no unfinished command and the engine's log (`FusionDrawing.log`) has been quiet for 5 s. A drawing opened by someone else, or before the add-in restarted, is refused (`drawing_open_elsewhere`): its engine's state is unknown. DXF holds the active sheet. `close:true` closes the drawing, and the design its open brought in when that design was not open before and is unmodified (opening a drawing also opens the design it references), then puts the previously active document back in front. `drawing_status` reports the same readiness without changing anything.++Sheets report their paper (`A3`), width and height (420 x 297 on an mm drawing) and their views. In Fusion 2705, `View.type` raises `InternalValidationError: pAsset` for every view of a fully opened, idle drawing (Fusion's log: no base model asset in the drawing document), so such views are listed as unreadable and do not hold up an export. With `dimensions:"none"` Fusion does not start Edit Auto Dimensions on open.++Between formats in one call, the operation reads the engine's log again and answers `drawing_not_ready` with the files written so far if the engine is still busy. With a DXF, the reply's `scale` is the scale the layout chose, read from the DXF's linear dimensions (sheet length over measured value, `1:1` for the test part on A3); it is null for a drawing without dimensions. `dimensions:"none"` plus `Sheet.autoDimension` later gives the same dimensions without Edit Auto Dimensions ever starting (3.8 s for the test part).++Measured on Fusion 2705 through the gated flow, for the 80 x 50 x 40 mm bracket: create 18 to 22 s, visible open 5 to 9 s, ready 0 to 14 s after the open (with automatic dimensions, one `terminateActiveCommand` of Edit Auto Dimensions took 0.45 s), then PDF 0.3 to 0.9 s, DWG 0.1 s (AutoCAD 2013 format) and DXF 0.2 s (AutoCAD 2013, mm, real DIMENSION entities): about 45 s from the call to three files.++End to end through a deployed bridge: `drawing_create` 18.5 s, then three `drawing_export` calls: the first opened the drawing (8.3 s, `drawing_not_ready`), the second ended Edit Auto Dimensions (3.2 s, `drawing_not_ready`), the third wrote PDF, DWG and DXF and closed the drawing (3.8 s). That was 41.6 s from `drawing_create` to three files, and every SHA-256 in the reply matched its file.+ ## Coverage and verification See [build handoff](build-2026-10-02.md) for the verified checkpoint and live host. See the [feature matrix](mechanical-comparison/FEATURE-MATRIX.md) for each surveyed external capability, its bridge route and remaining gaps. A discoverable native API or arbitrary Python execution does not establish that a dedicated bridge operation is implemented or live verified.
rust/core/tests/golden/mech_capabilities.json+276@@ -8165,6 +8165,280 @@ } }, "description": "Cast batches of rays against named occurrences, without changing anything (assembly planning: what a part seats on, what blocks its way in, whether a tool reaches a screw). Each ray is cast against each occurrence it names, in that occurrence's own component coordinates, about a millisecond on a part, where a ray against a big subassembly's component (thousands of bodies) took a quarter of a second. Returns hits: a row per ray answered, [[occurrence index, distance in mm rounded to 0.01], ...], one entry per occurrence the ray meets within length (its nearest hit), nearest first; a ray that starts inside a body meets that body's exit face. Also cast (rays answered, in order), complete, missing (indexes with no occurrence at that path), failed (casts Fusion refused) and seconds. Not journaled: it stops at budgetSeconds or before its reply passes 1 MiB (stopped: budget|reply_bytes) and the caller sends the remaining rays. Requests over the CLI's argument limit (128 KiB) go in several calls."+ },+ "drawing_create": {+ "type": "object",+ "description": "Make a 2D drawing of the active design with Fusion's automatic drawing: sheets laid out by Fusion, each with a base view and its projected views (front, top, right), an optional isometric view, a filled title block and automatic dimensions. The design must be saved to the cloud with no unsaved changes (or pass useSavedVersion); the drawing is a new cloud file next to the design, or in folderId, never in a project's root folder. Fusion picks the views' scale for the sheet size; the API cannot set it. Takes about 30 s for a part. Journaled. Follow with drawing_export.",+ "properties": {+ "operationId": {+ "type": "string"+ },+ "standard": {+ "type": "string",+ "enum": [+ "iso",+ "asme"+ ],+ "description": "Drawing standard; iso by default."+ },+ "units": {+ "type": "string",+ "enum": [+ "mm",+ "in"+ ],+ "description": "mm for iso, in for asme by default."+ },+ "sheetSize": {+ "type": "string",+ "enum": [+ "A4",+ "A3",+ "A2",+ "A1",+ "A0",+ "A",+ "B",+ "C",+ "D",+ "E"+ ],+ "description": "A4 to A0 with iso, A to E with asme; A3 or B by default."+ },+ "orientation": {+ "type": "string",+ "enum": [+ "landscape",+ "portrait"+ ]+ },+ "views": {+ "type": "object",+ "properties": {+ "orthographic": {+ "type": "boolean"+ },+ "isometric": {+ "type": "boolean"+ }+ },+ "additionalProperties": false,+ "description": "Base and projected views (default true) and an isometric view beside them (default true)."+ },+ "style": {+ "type": "string",+ "enum": [+ "visible",+ "visible_and_hidden",+ "shaded_and_hidden",+ "shaded"+ ]+ },+ "tangentEdges": {+ "type": "string",+ "enum": [+ "off",+ "full",+ "shortened"+ ]+ },+ "dimensions": {+ "type": "string",+ "enum": [+ "none",+ "overall",+ "automatic",+ "baseline",+ "chain",+ "ordinate",+ "symmetric",+ "symmetric_baseline",+ "symmetric_ordinate"+ ],+ "description": "Automatic dimension strategy; overall by default, none for views only."+ },+ "holeNotes": {+ "type": "string",+ "enum": [+ "hole_and_thread",+ "hole",+ "thread",+ "none"+ ]+ },+ "datum": {+ "type": "string",+ "enum": [+ "model_origin",+ "bottom_left",+ "bottom_right",+ "top_left",+ "top_right"+ ],+ "description": "Origin for baseline and ordinate dimensions on part sheets."+ },+ "content": {+ "type": "string",+ "enum": [+ "full",+ "visible"+ ],+ "description": "Draw every part, or only the visible ones."+ },+ "sheets": {+ "type": "object",+ "additionalProperties": false,+ "description": "Which sheets Fusion makes: the main assembly, subassemblies, one per part (component), sheet metal; levels first or all.",+ "properties": {+ "assembly": {+ "type": "boolean"+ },+ "subassemblies": {+ "type": "boolean"+ },+ "components": {+ "type": "boolean"+ },+ "sheetMetal": {+ "type": "boolean"+ },+ "partsList": {+ "type": "boolean"+ },+ "levels": {+ "type": "string",+ "enum": [+ "first",+ "all"+ ]+ }+ }+ },+ "omit": {+ "type": "object",+ "additionalProperties": false,+ "description": "Parts left out of part sheets: names containing these comma-separated keywords (Bolt,Screw,Nut,Washer by default) and, with fasteners, any part Fusion recognizes as a fastener.",+ "properties": {+ "keywords": {+ "type": "string"+ },+ "fasteners": {+ "type": "boolean"+ }+ }+ },+ "configuration": {+ "type": "string",+ "description": "Configuration name for a configured design; the active one by default."+ },+ "folderId": {+ "type": "string",+ "description": "Cloud folder to put the drawing in; the design's folder by default."+ },+ "name": {+ "type": "string",+ "description": "Name for the drawing file; Fusion's is '<design> Drawing'."+ },+ "useSavedVersion": {+ "type": "boolean",+ "description": "Draw the last saved version even though the design has unsaved changes."+ }+ },+ "required": [+ "op",+ "sessionId",+ "operationId",+ "target"+ ]+ },+ "drawing_export": {+ "type": "object",+ "description": "Export a drawing made by drawing_create to PDF, DWG and DXF (absolute paths on the PC), staged and published with byte counts and SHA-256. The first call opens the drawing in Fusion and answers drawing_not_ready (retryable, retryAfterSeconds); call again with a new operationId. Never in the call that opens it: an export sent while Fusion's Edit Auto Dimensions command runs on a newly opened drawing blocks Fusion's main thread for 10 minutes. A later call ends that command if it is running, and exports once the sheets read, Fusion runs no command and the drawing engine is idle and quiet. A drawing opened by someone else is refused (drawing_open_elsewhere). DXF holds the active sheet; with a DXF the reply also gives the scale Fusion chose, read from its dimensions. close:true closes the drawing and the design its open brought in. Journaled.",+ "properties": {+ "operationId": {+ "type": "string"+ },+ "drawing": {+ "type": "object",+ "description": "The drawing's cloud file, as drawing_create returned it.",+ "properties": {+ "fileId": {+ "type": "string"+ }+ },+ "required": [+ "fileId"+ ],+ "additionalProperties": false+ },+ "pdf": {+ "type": "string",+ "description": "Absolute .pdf path; one PDF of every sheet unless pdfSheets."+ },+ "dwg": {+ "type": "string",+ "description": "Absolute .dwg path."+ },+ "dxf": {+ "type": "string",+ "description": "Absolute .dxf path (the active sheet)."+ },+ "overwrite": {+ "type": "boolean"+ },+ "pdfSheets": {+ "type": "string",+ "description": "Sheets for the PDF, like \"1-3\" or \"1,4\"; every sheet by default."+ },+ "pdfLineWeights": {+ "type": "boolean",+ "description": "Print line weights (default true)."+ },+ "dwgFormat": {+ "type": "string",+ "enum": [+ "autocad",+ "simplified"+ ]+ },+ "dxfSplines": {+ "type": "boolean",+ "description": "Keep splines as splines (default true)."+ },+ "close": {+ "type": "boolean",+ "description": "Close the drawing in Fusion after exporting, with the design its open brought in when that was not open before and is unmodified, and put the previously active document back (default false)."+ }+ },+ "required": [+ "op",+ "sessionId",+ "operationId",+ "drawing"+ ]+ },+ "drawing_status": {+ "type": "object",+ "description": "Whether a drawing is open and ready for drawing_export: its sheets read, Fusion's active command, the drawing engine's unfinished commands and how long its log has been quiet, and the sheets with their views. Changes nothing.",+ "properties": {+ "drawing": {+ "type": "object",+ "description": "The drawing's cloud file, as drawing_create returned it.",+ "properties": {+ "fileId": {+ "type": "string"+ }+ },+ "required": [+ "fileId"+ ],+ "additionalProperties": false+ }+ },+ "required": [+ "op",+ "drawing"+ ] } }, "transactions": {@@ -8197,6 +8471,8 @@ "component_create", "component_metadata", "construction_axis",+ "drawing_create",+ "drawing_export", "efficiency_report", "entity_delete", "exploded_preview_create",
rust/core/tests/golden/mech_validation.json@@ -1 +1 @@
Reviews
Comments
Log in to comment.