OCCT中的XCAF文档
前言occ中ShapeTShape是拓扑概念Geom和gp是底层几何概念这些是模型的基础部分。在此之上为了服务业务 OCCT 提供的一个通用的、底层的应用程序框架一般称之为“OCAF”。它提供了一套更高维度的功能层它并没有取代Shape而是围绕Shape构建了一个完整的数据管理框架。OCAF管理的粒度是DocumentTDF一个文档中最核心的概念是“标签树”通过标签Lable与拓扑几何Shape关联并在此基础上提供属性系统、Undo/Redo、装配与引用管理、文档管理与数据持久化等功能。换言之occt希望上层应用直接基于OCAF框架开发业务功能不要直接自行管理维护Shape。OCAF、XCAF、DE和XDE等概念OCAF即Open CASCADE Application FrameworkXCAF 即Extended Application Framework是OCAF的特定扩展专门用于处理装配结构DEData Exchange Wrapper各自CAD格式数据交换包装器XDE即Extended DataExchange扩展的数据交换模型将交换的对象由Shape模型扩展到XCAF文档总结来说OCAF是一套框架提供通用的标签树和属性挂载机制而XCAF是这套框架的一个可直接使用的实例化工具一种文档类型提供现成的工具类如 ShapeTool, ColorTool简化了使用流程专门用于处理 CAD 领域中最核心的装配体Assembly、零件Part、颜色Color、材质Material和层Layer等复杂业务场景。DE是一个导入/导出的工具包提供了Shape与各种文件格式的转换接口而XDE则是提供了XCAF文档与各种文件格式的转换接口。所以应用程序要使用OCAF这套框架首选直接应用XCAF。OCAF的标签属性树标签Label与属性Attribute标签TDF_Label标签是标签树中的节点它本身不直接存储具体的业务数据而是作为一个“锚点”或“容器”提供上下导航、属性增删改查的能力属性TDF_Attribute属性是附着在标签上的具体数据一个标签上可以挂载多个不同类型的属性例如名称、颜色、几何形状等在OCAF的概念中Shape只是Label的属性之一层级结构与定位一个树有唯一的根节点Label每个节点有唯一的父节点和若干个的子节点和若干个兄弟节点。每个节点有两种标识方式一种是相对标识称之为Tag它的实质是一个整数但它只在特定的父标签范围内有意义换句话说Tag只是兄弟间的排序编号另一种是绝对标识称之为Entry是一个从根节点出发的Tag路径列表形式是一个字符串例如“0:1:5:2”一般根节点的Entry固定为“0:1”。Entry在整个文档中是绝对唯一的因为可以与Label对象互相转换。TDF_Label接口Tag()返回当前标签的整数标识符Tag。 Father()返回当前标签的父标签。如果是根标签则返回空NullIsRoot()判断当前标签是否为根标签。 NewChild()在当前标签下创建一个新的子标签并返回。FindChild(tag,create)根据指定的 Tag 查找子标签。如果 create 设为 Standard_True且该子标签不存在则会自动创建它。AddAttribute(attribute)将一个属性附加到当前标签上。如果该标签上已经存在相同类型的属性通常会抛出异常。FindAttribute(guid, attribute)根据属性的唯一标识符GUID在当前标签上查找特定类型的属性。ForgetAttribute(attribute / guid)从当前标签上移除指定的属性。ForgetAllAttributes(clearChildren)移除当前标签上的所有属性。如果 clearChildren 为True还会递归清除所有子标签的属性。IsAttribute(guid)检查当前标签上是否已经挂载了某种特定类型的属性。TDF_Attribute属性对象TDF_Attribute是所有属性的接口基类。在OCAF的属性体系中每一种属性类型TDF_Attribute的具体类需要有一个唯一的GUID作为标识OCAF以此区分不同属性类型并且一个Label上不同同时挂载相同GUID的多个属性对象。常用的派生类有DataStd_Integer存储整数TDataStd_Real存储浮点数TDataStd_Boolean存储布尔值TDataStd_Name和TDataStd_AsciiString存储字符串/名称TDataStd_RealArray和TDataStd_IntegerArray存储一维数组构建标签树示例voidBuildBoxLabelTree(constTDF_LabelparentLabel,TopoDS_Shape boxShape){// . 为整个 Box 创建标签并附加属性TDF_Label boxLabelparentLabel.NewChild();// 设置 Box 的类型属性 (整数 1)TDataStd_Integer::Set(boxLabel,1);// 设置 Box 的名称属性TDataStd_Name::Set(boxLabel,SOLID);// 将 Box 形状绑定到该标签TNaming_BuilderboxBuilderOcaf(boxLabel);boxBuilderOcaf.Generated(boxShape);// . 遍历 Box 下的所有面 (Face)并为每个面创建子标签TopExp_ExplorerfaceExplorer(boxShape,TopAbs_FACE);while(faceExplorer.More()){TopoDS_Shape currentFacefaceExplorer.Current();// 为当前 Face 创建一个新的子标签TDF_Label faceLabelboxLabel.NewChild();// 设置 Face 的类型属性 (整数 1)TDataStd_Integer::Set(faceLabel,1);// 设置 Face 的名称属性为形状的类型名称TDataStd_Name::Set(faceLabel,FACE);// 将 Face 形状绑定到该标签TNaming_BuilderfaceBuilderOcaf(faceLabel);faceBuilderOcaf.Generated(currentFace);faceExplorer.Next();}}TDocStd_Document文档体系文档标准类数据成员核心数据是持有的TDF_Data 对象它是一个储存容器其存储的对象是一个树形结构即所谓的TDF_Label树。功能接口访问底层标签树数据Main()返回文档的根标签Root Label固定入口为 0:1GetData() / SetData()用于访问或设置底层的 TDF_Data 对象事务与撤销/重做NewCommand() / OpenCommand()开启一个新的事务TransactionCommitCommand()提交当前事务。将事务期间的所有变更打包成一个不可变的 TDF_Delta变更集并压入撤销栈Undo Stack。AbortCommand()中止当前事务。放弃本次事务中记录的所有修改Undo() / Redo()执行撤销或重做操作。框架会基于 TDF_Delta 记录的信息回退或重放数据变更持久化与状态管理StorageFormat()返回当前文档的存储格式标识如 “BinXCAF” 或 “BinOCAF”IsSaved() / SetSaved()标记或检查文档是否已经成功保存到文件中IsChanged()检查文档自上次保存后是否有未提交的修改文档类型默认提供两种类型XmlXCAF和BinXCAF只是存储的格式不同实质内容并无差异创建与管理文档对象必须通过 TDocStd_Application的NewDocument创建并由其管理双方可互相索引TDocStd_Application代表的便是OCAF框架进程中可以new多个但一般将其视为单例使用直接通过XCAFApp_Application::GetApplication获取全局单例对象子类化TDocStd_Document允许应用程序子类化并且并不强制要求子类化必须重载哪些接口因为所有接口标准类都已有实现子类化主要是为了将底层的标签操作Label-Attribute 操作封装为符合你业务逻辑的高级 API。例如子类化一个MyCADDocument对象提供createBox接口接口内部直接创建出Shape并连带着name一起挂载到Label节点上。如此一来前端应用的开发只需围绕着MyCADDocument对象开展即可。作者对子类化并无实践经验所以此处不做过多介绍了~XCAF文档构建前文提到过XCAF是OCAF具体的应用工具提供了现成的工具类可以简化标签树的增删改查工具。XCAFDoc工具XCAFDoc_DocumentTool是一个工具类管理器作为一个门面Facade它通过静态函数方式对外提供具体的工具类这些接口都要求传入主LabelShapeTool(acces)获取 XCAFDoc_ShapeTool 句柄用于管理形状和装配体结构。ColorTool(acces)获取 XCAFDoc_ColorTool 句柄用于管理模型及子模型的颜色属性。NotesTool(acces)获取 XCAFDoc_NotesTool句柄用于为模型添加和管理自定义注释如文本评论或二进制数据。其他工具还包括LayerTool图层、MaterialTool材料、DimTolToolGDT 尺寸公差、ViewTool视图等。XCAFDoc_ShapeTool它是最核心的工具负责管理模型和装配结构这是后续正确XDE的基础。形状、组件与装配体形状即Shape代表一个独立的几何体。组件Component它是对某个 Shape 的引用是在Shape的基础上叠加一个位置变换矩阵也就意味着同一个 Shape 可以被实例化多次放置在不同的位置。装配体Assembly是XCAF的底层对象概念由多个 Component 组成的层级结构同时它可以嵌套使用即一个Assembly可以是另一个Assembly的组成部分。位置变换管理每个Label可以关联一个变换矩阵但是注意Shape本身也可以有一个变换矩阵它们之间并不冲突而是叠加应用的关系。SetLocation(TDF_Label compLabel, gp_Trsf location)设置某个组件相对于其父装配体的位置变换矩阵。GetLocation(TDF_Label compLabel)获取组件的位置变换。接口介绍按照其核心职责将其分为六大类形状与装配体创建、组件与引用管理、形状与标签查询、拓扑子形状管理、属性与状态检查、以及文档清理与维护。1. 形状与装配体的创建NewShape()创建一个新的空形状标签不包含几何体通常用于手动构建装配体节点。AddShape(const TopoDS_Shape S, Standard_Boolean makeAssembly, Standard_Boolean makePrepare)向文档中添加一个顶层形状并返回其标签。makeAssembly若为 True 且形状是 TopAbs_COMPOUND则递归解析内部结构创建装配体若为 False则视为单一实体。makePrepare若为 True自动为无位置的组件添加默认单位变换确保装配结构完整。注意如果该形状已存在于文档中可能会返回现有标签而非新建。AddShape(const TopoDS_Shape S)AddShape 的简化重载默认 makeAssemblyTrue, makePrepareTrue。2. 组件与引用管理 (装配体核心)AddComponent(TDF_Label assembly, TDF_Label comp)将一个已存在的形状标签作为组件添加到指定的装配体标签下AddComponent(TDF_Label assembly, TopoDS_Shape comp)将形状作为组件添加到装配体下如果形状不在文档中会自动添加。AddComponent(TDF_Label assembly, TopoDS_Shape comp, TopLoc_Location loc)添加组件并指定其相对于父装配体的位置变换矩阵。SetLocation(TDF_Label comp, TopLoc_Location loc)设置或更新组件的位置变换。GetLocation(TDF_Label comp)获取组件的位置变换。IsReference(TDF_Label label)判断某个标签是否是一个组件引用Instance。GetReferredShape(TDF_Label label, TDF_Label ref)获取组件引用所指向的实际形状定义标签。3. 形状与标签的查询与提取GetShape(TDF_Label label, TopoDS_Shape shape)根据标签获取对应的几何形状会自动应用位置变换。GetShape(TDF_Label label)直接返回标签对应的形状。FindShape(const TopoDS_Shape S, TDF_Label label)反向查找根据形状找到文档中对应的标签。FindShape(const TopoDS_Shape S)反向查找的简化版直接返回标签。GetFreeShapes(TDF_LabelSequence labels)获取文档中所有的“自由形状”顶层形状或顶层装配体不属于其他装配体的组件GetComponents(TDF_Label label, TDF_LabelSequence comps)获取某个装配体标签下的所有组件引用标签。GetUsers(TDF_Label label, TDF_LabelSequence users)获取所有引用了该形状的组件标签即查找该形状在哪些装配体中被使用了。4. 拓扑子形状管理 (Sub-shapes)AddSubShape(TDF_Label shapeLabel, TopoDS_Shape sub)将形状的子拓扑元素如Face, Edge作为子标签添加到形状标签下FindSubShape(TDF_Label shapeLabel, TopoDS_Shape sub, TDF_Label subLabel)在指定的形状标签下查找子拓扑元素对应的标签GetSubShapes(TDF_Label shapeLabel, TDF_LabelSequence subs)获取形状标签下所有的子形状标签。5. 属性与状态检查IsShape(TDF_Label label)检查标签是否包含形状属性。IsFree(TDF_Label label)检查形状标签是否为自由形状不在任何装配体下。IsAssembly(TDF_Label label)检查标签是否代表一个装配体包含组件。IsSimpleShape(TDF_Label label)检查标签是否代表一个简单形状非装配体、非复合体。IsCompound(TDF_Label label)检查标签是否为复合体。IsTopLevel(TDF_Label label)检查标签是否为顶层形状。IsSubShape(TDF_Label label)检查标签是否为子拓扑形状。IsComponent(TDF_Label label)检查标签是否为组件引用。GetShapeType(TDF_Label label)获取形状的类型枚举如TopAbs_SOLID, TopAbs_FACE 等。6. 文档清理与维护RemoveShape(TDF_Label label, Standard_Boolean removeCompletely)从文档中移除形状。如果 removeCompletely 为True则彻底删除标签及其所有属性若为 False仅移除形状属性保留其他业务属性。RemoveComponent(TDF_Label comp)从装配体中移除一个组件引用。UpdateAssemblies()更新文档中所有装配体的状态清理无效的引用。装配思路需求一个Shape存盘为step/xml加载后能恢复Shape1.遇到一个Compound或者CompSolid对象就NewShape创建一个Assembly节点然后对其内部的每个Shape递归XCAF文档读写核心步骤可以理解为三步注册驱动、准备文档、执行读写。导出xml格式// 1. 获取 XDE 应用程序实例并注册 XML 驱动Handle(XCAFApp_Application)appXCAFApp_Application::GetApplication();XmlXCAFDrivers::DefineFormat(app);// 注册 XmlXCAF 格式// 2. 创建一个新的 XCAF 文档指定格式为 XmlXCAFHandle(TDocStd_Document)doc;app-NewDocument(XmlXCAF,doc);// 3. 向文档中添加数据例如一个带颜色和名称的 Box// 获取 Shape 工具Handle(XCAFDoc_ShapeTool)shapeToolXCAFDoc_DocumentTool::ShapeTool(doc-Main());// 4. 保存文档到 XML 文件PCDM_StoreStatus statusapp-SaveAs(doc,my_xcaf_document.xml);if(statusPCDM_SS_OK){std::cout文档成功保存到 my_xcaf_document.xmlstd::endl;}else{std::cout文档保存失败状态码statusstd::endl;}导入xml文件// 1. 获取 XDE 应用程序实例并注册 XML 驱动Handle(XCAFApp_Application)appXCAFApp_Application::GetApplication();XmlXCAFDrivers::DefineFormat(app);// 2. 创建一个空的文档对象用于接收读取的数据// 注意XCAFApp_Application::Open 方法会创建并返回新文档所以这里创建一个空句柄即可Handle(TDocStd_Document)doc;// 3. 从 XML 文件加载数据到文档PCDM_ReaderStatus statusapp-Open(my_xcaf_document.xml,doc);if(status!PCDM_RS_OK){std::cout文档加载失败状态码statusstd::endl;return;}std::cout文档加载成功std::endl;// 4. 访问并读取文档中的数据Handle(XCAFDoc_ShapeTool)shapeToolXCAFDoc_DocumentTool::ShapeTool(doc-Main());Handle(XCAFDoc_ColorTool)colorToolXCAFDoc_DocumentTool::ColorTool(doc-Main());// 获取文档中所有独立的形状 (Free Shapes)TDF_LabelSequence freeShapes;shapeTool-GetFreeShapes(freeShapes);xbf格式xbf与xml相比只需要注册对应的驱动器即可Handle(XCAFApp_Application)appXCAFApp_Application::GetApplication();BinXCAFDrivers::DefineFormat(app);// 注册 BinXCAF 格式step格式step格式不是XCAF原生的格式所以BinXCAF 格式和“XmlXCAF”均可需要借助STEP 读写器STEPCAFControl_Writer和STEPCAFControl_Reader// // 将形状导出为 STEP 文件// // 导出前创建 XCAF 文档用于承载形状和附加数据Handle(XCAFApp_Application)appXCAFApp_Application::GetApplication();Handle(TDocStd_Document)doc;app-NewDocument(BinXCAF,doc);//BinXCAF 格式和“XmlXCAF”均可// 将形状添加到 XCAF 文档中Handle(XCAFDoc_ShapeTool)shapeToolXCAFDoc_DocumentTool::ShapeTool(doc-Main());TDF_Label shapeLabelshapeTool-AddShape(originalShape);// 创建 STEP 写入器STEPCAFControl_Writer writer;// 将 XCAF 文档写入 STEPwriter.Transfer(doc,STEPControl_AsIs);// 保存到文件IFSelect_ReturnStatus statuswriter.Write(box_output.stp);// // 从 STEP 文件读取形状// // 创建新的 XCAF 文档用于读取Handle(TDocStd_Document)readDoc;app-NewDocument(BinXCAF,readDoc);//BinXCAF 格式和“XmlXCAF”均可// 创建 STEP 读取器STEPCAFControl_Reader reader;// 读取文件IFSelect_ReturnStatus readStatusreader.ReadFile(box_output.stp);// 将文件内容传输到 XCAF 文档booltransferSuccessreader.Transfer(readDoc);DE_Wrapper统一形式DE_Wrapper 是 OCCT 7.7.0 版本后引入的统一数据交换接口它封装了各类格式的底层读写器让你能够用几乎相同的代码读写 STEP、IGES、STL、OBJ 等多种 CAD 文件格式。它通过自动识别文件扩展名来匹配合适的读写驱动而你只需要调用 Read() 和 Write() 这两个方法传入文件路径和要操作的数据容器即可。它同时支持两种数据载体TopoDS_Shape和XCAF文档。// 获取全局 DE_Wrapper 实例Handle(DE_Wrapper)aSessionDE_Wrapper::GlobalWrapper();// 假设已有形状 myShapeTopoDS_Shape myShape...;TCollection_AsciiStringaPath(output.stp);if(!aSession-Write(aPath,myShape)){// 写入失败处理}Handle(DE_Wrapper)aSessionDE_Wrapper::GlobalWrapper();// 创建一个空的 XCAF 文档用于存放读取的数据Handle(XCAFApp_Application)anAppXCAFApp_Application::GetApplication();Handle(TDocStd_Document)aDoc;anApp-NewDocument(BinXCAF,aDoc);TCollection_AsciiStringaPath(model.stp);if(!aSession-Read(aPath,aDoc)){// 读取失败处理}