osgEarth示例分析——osgearth_imageoverlay

前言

imageroverlay示例,在地球上贴图,并且添加控制面板,控制面板上有:mini图标、复选框(控制图片显隐)、图标名称的name、图片的透明度、Edit(控制编辑点的显隐)。

在原有的基础上,本示例又添加了changeImage(更换图片) 和 坐标位置(拖动编辑点,实时更新中心点的坐标)。

执行命令如下。图片参数,直接写入代码中。

osgearth_imageoverlayd.exe earth_image\china-simple.earth

执行效果

 

结构分析

代码分析

#include <osg/Notify>
#include <osgGA/StateSetManipulator>
#include <osgGA/GUIEventHandler>
#include <osgViewer/Viewer>
#include <osgViewer/ViewerEventHandlers>
#include <osgEarth/MapNode>
#include <osgEarthUtil/EarthManipulator>
#include <osgEarthUtil/AutoClipPlaneHandler>
#include <osgEarthUtil/Controls>
#include <osgEarth/Utils>
#include <osgEarth/VirtualProgram>
#include <osgEarth/FileUtils>

#include <osg/ImageStream>
#include <osgDB/FileNameUtils>

#include <osgEarthAnnotation/ImageOverlay>
#include <osgEarthAnnotation/ImageOverlayEditor>

using namespace osgEarth;
using namespace osgEarth::Annotation;
using namespace osgEarth::Util;
using namespace osgEarth::Util::Controls;

// 布局根结点
static Grid* s_layerBox = NULL;

// 创建布局
osg::Node*
createControlPanel( osgViewer::View* view )
{
    ControlCanvas* canvas = ControlCanvas::getOrCreate( view );

    // the outer container:
    s_layerBox = new Grid();
    s_layerBox->setBackColor(0,0,0,0.5);// 设置布局背景色
    s_layerBox->setMargin( 10 ); // 外边距
    s_layerBox->setPadding( 10 );// 内边距
    s_layerBox->setChildSpacing( 10 );// 布局内子类的间距
    s_layerBox->setChildVertAlign( Control::ALIGN_CENTER );// 子类水平居中
    s_layerBox->setAbsorbEvents( true );// 设置接收事件
    s_layerBox->setVertAlign( Control::ALIGN_BOTTOM );// 垂直底部

    canvas->addControl( s_layerBox );    
    return canvas;
}

int
usage( const std::string& msg )
{
    OE_NOTICE << msg << std::endl;
    OE_NOTICE << "USAGE: osgearth_imageoverlay file.earth" << std::endl;
    OE_NOTICE << "   --image <file> xmin ymin xmax ymax : An image to overlay and it's bounds" << std::endl;        
    OE_NOTICE << "   --vert                             : Move individual verts when editing" << std::endl;

        
    return -1;
}

// 透明度控制
struct OpacityHandler : public ControlEventHandler
{
    OpacityHandler( ImageOverlay* overlay ) : _overlay(overlay) { }
    void onValueChanged( Control* control, float value ) {
        _overlay->setAlpha( value );
    }
    ImageOverlay* _overlay;
};

// checkbox的值更改
struct EnabledHandler : public ControlEventHandler
{
    EnabledHandler( ImageOverlay* overlay ) :  _overlay(overlay) { }
    void onValueChanged( Control* control, bool value ) {
        _overlay->setNodeMask( value ? ~0 : 0 );
    }
    ImageOverlay* _overlay;
};

// label标签编辑事件,滑块右侧的edit的标签,进行编辑点显隐的切换
struct EditHandler : public ControlEventHandler
{
    EditHandler( ImageOverlay* overlay, osgViewer::Viewer* viewer, osg::Node* editor) :
      _overlay(overlay),
      _viewer(viewer),
      _editor(editor){ }

    void onClick( Control* control, int mouseButtonMask ) {        
        if (_editor->getNodeMask() != ~0)
        {
            static_cast<LabelControl*>(control)->setText( "Finish" );
            _editor->setNodeMask(~0);
        }
        else
        {
            static_cast<LabelControl*>(control)->setText( "Edit" );
            _editor->setNodeMask(0);
        }
    }

    ImageOverlay* _overlay;
    osgViewer::Viewer* _viewer;
    osg::Node* _editor;
};

// 获取点击鼠标事件,然后将用image替换原来的图片
struct ChangeImageHandler : public ControlEventHandler
{
    ChangeImageHandler( osg::Image* image, ImageOverlay* overlay, ImageControl* preview) :
      _image(image),
      _overlay(overlay),
      _preview(preview){ }

    void onClick( Control* control, int mouseButtonMask ) {
        _overlay->setImage( _image.get() );
        _preview->setImage( _image.get() );
    }
    ImageOverlay* _overlay;
    osg::ref_ptr< osg::Image > _image;
    osg::ref_ptr< ImageControl> _preview;
};

