/* -*-c++-*- */ /* osgEarth - Geospatial SDK for OpenSceneGraph * Copyright 2020 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_TERRAIN_H #define OSGEARTH_TERRAIN_H 1 #include #include #include #include #include namespace osgEarth { class Terrain; class TerrainTile; class SpatialReference; /** * This object is passed to terrain callbacks to provide context information * and a feedback interface to terrain callback consumers. */ class TerrainCallbackContext { public: const Terrain* getTerrain() const { return _terrain; } /** Indicate that the callback should be removed immediately */ void remove() { _remove = true; } /** whether the user called remove(). */ bool markedForRemoval() const { return _remove; } public: TerrainCallbackContext(Terrain* terrain) : _remove(false), _terrain(terrain) { } /** dtor */ virtual ~TerrainCallbackContext() { } protected: bool _remove; Terrain* _terrain; friend class Terrain; }; /** * Callback that you can register with the Terrain in order to receive * update messaged about the terrain scene graph. */ class TerrainCallback : public osg::Referenced { public: /** * A tile was added to the terrain graph. * @param key * Tile key of the new tile, including the geographic extents * @param graph * Scene graph that can be used to intersect the tile (though it * may include more than just the new tile) * @param context * Contextual information about the callback */ virtual void onTileUpdate( const TileKey& key, osg::Node* graph, TerrainCallbackContext& context) { // back compat only onTileAdded(key, graph, context); } /** dtor */ virtual ~TerrainCallback() { } public: // deprecated - exists for backwards compatibilty only virtual void onTileAdded( const TileKey& key, osg::Node* graph, TerrainCallbackContext& context) { } }; /** * Convenience adapter for hooking a callback into a class. The * class must be derived from osg::Referenced. When the class * destructs, the callback will automatically remove itself from * the Terrain object. */ template class TerrainCallbackAdapter : public TerrainCallback { public: TerrainCallbackAdapter(T* t) : _t(t) { } void onTileUpdate(const TileKey& key, osg::Node* tile, TerrainCallbackContext& context) { osg::ref_ptr t; if (_t.lock(t)) t->onTileUpdate(key, tile, context); else context.remove(); } protected: virtual ~TerrainCallbackAdapter() { } osg::observer_ptr _t; }; /** * Interface for an object that can resolve the terrain elevation * at a given map location. */ class /*interface-only*/ TerrainResolver { public: virtual bool getHeight( const SpatialReference* srs, double x, double y, double* out_heightAboveMSL, double* out_heightAboveEllipsoid =0L) const =0; virtual bool getHeight( osg::Node* patch, const SpatialReference* srs, double x, double y, double* out_heightAboveMSL, double* out_heightAboveEllipsoid =0L) const =0; /** dtor */ virtual ~TerrainResolver() { } }; // backwards compatibility typedef TerrainResolver TerrainHeightProvider; /** * Services for interacting with the live terrain graph. This differs from * the Map model; Map represents the parametric data backing the terrain, * while Terrain represents the actual geometry in memory. * * All returned map coordinate values are in the units conveyed in the * spatial reference at getSRS(). */ class OSGEARTH_EXPORT Terrain : public osg::Referenced, public TerrainResolver { public: /** * Gets the profile of the map with which this terrain is associated. */ const Profile* getProfile() const { return _profile.get(); } /** * Gets the spatial reference of the map with which this terrain is * associated. */ const SpatialReference* getSRS() const { return _profile->getSRS(); } /** * Returns the world coordinates under the mouse. * @param view * View in which to do the query * @param mx, my * Mouse coordinates * @param out_coords * Stores the world coordinates under the mouse (when returning true) */ bool getWorldCoordsUnderMouse( osg::View* view, float mx, float my, osg::Vec3d& out_world) const; //! Terrain Tile node under the mouse TerrainTile* getTerrainTileUnderMouse( osg::View* view, float mx, float my) const; public: // TerrainResolver interface /** * Intersects the terrain at the location x, y and returns the height data. * * @param srs * Spatial reference system of (x,y) coordinates * @param x, y * Coordinates at which to query the height * @param out_heightAboveMSL * The resulting relative height goes here. The height is relative to MSL * (mean sea level) as expressed by the map's vertical datum. * @param out_heightAboveEllipsoid * The resulting geodetic height goes here. The height is relative to the * geodetic ellipsoid expressed by the map's SRS. */ bool getHeight( const SpatialReference* srs, double x, double y, double* out_heightAboveMSL, double* out_heightAboveEllipsoid =0L) const; /** * Save as above, but specify a subgraph patch. */ bool getHeight( osg::Node* patch, const SpatialReference* srs, double x, double y, double* out_heightAboveMSL, double* out_heightAboveEllipsoid =0L) const; public: /** * Adds a terrain callback. * * @param callback * Terrain callback to add. This will get called whenever tile data changes in * the active terrain graph */ void addTerrainCallback(TerrainCallback* callback); /** * Removes a terrain callback. */ void removeTerrainCallback(TerrainCallback* callback ); public: /** * Accept a node visitor on the terrain's scene graph. */ void accept( osg::NodeVisitor& nv ); // access the raw terrain graph osg::Node* getGraph() const { return _graph.get(); } // queues the onTileUpdate callback (internal) void notifyTileUpdate( const TileKey& key, osg::Node* tile ); // queues the onTileRemoved callback (internal) void notifyTilesRemoved(const std::vector& keys); // internal void notifyMapElevationChanged(); /** dtor */ virtual ~Terrain() { } private: //! Construct the Terrain graph interface Terrain(osg::Node* graph, const Profile* profile); /** update traversal. */ void update(); friend class TerrainEngineNode; typedef std::list< osg::ref_ptr > CallbackList; CallbackList _callbacks; Threading::ReadWriteMutex _callbacksMutex; std::atomic_int _callbacksSize; // separate size tracker for MT size check w/o a lock osg::ref_ptr _profile; osg::observer_ptr _graph; osg::ref_ptr _updateQueue; void fireMapElevationChanged(); void fireTileUpdate( const TileKey& key, osg::Node* tile ); void fireTilesRemoved(const std::vector& keys); struct onTileUpdateOperation : public osg::Operation { osg::observer_ptr _terrain; TileKey _key; osg::observer_ptr _node; unsigned _count; onTileUpdateOperation(const TileKey& key, osg::Node* node, Terrain* terrain); void operator()(osg::Object*); int _delay; }; }; } #endif // OSGEARTH_COMPOSITING_H