OpenCascade Shape Representation in OpenSceneGraph
OpenCascade Shape Representation in OpenSceneGraph
摘要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
PDF Version: OpenCascade Shape Representation in OpenSceneGraph
OpenCascade Shape Representation in OpenSceneGraph的更多相关文章
- OpenCASCADE Shape Location
OpenCASCADE Shape Location eryar@163.com Abstract. The TopLoc package of OpenCASCADE gives resources ...
- Render OpenCascade Geometry Surfaces in OpenSceneGraph
在OpenSceneGraph中绘制OpenCascade的曲面 Render OpenCascade Geometry Surfaces in OpenSceneGraph eryar@163.co ...
- Render OpenCascade Geometry Curves in OpenSceneGraph
在OpenSceneGraph中绘制OpenCascade的曲线 Render OpenCascade Geometry Curves in OpenSceneGraph eryar@163.com ...
- Opencascade、OpenGL和OpenSceneGraph的区别与联系
OpenGL只是三维显示 Openscenegraph基于场景图的概念,它提供一个在OpenGL之上的面向对象的框架,从而能把开发者从实现和优化底层图形的调用中解脱出来 Opencascade更适合算 ...
- Representation Data in OpenCascade BRep
Representation Data in OpenCascade BRep eryar@163.com 摘要Abstract:现在的显示器大多数是光栅显示器,即可以看做一个像素的矩阵.在光栅显示器 ...
- Polynomial Library in OpenCascade
Polynomial Library in OpenCascade eryar@163.com 摘要Abstract:分析幂基曲线即多项式曲线在OpenCascade中的计算方法,以及利用OpenSc ...
- {ICIP2014}{收录论文列表}
This article come from HEREARS-L1: Learning Tuesday 10:30–12:30; Oral Session; Room: Leonard de Vinc ...
- Open Cascade DataExchange IGES
Open Cascade DataExchange IGES eryar@163.com 摘要Abstract:本文结合OpenCascade和Initial Graphics Exchange Sp ...
- CVPR2011录取结果
CVPR2011论文录取已经结束了,虽然论文都还没有在线公布出来,不过相信http://www.cvpapers.com/会很快有的.这里大体看一下结果统计与分析: At the end of the ...
随机推荐
- MySql数据源配置
1.tomcat的config/server.xml中将以下代码写到 </Host>前: <Context docBase="struts1" path=&quo ...
- Core Audio(三)
音频终端设备(Audio Endpoint Devices) endpoint device指的是应用程序的数据通道上起始或终止的硬件设备,如扬声器,耳机,话筒等:沿着数据通道可能穿越一定数目的硬件和 ...
- disconf使用
1.创建app,确定version 2.创建配置文件redis.config 3.选择app下env环境,上传redis.config到disconf 4.创建disconf.properties到c ...
- Java中的一个类怎么调用另一个类中的方法
如果另一个类中的那个方法是私有的话,就不能直接调用到,如果是其他类型的话看情况,如果是静态的(static)话,直接用类名可以调用到,如果是非静态的,就需要利用另一个类的实例(也就是用那个类生成的对象 ...
- JAVA读取TXT文件、新建TXT文件、写入TXT文件
1.创建TXT文件 按照正常的逻辑写就好 先定义一个文件给定一个路径——>判断这个路径上这个文件存不存在——>若不存在则建立,try/catch根据程序提示自动生成就好 2.读取TXT文件 ...
- 用CSS3的transform来做一个立方体
有一次上数据结构课老师布置了一个用队列的思想通过js和Html来做一个“跳舞配对”的网页,当时那个跳舞的部分用了css3里面transform的相关属性做了个个让图片无限翻转的效果,可能正是由于这个效 ...
- C++ 非阻塞套接字的使用 (1)
在维护代码的过程中,发现软件运行的CPU占用率居高不下,在4核的电脑上占用了25%的CPU.查阅资料的得知,这是可能是由于软件中出现了死循环. 经过对软件的一些测试,最终确定了死循环出现的位置——通讯 ...
- GP调用arctoolbox 以Clip为例
GP的功能非常强大,也是GIS建模的一个很重要的工具.在Arcengine中,实现Clip功能很多种方法,可以用IBasicGeoprocessor的clip方法,但是GP无疑是最简单的. publi ...
- 深入理解openstack网络架构(2)----Basic Use Cases
原文地址: https://blogs.oracle.com/ronen/entry/diving_into_openstack_network_architecture1 译文转自: http:// ...
- Javascript自己动手实现getter/setter
虽然ES5中为我们提供了Object.defineProperty方法来设置getter与setter,但此原生方法使用起来并不方便,我们何不自己来实现一个类,只要继承该类并遵循一定的规范就可以拥有媲 ...