00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00015
00016
00017 #include "pcl/surface/3rdparty/opennurbs/opennurbs.h"
00018
00019 ON_OBJECT_IMPLEMENT( ON_RevSurface, ON_Surface, "A16220D3-163B-11d4-8000-0010830122F0");
00020
00021
00022 void ON_RevSurface::DestroyRuntimeCache( bool bDelete )
00023 {
00024 ON_Surface::DestroyRuntimeCache(bDelete);
00025 if ( 0 != m_curve )
00026 m_curve->DestroyRuntimeCache(bDelete);
00027
00028
00029 m_bbox.Destroy();
00030 }
00031
00032
00033 ON_RevSurface* ON_RevSurface::New()
00034 {
00035 return new ON_RevSurface();
00036 }
00037
00038 ON_RevSurface* ON_RevSurface::New( const ON_RevSurface& rev_surface )
00039 {
00040 return new ON_RevSurface(rev_surface);
00041 }
00042
00043 ON_RevSurface::ON_RevSurface() : m_curve(0),
00044 m_axis( ON_origin, ON_zaxis ),
00045 m_angle( 0.0, 2.0*ON_PI ),
00046 m_t( 0.0, 2.0*ON_PI ),
00047 m_bTransposed(0)
00048 {
00049 ON__SET__THIS__PTR(m_s_ON_RevSurface_ptr);
00050 }
00051
00052 ON_RevSurface::~ON_RevSurface()
00053 {
00054 Destroy();
00055 }
00056
00057 void ON_RevSurface::Destroy()
00058 {
00059 DestroySurfaceTree();
00060 if ( m_curve)
00061 {
00062 delete m_curve;
00063 m_curve = 0;
00064 }
00065 m_axis.Create( ON_origin, ON_zaxis );
00066 m_angle.Set(0.0,2.0*ON_PI);
00067 m_t = m_angle;
00068 m_bTransposed = false;
00069 m_bbox.Destroy();
00070 }
00071
00072 ON_RevSurface::ON_RevSurface( const ON_RevSurface& src ) : ON_Surface(src)
00073 {
00074 ON__SET__THIS__PTR(m_s_ON_RevSurface_ptr);
00075 m_curve = src.m_curve ? src.m_curve->Duplicate() : NULL;
00076 m_axis = src.m_axis;
00077 m_angle = src.m_angle;
00078 m_t = src.m_t;
00079 m_bTransposed = src.m_bTransposed;
00080 m_bbox = src.m_bbox;
00081 }
00082
00083
00084 unsigned int ON_RevSurface::SizeOf() const
00085 {
00086 unsigned int sz = ON_Surface::SizeOf();
00087 if ( m_curve )
00088 sz += m_curve->SizeOf();
00089 return sz;
00090 }
00091
00092 ON__UINT32 ON_RevSurface::DataCRC(ON__UINT32 current_remainder) const
00093 {
00094 if ( m_curve )
00095 current_remainder = m_curve->DataCRC(current_remainder);
00096 current_remainder = ON_CRC32(current_remainder,sizeof(m_axis),&m_axis);
00097 current_remainder = ON_CRC32(current_remainder,sizeof(m_angle),&m_angle);
00098 current_remainder = ON_CRC32(current_remainder,sizeof(m_t),&m_t);
00099 current_remainder = ON_CRC32(current_remainder,sizeof(m_bTransposed),&m_bTransposed);
00100 return current_remainder;
00101 }
00102
00103
00104 ON_RevSurface& ON_RevSurface::operator=( const ON_RevSurface& src )
00105 {
00106 if ( this != &src )
00107 {
00108 Destroy();
00109 ON_Surface::operator=(src);
00110 if ( src.m_curve )
00111 m_curve = src.m_curve->Duplicate();
00112 m_axis = src.m_axis;
00113 m_angle = src.m_angle;
00114 m_t = src.m_t;
00115 m_bTransposed = src.m_bTransposed;
00116 m_bbox = src.m_bbox;
00117 }
00118 return *this;
00119 }
00120
00121
00122 ON_BOOL32 ON_RevSurface::SetAngleRadians(
00123 double start_angle_radians,
00124 double end_angle_radians
00125 )
00126 {
00127 bool rc = false;
00128 double d = end_angle_radians-start_angle_radians;
00129 if ( d >= 0.0 )
00130 {
00131 if ( d <= ON_ZERO_TOLERANCE || d > 2.0*ON_PI )
00132 {
00133 end_angle_radians = start_angle_radians + 2.0*ON_PI;
00134 }
00135 m_angle.Set( start_angle_radians, end_angle_radians );
00136 rc = true;
00137 DestroySurfaceTree();
00138 }
00139 return rc;
00140 }
00141
00142
00143 ON_BOOL32 ON_RevSurface::SetAngleDegrees (
00144 double start_angle_degrees,
00145 double end_angle_degrees
00146 )
00147 {
00148 return SetAngleRadians(
00149 start_angle_degrees*ON_PI/180.0,
00150 end_angle_degrees*ON_PI/180.0
00151 );
00152 }
00153
00154
00155 ON_BOOL32 ON_RevSurface::IsValid( ON_TextLog* text_log ) const
00156 {
00157 if ( !m_curve )
00158 {
00159 if ( text_log )
00160 text_log->Print( "ON_RevSurface.m_curve is NULL.\n");
00161 return false;
00162 }
00163 if ( !m_curve->IsValid(text_log) )
00164 {
00165 if ( text_log )
00166 text_log->Print( "ON_RevSurface.m_curve is not valid.\n");
00167 return false;
00168 }
00169 int dim = m_curve->Dimension();
00170 if ( dim != 3 )
00171 {
00172 if ( text_log )
00173 text_log->Print( "ON_RevSurface.m_curve->Dimension()=%d (should be 3).\n",dim);
00174 return false;
00175 }
00176 if ( !m_axis.IsValid() )
00177 {
00178 if ( text_log )
00179 text_log->Print( "ON_RevSurface.m_axis is not valid.\n");
00180 return false;
00181 }
00182 if ( !m_angle.IsIncreasing() )
00183 {
00184 if ( text_log )
00185 text_log->Print( "ON_RevSurface.m_angle = (%g,%g) (should be an increasing interval)\n",
00186 m_angle[0],m_angle[1]);
00187 return false;
00188 }
00189 double length = m_angle.Length();
00190 if ( length > 2.0*ON_PI + ON_ZERO_TOLERANCE )
00191 {
00192 if ( text_log )
00193 text_log->Print( "ON_RevSurface.m_angle.Length() = %g (should be <= 2*pi radians).\n",length);
00194 return false;
00195 }
00196 if ( m_angle.Length() <= ON_ZERO_TOLERANCE )
00197 {
00198 if ( text_log )
00199 text_log->Print( "ON_RevSurface.m_angle.Length() = %g (should be > ON_ZERO_TOLERANCE).\n",length);
00200 return false;
00201 }
00202 if ( !m_t.IsIncreasing() )
00203 {
00204 if ( text_log )
00205 text_log->Print( "ON_RevSurface.m_t = (%g,%g) (should be an increasing interval)\n",
00206 m_t[0],m_t[1]);
00207 return false;
00208 }
00209 return true;
00210 }
00211
00212 void ON_RevSurface::Dump( ON_TextLog& dump ) const
00213 {
00214 ON_Object::Dump(dump);
00215 dump.PushIndent();
00216 if ( m_bTransposed )
00217 dump.Print("Paramerization: (curve,angle)\n");
00218 else
00219 dump.Print("Paramerization: (angle,curve)\n");
00220 dump.Print("Axis: ");
00221 dump.Print(m_axis.from);
00222 dump.Print(" to ");
00223 dump.Print(m_axis.to);
00224 dump.Print("\n");
00225 dump.Print("Rotation angle: %g to %g radians.\n",m_angle[0],m_angle[1]);
00226 dump.Print("Angle evaluation parameter interval: [%g,%g].\n",m_t[0],m_t[1]);
00227 if ( m_curve ) {
00228 dump.Print("Revolute: \n");
00229 dump.PushIndent();
00230 m_curve->Dump(dump);
00231 dump.PopIndent();
00232 }
00233 }
00234
00235 ON_BOOL32 ON_RevSurface::Write( ON_BinaryArchive& file ) const
00236 {
00237 ON_BOOL32 rc = file.Write3dmChunkVersion(2,0);
00238 if (rc)
00239 {
00240 rc = file.WriteLine( m_axis );
00241 rc = file.WriteInterval( m_angle );
00242 rc = file.WriteInterval( m_t );
00243 rc = file.WriteBoundingBox( m_bbox );
00244 rc = file.WriteInt( m_bTransposed );
00245 if ( m_curve )
00246 {
00247 rc = file.WriteChar((char)1);
00248 if (rc) rc = file.WriteObject(*m_curve);
00249 }
00250 else
00251 {
00252 rc = file.WriteChar((char)0);
00253 }
00254 }
00255 return rc;
00256 }
00257
00258
00259 ON_BOOL32 ON_RevSurface::Read( ON_BinaryArchive& file )
00260 {
00261 int major_version = 0;
00262 int minor_version = 0;
00263 char bHaveCurve = 0;
00264 ON_BOOL32 rc = file.Read3dmChunkVersion(&major_version,&minor_version);
00265 if (rc && major_version == 1)
00266 {
00267 rc = file.ReadLine( m_axis );
00268 rc = file.ReadInterval( m_angle );
00269 rc = file.ReadBoundingBox( m_bbox );
00270 rc = file.ReadInt( &m_bTransposed );
00271 rc = file.ReadChar( &bHaveCurve );
00272 if ( bHaveCurve )
00273 {
00274 ON_Object* obj = 0;
00275 rc = file.ReadObject(&obj);
00276 if ( obj )
00277 {
00278 m_curve = ON_Curve::Cast(obj);
00279 if ( !m_curve )
00280 delete obj;
00281 }
00282 }
00283 m_t[0] = m_angle.Min();
00284 m_t[1] = m_angle.Max();
00285 }
00286 else if (rc && major_version == 2)
00287 {
00288 rc = file.ReadLine( m_axis );
00289 rc = file.ReadInterval( m_angle );
00290 rc = file.ReadInterval( m_t );
00291 rc = file.ReadBoundingBox( m_bbox );
00292 rc = file.ReadInt( &m_bTransposed );
00293 rc = file.ReadChar( &bHaveCurve );
00294 if ( bHaveCurve )
00295 {
00296 ON_Object* obj = 0;
00297 rc = file.ReadObject(&obj);
00298 if ( obj )
00299 {
00300 m_curve = ON_Curve::Cast(obj);
00301 if ( !m_curve )
00302 delete obj;
00303 }
00304 }
00305 }
00306 return rc;
00307 }
00308
00309 int ON_RevSurface::Dimension() const
00310 {
00311 return 3;
00312 }
00313
00314 ON_BOOL32 ON_RevSurface::Transform( const ON_Xform& xform )
00315 {
00316 DestroyRuntimeCache();
00317 TransformUserData(xform);
00318 ON_BOOL32 rc = (m_curve) ? m_curve->Transform(xform) : false;
00319 ON_3dVector X, Y, Z;
00320 Z = m_axis.Tangent();
00321 X.PerpendicularTo( Z );
00322 X.Unitize();
00323 Y = ON_CrossProduct( Z, X );
00324 if ( !m_axis.Transform(xform) )
00325 rc = false;
00326 ON_3dVector transZ = m_axis.Tangent();
00327
00328 if ( transZ.Length() == 0.0 )
00329 {
00330
00331 m_axis.to = m_axis.from + Z;
00332 }
00333 else
00334 {
00335
00336
00337
00338 ON_3dVector transX = xform*X;
00339 ON_3dVector transY = xform*Y;
00340 ON_3dVector transXxY = ON_CrossProduct( transX, transY );
00341 double d = transXxY*transZ;
00342 if ( d < 0.0 )
00343 m_axis.to = m_axis.from - m_axis.Direction();
00344 }
00345
00346 m_bbox.Destroy();
00347 m_bbox = BoundingBox();
00348 return rc;
00349 }
00350
00351 ON_BOOL32 ON_RevSurface::Evaluate(
00352 double s,
00353 double t,
00354
00355 int der_count,
00356 int v_stride,
00357 double* v,
00358 int side,
00359
00360
00361
00362
00363
00364 int* hint
00365
00366 ) const
00367 {
00368 bool rc = false;
00369
00370 double ds = 1.0;
00371 double x,y,z;
00372 int i, j, k, src_i, dst_i;
00373 ON_3dPoint pt;
00374
00375 if ( m_bTransposed )
00376 {
00377 x = s; s = t; t = x;
00378 if ( side == 2 ) side = 4; else if ( side == 4 ) side = 2;
00379 }
00380
00381 if ( m_t != m_angle )
00382 {
00383 if ( m_t.m_t[1] != m_t.m_t[0] )
00384 {
00385 ds = (m_angle.m_t[1] - m_angle.m_t[0])/(m_t.m_t[1] - m_t.m_t[0]);
00386 x = m_t.NormalizedParameterAt(s);
00387 y = m_angle.ParameterAt(x);
00388 s = y;
00389 }
00390 }
00391
00392
00393 double a = cos(s);
00394 double b = sin(s);
00395 const double ca[4] = {a, -b, -a, b};
00396 const double sa[4] = {b, a, -b, -a};
00397
00398 const int curve_dim = m_curve ? m_curve->Dimension() : 0;
00399 if ( curve_dim == 2 || curve_dim == 3 )
00400 {
00401 int curve_side = 0;
00402 switch(side)
00403 {
00404 case 1:
00405 case 2:
00406 curve_side = 1;
00407 break;
00408 case 3:
00409 case 4:
00410 curve_side = -1;
00411 break;
00412 }
00413 rc = m_curve->Evaluate( t, der_count, v_stride, v, curve_side, hint )?true:false;
00414 if ( rc )
00415 {
00416 ON_3dVector zaxis = m_axis.Tangent();
00417 ON_3dVector xaxis, yaxis;
00418 xaxis.PerpendicularTo(zaxis);
00419 xaxis.Unitize();
00420 yaxis = ON_CrossProduct(zaxis,xaxis);
00421
00422
00423 if ( curve_dim == 2 )
00424 {
00425 for ( i = der_count; i >= 1; i-- )
00426 {
00427
00428 src_i = v_stride*i;
00429 dst_i = v_stride*((i+1)*(i+2)/2 - 1);
00430 v[dst_i++] = v[src_i++];
00431 v[dst_i++] = 0.0;
00432 v[dst_i] = v[src_i];
00433 }
00434 }
00435 else
00436 {
00437 for ( i = der_count; i >= 1; i-- )
00438 {
00439
00440 src_i = v_stride*i;
00441 dst_i = v_stride*((i+1)*(i+2)/2 - 1);
00442 v[dst_i++] = v[src_i++];
00443 v[dst_i++] = v[src_i++];
00444 v[dst_i] = v[src_i];
00445 }
00446 }
00447
00448
00449 {
00450 pt = ON_3dPoint(v)-m_axis.from;
00451 v[0] = pt*xaxis;
00452 v[1] = pt*yaxis;
00453 v[2] = pt*zaxis;
00454 }
00455
00456
00457 for ( i = 1; i <= der_count; i++ )
00458 {
00459 dst_i = v_stride*((i+1)*(i+2)/2 - 1);
00460 pt = ON_3dPoint(v+dst_i);
00461 v[dst_i++] = pt*xaxis;
00462 v[dst_i++] = pt*yaxis;
00463 v[dst_i] = pt*zaxis;
00464 }
00465
00466 for ( i = der_count; i >= 0; i-- )
00467 {
00468
00469 double f = 1.0;
00470 for ( j = i; j >= 0; j-- )
00471 {
00472
00473
00474 dst_i = v_stride*(i*(i+1)/2 + j);
00475 src_i = v_stride*((j+1)*(j+2)/2 - 1);
00476 k=(i-j)%4;
00477 a = f*ca[k];
00478 b = f*sa[k];
00479 f *= ds;
00480
00481
00482 x = a*v[src_i] - b*v[src_i+1];
00483 y = b*v[src_i] + a*v[src_i+1];
00484 z = (j<i) ? 0.0 : v[src_i+2];
00485
00486 pt = x*xaxis + y*yaxis + z*zaxis;
00487 v[dst_i++] = pt.x;
00488 v[dst_i++] = pt.y;
00489 v[dst_i] = pt.z;
00490 }
00491 }
00492
00493
00494 v[0] += m_axis.from.x;
00495 v[1] += m_axis.from.y;
00496 v[2] += m_axis.from.z;
00497
00498 if ( m_bTransposed )
00499 {
00500 for ( i = 1; i <= der_count; i++ )
00501 {
00502 for ( j = 0, k = i; j < k; j++, k-- )
00503 {
00504 dst_i = i*(i+1)/2;
00505 src_i = dst_i + k;
00506 dst_i += j;
00507 src_i *= v_stride;
00508 dst_i *= v_stride;
00509 x = v[src_i]; v[src_i++] = v[dst_i]; v[dst_i++] = x;
00510 x = v[src_i]; v[src_i++] = v[dst_i]; v[dst_i++] = x;
00511 x = v[src_i]; v[src_i] = v[dst_i]; v[dst_i] = x;
00512 }
00513 }
00514 }
00515 }
00516 }
00517 return rc;
00518 }
00519
00520
00521 class ON_RevolutionTensor : public ON_TensorProduct
00522 {
00523 public:
00524 ON_3dPoint O;
00525 ON_3dVector X;
00526 ON_3dVector Y;
00527 ON_3dVector Z;
00528 int DimensionA() const;
00529 int DimensionB() const;
00530 int DimensionC() const;
00531 bool Evaluate( double,
00532 const double*,
00533 double,
00534 const double*,
00535 double*
00536 );
00537 };
00538
00539 int ON_RevolutionTensor::DimensionA() const
00540 {
00541 return 2;
00542 }
00543
00544 int ON_RevolutionTensor::DimensionB() const
00545 {
00546 return 3;
00547 }
00548
00549 int ON_RevolutionTensor::DimensionC() const
00550 {
00551 return 3;
00552 }
00553
00554 bool ON_RevolutionTensor::Evaluate( double a, const double* ArcPoint, double b, const double* ShapePoint, double* SrfPoint )
00555 {
00556 double x, y, z, c, s, rx, ry, A[2], B[3];
00557
00558 if (a != 1.0) {
00559 A[0] = a*ArcPoint[0];
00560 A[1] = a*ArcPoint[1];
00561 ArcPoint = A;
00562 }
00563
00564 if (b != 1.0) {
00565 B[0] = b*ShapePoint[0];
00566 B[1] = b*ShapePoint[1];
00567 B[2] = b*ShapePoint[2];
00568 ShapePoint = B;
00569 }
00570
00571
00572 x = (ShapePoint[0] - O.x)*X.x + (ShapePoint[1] - O.y)*X.y + (ShapePoint[2] - O.z)*X.z;
00573 y = (ShapePoint[0] - O.x)*Y.x + (ShapePoint[1] - O.y)*Y.y + (ShapePoint[2] - O.z)*Y.z;
00574 z = (ShapePoint[0] - O.x)*Z.x + (ShapePoint[1] - O.y)*Z.y + (ShapePoint[2] - O.z)*Z.z;
00575
00576 c = ArcPoint[0];
00577 s = ArcPoint[1];
00578
00579 rx = c*x - s*y;
00580 ry = s*x + c*y;
00581
00582 SrfPoint[0] = O.x + rx*X.x + ry*Y.x + z*Z.x;
00583 SrfPoint[1] = O.y + rx*X.y + ry*Y.y + z*Z.y;
00584 SrfPoint[2] = O.z + rx*X.z + ry*Y.z + z*Z.z;
00585
00586 return true;
00587 }
00588
00589 int ON_RevSurface::GetNurbForm(class ON_NurbsSurface& srf , double tolerance ) const
00590 {
00591 int rc = 0;
00592 if ( 0 != m_curve )
00593 {
00594 ON_NurbsCurve a, c;
00595 ON_Arc arc;
00596 arc.plane.CreateFromNormal( ON_origin, ON_zaxis );
00597 arc.radius = 1.0;
00598 arc.SetAngleRadians(m_angle[1]-m_angle[0]);
00599 if ( arc.GetNurbForm(a) )
00600 {
00601 if ( m_t.IsIncreasing() )
00602 a.SetDomain( m_t[0], m_t[1] );
00603 rc = m_curve->GetNurbForm(c,tolerance);
00604 if (rc)
00605 {
00606 if ( 2 == c.m_dim )
00607 {
00608
00609
00610
00611 ON_WARNING("ON_RevSurface.m_curve is 2-dimensional.");
00612 c.ChangeDimension(3);
00613 }
00614 if ( 3 != c.m_dim )
00615 {
00616 ON_ERROR("ON_RevSurface.m_curve is not valid.");
00617 return 0;
00618 }
00619
00620 if ( m_angle[0] != 0.0 )
00621 {
00622 c.Rotate( m_angle[0], m_axis.Direction(), m_axis.from );
00623 }
00624 ON_RevolutionTensor rho;
00625 rho.O = m_axis.from;
00626 rho.Z = m_axis.Direction();
00627 rho.Z.Unitize();
00628 rho.X.PerpendicularTo(rho.Z);
00629 rho.X.Unitize();
00630 rho.Y = ON_CrossProduct(rho.Z,rho.X);
00631 rho.Y.Unitize();
00632 if ( !srf.TensorProduct( a, c, rho ) )
00633 {
00634
00635
00636
00637
00638
00639 return 0;
00640 }
00641
00642
00643 ON_3dPoint C0 = c.PointAtStart();
00644 ON_3dPoint C1 = c.PointAtEnd();
00645 ON_3dPoint A0, A1;
00646 ON_4dPoint CV;
00647 double t0 = ON_UNSET_VALUE;
00648 double t1 = ON_UNSET_VALUE;
00649 if (m_axis.ClosestPointTo(C0,&t0) && ON_IsValid(t0) )
00650 {
00651 A0 = m_axis.PointAt(t0);
00652 if ( C0.DistanceTo(A0) <= ON_ZERO_TOLERANCE )
00653 {
00654
00655 int j = 0;
00656 for ( int i = 0; i < srf.m_cv_count[0]; i++ )
00657 {
00658 CV.w = srf.Weight(i,j);
00659 CV.x = CV.w*A0.x;
00660 CV.y = CV.w*A0.y;
00661 CV.z = CV.w*A0.z;
00662 srf.SetCV(i,j,CV);
00663 }
00664 }
00665 }
00666 if (m_axis.ClosestPointTo(C1,&t1) && ON_IsValid(t1) )
00667 {
00668 A1 = m_axis.PointAt(t1);
00669 if ( C1.DistanceTo(A1) <= ON_ZERO_TOLERANCE )
00670 {
00671
00672 int j = srf.m_cv_count[1]-1;
00673 for ( int i = 0; i < srf.m_cv_count[0]; i++ )
00674 {
00675 CV.w = srf.Weight(i,j);
00676 CV.x = CV.w*A1.x;
00677 CV.y = CV.w*A1.y;
00678 CV.z = CV.w*A1.z;
00679 srf.SetCV(i,j,CV);
00680 }
00681 }
00682 }
00683
00684 if ( m_bTransposed )
00685 srf.Transpose();
00686 }
00687 }
00688 }
00689 return (rc > 0) ? 2 : 0;
00690 }
00691
00692 int ON_RevSurface::HasNurbForm() const
00693
00694 {
00695 if (!IsValid())
00696 return 0;
00697 return 2;
00698 }
00699
00700 bool ON_RevSurface::GetSurfaceParameterFromNurbFormParameter(
00701 double nurbs_s, double nurbs_t,
00702 double* surface_s, double* surface_t
00703 ) const
00704 {
00705
00706 bool rc = (0 != m_curve);
00707
00708
00709
00710 if ( m_bTransposed )
00711 {
00712 double* pTemp = surface_s; surface_s = surface_t; surface_t = pTemp;
00713 double temp = nurbs_s; nurbs_s = nurbs_t; nurbs_t = temp;
00714 }
00715
00716 *surface_s = nurbs_s;
00717 *surface_t = nurbs_t;
00718
00719 ON_Circle circle( ON_xy_plane, 1.0 );
00720 ON_Arc arc( circle, m_angle );
00721 ON_ArcCurve arc_curve(arc, m_t[0], m_t[1]);
00722 if ( !arc_curve.GetCurveParameterFromNurbFormParameter( nurbs_s, surface_s ) )
00723 rc = false;
00724
00725 if ( m_curve )
00726 {
00727 if (!m_curve->GetCurveParameterFromNurbFormParameter( nurbs_t, surface_t ))
00728 rc = false;
00729 }
00730
00731
00732 return rc;
00733 }
00734
00735 bool ON_RevSurface::GetNurbFormParameterFromSurfaceParameter(
00736 double surface_s, double surface_t,
00737 double* nurbs_s, double* nurbs_t
00738 ) const
00739 {
00740
00741 bool rc = (0 != m_curve);
00742
00743 if ( m_bTransposed )
00744 {
00745 double temp = surface_s; surface_s = surface_t; surface_t = temp;
00746 double* pTemp = nurbs_s; nurbs_s = nurbs_t; nurbs_t = pTemp;
00747 }
00748
00749 *nurbs_s = surface_s;
00750 *nurbs_t = surface_t;
00751
00752 ON_Circle circle( ON_xy_plane, 1.0 );
00753 ON_Arc arc( circle, m_angle );
00754 ON_ArcCurve arc_curve(arc, m_t[0], m_t[1]);
00755 if ( !arc_curve.GetNurbFormParameterFromCurveParameter( surface_s, nurbs_s ) )
00756 rc = false;
00757
00758 if ( m_curve )
00759 {
00760 if (!m_curve->GetNurbFormParameterFromCurveParameter( surface_t, nurbs_t ))
00761 rc = false;
00762 }
00763
00764 return rc;
00765 }
00766
00767
00768 ON_Curve* ON_RevSurface::IsoCurve( int dir, double c ) const
00769 {
00770 if ( dir < 0 || dir > 1 || !m_curve )
00771 return NULL;
00772
00773 ON_Curve* crv = 0;
00774
00775 if ( m_bTransposed )
00776 dir = 1-dir;
00777
00778 if ( dir == 0 )
00779 {
00780
00781
00782 ON_Circle circle;
00783 ON_3dPoint P = m_curve->PointAt(c);
00784 circle.plane.origin = m_axis.ClosestPointTo(P);
00785 circle.plane.zaxis = m_axis.Tangent();
00786 circle.plane.xaxis = P - circle.plane.origin;
00787 circle.radius = circle.plane.xaxis.Length();
00788 if ( !circle.plane.xaxis.Unitize() )
00789 {
00790
00791
00792
00793 P = m_curve->PointAt(m_curve->Domain().ParameterAt(0.5));
00794 ON_3dPoint Q = m_axis.ClosestPointTo(P);
00795 circle.plane.xaxis = P-Q;
00796 if ( !circle.plane.xaxis.Unitize() )
00797 {
00798
00799 circle.plane.xaxis.PerpendicularTo(circle.plane.zaxis);
00800 }
00801 }
00802 circle.plane.yaxis = ON_CrossProduct( circle.plane.zaxis, circle.plane.xaxis );
00803 circle.plane.yaxis.Unitize();
00804 circle.plane.UpdateEquation();
00805 ON_Arc arc( circle, m_angle );
00806 crv = new ON_ArcCurve(arc, m_t[0], m_t[1]);
00807 }
00808 else if ( dir == 1 && m_curve )
00809 {
00810 crv = m_curve->DuplicateCurve();
00811 if ( crv )
00812 {
00813 double a = c;
00814 if ( m_t != m_angle )
00815 {
00816 double t = m_t.NormalizedParameterAt(c);
00817 a = m_angle.ParameterAt(t);
00818 }
00819 if ( a != 0.0 )
00820 {
00821 crv->Rotate( a, m_axis.Direction(), m_axis.from );
00822 }
00823 }
00824 }
00825 return crv;
00826 }
00827
00828 ON_BOOL32 ON_RevSurface::Trim( int dir, const ON_Interval& domain )
00829 {
00830 ON_BOOL32 rc = false;
00831 if ( dir != 0 && dir != 1 )
00832 return false;
00833 if ( !domain.IsIncreasing() )
00834 return false;
00835 if ( m_bTransposed )
00836 dir = 1-dir;
00837 if ( dir == 0 )
00838 {
00839 ON_Interval dom;
00840 dom.Intersection(domain,m_t);
00841 if ( !dom.IsIncreasing() || !m_t.IsIncreasing() || !m_angle.IsIncreasing() )
00842 return false;
00843 double t0 = m_t.NormalizedParameterAt(dom[0]);
00844 double t1 = m_t.NormalizedParameterAt(dom[1]);
00845 ON_Interval a;
00846 a[0] = m_angle.ParameterAt(t0);
00847 a[1] = m_angle.ParameterAt(t1);
00848 double d = a.Length();
00849 if ( fabs(d) > ON_ZERO_TOLERANCE && fabs(d) <= 2.0*ON_PI+ON_ZERO_TOLERANCE )
00850 {
00851 m_angle = a;
00852 m_t = domain;
00853 rc = true;
00854 }
00855 }
00856 else if ( dir == 1 && m_curve )
00857 {
00858 rc = m_curve->Trim( domain );
00859 }
00860 if ( rc )
00861 {
00862
00863 ON_BoundingBox bbox0 = m_bbox;
00864 m_bbox.Destroy();
00865 BoundingBox();
00866 if ( m_bbox.IsValid() && bbox0.IsValid() )
00867 m_bbox.Intersection(bbox0);
00868 }
00869 return rc;
00870 }
00871
00872 bool ON_RevSurface::Extend(
00873 int dir,
00874 const ON_Interval& domain
00875 )
00876 {
00877 if ( dir != 0 && dir != 1 )
00878 return false;
00879 if (IsClosed(dir))
00880 return false;
00881 bool do_it = false;
00882 ON_Interval dom = Domain(dir);
00883 if (domain[0] < dom[0])
00884 {
00885 dom[0] = domain[0];
00886 do_it = true;
00887 }
00888
00889 if (domain[1] > dom[1])
00890 {
00891 dom[1] = domain[1];
00892 do_it = true;
00893 }
00894
00895 if (!do_it)
00896 return false;
00897
00898 if ( m_bTransposed )
00899 dir = 1-dir;
00900
00901 bool rc = false;
00902
00903 if ( dir == 0 )
00904 {
00905 double t0 = m_t.NormalizedParameterAt(dom[0]);
00906 double t1 = m_t.NormalizedParameterAt(dom[1]);
00907 ON_Interval a;
00908 a[0] = m_angle.ParameterAt(t0);
00909 a[1] = m_angle.ParameterAt(t1);
00910 if (a.Length() > 2.0*ON_PI+ON_ZERO_TOLERANCE) a[1] = a[0]+2.0*ON_PI;
00911 m_angle = a;
00912 m_t = dom;
00913 rc = true;
00914 }
00915 else if ( dir == 1 && m_curve )
00916 {
00917 rc = m_curve->Extend(dom);
00918 }
00919
00920 if ( rc )
00921 {
00922 DestroySurfaceTree();
00923
00924 ON_BoundingBox bbox0 = m_bbox;
00925 m_bbox.Destroy();
00926 BoundingBox();
00927 }
00928 return rc;
00929 }
00930
00931 ON_BOOL32 ON_RevSurface::Split(
00932 int dir,
00933 double c,
00934 ON_Surface*& west_or_south_side,
00935 ON_Surface*& east_or_north_side
00936 ) const
00937 {
00938 ON_BOOL32 rc = false;
00939
00940 ON_RevSurface* srf_ws=ON_RevSurface::Cast(west_or_south_side);
00941 ON_RevSurface* srf_en=ON_RevSurface::Cast(east_or_north_side);
00942 if ( srf_ws && srf_ws == srf_en )
00943 return false;
00944 if ( west_or_south_side && !srf_ws )
00945 return false;
00946 if ( east_or_north_side && !srf_en )
00947 return false;
00948
00949 if ( dir != 0 && dir != 1 )
00950 return false;
00951 if ( m_bTransposed )
00952 dir = 1-dir;
00953
00954 ON_Curve* left_side = 0;
00955 ON_Curve* right_side = 0;
00956 ON_Interval left_angle, right_angle;
00957 ON_Interval left_t, right_t;
00958 left_angle = m_angle;
00959 right_angle = m_angle;
00960 left_t = m_t;
00961 right_t = m_t;
00962
00963 if ( dir == 0 )
00964 {
00965 double t = m_t.NormalizedParameterAt(c);
00966 if ( m_t.Includes(c,true) && 0.0 < t && t < 1.0 )
00967 {
00968 double a = m_angle.ParameterAt( t );
00969 if ( m_angle.Includes(a,true) )
00970 {
00971 rc = true;
00972
00973 left_angle[1] = a;
00974 right_angle[0] = a;
00975 left_t[1] = c;
00976 right_t[0] = c;
00977
00978 if ( srf_ws == this )
00979 left_side = m_curve;
00980 else
00981 left_side = m_curve->Duplicate();
00982 if ( srf_en == this )
00983 right_side = m_curve;
00984 else
00985 right_side = m_curve->Duplicate();
00986 }
00987 }
00988 }
00989 else if ( dir == 1 && m_curve )
00990 {
00991 rc = m_curve->Split( c, left_side, right_side );
00992 if ( rc )
00993 {
00994 if ( this == srf_ws )
00995 {
00996 delete m_curve;
00997 srf_ws->m_curve = left_side;
00998 }
00999 else if ( this == srf_en )
01000 {
01001 delete m_curve;
01002 srf_en->m_curve = right_side;
01003 }
01004 }
01005 }
01006
01007 if ( rc )
01008 {
01009
01010 const ON_BoundingBox input_bbox(m_bbox);
01011
01012 if ( !srf_ws )
01013 west_or_south_side = srf_ws = new ON_RevSurface();
01014 else if ( srf_ws != this && srf_ws->m_curve )
01015 {
01016 delete srf_ws->m_curve;
01017 srf_ws->m_curve = 0;
01018 }
01019 if ( !srf_en )
01020 east_or_north_side = srf_en = new ON_RevSurface();
01021 if ( srf_en != this && srf_en->m_curve )
01022 {
01023 delete srf_en->m_curve;
01024 srf_en->m_curve = 0;
01025 }
01026
01027 srf_ws->m_axis = m_axis;
01028 srf_ws->m_angle = left_angle;
01029 srf_ws->m_t = left_t;
01030 srf_ws->m_bTransposed = m_bTransposed;
01031 srf_ws->m_curve = left_side;
01032 srf_ws->m_bbox.Destroy();
01033
01034 srf_en->m_axis = m_axis;
01035 srf_en->m_angle = right_angle;
01036 srf_en->m_t = right_t;
01037 srf_en->m_bTransposed = m_bTransposed;
01038 srf_en->m_curve = right_side;
01039 srf_en->m_bbox.Destroy();
01040
01041
01042
01043
01044 srf_ws->BoundingBox();
01045 if ( srf_ws->m_bbox.IsValid() && input_bbox.IsValid() )
01046 srf_ws->m_bbox.Intersection(input_bbox);
01047
01048 srf_en->BoundingBox();
01049 if ( srf_en->m_bbox.IsValid() && input_bbox.IsValid() )
01050 srf_en->m_bbox.Intersection(input_bbox);
01051 }
01052
01053 return rc;
01054 }
01055
01056 ON_BOOL32 ON_RevSurface::Transpose()
01057 {
01058 m_bTransposed = m_bTransposed ? false : true;
01059 return true;
01060 }
01061
01062 bool ON_RevSurface::IsContinuous(
01063 ON::continuity desired_continuity,
01064 double s,
01065 double t,
01066 int* hint,
01067 double point_tolerance,
01068 double d1_tolerance,
01069 double d2_tolerance,
01070 double cos_angle_tolerance,
01071 double curvature_tolerance
01072 ) const
01073 {
01074 bool rc = true;
01075 if ( m_curve )
01076 {
01077 double curve_t = m_bTransposed ? s : t;
01078 rc = m_curve->IsContinuous( desired_continuity, curve_t, hint,
01079 point_tolerance, d1_tolerance, d2_tolerance,
01080 cos_angle_tolerance, curvature_tolerance );
01081 }
01082 return rc;
01083 }
01084
01085 ON_BOOL32 ON_RevSurface::Reverse( int dir )
01086 {
01087 ON_BOOL32 rc = false;
01088 if ( m_bTransposed )
01089 dir = dir ? 0 : 1;
01090 if ( dir == 0 )
01091 {
01092 m_axis.Reverse();
01093 double a0 = m_angle[0];
01094 double a1 = m_angle[1];
01095 m_angle.Set( 2.0*ON_PI - a1, 2.0*ON_PI - a0 );
01096 m_t.Reverse();
01097 rc = true;
01098 }
01099 else if ( dir == 1 && m_curve )
01100 {
01101 rc = m_curve->Reverse();
01102 }
01103 return rc;
01104 }
01105
01106 bool ON_RevSurface::GetNextDiscontinuity(
01107 int dir,
01108 ON::continuity c,
01109 double t0,
01110 double t1,
01111 double* t,
01112 int* hint,
01113 int* dtype,
01114 double cos_angle_tolerance,
01115 double curvature_tolerance
01116 ) const
01117 {
01118
01119 bool rc = false;
01120 if ( (m_bTransposed ? 1 : 0) == dir )
01121 {
01122
01123 ON_Circle circle(ON_xy_plane,1.0);
01124 ON_Arc arc( circle, m_angle );
01125 ON_ArcCurve arc_curve(arc, m_t[0], m_t[1]);
01126 rc = arc_curve.GetNextDiscontinuity(
01127 c,
01128 t0,t1,t,
01129 (hint? &hint[dir] : 0),
01130 dtype,cos_angle_tolerance,
01131 curvature_tolerance);
01132 }
01133 else
01134 {
01135 rc = m_curve->GetNextDiscontinuity(
01136 c,
01137 t0,t1,t,
01138 (hint? &hint[dir] : 0),
01139 dtype,cos_angle_tolerance,
01140 curvature_tolerance);
01141 }
01142 return rc;
01143 }
01144
01145 ON_BOOL32 ON_RevSurface::IsSingular( int side ) const
01146 {
01147 bool rc = false;
01148 ON_3dPoint P, Q;
01149
01150 if ( side < 0 || side > 3 )
01151 return false;
01152
01153 if ( m_bTransposed )
01154 {
01155 switch(side)
01156 {
01157 case 0: side = 3; break;
01158 case 1: side = 2; break;
01159 case 2: side = 1; break;
01160 case 3: side = 0; break;
01161 }
01162 }
01163
01164 if ( 0 == side || 2 == side )
01165 {
01166 P = (0 == side)
01167 ? m_curve->PointAtStart()
01168 : m_curve->PointAtEnd();
01169 Q = m_axis.ClosestPointTo(P);
01170
01171
01172
01173
01174
01175
01176
01177
01178
01179
01180
01181
01182
01183
01184
01185
01186
01187
01188
01189
01190
01191
01192
01193
01194
01195
01196
01197
01198
01199
01200
01201
01202
01203
01204
01205 rc = ON_PointsAreCoincident(3,0,&P.x,&Q.x);
01206
01207 }
01208
01209 return rc;
01210 }
01211
01212 ON_BOOL32 ON_RevSurface::IsPeriodic( int dir ) const
01213 {
01214 ON_BOOL32 rc = false;
01215 if ( m_bTransposed )
01216 dir = dir ? 0 : 1;
01217 if ( dir == 0 )
01218 {
01219 if (m_angle.Length() >= 2.0*ON_PI-ON_ZERO_TOLERANCE )
01220 rc = true;
01221 }
01222 else if ( dir == 1 && m_curve )
01223 {
01224 rc = m_curve->IsPeriodic();
01225 }
01226 return rc;
01227 }
01228
01229 ON_BOOL32 ON_RevSurface::IsPlanar(
01230 ON_Plane* plane,
01231 double tolerance
01232 ) const
01233 {
01234 ON_BOOL32 rc = false;
01235 if( IsValid()){
01236 ON_Plane AxisNormal( m_curve->PointAtStart(), m_axis.Tangent() );
01237 rc = m_curve->IsInPlane( AxisNormal, tolerance);
01238 if(rc && plane)
01239 *plane = AxisNormal;
01240 }
01241 return rc;
01242 }
01243
01244 ON_BOOL32 ON_RevSurface::IsClosed( int dir ) const
01245 {
01246 ON_BOOL32 rc = false;
01247 if ( m_bTransposed )
01248 dir = dir ? 0 : 1;
01249 if ( dir == 0 )
01250 {
01251 if (m_angle.Length() >= 2.0*ON_PI-ON_ZERO_TOLERANCE )
01252 rc = true;
01253 }
01254 else if ( dir == 1 && m_curve )
01255 {
01256 rc = m_curve->IsClosed();
01257 }
01258 return rc;
01259 }
01260
01261 ON_BOOL32 ON_RevSurface::GetParameterTolerance(
01262 int dir,
01263 double t,
01264 double* tminus,
01265 double* tplus
01266 ) const
01267 {
01268 ON_BOOL32 rc = false;
01269 if ( m_bTransposed )
01270 dir = dir ? 0 : 1;
01271 if ( dir == 0 )
01272 {
01273 if ( m_t.IsIncreasing() )
01274 rc = ON_GetParameterTolerance( m_t[0], m_t[1], t, tminus, tplus );
01275 }
01276 else if ( dir == 1 && m_curve )
01277 {
01278 rc = m_curve->GetParameterTolerance( t, tminus, tplus );
01279 }
01280 return rc;
01281 }
01282
01283 ON_BOOL32 ON_RevSurface::SetDomain(
01284 int dir,
01285 double t0,
01286 double t1
01287 )
01288 {
01289 bool rc = false;
01290 if ( m_bTransposed )
01291 dir = 1-dir;
01292 if ( dir == 0 )
01293 {
01294 if ( t0 < t1 )
01295 {
01296 m_t.Set(t0,t1);
01297 DestroyRuntimeCache();
01298 rc = true;
01299 }
01300 }
01301 else if ( dir == 1 && m_curve )
01302 {
01303 rc = m_curve->SetDomain( t0, t1 ) ? true : false;
01304 DestroyRuntimeCache();
01305 }
01306 return rc;
01307 }
01308
01309 ON_Interval ON_RevSurface::Domain( int dir ) const
01310 {
01311 ON_Interval d;
01312 if ( m_bTransposed )
01313 dir = 1-dir;
01314 if ( dir == 0 )
01315 {
01316 d = m_t;
01317 }
01318 else if ( dir == 1 && m_curve )
01319 {
01320 d = m_curve->Domain();
01321 }
01322 return d;
01323 }
01324
01325 ON_BOOL32 ON_RevSurface::GetSurfaceSize(
01326 double* width,
01327 double* height
01328 ) const
01329 {
01330 ON_BOOL32 rc = false;
01331 if ( m_bTransposed )
01332 {
01333 double* ptr = width;
01334 width = height;
01335 height = ptr;
01336 }
01337 if ( m_curve )
01338 {
01339 rc = true;
01340
01341 ON_Interval cdom = m_curve->Domain();
01342 int i, hint = 0;
01343 int imax = 64;
01344 double d = 1.0/((double)imax);
01345 ON_3dPoint pt0 = ON_UNSET_POINT;
01346 ON_3dPoint pt;
01347 double length_estimate = 0.0;
01348
01349 if ( width != NULL || height != NULL )
01350 {
01351 double radius_estimate = 0.0;
01352 double r;
01353 for ( i = 0; i <= imax; i++ )
01354 {
01355 if ( m_curve->EvPoint( cdom.ParameterAt(i*d), pt, 0, &hint ) )
01356 {
01357 r = m_axis.DistanceTo(pt);
01358 if ( r > radius_estimate )
01359 radius_estimate = r;
01360 if ( pt0 != ON_UNSET_POINT )
01361 length_estimate += pt0.DistanceTo(pt);
01362 pt0 = pt;
01363 }
01364 }
01365 if ( width != NULL )
01366 *width = m_angle.Length()*radius_estimate;
01367 }
01368
01369 if ( height != NULL )
01370 {
01371 *height = length_estimate;
01372 }
01373 }
01374 else
01375 {
01376 if ( width )
01377 *width = 0.0;
01378 if ( height )
01379 *height = 0.0;
01380 }
01381 return rc;
01382 }
01383
01384 int ON_RevSurface::SpanCount( int dir ) const
01385 {
01386 int span_count = 0;
01387 if ( m_bTransposed )
01388 dir = 1-dir;
01389 if ( dir==0 && m_t.IsIncreasing() )
01390 {
01391 double a = (0.5 + ON_SQRT_EPSILON)*ON_PI;
01392 double da = fabs(m_angle.Length());
01393 if (da <= a)
01394 span_count = 1;
01395 else if (da <= 2.0*a)
01396 span_count = 2;
01397 else
01398 span_count = 4;
01399 }
01400 else if ( dir == 1 && m_curve )
01401 span_count = m_curve->SpanCount();
01402 return span_count;
01403 }
01404
01405
01406 ON_BOOL32 ON_RevSurface::GetSpanVector( int dir, double* s ) const
01407 {
01408 ON_BOOL32 rc = false;
01409 if ( m_bTransposed )
01410 dir = 1-dir;
01411 if ( dir==0 && m_t.IsIncreasing() ) {
01412 int span_count = SpanCount(m_bTransposed?1-dir:dir);
01413 if ( span_count > 0 )
01414 {
01415 double d = 1.0/span_count;
01416 s[0] = m_t[0];
01417 for ( int i = 1; i < span_count; i++ )
01418 s[i] = m_t.ParameterAt( i*d );
01419 s[span_count] = m_t[1];
01420 rc = true;
01421 }
01422 }
01423 else if ( dir==1 && m_curve ) {
01424 rc = m_curve->GetSpanVector(s);
01425 }
01426 return rc;
01427 }
01428
01429
01430 int ON_RevSurface::Degree( int dir ) const
01431 {
01432 int span_degree = 0;
01433 if ( m_bTransposed )
01434 dir = 1-dir;
01435 if ( dir == 0 )
01436 span_degree = 2;
01437 else if ( dir == 1 && m_curve )
01438 span_degree = m_curve->Degree();
01439 return span_degree;
01440 }
01441
01442 void ON_RevSurface::ClearBoundingBox()
01443 {
01444 m_bbox.Destroy();
01445 }
01446
01447 ON_BOOL32 ON_RevSurface::GetBBox(
01448 double* boxmin,
01449 double* boxmax,
01450 ON_BOOL32 bGrowBox
01451 ) const
01452 {
01453 ON_BOOL32 rc = m_bbox.IsValid();
01454
01455 if ( !rc )
01456 {
01457 ON_BoundingBox bbox, cbox, abox;
01458 rc = m_curve->GetBoundingBox( cbox );
01459 if (rc)
01460 {
01461
01462
01463
01464 ON_3dPointArray corners;
01465 cbox.GetCorners(corners);
01466 ON_3dPoint P;
01467 ON_Arc arc;
01468 arc.plane.zaxis = m_axis.Tangent();
01469 arc.SetAngleRadians(m_angle[1] - m_angle[0]);
01470 int i;
01471 double t;
01472 for ( i = 0; i < 8; i++ )
01473 {
01474 P = corners[i];
01475 abox.Set(P,false);
01476 while( m_axis.ClosestPointTo(P,&t) )
01477 {
01478 abox.Set(arc.plane.origin,true);
01479
01480
01481
01482
01483 arc.plane.origin = m_axis.PointAt(t);
01484 arc.plane.xaxis = P-arc.plane.origin;
01485 arc.radius = arc.plane.xaxis.Length();
01486 if ( !arc.plane.xaxis.Unitize() )
01487 break;
01488 if ( fabs(arc.plane.xaxis*arc.plane.zaxis) > 0.0001 )
01489 break;
01490 arc.plane.yaxis = ON_CrossProduct(arc.plane.zaxis,arc.plane.xaxis);
01491 if ( !arc.plane.yaxis.Unitize() )
01492 break;
01493 arc.plane.UpdateEquation();
01494 arc.plane.Rotate( m_angle[0], arc.plane.zaxis );
01495 if ( !arc.IsValid() )
01496 break;
01497 abox = arc.BoundingBox();
01498 break;
01499 }
01500 bbox.Union(abox);
01501 }
01502
01503 if ( bbox.IsValid() )
01504 {
01505 ON_RevSurface* ptr = const_cast<ON_RevSurface*>(this);
01506 ptr->m_bbox = bbox;
01507 rc = true;
01508 }
01509 }
01510 }
01511
01512 if ( rc )
01513 {
01514 if ( boxmin )
01515 {
01516 if (bGrowBox){
01517 if (m_bbox.m_min.x < boxmin[0]) boxmin[0] = m_bbox.m_min.x;
01518 if (m_bbox.m_min.y < boxmin[1]) boxmin[1] = m_bbox.m_min.y;
01519 if (m_bbox.m_min.z < boxmin[2]) boxmin[2] = m_bbox.m_min.z;
01520 }
01521 else {
01522 boxmin[0] = m_bbox.m_min.x;
01523 boxmin[1] = m_bbox.m_min.y;
01524 boxmin[2] = m_bbox.m_min.z;
01525 }
01526 }
01527 if ( boxmax )
01528 {
01529 if (bGrowBox){
01530 if (m_bbox.m_max.x > boxmax[0]) boxmax[0] = m_bbox.m_max.x;
01531 if (m_bbox.m_max.y > boxmax[1]) boxmax[1] = m_bbox.m_max.y;
01532 if (m_bbox.m_max.z > boxmax[2]) boxmax[2] = m_bbox.m_max.z;
01533 }
01534 else {
01535 boxmax[0] = m_bbox.m_max.x;
01536 boxmax[1] = m_bbox.m_max.y;
01537 boxmax[2] = m_bbox.m_max.z;
01538 }
01539 }
01540 }
01541
01542 return rc;
01543 }
01544
01545 ON_BOOL32 ON_RevSurface::IsSpherical(ON_Sphere* sphere, double tolerance ) const
01546 {
01547 ON_BOOL32 rc = false;
01548 if ( m_curve )
01549 {
01550 ON_Plane plane;
01551 ON_Arc arc;
01552 ON_3dPoint P = m_curve->PointAt( m_curve->Domain().Mid() );
01553 plane.origin = m_axis.from;
01554 plane.yaxis = m_axis.Tangent();
01555 plane.zaxis = ON_CrossProduct( P-plane.origin, plane.yaxis );
01556 plane.zaxis.Unitize();
01557 plane.xaxis = ON_CrossProduct( plane.yaxis, plane.zaxis );
01558 plane.UpdateEquation();
01559 if ( plane.IsValid() )
01560 {
01561 if ( m_curve->IsArc( &plane, &arc, tolerance ) )
01562 {
01563 P = m_axis.ClosestPointTo( arc.Center() );
01564 if ( P.DistanceTo(arc.Center()) <= tolerance )
01565 {
01566 rc = true;
01567 if ( sphere )
01568 {
01569 sphere->plane.origin = arc.Center();
01570 sphere->plane.zaxis = m_axis.Tangent();
01571 sphere->plane.yaxis = arc.plane.zaxis;
01572 sphere->plane.xaxis = ON_CrossProduct( sphere->plane.zaxis, sphere->plane.yaxis );
01573 sphere->plane.UpdateEquation();
01574 sphere->radius = arc.radius;
01575 }
01576 }
01577 }
01578 }
01579 }
01580 return rc;
01581 }
01582
01583
01584 bool ON_Surface::IsSphere( ON_Sphere* sphere, double tolerance ) const
01585 {
01586 if ( !ON_IsValid(tolerance) || tolerance <= 0.0 )
01587 tolerance = ON_ZERO_TOLERANCE;
01588 const ON_RevSurface* rs = ON_RevSurface::Cast(this);
01589 if (rs)
01590 {
01591 return rs->IsSpherical(sphere,tolerance) ? true : false;
01592 }
01593
01594 ON_Curve* crv = IsoCurve(0,Domain(1).Mid());
01595 if ( !crv )
01596 return false;
01597
01598 ON_Arc arc0;
01599 int bIsArc0 = crv->IsArc(0,&arc0,tolerance > ON_ZERO_TOLERANCE ? tolerance : 0.0);
01600 delete crv;
01601 crv = 0;
01602 if ( !bIsArc0 )
01603 return false;
01604
01605 crv = IsoCurve(1,Domain(0).Mid());
01606 if ( !crv )
01607 return false;
01608 ON_Arc arc1;
01609 int bIsArc1 = crv->IsArc(0,&arc1,tolerance > ON_ZERO_TOLERANCE ? tolerance : 0.0);
01610 delete crv;
01611 crv = 0;
01612 if ( !bIsArc1 )
01613 return false;
01614
01615
01616
01617
01618 ON_Sphere sph0;
01619 sph0.plane = arc0.plane;
01620 sph0.radius = arc0.radius;
01621 bool bTestSphere0 = sph0.IsValid();
01622
01623 ON_Sphere sph1;
01624 sph1.plane = arc1.plane;
01625 sph1.radius = arc1.radius;
01626 bool bTestSphere1 = sph1.IsValid();
01627
01628 if ( !bTestSphere0 && !bTestSphere1 )
01629 return false;
01630
01631 double sph0tol = 0.0;
01632 double sph1tol = 0.0;
01633
01634 double tol = 0.5*ON_SQRT_EPSILON*(arc0.radius+arc1.radius);
01635
01636 ON_3dPoint P, S;
01637 double a, d;
01638 for ( a = 0.0; a < 1.0; a += 0.25 )
01639 {
01640 P = arc0.PointAt(a*2.0*ON_PI);
01641 if ( bTestSphere0 )
01642 {
01643 S = sph0.ClosestPointTo(P);
01644 d = S.DistanceTo(P);
01645 if ( d > tol )
01646 {
01647 bTestSphere0 = false;
01648 if ( !bTestSphere1 )
01649 return false;
01650 }
01651 else if ( d > sph0tol )
01652 sph0tol = d;
01653 }
01654 if ( bTestSphere1 )
01655 {
01656 S = sph1.ClosestPointTo(P);
01657 d = S.DistanceTo(P);
01658 if ( d > tol )
01659 {
01660 bTestSphere1 = false;
01661 if ( !bTestSphere0 )
01662 return false;
01663 }
01664 else if ( d > sph1tol )
01665 sph1tol = d;
01666 }
01667
01668 P = arc1.PointAt(a*2.0*ON_PI);
01669 if ( bTestSphere0 )
01670 {
01671 S = sph0.ClosestPointTo(P);
01672 d = S.DistanceTo(P);
01673 if ( d > tol )
01674 {
01675 bTestSphere0 = false;
01676 if ( !bTestSphere1 )
01677 return false;
01678 }
01679 else if ( d > sph0tol )
01680 sph0tol = d;
01681 }
01682 if ( bTestSphere1 )
01683 {
01684 S = sph1.ClosestPointTo(P);
01685 d = S.DistanceTo(P);
01686 if ( d > tol )
01687 {
01688 bTestSphere1 = false;
01689 if ( !bTestSphere0 )
01690 return false;
01691 }
01692 else if ( d > sph1tol )
01693 sph1tol = d;
01694 }
01695 }
01696
01697
01698
01699 if (!bTestSphere0 && !bTestSphere1)
01700 return false;
01701
01702 if ( tol < tolerance )
01703 tol = tolerance;
01704
01705 double u, v;
01706 int sc0 = SpanCount(0);
01707 int sc1 = SpanCount(1);
01708 double* s = (double*)onmalloc( (sc0+sc1+2)*sizeof(s[0]) );
01709 double* t = s + (sc0+1);
01710 GetSpanVector(0,s);
01711 GetSpanVector(1,t);
01712 for ( int i = 0; i < sc0; i++ )
01713 {
01714 for ( int ii = i?1:0; ii <= 4; ii++ )
01715 {
01716 u = 0.25*((4-ii)*s[i] + ii*s[i+1]);
01717 for ( int j = 0; j <= sc1; j++ )
01718 {
01719 for ( int jj = j?1:0; jj <= 4; jj++ )
01720 {
01721 v = 0.25*((4-jj)*t[j] + jj*t[j+1]);
01722 P = PointAt(u,v);
01723 if ( bTestSphere0 )
01724 {
01725 S = sph0.ClosestPointTo(P);
01726 d = S.DistanceTo(P);
01727 if ( d > tol )
01728 {
01729 bTestSphere0 = false;
01730 if ( !bTestSphere1 )
01731 {
01732 onfree(s);
01733 return false;
01734 }
01735 }
01736 else if ( d > sph0tol )
01737 sph0tol = d;
01738 }
01739 if ( bTestSphere1 )
01740 {
01741 S = sph1.ClosestPointTo(P);
01742 d = S.DistanceTo(P);
01743 if ( d > tol )
01744 {
01745 bTestSphere1 = false;
01746 if ( !bTestSphere0 )
01747 {
01748 onfree(s);
01749 return false;
01750 }
01751 }
01752 else if ( d > sph1tol )
01753 sph1tol = d;
01754 }
01755 }
01756 }
01757 }
01758 }
01759 onfree(s);
01760
01761 bool rc = (bTestSphere0 || bTestSphere1);
01762 if ( rc && sphere )
01763 {
01764 if (!bTestSphere0)
01765 *sphere = sph1;
01766 else if (!bTestSphere1)
01767 *sphere = sph0;
01768 else if (sph0tol <= sph1tol)
01769 *sphere = sph0;
01770 else
01771 *sphere = sph1;
01772 }
01773
01774 return rc;
01775 }
01776
01777 bool ON_Surface::IsCylinder( ON_Cylinder* cylinder, double tolerance ) const
01778 {
01779 if ( !ON_IsValid(tolerance) || tolerance <= 0.0 )
01780 tolerance = ON_ZERO_TOLERANCE;
01781 const ON_RevSurface* rs = ON_RevSurface::Cast(this);
01782 bool rc = rs && rs->IsCylindrical(cylinder,tolerance);
01783
01784 if ( !rc && !rs )
01785 {
01786 ON_Curve* crv = IsoCurve(0,Domain(1).Mid());
01787 if ( !crv )
01788 return false;
01789
01790 ON_Arc arc;
01791 ON_Line line;
01792 int bIsLine = 0;
01793 int bIsArc = crv->IsArc(0,&arc,tolerance > ON_ZERO_TOLERANCE ? tolerance : 0.0);
01794 if ( !bIsArc )
01795 {
01796 bIsLine = crv->IsLinear(tolerance > ON_ZERO_TOLERANCE ? tolerance : 0.0);
01797 if ( bIsLine )
01798 {
01799 line.from = crv->PointAtStart();
01800 line.to = crv->PointAtEnd();
01801 }
01802 }
01803 delete crv;
01804 crv = 0;
01805 if ( !bIsArc && !bIsLine )
01806 return false;
01807
01808 crv = IsoCurve(1,Domain(0).Mid());
01809 if ( !crv )
01810 return false;
01811 if ( !bIsArc )
01812 bIsArc = crv->IsArc(0,&arc,tolerance > ON_ZERO_TOLERANCE ? tolerance : 0.0);
01813 else if ( !bIsLine )
01814 {
01815 bIsLine = crv->IsLinear(tolerance > ON_ZERO_TOLERANCE ? tolerance : 0.0);
01816 if ( bIsLine )
01817 {
01818 line.from = crv->PointAtStart();
01819 line.to = crv->PointAtEnd();
01820 }
01821 }
01822 delete crv;
01823 crv = 0;
01824 if ( !bIsArc || !bIsLine )
01825 return false;
01826
01827 double tol = 0.5*ON_SQRT_EPSILON*(arc.radius);
01828 if ( tol < tolerance )
01829 tol = tolerance;
01830 double r = arc.plane.origin.DistanceTo(arc.plane.ClosestPointTo(line.from));
01831 if ( fabs(arc.radius - r) > tol )
01832 return false;
01833 r = arc.plane.origin.DistanceTo(arc.plane.ClosestPointTo(line.to));
01834 if ( fabs(arc.radius - r) > tol )
01835 return false;
01836
01837 ON_3dPoint P;
01838 double u, v;
01839 int sc0 = SpanCount(0);
01840 int sc1 = SpanCount(1);
01841 double* s = (double*)onmalloc( (sc0+sc1+2)*sizeof(s[0]) );
01842 double* t = s + (sc0+1);
01843 GetSpanVector(0,s);
01844 GetSpanVector(1,t);
01845 for ( int i = 0; i < sc0; i++ )
01846 {
01847 for ( int ii = i?1:0; ii <= 4; ii++ )
01848 {
01849 u = 0.25*((4-ii)*s[i] + ii*s[i+1]);
01850 for ( int j = 0; j < sc1; j++ )
01851 {
01852 for ( int jj = j?1:0; jj <= 4; jj++ )
01853 {
01854 v = 0.25*((4-jj)*t[j] + jj*t[j+1]);
01855 P = PointAt(u,v);
01856 r = arc.plane.origin.DistanceTo(arc.plane.ClosestPointTo(P));
01857 if ( fabs(arc.radius - r) > tol )
01858 {
01859 onfree(s);
01860 return false;
01861 }
01862 }
01863 }
01864 }
01865 }
01866 onfree(s);
01867
01868
01869 rc = true;
01870 if ( cylinder )
01871 {
01872 cylinder->Create(arc);
01873 rc = cylinder->IsValid();
01874 }
01875 }
01876
01877 return rc;
01878 }
01879
01880
01881 bool ON_Surface::IsCone( ON_Cone* cone, double tolerance ) const
01882 {
01883 if ( !ON_IsValid(tolerance) || tolerance <= 0.0 )
01884 tolerance = ON_ZERO_TOLERANCE;
01885
01886 const ON_RevSurface* rs = ON_RevSurface::Cast(this);
01887 if (rs)
01888 {
01889 return rs->IsConical(cone,tolerance) ? true : false;
01890 }
01891
01892
01893 ON_Curve* crv = IsoCurve(0,Domain(1).Mid());
01894 if ( !crv )
01895 return false;
01896
01897 ON_Arc arc;
01898 ON_Line line;
01899 int bIsLine = 0;
01900 int bIsArc = crv->IsArc(0,&arc,tolerance > ON_ZERO_TOLERANCE ? tolerance : 0.0);
01901 if ( !bIsArc )
01902 {
01903 bIsLine = crv->IsLinear(tolerance > ON_ZERO_TOLERANCE ? tolerance : 0.0);
01904 if ( bIsLine )
01905 {
01906 line.from = crv->PointAtStart();
01907 line.to = crv->PointAtEnd();
01908 }
01909 }
01910 delete crv;
01911 crv = 0;
01912 if ( !bIsArc && !bIsLine )
01913 return false;
01914
01915 crv = IsoCurve(1,Domain(0).Mid());
01916 if ( !crv )
01917 return false;
01918 if ( !bIsArc )
01919 bIsArc = crv->IsArc(0,&arc,tolerance > ON_ZERO_TOLERANCE ? tolerance : 0.0);
01920 else if ( !bIsLine )
01921 {
01922 bIsLine = crv->IsLinear(tolerance > ON_ZERO_TOLERANCE ? tolerance : 0.0);
01923 if ( bIsLine )
01924 {
01925 line.from = crv->PointAtStart();
01926 line.to = crv->PointAtEnd();
01927 }
01928 }
01929 delete crv;
01930 crv = 0;
01931 if ( !bIsArc || !bIsLine )
01932 return false;
01933
01934 double r0 = arc.plane.origin.DistanceTo(arc.plane.ClosestPointTo(line.from));
01935 double r1 = arc.plane.origin.DistanceTo(arc.plane.ClosestPointTo(line.to));
01936 if ( fabs(r0-r1) <= ON_ZERO_TOLERANCE )
01937 return false;
01938 double h0 = arc.plane.plane_equation.ValueAt(line.from);
01939 double h1 = arc.plane.plane_equation.ValueAt(line.to);
01940 if ( fabs(h0-h1) <= ON_ZERO_TOLERANCE )
01941 return false;
01942 double tol = 0.5*ON_SQRT_EPSILON*(r0+r1);
01943
01944 ON_Cone cn;
01945 cn.height = (h0*r1 - r0*h1)/(r1-r0);
01946 if ( !ON_IsValid(cn.height) || fabs(cn.height) <= ON_ZERO_TOLERANCE )
01947 return false;
01948 cn.plane = arc.plane;
01949 cn.plane.origin = cn.plane.origin + cn.height*cn.plane.zaxis;
01950 cn.plane.UpdateEquation();
01951 if ( r0 >= r1 )
01952 {
01953 cn.radius = r0;
01954 cn.height = h0-cn.height;
01955 }
01956 else
01957 {
01958 cn.radius = r1;
01959 cn.height = h1-cn.height;
01960 }
01961 if ( !cn.IsValid() )
01962 return false;
01963 tol *= fabs(cn.height);
01964
01965
01966 double h = cn.plane.plane_equation.ValueAt(line.from);
01967 if ( fabs(r0*cn.height - h*cn.radius) > tol )
01968 return false;
01969 h = cn.plane.plane_equation.ValueAt(line.to);
01970 if ( fabs(r1*cn.height - h*cn.radius) > tol )
01971 return false;
01972
01973 ON_3dPoint P;
01974 double u, v, r;
01975 int sc0 = SpanCount(0);
01976 int sc1 = SpanCount(1);
01977 double* s = (double*)onmalloc( (sc0+sc1+2)*sizeof(s[0]) );
01978 double* t = s + (sc0+1);
01979 GetSpanVector(0,s);
01980 GetSpanVector(1,t);
01981 tol = 0.5*ON_SQRT_EPSILON*(r0+r1);
01982 if ( tol < tolerance )
01983 tol = tolerance;
01984 tol *= fabs(cn.height);
01985 for ( int i = 0; i < sc0; i++ )
01986 {
01987 for ( int ii = i?1:0; ii <= 4; ii++ )
01988 {
01989 u = 0.25*((4-ii)*s[i] + ii*s[i+1]);
01990 for ( int j = 0; j < sc1; j++ )
01991 {
01992 for ( int jj = j?1:0; jj <= 4; jj++ )
01993 {
01994 v = 0.25*((4-jj)*t[j] + jj*t[j+1]);
01995 P = PointAt(u,v);
01996 h = cn.plane.plane_equation.ValueAt(P);
01997 r = cn.plane.origin.DistanceTo(cn.plane.ClosestPointTo(P));
01998
01999 if ( fabs(r*cn.height - h*cn.radius) > tol )
02000 {
02001 onfree(s);
02002 return false;
02003 }
02004 }
02005 }
02006 }
02007 }
02008 onfree(s);
02009
02010 if ( cone )
02011 {
02012 *cone = cn;
02013 }
02014
02015 return true;
02016 }
02017
02018
02019 bool ON_Surface::IsTorus( ON_Torus* torus, double tolerance ) const
02020 {
02021 if ( !ON_IsValid(tolerance) || tolerance <= 0.0 )
02022 tolerance = ON_ZERO_TOLERANCE;
02023
02024 ON_Curve* crv = IsoCurve(0,Domain(1).Mid());
02025 if ( !crv )
02026 return false;
02027
02028 ON_Arc arc0;
02029 int bIsArc0 = crv->IsArc(0,&arc0,tolerance > ON_ZERO_TOLERANCE ? tolerance : 0.0);
02030 delete crv;
02031 crv = 0;
02032 if ( !bIsArc0 )
02033 return false;
02034
02035 crv = IsoCurve(1,Domain(0).Mid());
02036 if ( !crv )
02037 return false;
02038 ON_Arc arc1;
02039 int bIsArc1 = crv->IsArc(0,&arc1,tolerance > ON_ZERO_TOLERANCE ? tolerance : 0.0);
02040 delete crv;
02041 crv = 0;
02042 if ( !bIsArc1 )
02043 return false;
02044
02045 double tol = 0.5*ON_SQRT_EPSILON*(arc0.radius+arc1.radius);
02046
02047 ON_Torus tr0;
02048 tr0.plane = arc0.plane;
02049 double h = tr0.plane.plane_equation.ValueAt(arc1.plane.origin);
02050 tr0.plane.origin = tr0.plane.origin + h*tr0.plane.zaxis;
02051 tr0.plane.UpdateEquation();
02052 tr0.major_radius = tr0.plane.origin.DistanceTo(arc1.plane.origin);
02053 tr0.minor_radius = arc1.radius;
02054
02055 ON_Torus tr1;
02056 tr1.plane = arc1.plane;
02057 h = tr1.plane.plane_equation.ValueAt(arc0.plane.origin);
02058 tr1.plane.origin = tr1.plane.origin + h*tr1.plane.zaxis;
02059 tr1.plane.UpdateEquation();
02060 tr1.major_radius = tr1.plane.origin.DistanceTo(arc0.plane.origin);
02061 tr1.minor_radius = arc0.radius;
02062
02063 bool bTestTorus0 = tr0.IsValid()?true:false;
02064 bool bTestTorus1 = tr1.IsValid()?true:false;
02065 if ( !bTestTorus0 && !bTestTorus1 )
02066 return false;
02067 double tr0tol = 0.0;
02068 double tr1tol = 0.0;
02069
02070 ON_3dPoint P, T;
02071 double a, d;
02072 for ( a = 0.0; a < 1.0; a += 0.25 )
02073 {
02074 P = arc0.PointAt(a*2.0*ON_PI);
02075 if ( bTestTorus0 )
02076 {
02077 T = tr0.ClosestPointTo(P);
02078 d = T.DistanceTo(P);
02079 if ( d > tol )
02080 {
02081 bTestTorus0 = false;
02082 if ( !bTestTorus1 )
02083 return false;
02084 }
02085 else if ( d > tr0tol )
02086 tr0tol = d;
02087 }
02088 if ( bTestTorus1 )
02089 {
02090 T = tr1.ClosestPointTo(P);
02091 d = T.DistanceTo(P);
02092 if ( d > tol )
02093 {
02094 bTestTorus1 = false;
02095 if ( !bTestTorus0 )
02096 return false;
02097 }
02098 else if ( d > tr1tol )
02099 tr1tol = d;
02100 }
02101
02102 P = arc1.PointAt(a*2.0*ON_PI);
02103 if ( bTestTorus0 )
02104 {
02105 T = tr0.ClosestPointTo(P);
02106 d = T.DistanceTo(P);
02107 if ( d > tol )
02108 {
02109 bTestTorus0 = false;
02110 if ( !bTestTorus1 )
02111 return false;
02112 }
02113 else if ( d > tr0tol )
02114 tr0tol = d;
02115 }
02116 if ( bTestTorus1 )
02117 {
02118 T = tr1.ClosestPointTo(P);
02119 d = T.DistanceTo(P);
02120 if ( d > tol )
02121 {
02122 bTestTorus1 = false;
02123 if ( !bTestTorus0 )
02124 return false;
02125 }
02126 else if ( d > tr1tol )
02127 tr1tol = d;
02128 }
02129 }
02130
02131
02132
02133 if (!bTestTorus0 && !bTestTorus1)
02134 return false;
02135
02136 if ( tol < tolerance )
02137 tol = tolerance;
02138
02139 double u, v;
02140 int sc0 = SpanCount(0);
02141 int sc1 = SpanCount(1);
02142 double* s = (double*)onmalloc( (sc0+sc1+2)*sizeof(s[0]) );
02143 double* t = s + (sc0+1);
02144 GetSpanVector(0,s);
02145 GetSpanVector(1,t);
02146 for ( int i = 0; i < sc0; i++ )
02147 {
02148 for ( int ii = i?1:0; ii <= 4; ii++ )
02149 {
02150 u = 0.25*((4-ii)*s[i] + ii*s[i+1]);
02151 for ( int j = 0; j < sc1; j++ )
02152 {
02153 for ( int jj = j?1:0; jj <= 4; jj++ )
02154 {
02155 v = 0.25*((4-jj)*t[j] + jj*t[j+1]);
02156 P = PointAt(u,v);
02157 if ( bTestTorus0 )
02158 {
02159 T = tr0.ClosestPointTo(P);
02160 d = T.DistanceTo(P);
02161 if ( d > tol )
02162 {
02163 bTestTorus0 = false;
02164 if ( !bTestTorus1 )
02165 {
02166 onfree(s);
02167 return false;
02168 }
02169 }
02170 else if ( d > tr0tol )
02171 tr0tol = d;
02172 }
02173 if ( bTestTorus1 )
02174 {
02175 T = tr1.ClosestPointTo(P);
02176 d = T.DistanceTo(P);
02177 if ( d > tol )
02178 {
02179 bTestTorus1 = false;
02180 if ( !bTestTorus0 )
02181 {
02182 onfree(s);
02183 return false;
02184 }
02185 }
02186 else if ( d > tr1tol )
02187 tr1tol = d;
02188 }
02189 }
02190 }
02191 }
02192 }
02193 onfree(s);
02194
02195 bool rc = (bTestTorus0 || bTestTorus1);
02196 if ( rc && torus )
02197 {
02198 if (!bTestTorus0)
02199 *torus = tr1;
02200 else if (!bTestTorus1)
02201 *torus = tr0;
02202 else if (tr0tol <= tr1tol)
02203 *torus = tr0;
02204 else
02205 *torus = tr1;
02206 }
02207
02208 return rc;
02209 }
02210
02211 static
02212 bool ON__IsCylConeHelper(
02213 const ON_Line& axis,
02214 const ON_Curve* curve,
02215 double tolerance,
02216 ON_Plane& plane,
02217 ON_Line& line,
02218 double r[2],
02219 double& h
02220 )
02221 {
02222 if ( !axis.IsValid() )
02223 return false;
02224 if ( !curve )
02225 return false;
02226 line.from = curve->PointAtStart();
02227 line.to = curve->PointAtEnd();
02228 if ( !line.IsValid() )
02229 return false;
02230 if ( line.Length() <= ON_ZERO_TOLERANCE )
02231 return false;
02232
02233 plane.zaxis = axis.Tangent();
02234 h = plane.zaxis*line.Direction();
02235 if ( !ON_IsValid(h) )
02236 return false;
02237 if ( h < 0.0 )
02238 {
02239 plane.zaxis.Reverse();
02240 h = -h;
02241 }
02242 if ( h <= ON_ZERO_TOLERANCE )
02243 return false;
02244
02245 double a0 = ON_UNSET_VALUE;
02246 if ( !axis.ClosestPointTo(line.from,&a0) )
02247 return false;
02248 double a1 = ON_UNSET_VALUE;
02249 if ( !axis.ClosestPointTo(line.to,&a1) )
02250 return false;
02251 if ( !ON_IsValid(a0) || !ON_IsValid(a1) )
02252 return false;
02253
02254
02255 ON_3dPoint A0 = axis.PointAt(a0);
02256 ON_3dPoint A1 = axis.PointAt(a1);
02257 plane.origin = A0;
02258 ON_3dVector x0 = line.from - A0;
02259 ON_3dVector x1 = line.to - A1;
02260 r[0] = x0.Length();
02261 r[1] = x1.Length();
02262 if ( x0*x0 < 0.0 && r[0] > ON_ZERO_TOLERANCE && r[1] > ON_ZERO_TOLERANCE )
02263 return false;
02264 plane.xaxis = ( r[0] >= r[1] ) ? x0 : x1;
02265 if (fabs(plane.xaxis.Length()) <= ON_ZERO_TOLERANCE)
02266 return false;
02267 if ( !plane.xaxis.Unitize() )
02268 return false;
02269 plane.yaxis = ON_CrossProduct(plane.zaxis,plane.xaxis);
02270 if ( !plane.yaxis.Unitize() )
02271 return false;
02272 plane.UpdateEquation();
02273 if ( !plane.IsValid() )
02274 return false;
02275
02276 x0 = line.Tangent();
02277 if ( fabs(x0*plane.yaxis) > ON_ZERO_TOLERANCE )
02278 return false;
02279
02280 return (curve->IsLinear( tolerance )?true:false);
02281 }
02282
02283 ON_BOOL32 ON_RevSurface::IsCylindrical(
02284 ON_Cylinder* cylinder,
02285 double tolerance
02286 ) const
02287 {
02288 ON_Cylinder c;
02289 ON_Line line;
02290 double r[2] = {0.0,0.0};
02291 double h = 0.0;
02292 if ( !ON_IsValid(tolerance) || tolerance <= 0.0 )
02293 tolerance = ON_ZERO_TOLERANCE;
02294 if ( !ON__IsCylConeHelper(m_axis,m_curve,tolerance,c.circle.plane,line,r,h) )
02295 return false;
02296 if ( fabs(r[0]-r[1]) > tolerance )
02297 return false;
02298 if ( fabs(line.Tangent()*c.circle.plane.xaxis) > ON_ZERO_TOLERANCE )
02299 return false;
02300 c.circle.radius = (r[0]==r[1]) ? r[0] : (0.5*(r[0]+r[1]));
02301 c.height[0] = 0.0;
02302 c.height[1] = h;
02303 if ( cylinder )
02304 *cylinder = c;
02305 return c.IsValid();
02306 }
02307
02308 ON_BOOL32 ON_RevSurface::IsConical(
02309 ON_Cone* cone,
02310 double tolerance
02311 ) const
02312 {
02313 ON_Cone c;
02314 ON_Line line;
02315 double r[2] = {0.0,0.0};
02316 double h = 0.0;
02317 if ( !ON_IsValid(tolerance) || tolerance <= 0.0 )
02318 tolerance = ON_ZERO_TOLERANCE;
02319 if ( !ON__IsCylConeHelper(m_axis,m_curve,tolerance,c.plane,line,r,h) )
02320 return false;
02321 double dr = r[0]-r[1];
02322 if ( fabs(dr) <= ON_ZERO_TOLERANCE )
02323 return false;
02324 if ( 0.0 == r[0] )
02325 {
02326 c.radius = r[1];
02327 c.height = h;
02328 }
02329 else if ( 0.0 == r[1] )
02330 {
02331 c.plane.origin += h*c.plane.zaxis;
02332 c.plane.UpdateEquation();
02333 c.radius = r[0];
02334 c.height = -h;
02335 }
02336 else if ( dr > 0.0 )
02337 {
02338 h *= (r[0]/dr);
02339 c.plane.origin += h*c.plane.zaxis;
02340 c.plane.UpdateEquation();
02341 c.radius = r[0];
02342 c.height = -h;
02343 }
02344 else
02345 {
02346 double d = h*r[0]/dr;
02347 c.plane.origin += d*c.plane.zaxis;
02348 c.plane.UpdateEquation();
02349 c.radius = r[1];
02350 c.height = h-d;
02351 }
02352
02353 if ( cone )
02354 *cone = c;
02355 return c.IsValid();
02356 }
02357