Esempio n. 1
0
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;
}
Esempio n. 2
0
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;
}
Esempio n. 3
0
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;
}
Esempio n. 4
0
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;
}
Esempio n. 5
0
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;
}
Esempio n. 6
0
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;
}
Esempio n. 7
0
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);
}
Esempio n. 8
0
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;
}