osgEarth 2.1.1
Public Types | Public Member Functions | Private Types | Private Member Functions | Private Attributes

osgEarth::ElevationQuery Class Reference

Collaboration diagram for osgEarth::ElevationQuery:

List of all members.

Public Types

enum  Technique { TECHNIQUE_GEOMETRIC, TECHNIQUE_PARAMETRIC }

Public Member Functions

 ElevationQuery (const Map *map)
 ElevationQuery (const MapFrame &mapFrame)
bool getElevation (const osg::Vec3d &point, const SpatialReference *pointSRS, double &out_elevation, double desiredResolution=0.0, double *out_actualResolution=0L)
bool getElevations (std::vector< osg::Vec3d > &points, const SpatialReference *pointsSRS, bool ignoreZ=true, double desiredResolution=0.0)
bool getElevations (const std::vector< osg::Vec3d > &points, const SpatialReference *pointsSRS, std::vector< double > &out_elevations, double desiredResolution=0.0)
void setTechnique (Technique technique)
Technique getTechnique () const
void setMaxTilesToCache (int value)
int getMaxTilesToCache () const
void setInterpolation (ElevationInterpolation interp)
ElevationInterpolation getElevationInterpolation () const
void setMaxLevelOverride (int maxLevelOverride)
int getMaxLevelOverride () const

Private Types

typedef LRUCache< TileKey,
osg::ref_ptr
< osgTerrain::TerrainTile > > 
TileCache

Private Member Functions

void postCTOR ()
void sync ()
bool getElevationImpl (const osg::Vec3d &point, const SpatialReference *pointSRS, double &out_elevation, double desiredResolution, double *out_actualResolution=0L)

Private Attributes

MapFrame _mapf
unsigned _maxCacheSize
int _tileSize
unsigned int _maxDataLevel
int _maxLevelOverride
Technique _technique
ElevationInterpolation _interpolation
TileCache _tileCache

Detailed Description

ElevationQuery (EQ) lets you query the elevation at any point on a map.

Rather than intersecting with a loaded scene graph, EQ uses the osgEarth engine to directly access the best terrain tile for elevation query. You give it the DEM resolution at which you want an elevation point, and it will access the necessary tile and sample it.

EQ supports two types of sampling:

PARAMTERIC - EQ will sample the actual heightfield directly. This method is the fastest since it does not require geometry intersection testing.

GEOMETRIC - EQ will create a temporary tesselated terrain tile and do an intersection test (using osgUtil::IntersectionVisitor). This method is slower but more visually correlated. (TODO: not really true anymore. This method will require a re-do in osgEarth 2.2 or 3.0)

NOTE: EQ does NOT take into account rendering properties like vertical scale or skirts. If you need a vertical scale, for example, simply scale the resulting elevation value.

Definition at line 50 of file ElevationQuery.


Member Typedef Documentation

typedef LRUCache< TileKey, osg::ref_ptr<osgTerrain::TerrainTile> > osgEarth::ElevationQuery::TileCache [private]

Definition at line 176 of file ElevationQuery.


Member Enumeration Documentation

Technique for elevation data sampling - see setTechnique

Enumerator:
TECHNIQUE_GEOMETRIC 

Intersect with triangulated geometry - using the highest resolution data available from the Map source layers

TECHNIQUE_PARAMETRIC 

Sample height from the parametric heightfield directly (bilinear)

Definition at line 54 of file ElevationQuery.


Constructor & Destructor Documentation

ElevationQuery::ElevationQuery ( const Map map)

Constructs a new elevation manager. If you are not using a MapNode, use this constructor to perform elevation queries against a Map. If you *do* have a MapNode, use the other CTOR that takes a MapNode.

Parameters:
mapMap against which to perform elevation queries.
techniqueTechnique to use for elevation data sampling.

Definition at line 13 of file ElevationQuery.cpp.

Here is the call graph for this function:

ElevationQuery::ElevationQuery ( const MapFrame mapFrame)

Definition at line 19 of file ElevationQuery.cpp.

                                                         :
_mapf( mapFrame )
{
    postCTOR();
}

Here is the call graph for this function:


Member Function Documentation

