








ACIS SAT(Standard ACIS Text)文件是由 Spatial 公司开发的 ACIS 几何建模内核使用的标准文件格式。它是一种文本格式,用于存储三维几何模型的边界表示(B-Rep)数据,包括:
ACIS 100 ACIS Verifier status: 0
ACIS:固定标识符100:主版本号(如 700 表示 v7.0,3300 表示 v33.0)ACIS 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 - 参数曲线(含 NURBS)plane-surface - 平面cylinder-surface - 圆柱面cone-surface - 圆锥面exactsur - 精确曲面(含 NURBS)vertex - 顶点edge - 边coedge - 协同边(有向边)loop - 环face - 面shell - 壳lump - 体块body - 实体classDiagram %% 核心流类 class SATInputStream { +std::istream& stream +size_t lineNumber +peekToken() String +nextToken() String +readInt() int +readDouble() double +readString() String +readEntityRef() int +readFlagsUntilNumber() List~String~ +static IsNumber(token) bool +static hasFlag(flags, flag) bool } %% 基础实体类 class SATEntity { #int m_satId #int m_refCount #SATEntityType m_type +getSatId() int +getRefCount() int +getType() SATEntityType +virtual Import(stm) void +virtual ResolvePointers() void } class SATFactory { +static createEntity(type, id) SATEntity* +static registerType(type, factory) void } %% 几何实体层次 class SATGeometry { +virtual GetCurve() Geom_Curve +virtual GetSurface() Geom_Surface } class SATPoint { -double m_x, m_y, m_z +Import(stm) void +GetPoint() gp_Pnt } class SATCurve { #Handle(Geom_Curve) m_curve +GetCurve() Geom_Curve } class SATIntersectionCurve { -int m_degree -bool m_isRational -List~double~ m_knots -List~int~ m_multiplicities -List~gp_Pnt~ m_controlPoints -List~double~ m_weights +Import(stm) void +buildBSplineCurve() void } class SATSurface { #Handle(Geom_Surface) m_surface +GetSurface() Geom_Surface } class SATExactSurface { -int m_uDegree, m_vDegree -bool m_isRational -List~List~gp_Pnt~ m_controlPoints -List~List~double~ m_weights +Import(stm) void +buildBSplineSurface() void } %% 拓扑实体层次 class SATTopology { +TopoDS_Shape GetShape() } class SATVertex { -SATPoint* m_point +ResolvePointers() void +GetShape() TopoDS_Vertex } class SATEdge { -SATCurve* m_curve -SATVertex* m_start, *m_end +ResolvePointers() void +GetShape() TopoDS_Edge } class SATFace { -SATSurface* m_surface -List~SATLoop~ m_loops +ResolvePointers() void +GetShape() TopoDS_Face } %% 文件解析器 class SATFile { -String filename -Map~int, SATEntity~ entities -Load() bool -BuildTopology() TopoDS_Shape -ExportBREP(shape, file) bool } %% 关系定义 SATInputStream --> SATEntity : 读取数据 SATFactory --> SATEntity : 创建实例 SATEntity <|-- SATGeometry SATEntity <|-- SATTopology SATCurve <|-- SATIntersectionCurve SATSurface <|-- SATExactSurface SATFile --> SATEntity : 管理所有实体 SATFile --> SATInputStream : 使用流解析
职责:提供 token 级别的流式读取功能
关键方法:
class SATInputStream {
public:
std::string peekToken(); // 预读下一个 token,不消耗
std::string nextToken(); // 读取并消耗下一个 token
int readInt(); // 读取整数
double readDouble(); // 读取浮点数
std::string readString(); // 读取字符串
int readEntityRef(); // 读取实体引用(跳过 $ 标记)
std::vector<std::string> readFlagsUntilNumber(); // 读取标志直到数字
static bool IsNumber(const std::string& token);
static bool hasFlag(const std::vector<std::string>& flags, const std::string& flag);
};
设计亮点:
职责:所有 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; }
};
两阶段解析模式:
职责:根据实体类型动态创建对应的解析器实例
实现原理:
class SATFactory {
private:
static std::map<std::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); });
最简单的几何实体:
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);
}
最复杂的曲线类型,支持 NURBS:
void 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 nubs:
nurbs(Non-Uniform Rational B-Spline):有理 B 样条,需要读取权重nubs(Non-Uniform B-Spline):非有理 B 样条,不需要权重节点向量展开:
// 压缩格式:knot=0, mult=3; knot=1, mult=3
// 展开后:[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);
}
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(); // 3=nubs, other=nurbs
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::vector<double> currentRow;
std::vector<double> 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);
}
}
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(i+1, j+1) = m_controlPoints[i][j];
weights(i+1, j+1) = 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();
}
}
void 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;
}
void 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;
}
int SATIntersectionCurve::readVersionAware(SATInputStream& stm) {
int version = stm.readInt();
// 不同版本有不同的字段顺序
if (version < 6) {
// Version 4: 没有 knotPairs 字段,需要动态检测
return readLegacyFormat(stm);
} else {
// Version 6+: 标准格式
return readStandardFormat(stm);
}
}
Handle(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());
}
}
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();
}
流式解析架构:
NURBS 完整支持:
容错与修复:
可扩展设计:
参考文献
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。