osgearth仿真平台之测量工具(2)

本文介绍了一种三维地理信息系统中的测量工具实现方法,包括表面距离、空间距离、表面面积及空间面积的测量。通过具体代码展示了如何捕捉用户输入,并计算两点间距离及多点构成区域的面积。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

测量工具主要是用于测量地球上两点之间的表面距离,空间距离,表面积可空间面积,以及两点之间的可视等。

表面距离测量:

核心代码:

bool GeoGlobe::DistanceMeasureHandler::handle( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa )
{    
    if (_Finished)
        return false;

    osgViewer::View* view = static_cast<osgViewer::View*>(aa.asView());                
    if (ea.getEventType() == osgGA::GUIEventAdapter::PUSH && ea.getButton() == _mouseButton)
    {        
        _mouseDown = true;
        _mouseDownX = ea.getX();
        _mouseDownY = ea.getY();

    }
    else if (ea.getEventType() == osgGA::GUIEventAdapter::RELEASE && ea.getButton() == _mouseButton)
    {        
        float eps = 1.0f;
        _mouseDown = false;
        if (osg::equivalent(ea.getX(), _mouseDownX, eps) && osg::equivalent(ea.getY(), _mouseDownY, eps))
        {
            double lon, lat;
            if (getLocationAt(view, ea.getX(), ea.getY(), lon, lat))
            {
                if (!_gotFirstLocation)
                {
                    _Finished = false;
                  //  clear();                    
                    _gotFirstLocation = true;
                    _feature->getGeometry()->push_back( osg::Vec3d( lon, lat, 0 ) );
                }
                else
                {
                    if (_lastPointTemporary)
                    {
                        _feature->getGeometry()->back() = osg::Vec3d( lon, lat, 0 );
                        _lastPointTemporary = false;
                    }
                    else
                    {                     
                        _feature->getGeometry()->push_back( osg::Vec3d( lon, lat, 0 ) );
                    }

                    _start = GeoPoint(getMapNode()->getMapSRS(), lon, lat, ALTMODE_ABSOLUTE);

                    _featureNode->init();


                    if (_geoInterpolation == GEOINTERP_GREAT_CIRCLE)
                    {
                        distance = GeoMath::distance(_feature->getGeometry()->asVector());
                    }

                    for (MeasureToolEventHandlerList::const_iterator i = _eventHandlers.begin(); i != _eventHandlers.end(); ++i)
                    {
                        i->get()->onDistanceChanged(this, distance);
                    }

                    std::ostringstream s1;
                    std::ostringstream osm;
                    osm.precision(2);           // 浮点数转换限制  
                    osm.setf(std::ios::fixed); // 将浮点数的位数限定为小数点之后的位数  
                    if (distance > 1000)
                    {
                        osm << distance / 1e3;
                        s1  << osm.str() << "km" << "\n";
                    }
                    else
                    {
                        osm << distance;
                        s1 << osm.str() << "m" << "\n";
                    }

                    std::string na = s1.str();
                    m_SymStyle.getOrCreate<osgEarth::Symbology::TextSymbol>()->size() = 18.0f;
                    m_SymStyle.getOrCreate<osgEarth::Symbology::TextSymbol>()->fill()->color() = Color::White;
                    m_SymStyle.getOrCreate<osgEarth::Symbology::TextSymbol>()->font() = "msyh.ttc";
                    m_SymStyle.getOrCreate<osgEarth::Symbology::TextSymbol>()->encoding() = osgEarth::Symbology::TextSymbol::ENCODING_UTF8;
                    m_ptrLabelNode = new GeoGlobe::Annotation::PlaceNode(_start, na, m_SymStyle);
                    m_ptrLabelNode->setDynamic(true);
                    m_ptrLabelNode->setCullingActive(true);
                    m_ptrGroup->addChild(m_ptrLabelNode);

                    if (_Finished || !_isPath) {
                        _gotFirstLocation = false;
                    }

                    fireDistanceChanged();
                    aa.requestRedraw();
                }
            }
        }
    }  
    else if (ea.getEventType() == osgGA::GUIEventAdapter::DOUBLECLICK) {        
        if (_gotFirstLocation)
        {
            _Finished = true;    
            aa.requestRedraw();

            return true;
        }
    }
    else if (ea.getEventType() == osgGA::GUIEventAdapter::MOVE)
    {
        if (_gotFirstLocation)
        {
            double lon, lat;
            if (getLocationAt(view, ea.getX(), ea.getY(), lon, lat))
            {
                if (!_lastPointTemporary)
                {
                    _feature->getGeometry()->push_back( osg::Vec3d( lon, lat, 0 ) );                 
                    _lastPointTemporary = true;
                }                        
                else
                {
                    _feature->getGeometry()->back() = osg::Vec3d( lon, lat, 0 );
                }
                _featureNode->init();
                fireDistanceChanged();

                aa.requestRedraw();

            }
        }
    }    
    return false;
}

 空间距离测量:

 核心代码:

