在OpenSceneGraph中繪制OpenCascade的曲面
Render?OpenCascade Geometry Surfaces in OpenSceneGraph
摘要Abstract:本文對OpenCascade中的幾何曲面數(shù)據(jù)進行簡要說明,并結(jié)合OpenSceneGraph將這些曲面顯示。?
關(guān)鍵字Key Words:OpenCascade、OpenSceneGraph、Geometry Surface、NURBS?
一、引言 Introduction
《BRep Format Description White Paper》中對OpenCascade的幾何數(shù)據(jù)結(jié)構(gòu)進行了詳細說明。BRep文件中用到的曲面總共有11種:?
1.Plane 平面;?
2.Cylinder 圓柱面;?
3.Cone 圓錐面;?
4.Sphere 球面;?
5.Torus 圓環(huán)面;?
6.Linear Extrusion 線性拉伸面;?
7.Revolution Surface 旋轉(zhuǎn)曲面;?
8.Bezier Surface 貝塞爾面;?
9.B-Spline Surface B樣條曲面;?
10.Rectangle Trim Surface 矩形裁剪曲面;?
11.Offset Surface 偏移曲面;?
曲面的幾何數(shù)據(jù)類都有一個共同的基類Geom_Surface,類圖如下所示:?
Figure 1.1 Geometry Surface class diagram?
抽象基類Geom_Surface有幾個純虛函數(shù)Bounds()、Value()等,可用來計算曲面上的點。類圖如下所示:?
Figure 1.2 Geom_Surface class diagram?
與另一幾何內(nèi)核sgCore中的幾何的概念一致,幾何(geometry)是用參數(shù)方程對曲線曲面精確表示的。?
每種曲面都對純虛函數(shù)進行實現(xiàn),使計算曲面上點的方式統(tǒng)一。?
曲線C(u)是單參數(shù)的矢值函數(shù),它是由直線段到三維歐幾里得空間的映射。曲面是關(guān)于兩個參數(shù)u和v的矢值函數(shù),它表示由uv平面上的二維區(qū)域R到三維歐幾里得空間的映射。把曲面表示成雙參數(shù)的形式為:?
它的參數(shù)方程為:?
u,v參數(shù)形成了一個參數(shù)平面,參數(shù)的變化區(qū)間在參數(shù)平面上構(gòu)成一個矩形區(qū)域。正常情況下,參數(shù)域內(nèi)的點(u,v)與曲面上的點r(u,v)是一一對應(yīng)的映射關(guān)系。?
給定一個具體的曲面方程,稱之為給定了一個曲面的參數(shù)化。它既決定了所表示的曲面的形狀,也決定了該曲面上的點與其參數(shù)域內(nèi)的點的一種對應(yīng)關(guān)系。同樣地,曲面的參數(shù)化不是唯一的。?
曲面雙參數(shù)u,v的變化范圍往往取為單位正方形,即u∈[0,1],v∈[0,1]。這樣討論曲面方程時,即簡單、方便,又不失一般性。?
二、程序示例 Code Example
使用函數(shù)Value(u, v)根據(jù)參數(shù)計算出曲面上的點,將點分u,v方向連成線,可以繪制出曲面的線框模型。程序如下所示:?
?
/* * Copyright (c) 2013 eryar All Rights Reserved. * * File : Main.cpp * Author : eryar@163.com * Date : 2013-08-11 10:36 * Version : V1.0 * * Description : Draw OpenCascade Geometry Surfaces in OpenSceneGraph. * */ // OpenSceneGraph #include <osgDB/ReadFile> #include <osgViewer/Viewer> #include <osgGA/StateSetManipulator> #include <osgViewer/ViewerEventHandlers> #pragma comment(lib, "osgd.lib") #pragma comment(lib, "osgDBd.lib") #pragma comment(lib, "osgGAd.lib") #pragma comment(lib, "osgViewerd.lib") // OpenCascade #define WNT #include <TColgp_Array2OfPnt.hxx> #include <TColStd_HArray1OfInteger.hxx> #include <TColGeom_Array2OfBezierSurface.hxx> #include <GeomConvert_CompBezierSurfacesToBSplineSurface.hxx> #include <Geom_Surface.hxx> #include <Geom_BezierSurface.hxx> #include <Geom_BSplineSurface.hxx> #include <Geom_ConicalSurface.hxx> #include <Geom_CylindricalSurface.hxx> #include <Geom_Plane.hxx> #include <Geom_ToroidalSurface.hxx> #include <Geom_SphericalSurface.hxx> #pragma comment(lib, "TKernel.lib") #pragma comment(lib, "TKMath.lib") #pragma comment(lib, "TKG3d.lib") #pragma comment(lib, "TKGeomBase.lib") // Approximation Delta. const double APPROXIMATION_DELTA = 0.1 ; /* * * @breif Build geometry surface. */ osg::Node * buildSurface( const Geom_Surface& surface) { osg::ref_ptr <osg::Geode> geode = new osg::Geode(); gp_Pnt point; Standard_Real uFirst = 0.0 ; Standard_Real vFirst = 0.0 ; Standard_Real uLast = 0.0 ; Standard_Real vLast = 0.0 ; surface.Bounds(uFirst, uLast, vFirst, vLast); Precision::IsNegativeInfinite(uFirst) ? uFirst = - 1.0 : uFirst; Precision::IsInfinite(uLast) ? uLast = 1.0 : uLast; Precision::IsNegativeInfinite(vFirst) ? vFirst = - 1.0 : vFirst; Precision::IsInfinite(vLast) ? vLast = 1.0 : vLast; // Approximation in v direction. for (Standard_Real u = uFirst; u <= uLast; u += APPROXIMATION_DELTA) { osg::ref_ptr <osg::Geometry> linesGeom = new osg::Geometry(); osg::ref_ptr <osg::Vec3Array> pointsVec = new osg::Vec3Array(); for (Standard_Real v = vFirst; v <= vLast; v += APPROXIMATION_DELTA) { point = surface.Value(u, v); pointsVec -> push_back(osg::Vec3(point.X(), point.Y(), point.Z())); } // Set the colors. osg::ref_ptr<osg::Vec4Array> colors = new osg::Vec4Array; colors ->push_back(osg::Vec4( 1.0f , 1.0f , 0.0f , 0.0f )); linesGeom ->setColorArray(colors. get ()); linesGeom -> setColorBinding(osg::Geometry::BIND_OVERALL); // Set the normal in the same way of color. osg::ref_ptr<osg::Vec3Array> normals = new osg::Vec3Array; normals ->push_back(osg::Vec3( 0.0f , - 1.0f , 0.0f )); linesGeom ->setNormalArray(normals. get ()); linesGeom -> setNormalBinding(osg::Geometry::BIND_OVERALL); // Set vertex array. linesGeom-> setVertexArray(pointsVec); linesGeom ->addPrimitiveSet( new osg::DrawArrays(osg::PrimitiveSet::LINE_STRIP, 0 , pointsVec-> size())); geode ->addDrawable(linesGeom. get ()); } // Approximation in u direction. for (Standard_Real v = vFirst; v <= vLast; v += APPROXIMATION_DELTA) { osg::ref_ptr <osg::Geometry> linesGeom = new osg::Geometry(); osg::ref_ptr <osg::Vec3Array> pointsVec = new osg::Vec3Array(); for (Standard_Real u = vFirst; u <= uLast; u += APPROXIMATION_DELTA) { point = surface.Value(u, v); pointsVec -> push_back(osg::Vec3(point.X(), point.Y(), point.Z())); } // Set the colors. osg::ref_ptr<osg::Vec4Array> colors = new osg::Vec4Array; colors ->push_back(osg::Vec4( 1.0f , 1.0f , 0.0f , 0.0f )); linesGeom ->setColorArray(colors. get ()); linesGeom -> setColorBinding(osg::Geometry::BIND_OVERALL); // Set the normal in the same way of color. osg::ref_ptr<osg::Vec3Array> normals = new osg::Vec3Array; normals ->push_back(osg::Vec3( 0.0f , - 1.0f , 0.0f )); linesGeom ->setNormalArray(normals. get ()); linesGeom -> setNormalBinding(osg::Geometry::BIND_OVERALL); // Set vertex array. linesGeom-> setVertexArray(pointsVec); linesGeom ->addPrimitiveSet( new osg::DrawArrays(osg::PrimitiveSet::LINE_STRIP, 0 , pointsVec-> size())); geode ->addDrawable(linesGeom. get ()); } return geode.release(); } /* * * @breif Test geometry surfaces of OpenCascade. */ osg::Node * buildScene( void ) { osg::ref_ptr <osg::Group> root = new osg::Group(); // Test Plane. Geom_Plane plane(gp::XOY()); root -> addChild(buildSurface(plane)); // Test Bezier Surface and B-Spline Surface. TColgp_Array2OfPnt array1( 1 , 3 , 1 , 3 ); TColgp_Array2OfPnt array2( 1 , 3 , 1 , 3 ); TColgp_Array2OfPnt array3( 1 , 3 , 1 , 3 ); TColgp_Array2OfPnt array4( 1 , 3 , 1 , 3 ); array1.SetValue( 1 , 1 ,gp_Pnt( 1 , 1 , 1 )); array1.SetValue( 1 , 2 ,gp_Pnt( 2 , 1 , 2 )); array1.SetValue( 1 , 3 ,gp_Pnt( 3 , 1 , 1 )); array1.SetValue( 2 , 1 ,gp_Pnt( 1 , 2 , 1 )); array1.SetValue( 2 , 2 ,gp_Pnt( 2 , 2 , 2 )); array1.SetValue( 2 , 3 ,gp_Pnt( 3 , 2 , 0 )); array1.SetValue( 3 , 1 ,gp_Pnt( 1 , 3 , 2 )); array1.SetValue( 3 , 2 ,gp_Pnt( 2 , 3 , 1 )); array1.SetValue( 3 , 3 ,gp_Pnt( 3 , 3 , 0 )); array2.SetValue( 1 , 1 ,gp_Pnt( 3 , 1 , 1 )); array2.SetValue( 1 , 2 ,gp_Pnt( 4 , 1 , 1 )); array2.SetValue( 1 , 3 ,gp_Pnt( 5 , 1 , 2 )); array2.SetValue( 2 , 1 ,gp_Pnt( 3 , 2 , 0 )); array2.SetValue( 2 , 2 ,gp_Pnt( 4 , 2 , 1 )); array2.SetValue( 2 , 3 ,gp_Pnt( 5 , 2 , 2 )); array2.SetValue( 3 , 1 ,gp_Pnt( 3 , 3 , 0 )); array2.SetValue( 3 , 2 ,gp_Pnt( 4 , 3 , 0 )); array2.SetValue( 3 , 3 ,gp_Pnt( 5 , 3 , 1 )); array3.SetValue( 1 , 1 ,gp_Pnt( 1 , 3 , 2 )); array3.SetValue( 1 , 2 ,gp_Pnt( 2 , 3 , 1 )); array3.SetValue( 1 , 3 ,gp_Pnt( 3 , 3 , 0 )); array3.SetValue( 2 , 1 ,gp_Pnt( 1 , 4 , 1 )); array3.SetValue( 2 , 2 ,gp_Pnt( 2 , 4 , 0 )); array3.SetValue( 2 , 3 ,gp_Pnt( 3 , 4 , 1 )); array3.SetValue( 3 , 1 ,gp_Pnt( 1 , 5 , 1 )); array3.SetValue( 3 , 2 ,gp_Pnt( 2 , 5 , 1 )); array3.SetValue( 3 , 3 ,gp_Pnt( 3 , 5 , 2 )); array4.SetValue( 1 , 1 ,gp_Pnt( 3 , 3 , 0 )); array4.SetValue( 1 , 2 ,gp_Pnt( 4 , 3 , 0 )); array4.SetValue( 1 , 3 ,gp_Pnt( 5 , 3 , 1 )); array4.SetValue( 2 , 1 ,gp_Pnt( 3 , 4 , 1 )); array4.SetValue( 2 , 2 ,gp_Pnt( 4 , 4 , 1 )); array4.SetValue( 2 , 3 ,gp_Pnt( 5 , 4 , 1 )); array4.SetValue( 3 , 1 ,gp_Pnt( 3 , 5 , 2 )); array4.SetValue( 3 , 2 ,gp_Pnt( 4 , 5 , 2 )); array4.SetValue( 3 , 3 ,gp_Pnt( 5 , 5 , 1 )); Geom_BezierSurface BZ1(array1); Geom_BezierSurface BZ2(array2); Geom_BezierSurface BZ3(array3); Geom_BezierSurface BZ4(array4); root -> addChild(buildSurface(BZ1)); root -> addChild(buildSurface(BZ2)); root -> addChild(buildSurface(BZ3)); root -> addChild(buildSurface(BZ4)); Handle_Geom_BezierSurface BS1 = new Geom_BezierSurface(array1); Handle_Geom_BezierSurface BS2 = new Geom_BezierSurface(array2); Handle_Geom_BezierSurface BS3 = new Geom_BezierSurface(array3); Handle_Geom_BezierSurface BS4 = new Geom_BezierSurface(array4); TColGeom_Array2OfBezierSurface bezierarray( 1 , 2 , 1 , 2 ); bezierarray.SetValue( 1 , 1 ,BS1); bezierarray.SetValue( 1 , 2 ,BS2); bezierarray.SetValue( 2 , 1 ,BS3); bezierarray.SetValue( 2 , 2 ,BS4); GeomConvert_CompBezierSurfacesToBSplineSurface BB (bezierarray); if (BB.IsDone()) { Geom_BSplineSurface BSPLSURF( BB.Poles() -> Array2(), BB.UKnots() -> Array1(), BB.VKnots() -> Array1(), BB.UMultiplicities() -> Array1(), BB.VMultiplicities() -> Array1(), BB.UDegree(), BB.VDegree() ); BSPLSURF.Translate(gp_Vec( 0 , 0 , 2 )); root -> addChild(buildSurface(BSPLSURF)); } // Test Spherical Surface. Geom_SphericalSurface sphericalSurface(gp::XOY(), 1.0 ); sphericalSurface.Translate(gp_Vec( 2.5 , 0.0 , 0.0 )); root -> addChild(buildSurface(sphericalSurface)); // Test Conical Surface. Geom_ConicalSurface conicalSurface(gp::XOY(), M_PI/ 8 , 1.0 ); conicalSurface.Translate(gp_Vec( 5.0 , 0.0 , 0.0 )); root -> addChild(buildSurface(conicalSurface)); // Test Cylindrical Surface. Geom_CylindricalSurface cylindricalSurface(gp::XOY(), 1.0 ); cylindricalSurface.Translate(gp_Vec( 8.0 , 0.0 , 0.0 )); root -> addChild(buildSurface(cylindricalSurface)); // Test Toroidal Surface. Geom_ToroidalSurface toroidalSurface(gp::XOY(), 1.0 , 0.2 ); toroidalSurface.Translate(gp_Vec( 11.0 , 0.0 , 0.0 )); root -> addChild(buildSurface(toroidalSurface)); return root.release(); } int main( int argc, char * argv[]) { osgViewer::Viewer myViewer; myViewer.setSceneData(buildScene()); myViewer.addEventHandler( new osgGA::StateSetManipulator(myViewer.getCamera()-> getOrCreateStateSet())); myViewer.addEventHandler( new osgViewer::StatsHandler); myViewer.addEventHandler( new osgViewer::WindowSizeHandler); return myViewer.run(); }
程序效果如下圖所示:?
Figure 2.1 OpenCascade Geometry Surfaces in OpenSceneGraph?
三、結(jié)論 Conclusion?
根據(jù)OpenCascade中的幾何曲面的函數(shù)Value(u, v)可以計算出曲面上的點。分u方向和v方向分別繪制曲面上的點,并將之連接成線,即可以表示出曲面的線框模型。因為這樣的模型沒有面的信息,所以不能有光照效果、材質(zhì)效果等。要有光照、材質(zhì)的信息,必須將曲面進行三角剖分。相關(guān)的剖分算法有Delaunay三角剖分等。?
?
PDF Version: Draw OpenCascade Geometry Surfaces in OpenSceneGraph
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯(lián)系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
