在OpenSceneGraph中繪制OpenCascade的曲面
Draw OpenCascade Geometry Surfaces in OpenSceneGraph
eryar@163.com
摘要Abstract:本文對(duì)OpenCascade中的幾何曲面數(shù)據(jù)進(jìn)行簡(jiǎn)要說(shuō)明,并結(jié)合OpenSceneGraph將這些曲面顯示。
關(guān)鍵字Key Words:OpenCascade、OpenSceneGraph、Geometry Surface、NURBS
一、引言 Introduction
《BRep Format Description White Paper》中對(duì)OpenCascade的幾何數(shù)據(jù)結(jié)構(gòu)進(jìn)行了詳細(xì)說(shuō)明。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ù)類(lèi)都有一個(gè)共同的基類(lèi)Geom_Surface,類(lèi)圖如下所示:
Figure 1.1 Geometry Surface class diagram
抽象基類(lèi)Geom_Surface有幾個(gè)純虛函數(shù)Bounds()、Value()等,可用來(lái)計(jì)算曲面上的點(diǎn)。類(lèi)圖如下所示:
Figure 1.2 Geom_Surface class diagram
與另一幾何內(nèi)核sgCore中的幾何的概念一致,幾何(geometry)是用參數(shù)方程對(duì)曲線曲面精確表示的。
每種曲面都對(duì)純虛函數(shù)進(jìn)行實(shí)現(xiàn),使計(jì)算曲面上點(diǎn)的方式統(tǒng)一。
曲線C(u)是單參數(shù)的矢值函數(shù),它是由直線段到三維歐幾里得空間的映射。曲面是關(guān)于兩個(gè)參數(shù)u和v的矢值函數(shù),它表示由uv平面上的二維區(qū)域R到三維歐幾里得空間的映射。把曲面表示成雙參數(shù)的形式為:
它的參數(shù)方程為:
u,v參數(shù)形成了一個(gè)參數(shù)平面,參數(shù)的變化區(qū)間在參數(shù)平面上構(gòu)成一個(gè)矩形區(qū)域。正常情況下,參數(shù)域內(nèi)的點(diǎn)(u,v)與曲面上的點(diǎn)r(u,v)是一一對(duì)應(yīng)的映射關(guān)系。
給定一個(gè)具體的曲面方程,稱(chēng)之為給定了一個(gè)曲面的參數(shù)化。它既決定了所表示的曲面的形狀,也決定了該曲面上的點(diǎn)與其參數(shù)域內(nèi)的點(diǎn)的一種對(duì)應(yīng)關(guān)系。同樣地,曲面的參數(shù)化不是唯一的。
曲面雙參數(shù)u,v的變化范圍往往取為單位正方形,即u∈[0,1],v∈[0,1]。這樣討論曲面方程時(shí),即簡(jiǎn)單、方便,又不失一般性。
二、程序示例 Code Example
使用函數(shù)Value(u, v)根據(jù)參數(shù)計(jì)算出曲面上的點(diǎn),將點(diǎn)分u,v方向連成線,可以繪制出曲面的線框模型。程序如下所示:
1 /*
2 * Copyright (c) 2013 eryar All Rights Reserved.
3 *
4 * File : Main.cpp
5 * Author : eryar@163.com
6 * Date : 2013-08-11 10:36
7 * Version : V1.0
8 *
9 * Description : Draw OpenCascade Geometry Surfaces in OpenSceneGraph.
10 *
11 */
12
13 // OpenSceneGraph
14 #include <osgDB/ReadFile>
15 #include <osgViewer/Viewer>
16 #include <osgGA/StateSetManipulator>
17 #include <osgViewer/ViewerEventHandlers>
18
19 #pragma comment(lib, "osgd.lib")
20 #pragma comment(lib, "osgDBd.lib")
21 #pragma comment(lib, "osgGAd.lib")
22 #pragma comment(lib, "osgViewerd.lib")
23
24 // OpenCascade
25 #define WNT
26 #include <TColgp_Array2OfPnt.hxx>
27 #include <TColStd_HArray1OfInteger.hxx>
28 #include <TColGeom_Array2OfBezierSurface.hxx>
29 #include <GeomConvert_CompBezierSurfacesToBSplineSurface.hxx>
30
31 #include <Geom_Surface.hxx>
32 #include <Geom_BezierSurface.hxx>
33 #include <Geom_BSplineSurface.hxx>
34 #include <Geom_ConicalSurface.hxx>
35 #include <Geom_CylindricalSurface.hxx>
36 #include <Geom_Plane.hxx>
37 #include <Geom_ToroidalSurface.hxx>
38 #include <Geom_SphericalSurface.hxx>
39
40 #pragma comment(lib, "TKernel.lib")
41 #pragma comment(lib, "TKMath.lib")
42 #pragma comment(lib, "TKG3d.lib")
43 #pragma comment(lib, "TKGeomBase.lib")
44
45 // Approximation Delta.
46 const double APPROXIMATION_DELTA = 0.1;
47
48 /**
49 * @breif Build geometry surface.
50 */
51 osg::Node* buildSurface(const Geom_Surface& surface)
52 {
53 osg::ref_ptr<osg::Geode> geode = new osg::Geode();
54
55 gp_Pnt point;
56 Standard_Real uFirst = 0.0;
57 Standard_Real vFirst = 0.0;
58 Standard_Real uLast = 0.0;
59 Standard_Real vLast = 0.0;
60
61 surface.Bounds(uFirst, uLast, vFirst, vLast);
62
63 Precision::IsNegativeInfinite(uFirst) ? uFirst = -1.0 : uFirst;
64 Precision::IsInfinite(uLast) ? uLast = 1.0 : uLast;
65
66 Precision::IsNegativeInfinite(vFirst) ? vFirst = -1.0 : vFirst;
67 Precision::IsInfinite(vLast) ? vLast = 1.0 : vLast;
68
69 // Approximation in v direction.
70 for (Standard_Real u = uFirst; u <= uLast; u += APPROXIMATION_DELTA)
71 {
72 osg::ref_ptr<osg::Geometry> linesGeom = new osg::Geometry();
73 osg::ref_ptr<osg::Vec3Array> pointsVec = new osg::Vec3Array();
74
75 for (Standard_Real v = vFirst; v <= vLast; v += APPROXIMATION_DELTA)
76 {
77 point = surface.Value(u, v);
78
79 pointsVec->push_back(osg::Vec3(point.X(), point.Y(), point.Z()));
80 }
81
82 // Set the colors.
83 osg::ref_ptr<osg::Vec4Array> colors = new osg::Vec4Array;
84 colors->push_back(osg::Vec4(1.0f, 1.0f, 0.0f, 0.0f));
85 linesGeom->setColorArray(colors.get());
86 linesGeom->setColorBinding(osg::Geometry::BIND_OVERALL);
87
88 // Set the normal in the same way of color.
89 osg::ref_ptr<osg::Vec3Array> normals = new osg::Vec3Array;
90 normals->push_back(osg::Vec3(0.0f, -1.0f, 0.0f));
91 linesGeom->setNormalArray(normals.get());
92 linesGeom->setNormalBinding(osg::Geometry::BIND_OVERALL);
93
94 // Set vertex array.
95 linesGeom->setVertexArray(pointsVec);
96 linesGeom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINE_STRIP, 0, pointsVec->size()));
97
98 geode->addDrawable(linesGeom.get());
99 }
100
101 // Approximation in u direction.
102 for (Standard_Real v = vFirst; v <= vLast; v += APPROXIMATION_DELTA)
103 {
104 osg::ref_ptr<osg::Geometry> linesGeom = new osg::Geometry();
105 osg::ref_ptr<osg::Vec3Array> pointsVec = new osg::Vec3Array();
106
107 for (Standard_Real u = vFirst; u <= uLast; u += APPROXIMATION_DELTA)
108 {
109 point = surface.Value(u, v);
110
111 pointsVec->push_back(osg::Vec3(point.X(), point.Y(), point.Z()));
112 }
113
114 // Set the colors.
115 osg::ref_ptr<osg::Vec4Array> colors = new osg::Vec4Array;
116 colors->push_back(osg::Vec4(1.0f, 1.0f, 0.0f, 0.0f));
117 linesGeom->setColorArray(colors.get());
118 linesGeom->setColorBinding(osg::Geometry::BIND_OVERALL);
119
120 // Set the normal in the same way of color.
121 osg::ref_ptr<osg::Vec3Array> normals = new osg::Vec3Array;
122 normals->push_back(osg::Vec3(0.0f, -1.0f, 0.0f));
123 linesGeom->setNormalArray(normals.get());
124 linesGeom->setNormalBinding(osg::Geometry::BIND_OVERALL);
125
126 // Set vertex array.
127 linesGeom->setVertexArray(pointsVec);
128 linesGeom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINE_STRIP, 0, pointsVec->size()));
129
130 geode->addDrawable(linesGeom.get());
131 }
132
133 return geode.release();
134 }
135
136 /**
137 * @breif Test geometry surfaces of OpenCascade.
138 */
139 osg::Node* buildScene(void)
140 {
141 osg::ref_ptr<osg::Group> root = new osg::Group();
142
143 // Test Plane.
144 Geom_Plane plane(gp::XOY());
145 root->addChild(buildSurface(plane));
146
147 // Test Bezier Surface and B-Spline Surface.
148 TColgp_Array2OfPnt array1(1,3,1,3);
149 TColgp_Array2OfPnt array2(1,3,1,3);
150 TColgp_Array2OfPnt array3(1,3,1,3);
151 TColgp_Array2OfPnt array4(1,3,1,3);
152
153 array1.SetValue(1,1,gp_Pnt(1,1,1));
154 array1.SetValue(1,2,gp_Pnt(2,1,2));
155 array1.SetValue(1,3,gp_Pnt(3,1,1));
156 array1.SetValue(2,1,gp_Pnt(1,2,1));
157 array1.SetValue(2,2,gp_Pnt(2,2,2));
158 array1.SetValue(2,3,gp_Pnt(3,2,0));
159 array1.SetValue(3,1,gp_Pnt(1,3,2));
160 array1.SetValue(3,2,gp_Pnt(2,3,1));
161 array1.SetValue(3,3,gp_Pnt(3,3,0));
162
163 array2.SetValue(1,1,gp_Pnt(3,1,1));
164 array2.SetValue(1,2,gp_Pnt(4,1,1));
165 array2.SetValue(1,3,gp_Pnt(5,1,2));
166 array2.SetValue(2,1,gp_Pnt(3,2,0));
167 array2.SetValue(2,2,gp_Pnt(4,2,1));
168 array2.SetValue(2,3,gp_Pnt(5,2,2));
169 array2.SetValue(3,1,gp_Pnt(3,3,0));
170 array2.SetValue(3,2,gp_Pnt(4,3,0));
171 array2.SetValue(3,3,gp_Pnt(5,3,1));
172
173 array3.SetValue(1,1,gp_Pnt(1,3,2));
174 array3.SetValue(1,2,gp_Pnt(2,3,1));
175 array3.SetValue(1,3,gp_Pnt(3,3,0));
176 array3.SetValue(2,1,gp_Pnt(1,4,1));
177 array3.SetValue(2,2,gp_Pnt(2,4,0));
178 array3.SetValue(2,3,gp_Pnt(3,4,1));
179 array3.SetValue(3,1,gp_Pnt(1,5,1));
180 array3.SetValue(3,2,gp_Pnt(2,5,1));
181 array3.SetValue(3,3,gp_Pnt(3,5,2));
182
183 array4.SetValue(1,1,gp_Pnt(3,3,0));
184 array4.SetValue(1,2,gp_Pnt(4,3,0));
185 array4.SetValue(1,3,gp_Pnt(5,3,1));
186 array4.SetValue(2,1,gp_Pnt(3,4,1));
187 array4.SetValue(2,2,gp_Pnt(4,4,1));
188 array4.SetValue(2,3,gp_Pnt(5,4,1));
189 array4.SetValue(3,1,gp_Pnt(3,5,2));
190 array4.SetValue(3,2,gp_Pnt(4,5,2));
191 array4.SetValue(3,3,gp_Pnt(5,5,1));
192
193 Geom_BezierSurface BZ1(array1);
194 Geom_BezierSurface BZ2(array2);
195 Geom_BezierSurface BZ3(array3);
196 Geom_BezierSurface BZ4(array4);
197 root->addChild(buildSurface(BZ1));
198 root->addChild(buildSurface(BZ2));
199 root->addChild(buildSurface(BZ3));
200 root->addChild(buildSurface(BZ4));
201
202 Handle_Geom_BezierSurface BS1 = new Geom_BezierSurface(array1);
203 Handle_Geom_BezierSurface BS2 = new Geom_BezierSurface(array2);
204 Handle_Geom_BezierSurface BS3 = new Geom_BezierSurface(array3);
205 Handle_Geom_BezierSurface BS4 = new Geom_BezierSurface(array4);
206 TColGeom_Array2OfBezierSurface bezierarray(1,2,1,2);
207 bezierarray.SetValue(1,1,BS1);
208 bezierarray.SetValue(1,2,BS2);
209 bezierarray.SetValue(2,1,BS3);
210 bezierarray.SetValue(2,2,BS4);
211
212 GeomConvert_CompBezierSurfacesToBSplineSurface BB (bezierarray);
213
214 if (BB.IsDone())
215 {
216 Geom_BSplineSurface BSPLSURF(
217 BB.Poles()->Array2(),
218 BB.UKnots()->Array1(),
219 BB.VKnots()->Array1(),
220 BB.UMultiplicities()->Array1(),
221 BB.VMultiplicities()->Array1(),
222 BB.UDegree(),
223 BB.VDegree() );
224
225 BSPLSURF.Translate(gp_Vec(0,0,2));
226
227 root->addChild(buildSurface(BSPLSURF));
228 }
229
230 // Test Spherical Surface.
231 Geom_SphericalSurface sphericalSurface(gp::XOY(), 1.0);
232 sphericalSurface.Translate(gp_Vec(2.5, 0.0, 0.0));
233 root->addChild(buildSurface(sphericalSurface));
234
235 // Test Conical Surface.
236 Geom_ConicalSurface conicalSurface(gp::XOY(), M_PI/8, 1.0);
237 conicalSurface.Translate(gp_Vec(5.0, 0.0, 0.0));
238 root->addChild(buildSurface(conicalSurface));
239
240 // Test Cylindrical Surface.
241 Geom_CylindricalSurface cylindricalSurface(gp::XOY(), 1.0);
242 cylindricalSurface.Translate(gp_Vec(8.0, 0.0, 0.0));
243 root->addChild(buildSurface(cylindricalSurface));
244
245 // Test Toroidal Surface.
246 Geom_ToroidalSurface toroidalSurface(gp::XOY(), 1.0, 0.2);
247 toroidalSurface.Translate(gp_Vec(11.0, 0.0, 0.0));
248 root->addChild(buildSurface(toroidalSurface));
249
250 return root.release();
251 }
252
253 int main(int argc, char* argv[])
254 {
255 osgViewer::Viewer myViewer;
256
257 myViewer.setSceneData(buildScene());
258
259 myViewer.addEventHandler(new osgGA::StateSetManipulator(myViewer.getCamera()->getOrCreateStateSet()));
260 myViewer.addEventHandler(new osgViewer::StatsHandler);
261 myViewer.addEventHandler(new osgViewer::WindowSizeHandler);
262
263 return myViewer.run();
264 }
程序效果如下圖所示:
Figure 2.1 OpenCascade Geometry Surfaces in OpenSceneGraph
三、結(jié)論 Conclusion
根據(jù)OpenCascade中的幾何曲面的函數(shù)Value(u, v)可以計(jì)算出曲面上的點(diǎn)。分u方向和v方向分別繪制曲面上的點(diǎn),并將之連接成線,即可以表示出曲面的線框模型。因?yàn)檫@樣的模型沒(méi)有面的信息,所以不能有光照效果、材質(zhì)效果等。要有光照、材質(zhì)的信息,必須將曲面進(jìn)行三角剖分。相關(guān)的剖分算法有Delaunay三角剖分等。