main
Drew Owens 0.11.4 source 8889116 1d ago

Modelling, importing and exporting — swx

Read this when creating geometry, importing a neutral file, exporting, or mapping a Fusion 360 habit onto SOLIDWORKS. Part of the solidworks-bridge skill — SKILL.md beside this folder has the rules that never bend. Trust each verb's own reply (_hint, errorCode) over anything written here.

Importing: 3D Interconnect decides what you get

  • If swx_import fails with interconnect_blocks_import, that is the whole answer: nothing imports while 3D Interconnect is on. Tell the user to uncheck Tools > Options > System Options > Import > "Enable 3D Interconnect" and try again. Do NOT hunt for a missing translator, and do not ask the bridge to change the setting — it will not, ever, not even temporarily.
  • swx_import reports interconnect, linked and sourcePath. Read them. With 3D Interconnect ON — the default, and TRUE on this install — a STEP is not translated: it is OPENED as a part holding a LINKED feature pointing at the source file. The part is NOT self-contained, and moving or deleting that file changes it. Tell the user that when it matters.
  • The bridge never changes that preference, not even temporarily. If they want an unlinked import, they turn 3D Interconnect off in Options and import again — the bridge will route through the translator and say so.
  • dissolve:true is refused (dissolve_not_measured) until the link-breaking API is verified on this install. Do not work around it; the refusal says what to measure.
  • A modal Import Diagnostics dialog can stop an import (auto-run is ON). The reply says stoppedByDialog; show the user a screenshot and let them answer. Never answer it — it decides whether faulty faces get healed.

Making something new

