osgEarth示例分析——osgearth_los

前言

osgearth_los示例,创建了模型动画路径、透视的用法。透视的顾名思义:两个点连线,从A到B,视线不被遮挡,则绘制绿色,视线被遮挡的部分,则设置为红色。此示例,加载earth文件时,需要加载地形文件。

执行命令:osgearth_losd.exe earth_image\world.earth

效果

圆形内的飞机,整个圆形,如果被遮挡,则绘制红色,不被遮挡,则绘制绿色。直线连接的两个飞机,从左下角的飞机点向右上角的飞机点看去,当被遮挡后,则后面的线都绘制红色。最下面的两个扫描圆形也是如此。

 代码分析

#include <osg/Notify>
#include <osgGA/StateSetManipulator>
#include <osgGA/GUIEventHandler>
#include <osgViewer/Viewer>
#include <osgViewer/ViewerEventHandlers>
#include <osgEarth/MapNode>
#include <osgEarth/XmlUtils>
#include <osgEarthUtil/EarthManipulator>
#include <osgEarthUtil/AutoClipPlaneHandler>
#include <osgEarthUtil/LinearLineOfSight>
#include <osgEarthUtil/RadialLineOfSight>
#include <osg/io_utils>
#include <osg/MatrixTransform>
#include <osg/Depth>
#include <osgEarth/TerrainTileNode>
#include <osgEarth/FileUtils>

using namespace osgEarth;
using namespace osgEarth::Util;

// 运动路径
osg::AnimationPath* createAnimationPath(const GeoPoint& pos, const SpatialReference* mapSRS, float radius, double looptime)
{
    // set up the animation path 
    osg::AnimationPath* animationPath = new osg::AnimationPath;// 设置动画路径对象
    animationPath->setLoopMode(osg::AnimationPath::LOOP);// 循环播放模式
    
    int numSamples = 40;// 采样点数

    double delta = osg::PI * 2.0 / (double)numSamples;

    //Get the center point in geocentric 获取大地测量坐标系下的中心点
    GeoPoint mapPos = pos.transform(mapSRS);
    osg::Vec3d centerWorld;
    mapPos.toWorld( centerWorld );

	// 是否为投影坐标系
    bool isProjected = mapSRS->isProjected();

	// 设置向上向量
    osg::Vec3d up = isProjected ? osg::Vec3d(0,0,1) : centerWorld;
    up.normalize();

    //Get the "side" vector 获取side向量
    osg::Vec3d side = isProjected ? osg::Vec3d(1,0,0) : up ^ osg::Vec3d(0,0,1);

	// 时间间隔
    double time=0.0f;
    double time_delta = looptime/(double)numSamples;

	// 第一个位置、第一个旋转矩阵
    osg::Vec3d firstPosition;
    osg::Quat firstRotation;

    for (unsigned int i = 0; i < (unsigned int)numSamples; i++)
    {
        double angle = delta * (double)i;
        osg::Quat quat(angle, up );
        osg::Vec3d spoke = quat * (side * radius);
        osg::Vec3d end = centerWorld + spoke;                

        osg::Quat makeUp;
        makeUp.makeRotate(osg::Vec3d(0,0,1), up);

        osg::Quat rot = makeUp;
        animationPath->insert(time,osg::AnimationPath::ControlPoint(end,rot));// 插入时间和控制点
        if (i == 0)
        {
            firstPosition = end;
            firstRotation = rot;
        }
        time += time_delta;            
    }
   
    animationPath->insert(time, osg::AnimationPath::ControlPoint(firstPosition, firstRotation));// 插入最后一个点

    return animationPath;    // 返回路径动画
}

// 调用 创建路径动画方法,且将路径动画对象放入 位置矩阵,并为 位置矩阵 设置更新回调
osg::Node* createPlane(osg::Node* node, const GeoPoint& pos, const SpatialReference* mapSRS, double radius, double time)
{
    osg::MatrixTransform* positioner = new osg::MatrixTransform;
    positioner->addChild( node );
    osg::AnimationPath* animationPath = createAnimationPath(pos, mapSRS, radius, time);
    positioner->setUpdateCallback( new osg::AnimationPathCallback(animationPath, 0.0, 1.0));
    return positioner;
}

