美文网首页
第17节 实例-倾斜摄影数据挖填方

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

作者: 杨石兴 | 来源:发表于2021-06-20 17:37 被阅读0次

    致谢

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

    问题描述

    在第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();
    }
    

    相关文章

      网友评论

          本文标题:第17节 实例-倾斜摄影数据挖填方

          本文链接:https://www.haomeiwen.com/subject/gossyltx.html