zoukankan      html  css  js  c++  java
  • Render OpenCascade Geometry Surfaces in OpenSceneGraph

    在OpenSceneGraph中绘制OpenCascade的曲面

    Render OpenCascade Geometry Surfaces in OpenSceneGraph

    eryar@163.com

    摘要Abstract:本文对OpenCascade中的几何曲面数据进行简要说明,并结合OpenSceneGraph将这些曲面显示。 

    关键字Key Words:OpenCascade、OpenSceneGraph、Geometry Surface、NURBS 

    一、引言 Introduction

    《BRep Format Description White Paper》中对OpenCascade的几何数据结构进行了详细说明。BRep文件中用到的曲面总共有11种: 

    1.Plane 平面; 

    2.Cylinder 圆柱面; 

    3.Cone 圆锥面; 

    4.Sphere 球面; 

    5.Torus 圆环面; 

    6.Linear Extrusion 线性拉伸面; 

    7.Revolution Surface 旋转曲面; 

    8.Bezier Surface 贝塞尔面; 

    9.B-Spline Surface B样条曲面; 

    10.Rectangle Trim Surface 矩形裁剪曲面; 

    11.Offset Surface 偏移曲面; 

    曲面的几何数据类都有一个共同的基类Geom_Surface,类图如下所示: 

    wps_clip_image-5993

    Figure 1.1 Geometry Surface class diagram 

    抽象基类Geom_Surface有几个纯虚函数Bounds()、Value()等,可用来计算曲面上的点。类图如下所示: 

    wps_clip_image-12898

    Figure 1.2 Geom_Surface class diagram 

    与另一几何内核sgCore中的几何的概念一致,几何(geometry)是用参数方程对曲线曲面精确表示的。 

    每种曲面都对纯虚函数进行实现,使计算曲面上点的方式统一。 

    曲线C(u)是单参数的矢值函数,它是由直线段到三维欧几里得空间的映射。曲面是关于两个参数u和v的矢值函数,它表示由uv平面上的二维区域R到三维欧几里得空间的映射。把曲面表示成双参数的形式为: 

    wps_clip_image-16905

    它的参数方程为: 

    wps_clip_image-19345

    u,v参数形成了一个参数平面,参数的变化区间在参数平面上构成一个矩形区域。正常情况下,参数域内的点(u,v)与曲面上的点r(u,v)是一一对应的映射关系。 

    给定一个具体的曲面方程,称之为给定了一个曲面的参数化。它既决定了所表示的曲面的形状,也决定了该曲面上的点与其参数域内的点的一种对应关系。同样地,曲面的参数化不是唯一的。 

    曲面双参数u,v的变化范围往往取为单位正方形,即u∈[0,1],v∈[0,1]。这样讨论曲面方程时,即简单、方便,又不失一般性。 

    二、程序示例 Code Example

    使用函数Value(u, v)根据参数计算出曲面上的点,将点分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();
    }

    程序效果如下图所示: 

    wps_clip_image-14066

    Figure 2.1 OpenCascade Geometry Surfaces in OpenSceneGraph 

    三、结论 Conclusion 

    根据OpenCascade中的几何曲面的函数Value(u, v)可以计算出曲面上的点。分u方向和v方向分别绘制曲面上的点,并将之连接成线,即可以表示出曲面的线框模型。因为这样的模型没有面的信息,所以不能有光照效果、材质效果等。要有光照、材质的信息,必须将曲面进行三角剖分。相关的剖分算法有Delaunay三角剖分等。 

  • 相关阅读:
    【第40套模拟题】【noip2011_mayan】解题报告【map】【数论】【dfs】
    【模拟题(63550802...)】解题报告【贪心】【拓扑排序】【找规律】【树相关】
    【模拟题(电子科大MaxKU)】解题报告【树形问题】【矩阵乘法】【快速幂】【数论】
    IMemoryBufferReference and IMemoryBufferByteAccess
    SoftwareBitmap and BitmapEncoder in Windows.Graphics.Imaging Namespace
    Windows UPnP APIs
    编译Android技术总结
    Windows函数转发器
    Two Ways in Delphi to Get IP Address on Android
    Delphi Call getifaddrs and freeifaddrs on Android
  • 原文地址:https://www.cnblogs.com/opencascade/p/3475110.html
Copyright © 2011-2022 走看看