Topology and Geometry in OpenCascade-Edge

eryar@163.com

摘要Abstract:本文简要介绍了几何造型中的边界表示法(BRep),并结合程序说明OpenCascade中的边界表示的具体实现,即拓朴与几何的联系。对具有几何信息的拓朴结构顶点(vertex)、边(edge)、面(face)进行了详细说明。本文只对拓朴边数据进行说明,着重介绍了OpenCascade中两个种特别的边缝合边(seam edge)和退化边(degenerated edge)。

关键字Key Words:OpenCascade、BRep、Topology、Edge、Geometry

一、引言 Introduction

边(Edge)是两个邻面(对正则形体而言)或多个邻面(对非正则形体而言)的交集。边有方向,它由起始顶点和终止顶点来界定;边的形状由边的几何信息来表示,可以是直线,也可以是曲线,曲线边可用一系列控制点或型值点来描述,也可以用显示、隐式或参数方程来描述。

边(Edge)是边界表示法中的重要结构,因为边界表示法(BRep)是用形体的边界来描述形体的一种方法。BRep认为形体是由有限数量的边界表面(平面或曲面)构成,而每个表面又由若干边界边与顶点构成,所有的单元面构成了形体的边界,形体的边界将形体和周围的环境分隔开来。

边界表示法不仅详细记录了构成形体的面、边方程的系数和顶点坐标值的几何信息,而且描述了这些几何元素之间的拓朴信息,即体、面、边、顶点的组成关系等。在保证对形体面的定义确定并且无二义性的前提下,它允许根据形体的拓朴结构、面表示的方便性等因素确定一个面是以一个整体表示,还是以几个部分之和进行表示。

在OpenCascade中边包含了一系列的曲线,其结构如下图所示:

Figure 1.1 BRep_TEdge members

其中,包含一系列的曲线由下面几种:

Figure 1.2 BRep_CurveRepresentation class diagram

二、边 Edge

边(edge)是对应于一维对象-曲线的拓朴实体。边可以是面的边界(如长方体的12条边之一);也可以只是一条不属于任何面的“悬空”边(floating edge),想像一下在构建锥形体或扫掠体之前的轮廓线;面的边可以被两个或更多面共享,或者只属于一个面。如下图所示:

Figure 2.1 Model used to illustrate Edge

在上图中用不同的颜色将不同类型的边区别开来:

l 红色:不属于任何面的悬空边(floating edge);

l 绿色:只属于一个面的自由边(free edge);

l 黄色:属于两个或多个面的共享边(shared edge);

边Edge包含几种几何表示:

n 三维空间中的曲线C(t),由Geom_Curve实现。这是边的基本表示方式;

n 曲线P(t)为二维空间的参数曲线,用来表示属于面的边,通常被称为pcurves,由类Geom2d_Curve实现;

n 多段线(Polygonal)由一组三维点表示,且由类Poly_Polygon3D实现。

n 多段线(Polygonal)也可由一组三角剖分面上点的索引来表示,且由类Poly_PolygonOnTriangulation实现。

他们的表示都可以使用前面提到的类BRep_Tool来获取。例如:

Standard_Real aFirst, aLast, aPFirst, aPLast;
Handle(Geom_Curve) aCurve3d = BRep_Tool::Curve (anEdge, aFirst, aLast);
Handle(Geom2d_Curve) aPCurve = BRep_Tool::CurveOnSurface (anEdge, aFace, aPFirst, aPLast);

边必须有曲面上的参数曲线(pcurves),除了平面以外。边中所有曲线必须一致,即朝向相同。这样边上的点可以使用任意表示方式计算得到,如曲线C(t),可以用[first, last]区间上的t来计算;也可根据u在区间[first1, last1]上取得曲面S1(P1x(u), P1y(u))上的点Pi,这里Pi是曲面Si上的参数曲线pcurve上的一点。

1. 边的标志位 Edge Flags 

边中的标志位有三种:

static const Standard_Integer ParameterMask       = ;
static const Standard_Integer RangeMask = ;
static const Standard_Integer DegeneratedMask = ;

这里对前两种标志位进行说明:

l RangeMask “same range”:(BRep_Tool::SameRange())取值区间相同,即几何表示的曲线参数取值区间相同;

l ParameterMask “same parameter”:(BRep_Tool::SameParameter())参数相同,即当C(t)=S1(P1x(t), P1y(t))时,对于同样的参数t,C(t)和曲面S1上的点P1(t)相同。即任何边上的点都对应参数曲线上相同的参数值。

许多算法假定设置了这两个标志位,因此建议你注意这种情况,一定要设置这些标志位。