adom-bridge --ai-thread "<thread>" swx_new_document '{"type":"part"}'
adom-bridge --ai-thread "<thread>" swx_run_script '{"script":[
  {"op":"sketch_rect","plane":"Front Plane","widthMm":50,"heightMm":30},
  {"op":"extrude","depthMm":20},
  {"op":"set_material","name":"6061 Alloy"},
  {"op":"set_prop","name":"PartNo","value":"BRK-100"}
]}'
adom-bridge --ai-thread "<thread>" swx_inspect_bodies '{}'      # verify the GEOMETRY
adom-bridge --ai-thread "<thread>" swx_save_as '{"outputPath":"C:\\parts\\bracket.sldprt"}'
  • swx_new_document gives you an unsaved document: it has a title (Part1) and no path until swx_save_as. Target it by name, not by path.

  • Batches reuse one document (measured, 2026-10-14).

    • Every NEW part costs SOLIDWORKS about 85 MB and 125 handles, kept until it restarts. Twelve builds in ONE reused part left it flat.
    • Make one visible part with swx_new_document, then run each script with "reuseDocument": "<its path>". Its leading new_part becomes clear_part, which deletes every feature after the origin, and only in a part the bridge created.
    • A hidden document (visible:false) CANNOT be modelled. SOLIDWORKS selects only in the active document, and a hidden one cannot be activated, so scripts refuse it (document_hidden). Everything is visible by default.
  • swx_run_script takes a JSON array of steps, not a string of code — SOLIDWORKS has no in-process scripting host the way Fusion has Python. Every dimension is in millimetres. A rejected script returns the full op list with every op's arguments (opArgs), the coordinate conventions and a worked example, so read the error.

  • The ops (0.10.0). Michael asked for these in issue #1. They were MEASURED live on SOLIDWORKS 2026 on 2026-10-14: tools/dsl-live-check.py passed 30 of 30 checks. See docs/LIVE-RESULTS.md in the bridge repo. On SOLIDWORKS 2021 a community swx_selftest {"level":"write"} run (2026-10-15, bridge 0.10.9) passed every modelling check, LEGO brick identical. Each step reports proven: {live, measuredOn}. live is true only when every variant the step ran was measured on the release it ran on. When it is false, unmeasured names the variant, so check that step's geometry with swx_inspect_bodies. swx_describe lists every variant as liveMeasured.

    • Sketching.
      • sketch holds SEVERAL profiles in ONE sketch: {"op":"sketch","plane":"Top Plane","entities":[{"rect":{...}},{"circle":{...}}]}. Concentric circles extrude into a ring, and a rectangle with circles inside it into a plate with holes. sketch_rect and sketch_circle are one-entity shorthands.
      • A sketch goes on a named plane, on an offset plane "plane":{"offsetFrom":"Top Plane","offsetMm":9.6} (the script makes it), or on a face "face":{"atPointMm":[x,y,z]}. A face must be parallel to Top, Front or Right, and is resolved to the offset plane that coincides with it.
      • A rectangle's xMm/yMm is its CORNER; anchor:"center" or centerMm:[x,y] centres it.
    • Extrude and cut. extrude and cut take reverse, direction:"both" (with depth2Mm), midPlane:true and throughAll:true.
    • Other features.
      • fillet {radiusMm, edges} and chamfer {distanceMm, angleDeg, edges}. edges is {"atPointsMm":[[x,y,z]]} or {"allOfFeature":"Boss-Extrude1"|"last"}.
      • shell {thicknessMm, removeFacesAtPointsMm}.
      • linear_pattern {feature, directions:[{axis, count, spacingMm}]}.
      • circular_pattern {feature, axis, count, angleDeg}.
      • set_appearance {rgb:[r,g,b], target}. swx_inspect_bodies reads it back as appearanceRgb.
  • Conventions.

    • On Top Plane, sketch +x is model +X and sketch +y is model −Z (measured by Michael).
    • An extrude goes along the plane's +normal (Top: +Y). A cut goes along the −normal; pass reverse:true when the material is on the other side.
    • From a FACE, an extrude goes OUTWARD and a cut INWARD, on any face, the hidden bottom one included. The face is the one your point lies on, picked by geometry, never through the view. A point on an edge between two faces is refused.
    • direction:"both": depthMm goes the op's own way (an extrude's +normal or outward, a cut's −normal or inward), and depth2Mm goes the other way.
    • A material wipes a part's colour (SOLIDWORKS behaviour). The bridge re-applies a colour the same script set earlier, and the set_material step lists it under appearanceReapplied. Put set_material first and nothing needs re-applying.
    • Fillet and chamfer edges are de-duplicated before they are selected. An edge selected twice would be deselected, so "fillet all of Boss-Extrude1" would select nothing.
    • A picked face or edge is selected through a verified ladder. The rungs are a typed MultiSelect2, then IEntity::Select4, then SelectByRay with the bridge's own ray, then SelectByID2 at the point. A rung counts only when the selection count grows by what was asked. The step reports the rung that worked as selectedVia. viewDependent:true means only the view-based last resort worked, so check that step's geometry.
    • A sketch need not be the step right before its extrude: the bridge re-selects it by name.
    • A feature SOLIDWORKS returns null is an error that stops the script. It is never a quiet success.
  • Prove it on the install: swx_selftest {"level":"write"} builds 32 scratch parts. It measures each one against geometry computed independently and closes it. Each row carries expected and measured, so it is the one call that proves the ops on a release we have not run.

  • examples/lego-2x4.json is a LEGO 2x4 brick in 4 features:

    1. the block;
    2. a hollow cut upward;
    3. three tubes from one sketch of concentric circles;
    4. eight studs on a plane offset 9.6 mm.

    Run it as swx_run_script {"script": <its "script">}.

  • Exam-grade ops (0.11.0, NOT YET MEASURED LIVE — every step says proven.live:false). Built for the CSWA benchmark:

    • Sketch geometry in the plane's 2D frame, like rect and circle: line {from, to}, centerline, polyline {points, close}, arc {center, radiusMm, startDeg, endDeg, ccw}, arc3 {start, mid, end}, tangentArc {to, radiusMm?} (continues the entity before it), slot {center, lengthMm, widthMm, angleDeg}, polygon {center, sides, circumradiusMm | inscribedRadiusMm, angleDeg}, rect.cornerRadiusMm, sketchFillet {at, radiusMm} and sketchChamfer {at, distanceMm} (the corner where two lines meet), and construction:true on any entity. Lines and arcs must form CLOSED contours: an open end is refused with the gap named, before anything is drawn. Composites are expanded into lines and arcs (ISketchManager::CreateLine / CreateArc / CreateCenterLine), so the simulator measures exactly what is drawn.
    • revolve / revolve_cut {axis: "x"|"y" | {entity: i} | {line: [[x,y],[x,y]]}, angleDeg: 360, midPlane, reverse} — the profile must lie on one side of the axis (FeatureRevolve2).
    • mirror {plane | face, features: "last" | name | [names] | "all", mirrorBody} (InsertMirrorFeature2).
    • hole {atMm, diameterMm, depthMm | throughAll, counterbore {diameterMm, depthMm} | countersink {diameterMm, angleDeg}} — cuts of circles on the face's plane (no Hole Wizard); flat-bottomed, depth from the face.
    • End conditions on extrude and cut: upToNext, upToSurface {face}, offsetFromSurface {face, distanceMm, reverseOffset}, and draftDeg (inward; draftOutward:true).
    • A plane offset from a face: plane: {offsetFrom: {face: {atPointMm}}, offsetMm}, along the face's OUTWARD normal (negative = into the part). The face's outward normal stays the reference, so a cut from it goes on inward.
    • set_material {densityKgM3}: with a name, the material's density must be that (material_density_mismatch); alone, the part's own density (refused while a library material is applied). The step reports the density READ BACK.
    • swx_mass_properties now also reports massG, volumeMm3, surfaceAreaMm2, centerOfMassMm (the document's frame), densityKgM3 and materialName.
  • Offset Entities and sketch regions (0.11.4, NOT YET MEASURED LIVE):

    • offsetEntities is a sketch entity: {offsetEntities: {fromFace: {atPointMm: [x,y,z]}, offsetMm: -1, loops: "outer"|"all", chain: true}}. SOLIDWORKS offsets a model face's outline into the sketch (IModelDoc2::SketchOffsetEntities2). That is the outline you could not draw, because it is the model's own.
    • A NEGATIVE offsetMm goes INTO the face. loops:"outer" (the default) takes the outer loop's edges; "all" selects the face, holes included.
    • SOLIDWORKS' sign does not decide the side, so the bridge reads where the new segments landed. It redoes the offset the other way once, and reports side / sideVerified.
    • A sketch with an offset cannot be revolved.
    • regionsAtMm: [[u, v], ...] on extrude / cut (regionAtMm for one) extrudes only the sketch regions holding those points, in the sketch's own coordinates. This is SOLIDWORKS' Selected Contours, for contours that CROSS (an offset outline and a circle).
    • The simulator offsets only a plain block's face. It models regions only of profiles that nest or stand apart, and refuses the rest, saying so.
    • The CSWA Tool Block Step 4 (cswa-08) uses both.
  • The CSWA benchmark: swx_selftest {"level":"cswa"} builds the exam parts shipped in resources/cswa/ (the official sample exam's Tool Block, the 3dengr practice set, the LEGO brick, and community parts with keys derived analytically), weighs each, and compares it with its key within the spec's tolerance: "N of M CSWA parts within tolerance". Call it with responseMode:"stream" or "job".

  • Verify with swx_inspect_bodies, not with the step list. It reports each solid's bounding box, size, volume, area and mass in millimetres — that is what tells you the model is what you meant. Each body's massKg is its volume times densityKgM3 (its material's density, densitySource says where it was read), so it agrees with swx_mass_properties; an unreadable density gives massKg: null, never a guess.

  • bridgeCreatedDocument on a swx_run_script reply is decided the way every other verb decides ownership — by PATH when the document has one — so a part made with swx_new_document (saved under the bridge's scratch folder) is true whether you address it by path or title.

  • Throwing it away is swx_close_doc {"name":"Part1","save":false}, or swx_reset_workspace to sweep every scratch document the bridge created.

  • swx_import opens one unsaved document and it STAYS OPEN until you close or save it — exactly like swx_new_document. It reports documentsOpened:1 and netCountOk:true. Importing in a loop without closing is what leaks documents (a live session was found holding 1342 STEP temps, 8 GB). If a count ever looks huge, swx_docs will say truncated:true with a count and a small sample instead of timing out — run swx_close_import_temps {"reason":"…"} to drain the leaked …\Temp\swx<pid>\IC~~\… conversion temps. That verb works in the default posture and can never touch a saved user document (a user file has a real path; a temp does not).

The everyday flow

  1. swx_find_files {"roots":["C:\\designs"],"query":"gearbox"} — locate documents on disk (works with SOLIDWORKS closed; newest first).
  2. swx_open {"path":"...sldasm"} — silent open, background. SOLIDWORKS launches automatically if closed (cold start 30-90s; the verb's progress block and swx_progress report it).
  3. Work the document:
    • swx_bom {"format":"csv"} — quantities per (file, configuration) with every custom property as a column; csvPath lands on the DESKTOP disk.
    • swx_mass_properties {} — mass/volume/area/CoM in SI units.
    • swx_interference {} — assembly clash check (count:0 = clean).
    • swx_rebuild_check {} — force rebuild + broken-feature census.
    • swx_props_get / swx_props_set — custom properties (then swx_save).
    • swx_export_step {"outputPath":"C:\\out\\part.step"} — or _iges/_stl/_3mf/_glb/_sat/_parasolid/_pdf/_dxf/_dwg, or the generic swx_export {"format":"..."}. Verified live from a part: STEP, IGES, STL, X_T, X_B, SAT, 3MF, GLB, PLY, AMF, 3DXML, PNG, JPG, TIF, PDF. DXF, DWG, OBJ and U3D are refused for a part (DXF/DWG are drawing formats). VRML is blocked by the bridge — it hangs SOLIDWORKS on a modal.
    • swx_design_info {} / swx_inspect_bodies {} / swx_get_parameters {} / swx_set_parameter {"name":"D1@Boss-Extrude1","valueMm":25} — read the design back and drive it.
    • swx_pack_and_go {"out":"C:\\handoff"} — self-contained copy with all references, for sending a design anywhere.
  4. swx_state {} any time — open docs + active doc, the look-then-act check.
  5. Address documents by path. A title is what Windows' "Hide extensions for known file types" makes of the file name: Part14-17 with it on (the Windows default, measured on a SOLIDWORKS 2021 machine), Part14-17.SLDPRT with it off. Since 0.10.10 every title match ignores .sldprt/.sldasm/.slddrw, but swx_new_document and swx_open give you the path — use it.

Export and cloud

  • The export format is the DESTINATION EXTENSION, not the format argument. swx_export_step {"outputPath":"x.wrl"} writes VRML, not STEP — which is why the bridge refuses .wrl on the filename (errorCode:"format_blocked") on every route. VRML raises a modal that hangs SOLIDWORKS for minutes.
  • There is no cloud. swx_cloud_status explains why with a live probe: the SOLIDWORKS COM API exposes no 3DSpace/3DDrive member at all. Local files work fully. Do not go looking for a cloud-open verb.

Coming from the Fusion 360 bridge?

Arg names and response keys mirror fusion_* wherever the concept survives: outputPath, filePath, name, parameters, bodies, current, applied, actions, stages, wouldPrompt, closed, remaining. The four things that do not transfer:

Fusion SOLIDWORKS
fusion_start launches the app swx_start launches Connected editions through the Platform's own shortcut — 1-3 minutes cold, and a sign-in window only the user can answer may stop it
fusion_run_modeling_script takes Python swx_run_script takes a JSON array of typed steps
Fusion has no macro road swx_run_macro runs a VBA .swp/.swb/.dll — always gated, and not yet live-proven
21 cloud verbs (APS) none — swx_cloud_status says why
fusion_export_optimized_glb needs a service swx_export_glb is native

docs/FUSION-PARITY-REPORT.md in the bridge repo has all 132 Fusion verbs with a verdict.

Rendering a picture

  • swx_render_image {reason, width, height, view, realView, ambientOcclusion, shadows, perspective, background, zoomToFit, zoomFactor} draws the ACTIVE document with SOLIDWORKS's own viewport (there is no PhotoView 360 on this edition) at the size asked and writes a PNG. Measured live: 4K (3840×2160) takes about as long as 1080p — ask for 4K for a hero shot. Activate the document first (swx_show_assembly / swx_activate_document).
  • Read width/height in the reply — they come from the file; capped:true means only the window size came out.
  • settings has a row for every setting you asked for: changed:false with why:"alreadyAsRequested" means it was already that way; why:"unreadable" or "setFailed" means it was NOT applied — say so rather than claiming it. why:"setIgnored" means SOLIDWORKS accepted the call and left the setting as it was (measured: RealView on an uncertified GPU); the reply's notes has a sentence for each — pass it on to the user. Never try to force RealView on.
  • If the model looks small after zoomToFit (an assembly fit leaves it at about a quarter of a 16:9 frame), add zoomFactor: >1 zooms in, and after a fit 1.4–1.6 usually fills the frame without clipping — 2.0 clipped a tall assembly. The camera is restored afterwards.
  • Every display setting it changed is restored (restoredSettings); if restoreIncomplete is true, tell the user which view settings may have changed. background:"transparent" is not available. A render that changes the view is refused user_is_active while the user is working; an export of the current view is not. Omit path to write into the bridge's exports folder; a path must be in a folder that exists and must not exist yet.
  • SOLIDWORKS Visualize: swx_start {app:"visualize", reason} starts it through its platform shortcut (never the executable — this edition refuses a direct start). Its dialogs are reported in visualize.waitingOn and NEVER answered: userVisualizeContentFolder (first run — the user picks a folder), userSignIn (swx_sign_in {userAuthorized:true, window:"visualize"} on the user's say-so), visualizePlatformNotice (started the wrong way). If the platform session has lapsed, Visualize does not start at all: the platform updater shows the sign-in first. swx_start then answers stage:"waitingOn", with visualize.parkedBehind and signInWindow.host:"desktopUpdate". Answer it with swx_sign_in {userAuthorized:true, window:<signInWindow.hwnd>} on the user's say-so. No render verb for Visualize yet.