前言

osgearth_pick示例,展示了鼠标移动(或者鼠标单击)时,触及到的矢量特征、绘制的线、遮盖图等内容,会将这些内容的信息打印输出到屏幕上。

执行命令

// 三维地图或者二维地图都可。// 三维图
osgearth_pickd.exe earth_image\china-simple.earth// 二维图
osgearth_pickd.exe earth_image\world_projected.earth

效果

鼠标移动到某条线上(线条会变色),获取到特征边界线的信息,显示在左上角。左下角显示矢量图。

鼠标移动到遮盖图上(或者线条上,线条会变色),获取遮盖图信息,现实在左上角下。左下角显示图元信息。

代码分析

本节示例,代码逻辑比前几篇更难理解一些。

#include <osgEarth/Registry>
#include <osgEarth/ShaderGenerator>
#include <osgEarth/ObjectIndex>
#include <osgEarth/GLUtils>
#include <osgEarthUtil/EarthManipulator>
#include <osgEarthUtil/ExampleResources>
#include <osgEarthUtil/Controls>
#include <osgEarthUtil/RTTPicker>
#include <osgEarthFeatures/Feature>
#include <osgEarthFeatures/FeatureIndex>
#include <osgEarthAnnotation/AnnotationNode>#include <osgEarth/IntersectionPicker>#include <osgViewer/CompositeViewer>
#include <osgGA/TrackballManipulator>
#include <osg/BlendFunc>#define LC "[rttpicker] "using namespace osgEarth;
using namespace osgEarth::Util;
using namespace osgEarth::Features;
using namespace osgEarth::Annotation;namespace ui = osgEarth::Util::Controls;//-----------------------------------------------------------------------//! Application-wide data.
struct App
{App(osg::ArgumentParser& args) : viewer(args), mainView(NULL), rttView(NULL), mapNode(NULL), picker(NULL) { }// 多视景器,且通过args初始化viewerosgViewer::CompositeViewer viewer;osgViewer::View* mainView;// 主视景器osgViewer::View* rttView; // rtt视景器osgEarth::MapNode* mapNode;osgEarth::Util::RTTPicker* picker;// rtt拾取类ui::LabelControl* fidLabel;ui::LabelControl* nameLabel;osg::Uniform*     highlightUniform;// 高亮的变量
};//! Callback that you install on the RTTPicker.
// 安装RTTPicker后,提供RTTPicker的回调方法
struct MyPickCallback : public RTTPicker::Callback
{App& _app;MyPickCallback(App& app) : _app(app) { }void onHit(ObjectID id){// First see whether it's a feature:FeatureIndex* index = Registry::objectIndex()->get<FeatureIndex>(id).get();Feature* feature = index ? index->getFeature( id ) : 0L;// 有feature标签,则拾取feature标签if ( feature ){_app.fidLabel->setText( Stringify() << "Feature ID = " << feature->getFID() << " (oid = " << id << ")" );_app.nameLabel->setText( Stringify() << "Name = " << feature->getString("name") );}else // 存在annotation标注,则拾取annotation标注{// Check whether it's an annotation:AnnotationNode* anno = Registry::objectIndex()->get<AnnotationNode>(id).get();if ( anno ){_app.fidLabel->setText( Stringify() << "ObjectID = " << id );_app.nameLabel->setName( Stringify() << "Name = " << anno->getName() );}// None of the above.. clear. 什么也没有获取到else{_app.fidLabel->setText( Stringify() << "unknown oid = " << id );_app.nameLabel->setText( " " );}}_app.highlightUniform->set( id );// 将对象id设置给高亮变量}// 取消拾取时,回复标签显示void onMiss(){_app.fidLabel->setText( "No pick." );_app.nameLabel->setText( " " );_app.highlightUniform->set( 0u );}// pick whenever the mouse moves.// 当鼠标移动时,获取。也可以改为鼠标点击时获取bool accept(const osgGA::GUIEventAdapter& ea, const osgGA::GUIActionAdapter& aa){// return ea.getEventType() == ea.MOVE;// 移动时获取,移动到空白区域,则取消选中和高亮。return ea.getEventType() == ea.RELEASE;// 点击时获取,再点击其他地方,则取消选中和高亮。}
};//-----------------------------------------------------------------------// Shaders that will highlight the currently "picked" feature.
// 顶点着色器和片段着色器
const char* highlightVert ="#version " GLSL_VERSION_STR "\n""uniform uint objectid_to_highlight; \n""uint oe_index_objectid;      // Stage global containing object id \n""flat out int selected; \n""void checkForHighlight(inout vec4 vertex) \n""{ \n""    selected = (objectid_to_highlight > 1u && objectid_to_highlight == oe_index_objectid) ? 1 : 0; \n""} \n";const char* highlightFrag ="#version " GLSL_VERSION_STR "\n""flat in int selected; \n""void highlightFragment(inout vec4 color) \n""{ \n""    if ( selected == 1 ) \n""        color.rgb = mix(color.rgb, clamp(vec3(0.5,2.0,2.0)*(1.0-color.rgb), 0.0, 1.0), 0.5); \n""} \n";// 安装高亮器到app
void installHighlighter(App& app)
{osg::StateSet* stateSet = app.mapNode->getOrCreateStateSet();// 索引geoemtry时要使用的顶点属性绑定位置。int attrLocation = Registry::objectIndex()->getObjectIDAttribLocation();// This shader program will highlight the selected object.// 着色器程序会使选中的object高亮VirtualProgram* vp = VirtualProgram::getOrCreate(stateSet);vp->setFunction( "checkForHighlight",  highlightVert, ShaderComp::LOCATION_VERTEX_CLIP );vp->setFunction( "highlightFragment",  highlightFrag, ShaderComp::LOCATION_FRAGMENT_COLORING );// Since we're accessing object IDs, we need to load the indexing shader as well:// 由于我们正在访问对象ID,因此还需要加载索引着色器:Registry::objectIndex()->loadShaders( vp );// A uniform that will tell the shader which object to highlight:// 通过uniform变量,告诉着色器哪个对象要被高亮app.highlightUniform = new osg::Uniform("objectid_to_highlight", 0u);stateSet->addUniform(app.highlightUniform );
}//------------------------------------------------------------------------// Configures a window that lets you see what the RTT camera sees.
// 配置一个窗口,使您可以看到RTT相机所看到的内容。
void
setupRTTView(osgViewer::View* view, osg::Texture* rttTex)
{view->setCameraManipulator(0L);view->getCamera()->setName( "osgearth_pick RTT view" );view->getCamera()->setViewport(0,0,256,256);view->getCamera()->setClearColor(osg::Vec4(1,1,1,1));view->getCamera()->setProjectionMatrixAsOrtho2D(-.5,.5,-.5,.5);// 二维正投影view->getCamera()->setViewMatrixAsLookAt(osg::Vec3d(0,-1,0), osg::Vec3d(0,0,0), osg::Vec3d(0,0,1));view->getCamera()->setProjectionResizePolicy(osg::Camera::FIXED);// 固定// v 和 t,都是通过绘制2个三角形拼接为正方形osg::Vec3Array* v = new osg::Vec3Array(6);(*v)[0].set(-.5,0,-.5); (*v)[1].set(.5,0,-.5); (*v)[2].set(.5,0,.5); (*v)[3].set((*v)[2]); (*v)[4].set(-.5,0,.5);(*v)[5].set((*v)[0]);osg::Vec2Array* t = new osg::Vec2Array(6);(*t)[0].set(0,0); (*t)[1].set(1,0); (*t)[2].set(1,1); (*t)[3].set((*t)[2]); (*t)[4].set(0,1); (*t)[5].set((*t)[0]);osg::Geometry* g = new osg::Geometry();g->setUseVertexBufferObjects(true);g->setUseDisplayList(false);g->setVertexArray( v );        // 几何顶点坐标g->setTexCoordArray( 0, t );// 纹理坐标g->addPrimitiveSet( new osg::DrawArrays(GL_TRIANGLES, 0, 6) );// 通过绘制三角形方式绘制osg::Geode* geode = new osg::Geode();geode->addDrawable( g );osg::StateSet* stateSet = geode->getOrCreateStateSet();stateSet->setDataVariance(osg::Object::DYNAMIC);// 动态的stateSet->setTextureAttributeAndModes(0, rttTex, 1);rttTex->setUnRefImageDataAfterApply( false );rttTex->setResizeNonPowerOfTwoHint(false);GLUtils::setLighting(stateSet, 0);stateSet->setMode(GL_CULL_FACE, 0);stateSet->setAttributeAndModes(new osg::BlendFunc(GL_ONE, GL_ZERO), 1);const char* fs ="#version " GLSL_VERSION_STR "\n""void swap(inout vec4 c) { c.rgba = c==vec4(0)? vec4(1) : vec4(vec3((c.r+c.g+c.b+c.a)/4.0),1); }\n";osgEarth::Registry::shaderGenerator().run(geode);VirtualProgram::getOrCreate(geode->getOrCreateStateSet())->setFunction("swap", fs, ShaderComp::LOCATION_FRAGMENT_COLORING);view->setSceneData( geode );
}void startPicker(App& app)
{// Note! Must stop and restart threading when removing the picker// because it changes the OSG View/Slave configuration.// 当移动拾取器时,必须停止并重置线程。app.viewer.stopThreading();// 创建rtt拾取器app.picker = new RTTPicker();app.mainView->addEventHandler(app.picker);// add the graph that will be picked.// 添加将要被拾取的mapNodeapp.picker->addChild(app.mapNode);// install a callback that controls the picker and listens for hits.// 安装回调方法,它控制拾取器并侦听命中。app.picker->setDefaultCallback(new MyPickCallback(app));// Make a view that lets us see what the picker sees.// 创建视景器,让我们看到拾取器看到了什么。if (app.rttView == NULL){app.rttView = new osgViewer::View();app.rttView->getCamera()->setGraphicsContext(app.mainView->getCamera()->getGraphicsContext());app.rttView->getCamera()->setSmallFeatureCullingPixelSize(-1.0f);app.viewer.addView(app.rttView);  // 子视景器加入到主视景器中  }setupRTTView(app.rttView, app.picker->getOrCreateTexture(app.mainView));app.rttView->getCamera()->setNodeMask(~0);app.viewer.startThreading();// 开启主视景器线程
}// 停止拾取
void stopPicker(App& app)
{// Note! Must stop and restart threading when removing the picker// because it changes the OSG View/Slave configuration.app.viewer.stopThreading();//app.viewer.removeView(app.rttView);app.rttView->getCamera()->setNodeMask(0);app.mainView->removeEventHandler(app.picker);app.picker = 0L;// 停止拾取的状态app.viewer.startThreading();
}struct TogglePicker : public ui::ControlEventHandler
{App& _app;TogglePicker(App& app) : _app(app) { }// 点击拾取时,需要判断是否为拾取状态。处于停止状态,则开启;反之,则停止。void onClick(Control* button){if (_app.picker == 0L)// 当前处于停止拾取的状态startPicker(_app);elsestopPicker(_app);}
};//-----------------------------------------------------------------------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);if ( arguments.read("--help") )return usage(argv[0]);App app(arguments);// 创建主视景器app.mainView = new osgViewer::View();app.mainView->setUpViewInWindow(30, 30, 1024, 1024, 0);app.mainView->getCamera()->setSmallFeatureCullingPixelSize(-1.0f);app.viewer.addView(app.mainView);app.mainView->getDatabasePager()->setUnrefImageDataAfterApplyPolicy( false, false );app.mainView->setCameraManipulator( new EarthManipulator() );    // Made some UI components: 制作一些ui控件ui::VBox* uiContainer = new ui::VBox();uiContainer->setAlign( ui::Control::ALIGN_LEFT, ui::Control::ALIGN_TOP );uiContainer->setAbsorbEvents( true );uiContainer->setBackColor(0,0,0,0.8);uiContainer->addControl( new ui::LabelControl("RTT Picker Test", osg::Vec4(1,1,0,1)) );uiContainer->addControl( new ui::ButtonControl("Toggle picker", new TogglePicker(app)) );// 控制是否允许拾取app.fidLabel = new ui::LabelControl("---");uiContainer->addControl( app.fidLabel );app.nameLabel = uiContainer->addControl( new ui::LabelControl( "---" ) );// Load up the earth file. 加载earth文件osg::Node* node = MapNodeHelper().load( arguments, &app.viewer, uiContainer );if ( node ){app.mainView->setSceneData( node );app.mapNode = MapNode::get(node);// start with a picker running 开始拾取startPicker(app);// Highlight features as we pick'em.installHighlighter(app); // 高亮app.mainView->getCamera()->setName( "Main view" );return app.viewer.run();}else{return usage(argv[0]);}
}