2. 边的容差 Tolerance 

边的容差(Tolerance)是其三维曲线和其他任何表示方式之间的最大偏差。其几何意义就是以容差为半径沿边的一个包含边的三维曲线及其他任何形式表示的管子。如下图所示:

Figure 2.2 Edge Tolerance

3. 特殊类型的边 Special edge types 

在OpenCascade有两种特别类型的边,他们是:

l 缝合边(seam edge):即在同一个面上出现两次的边(如:在同一个面上具有2个参数曲线);

l 退化边(degenerated edge):这种边位于曲面的奇异点处,在三维空间中退化为一个点;

球面中这两种类型的边都有。缝合边位于经线(U iso-lines),参数为0和2*PI。退化边位于南北极点,对应于纬线(V iso-lines),参数为-PI/2和PI/2。因为球面的参数方程为:

当参数u取0和2*PI时,球面的参数方程计算如下:

从计算结果可以看出,缝合边是位于Dx和Dz所在平面上的半圆弧。

当参数v取-PI/2和PI/2时,球面的参数方程计算如下:

从计算结果可以看出,曲面上的两个边分别退化为两个点。即v取-PI/2和PI/2时球面的两个退化边分别位于南北极点上。如下图所示:

Figure 2.3 seam edge and degenerated edge of sphere

另外例子:环形体(torus)、圆柱体(cylinder)、圆锥体(cone)。环形体torus有两条缝合边(seam edge),对应于它的参数空间的边界;圆柱体(cylinder)有一条缝合边(seam edge)。圆锥(cone)顶点处为退化边(degenerated edge)。

检查边是否是缝化边或退化边,可以使用函数BRep_Tool::IsClosed()和BRep_Tool::Degenerated()。

4. 边的朝向 

边的朝向为正向(forward edge orientation)意味着边的逻辑方向与曲线的方向相同。反向(reversed)意味着逻辑方向与曲线方向相反。所以,缝合边(seam-edge)在一个面中总是有两个朝向:一个反向(reversed),一个正向(forward)。

三、示例程序 Example Code 

以边界表示BRep表示的球面为例,说明其边的类型。程序代码如下所示:

/*
* Copyright (c) 2013 eryar All Rights Reserved.
*
* File : Main.cpp
* Author : eryar@163.com
* Date : 2013-08-24 16:11
* Version : 1.0v
*
* Description : Demonstrate seam edge and degenerated edge of sphere.
*
*/ #include <iostream> // OpenCascade Library.
#define WNT
#include <TopoDS.hxx>
#include <TopoDS_Edge.hxx>
#include <TopExp_Explorer.hxx>
#include <BRepPrimAPI_MakeSphere.hxx> #pragma comment(lib, "TKernel.lib")
#pragma comment(lib, "TKMath.lib")
#pragma comment(lib, "TKBRep.lib")
#pragma comment(lib, "TKPrim.lib")
#pragma comment(lib, "TKTopAlgo.lib") /**
* @breif Dump orientation types.
* Orientation definitaion:
* enum TopAbs_Orientation { * TopAbs_FORWARD, * TopAbs_REVERSED, * TopAbs_INTERNAL, * TopAbs_EXTERNAL * };
*/
std::string dumpOrientation(const TopAbs_Orientation& orient)
{
std::string strType; switch (orient)
{
case TopAbs_FORWARD:
strType = "TopAbs_FORWARD";
break; case TopAbs_REVERSED:
strType = "TopAbs_REVERSED";
break; case TopAbs_INTERNAL:
strType = "TopAbs_INTERNAL";
break; case TopAbs_EXTERNAL:
strType = "TopAbs_EXTERNAL";
break;
} return strType;
} /**
* @breif Dump edge information.
*/
void processEdge(const TopoDS_Edge& edge, const TopoDS_Face& face)
{
Standard_Real dTolerance = BRep_Tool::Tolerance(edge); Standard_Boolean bIsGeometric = BRep_Tool::IsGeometric(edge);
Standard_Boolean bIsSameParameter = BRep_Tool::SameParameter(edge);
Standard_Boolean bIsSameRange = BRep_Tool::SameRange(edge);
Standard_Boolean bIsDegenerated = BRep_Tool::Degenerated(edge);
Standard_Boolean bIsClosed = BRep_Tool::IsClosed(edge, face); TopAbs_Orientation nOrientation = edge.Orientation(); // Dump edge info.
std::cout<<"====== Edge Info ======="<<std::endl;
std::cout<<"Tolerance: "<<dTolerance<<std::endl;
std::cout<<"Orientation: "<<dumpOrientation(nOrientation)<<std::endl;
std::cout<<"Geometric: "<<(bIsGeometric?"True":"False")<<std::endl;
std::cout<<"Same Parameter: "<<(bIsSameParameter?"True":"False")<<std::endl;
std::cout<<"Same Range: "<<(bIsSameRange? "True":"False")<<std::endl;
std::cout<<"Degenerated edge: "<<(bIsDegenerated?"True":"False")<<std::endl;
std::cout<<"Seam edge: "<<(bIsClosed? "True":"False")<<std::endl; // Dump vertex of the edge.
for (TopExp_Explorer vertexItr(edge, TopAbs_VERTEX);
vertexItr.More();
vertexItr.Next())
{
const TopoDS_Vertex& aVertex = TopoDS::Vertex(vertexItr.Current());
gp_Pnt pnt = BRep_Tool::Pnt(aVertex); std::cout<<"Vertex: ("<<pnt.X()<<", "<<pnt.Y()<<", "<<pnt.Z()<<")"<<std::endl;
}
} int main(void)
{
Standard_Integer nSphereFaceCount = ;
Standard_Integer nSphereEdgeCount = ; TopoDS_Shape sphere = BRepPrimAPI_MakeSphere(1.0); for (TopExp_Explorer faceItr(sphere, TopAbs_FACE);
faceItr.More();
faceItr.Next())
{
const TopoDS_Face& aFace = TopoDS::Face(faceItr.Current()); ++nSphereFaceCount; for (TopExp_Explorer edgeItr(aFace, TopAbs_EDGE);
edgeItr.More();
edgeItr.Next())
{
const TopoDS_Edge& aEdge = TopoDS::Edge(edgeItr.Current()); processEdge(aEdge, aFace); ++nSphereEdgeCount;
}
} std::cout<<"Sphere face count: "<<nSphereFaceCount<<std::endl;
std::cout<<"Sphere edge count: "<<nSphereEdgeCount<<std::endl; return ;
}

