#include "Gradient.h" #include "CubicSpline.h" #include #include #include Gradient::Gradient(void) : max{ 1.0 } { } Gradient::Gradient(std::vector> colors, bool repeat, int precalcSteps) : repeat{ repeat } { if(colors.empty() || colors.size() < 2) return; std::sort(colors.begin(), colors.end(), [] (const auto& a, const auto& b) { return a.second < b.second; }); max = colors.at(colors.size() - 1).second; std::vector> linearColors; std::transform(colors.begin(), colors.end(), std::back_inserter(linearColors), [] (auto c) { return c; }); std::vector> rs; std::vector> gs; std::vector> bs; std::transform(linearColors.begin(), linearColors.end(), std::back_inserter(rs), [] (auto p) { return std::pair{ p.second, p.first.r }; }); std::transform(linearColors.begin(), linearColors.end(), std::back_inserter(gs), [] (auto p) { return std::pair{ p.second, p.first.g }; }); std::transform(linearColors.begin(), linearColors.end(), std::back_inserter(bs), [] (auto p) { return std::pair{ p.second, p.first.b }; }); CubicSpline rsp(rs, false); CubicSpline gsp(gs, false); CubicSpline bsp(bs, false); if(precalcSteps <= 0) { precalcSteps = int(max * 15) + 10; } for (int i = 0; i < precalcSteps; i++) { float position = i * max / precalcSteps; RGBColorf at = { rsp.interpolateAt(position), gsp.interpolateAt(position), bsp.interpolateAt(position) }; this->colors.push_back(at); } } Gradient Gradient::defaultGradient(void) { /*QFile res(":/gradients/default"); res.open(QIODevice::ReadOnly); QString str = QString::fromUtf8(res.readAll()); return readXml(str);*/ return Gradient({ { RGBColor{ 0, 0, 0 }, 0.0f }, { RGBColor{ 0, 255, 255 }, 30.0f }, { RGBColor{ 50, 100, 170 }, 60.0f }, { RGBColor{ 180, 140, 20 }, 90.0f }, { RGBColor{ 255, 255, 0 }, 120.0f }, { RGBColor{ 143, 67, 0 }, 150.0f }, { RGBColor{ 255, 255, 255 }, 180.0f }, { RGBColor{ 20, 30, 180 }, 210.0f }, { RGBColor{ 20, 190, 30 }, 240.0f }, { RGBColor{ 120, 240, 120 }, 270.0f }, { RGBColor{ 40, 40, 40 }, 300.0f }, }, true); } RGBColor Gradient::get(float x) const { if (colors.empty() || std::isnan(x) || std::isinf(x)) return RGBColor(); /*const auto [left, right, lerp] = getNeighbors(x); RGBColor lerped = lerpColors(left, right, lerp); return lerped;*/ if (x < 0) return colors[0]; if (x > this->max) { if (repeat) x = ::fmodf(x, this->max); else x = this->max; } float pos = x * colors.size() / max; if (pos < 0) { pos = 0; } if (pos > colors.size() - 1) { pos = colors.size() - 1; } int left = int(pos); int right = int(pos + 1); float lerp = pos - left; if (lerp < 1e-5f) { return colors[left]; } else { return lerpColors(colors[left], colors[right], lerp); } } RGBColorf Gradient::lerpColors(RGBColorf a, RGBColorf b, float val) { return RGBColorf { b.r * val + a.r * (1 - val), b.g * val + a.g * (1 - val), b.b * val + a.b * (1 - val) }; } RGBColor Gradient::lerpColors(RGBColor a, RGBColor b, float val) { return RGBColor{ lerpColors(RGBColorf{ a }, RGBColorf{ b }, val) }; } /*std::tuple Gradient::getNeighbors(float x) const { for (auto it = colors.begin(); it != colors.end(); ++it) { if (it->second > x) { if (it == colors.begin()) { return { it->first, it->first, 0 }; } else { float lerp = (x - (it - 1)->second) / (it->second - (it - 1)->second); return { (it - 1)->first, it->first, lerp }; } } } return { (colors.end() - 1)->first, (colors.end() - 1)->first, 0 }; }*/