osgEarth示例分析——osgearth_infinitescroll

前言

osgearth_infinitescroll示例,是一个可以将二维地图无限拖动的示例。在示例中,可以控制黄色的线一直显示,两张覆盖图默认显示,但拖动地图的时候,有时候显示有时候不显示。

之前一直没有找到如何通过earth文件的方式加载二维地图,真是众里寻他千百度,那earth文件竟在此处呀。

 earth文件如下:两个地方重点,一个是 map 的 type,一个是options标签。之前一直加不上,是因为没有设置 options标签。其他的annotations图元,就可以照葫芦画瓢的添加了。

<map name="Globe" type="projected" version = "2">
	<options>
        <profile>plate-carre</profile>
    </options>
	
	<!--此为全球影像图-->
	<image name="GlobeImage" driver="gdal">
		<url>./globe/globel.tif</url>
	</image>
	
	<annotations>

        <feature name="Flight Path">
            <srs>wgs84</srs>
            <geometry>
LINESTRING(140.385 35.765 0, 141.1 35.4917 3944.77, 142.163 35.1617 9645.92, 142.665 35.38 12496.8, 143.872 35.8933 12496.8, 145.667 37.1967 12496.8, 149.825 39.1533 12496.8, 155.668 42.9817 12496.8, 162.31 46.415 13716, 168.783 48.675 13716, 180 50 13716, 190 50 13716, 200 49 13716, 210 48 13716, 220 46 13716, 233 40.625 14935.2, 236.725 39.0533 14935.2, 238.828 37.8333 14935.2, 240.842 36.0417 14935.2, 240.98 35.9133 13819.4, 241.125 35.5133 11087.5, 241.245 35.1833 8832.26, 241.298 35.0317 7798.3, 241.423 34.6833 5419.12, 241.532 34.4967 4063.71, 241.583 34.41 3430.97, 241.73 34.1567 1591.04, 241.59 33.9433 0)
            </geometry>

            <style type="text/css">
                stroke:              #ffff00;
                stroke-width:        3;
                render-lighting:     false;
            </style>
        </feature>


       <!--An image overlay that crosses the date line and should be split into two chunks-->
        <imageoverlay>
            <url>../fractal.png</url>
            <geometry>POLYGON((170 26, 190 26, 190 56, 170 56))</geometry>
        </imageoverlay>

        <!--An image overlay with non-axis aligned corners-->
        <imageoverlay>
            <url>../fractal.png</url>
            <geometry>POLYGON((-81 26, -40.5 45, -40.5 75.5, -81 60))</geometry>
        </imageoverlay>


    </annotations>
</map>

执行命令: osgearth_infinitescrolld.exe earth_image\world_projected.earth

效果

左移和右移的打印输入部分内容:

测试移动:direction:-1, offset: -4.0075e+07
测试移动:direction:-1, offset: -4.0075e+07
测试移动:direction:1, offset: 4.0075e+07
测试移动:direction:1, offset: 4.0075e+07
测试移动:direction:1, offset: 4.0075e+07

 代码分析

#include <osgViewer/Viewer>
#include <osgEarth/Notify>
#include <osgEarthUtil/EarthManipulator>
#include <osgEarthUtil/ExampleResources>
#include <osgEarth/MapNode>
#include <osgEarth/ThreadingUtils>
#include <osgEarth/Metrics>
#include <iostream>

#define LC "[viewer] "

using namespace osgEarth;
using namespace osgEarth::Util;

int
usage(const char* name)
{
    OE_NOTICE
        << "\nUsage: " << name << " file.earth" << std::endl
        << MapNodeHelper().usage() << std::endl;

    return 0;
}


