第17节 实例-倾斜摄影数据挖填方

致谢

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

问题描述

在第12节(这是第17节,往前翻翻)挖填方的基础上,仍有网友提问怎么做倾斜摄影的挖填方,仿照大疆的一个什么软件的结果。如图:
image.png

下图是本程序的对比(结果大差不差):


image.png

各方确认各点的精确值并没有,因此上面的点我只能大差不差的点,而上图还一个最关键信息是:基准面:最低点

也就是以点出的点的最低点为基准面来计算挖填方。同时也有网友提出来我要在这个图形上挖个沟,沟的模型有,地表的模型有,求挖沟的挖方与填方。这与本节中所说的方法都是一样的。以供大家参考。

资源下载(这一节是有模型的)

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

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

本节程序功能

1.程序加载倾斜摄影,调整到要测试挖填方的位置后,按住左shift键,鼠标在地图上单击,则会出现小球。超过三个点则会出现小球围成的面。
2.点完之后,点击s键,就会进行挖填方的计算。即使用原始点围面的面来计算,也使用以最低点为基准面围成的面来计算。

关键思想

1.比之第12节,我们求交发生了变化,首先与我们点的面来求交,其次再与地形求交。比较其z值的大小,看谁在谁之上。若面在地形之上,则是填方,若地形在面之上则是挖方。
2.若依最低点为基准面,则只需要遍历所有的顶点的z值,找到最小的,在上一步的基础上将与点的面的求交点的z值设置为最低点的z值。再按照上一步的思路求一下就OK。

以下为全部代码,模型在网盘中下载


#include <osgViewer/Viewer>
#include <osgDB/ReadFile>
#include <osgGA/EventHandler>
#include <osg/ShapeDrawable>
#include <osg/Shape>

osg::Node* _base = nullptr;//地形
osg::Group* _root = new osg::Group;//场景根结点


osg::Geode* _mask = new osg::Geode;//鼠标点出来的面
osg::Geometry* _maskGeom = new osg::Geometry;
osg::DrawArrays* _da = new osg::DrawArrays;

osg::Group* _mark = new osg::Group;//小球

osg::Node* createSphere(osg::Vec3 center)
{
    osg::Geode* gnode = new osg::Geode;
    osg::ShapeDrawable* sd = new osg::ShapeDrawable(new osg::Sphere(center, 0.2));
    gnode->addDrawable(sd);
    gnode->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
    return gnode;
}

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

class MyEventHandler : public osgGA::GUIEventHandler
{
public:
    MyEventHandler()
    {
        vertexArray = new osg::Vec3Array;
        _maskGeom->setVertexArray(vertexArray);

        osg::Vec4Array* color = new osg::Vec4Array;
        color->push_back(osg::Vec4(1.0, 0.0, 0.0, 0.4));
        _maskGeom->setColorArray(color, osg::Array::BIND_OVERALL);
    }

