opennurbs_ellipse.cpp
Go to the documentation of this file.
00001 /* $NoKeywords: $ */
00002 /*
00003 //
00004 // Copyright (c) 1993-2012 Robert McNeel & Associates. All rights reserved.
00005 // OpenNURBS, Rhinoceros, and Rhino3D are registered trademarks of Robert
00006 // McNeel & Associates.
00007 //
00008 // THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY.
00009 // ALL IMPLIED WARRANTIES OF FITNESS FOR ANY PARTICULAR PURPOSE AND OF
00010 // MERCHANTABILITY ARE HEREBY DISCLAIMED.
00011 //                              
00012 // For complete openNURBS copyright information see <http://www.opennurbs.org>.
00013 //
00015 */
00016 
00017 #include "pcl/surface/3rdparty/opennurbs/opennurbs.h"
00018 
00019 ON_Ellipse::ON_Ellipse() 
00020 {
00021   radius[0] = radius[1] = 0.0;
00022 }
00023 
00024 
00025 ON_Ellipse::ON_Ellipse(
00026     const ON_Plane& p,
00027     double rx, double ry
00028     )
00029 {
00030   Create(p,rx,ry);
00031 }
00032 
00033 
00034 ON_Ellipse::ON_Ellipse(
00035     const ON_Circle& c
00036     )
00037 {
00038   Create(c);
00039 }
00040 
00041 ON_Ellipse::~ON_Ellipse()
00042 {}
00043 
00044 ON_Ellipse& ON_Ellipse::operator=(const ON_Circle& c)
00045 {
00046   Create( c );
00047   return *this;
00048 }
00049 
00050 ON_BOOL32 ON_Ellipse::Create( const ON_Plane& p, double rx, double ry )
00051 {
00052   plane = p;
00053   radius[0] = rx;
00054   radius[1] = ry;
00055   return IsValid();
00056 }
00057 
00058 ON_BOOL32 ON_Ellipse::Create( const ON_Circle& c )
00059 {
00060   return Create( c.Plane(), c.Radius(), c.Radius() );
00061 }
00062 
00063 ON_BOOL32 ON_Ellipse::IsValid() const
00064 {
00065   return (plane.IsValid() && radius[0] > ON_ZERO_TOLERANCE && radius[1] > ON_ZERO_TOLERANCE) ? true : false;
00066 }
00067 
00068 ON_BOOL32 ON_Ellipse::IsCircle() const
00069 {
00070   double r0 = radius[0];
00071   return ( ON_IsValid(r0) && fabs(r0-radius[1]) <= fabs(r0)*ON_ZERO_TOLERANCE && IsValid() ) ? true : false;
00072 }
00073 
00074 double ON_Ellipse::Radius( int i ) const
00075 {
00076   return radius[(i)?1:0];
00077 }
00078 
00079 const ON_3dPoint& ON_Ellipse::Center() const
00080 {
00081   return plane.origin;
00082 }
00083 
00084 double ON_Ellipse::FocalDistance() const
00085 {
00086   int i = (fabs(radius[0]) >= fabs(radius[1])) ? 0 : 1;
00087   const double a = fabs(radius[i]);
00088   const double b = a > 0.0 ? fabs(radius[1-i])/a : 0.0;
00089   return a*sqrt(1.0 - b*b);
00090 }
00091 
00092 bool ON_Ellipse::GetFoci( ON_3dPoint& F1, ON_3dPoint& F2 ) const
00093 {
00094   const double f = FocalDistance();
00095   const ON_3dVector& majorAxis = (radius[0] >= radius[1]) ? plane.xaxis : plane.yaxis;
00096   F1 = plane.origin + f*majorAxis;
00097   F2 = plane.origin - f*majorAxis;
00098   return true;
00099 }
00100 
00101 const ON_3dVector& ON_Ellipse::Normal() const
00102 {
00103   return plane.zaxis;
00104 }
00105 
00106 const ON_Plane& ON_Ellipse::Plane() const
00107 {
00108   return plane;
00109 }
00110 
00111 ON_3dPoint ON_Ellipse::PointAt( double t ) const
00112 {
00113   return plane.PointAt( cos(t)*radius[0], sin(t)*radius[1] );
00114 }
00115 
00116 ON_3dVector ON_Ellipse::DerivativeAt( 
00117                  int d, // desired derivative ( >= 0 )
00118                  double t // parameter
00119                  ) const
00120 {
00121   double r0 = radius[0];
00122   double r1 = radius[1];
00123   switch (abs(d)%4) {
00124   case 0:
00125     r0 *=  cos(t);
00126     r1 *=  sin(t);
00127     break;
00128   case 1:
00129     r0 *= -sin(t);
00130     r1 *=  cos(t);
00131     break;
00132   case 2:
00133     r0 *= -cos(t);
00134     r1 *= -sin(t);
00135     break;
00136   case 3:
00137     r0 *=  sin(t);
00138     r1 *= -cos(t);
00139     break;
00140   }
00141   return ( r0*plane.xaxis + r1*plane.yaxis );
00142 }
00143 
00144 ON_3dVector ON_Ellipse::TangentAt( 
00145                  double t // parameter
00146                  ) const
00147 {
00148   ON_3dVector T = DerivativeAt( 1, t );
00149   T.Unitize();
00150   return T;
00151 }
00152 
00153 ON_3dVector ON_Ellipse::CurvatureAt( 
00154                  double t // parameter
00155                  ) const
00156 {
00157   ON_3dVector T, K;
00158   ON_EvCurvature(DerivativeAt( 1, t ),DerivativeAt( 2, t ),T,K);
00159   return K;
00160 }
00161 
00162 static int distSqToEllipse(void* p, double t, double* f, double* df )
00163 {
00164   // used in call to TL_NRdbrent().
00165   double dx, dy, st, ct;
00166   const double* a = (const double*)p;
00167   // a[0], a[1] = x/y radii of 2d ellipse
00168   // (a[2],a[3]) = 2d point
00169   // f(t) = distance squared from ellipse(t) to 2d point
00170   ct = cos(t);
00171   st = sin(t);
00172   dx = ct*a[0] - a[2];
00173   dy = st*a[1] - a[3];
00174   if ( f ) {
00175     *f = dx*dx + dy*dy;
00176   }
00177   if ( df ) {
00178     *df = 2.0*(dy*a[1]*ct - dx*a[0]*st);
00179   }
00180   return 0;
00181 }
00182 
00183 #if defined(ON_COMPILER_MSC)
00184 // Disable the MSC /W4 warning
00185 //   C4127: conditional expression is constant
00186 // on the line
00187 //   for(...; true; ... )
00188 //
00189 // This source code is used on many compilers and
00190 // I do not trust all of them to get for(..;;...)
00191 // right.
00192 #pragma warning( push )
00193 #pragma warning( disable : 4127 ) 
00194 #endif
00195 
00196 ON_BOOL32 ON_Ellipse::ClosestPointTo( const ON_3dPoint& point, double* t ) const
00197 {
00198   ON_BOOL32 rc = true;
00199   if ( t ) {
00200     ON_2dPoint uv;
00201     rc = plane.ClosestPointTo( point, &uv.x, &uv.y );
00202     if ( uv.x == 0.0 ) {
00203       if ( uv.y == 0.0 ) {
00204         *t = (radius[0] <= radius[1]) ? 0.0 : 0.5*ON_PI;
00205         return true;
00206       }
00207       if ( uv.y >= radius[1] ) {
00208         *t = 0.5*ON_PI;
00209         return true;
00210       }
00211       if ( uv.y <= -radius[1] ) {
00212         *t = 1.5*ON_PI;
00213         return true;
00214       }
00215     }
00216     else if ( uv.y == 0.0 ) {
00217       if ( uv.x >= radius[0] ) {
00218         *t = 0.0;
00219         return true;
00220       }
00221       if ( uv.x <= -radius[0] ) {
00222         *t = ON_PI;
00223         return true;
00224       }
00225     }
00226     {
00227       // use circluar approximation to get a seed value
00228       double t0, t1;
00229       *t = atan2( uv.y, uv.x );
00230       if ( *t < 0.0 )
00231       {
00232         *t += 2.0*ON_PI;
00233         if ( 2.0*ON_PI <= *t)
00234         {
00235           // == happens when atan2() <= 0.5*ON_EPSILON*2.0*PI
00236           *t = 0.0;
00237         }
00238       }
00239       if ( radius[0] != radius[1] ) {
00240         // set limits for search
00241         if ( uv.x >= 0.0 ) {
00242           if ( uv.y >= 0.0 ) {
00243             // search quadrant I
00244             t0 = 0.0;
00245             t1 = 0.5*ON_PI;
00246           }
00247           else {
00248             // search quadrant IV
00249             t0 = 1.5*ON_PI;
00250             t1 = 2.0*ON_PI;
00251           }
00252         }
00253         else {
00254           if ( uv.y >= 0.0 ) {
00255             // search quadrant II
00256             t0 = 0.5*ON_PI;
00257             t1 = ON_PI;
00258           }
00259           else {
00260             // search quadrant III
00261             t0 = ON_PI;
00262             t1 = 1.5*ON_PI;
00263           }
00264         }
00265 
00266         // solve for closest point using Brent's algorithm
00267         {
00268           // 6 October 2003 Dale Lear:
00269           //    Fixed several serious bugs here.
00270           // get seed value appropriate for Brent
00271           double p[4], et, d0, d1, dt;
00272           int i;
00273           p[0] = radius[0];
00274           p[1] = radius[1];
00275           p[2] = uv.x;
00276           p[3] = uv.y;
00277           et = *t;
00278           if ( et <= t0 )
00279             et = 0.9*t0 + 0.1*t1;
00280           else if ( et >= t1 )
00281             et = 0.9*t1 + 0.1*t0;
00282           distSqToEllipse( p, t0, &d0, NULL );
00283           distSqToEllipse( p, t1, &d1, NULL );
00284           if ( d0 == 0.0 ) {
00285             *t = (t0 == 2.0*ON_PI) ? 0.0 : t0;
00286             return true;
00287           }
00288           if ( d1 == 0.0 ) {
00289             *t = (t1 == 2.0*ON_PI) ? 0.0 : t1;
00290             return true;
00291           }
00292           if ( d0 > d1 ) {
00293             dt = t0; t0 = t1; t1 = dt;
00294             dt = d0; d0 = d1; d1 = dt;
00295           }
00296           *t = (t0 == 2.0*ON_PI) ? 0.0 : t0;
00297           for ( i = 0; true; i++ ) {
00298             distSqToEllipse( p, et, &dt, NULL );
00299             if ( dt < d0 )
00300             {
00301               *t = (et >= 2.0*ON_PI) ? 0.0 : et;
00302               break;
00303             }
00304             if ( i >= 100 ) 
00305             {
00306               ON_3dPoint E0 = PointAt(t0);
00307               if (    sqrt(d0) <= ON_ZERO_TOLERANCE 
00308                    || sqrt(d0) <= ON_SQRT_EPSILON*E0.DistanceTo(Center()) 
00309                    )
00310               {
00311                 // Could not find a seed value for dbrent, 
00312                 // but t0 is pretty close.
00313                 return true;
00314               }
00315               ON_3dVector T = TangentAt(t0);
00316               ON_3dVector V = E0 - point;
00317               if ( V.Unitize() )
00318               {
00319                 // Could not find a seed value for dbrent, 
00320                 // but V and T are orthoganal, so t0 is 
00321                 // pretty close.
00322                 if ( fabs(V*T) <= 0.087155742747658173558064270837474 )
00323                   return true;
00324               }
00325               return false; // can't get valid seed - bail out
00326             }
00327             et = (i) ? (0.5*(t0+et)) : 0.5*(t0+t1);
00328             if ( et == t0 )
00329             {
00330               return true;
00331             }
00332           }
00333 
00334           rc = ON_FindLocalMinimum( distSqToEllipse, p,
00335                             t0, et, t1, 
00336                             ON_EPSILON,  ON_SQRT_EPSILON, 100,
00337                             &et );
00338           rc = (rc > 0) ? true : false;
00339           if ( rc )
00340             *t = (et >= 2.0*ON_PI) ? 0.0 : et;
00341         }
00342       }
00343     }
00344   }
00345   return rc;
00346 }
00347 
00348 #if defined(ON_COMPILER_MSC)
00349 #pragma warning( pop )
00350 #endif
00351 
00352 ON_3dPoint ON_Ellipse::ClosestPointTo( const ON_3dPoint& point ) const
00353 {
00354   double t;
00355   ClosestPointTo( point, &t );
00356   return PointAt( t );
00357 }
00358 
00359 double ON_Ellipse::EquationAt( 
00360                  const ON_2dPoint& p // coordinates in plane
00361                  ) const
00362 {
00363   double e, x, y;
00364   if ( radius[0] != 0.0 && radius[1] != 0.0 ) {
00365     x = p.x/radius[0];
00366     y = p.y/radius[1];
00367     e = x*x + y*y - 1.0;
00368   }
00369   else {
00370     e = 0.0;
00371   }
00372   return e;
00373 }
00374 
00375 ON_2dVector ON_Ellipse::GradientAt( 
00376                  const ON_2dPoint& p // coordinates in plane
00377                  ) const
00378 {
00379   ON_2dVector g;
00380   if ( radius[0] != 0.0 && radius[1] != 0.0 ) {
00381     g.x = 2.0*p.x/(radius[0]*radius[0]);
00382     g.y = 2.0*p.y/(radius[1]*radius[1]);
00383   }
00384   else {
00385     g.Zero();
00386   }
00387   return g;
00388 }
00389 
00390 ON_BOOL32 ON_Ellipse::Rotate( 
00391                           double sin_angle, double cos_angle, 
00392                           const ON_3dVector& axis
00393                           )
00394 {
00395   return plane.Rotate( sin_angle, cos_angle, axis );
00396 }
00397 
00398 ON_BOOL32 ON_Ellipse::Rotate( 
00399                           double angle, 
00400                           const ON_3dVector& axis
00401                           )
00402 {
00403   return plane.Rotate( angle, axis );
00404 }
00405 
00406 ON_BOOL32 ON_Ellipse::Rotate( 
00407                           double sin_angle, double cos_angle, 
00408                           const ON_3dVector& axis,
00409                           const ON_3dPoint& point
00410                           )
00411 {
00412   return plane.Rotate( sin_angle, cos_angle, axis, point );
00413 }
00414 
00415 ON_BOOL32 ON_Ellipse::Rotate( 
00416                           double angle, 
00417                           const ON_3dVector& axis,
00418                           const ON_3dPoint& point
00419                           )
00420 {
00421   return plane.Rotate( angle, axis, point );
00422 }
00423 
00424 
00425 ON_BOOL32 ON_Ellipse::Translate(
00426                           const ON_3dVector& delta
00427                             )
00428 {
00429   return plane.Translate( delta );
00430 }
00431 
00432 ON_BOOL32 ON_Ellipse::GetNurbForm( ON_NurbsCurve& nurbscurve ) const
00433 {
00434   int rc = 0;
00435   if ( IsValid() ) {
00436     nurbscurve.Create( 3, true, 3, 9 );
00437     nurbscurve.m_knot[0] = nurbscurve.m_knot[1] = 0.0;
00438     nurbscurve.m_knot[2] = nurbscurve.m_knot[3] = 0.5*ON_PI;
00439     nurbscurve.m_knot[4] = nurbscurve.m_knot[5] = ON_PI;
00440     nurbscurve.m_knot[6] = nurbscurve.m_knot[7] = 1.5*ON_PI;
00441     nurbscurve.m_knot[8] = nurbscurve.m_knot[9] = 2.0*ON_PI;
00442     ON_4dPoint* CV = (ON_4dPoint*)nurbscurve.m_cv;
00443 
00444     CV[0] = plane.PointAt( radius[0],        0.0);
00445     CV[1] = plane.PointAt( radius[0],  radius[1]);
00446     CV[2] = plane.PointAt(       0.0,  radius[1]);
00447     CV[3] = plane.PointAt(-radius[0],  radius[1]);
00448     CV[4] = plane.PointAt(-radius[0],        0.0);
00449     CV[5] = plane.PointAt(-radius[0], -radius[1]);
00450     CV[6] = plane.PointAt(       0.0, -radius[1]);
00451     CV[7] = plane.PointAt( radius[0], -radius[1]);
00452     CV[8] = CV[0];
00453     
00454     const double w = 1.0/sqrt(2.0);
00455     int i;
00456     for ( i = 1; i < 8; i += 2 ) {
00457       CV[i].x *= w;
00458       CV[i].y *= w;
00459       CV[i].z *= w;
00460       CV[i].w = w;
00461     }
00462     rc = 2;
00463   }
00464   return rc;
00465 }


pcl
Author(s): Open Perception
autogenerated on Wed Aug 26 2015 15:27:00