osgEarth示例分析——osgearth_transform

前言

osgearth_transform示例,是控制三维坐标轴的示例。通过控制面板的滑块,进而控制坐标轴的经度、纬度、高度、俯仰角、偏航角、旋转等操作。

执行效果

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

 

Lat 南北移动
Long 东西移动
Alt /Zero 上下移动 / 高度置零
Heading 绕Z轴旋转
Pitch 绕X轴旋转
Roll 绕Y轴旋转
Relative Z 由于没有加载高程数据,所以无法看到效果

代码分析

本节代码的重点:控制视点、以及在地球上如何操作模型的移动、旋转。

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define LC "[osgearth_transform] "


using namespace osgEarth;
using namespace osgEarth::Util;

namespace ui = osgEarth::Util::Controls;

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

    return 0;
}

struct App
{
    const osgEarth::SpatialReference* srs;// 坐标系
    osgEarth::GeoTransform*           geo;// 接受地理空间坐标的变换节点。
    osg::PositionAttitudeTransform*   pat;// 节点姿态控制

	// 水平滑块控件
    ui::HSliderControl* uiLat;			// 控制纬度
    ui::HSliderControl* uiLon;			// 控制经度
    ui::HSliderControl* uiAlt;			// 控制高度
    ui::HSliderControl* uiHeading;		// 偏航角
    ui::HSliderControl* uiPitch;		// 俯仰角
    ui::HSliderControl* uiRoll;			// 旋转角
    ui::CheckBoxControl* uiRelativeZ;	// 相对值Z还是绝对值Z

    void apply()
    {
		// altMode 指示如何解释Z坐标。地形之上的高度,还是绝对高度
        AltitudeMode altMode = uiRelativeZ->getValue() ? ALTMODE_RELATIVE : ALTMODE_ABSOLUTE;

		// 根据传入值,创建pos
        GeoPoint pos(
            srs,
            uiLon->getValue(), uiLat->getValue(), uiAlt->getValue(),
            altMode);

		// 将坐标点pos添加到变换节点geo
        geo->setPosition( pos );

		// 四元数
        osg::Quat ori =
            osg::Quat(osg::DegreesToRadians(uiRoll->getValue()),    osg::Vec3(0,1,0)) *		// 角度和方向
            osg::Quat(osg::DegreesToRadians(uiPitch->getValue()),   osg::Vec3(1,0,0)) *
            osg::Quat(osg::DegreesToRadians(uiHeading->getValue()), osg::Vec3(0,0,-1));

		// 设置节点姿态
        pat->setAttitude( ori );
    }
};

struct Apply : public ui::ControlEventHandler
{
    Apply(App& app) : _app(app) { }
    void onValueChanged(ui::Control* control) {
        _app.apply();
    }
    App& _app;
};

// 高度置零
struct ZeroAlt : public ui::ControlEventHandler {
    ZeroAlt(App& app) : _app(app) { }
    void onClick(ui::Control* control) {
        _app.uiAlt->setValue(0.0f);
        _app.apply();
    }
    App& _app;
};

