OpenCascade Shape Representation in OpenSceneGraph

eryar@163.com

摘要Abstract:本文通过程序实例,将OpenCascade中的拓朴数据(边、面)离散化后在OpenSceneGraph中进行显示。有了这些离散数据,就可以不用OpenCascade的显示模块了,可以使用其他显示引擎对形状进行显示。即若要线框模式显示形状时,就绘制离散形状拓朴边后得到的多段线;若要实体渲染模式显示形状时,就绘制离散形状拓朴面得到的三角网格。理解这些概念也有助于理解显示模块的实现,及拓朴数据中包含的几何数据的意义。

关键字 Key Words:OpenCascade, polygon curve, triangulation,discrete edge, discrete face,  OpenSceneGraph, OSG

一、引言 Introduction

“实体造型技术主流的是边界表达BRep,就是模型由面和边组成,这些面和边都是参数化的解析曲面和曲线,当拉伸或切割实体操作时候,就是用生成的实体和已有的实体进行实体布尔运算,其实是进行的面和边的相交运算,从而算出到新的面或者边。比如圆柱面和平面相交,以前的圆柱面分成了两个,同时产生出一条相交的空间椭圆曲线段,这些解析面/线边要通过三角化算法离散成三角网格或者线段条作为逼近表达,才能用OpenGL画出来。”以上内容来自博客:http://yrcpp.blog.163.com/blog/static/126045259201310199515969/ ,感谢网友的分享,言简意赅地把造型的核心进行了说明。

以前看《计算机图形学》相关的书时,从数学概念到具体实现的桥梁总是无法衔接。现在,通过学习OpenCascade,终于把这些都串起来了。正如上面网友所说,面和边要在OpenGL中显示出来就需要离散化,即把边离散为多段线,把面离散为三角网格。这样就可以把用参数精确表示的几何数据在计算机布满像素点的屏幕上逼近显示了。

本文通过程序实例,将OpenCascade中的拓朴数据(边、面)离散化后在OpenSceneGraph中进行显示。有了这些离散数据,就可以不用OpenCascade的显示模块了,可以使用其他显示引擎对形状进行显示。即若要线框模式显示形状时,就绘制离散形状拓朴边后得到的多段线;若要实体渲染模式显示形状时,就绘制离散形状拓朴面得到的三角网格。理解这些概念也有助于理解显示模块的实现,及拓朴数据中包含的几何数据的意义。

二、程序示例

以下通过一个具体程序实例,来对OpenCascade中的拓朴边和拓朴面进行离散化。

