/* -*-c++-*- */
/* osgEarth - Geospatial SDK for OpenSceneGraph
* Copyright 2008-2016 Pelican Mapping
* http://osgearth.org
*
* osgEarth is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see
*/
#ifndef OSGEARTH_ELEVATION_POOL_H
#define OSGEARTH_ELEVATION_POOL_H
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
namespace osgEarth
{
/**
* Stores pointers to elevation data wherever it might exist
* so we can quickly access it for queries.
*/
class OSGEARTH_EXPORT ElevationPool : public osg::Referenced
{
public:
using WeakPointer = osg::observer_ptr;
using Pointer = osg::ref_ptr;
using WeakLUT = std::unordered_map;
private:
struct OSGEARTH_EXPORT StrongLRU {
StrongLRU(unsigned maxSize=64u);
Mutexed> _lru;
unsigned _maxSize;
void push(Pointer& p);
void clear();
};
public:
//! User data that a client can use to speed up queries in
//! a local geographic area or sample a custom set of layers.
class OSGEARTH_EXPORT WorkingSet
{
public:
//! Construct a new local working set cache.
//! @param size Cache size
WorkingSet(unsigned size =32u);
//! Assign a specific set of elevation layer to use
//! for sampling. Usually this is unnecessary as the Pool
//! will synchronize with the map set by setMap, but you
//! may want to use a custom Pool with a specific subset
//! of query layers.
//! @param layers Set of elevation layers to use
void setElevationLayers(const ElevationLayerVector& layers) {
_elevationLayers = layers;
}
//! Invalidate the cache.
void clear();
private:
StrongLRU _lru;
ElevationLayerVector _elevationLayers;
friend class ElevationPool;
};
/**
* Object for doing lots of queries in a localized area.
* Call prepareEnvelope to initialize one.
*/
class OSGEARTH_EXPORT Envelope
{
public:
//! For each point in an array of points, sample the elevation and store
//! the result in the Z coordinate. Input points must be in the map's SRS.
//! @param begin Iterator pointing to beginning of point array
//! @param end Iterator pointing to end of point array
//! @param progress Optional progress callback (can be nullptr)
//! @param failValue Value to store in Z if the sampling fails
//! @return Number of valid elevations sampled, or -1 if there was an error
int sampleMapCoords(
std::vector::iterator begin,
std::vector::iterator end,
ProgressCallback* progress,
float failValue = NO_DATA_VALUE);
public:
// internal
using QuickCache = vector_map<
Internal::RevElevationKey,
osg::ref_ptr>;
// internal
struct QuickSampleVars {
double sizeS, sizeT;
double s, t;
double s0, s1, smix;
double t0, t1, tmix;
osg::Vec4f UL, UR, LL, LR, TOP, BOT;
};
private:
Internal::RevElevationKey _key;
QuickCache _cache;
QuickSampleVars _vars;
double _pw, _ph, _pxmin, _pymin;
osg::ref_ptr _raster;
int _lod;
unsigned _tw, _th;
WorkingSet* _ws;
WorkingSet _default_ws;
osg::ref_ptr _map;
osg::ref_ptr _profile;
ElevationPool* _pool;
friend class ElevationPool;
};
public:
//! Construct the elevation pool
ElevationPool();
//! Assign map to the pool. Required.
void setMap(const Map* map);
//! Sample the map's elevation at a point.
//! @param p Point at which to sample
//! @param ws Optional working set (can be NULL)
//! @param progress Optional progress callback
ElevationSample getSample(
const GeoPoint& p,
WorkingSet* ws,
ProgressCallback* progress =nullptr);
//! Sample the map's elevation at a point.
//! @param p Point at which to sample
//! @param resolution Resolution at which to attempt to sample (in point srs)
//! @param ws Optional working set (can be NULL)
//! @param progress Optional progress callback
ElevationSample getSample(
const GeoPoint& p,
const Distance& resolution,
WorkingSet* ws,
ProgressCallback* progress =nullptr);
//! Extract a complete tile of elevation data
//! @param key TileKey or data to extact
//! @param acceptLowerRes Return a lower resolution tile if the requested one isn't available
//! @param out_elev Output elevation texture tile
//! @param ws Optional working set (can be nullptr)
//! @param progress Optional progress callback (can be nullptr)
//! @return true upon success, false upon failure
bool getTile(
const TileKey& key,
bool acceptLowerRes,
osg::ref_ptr& out_elev,
WorkingSet* ws,
ProgressCallback* progress);
//! For each point in an array of points, sample the elevation and store
//! the result in the Z coordinate. Input points must be in the map's SRS,
//! and the sampling resolution is taken from the W coordinate.
//! @param begin Iterator pointing to beginning of point array
//! @param end Iterator pointing to end of point array
//! @param ws Optional working set (local cache, can be nullptr)
//! @param progress Optional progress callback (can be nullptr)
//! @param failValue Value to store in Z if the sampling fails
//! @return Number of valid elevations sampled, or -1 if there was an error
int sampleMapCoords(
std::vector::iterator begin,
std::vector::iterator end,
WorkingSet* ws,
ProgressCallback* progress,
float failValue =NO_DATA_VALUE);
//! For each point in an array of points, sample the elevation and store
//! the result in the Z coordinate. Input points must be in the map's SRS.
//! @param begin Iterator pointing to beginning of point array
//! @param end Iterator pointing to end of point array
//! @param resolution Resolution at which to sample the points
//! @param ws Optional working set (local cache, can be nullptr)
//! @param progress Optional progress callback (can be nullptr)
//! @param failValue Value to store in Z if the sampling fails
//! @return Number of valid elevations sampled, or -1 if there was an error
int sampleMapCoords(
std::vector::iterator begin,
std::vector::iterator end,
const Distance& resolution,
WorkingSet* ws,
ProgressCallback* progress,
float failValue = NO_DATA_VALUE);
//! Creates an envelope for sampling lots of points in a localized region
//! @param out Created envelope (output)
//! @param refPoint Reference point near which you intend to sample points
//! @param resolution Resolution at which to intend to sample points
//! @param ws Optional working set (can be nullptr)
bool prepareEnvelope(
Envelope& out,
const GeoPoint& refPoint,
const Distance& resolution,
WorkingSet* ws =nullptr);
protected:
//! Destructor
virtual ~ElevationPool();
private:
bool needsRefresh();
// weak pointer to the map from whence this pool came
osg::observer_ptr _map;
// stores weak pointers to elevation textures wherever they may exist
// elsewhere in the system, including the local L2 LRU.
WeakLUT _globalLUT;
Threading::ReadWriteMutex _globalLUTMutex;
// LRU container that stores the last N strong references to accessed tiles.
// Not used directly - just used to hold ref_ptrs to things so they stay
// alive in the global LUT (see above).
StrongLRU _L2;
// internal: spatial index of data extents
void* _index;
// elevation tile size
unsigned _tileSize;
//WorkingSet* _L2;
size_t _elevationHash;
int _mapRevision;
Threading::ReadWriteMutex _mutex;
ElevationLayerVector _elevationLayers;
size_t getElevationHash(WorkingSet*) const;
void sync(const Map*, WorkingSet*);
void refresh(const Map*);
ElevationSample getSample(
const GeoPoint& p,
unsigned maxLOD,
const Map* map,
WorkingSet* ws,
ProgressCallback* progress);
//! Best LOD this a point, or -1 if no data in index
int getLOD(double x, double y) const;
osg::ref_ptr getOrCreateRaster(
const Internal::RevElevationKey& key,
const Map* map,
bool acceptLowerRes,
WorkingSet* ws,
ProgressCallback* progress);
bool findExistingRaster(
const Internal::RevElevationKey& key,
WorkingSet* ws,
osg::ref_ptr& result,
bool* fromWorkingSet,
bool* fromL2Cache,
bool* fromGlobalWeakLUT);
};
/**
* Utility to run elevation queries in the background.
*/
class OSGEARTH_EXPORT AsyncElevationSampler
{
public:
//! Construct a new sampler
//! @param map Map the sampler will use to sample elevation data
//! @param threads Number of threads the sampler should use
AsyncElevationSampler(
const Map* map,
unsigned threads =0u);
//! Destructor
virtual ~AsyncElevationSampler() { }
//! Sample elevation at a point at highest available resolution
//! @param p Point at which to sample terrain elevation
//! @return Future result of the sample
jobs::future getSample(
const GeoPoint& p);
//! Sample elevation at a point and a target resolution
//! @param p Point at which to sample terrain elevation
//! @param resolution Resolution at which to sample terrain
//! @return Future result of the sample
jobs::future getSample(
const GeoPoint& p,
const Distance& resolution);
protected:
osg::observer_ptr _map;
ElevationPool::WorkingSet _ws;
jobs::jobpool* _arena;
};
} // namespace
#endif // OSGEARTH_ELEVATION_POOL_H