天天看點

Representation Data in OpenCascade BRep

摘要Abstract:現在的顯示器大多數是光栅顯示器,即可以看做一個像素的矩陣。在光栅顯示器上顯示的任何圖形,實際上都是一些具有一種或多種顔色的集合。數學上精确表示的圖形在顯示器中隻能用逼近的方式顯示出來。本文主要對OpenCascade的BRep檔案中用來顯示曲線和曲面的離散資料結構進行說明。   關鍵字:OpenCascade, BRep, Polygon, Triangulation, Subdivision Curves,

Representation Data in OpenCascade BRep

[email protected]

摘要Abstract:現在的顯示器大多數是光栅顯示器,即可以看做一個像素的矩陣。在光栅顯示器上顯示的任何圖形,實際上都是一些具有一種或多種顔色的集合。數學上精确表示的圖形在顯示器中隻能用逼近的方式顯示出來。本文主要對OpenCascade的BRep檔案中用來顯示曲線和曲面的離散資料結構進行說明。 

關鍵字:OpenCascade, BRep, Polygon, Triangulation, Subdivision Curves, 

一、引言 Introduction

光栅圖形顯示器可以看做一個像素矩陣。在光栅顯示器上顯示的任何一種圖形,實際上都是一些具有一種或多種顔色的像素的集合。在數學上,理想的曲線是沒有寬度的,它是由無數個點構成的集合,而當要顯示曲線時,就不能用無數個點在顯示器中顯示,必須對其進行離散化,即細分處理。考慮性能要求,需要用盡可能少的點來顯示曲線。對于曲面也是一樣,雖然已經有曲面的數學解析表示,但是需要在顯示器中顯示時,必須對其離散化,即三角剖分得到的逼近曲面的三角網格。 

在OpenCascade中已經有曲線和曲面的精确的數學解析表達形式的類,如下圖所示: 

Representation Data in OpenCascade BRep

Figure 1.1 Parametric geometry curves 

Representation Data in OpenCascade BRep

Figure 1.2 Parametric geometry surfaces 

在OpenGL中顯示這些曲線和曲面時,不能直接顯示出由參數方程精确表示的曲線和曲面,必須對曲線和曲面進行細分,即離散化,得到OpenGL顯示用的點和三角網格。 

在OpenCascade中使用類Poly_Polygon3D/Poly_Polygon2D來儲存多段線的資料,即可以用來儲存逼近顯示由參數方程精确表示的曲線的離散點資料。 

在OpenCascade中使用類Poly_Triangulation來儲存網格資料,即用三角網格來逼近表示的曲面,或更通用的一個形狀。 

形狀的離散化由函數BRepMesh::Mesh()來統一處理,處理後就可以得到形狀用來顯示的多段線和三角網格資料。有了這些離散資料,不管是将形狀交給顯示子產品進行顯示,還是将形狀在其他顯示引擎中顯示,就很友善了。 

在OpenCascade的BRep中也儲存了形狀的用來顯示用的離散資料,即多段線和三角網格。隻有經過BRepMesh::Mesh()離散化之後,形狀才具有這些資料。 

二、細分曲線 Subdivision of Curves

在前面的一篇文章《在OpenSceneGraph中繪制OpenCascade的曲線 》中對曲線的顯示使用了統一細分處理(uniform subdivision),即将曲線在整個參數區域内均分後得到一些線段來顯示。沒有考慮這樣的問題:在曲線很平的區域内,就會存在備援的點;在曲線曲度很大的區域内,可能點的數量還不足以顯示出光滑的曲線。自适應細分(Adaptive Subdivision)的方法就是将點放在最需要的地方,其主要目的是可視化曲線時更高效的渲染。通常這種方法主要用于遊戲,因為其顯示更高效,性能更好。 

Representation Data in OpenCascade BRep

Figure 2.1 Uniform sampling on a curve 

如上圖所示,統一采樣來繪制曲線時,通常會在直線段區域生成很多多餘的點,而在曲線區域的點太少,不能表示出光滑的曲線。自适應細分曲線有很多種方法,每種方法都會考慮速度、效率和精度,即如何用最少的點精确地表示出曲線。當你了解這個基本概念後,也可以對其他方法進行研究。 

