Gradient.cpp 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. #include "Gradient.h"
  2. #include "CubicSpline.h"
  3. #include <cmath>
  4. #include <algorithm>
  5. #include <functional>
  6. Gradient::Gradient(void) :
  7. max{ 1.0 }
  8. {
  9. }
  10. Gradient::Gradient(std::vector<std::pair<RGBColor, float>> colors, bool repeat, int precalcSteps) :
  11. repeat{ repeat }
  12. {
  13. if(colors.empty() || colors.size() < 2)
  14. return;
  15. std::sort(colors.begin(), colors.end(),
  16. [] (const auto& a, const auto& b) {
  17. return a.second < b.second;
  18. });
  19. max = colors.at(colors.size() - 1).second;
  20. std::vector<std::pair<RGBColorf, float>> linearColors;
  21. std::transform(colors.begin(), colors.end(), std::back_inserter(linearColors),
  22. [] (auto c) { return c; });
  23. std::vector<std::pair<float, float>> rs;
  24. std::vector<std::pair<float, float>> gs;
  25. std::vector<std::pair<float, float>> bs;
  26. std::transform(linearColors.begin(), linearColors.end(), std::back_inserter(rs),
  27. [] (auto p) { return std::pair{ p.second, p.first.r }; });
  28. std::transform(linearColors.begin(), linearColors.end(), std::back_inserter(gs),
  29. [] (auto p) { return std::pair{ p.second, p.first.g }; });
  30. std::transform(linearColors.begin(), linearColors.end(), std::back_inserter(bs),
  31. [] (auto p) { return std::pair{ p.second, p.first.b }; });
  32. CubicSpline rsp(rs, false);
  33. CubicSpline gsp(gs, false);
  34. CubicSpline bsp(bs, false);
  35. if(precalcSteps <= 0) {
  36. precalcSteps = int(max * 15) + 10;
  37. }
  38. for (int i = 0; i < precalcSteps; i++) {
  39. float position = i * max / precalcSteps;
  40. RGBColorf at = {
  41. rsp.interpolateAt(position),
  42. gsp.interpolateAt(position),
  43. bsp.interpolateAt(position)
  44. };
  45. this->colors.push_back(at);
  46. }
  47. }
  48. Gradient Gradient::defaultGradient(void)
  49. {
  50. /*QFile res(":/gradients/default");
  51. res.open(QIODevice::ReadOnly);
  52. QString str = QString::fromUtf8(res.readAll());
  53. return readXml(str);*/
  54. return Gradient({
  55. { RGBColor{ 0, 0, 0 }, 0.0f },
  56. { RGBColor{ 0, 255, 255 }, 30.0f },
  57. { RGBColor{ 50, 100, 170 }, 60.0f },
  58. { RGBColor{ 180, 140, 20 }, 90.0f },
  59. { RGBColor{ 255, 255, 0 }, 120.0f },
  60. { RGBColor{ 143, 67, 0 }, 150.0f },
  61. { RGBColor{ 255, 255, 255 }, 180.0f },
  62. { RGBColor{ 20, 30, 180 }, 210.0f },
  63. { RGBColor{ 20, 190, 30 }, 240.0f },
  64. { RGBColor{ 120, 240, 120 }, 270.0f },
  65. { RGBColor{ 40, 40, 40 }, 300.0f },
  66. }, true);
  67. }
  68. RGBColor Gradient::get(float x) const
  69. {
  70. if (colors.empty() || std::isnan(x) || std::isinf(x))
  71. return RGBColor();
  72. /*const auto [left, right, lerp] = getNeighbors(x);
  73. RGBColor lerped = lerpColors(left, right, lerp);
  74. return lerped;*/
  75. if (x < 0)
  76. return colors[0];
  77. if (x > this->max) {
  78. if (repeat)
  79. x = ::fmodf(x, this->max);
  80. else
  81. x = this->max;
  82. }
  83. float pos = x * colors.size() / max;
  84. if (pos < 0) {
  85. pos = 0;
  86. }
  87. if (pos > colors.size() - 1) {
  88. pos = colors.size() - 1;
  89. }
  90. int left = int(pos);
  91. int right = int(pos + 1);
  92. float lerp = pos - left;
  93. if (lerp < 1e-5f) {
  94. return colors[left];
  95. }
  96. else {
  97. return lerpColors(colors[left], colors[right], lerp);
  98. }
  99. }
  100. RGBColorf Gradient::lerpColors(RGBColorf a, RGBColorf b, float val)
  101. {
  102. return RGBColorf {
  103. b.r * val + a.r * (1 - val),
  104. b.g * val + a.g * (1 - val),
  105. b.b * val + a.b * (1 - val)
  106. };
  107. }
  108. RGBColor Gradient::lerpColors(RGBColor a, RGBColor b, float val)
  109. {
  110. return RGBColor{ lerpColors(RGBColorf{ a }, RGBColorf{ b }, val) };
  111. }
  112. /*std::tuple<RGBColor, RGBColor, float> Gradient::getNeighbors(float x) const
  113. {
  114. for (auto it = colors.begin(); it != colors.end(); ++it) {
  115. if (it->second > x) {
  116. if (it == colors.begin()) {
  117. return { it->first, it->first, 0 };
  118. }
  119. else {
  120. float lerp = (x - (it - 1)->second) / (it->second - (it - 1)->second);
  121. return { (it - 1)->first, it->first, lerp };
  122. }
  123. }
  124. }
  125. return { (colors.end() - 1)->first, (colors.end() - 1)->first, 0 };
  126. }*/