bool Distance3DTrakerElement::handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa)
{
    if (m_bIsFinished)
        return false;

    osgViewer::View* view = static_cast<osgViewer::View*>(aa.asView());
    
    int size;
    std::ostringstream s1;
    osgEarth::GeoPoint mapPoint;

    if (ea.getEventType() == osgGA::GUIEventAdapter::RELEASE && ea.getButton()== osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON)
    {
        if (m_isDrag)
        {
            m_isDrag = false;
            return true;
        }

        if (!pick(view, ea, world))
        {
            return false;
            m_isDrag = false;
        }

        //线的起点
        if (m_bIsFirst)
        {        
            m_PickPoints.push_back(world);
            size = m_PickPoints.size();

            RubberBand = createLine(m_PickPoints[m_PickPoints.size() - 1], world, m_PickPoints[0]);
            displayGroup->addChild(RubberBand);

            std::string strText = "start";
            mapPoint.fromWorld(m_mapNode->getTerrain()->getSRS(), world);
            displayGroup->addChild(CreateLabel(m_mapNode, mapPoint, strText));

            m_isDrag = false;
            m_bIsFirst = false;
            return false;
        }
        else
        {
            m_PickPoints.push_back(world);
            size = m_PickPoints.size();
                
            //画线,使用相对位置,再偏移至绝对位置,数值小,线不抖
            osg::Node* ptrLine3D = createLine(m_PickPoints[size - 2], m_PickPoints[size - 1], m_PickPoints[0]);
            displayGroup->addChild(ptrLine3D);

            //计算三维距离
            m_Distance3D += (m_PickPoints[size - 2]- m_PickPoints[size - 1]).length();

            //添加标签,设置有效位        
            s1 << setiosflags(ios::fixed) << setprecision(2) << m_Distance3D << "m" << "\n";
            std::string strText = s1.str();
            mapPoint.fromWorld(m_mapNode->getTerrain()->getSRS(), world);
            displayGroup->addChild(CreateLabel(m_mapNode, mapPoint, strText));

            //删除橡皮筋对象
            displayGroup->removeChild(RubberBand);
            m_isDrag = false;
        }        
        m_isDrag = false;
    }
    else if(ea.getEventType() == osgGA::GUIEventAdapter::MOVE)
    {
        if (!m_bIsFirst)
        {
            if (!pick(view, ea, world))
                return false;
            
            displayGroup->removeChild(RubberBand);
            RubberBand = createLine(m_PickPoints[m_PickPoints.size() - 1], world, m_PickPoints[0]);
            displayGroup->addChild(RubberBand);
        }
    }
    else if(ea.getEventType() == osgGA::GUIEventAdapter::DOUBLECLICK)
    {
        m_isDrag = false;
        m_bIsFinished = true;
        displayGroup->removeChild(RubberBand);
    }
    else if (ea.getEventType() == osgGA::GUIEventAdapter::DRAG)
    {
        m_isDrag = true;
    }
    return false;
}

表面面积:

核心代码:

    bool AreaTrakerElement::handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa, osg::Object* object, osg::NodeVisitor* visitor)
    {
        if (m_bFinished)
            return false;

        osgViewer::View* view = static_cast<osgViewer::View*>(aa.asView());
        if (ea.getEventType() == osgGA::GUIEventAdapter::PUSH && ea.getButton() == osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON)
        {

        }
        else if (ea.getEventType() == osgGA::GUIEventAdapter::RELEASE && ea.getButton() == osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON)
        {
            if (m_bIsDrag)
            {
                m_bIsDrag = false;
                return false;
            }

            osg::Vec3d vecWord;
            m_ptrMapNode->getTerrain()->getWorldCoordsUnderMouse(aa.asView(), ea.getX(), ea.getY(), vecWord);
            m_vecWorld.push_back(vecWord);
            osgEarth::GeoPoint mapPoint;
            mapPoint.fromWorld(m_ptrMapNode->getMapSRS(), vecWord);
            m_vecWgs84.push_back(mapPoint.vec3d());
            if (mapPoint.x() < -180 || mapPoint.x() > 180 || mapPoint.y() < -90 || mapPoint.y() > 90 || fabs(mapPoint.z()) > 1000000)
                return false;

            osgEarth::Features::Feature* ptrFeature = m_ptrFeartureNode->getFeature();
            ptrFeature->getGeometry()->push_back(mapPoint.vec3d());
            m_ptrFeartureNode->dirty();

        }
        else if (ea.getEventType() == osgGA::GUIEventAdapter::DOUBLECLICK && ea.getButton() == osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON)
        {
            m_bFinished = true;
            Calcuate();
        }
        else if (ea.getEventType() == osgGA::GUIEventAdapter::MOVE)
        {
            osgEarth::Features::Feature* ptrFeature = m_ptrFeartureNode->getFeature();

            if (ptrFeature->getGeometry()->size() == 0)
                return false;

            osg::Vec3d vecWord;
            m_ptrMapNode->getTerrain()->getWorldCoordsUnderMouse(aa.asView(), ea.getX(), ea.getY(), vecWord);
            osgEarth::GeoPoint mapPoint;
            mapPoint.fromWorld(m_ptrMapNode->getMapSRS(), vecWord);

            if (mapPoint.x() < -180 || mapPoint.x() > 180 || mapPoint.y() < -90 || mapPoint.y() > 90 || fabs(mapPoint.z()) > 1000000)
                return false;

            if (ptrFeature->getGeometry()->size() == 1)
                ptrFeature->getGeometry()->push_back(mapPoint.vec3d());
            else
                ptrFeature->getGeometry()->back() = mapPoint.vec3d();

            m_ptrFeartureNode->dirty();
        }
        else if (ea.getEventType() == osgGA::GUIEventAdapter::DRAG)
        {
            m_bIsDrag = true;
        }

        return false;
    }

 空间面积:

核心代码:

bool Area3DTrakerElement::handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa)
{
    if (m_bIsFinished)
        return false;

    osgViewer::View* view = static_cast<osgViewer::View*>(aa.asView());
    osg::Group* root = static_cast<osg::Group*>(view->getSceneData());
    int size;
    std::ostringstream s1;
    osgEarth::GeoPoint mapPoint;

    if (ea.getEventType() == osgGA::GUIEventAdapter::RELEASE && ea.getButton() == osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON)
    {
        if (m_isDrag)
        {
            m_isDrag = false;
            return true;
        }

        //线的起点
        if (m_bIsFirst)
        {
            if (!pick(view, ea, world))
                return false;

            m_PickPoints.push_back(world);
            size = m_PickPoints.size();

            /*    
            std::string strText = CodeHelp::String_To_UTF8("起点");
            mapPoint.fromWorld(m_mapNode->getTerrain()->getSRS(), world);
            displayGroup->addChild(CreateLabel(m_mapNode, mapPoint, strText));        
            */

            m_bIsFirst = false;
            m_isDrag = false;
            return false;
        }
        else
        {
            m_PickPoints.push_back(world);
            size = m_PickPoints.size();
            //画线,使用相对位置,再偏移至绝对位置,数值小,线不抖
            osg::Node* ptrLine3D = createLine(m_PickPoints[size - 2], m_PickPoints[size - 1], m_PickPoints[0]);
            displayGroup->addChild(ptrLine3D);
            
            //删除橡皮筋对象
            displayGroup->removeChild(RubberBand);
            displayGroup->removeChild(m_closeRubberBand);
        }
        m_isDrag = false;
    }
    else if (ea.getEventType() == osgGA::GUIEventAdapter::MOVE)
    {
        if (!m_bIsFirst)
        {
            if (!pick(view, ea, world))
                return false;

            displayGroup->removeChild(RubberBand);
            displayGroup->removeChild(m_closeRubberBand);
            RubberBand = createLine(m_PickPoints[m_PickPoints.size() - 1], world, m_PickPoints[0]);

            m_closeRubberBand = createLine(m_PickPoints[0], world, m_PickPoints[0]);
            displayGroup->addChild(RubberBand);
            displayGroup->addChild(m_closeRubberBand);
        }
    }
    else if (ea.getEventType() == osgGA::GUIEventAdapter::DOUBLECLICK)
    {
        //面积闭合
        osg::Node* ptrLine3D = createLine(m_PickPoints[0], m_PickPoints[m_PickPoints.size() - 1], m_PickPoints[0]);
        displayGroup->addChild(ptrLine3D);

        m_isDrag = false;

        //计算三维距离
        //1 三角形剖分
        if (!AreaMeasurement(m_PickPoints, m_Area3D))
            return false;
        ////2 平面拟合
        //double Area;
        //calArea3D(m_PickPoints,Area);

        //3 直接去掉Z值
        std::vector<osg::Vec2d> Points;
        double area;

        //添加标签,设置有效位
        if (m_Area3D > 100000)
        {
            double showValue = m_Area3D / 1000000;
            s1 << setiosflags(ios::fixed) << setprecision(2) << showValue << "km^2" << "\n";
        }
        else
            s1 << setiosflags(ios::fixed) << setprecision(2) << m_Area3D << "m^2" << "\n";

        osg::Vec3d labelPos;
        for (int i = 0;i<m_PickPoints.size();i++)
        {
            labelPos += m_PickPoints[i];
        }
        labelPos = labelPos / m_PickPoints.size();
        mapPoint.fromWorld(m_mapNode->getTerrain()->getSRS(),labelPos);

        std::string strText = s1.str();
        osgEarth::Symbology::Style style;
        style.getOrCreate<osgEarth::Symbology::TextSymbol>()->size() = 18.0f;
        style.getOrCreate<osgEarth::Symbology::TextSymbol>()->fill()->color() = osgEarth::Symbology::Color::White;
        style.getOrCreate<osgEarth::Symbology::TextSymbol>()->font() = "msyh.ttc";
        style.getOrCreate<osgEarth::Symbology::TextSymbol>()->encoding() = osgEarth::Symbology::TextSymbol::ENCODING_UTF8;
        osg::ref_ptr<GeoGlobe::PlaceName::GeoBillboard> billboard = new GeoGlobe::PlaceName::GeoBillboard(osgEarth::GeoPoint(m_mapNode->getMapSRS(), mapPoint), strText, style, true);
        billboard->setCullingActive(false);

        displayGroup->addChild(/*CreateLabel(m_mapNode, mapPoint, strText)*/billboard);

        m_bIsFinished = true;
        displayGroup->removeChild(RubberBand);
        displayGroup->removeChild(m_closeRubberBand);
    }
    else if (ea.getEventType() == osgGA::GUIEventAdapter::DRAG)
    {
        m_isDrag = true;
    }

    return false;
}

 

### OSGEarth 使用指南及相关资源 OSGEarth 是 OpenSceneGraph (OSG) 的扩展库,专注于地理空间数据的可视化。它支持多种地理空间数据格式,并提供了一系列工具来帮助开发者快速构建基于地球模型的应用程序。 #### 下载与安装 可以从官方渠道获取 OSGOSGEarth 的源码和预编译库[^2]。以下是主要下载链接: - **OSG 官网**: [http://www.openscenegraph.org/](http://www.openscenegraph.org/) - **OSG GitHub 仓库**: [https://github.com/openscenegraph/OpenSceneGraph](https://github.com/openscenegraph/OpenSceneGraph) - **OSGEarth 下载页面**: [http://www.openscenegraph.org/index.php/download-section/stable-releases](http://www.openscenegraph.org/index.php/download-section/stable-releases) 对于第三方依赖项,可以访问以下地址: - **Third Party Libraries**: [https://download.osgvisual.org/](https://download.osgvisual.org/) 如果需要特定平台的支持或者已经编译好的库文件,推荐参考 osgChina 站长提供的资源[^2]。 #### 支持的数据格式 OSGEarth 能够解析并渲染多种类型的地理空间数据,包括但不限于以下几种[^3]: - **GeoTIFF 图像与 DEM 文件** - **ESRI Shapefile (.shp)** 矢量数据 - **WMS (Web Map Service)** 提供的地图服务 - **OpenStreetMap**, **ArcGIS Online**, **NASA OnEarth** 等在线地图服务 这些数据可以通过配置 `.earth` 文件的方式加载到应用程序中。 #### 工具与功能演示 OSGEarth 自带了一些实用工具,其中最常用的是 `osgearth_viewer`,它可以用来测试不同的 `.earth` 配置文件并展示其效果[^4]。下面是一些常见的 `.earth` 文件及其用途: - **Feature_draped_lines.earth**: 展示国界线。 - **Graticule.earth**: 显示经纬网格及坐标标注。 - **Ldb.earth**: 在地球上某个固定高度放置一个静态对象(如飞机)。 通过运行这些样例文件,用户能够直观理解如何利用 OSGEarth 实现复杂的功能需求。 #### 编程接口简介 为了更好地集成 OSGEarth 到项目中,建议熟悉以下几个核心概念: 1. 场景图结构:类似于标准 OSG 应用程序,但增加了对地理坐标的原生支持。 2. 数据源管理:定义从何处读取地理信息以及如何缓存它们。 3. 渲染选项定制:调整视口范围、分辨率以及其他视觉参数以满足具体应用的要求。 下面是创建基本场景的一个简单代码片段: ```cpp #include <osgViewer/Viewer> #include <osgEarth/MapNode> int main(int argc, char* argv[]) { // 初始化 viewer osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer(); // 加载 earth 文件作为 map osg::ref_ptr<osgEarth::Map> map = osgEarth::MapFactory::load("path/to/map_file.earth"); if (!map.valid()) { std::cerr << "Failed to load the specified .earth file." << std::endl; return EXIT_FAILURE; } // 创建 MapNode 并添加至 scene graph osg::ref_ptr<osgEarth::MapNode> mapNode = new osgEarth::MapNode(map); viewer->setSceneData(mapNode); // 启动主循环 return viewer->run(); } ``` 此脚本展示了如何加载自定义 `.earth` 文件并将生成的地图节点设置为主场景的一部分。 --- ###
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

吉生太

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值