在OpenCascade中對曲線的細分使用的類是GCPnts_TangentialDeflection,其算法描述如下,感興趣的讀者可以結合源程式對其算法實作進行研究: 

Representation Data in OpenCascade BRep

其中各個點的橫坐标對應的參數分别為: 

Representation Data in OpenCascade BRep

從上述公式結合向量的數量積公式可以看出,限制條件是兩個向量夾角的餘弦值分别小于角度偏差和曲率偏差。算法将産生滿足限制條件的曲線上的最少數量的點。 

Representation Data in OpenCascade BRep

細分曲線後的點儲存在類Poly_Polygon3D中。在BRep中也儲存有多段線資料,如下所示: 

示例: 

Representation Data in OpenCascade BRep

BNF定義: 

Representation Data in OpenCascade BRep

詳細說明: 

<3D polygon record>定義了空間多段線(3D polyline)L,用來逼近空間參數曲線C。多段線的資料包含節點數m>=2,參數顯示标志位p,逼近偏差(deflection)d>=0,節點Ni(1=<i<=m),參數ui(1=<i<=m)。當參數顯示标志位p=1時,參數u才會顯示。多段線L通過這些節點,多段線L逼近曲線C的逼近偏差定義如下所示: 

Representation Data in OpenCascade BRep

參數ui(1=<i<=m)是曲線C上通過節點Ni的參數值: 

Representation Data in OpenCascade BRep

示例資料表示的多段線為:m=2,參數顯示标志位p=1,逼近偏差d=0.1,節點N1=(1,0,0),N2=(2,0,0),參數u1=0,u2=1。 

三、細分曲面 Subdivision of surfaces

我們知道使用參數方程可以精确表示出三維曲線和曲面,但是參數方程表示的曲線曲面并不能直接交給OpenGL直接顯示出來。為此,圖形學中廣泛使用三角網格來表達三維模型,即用三角形組成的面片清單來近似逼近表示三維模型。 

Representation Data in OpenCascade BRep

Figure 3.1 Triangulation of Chinese Dragon 

用三角網格表示的曲面需要解決幾個問題:三角網格的産生、描述、周遊、簡化和壓縮等。在OpenCascade中三角網格的産生使用算法Delaunay三角剖分算法生成網格資料,網格的描述使用類Poly_Triangulation。BRep檔案中也儲存三角網格的資料,如下所示: 

Representation Data in OpenCascade BRep
Representation Data in OpenCascade BRep

<triangulation record>定義了逼近曲面S的三角剖分T(triangulation)。三角剖分的資料包含節點數m>=3,三角形數k>=1,參數顯示标志位p,逼近偏差d>=0,節點Ni(1<=i<=m),參數對ui,vi(1<=i<=m),三角形nj,1,nj,2,nj,3。參數隻有當參數顯示标志位p=1時才顯示。三角剖分逼近曲面的偏差d定義如下所示: 

Representation Data in OpenCascade BRep

參數對ui,vi描述了曲面S上過節點Ni的參數: 

Representation Data in OpenCascade BRep

三角形nj,1, nj,2, nj,3用來取得三角形的三個頂點值Nnj,1,Nnj,2,Nnj,3,節點周遊的順序就是Nnj,1,Nnj,2,Nnj,3。從三角剖分T的任意一側周遊,所有三角形都有相同的方向:順時針或逆時針。 

三角剖分中的三角形資料: 

Representation Data in OpenCascade BRep

表示的三角剖分為:m=4個節點,k=2個三角形,參數顯示标志位p=1,逼近偏差d=0,節點N1(0,0,0),N2(0,0,3),N3(0,2,3),N4(0,2,0),參數值(u1,v1)=(0,0),(u2,v2)=(3,0),(u3,v3)=(3,-2),(u4,v4)=(0,-2)。從點(1,0,0)((-1,0,0)),三角形是順時針(逆時針)的。 

四、程式示例 Code Example

通過建立多段線和三角網格資料并将其輸出,可以了解BRep檔案中用來顯示的離散的資料結構。程式示例如下所示:

