osgearth开发三维地球

OSGEARTH开发三维地球

背景介绍

    由于先前搞了一个qgis的二维地图,现在项目组提出新的需求,需要二维三维地图进行联动。经过前期的调研,发现qgis好像并不具备三维地图展示的能力,于是搜索到osg, osgearth ,经过的几天的编译折腾,环境搞定了。我们的项目主要涉及,点,线,面绘制,shp文件,tif文件加载。飞机模型演示等,具体需求相对简单。
    经过几天的摸索,初步完成了三维地图的加载,点,线,面的绘制工作。并且将osgearth与Qt进行了结合。下面来看看代码。

Qt 与 osgearth示例代码

main.cpp文件

#include "MWidget.h"
#include 
#include 

int usage(const std::string& msg, osg::ArgumentParser& args)
{
	OE_NOTICE << msg << std::endl << std::endl;
	OE_NOTICE << "USAGE: " << args[0] << " file.earth" << std::endl;

	return -1;
}

int main(int argc, char** argv)
{

	qDebug() << "argv[1]:" << argv[1] ;

	//参数解析器,
	osg::ArgumentParser args(&argc, argv);
	if (args.find("--help") >= 0)
		return usage("Help", args);

	// load something  获取场景操作的节点.
	osg::ref_ptr<osg::Node> node = osgDB::readNodeFiles(args);
	if (!node.valid())
		return usage("Can't load a scene!", args);

	// Qt setup:
	QApplication q(argc, argv);

	//osg::Node* scene get获取node指针.
	MWidget m(args, node.get()); 
	m.show();

	return q.exec();
}

MWidget.h 文件

#pragma once

#include 
#include "ui_MWidget.h"

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

#include 

//
#include 

#include 
#include 

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

#include 
#include 

#include 



class MWidget : public QWidget
{
	Q_OBJECT

public:
	MWidget(QWidget *parent = Q_NULLPTR);
	MWidget( osg::ArgumentParser& args, osg::Node* scene, QWidget *parent = Q_NULLPTR);
	
	void paintEvent(QPaintEvent* e);

public slots:
	void addView();

public:
	QTimer                     _timer;
	osgViewer::CompositeViewer _viewer;
	osg::ref_ptr<osg::Node>    _scene;
	osg::ref_ptr<osg::Node>  node;
	
private:
	Ui::MWidget ui;
};

MWidget.cpp 文件

#include "MWidget.h"

using namespace osgEarth;
using namespace osgEarth::Util;
using namespace osgEarth::QtGui;


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

//暂时使用这种形式,
//extern osg::ref_ptr  node;

MWidget::MWidget(QWidget *parent)
	: QWidget(parent)
{
	ui.setupUi(this);
}


MWidget::MWidget( osg::ArgumentParser& args, osg::Node* scene, QWidget *parent)
	: QWidget(parent), _viewer(args), _scene(scene)
{
	ui.setupUi(this);

	node = scene;

	_viewer.setThreadingModel(_viewer.SingleThreaded);

	// timer fires a paint event.
	connect(&_timer, SIGNAL(timeout()), this, SLOT(update()));
	_timer.start(20);

	connect(ui.pushButton, SIGNAL(clicked()), this, SLOT(addView()));

	//构造器中必须要有.否则没有任何效果.
	addView();

}

void MWidget::paintEvent(QPaintEvent* e)
{
	// refresh all the views.
	if (_viewer.getRunFrameScheme() == osgViewer::ViewerBase::CONTINUOUS ||
		_viewer.checkNeedToDoFrame())
	{
		_viewer.frame();
	}
}

void MWidget::addView()
{

	// the new View we want to add:
	osgViewer::View* view = new osgViewer::View();

	// a widget to hold our view:
	QWidget* viewWidget = new osgEarth::QtGui::ViewWidget(view);  //将osgViewer 转换为 QWidget, 方便进行填充编程.
	///

	osg::Group* root = new osg::Group();
	// find the map node that we loaded.
	MapNode* mapNode = MapNode::findMapNode(node);
	if (!mapNode)
		;

	// Group to hold all our annotation elements.
	//创建一个组用来保存所有的元素.
	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;
	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:
		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->addChild(new PlaceNode(GeoPoint(geoSRS, 14.68, 50.0), "Prague", pm), 0.0, 2e6);
		labelGroup->addChild(lod);

		// absolute altitude:
		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 osgEarth::Symbology::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()->stroke()->color() = Color::Cyan;
		geomStyle.getOrCreate<LineSymbol>()->stroke()->color() = Color::Red;
		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;

		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)); //geoSRS 空间参考坐标系
		labelGroup->addChild(label);
	}

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

	// another rhumb box that crosses the antimeridian
	{
		Geometry* geom = new osgEarth::Symbology::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);

		annoGroup->addChild(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);

		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
		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<ExtrusionSymbol>()->height() = 1250000.0; // meters MSL
		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 osgEarth::Symbology::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() = 1250000.0; // meters MSL
		utahStyle.getOrCreate<PolygonSymbol>()->fill()->color() = Color(Color::Red, 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");
		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");
		ModelNode* modelNode = new ModelNode(mapNode, style);
		modelNode->setPosition(GeoPoint(geoSRS, -100, 52));
		annoGroup->addChild(modelNode);
	}

	//

	// a dialog to hold the view widget: 向widget中添加一个dialog对象
	QDialog* win = new QDialog(this);
	win->setModal(false);  //设置非模态对话框.
	win->setLayout(new QHBoxLayout()); //设置水平排列
	win->layout()->addWidget(viewWidget); //
	int x = osgEarth::Random().next(1024); //产生随机数,0 ~ 1024
	int y = osgEarth::Random().next(768); //产生随机数, 0 ~ 768

	qDebug() << "x:" << x << "  y:" << y << endl;

	win->setGeometry(x, y, 640, 480);
	win->show();

	// set up the view, 相当于node 节点.
	view->setCameraManipulator(new osgEarth::Util::EarthManipulator);
	view->setSceneData(_scene.get());
	view->getDatabasePager()->setUnrefImageDataAfterApplyPolicy(true, false);

	// add it to the composite viewer.
	_viewer.addView(view);

}

效果展示

点击addview 按钮不断的产生新图片.
osgearth开发三维地球_第1张图片
osgearth开发三维地球_第2张图片

你可能感兴趣的:(osgearth)