ON_BOOL32 ON_ArcCurve::SetEndPoint(ON_3dPoint end_point) { if (IsCircle()) return false; ON_BOOL32 rc = false; if ( m_dim == 3 || end_point.z == 0.0 ) { ON_3dPoint P; ON_3dVector T; double t = Domain()[0]; Ev1Der( t, P, T ); ON_Arc a; rc = a.Create( P, T, end_point ); if ( rc ) { m_arc = a; } else { ON_3dPoint start_point = PointAt(Domain()[0]); if (end_point.DistanceTo(start_point) < ON_ZERO_TOLERANCE*m_arc.Radius()){ //make arc into circle m_arc.plane.xaxis = start_point - m_arc.Center(); m_arc.plane.xaxis.Unitize(); m_arc.plane.yaxis = ON_CrossProduct(m_arc.Normal(), m_arc.plane.xaxis); m_arc.plane.yaxis.Unitize(); m_arc.SetAngleRadians(2.0*ON_PI); rc = true; } } } return rc; }
int ON_Intersect( const ON_Plane& plane, const ON_Arc& arc, ON_3dPoint& point0, ON_3dPoint& point1 ) { int rval = -1; ON_Line xline; double a,b; bool rc = ON_Intersect(plane, arc.Plane(), xline); if(rc) { rval = ON_Intersect(xline, arc, &a, point0, &b, point1); } else { double d = plane.plane_equation.ValueAt( arc.StartPoint() ); if(d<ON_ZERO_TOLERANCE) rval =3; else rval = 0; } return rval; }
/* 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); } }
/* 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; } } }
ON_RevSurface* ON_Sphere::RevSurfaceForm( bool bArcLengthParameterization, ON_RevSurface* srf ) const { if ( srf ) srf->Destroy(); ON_RevSurface* pRevSurface = NULL; if ( IsValid() ) { ON_Arc arc; arc.plane.origin = plane.origin; arc.plane.xaxis = -plane.zaxis; arc.plane.yaxis = plane.xaxis; arc.plane.zaxis = -plane.yaxis; arc.plane.UpdateEquation(); arc.radius = radius; arc.SetAngleRadians(ON_PI); ON_ArcCurve* arc_curve = new ON_ArcCurve( arc, -0.5*ON_PI, 0.5*ON_PI ); if ( srf ) pRevSurface = srf; else pRevSurface = new ON_RevSurface(); pRevSurface->m_angle.Set(0.0,2.0*ON_PI); pRevSurface->m_t = pRevSurface->m_angle; pRevSurface->m_curve = arc_curve; pRevSurface->m_axis.from = plane.origin; pRevSurface->m_axis.to = plane.origin + plane.zaxis; pRevSurface->m_bTransposed = false; pRevSurface->m_bbox.m_min = plane.origin; pRevSurface->m_bbox.m_min.x -= radius; pRevSurface->m_bbox.m_min.y -= radius; pRevSurface->m_bbox.m_min.z -= radius; pRevSurface->m_bbox.m_max = plane.origin; pRevSurface->m_bbox.m_max.x += radius; pRevSurface->m_bbox.m_max.y += radius; pRevSurface->m_bbox.m_max.z += radius; if ( bArcLengthParameterization ) { double r = fabs(radius); if ( !(r > ON_SQRT_EPSILON) ) r = 1.0; r *= ON_PI; pRevSurface->SetDomain(0,0.0,2.0*r); pRevSurface->SetDomain(1,-0.5*r,0.5*r); } } return pRevSurface; }
ON_RevSurface* ON_Sphere::RevSurfaceForm( ON_RevSurface* srf ) const { if ( srf ) srf->Destroy(); ON_RevSurface* pRevSurface = NULL; if ( IsValid() ) { ON_Arc arc; arc.plane.origin = plane.origin; arc.plane.xaxis = -plane.zaxis; arc.plane.yaxis = plane.xaxis; arc.plane.zaxis = -plane.yaxis; arc.plane.UpdateEquation(); arc.radius = radius; arc.SetAngleRadians(ON_PI); ON_ArcCurve* arc_curve = new ON_ArcCurve( arc, -0.5*ON_PI, 0.5*ON_PI ); if ( srf ) pRevSurface = srf; else pRevSurface = new ON_RevSurface(); pRevSurface->m_angle.Set(0.0,2.0*ON_PI); pRevSurface->m_t = pRevSurface->m_angle; pRevSurface->m_curve = arc_curve; pRevSurface->m_axis.from = plane.origin; pRevSurface->m_axis.to = plane.origin + plane.zaxis; pRevSurface->m_bTransposed = false; pRevSurface->m_bbox.m_min = plane.origin; pRevSurface->m_bbox.m_min.x -= radius; pRevSurface->m_bbox.m_min.y -= radius; pRevSurface->m_bbox.m_min.z -= radius; pRevSurface->m_bbox.m_max = plane.origin; pRevSurface->m_bbox.m_max.x += radius; pRevSurface->m_bbox.m_max.y += radius; pRevSurface->m_bbox.m_max.z += radius; } return pRevSurface; }
int ON_Intersect( const ON_Line& line, const ON_Arc& arc, double* line_t0, ON_3dPoint& arc_point0, double* line_t1, ON_3dPoint& arc_point1 ) { ON_Circle c = arc; ON_3dPoint p[2]; double t[2], a[2], s; ON_BOOL32 b[2] = {false,false}; int i, xcnt = ON_Intersect( line, c, &t[0], p[0], &t[1], p[1] ); if ( xcnt > 0 ) { // make sure points are on the arc; ON_Interval arc_domain = arc.DomainRadians(); for ( i = 0; i < xcnt; i++ ) { b[i] = c.ClosestPointTo(p[i], &a[i]); if ( b[i] ) { s = arc_domain.NormalizedParameterAt(a[i]); if ( s < 0.0 ) { if ( s >= -ON_SQRT_EPSILON ) { a[i] = arc_domain[0]; p[i] = c.PointAt(a[i]); b[i] = line.ClosestPointTo( p[i], &t[i] ); } else b[i] = false; } else if ( s > 1.0 ) { if ( s <= 1.0+ON_SQRT_EPSILON ) { a[i] = arc_domain[1]; p[i] = c.PointAt(a[i]); b[i] = line.ClosestPointTo( p[i], &t[i] ); } else b[i] = false; } } } if ( !b[0] && !b[1] ) xcnt = 0; if ( xcnt == 2 ) { if ( !b[1] ) xcnt = 1; if ( !b[0] ) { xcnt = 1; b[0] = b[1]; t[0] = t[1]; a[0] = a[1]; p[0] = p[1]; b[1] = 0; } if ( xcnt == 2 && t[0] == t[1] ) { xcnt = 1; b[1] = 0; ON_3dPoint q = line.PointAt(t[0]); if ( p[0].DistanceTo(q) > p[1].DistanceTo(q) ) { a[0] = a[1]; t[0] = t[1]; p[0] = p[1]; } } } if ( xcnt == 1 && !b[0] ) xcnt = 0; if ( xcnt >= 1 ) { if ( line_t0 ) *line_t0 = t[0]; arc_point0 = p[0]; } if ( xcnt == 2 ) { if ( line_t1 ) *line_t1 = t[1]; arc_point1 = p[1]; } } return xcnt; }
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; }