bool ON_Arc::Create( // arc through 3 3d points const ON_3dPoint& P, // point P const ON_3dPoint& Q, // point Q const ON_3dPoint& R // point R ) { ON_Circle c; double a = 0.0; for (;;) { if ( !c.Create(P,Q,R) ) break; if ( !c.ClosestPointTo( R, &a ) ) break; if ( !(a > 0.0) ) break; if ( !Create( c, ON_Interval(0.0,a) ) ) break; return true; } plane = ON_Plane::World_xy; radius = 0.0; m_angle.Set(0.0,0.0); return false; }
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; }
int ON_Intersect( const ON_Line& line, const ON_Circle& circle, double* line_t0, ON_3dPoint& circle_point0, double* line_t1, ON_3dPoint& circle_point1 ) { // transform to coordinate system where equation of circle // is x^2 + y^2 = R^2 and solve for line parameter(s). ON_Xform xform; xform.ChangeBasis( circle.plane, ON_xy_plane ); xform.ChangeBasis( ON_xy_plane, circle.plane ); ON_Line L = line; L.Transform(xform); double r = fabs(circle.radius); double tol = r*ON_SQRT_EPSILON; if ( tol < ON_ZERO_TOLERANCE ) tol = ON_ZERO_TOLERANCE; int xcnt; if ( fabs(L.from.x - L.to.x) <= tol && fabs(L.from.y - L.to.y) <= tol && fabs(L.from.z - L.to.z) > tol ) { xcnt = 0; } else { xcnt = Intersect2dLineCircle( L.from, L.to, r, tol, line_t0, line_t1 ); if ( xcnt == 3 ) xcnt = 1; } if ( xcnt == 0 ) { if ( L.ClosestPointTo( circle.Center(), line_t0 ) ) { xcnt = 1; *line_t1 = *line_t0; } } ON_3dPoint line_point1, line_point0 = line.PointAt(*line_t0); circle_point0 = circle.ClosestPointTo(line_point0); double d1, d0 = line_point0.DistanceTo(circle_point0); if ( xcnt == 2 ) { line_point1 = line.PointAt(*line_t1); circle_point1 = circle.ClosestPointTo(line_point1); d1 = line_point1.DistanceTo(circle_point1); } else { line_point1 = line_point0; circle_point1 = circle_point0; d1 = d0; } if ( xcnt==2 && (d0 > tol && d1 > tol) ) { xcnt = 1; if ( d0 <= d1 ) { *line_t1 = *line_t0; line_point1 = line_point0; circle_point1 = circle_point0; d1 = d0; } else { *line_t0 = *line_t1; line_point0 = line_point1; circle_point0 = circle_point1; d0 = d1; } } if ( xcnt == 1 && d0 > tol ) { // TODO: iterate to closest point } return xcnt; }