#include "colorscale.h" #include <cmath> const float EPSILON = 1e-3f; Color::Color() : Color(0, 0, 0, 255) { } Color::Color(int r, int g, int b) : Color(r, g, b, 255) { } Color::Color(int r, int g, int b, int a) : r(r) , g(g) , b(b) , a(a) { } Color::Color(float r, float g, float b) : Color(r, g, b, 0.0f) { } Color::Color(float r, float g, float b, float a) : Color(static_cast<int>(round(255 * r)), static_cast<int>(round(255 * g)), static_cast<int>(round(255 * b)), static_cast<int>(round(255 * a))) { } void Color::getRgbF(float *r, float *g, float *b) const { *r = static_cast<float>(this->r) / 255.0f; *g = static_cast<float>(this->g) / 255.0f; *b = static_cast<float>(this->b) / 255.0f; } void Color::getRgbF(float *r, float *g, float *b, float *a) const { getRgbF(r, g, b); *a = static_cast<float>(this->a) / 255.0f; } void Color::setRgb(int r, int g, int b) { setRgb(r, g, b, 255); } void Color::setRgb(int r, int g, int b, int a) { this->r = r; this->g = g; this->b = b; this->a = a; } void Color::setRgbF(float r, float g, float b) { setRgb(static_cast<int>(round(255 * r)), static_cast<int>(round(255 * g)), static_cast<int>(round(255 * b))); } void Color::setRgbF(float r, float g, float b, float a) { setRgb(static_cast<int>(round(255 * r)), static_cast<int>(round(255 * g)), static_cast<int>(round(255 * b)), static_cast<int>(round(255 * a))); } ColorScale::ColorScale(const Color &firstColor, const Color &lastColor) : m_colors{{firstColor, lastColor}} { setExtents(0.0f, 1.0f); } ColorScale::ColorScale(std::initializer_list<Color> colors) : m_colors(colors) { setExtents(0.0f, 1.0f); } ColorScale::ColorScale(const std::vector<Color> &colors) : m_colors(colors) { setExtents(0.0f, 1.0f); } ColorScale::~ColorScale() { } void ColorScale::setExtents(float min, float max) { if (min >= max) { return; } m_min = min; m_max = max; } Color ColorScale::lerp(const Color &c1, const Color &c2, float _t) { float r1, g1, b1, a1; float r2, g2, b2, a2; float t = _t; c1.getRgbF(&r1, &g1, &b1, &a1); c2.getRgbF(&r2, &g2, &b2, &a2); Color color; color.setRgbF(r1 * (1.0f - t) + r2 * t, g1 * (1.0f - t) + g2 * t, b1 * (1.0f - t) + b2 * t, a1 * (1.0f - t) + a2 * t); return color; } Color ColorScale::color(float t) const { if (t < m_min || t > m_max) { return Color(); } // normalize t t = (t - m_min) / (m_max - m_min); // two colors, use a simpler solution if (m_colors.size() == 2) { return lerp(m_colors.front(), m_colors.back(), t); } if (fabs(t - m_min) < EPSILON) { return m_colors.front(); } if (fabs(t - m_max) < EPSILON) { return m_colors.back(); } // find which colors in the scale are adjacent to ours int i = int(t * m_colors.size()); int j = i + 1; if (i >= m_colors.size() - 1) { return Color(m_colors.back()); } // normalize t between the two colors float step = 1.0f / m_colors.size(); t = (t - i*step) / (j*step - i*step); return lerp(m_colors[i], m_colors[j], t); }