/*
*    Copyright (c) 2013 eryar All Rights Reserved.
*
*        File    : Main.cpp
*        Author  : [email protected]
*        Date    : 2013-12-12 21:46
*        Version : 1.0v
*
*    Description : There are two kind of data for shape representation 
*                  of the BRep file of OpenCascade. One is Polyline to
*                  approximates a 3D curve; the other is triangulations
*                  to approximates a surface.
*
*       KeyWords : OpenCascade, BRep File, Polygon, Triangulation
*                  
*/

#define WNT
#include <TColStd_Array1OfReal.hxx>
#include <TColgp_Array1OfPnt.hxx>
#include <TColgp_Array1OfPnt2d.hxx>

#include <Poly.hxx>
#include <Poly_Polygon3D.hxx>
#include <Poly_Array1OfTriangle.hxx>
#include <Poly_Triangulation.hxx>

#pragma comment(lib, "TKernel.lib")
#pragma comment(lib, "TKMath.lib")

int main(void)
{
    // 3D Polygons:
    // Polygon3D 1
    // 2 1
    // 0.1
    // 1 0 0 2 0 0
    // 0 1
    TColStd_Array1OfReal parameters(1, 2);
    TColgp_Array1OfPnt nodes(1, 2);
    Handle_Poly_Polygon3D polyline;

    nodes.SetValue(1, gp_Pnt(1, 0, 0));
    nodes.SetValue(2, gp_Pnt(2, 0, 0));

    parameters.SetValue(1, 0.0);
    parameters.SetValue(2, 1.0);

    polyline = new Poly_Polygon3D(nodes, parameters);
    polyline->Deflection(0.1);

    Poly::Write(polyline, std::cout);
    Poly::Write(polyline, std::cout, false);

    // Triangulations.
    // 4 2 1 0
    // 0 0 0 0 0 3 0 2 3 0 2 0 0 0 3 0 3 -2 0 -2 2 4 3 2 1 4 
    Standard_Integer nodeCount = 4;
    Standard_Integer triangleCount = 2;
    Standard_Real deflection = 0.0;
    Standard_Boolean hasUV = Standard_True;

    TColgp_Array1OfPnt triNodes(1, nodeCount);
    TColgp_Array1OfPnt2d UVNodes(1, nodeCount);
    Poly_Array1OfTriangle triangles(1, triangleCount);
    Handle_Poly_Triangulation triangulation;

    triNodes(1).SetCoord(0, 0, 0);
    triNodes(2).SetCoord(0, 0, 3);
    triNodes(3).SetCoord(0, 2, 3);
    triNodes(4).SetCoord(0, 2, 0);

    UVNodes(1).SetCoord(0.0, 0.0);
    UVNodes(2).SetCoord(3.0, 0.0);
    UVNodes(3).SetCoord(3.0, -2.0);
    UVNodes(4).SetCoord(0.0, -2.0);

    triangles(1).Set(2, 4, 3);
    triangles(2).Set(2, 1, 4);

    triangulation = new Poly_Triangulation(triNodes, UVNodes, triangles);
    triangulation->Deflection(deflection);

    Poly::Write(triangulation, std::cout);
    Poly::Write(triangulation, std::cout, false);

    return 0;
}      

輸出結果如下所示: 

Poly_Polygon3D
2 1
0.1
1 0 0
2 0 0
0 1
Poly_Polygon3D
       2 Nodes
with parameters
Deflection : 0.1

Nodes :
         1 :                 1                 0                 0
         2 :                 2                 0                 0

Parameters :
0 1
Poly_Triangulation
4 2 1
0
0 0 0
0 0 3
0 2 3
0 2 0
0 0
3 0
3 -2
0 -2
2 4 3
2 1 4
Poly_Triangulation
       4 Nodes
       2 Triangles
with UV nodes
Deflection : 0

3D Nodes :
         1 :                 0                 0                 0
         2 :                 0                 0                 3
         3 :                 0                 2                 3
         4 :                 0                 2                 0

UV Nodes :
         1 :                 0                 0
         2 :                 3                 0
         3 :                 3                -2
         4 :                 0                -2

Triangles :
         1 :          2          4          3
         2 :          2          1          4
Press any key to continue . . .      

五、結論

繼續閱讀