第12节 实例-挖方填方量的计算

感谢

感谢网友热心提出这个问题,大家有问题也可以在评论区提出。

资源下载

本文集包括本节所有资源包括模型代码都在此下载,按节的序号有文件或文件夹:

注意:务必使用浏览器打开:
链接:https://pan.baidu.com/s/13gwJLwo_LbRnN3Bl2NXXXw
提取码:xrf5

功能

1.我们先画一个盒子,长宽高是10,8,7,再随便旋转个30度,盒子的体积是560。这样我们就好看看我们自己的方式算的准不准。
2.点击w键,会采样变密,点击s键会采样变粗,命令行中打印出采样的间隔以及算出的体积和盒子本身的体积560的对比来看看误差。

image.png

具体实现

思想:我寻思填方是把一个坑填平喽,挖方是再把填的挖出来,因此应该是一个算法。我们找到要填的几何体,这里是一个盒子然后算出包围球,这样就求出来全覆盖这个包围球的xyz,然后以xy为平面,固定间隔连一条直线,然后与盒子求交,求出来的交点以采样间隔为长宽,以交点间的距离为高,然后算出来体积,这么多体积相加,就是总体积。有点微积分的味道。

实现:具体实现也没有什么好说的,直线和物体求交也就是个函数的API,没有什么好讲的。看代码吧。

结果:有一点是肯定的,当采样越密的时候,精度就越高,这个是可以显见收敛的。有些人可能说我采样往粗了变,怎么有时候误差大有时候误差小呢?这就是采样过粗是不行的。因此以采样点密为要。如果要非常精确,不考虑实时性,可以增加采样点,肯定会越来越精确。

扩展思考:如果有些几何体特别复杂,比如你溶洞似的,那么怎么办呢?这就牵扯到一条线可能有多个交点的问题,一般情况下交点必为偶数个则才成为一个封闭的体,则两两认为是在一个空间,是要求的。自己想象一下。

具体代码如下:

#include <osgViewer/viewer>
#include <osgDB/ReadFile>
#include <osg/Geode>
#include <osg/Geometry>
#include <osg/ShapeDrawable>
#include <osg/MatrixTransform>
#include <osgUtil/IntersectionVisitor>

//定义全局变量用着方便
osg::Group* _root = nullptr;
osg::Node* _box = nullptr;
osg::Group* _shiyi = nullptr;

osg::Geode* CreateBox(osg::Vec3 from, osg::Vec3 to, float stepSize)
{
    osg::Geode* gnode = new osg::Geode;
    gnode->addDrawable(new osg::ShapeDrawable(new osg::Box((from+to)/2, stepSize, stepSize, std::abs(to.z()-from.z()))));
    return gnode;
}

//画一个盒子
osg::Node* CreateScene()
{
    osg::Group* root = new osg::Group;
    _root = root;

    osg::MatrixTransform* mt = new osg::MatrixTransform;
    _box = mt;
    root->addChild(mt);
    mt->setMatrix(osg::Matrix::rotate(osg::inDegrees(30.0), osg::Vec3(1.0, 1.0, 1.0)));

    osg::Geode* gnode = new osg::Geode;
    osg::ShapeDrawable* sd = new osg::ShapeDrawable(new osg::Box(osg::Vec3(0.0, 0.0, 0.0), 10, 8, 7));
    gnode->addDrawable(sd);

    mt->addChild(gnode);

    return root;
}

class MyEventHandler : public osgGA::GUIEventHandler
{
public:
    MyEventHandler()
    {
        _jiange = 0.5;
    }

    virtual bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa)
    {
        if (ea.getEventType() == ea.KEYDOWN)
        {
            bool _push = false;
            if ((ea.getKey() == 'w') || (ea.getKey() == 'W'))
            {
                _push = true;
                _jiange /= 1.5;
            }
            
            if ((ea.getKey() == 's') || (ea.getKey() == 'S'))
            {
                _push = true;
                _jiange *= 1.5;
            }

            if (_push)
            {
                //清空上一次采样结果
                if (_shiyi != nullptr)
                {
                    _root->removeChild(_shiyi);
                    _shiyi = nullptr;
                }

                _shiyi = new osg::Group();
                _root->addChild(_shiyi);

                std::cout << "采样间隔:"<<_jiange << std::endl;
                //求要求的场景的boudingbox
                osg::BoundingSphere bs = _box->getBound();
                //求出xyz的最小值和最大值,然后根据间隔来求
                osg::Vec3 center = bs.center();
                float r = bs.radius();
                float areas = 0.0;
                for (float fromx = center.x() - r; fromx <= center.x() + r; fromx += _jiange)
                {
                    for (float fromy = center.y() - r; fromy <= center.y() + r; fromy += _jiange)
                    {
                        osg::Vec3 from = osg::Vec3(fromx, fromy, center.z() - r);
                        osg::Vec3 to = osg::Vec3(fromx, fromy, center.z() + r);
                        osgUtil::LineSegmentIntersector::Intersections intersections;
                        osg::ref_ptr<osgUtil::LineSegmentIntersector> ls = new osgUtil::LineSegmentIntersector(from, to);
                        osg::ref_ptr<osgUtil::IntersectionVisitor> iv = new osgUtil::IntersectionVisitor(ls);
                        _box->accept(*iv.get());

                        if (ls->containsIntersections())
                        {
                            intersections = ls->getIntersections();
                            //判断当前交点数
                            if (intersections.size() == 2)
                            {
                                osgUtil::LineSegmentIntersector::Intersections::iterator iter = intersections.begin();
                                osg::Vec3 firstInter = iter->getWorldIntersectPoint();
                                iter++;
                                osg::Vec3 secondInter = iter->getWorldIntersectPoint();
                                _shiyi->addChild(CreateBox(firstInter, secondInter, _jiange));
                                areas += (_jiange*_jiange*std::abs(firstInter.z() - secondInter.z()));
                            }
                        }
                    }
                }

                std::cout << "实际面积:560 计算面积:" << areas << std::endl;
            }
        }

        return false;
    }

    float _jiange;
};


int main()
{
    osgViewer::Viewer viewer;
    viewer.addEventHandler(new MyEventHandler());
    viewer.setSceneData(CreateScene());
    return viewer.run();
}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,222评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,455评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,720评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,568评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,696评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,879评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,028评论 3 409
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,773评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,220评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,550评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,697评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,360评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,002评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,782评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,010评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,433评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,587评论 2 350

推荐阅读更多精彩内容