RH_C_FUNCTION int ON_RayShooter_OneSurface(ON_3DPOINT_STRUCT _point, ON_3DVECTOR_STRUCT _direction, const ON_Surface* pConstSurface, ON_SimpleArray<ON_3dPoint>* pPoints, int maxReflections)
{
  int rc = 0;
  ON_3dPoint point(_point.val[0], _point.val[1], _point.val[2]);
  ON_3dVector direction(_direction.val[0], _direction.val[1], _direction.val[2]);
  if( pConstSurface && pPoints && maxReflections>0 && point.IsValid() && direction.Unitize() )
  {
    ON_RayShooter shooter;
    ON_X_EVENT hit;
    ON_3dPoint Q = point;
    ON_3dVector R = direction;
    ON_3dVector V[3];
    for( int i=0; i<maxReflections; i++ )
    {
      memset(&hit,0,sizeof(hit));
      ON_3dVector T = R;
      if( !T.Unitize() )
        break;
      if( !shooter.Shoot(Q,T,pConstSurface,hit) )
        break;
      Q = hit.m_A[0];
      pPoints->Append(Q);
      if( !hit.m_snodeB[0] )
        break;
      hit.m_snodeB[0]->Evaluate(hit.m_b[0], hit.m_b[1], 1, 3, &V[0].x);
      ON_3dVector N = ON_CrossProduct(V[1],V[2]);
      if ( !N.Unitize() )
        break;
      double d = N*T;
      R = T + (-2.0*d)*N; // R = reflection direction
    }
    rc = pPoints->Count();
  }
  return rc;
}
// Try to make up a 1st derivative if one is zero length
static void CookDerivativesHelper( ON_3dVector& du, ON_3dVector& dv, ON_3dVector& duu, ON_3dVector& duv, ON_3dVector& dvv)
{
  bool du_ok = du.LengthSquared() > ON_SQRT_EPSILON;
  bool dv_ok = dv.LengthSquared() > ON_SQRT_EPSILON;

  if( !du_ok || !dv_ok)
  {
    ON_3dVector normal;
    bool normal_ok = ON_EvNormal( 0, du, dv, duu, duv, dvv, normal ) ? true : false;
    if( normal_ok)
      normal_ok = normal.LengthSquared() > ON_SQRT_EPSILON;
   
    if( normal_ok)
    {
      if(( !du_ok) && ( dv_ok && normal_ok))
      {
        du = ON_CrossProduct( dv, normal);
        du_ok = du.Unitize();
        du *= (0.00390625*dv.Length());
      }
      if( du_ok && ( !dv_ok) && normal_ok)
      {
        dv = ON_CrossProduct( normal, du);
        dv_ok = dv.Unitize();
        dv *= (0.00390625*du.Length());
      }
    }
  }
}  
ON_3dPoint ON_Torus::ClosestPointTo( ON_3dPoint test_point ) const
{
  const ON_Circle major_circle(plane,major_radius);
  ON_3dPoint C = major_circle.ClosestPointTo( test_point );
  ON_3dVector v = test_point - C;
  if ( !v.Unitize() )
  {
    v = C - plane.origin;
    v.Unitize();
  }
  return C + minor_radius*v;
}
Exemple #4
0
ON_3dPoint ON_Circle::ClosestPointTo( const ON_3dPoint& point ) const
{
  ON_3dPoint P;
  ON_3dVector V = plane.ClosestPointTo( point ) - Center();
  if ( V.Unitize() ) {
    V.Unitize();
    P = Center() + Radius()*V;
  }
  else {
    P = PointAt(0.0);
  }
  return P;
}
Exemple #5
0
ON_3dVector ON_Light::PerpindicularDirection() const
{
  // returns a consistent vector perpendicular to the
  // light's direction.  This vector is useful for
  // user interface display.
  ON_3dVector dir = m_direction;
  if ( !dir.IsValid() || !dir.Unitize() )
    return ON_UNSET_VECTOR;

  ON_3dVector xdir;
  if ( IsLinearLight() || IsRectangularLight() )
  {
    xdir = m_length;
    if ( xdir.IsValid() && xdir.Unitize() && fabs(xdir*dir) <= ON_SQRT_EPSILON )
      return xdir;
  }

  if( dir.IsParallelTo( ON_zaxis, ON_DEGREES_TO_RADIANS * 3.0))
    xdir = ON_CrossProduct( dir, ON_xaxis);
  else
    xdir = ON_CrossProduct( dir, ON_zaxis);
  xdir.Unitize();
  ON_3dVector ydir = ON_CrossProduct(dir,xdir);
  ydir.Unitize();
  ON_3dVector right;

  switch(dir.MaximumCoordinateIndex())
  {
  case 0:
    right = (fabs(xdir.y) > fabs(ydir.y)) ? xdir : ydir;
    if ( right.y < 0.0 )
      right.Reverse();
    break;
  case 1:
  case 2:
    right = (fabs(xdir.x) > fabs(ydir.x)) ? xdir : ydir;
    if ( right.x < 0.0 )
      right.Reverse();
    break;
  default:
    right = xdir;
    break;
  }

  if ( right[right.MaximumCoordinateIndex()] < 0.0 )
    right.Reverse();

  return right;  
}
ON_BOOL32 ON_Torus::ClosestPointTo( 
         ON_3dPoint test_point, 
         double* major__angle_radians, 
         double* minor__angle_radians
       ) const
{
  double major_angle_radians, minor_angle_radians;
  const ON_Circle major_circle(plane,major_radius);
  ON_BOOL32 rc = major_circle.ClosestPointTo( test_point, &major_angle_radians );
  if ( rc && minor__angle_radians )
  {
    EVAL_SETUP_MAJOR;
    ON_3dVector v = test_point - major_radius*raxis;
    rc = v.Unitize();
    if ( rc )
    {
      double sma = v*plane.zaxis;
      double cma = v*raxis;
      minor_angle_radians = atan2(sma,cma);
      if ( minor_angle_radians < 0.0 )
        minor_angle_radians += 2.0*ON_PI;
    }
    else
      minor_angle_radians = 0.0;
    *minor__angle_radians = minor_angle_radians;
  }
  if ( major__angle_radians )
    *major__angle_radians = major_angle_radians;
  return rc;
}
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_3dVector ON_Ellipse::TangentAt( 
                 double t // parameter
                 ) const
{
  ON_3dVector T = DerivativeAt( 1, t );
  T.Unitize();
  return T;
}
bool ON_Quaternion::GetRotation(double& angle, ON_3dVector& axis) const
{
  const double s = Length();
  angle = (s > ON_DBL_MIN) ? 2.0*acos(a/s) : 0.0;
  axis.x = b;
  axis.y = c;
  axis.z = d;
  return (axis.Unitize() && s > ON_DBL_MIN);
}
Exemple #10
0
void arbaxis(const ON_3dVector& givenaxis, ON_3dVector& newaxis)
{
  if(fabs(givenaxis[0]) < ARBBOUND && fabs(givenaxis[1]) < ARBBOUND) // near world z
    newaxis = ON_CrossProduct(ON_yaxis, givenaxis);
  else
    newaxis = ON_CrossProduct(ON_zaxis, givenaxis);

  newaxis.Unitize();
}
Exemple #11
0
static double Angle3d(const ON_3dVector& axis, ON_3dVector& from, const ON_3dVector& to)
{
  ON_3dVector x = from, a = to;
  x.Unitize();
  a.Unitize();

  ON_3dVector y = ON_CrossProduct(axis, from);
  y.Unitize();

  double cosa = x * a;

  if(cosa > 1.0 - ON_SQRT_EPSILON)
    return 0.0;
  if(cosa < ON_SQRT_EPSILON - 1.0)
    return ON_PI;

  double sina = a * y;

  return atan2(sina, cosa);
}
Exemple #12
0
bool ON_Cone::ClosestPointTo(
          ON_3dPoint point,
          double* radial_parameter,
          double* height_parameter
       ) const
{
  // untested code

  bool rc = false;

  ON_3dVector v = (point-plane.origin);
  double x = v*plane.xaxis;
  double y = v*plane.yaxis;
  double z = v*plane.zaxis;

  if ( radial_parameter )
  {
    double a = ( 0.0 == y && 0.0 == x ) ? 0.0 : atan2(y,x);

    if (a > 2.0*ON_PI )
    {
      a -= 2.0*ON_PI;
    }

    if (a < 0.0 )
    {
      a += 2.0*ON_PI;
    }

    *radial_parameter = a;
  }

  if (height_parameter)
  {
    point.x -= plane.origin.x;
    point.y -= plane.origin.y;
    point.z -= plane.origin.z;
    v.x = x;
    v.y = y;
    v.z = 0.0;
    v.Unitize();
    v.x *= radius;
    v.y *= radius;
    ON_Line line(ON_origin, v.x*plane.xaxis + v.y*plane.yaxis + height*plane.zaxis );
    rc = line.ClosestPointTo(point,&z);
    if (rc)
    {
      *height_parameter = z*height;
    }
  }

  return rc;
}
Exemple #13
0
ON_3dVector ON_Cone::NormalAt( double radial_parameter, double height_parameter ) const
{
  double s = sin(radial_parameter);
  double c = cos(radial_parameter);
  if ( radius<0.) {
    c = -c;
    s = -s;
  }
  ON_3dVector ds = c*plane.yaxis - s*plane.xaxis;
  ON_3dVector N = ON_CrossProduct( ((radius<0.0)?-ds:ds),
                                   plane.PointAt(radius*c,radius*s,height) - plane.origin
                                   );
  N.Unitize();
  return N;
}
RH_C_FUNCTION ON_AngularDimension2* ON_AngularDimension2_New(ON_Arc* arc, double offset)
{
  ON_AngularDimension2* rc = NULL;
  if( arc )
  {
    rc = new ON_AngularDimension2();
    ON_3dVector v = arc->StartPoint()-arc->Center();
    v.Unitize();
    ON_3dPoint apex = arc->Center();
    ON_3dPoint p0 = arc->StartPoint();
    ON_3dPoint p1 = arc->EndPoint();
    ON_3dPoint arc_pt = p0 + ( v * offset );
    ON_3dVector normal = arc->Normal();
    rc->CreateFromPoints(apex, p0, p1, arc_pt, normal);
  }
  return rc;
}
Exemple #15
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;
}
Exemple #16
0
bool ON_Line::InPlane( ON_Plane& plane, double tolerance ) const
{
  const ON_3dVector v = to-from;
  const bool bTinyX = fabs(v.x) <= tolerance;
  const bool bTinyY = fabs(v.y) <= tolerance;
  const bool bTinyZ = fabs(v.z) <= tolerance;
  bool rc = true;
  ON_3dVector X;
  ON_3dVector Y;
  if ( bTinyZ && ( !bTinyX || !bTinyY ) )
  {
    X = ON_xaxis;
    Y = ON_yaxis;
  }
  else if ( bTinyX && ( !bTinyY || !bTinyZ ) )
  {
    X = ON_yaxis;
    Y = ON_zaxis;
  }
  else if ( bTinyY && ( !bTinyZ || !bTinyX ) )
  {
    X = ON_zaxis;
    Y = ON_xaxis;
  }
  else
  {
    X = v;
    X.Unitize();
    Y.PerpendicularTo(X);
    if ( bTinyX && bTinyY && bTinyZ )
    {
      rc = false;
      if ( X.IsZero() )
      {
        X = ON_xaxis;
        Y = ON_yaxis;
      }
    }
  }
  plane.CreateFromFrame( from, X, Y );
  return rc;
}
Exemple #17
0
bool ON_Plane::IsValid() const
{
  if ( !plane_equation.IsValid() )
    return false;


  double x = plane_equation.ValueAt(origin);
  if ( fabs(x) >  ON_ZERO_TOLERANCE )
  {
    double tol = fabs(origin.MaximumCoordinate()) + fabs(plane_equation.d);
    if ( tol > 1000.0 && origin.IsValid() )
    {
      // 8 September 2003 Chuck and Dale:
      //   Fixing discrepancy between optimized and debug behavior.
      //   In this case, the ON_ZERO_TOLERANCE test worked in release
      //   and failed in debug. The principal behind this fix is valid
      //   for release builds too.
      //   For large point coordinates or planes far from the origin,
      //   the best we can hope for is to kill the first 15 or so decimal
      //   places.
      tol *= (ON_EPSILON*10.0);
      if ( fabs(x) > tol )
        return false;
    }
    else
      return false;
  }

  if ( !ON_IsRightHandFrame( xaxis, yaxis, zaxis ) )
    return false;

  ON_3dVector N = plane_equation;
  N.Unitize();
  x = ON_DotProduct( N, zaxis );
  if ( fabs(x-1.0) >  ON_SQRT_EPSILON )
    return false;

  return true;
}
Exemple #18
0
bool ON_Plane::GetDistanceToBoundingBox(const ON_BoundingBox& Box,
				                                double* min, double* max) const
{
  //min and max signed distance.  Returns false if plane normal has zero length.

  ON_3dVector UnitNormal = Normal();
  if (!UnitNormal.Unitize()) 
    return false;

  double mind, maxd;
  mind = maxd = (Box.Min() - Origin())*UnitNormal;
  int i0, i1, i2;
  for (i0=0;i0<2;i0++)
  {
    for(i1=0;i1<2;i1++) 
    {
      for (i2=0;i2<2;i2++) 
      {
        if (i0||i1||i2) 
        {
          ON_3dPoint P;
          P[0]=(i0)?Box.Max()[0]:Box.Min()[0];
          P[1]=(i1)?Box.Max()[1]:Box.Min()[1];
          P[2]=(i2)?Box.Max()[2]:Box.Min()[2];
          double d = (P - Origin())*UnitNormal;
          //double dd = P.DistanceTo(ClosestPointTo(P));
          if (d < mind) 
            mind=d;
          else if (d > maxd) 
            maxd=d;
        }
      }
    }
  }
  *min = mind;
  *max = maxd;
  return true;
}
Exemple #19
0
// returns point on cylinder that is closest to given point
ON_3dPoint ON_Cone::ClosestPointTo(
       ON_3dPoint point
       ) const
{
  // untested code

  ON_3dVector v = (point-plane.origin);
  double x = v*plane.xaxis;
  double y = v*plane.yaxis;
  //double z = v*plane.zaxis;

  point.x -= plane.origin.x;
  point.y -= plane.origin.y;
  point.z -= plane.origin.z;
  v.x = x;
  v.y = y;
  v.z = 0.0;
  v.Unitize();
  v.x *= radius;
  v.y *= radius;
  ON_Line line(ON_origin, v.x*plane.xaxis + v.y*plane.yaxis + height*plane.zaxis );
  return line.ClosestPointTo(point);
}
Exemple #20
0
ON_3dVector ON_Polyline::SegmentTangent( int segment_index ) const
{
    ON_3dVector v = SegmentDirection(segment_index);
    v.Unitize();
    return v;
}
Exemple #21
0
int ON_Intersect( const ON_Sphere& sphere0, 
                  const ON_Sphere& sphere1, 
                  ON_Circle& circle
                 )

