CATIA 数据交换 STEP / IGES / JT / 3D PDF:批量导入导出实战

琛兴科技 · CATIA 二次开发系列 · 适用 V5R19~R32

一、原理:CATIA 的两套导入导出通道

CATIA 对外格式互通走两条通道,混着用最容易踩坑:

通道API支持的格式语义
原生 Export/ImportCATDocument::ExportSTEP / IGES / STL / CGR / VRML把当前文档另存为外部格式
Doc ServiceCATDocumentServices::OpenDocumentSTEP / IGES(自动转 CATPart)把外部格式作为新文档打开

另外还有 V5 自带或选购的转换器:DELMIA→JT、SolidWorks/Inventor 直读插件、3D PDF 发布器,调用方式各不相同。本文以工业最常用的 STEP / IGES / 3D PDF 为主,覆盖批量导入导出。

STEP(ISO 10303)有 AP203 / AP214 / AP242 三个常见 Application Protocol:AP203 只有几何 + 装配;AP214 加了汽车行业属性(颜色、属性、配置);AP242 是新一代,支持 PMI 语义。BIW 行业默认 AP214;含 PMI 的工艺图发新供应商用 AP242。

二、流程:批量导入导出 5 步

  1. 设置 Export Settings:通过 CATIA::SystemConfiguration::Settings::STEP 改 AP 级别、单位、写入精度。CAA 里通过 CATXMLDataServices 写到 setting 文件。
  2. 打开源文档CATDocumentServices::OpenDocument 加载 .CATPart / .CATProduct。
  3. 调用 ExportpDoc->Export(outPath, "step"),第二参用小写格式标识。
  4. 处理失败和警告:Export 返回 HRESULT,但具体警告(哪些面没导出)写在 .err / .log 文件里,必须读。
  5. 导入相反OpenDocument(stpPath, pDoc) 自动新建 CATPart 容器。导入完后必须 SaveAs 否则不保留。

三、避坑:数据交换七大坑

坑 1:单位不一致 → 模型变小或变大 1000 倍
CATIA 内部 SI(米);STEP 默认 mm;IGES 默认 inch。SetExportUnit("MM") 或在源 Part Settings 里固定。批量自动化里务必显式写。
坑 2:导出 PMI 默认关闭
AP242 想带 3D 标注必须 SetExportPMI(TRUE),否则只导几何。下游验厂时找不到工艺信息现场扯皮。
坑 3:装配体导出 STEP 后丢失约束
STEP 不支持 CATIA 的约束语义,只保留每个零件的位置矩阵。下游打开后拖动零件不会受约束保护。
坑 4:IGES 导出曲线类型自动降级
NURBS 7 阶以上的曲线 IGES 标准不支持,导出时静默降到 3 阶 + 加密控制点。精度从 0.001mm 退化到 0.05mm 是常事。
坑 5:批量导入 STEP 时 OpenDocument 串行慢
单线程 1 个/几秒。要并行得开多个 process(Session 不能并行打开 Doc)。
坑 6:Export 后 Doc 还在内存 = 内存泄漏
Export 不会自动 close,必须 CATDocumentServices::Remove。批量 1000 个零件不释放就 OOM。
坑 7:3D PDF 发布需要 PRC 模板
没有 PRC 模板(Adobe 出的样式文件)默认只导个静态截图,没有可旋转 3D。模板路径在 Settings::PDF。
实战建议:跨企业数据交换走 STEP AP242 + 3D PDF 双发布——前者给 CAD 软件互通(含 PMI),后者给非 CAD 用户(采购、销售、现场审核)。一份 .CATPart 同时输出两份,既精确又通用。

四、完整代码:批量目录 STEP 互转

// BatchStepConvert.cpp
// 模式 1:CATPart → STEP(递归遍历目录)
// 模式 2:STEP → CATPart

#include "CATDocumentServices.h"
#include "CATDocument.h"
#include "CATUnicodeString.h"
#include <filesystem>
namespace fs = std::filesystem;

HRESULT ExportPartToStep(
    const CATUnicodeString& partPath,
    const CATUnicodeString& stpPath)
{
    HRESULT rc = S_OK;
    CATDocument* pDoc = NULL;
    rc = CATDocumentServices::OpenDocument(partPath, pDoc);
    if (FAILED(rc) || !pDoc) return rc;

    // 设置 STEP 选项(AP214 / mm / 不带 PMI)
    SetExportSetting("STEP", "AP", "214");
    SetExportSetting("STEP", "Unit", "MM");
    SetExportSetting("STEP", "Tolerance", "0.001");

    rc = pDoc->Export(stpPath, "step");
    CATDocumentServices::Remove(*pDoc);
    return rc;
}

HRESULT ImportStepToPart(
    const CATUnicodeString& stpPath,
    const CATUnicodeString& partPath)
{
    HRESULT rc = S_OK;
    CATDocument* pDoc = NULL;
    rc = CATDocumentServices::OpenDocument(stpPath, pDoc);
    if (FAILED(rc) || !pDoc) return rc;

    rc = CATDocumentServices::SaveAs(*pDoc, partPath);
    CATDocumentServices::Remove(*pDoc);
    return rc;
}

HRESULT BatchDir(
    const std::string& rootDir,
    const std::string& outDir,
    bool toStep)
{
    fs::create_directories(outDir);
    int ok=0, fail=0;
    for (auto& e : fs::recursive_directory_iterator(rootDir)) {
        if (!e.is_regular_file()) continue;
        std::string ext = e.path().extension().string();
        if (toStep && ext != ".CATPart") continue;
        if (!toStep && ext != ".stp" && ext != ".step") continue;

        fs::path outPath = fs::path(outDir) / e.path().stem();
        outPath += toStep ? ".stp" : ".CATPart";

        HRESULT rc = toStep
            ? ExportPartToStep(e.path().string().c_str(),
                               outPath.string().c_str())
            : ImportStepToPart(e.path().string().c_str(),
                               outPath.string().c_str());
        SUCCEEDED(rc) ? ++ok : ++fail;

        // 每 100 个 GC 一次防内存胀
        if ((ok+fail) % 100 == 0) {
            CATDocumentServices::CloseAllDocuments();
        }
    }
    cout << "OK=" << ok << " FAIL=" << fail << "\n";
    return S_OK;
}

© 上海琛兴科技发展有限公司 · 转载请注明出处 · CATIA 是 Dassault Systèmes 注册商标