# 使用 SOLIDWORKS 进行建模与反馈验证

<!-- autos.skill.namespace: autos.skills.solidWorks -->
<!-- autos.skill.description: 操作 SOLIDWORKS：零件建模、装配体配合、工程图、模型反馈与 API 文档查询。 -->
<!-- autos.skill.version: 0.7.0 -->
<!-- autos.skill.minAutos: 4.13 -->
<!-- autos.skill.disabled: true -->

## 首选路线

**`com.sldWorks` 助手 + 原生 SOLIDWORKS API；结构化读回优先，模型图像辅助，UI 自动化仅作诊断/兑底。** 不需要 MCP 服务。复用已有 SOLIDWORKS VBA/C# API 知识，将调用翻译为 aardio；库未封装的接口直接在 COM 对象上调用，复杂宏可用库的 `VBA` / `NetCompiler`。

本技能包依赖 aardio 标准库  `com.sldWorks`（含 `NewSketch/Extrude/Fillet/Chamfer/Revolve/LinearPattern/CircularPattern/AddComponent/AddMate/GetDrawingViews/InsertModelDimensions/GetFaces/GetEdges/GetDimensions/SetDimension/SetMaterial/SetCustomProperty/CaptureView/CloseNewDocs/probe` 等）与内置函数 **`com.nothing()`**。

## 立即上手：先探测 SOLIDWORKS ，再只观察

```aardio
import autos.skills.solidWorks; // 同时导入 com.sldWorks
var sk=autos.skills.solidWorks;

var pre=sk.preflight(2000);        // 不经 COM：进程/线程响应/可见对话框；ok=false 时不要再发任何 COM 调用
if(!pre.ok) return pre;            // 直接返回 advice 与 dialogs 给用户

var sw,err=com.sldWorks(); // 连接或启动 SOLIDWORKS
// var sw,err=com.sldWorks(false); // 仅连接前台实例；不启动、参数 2 指定版本则不回退
if(!sw) return {error=err};

sw.Visible=true; //转为前台实例

var state,message=sk.observe(sw);
return state : {error=message};
```

✅ GOOD: 使用 `com.sldWorks` 查找或启动 SOLIDWORKS
❌ BAD: 用其他方法到处找 SOLIDWORKS 进程或安装位置

**为什么必须先探测**：SOLIDWORKS 主线程一旦停止泵消息（长命令、模态对话框、同名文档堆积导致的内部死循环），所有 COM 调用包括“连接”都会**无限等待且无错误**，工具调用看起来只是没返回。`preflight`/`observe` 的探测用 `SendMessageTimeout` 在几十毫秒内给出结论。

通过 ROT 遍历已前台运行的实例:

```aardio 
import com.sldWorks
for sldWorks in com.sldWorks.eachRunning() {
    //sldWorks 已转为 com.sldWorks 对象
	print(sldWorks.ProcessId,sldWorks.MajorVersion(),sldWorks.Path);
}
```

后台启动 SOLIDWORKS （保持 Visible=false）在 ROT 不可见（私有），com.sldWorks(false) 无法连接。

## 会话卫生（每个写任务必做）

```aardio
var snapshot=sw.GetDocumentList();                 // 任务开始前的文档不属于本任务
var runTag=tostring(time(),"%Y%m%d-%H%M%S");        // 输出文件名一律带运行标记，绝不重复用固定名字
// ... NewDoc / 建模 / SaveAs(io.joinpath(dir,"part-"+runTag+".SLDPRT"),,,,doc) ...
var cleanup=sw.CloseNewDocs(snapshot,true);        // 结束时关闭本任务打开的全部文档（含隐藏加载的引用件）
```

- SOLIDWORKS 按**文件名（含扩展名）**索引文档，同名不同路径的文档不能同时打开。库的 `SaveAs`/`OpenDoc` 会拒绝这种冲突（`OpenDoc` 返回码 65536）；不要绕过。
- 长任务或多步任务：每一步开始前 `sk.preflight()` 或 `sw.IsResponsive()`；每一次工具调用都用 **异步线程 + 超时** 运行，不要在对话线程里阻塞等待 COM。
- `CloseDoc(doc)` 默认拒绝丢弃未保存修改；只对自己创建的测试文档传 `discardChanges=true`。用户原有文档只在用户明确要求时保存或关闭。

