int ON_Intersect( // returns 0 = no intersections, // 1 = one intersection, // 2 = 2 intersections // If 0 is returned, first point is point // on line closest to sphere and 2nd point is the point // on the sphere closest to the line. // If 1 is returned, first point is obtained by evaluating // the line and the second point is obtained by evaluating // the sphere. const ON_Line& line, const ON_Sphere& sphere, ON_3dPoint& A, ON_3dPoint& B // intersection point(s) returned here ) { int rc = 0; const ON_3dPoint sphere_center = sphere.plane.origin; const double sphere_radius = fabs(sphere.radius); double tol = sphere_radius*ON_SQRT_EPSILON; if ( tol < ON_ZERO_TOLERANCE ) tol = ON_ZERO_TOLERANCE; ON_3dPoint line_center = line.ClosestPointTo(sphere_center); double d = line_center.DistanceTo(sphere_center); if ( d >= sphere_radius-tol ) { rc = ( d <= sphere_radius-tol ) ? 1 : 0; A = line_center; B = sphere.ClosestPointTo(line_center); } else { d /= sphere_radius; double h = sphere_radius*sqrt(1.0 - d*d); ON_3dVector V = line.Direction(); V.Unitize(); A = sphere.ClosestPointTo(line_center - h*V); B = sphere.ClosestPointTo(line_center + h*V); d = A.DistanceTo(B); if ( d <= ON_ZERO_TOLERANCE ) { A = line_center; B = sphere.ClosestPointTo(line_center); rc = 1; } else rc = 2; } return rc; }
double ON_Line::MinimumDistanceTo( const ON_Line& L ) const { ON_3dPoint A, B; double a, b, t, x, d; bool bCheckA, bCheckB; bool bGoodX = ON_Intersect(*this,L,&a,&b); bCheckA = true; if ( a < 0.0) a = 0.0; else if (a > 1.0) a = 1.0; else bCheckA=!bGoodX; bCheckB = true; if ( b < 0.0) b = 0.0; else if (b > 1.0) b = 1.0; else bCheckB=!bGoodX; A = PointAt(a); B = L.PointAt(b); d = A.DistanceTo(B); if ( bCheckA ) { L.ClosestPointTo(A,&t); if (t<0.0) t = 0.0; else if (t > 1.0) t = 1.0; x = L.PointAt(t).DistanceTo(A); if ( x < d ) d = x; } if ( bCheckB ) { ClosestPointTo(B,&t); if (t<0.0) t = 0.0; else if (t > 1.0) t = 1.0; x = PointAt(t).DistanceTo(B); if (x < d ) d = x; } return d; }
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; }
int ON_Intersect( // returns 0 = no intersections, // 1 = one intersection, // 2 = 2 intersections // 3 = line lies on cylinder // If 0 is returned, first point is point // on line closest to cylinder and 2nd point is the point // on the sphere closest to the line. // If 1 is returned, first point is obtained by evaluating // the line and the second point is obtained by evaluating // the cylinder. const ON_Line& line, const ON_Cylinder& cylinder, // if cylinder.height[0]==cylinder.height[1], // then infinite cyl is used. Otherwise // finite cyl is used. ON_3dPoint& A, ON_3dPoint& B // intersection point(s) returned here ) { ON_BOOL32 bFiniteCyl = true; int rc = 0; const double cylinder_radius = fabs(cylinder.circle.radius); double tol = cylinder_radius*ON_SQRT_EPSILON; if ( tol < ON_ZERO_TOLERANCE ) tol = ON_ZERO_TOLERANCE; ON_Line axis; axis.from = cylinder.circle.plane.origin + cylinder.height[0]*cylinder.circle.plane.zaxis; axis.to = cylinder.circle.plane.origin + cylinder.height[1]*cylinder.circle.plane.zaxis; if ( axis.Length() <= tol ) { axis.to = cylinder.circle.plane.origin + cylinder.circle.plane.zaxis; bFiniteCyl = false; } //ON_BOOL32 bIsParallel = false; double line_t, axis_t; if ( !ON_Intersect(line,axis,&line_t,&axis_t) ) { axis.ClosestPointTo( cylinder.circle.plane.origin, &axis_t ); line.ClosestPointTo( cylinder.circle.plane.origin, &line_t ); } ON_3dPoint line_point = line.PointAt(line_t); ON_3dPoint axis_point = axis.PointAt(axis_t); double d = line_point.DistanceTo(axis_point); if ( bFiniteCyl ) { if ( axis_t < 0.0 ) axis_t = 0.0; else if ( axis_t > 1.0 ) axis_t = 1.0; axis_point = axis.PointAt(axis_t); } if ( d >= cylinder_radius-tol) { rc = ( d <= cylinder_radius+tol ) ? 1 : 0; A = line_point; ON_3dVector V = line_point - axis_point; if ( bFiniteCyl ) { V = V - (V*cylinder.circle.plane.zaxis)*cylinder.circle.plane.zaxis; } V.Unitize(); B = axis_point + cylinder_radius*V; if ( rc == 1 ) { // check for overlap ON_3dPoint P = axis.ClosestPointTo(line.from); d = P.DistanceTo(line.from); if ( fabs(d-cylinder_radius) <= tol ) { P = axis.ClosestPointTo(line.to); d = P.DistanceTo(line.to); if ( fabs(d-cylinder_radius) <= tol ) { rc = 3; A = cylinder.ClosestPointTo(line.from); B = cylinder.ClosestPointTo(line.to); } } } } else { // transform to coordinate system where equation of cyl // is x^2 + y^2 = R^2 and solve for line parameter(s). ON_Xform xform; xform.Rotation( cylinder.circle.plane, ON_xy_plane ); ON_Line L = line; L.Transform(xform); const double x0 = L.from.x; const double x1 = L.to.x; const double x1mx0 = x1-x0; double ax = x1mx0*x1mx0; double bx = 2.0*x1mx0*x0; double cx = x0*x0; const double y0 = L.from.y; const double y1 = L.to.y; const double y1my0 = y1-y0; double ay = y1my0*y1my0; double by = 2.0*y1my0*y0; double cy = y0*y0; double t0, t1; int qerc = ON_SolveQuadraticEquation(ax+ay, bx+by, cx+cy-cylinder_radius*cylinder_radius, &t0,&t1); if ( qerc == 2 ) { // complex roots - ignore (tiny) imaginary part caused by computational noise. t1 = t0; } A = cylinder.ClosestPointTo(line.PointAt(t0)); B = cylinder.ClosestPointTo(line.PointAt(t1)); d = A.DistanceTo(B); if ( d <= ON_ZERO_TOLERANCE ) { A = line_point; ON_3dVector V = line_point - axis_point; if ( bFiniteCyl ) { V = V - (V*cylinder.circle.plane.zaxis)*cylinder.circle.plane.zaxis; } V.Unitize(); B = axis_point + cylinder_radius*V; rc = 1; } else rc = 2; } return rc; }
bool ON_Intersect( const ON_Line& lineA, const ON_Line& lineB, double* lineA_parameter, double* lineB_parameter ) { // If you are looking at this code because you don't like an // answer you are getting, then the first thing to try is // to read the header file comments and try calling // ON_IntersectLineLine. bool rc = false; double M_zero_tol = 0.0; int i, rank; double pr_tolerance, pivot, X[2], Y[2]; ON_3dVector A = lineA.Direction(); ON_3dVector B = lineB.Direction(); ON_3dVector C = lineB[0] - lineA[0]; ON_Matrix M(2,2); M[0][0] = ON_DotProduct( A, A ); M[1][1] = ON_DotProduct( B, B ); M[0][1] = M[1][0] = -ON_DotProduct( A, B ); // this swap done to get row+col pivot accuracy if ( M[0][0] < M[1][1] ) { M.SwapCols(0,1); i = 1; } else { i = 0; } pr_tolerance = fabs(M[1][1])*ON_SQRT_EPSILON; M_zero_tol = fabs(M[1][1])*ON_EPSILON; Y[0] = ON_DotProduct( A, C ); Y[1] = -ON_DotProduct( B, C ); rank = M.RowReduce( M_zero_tol, Y, &pivot ); if ( rank == 2 ) { // 19 November 2003 Dale Lear and Chuck // Added lineA.from/to == lineB.from/to tests // so exact answer gets returned when people // expect it. rc = true; if ( lineA.from == lineB.from ) { if ( lineA_parameter ) *lineA_parameter = 0.0; if ( lineB_parameter ) *lineB_parameter = 0.0; } else if ( lineA.from == lineB.to ) { if ( lineA_parameter ) *lineA_parameter = 0.0; if ( lineB_parameter ) *lineB_parameter = 1.0; } else if ( lineA.to == lineB.from ) { if ( lineA_parameter ) *lineA_parameter = 1.0; if ( lineB_parameter ) *lineB_parameter = 0.0; } else if ( lineA.to == lineB.to ) { if ( lineA_parameter ) *lineA_parameter = 1.0; if ( lineB_parameter ) *lineB_parameter = 1.0; } else { rc = M.BackSolve( 0.0, 2, Y, X ); if ( rc ) { if ( lineA_parameter ) *lineA_parameter = X[i]; if ( lineB_parameter ) *lineB_parameter = X[1-i]; if ( fabs(pivot) <= pr_tolerance ) { // test answer because matrix was close to singular // (This test is slow but it is rarely used.) ON_3dPoint pA = lineA.PointAt(X[i]); ON_3dPoint pB = lineB.PointAt(X[1-i]); double d = pA.DistanceTo(pB); if ( d > pr_tolerance && d > ON_ZERO_TOLERANCE ) { ON_3dPoint qA = lineA.ClosestPointTo(pB); ON_3dPoint qB = lineB.ClosestPointTo(pA); double dA = pA.DistanceTo(qB); double dB = pB.DistanceTo(qA); if ( 1.1*dA < d ) { rc = false; } else if ( 1.1*dB < d ) { rc = false; } } } } } } return rc; }
bool ON_Line::IsFartherThan( double d, const ON_Line& L ) const { ON_3dPoint A, B; double a, b, t, x; bool bCheckA, bCheckB; a = from.x; if (to.x < a) {b=a; a = to.x;} else b = to.x; if ( b+d < L.from.x && b+d < L.to.x ) return true; if ( a-d > L.from.x && a-d > L.to.x ) return true; a = from.y; if (to.y < a) {b=a; a = to.y;} else b = to.y; if ( b+d < L.from.y && b+d < L.to.y ) return true; if ( a-d > L.from.y && a-d > L.to.y ) return true; a = from.z; if (to.z < a) {b=a; a = to.z;} else b = to.z; if ( b+d < L.from.z && b+d < L.to.z ) return true; if ( a-d > L.from.z && a-d > L.to.z ) return true; if ( !ON_Intersect(*this,L,&a,&b) ) { // lines are parallel or anti parallel if ( Direction()*L.Direction() >= 0.0 ) { // lines are parallel a = 0.0; L.ClosestPointTo(from,&b); // If ( b >= 0.0), then this->from and L(b) are a pair of closest points. if ( b < 0.0 ) { // Othersise L.from and this(a) are a pair of closest points. b = 0.0; ClosestPointTo(L.from,&a); } } else { // lines are anti parallel a = 1.0; L.ClosestPointTo(to,&b); // If ( b >= 0.0), then this->to and L(b) are a pair of closest points. if ( b < 0.0 ) { // Othersise L.to and this(a) are a pair of closest points. b = 0.0; ClosestPointTo(L.from,&a); } } } A = PointAt(a); B = L.PointAt(b); x = A.DistanceTo(B); if (x > d) return true; bCheckA = true; if ( a < 0.0) a = 0.0; else if (a > 1.0) a = 1.0; else bCheckA=false; if (bCheckA ) { A = PointAt(a); L.ClosestPointTo(A,&t); if (t<0.0) t = 0.0; else if (t > 1.0) t = 1.0; x = L.PointAt(t).DistanceTo(A); } bCheckB = true; if ( b < 0.0) b = 0.0; else if (b > 1.0) b = 1.0; else bCheckB=false; if ( bCheckB ) { B = L.PointAt(b); ClosestPointTo(B,&t); if (t<0.0) t = 0.0; else if (t > 1.0) t = 1.0; t = PointAt(t).DistanceTo(B); if ( bCheckA ) { if ( t<x ) x = t; } else { x = t; } } return (x > d); }
int ON_ArePointsOnLine( // returns 0=no, 1 = yes, 2 = pointset is (to tolerance) a single point on the line int dim, // 2 or 3 int is_rat, int count, int stride, const double* point, const ON_BoundingBox& bbox, // if needed, use ON_GetBoundingBox(dim,is_rat,count,stride,point) const ON_Line& line, // line to test double tolerance ) { double w; int i, j, k; if ( count < 1 ) return 0; if ( !line.IsValid() ) { ON_ERROR("line parameter not valid"); return 0; } if ( !bbox.IsValid() ) { ON_ERROR("bbox parameter not valid"); return 0; } if ( !ON_IsValid(tolerance) || tolerance < 0.0 ) { ON_ERROR("tolerance parameter not valid"); return 0; } if ( dim < 2 || dim > 3 ) { ON_ERROR("dim parameter not valid"); return 0; } if ( 0 == point ) { ON_ERROR("point parameter not valid"); return 0; } if ( stride < (is_rat?(dim+1):dim) ) { ON_ERROR("stride parameter not valid"); return 0; } int rc = 0; if ( tolerance == 0.0 ) { tolerance = bbox.Tolerance(); } ON_3dPoint Q; // test bounding box to quickly detect the common coordinate axis cases rc = (count == 1 || bbox.Diagonal().Length() <= tolerance) ? 2 : 1; for ( i = 0; rc && i < 2; i++ ) { Q.x = bbox[i].x; for ( j = 0; rc && j < 2; j++) { Q.y = bbox[j].y; for ( k = 0; rc && k < 2; k++) { Q.z = bbox[k].z; if ( Q.DistanceTo( line.ClosestPointTo( Q ) ) > tolerance ) rc = 0; } } } if ( !rc ) { // test points one by one Q.Zero(); rc = (count == 1 || bbox.Diagonal().Length() <= tolerance) ? 2 : 1; if ( is_rat ) { for ( i = 0; i < count; i++ ) { w = point[dim]; if ( w == 0.0 ) { ON_ERROR("rational point has zero weight"); return 0; } ON_ArrayScale( dim, 1.0/w, point, &Q.x ); if ( Q.DistanceTo( line.ClosestPointTo( Q ) ) > tolerance ) { rc = 0; break; } point += stride; } } else { for ( i = 0; i < count; i++ ) { memcpy( &Q.x, point, dim*sizeof(Q.x) ); if ( Q.DistanceTo( line.ClosestPointTo( Q ) ) > tolerance ) { rc = 0; break; } point += stride; } } } return rc; }