1. 只有3D曲线
在三维空间中直接构建的实体(如拉伸一个长方体,或者直接画一条三维直线)。
生成的TopoDS_Edge只存储三维空间中的直线或样条线(Geom_Curve)。
为什么没有 2D? 因为这条边并不依附于任何曲面,它本身就是三维空间的边界。如果需要它在某个平面上的二维参数,通常是通过投影算法临时计算,而不需要永久存储。
cpp
// 创建一条三维空间的直线边
gp_Pnt p1(0, 0, 0);
gp_Pnt p2(10, 0, 0);
TopoDS_Edge edge3D = BRepBuilderAPI_MakeEdge(p1, p2);
此时通过BRep_Tool::Curve可以获取到这条曲线。
cpp
Standard_Real first, last;
Handle(Geom_Curve) curve3D = BRep_Tool::Curve(edge3D, first, last);
brep输出入下

2.只有2D曲线,没有3D曲线
例子:
当你在一个曲面上画一条线(比如在圆柱面上画一条螺旋线,或者在球面上画一条曲线),随后用这条线去裁剪曲面生成一个面(Face)。
此时生成的TopoDS_Edge在三维空间中是一条空间曲线,但在 BRep 底层存储中,它只存了该边在曲面参数空间(UV 空间)的 2D 曲线(Geom2d_Curve)以及一个Surface。
这样存储够了吗?够了,只要知道"曲面(Surface)" + "UV 空间中的 2D 曲线",通过曲面的数学方程 S(u,v) 随时可以三维空间中算出任意点的 3D 坐标。如果额外去存一条 3D 曲线,不仅浪费内存,还可能在浮点运算中产生与曲面定义不一致的微小偏差(容差问题)。
cpp
//1. 创建一个圆柱面
Standard_Real radius = 5.0;
Standard_Real height = 10.0;
TopoDS_Face cylinderFace = BRepPrimAPI_MakeCylinder(radius, height);
// 2. 在圆柱的 UV 参数空间定义一条线(螺旋线或斜线)
// 圆柱面的参数化:u ∈ [0, 2π], v ∈ [0, height]
// 我们创建一条斜线:从 (0, 0) 到 (2π, height)
Handle(Geom2d_Line) pcurve = new Geom2d_Line(gp_Pnt2d(0, 0), gp_Dir2d(1, 1));
Standard_Real uFirst = 0.0;
Standard_Real uLast = 2 * M_PI;
// 3. 通过曲面和 2D 曲线构建边(此时只有 2D 曲线,没有 3D 曲线)
BRepAdaptor_Surface theSurfaceAdaptor(cylinderFace);
TopoDS_Edge edgeOnSurface = BRepBuilderAPI_MakeEdge(pcurve, theSurfaceAdaptor.Surface().Surface(), uFirst, uLast);
BRepTools::Write(edgeOnSurface, "D:\\EdgeOnSurface.brep");
此时通过BRep_Tool::CurveOnSurface可以取得这条2d边
cpp
Standard_Real first, last;
Handle(Geom2d_Curve) curve2D = BRep_Tool::CurveOnSurface(theEdge, cylinderFace, first, last);
brep输出如下,发现确实只存储了Geom2d_Curve与一个Surface

3. 既有 3D 曲线,又有 2D 曲线(复合边/缝合边)
当你将一个圆柱面(有曲面)与一个平面长方体进行布尔运算(Boolean Operation)缝合时。
缝合线既是三维空间的交线(Geom_Curve),也是圆柱面和平面各自 UV 空间中的 2D 曲线(Geom2d_Curve)。两者同时存储,用于确保在不同算法(求交用 3D,网格剖分用 2D)下都能直接读取,无需临时计算。
cpp
// 1. 创建两个实体:一个圆柱和一个方块
TopoDS_Shape cylinder = BRepPrimAPI_MakeCylinder(5.0, 10.0);
TopoDS_Shape box = BRepPrimAPI_MakeBox(10.0, 10.0, 10.0);
// 2. 将方块平移,使其与圆柱相交
gp_Trsf transform;
transform.SetTranslation(gp_Vec(3, 0, 0));
BRepBuilderAPI_Transform boxTransformed(box, transform);
// 3. 布尔运算:用方块切割圆柱(产生交线)
BRepAlgoAPI_Cut cutter(cylinder, boxTransformed);
TopoDS_Shape result = cutter.Shape();
BRepTools::Write(result, "D:\\Edge3dAnd2d.brep");
// 4. 遍历结果中的边,查找交线边
TopExp_Explorer explorer(result, TopAbs_EDGE);
for (; explorer.More(); explorer.Next()) {
TopoDS_Edge edge = TopoDS::Edge(explorer.Current());
Standard_Real first, last;
Handle(Geom_Curve) curve3D = BRep_Tool::Curve(edge, first, last);
// 交线边通常依附于某个面,我们需要找到它所属的面
TopExp_Explorer faceExplorer(result, TopAbs_FACE);
if (faceExplorer.More()) {
TopoDS_Face face = TopoDS::Face(faceExplorer.Current());
Handle(Geom2d_Curve) curve2D = BRep_Tool::CurveOnSurface(edge, face, first, last);
std::cout << "\n=== 布尔运算生成的复合边 ===" << std::endl;
std::cout << "3D 曲线: " << (curve3D.IsNull() ? "无" : "有") << std::endl;
std::cout << "2D 曲线 (在面上): " << (curve2D.IsNull() ? "无" : "有") << std::endl;
// 通常输出:3D 曲线: 有,2D 曲线: 有
break;
}
brep输出如下:

4.关于Poly_Polygon2D与Poly_Polygon3D
Handle(Poly_Polygon2D) BRep_Tool::PolygonOnSurface
const Handle(Poly_Polygon3D)& BRep_Tool::Polygon3D
对于平面(Face):由于曲面的 UV 参数空间就是 3D 空间的映射,PolygonOnSurface 就是 3D 多边形(Polygon3D)在平面上的"投影"。两者形状完全一致,只是坐标从 (x,y,z) 变成了 (u,v,0)。
对于非平面(圆柱、球体等):它是展开图上的折线。
想象一个圆柱面,有一条螺旋线。Polygon3D 是在三维空间里绕圆柱转着上升的折线。
而 PolygonOnSurface 则是把圆柱面剪开展平后,在矩形纸上画出的斜直线折线段。
那么,这个容器里的数据是谁放进去的呢?主要有以下两种途径:
方式一:通过网格划分算法生成(最常见的情况)
这是最主要的方式。当你对模型进行三角化(Tessellation)时,例如调用 BRepMesh_IncrementalMesh,算法在离散化面的过程中,会同时生成:
- 面的三角化数据 (Poly_Triangulation)
- 边在3D空间的多边形数据 (Polygon3D)
- 边在该面参数空间(UV空间)的多边形数据 (PolygonOnSurface)
方式二:从文件中读取(数据持久化)
当从 .brep、.step 或 .iges 等文件中读取模型时,如果这些文件里已经存储了模型的网格数据(离散化数据),那么在加载时,这些 PolygonOnSurface 数据也会被一并读入并附着在对应的边和面上,从而可以直接被 BRep_Tool 获取到。
因此,只有在成功执行了网格划分后,PolygonOnSurface 才能获取成功。一个从未被网格化的曲面,其边上是没有这些2D多边形数据的
5. 在圆柱的 UV 参数空间定义一条线,是如何定义出一条3D线的?