- `sw` 是附加了便利方法的原生 **ISldWorks COM 对象**；`sw.FindDoc(...)` 与 `sk.resolveTarget(...)` 返回原生 **IModelDoc2 COM 文档**，可继续访问 `SketchManager/FeatureManager/Extension` 等。
- `sk.observe(sw)` 只列会话，**不会把 ActiveDoc 默认当作目标**。`documents` 每项含 `{document,identity}`；`document` 已包含 `units`（mm/deg 与换算因子）、`configurations`、零件 `material`。
- 已确认目标后：`sk.observe(sw,完整路径或准确标题,{features=true;mass=true;dimensions="AA_Block";faces=true;properties=true})`。不接受 COM 对象作为 target。默认仅轻量摘要；不重复列所有文档，除非 `listDocuments=true`。
- `features`：顶层特征。`featureLimit=60`（1..10000）；返回 `featureScan={count,limit,truncated,issues,errorCount,warningCount}`，草图项带 `constrainedStatusName`（`fullyDefined` 才是完全定义）。
- `dimensions`：特征名、特征名数组或 `true`（整个文档，`dimensionLimit=100`）；`dimensions[]` 含 `fullName,value(米/弧度),unit,driven,readOnly`，`dimensionScan.missing` 列出不存在的特征。
- `faces`：仅零件；每面含 `normal`（平面）、`area`、`box`、`point`（面上实际点，可直接用于 `NewSketch`/`SelectByPoint`）、`surfaceTypeName`。面索号不是持久引用。
- `mass`：整个模型的 SI 质量属性；工程图 `massState="not-applicable"`，失败 `unavailable`，不以 0 冒充。未指定材料时密度是默认值，质量无工程意义。
- `readOk` 只表示请求的读取成功，**不是模型健康/业务验收**。可独立失败的局部读取保留其余反馈并置 `readOk=false`，`errors[]` 给出 section。
- `observe` 不激活、不重建、不清选择、不截图、不保存；返回纯数据表。不要返回或跨线程传递 COM 对象。

## 写操作前：重新核对目标

从 `state.identity` 取得纯数据凭据。下一次工具调用重新连接，`sk.resolveTarget(sw,identity)` 核对 **PID、版本、路径/未保存标题、文档类型、活动配置**；不匹配就停止，不回退 ActiveDoc、不自动切换配置。

它不是文件版本号、实体持久引用、写权限或事务锁；不能辨别“关闭后重开同一路径”。写前再核对只读标志、`editingSketch`、预期旧值（用 `dimensions`/`mass` 读回）；装配体用 `IsEditingSelf()`，`GetEditTargetComponent()` 非空不等于正在原位编辑零件。另存为或切换配置后重新观察。返回文档不会自动激活；实测坐标选择、进入草图、拉伸、改尺寸在非活动文档上均可执行；`CaptureView`/`SaveAs` 会自行激活。

## 建模助手（已实测，优先使用）