osgEarth示例分析——osgearth_pick相关推荐

  1. osgEarth示例分析——osgearth_annotation

    前言 本章为osgearth_annotation示例分析,示例中采用osgEarth提供的类,绘制标签.线.billboard.遮盖图.墙等内容. 运行时,在生成的可执行路径下,打开命令框,输入: ...

  2. osgEarth示例分析——osgearth_skyview

    前言 本示例分析osgearth操作深空场景,或者是银河系场景,可以想象人拿着相机站在地球表面上观看天空/银河系的场景. 重点是相机操作器的使用. 在命令框输入执行程序,在data路径下有加载的图,且 ...

  3. osgEarth示例分析——osgearth_manip

    前言 本示例主要演示osgEarth的事件处理的用法,内容比较多,这部分功能也很重要. 输入命令依然采用china-simple.earth的示例,加上了模型,但是模型并没有看到,可能是因为模型没有放 ...

  4. osgEarth示例分析——osgearth_elevation

    前言 osgearth_elevation示例,展示了如何通过点击地球获取不同定义下的高程数据.包括:MSL高程.HAE高程.EGM96高程.点击按钮,可以移除高程图层. MSL高程:是mean se ...

  5. osgEarth示例分析——osgearth_graticule

    前言 本示例最具有借鉴的功能:绘制网格.网格上的文字显示.拾取地球的坐标.在地球网格示例中,可以设置4种网格.执行命令如下: // --geodetic osgearth_graticuled.exe ...

  6. osgEarth示例分析——osgearth_srstest

    前言 osgearth_srstest示例,主要涉及到两个坐标系转换,wgs84→egm96  wgs84→plate-carre wgs84:World Geodetic System 1984,是 ...

  7. osgEarth示例分析——osgearth_eci

    前言 osgearth_eci示例,展示了J2000的天体坐标系和ECEF地固系的转换,绘制坐标系,以及读取卫星参数绘制卫星的功能.绘制卫星轨迹,添加差值效果和未添加差值的效果. 关于卫星两行根数的数 ...

  8. osgEarth示例分析——osgearth_terrainprofile

    前言 osgearth_terrainprofile示例,涉及到一个新的类 TerrainProfileCalculator(地形轮廓计算器类),用来计算两个点连线之间的地形数据.左下角会根据点击的起 ...

  9. osgEarth示例分析——osgearth_features

    前言 osgearth_features示例,主要演示如何通过代码方式加载shp文件,并设置其样式.在执行时,通过不同 的命令,得到不一样的效果. cmd执行命令: // rasterize 光栅化, ...

