osgEarth 2.1.1

/home/cube/sources/osgearth/src/applications/osgearth_viewer/osgearth_viewer.cpp

Go to the documentation of this file.
00001 /* -*-c++-*- */
00002 /* osgEarth - Dynamic map generation toolkit for OpenSceneGraph
00003 * Copyright 2008-2010 Pelican Mapping
00004 * http://osgearth.org
00005 *
00006 * osgEarth is free software; you can redistribute it and/or modify
00007 * it under the terms of the GNU Lesser General Public License as published by
00008 * the Free Software Foundation; either version 2 of the License, or
00009 * (at your option) any later version.
00010 *
00011 * This program is distributed in the hope that it will be useful,
00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 * GNU Lesser General Public License for more details.
00015 *
00016 * You should have received a copy of the GNU Lesser General Public License
00017 * along with this program.  If not, see <http://www.gnu.org/licenses/>
00018 */
00019 
00020 #include <osg/Notify>
00021 #include <osgGA/StateSetManipulator>
00022 #include <osgGA/GUIEventHandler>
00023 #include <osgViewer/Viewer>
00024 #include <osgViewer/ViewerEventHandlers>
00025 #include <osgEarth/MapNode>
00026 #include <osgEarth/XmlUtils>
00027 #include <osgEarthUtil/EarthManipulator>
00028 #include <osgEarthUtil/AutoClipPlaneHandler>
00029 #include <osgEarthUtil/Controls>
00030 #include <osgEarthUtil/Graticule>
00031 #include <osgEarthUtil/SkyNode>
00032 #include <osgEarthUtil/Viewpoint>
00033 #include <osgEarthUtil/Formatters>
00034 #include <osgEarthUtil/Annotation>
00035 #include <osgEarthSymbology/Color>
00036 #include <osgEarthDrivers/kml/KML>
00037 
00038 using namespace osgEarth::Util;
00039 using namespace osgEarth::Util::Annotation;
00040 using namespace osgEarth::Util::Controls;
00041 using namespace osgEarth::Symbology;
00042 using namespace osgEarth::Drivers;
00043 
00044 int
00045 usage( const std::string& msg )
00046 {
00047     OE_NOTICE << msg << std::endl;
00048     OE_NOTICE << std::endl;
00049     OE_NOTICE << "USAGE: osgearth_viewer [options] file.earth" << std::endl;
00050     OE_NOTICE << "   --sky           : activates the atmospheric model" << std::endl;
00051     OE_NOTICE << "   --autoclip      : activates the auto clip-plane handler" << std::endl;
00052     OE_NOTICE << "   --dms           : format coordinates as degrees/minutes/seconds" << std::endl;
00053     OE_NOTICE << "   --mgrs          : format coordinates as MGRS" << std::endl;
00054     
00055         
00056     return -1;
00057 }
00058 
00059 static EarthManipulator* s_manip         =0L;
00060 static Control*          s_controlPanel  =0L;
00061 static SkyNode*          s_sky           =0L;
00062 static bool              s_dms           =false;
00063 static bool              s_mgrs          =false;
00064 
00065 struct SkySliderHandler : public ControlEventHandler
00066 {
00067     virtual void onValueChanged( class Control* control, float value )
00068     {
00069         s_sky->setDateTime( 2011, 3, 6, value );
00070     }
00071 };
00072 
00073 struct ToggleNodeHandler : public ControlEventHandler
00074 {
00075     ToggleNodeHandler( osg::Node* node ) : _node(node) { }
00076 
00077     virtual void onValueChanged( class Control* control, bool value )
00078     {
00079         osg::ref_ptr<osg::Node> safeNode = _node.get();
00080         if ( safeNode.valid() )
00081             safeNode->setNodeMask( value ? ~0 : 0 );
00082     }
00083 
00084     osg::observer_ptr<osg::Node> _node;
00085 };
00086 
00087 struct ClickViewpointHandler : public ControlEventHandler
00088 {
00089     ClickViewpointHandler( const Viewpoint& vp ) : _vp(vp) { }
00090     Viewpoint _vp;
00091 
00092     virtual void onClick( class Control* control )
00093     {
00094         s_manip->setViewpoint( _vp, 4.5 );
00095     }
00096 };
00097 
00098 struct MouseCoordsHandler : public osgGA::GUIEventHandler
00099 {
00100     MouseCoordsHandler( LabelControl* label, osgEarth::MapNode* mapNode )
00101         : _label( label ),
00102           _mapNode( mapNode )
00103     {
00104         _mapNodePath.push_back( mapNode->getTerrainEngine() );
00105     }
00106 
00107     bool handle( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa )
00108     {
00109         osgViewer::View* view = static_cast<osgViewer::View*>(aa.asView());
00110         if (ea.getEventType() == ea.MOVE || ea.getEventType() == ea.DRAG)
00111         {
00112             osgUtil::LineSegmentIntersector::Intersections results;
00113             if ( view->computeIntersections( ea.getX(), ea.getY(), _mapNodePath, results ) )
00114             {
00115                 // find the first hit under the mouse:
00116                 osgUtil::LineSegmentIntersector::Intersection first = *(results.begin());
00117                 osg::Vec3d point = first.getWorldIntersectPoint();
00118                 osg::Vec3d lla;
00119 
00120                 // transform it to map coordinates:
00121                 _mapNode->getMap()->worldPointToMapPoint(point, lla);
00122 
00123                 std::stringstream ss;
00124 
00125                 if ( s_mgrs )
00126                 {
00127                     MGRSFormatter f( MGRSFormatter::PRECISION_1M );
00128                     ss << "MGRS: " << f.format(lla.y(), lla.x()) << "   ";
00129                 }
00130                  // lat/long
00131                 {
00132                     LatLongFormatter::AngularFormat fFormat = s_dms?
00133                         LatLongFormatter::FORMAT_DEGREES_MINUTES_SECONDS :
00134                         LatLongFormatter::FORMAT_DECIMAL_DEGREES;
00135                     
00136                     LatLongFormatter f( fFormat );
00137 
00138                     ss 
00139                         << "Lat: " << f.format( Angular(lla.y(),Units::DEGREES), 4 ) << "  "
00140                         << "Lon: " << f.format( Angular(lla.x(),Units::DEGREES), 5 );
00141                 }
00142 
00143                 _label->setText( ss.str() );
00144             }
00145             else
00146             {
00147                 //Clear the text
00148                 _label->setText( "" );
00149             }
00150         }
00151         return false;
00152     }
00153 
00154     osg::ref_ptr< LabelControl > _label;
00155     MapNode*                     _mapNode;
00156     osg::NodePath                _mapNodePath;
00157 };
00158 
00159 
00160 
00161 void
00162 createControlPanel( osgViewer::View* view, std::vector<Viewpoint>& vps )
00163 {
00164     ControlCanvas* canvas = ControlCanvas::get( view );
00165 
00166     VBox* main = new VBox();
00167     main->setBackColor(0,0,0,0.5);
00168     main->setMargin( 10 );
00169     main->setPadding( 10 );
00170     main->setChildSpacing( 10 );
00171     main->setAbsorbEvents( true );
00172     main->setVertAlign( Control::ALIGN_BOTTOM );
00173 
00174     if ( vps.size() > 0 )
00175     {
00176         // the viewpoint container:
00177         Grid* g = new Grid();
00178         g->setChildSpacing( 0 );
00179         g->setChildVertAlign( Control::ALIGN_CENTER );
00180 
00181         unsigned i;
00182         for( i=0; i<vps.size(); ++i )
00183         {
00184             const Viewpoint& vp = vps[i];
00185             std::stringstream buf;
00186             buf << (i+1);
00187             Control* num = new LabelControl(buf.str(), 16.0f, osg::Vec4f(1,1,0,1));
00188             num->setPadding( 4 );
00189             g->setControl( 0, i, num );
00190 
00191             Control* vpc = new LabelControl(vp.getName().empty() ? "<no name>" : vp.getName(), 16.0f);
00192             vpc->setPadding( 4 );
00193             vpc->setHorizFill( true );
00194             vpc->setActiveColor( Color::Blue );
00195             vpc->addEventHandler( new ClickViewpointHandler(vp) );
00196             g->setControl( 1, i, vpc );
00197         }
00198         main->addControl( g );
00199     }
00200 
00201     // sky time slider:
00202     if ( s_sky )
00203     {
00204         HBox* skyBox = new HBox();
00205         skyBox->setChildVertAlign( Control::ALIGN_CENTER );
00206         skyBox->setChildSpacing( 10 );
00207         skyBox->setHorizFill( true );
00208 
00209         skyBox->addControl( new LabelControl("Time: ", 16) );
00210 
00211         HSliderControl* skySlider = new HSliderControl( 0.0f, 24.0f, 18.0f );
00212         skySlider->setBackColor( Color::Gray );
00213         skySlider->setHeight( 12 );
00214         skySlider->setHorizFill( true, 200 );
00215         skySlider->addEventHandler( new SkySliderHandler );
00216         skyBox->addControl( skySlider );
00217 
00218         main->addControl( skyBox );
00219     }
00220     
00221     canvas->addControl( main );
00222 
00223     s_controlPanel = main;
00224 }
00225 
00229 struct KMLUIBuilder : public osg::NodeVisitor
00230 {
00231     KMLUIBuilder( ControlCanvas* canvas ) : osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN), _canvas(canvas)
00232     {
00233         _grid = new Grid();
00234         _grid->setAbsorbEvents( true );
00235         _grid->setPadding( 5 );
00236         _grid->setVertAlign( Control::ALIGN_TOP );
00237         _grid->setHorizAlign( Control::ALIGN_LEFT );
00238         _grid->setBackColor( Color(Color::Black,0.5) );
00239         _canvas->addControl( _grid );
00240     }
00241 
00242     void apply( osg::Node& node )
00243     {
00244         AnnotationData* data = dynamic_cast<AnnotationData*>( node.getUserData() );
00245         if ( data )
00246         {
00247             ControlVector row;
00248             CheckBoxControl* cb = new CheckBoxControl( node.getNodeMask() != 0, new ToggleNodeHandler( &node ) );
00249             cb->setSize( 12, 12 );
00250             row.push_back( cb );
00251             std::string name = data->getName().empty() ? "<unnamed>" : data->getName();
00252             LabelControl* label = new LabelControl( name, 14.0f );
00253             label->setMargin(Gutter(0,0,0,(this->getNodePath().size()-3)*20));
00254             if ( data->getViewpoint() )
00255             {
00256                 label->addEventHandler( new ClickViewpointHandler(*data->getViewpoint()) );
00257                 label->setActiveColor( Color::Blue );
00258             }
00259             row.push_back( label );
00260             _grid->addControls( row );
00261         }
00262         traverse(node);
00263     }
00264 
00265     ControlCanvas* _canvas;
00266     Grid*          _grid;
00267 };
00268 
00269 void addMouseCoords(osgViewer::Viewer* viewer, osgEarth::MapNode* mapNode)
00270 {
00271     ControlCanvas* canvas = ControlCanvas::get( viewer );
00272     LabelControl* mouseCoords = new LabelControl();
00273     mouseCoords->setHorizAlign(Control::ALIGN_CENTER );
00274     mouseCoords->setVertAlign(Control::ALIGN_BOTTOM );
00275     mouseCoords->setBackColor(0,0,0,0.5);    
00276     mouseCoords->setSize(400,50);
00277     mouseCoords->setMargin( 10 );
00278     canvas->addControl( mouseCoords );
00279 
00280     viewer->addEventHandler( new MouseCoordsHandler(mouseCoords, mapNode ) );
00281 }
00282 
00283 struct ViewpointHandler : public osgGA::GUIEventHandler
00284 {
00285     ViewpointHandler( const std::vector<Viewpoint>& viewpoints )
00286         : _viewpoints( viewpoints ) { }
00287 
00288     bool handle( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa )
00289     {
00290         if ( ea.getEventType() == ea.KEYDOWN )
00291         {
00292             int index = (int)ea.getKey() - (int)'1';
00293             if ( index >= 0 && index < (int)_viewpoints.size() )
00294             {
00295                 s_manip->setViewpoint( _viewpoints[index], 4.5 );
00296             }
00297             else if ( ea.getKey() == 'v' )
00298             {
00299                 Viewpoint vp = s_manip->getViewpoint();
00300                 XmlDocument xml( vp.getConfig() );
00301                 xml.store( std::cout );
00302                 std::cout << std::endl;
00303             }
00304             else if ( ea.getKey() == '?' )
00305             {
00306                 s_controlPanel->setVisible( !s_controlPanel->visible() );
00307             }
00308         }
00309         return false;
00310     }
00311 
00312     std::vector<Viewpoint> _viewpoints;
00313 };
00314 
00315 int
00316 main(int argc, char** argv)
00317 {
00318     osg::ArgumentParser arguments(&argc,argv);
00319     osg::DisplaySettings::instance()->setMinimumNumStencilBits( 8 );
00320     osgViewer::Viewer viewer(arguments);
00321 
00322     bool useAutoClip  = arguments.read( "--autoclip" );
00323     bool useSky       = arguments.read( "--sky" );
00324     s_dms             = arguments.read( "--dms" );
00325     s_mgrs            = arguments.read( "--mgrs" );
00326 
00327     std::string kmlFile;
00328     arguments.read( "--kml", kmlFile );
00329 
00330     // load the .earth file from the command line.
00331     osg::Node* earthNode = osgDB::readNodeFiles( arguments );
00332     if (!earthNode)
00333         return usage( "Unable to load earth model." );
00334     
00335     s_manip = new EarthManipulator();
00336     s_manip->getSettings()->setArcViewpointTransitions( true );
00337     viewer.setCameraManipulator( s_manip );
00338 
00339     osg::Group* root = new osg::Group();
00340     root->addChild( earthNode );
00341 
00342     // create a graticule and clip plane handler.
00343     Graticule* graticule = 0L;
00344     osgEarth::MapNode* mapNode = osgEarth::MapNode::findMapNode( earthNode );
00345     if ( mapNode )
00346     {
00347         const Config& externals = mapNode->externalConfig();
00348 
00349         if ( mapNode->getMap()->isGeocentric() )
00350         {
00351             // Sky model.
00352             Config skyConf = externals.child( "sky" );
00353             if ( !skyConf.empty() )
00354                 useSky = true;
00355 
00356             if ( useSky )
00357             {
00358                 double hours = skyConf.value( "hours", 12.0 );
00359                 s_sky = new SkyNode( mapNode->getMap() );
00360                 s_sky->setDateTime( 2011, 3, 6, hours );
00361                 s_sky->attach( &viewer );
00362                 root->addChild( s_sky );
00363             }
00364 
00365             if ( externals.hasChild("autoclip") )
00366                 useAutoClip = externals.child("autoclip").boolValue( useAutoClip );
00367 
00368             // the AutoClipPlaneHandler will automatically adjust the near/far clipping
00369             // planes based on your view of the horizon. This prevents near clipping issues
00370             // when you are very close to the ground. If your app never brings a user very
00371             // close to the ground, you may not need this.
00372             if ( useSky || useAutoClip )
00373             {
00374                 viewer.getCamera()->addEventCallback( new AutoClipPlaneCallback() );
00375             }
00376         }
00377 
00378         // read in viewpoints, if any
00379         std::vector<Viewpoint> viewpoints;
00380         const ConfigSet children = externals.children("viewpoint");
00381         if ( children.size() > 0 )
00382         {
00383             for( ConfigSet::const_iterator i = children.begin(); i != children.end(); ++i )
00384                 viewpoints.push_back( Viewpoint(*i) );
00385 
00386             viewer.addEventHandler( new ViewpointHandler(viewpoints) );
00387         }
00388 
00389         // Add a control panel to the scene
00390         root->addChild( ControlCanvas::get( &viewer ) );
00391         if ( viewpoints.size() > 0 || s_sky )
00392             createControlPanel(&viewer, viewpoints);
00393 
00394         addMouseCoords( &viewer, mapNode );
00395 
00396         // Load a KML file if specified
00397         if ( !kmlFile.empty() )
00398         {
00399             KMLOptions kmlo;
00400             kmlo.defaultIconImage() = URI("http://www.osgearth.org/chrome/site/pushpin_yellow.png").readImage();
00401 
00402             osg::Node* kml = KML::load( URI(kmlFile), mapNode, kmlo );
00403             if ( kml )
00404             {
00405                 root->addChild( kml );
00406 
00407                 KMLUIBuilder uibuilder( ControlCanvas::get(&viewer) );
00408                 root->accept( uibuilder );                
00409             }
00410         }
00411     }
00412 
00413     // osgEarth benefits from pre-compilation of GL objects in the pager. In newer versions of
00414     // OSG, this activates OSG's IncrementalCompileOpeartion in order to avoid frame breaks.
00415     viewer.getDatabasePager()->setDoPreCompile( true );
00416 
00417     viewer.setSceneData( root );
00418 
00419     // add some stock OSG handlers:
00420     viewer.addEventHandler(new osgViewer::StatsHandler());
00421     viewer.addEventHandler(new osgViewer::WindowSizeHandler());
00422     viewer.addEventHandler(new osgViewer::ThreadingHandler());
00423     viewer.addEventHandler(new osgViewer::LODScaleHandler());
00424     viewer.addEventHandler(new osgGA::StateSetManipulator(viewer.getCamera()->getOrCreateStateSet()));
00425 
00426     return viewer.run();
00427 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines