/* find a point of inflection on a bezier curve, if it exists, by finding the * value of parameter 't' where the signed curvature of the bezier changes * signs. Returns true if an inflection point is found. */ HIDDEN bool bezier_inflection(const ON_BezierCurve& bezier, fastf_t& inflection_pt) { int sign; fastf_t t, step, crv; ON_3dVector d1, d2; // first derivative, second derivative ON_3dPoint tmp; // not used, but needed by Ev2Der // calculate curvature at t=0 bezier.Ev2Der(0, tmp, d1, d2); crv = CURVATURE(d1, d2); // step size decreases as |crv| -> 0 step = GETSTEPSIZE(fabs(crv)); sign = SIGN(crv); for (t = step; t <= 1.0; t += step) { bezier.Ev2Der(t, tmp, d1, d2); crv = CURVATURE(d1, d2); // if sign changes, t is an inflection point if (sign != SIGN(crv)) { inflection_pt = t; return true; } step = GETSTEPSIZE(fabs(crv)); } return false; }
/* approximates a bezier curve with a set of circular arcs by dividing where * the bezier's deviation from its approximating biarc is at a maximum, then * recursively calling on the subsections until it is approximated to * tolerance by the biarc */ HIDDEN void approx_bezier(const ON_BezierCurve& bezier, const ON_Arc& biarc, const struct bn_tol *tol, std::vector<ON_Arc>& approx) { fastf_t t = 0.0, step = 0.0; fastf_t crv = 0.0, err = 0.0, max_t = 0.0, max_err = 0.0; ON_3dPoint test; ON_3dVector d1, d2; // walk the bezier curve at interval given by step for (t = 0; t <= 1.0; t += step) { bezier.Ev2Der(t, test, d1, d2); err = fabs((test - biarc.Center()).Length() - biarc.Radius()); // find the maximum point of deviation if (err > max_err) { max_t = t; max_err = err; } crv = CURVATURE(d1, d2); // step size decreases as |crv| -> 1 step = GETSTEPSIZE(1.0 - fabs(crv)); } if (max_err + VDIVIDE_TOL < tol->dist) { // max deviation is less than the given tolerance, add the biarc approximation approx.push_back(biarc); } else { ON_BezierCurve head, tail; // split bezier at point of maximum deviation and recurse on the new subsections bezier.Split(max_t, head, tail); approx_bezier(head, make_biarc(head), tol, approx); approx_bezier(tail, make_biarc(tail), tol, approx); } }