| 动作 | 调用 |
| --- | --- |
| 新建草图 | `sw.NewSketch(doc,基准面特征或{x=,y=,z=}面上点,function(sm,doc,sketch){...},"AA_Profile")` → 草图特征；回调报错也会退出草图 |
| 凸台/切除 | `sw.Extrude(doc,"AA_Profile",{depth=0.02;name="AA_Block"})` / `{cut=true;endCondition="throughAll"}`；返回 `特征,错误码` |
| 找面 | `sw.GetFaces(doc)` 按 `normal`/`area` 选，用 `face.point` 开草图或 `sw.SelectByPoint(doc,"FACE",x,y,z)` |
| 尺寸 | `sw.GetDimensions(doc,"AA_Block")` → `sw.SetDimension(doc,"D1@AA_Block",0.03)`（米；状态 0 才成功，默认重建并回读） |
| 材料 | `sw.GetMaterials()` 查本地化名→ `sw.SetMaterial(doc,name,"solidworks materials.sldmat")` → 质量=体积×密度 |
| 属性 | `sw.SetCustomProperty(doc,"Description","...")` / `sw.GetCustomProperties(doc)` |
| 找边 | `sw.GetEdges(doc)` 按 `isLine/length/mid` 选；`edge.mid` 直接作圆角/倒角/阵列方向参考；`sw.FindEntity(doc,"EDGE",{x,y,z})` 按几何定位不依赖视角 |
| 圆角/倒角 | `sw.Fillet(doc,[edge.mid,...],{radius=0.005})` / `sw.Chamfer(doc,edge.mid,{distance=0.004[,distance2 或 angle=弧度]})` |
| 旋转 | `sw.NewSketch(...,function(sm){...;return sm.CreateCenterLine(...)})` 的第 3 个返回值作 `sw.Revolve(doc,sketch,{axis=centerline})` 的轴 |
| 阵列 | `sw.LinearPattern(doc,"AA_H1",{direction1=edge.mid;count1=3;spacing1=0.02;toward1=[1,0,0][;direction2;count2;spacing2;toward2]})` 返回第 4 值 `info`（实际 `direction1/2`、`flip`、`corrected`），`toward` 指定期望方向后库自动定向并回读校正，不必再手工 flip / `sw.CircularPattern(doc,"AA_Hole",{axis=cylinderFace.point;count=6})` |
| 配置 | `sw.GetConfigurations(doc)` → `sw.AddConfiguration(doc,"AA_Heavy",{comment;parent;activate=false})` → `sw.SetDimension(doc,"D1@AA_Boss",0.02,"AA_Heavy")` / `sw.SetFeatureSuppression(doc,"AA_H1",true,"AA_Heavy")` → `sw.ActivateConfiguration(doc,"AA_Heavy")` 后读质量属性 → `sw.GetFeatureSuppression(doc,"AA_H1")` → `sw.DeleteConfiguration(doc,name)`（拒绝活动/唯一配置，父配置连带派生配置） |
| 配置表 | 系列零件一次读写：`sw.GetConfigurationTable(doc[,{configurations;dimensions;features;properties;material;mass=true}])` → 每配置一行的尺寸/压缩/属性/材料/质量 + `differences` 差异列；`sw.ApplyConfigurationTable(doc,[{name;comment;parent;dimensions={["D1@AA_Boss"]=0.02};features={AA_H1=true};properties={PartNo="PL-20"};material="1060 合金"}],{baseConfiguration;activate;verify})` 自动建缺失配置、逐格写入并回读到 `verified`；任何行失败返回 `null,说明,结果`（`结果.failed`） |
| 装配 | `sw.AddComponent(asm,path,{x,y,z})`（隐藏加载引用件）→ `sw.AddMate(asm,{component=名,x,y,z},{component=名,x,y,z},{type="coincident";align="antiAligned"})` → `sw.GetMates(asm)` |
| 工程图 | 先 `sw.OpenDoc(modelPath,,,,false)` 隐藏加载模型，再 `drawing.Create3rdAngleViews2(modelPath)` → `sw.InsertModelDimensions(drawing)` → `sw.GetDrawingViews(drawing)` / `sw.AddNote(drawing,text,{x,y})` |
| 图像 | `sw.CaptureView(path,doc,960,720,"isometric")`；工程图用 `"fit"` |
| 清理 | `sw.GetDocumentList()` 快照 → `sw.CloseNewDocs(snapshot,discard)`；单个 `sw.CloseDoc(doc,discard)` 返回 `closed/hidden/referenced` |

完整参数、返回值与限制：`lookup_library_reference("com.sldWorks")`。

## 默认小闭环

1. **Observe**：核对实例、目标、配置、单位、模板与原有未保存修改；明确此次动作与可验证的不变量（体积、面数、尺寸值）。
2. **Act**：每次一个逻辑步骤或短批次；优先库助手，选择集显式建立，检查返回对象与状态码。重要现有模型先按用户意图备份；新建测试模型用唯一名称。
3. **Verify**：`RebuildDoc(doc)` 后读尺寸、实体数、面数、体积/组件数/视图引用等独立证据。失败先观察，不盲目再次建模。
4. **See**：必要时 `CaptureView(新图像路径,doc,960,720,"isometric")`，再用 `analyze_image` 分析。工程图不要套用三维等轴测。
5. **Persist**：按要求保存/导出，保留所有错误与警告码；必要时对自己的测试文档关闭重开再验证。交付原生可编辑文件 + 所需交换格式 + JSON/图像证据。

长度 **m**、角度 **rad**、体积 **m³**、质量 **kg**；mm ÷1000 再传 API，`document.units.lengthFactor` 用于换回文档显示单位。`GetPartBox` 是近似包围盒，不做精密尺寸验收。

## 按需阅读路由

技能资源根：`~/lib/autos/skills/solidWorks/.res/`。不要一次加载全部资料。

| 任务 | 读取/执行入口 |
| --- | --- |
| 原生 API 签名、参数、枚举值、编程指南与 VBA/C# 示例 | 本文“离线 API 文档”：`import autos.skills.solidWorks.help` → `help()` → `read()` / `search()`；不启动 SOLIDWORKS |
| 新建零件：完全定义草图、拉伸、顶面通孔、材料、属性、改尺寸 | `knowledge/parts.md`；`examples/plate-with-hole.aardio`，参数 `{version=2025;template=实际prtdot;outputRoot=输出根目录;material=可选}` |
| 圆角/倒角/旋转/阵列、按几何找边、装配配合、工程图尺寸 | 本机 `~/docs/library/com/sldWorks/features.md`（每段都有实测体积回读）；库实机用例 Autos 工作区 `sldworks-library/tests/round3-live.aardio` |
| 多配置（增删/派生/切换）、按配置改尺寸与压缩特征、线性阵列方向规则 | 本机 `~/docs/library/com/sldWorks/properties.md` §3、`features.md` §3；库实机用例 `sldworks-library/tests/round5-live.aardio` |
| 配置表 / 系列零件（一张表写完厚度、孔压缩、零件号、材料，再按配置读质量并截图） | 本机 `~/docs/library/com/sldWorks/properties.md` §4；`examples/series-part.aardio`，参数 `{version;template;outputRoot[;material;heavyMaterial]}`；库实机用例 `sldworks-library/tests/round6-live.aardio` |
| SOLIDWORKS 无响应 / 文档越开越多 / 同名冲突 / 探测与清理 | `knowledge/recovery.md` 第 0 节；本机 `~/docs/library/com/sldWorks/documents.md` §5.1 |
| 跑 20→40 mm 旧闭环及关闭重开验证 | `examples/closed-loop.aardio`，参数 `{version=2025;template=实际prtdot;outputRoot=输出根目录}` |
| 双组件装配体、三视图、PDF | `knowledge/assembly-drawing.md` 与 `examples/assembly-drawing.aardio` |
| 连接/模板/选择/模态窗口/中断/保存问题 | `knowledge/recovery.md` |
| 函数签名、错误码、宏、反馈字段 | `lookup_library_reference("com.sldWorks")`；本机 `~/docs/library/com/sldWorks/{documents,modeling,features,feedback,properties,macros}.md` |
| 包自身三个辅助入口（preflight/observe/resolveTarget）的完整契约 | `lookup_library_reference("autos.skills.solidWorks")` |

示例通过 `loadcodex(文件路径,配置表)` 执行，均返回纯数据报告，输出总在 outputRoot 下新建唯一子目录。示例复用当前库的 `~/docs/library/com/sldWorks/{closed-loop,plate-with-hole}.aardio`，分发技能时必须保留该依赖。

模板由调用者提供，或使用经过校验的系统默认模板；**不扫描后随意猜选、不改全局首选项**。验证机的默认模板配置失效（指向旧 2023 路径），有效中文 2025 模板位于 `%ProgramData%\SOLIDWORKS\SOLIDWORKS 2025\templates`。这只是已知环境线索。

## 不要踩的坑

- 原生 nullable COM 对象参数用 `com.nothing()`，不是普通 null；库助手已自动处理。
- `AddDimension2` 在系统选项 swInputDimValOnCreate（编号 10）为 true 时弹对话框阻塞；先 `sw.SetUserPreferenceToggle(10,false)`，完成后恢复。
- `InsertSketch(true)` 是切换，不幂等；用 `NewSketch` 代替手工进出。`ISketch` 没有 `GetFeature()`，用 `sw.IsSame(feature.GetSpecificFeature2(),sketch)==1` 找回。
- `SetSystemValue3`/`SetDimension` 的状态码 **0 才是成功**；`ShowConfiguration2` 在目标配置已激活或不存在时都返回 false，用 `sw.ActivateConfiguration` 或以 `GetDocInfo().configuration` 回读为准。
- 特征对象绑定取得它时的活动配置：切换配置后旧 `IFeature.IsSuppressed()`/`SetSuppression2(swThisConfiguration)` 作用于旧配置；`IsSuppressed2(swSpecifyConfiguration,数组)` 按文档配置顺序返回而非传入顺序。用 `sw.SetFeatureSuppression/GetFeatureSuppression`（重新按名取特征、逐配置查询）。
- 线性阵列沿直线边的正方向 = 边的起点→终点，沿平面 = 法向；不要用 `suppressed ? 0 : 1` 之类的伪三元传 0（aardio 会落到 c），库内已修。
- 尺寸未按配置改过时（`IsAppliedToAllConfigurations()`），`GetSystemValue3(swAllConfiguration)` 除首槽位外全是 0、`swSpecifyConfiguration` 读非首配置也是 0，但几何正确；已按配置区分后 `swAllConfiguration` 按文档顺序、`swSpecifyConfiguration` 按传入顺序返回（与 `IsSuppressed2` 相反）。新配置复制**当前活动配置**的值；密度只反映活动配置。用 `GetConfigurationTable`/`SetDimension`（内部已处理），不要手写批量读取。
- 工程图先于隐藏加载的引用模型创建时 `InsertModelAnnotations3` 首次返回空；`InsertModelDimensions` 会激活引用模型重试，最稳妥是先 `OpenDoc(model,,,,false)` 再 `NewDoc(3,...)`。
- 材料名随安装语言本地化（中文库是 `1060 合金`）；SOLIDWORKS 对未知名静默忽略，`SetMaterial` 会回读并报错。
- aardio 中 `for i,face in body.GetFaces(){}` 会报 attempt to call；先赋值变量或写 `for i,face in (body.GetFaces()){}`。
- 工程图 `hasActiveSketch=true` 可能只是图纸草图；`editingSketch` 仅零件/装配体提供。
- `SaveAs` 会激活、清选择、可能覆盖已有文件；库 `CloseDoc(doc,discardChanges)` 默认拒绝丢弃未保存修改，原生 `QuitDoc` 会直接丢弃。不要 CloseAllDocuments/ExitApp 清场，用 `CloseNewDocs(snapshot)`。
- 不要把测试/临时文档留在会话里“供查看”，也不要用固定文件名反复另存：同名文档堆积会让 SOLIDWORKS 整个会话失去响应（实测 3 小时），届时只能由用户结束进程。
- `Create3rdAngleViews2(modelPath)` 要求模型已打开，否则返回 false；先 `OpenDoc(modelPath,,,,false)` 隐藏加载。
- 与圆角相切的边做倒角时，即使 `propagate=false`，去除体积仍约为解析值的 1.7 倍（延伸进过渡面）；验收用回读体积，不用公式。
- 文档标题含中文（如 `零件1`、`x - 图纸1`）时旧版 `FindDoc` 会误判为路径，已修复；仍建议已保存文档一律用完整路径定位。
- 模型 PNG 不含独立对话框、完整 UI，也不是屏幕→模型坐标转换。图像与几何矛盾时先查原生证据。
- API 未抛异常/宏返回 true/文件存在都不是验收。COM 忙或超时不表示写入没有发生；不自动重试，不强杀进程，不声称自动回滚。

## 离线 API 文档（文档子技能）

**只查文档时不连接 SOLIDWORKS，也不需要 preflight。** `help()` 首次缺少缓存时自动获取最新 Release；已有缓存直接离线使用。底层 `zlib.unzip` 直接读取 ZIP，配合本地 JSON 目录索引。

```aardio
import autos.skills.solidWorks.help;
var help,err = autos.skills.solidWorks.help();
if(!help) return {error=err};

// 已知 API 名称直接读；也接受 IFeatureManager::FeatureExtrusion3。
return help.read("IFeatureManager.FeatureExtrusion3");
```

- 不知道准确名称：`help.search("extrusion",{scope="examples";limit=5})` → `items[].path/title/snippet`；再把 `path` 传给 `help.read()`。默认按名称/路径查找，关键词忽略大小写，空格分词 AND，**不是正则**。
- 查用途、参数或枚举成员：`help.search("swDocPART",{scope="enums";fullText=true})`。全文查询扫描所选范围；`scope` 可为 `types/enums/examples/docs/index` 或 `types/IModelDoc2` 等目录。优先英文/API 关键词。
- `read()` 也接受类型名 `IModelDoc2`、枚举名 `swDocumentTypes_e`、简单 `[[Type::Member]]` 引用与精确文档路径；返回 `{text,path,title,release,truncated,nextStart}`，默认最多 16000 个 Unicode 字符。截断时 `help.read(path,{start=page.nextStart})` 续读。查询分页用 `offset=hits.nextOffset`。
- `help.info()` 返回缓存位置、包版本和篇数；默认缓存 `%LOCALAPPDATA%\aardio\autos\solidWorks\help`，可在构造参数中用 `{cacheDir=...}` 指定。各入口失败返回 `null,err`；无需关闭对象。
- 文档来自 `pedropaulovc/offline-solidworks-api-docs` 对 SOLIDWORKS API Help 的第三方离线整理，保留原签名、参数、备注及 VBA/C#/VB.NET 等示例，按已有语言知识翻译为 aardio；未收录不能作为 API 不存在的证据。`release` 是文档包版本，不是本机 SOLIDWORKS 版本；必要时再查官方 Help。
- 少数需要更新的情况调用 `help.update()`；强制重新下载最新包，失败保留旧缓存。完整契约：`lookup_library_reference("autos.skills.solidWorks.help")`。

