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中的拓朴边和拓朴面进行离散化。

  1. /*
  2. * Copyright (c) 2013 eryar All Rights Reserved.
  3. *
  4. * File : Main.cpp
  5. * Author : eryar@163.com
  6. * Date : 2013-12-03 18:09
  7. * Version : 1.0v
  8. *
  9. * Description : Draw OpenCascade polygon Curves of the edge
  10. * and triangulations of the face in OpenSceneGraph.
  11. * When you want to display the shape in the computer,
  12. * you can not display the geometry exactly, the only
  13. * way to show them is in the approximation form.
  14. *
  15. * Key Words : OpenCascade, polygon curve, triangulation,
  16. * discrete edge, discrete face, OpenSceneGraph, OSG
  17. *
  18. */
  19.  
  20. // OpenCascade library.
  21. #define WNT
  22. #include <gp_Circ.hxx>
  23. #include <gp_Elips.hxx>
  24. #include <gp_Sphere.hxx>
  25.  
  26. #include <Poly_Polygon3D.hxx>
  27. #include <Poly_Triangulation.hxx>
  28.  
  29. #include <TopoDS_Edge.hxx>
  30. #include <TopoDS_Face.hxx>
  31.  
  32. #include <BRep_Tool.hxx>
  33. #include <BRepMesh.hxx>
  34. #include <BRepBuilderAPI_MakeEdge.hxx>
  35. #include <BRepBuilderAPI_MakeFace.hxx>
  36.  
  37. #pragma comment(lib, "TKernel.lib")
  38. #pragma comment(lib, "TKMath.lib")
  39. #pragma comment(lib, "TKBRep.lib")
  40. #pragma comment(lib, "TKMesh.lib")
  41. #pragma comment(lib, "TKTopAlgo.lib")
  42.  
  43. // OpenSceneGraph library.
  44. #include <osgDB/ReadFile>
  45. #include <osgViewer/Viewer>
  46. #include <osgGA/StateSetManipulator>
  47. #include <osgViewer/ViewerEventHandlers>
  48.  
  49. #pragma comment(lib, "osgd.lib")
  50. #pragma comment(lib, "osgDBd.lib")
  51. #pragma comment(lib, "osgGAd.lib")
  52. #pragma comment(lib, "osgViewerd.lib")
  53.  
  54. /*
  55. * @breif Descret the shape: edge.
  56. * For Edge will be discreted to polylines; (GCPnts_TangentialDeflection)
  57. * To get the polyline of the edge, use BRep_Tool::Polygon3D(Edge, L);
  58. */
  59. osg::Node* BuildPolyline(const TopoDS_Edge& edge, double deflection = 0.1)
  60. {
  61. osg::ref_ptr<osg::Geode> geode = new osg::Geode();
  62. osg::ref_ptr<osg::Geometry> linesGeom = new osg::Geometry();
  63. osg::ref_ptr<osg::Vec3Array> pointsVec = new osg::Vec3Array();
  64.  
  65. TopLoc_Location location;
  66.  
  67. BRepMesh::Mesh(edge, deflection);
  68. Handle_Poly_Polygon3D polyline = BRep_Tool::Polygon3D(edge, location);
  69.  
  70. for (int i = ; i < polyline->NbNodes(); i++)
  71. {
  72. gp_Pnt point = polyline->Nodes().Value(i);
  73.  
  74. pointsVec->push_back(osg::Vec3(point.X(), point.Y(), point.Z()));
  75. }
  76.  
  77. // Set the color of the polyline.
  78. osg::ref_ptr<osg::Vec4Array> colors = new osg::Vec4Array;
  79. colors->push_back(osg::Vec4(1.0f, 1.0f, 0.0f, 0.0f));
  80. linesGeom->setColorArray(colors.get());
  81. linesGeom->setColorBinding(osg::Geometry::BIND_OVERALL);
  82.  
  83. // Set vertex array.
  84. linesGeom->setVertexArray(pointsVec);
  85. linesGeom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINE_LOOP, , pointsVec->size()));
  86.  
  87. geode->addDrawable(linesGeom.get());
  88.  
  89. return geode.release();
  90. }
  91.  
  92. /*
  93. * @breif Descret the shape: face.
  94. * For Face will be discreted to triangles; (BRepMesh_FastDiscret)
  95. * To get the triangles of the face, use BRep_Tool::Triangulation(Face, L);
  96. */
  97. osg::Node* BuildMesh(const TopoDS_Face& face, double deflection = 0.1)
  98. {
  99. osg::ref_ptr<osg::Geode> geode = new osg::Geode();
  100. osg::ref_ptr<osg::Geometry> triGeom = new osg::Geometry();
  101. osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array();
  102. osg::ref_ptr<osg::Vec3Array> normals = new osg::Vec3Array();
  103.  
  104. TopLoc_Location location;
  105. BRepMesh::Mesh(face, deflection);
  106.  
  107. Handle_Poly_Triangulation triFace = BRep_Tool::Triangulation(face, location);
  108.  
  109. Standard_Integer nTriangles = triFace->NbTriangles();
  110.  
  111. gp_Pnt vertex1;
  112. gp_Pnt vertex2;
  113. gp_Pnt vertex3;
  114.  
  115. Standard_Integer nVertexIndex1 = ;
  116. Standard_Integer nVertexIndex2 = ;
  117. Standard_Integer nVertexIndex3 = ;
  118.  
  119. TColgp_Array1OfPnt nodes(, triFace->NbNodes());
  120. Poly_Array1OfTriangle triangles(, triFace->NbTriangles());
  121.  
  122. nodes = triFace->Nodes();
  123. triangles = triFace->Triangles();
  124.  
  125. for (Standard_Integer i = ; i <= nTriangles; i++)
  126. {
  127. Poly_Triangle aTriangle = triangles.Value(i);
  128.  
  129. aTriangle.Get(nVertexIndex1, nVertexIndex2, nVertexIndex3);
  130.  
  131. vertex1 = nodes.Value(nVertexIndex1).Transformed(location.Transformation());
  132. vertex2 = nodes.Value(nVertexIndex2).Transformed(location.Transformation());
  133. vertex3 = nodes.Value(nVertexIndex3).Transformed(location.Transformation());
  134.  
  135. gp_XYZ vector12(vertex2.XYZ() - vertex1.XYZ());
  136. gp_XYZ vector13(vertex3.XYZ() - vertex1.XYZ());
  137. gp_XYZ normal = vector12.Crossed(vector13);
  138. Standard_Real rModulus = normal.Modulus();
  139.  
  140. if (rModulus > gp::Resolution())
  141. {
  142. normal.Normalize();
  143. }
  144. else
  145. {
  146. normal.SetCoord(., ., .);
  147. }
  148.  
  149. //if (face.Orientable() != TopAbs_FORWARD)
  150. //{
  151. // normal.Reverse();
  152. //}
  153.  
  154. vertices->push_back(osg::Vec3(vertex1.X(), vertex1.Y(), vertex1.Z()));
  155. vertices->push_back(osg::Vec3(vertex2.X(), vertex2.Y(), vertex2.Z()));
  156. vertices->push_back(osg::Vec3(vertex3.X(), vertex3.Y(), vertex3.Z()));
  157.  
  158. normals->push_back(osg::Vec3(normal.X(), normal.Y(), normal.Z()));
  159. }
  160.  
  161. triGeom->setVertexArray(vertices.get());
  162. triGeom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::TRIANGLES, , vertices->size()));
  163.  
  164. triGeom->setNormalArray(normals);
  165. triGeom->setNormalBinding(osg::Geometry::BIND_PER_PRIMITIVE);
  166.  
  167. geode->addDrawable(triGeom);
  168.  
  169. return geode.release();
  170. }
  171.  
  172. osg::Node* BuildScene(void)
  173. {
  174. osg::ref_ptr<osg::Group> root = new osg::Group();
  175.  
  176. gp_Ax2 axis;
  177.  
  178. // 1. Test circle while deflection is default 0.1;
  179. TopoDS_Edge circleEdge1 = BRepBuilderAPI_MakeEdge(gp_Circ(axis, 6.0));
  180. root->addChild(BuildPolyline(circleEdge1));
  181.  
  182. // 2. Test circle while deflection is 0.001.
  183. axis.SetLocation(gp_Pnt(8.0, 0.0, 0.0));
  184. axis.SetDirection(gp_Dir(1.0, 1.0, 1.0));
  185.  
  186. TopoDS_Edge circleEdge2 = BRepBuilderAPI_MakeEdge(gp_Circ(axis, 6.0));
  187. root->addChild(BuildPolyline(circleEdge2, 0.001));
  188.  
  189. // 3. Test ellipse while deflection is 1.0.
  190. TopoDS_Edge ellipseEdge = BRepBuilderAPI_MakeEdge(gp_Elips(gp::XOY(), 16.0, 8.0));
  191. root->addChild(BuildPolyline(ellipseEdge, 1.0));
  192.  
  193. // 4. Test sphere face while deflection is default 0.1.
  194. axis.SetLocation(gp_Pnt(26.0, 0.0, 0.0));
  195. TopoDS_Face sphereFace1 = BRepBuilderAPI_MakeFace(gp_Sphere(axis, 8.0));
  196. root->addChild(BuildMesh(sphereFace1));
  197.  
  198. // 5. Test sphere face while deflection is 2.0.
  199. axis.SetLocation(gp_Pnt(26.0, 18.0, 0.0));
  200. TopoDS_Face sphereFace2 = BRepBuilderAPI_MakeFace(gp_Sphere(axis, 8.0));
  201. root->addChild(BuildMesh(sphereFace2, 2.0));
  202.  
  203. // 6. Test sphere face while deflection is 0.001.
  204. axis.SetLocation(gp_Pnt(26.0, -18.0, 0.0));
  205. TopoDS_Face sphereFace3 = BRepBuilderAPI_MakeFace(gp_Sphere(axis, 8.0));
  206. root->addChild(BuildMesh(sphereFace3, 0.001));
  207.  
  208. return root.release();
  209. }
  210.  
  211. int main(void)
  212. {
  213. osgViewer::Viewer myViewer;
  214.  
  215. myViewer.setSceneData(BuildScene());
  216.  
  217. myViewer.addEventHandler(new osgGA::StateSetManipulator(myViewer.getCamera()->getOrCreateStateSet()));
  218. myViewer.addEventHandler(new osgViewer::StatsHandler);
  219. myViewer.addEventHandler(new osgViewer::WindowSizeHandler);
  220.  
  221. return myViewer.run();
  222. }

