osgEarth示例分析——osgearth_annotation

  • Post author:
  • Post category:其他


前言

本章为osgearth_annotation示例分析,示例中采用osgEarth提供的类,绘制标签、线、billboard、遮盖图、墙等内容。

运行时,在生成的可执行路径下,打开命令框,输入:

osgearth_annotationd.exe xxx.earth

为方便测试,这里直接将文件路径写在程序中,直接执行加载earth文件。

效果如下:

addChild关系以及简单类关系

代码分析

#include <osgEarth/MapNode>

#include <osgEarthUtil/EarthManipulator>
#include <osgEarthUtil/ExampleResources>

#include <osgEarthAnnotation/ImageOverlay>
#include <osgEarthAnnotation/CircleNode>
#include <osgEarthAnnotation/RectangleNode>
#include <osgEarthAnnotation/EllipseNode>
#include <osgEarthAnnotation/PlaceNode>
#include <osgEarthAnnotation/LabelNode>
#include <osgEarthAnnotation/LocalGeometryNode>
#include <osgEarthAnnotation/FeatureNode>
#include <osgEarthAnnotation/ModelNode>

#include <osgEarthAnnotation/AnnotationEditing>
#include <osgEarthAnnotation/ImageOverlayEditor>

#include <osgEarthSymbology/GeometryFactory>

#include <osgViewer/Viewer>
#include <osgDB/ReadFile>// 读取earth文件需要加入头文件

using namespace osgEarth;
using namespace osgEarth::Annotation;
using namespace osgEarth::Features;
using namespace osgEarth::Util;

//------------------------------------------------------------------

int
usage( char** argv )
{
    OE_WARN << "Usage: " << argv[0] << " <earthfile>" << std::endl;
    return -1;
}

//------------------------------------------------------------------