最新文章

  1. lzma打包exe_Web 项目打包EXE
  2. php webstorm,webstorm和phpstorm的区别
  3. JavaScript 事件入门知识
  4. 提升方法---提升树
  5. ThreadLocal可以解决并发问题吗
  6. 重写__repr__与__str__函数
  7. python 简单socket_Python 简单socket
  8. python2精确除法
  9. html手册_前端学习感悟——HTML
  10. 搜狐被SEC列入“预摘牌名单”!回应:不打算提出异议
  11. 用python写出九九乘法表
  12. python历史上的今天_历史上的今天接口调用示例
  13. Error accessing PRODUCT_USER_PROFILE?
  14. VS下使用多字符集编码和Unicode字符集编码的总结
  15. SQL数据库学习,常用语句查询大全
  16. Java中字符串数组转 long[]基本类型数组的方法
  17. Ubuntu虚拟机全屏问题
  18. 如何构建Redis Streams应用程序
  19. 2022年春招美团二面总结 凉经
  20. iPhone12、iPhone12 Pro、iPhone12 Max、iPhone12 Pro Max有几个颜色

热门文章

  1. swig 转义html,Swig 使用指南
  2. 大学四年应是这 样度过
  3. 监控swagger 接口变动
  4. win python_winpython下载|windows python v3.6.7.1 官方版 - 软件下载 - 绿茶软件园|33LC.com...
  5. JAVA中通用JPEG缩影图Bean的制作与示例
  6. mysql报错max_prepared_stmt_count的解决过程
  7. 单片机移频防啸叫_麦克风防啸叫的方法
  8. python矩阵求导代码_搞点枯燥的公式推导:深度学习中的矩阵求导
  9. 微软云盘多端同步_微软谈论客户端+云的未来
  10. 很多人不知道的Python 炫技操作:海象运算符的三种用法