示例程序测试了不同的离散精度情况下同一个形状的显示效果,程序结果如下图所示:

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. Json格式的字符串转换为正常显示的日期格式

    //返回自定义格式日期: 2015-07-17 13:53:37function ChangeDateFormat(jsondate) { jsondate = jsondate.replace(&q ...

  2. make基础(转)

    1. 基本规则 请点评 除了Hello World这种极简单的程序之外,一般的程序都是由多个源文件编译链接而成的,这些源文件的处理步骤通常用Makefile来管理.Makefile起什么作用呢?我们先 ...

  3. delphi7 编译程序时报win32.indcu.a病毒的解决方法

    Delphi7用了很久一直都没问题,同一个工程文件昨天编译时mod32还不会报毒,今天重新编译时,生成的exe突然nod32报毒. 提示: “Project1.exe Win32/Induc.A 病毒 ...

  4. JSP中<base href="<%=basePath%>">作用

    通常在JSP页面开通有如下代码: <% String path = request.getContextPath(); String basePath = request.getScheme() ...

  5. JS实现雪花效果

    演示效果 http://www.9696e.com/demo/snow/ 春节之前新一博客也会一直挂着的. 加载链接 <script src="http://www.9696e.com ...

  6. linux的一些小问题

    1.需要使用root权限时提示xxx is not sudoers.... 1).root用户下输入visudo 2).在打开的文件中找到 root ALL=(ALL) ALL,以xxx为用户名,添加 ...

  7. 使用vim在Linux下编写C语言程序

    1.进入字符界面 2.创建文件夹用于存放源文件 mkdir helloworld    //创建文件夹命令 cd helloworld        //进入新建的文件夹,这里应该说目录比较好,win ...

  8. MyEclipse 自带的TomCat 新增部署的时候不显示 Deploy Location

    项目总是报错,添了删,删了又添了N次以后,发现添加部署的时候,Deploy Location 没有值了,Deploy Location 没有值在自带的Tomcat上就无法用浏览器浏览(Open in ...

  9. sql 优化 链接提示 查询提示 标提示

    SQL Server的查询优化器在select查询执行的时候产生一个高效的查询执行计划.如果优化器不能选择最优的计划,那么就需要检查查询计划.统计信息.支持的索引等,而通过使用提示可以改变优化器选择查 ...

  10. 解剖SQLSERVER 第十二篇 OrcaMDF 行压缩支持(译)

    解剖SQLSERVER 第十二篇   OrcaMDF 行压缩支持(译) http://improve.dk/orcamdf-row-compression-support/ 在这两个月的断断续续的开发 ...