Beispiel #1
0
void SBezier::ClosestPointTo(Vector p, double *t, bool converge) {
    int i;
    double minDist = VERY_POSITIVE;
    *t = 0;
    double res = (deg <= 2) ? 7.0 : 20.0;
    for(i = 0; i < (int)res; i++) {
        double tryt = (i/res);
        
        Vector tryp = PointAt(tryt);
        double d = (tryp.Minus(p)).Magnitude();
        if(d < minDist) {
            *t = tryt;
            minDist = d;
        }
    }

    Vector p0;
    for(i = 0; i < (converge ? 15 : 5); i++) {
        p0 = PointAt(*t);
        if(p0.Equals(p, RATPOLY_EPS)) {
            return;
        }

        Vector dp = TangentAt(*t);
        Vector pc = p.ClosestPointOnLine(p0, dp);
        *t += (pc.Minus(p0)).DivPivoting(dp);
    }
    if(converge) {
        dbp("didn't converge (closest point on bezier curve)");
    }
}
bool ON_PolyEdgeCurve::EvSrfTangent( 
        double t,
        bool bIsoDir,
        ON_3dPoint& srfpoint,
        ON_3dVector& srftangent,
        ON_3dVector& srfnormal
        ) const
{
  ON_3dPoint srfpt;
  ON_3dVector du, dv, duu, duv, dvv;
  bool rc = EvSrfDerivatives(t,srfpoint,du,dv,duu,duv,dvv);
  if (rc )
    rc = ON_EvNormal( 0, du, dv, duu, duv, dvv, srfnormal ) ? true : false;
  if (rc)
  {
    int segment_index = SegmentIndex(t);
    ON_PolyEdgeSegment* seg = SegmentCurve(segment_index);
    if ( seg )
    {
      if ( bIsoDir && seg->IsoType() == ON_Surface::not_iso )
        bIsoDir = false;
      
      ON_3dVector crvtangent = TangentAt(t);
      ON_3dVector binormal = ON_CrossProduct(crvtangent,srfnormal);
      binormal.Unitize();
      if ( seg->ReversedTrimDir() )
        binormal.Reverse();
      // at this point, binormal points "out" and is tangent
      // to the surface.
      if ( bIsoDir )
      {
        du.Unitize();
        dv.Unitize();
        double B_dot_du = binormal*du;
        double B_dot_dv = binormal*dv;
        if ( fabs(B_dot_dv) > fabs(B_dot_du) )
        {
          if (B_dot_dv < 0.0)
            dv.Reverse();
          srftangent = dv;
        }
        else
        {
          if (B_dot_du < 0.0)
            du.Reverse();
          srftangent = du;
        }
      }
      else
        srftangent = binormal;

      if ( seg && seg->m_face && seg->m_face->m_bRev )
        srfnormal.Reverse();
    }
    else
      rc = false;
  }
  return rc;
}
ON_BOOL32 ON_Ellipse::ClosestPointTo( const ON_3dPoint& point, double* t ) const
{
  ON_BOOL32 rc = true;
  if ( t ) {
    ON_2dPoint uv;
    rc = plane.ClosestPointTo( point, &uv.x, &uv.y );
    if ( uv.x == 0.0 ) {
      if ( uv.y == 0.0 ) {
        *t = (radius[0] <= radius[1]) ? 0.0 : 0.5*ON_PI;
        return true;
      }
      if ( uv.y >= radius[1] ) {
        *t = 0.5*ON_PI;
        return true;
      }
      if ( uv.y <= -radius[1] ) {
        *t = 1.5*ON_PI;
        return true;
      }
    }
    else if ( uv.y == 0.0 ) {
      if ( uv.x >= radius[0] ) {
        *t = 0.0;
        return true;
      }
      if ( uv.x <= -radius[0] ) {
        *t = ON_PI;
        return true;
      }
    }
    {
      // use circluar approximation to get a seed value
      double t0, t1;
      *t = atan2( uv.y, uv.x );
      if ( *t < 0.0 )
      {
        *t += 2.0*ON_PI;
        if ( 2.0*ON_PI <= *t)
        {
          // == happens when atan2() <= 0.5*ON_EPSILON*2.0*PI
          *t = 0.0;
        }
      }
      if ( radius[0] != radius[1] ) {
        // set limits for search
        if ( uv.x >= 0.0 ) {
          if ( uv.y >= 0.0 ) {
            // search quadrant I
            t0 = 0.0;
            t1 = 0.5*ON_PI;
          }
          else {
            // search quadrant IV
            t0 = 1.5*ON_PI;
            t1 = 2.0*ON_PI;
          }
        }
        else {
          if ( uv.y >= 0.0 ) {
            // search quadrant II
            t0 = 0.5*ON_PI;
            t1 = ON_PI;
          }
          else {
            // search quadrant III
            t0 = ON_PI;
            t1 = 1.5*ON_PI;
          }
        }

        // solve for closest point using Brent's algorithm
        {
          // 6 October 2003 Dale Lear:
          //    Fixed several serious bugs here.
          // get seed value appropriate for Brent
          double p[4], et, d0, d1, dt;
          int i;
          p[0] = radius[0];
          p[1] = radius[1];
          p[2] = uv.x;
          p[3] = uv.y;
          et = *t;
          if ( et <= t0 )
            et = 0.9*t0 + 0.1*t1;
          else if ( et >= t1 )
            et = 0.9*t1 + 0.1*t0;
          distSqToEllipse( p, t0, &d0, NULL );
          distSqToEllipse( p, t1, &d1, NULL );
          if ( d0 == 0.0 ) {
            *t = (t0 == 2.0*ON_PI) ? 0.0 : t0;
            return true;
          }
          if ( d1 == 0.0 ) {
            *t = (t1 == 2.0*ON_PI) ? 0.0 : t1;
            return true;
          }
          if ( d0 > d1 ) {
            dt = t0; t0 = t1; t1 = dt;
            dt = d0; d0 = d1; d1 = dt;
          }
          *t = (t0 == 2.0*ON_PI) ? 0.0 : t0;
          for ( i = 0; true; i++ ) {
            distSqToEllipse( p, et, &dt, NULL );
            if ( dt < d0 )
            {
              *t = (et >= 2.0*ON_PI) ? 0.0 : et;
              break;
            }
            if ( i >= 100 ) 
            {
              ON_3dPoint E0 = PointAt(t0);
              if (    sqrt(d0) <= ON_ZERO_TOLERANCE 
                   || sqrt(d0) <= ON_SQRT_EPSILON*E0.DistanceTo(Center()) 
                   )
              {
                // Could not find a seed value for dbrent, 
                // but t0 is pretty close.
                return true;
              }
              ON_3dVector T = TangentAt(t0);
              ON_3dVector V = E0 - point;
              if ( V.Unitize() )
              {
                // Could not find a seed value for dbrent, 
                // but V and T are orthoganal, so t0 is 
                // pretty close.
                if ( fabs(V*T) <= 0.087155742747658173558064270837474 )
                  return true;
              }
              return false; // can't get valid seed - bail out
            }
            et = (i) ? (0.5*(t0+et)) : 0.5*(t0+t1);
            if ( et == t0 )
            {
              return true;
            }
          }

          rc = ON_FindLocalMinimum( distSqToEllipse, p,
                            t0, et, t1, 
                            ON_EPSILON,  ON_SQRT_EPSILON, 100,
                            &et );
          rc = (rc > 0) ? true : false;
          if ( rc )
            *t = (et >= 2.0*ON_PI) ? 0.0 : et;
        }
      }
    }
  }
  return rc;
}