瀏覽代碼

better splines for gradient

Nicolas Winkler 5 年之前
父節點
當前提交
8cb395b32c
共有 10 個文件被更改,包括 43 次插入95 次删除
  1. 12 1
      Almond.cpp
  2. 0 2
      Almond.pro
  3. 0 66
      CubicSpline.cpp
  4. 0 19
      CubicSpline.h
  5. 5 0
      GradientMenu.cpp
  6. 1 0
      GradientMenu.h
  7. 1 1
      libalmond/include/CubicSpline.h
  8. 3 0
      libalmond/include/Gradient.h
  9. 11 3
      libalmond/src/CubicSpline.cpp
  10. 10 3
      libalmond/src/Gradient.cpp

+ 12 - 1
Almond.cpp

@@ -216,7 +216,7 @@ void Almond::gradientEditOk(void)
         }
     }
 
-    std::for_each(np.begin(), np.end(), [](auto& x) { x.second *= 100; });
+    std::for_each(np.begin(), np.end(), [](auto& x) { x.second *= 300; });
 
     Gradient g{ np, true };
     mw->setGradient(std::move(g));
@@ -304,6 +304,17 @@ void Almond::on_maxIterations_editingFinished()
 
 void Almond::on_chooseGradient_clicked()
 {
+    const auto& gradient = mw->getGradient();
+    auto points = gradient.getPoints();
+    std::for_each(points.begin(), points.end(), [](auto& x) { x.second /= 300; });
+
+    QVector<QPair<float, QColor>> np;
+    std::transform(points.begin(), points.end(), std::back_inserter(np),
+        [](auto& qp) -> QPair<float, QColor> {
+        auto& [col, pos] = qp;
+        return { pos, QColor{ (col.r), (col.g), (col.b) } };
+    });
+    this->gradientMenu->setGradient(std::move(np));
     emit this->amw->showSubMenu(2);
     //gcd.exec();
     //auto gradient = gcd.getGradient();

+ 0 - 2
Almond.pro

@@ -33,7 +33,6 @@ SOURCES += \
         CubicSpline.cpp \
         ExportImageMenu.cpp \
         ExportVideoMenu.cpp \
-        Gradient.cpp \
         GradientMenu.cpp \
         GradientWidget.cpp \
         MandelWidget.cpp \
@@ -52,7 +51,6 @@ HEADERS += \
         CubicSpline.h \
         ExportImageMenu.h \
         ExportVideoMenu.h \
-        Gradient.h \
         GradientMenu.h \
         GradientWidget.h \
         MandelWidget.h \

+ 0 - 66
CubicSpline.cpp

@@ -1,66 +0,0 @@
-#include "CubicSpline.h"
-
-CubicSpline::CubicSpline(const std::vector<std::pair<float, float> >& dataPoints, bool useSlopes) :
-    useSlopes{ useSlopes }
-{
-    if (dataPoints.size() < 2) {
-        return;
-    }
-
-    points.push_back({ dataPoints[0].first, dataPoints[0].second,
-                       (dataPoints[1].second - dataPoints[0].second) /
-                       (dataPoints[1].first - dataPoints[0].first) });
-    for (size_t i = 1; i < dataPoints.size() - 1; i++) {
-
-        auto& dp1 = dataPoints[i - 1];
-        auto& dp2 = dataPoints[i];
-        auto& dp3 = dataPoints[i + 1];
-
-        float w1 = dp2.first - dp1.first;
-        float w2 = dp3.first - dp2.first;
-        float h1 = dp2.second - dp1.second;
-        float h2 = dp3.second - dp2.second;
-
-        float s1 = h1 / w1;
-        float s2 = h2 / w2;
-
-        float avgSlope = (s1 + s2) / 2;
-        points.push_back({ dp2.first, dp2.second, avgSlope });
-    }
-    points.push_back({ dataPoints[dataPoints.size() - 1].first, dataPoints[dataPoints.size() - 1].second,
-                       (dataPoints[dataPoints.size() - 2].second - dataPoints[dataPoints.size() - 1].second) /
-                       (dataPoints[dataPoints.size() - 2].first - dataPoints[dataPoints.size() - 1].first) });
-}
-
-
-float CubicSpline::interpolateAt(float x)
-{
-    const static auto h00 = [] (float t) { return (1 + 2 * t) * (1 - t) * (1 - t); };
-    const static auto h01 = [] (float t) { return t * t * (3 - 2 * t); };
-    const static auto h10 = [] (float t) { return t * (1 - t) * (1 - t); };
-    const static auto h11 = [] (float t) { return t * t * (t - 1); };
-    for (auto it = points.begin(); it != points.end() && (it + 1) != points.end(); ++it) {
-        auto& left = *it;
-        auto& right = *(it + 1);
-        float xleft = std::get<0>(left);
-        float xright = std::get<0>(right);
-        if (xleft < x && xright >= x) {
-            float w = (xright - xleft);
-            float t = (x - xleft) / w;
-            float yleft = std::get<1>(left);
-            float yright = std::get<1>(right);
-            float sleft = std::get<2>(left);
-            float sright = std::get<2>(right);
-
-            float inter = h00(t) * yleft +
-                          h01(t) * yright;
-
-            if (useSlopes)
-                inter += h10(t) * w * sleft +
-                         h11(t) * w * sright;
-
-            return inter;
-        }
-    }
-    return std::get<1>(points[points.size() - 1]);
-}

+ 0 - 19
CubicSpline.h

@@ -1,19 +0,0 @@
-#ifndef CUBICSPLINE_H
-#define CUBICSPLINE_H
-
-#include <vector>
-#include <utility>
-#include <tuple>
-
-class CubicSpline
-{
-    /// contains x, y and y' of each interpolation point
-    std::vector<std::tuple<float, float, float>> points;
-    bool useSlopes;
-public:
-    CubicSpline(const std::vector<std::pair<float, float>>& dataPoints, bool useSlopes);
-
-    float interpolateAt(float x);
-};
-
-#endif // CUBICSPLINE_H

+ 5 - 0
GradientMenu.cpp

@@ -25,3 +25,8 @@ const QVector<QPair<float, QColor>>& GradientMenu::getGradient(void)
 {
     return ui->gradientWidget->getGradient();
 }
+
+void GradientMenu::setGradient(QVector<QPair<float, QColor>> grad)
+{
+    ui->gradientWidget->setGradient(std::move(grad));
+}

+ 1 - 0
GradientMenu.h

@@ -18,6 +18,7 @@ public:
     ~GradientMenu(void);
 
     const QVector<QPair<float, QColor>>& getGradient(void);
+    void setGradient(QVector<QPair<float, QColor>> grad);
 
 private:
     Ui::GradientMenu *ui;

+ 1 - 1
libalmond/include/CubicSpline.h

@@ -11,7 +11,7 @@ class CubicSpline
     std::vector<std::tuple<float, float, float>> points;
     bool useSlopes;
 public:
-    CubicSpline(const std::vector<std::pair<float, float>>& dataPoints, bool useSlopes);
+    CubicSpline(const std::vector<std::pair<float, float>>& dataPoints, bool useSlopes, bool minSlopes);
 
     float interpolateAt(float x);
 };

+ 3 - 0
libalmond/include/Gradient.h

@@ -10,6 +10,7 @@
 
 class Gradient
 {
+    std::vector<std::pair<RGBColor, float>> points;
     /// the colors of this gradient stored in linear RGB format
     /// so they can be easily interpolated
     std::vector<RGBColorf> colors;
@@ -19,6 +20,8 @@ public:
     Gradient(void);
     Gradient(std::vector<std::pair<RGBColor, float>> colors, bool repeat = false, int precalcSteps = -1);
 
+    const std::vector<std::pair<RGBColor, float>>& getPoints(void) const;
+
     static Gradient defaultGradient(void);
 
     //static Gradient readXml(const std::string& xml);

+ 11 - 3
libalmond/src/CubicSpline.cpp

@@ -1,6 +1,7 @@
 #include "CubicSpline.h"
+#include <cmath>
 
-CubicSpline::CubicSpline(const std::vector<std::pair<float, float> >& dataPoints, bool useSlopes) :
+CubicSpline::CubicSpline(const std::vector<std::pair<float, float> >& dataPoints, bool useSlopes, bool minSlopes) :
     useSlopes{ useSlopes }
 {
     if (dataPoints.size() < 2) {
@@ -24,8 +25,15 @@ CubicSpline::CubicSpline(const std::vector<std::pair<float, float> >& dataPoints
         float s1 = h1 / w1;
         float s2 = h2 / w2;
 
-        float avgSlope = (s1 + s2) / 2;
-        points.push_back({ dp2.first, dp2.second, avgSlope });
+        float slope;
+        if (minSlopes) {
+            if (fabs(s1) > fabs(s2))
+                slope = s2;
+            else
+                slope = s1;
+        } else
+            slope = (s1 + s2) / 2;
+        points.push_back({ dp2.first, dp2.second, slope });
     }
     points.push_back({ dataPoints[dataPoints.size() - 1].first, dataPoints[dataPoints.size() - 1].second,
                        (dataPoints[dataPoints.size() - 2].second - dataPoints[dataPoints.size() - 1].second) /

+ 10 - 3
libalmond/src/Gradient.cpp

@@ -23,6 +23,7 @@ Gradient::Gradient(std::vector<std::pair<RGBColor, float>> colors, bool repeat,
             return a.second < b.second;
         });
 
+    points = colors;
     max = colors.at(colors.size() - 1).second;
 
     std::vector<std::pair<RGBColorf, float>> linearColors;
@@ -40,9 +41,9 @@ Gradient::Gradient(std::vector<std::pair<RGBColor, float>> colors, bool repeat,
     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);
+    CubicSpline rsp(rs, true, true);
+    CubicSpline gsp(gs, true, true);
+    CubicSpline bsp(bs, true, true);
 
     if(precalcSteps <= 0) {
         precalcSteps = int(max * 15) + 10;
@@ -60,6 +61,12 @@ Gradient::Gradient(std::vector<std::pair<RGBColor, float>> colors, bool repeat,
 }
 
 
+const std::vector<std::pair<RGBColor, float>>& Gradient::getPoints(void) const
+{
+    return points;
+}
+
+
 Gradient Gradient::defaultGradient(void)
 {
     /*QFile res(":/gradients/default");