/* approximates a bezier curve with a set of circular arcs. * returns approximation in carcs */ HIDDEN void bezier_to_carcs(const ON_BezierCurve& bezier, const struct bn_tol *tol, std::vector<ON_Arc>& carcs) { bool skip_while = true, curvature_changed = false; fastf_t inflection_pt, biarc_angle; ON_Arc biarc; ON_BezierCurve current, next; std::vector<ON_BezierCurve> rest; // find inflection point, if it exists if (bezier_inflection(bezier, inflection_pt)) { curvature_changed = true; bezier.Split(inflection_pt, current, next); rest.push_back(next); } else { current = bezier; } while (skip_while || !rest.empty()) { if (skip_while) skip_while = false; biarc = make_biarc(current); if ((biarc_angle = biarc.AngleRadians()) <= M_PI_2) { // approximate the current bezier segment and add its biarc // approximation to carcs approx_bezier(current, biarc, tol, carcs); } else if (biarc_angle <= M_PI) { // divide the current bezier segment in half current.Split(0.5, current, next); // approximate first bezier segment approx_bezier(current, biarc, tol, carcs); // approximate second bezier segment approx_bezier(next, biarc, tol, carcs); } else { fastf_t t = 1.0; ON_Arc test_biarc; ON_BezierCurve test_bezier; // divide the current bezier such that the first curve segment would // have an approximating biarc segment <=90 degrees do { t *= 0.5; current.Split(t, test_bezier, next); test_biarc = make_biarc(test_bezier); } while(test_biarc.AngleRadians() > M_PI_2); approx_bezier(test_bezier, test_biarc, tol, carcs); current = next; skip_while = true; continue; } if (curvature_changed) { curvature_changed = false; current = rest.back(); rest.pop_back(); // continue even if we just popped the last element skip_while = true; } } }
static ON_BOOL32 NurbsCurveArc ( const ON_Arc& arc, int dim, ON_NurbsCurve& nurb ) { if ( !arc.IsValid() ) return false; // makes a quadratic nurbs arc const ON_3dPoint center = arc.Center(); double angle = arc.AngleRadians(); ON_Interval dom = arc.DomainRadians(); const double angle0 = dom[0]; const double angle1 = dom[1]; ON_3dPoint start_point = arc.StartPoint(); //ON_3dPoint mid_point = arc.PointAt(angle0 + 0.5*angle); ON_3dPoint end_point = arc.IsCircle() ? start_point : arc.EndPoint(); ON_4dPoint CV[9]; double knot[10]; double a, b, c, w, winv; double *cv; int j, span_count, cv_count; a = (0.5 + ON_SQRT_EPSILON)*ON_PI; if (angle <= a) span_count = 1; else if (angle <= 2.0*a) span_count = 2; else if (angle <= 3.0*a) span_count = 4; // TODO - make a 3 span case else span_count = 4; cv_count = 2*span_count + 1; switch(span_count) { case 1: CV[0] = start_point; CV[1] = arc.PointAt(angle0 + 0.50*angle); CV[2] = end_point; break; case 2: CV[0] = start_point; CV[1] = arc.PointAt(angle0 + 0.25*angle); CV[2] = arc.PointAt(angle0 + 0.50*angle); CV[3] = arc.PointAt(angle0 + 0.75*angle); CV[4] = end_point; angle *= 0.5; break; default: // 4 spans CV[0] = start_point; CV[1] = arc.PointAt(angle0 + 0.125*angle); CV[2] = arc.PointAt(angle0 + 0.250*angle); CV[3] = arc.PointAt(angle0 + 0.375*angle); CV[4] = arc.PointAt(angle0 + 0.500*angle); CV[5] = arc.PointAt(angle0 + 0.625*angle); CV[6] = arc.PointAt(angle0 + 0.750*angle); CV[7] = arc.PointAt(angle0 + 0.875*angle); CV[8] = end_point; angle *= 0.25; break; } a = cos(0.5*angle); b = a - 1.0; //c = (radius > 0.0) ? radius*angle : angle; c = angle; span_count *= 2; knot[0] = knot[1] = angle0; //0.0; for (j = 1; j < span_count; j += 2) { CV[j].x += b * center.x; CV[j].y += b * center.y; CV[j].z += b * center.z; CV[j].w = a; CV[j+1].w = 1.0; knot[j+1] = knot[j+2] = knot[j-1] + c; } knot[cv_count-1] = knot[cv_count] = angle1; for ( j = 1; j < span_count; j += 2 ) { w = CV[j].w; winv = 1.0/w; a = CV[j].x*winv; b = ArcDeFuzz(a); if ( a != b ) { CV[j].x = b*w; } a = CV[j].y*winv; b = ArcDeFuzz(a); if ( a != b ) { CV[j].y = b*w; } a = CV[j].z*winv; b = ArcDeFuzz(a); if ( a != b ) { CV[j].z = b*w; } } nurb.m_dim = (dim==2) ? 2 : 3; nurb.m_is_rat = 1; nurb.m_order = 3; nurb.m_cv_count = cv_count; nurb.m_cv_stride = (dim==2 ? 3 : 4); nurb.ReserveCVCapacity( nurb.m_cv_stride*cv_count ); nurb.ReserveKnotCapacity( cv_count+1 ); for ( j = 0; j < cv_count; j++ ) { cv = nurb.CV(j); cv[0] = CV[j].x; cv[1] = CV[j].y; if ( dim == 2 ) { cv[2] = CV[j].w; } else { cv[2] = CV[j].z; cv[3] = CV[j].w; } nurb.m_knot[j] = knot[j]; } nurb.m_knot[cv_count] = knot[cv_count]; return true; }