/* -*-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