#pragma once
#ifndef TSPECTRUM_INCLUDED
#define TSPECTRUM_INCLUDED
#include "tpixelutils.h"
#include "tutil.h"
#undef DVAPI
#undef DVVAR
#ifdef TCOLOR_EXPORTS
#define DVAPI DV_EXPORT_API
#define DVVAR DV_EXPORT_VAR
#else
#define DVAPI DV_IMPORT_API
#define DVVAR DV_IMPORT_VAR
#endif
#ifdef _MSC_VER
#pragma warning(disable : 4251)
#endif
//===================================================================
template <class T>
class DVAPI TSpectrumT {
public:
typedef std::pair<double, T> ColorKey;
typedef ColorKey Key;
private:
typedef std::vector<ColorKey> KeyTable;
KeyTable m_keys, m_sortedKeys;
typedef std::pair<T, T> Pair; // premultiplied/not premultiplied
std::vector<Pair> m_samples;
inline T getActualValue(double s) {
assert(!m_sortedKeys.empty());
typename std::vector<ColorKey>::const_iterator b;
b = std::lower_bound(m_sortedKeys.begin(), m_sortedKeys.end(),
ColorKey(s, T()),
[](const ColorKey &a, const ColorKey &b) {
return a.first < b.first;
}); // compare only key positions
if (b == m_sortedKeys.end())
return m_sortedKeys.rbegin()->second;
else if (b == m_sortedKeys.begin() || areAlmostEqual(b->first, s))
return b->second;
else {
typename KeyTable::const_iterator a = b;
a--;
assert(a->first < s && s <= b->first);
double f = (s - a->first) / (b->first - a->first);
return blend(a->second, b->second, f);
}
}
void update() {
assert(!m_keys.empty());
m_sortedKeys = m_keys;
std::sort(m_sortedKeys.begin(), m_sortedKeys.end());
if (m_samples.empty()) m_samples.resize(100);
int n = m_samples.size();
for (int i = 0; i < n; i++) {
T v = getActualValue((double)i / (double)(n - 1));
m_samples[i].second = v;
m_samples[i].first = premultiply(v);
}
}
public:
TSpectrumT() : m_keys(), m_sortedKeys(), m_samples() {}
TSpectrumT(const TSpectrumT<T> &s)
: m_keys(s.m_keys)
, m_sortedKeys(s.m_sortedKeys)
, m_samples(s.m_samples) {}
TSpectrumT(int keyCount, ColorKey keys[], int sampleCount = 100)
: m_keys(keys, keys + keyCount) {
m_samples.resize(sampleCount);
update();
}
/*SpectrumT(std::map<double, T> &keys, int sampleCount=100)
{
m_keys = keys;
updateTable(sampleCount);
}
*/
TSpectrumT(const T &a, const T &b, int sampleCount = 100) {
m_keys.push_back(ColorKey(0, a));
m_keys.push_back(ColorKey(1, b));
m_samples.resize(sampleCount);
update();
}
bool operator==(const TSpectrumT<T> &s) const {
if (m_keys.size() != s.m_keys.size()) return false;
typename KeyTable::const_iterator i0, i1;
for (i0 = m_keys.begin(), i1 = s.m_keys.begin(); i0 != m_keys.end();
++i0, ++i1) {
assert(i1 != s.m_keys.end());
if (i0->first != i1->first) return false;
if (i0->second != i1->second) return false;
}
return true;
}
bool operator!=(const TSpectrumT<T> &s) const { return !operator==(s); }
T getValue(double s) const // non premoltiplicati
{
assert(!m_keys.empty());
int m = m_samples.size();
assert(m > 1);
if (s <= 0)
return m_samples.front().second;
else if (s >= 1)
return m_samples.back().second;
s = s * (m - 1);
int i = tfloor(s);
assert(0 <= i && i < m - 1);
s -= i;
assert(0 <= s && s < 1);
T a = m_samples[i].second;
T b = m_samples[i + 1].second;
return blend<T>(a, b, s);
}
T getPremultipliedValue(double s) const // non premoltiplicati
{
assert(!m_keys.empty());
int m = m_samples.size();
assert(m > 1);
if (s <= 0)
return m_samples.front().first;
else if (s >= 1)
return m_samples.back().first;
s = s * (m - 1);
int i = tfloor(s);
assert(0 <= i && i < m - 1);
s -= i;
assert(0 <= s && s < 1);
T a = m_samples[i].first;
T b = m_samples[i + 1].first;
return blend<T>(a, b, s);
}
int getKeyCount() const { return m_keys.size(); }
Key getKey(int index) const {
assert(0 <= index && index < getKeyCount());
return m_keys[index];
}
void setKey(int index, const Key &key) {
assert(0 <= index && index < getKeyCount());
assert(0 <= key.first && key.first <= 1);
m_keys[index] = key;
update();
}
void addKey(const Key &key) {
m_keys.push_back(key);
update();
}
void removeKey(int index) {
if (m_keys.size() <= 1) return;
assert(0 <= index && index < getKeyCount());
m_keys.erase(m_keys.begin() + index);
update();
}
};
DVAPI TSpectrumT<TPixel64> convert(const TSpectrumT<TPixel32> &s);
#ifdef _WIN32
template class DVAPI TSpectrumT<TPixel32>;
template class DVAPI TSpectrumT<TPixel64>;
template class DVAPI TSpectrumT<TPixelF>;
#endif
typedef TSpectrumT<TPixel32> TSpectrum;
typedef TSpectrumT<TPixel64> TSpectrum64;
typedef TSpectrumT<TPixelF> TSpectrumF;
#ifdef _MSC_VER
#pragma warning(default : 4251)
#endif
#endif