DYT/Tool/OpenSceneGraph-3.6.5/include/osgEarth/Coverage

423 lines
12 KiB
Plaintext
Raw Normal View History

2024-12-24 23:49:36 +00:00
/* -*-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 <http://www.gnu.org/licenses/>
*/
#ifndef OSGEARTH_COVERAGE_H
#define OSGEARTH_COVERAGE_H 1
#include <osgEarth/GeoData>
#include <osgEarth/ImageUtils>
#include <unordered_map>
#include <vector>
#include <map>
namespace osgEarth
{
/**
* Grid of templated values.
*
* The parameter <T> must follow implement the interface:
*
* // default constructor, which will result in valid()==false
* T() { }
*
* // return true for valid data, false for NO DATA.
* bool valid() const { return ...has a valid data value...; }
*
* // "less than" operator for sorting
* bool operator < (const T& rhs) const
*
* Note: This is a sparse grid for memory conservation purposes,
* but includes some optimizations for fast mass-insertion.
*/
template<typename T>
class Coverage
{
public:
using Ptr = std::shared_ptr<Coverage<T>>;
// maps T to index for duplicate values (std::map so that T doesn't need std::hash)
using LUT = std::map<T, int>;
// reverse lookup for reading; maps index to value
using RLUT = std::unordered_map<int, T>;
// max out at 255 different indices. Make it a short if you want more.
// TODO: consider templatizing this with something like
// <typename T, typename Index=unsigned char>
using Index = unsigned char;
// raster of indices
using Grid = std::vector<Index>;
using pixel_type = T;
//! create a new coverage (must be a shared_ptr)
static Ptr create()
{
return Ptr(new Coverage<T>());
}
//! copy constructor
Coverage(const Coverage<T>& rhs) :
_width(rhs._width),
_height(rhs._height),
_valid_count(rhs._valid_count),
_pixels(rhs._pixels),
_lut(rhs._lut),
_rlut(rhs._rlut)
{
//nop
}
//! move constructor
Coverage(Coverage<T>&& rhs) :
_width(rhs._width),
_height(rhs._height),
_valid_count(rhs._valid_count),
_pixels(std::move(rhs._pixels)),
_lut(std::move(rhs._lut)),
_rlut(std::move(rhs._rlut))
{
//nop
}
//! allocate width*height pixels
void allocate(unsigned w, unsigned h)
{
_width = w, _height = h;
_lut.clear();
_rlut.clear();
_pixels.assign(w*h, 0);
_valid_count = 0;
}
//! raster width
unsigned s() const
{
return _width;
}
//! raster height
unsigned t() const
{
return _height;
}
//! Number of pixels containing "NO DATA" value
unsigned nodataCount() const
{
return (_width*_height) - _valid_count;
}
//! Is this coverage empty?
bool empty() const
{
return _valid_count == 0;
}
//! Write a value to a pixel.
//! Optional optimization: This method returns a value "k". If you
//! are writing the same value again on the next call, pass "k" back
//! in as your final argument, and this will dramatically speed up
//! performance. This helps a lot when writing the same value many
//! times in a row.
int write(const T& value, unsigned s, unsigned t, int k = -1)
{
int ptr = t * _width + s;
if (value.valid())
{
if (_pixels[ptr] > 0)
--_valid_count;
if (k < 0)
{
typename LUT::iterator i = _lut.find(value);
if (i != _lut.end())
{
k = i->second;
}
else
{
k = _lut.size() + 1; // skip 0, 0=>nodata
_lut[value] = k;
_rlut[k] = value;
}
}
++_valid_count;
}
else
{
k = 0;
if (_pixels[ptr] > 0)
--_valid_count;
}
_pixels[ptr] = k;
return k;
}
bool read(T& output, unsigned s, unsigned t) const
{
const T* value = read(s, t);
if (value) output = *value;
return value != nullptr;
}
bool read(T& output, double u, double v) const
{
const T* value = read(u, v);
if (value) output = *value;
return value != nullptr;
}
const T* read(double u, double v) const
{
unsigned s, t;
ImageUtils::nnUVtoST(u, v, s, t, _width, _height);
return read(s, t);
}
const T* read(unsigned s, unsigned t) const
{
OE_SOFT_ASSERT_AND_RETURN(s < _width && t < _height, nullptr);
int ptr = t * _width + s;
Index i = _pixels[ptr];
if (i > 0)
{
return &_rlut[i];
}
return nullptr;
}
bool hasDataAt(unsigned s, unsigned t) const
{
OE_SOFT_ASSERT_AND_RETURN(s < _width && t < _height, false);
int ptr = t * _width + s;
return _pixels[ptr] > 0;
}
Config getConfig() const
{
Config root("coverage");
root.set("width", _width);
root.set("height", _height);
Config values("values");
for (auto& entry : _lut)
{
Config value_conf = entry.first.getConfig();
value_conf.set("__coverage_index", entry.second);
values.add(value_conf);
}
root.add(values);
std::ostringstream pixels_string;
int count = 0;
int last_value = -1;
for(auto& pixel : _pixels)
{
if (last_value >= 0 && pixel != last_value) {
pixels_string << (int)count << ' ' << (int)last_value << ' ';
count = 0;
}
last_value = pixel;
++count;
}
if (count > 0) {
pixels_string << (int)count << ' ' << (int)last_value;
}
root.add(Config("pixels", pixels_string.str()));
return root;
}
void setConfig(const Config& root)
{
unsigned w = 256, h = 256;
root.get("width", w);
root.get("height", h);
allocate(w, h);
Config values = root.child("values");
for (auto& value_conf : values.children())
{
T value(value_conf);
int index;
value_conf.get("__coverage_index", index);
_lut[value] = index;
_rlut[index] = value;
}
std::string pixels_string = root.value("pixels");
std::istringstream pixels_stream(pixels_string);
int count, pixel;
int ptr = 0;
while (!pixels_stream.eof() && ptr < (int)(w*h))
{
pixels_stream >> count >> pixel;
for (int i = 0; i < count; ++i) {
_pixels[ptr++] = pixel;
if (pixel > 0)
++_valid_count;
}
}
}
private:
Coverage()
{
allocate(0, 0);
}
private:
unsigned _width, _height;
unsigned _valid_count;
Grid _pixels;
LUT _lut;
mutable RLUT _rlut;
};
template<typename T>
class GeoCoverage
{
public:
using pixel_type = T;
//! Construct a GeoCoverage
//! @param coverage Coverage to include in the geocoverage
//! @param extent geospatial extent of the coverage data
GeoCoverage(typename Coverage<T>::Ptr coverage, const GeoExtent& extent)
: _coverage(coverage), _extent(extent), _valid(true)
{
if (coverage == nullptr)
_valid = false;
}
GeoCoverage()
: _valid(false)
{
//nop
}
inline bool valid() const {
return _valid;
}
inline unsigned s() const {
return _coverage ? _coverage->s() : 0u;
}
inline unsigned t() const {
return _coverage ? _coverage->t() : 0u;
}
inline unsigned nodataCount() const {
return _coverage ? _coverage->nodataCount() : 0u;
}
inline unsigned empty() const {
return _coverage ? _coverage->empty() : true;
}
void write(const T& value, unsigned s, unsigned t)
{
OE_SOFT_ASSERT_AND_RETURN(_coverage != nullptr, void());
_coverage->write(value, s, t);
}
bool read(T& value, unsigned s, unsigned t) const
{
OE_SOFT_ASSERT_AND_RETURN(_coverage != nullptr, false);
return _coverage->read(value, s, t);
}
bool read(T& value, double u, double v) const
{
OE_SOFT_ASSERT_AND_RETURN(_coverage != nullptr, false);
return _coverage->read(value, u, v);
}
const T* read(unsigned s, unsigned t) const
{
OE_SOFT_ASSERT_AND_RETURN(_coverage != nullptr, nullptr);
return _coverage->read(s, t);
}
const T* read(double u, double v) const
{
OE_SOFT_ASSERT_AND_RETURN(_coverage != nullptr, nullptr);
return _coverage->read(u, v);
}
bool readAtCoords(T& value, double x, double y) const
{
if (_extent.contains(x, y))
{
unsigned xs = (unsigned)((double)(s() - 1) * (x - _extent.xMin()) / _extent.width());
unsigned yt = (unsigned)((double)(t() - 1) * (y - _extent.yMin()) / _extent.height());
if (xs >= 0 && xs < s() && yt >= 0 && yt < t())
{
read(value, xs, yt);
return true;
}
}
return false;
}
const T* readAtCoords(double x, double y) const
{
if (_extent.contains(x, y))
{
unsigned xs = (unsigned)((double)(s() - 1) * (x - _extent.xMin()) / _extent.width());
unsigned yt = (unsigned)((double)(t() - 1) * (y - _extent.yMin()) / _extent.height());
if (xs >= 0 && xs < s() && yt >= 0 && yt < t())
{
return read(xs, yt);
}
}
return nullptr;
}
const GeoExtent& getExtent() const
{
return _extent;
}
Config getConfig() const
{
Config root("geocoverage");
root.set("extent", _extent.getConfig());
root.add(_coverage->getConfig());
return root;
}
void setConfig(const Config& in)
{
_extent.fromConfig(in.child("extent"));
_coverage->setConfig(in.child("coverage"));
}
private:
GeoExtent _extent;
bool _valid;
typename Coverage<T>::Ptr _coverage;
};
}
#endif // OSGEARTH_COVERAGE_H