/*
* Copyright (c) 2013 eryar All Rights Reserved.
*
* File : Main.cpp
* Author : eryar@163.com
* Date : 2013-12-03 18:09
* Version : 1.0v
*
* Description : Draw OpenCascade polygon Curves of the edge
* and triangulations of the face in OpenSceneGraph.
* When you want to display the shape in the computer,
* you can not display the geometry exactly, the only
* way to show them is in the approximation form.
*
* Key Words : OpenCascade, polygon curve, triangulation,
* discrete edge, discrete face, OpenSceneGraph, OSG
*
*/ // OpenCascade library.
#define WNT
#include <gp_Circ.hxx>
#include <gp_Elips.hxx>
#include <gp_Sphere.hxx> #include <Poly_Polygon3D.hxx>
#include <Poly_Triangulation.hxx> #include <TopoDS_Edge.hxx>
#include <TopoDS_Face.hxx> #include <BRep_Tool.hxx>
#include <BRepMesh.hxx>
#include <BRepBuilderAPI_MakeEdge.hxx>
#include <BRepBuilderAPI_MakeFace.hxx> #pragma comment(lib, "TKernel.lib")
#pragma comment(lib, "TKMath.lib")
#pragma comment(lib, "TKBRep.lib")
#pragma comment(lib, "TKMesh.lib")
#pragma comment(lib, "TKTopAlgo.lib") // OpenSceneGraph library.
#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") /*
* @breif Descret the shape: edge.
* For Edge will be discreted to polylines; (GCPnts_TangentialDeflection)
* To get the polyline of the edge, use BRep_Tool::Polygon3D(Edge, L);
*/
osg::Node* BuildPolyline(const TopoDS_Edge& edge, double deflection = 0.1)
{
osg::ref_ptr<osg::Geode> geode = new osg::Geode();
osg::ref_ptr<osg::Geometry> linesGeom = new osg::Geometry();
osg::ref_ptr<osg::Vec3Array> pointsVec = new osg::Vec3Array(); TopLoc_Location location; BRepMesh::Mesh(edge, deflection);
Handle_Poly_Polygon3D polyline = BRep_Tool::Polygon3D(edge, location); for (int i = ; i < polyline->NbNodes(); i++)
{
gp_Pnt point = polyline->Nodes().Value(i); pointsVec->push_back(osg::Vec3(point.X(), point.Y(), point.Z()));
} // Set the color of the polyline.
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 vertex array.
linesGeom->setVertexArray(pointsVec);
linesGeom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINE_LOOP, , pointsVec->size())); geode->addDrawable(linesGeom.get()); return geode.release();
} /*
* @breif Descret the shape: face.
* For Face will be discreted to triangles; (BRepMesh_FastDiscret)
* To get the triangles of the face, use BRep_Tool::Triangulation(Face, L);
*/
osg::Node* BuildMesh(const TopoDS_Face& face, double deflection = 0.1)
{
osg::ref_ptr<osg::Geode> geode = new osg::Geode();
osg::ref_ptr<osg::Geometry> triGeom = new osg::Geometry();
osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array();
osg::ref_ptr<osg::Vec3Array> normals = new osg::Vec3Array(); TopLoc_Location location;
BRepMesh::Mesh(face, deflection); Handle_Poly_Triangulation triFace = BRep_Tool::Triangulation(face, location); Standard_Integer nTriangles = triFace->NbTriangles(); gp_Pnt vertex1;
gp_Pnt vertex2;
gp_Pnt vertex3; Standard_Integer nVertexIndex1 = ;
Standard_Integer nVertexIndex2 = ;
Standard_Integer nVertexIndex3 = ; TColgp_Array1OfPnt nodes(, triFace->NbNodes());
Poly_Array1OfTriangle triangles(, triFace->NbTriangles()); nodes = triFace->Nodes();
triangles = triFace->Triangles(); for (Standard_Integer i = ; i <= nTriangles; i++)
{
Poly_Triangle aTriangle = triangles.Value(i); aTriangle.Get(nVertexIndex1, nVertexIndex2, nVertexIndex3); vertex1 = nodes.Value(nVertexIndex1).Transformed(location.Transformation());
vertex2 = nodes.Value(nVertexIndex2).Transformed(location.Transformation());
vertex3 = nodes.Value(nVertexIndex3).Transformed(location.Transformation()); gp_XYZ vector12(vertex2.XYZ() - vertex1.XYZ());
gp_XYZ vector13(vertex3.XYZ() - vertex1.XYZ());
gp_XYZ normal = vector12.Crossed(vector13);
Standard_Real rModulus = normal.Modulus(); if (rModulus > gp::Resolution())
{
normal.Normalize();
}
else
{
normal.SetCoord(., ., .);
} //if (face.Orientable() != TopAbs_FORWARD)
//{
// normal.Reverse();
//} vertices->push_back(osg::Vec3(vertex1.X(), vertex1.Y(), vertex1.Z()));
vertices->push_back(osg::Vec3(vertex2.X(), vertex2.Y(), vertex2.Z()));
vertices->push_back(osg::Vec3(vertex3.X(), vertex3.Y(), vertex3.Z())); normals->push_back(osg::Vec3(normal.X(), normal.Y(), normal.Z()));
} triGeom->setVertexArray(vertices.get());
triGeom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::TRIANGLES, , vertices->size())); triGeom->setNormalArray(normals);
triGeom->setNormalBinding(osg::Geometry::BIND_PER_PRIMITIVE); geode->addDrawable(triGeom); return geode.release();
} osg::Node* BuildScene(void)
{
osg::ref_ptr<osg::Group> root = new osg::Group(); gp_Ax2 axis; // 1. Test circle while deflection is default 0.1;
TopoDS_Edge circleEdge1 = BRepBuilderAPI_MakeEdge(gp_Circ(axis, 6.0));
root->addChild(BuildPolyline(circleEdge1)); // 2. Test circle while deflection is 0.001.
axis.SetLocation(gp_Pnt(8.0, 0.0, 0.0));
axis.SetDirection(gp_Dir(1.0, 1.0, 1.0)); TopoDS_Edge circleEdge2 = BRepBuilderAPI_MakeEdge(gp_Circ(axis, 6.0));
root->addChild(BuildPolyline(circleEdge2, 0.001)); // 3. Test ellipse while deflection is 1.0.
TopoDS_Edge ellipseEdge = BRepBuilderAPI_MakeEdge(gp_Elips(gp::XOY(), 16.0, 8.0));
root->addChild(BuildPolyline(ellipseEdge, 1.0)); // 4. Test sphere face while deflection is default 0.1.
axis.SetLocation(gp_Pnt(26.0, 0.0, 0.0));
TopoDS_Face sphereFace1 = BRepBuilderAPI_MakeFace(gp_Sphere(axis, 8.0));
root->addChild(BuildMesh(sphereFace1)); // 5. Test sphere face while deflection is 2.0.
axis.SetLocation(gp_Pnt(26.0, 18.0, 0.0));
TopoDS_Face sphereFace2 = BRepBuilderAPI_MakeFace(gp_Sphere(axis, 8.0));
root->addChild(BuildMesh(sphereFace2, 2.0)); // 6. Test sphere face while deflection is 0.001.
axis.SetLocation(gp_Pnt(26.0, -18.0, 0.0));
TopoDS_Face sphereFace3 = BRepBuilderAPI_MakeFace(gp_Sphere(axis, 8.0));
root->addChild(BuildMesh(sphereFace3, 0.001)); return root.release();
} int main(void)
{
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 Edge and Face representation in OpenSceneGraph

从图中可知,离散精度越高,离散后得到线上的点或三角网格就越多,显示越细腻。

Figure 2.2 Edge and Face representation in OpenSceneGraph

其中,边的离散化使用到了类:GCPnts_TangentialDeflection;面的离散化使用到了类:BRepMesh_FastDiscret。有兴趣的读者可跟踪调试,理解其具体实现的算法。边的离散应该很好理解,面的离散使用了Delauney三角剖分算法。关于Delauney三角剖分算法的介绍可参考博客:http://www.cppblog.com/eryar/archive/2013/05/26/200605.aspx

三、结论

通过把OpenCascade中的拓朴边和面离散化用OpenSceneGraph显示,填补了形状数学精确表示与在计算机屏幕上近似显示之间的隔阂。也有助于理解拓朴结构中包含几何数据的BRep_TFace、BRep_TEdge、BRep_TVertex中除了包含面、边的精确的参数表示数据外,还包含了用于近似显示的离散数据的意义。

四、参考资料

1. 博客:http://yrcpp.blog.163.com/blog/static/126045259201310199515969/

2. 博客:http://www.cppblog.com/eryar/archive/2013/05/26/200605.aspx

OpenCascade Shape Representation in OpenSceneGraph的更多相关文章

  1. OpenCASCADE Shape Location

    OpenCASCADE Shape Location eryar@163.com Abstract. The TopLoc package of OpenCASCADE gives resources ...

  2. Render OpenCascade Geometry Surfaces in OpenSceneGraph

    在OpenSceneGraph中绘制OpenCascade的曲面 Render OpenCascade Geometry Surfaces in OpenSceneGraph eryar@163.co ...

  3. Render OpenCascade Geometry Curves in OpenSceneGraph

    在OpenSceneGraph中绘制OpenCascade的曲线 Render OpenCascade Geometry Curves in OpenSceneGraph eryar@163.com ...

  4. Opencascade、OpenGL和OpenSceneGraph的区别与联系

    OpenGL只是三维显示 Openscenegraph基于场景图的概念,它提供一个在OpenGL之上的面向对象的框架,从而能把开发者从实现和优化底层图形的调用中解脱出来 Opencascade更适合算 ...

  5. Representation Data in OpenCascade BRep

    Representation Data in OpenCascade BRep eryar@163.com 摘要Abstract:现在的显示器大多数是光栅显示器,即可以看做一个像素的矩阵.在光栅显示器 ...

  6. Polynomial Library in OpenCascade

    Polynomial Library in OpenCascade eryar@163.com 摘要Abstract:分析幂基曲线即多项式曲线在OpenCascade中的计算方法,以及利用OpenSc ...

  7. {ICIP2014}{收录论文列表}

    This article come from HEREARS-L1: Learning Tuesday 10:30–12:30; Oral Session; Room: Leonard de Vinc ...

  8. Open Cascade DataExchange IGES

    Open Cascade DataExchange IGES eryar@163.com 摘要Abstract:本文结合OpenCascade和Initial Graphics Exchange Sp ...

  9. CVPR2011录取结果

    CVPR2011论文录取已经结束了,虽然论文都还没有在线公布出来,不过相信http://www.cvpapers.com/会很快有的.这里大体看一下结果统计与分析: At the end of the ...

随机推荐

  1. BZOJ3218 UOJ#77 A+B Problem(最小割+主席树)

    竟然在BZOJ上拿了Rank1太给力啦. p.s.:汗,一发这个就被一堆人在2月27号强势打脸-- 传送门(BZOJ) 传送门(UOJ) 说说这道题目吧: 首先是说说这个构图吧.因为有选择关系,我们很 ...

  2. PYTHON学习之路_PYTHON基础(6)

    学习内容: Python模块介绍 1.time &datetime模块 2.random 3.shutil 4.shelve 5.xml处理 6.configparser 7.hashlib ...

  3. Python学习之路-Day2

    数据类型常用操作 不管是查整数还是查布尔或者是列表...要记住 dir(int)   查看某个类型的功能 help(int) 查看该类型的功能及文档说明 type(4)   查看某个字符或数字的类型- ...

  4. 关于sitemesh和freemark在struts2中的一些问题总结

    最近刚开始工作,首先让我在熟悉公司编程环境的前提下做一些简单的增删改查,在此总结一些这些天遇到的问题. 1,在刚开始建表的时候,我在oracle数据库中设置的主键id为四位的number类型,对应的实 ...

  5. 初识selenium--百度实例录制

    Selenium 是一个web的自动化测试工具,不少学习功能自动化的朋友首选的就是Selenium,它相比QTP有许多优点(QTP笔者由于种种原因暂未使用过O(∩_∩)O哈!): ①Selenium是 ...

  6. 如何查看Android的Keystore文件的SHA1值

    像使用百度地图api时候,一般需要获取keystore的SHA1值,这里就手把手教大家如何查看Android的keystore文件中的SHA1值. 第一步: 打开cmd,切换到keystore所在的文 ...

  7. 关于最近的CSRF攻击

    摘要 最近公司内部爆出一大波页面没有加token校验,然后各路大神就开始进行CSRF攻击了.CSRF攻击:攻击者盗用了你的身份,以你的名义发送恶意请求.CSRF能够做的事情包括:以你名义发送邮件,发消 ...

  8. ENode 2.0 - 介绍一下关于ENode中对Command的调度设计

    CQRS架构,C端的职责是处理从上层发送过来的command.对于单台机器来说,我们如何尽快的处理command呢?本文想通过不断提问和回答的方式,把我的思考写出来. 首先,我们最容易想到的是使用多线 ...

  9. 接口分离原则(Interface Segregation Principle)

    接口分离原则(Interface Segregation Principle)用于处理胖接口(fat interface)所带来的问题.如果类的接口定义暴露了过多的行为,则说明这个类的接口定义内聚程度 ...

  10. 作业二:Github注册过程

    第一步.打开Github官网https://github.com/ ,在相应位置填写注册名.注册邮箱.注册密码完成后点击注册. 第二步.这时会弹出一个界面,让你选择你的私人计划(personal pl ...