{
  double r0 = sphere0.Radius();
  double r1 = sphere1.Radius();
  ON_3dPoint C0 = sphere0.Center();
  ON_3dPoint C1 = sphere1.Center();
  ON_3dVector D = C1-C0;
  double d = D.Length();
  if (!D.Unitize()){
    if (fabs(r1-r0) > ON_ZERO_TOLERANCE)
      return 0;//Same center, different radii
    return 3;//Same sphere.
  }

  //Spheres are appart.
  if (d > r0 + r1)
    return 0;

  //Spheres tangent and appart
  if (d == r0+r1){
    ON_3dPoint P = C0 + r0*D;
    circle.Create(P, 0.0);
    return 1;
  }

  //Spheres tangent, one inside the other
  if (d == fabs(r0-r1)){
    ON_3dPoint P = (r0 > r1) ? C0 + r0*D : C0 - r0*D;
    circle.Create(P, 0.0);
    return 1;
  }

  //Spheres don't intersect, one inside the other.
  if (d < fabs(r0-r1))
    return 0;

  //Intersection is a circle
  double x = 0.5*(d*d + r0*r0 - r1*r1)/d;
  if (x >= r0){//Shouldn't happen
    ON_3dPoint P = C0 + r0*D;
    circle.Create(P, 0.0);
    return 1;
  }
  if (x <= -r0){//Shouldn't happen
    ON_3dPoint P = C0 - r0*D;
    circle.Create(P, 0.0);
    return 1;
  }
  double y = r0*r0 - x*x;
  if (y < 0.0)//Shouldn't happen
    return 0;
  y = sqrt(y);

  ON_3dPoint P = C0 + x*D;
  ON_Plane plane(P, D);
  circle.Create(plane, y);
  return 2;
}
Exemple #22
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;
}
RH_C_FUNCTION int ON_RayShooter_ShootRay(ON_3DPOINT_STRUCT _point, ON_3DVECTOR_STRUCT _direction,
                                           const ON_SimpleArray<const ON_Geometry*>* pConstGeometryArray,
                                           ON_SimpleArray<ON_3dPoint>* pPoints, int maxReflections)
{
  int rc = 0;
  ON_3dPoint point(_point.val[0], _point.val[1], _point.val[2]);
  ON_3dVector direction(_direction.val[0], _direction.val[1], _direction.val[2]);

  // Currently only supports surfaces and breps with untrimmed faces.
  // Add support for meshes and trimmed breps

  int count = pConstGeometryArray?pConstGeometryArray->Count():0;
  if( count<1 )
    return 0;
  ON_SimpleArray<const ON_SurfaceTreeNode*> snode_list(count);
  for ( int i=0; i<count; i++ )
  {
    const ON_Geometry* pGeometry = (*pConstGeometryArray)[i];
    const ON_Surface* surface = ON_Surface::Cast(pGeometry);
    if ( surface )
    {
      const ON_SurfaceTree* stree = surface->SurfaceTree();
      if ( stree )
        snode_list.Append(stree);
      continue;
    }
    const ON_Brep* brep = ON_Brep::Cast(pGeometry);
    if( brep )
    {
      for( int fi=0; fi<brep->m_F.Count(); fi++ )
      {
        const ON_SurfaceTree* stree = brep->m_F[fi].SurfaceTree();
        if( stree )
        snode_list.Append(stree);
      }
      continue;
    }
  }
  if( snode_list.Count()<1 )
    return 0;

  if( pPoints && maxReflections>0 && point.IsValid() && direction.Unitize() )
  {
    ON_RayShooter shooter;
    ON_X_EVENT hit;
    ON_3dPoint Q = point;
    ON_3dVector R = direction;
    ON_3dVector V[3];
    for( int i=0; i<maxReflections; i++ )
    {
      memset(&hit,0,sizeof(hit));
      ON_3dVector T = R;
      if( !T.Unitize() )
        break;
      if( !shooter.Shoot(Q,T,snode_list,hit) )
        break;
      Q = hit.m_A[0];
      pPoints->Append(Q);
      if( !hit.m_snodeB[0] )
        break;

      ON_3dVector N = hit.m_B[1]; // surface normal
      double d = -2.0*(N.x*T.x + N.y*T.y + N.z*T.z);
      R.x = T.x + d*N.x;
      R.y = T.y + d*N.y;
      R.z = T.z + d*N.z;

      // Part of the fix for RR 22717.  See opennurbs_plus_xray.cpp
      // for the rest of the fix.
      d = hit.m_A[0].DistanceTo( hit.m_B[0] );
      shooter.m_min_travel_distance = d;
      if( shooter.m_min_travel_distance < 1.0e-8 )
        shooter.m_min_travel_distance = 1.0e-8;
    }
    rc = pPoints->Count();
  }
  return rc;
}
// Copied from opennurbs_intersect.cpp but with a bug fix.
// We can remove it once the bug is fixed in OpenNurbs and once 
// Grasshopper has dropped Rhino4 support.
int PS_Intersect(
        const ON_Plane& plane,
        const ON_Sphere& sphere, 
        ON_Circle& circle
        )
{
  // 16 April 2011 Dale Lear
  //   Prior to this date, this function did not return the correct answer.

  int rc = 0;
  const double sphere_radius = fabs(sphere.radius);
  double tol = sphere_radius*ON_SQRT_EPSILON;
  if ( !(tol >= ON_ZERO_TOLERANCE) )
    tol = ON_ZERO_TOLERANCE;
  const ON_3dPoint sphere_center = sphere.Center();
  ON_3dPoint circle_center = plane.ClosestPointTo(sphere_center);
  double d = circle_center.DistanceTo(sphere_center);

  circle.radius = 0.0;

  if ( ON_IsValid(sphere_radius) && ON_IsValid(d) && d <= sphere_radius + tol )
  {
    if ( sphere_radius > 0.0 )
    {
      d /= sphere_radius;
      d = 1.0 - d*d;
      // The d > 4.0*ON_EPSILON was picked by testing spheres with
      // radius = 1 and center = (0,0,0).  Do not make 4.0*ON_EPSILON 
      // any smaller and please discuss changes with Dale Lear.
      circle.radius = (d > 4.0*ON_EPSILON) ? sphere_radius*sqrt(d) : 0.0;
    }
    else
      circle.radius = 0.0;

    if ( circle.radius <= ON_ZERO_TOLERANCE )
    {
      // return a single point
      rc = 1;
      
      circle.radius = 0.0;

      //  When tolerance is in play, put the point on the sphere.
      //  If the caller prefers the plane, then they can adjust the
      //  returned answer to get the plane.
      ON_3dVector R = circle_center - sphere_center;
      double r0 = R.Length();
      if ( r0 > 0.0 )
      {
        R.Unitize();
        ON_3dPoint C1 = sphere_center + sphere_radius*R;
        double r1 = C1.DistanceTo(sphere_center);
        if ( fabs(sphere.radius-r1) < fabs(sphere.radius-r0) )
          circle_center = C1;
      }
    }
    else 
    {
      // return a circle
      rc = 2;
    }
  }

  // Update circle's plane here in case the input plane 
  // is the circle's plane member.
  circle.plane = plane;
  circle.plane.origin = circle_center;
  circle.plane.UpdateEquation();

  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;
}
Exemple #26
0
bool ON_Mesh::CollapseEdge( int topei )
{
  ON_Mesh& mesh = *this;

  ON__MESHEDGE me;
  memset(&me,0,sizeof(me));
  const ON_MeshTopology& top = mesh.Topology();  
  const int F_count = mesh.m_F.Count();
  const int V_count = mesh.m_V.Count();
  const int topv_count = top.m_topv.Count();
  //const int tope_count = top.m_tope.Count();

  if ( topei < 0 || topei >= top.m_tope.Count() )
  {
    return false;
  }

  const ON_MeshTopologyEdge& tope = top.m_tope[topei];

  if (    tope.m_topf_count < 1 
       || tope.m_topvi[0] == tope.m_topvi[1] 
       || tope.m_topvi[0] < 0
       || tope.m_topvi[1] < 0
       || tope.m_topvi[0] >= topv_count
       || tope.m_topvi[1] >= topv_count )
  {
    return false;
  }

  const ON_MeshTopologyVertex& topv0 = top.m_topv[tope.m_topvi[0]];
  const ON_MeshTopologyVertex& topv1 = top.m_topv[tope.m_topvi[1]];
  if ( topv0.m_v_count < 1 || topv1.m_v_count < 1 )
  {
    return false;
  }
  if ( topv0.m_vi[0] < 0 || topv0.m_vi[0] >= V_count )
  {
    return false;
  }
  if ( topv1.m_vi[0] < 0 || topv1.m_vi[0] >= V_count )
  {
    return false;
  }
  
  // create a ON__MESHEDGE for each face (usually one or two) that uses the edge
  ON__MESHEDGE* me_list = (ON__MESHEDGE*)alloca(tope.m_topf_count*sizeof(me_list[0]));
  int me_list_count = 0;
  int efi;
  for ( efi = 0; efi < tope.m_topf_count; efi++ )
  {
    int fi = tope.m_topfi[efi];
    if ( fi < 0 || fi >= F_count )
      continue;
    const ON_MeshFace& f = mesh.m_F[fi];
    if ( !f.IsValid(V_count) )
      continue;
    me.vi1 = f.vi[3];
    me.topvi1 = top.m_topv_map[me.vi1];
    int fvi;
    for ( fvi = 0; fvi < 4; fvi++ )
    {
      me.vi0 = me.vi1;
      me.topvi0 = me.topvi1;
      me.vi1 = f.vi[fvi];
      me.topvi1 = top.m_topv_map[me.vi1];
      if ( me.vi0 != me.vi1 )
      {
        if (    (me.topvi0 == tope.m_topvi[0] && me.topvi1 == tope.m_topvi[1])
             || (me.topvi0 == tope.m_topvi[1] && me.topvi1 == tope.m_topvi[0]) )
        {
          if ( me.vi0 > me.vi1 )
          {
            int i = me.vi0; me.vi0 = me.vi1; me.vi1 = i;
            i = me.topvi0; me.topvi0 = me.topvi1; me.topvi1 = i;
          }
          me_list[me_list_count++] = me;
          break;
        }
      }
    }
  }

  if (me_list_count<1)
  {
    return false;
  }

  // Sort me_list[] so edges using same vertices are adjacent
  // to each other in the list.  This is needed so that non-manifold
  // crease edges will be properly collapsed.
  ON_qsort(me_list,me_list_count,sizeof(me_list[0]),(QSORTCMPFUNC)CompareMESHEDGE);

  // create new vertex or vertices that edge will be
  // collapsed to.
  mesh.m_C.Destroy();
  mesh.m_K.Destroy();
  
  int mei;
  bool bHasVertexNormals = mesh.HasVertexNormals();
  bool bHasTextureCoordinates = mesh.HasTextureCoordinates();
  bool bHasFaceNormals = mesh.HasFaceNormals();
  if ( topv0.m_v_count == 1 || topv1.m_v_count == 1 )
  {
    // a single new vertex
    ON_Line Vline(ON_origin,ON_origin);
    ON_Line Tline(ON_origin,ON_origin);
    ON_3dVector N0(0,0,0);
    ON_3dVector N1(0,0,0);
    ON_3dPoint P;
    int vi, tvi, cnt;

    int newvi = topv0.m_vi[0];

    cnt = 0;
    for ( tvi = 0; tvi < topv0.m_v_count; tvi++ )
    {
      vi = topv0.m_vi[tvi];
      if ( vi < 0 || vi > V_count )
        continue;
      if ( vi < newvi )
        newvi = vi;
      cnt++;
      P = mesh.m_V[vi];
      Vline.from += P;
      if ( bHasVertexNormals )
      {
        N0 += ON_3dVector(mesh.m_N[vi]);
      }
      if ( bHasTextureCoordinates )
      {
        P = mesh.m_T[vi];
        Tline.from += P;
      }
    }

    if (cnt > 1)
    {
      double s = 1.0/((double)cnt);
      Vline.from.x *= s;
      Vline.from.y *= s;
      Vline.from.z *= s;
      Tline.from.x *= s;
      Tline.from.y *= s;
      Tline.from.z *= s;
      N0 = s*N0;
    }

    cnt = 0;
    for ( tvi = 0; tvi < topv1.m_v_count; tvi++ )
    {
      vi = topv1.m_vi[tvi];
      if ( vi < 0 || vi > V_count )
        continue;
      if ( vi < newvi )
        newvi = vi;
      cnt++;
      P = mesh.m_V[vi];
      Vline.to += P;
      if ( bHasVertexNormals )
      {
        N1 += ON_3dVector(mesh.m_N[vi]);
      }
      if ( bHasTextureCoordinates )
      {
        P = mesh.m_T[vi];
        Tline.to += P;
      }
    }

    if (cnt > 1)
    {
      double s = 1.0/((double)cnt);
      Vline.to.x *= s;
      Vline.to.y *= s;
      Vline.to.z *= s;
      Tline.to.x *= s;
      Tline.to.y *= s;
      Tline.to.z *= s;
      N1 = s*N1;
    }

    ON_3fPoint newV(Vline.PointAt(0.5));
    ON_3fVector newN;
    ON_2fPoint newT;
    if ( bHasVertexNormals )
    {
      N0.Unitize();
      N1.Unitize();
      ON_3dVector N = N0+N1;
      if ( !N.Unitize() )
      {
        N = (topv0.m_v_count == 1) ? mesh.m_N[topv0.m_vi[0]] :mesh.m_N[topv1.m_vi[0]];
      }
      newN = N;
    }
    if ( bHasTextureCoordinates )
    {
      newT = Tline.PointAt(0.5);
    }
    for ( mei = 0; mei < me_list_count; mei++ )
    {
      me_list[mei].newvi = newvi;
      me_list[mei].newV = newV;
      me_list[mei].newN = newN;
      me_list[mei].newT = newT;
    }
  }
  else
  {
    // collapsing a "crease" edge - attempt to preserve
    // the crease.
    memset(&me,0,sizeof(me));
    me.vi0 = -1;
    me.vi1 = -1;
    for ( mei = 0; mei < me_list_count; mei++ )
    {
      if ( 0 == mei && CompareMESHEDGE(&me,me_list+mei) )
      {
        // cook up new vertex
        me_list[mei].newvi = mesh.m_V.Count();
        me = me_list[mei];
        ON_Line line;
        line.from = mesh.m_V[me.vi0];
        line.to   = mesh.m_V[me.vi1];
        me.newV = line.PointAt(0.5);
        if ( bHasVertexNormals )
        {
          ON_3dVector N0(mesh.m_N[me.vi0]);
          ON_3dVector N1(mesh.m_N[me.vi1]);
          ON_3dVector N = N0 + N1;
          if ( !N.Unitize() )
            N = N0;
          me.newN = N;
        }
        if ( bHasTextureCoordinates )
        {
          line.from = mesh.m_T[me.vi0];
          line.to   = mesh.m_T[me.vi1];
          me.newT = line.PointAt(0.5);
        }
        me.newvi = (me.vi0 < me.vi1) ? me.vi0 : me.vi1;
      }
      else
      {
        me_list[mei].newvi = me.newvi;
        me_list[mei].newV = me.newV;
        me_list[mei].newN = me.newN;
        me_list[mei].newT = me.newT;
      }
    }
  }

  // We are done averaging old mesh values.
  // Change values in mesh m_V[], m_N[] and m_T[] arrays.
  for ( mei = 0; mei < me_list_count; mei++ )
  {
    mesh.m_V[me_list[mei].vi0] = me_list[mei].newV;
    mesh.m_V[me_list[mei].vi1] = me_list[mei].newV;
    if ( bHasVertexNormals )
    {
      mesh.m_N[me_list[mei].vi0] = me_list[mei].newN;
      mesh.m_N[me_list[mei].vi1] = me_list[mei].newN;
    }
    if ( bHasTextureCoordinates )
    {
      mesh.m_T[me_list[mei].vi0] = me_list[mei].newT;
      mesh.m_T[me_list[mei].vi1] = me_list[mei].newT;
    }
  }

  // make a map of old to new
  int old2new_map_count = 0;
  ON__NEWVI* old2new_map = (ON__NEWVI*)alloca(2*me_list_count*sizeof(old2new_map[0]));

  for ( mei = 0; mei < me_list_count; mei++ )
  {
    old2new_map[old2new_map_count].oldvi = me_list[mei].vi0;
    old2new_map[old2new_map_count].newvi = me_list[mei].newvi;
    old2new_map_count++;
    old2new_map[old2new_map_count].oldvi = me_list[mei].vi1;
    old2new_map[old2new_map_count].newvi = me_list[mei].newvi;
    old2new_map_count++;
  }

  // sort old2new_map[] so we can use a fast bsearch() call
  // to update faces.
  ON_qsort(old2new_map,old2new_map_count,sizeof(old2new_map[0]),(QSORTCMPFUNC)CompareNEWVI);

  // count faces that use the vertices that are being changed
  int bad_fi_count = 0;
  int topv_end, vei, fi, fvi23, fvi;
  ON__NEWVI nvi;

  for ( topv_end = 0; topv_end < 2; topv_end++ )
  {
    const ON_MeshTopologyVertex& topv = (topv_end) ? topv1 : topv0;
    for ( vei = 0; vei < topv.m_tope_count; vei++ )
    {
      topei = topv.m_topei[vei];
      if ( topei < 0 && topei >= top.m_tope.Count() )
        continue;
      bad_fi_count += top.m_tope[topei].m_topf_count;
    }
  }
  int* bad_fi = (int*)alloca(bad_fi_count*sizeof(*bad_fi));
  bad_fi_count = 0;

  // Go through all the faces that use the vertices at the
  // ends of the edge and update the vi[] values to use the
  // new vertices.
  for ( topv_end = 0; topv_end < 2; topv_end++ )
  {
    const ON_MeshTopologyVertex& topv = (topv_end) ? topv1 : topv0;
    for ( vei = 0; vei < topv.m_tope_count; vei++ )
    {
      topei = topv.m_topei[vei];
      if ( topei < 0 && topei >= top.m_tope.Count() )
        continue;
      const ON_MeshTopologyEdge& e = top.m_tope[topei];
      for ( efi = 0; efi < e.m_topf_count; efi++ )
      {
        fi = e.m_topfi[efi];
        if ( fi < 0 || fi >= F_count )
          continue;
        bool bChangedFace = false;
        ON_MeshFace& f = mesh.m_F[fi];
        for ( fvi = 0; fvi < 4; fvi++ )
        {
          nvi.oldvi = f.vi[fvi];
          ON__NEWVI* p = (ON__NEWVI*)bsearch(&nvi,old2new_map,old2new_map_count,sizeof(old2new_map[0]),(QSORTCMPFUNC)CompareNEWVI);
          if ( 0 != p && p->oldvi != p->newvi)
          {
            f.vi[fvi] = p->newvi;
            bChangedFace = true;
          }
        }
        if ( bChangedFace )
        {
          if ( !f.IsValid(V_count) )
          {
            if ( f.vi[3] == f.vi[0] )
            {
              f.vi[0] = f.vi[1];
              f.vi[1] = f.vi[2];
              f.vi[2] = f.vi[3];
            }
            else if ( f.vi[0] == f.vi[1] )
            {
              fvi23 = f.vi[0];
              f.vi[0] = f.vi[2];
              f.vi[1] = f.vi[3];
              f.vi[2] = fvi23;
              f.vi[3] = fvi23;
            }
            else if ( f.vi[1] == f.vi[2] )
            {
              fvi23 = f.vi[1];
              f.vi[1] = f.vi[0];
              f.vi[0] = f.vi[3];
              f.vi[2] = fvi23;
              f.vi[3] = fvi23;
            }
            if ( f.vi[0] == f.vi[1] || f.vi[1] == f.vi[2] || f.vi[2] == f.vi[0] || f.vi[2] != f.vi[3] )
            {
              bad_fi[bad_fi_count++] = fi;
            }
          }
          if ( bHasFaceNormals )
          {
            // invalid faces are removed below
            ON_3fVector a, b, n;
            a = mesh.m_V[f.vi[2]] - mesh.m_V[f.vi[0]];
            b = mesh.m_V[f.vi[3]] - mesh.m_V[f.vi[1]];
            n = ON_CrossProduct( a, b );
            n.Unitize();
            mesh.m_FN[fi] = n;
          }
        }
      }
    }
  }

  if ( bad_fi_count > 0 )
  {
    // remove collapsed faces
    ON_qsort(bad_fi,bad_fi_count,sizeof(bad_fi[0]),CompareInt);
    int bfi = 1;
    int dest_fi = bad_fi[0];
    for ( fi = dest_fi+1; fi < F_count && bfi < bad_fi_count; fi++ )
    {
      if ( fi == bad_fi[bfi] )
      {
        bfi++;
      }
      else
      {
        mesh.m_F[dest_fi++] = mesh.m_F[fi];
      }
    }
    while (fi<F_count)
    {
      mesh.m_F[dest_fi++] = mesh.m_F[fi++];
    }
    mesh.m_F.SetCount(dest_fi);

    if ( bHasFaceNormals )
    {
      bfi = 1;
      dest_fi = bad_fi[0];
      for ( fi = dest_fi+1; fi < F_count && bfi < bad_fi_count; fi++ )
      {
        if ( fi == bad_fi[bfi] )
        {
          bfi++;
        }
        else
        {
          mesh.m_FN[dest_fi++] = mesh.m_FN[fi];
        }
      }
      while (fi<F_count)
      {
        mesh.m_FN[dest_fi++] = mesh.m_FN[fi++];
      }
      mesh.m_FN.SetCount(dest_fi);
    }
  }

  mesh.Compact();
  mesh.DestroyTopology();
  mesh.DestroyPartition();

  return true;
}
Exemple #27
0
// returns point on cylinder that is closest to given point
ON_3dPoint ON_Sphere::ClosestPointTo( ON_3dPoint point ) const
{
  ON_3dVector v = point - plane.origin;
  v.Unitize();
  return plane.origin + radius*v;
}
Exemple #28
0
ON_3dVector ON_Polyline::TangentAt( double t ) const
{
    ON_3dVector v = DerivativeAt(t);
    v.Unitize();
    return v;
}
RH_C_FUNCTION double ON_Intersect_MeshRay1(const ON_Mesh* pMesh, ON_3dRay* ray, ON_SimpleArray<int>* face_indices)
{
  double rc = -1.0;
  // it is ok if face_indices is null
  if( pMesh && ray )
  {
#if defined(RHINO_V5SR) // only available in V5
    const ON_MeshTree* mt = pMesh->MeshTree(true);
#else
    const ON_MeshTree* mt = pMesh->MeshTree();
#endif
    ON_3dVector rayVec = ray->m_V;
    if( mt && rayVec.Unitize() )
    {
      // increase the range by a factor of 2 so we are confident the
      // line passes entirely through the mesh
      double rayRange = RhCmnMaxDistance_Helper( mt->m_bbox, ray->m_P ) * 2.0;
      ON_Line line(ray->m_P, ray->m_P + rayRange * rayVec );

      ON_SimpleArray<ON_CMX_EVENT> hits;
      mt->IntersectLine( line, hits );
      int hitCount = hits.Count();
      if( hitCount > 0 )
      {
        ON_SimpleArray<double> tvals;
        ON_SimpleArray<int> indices;
        // tMin should be between 0 and 1 for the line
        double tMin = 100.0;
        for( int i=0; i<hitCount; i++ )
        {
          const ON_CMX_EVENT& e = hits[i];
          if( e.m_C[0].m_t <= tMin )
          {
            tMin = e.m_C[0].m_t;
            if( face_indices )
            {
              tvals.Append(tMin);
              indices.Append(e.m_M[0].m_face_index);
            }
          }
          if( e.m_type == ON_CMX_EVENT::cmx_overlap && e.m_C[1].m_t <= tMin )
          {
            tMin = e.m_C[1].m_t;
            if( face_indices )
            {
              tvals.Append(tMin);
              indices.Append( e.m_M[1].m_face_index);
            }
          }
        }
        if( tMin >=0 && tMin <= 1.0 )
        {
          if( face_indices )
          {
            for( int i=0; i<tvals.Count(); i++ )
            {
              if( tvals[i]==tMin )
                face_indices->Append(indices[i]);
            }
          }

          double lineLength = line.Length();
          double rayLength = ray->m_V.Length();
          if( rayLength > ON_SQRT_EPSILON )
          {
            rc = tMin * lineLength / rayLength;
          }
        }
      }
    }
  }
  return rc;
}
Exemple #30
0
ON_BOOL32
ON_Surface::EvNormal( // returns false if unable to evaluate
         double s, double t, // evaluation parameters (s,t)
         ON_3dPoint& point,  // returns value of surface
         ON_3dVector& ds, // first partial derivatives (Ds)
         ON_3dVector& dt, // (Dt)
         ON_3dVector& normal, // unit normal
         int side,       // optional - determines which side to evaluate from
                         //         0 = default
                         //         1 from NE quadrant
                         //         2 from NW quadrant
                         //         3 from SW quadrant
                         //         4 from SE quadrant
         int* hint       // optional - evaluation hint (int[2]) used to speed
                         //            repeated evaluations
         ) const
{
  // simple cross product normal - override to support singular surfaces
  ON_BOOL32 rc = Ev1Der( s, t, point, ds, dt, side, hint );
  if ( rc ) {
    const double len_ds = ds.Length();
    const double len_dt = dt.Length();

    // do not reduce the tolerance used here - there is a retry in the code
    // below.
    if ( len_ds >  ON_SQRT_EPSILON*len_dt && len_dt >  ON_SQRT_EPSILON*len_ds ) 
    {
      ON_3dVector a = ds/len_ds;
      ON_3dVector b = dt/len_dt;
      normal = ON_CrossProduct( a, b );
      rc = normal.Unitize();
    }
    else 
    {
      // see if we have a singular point 
      double v[6][3];
      int normal_side = side;
      ON_BOOL32 bOnSide = false;
      ON_Interval sdom = Domain(0);
      ON_Interval tdom = Domain(1);
		  if (s == sdom.Min()) {
			  normal_side = (normal_side >= 3) ? 4 : 1;
        bOnSide = true;
		  }
		  else if (s == sdom.Max()) {
			  normal_side = (normal_side >= 3) ? 3 : 2;
        bOnSide = true;
		  }
		  if (t == tdom.Min()) {
			  normal_side = (normal_side == 2 || normal_side == 3) ? 2 : 1;
        bOnSide = true;
		  }
		  else if (t == tdom.Max()) {
			  normal_side = (normal_side == 2 || normal_side == 3) ? 3 : 4;
        bOnSide = true;
		  }
      if ( !bOnSide )
      {
        // 2004 November 11 Dale Lear 
        //  Added a retry again with a more generous tolerance
        if ( len_ds >  ON_EPSILON*len_dt && len_dt >  ON_EPSILON*len_ds ) 
        {
          ON_3dVector a = ds/len_ds;
          ON_3dVector b = dt/len_dt;
          normal = ON_CrossProduct( a, b );
          rc = normal.Unitize();
        }
        else
        {
          rc = false;
        }
      }
      else {
        rc = Evaluate( s, t, 2, 3, &v[0][0], normal_side, hint );
        if ( rc ) {
	        rc = ON_EvNormal( normal_side, v[1], v[2], v[3], v[4], v[5], normal);
        }
      }
    }
  }
  if ( !rc ) {
    normal.Zero();
  }
  return rc;
}