// 存储ExtentNode访问器??
class CacheExtentNodeVisitor : public osg::NodeVisitor
{
public:
    CacheExtentNodeVisitor(GeoExtent& extent):
      osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN ),
          _extent(extent)
      {
      }

      void apply(osg::Node& node)
      {
          TerrainTileNode* tile = dynamic_cast<TerrainTileNode*>(&node);
          if (tile && tile->getKey().valid())
          {              
              if (tile->getKey().getExtent().intersects(_extent) && tile->getKey().getLevelOfDetail() < 11)
              {
                  // Set this tile to not expire.
                  tile->setMinimumExpirationTime(DBL_MAX);
                  OE_NOTICE << "Preloading children for " << tile->getKey().str() << std::endl;
                  tile->loadChildren();
              }
          }          
          traverse(node);
      }

      GeoExtent _extent;
};


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

    // load the .earth file from the command line.
    osg::ref_ptr<osg::Node> earthNode = osgDB::readNodeFiles( arguments );
    if (!earthNode.valid())
    {
        OE_NOTICE << "Unable to load earth model" << std::endl;
        return 1;
    }

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

    osgEarth::MapNode * mapNode = osgEarth::MapNode::findMapNode( earthNode.get() );
    if (!mapNode)
    {
        OE_NOTICE << "Could not find MapNode " << std::endl;
        return 1;
    }

    osgEarth::Util::EarthManipulator* manip = new EarthManipulator();
    viewer.setCameraManipulator( manip );
    
    root->addChild( earthNode );    
    //viewer.getCamera()->addCullCallback( new AutoClipPlaneCullCallback(mapNode));

    osg::Group* losGroup = new osg::Group();
    losGroup->getOrCreateStateSet()->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);// 渲染方式:透明
    losGroup->getOrCreateStateSet()->setAttributeAndModes(new osg::Depth(osg::Depth::ALWAYS, 0, 1, false));
    root->addChild(losGroup);

    // so we can speak lat/long:
    const SpatialReference* mapSRS = mapNode->getMapSRS();
    const SpatialReference* geoSRS = mapSRS->getGeographicSRS();// 地理坐标系

    //Create a point to point LineOfSightNode.
	// 创建 可用于显示点对点视线计算的节点los
    LinearLineOfSightNode* los = new LinearLineOfSightNode(
        mapNode, 
        GeoPoint(geoSRS, -121.665, 46.0878, 1258.00, ALTMODE_ABSOLUTE),
        GeoPoint(geoSRS, -121.488, 46.2054, 3620.11, ALTMODE_ABSOLUTE) );

    losGroup->addChild( los );
    
    //Create an editor for the point to point line of sight that allows you to drag the beginning and end points around.
    //This is just one way that you could manipulator the LineOfSightNode.
	// 为los添加编辑器
    LinearLineOfSightEditor* p2peditor = new LinearLineOfSightEditor( los );
    root->addChild( p2peditor );

    //Create a relative point to point LineOfSightNode.
	// 再创建一个比los低一些的 relativeLOS
    LinearLineOfSightNode* relativeLOS = new LinearLineOfSightNode( 
        mapNode, 
        GeoPoint(geoSRS, -121.2, 46.1, 10, ALTMODE_RELATIVE),
        GeoPoint(geoSRS, -121.488, 46.2054, 10, ALTMODE_RELATIVE) );

    losGroup->addChild( relativeLOS );

	// 为 relativeLOS 添加编辑器
    LinearLineOfSightEditor* relEditor = new LinearLineOfSightEditor( relativeLOS );
    root->addChild( relEditor );

    //Create a RadialLineOfSightNode that allows you to do a 360 degree line of sight analysis.
	// 可用于显示径向视线计算的节点 radial
	// radial 允许进行360度视线分析。
    RadialLineOfSightNode* radial = new RadialLineOfSightNode( mapNode );
    radial->setCenter( GeoPoint(geoSRS, -121.515, 46.054, 847.604, ALTMODE_ABSOLUTE) );
    radial->setRadius( 2000 );
    radial->setNumSpokes( 100 );    // 设置径向视线计算中的轮辐数。
    losGroup->addChild( radial );
	// 为 radial 添加编辑器
    RadialLineOfSightEditor* radialEditor = new RadialLineOfSightEditor( radial );
    losGroup->addChild( radialEditor );

    //Create a relative RadialLineOfSightNode that allows you to do a 360 degree line of sight analysis.
    RadialLineOfSightNode* radialRelative = new RadialLineOfSightNode( mapNode );
    radialRelative->setCenter( GeoPoint(geoSRS, -121.2, 46.054, 10, ALTMODE_RELATIVE) );
    radialRelative->setRadius( 3000 );
    radialRelative->setNumSpokes(60);
    losGroup->addChild( radialRelative );
    RadialLineOfSightEditor* radialRelEditor = new RadialLineOfSightEditor( radialRelative );
    losGroup->addChild( radialRelEditor );

    //Load a plane model.  添加一个飞机模型 cessna赛斯纳,飞行器公司
    osg::ref_ptr< osg::Node >  plane = osgDB::readRefNodeFile("../data/cessna.osgb.50,50,50.scale");

    //Create 2 moving planes 创建两个移动飞机
    osg::Node* plane1 = createPlane(plane.get(), GeoPoint(geoSRS, -121.656, 46.0935, 4133.06, ALTMODE_ABSOLUTE), mapSRS, 5000, 40);
    osg::Node* plane2 = createPlane(plane.get(), GeoPoint(geoSRS, -121.321, 46.2589, 1390.09, ALTMODE_ABSOLUTE), mapSRS, 3000, 25);
    root->addChild( plane1 );
    root->addChild( plane2 );

    //Create a LineOfSightNode that will use a LineOfSightTether callback to monitor
    //the two plane's positions and recompute the LOS when they move
    LinearLineOfSightNode* tetheredLOS = new LinearLineOfSightNode( mapNode);
    losGroup->addChild( tetheredLOS );
    tetheredLOS->setUpdateCallback( new LineOfSightTether( plane1, plane2 ) );

    //Create another plane and attach a RadialLineOfSightNode to it using the RadialLineOfSightTether
    osg::Node* plane3 = createPlane(plane.get(), GeoPoint(geoSRS, -121.463, 46.3548, 1348.71, ALTMODE_ABSOLUTE), mapSRS, 10000, 5);
    losGroup->addChild( plane3 );
    RadialLineOfSightNode* tetheredRadial = new RadialLineOfSightNode( mapNode );
    tetheredRadial->setRadius( 5000 );

    //This RadialLineOfSightNode is going to be filled, so set some alpha values for the colors so it's partially transparent
    tetheredRadial->setFill( true );
    tetheredRadial->setGoodColor( osg::Vec4(0,1,0,0.3) );
    tetheredRadial->setBadColor( osg::Vec4(1,0,0,0.3) );
    tetheredRadial->setNumSpokes( 100 );
    losGroup->addChild( tetheredRadial );
    tetheredRadial->setUpdateCallback( new RadialLineOfSightTether( plane3 ) );

	// 设置视角信息
    osgEarth::Viewpoint vp;
    vp.name() = "Mt Ranier";
    vp.focalPoint()->set(geoSRS, -121.488, 46.2054, 0, ALTMODE_ABSOLUTE);
    vp.pitch() = -50.0;
    vp.range() = 100000;

    manip->setHomeViewpoint( vp );// 设置home视角

    viewer.setSceneData( root );    

    // add some stock OSG handlers:
    viewer.addEventHandler(new osgViewer::StatsHandler());
    viewer.addEventHandler(new osgViewer::WindowSizeHandler());
    viewer.addEventHandler(new osgViewer::ThreadingHandler());
    viewer.addEventHandler(new osgViewer::LODScaleHandler());
    viewer.addEventHandler(new osgGA::StateSetManipulator(viewer.getCamera()->getOrCreateStateSet()));

    /*
    TerrainTileNodeVisitor v;
    root->accept(v);
    */
	// 下面的节点遍历代码,导致程序容易崩溃,暂时没看出这段代码有什么用,所以先注释掉

   // GeoPoint center(geoSRS, -121.656, 46.0935, 4133.06, ALTMODE_ABSOLUTE);

    //GeoExtent extent(geoSRS, center.x() - 0.5, center.y() - 0.5, center.x() + 0.5, center.y() + 0.5);
    //CacheExtentNodeVisitor v(extent);

    //root->accept(v);

    while (!viewer.done())
    {        
        viewer.frame();
    }
    return 0;
}

  • 0
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值