int
main(int argc, char** argv)
{
    osg::Group* root = new osg::Group();
	// [1 begin] 方式一:通过传入的earth文件参数初始化地球界面
    // try to load an earth file.
    //osg::ArgumentParser arguments(&argc,argv);

    //osgViewer::Viewer viewer(arguments);
    //viewer.setCameraManipulator( new EarthManipulator() );

     load an earth file and parse demo arguments
    //osg::Node* node = MapNodeHelper().load(arguments, &viewer);
    //if ( !node )
    //    return usage(argv);

	//root->addChild( node );

	// find the map node that we loaded.
	//MapNode* mapNode = MapNode::findMapNode(node);
	//if ( !mapNode )
	//    return usage(argv);

	// [1 end]

	// [2 begin] 方式二,通过readNodeFile方式加载earth文件。方便调试代码测试
	const std::string earthFile = "F:/osgData/Data/earth_image/china-simple.earth";
	osg::ref_ptr<osg::Node> node = osgDB::readNodeFile(earthFile);// 将earth文件作为一个节点
	if (!node.valid())
		return -1;
	osg::ref_ptr<osgEarth::MapNode> mapNode;
	mapNode = dynamic_cast<osgEarth::MapNode*>(node.get());// 强制转换为地图节点

	osg::ref_ptr<osgEarth::Util::EarthManipulator> em;
	em = new osgEarth::Util::EarthManipulator;
	if (!mapNode.valid())
		return -1;
	em->setNode(mapNode);//因为设置了节点,将忽略“焦点”,节点不会序列化到Config中
	em->getSettings()->setArcViewpointTransitions(true);// 获取当前操纵器设置对象的句柄,并转为弧形

	osgViewer::Viewer viewer;
	viewer.setCameraManipulator(em);// 为主摄像机设置相机操作器

	root->addChild(node);// 将地图节点放入根节点,根节点再放入场景。其实也可以直接将node放入场景
	// [2 end]

    // Group to hold all our annotation elements.
	// 后面所有的元素结点均添加到annoGroup结点下
    osg::Group* annoGroup = new osg::Group();
    MapNode::get(node)->addChild( annoGroup );

    // Make a group for labels
    osg::Group* labelGroup = new osg::Group();
    annoGroup->addChild( labelGroup );

    osg::Group* editGroup = new osg::Group();
    MapNode::get(node)->addChild( editGroup );

    // Style our labels:
    Style labelStyle;
    labelStyle.getOrCreate<TextSymbol>()->alignment() = TextSymbol::ALIGN_CENTER_CENTER;// label的对齐方式
    labelStyle.getOrCreate<TextSymbol>()->fill()->color() = Color::Yellow;// 设置文本颜色

    // A lat/long SRS for specifying points.
	// 可以理解为 获取 空间参考系,有了参考系,就可以给经纬高进而在指定位置进行绘制
    const SpatialReference* geoSRS = mapNode->getMapSRS()->getGeographicSRS();

    //--------------------------------------------------------------------

    // A series of place nodes (an icon with a text label)
    {
        Style pm;
        pm.getOrCreate<IconSymbol>()->url()->setLiteral( "../data/placemark32.png" );// 图标资源
        pm.getOrCreate<IconSymbol>()->declutter() = true;
        pm.getOrCreate<TextSymbol>()->halo() = Color("#5f5f5f");// 文本颜色

        // bunch of pins:
		// GeoPoint 此构造方式中,默认模式为地形高度,贴地标签,高度为0
        labelGroup->addChild( new PlaceNode(GeoPoint(geoSRS, -74.00, 40.71), "New York"      , pm));
        labelGroup->addChild( new PlaceNode(GeoPoint(geoSRS, -77.04, 38.85), "Washington, DC", pm));
        labelGroup->addChild( new PlaceNode(GeoPoint(geoSRS,-118.40, 33.93), "Los Angeles"   , pm));
        labelGroup->addChild( new PlaceNode(GeoPoint(geoSRS, -71.03, 42.37), "Boston"        , pm));
        labelGroup->addChild( new PlaceNode(GeoPoint(geoSRS,-157.93, 21.35), "Honolulu"      , pm));
        labelGroup->addChild( new PlaceNode(GeoPoint(geoSRS, 139.75, 35.68), "Tokyo"         , pm));
        labelGroup->addChild( new PlaceNode(GeoPoint(geoSRS, -90.25, 29.98), "New Orleans"   , pm));
        labelGroup->addChild( new PlaceNode(GeoPoint(geoSRS, -80.28, 25.82), "Miami"         , pm));
        labelGroup->addChild( new PlaceNode(GeoPoint(geoSRS,-117.17, 32.72), "San Diego"     , pm));

        // test with an LOD:
        osg::LOD* lod = new osg::LOD();
		// 通过lod设置显示范围
        lod->addChild( new PlaceNode(GeoPoint(geoSRS, 14.68, 50.0), "Prague", pm), 0.0, 2e6);
        labelGroup->addChild( lod );

        // absolute altitude:
		// GeoPoint 设置了绝对高度。另一个模式是地形以上的高度。
        labelGroup->addChild( new PlaceNode(GeoPoint(geoSRS, -87.65, 41.90, 1000, ALTMODE_ABSOLUTE), "Chicago", pm));
    }

    //--------------------------------------------------------------------

    // a box that follows lines of latitude (rhumb line interpolation, the default)
    // and flashes on and off using a cull callback.
	// 使用剔除回调打开和关闭闪烁
    {
        struct C : public osg::NodeCallback {
			// 重载操作符,并实现回调动画
            void operator()(osg::Node* n, osg::NodeVisitor* nv) {
                static int i=0;
                i++;
                if (i % 100 < 50)
                    traverse(n, nv);
            }
        };
        Geometry* geom = new Polygon();
        geom->push_back( osg::Vec3d(0,   40, 0) );
        geom->push_back( osg::Vec3d(-60, 40, 0) );
        geom->push_back( osg::Vec3d(-60, 60, 0) );
        geom->push_back( osg::Vec3d(0,   60, 0) );

        Feature* feature = new Feature(geom, geoSRS);
        feature->geoInterp() = GEOINTERP_RHUMB_LINE;// 差值方式,直线模式

        Style geomStyle;
        geomStyle.getOrCreate<LineSymbol>()->stroke()->color() = Color::Cyan;// 线颜色
        geomStyle.getOrCreate<LineSymbol>()->stroke()->width() = 5.0f;// 线宽
        geomStyle.getOrCreate<LineSymbol>()->tessellationSize() = 75000; // 细分大小
        geomStyle.getOrCreate<AltitudeSymbol>()->clamping() = AltitudeSymbol::CLAMP_TO_TERRAIN;// 贴地形
        geomStyle.getOrCreate<AltitudeSymbol>()->technique() = AltitudeSymbol::TECHNIQUE_GPU;// GPU渲染贴地几何体
        
        FeatureNode* fnode = new FeatureNode(feature, geomStyle);

        fnode->addCullCallback(new C());// 将回调方法设置到节点中

        annoGroup->addChild( fnode );

        LabelNode* label = new LabelNode("Rhumb line polygon", labelStyle);
        label->setPosition(GeoPoint(geoSRS, -30, 50));
        labelGroup->addChild(label);
    }

    //--------------------------------------------------------------------

    // another rhumb box that crosses the antimeridian
    {
        Geometry* geom = new Polygon();// Geometry是Polygon的父类的父类
        geom->push_back( -160., -30. );
        geom->push_back(  150., -20. );
        geom->push_back(  160., -45. );
        geom->push_back( -150., -40. );
        Style geomStyle;

        Feature* feature = new Feature(geom, geoSRS);
        feature->geoInterp() = GEOINTERP_RHUMB_LINE;

        geomStyle.getOrCreate<LineSymbol>()->stroke()->color() = Color::Lime;
        geomStyle.getOrCreate<LineSymbol>()->stroke()->width() = 3.0f;
        geomStyle.getOrCreate<LineSymbol>()->tessellationSize() = 75000;
        geomStyle.getOrCreate<AltitudeSymbol>()->clamping() = AltitudeSymbol::CLAMP_TO_TERRAIN;
        geomStyle.getOrCreate<AltitudeSymbol>()->technique() = AltitudeSymbol::TECHNIQUE_GPU;

        FeatureNode* gnode = new FeatureNode(feature, geomStyle);
        annoGroup->addChild( gnode );

        LabelNode* label = new LabelNode("Antimeridian polygon", labelStyle);
        label->setPosition(GeoPoint(geoSRS, -175, -35));
        labelGroup->addChild(label);
    }

    //--------------------------------------------------------------------



    // A path using great-circle interpolation.使用大圆插值的路径。
    // Keep a pointer to it so we can modify it later on.
    FeatureNode* pathNode = 0;
    {
        Geometry* path = new LineString();
        path->push_back( osg::Vec3d(-74, 40.714, 0) );   // New York
        path->push_back( osg::Vec3d(139.75, 35.68, 0) ); // Tokyo

        Feature* pathFeature = new Feature(path, geoSRS);
        pathFeature->geoInterp() = GEOINTERP_GREAT_CIRCLE;// 圆形差值方法

        Style pathStyle;
        pathStyle.getOrCreate<LineSymbol>()->stroke()->color() = Color::White;
        pathStyle.getOrCreate<LineSymbol>()->stroke()->width() = 1.0f;
        pathStyle.getOrCreate<LineSymbol>()->stroke()->smooth() = true;
        pathStyle.getOrCreate<LineSymbol>()->tessellationSize() = 75000;
        pathStyle.getOrCreate<PointSymbol>()->size() = 8;// 线上绘制点的尺寸
        pathStyle.getOrCreate<PointSymbol>()->fill()->color() = Color::Red;// 点颜色
        pathStyle.getOrCreate<PointSymbol>()->smooth() = true;
        pathStyle.getOrCreate<AltitudeSymbol>()->clamping() = AltitudeSymbol::CLAMP_TO_TERRAIN;
        pathStyle.getOrCreate<AltitudeSymbol>()->technique() = AltitudeSymbol::TECHNIQUE_GPU;
        pathStyle.getOrCreate<RenderSymbol>()->depthOffset()->enabled() = true;

        //OE_INFO << "Path extent = " << pathFeature->getExtent().toString() << std::endl;

        pathNode = new FeatureNode(pathFeature, pathStyle);
        annoGroup->addChild( pathNode );

        LabelNode* label = new LabelNode("Great circle path", labelStyle);
        label->setPosition(GeoPoint(geoSRS,-170, 61.2));
        labelGroup->addChild(label);
    }

    //--------------------------------------------------------------------

    // Two circle segments around New Orleans.
    {
        Style circleStyle;
        circleStyle.getOrCreate<PolygonSymbol>()->fill()->color() = Color(Color::Cyan, 0.5);
        circleStyle.getOrCreate<AltitudeSymbol>()->clamping() = AltitudeSymbol::CLAMP_TO_TERRAIN;
        circleStyle.getOrCreate<AltitudeSymbol>()->technique() = AltitudeSymbol::TECHNIQUE_DRAPE;// 悬垂

        CircleNode* circle = new CircleNode();
        circle->set(
            GeoPoint(geoSRS, -90.25, 29.98, 1000., ALTMODE_RELATIVE),
            Distance(300, Units::KILOMETERS),// 距离和单位
            circleStyle, 
            Angle(-45.0, Units::DEGREES),// 角度
            Angle(45.0, Units::DEGREES),
            true);

		// 绘制并显示circle,如果注释掉此句,则不会显示图形。
        annoGroup->addChild( circle );
		// 为circle添加编辑点,让editGroup来管理circle的编辑点
        editGroup->addChild( new CircleNodeEditor(circle) );
    }

	{
		Style circleStyle;
		circleStyle.getOrCreate<PolygonSymbol>()->fill()->color() = Color(Color::Red, 0.5);
		circleStyle.getOrCreate<AltitudeSymbol>()->clamping() = AltitudeSymbol::CLAMP_TO_TERRAIN;
		circleStyle.getOrCreate<AltitudeSymbol>()->technique() = AltitudeSymbol::TECHNIQUE_DRAPE;

		CircleNode* circle = new CircleNode();
        circle->set(
			GeoPoint(geoSRS, -90.25, 29.98, 1000., ALTMODE_RELATIVE),
			Distance(300, Units::KILOMETERS),
			circleStyle,
            Angle(45.0, Units::DEGREES),
            Angle(360.0 - 45.0, Units::DEGREES),
            true);// true-使用0-360度,如果为false,则需要使用弧度

		annoGroup->addChild( circle );

        editGroup->addChild( new CircleNodeEditor(circle) );
	}

    //--------------------------------------------------------------------

    // An extruded ellipse around Miami.
    {
        Style ellipseStyle;
        ellipseStyle.getOrCreate<PolygonSymbol>()->fill()->color() = Color(Color::Orange, 0.75);// 多边形填充色
        ellipseStyle.getOrCreate<ExtrusionSymbol>()->height() = 250000.0; // meters MSL 多边形高度,单位m
        EllipseNode* ellipse = new EllipseNode();
        ellipse->set(
            GeoPoint(geoSRS, -80.28, 25.82, 0.0, ALTMODE_RELATIVE),// 地形之上的高度
            Distance(250, Units::MILES),// 长半轴
            Distance(100, Units::MILES),// 短半轴
            Angle   (0, Units::DEGREES),// 旋转角度
            ellipseStyle,
            Angle(45.0, Units::DEGREES),// 开始角度
            Angle(360.0 - 45.0, Units::DEGREES), // 结束角度
            true); // 角度制
        annoGroup->addChild( ellipse );

        editGroup->addChild( new EllipseNodeEditor(ellipse) );
    }
	{
		Style ellipseStyle;
		ellipseStyle.getOrCreate<PolygonSymbol>()->fill()->color() = Color(Color::Blue, 0.75);
		ellipseStyle.getOrCreate<ExtrusionSymbol>()->height() = 250000.0; // meters MSL
		EllipseNode* ellipse = new EllipseNode();
        ellipse->set(
			GeoPoint(geoSRS, -80.28, 25.82, 0.0, ALTMODE_RELATIVE),
			Distance(250, Units::MILES),
			Distance(100, Units::MILES),
			Angle   (0, Units::DEGREES),
			ellipseStyle, 
            Angle(-40.0, Units::DEGREES), 
            Angle(40.0, Units::DEGREES), 
            true);
		annoGroup->addChild( ellipse );

        editGroup->addChild( new EllipseNodeEditor(ellipse) );
	}
    
    //--------------------------------------------------------------------

    {
        // A rectangle around San Diego
        Style rectStyle;
        rectStyle.getOrCreate<PolygonSymbol>()->fill()->color() = Color(Color::Green, 0.5);
        rectStyle.getOrCreate<AltitudeSymbol>()->clamping() = AltitudeSymbol::CLAMP_TO_TERRAIN;// 贴地
        rectStyle.getOrCreate<AltitudeSymbol>()->technique() = AltitudeSymbol::TECHNIQUE_DRAPE;
        RectangleNode* rect = new RectangleNode(
            GeoPoint(geoSRS, -117.172, 32.721),
            Distance(300, Units::KILOMETERS ),
            Distance(600, Units::KILOMETERS ),
            rectStyle);
        annoGroup->addChild( rect );

        editGroup->addChild( new RectangleNodeEditor(rect) );
    }    

    //--------------------------------------------------------------------

    // An extruded polygon roughly the shape of Utah. Here we demonstrate the
    // FeatureNode, where you create a geographic geometry and use it as an
    // annotation.
    {
        Geometry* utah = new Polygon();
        utah->push_back( -114.052, 37.0   );
        utah->push_back( -109.054, 37.0   );
        utah->push_back( -109.054, 41.0   );
        utah->push_back( -111.040, 41.0   );
        utah->push_back( -111.080, 42.059 );
        utah->push_back( -114.080, 42.024 );

        Style utahStyle;
        utahStyle.getOrCreate<ExtrusionSymbol>()->height() = 250000.0; // meters MSL
        utahStyle.getOrCreate<PolygonSymbol>()->fill()->color() = Color(Color::White, 0.8);
		// 有高度的多边形,且没有顶
        Feature*     utahFeature = new Feature(utah, geoSRS);
        FeatureNode* featureNode = new FeatureNode(utahFeature, utahStyle);

        annoGroup->addChild( featureNode );
    }

    //--------------------------------------------------------------------

    // an image overlay.
    {
        ImageOverlay* imageOverlay = 0L;
        osg::ref_ptr<osg::Image> image = osgDB::readRefImageFile( "../data/USFLAG.TGA" );// 读取图片,支持多种格式:ive jpg png gif rgb rgba TGA
        if (image.valid())
        {
            imageOverlay = new ImageOverlay(mapNode, image.get());// 创建一个遮盖图
            imageOverlay->setBounds( Bounds( -100.0, 35.0, -90.0, 40.0) );// 设置边界
            annoGroup->addChild( imageOverlay );

            editGroup->addChild( new ImageOverlayEditor(imageOverlay) );
        }
    }

    //--------------------------------------------------------------------

    // a model node with auto scaling.
    {
        Style style;
        style.getOrCreate<ModelSymbol>()->autoScale() = true;// 打开模型自动缩放
        style.getOrCreate<ModelSymbol>()->url()->setLiteral("../data/red_flag.osg.50.scale");// 自动放大50倍。在模型后面追加倍数和scale,就会对应缩放这么多倍
        ModelNode* modelNode = new ModelNode(mapNode, style); 
        modelNode->setPosition(GeoPoint(geoSRS, -100, 52));
        annoGroup->addChild(modelNode);
    }

    //--------------------------------------------------------------------

    // initialize the viewer:    
    viewer.setSceneData( root ); 
	// 剔除小特征阈值
    viewer.getCamera()->setSmallFeatureCullingPixelSize(-1.0f);
    return viewer.run();
}



版权声明:本文为qq_34732729原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。