// 覆盖图更新位置回调方法
struct UpdateLabelCallback : public ImageOverlay::ImageOverlayCallback
{
    UpdateLabelCallback(LabelControl* label, ImageOverlay* overlay, ImageOverlay::ControlPoint controlPoint):
      _label(label),
      _overlay(overlay),
      _controlPoint(controlPoint)
    {

    }
	// 当覆盖图被移动时,会打印输出位置信息到label标签上
    virtual void onOverlayChanged()
    {
        osg::Vec2d location = _overlay->getControlPoint( _controlPoint );
        std::stringstream ss;
        ss << location.y() << ", " << location.x();
        std::string str;
        str = ss.str();
        _label->setText( str );
    }
    

    osg::ref_ptr< LabelControl > _label;
    osg::ref_ptr< ImageOverlay > _overlay;
    ImageOverlay::ControlPoint _controlPoint;
};



int
main(int argc, char** argv)
{
    osg::ArgumentParser arguments(&argc,argv);
	// osg::DisplaySettings 封装所需和已设置的视觉效果以及立体观看的状态类
    osg::DisplaySettings::instance()->setMinimumNumStencilBits( 8 );


    std::vector< std::string > imageFiles;
    std::vector< Bounds > imageBounds;

    //Read in the image files
	// 可以通过命令窗口输入文件路径,图片尺寸,并且尺寸是经纬度
    std::string filename;
    Bounds bounds;// 继承自包围盒类
    while (arguments.read("--image", filename, bounds.xMin(), bounds.yMin(), bounds.xMax(), bounds.yMax()))
    {
        imageFiles.push_back( filename );
        imageBounds.push_back( bounds );
    }
	// 
    if (imageFiles.empty())
    {
      imageFiles.push_back("../data/m2525_air.png");// 仅支持png ,加载gif jpg,会显示黑图
      imageBounds.push_back( Bounds(-100, 30, -90, 40) );

	  // 继续追加一张图
	  imageFiles.push_back("../data/m2525_air.png");
	  imageBounds.push_back(Bounds(-120, 30, -110, 40));
    }
 

    bool moveVert = arguments.read("--vert");

    // load the .earth file from the command line.加载map地图
    osg::ref_ptr<osg::Node> earthNode = osgDB::readNodeFiles( arguments );
    if (!earthNode.valid())
        return usage( "Unable to load earth model." );

    osgViewer::Viewer viewer(arguments);
    // 创建操作器并添加到视景器viewer
    EarthManipulator* manip = new EarthManipulator();
    viewer.setCameraManipulator( manip );

    osg::Group* root = new osg::Group();
    root->addChild( earthNode.get() );

    //Create the control panel 创建控制面板
    root->addChild( createControlPanel(&viewer) );

    viewer.setSceneData( root );
    // 获取mapNode
    osgEarth::MapNode* mapNode = osgEarth::MapNode::findMapNode( earthNode.get() );
    if ( mapNode )
    {
		// 当处理多张图时,会添加多组控件
        for (unsigned int i = 0; i < imageFiles.size(); i++)
        {
            std::string imageFile = imageFiles[i];
            //Read the image file and play it if it's a movie 如果传入的图多个,则读取并播放
            osg::ref_ptr<osg::Image> image = osgDB::readRefImageFile(imageFile);
            if (image.valid())
            {
                osg::ImageStream* is = dynamic_cast<osg::ImageStream*>(image.get());
                if (is)
                {
					std::cout << "is->play()" << std::endl;
                    is->play();
                }
            }

            //Create a new ImageOverlay and set it's bounds,创建覆盖图并设置图的边界
            //ImageOverlay* overlay = new ImageOverlay(mapNode->getMap()->getProfile()->getSRS()->getEllipsoid(), image);        
            ImageOverlay* overlay = new ImageOverlay(mapNode);
            overlay->setImage( image.get() );
            overlay->setBounds(imageBounds[i]);
            // 覆盖图加入到mapNode
            mapNode->addChild( overlay );


            //Create a new ImageOverlayEditor and set it's node mask to 0 to hide it initially
			// 遮盖图编辑器
            osg::Node* editor = new ImageOverlayEditor( overlay, moveVert);
            editor->setNodeMask( 1 );//编辑器的绿色点是否可见
            mapNode->addChild( editor );      
            
            // Add an image preview 预览图
            ImageControl* imageCon = new ImageControl( image.get() );
            imageCon->setSize( 64, 64 );
            imageCon->setVertAlign( Control::ALIGN_CENTER );
            s_layerBox->setControl( 0, i, imageCon );            


            //Add some controls    复选框控件    
            CheckBoxControl* enabled = new CheckBoxControl( true );
            enabled->addEventHandler( new EnabledHandler(overlay) );// checkbox控件的事件处理器,仅控制地图上的覆盖图显隐
            enabled->setVertAlign( Control::ALIGN_CENTER );
            s_layerBox->setControl( 1, i, enabled );

            //The overlay name 获取到图片的名称
            LabelControl* name = new LabelControl( osgDB::getSimpleFileName( imageFile) );      
            name->setVertAlign( Control::ALIGN_CENTER );
			name->addEventHandler(new EnabledHandler(overlay));
			//name->addEventHandler(new ChangeImageHandler(image, overlay, imageCon));// 同时控制地图上的覆盖图和预览图显隐
            s_layerBox->setControl( 2, i, name );

            // an opacity slider 滑块,更改透明度
            HSliderControl* opacity = new HSliderControl( 0.0f, 1.0f, overlay->getAlpha() );// 设置范围
            opacity->setWidth( 125 );
            opacity->setHeight( 12 );
            opacity->setVertAlign( Control::ALIGN_CENTER );
            opacity->addEventHandler( new OpacityHandler(overlay) );// 添加事件处理器
            s_layerBox->setControl( 3, i, opacity );

            // Add a text label:
            LabelControl* edit = new LabelControl( "Edit" );        
            edit->setVertAlign( Control::ALIGN_CENTER );
            edit->addEventHandler(new EditHandler(overlay, &viewer, editor));
            s_layerBox->setControl(4, i, edit );

			// 替换遮盖图和预览图标。LabelControl不支持中文
			LabelControl *change = new LabelControl("changeImage");
			change->setVertAlign(Control::ALIGN_CENTER);
			osg::ref_ptr<osg::Image> image2 = osgDB::readRefImageFile("../data/fractal.png");// 替换一张图片
			change->addEventHandler(new ChangeImageHandler(image2.get(), overlay, imageCon));
			s_layerBox->setControl(5, i, change);

			// 拖动图片编辑点,打印输出点的位置信息
			LabelControl *position = new LabelControl("position");// 用于显示坐标信息
			position->setVertAlign(Control::ALIGN_CENTER);
			ImageOverlay::ControlPoint controlPoint(ImageOverlay::ControlPoint::CONTROLPOINT_CENTER);// 获取中心点的坐标
			overlay->addCallback(new UpdateLabelCallback(position, overlay, controlPoint));// 为覆盖图添加回调方法
			s_layerBox->setControl(6, i, position);
        }        
    }

    // add some stock OSG handlers:
    viewer.addEventHandler(new osgViewer::StatsHandler());
    viewer.addEventHandler(new osgViewer::WindowSizeHandler());    
    viewer.addEventHandler(new osgViewer::LODScaleHandler());
    viewer.addEventHandler(new osgGA::StateSetManipulator(viewer.getCamera()->getOrCreateStateSet()));
    viewer.addEventHandler(new osgViewer::HelpHandler(arguments.getApplicationUsage()));
        
    return viewer.run();
}

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在 vue3 中将 Leaflet 的 ImageOverlay 改为 CanvasOverlay,需要进行以下步骤: 1. 安装 Leaflet 和 leaflet-canvas-overlay 包。 ```bash npm install leaflet leaflet-canvas-overlay --save ``` 2. 在 Vue 中引入 Leaflet 和 leaflet-canvas-overlay 包。 在 Vue 中引入 Leaflet 和 leaflet-canvas-overlay 包,可以在 main.js 文件中添加以下代码: ```javascript import L from "leaflet"; import "leaflet-canvas-overlay"; ``` 3. 创建 CanvasOverlay 组件。 在 Vue 中创建 CanvasOverlay 组件,可以在 components 文件夹下创建一个名为 CanvasOverlay.vue 的文件。在该文件中,可以定义组件的模板和方法。 ```html <template> <div> <canvas ref="canvas"></canvas> </div> </template> <script> import L from "leaflet"; import "leaflet-canvas-overlay"; export default { name: "CanvasOverlay", props: { url: { type: String, default: "", }, bounds: { type: Array, default: () => [], }, }, mounted() { const map = this.$parent.map; const canvas = this.$refs.canvas; const overlay = L.canvasOverlay() .params({ url: this.url, bounds: this.bounds, }) .drawing(canvas) .addTo(map); }, }; </script> ``` 4. 使用 CanvasOverlay 组件。 在 Vue 中使用 CanvasOverlay 组件,可以在 App.vue 文件中添加以下代码: ```html <template> <div id="app"> <CanvasOverlay url="./image.png" :bounds="[[40.712, -74.227], [40.774, -74.125]]" /> </div> </template> <script> import CanvasOverlay from "./components/CanvasOverlay.vue"; export default { name: "App", components: { CanvasOverlay, }, mounted() { const map = L.map("app").setView([40.712, -74.227], 13); L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png").addTo( map ); this.map = map; }, }; </script> ``` 其中,CanvasOverlay 组件接受两个 props:url 和 bounds。url 表示图片的路径,bounds 表示图片的经纬度坐标范围。在 mounted 钩子函数中,使用 L.canvasOverlay() 方法创建 CanvasOverlay,将其绑定到地图上即可。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值