    virtual bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa)
    {
        if (ea.getEventType() == ea.PUSH)
        {
            //是左键且左shift按下了
            if ((ea.getButton() == ea.LEFT_MOUSE_BUTTON) && (ea.getModKeyMask() == ea.MODKEY_LEFT_SHIFT))
            {
                osgUtil::LineSegmentIntersector::Intersections intersections;
                osgViewer::View* view = dynamic_cast<osgViewer::View*>(&aa);
                if (view->computeIntersections(ea, intersections))
                {
                    //有交点,先画个球
                    osg::Vec3 hitPoint = intersections.begin()->getWorldIntersectPoint();
                    _mark->addChild(createSphere(hitPoint));

                    vertexArray->push_back(hitPoint);

                    if (vertexArray->size() >= 3)
                    {
                        _da->set(GL_POLYGON, 0, vertexArray->size());
                        _maskGeom->dirtyDisplayList();//redraw
                    }
                    
                }

                
            }
        }

        if (ea.getEventType() == ea.KEYDOWN)
        {
            if((ea.getKey() == 'x')|| (ea.getKey() == 'X'))
            {
                _da->set(GL_POLYGON, 0, 0);
                _maskGeom->dirtyDisplayList();//redraw

                _mark->removeChildren(0, _mark->getNumChildren());

                vertexArray->clear();
            }

            if ((ea.getKey() == 's') || (ea.getKey() == 'S'))
            {
                //开始计算挖方量与填方量
                //与点围成的面先求是否有交点,有交点再求与地形交点,两个交点之间的距离就是需要挖/填的方
                //其中与面的距离在上,则是填方,与地形交点距离在上,则是挖方,使用z值大小来判断距离
                //求要求的场景的boudingbox
                _maskGeom->dirtyBound();//因为顶点改变,必须重新计算包围盒
                osg::BoundingSphere bs = _maskGeom->getBound();
                //求出xyz的最小值和最大值,然后根据间隔来求
                osg::Vec3 center = bs.center();
                float r = bs.radius();

                //以点的原点为基准面
                //挖方量
                float volumesW = 0.0;
                //填方量
                float volumesT = 0.0;

                //以最低点为基准面
                //挖方量
                float volumesWL = 0.0;
                //填方量
                float volumesTL = 0.0;
                //查找基准面的z值的最小值
                float zmin = FLT_MAX;
                for (int i = 0; i < vertexArray->size(); i++)
                {
                    if (zmin > vertexArray->at(i).z())
                    {
                        zmin = vertexArray->at(i).z();
                    }
                }

                //采样一个方向上采50份
                float stepSize = r / 50;
                for (float fromx = center.x() - r; fromx <= center.x() + r; fromx += stepSize)
                {
                    for (float fromy = center.y() - r; fromy <= center.y() + r; fromy += stepSize)
                    {
                        //乘1000是为了确保与地形相交,与面相交不需要乘1000
                        osg::Vec3 from = osg::Vec3(fromx, fromy, center.z() - r*1000);
                        osg::Vec3 to = osg::Vec3(fromx, fromy, center.z() + r*1000);
                        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);
                        _mask->accept(*iv.get());

                        if (ls->containsIntersections()) //与点出来的面有交点
                        {
                            intersections = ls->getIntersections();

                            //与地形必有交点
                            osgUtil::LineSegmentIntersector::Intersections intersections0;
                            osg::ref_ptr<osgUtil::LineSegmentIntersector> ls0 = new osgUtil::LineSegmentIntersector(from, to);
                            osg::ref_ptr<osgUtil::IntersectionVisitor> iv0 = new osgUtil::IntersectionVisitor(ls0);
                            _base->accept(*iv0.get());

                            if (ls0->containsIntersections()) //与地形必有交点
                            {
                                intersections0 = ls0->getIntersections();


                                osg::Vec3 maskInter = intersections.begin()->getWorldIntersectPoint();
                                osg::Vec3 terrainInter = intersections0.begin()->getWorldIntersectPoint();

                                if (maskInter.z() > terrainInter.z())
                                {
                                    volumesT += (stepSize * stepSize * std::abs(maskInter.z() - terrainInter.z()));
                                    _mark->addChild(CreateBox(maskInter, terrainInter, stepSize, osg::Vec4(0.0, 1.0, 0.0, 1.0)));
                                }
                                else
                                {
                                    volumesW += (stepSize * stepSize * std::abs(maskInter.z() - terrainInter.z()));
                                    _mark->addChild(CreateBox(maskInter, terrainInter, stepSize, osg::Vec4(1.0, 0.0, 0.0, 1.0)));
                                }

                                maskInter.z() = zmin;
                                if (maskInter.z() > terrainInter.z())
                                {
                                    volumesTL += (stepSize * stepSize * std::abs(maskInter.z() - terrainInter.z()));
                                }
                                else
                                {
                                    volumesWL += (stepSize * stepSize * std::abs(maskInter.z() - terrainInter.z()));
                                }

                            }                            
                        }

                    }
                }

                std::cout << "采用原点为基准面:" << std::endl;
                std::cout << "挖方量:" << volumesW << std::endl;
                std::cout << "填方量:" << volumesT << std::endl;
                std::cout << "采用最低点为基准面:" << std::endl;
                std::cout << "挖方量:" << volumesWL << std::endl;
                std::cout << "填方量:" << volumesTL << std::endl;
                
            }
        }

        return false;
    }

    osg::Vec3Array* vertexArray;
};


int main()
{
    osgViewer::Viewer viewer;

    _base = osgDB::readNodeFile("model/Block/Block.osgb");
    _base->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
    _root->addChild(_base);

    _mask->addDrawable(_maskGeom);
    _maskGeom->addPrimitiveSet(_da);
    _mask->getOrCreateStateSet()->setMode(GL_BLEND, osg::StateAttribute::ON);
    _mask->getOrCreateStateSet()->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);

    _root->addChild(_mark);
    _root->addChild(_mask);

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