找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
热搜: 活动 交友 discuz
查看: 206|回复: 0

OSG绘制空间凹多边形并计算其面积

[复制链接]

1

主题

0

回帖

35

积分

管理员

积分
35
发表于 2024-3-16 09:11:09 | 显示全部楼层 |阅读模式
1.        思路
这个问题其实涉及到OSG中的两个问题:多边形分格化和几何图元遍历。

1)        多边形分格化
在OpenGL/OSG中,由于效率的原因,默认是直接显示的简单的凸多边形。如果直接强行显示凹多边形,渲染结果是不确定的。所以对于复杂的凹多边形,需要将其分解成简单的凸多边形,这个过程就是多边形分格化。在OSG中是通过osgUtil::Tessellator类来实现多边形分格化的。

2)        几何图元遍历
对于二维的凹多边形,可以有办法计算其面积。但是对于三维空间的凹多边形,计算其面积却很困难。这是因为三维空间凹多边形甚至都有可能不是共面的。而我们知道,任何复杂的图形都是通过分解成三角形进行绘制的,只要获取分解成的三角形,计算其面积并相加(空间三角形的面积计算比较简单),就可以得到凹多边形的总面积。 在OSG中提供了一个用来访问图元的类:osgPrimitiveFunctor,其继承类osgTriangleFunctor可以获取其三角面图元。几何体类osg::Geometry提供了遍历几何图元的访问器接口。

2.        实现
其具体实现如下。注意在查找多边形分格化的资料的时候,提到了环绕数和环绕规则的概念。在OSG里面也有相应的参数设置。可惜这一段没有看明白,只能根据仿照例子来设置了。
  1. #include <iostream>
  2. #include <Windows.h>
  3. #include <osgViewer/Viewer>
  4. #include <osgDB/ReadFile>
  5. #include <osgUtil/Tessellator>
  6. #include <osg/TriangleFunctor>
  7. using namespace std;
  8. using namespace osg;
  9. osg::ref采用ptr<osg::Geometry> redPolygon;
  10. //计算空间三角形的面积
  11. double CalTriangleArea(const osg::Vec3& a, const osg::Vec3& b, const osg::Vec3& c)
  12. {
  13.         double area = 0;
  14.         double side[3];//存储三条边的长度;
  15.         side[0] = sqrt(pow(a.x() - b.x(), 2) + pow(a.y() - b.y(), 2) + pow(a.z() - b.z(), 2));
  16.         side[1] = sqrt(pow(a.x() - c.x(), 2) + pow(a.y() - c.y(), 2) + pow(a.z() - c.z(), 2));
  17.         side[2] = sqrt(pow(c.x() - b.x(), 2) + pow(c.y() - b.y(), 2) + pow(c.z() - b.z(), 2));
  18.         //不能构成三角形;
  19.         if (side[0] + side[1] <= side[2] || side[0] + side[2] <= side[1] || side[1] + side[2] <= side[0]) return area;
  20.         //利用海伦公式。s=sqr(p*(p-a)(p-b)(p-c));
  21.         double p = (side[0] + side[1] + side[2]) / 2; //半周长;
  22.         area = sqrt(p*(p - side[0])*(p - side[1])*(p - side[2]));
  23.         return area;
  24. }
  25. //三角面片访问器
  26. struct TriangleAreaFunctor
  27. {
  28.         TriangleAreaFunctor()
  29.         {
  30.                 sumArea = new double;
  31.         }
  32.         ~TriangleAreaFunctor()
  33.         {
  34.                 if (sumArea)
  35.                 {
  36.                         delete sumArea;
  37.                         sumArea = nullptr;
  38.                 }
  39.         }
  40.         void operator() (const osg::Vec3& v1, const osg::Vec3& v2, const osg::Vec3& v3) const
  41.         {
  42.                 *sumArea = *sumArea + CalTriangleArea(v1, v2, v3);
  43.         }
  44.         double GetSumArea()
  45.         {
  46.                 return *sumArea;
  47.         }
  48. protected:
  49.         double *sumArea = nullptr;
  50. };
  51. //
  52. ref采用ptr<Geode> createPolygon()
  53. {
  54.         const float wall[6][3] =
  55.         {
  56.                 { -115.54f, 70.873f, -118.952f},
  57.                 { -111.516f, 70.7189f, -71.8492f },
  58.                 { -88.5345f, 70.8667f, -86.3565f },
  59.                 { -64.9495f, 71.8231f, -53.6525f },
  60.                 { -52.9755f, 69.028f, -129.093f },
  61.                 { -89.2272f, 71.1478f, -105.434f }
  62.         };
  63.         //
  64.         ref采用ptr<Geode> geode = new Geode();
  65.         redPolygon = new osg::Geometry;
  66.        
  67.         //
  68.         osg::ref采用ptr<osg::Vec3Array> redVex = new osg::Vec3Array;
  69.         redPolygon->setVertexArray(redVex);
  70.         for (int i = 0; i< 6; i++)
  71.         {               
  72.                 redVex->push采用back(osg::Vec3(wall[i][0], wall[i][1], wall[i][2]));
  73.         }
  74.        
  75.         redPolygon->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::POLYGON, 0, 6));
  76.         //设置颜色数组
  77.         osg::ref采用ptr<osg::Vec4Array> redColors = new osg::Vec4Array;
  78.         redColors->push采用back(osg::Vec4(1.0, 0.0, 0.0, 0.5));
  79.         redPolygon->setColorArray(redColors);
  80.         redColors->setBinding(osg::Array::BIND采用PER采用PRIMITIVE采用SET);
  81.         //如果需要透明,则加入这个
  82.         redPolygon->getOrCreateStateSet()->setMode(GL采用BLEND, osg::StateAttribute::ON);
  83.         redPolygon->getOrCreateStateSet()->setRenderingHint(osg::StateSet::TRANSPARENT采用BIN);
  84.        
  85.         //创建分格化对象(支持凹多边形)
  86.         osg::ref采用ptr<osgUtil::Tessellator> tscx = new osgUtil::Tessellator;
  87.         //设置分格类型为几何体
  88.         tscx->setTessellationType(osgUtil::Tessellator::TESS采用TYPE采用GEOMETRY);
  89.         //设置只显示轮廓线为false。设置环绕规则,这里不太懂
  90.         tscx->setWindingType(osgUtil::Tessellator::TESS采用WINDING采用ODD);
  91.         //使用分格化
  92.         tscx->retessellatePolygons(*(redPolygon.get()));
  93.        
  94.         geode->addDrawable(redPolygon);
  95.         return geode;
  96. }
  97. int main()
  98. {
  99.         //
  100.         ref采用ptr<Group> root = new Group();
  101.         root->getOrCreateStateSet()->setMode(GL采用LIGHTING, osg::StateAttribute::OFF | osg::StateAttribute::OVERRIDE);                //关闭默认光照
  102.         root->addChild(createPolygon());
  103.         //
  104.         osgViewer::Viewer viewer;
  105.         viewer.setSceneData(root);
  106.         viewer.setUpViewInWindow(100, 100, 800, 600);
  107.         viewer.run();
  108.         osg::TriangleFunctor<TriangleAreaFunctor> tf;
  109.         redPolygon->accept(tf);
  110.         cout << "面积:" << tf.GetSumArea() << endl;
  111.         return 0;
  112. }
复制代码
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|膜结构网

GMT+8, 2025-1-1 17:48 , Processed in 0.117774 second(s), 22 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表