ACIS SAT 文件格式详解及其解析

📅 2026/6/30 2:44:59
ACIS SAT 文件格式详解及其解析
是 SAT 文件ACIS SATStandard ACIS Text文件是由 Spatial 公司开发的 ACIS 几何建模内核使用的标准文件格式。它是一种文本格式用于存储三维几何模型的边界表示B-Rep数据包括几何信息点、线、面、体等几何实体的数学定义拓扑信息顶点、边、环、面、壳等拓扑实体及其连接关系属性信息颜色、名称、图层等附加属性NURBS 支持完整的 NURBS非均匀有理 B 样条曲线和曲面表示SAT 文件的特点文本格式人可读便于调试和分析版本号标识文件开头明确标注 ACIS 版本实体编号系统每个实体有唯一的 ID 和引用计数前向引用支持实体间的相互引用灵活的扩展性支持自定义属性和扩展字段文件结构与版本文件头格式ACIS 100 ACIS Verifier status: 0ACIS固定标识符100主版本号如 700 表示 v7.03300 表示 v33.0ACIS Verifier status: 0验证状态实体记录格式每个实体记录遵循以下格式count entity-type ref1 ref2 ... data-fields { nested-data }示例-40 intcurve-curve $-1 -1 -1 $-1 forward { exactcur 6 full nurbs 3 open 2 ... }字段说明-40实体编号负数表示引用计数intcurve-curve实体类型相交曲线$-1 -1 -1 $-1前置引用$ 表示向前引用forward方向标志{ ... }嵌套数据块主要实体类型几何实体point- 点straight-curve- 直线circle-curve- 圆ellipse-curve- 椭圆intcurve-curve- 参数曲线含 NURBSplane-surface- 平面cylinder-surface- 圆柱面cone-surface- 圆锥面exactsur- 精确曲面含 NURBS拓扑实体vertex- 顶点edge- 边coedge- 协同边有向边loop- 环face- 面shell- 壳lump- 体块body- 实体核心解析类设计类图概览读取数据创建实例管理所有实体使用流解析SATInputStreamstd::istream streamsize_t lineNumberpeekToken() : StringnextToken() : StringreadInt() : intreadDouble() : doublereadString() : StringreadEntityRef() : intreadFlagsUntilNumber() : ListStringstatic IsNumber(token) : boolstatic hasFlag(flags, flag) : boolSATEntity#int m_satId#int m_refCount#SATEntityType m_typegetSatId() : intgetRefCount() : intgetType() : SATEntityTypevirtual Import(stm) : voidvirtual ResolvePointers() : voidSATFactorystatic createEntity(type, id) : SATEntitystatic registerType(type, factory) : voidSATGeometryvirtual GetCurve() : Geom_Curvevirtual GetSurface() : Geom_SurfaceSATPoint-double m_x, m_y, m_zImport(stm) : voidGetPoint() : gp_PntSATCurve#Handle(Geom_Curve) : m_curveGetCurve() : Geom_CurveSATIntersectionCurve-int m_degree-bool m_isRational-Listdouble m_knots-Listint m_multiplicities-Listgp_Pnt m_controlPoints-Listdouble m_weightsImport(stm) : voidbuildBSplineCurve() : voidSATSurface#Handle(Geom_Surface) : m_surfaceGetSurface() : Geom_SurfaceSATExactSurface-int m_uDegree, m_vDegree-bool m_isRational-ListList~gp_Pnt m_controlPoints-ListList~double m_weightsImport(stm) : voidbuildBSplineSurface() : voidSATTopologyTopoDS_Shape GetShape()SATVertex-SATPoint* m_pointResolvePointers() : voidGetShape() : TopoDS_VertexSATEdge-SATCurve* m_curve-SATVertex* m_start, *m_endResolvePointers() : voidGetShape() : TopoDS_EdgeSATFace-SATSurface* m_surface-ListSATLoop m_loopsResolvePointers() : voidGetShape() : TopoDS_FaceSATFile-String filename-Mapint, SATEntity entities-Load() : bool-BuildTopology() : TopoDS_Shape-ExportBREP(shape, file) : bool核心类详解1. SATInputStream - 流式解析器职责提供 token 级别的流式读取功能关键方法class SATInputStream { public: std::string peekToken(); // 预读下一个 token不消耗 std::string nextToken(); // 读取并消耗下一个 token int readInt(); // 读取整数 double readDouble(); // 读取浮点数 std::string readString(); // 读取字符串 int readEntityRef(); // 读取实体引用跳过 $ 标记 std::vectorstd::string readFlagsUntilNumber(); // 读取标志直到数字 static bool IsNumber(const std::string token); static bool hasFlag(const std::vectorstd::string flags, const std::string flag); };设计亮点Token 预读机制支持前瞻解析自动跳过空白字符和注释行号跟踪便于错误定位静态辅助函数支持类型检测和标志判断2. SATEntity - 实体基类职责所有 SAT 实体的抽象基类关键特性enum class SATEntityType { POINT, CURVE, SURFACE, // 几何实体 VERTEX, EDGE, FACE, // 拓扑实体 LOOP, COEDGE, SHELL, // 拓扑实体 LUMP, BODY, ATTRIBUTE // 其他实体 }; class SATEntity { protected: int m_satId; // SAT 文件中的实体 ID int m_refCount; // 引用计数 SATEntityType m_type; // 实体类型 public: virtual void Import(SATInputStream stm) 0; // 从流导入数据 virtual void ResolvePointers(); // 解析引用第二阶段 int GetSatId() const { return m_satId; } SATEntityType GetType() const { return m_type; } };两阶段解析模式Import 阶段读取自身数据保存引用 IDResolvePointers 阶段根据引用 ID 查找并建立指针链接3. SATFactory - 工厂类职责根据实体类型动态创建对应的解析器实例实现原理class SATFactory { private: static std::mapstd::string, EntityCreator creators; public: static SATEntity* createEntity(const std::string type, int id) { if (creators.find(type) creators.end()) { std::cerr WARNING: No factory for type std::endl; return nullptr; } return creators[type](id); } static void registerType(const std::string type, EntityCreator creator) { creators[type] creator; } };注册示例// 在初始化时注册所有实体类型 SATFactory::registerType(point, [](int id) { return new SATPoint(id); }); SATFactory::registerType(intcurve-curve, [](int id) { return new SATIntersectionCurve(id); }); SATFactory::registerType(exactsur, [](int id) { return new SATExactSurface(id); });几何实体解析点SATPoint最简单的几何实体void SATPoint::Import(SATInputStream stm) { auto header stm.readEntityHeader(); // 读取三个坐标值 m_x stm.readDouble(); m_y stm.readDouble(); m_z stm.readDouble(); } gp_Pnt SATPoint::GetPoint() const { return gp_Pnt(m_x, m_y, m_z); }参数曲线SATIntersectionCurve最复杂的曲线类型支持 NURBSvoid SATIntersectionCurve::Import(SATInputStream stm) { // 1. 读取实体头 auto header stm.readEntityHeader(); // 2. 跳过前置标记直到 { skipPrecedingTokens(stm); // 3. 读取曲线类型及基础信息 std::string curveType stm.readString(); // exactcur int version stm.readInt(); // 版本号 std::string flags stm.readString(); // full std::string curveKind stm.readString(); // nurbs 或 nubs // 根据标志设置理性标志 m_isRational (curveKind nurbs); int dimension stm.readInt(); // 维度通常是 3 std::string knotType stm.readString(); // open/closed/periodic m_degree stm.readInt(); // 阶数 // 节点对数量 - 版本 6 才有此字段 int knotPairs 0; if (version 6) { knotPairs stm.readInt(); } // 4. 读取节点向量 for (int i 0; i knotPairs; i) { double knot stm.readDouble(); int mult stm.readInt(); // 端点重复度修正 if ((i 0 || i knotPairs - 1) mult m_degree) { mult m_degree 1; } m_knots.push_back(knot); m_multiplicities.push_back(mult); } // 5. 读取控制点根据是否有理决定是否读取权重 while (true) { std::string token stm.peekToken(); if (!SATInputStream::IsNumber(token) || token }) break; double x stm.readDouble(); double y stm.readDouble(); double z stm.readDouble(); double w 1.0; if (m_isRational) { // 有理曲线必须有权重 if (SATInputStream::IsNumber(stm.peekToken())) { w stm.readDouble(); } } m_controlPoints.push_back(gp_Pnt(x, y, z)); m_weights.push_back(w); m_controlPointCount; } // 6. 跳过尾部固定字段 skipTrailingFields(stm); // 7. 构建 OCCT B-Spline 曲线 buildBSplineCurve(); }关键设计决策nurbs vs nubsnurbsNon-Uniform Rational B-Spline有理 B 样条需要读取权重nubsNon-Uniform B-Spline非有理 B 样条不需要权重节点向量展开// 压缩格式knot0, mult3; knot1, mult3 // 展开后[0, 0, 0, 1, 1, 1] TColStd_Array1OfReal knots(1, expandedSize); int idx 1; for (size_t i 0; i m_knots.size(); i) { for (int j 0; j m_multiplicities[i]; j) { knots(idx) m_knots[i]; } }有理曲线构造if (m_isRational) { m_curve new Geom_BSplineCurve(poles, weights, knots, mults, degree, false); } else { m_curve new Geom_BSplineCurve(poles, knots, mults, degree, false); }NURBS 曲面解析SATExactSurface数据格式exactsur version rational_flag u_degree v_degree u_knot_pairs v_knot_pairs u_knots... v_knots... control_points_with_weights...解析流程void SATExactSurface::Import(SATInputStream stm) { // 1. 读取基本信息 auto header stm.readEntityHeader(); skipPrecedingTokens(stm); std::string type stm.readString(); // exactsur int version stm.readInt(); int rationalFlag stm.readInt(); // 3nubs, othernurbs m_isRational (rationalFlag ! 3); // 2. 读取次数 m_uDegree stm.readInt(); m_vDegree stm.readInt(); // 3. 读取节点对数量 int uKnotPairs stm.readInt(); int vKnotPairs stm.readInt(); // 4. 读取 U 方向节点向量 for (int i 0; i uKnotPairs; i) { double knot stm.readDouble(); int mult stm.readInt(); m_uKnots.push_back(knot); m_uMultiplicities.push_back(mult); } // 5. 读取 V 方向节点向量 for (int i 0; i vKnotPairs; i) { double knot stm.readDouble(); int mult stm.readInt(); m_vKnots.push_back(knot); m_vMultiplicities.push_back(mult); } // 6. 读取控制点网格带权重 readControlPointGrid(stm); // 7. 跳过尾部字段 skipTrailingFields(stm); // 8. 构建 OCCT NURBS 曲面 buildBSplineSurface(); }控制点网格读取void SATExactSurface::readControlPointGrid(SATInputStream stm) { m_controlPoints.clear(); m_weights.clear(); std::vectordouble currentRow; std::vectordouble weightRow; while (!stm.eof() !stm.isToken(#)) { std::string token stm.peekToken(); // 检查是否遇到结束标记 if (token } || token #) break; // 尝试读取 4 个值x, y, z, weight if (SATInputStream::IsNumber(token)) { double x stm.readDouble(); double y stm.readDouble(); double z stm.readDouble(); // 有理曲面必须读取权重 double w 1.0; if (m_isRational SATInputStream::IsNumber(stm.peekToken())) { w stm.readDouble(); } currentRow.push_back(x); currentRow.push_back(y); currentRow.push_back(z); weightRow.push_back(w); // 每 3 个值xyz完成一个控制点 if (currentRow.size() % 3 0) { // 检查是否需要开始新行通过检测下一行的第一个值 if (shouldStartNewRow(stm)) { addControlPointRow(currentRow, weightRow); currentRow.clear(); weightRow.clear(); } } } else { break; } } // 添加最后一行 if (!currentRow.empty()) { addControlPointRow(currentRow, weightRow); } }NURBS 曲面构建void SATExactSurface::buildBSplineSurface() { try { // 1. 展开节点向量 auto [uKnots, uMults] expandKnotVector(m_uKnots, m_uMultiplicities); auto [vKnots, vMults] expandKnotVector(m_vKnots, m_vMultiplicities); // 2. 构建控制点数组 int uSize getUControlPointSize(); int vSize getVControlPointSize(); TColgp_Array2OfPnt poles(1, uSize, 1, vSize); TColStd_Array2OfReal weights(1, uSize, 1, vSize); for (int i 0; i uSize; i) { for (int j 0; j vSize; j) { poles(i1, j1) m_controlPoints[i][j]; weights(i1, j1) m_weights[i][j]; } } // 3. 创建 OCCT NURBS 曲面 if (m_isRational) { m_surface new Geom_BSplineSurface( poles, weights, uKnots, vKnots, uMults, vMults, m_uDegree, m_vDegree, false, false // not periodic ); } else { m_surface new Geom_BSplineSurface( poles, uKnots, vKnots, uMults, vMults, m_uDegree, m_vDegree, false, false ); } } catch (const Standard_ConstructionError e) { std::cerr ERROR: Failed to build NURBS surface: e.GetMessageString() std::endl; fallbackToPlane(); } }拓扑实体解析边SATEdgevoid SATEdge::Import(SATInputStream stm) { auto header stm.readEntityHeader(); // 读取曲线引用 m_curveId stm.readEntityRef(); // 读取参数范围 m_firstParameter stm.readOptionalDouble(); m_lastParameter stm.readOptionalDouble(); // 读取 PCurves可选 readPCurves(stm); // 读取同侧标记 m_sameSense stm.readBoolean(); } void SATEdge::ResolvePointers() { // 查找引用的曲线 SATCurve* curve getFile()-getCurveById(m_curveId); // 创建 OCCT 边 TopoDS_Edge edge BRepBuilderAPI_MakeEdge(curve-GetCurve(), m_firstParameter, m_lastParameter); m_shape edge; }面SATFacevoid SATFace::Import(SATInputStream stm) { auto header stm.readEntityHeader(); // 读取曲面引用 m_surfaceId stm.readEntityRef(); // 读取边界环 while (!stm.isToken(#)) { int loopId stm.readEntityRef(); m_loopIds.push_back(loopId); } // 读取 2D 参数可选 read2DParameters(stm); } void SATFace::ResolvePointers() { // 获取曲面 SATSurface* surface getFile()-getSurfaceById(m_surfaceId); // 创建面 TopoDS_Face face BRepBuilderAPI_MakeFace(surface-GetSurface(), Precision::Confusion()); // 添加边界环 for (int loopId : m_loopIds) { SATLoop* loop getFile()-getLoopById(loopId); TopoDS_Wire wire loop-GetWire(); if (loop.isOuter()) { face.Add(wire); // 外环 } else { face.Add(wire); // 内环孔 } } m_shape face; }错误处理与容错机制1. 版本兼容性处理int SATIntersectionCurve::readVersionAware(SATInputStream stm) { int version stm.readInt(); // 不同版本有不同的字段顺序 if (version 6) { // Version 4: 没有 knotPairs 字段需要动态检测 return readLegacyFormat(stm); } else { // Version 6: 标准格式 return readStandardFormat(stm); } }2. 回退策略FallbackHandle(Geom_Surface) SATExactSurface::GetSurface() { if (!m_surface.IsNull()) { return m_surface; } try { buildBSplineSurface(); } catch (const Standard_ConstructionError e) { std::cerr ERROR: NURBS surface construction failed, falling back to plane std::endl; // 回退到平面 fallbackToPlane(); } return m_surface; } void SATExactSurface::fallbackToPlane() { // 尝试用前三个控制点构造平面 if (m_controlPoints.size() 3) { gp_Pnt p1 m_controlPoints[0][0]; gp_Pnt p2 m_controlPoints[0][1]; gp_Pnt p3 m_controlPoints[1][0]; gp_Vec v1(p1, p2); gp_Vec v2(p1, p3); gp_Dir normal v1.Crossed(v2); m_surface new Geom_Plane(p1, normal); } else { // 默认 XY 平面 m_surface new Geom_Plane(gp::XOY()); } }3. 形状修复协议TopoDS_Shape SATFile::BuildTopology() { TopoDS_Compound compound; BRep_Builder builder; builder.MakeCompound(compound); // 1. 构建所有拓扑实体 for (auto entity : entities) { if (entity-isBody()) { TopoDS_Shape shape entity-GetShape(); if (!shape.IsNull()) { builder.Add(compound, shape); } } } // 2. 应用 ShapeFix 修复 ShapeFix_Shape fix(compound); fix.SetPrecision(Precision::Confusion()); fix.SetMaxTolerance(1e-3); fix.Perform(); return fix.Shape(); }总结与展望技术要点总结