/***************************************************************************************** * * * OpenSpace * * * * Copyright (c) 2015 * * * * Permission is hereby granted, free of charge, to any person obtaining a copy of this * * software and associated documentation files (the "Software"), to deal in the Software * * without restriction, including without limitation the rights to use, copy, modify, * * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * * permit persons to whom the Software is furnished to do so, subject to the following * * conditions: * * * * The above copyright notice and this permission notice shall be included in all copies * * or substantial portions of the Software. * * * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ #include #include #include #include namespace { const std::string _loggerCat = "Histogram"; } namespace openspace { Histogram::Histogram() : _minBin(0) , _maxBin(0) , _numBins(-1) , _data(nullptr) {} Histogram::Histogram(float minBin, float maxBin, int numBins) : _minBin(minBin) , _maxBin(maxBin) , _numBins(numBins) , _data(nullptr) { _data = new float[numBins]; for (int i = 0; i < numBins; ++i) { _data[i] = 0.0; } } Histogram::Histogram(float minBin, float maxBin, int numBins, float *data) : _minBin(minBin) , _maxBin(maxBin) , _numBins(numBins) , _data(data) {} Histogram::Histogram(Histogram&& other) { _minBin = other._minBin; _maxBin = other._maxBin; _numBins = other._numBins; _data = other._data; other._data = nullptr; } Histogram& Histogram::operator=(Histogram&& other) { _minBin = other._minBin; _maxBin = other._maxBin; _numBins = other._numBins; _data = other._data; other._data = nullptr; return *this; } Histogram::~Histogram() { if (_data) { delete[] _data; } } int Histogram::numBins() const { return _numBins; } float Histogram::minBin() const { return _minBin; } float Histogram::maxBin() const { return _maxBin; } bool Histogram::isValid() const { return _numBins != -1; } bool Histogram::add(float bin, float value) { if (bin < _minBin || bin > _maxBin) { // Out of range return false; } float normalizedBin = (bin - _minBin) / (_maxBin - _minBin); // [0.0, 1.0] int binIndex = floor(normalizedBin * _numBins); // [0, _numBins] if (binIndex == _numBins) binIndex--; // [0, _numBins[ _data[binIndex] += value; return true; } bool Histogram::add(const Histogram& histogram) { if (_minBin == histogram.minBin() && _maxBin == histogram.maxBin() && _numBins == histogram.numBins()) { const float* data = histogram.data(); for (int i = 0; i < _numBins; i++) { _data[i] += data[i]; } return true; } else { LERROR("Dimension mismatch"); return false; } } bool Histogram::addRectangle(float lowBin, float highBin, float value) { if (lowBin == highBin) return true; if (lowBin > highBin) { std::swap(lowBin, highBin); } if (lowBin < _minBin || highBin > _maxBin) { // Out of range return false; } float normalizedLowBin = (lowBin - _minBin) / (_maxBin - _minBin); float normalizedHighBin = (highBin - _minBin) / (_maxBin - _minBin); float lowBinIndex = normalizedLowBin * _numBins; float highBinIndex = normalizedHighBin * _numBins; int fillLow = floor(lowBinIndex); int fillHigh = ceil(highBinIndex); for (int i = fillLow; i < fillHigh; i++) { _data[i] += value; } if (lowBinIndex > fillLow) { float diff = lowBinIndex - fillLow; _data[fillLow] -= diff * value; } if (highBinIndex < fillHigh) { float diff = -highBinIndex + fillHigh; _data[fillHigh - 1] -= diff * value; } return true; } float Histogram::interpolate(float bin) const { float normalizedBin = (bin - _minBin) / (_maxBin - _minBin); float binIndex = normalizedBin * _numBins - 0.5; // Center float interpolator = binIndex - floor(binIndex); int binLow = floor(binIndex); int binHigh = ceil(binIndex); // Clamp bins if (binLow < 0) binLow = 0; if (binHigh >= _numBins) binHigh = _numBins - 1; return (1.0 - interpolator) * _data[binLow] + interpolator * _data[binHigh]; } float Histogram::sample(int binIndex) const { assert(binIndex >= 0 && binIndex < _numBins); return _data[binIndex]; } const float* Histogram::data() const { return _data; } std::vector> Histogram::getDecimated(int numBins) const { // Return a copy of _data decimated as in Ljung 2004 return std::vector>(); } void Histogram::normalize() { float sum = 0.0; for (int i = 0; i < _numBins; i++) { sum += _data[i]; } for (int i = 0; i < _numBins; i++) { _data[i] /= sum; } } void Histogram::print() const { std::cout << "number of bins: " << _numBins << std::endl << "range: " << _minBin << " - " << _maxBin << std::endl << std::endl; for (int i = 0; i < _numBins; i++) { float low = _minBin + float(i) / _numBins * (_maxBin - _minBin); float high = low + (_maxBin - _minBin) / float(_numBins); std::cout << "[" << low << ", " << high << "[" << std::endl << " " << _data[i] << std::endl; } } }