/* * find_bezier_roots : Given an equation in Bernstein-Bezier form, find all * of the roots in the interval [0, 1]. Return the number of roots found. */ void find_parametric_bezier_roots(Geom::Point const *w, /* The control points */ unsigned degree, /* The degree of the polynomial */ std::vector<double> &solutions, /* RETURN candidate t-values */ unsigned depth) /* The depth of the recursion */ { total_steps++; const unsigned max_crossings = crossing_count(w, degree); switch (max_crossings) { case 0: /* No solutions here */ return; case 1: /* Unique solution */ /* Stop recursion when the tree is deep enough */ /* if deep enough, return 1 solution at midpoint */ if (depth >= MAXDEPTH) { solutions.push_back((w[0][Geom::X] + w[degree][Geom::X]) / 2.0); return; } // I thought secant method would be faster here, but it'aint. -- njh if (control_poly_flat_enough(w, degree)) { solutions.push_back(compute_x_intercept(w, degree)); return; } break; } /* * Otherwise, solve recursively after subdividing control polygon * New left and right control polygons */ Geom::Point *Left = new Geom::Point[degree+1]; Geom::Point *Right = new Geom::Point[degree+1]; Bezier(w, degree, 0.5, Left, Right); total_subs ++; find_parametric_bezier_roots(Left, degree, solutions, depth+1); find_parametric_bezier_roots(Right, degree, solutions, depth+1); delete[] Left; delete[] Right; }
/* * find_bernstein_roots : Given an equation in Bernstein-Bernstein form, find all * of the roots in the open interval (0, 1). Return the number of roots found. */ void find_bernstein_roots(double const *w, /* The control points */ unsigned degree, /* The degree of the polynomial */ std::vector<double> &solutions, /* RETURN candidate t-values */ unsigned depth, /* The depth of the recursion */ double left_t, double right_t) { unsigned n_crossings = 0; /* Number of zero-crossings */ int old_sign = SGN(w[0]); for (unsigned i = 1; i <= degree; i++) { int sign = SGN(w[i]); if (sign) { if (sign != old_sign && old_sign) { n_crossings++; } old_sign = sign; } } switch (n_crossings) { case 0: /* No solutions here */ return; case 1: /* Unique solution */ /* Stop recursion when the tree is deep enough */ /* if deep enough, return 1 solution at midpoint */ if (depth >= MAXDEPTH) { solutions.push_back((left_t + right_t) / 2.0); return; } // I thought secant method would be faster here, but it'aint. -- njh if (control_poly_flat_enough(w, degree, left_t, right_t)) { const double Ax = right_t - left_t; const double Ay = w[degree] - w[0]; solutions.push_back(left_t - Ax*w[0] / Ay); return; } break; } /* Otherwise, solve recursively after subdividing control polygon */ std::vector<double> Left(degree+1); /* New left and right */ std::vector<double> Right(degree+1);/* control polygons */ const double split = 0.5; Bernstein(w, degree, split, &Left[0], &Right[0]); double mid_t = left_t*(1-split) + right_t*split; find_bernstein_roots(&Left[0], degree, solutions, depth+1, left_t, mid_t); /* Solution is exactly on the subdivision point. */ if (Right[0] == 0) solutions.push_back(mid_t); find_bernstein_roots(&Right[0], degree, solutions, depth+1, mid_t, right_t); }