int
main(int argc, char** argv)
{
    osg::ArgumentParser arguments(&argc,argv);

    // help?
    if ( arguments.read("--help") )
        return usage(argv[0]);

	// 通过vfov,设置视角大小。
	// 增大fov值以提供更沉浸的体验。vfov:视野(Field of View),通常设置45度
    float vfov = -1.0f;
    arguments.read("--vfov", vfov);

    // create a viewer:
    osgViewer::Viewer viewer(arguments);

    // Tell the database pager to not modify the unref settings 
	// 保持 database pager 默认设置
    viewer.getDatabasePager()->setUnrefImageDataAfterApplyPolicy( true, false );

    // thread-safe initialization of the OSG wrapper manager. Calling this here
    // prevents the "unsupported wrapper" messages from OSG
	// OSG包装器管理器的线程安全初始化。
	// 在这里调用它可以防止来自OSG的“不支持的包装器”消息
    osgDB::Registry::instance()->getObjectWrapperManager()->findWrapper("osg::Image");

    // install our default manipulator (do this before calling load)
	// 安装默认操作器
    osg::ref_ptr< EarthManipulator > manipulator = new EarthManipulator(arguments);
    viewer.setCameraManipulator( manipulator );

    // disable the small-feature culling
    viewer.getCamera()->setSmallFeatureCullingPixelSize(-1.0f);

    // set a near/far ratio that is smaller than the default. This allows us to get
    // closer to the ground without near clipping. If you need more, use --logdepth
	// 设置 近远率
    viewer.getCamera()->setNearFarRatio(0.0001);

    if ( vfov > 0.0 )
    {
		// 设置 透视投影矩阵
        double fov, ar, n, f;
        viewer.getCamera()->getProjectionMatrixAsPerspective(fov, ar, n, f);
        viewer.getCamera()->setProjectionMatrixAsPerspective(vfov, ar, n, f);
    }

    // load an earth file, and support all or our example command-line options
    // and earth file <external> tags
    osg::ref_ptr< osg::Node > node = MapNodeHelper().load(arguments, &viewer);

    osg::ref_ptr< MapNode > mapNode = MapNode::findMapNode(node.get());

    if ( mapNode.valid() )
    {
		// 如果是地球类型,则报错退出
        if (mapNode->isGeocentric())
        {
            OE_NOTICE << "Please run this example with a projected earth file" << std::endl;
            return 1;
        }
		// GeoExtent 轴对齐的地理空间范围。与空间参照的坐标系对齐的边界框。
		// 不是特清楚 GeoExtent 类具体的意义。在这里先假设 mapExtene是二维坐标空间。
        GeoExtent mapExtent = mapNode->getMap()->getProfile()->getExtent();

        //Disable the middle mouse by default, which is rotate.  This will keep us in 2D mode.
		// 禁止中轮的旋转操作
        manipulator->getSettings()->bindMouse(osgEarth::Util::EarthManipulator::ACTION_NULL, osgGA::GUIEventAdapter::MIDDLE_MOUSE_BUTTON, 0);

        // Compute a sensible max range so that the user can't zoom out too far to where we need more than 3 transforms.
		// 计算一个合理的最大范围,这样用户就不会缩缩放太远以至于需要3次以上变换才能回到合适位置。
		// width():东西跨度。 height():南北跨度
        double maxDim = osg::maximum(mapExtent.width(), mapExtent.height());// 返回二者中较大的
        double range = ((0.5 * maxDim) / 0.267949849);// 暂时不理解这个计算,总之 range > maxDim
        manipulator->getSettings()->setMinMaxDistance(0.0, range);

        osg::Group* root = new osg::Group;

        // We're going to draw the map three times so that we can provide an infinite view scrolling left to right.
        // 我们将绘制三份地图,以便提供从左向右滚动的无限视图。
        // The centerMatrix is centered around the eye point.
		// 以视点为中心的矩阵
        osg::MatrixTransform* centerMatrix = new osg::MatrixTransform;
        centerMatrix->addChild( mapNode );
        root->addChild( centerMatrix );


        // The left matrix is to the left of the center matrix
		// 中心左侧的矩阵
        osg::MatrixTransform* leftMatrix = new osg::MatrixTransform;
        leftMatrix->addChild( mapNode );
        root->addChild( leftMatrix );

        // The right matrix is to the right of the center matrix
		// 中心右侧矩阵
        osg::MatrixTransform* rightMatrix = new osg::MatrixTransform;
        rightMatrix->addChild( mapNode );
        root->addChild( rightMatrix );

        viewer.setSceneData( root );

        while (!viewer.done())
        {
            // Get the current viewpoint from the EarthManipulator
			// 获取操作器的视点信息
            Viewpoint vp = manipulator->getViewpoint();
            double eyeX = vp.focalPoint()->x();

			// focalPoint() 相机所指向的地理空间位置。
            GeoPoint focalPoint = *vp.focalPoint();

            // Adjust the focal point if the user is trying to too far north or south.
			// 如果用户拖动地图太北或者太南,则调整焦点
            if (focalPoint.y() > mapExtent.yMax())
            {
                focalPoint.y() = mapExtent.yMax();
                vp.focalPoint() = focalPoint;
                manipulator->setViewpoint( vp );
            }
            else if (focalPoint.y() < mapExtent.yMin())
            {
                focalPoint.y() = mapExtent.yMin();
                vp.focalPoint() = focalPoint;
                manipulator->setViewpoint( vp );
            }
             
			// 这是为中心图的坐标空间??
            GeoExtent centerExtent =  mapExtent;
            
            // Figure out which direction we need to shift the map extent 
			// 找出我们需要改变地图范围的方向
            float direction = 0.0;
            if (eyeX < mapExtent.xMin())// 视点在坐标范围的左侧,则图左移。
            {
                // Move to the left
                direction = -1.0;
            }
            else if (eyeX > mapExtent.xMax())
            {
                // Move to the right
                direction = 1.0;
            }


            // Shift the center extent so that it's centered around the eye point.
			// 转换中心坐标,以至于总能 让视点与 center extent坐标系一致
            float offset = 0.0;

            if (direction != 0.0)
            {	
				// 不太理解这一部分的处理方法
                while (true)// 左右移动时,X方向,一直调整,直到调整到合适位置
                {
                    centerExtent = GeoExtent(centerExtent.getSRS(),
                                   mapExtent.xMin() + offset, mapExtent.yMin(), 
                                   mapExtent.xMax() + offset, mapExtent.yMax());
                    if (eyeX >= centerExtent.xMin() && eyeX <= centerExtent.xMax())
                    {
                        break;
                    }

                    offset += direction * centerExtent.width();
					// std::cout << "测试移动:direction:" << direction << ", offset: " << offset << std::endl;
                }
            }

            // Update the matrix transforms. 更新矩阵。三个矩阵上,各有一份地图
            centerMatrix->setMatrix(osg::Matrixd::translate(offset, 0.0, 0.0));
            leftMatrix->setMatrix(osg::Matrixd::translate(offset - mapExtent.width(), 0.0, 0.0));
            rightMatrix->setMatrix(osg::Matrixd::translate(offset + mapExtent.width(), 0.0, 0.0));
          
            viewer.frame();
        }
        
    }
    else
    {
        return usage(argv[0]);
    }

    return 0;
}

  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是在 Visual Studio 2022 中使用 osgEarth示例: 1. 安装 osgEarth 首先需要在你的系统中安装 osgEarth。可以从官网下载安装包进行安装,也可以使用 CMake 进行源码编译安装。 2. 创建一个 osgEarth 应用程序 在 Visual Studio 2022 中创建一个新的 C++ 控制台应用程序项目。然后,将 osgEarth 的 include 和 library 路径添加到项目中: - 右键单击项目,选择“属性”。 - 在“VC++ 目录”中添加包含路径和库路径。 - 在“链接器 -> 输入”中添加 osgEarth 的库文件。 3. 创建一个 osgEarth 地图节点 在应用程序中创建一个 osgEarth 地图节点,并将其添加到场景图中: ```cpp #include <osgEarth/MapNode> #include <osgEarthUtil/EarthManipulator> int main(int argc, char** argv) { // 初始化 osgEarthosgEarth::initialize(); // 创建一个 osgEarth 地图节点 osg::ref_ptr<osgEarth::MapNode> mapNode = osgEarth::MapNode::create(osgEarth::MapNodeOptions()); // 创建一个 osgEarth 视图并添加地图节点 osg::ref_ptr<osgViewer::View> view = new osgViewer::View; view->setSceneData(mapNode); // 设置地球操纵器 osg::ref_ptr<osgEarth::Util::EarthManipulator> manipulator = new osgEarth::Util::EarthManipulator; view->setCameraManipulator(manipulator); // 显示视图 osgViewer::Viewer viewer; viewer.addView(view); return viewer.run(); } ``` 以上代码创建了一个 osgEarth 地图节点,并使用 EarthManipulator 对其进行控制。注意要在程序结束前调用 osgEarth::shutdown(),以释放资源。 4. 运行应用程序 点击“生成”按钮编译应用程序,并运行应用程序。如果一切正常,应该可以看到一个 osgEarth 地球视图。 以上是在 Visual Studio 2022 中使用 osgEarth 的简单示例。根据需要,还可以使用 osgEarth 的其他功能来创建更复杂的地图应用程序。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值