1 #include <2geom/solver.h>
2 #include <2geom/point.h>
3 #include <algorithm>
5 /*** Find the zeros of the bernstein function. The code subdivides until it is happy with the
6 * linearity of the function. This requires an O(degree^2) subdivision for each step, even when
7 * there is only one solution.
8 */
10 namespace Geom{
12 template<class t>
13 static int SGN(t x) { return (x > 0 ? 1 : (x < 0 ? -1 : 0)); }
15 const unsigned MAXDEPTH = 23; // Maximum depth for recursion. Using floats means 23 bits precision max
17 const double BEPSILON = ldexp(1.0,(-MAXDEPTH-1)); /*Flatness control value */
18 const double SECANT_EPSILON = 1e-13; // secant method converges much faster, get a bit more precision
19 /**
20 * This function is called _a lot_. We have included various manual memory management stuff to reduce the amount of mallocing that goes on. In the future it is possible that this will hurt performance.
21 **/
22 class Bernsteins{
23 public:
24 double *Vtemp;
25 unsigned N,degree;
26 std::vector<double> &solutions;
27 bool use_secant;
28 Bernsteins(int degr, std::vector<double> &so) : N(degr+1), degree(degr),solutions(so), use_secant(false) {
29 Vtemp = new double[N*2];
30 }
31 ~Bernsteins() {
32 delete[] Vtemp;
33 }
34 void subdivide(double const *V,
35 double t,
36 double *Left,
37 double *Right);
39 double horner(const double *b, double t);
41 unsigned
42 control_poly_flat_enough(double const *V);
44 void
45 find_bernstein_roots(double const *w, /* The control points */
46 unsigned depth, /* The depth of the recursion */
47 double left_t, double right_t);
48 };
49 /*
50 * find_bernstein_roots : Given an equation in Bernstein-Bernstein form, find all
51 * of the roots in the open interval (0, 1). Return the number of roots found.
52 */
53 void
54 find_bernstein_roots(double const *w, /* The control points */
55 unsigned degree, /* The degree of the polynomial */
56 std::vector<double> &solutions, /* RETURN candidate t-values */
57 unsigned depth, /* The depth of the recursion */
58 double left_t, double right_t, bool use_secant)
59 {
60 Bernsteins B(degree, solutions);
61 B.use_secant = use_secant;
62 B.find_bernstein_roots(w, depth, left_t, right_t);
63 }
65 void
66 Bernsteins::find_bernstein_roots(double const *w, /* The control points */
67 unsigned depth, /* The depth of the recursion */
68 double left_t, double right_t)
69 {
71 unsigned n_crossings = 0; /* Number of zero-crossings */
73 int old_sign = SGN(w[0]);
74 for (unsigned i = 1; i < N; i++) {
75 int sign = SGN(w[i]);
76 if (sign) {
77 if (sign != old_sign && old_sign) {
78 n_crossings++;
79 }
80 old_sign = sign;
81 }
82 }
84 if (n_crossings == 0) // no solutions here
85 return;
87 if (n_crossings == 1) {
88 /* Unique solution */
89 /* Stop recursion when the tree is deep enough */
90 /* if deep enough, return 1 solution at midpoint */
91 if (depth >= MAXDEPTH) {
92 //printf("bottom out %d\n", depth);
93 const double Ax = right_t - left_t;
94 const double Ay = w[degree] - w[0];
96 solutions.push_back(left_t - Ax*w[0] / Ay);
97 return;
98 solutions.push_back((left_t + right_t) / 2.0);
99 return;
100 }
102 // I thought secant method would be faster here, but it'aint. -- njh
103 // Actually, it was, I just was using the wrong method for bezier evaluation. Horner's rule results in a very efficient algorithm - 10* faster (20080816)
104 // Future work: try using brent's method
105 if(use_secant) { // false position
106 double s = 0;double t = 1;
107 double e = 1e-10;
108 int n,side=0;
109 double r,fr,fs = w[0],ft = w[degree];
111 for (n = 1; n <= 100; n++)
112 {
113 r = (fs*t - ft*s) / (fs - ft);
114 if (fabs(t-s) < e*fabs(t+s)) break;
115 fr = horner(w, r);
117 if (fr * ft > 0)
118 {
119 t = r; ft = fr;
120 if (side==-1) fs /= 2;
121 side = -1;
122 }
123 else if (fs * fr > 0)
124 {
125 s = r; fs = fr;
126 if (side==+1) ft /= 2;
127 side = +1;
128 }
129 else break;
130 }
131 solutions.push_back(r*right_t + (1-r)*left_t);
132 return;
133 }
134 }
136 /* Otherwise, solve recursively after subdividing control polygon */
137 double Left[N], /* New left and right */
138 Right[N]; /* control polygons */
139 const double t = 0.5;
142 /*
143 * Bernstein :
144 * Evaluate a Bernstein function at a particular parameter value
145 * Fill in control points for resulting sub-curves.
146 *
147 */
148 for (unsigned i = 0; i < N; i++)
149 Vtemp[i] = w[i];
151 /* Triangle computation */
152 const double omt = (1-t);
153 Left[0] = Vtemp[0];
154 Right[degree] = Vtemp[degree];
155 double *prev_row = Vtemp;
156 double *row = Vtemp + N;
157 for (unsigned i = 1; i < N; i++) {
158 for (unsigned j = 0; j < N - i; j++) {
159 row[j] = omt*prev_row[j] + t*prev_row[j+1];
160 }
161 Left[i] = row[0];
162 Right[degree-i] = row[degree-i];
163 std::swap(prev_row, row);
164 }
166 double mid_t = left_t*(1-t) + right_t*t;
168 find_bernstein_roots(Left, depth+1, left_t, mid_t);
170 /* Solution is exactly on the subdivision point. */
171 if (Right[0] == 0)
172 solutions.push_back(mid_t);
174 find_bernstein_roots(Right, depth+1, mid_t, right_t);
175 }
177 /*
178 * control_poly_flat_enough :
179 * Check if the control polygon of a Bernstein curve is flat enough
180 * for recursive subdivision to bottom out.
181 *
182 */
183 unsigned
184 Bernsteins::control_poly_flat_enough(double const *V)
185 {
186 /* Find the perpendicular distance from each interior control point to line connecting V[0] and
187 * V[degree] */
189 /* Derive the implicit equation for line connecting first */
190 /* and last control points */
191 const double a = V[0] - V[degree];
193 double max_distance_above = 0.0;
194 double max_distance_below = 0.0;
195 double ii = 0, dii = 1./degree;
196 for (unsigned i = 1; i < degree; i++) {
197 ii += dii;
198 /* Compute distance from each of the points to that line */
199 const double d = (a + V[i]) * ii - a;
200 double dist = d*d;
201 // Find the largest distance
202 if (d < 0.0)
203 max_distance_below = std::min(max_distance_below, -dist);
204 else
205 max_distance_above = std::max(max_distance_above, dist);
206 }
208 const double abSquared = 1./((a * a) + 1);
210 const double intercept_1 = (a - max_distance_above * abSquared);
211 const double intercept_2 = (a - max_distance_below * abSquared);
213 /* Compute bounding interval*/
214 const double left_intercept = std::min(intercept_1, intercept_2);
215 const double right_intercept = std::max(intercept_1, intercept_2);
217 const double error = 0.5 * (right_intercept - left_intercept);
218 //printf("error %g %g %g\n", error, a, BEPSILON * a);
219 return error < BEPSILON * a;
220 }
222 // suggested by Sederberg.
223 double Bernsteins::horner(const double *b, double t) {
224 int n = degree;
225 double u, bc, tn, tmp;
226 int i;
227 u = 1.0 - t;
228 bc = 1;
229 tn = 1;
230 tmp = b[0]*u;
231 for(i=1; i<n; i++){
232 tn = tn*t;
233 bc = bc*(n-i+1)/i;
234 tmp = (tmp + tn*bc*b[i])*u;
235 }
236 return (tmp + tn*t*b[n]);
237 }
240 };
242 /*
243 Local Variables:
244 mode:c++
245 c-file-style:"stroustrup"
246 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
247 indent-tabs-mode:nil
248 fill-column:99
249 End:
250 */
251 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :