1 /* $NoKeywords: $ */
2 /*
3 //
4 // Copyright (c) 1993-2012 Robert McNeel & Associates. All rights reserved.
5 // OpenNURBS, Rhinoceros, and Rhino3D are registered trademarks of Robert
6 // McNeel & Associates.
7 //
8 // THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY.
9 // ALL IMPLIED WARRANTIES OF FITNESS FOR ANY PARTICULAR PURPOSE AND OF
10 // MERCHANTABILITY ARE HEREBY DISCLAIMED.
11 //
12 // For complete openNURBS copyright information see <http://www.opennurbs.org>.
13 //
14 ////////////////////////////////////////////////////////////////
15 */
16 
17 #include "pcl/surface/3rdparty/opennurbs/opennurbs.h"
18 
ON_Circle()19 ON_Circle::ON_Circle()
20                   : radius(1.0)
21 {
22   //m_point[0].Zero();
23   //m_point[1].Zero();
24   //m_point[2].Zero();
25 }
26 
~ON_Circle()27 ON_Circle::~ON_Circle()
28 {}
29 
ON_Circle(const ON_Plane & p,double r)30 ON_Circle::ON_Circle( const ON_Plane& p, double r )
31 {
32   Create( p, r );
33 }
34 
ON_Circle(const ON_3dPoint & C,double r)35 ON_Circle::ON_Circle( const ON_3dPoint& C, double r )
36 {
37   Create( C, r );
38 }
39 
ON_Circle(const ON_Plane & pln,const ON_3dPoint & C,double r)40 ON_Circle::ON_Circle( const ON_Plane& pln, const ON_3dPoint& C, double r )
41 {
42   Create( pln, C, r );
43 }
44 
ON_Circle(const ON_2dPoint & P,const ON_2dPoint & Q,const ON_2dPoint & R)45 ON_Circle::ON_Circle( const ON_2dPoint& P, const ON_2dPoint& Q, const ON_2dPoint& R )
46 {
47   Create(P,Q,R);
48 }
49 
ON_Circle(const ON_3dPoint & P,const ON_3dPoint & Q,const ON_3dPoint & R)50 ON_Circle::ON_Circle( const ON_3dPoint& P, const ON_3dPoint& Q, const ON_3dPoint& R )
51 {
52   Create(P,Q,R);
53 }
54 
55 
Radius() const56 double ON_Circle::Radius() const
57 {
58   return radius;
59 }
60 
Diameter() const61 double ON_Circle::Diameter() const
62 {
63   return 2.0*radius;
64 }
65 
Center() const66 const ON_3dPoint& ON_Circle::Center() const
67 {
68   return plane.origin;
69 }
70 
Normal() const71 const ON_3dVector& ON_Circle::Normal() const
72 {
73   return plane.zaxis;
74 }
75 
Plane() const76 const ON_Plane& ON_Circle::Plane() const
77 {
78   return plane;
79 }
80 
BoundingBox() const81 ON_BoundingBox ON_Circle::BoundingBox() const
82 {
83   ON_BoundingBox bbox;
84   ON_3dPoint corners[4]; // = corners of square that contains circle
85   corners[0] = plane.PointAt( radius, radius );
86   corners[1] = plane.PointAt( radius,-radius );
87   corners[2] = plane.PointAt(-radius, radius );
88   corners[3] = plane.PointAt(-radius,-radius );
89   bbox.Set(3,0,4,3,&corners[0].x,false);
90   return bbox;
91 }
92 
Transform(const ON_Xform & xform)93 bool ON_Circle::Transform( const ON_Xform& xform )
94 {
95   const ON_Plane plane0(plane);
96   const bool rc = plane.Transform(xform);
97   if (!rc)
98   {
99     // restore original
100     plane = plane0;
101   }
102   else
103   {
104     const double ztol = 1.0e-12;
105     double a,b,c,d,r1,r2,s;
106     // determine scale factor in circle's plane
107     // In practice, transformation are either rotations,
108     // the scale factor is clearly distinct from 1,
109     // or the transformation does not map a circle
110     // to a circle.  The code below has tolerance checks
111     // so that anything that is close to a rotation gets
112     // treated does not change the radius.  If it is
113     // clearly a uniform scale in the plane of the circle
114     // the scale factor is calculated without using a
115     // determinant.  Sine "2d scales" are common, it doesn't
116     // work well use the cubed root of the xform'd determinant.
117     ON_3dVector V = xform*plane0.xaxis;
118     a = V*plane.xaxis;
119     b = V*plane.yaxis;
120     if (fabs(a) >= fabs(b))
121     {
122       r1 = fabs(a);
123       if ( r1 > 0.0)
124       {
125         a = (a>0.0) ? 1.0 : -1.0;
126         b /= r1;
127         if ( fabs(b) <= ztol )
128         {
129           b = 0.0;
130           if ( fabs(1.0-r1) <= ztol )
131             r1 = 1.0;
132         }
133       }
134     }
135     else
136     {
137       r1 = fabs(b);
138       b = (b>0.0) ? 1.0 : -1.0;
139       a /= r1;
140       if ( fabs(a) <= ztol )
141       {
142         a = 0.0;
143         if ( fabs(1.0-r1) <= ztol )
144           r1 = 1.0;
145       }
146     }
147     V = xform*plane0.yaxis;
148     c = V*plane.xaxis;
149     d = V*plane.yaxis;
150     if (fabs(d) >= fabs(c))
151     {
152       r2 = fabs(d);
153       if (r2 > 0.0)
154       {
155         d = (d>0.0) ? 1.0 : -1.0;
156         c /= r2;
157         if ( fabs(c) <= ztol )
158         {
159           c = 0.0;
160           if ( fabs(1.0-r2) <= ztol )
161             r2 = 1.0;
162         }
163       }
164     }
165     else
166     {
167       r2 = fabs(c);
168       c = (c>0.0) ? 1.0 : -1.0;
169       d /= r2;
170       if ( fabs(d) <= ztol )
171       {
172         d = 0.0;
173         if ( fabs(1.0-r2) <= ztol )
174           r2 = 1.0;
175       }
176     }
177     if (    0.0 == b
178          && 0.0 == c
179          && fabs(r1-r1) <= ON_SQRT_EPSILON*(r1+r2)
180        )
181     {
182       // transform is a similarity
183       s = 0.5*(r1+r2); // = sqrt(r1*r2) but more accurate
184     }
185     else
186     {
187       // non-uniform scaling or skew in circle's plane
188       // do something reasonable
189       s = sqrt(fabs(r1*r2*(a*d-b*c)));
190     }
191 
192     if ( s > 0.0 )
193     {
194       //#if defined(ON_DEBUG) && !defined(ON_COMPILER_GNU)
195       //double det = fabs(xform.Determinant());
196       //double s0 = pow(det,1.0/3.0);
197       //if ( fabs(s-s0) > ON_SQRT_EPSILON*s0 )
198       //{
199       //  // non-uniform scale or a bug
200       //  // In the non-uniform scal case, b and c should be
201       //  // "zero".
202       //  int breakpointhere = 0; // (generates gcc warning)
203       //}
204       //#endif
205       if ( fabs(s-1.0) > ON_SQRT_EPSILON )
206         radius *= s;
207     }
208   }
209 
210   return rc;
211 }
212 
213 
Circumference() const214 double ON_Circle::Circumference() const
215 {
216   return fabs(2.0*ON_PI*radius);
217 }
218 
Create(const ON_Plane & p,double r)219 bool ON_Circle::Create( const ON_Plane& p, double r )
220 {
221   plane = p;
222   if ( !plane.IsValid() )
223     plane.UpdateEquation(); // people often forget to set equation
224   radius = r;
225   //m_point[0] = plane.PointAt( radius, 0.0 );
226   //m_point[1] = plane.PointAt( 0.0, radius );
227   //m_point[2] = plane.PointAt( -radius, 0.0 );
228   return ( radius > 0.0 );
229 }
230 
Create(const ON_3dPoint & C,double r)231 bool ON_Circle::Create( const ON_3dPoint& C, double r )
232 {
233   ON_Plane p = ON_xy_plane;
234   p.origin = C;
235   p.UpdateEquation();
236   return Create( p, r );
237 }
238 
Create(const ON_Plane & pln,const ON_3dPoint & C,double r)239 bool ON_Circle::Create( const ON_Plane& pln,
240                           const ON_3dPoint& C,
241                           double r
242                           )
243 {
244   ON_Plane p = pln;
245   p.origin = C;
246   p.UpdateEquation();
247   return Create( p, r );
248 }
249 
Create(const ON_2dPoint & P,const ON_2dPoint & Q,const ON_2dPoint & R)250 bool ON_Circle::Create( // circle through three 3d points
251     const ON_2dPoint& P,
252     const ON_2dPoint& Q,
253     const ON_2dPoint& R
254     )
255 {
256   return Create(ON_3dPoint(P),ON_3dPoint(Q),ON_3dPoint(R));
257 }
258 
Create(const ON_3dPoint & P,const ON_3dPoint & Q,const ON_3dPoint & R)259 bool ON_Circle::Create( // circle through three 3d points
260     const ON_3dPoint& P,
261     const ON_3dPoint& Q,
262     const ON_3dPoint& R
263     )
264 {
265   ON_3dPoint C;
266   ON_3dVector X, Y, Z;
267   // return ( radius > 0.0 && plane.IsValid() );
268   //m_point[0] = P;
269   //m_point[1] = Q;
270   //m_point[2] = R;
271 
272   // get normal
273   for(;;)
274   {
275     if ( !Z.PerpendicularTo( P, Q, R ) )
276       break;
277 
278     // get center as the intersection of 3 planes
279     ON_Plane plane0( P, Z );
280     ON_Plane plane1( 0.5*(P+Q), P-Q );
281     ON_Plane plane2( 0.5*(R+Q), R-Q );
282     if ( !ON_Intersect( plane0, plane1, plane2, C ) )
283       break;
284 
285     X = P - C;
286     radius = X.Length();
287     if ( !(radius > 0.0) )
288       break;
289 
290     if ( !X.Unitize() )
291       break;
292 
293     Y = ON_CrossProduct( Z, X );
294     if ( !Y.Unitize() )
295       break;
296 
297     plane.origin = C;
298     plane.xaxis = X;
299     plane.yaxis = Y;
300     plane.zaxis = Z;
301 
302     plane.UpdateEquation();
303 
304     return true;
305   }
306 
307   plane = ON_Plane::World_xy;
308   radius = 0.0;
309   return false;
310 }
311 
312 //////////
313 // Create an circle from two 2d points and a tangent at the first point.
Create(const ON_2dPoint & P,const ON_2dVector & Pdir,const ON_2dPoint & Q)314 bool ON_Circle::Create(
315   const ON_2dPoint& P,     // [IN] point P
316   const ON_2dVector& Pdir, // [IN] tangent at P
317   const ON_2dPoint& Q      // [IN] point Q
318   )
319 {
320   return Create( ON_3dPoint(P), ON_3dVector(Pdir), ON_3dPoint(Q) );
321 }
322 
323 //////////
324 // Create an circle from two 3d points and a tangent at the first point.
Create(const ON_3dPoint & P,const ON_3dVector & Pdir,const ON_3dPoint & Q)325 bool ON_Circle::Create(
326   const ON_3dPoint& P,      // [IN] point P
327   const ON_3dVector& Pdir, // [IN] tangent at P
328   const ON_3dPoint& Q      // [IN] point Q
329   )
330 {
331   bool rc = false;
332   double a, b;
333   ON_3dVector QP, RM, RP, X, Y, Z;
334   ON_3dPoint M, C;
335   ON_Line A, B;
336 
337   // n = normal to circle
338   QP = Q-P;
339   Z = ON_CrossProduct( QP, Pdir );
340   if ( Z.Unitize() ) {
341     M = 0.5*(P+Q);
342     RM = ON_CrossProduct( QP, Z ); // vector parallel to center-M
343     A.Create(M,M+RM);
344     RP = ON_CrossProduct( Pdir, Z ); //  vector parallel to center-P
345     B.Create(P,P+RP);
346     if ( ON_Intersect( A, B, &a, &b ) ) {
347       C = A.PointAt( a ); // center = intersection of lines A and B
348       X = P-C;
349       radius = C.DistanceTo(P);
350       if ( X.Unitize() ) {
351         Y = ON_CrossProduct( Z, X );
352         if ( Y*Pdir < 0.0 ) {
353           Z.Reverse();
354           Y.Reverse();
355           RM.Reverse();
356         }
357         plane.origin = C;
358         plane.xaxis = X;
359         plane.yaxis = Y;
360         plane.zaxis = Z;
361         plane.UpdateEquation();
362         //m_point[0] = P;
363         //m_point[1] = C + radius*RM/RM.Length();
364         //m_point[2] = Q;
365         rc = IsValid();
366       }
367     }
368   }
369   return rc;
370 }
371 
372 
IsValid() const373 bool ON_Circle::IsValid() const
374 {
375   bool rc = (    ON_IsValid(radius)
376               && radius > 0.0
377               && plane.IsValid()
378             );
379   return rc;
380 }
381 
IsInPlane(const ON_Plane & plane,double tolerance) const382 bool ON_Circle::IsInPlane( const ON_Plane& plane, double tolerance ) const
383 {
384   double d;
385   int i;
386   for ( i = 0; i < 8; i++ ) {
387     d = plane.plane_equation.ValueAt( PointAt(0.25*i*ON_PI) );
388     if ( fabs(d) > tolerance )
389       return false;
390   }
391   return true;
392 }
393 
PointAt(double t) const394 ON_3dPoint ON_Circle::PointAt( double t ) const
395 {
396   return plane.PointAt( cos(t)*radius, sin(t)*radius );
397 }
398 
DerivativeAt(int d,double t) const399 ON_3dVector ON_Circle::DerivativeAt(
400                  int d, // desired derivative ( >= 0 )
401                  double t // parameter
402                  ) const
403 {
404   double r0 = radius;
405   double r1 = radius;
406   switch (abs(d)%4) {
407   case 0:
408     r0 *=  cos(t);
409     r1 *=  sin(t);
410     break;
411   case 1:
412     r0 *= -sin(t);
413     r1 *=  cos(t);
414     break;
415   case 2:
416     r0 *= -cos(t);
417     r1 *= -sin(t);
418     break;
419   case 3:
420     r0 *=  sin(t);
421     r1 *= -cos(t);
422     break;
423   }
424   return ( r0*plane.xaxis + r1*plane.yaxis );
425 }
426 
TangentAt(double t) const427 ON_3dVector ON_Circle::TangentAt( double t ) const
428 {
429   ON_3dVector T = DerivativeAt(1,t);
430   T.Unitize();
431   return T;
432 }
433 
ClosestPointTo(const ON_3dPoint & point,double * t) const434 bool ON_Circle::ClosestPointTo( const ON_3dPoint& point, double* t ) const
435 {
436   bool rc = true;
437   if ( t ) {
438     double u, v;
439     rc = plane.ClosestPointTo( point, &u, &v );
440     if ( u == 0.0 && v == 0.0 ) {
441       *t = 0.0;
442     }
443     else {
444       *t = atan2( v, u );
445       if ( *t < 0.0 )
446         *t += 2.0*ON_PI;
447     }
448   }
449   return rc;
450 }
451 
ClosestPointTo(const ON_3dPoint & point) const452 ON_3dPoint ON_Circle::ClosestPointTo( const ON_3dPoint& point ) const
453 {
454   ON_3dPoint P;
455   ON_3dVector V = plane.ClosestPointTo( point ) - Center();
456   if ( V.Unitize() ) {
457     V.Unitize();
458     P = Center() + Radius()*V;
459   }
460   else {
461     P = PointAt(0.0);
462   }
463   return P;
464 }
465 
EquationAt(const ON_2dPoint & p) const466 double ON_Circle::EquationAt(
467                  const ON_2dPoint& p // coordinates in plane
468                  ) const
469 {
470   double e, x, y;
471   if ( radius != 0.0 ) {
472     x = p.x/radius;
473     y = p.y/radius;
474     e = x*x + y*y - 1.0;
475   }
476   else {
477     e = 0.0;
478   }
479   return e;
480 }
481 
GradientAt(const ON_2dPoint & p) const482 ON_2dVector ON_Circle::GradientAt(
483                  const ON_2dPoint& p // coordinates in plane
484                  ) const
485 {
486   ON_2dVector g;
487   if ( radius != 0.0 ) {
488     const double rr = 2.0/(radius*radius);
489     g.x = rr*p.x;
490     g.y = rr*p.y;
491   }
492   else {
493     g.Zero();
494   }
495   return g;
496 }
497 
Rotate(double sin_angle,double cos_angle,const ON_3dVector & axis)498 bool ON_Circle::Rotate(
499                           double sin_angle, double cos_angle,
500                           const ON_3dVector& axis
501                           )
502 {
503   return plane.Rotate( sin_angle, cos_angle, axis );
504 }
505 
Rotate(double angle,const ON_3dVector & axis)506 bool ON_Circle::Rotate(
507                           double angle,
508                           const ON_3dVector& axis
509                           )
510 {
511   return plane.Rotate( angle, axis );
512 }
513 
Rotate(double sin_angle,double cos_angle,const ON_3dVector & axis,const ON_3dPoint & point)514 bool ON_Circle::Rotate(
515                           double sin_angle, double cos_angle,
516                           const ON_3dVector& axis,
517                           const ON_3dPoint& point
518                           )
519 {
520   return plane.Rotate( sin_angle, cos_angle, axis, point );
521 }
522 
Rotate(double angle,const ON_3dVector & axis,const ON_3dPoint & point)523 bool ON_Circle::Rotate(
524                           double angle,
525                           const ON_3dVector& axis,
526                           const ON_3dPoint& point
527                           )
528 {
529   return plane.Rotate( angle, axis, point );
530 }
531 
532 
Translate(const ON_3dVector & delta)533 bool ON_Circle::Translate(
534                           const ON_3dVector& delta
535                             )
536 {
537   //m_point[0] += delta;
538   //m_point[1] += delta;
539   //m_point[2] += delta;
540   return plane.Translate( delta );
541 }
542 
Reverse()543 bool ON_Circle::Reverse()
544 {
545   //ON_3dPoint P = m_point[0];
546   //m_point[0] = m_point[2];
547   //m_point[2] = P;
548   plane.yaxis = -plane.yaxis;
549   plane.zaxis = -plane.zaxis;
550   plane.UpdateEquation();
551   return true;
552 }
553 
GetNurbForm(ON_NurbsCurve & nurbscurve) const554 int ON_Circle::GetNurbForm( ON_NurbsCurve& nurbscurve ) const
555 {
556   int rc = 0;
557   if ( IsValid() ) {
558     nurbscurve.Create( 3, true, 3, 9 );
559     nurbscurve.m_knot[0] = nurbscurve.m_knot[1] = 0.0;
560     nurbscurve.m_knot[2] = nurbscurve.m_knot[3] = 0.5*ON_PI;
561     nurbscurve.m_knot[4] = nurbscurve.m_knot[5] = ON_PI;
562     nurbscurve.m_knot[6] = nurbscurve.m_knot[7] = 1.5*ON_PI;
563     nurbscurve.m_knot[8] = nurbscurve.m_knot[9] = 2.0*ON_PI;
564     ON_4dPoint* CV = (ON_4dPoint*)nurbscurve.m_cv;
565 
566     CV[0] = plane.PointAt( radius,     0.0);
567     CV[1] = plane.PointAt( radius,  radius);
568     CV[2] = plane.PointAt(    0.0,  radius);
569     CV[3] = plane.PointAt(-radius,  radius);
570     CV[4] = plane.PointAt(-radius,     0.0);
571     CV[5] = plane.PointAt(-radius, -radius);
572     CV[6] = plane.PointAt(    0.0, -radius);
573     CV[7] = plane.PointAt( radius, -radius);
574     CV[8] = CV[0];
575 
576     const double w = 1.0/sqrt(2.0);
577     int i;
578     for ( i = 1; i < 8; i += 2 ) {
579       CV[i].x *= w;
580       CV[i].y *= w;
581       CV[i].z *= w;
582       CV[i].w = w;
583     }
584     rc = 2;
585   }
586   return rc;
587 }
588 
589 
590 
GetRadianFromNurbFormParameter(double NurbParameter,double * RadianParameter) const591 bool ON_Circle::GetRadianFromNurbFormParameter( double NurbParameter, double* RadianParameter ) const
592 //returns false unless   0<= NurbParameter,  <= 2*PI*Radius
593 {
594 	if(!IsValid())
595 		return false;
596 
597 	ON_Arc arc(*this, 2*ON_PI);
598 	return arc.GetRadianFromNurbFormParameter( NurbParameter, RadianParameter);
599 }
600 
601 
602 
GetNurbFormParameterFromRadian(double RadianParameter,double * NurbParameter) const603 bool ON_Circle::GetNurbFormParameterFromRadian( double RadianParameter, double* NurbParameter) const
604 {
605 	if(!IsValid())
606 		return false;
607 
608 	ON_Arc arc(*this, 2*ON_PI);
609 	return arc.GetNurbFormParameterFromRadian(  RadianParameter, NurbParameter);
610 }
611 
612 
613 
614