Gradient.cpp 4.3 KB

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