/src/applications/osgearth_qt/osgearth_qt.cpp

http://github.com/gwaldron/osgearth · C++ · 430 lines · 291 code · 87 blank · 52 comment · 23 complexity · 4d8c5c4896eaee69a0c98d8c5589179d MD5 · raw file

  1. /* -*-c++-*- */
  2. /* osgEarth - Dynamic map generation toolkit for OpenSceneGraph
  3. * Copyright 2008-2013 Pelican Mapping
  4. * http://osgearth.org
  5. *
  6. * osgEarth is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU Lesser General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public License
  17. * along with this program. If not, see <http://www.gnu.org/licenses/>
  18. */
  19. #include <osg/Notify>
  20. #include <osgEarth/ImageUtils>
  21. #include <osgEarth/MapNode>
  22. #include <osgEarthAnnotation/AnnotationData>
  23. #include <osgEarthAnnotation/AnnotationNode>
  24. #include <osgEarthAnnotation/PlaceNode>
  25. #include <osgEarthAnnotation/ScaleDecoration>
  26. #include <osgEarthAnnotation/TrackNode>
  27. #include <osgEarthQt/ViewerWidget>
  28. #include <osgEarthQt/MultiViewerWidget>
  29. #include <osgEarthQt/LayerManagerWidget>
  30. #include <osgEarthQt/MapCatalogWidget>
  31. #include <osgEarthQt/DataManager>
  32. #include <osgEarthQt/AnnotationListWidget>
  33. #include <osgEarthQt/LOSControlWidget>
  34. #include <osgEarthQt/TerrainProfileWidget>
  35. #include <osgEarthUtil/AnnotationEvents>
  36. #include <osgEarthUtil/AutoClipPlaneHandler>
  37. #include <osgEarthUtil/SkyNode>
  38. #include <osgEarthUtil/EarthManipulator>
  39. #include <osgEarthDrivers/ocean_surface/OceanSurface>
  40. #include <QAction>
  41. #include <QDockWidget>
  42. #include <QMainWindow>
  43. #include <QToolBar>
  44. #include <QtGui/QApplication>
  45. #include "DemoMainWindow"
  46. #ifdef Q_WS_X11
  47. #include <X11/Xlib.h>
  48. #endif
  49. using namespace osgEarth::Util;
  50. #define TRACK_ICON_URL "../data/m2525_air.png"
  51. #define TRACK_ICON_SIZE 24
  52. #define TRACK_FIELD_NAME "name"
  53. static osg::ref_ptr<osg::Group> s_annoGroup;
  54. static osgEarth::Util::SkyNode* s_sky=0L;
  55. static osgEarth::Drivers::OceanSurfaceNode* s_ocean=0L;
  56. //------------------------------------------------------------------
  57. int
  58. usage( const std::string& msg )
  59. {
  60. OE_NOTICE << msg << std::endl;
  61. OE_NOTICE << std::endl;
  62. OE_NOTICE << "USAGE: osgearth_qt [options] file.earth" << std::endl;
  63. OE_NOTICE << " --multi n : use a multi-pane viewer with n initial views" << std::endl;
  64. OE_NOTICE << " --stylesheet filename : optional Qt stylesheet" << std::endl;
  65. OE_NOTICE << " --run-on-demand : use the OSG ON_DEMAND frame scheme" << std::endl;
  66. OE_NOTICE << " --tracks : create some moving track data" << std::endl;
  67. return -1;
  68. }
  69. //------------------------------------------------------------------
  70. /**
  71. * Event handler that processes events fired from the
  72. * AnnotationEventCallback
  73. */
  74. struct MyAnnoEventHandler : public AnnotationEventHandler
  75. {
  76. MyAnnoEventHandler(osgEarth::QtGui::DataManager* manager) : _manager(manager) {}
  77. void onClick( AnnotationNode* node, const EventArgs& details )
  78. {
  79. if (_manager.valid() && details.buttons == osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON)
  80. {
  81. if (details.modkeys & osgGA::GUIEventAdapter::MODKEY_CTRL)
  82. {
  83. if (_manager->isSelected(node))
  84. _manager->removeSelectedAnnotation(node);
  85. else
  86. _manager->addSelectedAnnotation(node);
  87. }
  88. else
  89. {
  90. _manager->clearSelectedAnnotations();
  91. _manager->addSelectedAnnotation(node);
  92. }
  93. }
  94. }
  95. osg::ref_ptr<osgEarth::QtGui::DataManager> _manager;
  96. };
  97. //------------------------------------------------------------------
  98. // Methods for demo track simulation
  99. struct TrackSim : public osg::Referenced
  100. {
  101. TrackSim(TrackNode* track, const osg::Vec3d& center, float radius, double time, osgEarth::MapNode* mapNode)
  102. : _track(track), _mapNode(mapNode), _radius(radius), _time(time)
  103. {
  104. //Get the center point in geocentric
  105. GeoPoint centerMap(mapNode->getMapSRS(), center, ALTMODE_ABSOLUTE);
  106. centerMap.toWorld( _center, mapNode->getTerrain() );
  107. //mapNode->getMap()->toWorldPoint( centerMap, _center );
  108. _up = _center;
  109. _up.normalize();
  110. //Get the "side" vector
  111. _side = _up ^ osg::Vec3d(0,0,1);
  112. }
  113. void update(double time)
  114. {
  115. double angle = (time / _time);
  116. angle = (angle - (int)angle) * osg::PI * 2.0;
  117. osg::Quat quat(angle, _up );
  118. osg::Vec3d spoke = quat * (_side * _radius);
  119. osg::Vec3d end = _center + spoke;
  120. GeoPoint mapPos;
  121. mapPos.fromWorld( _mapNode->getMapSRS(), end );
  122. //_mapNode->getMap()->worldPointToMapPoint(end, mapPos);
  123. _track->setPosition(mapPos);
  124. }
  125. TrackNode* _track;
  126. osgEarth::MapNode* _mapNode;
  127. osg::Vec3d _center, _side, _up;
  128. float _radius;
  129. double _time;
  130. };
  131. typedef std::vector< osg::ref_ptr<TrackSim> > TrackSimVector;
  132. /** Update operation that runs the simulators. */
  133. struct TrackSimUpdate : public osg::Operation
  134. {
  135. TrackSimUpdate(TrackSimVector& sims) : osg::Operation("tracksim", true), _sims(sims) { }
  136. void operator()(osg::Object* obj)
  137. {
  138. osg::View* view = dynamic_cast<osg::View*>(obj);
  139. double t = view->getFrameStamp()->getSimulationTime();
  140. for(TrackSimVector::iterator i = _sims.begin(); i != _sims.end(); ++i)
  141. i->get()->update(t);
  142. }
  143. TrackSimVector& _sims;
  144. };
  145. TrackNode* createTrack(TrackNodeFieldSchema& schema, osg::Image* image, const std::string& name, MapNode* mapNode, const osg::Vec3d& center, double radius, double time, TrackSimVector& trackSims)
  146. {
  147. TrackNode* track = new TrackNode(mapNode, GeoPoint(mapNode->getMapSRS(),center,ALTMODE_ABSOLUTE), image, schema);
  148. track->setFieldValue(TRACK_FIELD_NAME, name);
  149. AnnotationData* data = new AnnotationData();
  150. data->setName(name);
  151. data->setViewpoint(osgEarth::Viewpoint(center, 0.0, -90.0, 1e5));
  152. track->setAnnotationData( data );
  153. trackSims.push_back(new TrackSim(track, center, radius, time, mapNode));
  154. return track;
  155. }
  156. void createTrackSchema(TrackNodeFieldSchema& schema)
  157. {
  158. // draw the track name above the icon:
  159. TextSymbol* nameSymbol = new TextSymbol();
  160. nameSymbol->pixelOffset()->set( 0, 2+TRACK_ICON_SIZE/2 );
  161. nameSymbol->alignment() = TextSymbol::ALIGN_CENTER_BOTTOM;
  162. nameSymbol->halo()->color() = Color::Black;
  163. schema[TRACK_FIELD_NAME] = TrackNodeField(nameSymbol, false);
  164. }
  165. //------------------------------------------------------------------
  166. int
  167. main(int argc, char** argv)
  168. {
  169. osg::ArgumentParser arguments(&argc,argv);
  170. osg::DisplaySettings::instance()->setMinimumNumStencilBits(8);
  171. std::string compNum;
  172. bool composite = arguments.read("--multi", compNum);
  173. int numViews = composite ? osgEarth::as<int>(compNum, 4) : 1;
  174. std::string stylesheet;
  175. bool styled = arguments.read("--stylesheet", stylesheet);
  176. bool on_demand = arguments.read("--run-on-demand");
  177. bool trackData = arguments.read("--tracks");
  178. bool testUseExistingViewer = arguments.read("--use-existing");
  179. // load the .earth file from the command line.
  180. osg::Node* earthNode = osgDB::readNodeFiles( arguments );
  181. if (!earthNode)
  182. return usage( "Unable to load earth model." );
  183. osg::Group* root = new osg::Group();
  184. root->addChild( earthNode );
  185. s_annoGroup = new osg::Group();
  186. root->addChild( s_annoGroup );
  187. #ifdef Q_WS_X11
  188. XInitThreads();
  189. #endif
  190. QApplication app(argc, argv);
  191. osg::ref_ptr<osgEarth::MapNode> mapNode = osgEarth::MapNode::findMapNode( earthNode );
  192. osg::ref_ptr<osgEarth::QtGui::DataManager> dataManager = new osgEarth::QtGui::DataManager(mapNode.get());
  193. DemoMainWindow appWin(dataManager.get(), mapNode.get(), s_annoGroup);
  194. // install an event handler for picking and selection
  195. AnnotationEventCallback* cb = new AnnotationEventCallback();
  196. cb->addHandler(new MyAnnoEventHandler(dataManager.get()));
  197. s_annoGroup->addEventCallback(cb);
  198. osgEarth::QtGui::ViewVector views;
  199. osg::ref_ptr<osgViewer::ViewerBase> viewer;
  200. // create viewer widget
  201. if (composite)
  202. {
  203. osgEarth::QtGui::MultiViewerWidget* viewerWidget = new osgEarth::QtGui::MultiViewerWidget(root);
  204. osgViewer::View* primary = viewerWidget->createViewWidget(root);
  205. primary->getCamera()->addCullCallback(new osgEarth::Util::AutoClipPlaneCullCallback(mapNode));
  206. views.push_back(primary);
  207. for (int i=0; i < numViews - 1; i++)
  208. {
  209. osgViewer::View* view = viewerWidget->createViewWidget(root, primary);
  210. view->getCamera()->addCullCallback(new osgEarth::Util::AutoClipPlaneCullCallback(mapNode));
  211. views.push_back(view);
  212. }
  213. //viewerWidget->setGeometry(50, 50, 1024, 768);
  214. appWin.setViewerWidget(viewerWidget, views);
  215. viewer = viewerWidget;
  216. }
  217. else
  218. {
  219. osgEarth::QtGui::ViewerWidget* viewerWidget = 0L;
  220. if ( testUseExistingViewer )
  221. {
  222. // tests: create a pre-existing viewer and install that in the widget.
  223. osgViewer::Viewer* v = new osgViewer::Viewer();
  224. v->setSceneData(root);
  225. v->setThreadingModel(osgViewer::Viewer::DrawThreadPerContext);
  226. v->setCameraManipulator(new osgEarth::Util::EarthManipulator());
  227. viewerWidget = new osgEarth::QtGui::ViewerWidget(v);
  228. }
  229. else
  230. {
  231. // tests: implicity creating a viewer.
  232. viewerWidget = new osgEarth::QtGui::ViewerWidget( root );
  233. }
  234. //osgEarth::QtGui::ViewerWidget* viewerWidget = new osgEarth::QtGui::ViewerWidget(root);
  235. //viewerWidget->setGeometry(50, 50, 1024, 768);
  236. viewerWidget->getViews( views );
  237. for(osgEarth::QtGui::ViewVector::iterator i = views.begin(); i != views.end(); ++i )
  238. {
  239. i->get()->getCamera()->addCullCallback(new osgEarth::Util::AutoClipPlaneCullCallback(mapNode));
  240. }
  241. appWin.setViewerWidget(viewerWidget);
  242. if (mapNode.valid())
  243. {
  244. const Config& externals = mapNode->externalConfig();
  245. if (mapNode->getMap()->isGeocentric())
  246. {
  247. // Sky model.
  248. Config skyConf = externals.child("sky");
  249. double hours = skyConf.value("hours", 12.0);
  250. s_sky = new osgEarth::Util::SkyNode(mapNode->getMap());
  251. s_sky->setDateTime( DateTime(2011, 3, 6, hours) );
  252. for(osgEarth::QtGui::ViewVector::iterator i = views.begin(); i != views.end(); ++i )
  253. s_sky->attach( *i );
  254. root->addChild(s_sky);
  255. // Ocean surface.
  256. if (externals.hasChild("ocean"))
  257. {
  258. s_ocean = new osgEarth::Drivers::OceanSurfaceNode(mapNode.get(), externals.child("ocean"));
  259. if (s_ocean)
  260. root->addChild(s_ocean);
  261. }
  262. }
  263. }
  264. viewer = viewerWidget->getViewer();
  265. }
  266. // activate "on demand" rendering if requested:
  267. if ( on_demand )
  268. {
  269. viewer->setRunFrameScheme( osgViewer::ViewerBase::ON_DEMAND );
  270. OE_NOTICE << "On-demand rendering activated" << std::endl;
  271. }
  272. TrackSimVector trackSims;
  273. if ( trackData )
  274. {
  275. // create demo tracks
  276. osg::ref_ptr<osg::Image> srcImage = osgDB::readImageFile(TRACK_ICON_URL);
  277. osg::ref_ptr<osg::Image> image;
  278. ImageUtils::resizeImage(srcImage.get(), TRACK_ICON_SIZE, TRACK_ICON_SIZE, image);
  279. TrackNodeFieldSchema schema;
  280. createTrackSchema(schema);
  281. dataManager->addAnnotation(createTrack(schema, image, "Plane 1", mapNode.get(), osg::Vec3d(-121.463, 46.3548, 1500.71), 10000, 24, trackSims), s_annoGroup);
  282. dataManager->addAnnotation(createTrack(schema, image, "Plane 2", mapNode.get(), osg::Vec3d(-121.656, 46.0935, 4133.06), 10000, 8, trackSims), s_annoGroup);
  283. dataManager->addAnnotation(createTrack(schema, image, "Plane 3", mapNode.get(), osg::Vec3d(-121.321, 46.2589, 1390.09), 10000, 12, trackSims), s_annoGroup);
  284. viewer->addUpdateOperation(new TrackSimUpdate(trackSims));
  285. }
  286. // create catalog widget and add as a docked widget to the main window
  287. QDockWidget *catalogDock = new QDockWidget(QWidget::tr("Layers"));
  288. catalogDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
  289. osgEarth::QtGui::MapCatalogWidget* layerCatalog = new osgEarth::QtGui::MapCatalogWidget(dataManager.get(), osgEarth::QtGui::MapCatalogWidget::ALL_LAYERS);
  290. layerCatalog->setActiveViews(views);
  291. layerCatalog->setHideEmptyGroups(true);
  292. catalogDock->setWidget(layerCatalog);
  293. appWin.addDockWidget(Qt::LeftDockWidgetArea, catalogDock);
  294. // create and dock an annotation list widget
  295. QDockWidget *annoDock = new QDockWidget;
  296. annoDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
  297. osgEarth::QtGui::AnnotationListWidget* annoList = new osgEarth::QtGui::AnnotationListWidget(dataManager.get());
  298. annoList->setActiveViews(views);
  299. annoDock->setWidget(annoList);
  300. appWin.addDockWidget(Qt::LeftDockWidgetArea, annoDock);
  301. // create a second catalog widget for viewpoints
  302. QDockWidget *vpDock = new QDockWidget;
  303. vpDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
  304. osgEarth::QtGui::MapCatalogWidget* vpCatalog = new osgEarth::QtGui::MapCatalogWidget(dataManager.get(), osgEarth::QtGui::MapCatalogWidget::VIEWPOINTS);
  305. vpCatalog->setActiveViews(views);
  306. vpDock->setWidget(vpCatalog);
  307. appWin.addDockWidget(Qt::LeftDockWidgetArea, vpDock);
  308. // create layer manager widget and add as a docked widget on the right
  309. QDockWidget *layersDock = new QDockWidget(QWidget::tr("Image Layers"));
  310. layersDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
  311. osgEarth::QtGui::LayerManagerWidget* layerManager = new osgEarth::QtGui::LayerManagerWidget(dataManager.get(), osgEarth::QtGui::LayerManagerWidget::IMAGE_LAYERS);
  312. layerManager->setActiveViews(views);
  313. layersDock->setWidget(layerManager);
  314. appWin.addDockWidget(Qt::RightDockWidgetArea, layersDock);
  315. // create and dock a LOSControlWidget
  316. QDockWidget *losDock = new QDockWidget;
  317. losDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
  318. osgEarth::QtGui::LOSControlWidget* losControl = new osgEarth::QtGui::LOSControlWidget(root, mapNode.get(), dataManager.get());
  319. losControl->setActiveViews(views);
  320. losDock->setWidget(losControl);
  321. appWin.addDockWidget(Qt::RightDockWidgetArea, losDock);
  322. // create terrain profile widget
  323. osgEarth::QtGui::TerrainProfileWidget* terrainProfiler = new osgEarth::QtGui::TerrainProfileWidget(root, mapNode.get());
  324. terrainProfiler->setActiveViews(views);
  325. appWin.setTerrainProfileWidget(terrainProfiler);
  326. // attempt to load .qss stylesheet if one was provided
  327. if (styled)
  328. {
  329. QFile file(QString(stylesheet.c_str()));
  330. if (file.exists())
  331. {
  332. file.open(QFile::ReadOnly);
  333. QString qstylesheet = QLatin1String(file.readAll());
  334. app.setStyleSheet(qstylesheet);
  335. layerManager->setStyleSheet(qstylesheet);
  336. annoList->setStyleSheet(qstylesheet);
  337. losControl->setStyleSheet(qstylesheet);
  338. }
  339. }
  340. appWin.setGeometry(100, 100, 1280, 800);
  341. appWin.show();
  342. return app.exec();
  343. }