// 创建控制面板的UI界面
ui::Control* makeUI(App& app)
{
    ui::Grid* grid = new ui::Grid();
    grid->setBackColor(0,0,0,0.5);

    grid->setControl(0, 0, new ui::LabelControl("Lat:"));
    grid->setControl(0, 1, new ui::LabelControl("Long:"));
    grid->setControl(0, 2, new ui::LabelControl("Alt:"));
    grid->setControl(0, 3, new ui::LabelControl("Heading:"));
    grid->setControl(0, 4, new ui::LabelControl("Pitch:"));
    grid->setControl(0, 5, new ui::LabelControl("Roll:"));
    grid->setControl(0, 6, new ui::LabelControl("Relative Z:"));

	// 设置滑块的起止值与当前值,添加Apply事件方法
    app.uiLat = grid->setControl(1, 0, new ui::HSliderControl(40.0f, 50.0f, 44.7433f, new Apply(app)));
    grid->setControl(2, 0, new LabelControl(app.uiLat));// 添加标签,标签内容会随着app的apply方法更改而更改
    app.uiLon = grid->setControl(1, 1, new ui::HSliderControl(6.0f, 8.0f, 7.0f, new Apply(app)));
    grid->setControl(2, 1, new LabelControl(app.uiLon));
    app.uiAlt = grid->setControl(1, 2, new ui::HSliderControl(-3000.0f, 100000.0f, 25000.0f, new Apply(app)));
    grid->setControl(2, 2, new LabelControl(app.uiAlt));
    grid->setControl(3, 2, new ButtonControl("Zero", new ZeroAlt(app)));// 置零按钮
    app.uiHeading = grid->setControl(1, 3, new ui::HSliderControl(-180.0f, 180.0f, 0.0f, new Apply(app)));
    grid->setControl(2, 3, new LabelControl(app.uiHeading));
    app.uiPitch   = grid->setControl(1, 4, new ui::HSliderControl(-90.0f, 90.0f, 0.0f, new Apply(app)));
    grid->setControl(2, 4, new LabelControl(app.uiPitch));
    app.uiRoll    = grid->setControl(1, 5, new ui::HSliderControl(-180.0f, 180.0f, 0.0f, new Apply(app)));
    grid->setControl(2, 5, new LabelControl(app.uiRoll));
    app.uiRelativeZ = grid->setControl(1, 6, new ui::CheckBoxControl(true, new Apply(app))); app.uiRelativeZ->setWidth(15.0f);
    grid->setControl(2, 6, new LabelControl(app.uiRelativeZ));

    app.uiLat->setHorizFill(true, 700.0f);
    return grid;
}

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

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

    osgViewer::Viewer viewer(arguments);
    EarthManipulator* em = new EarthManipulator();// 默认操作器
    viewer.setCameraManipulator( em );

    // load an earth file, and support all or our example command-line options
    // and earth file  tags    
    osg::Node* earth = MapNodeHelper().load( arguments, &viewer );
    MapNode* mapNode = MapNode::get(earth);
    if (!mapNode)
        return usage(argv[0]);

    // load the model file into the local coordinate frame, which will be
    // +X=east, +Y=north, +Z=up. 模型一定要放大很多倍,才能容易发现,模型初始位置位于欧洲的某一处高山位置。
    osg::ref_ptr model = osgDB::readRefNodeFile("axes.osgt.(10000).scale.osgearth_shadergen");
    if (!model.valid())
        return usage(argv[0]);

    osg::Group* root = new osg::Group();
    root->addChild( earth );
    
	// 这个结构体设计的有点不合理
    App app;
    app.srs = mapNode->getMapSRS();
    app.geo = new GeoTransform();
    app.pat = new osg::PositionAttitudeTransform();// 位置和姿态
    app.pat->addChild( model.get() );// 添加模型
    app.geo->addChild( app.pat );

    // Place your GeoTransform under the map node and it will automatically support clamping.
    // If you don't do this, you must call setTerrain to get terrain clamping.
    mapNode->addChild( app.geo );
    
    viewer.setSceneData( root );
    viewer.getCamera()->setNearFarRatio(0.00002);
    viewer.getCamera()->setSmallFeatureCullingPixelSize(-1.0f);

	// 创建控制面板
    ui::ControlCanvas::getOrCreate(&viewer)->addControl( makeUI(app) );
    app.apply();// 遍历节点

    osgEarth::Viewpoint vp;// 视点控制
    vp.setNode( app.geo );
    vp.heading()->set( -45.0, Units::DEGREES );// 偏航角
    vp.pitch()->set( -20.0, Units::DEGREES );// 俯仰角
    vp.range()->set( model->getBound().radius()*10.0, Units::METERS );// 模型可见范围
    em->setViewpoint( vp );

    return viewer.run();
}

你可能感兴趣的:(osgEarth,c++)