OpenCASCADE Linear Extrusion Surface
eryar@163.com
Abstract. OpenCASCADE linear extrusion surface is a generalized cylinder. Such a surface is obtained by sweeping a curve (called the “extruded curve” or “basis”) in a given direction (referred to as the direction of extrusion and defined by a unit vector). The u parameter is along the extruded curve. The v parameter is along the direction of extrusion. The form of a surface of linear extrusion is generally a ruled surface. It can be a cylindrical surface, or a planar surface.
Key Words. OpenCASCADE, Extrusion Surface, Sweeping
1. Introduction
一般柱面(The General Cylinder)可以由一段或整個(gè)圓弧沿一個(gè)方向偏移一定的距離得到。如下圖所示:
Figure 1.1 Extrusion Shapes
當(dāng)將頂點(diǎn)拉伸時(shí),會(huì)生成一條邊;當(dāng)將邊拉伸時(shí),會(huì)生成面;當(dāng)將Wire拉伸時(shí),會(huì)生成Shell,當(dāng)將面拉伸時(shí),會(huì)生成體。當(dāng)將曲線沿一個(gè)方向拉伸時(shí),會(huì)形成一個(gè)曲面,如果此方向?yàn)橹本€,則會(huì)生成一般柱面。如果此方向是曲線時(shí),會(huì)生成如下圖所示曲面:
Figure 1.2 Swept surface/ loft surface
本文主要介紹將曲線沿直線方向拉伸的算法,即一般柱面生成算法。并將生成的曲面在OpenSceneGraph中進(jìn)行顯示。
2.Cylinder Surface Definition
設(shè)W是一個(gè)單位向量,C(u)是定義在節(jié)點(diǎn)矢量U上,權(quán)值為wi的p次NURBS曲線。我們要得到一般柱面S(u,v)的表達(dá)式,S(u,v)是通過將C(u)沿方向W平行掃描(sweep)距離d得到的。記掃描方向的參數(shù)為v, 0<v<1,顯然,S(u,v)必須滿足以下兩個(gè)條件:
v 對(duì)于固定的u0, S(u0, v)為由C(u0)到C(u0)+dW的直線段;
v 對(duì)于固定的v0:
所要求的柱面的表達(dá)式為:
S(u,v)定義在節(jié)點(diǎn)矢量U和V上,這里V={0,0,1,1},U為C(u)的節(jié)點(diǎn)矢量??刂祈旤c(diǎn)由Pi,0=Pi和Pi,1=Pi+dW給出,權(quán)值wi,0=wi,1=wi。如下圖所示為一般柱面:
Figure 2.1 A general cylinder obtained by translating C(u) a distance d along W.
其中OpenCASCADE中一般柱面的表達(dá)式如下所示:
其取值范圍的代碼如下所示:
//=======================================================================
//function : Bounds
//purpose :
//=======================================================================
void Geom_SurfaceOfLinearExtrusion::Bounds ( Standard_Real& U1,
Standard_Real& U2,
Standard_Real& V1,
Standard_Real& V2 ) const {
V1 = -Precision::Infinite(); V2 = Precision::Infinite();
U1 = basisCurve->FirstParameter(); U2 = basisCurve->LastParameter();
}
由上代碼可知,參數(shù)在v方向上是趨于無窮的;在u方向上參數(shù)的范圍為曲線的范圍。計(jì)算柱面上點(diǎn)的方法代碼如下所示:
//=======================================================================
//function : D0
//purpose :
//=======================================================================
void Geom_SurfaceOfLinearExtrusion::D0 (const Standard_Real U,
const Standard_Real V,
Pnt& P) const {
XYZ Pxyz = direction.XYZ();
Pxyz.Multiply (V);
Pxyz.Add (basisCurve->Value (U).XYZ());
P.SetXYZ(Pxyz);
}
即將柱面上點(diǎn)先按V方向來計(jì)算,再按U方向來計(jì)算,最后將兩個(gè)方向的值相加即得到柱面上的點(diǎn)。
由上述代碼可知,OpenCASCADE中一般柱面沒有使用NURBS曲面來表示。根據(jù)這個(gè)方法,可以將任意曲線沿給定的方向來得到一個(gè)柱面,這個(gè)曲線可以是直線、圓弧、圓、橢圓等。關(guān)于柱面上更多算法,如求微分等,可以參考源程序。
3.Display the Surface
還是在OpenSceneGraph中來對(duì)一般柱面進(jìn)行可視化,來驗(yàn)證結(jié)果。因?yàn)镺penSceneGraph的簡(jiǎn)單易用,顯示曲面的程序代碼如下所示:
/*
* Copyright (c) 2013 to current year. All Rights Reserved.
*
* File : Main.cpp
* Author : eryar@163.com
* Date : 2014-11-23 10:18
* Version : OpenCASCADE6.8.0
*
* Description : Test the Linear Extrusion Surface of OpenCASCADE.
*
* Key Words : OpenCascade, Linear Extrusion Surface, General Cylinder
*
*/
// OpenCASCADE.
#define WNT
#include <Precision.hxx>
#include <gp_Circ.hxx>
#include <Geom_SurfaceOfLinearExtrusion.hxx>
#include <GC_MakeCircle.hxx>
#include <GC_MakeSegment.hxx>
#include <GC_MakeArcOfCircle.hxx>
#pragma comment(lib, "TKernel.lib")
#pragma comment(lib, "TKMath.lib")
#pragma comment(lib, "TKG3d.lib")
#pragma comment(lib, "TKGeomBase.lib")
// OpenSceneGraph.
#include <osgViewer/Viewer>
#include <osgViewer/ViewerEventHandlers>
#include <osgGA/StateSetManipulator>
#pragma comment(lib, "osgd.lib")
#pragma comment(lib, "osgGAd.lib")
#pragma comment(lib, "osgViewerd.lib")
const double TOLERANCE_EDGE = 1e-6;
const double APPROXIMATION_DELTA = 0.05;
/**
* @brief Render 3D geometry surface.
*/
osg::Node* BuildSurface(const Handle_Geom_Surface& theSurface)
{
osg::ref_ptr<osg::Geode> aGeode = new osg::Geode();
Standard_Real aU1 = 0.0;
Standard_Real aV1 = 0.0;
Standard_Real aU2 = 0.0;
Standard_Real aV2 = 0.0;
Standard_Real aDeltaU = 0.0;
Standard_Real aDeltaV = 0.0;
theSurface->Bounds(aU1, aU2, aV1, aV2);
// trim the parametrical space to avoid infinite space.
Precision::IsNegativeInfinite(aU1) ? aU1 = -1.0 : aU1;
Precision::IsInfinite(aU2) ? aU2 = 1.0 : aU2;
Precision::IsNegativeInfinite(aV1) ? aV1 = -1.0 : aV1;
Precision::IsInfinite(aV2) ? aV2 = 1.0 : aV2;
// Approximation in v direction.
aDeltaU = (aU2 - aU1) * APPROXIMATION_DELTA;
aDeltaV = (aV2 - aV1) * APPROXIMATION_DELTA;
for (Standard_Real u = aU1; (u - aU2) <= TOLERANCE_EDGE; u += aDeltaU)
{
osg::ref_ptr<osg::Geometry> aLine = new osg::Geometry();
osg::ref_ptr<osg::Vec3Array> aPoints = new osg::Vec3Array();
for (Standard_Real v = aV1; (v - aV2) <= TOLERANCE_EDGE; v += aDeltaV)
{
gp_Pnt aPoint = theSurface->Value(u, v);
aPoints->push_back(osg::Vec3(aPoint.X(), aPoint.Y(), aPoint.Z()));
}
// Set vertex array.
aLine->setVertexArray(aPoints);
aLine->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINE_STRIP, 0, aPoints->size()));
aGeode->addDrawable(aLine.get());
}
// Approximation in u direction.
for (Standard_Real v = aV1; (v - aV2) <= TOLERANCE_EDGE; v += aDeltaV)
{
osg::ref_ptr<osg::Geometry> aLine = new osg::Geometry();
osg::ref_ptr<osg::Vec3Array> aPoints = new osg::Vec3Array();
for (Standard_Real u = aU1; (u - aU2) <= TOLERANCE_EDGE; u += aDeltaU)
{
gp_Pnt aPoint = theSurface->Value(u, v);
aPoints->push_back(osg::Vec3(aPoint.X(), aPoint.Y(), aPoint.Z()));
}
// Set vertex array.
aLine->setVertexArray(aPoints);
aLine->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINE_STRIP, 0, aPoints->size()));
aGeode->addDrawable(aLine.get());
}
return aGeode.release();
}
/**
* @brief Build the test scene.
*/
osg::Node* BuildScene(void)
{
osg::ref_ptr<osg::Group> aRoot = new osg::Group();
// test the linear extrusion surface.
// test linear extrusion surface of a line.
Handle_Geom_Curve aSegment = GC_MakeSegment(gp_Pnt(3.0, 0.0, 0.0), gp_Pnt(6.0, 0.0, 0.0));
Handle_Geom_Surface aPlane = new Geom_SurfaceOfLinearExtrusion(aSegment, gp::DZ());
aRoot->addChild(BuildSurface(aPlane));
// test linear extrusion surface of a arc.
Handle_Geom_Curve aArc = GC_MakeArcOfCircle(gp_Circ(gp::ZOX(), 2.0), 0.0, M_PI, true);
Handle_Geom_Surface aSurface = new Geom_SurfaceOfLinearExtrusion(aArc, gp::DY());
aRoot->addChild(BuildSurface(aSurface));
// test linear extrusion surface of a circle.
Handle_Geom_Curve aCircle = GC_MakeCircle(gp::XOY(), 1.0);
Handle_Geom_Surface aCylinder = new Geom_SurfaceOfLinearExtrusion(aCircle, gp::DZ());
aRoot->addChild(BuildSurface(aCylinder));
return aRoot.release();
}
int main(int argc, char* argv[])
{
osgViewer::Viewer aViewer;
aViewer.setSceneData(BuildScene());
aViewer.addEventHandler(new osgGA::StateSetManipulator(
aViewer.getCamera()->getOrCreateStateSet()));
aViewer.addEventHandler(new osgViewer::StatsHandler);
aViewer.addEventHandler(new osgViewer::WindowSizeHandler);
return aViewer.run();
return 0;
}
上述顯示方法只是顯示線框的最簡(jiǎn)單的算法,只為驗(yàn)證一般柱面結(jié)果,不是高效算法。顯示結(jié)果如下圖所示:
Figure 3.1 General Cylinder for: Circle, Arc, Line
如上圖所示分別為對(duì)圓、圓弧和直線進(jìn)行拉伸得到的一般柱面。根據(jù)這個(gè)原理可以將任意曲線沿給定方向進(jìn)行拉伸得到一個(gè)柱面。
4.Conclusion
通過對(duì)OpenCASCADE中一般柱面的類中代碼進(jìn)行分析可知,OpenCASCADE的這個(gè)線性拉伸柱面Geom_SurfaceOfLinearExtrusion是根據(jù)一般柱面的定義實(shí)現(xiàn)的,并不是使用NURBS曲面來表示的。當(dāng)需要用NURBS曲面來表示一般柱面時(shí),需要注意控制頂點(diǎn)及權(quán)值的計(jì)算取值。
5. References
1. 趙罡,穆國(guó)旺,王拉柱譯. 非均勻有理B樣條. 清華大學(xué)出版社. 2010
2. Les Piegl, Wayne Tiller. The NURBS Book. Springer-Verlag. 1997
3. OpenCASCADE Team, OpenCASCADE BRep Format. 2014
4. Donald Hearn, M. Pauline Baker. Computer Graphics with OpenGL. Prentice Hall. 2009
5. 莫蓉,常智勇. 計(jì)算機(jī)輔助幾何造型技術(shù). 科學(xué)出版社. 2009