bool ElevationQuery::getElevation ( const osg::Vec3d &  point,
const SpatialReference pointSRS,
double &  out_elevation,
double  desiredResolution = 0.0,
double *  out_actualResolution = 0L 
)

Gets the terrain elevation at a point, given a terrain resolution.

Parameters:
pointMap coordinates for which to query elevation.
pointSRSSpatial reference of "point" and "desiredResolution" If this is NULL, assume that the input values are expressed in terms of the Map's SRS.
out_elevationStores the elevation result in this variable upon success.
desiredResolutionOptimal resolution of elevation data to use for the query (if available). Pass in 0 (zero) to use the best available resolution.
out_resolutionResolution of the resulting elevation value (if the method returns true).
Returns:
True if the query succeeded, false upon failure.

Definition at line 99 of file ElevationQuery.cpp.

{
    sync();
    return getElevationImpl( point, pointSRS, out_elevation, desiredResolution, out_actualResolution );
}

Here is the call graph for this function:

Here is the caller graph for this function:

bool ElevationQuery::getElevationImpl ( const osg::Vec3d &  point,
const SpatialReference pointSRS,
double &  out_elevation,
double  desiredResolution,
double *  out_actualResolution = 0L 
) [private]

Definition at line 147 of file ElevationQuery.cpp.

{
    if ( _maxDataLevel == 0 || _tileSize == 0 )
    {
        // this means there are no heightfields.
        out_elevation = 0.0;
        return true;
    }
   
    // this is the ideal LOD for the requested resolution:
    unsigned int idealLevel = desiredResolution > 0.0
        ? _mapf.getProfile()->getLevelOfDetailForHorizResolution( desiredResolution, _tileSize )
        : _maxDataLevel;        

    // based on the heightfields available, this is the best we can theorically do:
    unsigned int bestAvailLevel = osg::minimum( idealLevel, _maxDataLevel );
    if (_maxLevelOverride >= 0)
    {
        bestAvailLevel = osg::minimum(bestAvailLevel, (unsigned int)_maxLevelOverride);
    }
    
    // transform the input coords to map coords:
    osg::Vec3d mapPoint = point;
    if ( pointSRS && !pointSRS->isEquivalentTo( _mapf.getProfile()->getSRS() ) )
    {
        if ( !pointSRS->transform2D( point.x(), point.y(), _mapf.getProfile()->getSRS(), mapPoint.x(), mapPoint.y() ) )
        {
            OE_WARN << LC << "Fail: coord transform failed" << std::endl;
            return false;
        }
    }

    osg::ref_ptr<osg::HeightField> hf;
    osg::ref_ptr<osgTerrain::TerrainTile> tile;

    // get the tilekey corresponding to the tile we need:
    TileKey key = _mapf.getProfile()->createTileKey( mapPoint.x(), mapPoint.y(), bestAvailLevel );
    if ( !key.valid() )
    {
        OE_WARN << LC << "Fail: coords fall outside map" << std::endl;
        return false;
    }

    // Check the tile cache. Note that the TileSource already likely has a MemCache
    // attached to it. We employ a secondary cache here for a couple reasons. One, this
    // cache will store not only the heightfield, but also the tesselated tile in the event
    // that we're using GEOMETRIC mode. Second, since the call the getHeightField can 
    // fallback on a lower resolution, this cache will hold the final resolution heightfield
    // instead of trying to fetch the higher resolution one each tiem.

    TileCache::Record record = _tileCache.get( key );
    if ( record.valid() )
        tile = record.value().get();
         
    // if we found it, make sure it has a heightfield in it:
    if ( tile.valid() )
    {
        osgTerrain::HeightFieldLayer* layer = dynamic_cast<osgTerrain::HeightFieldLayer*>(tile->getElevationLayer());
        if ( layer )
            hf = layer->getHeightField();

        if ( !hf.valid() )
            tile = 0L;
    }

    // if we didn't find it (or it didn't have heightfield data), build it.
    if ( !tile.valid() )
    {
        // generate the heightfield corresponding to the tile key, automatically falling back
        // on lower resolution if necessary:
        _mapf.getHeightField( key, true, hf, 0L, _interpolation );

        // bail out if we could not make a heightfield a all.
        if ( !hf.valid() )
        {
            OE_WARN << LC << "Unable to create heightfield for key " << key.str() << std::endl;
            return false;
        }

        // All this stuff is requires for GEOMETRIC mode. An optimization would be to
        // defer this so that PARAMETRIC mode doesn't waste time
        GeoLocator* locator = GeoLocator::createForKey( key, _mapf.getMapInfo() );

        tile = new osgTerrain::TerrainTile();

        osgTerrain::HeightFieldLayer* layer = new osgTerrain::HeightFieldLayer( hf.get() );
        layer->setLocator( locator );

        tile->setElevationLayer( layer );
        tile->setRequiresNormals( false );
        tile->setTerrainTechnique( new osgTerrain::GeometryTechnique );

        // store it in the local tile cache.
        _tileCache.insert( key, tile.get() );
    }

    OE_DEBUG << LC << "LRU Cache, hit ratio = " << _tileCache.getStats()._hitRatio << std::endl;

    // see what the actual resolution of the heightfield is.
    if ( out_actualResolution )
        *out_actualResolution = (double)hf->getXInterval();

    // finally it's time to get a height value:
    if ( _technique == TECHNIQUE_PARAMETRIC )
    {
        const GeoExtent& extent = key.getExtent();
        double xInterval = extent.width()  / (double)(hf->getNumColumns()-1);
        double yInterval = extent.height() / (double)(hf->getNumRows()-1);
        out_elevation = (double) HeightFieldUtils::getHeightAtLocation( 
            hf.get(), mapPoint.x(), mapPoint.y(), extent.xMin(), extent.yMin(), xInterval, yInterval );
        return true;
    }
    else // ( _technique == TECHNIQUE_GEOMETRIC )
    {
        osg::Vec3d start, end, zero;

        if ( _mapf.getMapInfo().isGeocentric() )
        {
            const SpatialReference* mapSRS = _mapf.getProfile()->getSRS();

            mapSRS->transformToECEF( osg::Vec3d(mapPoint.y(), mapPoint.x(),  50000.0), start );
            mapSRS->transformToECEF( osg::Vec3d(mapPoint.y(), mapPoint.x(), -50000.0), end );
            mapSRS->transformToECEF( osg::Vec3d(mapPoint.y(), mapPoint.x(),      0.0), zero );
        }
        else // PROJECTED
        {
            start.set( mapPoint.x(), mapPoint.y(),  50000.0 );
            end.set  ( mapPoint.x(), mapPoint.y(), -50000.0 );
            zero.set ( mapPoint.x(), mapPoint.y(),      0.0 );
        }

        osgUtil::LineSegmentIntersector* i = new osgUtil::LineSegmentIntersector( start, end );
        osgUtil::IntersectionVisitor iv;
        iv.setIntersector( i );

        tile->accept( iv );

        osgUtil::LineSegmentIntersector::Intersections& results = i->getIntersections();
        if ( !results.empty() )
        {
            const osgUtil::LineSegmentIntersector::Intersection& result = *results.begin();
            osg::Vec3d isectPoint = result.getWorldIntersectPoint();
            out_elevation = (isectPoint-end).length2() > (zero-end).length2()
                ? (isectPoint-zero).length()
                : -(isectPoint-zero).length();
            return true;            
        }

        OE_DEBUG << LC << "No intersection" << std::endl;
        return false;
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

ElevationInterpolation ElevationQuery::getElevationInterpolation ( ) const

Gets the elevation interpolation to use when sampling data

Definition at line 93 of file ElevationQuery.cpp.

{
    return _interpolation;
}
bool ElevationQuery::getElevations ( std::vector< osg::Vec3d > &  points,
const SpatialReference pointsSRS,
bool  ignoreZ = true,
double  desiredResolution = 0.0 
)

Gets elevations for a whole array of points, storing the result in the "z" element. If "ignoreZ" is false, the new Z value will be offset by the original Z value.

Definition at line 110 of file ElevationQuery.cpp.

{
    sync();
    for( osg::Vec3dArray::iterator i = points.begin(); i != points.end(); ++i )
    {
        double elevation;
        double z = (*i).z();
        if ( getElevationImpl( *i, pointsSRS, elevation, desiredResolution ) )
        {
            (*i).z() = ignoreZ ? elevation : elevation + z;
        }
    }
    return true;
}

Here is the call graph for this function:

Here is the caller graph for this function:

bool ElevationQuery::getElevations ( const std::vector< osg::Vec3d > &  points,
const SpatialReference pointsSRS,
std::vector< double > &  out_elevations,
double  desiredResolution = 0.0 
)

Gets elevations for a whole array of points, storing the results in the "out_elevations" vector.

Definition at line 129 of file ElevationQuery.cpp.

{
    sync();
    for( osg::Vec3dArray::const_iterator i = points.begin(); i != points.end(); ++i )
    {
        double elevation;
        if ( getElevationImpl( *i, pointsSRS, elevation, desiredResolution ) )
        {
            out_elevations.push_back( elevation );
        }
    }
    return true;
}

Here is the call graph for this function:

int osgEarth::ElevationQuery::getMaxLevelOverride ( ) const

Gets the maximum level override for elevation queries.

int ElevationQuery::getMaxTilesToCache ( ) const

Gets the maximum cache size for elevation tiles.

Definition at line 81 of file ElevationQuery.cpp.

{
    return _tileCache.getMaxSize();
}

Here is the call graph for this function:

ElevationQuery::Technique ElevationQuery::getTechnique ( ) const

Gets the technique to use for height determination. See the Technique enum in this class.

Definition at line 63 of file ElevationQuery.cpp.

{
    return _technique;
}
void ElevationQuery::postCTOR ( ) [private]

Definition at line 26 of file ElevationQuery.cpp.

{
    _tileSize         = 0;
    _maxDataLevel     = 0;
    _technique        = TECHNIQUE_PARAMETRIC;
    _interpolation    = INTERP_BILINEAR;
    _maxLevelOverride = -1;

    // Limit the size of the cache we'll use to cache heightfields. This is an
    // LRU cache.
    _tileCache.setMaxSize( 50 );
}

Here is the call graph for this function:

Here is the caller graph for this function:

void ElevationQuery::setInterpolation ( ElevationInterpolation  interp)

Sets the elevation interpolation to use when sampling data

Definition at line 87 of file ElevationQuery.cpp.

{
    _interpolation = interp;
}
void osgEarth::ElevationQuery::setMaxLevelOverride ( int  maxLevelOverride)

Sets the maximum level override for elevation queries. A value of -1 turns off the override.

void ElevationQuery::setMaxTilesToCache ( int  value)

Sets the maximum cache size for elevation tiles.

Definition at line 75 of file ElevationQuery.cpp.

{
    _tileCache.setMaxSize( value );
}

Here is the call graph for this function:

void ElevationQuery::setTechnique ( ElevationQuery::Technique  technique)

Sets the technique to use for height determination. See the Technique enum in this class. The default is TECHNIQUE_PARAMETRIC.

Definition at line 69 of file ElevationQuery.cpp.

{
    _technique = technique;
}
void ElevationQuery::sync ( ) [private]

Definition at line 40 of file ElevationQuery.cpp.

{
    if ( _mapf.sync() || _tileSize == 0 || _maxDataLevel == 0 )
    {
        _tileSize = 0;
        _maxDataLevel = 0;

        for( ElevationLayerVector::const_iterator i = _mapf.elevationLayers().begin(); i != _mapf.elevationLayers().end(); ++i )
        {
            // we need the maximum tile size
            int layerTileSize = i->get()->getTileSize();
            if ( layerTileSize > _tileSize )
                _tileSize = layerTileSize;

            // we also need the maximum available data level.
            unsigned int layerMaxDataLevel = i->get()->getMaxDataLevel();
            if ( layerMaxDataLevel > _maxDataLevel )
                _maxDataLevel = layerMaxDataLevel;
        }
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:


Member Data Documentation

ElevationInterpolation osgEarth::ElevationQuery::_interpolation [private]

Definition at line 174 of file ElevationQuery.

Definition at line 168 of file ElevationQuery.

Definition at line 169 of file ElevationQuery.

Definition at line 171 of file ElevationQuery.

Definition at line 172 of file ElevationQuery.

Definition at line 173 of file ElevationQuery.

Definition at line 177 of file ElevationQuery.

Definition at line 170 of file ElevationQuery.


The documentation for this class was generated from the following files:
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines