3 * Bezier Curves - Compute them and put on Bitmaps
7 #include <ctime> // for performance measurements
8 #include <unordered_map> // hashtable
12 #include "pointstobitmap.h"
19 * Use dynamic programming / recursion
23 static unordered_map<int, int> dp;
24 static bool init = false;
33 int result = n*Factorial(n-1);
39 * Binomial coefficients
41 int BinomialCoeff(int n, int k)
43 return Factorial(n) / Factorial(k) / Factorial(n-k);
47 * Bernstein Basis Polynomial
49 template <class T> T Bernstein(int k, int n, const T & u)
51 return T(BinomialCoeff(n, k)) * pow(u, k) * pow(T(1.0) - u, n-k);
55 * Evaluate a Bezier at a single point u
57 template <class T> pair<T, T> Bezier(const vector<pair<T, T> > & control, const T & u)
59 pair<T,T> result(0,0);
60 for (size_t k = 0; k < control.size(); ++k)
62 T bez(Bernstein<T>(k, control.size()-1, u));
63 result.first += control[k].first * bez;
64 result.second += control[k].second * bez;
70 * Form a Bezier curve from the control points using the specified number of intervals
72 template <class T> vector<pair<T, T> > BezierCurve(const vector<pair<T, T> > & control, int intervals = 200)
74 vector<pair<T, T> > result(intervals+1);
75 T dU = T(1)/intervals;
77 for (int i = 0; i <= intervals; ++i)
79 result[i] = Bezier<T>(control, u);
88 * Make a circle using Beziers
89 * Actually just makes one Bezier for a quadrant and then mirrors it for the others
91 template <class T> vector<pair<T, T> > BezierCircle(const T & scale = 1, int intervals = 50)
93 T k = T(4) * (pow(T(2), T(0.5)) - T(1)) / T(3); // k = 4/3 * (2^(1/2) - 1) because maths says so
94 vector<pair<T, T> >control(4);
95 control[0] = pair<T,T>(0,scale);
96 control[1] = pair<T,T>(k*scale, scale);
97 control[2] = pair<T,T>(scale, k*scale);
98 control[3] = pair<T,T>(scale, 0);
100 auto points = BezierCurve<T>(control, intervals);
102 points.reserve(intervals*4);
103 for (int i = 0; i < intervals; ++i)
105 points.push_back(pair<T,T>(-points[i].first, points[i].second));
107 for (int i = 0; i < intervals; ++i)
109 points.push_back(pair<T,T>(points[i].first, -points[i].second));
111 for (int i = 0; i < intervals; ++i)
113 points.push_back(pair<T,T>(-points[i].first, -points[i].second));
120 * Test Bezier Curve with a scale applied to the *control* points
122 template <class T> vector<pair<T,T> > TestCurve(const T & scale = 1, long intervals = 50)
124 vector<pair<T,T> > control(3);
125 control[0] = pair<T,T>(0,0);
126 control[1] = pair<T,T>(0.4*scale, 0.8*scale);
127 control[2] = pair<T,T>(scale,scale);
128 return BezierCurve<T>(control, intervals);
133 * Test the Beziers over a range of scales. Can print the Nth bezier to stdout
135 void TestBeziers(long intervals = 50, long double start = 1e-38, long double end = 1e38, int print = -1)
138 // Choose our Bezier here
139 //#define TESTBEZIER TestCurve
140 #define TESTBEZIER BezierCircle
142 for (auto scale = start; scale < end; scale *= 10)
144 auto f = TESTBEZIER<float>(scale, intervals);
145 auto d = TESTBEZIER<double>(scale, intervals);
146 auto l = TESTBEZIER<long double>(scale, intervals);
150 s << "bezier" << count << "_" << scale << ".bmp";
151 PointsToBitmap<float>(f, scale, 5*(count++),0,0,s.str().c_str(),false);
153 #if REAL > REAL_LONG_DOUBLE
154 auto r = TESTBEZIER<Real>(scale, intervals);
156 if (count++ == print)
158 for (auto i = 0; i < f.size(); ++i)
160 printf("%d\t%.50lf\t%.50lf\t%.50llf\t%.50llf", f[i].first, f[i].second, d[i].first, d[i].second, l[i].first, l[i].second);
161 #if REAL > REAL_LONG_DOUBLE
162 printf("\t%.50lf\t%.50lf", r[i].first, r[i].second);
168 // optional: Overlay images instead
175 int main(int argc, char ** argv)
178 // Makes a movie, not really that exciting though
179 //system("for i in *.bmp; do convert $i -filter Point -resize x600 +antialias $i; done");
180 //system("ffmpeg -i bezier%d.bmp -framerate 2 -vcodec mpeg4 bezier.mp4");