osgEarth 2.1.1
|
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 |
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.
typedef LRUCache< TileKey, osg::ref_ptr<osgTerrain::TerrainTile> > osgEarth::ElevationQuery::TileCache [private] |
Definition at line 176 of file ElevationQuery.
Technique for elevation data sampling - see setTechnique
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.
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.
map | Map against which to perform elevation queries. |
technique | Technique to use for elevation data sampling. |
Definition at line 13 of file ElevationQuery.cpp.
: _mapf( map, Map::ELEVATION_LAYERS ) { postCTOR(); }
ElevationQuery::ElevationQuery | ( | const MapFrame & | mapFrame | ) |
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.
point | Map coordinates for which to query elevation. |
pointSRS | Spatial reference of "point" and "desiredResolution" If this is NULL, assume that the input values are expressed in terms of the Map's SRS. |
out_elevation | Stores the elevation result in this variable upon success. |
desiredResolution | Optimal resolution of elevation data to use for the query (if available). Pass in 0 (zero) to use the best available resolution. |
out_resolution | Resolution of the resulting elevation value (if the method returns true). |
Definition at line 99 of file ElevationQuery.cpp.
{ sync(); return getElevationImpl( point, pointSRS, out_elevation, desiredResolution, out_actualResolution ); }
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; } }
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; }
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; }
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(); }
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 ); }
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 ); }
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; } } }
ElevationInterpolation osgEarth::ElevationQuery::_interpolation [private] |
Definition at line 174 of file ElevationQuery.
MapFrame osgEarth::ElevationQuery::_mapf [private] |
Definition at line 168 of file ElevationQuery.
unsigned osgEarth::ElevationQuery::_maxCacheSize [private] |
Definition at line 169 of file ElevationQuery.
unsigned int osgEarth::ElevationQuery::_maxDataLevel [private] |
Definition at line 171 of file ElevationQuery.
int osgEarth::ElevationQuery::_maxLevelOverride [private] |
Definition at line 172 of file ElevationQuery.
Definition at line 173 of file ElevationQuery.
Definition at line 177 of file ElevationQuery.
int osgEarth::ElevationQuery::_tileSize [private] |
Definition at line 170 of file ElevationQuery.