/* -*-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_TILE_KEY_H #define OSGEARTH_TILE_KEY_H 1 #include #include #include #include #include namespace osgEarth { /** * Uniquely identifies a single tile on the map, relative to a Profile. * Profiles have an origin of 0,0 at the top left. */ class OSGEARTH_EXPORT TileKey { public: /** * Constructs an invalid TileKey. */ TileKey() : _lod(0), _x(0), _y(0), _hash(0) { } /** * Creates a new TileKey with the given tile xy at the specified level of detail * * @param lod * The level of detail (subdivision recursion level) of the tile * @param tile_x * The x index of the tile * @param tile_y * The y index of the tile * @param profile * The profile for the tile */ TileKey( unsigned int lod, unsigned int tile_x, unsigned int tile_y, const Profile* profile ); /** Copy constructor. */ TileKey( const TileKey& rhs ); /** dtor */ virtual ~TileKey() { } /** Compare two tilekeys for equality. */ inline bool operator == (const TileKey& rhs) const { return valid() == rhs.valid() && _lod == rhs._lod && _x == rhs._x && _y == rhs._y && (_profile.valid() ? _profile->isHorizEquivalentTo(rhs._profile.get()) : true); } /** Compare two tilekeys for inequality */ inline bool operator != (const TileKey& rhs) const { return valid() != rhs.valid() || _lod != rhs._lod || _x != rhs._x || _y != rhs._y || (_profile.valid() ? !_profile->isEquivalentTo(rhs._profile.get()) : false); } /** Sorts tilekeys, ignoring profiles */ inline bool operator < (const TileKey& rhs) const { if (!rhs.valid()) return false; if (!valid()) return true; if (_lod < rhs._lod) return true; if (_lod > rhs._lod) return false; if (_x < rhs._x) return true; if (_x > rhs._x) return false; if (_y < rhs._y) return true; if (_y > rhs._y) return false; return _profile->getHorizSignature() < rhs._profile->getHorizSignature(); } /** * Canonical invalid tile key. */ static TileKey INVALID; /** * Gets the string representation of the key, formatted like: * "lod_x_y" */ const std::string str() const; /** * Gets the profile within which this key is interpreted. */ const osgEarth::Profile* getProfile() const; /** * Whether this is a valid key. */ bool valid() const { return _profile.valid(); } /** * Get the quadrant relative to this key's parent. */ unsigned getQuadrant() const; /** * Gets a reference to the child key of this key in the specified * quadrant (0, 1, 2, or 3). */ TileKey createChildKey( unsigned int quadrant ) const; /** * Creates and returns a key that represents the parent tile of this key. */ TileKey createParentKey() const; //! Convert this key to its parent //! @return true upon success, false if invalid bool makeParent(); /** * Creates and returns a key that represents an ancestor tile corresponding to * the specified LOD. */ TileKey createAncestorKey( int ancestorLod ) const; /** * Creates a key that represents this tile's neighbor at the same LOD. Wraps * around in X and Y automatically. For example, xoffset=-1 yoffset=1 will * give you the key for the tile SW of this tile. */ TileKey createNeighborKey( int xoffset, int yoffset ) const; /** * Gets the level of detail of the tile represented by this key. */ unsigned getLevelOfDetail() const { return _lod; } unsigned getLOD() const { return _lod; } /** * Gets the geospatial extents of the tile represented by this key. */ const GeoExtent getExtent() const; /** * Gets the extents of this key's tile, in pixels */ void getPixelExtents( unsigned int& out_minx, unsigned int& out_miny, unsigned int& out_maxx, unsigned int& out_maxy, const unsigned int& tile_size) const; /** * Gets the X and Y indexes of this tile at its level of detail. */ void getTileXY( unsigned int& out_tile_x, unsigned int& out_tile_y) const; unsigned int getTileX() const { return _x; } unsigned int getTileY() const { return _y; } /** * Maps this tile key to another tile key in order to account in * a resolution difference. For example: we are requesting data for * a TileKey at LOD 4, at a tile size of 32. The source data's tile * size if 256. That means the source data at LOD 1 will contain the * data necessary to build the tile. * * usage: TileKey tk = mapResolution(31, 256); * * We want a 31x31 tile. The source data is 256x256. This will return * a TileKey that access the appropriate source data, which we will then * need to crop to populate our tile. * * You can set "minimumLOD" if you don't want a key below a certain LOD. */ TileKey mapResolution( unsigned targetSize, unsigned sourceDataSize, unsigned minimumLOD =0) const; //! X and Y resolution (in profile units) for the given tile size std::pair getResolution( unsigned tileSize) const; //! Convenience method to match this key. bool is(unsigned lod, unsigned x, unsigned y) const { return _lod == lod && _x == x && _y == y; } protected: unsigned int _lod; unsigned int _x; unsigned int _y; osg::ref_ptr _profile; size_t _hash; void rehash(); public: size_t hash() const { return _hash; } }; } namespace std { // std::hash specialization for TileKey template<> struct hash { inline size_t operator()(const osgEarth::TileKey& value) const { return value.hash(); } }; } #endif // OSGEARTH_TILE_KEY_H