程序运行结果如下所示:

  ====== Edge Info =======
  Tolerance: 1e-
  Orientation: TopAbs_REVERSED
  Geometric: True
  Same Parameter: True
  Same Range: True
  Degenerated edge: True
  Seam edge: False
  Vertex: (6.12323e-017, -1.49976e-032, )
  Vertex: (6.12323e-017, -1.49976e-032, )
  ====== Edge Info =======
  Tolerance: 1e-
  Orientation: TopAbs_FORWARD
  Geometric: True
  Same Parameter: True
  Same Range: True
  Degenerated edge: False
  Seam edge: True
  Vertex: (6.12323e-017, -1.49976e-032, )
  Vertex: (6.12323e-017, -1.49976e-032, -)
  ====== Edge Info =======
  Tolerance: 1e-
  Orientation: TopAbs_FORWARD
  Geometric: True
  Same Parameter: True
  Same Range: True
  Degenerated edge: True
  Seam edge: False
  Vertex: (6.12323e-017, -1.49976e-032, -)
  Vertex: (6.12323e-017, -1.49976e-032, -)
  ====== Edge Info =======
  Tolerance: 1e-
  Orientation: TopAbs_REVERSED
  Geometric: True
  Same Parameter: True
  Same Range: True
  Degenerated edge: False
  Seam edge: True
  Vertex: (6.12323e-017, -1.49976e-032, )
  Vertex: (6.12323e-017, -1.49976e-032, -)
  Sphere face count:
  Sphere edge count:
  Press any key to continue . . .

从运行结果可以看,当球的边为退化边时,边的两个顶点的坐标值相同。退化边位于球的南北极点上。缝合边为连接两个退化边的曲线。

根据遍历顺序,

第一条边为退化边(degenerated edge),其朝向为反向(reversed);

第二条边为缝合边(seam-edge),其朝向为正向(forward);

第三条边为退化边,其朝向为正向(forward);

第四条边为缝合边,其朝向为反向(reversed)。

由上可见,缝合边有两个朝向,一个正向一个反向。

四、结论 Conclusion 

对与几何相关的拓朴边(edge)的类的属性数据进行详细说明。并结合程序代码详细说明边的标志位(myFlags)属性的意义,从参数方程出发,理解缝合边(seam-edge)和退化边(degenerated edge),即标志位中DegeneratedMask的意义。

五、参考资料 

1. Roman Lygin, OpenCascade notes, opencascade.blogspot.com

2. 孙家广等. 计算机图形学. 清华大学出版社

3. OpenCascade source code.

