osgEarth 2.1.1

/home/cube/sources/osgearth/src/osgEarthUtil/ObjectPlacer.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 #include <osgEarthUtil/ObjectPlacer>
00020 #include <osgEarth/FindNode>
00021 #include <osgEarth/MapNode>
00022 #include <osgEarth/SpatialReference>
00023 #include <osgSim/LineOfSight>
00024 #include <osgUtil/IntersectionVisitor>
00025 #include <osgUtil/LineSegmentIntersector>
00026 #include <osg/MatrixTransform>
00027 #include <osg/CoordinateSystemNode>
00028 
00029 using namespace osgEarth::Util;
00030 using namespace osgEarth;
00031 
00032 struct CachingReadCallback : public osgSim::DatabaseCacheReadCallback
00033 {
00034     CachingReadCallback(int maxReads) : _reads(0), _maxReads(maxReads) { }
00035     void reset() { _reads = 0; }
00036     virtual osg::Node* readNodeFile(const std::string& filename) {
00037         if ( _reads < _maxReads ) {
00038             _reads++;
00039             return osgSim::DatabaseCacheReadCallback::readNodeFile(filename);
00040         }
00041         else {
00042             return NULL;
00043         }
00044     }
00045     int _reads, _maxReads;
00046     osg::ref_ptr<osg::Node> _lastNodeRead;
00047 };
00048 
00049 ObjectPlacer::ObjectPlacer( osg::Node* terrain, int traversalMask, bool clamp, int maxLevel ) :
00050 _traversalMask( traversalMask ),
00051 _clamp( clamp )
00052 {
00053     _mapNode = findTopMostNodeOfType<osgEarth::MapNode>( terrain );
00054     _csn = findTopMostNodeOfType<osg::CoordinateSystemNode>( terrain );
00055     _readCallback = new CachingReadCallback( maxLevel );
00056 }
00057 
00058 bool
00059 ObjectPlacer::clampGeocentric( osg::CoordinateSystemNode* csn, double lat_rad, double lon_rad, osg::Vec3d& out ) const
00060 {
00061     osg::Vec3d start, end;
00062     
00063     csn->getEllipsoidModel()->convertLatLongHeightToXYZ( lat_rad, lon_rad, 50000, start.x(), start.y(), start.z() );
00064     csn->getEllipsoidModel()->convertLatLongHeightToXYZ( lat_rad, lon_rad, -50000, end.x(), end.y(), end.z() );
00065     osgUtil::LineSegmentIntersector* i = new osgUtil::LineSegmentIntersector( start, end );
00066     
00067     osgUtil::IntersectionVisitor iv;
00068     iv.setIntersector( i );
00069     static_cast<CachingReadCallback*>(_readCallback.get())->reset();
00070     iv.setReadCallback( _readCallback.get() );
00071     iv.setTraversalMask( _traversalMask );
00072 
00073     _mapNode->accept( iv );
00074 
00075     osgUtil::LineSegmentIntersector::Intersections& results = i->getIntersections();
00076     if ( !results.empty() )
00077     {
00078         const osgUtil::LineSegmentIntersector::Intersection& result = *results.begin();
00079         out = result.matrix.valid() ?
00080             result.localIntersectionPoint * (*result.matrix) :
00081             result.localIntersectionPoint;
00082         return true;            
00083     }
00084     return false;
00085 }
00086 
00087 bool
00088 ObjectPlacer::clampProjected( osg::CoordinateSystemNode* csn, double x, double y, osg::Vec3d& out ) const
00089 {
00090     osg::Vec3d start( x, y, 50000 );
00091     osg::Vec3d end(x, y, -50000);
00092     osgUtil::LineSegmentIntersector* i = new osgUtil::LineSegmentIntersector( start, end );
00093     
00094     osgUtil::IntersectionVisitor iv;
00095     iv.setIntersector( i );
00096     static_cast<CachingReadCallback*>(_readCallback.get())->reset();
00097     iv.setReadCallback( _readCallback.get() );
00098     iv.setTraversalMask( _traversalMask );
00099 
00100     _mapNode->accept( iv );
00101 
00102     osgUtil::LineSegmentIntersector::Intersections& results = i->getIntersections();
00103     if ( !results.empty() )
00104     {
00105         const osgUtil::LineSegmentIntersector::Intersection& result = *results.begin();
00106         out = result.matrix.valid() ?
00107             result.localIntersectionPoint * (*result.matrix) :
00108             result.localIntersectionPoint;
00109         return true;            
00110     }
00111     return false;
00112 }
00113 
00114 bool
00115 ObjectPlacer::createPlacerMatrix( double lat_deg, double lon_deg, double height, osg::Matrixd& out_result ) const
00116 {
00117     if ( !_mapNode.valid() || !_csn.valid() )
00118     {
00119         OE_WARN << "ObjectPlacer: terrain is missing either a Map or CSN node" << std::endl;             
00120         return false;
00121     }
00122 
00123     // see whether this is a geocentric model:
00124     bool is_geocentric = _csn.valid() && _csn->getEllipsoidModel() != NULL;
00125 
00126     const SpatialReference* srs = _mapNode->getMap()->getProfile()->getSRS();
00127 
00128     // now build a matrix:
00129     if ( is_geocentric )
00130     {
00131         double lat_rad = osg::DegreesToRadians( lat_deg );
00132         double lon_rad = osg::DegreesToRadians( lon_deg );
00133 
00134         if ( _clamp )
00135         {
00136             osg::Vec3d c;
00137             if ( clampGeocentric( _csn.get(), lat_rad, lon_rad, c ) )
00138             {
00139                 srs->getEllipsoid()->computeLocalToWorldTransformFromXYZ( c.x(), c.y(), c.z(), out_result );
00140             }
00141         }
00142         else
00143         {
00144             srs->getEllipsoid()->computeLocalToWorldTransformFromLatLongHeight( lat_rad, lon_rad, height, out_result );
00145         }
00146     }
00147     else // projected or "flat geographic"
00148     {
00149         osg::Vec3d local(0, 0, height);
00150         
00151         // first convert the input coords to the map srs:
00152         srs->getGeographicSRS()->transform2D( lon_deg, lat_deg, srs, local.x(), local.y());
00153 
00154         if ( _clamp )
00155         {
00156             clampProjected( _csn.get(), local.x(), local.y(), local );
00157             local.z() += height;
00158         }
00159         out_result = osg::Matrixd::translate( local );
00160     }
00161 
00162     return true;
00163 }
00164 
00165 osg::Node*
00166 ObjectPlacer::placeNode( osg::Node* node, double lat_deg, double lon_deg, double height ) const
00167 {
00168     osg::Node* result = NULL;
00169 
00170     osg::Matrixd matrix;
00171     if ( createPlacerMatrix( lat_deg, lon_deg, height, matrix ) )
00172     {
00173         osg::MatrixTransform* mt = new osg::MatrixTransform( matrix );
00174         mt->addChild( node );
00175         result = mt;
00176     }
00177 
00178     return result;
00179 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines