一、痛点引入
整机装配做完,工艺评审前领导扔过来一份评审清单:"这份装配里有几条约束、分别是什么类型?有没有失效的、破损的、被 Deactivate 暂存的?把明细整理成 Excel 给我。"
你打开模型树,找到"约束"节点——300 多个 Constraint,看得头皮发麻。CATIA 的对话框能让你点开单条查属性,但要"全装配盘点 + 分类统计",就得手动逐条记录:
- 接触约束有几条?距离/角度/固定各几条?
- 这条 Constraint.45 状态是 OK 还是 Broken?
- 那几条被我 Deactivate 暂存的,怎么标记?
- 装配里换了零件,原来几条约束的连接是不是还正常?
300 多条手工整理大半天,工艺等半天就被催。这是 CATIA 装配功能在"汇总"维度上设计不足的真实场景——它把每条约束都藏在了"约束"节点下,工具是给人"看"的,不是给人"汇总导出"的。
今天教你用 Python COM API,一键遍历全装配所有约束、按类型/状态/值分列、统计破损与 Deactivate 数量、导出 CSV——30 秒出评审报告。
二、核心思路
CATIA 装配的约束集合挂在根 Product 下,通过 Connections("CATIAConstraints") 取到。集合支持 1-based 索引遍历,每个 Constraint 对象带类型 Type、状态 Status、约束值 Dimension.Value、是否暂存 IsInactive() 等属性。集合级还有两个便利计数器:BrokenConstraintsCount 直接给出破损约束数、UnUpdatedConstraintsCount 给出未更新约束数。
Python脚本 COM接口 CATIA装配文档
├─ doc.Product 取根产品
├─ root.Connections("CATIAConstraints") 取约束集合
├─ cs.Count / cs.BrokenConstraintsCount 快速总览
├─ for i in range(1, cs.Count+1):
│ c = cs.Item(i)
│ ├─ c.Type 类型枚举(0固定/1距离/2相合/6角度/20接触…)
│ ├─ c.Status 状态枚举(0OK/1强不满足/3值错误/5破损)
│ ├─ c.Dimension.Value 距离值/角度值(破损/相切时无意义)
│ └─ c.IsInactive() 是否Deactivate暂存
└─ CSV DictWriter 写出约束评审报告你需要准备:
- Python 3.7+、
pywin32 - CATIA V5 已打开目标装配文档(.CATProduct),装配至少下挂一组约束
三、环境搭建(2分钟)
pip install pywin32验证当前装配能取到约束集合:
import win32com.client
catia = win32com.client.Dispatch("CATIA.Application")
root = catia.ActiveDocument.Product
cs = root.Connections("CATIAConstraints") # 装配约束集合
print(f"装配: {root.Name}")
print(f"约束总数: {cs.Count}")
print(f"破损约束数: {cs.BrokenConstraintsCount}")
print(f"未更新约束数: {cs.UnUpdatedConstraintsCount}")
print("约束接口可用,连接成功。")能打印出约束总数和破损数,说明装配接口已就绪;如果集合为空说明当前装配没建约束,不影响后续逻辑。
四、核心代码
下面分四步:连 CATIA 取集合 枚举映射 遍历约束 写出 CSV 评审清单。
import win32com.client
import csv
# ========== 第1步:连接CATIA,取装配约束集合 ==========
catia = win32com.client.Dispatch("CATIA.Application")
root = catia.ActiveDocument.Product
cs = root.Connections("CATIAConstraints")
# ========== 第2步:枚举映射 ==========
# pywin32拿不到catCstTypeReference等可读名,直接用整数映射最稳
# CatConstraintType 枚举:装配设计常用值
TYPE_MAP = {
0: "固定", # catCstTypeReference
1: "距离/偏移", # catCstTypeDistance
2: "相合", # catCstTypeOn
3: "同心", # catCstTypeConcentricity
4: "相切", # catCstTypeTangency
6: "角度", # catCstTypeAngle
8: "平行", # catCstTypeParallelism
11: "垂直", # catCstTypePerpendicularity
15: "对称", # catCstTypeSymmetry
20: "面接触", # catCstTypeSurfContact
21: "线接触", # catCstTypeLinContact
22: "点接触", # catCstTypePoncContact
25: "环面接触", # catCstTypeAnnulContact
}
# CatConstraintStatus 枚举:状态码
# 0=OK / 1=强不满足 / 2=方向错误 / 3=值错误 / 4=元素类型错误 / 5=破损
STATUS_MAP = {
0: "OK", 1: "强不满足", 2: "方向错误",
3: "值错误", 4: "元素类型错误", 5: "破损",
}
# ========== 第3步:遍历约束、按维度汇总 ==========
rows = []
broken_count = 0
deactivate_count = 0
for i in range(1, cs.Count + 1): # 集合是1-based索引
c = cs.Item(i)
# 类型/状态:返回枚举整数,需int()强转
ctype = TYPE_MAP.get(int(c.Type), f"类型{int(c.Type)}")
status = STATUS_MAP.get(int(c.Status), f"状态{int(c.Status)}")
# 约束值:固定/接触/相切等无意义的Type不能读Dimension
val = ""
try:
# 仅1=距离、6/7=角度这几种带数值含义的约束能取Dimension.Value
if int(c.Type) in (1, 6, 7):
val = round(c.Dimension.Value, 4)
except Exception:
val = "" # 破损或Deactivate时Dimension可能取不到
# 是否被Deactivate暂存
is_inactive = c.IsInactive() # 是方法、带括号,不是属性
if int(c.Status) == 5:
broken_count += 1
if is_inactive:
deactivate_count += 1
rows.append({
"序号": i,
"约束名": c.Name,
"类型": ctype,
"状态": status,
"值": val,
"暂存": "是" if is_inactive else "否",
})
# ========== 第4步:写出CSV评审清单 ==========
out_path = "约束评审清单.csv"
with open(out_path, "w", newline="", encoding="utf-8-sig") as f:
writer = csv.DictWriter(
f, fieldnames=["序号", "约束名", "类型", "状态", "值", "暂存"]
)
writer.writeheader()
writer.writerows(rows)
print(f"约束总数: {cs.Count}")
print(f"破损约束: {broken_count} 条 | 暂存(Deactivate): {deactivate_count} 条")
print(f"报告已导出: {out_path}")代码解析:
root.Connections("CATIAConstraints")取装配约束集合;字符串"CATIAConstraints"不可拼错,大小写要严格保持(部分版本可用全小写,但首字母大写最稳)c.Type/c.Status枚举整数,pywin32 拿不到catCstTypeReference/catCstStatusOK这样的可读名字(除非 makepy 早绑定类型库),手动维护一份映射最简单也最稳c.Dimension.Value只有"距离"(1)、"角度"(6/7)等带值的约束类型才有意义;固定/接触/相切等类型读 Dimension 会抛异常,必须 try/except 兜底c.IsInactive()True 表示被 Deactivate 暂存不参与计算、False 表示生效;调用时必须带括号(是方法不是属性),写成c.IsInactive会拿到 COM 方法对象本身、布尔判断永远为 Truecs.BrokenConstraintsCount/cs.UnUpdatedConstraintsCount集合级计数器,零成本快速盘点破损与未更新约束数,比循环里逐个加 1 更快
五、效果对比
| 对比项 | 传统方法 | 自动化脚本 |
|---|---|---|
| 盘点300+约束 | 半天逐条点 | 30秒全出 |
| 类型/状态统计 | Excel 手工分类 | 自动分类+计数 |
| 破损清单 | 找约束节点肉眼挑 | 状态码 = "破损" 列表筛选 |
| Deactivate 暂存 | 节点名前找括号 | 单独"暂存"列标识 |
| 重复使用 | 每次重复劳动 | 改完重跑同一脚本 |
| 报告交付 | 截图发群 | 标准 CSV 给工艺 |
六、进阶用法
技巧1:批量 Deactivate / Activate,临时释放约束
大型装配里要快速重定位组件时,常用"先全部 Deactivate 距离约束 拖到新位置 再 Activate"的工作流。脚本里就能批量做,再也不用手点几十下:
# 例:把所有"距离(1)/相合(2)/相切(4)"约束批量 Deactivate 暂存
TARGET_TYPES = {1, 2, 4}
n_off = 0
for i in range(1, cs.Count + 1):
c = cs.Item(i)
if int(c.Type) in TARGET_TYPES and not c.IsInactive():
c.Deactivate()
n_off += 1
root.Update()
print(f"已 Deactivate {n_off} 条目标约束")
# 重定位结束后,可以照同样逻辑改 c.Activate() 重新启用技巧2:递归扫所有 Product 节点,找"哪段装配破损最多"
整机装配层级深时,约束既可能在根产品,也可能在子产品装配里。要递归汇总每一层的约束状况,做整体状态盘点:
def collect_all_constraints(product, report=None):
if report is None:
report = []
cs = product.Connections("CATIAConstraints")
report.append((product.Name, cs.Count, cs.BrokenConstraintsCount))
for j in range(1, product.Products.Count + 1):
sub = product.Products.Item(j)
collect_all_constraints(sub, report)
report = []
collect_all_constraints(root, report)
for name, total, broken in report:
print(f"{name}: 约束{total}条,破损{broken}条")这一招在做大型装配状态评审时尤其有用——一眼看到"机身段装配破损 0,站位段破损 7",下一步就知道该往哪段装配里下钻去修。
关注回复「约束清单」获取完整源码 + CSV 报告模板
_栏目:开发实战 | 发布日期:2026-08-29 | 字数:约 1180 字 | 系列:CATIA Python COM API 入门 #10_