Topology and Geometry in OpenCascade-Edge的更多相关文章

  1. Topology and Geometry in OpenCascade-Adapters

    Topology and Geometry in OpenCascade-Adapters eryar@163.com 摘要Abstract:本文简要介绍了适配器模式(adapter pattern) ...

  2. Topology and Geometry in OpenCascade-Face

    Topology and Geometry in OpenCascade-Face eryar@163.com 摘要Abstract:本文简要介绍了几何造型中的边界表示法(BRep),并结合程序说明O ...

  3. Topology and Geometry in OpenCascade-Topology

    Topology and Geometry in OpenCascade-Topology eryar@163.com 摘要Abstract:本文简要介绍了几何造型中的边界表示法(BRep),并结合程 ...

  4. Topology and Geometry in OpenCascade-Vertex

    Topology and Geometry in OpenCascade-Vertex eryar@163.com 摘要Abstract:本文简要介绍了几何造型中的边界表示法(BRep),并结合程序说 ...

  5. Topology Shapes of OpenCascade BRep

    Topology Shapes of OpenCascade BRep eryar@163.com 摘要Abstract:通过对OpenCascade中的BRep数据的读写,理解边界表示法的概念及实现 ...

  6. Geometry Surface of OpenCascade BRep

    Geometry Surface of OpenCascade BRep eryar@163.com 摘要Abstract:几何曲面是参数表示的曲面 ,在边界表示中其数据存在于BRep_TFace中, ...

  7. Geometry Curve of OpenCascade BRep

    Geometry Curve of OpenCascade BRep eryar@163.com 摘要Abstract:几何曲线是参数表示的曲线 ,在边界表示中其数据存在于BRep_TEdge中,BR ...

  8. OpenCASCADE PCurve of Topological Face

    OpenCASCADE PCurve of Topological Face eryar@163.com Abstract. OpenCASCADE provides a class BRepBuil ...

  9. OpenCASCADE BRepTools

    OpenCASCADE BRepTools eryar@163.com Abstract. OpenCASCADE BRepTools provides utilities for BRep data ...

随机推荐

  1. Android ImageView高度根据图片比例自适应

    设置adjustViewBounds // 是否保持宽高比 <ImageView android:id="@+id/iv_test" android:layout_width ...

  2. OpenMP之数值积分(求圆周率Pi)(sections)

    // Pi.cpp : 定义控制台应用程序的入口点. //求圆周率PI #include "stdafx.h" #include <windows.h> #includ ...

  3. js继承理解(有引用)

    具体栗子:http://www.cnblogs.com/ayqy/p/4471638.html(地下为自己理解总结,可能晦涩,链接详细) 1.父类实例赋予子类原型. 2.利用子类函数引用 父类.cal ...

  4. 浅析C语言指针问题

    首先明白c语言操作符的优先级及结合性就很容易理解了. 链接 1.关于char *s 及 char s[] char *s指向的是一个字符串对象的指针,可以理解为间接引用,比如 char *s = “1 ...

  5. Eclipse断点调试

    转自:http://blog.csdn.net/maritimesun/article/details/7815903 作为开发人员,掌握开发环境下的调试技巧十分有必要.去年就想把关于Eclipse断 ...

  6. [ASE]sprint2 总结 & sprint3计划

    第二个sprint半圆满的结束了, 经历了四周之后我们将整个的框架搭建好,并且能够正常的游戏对战,破坏场景,聊天…… 但是正如老师所述,缺乏亮点. 不过大家都是第一次做,完全把他当成一个工程来一点一点 ...

  7. 360等杀掉了app的主进程后 ,如何自动开启 如何防止被kill

    如何阻止360等进程查杀工具停止App后台进程安全软件优化内存时需要关闭没用的进程既然你同意使用360,,也允许了360的最高权限..那么他就有足够的权限来杀掉app后台进程. 一 如何保证app进程 ...

  8. svn patch用法

    最近遇到了一个patch的使用场景: 有一个同事对源码做了一些修改,但是又不想将源码提交到SVN服务器,而我又想得到他所做的修改. patch的使用方法: 创建patch 在要导出“修改”的目录中,单 ...

  9. Grpc微服务从零入门

    快速入门 安装 JDK 毫无疑问,要想玩Java,就必须得先装Java JDK,目前公司主要使用的是Oracle JDK 8,安装完成后要配置环境才能正常使用,真蠢,不过也就那么一下下,认了吧.配置方 ...

  10. 如何捕获和分析 JavaScript Error

    前端工程师都知道 JavaScript 有基本的异常处理能力.我们可以 throw new Error(),浏览器也会在我们调用 API 出错时抛出异常.但估计绝大多数前端工程师都没考虑过收集这些异常 ...