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