00001 #include "pcl/surface/3rdparty/opennurbs/opennurbs.h"
00002
00003 static bool ON_ExtrusionPolyCurveProfileIsNotValid()
00004 {
00005 return false;
00006 }
00007
00008 bool ON_Extrusion::IsValidPolyCurveProfile( const ON_PolyCurve& polycurve, ON_TextLog* text_log )
00009 {
00010 const bool bAllowGaps = true;
00011 bool rc = polycurve.IsValid(bAllowGaps,text_log) ? true : ON_ExtrusionPolyCurveProfileIsNotValid();
00012 if (!rc)
00013 return ON_ExtrusionPolyCurveProfileIsNotValid();
00014
00015 const int profile_count = polycurve.Count();
00016
00017 if ( profile_count < 1 )
00018 {
00019 if ( text_log )
00020 {
00021 text_log->Print("polycurve has < 1 segments.\n");
00022 }
00023 return ON_ExtrusionPolyCurveProfileIsNotValid();
00024 }
00025
00026 if ( 2 != polycurve.Dimension() )
00027 {
00028 if ( 3 != polycurve.Dimension() )
00029 {
00030 if ( text_log )
00031 {
00032 text_log->Print("polycurve dimension = %d (should be 2).\n",polycurve.Dimension());
00033 }
00034 return ON_ExtrusionPolyCurveProfileIsNotValid();
00035 }
00036 ON_BoundingBox bbox = polycurve.BoundingBox();
00037 if ( !bbox.IsValid() )
00038 {
00039 if ( text_log )
00040 {
00041 text_log->Print("polycurve.BoundingBox() is not valid.\n");
00042 }
00043 return ON_ExtrusionPolyCurveProfileIsNotValid();
00044 }
00045 if ( !( 0.0 == bbox.m_min.z) || !(0.0 == bbox.m_max.z) )
00046 {
00047 if ( text_log )
00048 {
00049 text_log->Print("polycurve.BoundingBox() z values are not both 0.0.\n");
00050 }
00051 return ON_ExtrusionPolyCurveProfileIsNotValid();
00052 }
00053 }
00054
00055 if ( 1 == profile_count )
00056 return true;
00057
00058 if ( profile_count > 1 )
00059 {
00060 for ( int i = 0; i < profile_count; i++ )
00061 {
00062 const ON_Curve* segment = polycurve.SegmentCurve(i);
00063 if ( 0 == segment )
00064 {
00065 if ( text_log )
00066 {
00067 text_log->Print("polycurve.SegmentCurve(%d) is null.\n",i);
00068 }
00069 return ON_ExtrusionPolyCurveProfileIsNotValid();
00070 }
00071 if ( !segment->IsClosed() )
00072 {
00073 if ( text_log )
00074 {
00075 text_log->Print("polycurve.SegmentCurve(%d) is not closed.\n",i);
00076 }
00077 return ON_ExtrusionPolyCurveProfileIsNotValid();
00078 }
00079 if ( segment->Domain() != polycurve.SegmentDomain(i) )
00080 {
00081 if ( text_log )
00082 {
00083 text_log->Print("polycurve.Segment(%d).Domain() does not match polycurve.SegmentDomain(%d).\n",i,i);
00084 }
00085 return ON_ExtrusionPolyCurveProfileIsNotValid();
00086 }
00087 }
00088 }
00089 return true;
00090 }
00091
00092 bool ON_Extrusion::CleanupPolyCurveProfile( ON_PolyCurve& polycurve )
00093 {
00094 if ( !ON_Extrusion::IsValidPolyCurveProfile(polycurve) )
00095 {
00096
00097 int i;
00098 const int old_count = polycurve.Count();
00099 if ( old_count <= 1 )
00100 return false;
00101
00102
00103 for ( i = 0; i < old_count; i++ )
00104 {
00105 ON_Curve* old_segment = polycurve.SegmentCurve(i);
00106 if ( 0 == old_segment )
00107 return false;
00108 if ( 2 != old_segment->Dimension() && !old_segment->ChangeDimension(2) )
00109 return false;
00110 }
00111
00112
00113 polycurve.SynchronizeSegmentDomains();
00114
00115
00116 ON_SimpleArray<ON_PolyCurve*> new_polycurves(old_count);
00117 ON_SimpleArray<ON_Curve*> new_segments(old_count);
00118 ON_PolyCurve* new_segment = 0;
00119 bool rc = true;
00120 for ( i = 0; i < old_count && rc; i++ )
00121 {
00122 ON_Curve* old_segment = polycurve.SegmentCurve(i);
00123 if ( old_segment->IsClosed() )
00124 {
00125 if ( 0 != new_segment )
00126 {
00127 rc = false;
00128 break;
00129 }
00130 new_segments.Append(old_segment);
00131 }
00132 else if ( 0 == new_segment )
00133 {
00134 new_segment = new ON_PolyCurve();
00135 new_polycurves.Append(new_segment);
00136 new_segment->Append(old_segment);
00137 }
00138 else
00139 {
00140 new_segment->Append(old_segment);
00141 if ( new_segment->FindNextGap(0) )
00142 {
00143 rc = false;
00144 break;
00145 }
00146 if ( new_segment->IsClosed() )
00147 {
00148 new_segments.Append(new_segment);
00149 new_segment = 0;
00150 }
00151 }
00152 }
00153
00154 if ( 0 != new_segment )
00155 {
00156 rc = false;
00157 }
00158
00159 if ( !rc )
00160 {
00161
00162 for ( i = 0; i < new_polycurves.Count(); i++ )
00163 {
00164 new_segment = new_polycurves[i];
00165 if ( new_segment )
00166 {
00167 for ( int j = new_segment->Count()-1; j >= 0; j-- )
00168 {
00169 new_segment->HarvestSegment(j);
00170 }
00171 delete new_segment;
00172 }
00173 }
00174 return false;
00175 }
00176
00177 for ( i = 0; i < new_polycurves.Count(); i++ )
00178 {
00179 new_polycurves[i]->RemoveNesting();
00180 }
00181
00182 for ( i = old_count-1; i >= 0; i-- )
00183 {
00184 polycurve.HarvestSegment(i);
00185 polycurve.Remove(i);
00186 }
00187 for ( i = 0; i < new_segments.Count(); i++ )
00188 {
00189 polycurve.Append(new_segments[i]);
00190 }
00191 }
00192 else
00193 {
00194 polycurve.ChangeDimension(2);
00195 }
00196 return true;
00197 }
00198
00199
00200 bool ON_GetEndCapTransformation(ON_3dPoint P, ON_3dVector T, ON_3dVector U,
00201 const ON_3dVector* Normal,
00202 ON_Xform& xform,
00203 ON_Xform* scale2d,
00204 ON_Xform* rot3d
00205 )
00206 {
00207 if ( scale2d )
00208 scale2d->Identity();
00209 if ( rot3d )
00210 rot3d->Identity();
00211 if ( !T.IsUnitVector() && !T.Unitize() )
00212 return false;
00213 if ( !U.IsUnitVector() && !U.Unitize() )
00214 return false;
00215 ON_3dVector N(0.0,0.0,0.0);
00216 if ( Normal )
00217 {
00218 N = *Normal;
00219 if ( !N.IsUnitVector() && !N.Unitize() )
00220 N.Zero();
00221 }
00222
00223 ON_Plane p0;
00224 p0.origin = P;
00225 p0.zaxis = T;
00226 p0.yaxis = U;
00227 p0.xaxis = ON_CrossProduct(U,T);
00228 if ( !p0.xaxis.IsUnitVector() )
00229 p0.xaxis.Unitize();
00230 p0.UpdateEquation();
00231 xform.Rotation(ON_xy_plane,p0);
00232 if ( rot3d )
00233 *rot3d = xform;
00234 if ( N.z > ON_Extrusion::m_Nz_min && N.IsUnitVector() )
00235 {
00236
00237 double cosa = N.z;
00238 for(;;)
00239 {
00240 ON_3dVector A(-N.y,N.x,0.0);
00241 if ( !A.IsValid() )
00242 break;
00243 double sina = A.Length();
00244 if ( !ON_IsValid(sina) )
00245 break;
00246 if ( !A.Unitize() )
00247 break;
00248
00249
00250
00251
00252
00253 ON_Xform S(0.0);
00254 const double c = 1.0 - 1.0/cosa;
00255 S.m_xform[0][0] = 1.0 - c*A.y*A.y;
00256 S.m_xform[0][1] = c*A.x*A.y;
00257
00258 S.m_xform[1][0] = S.m_xform[0][1];
00259 S.m_xform[1][1] = 1.0 - c*A.x*A.x;
00260
00261 S.m_xform[2][2] = 1.0;
00262
00263 S.m_xform[3][3] = 1.0;
00264 if (scale2d)
00265 *scale2d = S;
00266
00267
00268 ON_Xform R;
00269 R.Rotation(sina,cosa,A,ON_origin);
00270 if ( rot3d )
00271 *rot3d = xform*R;
00272
00273 xform = xform*R*S;
00274 break;
00275 }
00276 }
00277 return true;
00278 }
00279
00280 static void ON_ExtrusionInitializeHelper(ON_Extrusion& extrusion)
00281 {
00282 extrusion.m_path.from.Zero();
00283 extrusion.m_path.to.Zero();
00284 extrusion.m_t.m_t[0] = 0.0;
00285 extrusion.m_t.m_t[1] = 1.0;
00286 extrusion.m_up.Zero();
00287 extrusion.m_profile_count = 0;
00288 extrusion.m_profile = 0;
00289 extrusion.m_bCap[0] = false;
00290 extrusion.m_bCap[1] = false;
00291 extrusion.m_bHaveN[0] = false;
00292 extrusion.m_bHaveN[1] = false;
00293 extrusion.m_N[0].Zero();
00294 extrusion.m_N[1].Zero();
00295 extrusion.m_path_domain.m_t[0] = 0.0;
00296 extrusion.m_path_domain.m_t[1] = 1.0;
00297 extrusion.m_bTransposed = false;
00298 }
00299
00300 static void ON_ExtrusionCopyHelper(const ON_Extrusion& src,ON_Extrusion& dst)
00301 {
00302 if ( &src != &dst )
00303 {
00304 if ( dst.m_profile )
00305 {
00306 delete dst.m_profile;
00307 dst.m_profile = 0;
00308 }
00309 dst.m_path = src.m_path;
00310 dst.m_t = src.m_t;
00311 dst.m_up = src.m_up;
00312 dst.m_profile_count = src.m_profile_count;
00313 dst.m_profile = src.m_profile
00314 ? src.m_profile->DuplicateCurve()
00315 : 0;
00316 dst.m_bCap[0] = src.m_bCap[0];
00317 dst.m_bCap[1] = src.m_bCap[1];
00318 dst.m_bHaveN[0] = src.m_bHaveN[0];
00319 dst.m_bHaveN[1] = src.m_bHaveN[1];
00320 dst.m_N[0] = src.m_N[0];
00321 dst.m_N[1] = src.m_N[1];
00322 dst.m_path_domain = src.m_path_domain;
00323 dst.m_bTransposed = src.m_bTransposed;
00324 }
00325 }
00326
00327 bool ON_Extrusion::SetPath(ON_3dPoint A, ON_3dPoint B)
00328 {
00329 double distAB = 0.0;
00330 bool rc = A.IsValid() && B.IsValid()
00331 && (distAB = A.DistanceTo(B)) > ON_ZERO_TOLERANCE;
00332 if (rc)
00333 {
00334 m_path.from = A;
00335 m_path.to = B;
00336 m_t.Set(0.0,1.0);
00337 m_path_domain.Set(0.0,distAB);
00338 }
00339 return rc;
00340 }
00341
00342 bool ON_Extrusion::SetPathAndUp( ON_3dPoint A, ON_3dPoint B, ON_3dVector up )
00343 {
00344 double distAB = 0.0;
00345
00346 bool rc = up.IsValid()
00347 && up.Length() > ON_ZERO_TOLERANCE
00348 && A.IsValid()
00349 && B.IsValid()
00350 && (distAB = A.DistanceTo(B)) > ON_ZERO_TOLERANCE;
00351
00352 if (rc)
00353 {
00354 ON_3dVector D = A-B;
00355 D.Unitize();
00356 double d = up*D;
00357 if ( !up.IsUnitVector() || fabs(d) > distAB*ON_SQRT_EPSILON*0.015625 )
00358 {
00359
00360
00361 D.Unitize();
00362 up = up - d*D;
00363 up.Unitize();
00364
00365 d = up*D;
00366 rc = ( up.IsUnitVector() && fabs(d) <= ON_SQRT_EPSILON );
00367 }
00368
00369 if (rc)
00370 {
00371 m_path.from = A;
00372 m_path.to = B;
00373 m_t.Set(0.0,1.0);
00374 m_path_domain.Set(0.0,distAB);
00375 m_up = up;
00376 }
00377 }
00378
00379 return rc;
00380 }
00381
00382 int ON_Extrusion::PathParameter() const
00383 {
00384 return m_bTransposed ? 0 : 1;
00385 }
00386
00387 int ON_Extrusion::ProfileParameter() const
00388 {
00389 return m_bTransposed ? 1 : 0;
00390 }
00391
00392 ON_3dPoint ON_Extrusion::PathStart() const
00393 {
00394 ON_3dPoint P(ON_UNSET_POINT);
00395 const double t = m_t.m_t[0];
00396 if ( 0.0 <= t && t <= 1.0 && m_path.IsValid() )
00397 P = m_path.PointAt(t);
00398 return P;
00399 }
00400
00401 ON_3dPoint ON_Extrusion::PathEnd() const
00402 {
00403 ON_3dPoint P(ON_UNSET_POINT);
00404 const double t = m_t.m_t[1];
00405 if ( 0.0 <= t && t <= 1.0 && m_path.IsValid() )
00406 P = m_path.PointAt(t);
00407 return P;
00408 }
00409
00410 ON_3dVector ON_Extrusion::PathTangent() const
00411 {
00412 ON_3dVector T(ON_UNSET_VECTOR);
00413 if ( m_path.IsValid() )
00414 T = m_path.Tangent();
00415 return T;
00416 }
00417
00418 void ON_Extrusion::Destroy()
00419 {
00420 if ( m_profile)
00421 {
00422 delete m_profile;
00423 m_profile = 0;
00424 }
00425 ON_ExtrusionInitializeHelper(*this);
00426 DestroyRuntimeCache();
00427 PurgeUserData();
00428 }
00429
00430 bool ON_Extrusion::SetMiterPlaneNormal(ON_3dVector N, int end)
00431 {
00432 bool rc = false;
00433 if ( end >= 0 && end <= 1 )
00434 {
00435 if ( N.IsValid()
00436 && N.z > ON_Extrusion::m_Nz_min
00437 && (N.IsUnitVector() || N.Unitize())
00438 )
00439 {
00440 if (fabs(N.x) <= ON_SQRT_EPSILON && fabs(N.y) <= ON_SQRT_EPSILON)
00441 N.Set(0.0,0.0,1.0);
00442 m_N[end] = N;
00443 m_bHaveN[end] = (N.z != 1.0);
00444 rc = true;
00445 }
00446 else if ( N.IsZero() || ON_UNSET_VECTOR == N )
00447 {
00448 m_bHaveN[end] = false;
00449 rc = true;
00450 }
00451 }
00452 return rc;
00453 }
00454
00455 void ON_Extrusion::GetMiterPlaneNormal(int end, ON_3dVector& N) const
00456 {
00457 if ( end >= 0 && end <= 1 && m_bHaveN[end] )
00458 N = m_N[end];
00459 else
00460 N.Set(0.0,0.0,1.0);
00461 }
00462
00463 int ON_Extrusion::IsMitered() const
00464 {
00465 int rc = 0;
00466 if ( m_bHaveN[0] && m_N[0].IsUnitVector() && m_N[0].z > m_Nz_min && (m_N[0].x != 0.0 || m_N[0].y != 0.0) )
00467 rc += 1;
00468 if ( m_bHaveN[1] && m_N[1].IsUnitVector() && m_N[1].z > m_Nz_min && (m_N[1].x != 0.0 || m_N[1].y != 0.0) )
00469 rc += 2;
00470 return rc;
00471 }
00472
00473 int ON_Extrusion::CapCount() const
00474 {
00475
00476 switch (IsCapped())
00477 {
00478 case 1:
00479 case 2:
00480 return 1;
00481 case 3:
00482 return 2;
00483 }
00484 return 0;
00485 }
00486
00487 int ON_Extrusion::IsCapped() const
00488 {
00489
00490
00491 if ( !m_bCap[0] && !m_bCap[1] )
00492 return 0;
00493
00494 if ( m_profile_count < 1 || 0 == m_profile )
00495 return 0;
00496
00497 if ( 1 == m_profile_count )
00498 {
00499 if ( !m_profile->IsClosed() )
00500 return 0;
00501 }
00502 else if ( m_profile_count > 1 )
00503 {
00504 const ON_PolyCurve* p = ON_PolyCurve::Cast(m_profile);
00505 if ( 0 == p )
00506 return 0;
00507 const ON_Curve* outer_profile = p->SegmentCurve(0);
00508 if ( 0 == outer_profile )
00509 return 0;
00510 if ( !outer_profile->IsClosed() )
00511 return 0;
00512 }
00513
00514 return (m_bCap[0] ? (m_bCap[1] ? 3 : 1) : 2);
00515 }
00516
00517 int ON_Extrusion::FaceCount() const
00518 {
00519 int face_count = 0;
00520 const ON_Curve* profile0 = Profile(0);
00521
00522 if ( m_profile_count > 0 && 0 != profile0 )
00523 {
00524 int is_capped = IsCapped();
00525 if ( is_capped != 0 && !profile0->IsClosed() )
00526 {
00527 is_capped = 0;
00528 }
00529
00530 switch(is_capped)
00531 {
00532 case 1:
00533 case 2:
00534 face_count = m_profile_count + 1;
00535 break;
00536
00537 case 3:
00538 face_count = m_profile_count + 2;
00539 break;
00540
00541 default:
00542 face_count = 1;
00543 break;
00544 }
00545 }
00546
00547 return face_count;
00548 }
00549
00550
00551 bool ON_Extrusion::IsSolid() const
00552 {
00553 if ( !m_bCap[0] || !m_bCap[1] )
00554 return false;
00555 return 3 == IsCapped();
00556 }
00557
00558 bool ON_Extrusion::GetPathPlane( double s, ON_Plane& plane ) const
00559 {
00560 ON_Plane p;
00561 p.origin = ON_3dPoint::Origin;
00562 p.zaxis = PathTangent();
00563 p.yaxis = m_up;
00564 p.xaxis = ON_CrossProduct(p.yaxis,p.zaxis);
00565 if ( !p.xaxis.Unitize() )
00566 return false;
00567 if ( !p.yaxis.Unitize() )
00568 return false;
00569 p.UpdateEquation();
00570 if ( !p.IsValid() )
00571 {
00572 p.yaxis = ON_CrossProduct(p.zaxis,p.xaxis);
00573 p.yaxis.Unitize();
00574 if ( !p.IsValid() )
00575 return false;
00576 }
00577 p.origin = m_path.PointAt(m_t.ParameterAt(s));
00578 p.UpdateEquation();
00579 plane = p;
00580 return plane.IsValid();
00581 }
00582
00583 bool ON_Extrusion::GetProfilePlane( double s, ON_Plane& plane ) const
00584 {
00585 ON_Plane p;
00586 p.origin = ON_3dPoint::Origin;
00587 p.zaxis = PathTangent();
00588 p.yaxis = m_up;
00589 p.xaxis = ON_CrossProduct(p.yaxis,p.zaxis);
00590 if ( !p.xaxis.Unitize() )
00591 return false;
00592 if ( !p.yaxis.Unitize() )
00593 return false;
00594 p.UpdateEquation();
00595 if ( !p.IsValid() )
00596 {
00597 p.yaxis = ON_CrossProduct(p.zaxis,p.xaxis);
00598 p.yaxis.Unitize();
00599 if ( !p.IsValid() )
00600 return false;
00601 }
00602 if ( (!m_bHaveN[0] || (0.0 == m_N[0].x && 0.0 == m_N[0].y))
00603 && (!m_bHaveN[1] || (0.0 == m_N[1].x && 0.0 == m_N[1].y))
00604 )
00605 {
00606 p.origin = m_path.PointAt(m_t.ParameterAt(s));
00607 p.UpdateEquation();
00608 plane = p;
00609 }
00610 else
00611 {
00612 ON_Xform xform;
00613 if ( !GetProfileTransformation(s,xform) )
00614 return false;
00615 if (!p.Transform(xform))
00616 return false;
00617 plane = p;
00618 }
00619 return plane.IsValid();
00620 }
00621
00622
00623 bool ON_Extrusion::GetProfileTransformation( double s, ON_Xform& xform ) const
00624 {
00625
00626 const ON_3dVector T = m_path.Tangent();
00627 if ( 0.0 == s )
00628 {
00629 return ON_GetEndCapTransformation(m_path.PointAt(m_t.m_t[0]),T,m_up,m_bHaveN[0]?&m_N[0]:0,xform,0,0);
00630 }
00631 if ( 1.0 == s )
00632 {
00633 return ON_GetEndCapTransformation(m_path.PointAt(m_t.m_t[1]),T,m_up,m_bHaveN[1]?&m_N[1]:0,xform,0,0);
00634 }
00635 ON_Xform xform0, xform1;
00636 if ( !ON_GetEndCapTransformation(m_path.PointAt(m_t.m_t[0]),T,m_up,m_bHaveN[0]?&m_N[0]:0,xform0,0,0) )
00637 return false;
00638 if ( !ON_GetEndCapTransformation(m_path.PointAt(m_t.m_t[1]),T,m_up,m_bHaveN[1]?&m_N[1]:0,xform1,0,0) )
00639 return false;
00640
00641 const double s0 = 1.0-s;
00642 xform.m_xform[0][0] = s0*xform0.m_xform[0][0] + s*xform1.m_xform[0][0];
00643 xform.m_xform[0][1] = s0*xform0.m_xform[0][1] + s*xform1.m_xform[0][1];
00644 xform.m_xform[0][2] = s0*xform0.m_xform[0][2] + s*xform1.m_xform[0][2];
00645 xform.m_xform[0][3] = s0*xform0.m_xform[0][3] + s*xform1.m_xform[0][3];
00646 xform.m_xform[1][0] = s0*xform0.m_xform[1][0] + s*xform1.m_xform[1][0];
00647 xform.m_xform[1][1] = s0*xform0.m_xform[1][1] + s*xform1.m_xform[1][1];
00648 xform.m_xform[1][2] = s0*xform0.m_xform[1][2] + s*xform1.m_xform[1][2];
00649 xform.m_xform[1][3] = s0*xform0.m_xform[1][3] + s*xform1.m_xform[1][3];
00650 xform.m_xform[2][0] = s0*xform0.m_xform[2][0] + s*xform1.m_xform[2][0];
00651 xform.m_xform[2][1] = s0*xform0.m_xform[2][1] + s*xform1.m_xform[2][1];
00652 xform.m_xform[2][2] = s0*xform0.m_xform[2][2] + s*xform1.m_xform[2][2];
00653 xform.m_xform[2][3] = s0*xform0.m_xform[2][3] + s*xform1.m_xform[2][3];
00654 xform.m_xform[3][0] = s0*xform0.m_xform[3][0] + s*xform1.m_xform[3][0];
00655 xform.m_xform[3][1] = s0*xform0.m_xform[3][1] + s*xform1.m_xform[3][1];
00656 xform.m_xform[3][2] = s0*xform0.m_xform[3][2] + s*xform1.m_xform[3][2];
00657 xform.m_xform[3][3] = s0*xform0.m_xform[3][3] + s*xform1.m_xform[3][3];
00658
00659 return true;
00660 }
00661
00662 static bool CleanProfileSegment( ON_Curve* curve )
00663 {
00664 ON_NurbsCurve* nurbs_curve = ON_NurbsCurve::Cast(curve);
00665 if ( nurbs_curve )
00666 {
00667 nurbs_curve->RemoveSingularSpans();
00668 return ( nurbs_curve->IsValid() && false == nurbs_curve->SpanIsSingular(0) );
00669 }
00670
00671 return true;
00672 }
00673
00674 static bool ProfileHelper( int desired_orientation, ON_Curve* profile )
00675 {
00676
00677
00678
00679
00680 if ( 0 == profile )
00681 {
00682 ON_ERROR("ON_Extrusion::Set/Add Profile - null input curve pointer.");
00683 return false;
00684 }
00685 ON_BoundingBox bbox = profile->BoundingBox();
00686 if ( !bbox.IsValid() )
00687 {
00688 ON_ERROR("ON_Extrusion::Set/Add Profile - profile->BoundingBox() failed.");
00689 return false;
00690 }
00691 if ( fabs(bbox.m_min.z) > ON_ZERO_TOLERANCE || fabs(bbox.m_max.z) > ON_ZERO_TOLERANCE )
00692 {
00693 ON_ERROR("ON_Extrusion::Set/Add Profile - profile->BoundingBox() is not in the world xy plane.");
00694 return false;
00695 }
00696 if ( !profile->ChangeDimension(2) )
00697 {
00698 ON_ERROR("ON_Extrusion::Set/Add Profile - profile->ChangeDimension(2) failed.");
00699 return false;
00700 }
00701
00702 if ( profile->IsClosed() )
00703 {
00704 int profile_orientation = ON_ClosedCurveOrientation(*profile,0);
00705 switch(desired_orientation)
00706 {
00707 case 1:
00708 case 0:
00709 if ( -1 == profile_orientation )
00710 {
00711 if ( !profile->Reverse() )
00712 {
00713 ON_ERROR("ON_Extrusion::SetOuterProfile() - profile->Reverse() failed.");
00714 return false;
00715 }
00716 profile_orientation = 1;
00717 }
00718 if ( 1 == desired_orientation && 1 != profile_orientation )
00719 {
00720 ON_ERROR("ON_Extrusion::SetOuterProfile() - profile has wrong orientation.");
00721 return false;
00722 }
00723 break;
00724 case -1:
00725 if ( 1 == profile_orientation )
00726 {
00727 if ( !profile->Reverse() )
00728 {
00729 ON_ERROR("ON_Extrusion::AddInnerProfile() - profile->Reverse() failed.");
00730 return false;
00731 }
00732 profile_orientation = -1;
00733 }
00734 if ( -1 != profile_orientation )
00735 {
00736 ON_ERROR("ON_Extrusion::AddInnerProfile() - profile has wrong orientation.");
00737 return false;
00738 }
00739 break;
00740 default:
00741 {
00742 ON_ERROR("ON_Extrusion::Set/Add Profile - invalid desired_orientation parameter.");
00743 return false;
00744 }
00745 break;
00746 }
00747 }
00748 else if ( 0 != desired_orientation )
00749 {
00750 ON_ERROR("ON_Extrusion::Set/Add Profile - profile is an open curve.");
00751 return false;
00752 }
00753
00754 ON_PolyCurve* polycurve = ON_PolyCurve::Cast(profile);
00755 if ( 0 != polycurve )
00756 {
00757 polycurve->RemoveNesting();
00758
00759 if ( polycurve->SegmentCurves().Count() < 1 )
00760 {
00761 ON_ERROR("ON_Extrusion::Set/Add Profile - ON_PolyCurve has no segments.");
00762 return false;
00763 }
00764
00765 if ( polycurve->SegmentCurves().Count() + 1 != polycurve->SegmentParameters().Count() )
00766 {
00767 ON_ERROR("ON_Extrusion::Set/Add Profile - ON_PolyCurve segment and parameter counts do not agree.");
00768 return false;
00769 }
00770
00771 for ( int i = polycurve->Count()-1; i >= 0; i-- )
00772 {
00773 ON_Curve* segment = polycurve->SegmentCurve(i);
00774 if ( !CleanProfileSegment(segment) )
00775 polycurve->Remove(i);
00776 }
00777
00778 for ( int i = 0; i < polycurve->Count(); i++ )
00779 {
00780 ON_Curve* segment = polycurve->SegmentCurve(i);
00781 if ( 0 == segment )
00782 {
00783 ON_ERROR("ON_Extrusion::Set/Add Profile - ON_PolyCurve has null segment.");
00784 return false;
00785 }
00786 const ON_Interval segment_domain = polycurve->SegmentDomain(i);
00787 if ( !segment_domain.IsIncreasing() )
00788 {
00789 ON_ERROR("ON_Extrusion::Set/Add Profile - segment has invalid domain.");
00790 return false;
00791 }
00792 if ( !segment->SetDomain( segment_domain ) )
00793 {
00794 ON_ERROR("ON_Extrusion::Set/Add Profile - segment->SetDomain() failed.");
00795 return false;
00796 }
00797 }
00798 }
00799 else if ( !CleanProfileSegment(profile) )
00800 {
00801 }
00802
00803 return true;
00804 }
00805
00806 bool ON_Extrusion::SetOuterProfile( ON_Curve* outer_profile, bool bCap )
00807 {
00808 if ( 0 != m_profile )
00809 {
00810 ON_ERROR("ON_Extrusion::SetOuterProfile() called when m_profile is already not null.");
00811 return false;
00812 }
00813
00814 if ( !ProfileHelper( 0, outer_profile ) )
00815 return false;
00816
00817 m_profile_count = 1;
00818 m_profile = outer_profile;
00819
00820 if ( outer_profile->IsClosed() )
00821 {
00822 m_bCap[0] = m_bCap[1] = (bCap ? true : false);
00823 }
00824 else
00825 {
00826 m_bCap[0] = m_bCap[1] = false;
00827 }
00828
00829 return true;
00830 }
00831
00832 bool ON_Extrusion::AddInnerProfile( ON_Curve* inner_profile )
00833 {
00834 if ( m_profile_count < 1 )
00835 {
00836 ON_ERROR("ON_Extrusion::AddInnerProfile() called when m_profile_count < 1.");
00837 return false;
00838 }
00839 if ( 0 == m_profile )
00840 {
00841 ON_ERROR("ON_Extrusion::AddInnerProfile() called when m_profile is null.");
00842 return false;
00843 }
00844
00845 if ( 1 == m_profile_count && !m_profile->IsClosed() )
00846 {
00847 ON_ERROR("ON_Extrusion::AddInnerProfile() called when outer profile is not closed.");
00848 return false;
00849 }
00850
00851 ON_PolyCurve* polycurve = ON_PolyCurve::Cast(m_profile);
00852 if ( m_profile_count > 1 && 0 == polycurve )
00853 {
00854 ON_ERROR("ON_Extrusion::AddInnerProfile() called when m_profile_count > 1 but m_profile is not an ON_PolyCurve.");
00855 return false;
00856 }
00857 if ( m_profile_count > 1 && m_profile_count != polycurve->Count() )
00858 {
00859 ON_ERROR("ON_Extrusion::AddInnerProfile() called when m_profile_count > 1 but m_profile_count != m_profile->Count().");
00860 return false;
00861 }
00862
00863 if ( !ProfileHelper( -1, inner_profile ) )
00864 return false;
00865
00866 if ( 1 == m_profile_count )
00867 {
00868 if ( 0 != polycurve )
00869 {
00870 polycurve->RemoveNesting();
00871 }
00872
00873 if ( 0 == polycurve || 1 != polycurve->Count() )
00874 {
00875 polycurve = new ON_PolyCurve();
00876 polycurve->Append(m_profile);
00877 m_profile = polycurve;
00878 }
00879 }
00880
00881 polycurve->Append(inner_profile);
00882 if ( polycurve->SegmentDomain(m_profile_count) != inner_profile->Domain() )
00883 {
00884 inner_profile->SetDomain( polycurve->SegmentDomain(m_profile_count) );
00885
00886
00887
00888 polycurve = ON_PolyCurve::Cast(inner_profile);
00889 if ( 0 != polycurve )
00890 {
00891 polycurve->SynchronizeSegmentDomains();
00892 }
00893 }
00894 m_profile_count++;
00895
00896
00897 return true;
00898 }
00899
00900 const ON_PolyCurve* ON_Extrusion::PolyProfile() const
00901 {
00902 if ( m_profile_count <= 1 )
00903 return 0;
00904 const ON_PolyCurve* poly_profile = ON_PolyCurve::Cast(m_profile);
00905 return (0 != poly_profile && m_profile_count == poly_profile->Count() ) ? poly_profile : 0;
00906 }
00907
00908 const ON_Curve* ON_Extrusion::Profile(int profile_index) const
00909 {
00910 if ( 0 == profile_index && 1 == m_profile_count )
00911 return m_profile;
00912 if ( profile_index < 0 || profile_index > m_profile_count )
00913 return 0;
00914 const ON_PolyCurve* poly_profile = PolyProfile();
00915 return ( 0 != poly_profile ? poly_profile->SegmentCurve(profile_index) : 0 );
00916 }
00917
00918 ON_Curve* ON_Extrusion::Profile3d( ON_COMPONENT_INDEX ci ) const
00919 {
00920 double s = ON_UNSET_VALUE;
00921 if ( ON_COMPONENT_INDEX::extrusion_bottom_profile == ci.m_type )
00922 s = 0.0;
00923 else if ( ON_COMPONENT_INDEX::extrusion_top_profile == ci.m_type )
00924 s = 1.0;
00925 else
00926 return 0;
00927 return Profile3d(ci.m_index,s);
00928 }
00929
00930 ON_LineCurve* ON_Extrusion::PathLineCurve(ON_LineCurve* line_curve) const
00931 {
00932 if ( !m_path.IsValid() )
00933 return 0;
00934
00935 ON_Interval path_domain = Domain(PathParameter());
00936 if ( !path_domain.IsIncreasing() )
00937 return 0;
00938
00939 if ( 0 == line_curve )
00940 line_curve = new ON_LineCurve();
00941 line_curve->m_line = m_path;
00942 line_curve->SetDomain( path_domain[0], path_domain[1] );
00943
00944 return line_curve;
00945 }
00946
00947
00948 ON_Curve* ON_Extrusion::WallEdge( ON_COMPONENT_INDEX ci ) const
00949 {
00950 if ( ON_COMPONENT_INDEX::extrusion_wall_edge != ci.m_type )
00951 return 0;
00952 if ( ci.m_index < 0 )
00953 return 0;
00954
00955 int profile_index = ci.m_index/2;
00956 int profile_end = ci.m_index % 2;
00957 const ON_Curve* profile2d = Profile(profile_index);
00958 if ( 0 == profile2d )
00959 return 0;
00960
00961 ON_3dPoint profileP = profile_end
00962 ? profile2d->PointAtEnd()
00963 : profile2d->PointAtStart();
00964 if ( !profileP.IsValid() )
00965 return 0;
00966 profileP.z = 0.0;
00967
00968 ON_Xform xform0, xform1;
00969 if ( !GetProfileTransformation(0.0,xform0) )
00970 return 0;
00971 if ( !GetProfileTransformation(1.0,xform1) )
00972 return 0;
00973
00974 ON_Line line;
00975 line.from = xform0*profileP;
00976 line.to = xform1*profileP;
00977 if ( !line.IsValid() )
00978 return 0;
00979
00980 ON_LineCurve* line_curve = new ON_LineCurve();
00981 line_curve->m_line = line;
00982
00983 ON_Interval path_domain = Domain(PathParameter());
00984 line_curve->SetDomain( path_domain[0], path_domain[1] );
00985
00986 return line_curve;
00987 }
00988
00989
00990 ON_Surface* ON_Extrusion::WallSurface( ON_COMPONENT_INDEX ci ) const
00991 {
00992 if ( ON_COMPONENT_INDEX::extrusion_wall_surface != ci.m_type )
00993 return 0;
00994
00995 const ON_Curve* profile2d = Profile(ci.m_index);
00996 if ( 0 == profile2d )
00997 return 0;
00998
00999 ON_Interval wall_profile2d_domain = m_path_domain;
01000 if ( m_profile_count > 1 )
01001 {
01002 const ON_PolyCurve* polyprofile2d = PolyProfile();
01003 if ( 0 == polyprofile2d )
01004 return 0;
01005 if ( polyprofile2d->Count() != m_profile_count )
01006 return 0;
01007 wall_profile2d_domain = polyprofile2d->SegmentDomain(ci.m_index);
01008 }
01009
01010 ON_Curve* wall_profile2d = profile2d->DuplicateCurve();
01011 if ( 0 == wall_profile2d )
01012 return 0;
01013 wall_profile2d->SetDomain(wall_profile2d_domain);
01014 wall_profile2d->ChangeDimension(2);
01015
01016 ON_Extrusion* wall = new ON_Extrusion();
01017 wall->SetOuterProfile(wall_profile2d,false);
01018
01019 wall->m_path = m_path;
01020 wall->m_t = m_t;
01021 wall->m_up = m_up;
01022 wall->m_bHaveN[0] = m_bHaveN[0];
01023 wall->m_bHaveN[1] = m_bHaveN[1];
01024 wall->m_N[0] = m_N[0];
01025 wall->m_N[1] = m_N[1];
01026 wall->m_bTransposed = m_bTransposed;
01027
01028 return wall;
01029 }
01030
01031 ON_Curve* ON_Extrusion::Profile3d( int profile_index, double s ) const
01032 {
01033 if ( profile_index < 0 || !(0.0 <= s && s <= 1.0) || 0 == m_profile )
01034 return 0;
01035
01036 ON_Xform xform;
01037 if ( !GetProfileTransformation(s,xform) )
01038 return 0;
01039
01040 const ON_Curve* profile2d = Profile(profile_index);
01041 if ( 0 == profile2d )
01042 return 0;
01043
01044 ON_Curve* profile3d = profile2d->DuplicateCurve();
01045 if ( 0 == profile3d )
01046 return 0;
01047
01048 if ( !profile3d->ChangeDimension(3)
01049 || !profile3d->Transform(xform)
01050 )
01051 {
01052 delete profile3d;
01053 return 0;
01054 }
01055
01056 return profile3d;
01057 }
01058
01059 int ON_Extrusion::ProfileIndex( double profile_parameter ) const
01060 {
01061 if ( !m_profile )
01062 return -1;
01063
01064 if ( m_profile_count < 1 )
01065 return -1;
01066
01067 if ( 1 == m_profile_count )
01068 {
01069 return m_profile->Domain().Includes(profile_parameter,false) ? 0 : -1;
01070 }
01071
01072 const ON_PolyCurve* polycurve = PolyProfile();
01073 if ( 0 == polycurve )
01074 return -1;
01075
01076 const ON_SimpleArray<double>& polycurve_t = polycurve->SegmentParameters();
01077 if ( polycurve_t.Count() != m_profile_count+1 )
01078 return -1;
01079
01080 int profile_index = ON_SearchMonotoneArray( polycurve_t.Array(), polycurve_t.Count(), profile_parameter );
01081 if ( profile_index == m_profile_count )
01082 profile_index = m_profile_count-1;
01083 else if ( profile_index < 0 || profile_index > m_profile_count )
01084 profile_index = -1;
01085 return profile_index;
01086 }
01087
01088 int ON_Extrusion::ProfileCount() const
01089 {
01090 if ( !m_profile )
01091 return 0;
01092
01093 if ( m_profile_count < 1 )
01094 return 0;
01095
01096 if ( m_profile_count > 1 )
01097 {
01098 const ON_PolyCurve* polycurve = ON_PolyCurve::Cast(m_profile);
01099 if ( 0 == polycurve )
01100 return 0;
01101 if ( polycurve->Count() != m_profile_count )
01102 return 0;
01103 }
01104
01105 return m_profile_count;
01106 }
01107
01108
01109 int ON_Extrusion::GetProfileCurves( ON_SimpleArray< const ON_Curve* >& profile_curves ) const
01110 {
01111 if ( !m_profile )
01112 return 0;
01113
01114 if ( m_profile_count < 1 )
01115 return 0;
01116
01117 if ( 1 == m_profile_count )
01118 {
01119 profile_curves.Reserve(profile_curves.Count()+1);
01120 profile_curves.Append(m_profile);
01121 }
01122 else
01123 {
01124 const ON_PolyCurve* polycurve = ON_PolyCurve::Cast(m_profile);
01125 if ( 0 == polycurve )
01126 return 0;
01127 if ( polycurve->Count() != m_profile_count )
01128 return 0;
01129 const int count0 = profile_curves.Count();
01130 profile_curves.Reserve(count0+m_profile_count);
01131 for ( int i = 0; i < m_profile_count; i++ )
01132 {
01133 const ON_Curve* segment = polycurve->SegmentCurve(i);
01134 if ( 0 == segment )
01135 {
01136 profile_curves.SetCount(count0);
01137 return 0;
01138 }
01139 profile_curves.Append(segment);
01140 }
01141 }
01142
01143 return m_profile_count;
01144 }
01145
01146
01147 const double ON_Extrusion::m_Nz_min = 1.0/64.0;
01148
01149 const double ON_Extrusion::m_path_length_min = ON_ZERO_TOLERANCE;
01150
01151 ON_OBJECT_IMPLEMENT(ON_Extrusion,ON_Surface,"36F53175-72B8-4d47-BF1F-B4E6FC24F4B9");
01152
01153 ON_Extrusion::ON_Extrusion()
01154 {
01155 ON_ExtrusionInitializeHelper(*this);
01156 }
01157
01158 ON_Extrusion::ON_Extrusion(const ON_Extrusion& src) : ON_Surface(src), m_profile(0)
01159 {
01160 ON_ExtrusionCopyHelper(src,*this);
01161 }
01162
01163 ON_Extrusion::~ON_Extrusion()
01164 {
01165 if ( m_profile)
01166 {
01167 delete m_profile;
01168 }
01169 }
01170
01171 ON_Extrusion& ON_Extrusion::operator=(const ON_Extrusion& src)
01172 {
01173 if ( this != &src )
01174 {
01175 Destroy();
01176 ON_Surface::operator=(src);
01177 ON_ExtrusionCopyHelper(src,*this);
01178 }
01179 return *this;
01180 }
01181
01182 static
01183 void ON_Extrusion_IsNotValidMessage( ON_TextLog* text_log, const char* msg )
01184 {
01185
01186 if ( text_log && msg && msg[0] )
01187 text_log->Print("%s\n",msg);
01188 }
01189
01190 static bool ON_ExtrusionIsNotValid()
01191 {
01192 return ON_IsNotValid();
01193 }
01194
01195 ON_BOOL32 ON_Extrusion::IsValid( ON_TextLog* text_log ) const
01196 {
01197
01198 if ( m_profile_count < 1 )
01199 {
01200 ON_Extrusion_IsNotValidMessage(text_log,"m_profile_count < 1.");
01201 return ON_ExtrusionIsNotValid();
01202 }
01203 if ( !m_profile )
01204 {
01205 ON_Extrusion_IsNotValidMessage(text_log,"m_profile is NULL.");
01206 return ON_ExtrusionIsNotValid();
01207 }
01208 if ( m_profile_count > 1 )
01209 {
01210 const ON_PolyCurve* c = ON_PolyCurve::Cast(m_profile);
01211 if ( 0 == c )
01212 {
01213 ON_Extrusion_IsNotValidMessage(text_log,"m_profile_count > 1 but m_profile is not an ON_PolyCurve.");
01214 return ON_ExtrusionIsNotValid();
01215 }
01216 if ( m_profile_count != c->Count() )
01217 {
01218 ON_Extrusion_IsNotValidMessage(text_log,"m_profile_count > 1 but m_profile_count != m_profile->SegmentCount().");
01219 return ON_ExtrusionIsNotValid();
01220 }
01221
01222 if ( !ON_Extrusion::IsValidPolyCurveProfile(*c,text_log) )
01223 {
01224 ON_Extrusion_IsNotValidMessage(text_log,"m_profile is not a valid ON_PolyCurve.");
01225 return ON_ExtrusionIsNotValid();
01226 }
01227 for ( int i = 0; i < m_profile_count; i++ )
01228 {
01229 const ON_Curve* segment = c->SegmentCurve(i);
01230 if ( 0 == segment )
01231 {
01232 ON_Extrusion_IsNotValidMessage(text_log,"m_profile_count > 1 but a m_profile_count->SegmentCurve() is null.");
01233 return ON_ExtrusionIsNotValid();
01234 }
01235 if ( !segment->IsClosed() )
01236 {
01237 ON_Extrusion_IsNotValidMessage(text_log,"m_profile_count > 1 but a m_profile_count->SegmentCurve() is not closed.");
01238 return ON_ExtrusionIsNotValid();
01239 }
01240 }
01241 }
01242 else if ( !m_profile->IsValid(text_log) )
01243 {
01244 ON_Extrusion_IsNotValidMessage(text_log,"m_profile is not valid.");
01245 return ON_ExtrusionIsNotValid();
01246 }
01247
01248
01249 if ( !m_path.IsValid() )
01250 {
01251 ON_Extrusion_IsNotValidMessage(text_log,"m_path is not valid.");
01252 return ON_ExtrusionIsNotValid();
01253 }
01254 ON_3dVector D = m_path.to - m_path.from;
01255 double len = D.Length();
01256 if ( !ON_IsValid(len) || len <= 0.0 )
01257 {
01258 ON_Extrusion_IsNotValidMessage(text_log,"m_path has zero length.");
01259 return ON_ExtrusionIsNotValid();
01260 }
01261 if ( !ON_IsValid(len) || len <= ON_Extrusion::m_path_length_min )
01262 {
01263 if ( text_log )
01264 text_log->Print("m_path has zero length <= ON_Extrusion::m_path_length_min.");
01265 return ON_ExtrusionIsNotValid();
01266 }
01267 if ( !D.Unitize() || !D.IsUnitVector() )
01268 {
01269 ON_Extrusion_IsNotValidMessage(text_log,"m_path has zero direction.");
01270 return ON_ExtrusionIsNotValid();
01271 }
01272
01273
01274 if ( !(0.0 <= m_t.m_t[0] && m_t.m_t[0] < m_t.m_t[1] && m_t.m_t[1] <= 1.0) )
01275 {
01276 ON_Extrusion_IsNotValidMessage(text_log,"m_t does not satisfy 0<=m_t[0]<m_t[1]<=1");
01277 return ON_ExtrusionIsNotValid();
01278 }
01279
01280
01281 if ( !m_up.IsUnitVector() )
01282 {
01283 ON_Extrusion_IsNotValidMessage(text_log,"m_up is not a unit vector.");
01284 return ON_ExtrusionIsNotValid();
01285 }
01286 len = m_up*D;
01287 if ( fabs(len) > ON_SQRT_EPSILON )
01288 {
01289 ON_Extrusion_IsNotValidMessage(text_log,"m_up is not perpendicular to m_path.");
01290 return ON_ExtrusionIsNotValid();
01291 }
01292
01293
01294 if ( m_bHaveN[0] )
01295 {
01296 if ( !m_N[0].IsUnitVector() )
01297 {
01298 ON_Extrusion_IsNotValidMessage(text_log,"m_N[0] is not a unit vector.");
01299 return ON_ExtrusionIsNotValid();
01300 }
01301 if ( !(m_N[0].z > ON_Extrusion::m_Nz_min) )
01302 {
01303 ON_Extrusion_IsNotValidMessage(text_log,"m_N[0].z is too small (<=ON_Extrusion::m_Nz_min) or negative");
01304 return ON_ExtrusionIsNotValid();
01305 }
01306 }
01307 if ( m_bHaveN[1] )
01308 {
01309 if ( !m_N[1].IsUnitVector() )
01310 {
01311 ON_Extrusion_IsNotValidMessage(text_log,"m_N[1] is not a unit vector.");
01312 return ON_ExtrusionIsNotValid();
01313 }
01314 if ( !(m_N[1].z > ON_Extrusion::m_Nz_min) )
01315 {
01316 ON_Extrusion_IsNotValidMessage(text_log,"m_N[1].z is too small (<=ON_Extrusion::m_Nz_min) or negative");
01317 return ON_ExtrusionIsNotValid();
01318 }
01319 }
01320
01321 return true;
01322 }
01323
01324 void ON_Extrusion::Dump( ON_TextLog& text_log ) const
01325 {
01326 text_log.Print("ON_Extrusion: \n");
01327 {
01328 text_log.PushIndent();
01329 text_log.Print("Path: ");
01330 text_log.Print(m_path.PointAt(m_t[0]));
01331 text_log.Print(" ");
01332 text_log.Print(m_path.PointAt(m_t[1]));
01333 text_log.Print("\n");
01334 text_log.Print("Up: ");
01335 text_log.Print(m_up);
01336 text_log.Print("\n");
01337 text_log.Print("m_bCap[] = (%d, %d)\n",m_bCap[0],m_bCap[1]);
01338 text_log.Print("m_bHaveN[] = (%d, %d)\n",m_bHaveN[0],m_bHaveN[1]);
01339 text_log.Print("m_N[] = (");
01340 text_log.Print(m_N[0]);
01341 text_log.Print(", ");
01342 text_log.Print(m_N[1]);
01343 text_log.Print("\n");
01344 text_log.Print("m_path_domain = (%.17g, %.17g)\n",m_path_domain[0],m_path_domain[1]);
01345 text_log.Print("m_bTransposed = %d\n",m_bTransposed);
01346 text_log.Print("Profile Count: %d\n",m_profile_count);
01347 text_log.Print("Profile:\n");
01348 {
01349 text_log.PushIndent();
01350 if ( !m_profile )
01351 text_log.Print("NULL");
01352 else
01353 m_profile->Dump(text_log);
01354 text_log.PopIndent();
01355 }
01356 text_log.PopIndent();
01357 }
01358 return;
01359 }
01360
01361 unsigned int ON_Extrusion::SizeOf() const
01362 {
01363 unsigned int sz = sizeof(*this) - sizeof(ON_Surface);
01364 if ( m_profile )
01365 sz += m_profile->SizeOf();
01366 return sz;
01367 }
01368
01369 ON__UINT32 ON_Extrusion::DataCRC(ON__UINT32 current_remainder) const
01370 {
01371 if ( m_profile )
01372 current_remainder = m_profile->DataCRC(current_remainder);
01373 current_remainder = ON_CRC32(current_remainder,sizeof(m_path),&m_path);
01374 current_remainder = ON_CRC32(current_remainder,sizeof(m_t),&m_t);
01375 current_remainder = ON_CRC32(current_remainder,sizeof(m_up),&m_up);
01376 current_remainder = ON_CRC32(current_remainder,sizeof(m_bHaveN[0]), &m_bHaveN[0]);
01377 current_remainder = ON_CRC32(current_remainder,sizeof(m_bHaveN[1]), &m_bHaveN[1]);
01378 current_remainder = ON_CRC32(current_remainder,sizeof(m_N[0]), &m_N[0]);
01379 current_remainder = ON_CRC32(current_remainder,sizeof(m_N[1]), &m_N[1]);
01380 current_remainder = ON_CRC32(current_remainder,sizeof(m_path_domain), &m_path_domain);
01381 current_remainder = ON_CRC32(current_remainder,sizeof(m_bTransposed), &m_bTransposed);
01382 current_remainder = ON_CRC32(current_remainder,sizeof(m_profile_count), &m_profile_count);
01383 current_remainder = ON_CRC32(current_remainder,sizeof(m_bCap[0]), &m_bCap[0]);
01384 current_remainder = ON_CRC32(current_remainder,sizeof(m_bCap[1]), &m_bCap[1]);
01385 if ( m_profile )
01386 current_remainder = m_profile->DataCRC(current_remainder);
01387 return current_remainder;
01388 }
01389
01390 ON_BOOL32 ON_Extrusion::Write(
01391 ON_BinaryArchive& binary_archive
01392 ) const
01393 {
01394 bool rc = binary_archive.BeginWrite3dmChunk(TCODE_ANONYMOUS_CHUNK,1,2);
01395 if (!rc)
01396 return false;
01397 for (;;)
01398 {
01399 rc = binary_archive.WriteObject(m_profile);
01400 if (!rc) break;
01401 rc = binary_archive.WriteLine(m_path);
01402 if (!rc) break;
01403 rc = binary_archive.WriteInterval(m_t);
01404 if (!rc) break;
01405 rc = binary_archive.WriteVector(m_up);
01406 if (!rc) break;
01407 rc = binary_archive.WriteBool(m_bHaveN[0]);
01408 if (!rc) break;
01409 rc = binary_archive.WriteBool(m_bHaveN[1]);
01410 if (!rc) break;
01411 rc = binary_archive.WriteVector(m_N[0]);
01412 if (!rc) break;
01413 rc = binary_archive.WriteVector(m_N[1]);
01414 if (!rc) break;
01415 rc = binary_archive.WriteInterval(m_path_domain);
01416 if (!rc) break;
01417 rc = binary_archive.WriteBool(m_bTransposed);
01418 if (!rc) break;
01419
01420 rc = binary_archive.WriteInt(m_profile_count);
01421 if (!rc) break;
01422
01423 rc = binary_archive.WriteBool(m_bCap[0]);
01424 if (!rc) break;
01425 rc = binary_archive.WriteBool(m_bCap[1]);
01426 if (!rc) break;
01427
01428 break;
01429 }
01430 if ( !binary_archive.EndWrite3dmChunk() )
01431 rc = false;
01432 return rc;
01433 }
01434
01435
01436 ON_BOOL32 ON_Extrusion::Read(
01437 ON_BinaryArchive& binary_archive
01438 )
01439 {
01440 Destroy();
01441 int major_version = 0;
01442 int minor_version = 0;
01443 bool rc = binary_archive.BeginRead3dmChunk(TCODE_ANONYMOUS_CHUNK,&major_version,&minor_version);
01444 if (!rc)
01445 return false;
01446 for (;;)
01447 {
01448 rc = (1 == major_version);
01449 if (!rc) break;
01450 ON_Object* obj = 0;
01451 rc = (1==binary_archive.ReadObject(&obj));
01452 if (!rc) break;
01453 if ( obj )
01454 {
01455 m_profile = ON_Curve::Cast(obj);
01456 if ( !m_profile )
01457 {
01458 delete obj;
01459 rc = false;
01460 break;
01461 }
01462 }
01463 rc = binary_archive.ReadLine(m_path);
01464 if (!rc) break;
01465 rc = binary_archive.ReadInterval(m_t);
01466 if (!rc) break;
01467 rc = binary_archive.ReadVector(m_up);
01468 if (!rc) break;
01469 rc = binary_archive.ReadBool(&m_bHaveN[0]);
01470 if (!rc) break;
01471 rc = binary_archive.ReadBool(&m_bHaveN[1]);
01472 if (!rc) break;
01473 rc = binary_archive.ReadVector(m_N[0]);
01474 if (!rc) break;
01475 rc = binary_archive.ReadVector(m_N[1]);
01476 if (!rc) break;
01477 rc = binary_archive.ReadInterval(m_path_domain);
01478 if (!rc) break;
01479 rc = binary_archive.ReadBool(&m_bTransposed);
01480 if (!rc) break;
01481
01482
01483 m_profile_count = (0 != m_profile) ? 1 : 0;
01484
01485 if ( minor_version >= 1 )
01486 {
01487
01488 rc = binary_archive.ReadInt(&m_profile_count);
01489 if (!rc) break;
01490
01491 if ( minor_version >= 2 )
01492 {
01493
01494 rc = binary_archive.ReadBool(&m_bCap[0]);
01495 if (!rc) break;
01496 rc = binary_archive.ReadBool(&m_bCap[1]);
01497 if (!rc) break;
01498 }
01499 }
01500
01501 if ( minor_version < 2 )
01502 {
01503 const ON_Curve* outer_profile = Profile(0);
01504 if ( 0 != outer_profile && outer_profile->IsClosed() )
01505 {
01506 m_bCap[0] = m_bCap[1] = true;
01507 }
01508 }
01509
01510 break;
01511 }
01512 if ( !binary_archive.EndRead3dmChunk() )
01513 rc = false;
01514 return rc;
01515 }
01516
01517 ON::object_type ON_Extrusion::ObjectType() const
01518 {
01519 return ON::extrusion_object;
01520 }
01521
01522
01523
01524 int ON_Extrusion::Dimension() const
01525 {
01526 return 3;
01527 }
01528
01529 static
01530 bool GetBoundingBoxHelper(const ON_Extrusion& extrusion,
01531 ON_BoundingBox& bbox,
01532 const ON_Xform* xform
01533 )
01534 {
01535
01536 ON_3dPoint corners[8];
01537 bbox.m_min.z = 0.0;
01538 bbox.m_max.z = 0.0;
01539 corners[0] = corners[1] = bbox.m_min;
01540 corners[1].x = bbox.m_max.x;
01541 corners[2] = corners[3] = bbox.m_max;
01542 corners[3].x = bbox.m_min.x;
01543 corners[4] = corners[0];
01544 corners[5] = corners[1];
01545 corners[6] = corners[2];
01546 corners[7] = corners[3];
01547
01548 ON_Xform xform0;
01549 if ( !extrusion.GetProfileTransformation(0,xform0) )
01550 return false;
01551 ON_Xform xform1;
01552 if ( !extrusion.GetProfileTransformation(1,xform1) )
01553 return false;
01554 if ( xform && !xform->IsIdentity() )
01555 {
01556 xform0 = (*xform)*xform0;
01557 xform1 = (*xform)*xform1;
01558 }
01559 corners[0] = xform0*corners[0];
01560 corners[1] = xform0*corners[1];
01561 corners[2] = xform0*corners[2];
01562 corners[3] = xform0*corners[3];
01563 corners[4] = xform1*corners[4];
01564 corners[5] = xform1*corners[5];
01565 corners[6] = xform1*corners[6];
01566 corners[7] = xform1*corners[7];
01567 bbox.Set(3,0,8,3,&corners[0].x,false);
01568 return true;
01569 }
01570
01571 ON_BOOL32 ON_Extrusion::GetBBox(double* boxmin,double* boxmax,int bGrowBox) const
01572 {
01573 bool rc = false;
01574 if ( m_path.IsValid() && m_profile )
01575 {
01576 ON_BoundingBox bbox;
01577 if ( m_profile->GetTightBoundingBox(bbox) && GetBoundingBoxHelper(*this,bbox,0) )
01578 {
01579 rc = true;
01580 if ( bGrowBox )
01581 {
01582 bGrowBox = ( boxmin[0] <= boxmax[0]
01583 && boxmin[1] <= boxmax[1]
01584 && boxmin[2] <= boxmax[2]
01585 && ON_IsValid(boxmax[0])
01586 && ON_IsValid(boxmax[1])
01587 && ON_IsValid(boxmax[2]));
01588 }
01589 if ( bGrowBox )
01590 {
01591 if ( boxmin[0] > bbox.m_min.x ) boxmin[0] = bbox.m_min.x;
01592 if ( boxmin[1] > bbox.m_min.y ) boxmin[1] = bbox.m_min.y;
01593 if ( boxmin[2] > bbox.m_min.z ) boxmin[2] = bbox.m_min.z;
01594 if ( boxmax[0] < bbox.m_max.x ) boxmax[0] = bbox.m_max.x;
01595 if ( boxmax[1] < bbox.m_max.y ) boxmax[1] = bbox.m_max.y;
01596 if ( boxmax[2] < bbox.m_max.z ) boxmax[2] = bbox.m_max.z;
01597 }
01598 else
01599 {
01600 boxmin[0] = bbox.m_min.x;
01601 boxmin[1] = bbox.m_min.y;
01602 boxmin[2] = bbox.m_min.z;
01603 boxmax[0] = bbox.m_max.x;
01604 boxmax[1] = bbox.m_max.y;
01605 boxmax[2] = bbox.m_max.z;
01606 }
01607 }
01608 }
01609 return rc;
01610 }
01611
01612
01613 bool ON_Extrusion::GetTightBoundingBox(ON_BoundingBox& tight_bbox, int bGrowBox, const ON_Xform* xform ) const
01614 {
01615 bool rc = false;
01616 if ( m_path.IsValid() && m_profile )
01617 {
01618 ON_BoundingBox bbox;
01619 if ( m_profile->GetTightBoundingBox(bbox) && GetBoundingBoxHelper(*this,bbox,xform) )
01620 {
01621 if ( bGrowBox )
01622 tight_bbox.Union(bbox);
01623 else
01624 tight_bbox = bbox;
01625 rc = true;
01626 }
01627 }
01628 return rc;
01629 }
01630
01631 static bool ON_Extrusion_TransformFailed()
01632 {
01633 return false;
01634 }
01635
01636 static bool Profile2dTransform( ON_Extrusion& e, const ON_Xform& profile_xform, bool bNeedReverse )
01637 {
01638 if ( profile_xform.IsIdentity() )
01639 {
01640
01641 return true;
01642 }
01643
01644
01645 bool rc = false;
01646 bool bNeedDeformable = ( fabs(profile_xform.m_xform[0][0]) != fabs(profile_xform.m_xform[1][1])
01647 || 0.0 != profile_xform.m_xform[1][0]
01648 );
01649 ON_PolyCurve* polyprofile = const_cast<ON_PolyCurve*>(e.PolyProfile());
01650 if ( 0 != polyprofile )
01651 {
01652 rc = true;
01653 if ( bNeedDeformable )
01654 polyprofile->MakeDeformable();
01655 for ( int i = 0; i < polyprofile->Count(); i++ )
01656 {
01657 ON_Curve* profile_segment = polyprofile->SegmentCurve(i);
01658 if ( 0 == profile_segment )
01659 {
01660 continue;
01661 }
01662 if ( !profile_segment->Transform(profile_xform) )
01663 {
01664 rc = ON_Extrusion_TransformFailed();
01665 continue;
01666 }
01667 if ( bNeedReverse )
01668 {
01669 double t0, t1;
01670 if ( profile_segment->GetDomain(&t0,&t1) )
01671 {
01672
01673
01674 profile_segment->Reverse();
01675
01676 profile_segment->SetDomain(t0,t1);
01677 }
01678 }
01679 }
01680 }
01681 else
01682 {
01683 if ( bNeedDeformable && !e.m_profile->IsDeformable() )
01684 {
01685 ON_NurbsCurve* c = e.m_profile->NurbsCurve();
01686 if ( 0 != c )
01687 {
01688 c->CopyUserData(*e.m_profile);
01689 if( c->Transform(profile_xform) )
01690 {
01691 rc = true;
01692 delete e.m_profile;
01693 e.m_profile = c;
01694 }
01695 else
01696 {
01697 delete c;
01698 rc = ON_Extrusion_TransformFailed();
01699 }
01700 }
01701 else
01702 {
01703 rc = ON_Extrusion_TransformFailed();
01704 }
01705 }
01706 else
01707 {
01708 rc = e.m_profile->Transform(profile_xform)?true:ON_Extrusion_TransformFailed();
01709 }
01710 if ( rc && bNeedReverse )
01711 {
01712 double t0, t1;
01713 if ( e.m_profile->GetDomain(&t0,&t1) )
01714 {
01715
01716
01717 e.m_profile->Reverse();
01718
01719 e.m_profile->SetDomain(t0,t1);
01720 }
01721 }
01722 }
01723
01724 return rc;
01725 }
01726
01727 ON_BOOL32 ON_Extrusion::Transform( const ON_Xform& xform )
01728 {
01729 if ( !m_path.IsValid() || !m_up.IsUnitVector() || m_profile_count < 1 )
01730 return ON_Extrusion_TransformFailed();
01731
01732 ON_3dVector T = m_path.Tangent();
01733 ON_3dVector UxT = ON_CrossProduct(m_up,T);
01734 if ( !UxT.IsUnitVector() && !UxT.Unitize() )
01735 return ON_Extrusion_TransformFailed();
01736
01737 const bool bUseVectorXform = (0.0 == xform[3][0] && 0.0 == xform[3][1] && 0.0 == xform[3][2]);
01738
01739 ON_3dPoint E[2], QE[2];
01740 E[0] = m_path.from;
01741 E[1] = m_path.to;
01742 QE[0] = xform*E[0];
01743 QE[1] = xform*E[1];
01744 if ( !QE[0].IsValid() )
01745 return ON_Extrusion_TransformFailed();
01746 if ( !QE[1].IsValid() )
01747 return ON_Extrusion_TransformFailed();
01748 ON_3dVector QT0 = bUseVectorXform ? (xform*(E[1] - E[0])) : (QE[1]-QE[0]);
01749 if ( !QT0.Unitize() )
01750 return ON_Extrusion_TransformFailed();
01751
01752 const int base_index = ( QE[1].DistanceTo(E[1]) < QE[0].DistanceTo(E[0]) ) ? 1 : 0;
01753 const ON_3dPoint B(E[base_index]);
01754 const ON_3dPoint QB(QE[base_index]);
01755
01756 const double QT0oT = QT0*T;
01757 bool bSamePathDir = ( fabs(fabs(QT0oT) - 1.0) <= ON_SQRT_EPSILON );
01758 ON_3dVector QT = bSamePathDir ? ((QT0oT < 0.0) ? -T : T) : QT0;
01759 const double Qlen = QE[0].DistanceTo(QE[1]);
01760 if ( bSamePathDir )
01761 {
01762 ON_3dPoint R = QB + (base_index ? -Qlen : Qlen)*QT;
01763 if ( QE[1-base_index].DistanceTo( R ) <= ON_SQRT_EPSILON*Qlen )
01764 {
01765 QE[1-base_index] = R;
01766 }
01767 else
01768 {
01769 bSamePathDir = false;
01770 QT = QT0;
01771 }
01772 }
01773
01774 const ON_3dPoint X0 = xform*(B + UxT);
01775 const ON_3dPoint Y0 = xform*(B + m_up);
01776 const ON_3dVector QDY = bUseVectorXform ? (xform*m_up) : (Y0-QB);
01777 ON_3dVector QY = QDY;
01778 if ( !QY.Unitize() )
01779 return ON_Extrusion_TransformFailed();
01780 ON_3dVector QU0 = QDY - (QDY*QT)*QT;
01781 if ( !QU0.Unitize() )
01782 return ON_Extrusion_TransformFailed();
01783
01784 const double QU0oU = QU0*m_up;
01785 bool bSameUpDir = ( fabs(fabs(QU0oU) - 1.0) <= ON_SQRT_EPSILON );
01786 ON_3dVector QU = bSameUpDir ? ((QU0oU < 0.0) ? -m_up : m_up) : QU0;
01787
01788 if (bSameUpDir && !bSamePathDir && fabs(QU*QT) > fabs(QU0*QT) )
01789 {
01790
01791 bSameUpDir = false;
01792 QU = QU0;
01793 }
01794
01795 ON_3dVector QUxQT = ON_CrossProduct(QU,QT);
01796 if ( !QUxQT.Unitize() )
01797 return ON_Extrusion_TransformFailed();
01798
01799 const double QUxQToUxT = QUxQT*UxT;
01800 if ( (bSamePathDir && bSameUpDir) || fabs(fabs(QUxQToUxT) - 1.0) <= ON_SQRT_EPSILON )
01801 {
01802 if ( QUxQToUxT < 0.0 )
01803 QUxQT = -UxT;
01804 else
01805 QUxQT = UxT;
01806 }
01807
01808 const double QUoQY = QU*QY;
01809 if ( fabs(QUoQY - 1.0) < ON_SQRT_EPSILON )
01810 QY = QU;
01811 else if ( fabs(QUoQY + 1.0) < ON_SQRT_EPSILON )
01812 QY = -QU;
01813
01814
01815
01816 const ON_3dVector QDX = bUseVectorXform ? (xform*UxT) : (X0 - QB);
01817 ON_3dVector QX = QDX - (QDX*QY)*QY;
01818 if ( !QX.Unitize() )
01819 return ON_Extrusion_TransformFailed();
01820
01821 const double QUxQToQX = QUxQT*QX;
01822 if ( fabs(QUxQToQX - 1.0) < ON_SQRT_EPSILON )
01823 QX = QUxQT;
01824 else if ( fabs(QUxQToQX + 1.0) < ON_SQRT_EPSILON )
01825 QX = -QUxQT;
01826
01827
01828 ON_3dVector QXxQY = ON_CrossProduct(QX,QY);
01829 if ( !QXxQY.IsUnitVector() && !QXxQY.Unitize() )
01830 return ON_Extrusion_TransformFailed();
01831 if ( QXxQY*QT < 0.0 )
01832 {
01833 QX.Reverse();
01834 QXxQY.Reverse();
01835 }
01836
01837 ON_3dVector path_shear(0.0,QU*QXxQY,QT*QXxQY);
01838 bool bHavePathShear = path_shear.z > ON_Extrusion::m_Nz_min
01839 && path_shear.z < 1.0 - ON_SQRT_EPSILON
01840 && path_shear.y < 1.0 - ON_SQRT_EPSILON;
01841 if ( bHavePathShear )
01842 {
01843 double x2 = path_shear.y*path_shear.y + path_shear.z*path_shear.z;
01844 if ( x2 > ON_SQRT_EPSILON && x2 <= 1.0 )
01845 {
01846 double QUxQToQXxQY = QUxQT*QXxQY;
01847 path_shear.x = sqrt(1.0 - x2);
01848 if ( QUxQToQXxQY < 0.0 )
01849 path_shear.x = -path_shear.x;
01850 }
01851 if ( fabs(path_shear.y) <= ON_SQRT_EPSILON )
01852 path_shear.y = 0.0;
01853 bHavePathShear = path_shear.IsUnitVector() && (path_shear.x != 0.0 || path_shear.y != 0.0);
01854 }
01855
01856 if ( !bHavePathShear )
01857 {
01858 path_shear.Set(0.0,0.0,1.0);
01859 QXxQY = QT;
01860 }
01861
01862
01863 ON_3dVector QN[2] = {ON_3dVector::ZeroVector,ON_3dVector::ZeroVector};
01864 bool bHaveQN[2] = {false,false};
01865 bool bUseQN[2] = {false,false};
01866 for ( int i = 0; i < 2; i++ )
01867 {
01868 if ( m_bHaveN[i] )
01869 {
01870 QN[i] = m_N[i];
01871 bHaveQN[i] = true;
01872 bUseQN[i] = true;
01873
01874
01875
01876
01877
01878
01879 ON_3dVector QN3d;
01880 if ( bHavePathShear )
01881 {
01882
01883 ON_3dVector V1(m_N[i].y,-m_N[i].x,0.0);
01884 V1.Unitize();
01885 ON_3dVector V2 = ON_CrossProduct( m_N[i],V1);
01886 V1 = V1.x*UxT + V1.y*m_up + V1.z*T;
01887 V2 = V2.x*UxT + V2.y*m_up + V2.z*T;
01888
01889
01890
01891 ON_3dVector QV1 = xform*V1;
01892 ON_3dVector QV2 = xform*V2;
01893 double lenQV1 = QV1.Length();
01894 double lenQV2 = QV2.Length();
01895 if ( fabs(lenQV1 - lenQV2) > 0.125*(lenQV1 + lenQV2) )
01896 {
01897
01898
01899
01900
01901
01902 QV1.Unitize();
01903 QV2.Unitize();
01904 }
01905
01906
01907 QN3d = ON_CrossProduct(QV1,QV2);
01908 }
01909 else
01910 {
01911 const ON_3dVector N3d = m_N[i].x*UxT + m_N[i].y*m_up + m_N[i].z*T;
01912 ON_3dPoint QTip = xform*(E[i] + N3d);
01913 QN3d = bUseVectorXform ? (xform*N3d) : (QTip - QE[i]);
01914 }
01915 if ( !QN3d.Unitize() )
01916 continue;
01917
01918
01919 QN[i].x = QUxQT*QN3d;
01920 QN[i].y = QU*QN3d;
01921 QN[i].z = QT*QN3d;
01922 if ( QN[i].z < 0.0 )
01923 QN[i].Reverse();
01924 if ( !QN[i].Unitize() )
01925 {
01926 bHaveQN[i] = false;
01927 }
01928 if ( fabs(QN[i].x) <= ON_SQRT_EPSILON )
01929 QN[i].x = 0.0;
01930 if ( fabs(QN[i].y) <= ON_SQRT_EPSILON )
01931 QN[i].y = 0.0;
01932 if ( QN[i].z < ON_Extrusion::m_Nz_min
01933 || QN[i].z >= 1.0 - ON_SQRT_EPSILON
01934 || (fabs(QN[i].x) <= ON_SQRT_EPSILON && fabs(QN[i].y) <= ON_SQRT_EPSILON )
01935 )
01936 {
01937 bHaveQN[i] = false;
01938 }
01939
01940 if ( !bHaveQN[i] )
01941 QN[i] = ON_3dVector::ZeroVector;
01942 else if ( fabs(QN[i]*m_N[i] - 1.0) <= 1.0e-6 )
01943 QN[i] = m_N[i];
01944 }
01945 }
01946
01947
01948 ON_Xform profile_xform(1.0);
01949
01950 const double profile_y_scale = QDY.Length();
01951
01952 if ( !bHavePathShear )
01953 {
01954 const double profile_x_scale = QX*QDX;
01955
01956 if ( !ON_IsValid(profile_y_scale) || 0.0 == profile_y_scale )
01957 {
01958
01959 return ON_Extrusion_TransformFailed();
01960 }
01961
01962 if ( !ON_IsValid(profile_x_scale) || 0.0 == profile_x_scale )
01963 {
01964
01965 return ON_Extrusion_TransformFailed();
01966 }
01967
01968
01969
01970
01971 const double profile_y_scale_tol = ON_SQRT_EPSILON;
01972 const double profile_x_scale_tol = 10.0*profile_y_scale_tol;
01973
01974 if ( fabs(profile_y_scale - 1.0) <= profile_y_scale_tol )
01975 profile_xform.m_xform[1][1] = 1.0;
01976 else
01977 profile_xform.m_xform[1][1] = profile_y_scale;
01978
01979 if ( fabs( profile_x_scale - 1.0 ) <= profile_x_scale_tol )
01980 profile_xform.m_xform[0][0] = 1.0;
01981 else if ( fabs( profile_x_scale + 1.0 ) <= profile_x_scale_tol )
01982 profile_xform.m_xform[0][0] = -1.0;
01983 else
01984 profile_xform.m_xform[0][0] = profile_x_scale;
01985
01986 const double profile_xform_tol = profile_x_scale_tol*(fabs(profile_xform.m_xform[0][0]) + profile_xform.m_xform[1][1]);
01987 if ( fabs(fabs(profile_xform.m_xform[0][0]) - profile_xform.m_xform[1][1]) <= profile_xform_tol )
01988 {
01989 profile_xform.m_xform[0][0] = ((profile_xform.m_xform[0][0] < 0.0)?-1.0:1.0)*profile_xform.m_xform[1][1];
01990 }
01991 else if ( fabs(profile_xform.m_xform[0][0]) <= profile_xform_tol )
01992 {
01993
01994 return ON_Extrusion_TransformFailed();
01995 }
01996
01997 double profile_det = profile_xform.m_xform[0][0]*profile_xform.m_xform[1][1];
01998 if ( !ON_IsValid(profile_det) || 0.0 == profile_det )
01999 return ON_Extrusion_TransformFailed();
02000
02001
02002 const double profile_shear_tol = profile_xform_tol;
02003 const double QYoQDX = QY*QDX;
02004 if ( fabs( QYoQDX ) <= profile_shear_tol )
02005 profile_xform.m_xform[1][0] = 0.0;
02006 else
02007 profile_xform.m_xform[1][0] = QYoQDX;
02008 }
02009 else
02010 {
02011
02012
02013 ON_Plane plane0;
02014 plane0.origin = B; plane0.xaxis = UxT; plane0.yaxis = m_up; plane0.zaxis = T;
02015 plane0.UpdateEquation();
02016
02017
02018
02019 ON_Plane plane1;
02020 plane1.origin = QB; plane1.xaxis = QUxQT; plane1.yaxis = QU; plane1.zaxis = QT;
02021 plane1.UpdateEquation();
02022
02023 ON_Xform xform1, xform3, xform4, xform5;
02024
02025
02026 xform1.Rotation(ON_Plane::World_xy,plane0);
02027
02028
02029
02030
02031
02032 xform3.PlanarProjection(plane1);
02033
02034
02035 xform4.Rotation(plane1, ON_Plane::World_xy);
02036
02037 profile_xform = xform4*xform3*xform*xform1;
02038 profile_xform.m_xform[0][2] = 0.0;
02039 profile_xform.m_xform[1][2] = 0.0;
02040 profile_xform.m_xform[2][0] = 0.0; profile_xform.m_xform[2][1] = 0.0; profile_xform.m_xform[2][2] = 1.0; profile_xform.m_xform[2][3] = 0.0;
02041 profile_xform.m_xform[3][0] = 0.0; profile_xform.m_xform[3][1] = 0.0; profile_xform.m_xform[3][2] = 0.0; profile_xform.m_xform[3][3] = 1.0;
02042
02043 const double xform_tol = 10.0*ON_SQRT_EPSILON;
02044 if ( profile_y_scale > xform_tol && fabs(profile_y_scale - 1.0) > xform_tol )
02045 {
02046 double profile_scale_tol = profile_y_scale*ON_SQRT_EPSILON;
02047 if ( fabs(profile_xform.m_xform[0][0] - profile_y_scale) < profile_scale_tol )
02048 {
02049 profile_xform.m_xform[0][0] = profile_y_scale;
02050 if ( fabs(profile_xform.m_xform[1][1] - profile_y_scale) < profile_scale_tol )
02051 profile_xform.m_xform[1][1] = profile_y_scale;
02052 else if ( fabs(profile_xform.m_xform[1][1] + profile_y_scale) < profile_scale_tol )
02053 profile_xform.m_xform[1][1] = -profile_y_scale;
02054 }
02055 }
02056
02057 for ( int i = 0; i < 2; i++ ) for ( int j = 0; j < 4; j++ )
02058 {
02059 if ( 2 == j )
02060 continue;
02061 double x = fabs(profile_xform.m_xform[i][j]);
02062 if ( fabs(x) <= xform_tol )
02063 profile_xform.m_xform[i][j] = 0.0;
02064 else if ( fabs(1.0-x) <= xform_tol )
02065 profile_xform.m_xform[i][j] = 1.0;
02066 else if ( fabs(x-1.0) <= xform_tol )
02067 profile_xform.m_xform[i][j] = -1.0;
02068 }
02069 }
02070
02071
02072 TransformUserData(xform);
02073
02074
02075 m_path.from = QE[0];
02076 m_path.to = QE[1];
02077 m_up = QU;
02078 for ( int i = 0; i < 2; i++ )
02079 {
02080 if ( bUseQN[i] )
02081 {
02082 m_N[i] = QN[i];
02083 m_bHaveN[i] = bHaveQN[i];
02084 }
02085 else if ( bHavePathShear )
02086 {
02087 m_N[i] = path_shear;
02088 m_bHaveN[i] = true;
02089 }
02090 else
02091 {
02092 m_N[i].Set(0.0,0.0,0.0);
02093 m_bHaveN[i] = false;
02094 }
02095 }
02096
02097
02098
02099
02100
02101
02102
02103
02104
02105
02106
02107
02108
02109
02110
02111
02112
02113 if ( profile_xform.IsIdentity() )
02114 return true;
02115
02116 double profile_det = profile_xform[0][0]*profile_xform[1][1] - profile_xform[1][0]*profile_xform[0][1];
02117 bool bNeedReverse = (profile_det < 0.0);
02118 return Profile2dTransform( *this, profile_xform, bNeedReverse );
02119 }
02120
02121 class CMyBrepIsSolidSetter : public ON_Brep
02122 {
02123 public:
02124 void SetIsSolid(int is_solid) {m_is_solid = is_solid;}
02125 void SetBBox( const ON_Extrusion& extrusion)
02126 {
02127 ON_BoundingBox brep_bbox = BoundingBox();
02128 ON_BoundingBox extr_bbox = extrusion.BoundingBox();
02129 ON_BoundingBox bbox;
02130 bbox.Intersection(brep_bbox,extr_bbox);
02131 m_bbox = bbox;
02132 }
02133 };
02134
02135 class ON_Extrusion_BrepForm_FaceInfo
02136 {
02137 public:
02138 ON_Extrusion_BrepForm_FaceInfo();
02139
02140 ~ON_Extrusion_BrepForm_FaceInfo();
02141
02142
02143
02144
02145
02146
02147
02148
02149
02150 bool HaveBrepFaceFace() const;
02151
02152 void Init();
02153
02154
02155
02156
02157
02158
02159 bool m_bClosedProfile;
02160 int m_profile_orientation;
02161 int m_profile_index;
02162
02163
02164 ON_Curve* m_extrusion_profile;
02165 ON_Extrusion* m_extrusion_srf;
02166 int m_face_index;
02167 int m_vid[4];
02168 int m_eid[4];
02169 ON_BOOL32 m_bRev3d[4];
02170
02171
02172 int m_cap_trim_index[2];
02173 int m_cap_edge_index[2];
02174 ON_NurbsCurve* m_cap_c2[2];
02175 };
02176
02177 ON_Extrusion_BrepForm_FaceInfo::ON_Extrusion_BrepForm_FaceInfo()
02178 {
02179 Init();
02180 }
02181
02182 ON_Extrusion_BrepForm_FaceInfo::~ON_Extrusion_BrepForm_FaceInfo()
02183 {
02184
02185 if ( 0 != m_extrusion_srf )
02186 {
02187
02188
02189 m_extrusion_profile = 0;
02190 delete m_extrusion_srf;
02191 m_extrusion_srf = 0;
02192 }
02193
02194 if ( 0 != m_extrusion_profile )
02195 {
02196 delete m_extrusion_profile;
02197 m_extrusion_profile = 0;
02198 }
02199
02200 if ( m_cap_c2[0] )
02201 {
02202 delete m_cap_c2[0];
02203 m_cap_c2[0] = 0;
02204 }
02205
02206 if ( m_cap_c2[1] )
02207 {
02208 delete m_cap_c2[1];
02209 m_cap_c2[1] = 0;
02210 }
02211
02212 memset(this,0,sizeof(*this));
02213 }
02214
02215 bool ON_Extrusion_BrepForm_FaceInfo::HaveBrepFaceFace() const
02216 {
02217 if ( m_face_index < 0 )
02218 return false;
02219 return true;
02220 }
02221
02222 void ON_Extrusion_BrepForm_FaceInfo::Init()
02223 {
02224 memset(this,0,sizeof(*this));
02225
02226 m_bClosedProfile = false;
02227 m_profile_orientation = 0;
02228 m_profile_index = -1;
02229
02230 m_extrusion_profile = 0;
02231 m_extrusion_srf = 0;
02232 m_face_index = -1;
02233 m_vid[0] = m_vid[1] = m_vid[2] = m_vid[3] = -1;
02234 m_eid[0] = m_eid[1] = m_eid[2] = m_eid[3] = -1;
02235
02236
02237 m_bRev3d[0] = m_bRev3d[1] = 0;
02238 m_bRev3d[2] = m_bRev3d[3] = 1;
02239
02240 m_cap_trim_index[0] = m_cap_trim_index[1] = -1;
02241 m_cap_edge_index[0] = m_cap_edge_index[1] = -1;
02242 m_cap_c2[0] = m_cap_c2[1] = 0;
02243 }
02244
02245 ON_Brep* ON_Extrusion::BrepForm( ON_Brep* brep ) const
02246 {
02247 return BrepForm(brep,true);
02248 }
02249
02250 static
02251 ON_PlaneSurface* MakeCapPlaneHelper(
02252 ON_ClassArray< ON_Extrusion_BrepForm_FaceInfo >& finfo,
02253 int cap_index,
02254 const ON_Xform& rot
02255 )
02256 {
02257 double d;
02258 ON_BoundingBox bbox;
02259
02260
02261 int outer_loop_trim_count = 0;
02262 int outer_loop_iso_trim_count = 0;
02263 for ( int i = 0; i < finfo.Count(); i++ )
02264 {
02265 if ( false == finfo[i].HaveBrepFaceFace() )
02266 continue;
02267
02268 if ( 0 != finfo[i].m_profile_index )
02269 {
02270
02271
02272 break;
02273 }
02274 const ON_NurbsCurve* c2 = finfo[i].m_cap_c2[cap_index];
02275 if ( 0 == c2 )
02276 return 0;
02277 ON_BoundingBox c2bbox;
02278 c2->GetTightBoundingBox( c2bbox, false );
02279 if ( 0 == i )
02280 bbox = c2bbox;
02281 else
02282 bbox.Union(c2bbox);
02283 if ( outer_loop_iso_trim_count == outer_loop_trim_count )
02284 {
02285
02286 ON_3dVector D = c2bbox.Diagonal();
02287 double zero_tol = ON_ZERO_TOLERANCE;
02288 double nonzero_tol = 1000.0*ON_ZERO_TOLERANCE;
02289 if ( (D.x <= zero_tol && D.y > nonzero_tol)
02290 || (D.y <= zero_tol && D.x > nonzero_tol)
02291 )
02292 {
02293 outer_loop_iso_trim_count++;
02294 }
02295 }
02296 outer_loop_trim_count++;
02297 }
02298
02299 if ( outer_loop_trim_count <= 0 )
02300 {
02301
02302 return 0;
02303 }
02304
02305 ON_Interval u(bbox.m_min.x,bbox.m_max.x);
02306 ON_Interval v(bbox.m_min.y,bbox.m_max.y);
02307
02308 if ( outer_loop_iso_trim_count < outer_loop_trim_count
02309 || !u.IsIncreasing()
02310 || !v.IsIncreasing()
02311 )
02312 {
02313
02314 d = u.Length();
02315 if ( 0.0 == d )
02316 d = 1.0;
02317 d *= 0.125; u.m_t[0] -= d; u.m_t[1] += d;
02318
02319 d = v.Length();
02320 if ( 0.0 == d )
02321 d = 1.0;
02322 d *= 0.125; v.m_t[0] -= d; v.m_t[1] += d;
02323 }
02324
02325 if ( !u.IsIncreasing() || !v.IsIncreasing() )
02326 return 0;
02327
02328 ON_PlaneSurface* plane = new ON_PlaneSurface(ON_xy_plane);
02329 plane->SetExtents(0,u,true);
02330 plane->SetExtents(1,v,true);
02331 if ( !rot.IsIdentity() )
02332 plane->Transform(rot);
02333
02334 return plane;
02335 }
02336
02337 static
02338 int MakeCapLoopHelper(
02339 ON_ClassArray< ON_Extrusion_BrepForm_FaceInfo >& finfo,
02340 int fi0,
02341 int cap_index,
02342 ON_BrepFace* capface,
02343 ON_BrepLoop::TYPE loop_type,
02344 bool* bTrimsWereModified
02345 )
02346 {
02347 ON_BrepEdge* edge;
02348
02349 if ( 0 == capface )
02350 return fi0;
02351
02352 ON_Brep* brep = capface->Brep();
02353 if ( 0 == brep )
02354 return fi0;
02355
02356 if ( fi0 < 0 || fi0 >= finfo.Count() )
02357 return fi0;
02358
02359 ON_BrepLoop& loop = brep->NewLoop(loop_type,*capface);
02360
02361 bool bRev3d = false;
02362 bool bCloseGaps = true;
02363
02364 int fi1;
02365 for ( fi1 = fi0; fi1 < finfo.Count(); fi1++ )
02366 {
02367 if ( false == finfo[fi1].HaveBrepFaceFace() )
02368 continue;
02369
02370 if ( finfo[fi0].m_profile_index != finfo[fi1].m_profile_index )
02371 break;
02372
02373 ON_NurbsCurve* c2 = finfo[fi1].m_cap_c2[cap_index];
02374 if ( 0 == c2 )
02375 {
02376 bCloseGaps = false;
02377 break;
02378 }
02379 int c2i = brep->AddTrimCurve(c2);
02380 finfo[fi1].m_cap_c2[cap_index] = 0;
02381 edge = brep->Edge(finfo[fi1].m_cap_edge_index[cap_index]);
02382 if ( 0 == edge )
02383 {
02384 bCloseGaps = false;
02385 break;
02386 }
02387 ON_BrepTrim& trim = brep->NewTrim(*edge, bRev3d, loop, c2i);
02388 trim.m_tolerance[0] = trim.m_tolerance[1] = 0.0;
02389 }
02390 brep->SetTrimIsoFlags( loop );
02391
02392
02393
02394
02395
02396
02397 if ( bCloseGaps ) for ( int lti = 0; lti < loop.m_ti.Count(); lti++ )
02398 {
02399 ON_BrepTrim& trim0 = brep->m_T[loop.m_ti[lti]];
02400 ON_BrepTrim& trim1 = brep->m_T[loop.m_ti[(lti+1)%loop.m_ti.Count()]];
02401 if ( trim0.PointAtEnd() != trim1.PointAtStart() )
02402 {
02403 if ( brep->CloseTrimGap(trim0,trim1) )
02404 {
02405 edge = trim0.Edge();
02406 if ( edge )
02407 edge->m_tolerance = ON_UNSET_VALUE;
02408 edge = trim1.Edge();
02409 if ( edge )
02410 edge->m_tolerance = ON_UNSET_VALUE;
02411 if ( 0 != bTrimsWereModified )
02412 *bTrimsWereModified = true;
02413 }
02414 }
02415 }
02416
02417 return fi1;
02418 }
02419
02420 static
02421 bool MakeCap2dCurvesHelper(
02422 ON_ClassArray< ON_Extrusion_BrepForm_FaceInfo >& finfo,
02423 int is_capped,
02424 const ON_Xform& scale0,
02425 const ON_Xform& scale1
02426 )
02427 {
02428 switch(is_capped)
02429 {
02430 case 1:
02431 case 2:
02432 case 3:
02433 break;
02434 default:
02435 return false;
02436 }
02437
02438 for ( int i = 0; i < finfo.Count(); i++ )
02439 {
02440 ON_NurbsCurve* c20 = 0;
02441 ON_NurbsCurve* c21 = 0;
02442
02443 if ( false == finfo[i].HaveBrepFaceFace() )
02444 continue;
02445
02446 c20 = finfo[i].m_extrusion_srf->m_profile->NurbsCurve();
02447 if ( 0 == c20 )
02448 return false;
02449
02450 c20->ChangeDimension(2);
02451 c20->MakePiecewiseBezier(true);
02452 if ( 2 == is_capped )
02453 {
02454 c21 = c20;
02455 c20 = 0;
02456 }
02457 else if ( 3 == is_capped )
02458 {
02459 c21 = c20->Duplicate();
02460 }
02461
02462 if ( 0 != c20 && !scale0.IsIdentity() )
02463 c20->Transform(scale0);
02464 if ( 0 != c21 && !scale1.IsIdentity() )
02465 c21->Transform(scale1);
02466
02467 finfo[i].m_cap_c2[0] = c20;
02468 finfo[i].m_cap_c2[1] = c21;
02469 }
02470
02471 return true;
02472 }
02473
02474
02475 static bool GetNextProfileSegmentDiscontinuity(
02476 const ON_Curve* profile_segment,
02477 double t0,
02478 double t1,
02479 double *t
02480 )
02481 {
02482
02483
02484 if ( 0 == profile_segment )
02485 return false;
02486 return profile_segment->GetNextDiscontinuity(
02487 ON::Gsmooth_continuous,
02488 t0,t1,t,
02489 0,0,
02490 ON_DEFAULT_ANGLE_TOLERANCE_COSINE,
02491 ON_SQRT_EPSILON
02492 );
02493 }
02494
02495
02496 bool ON_Extrusion::ProfileIsKinked( int profile_index ) const
02497 {
02498 const ON_Curve* profile = Profile(profile_index);
02499 if ( 0 == profile )
02500 return false;
02501 double t0 = ON_UNSET_VALUE;
02502 double t1 = ON_UNSET_VALUE;
02503 double t;
02504 if ( !profile->GetDomain(&t0,&t1) )
02505 return 0;
02506 if ( !ON_IsValid(t0) || !(t0 < t1) )
02507 return 0;
02508 t = t0;
02509 return (GetNextProfileSegmentDiscontinuity( profile, t0,t1, &t) && t0 < t && t < t1);
02510 }
02511
02512 int ON_Extrusion::ProfileSmoothSegmentCount( int profile_index ) const
02513 {
02514 if ( 0 == Profile(profile_index) )
02515 return 0;
02516 ON_SimpleArray<double> * k = 0;
02517 return (1 + GetProfileKinkParameters(profile_index,*k));
02518 }
02519
02520 int ON_Extrusion::GetProfileKinkParameters( int profile_index, ON_SimpleArray<double>& profile_kink_parameters ) const
02521 {
02522 const ON_Curve* profile2d = Profile(profile_index);
02523 if ( 0 == profile2d )
02524 return 0;
02525 double t0 = ON_UNSET_VALUE;
02526 double t1 = ON_UNSET_VALUE;
02527 double t;
02528 if ( !profile2d->GetDomain(&t0,&t1) )
02529 return 0;
02530 if ( !ON_IsValid(t0) || !(t0 < t1) )
02531 return 0;
02532 ON_SimpleArray<double> * k = &profile_kink_parameters;
02533 int count = 0;
02534 while ( GetNextProfileSegmentDiscontinuity( profile2d, t0,t1, &t) )
02535 {
02536 if ( t0 < t && t < t1 )
02537 {
02538 if ( 0 != k )
02539 {
02540 k->Append(t);
02541 count++;
02542 }
02543 t0 = t;
02544 }
02545 }
02546 return count;
02547 }
02548
02549
02550 ON_Brep* ON_Extrusion::BrepForm( ON_Brep* brep, bool bSmoothFaces ) const
02551 {
02552 if ( brep )
02553 brep->Destroy();
02554
02555 ON_SimpleArray<const ON_Curve*> profile_curves;
02556 const int profile_count = GetProfileCurves(profile_curves );
02557 if ( profile_count < 1 || profile_count != profile_curves.Count() )
02558 return 0;
02559
02560
02561
02562 const ON_3dVector T = m_path.Tangent();
02563 if ( !T.IsUnitVector() )
02564 return 0;
02565
02566 ON_Xform xform0(1.0), xform1(1.0), scale0(1.0), scale1(1.0), rot0(1.0), rot1(1.0);
02567 if ( !ON_GetEndCapTransformation(m_path.PointAt(m_t.m_t[0]),T,m_up,m_bHaveN[0]?&m_N[0]:0,xform0,&scale0,&rot0) )
02568 return 0;
02569
02570 if ( !ON_GetEndCapTransformation(m_path.PointAt(m_t.m_t[1]),T,m_up,m_bHaveN[1]?&m_N[1]:0,xform1,&scale1,&rot1) )
02571 return 0;
02572
02573 ON_Brep* newbrep = brep ? brep : ON_Brep::New();
02574
02575 if ( 0 == newbrep )
02576 return 0;
02577
02578 int is_capped = IsCapped();
02579 if ( is_capped < 0 || is_capped > 3 )
02580 is_capped = 0;
02581
02582 int cap_count = (3==is_capped) ? 2 : (0 != is_capped ? 1 : 0);
02583
02584 newbrep->m_S.Reserve(profile_count + cap_count);
02585 newbrep->m_F.Reserve(profile_count + cap_count);
02586 newbrep->m_L.Reserve((1 + cap_count)*profile_count);
02587
02588
02589
02590
02591
02592 newbrep->m_C2.Reserve((4 + cap_count)*profile_count);
02593 newbrep->m_T.Reserve((4 + cap_count)*profile_count);
02594 newbrep->m_C3.Reserve(4*profile_count);
02595 newbrep->m_E.Reserve(4*profile_count);
02596
02597
02598 int vidmap[4] = {0,1,2,3};
02599 int eidmap[4] = {0,1,2,3};
02600 if ( m_bTransposed )
02601 {
02602 vidmap[1] = 3;
02603 vidmap[3] = 1;
02604 eidmap[0] = 3;
02605 eidmap[1] = 2;
02606 eidmap[2] = 1;
02607 eidmap[3] = 0;
02608 }
02609
02610 int fi0, fi1;
02611
02612 ON_ClassArray< ON_Extrusion_BrepForm_FaceInfo > finfo(2*profile_count);
02613 for ( int profile_index = 0; profile_index < profile_count; profile_index++ )
02614 {
02615 const ON_Curve* profile_segment = profile_curves[profile_index];
02616 if ( 0 == profile_segment )
02617 {
02618 if (newbrep != brep )
02619 delete newbrep;
02620 return 0;
02621 }
02622
02623 fi0 = finfo.Count();
02624 ON_Extrusion_BrepForm_FaceInfo profile_fi;
02625 profile_fi.Init();
02626 {
02627 ON_Curve* newprofile = profile_segment->DuplicateCurve();
02628 if ( 0 == newprofile )
02629 {
02630 if (newbrep != brep )
02631 delete newbrep;
02632 return 0;
02633 }
02634
02635 profile_fi.m_bClosedProfile = newprofile->IsClosed() ? true : false;
02636 profile_fi.m_profile_orientation = ( profile_fi.m_bClosedProfile )
02637 ? ON_ClosedCurveOrientation(*newprofile,0)
02638 : 0;
02639
02640 if ( is_capped && profile_fi.m_profile_orientation != ((0==profile_index) ? 1 : -1) )
02641 {
02642
02643 is_capped = 0;
02644 cap_count = 0;
02645 }
02646
02647 if ( bSmoothFaces )
02648 {
02649
02650
02651
02652
02653 double t0 = ON_UNSET_VALUE;
02654 double t1 = ON_UNSET_VALUE;
02655 if ( !profile_segment->GetDomain(&t0,&t1)
02656 || !ON_IsValid(t0)
02657 || !ON_IsValid(t1)
02658 || !(t0 < t1)
02659 )
02660 {
02661 delete newprofile;
02662 if (newbrep != brep )
02663 delete newbrep;
02664 return 0;
02665 }
02666 double t = t1;
02667 while ( GetNextProfileSegmentDiscontinuity(profile_segment,t0,t1,&t) )
02668 {
02669 if ( t0 < t && t < t1 )
02670 {
02671 ON_Curve* left_side = 0;
02672 ON_Curve* right_side = 0;
02673 if ( newprofile->Split(t,left_side,right_side)
02674 && 0 != left_side
02675 && 0 != right_side
02676 )
02677 {
02678 finfo.AppendNew().m_extrusion_profile = left_side;
02679 left_side = 0;
02680 delete newprofile;
02681 newprofile = right_side;
02682 right_side = 0;
02683 t0 = t;
02684 t = t1;
02685 continue;
02686 }
02687 if ( 0 != left_side )
02688 delete left_side;
02689 if ( 0 != right_side )
02690 delete right_side;
02691 }
02692 break;
02693 }
02694 }
02695 finfo.AppendNew().m_extrusion_profile = newprofile;
02696 }
02697
02698 fi1 = finfo.Count();
02699
02700 if ( fi1 <= fi0 )
02701 {
02702 if (newbrep != brep )
02703 delete newbrep;
02704 return 0;
02705 }
02706
02707 for ( int finfo_index = fi0; finfo_index < fi1; finfo_index++ )
02708 {
02709
02710
02711 ON_Extrusion_BrepForm_FaceInfo& fi = finfo[finfo_index];
02712 fi.m_face_index = -1;
02713
02714 fi.m_extrusion_srf = new ON_Extrusion();
02715 fi.m_extrusion_srf->m_path = m_path;
02716 fi.m_extrusion_srf->m_t = m_t;
02717 fi.m_extrusion_srf->m_up = m_up;
02718 fi.m_extrusion_srf->m_profile_count = 1;
02719 fi.m_extrusion_srf->m_profile = fi.m_extrusion_profile;
02720 fi.m_extrusion_srf->m_bCap[0] = false;
02721 fi.m_extrusion_srf->m_bCap[1] = false;
02722 fi.m_extrusion_srf->m_bHaveN[0] = m_bHaveN[0];
02723 fi.m_extrusion_srf->m_bHaveN[1] = m_bHaveN[1];
02724 fi.m_extrusion_srf->m_N[0] = m_N[0];
02725 fi.m_extrusion_srf->m_N[1] = m_N[1];
02726 fi.m_extrusion_srf->m_path_domain = m_path_domain;
02727 fi.m_extrusion_srf->m_bTransposed = m_bTransposed;
02728
02729 fi.m_profile_index = profile_index;
02730 fi.m_bClosedProfile = profile_fi.m_bClosedProfile;
02731 fi.m_profile_orientation = profile_fi.m_profile_orientation;
02732
02733
02734
02735
02736 fi.m_vid[vidmap[0]] = profile_fi.m_vid[vidmap[1]];
02737 fi.m_vid[vidmap[3]] = profile_fi.m_vid[vidmap[2]];
02738 fi.m_eid[eidmap[3]] = profile_fi.m_eid[eidmap[1]];
02739 if ( fi.m_eid[eidmap[3]] >= 0 )
02740 fi.m_bRev3d[eidmap[3]] = (profile_fi.m_bRev3d[eidmap[1]]) ? false : true;
02741
02742 if ( profile_fi.m_bClosedProfile
02743 && finfo_index > fi0
02744 && finfo_index == fi1 - 1
02745 )
02746 {
02747
02748
02749
02750
02751 fi.m_vid[vidmap[1]] = profile_fi.m_vid[vidmap[0]];
02752 fi.m_vid[vidmap[2]] = profile_fi.m_vid[vidmap[3]];
02753 fi.m_eid[eidmap[1]] = profile_fi.m_eid[eidmap[3]];
02754 if ( fi.m_eid[eidmap[1]] >= 0 )
02755 fi.m_bRev3d[eidmap[1]] = (profile_fi.m_bRev3d[eidmap[3]]) ? false : true;
02756 }
02757
02758
02759 ON_NurbsSurface* face_srf = fi.m_extrusion_srf->NurbsSurface();
02760 if ( 0 == face_srf )
02761 {
02762 continue;
02766 }
02767
02768 const ON_BrepFace* face = newbrep->NewFace(face_srf,fi.m_vid,fi.m_eid,fi.m_bRev3d);
02769 if ( 0 == face )
02770 {
02771
02772 delete face_srf;
02773
02774
02775
02776
02777
02778 continue;
02782 }
02783 fi.m_face_index = face->m_face_index;
02784
02785
02786
02787 if ( finfo_index == fi0 )
02788 {
02789 profile_fi.m_vid[vidmap[0]] = fi.m_vid[vidmap[0]];
02790 profile_fi.m_vid[vidmap[3]] = fi.m_vid[vidmap[3]];
02791 profile_fi.m_eid[eidmap[3]] = fi.m_eid[eidmap[3]];
02792 profile_fi.m_bRev3d[eidmap[3]] = fi.m_bRev3d[eidmap[3]];
02793 }
02794 profile_fi.m_vid[vidmap[1]] = fi.m_vid[vidmap[1]];
02795 profile_fi.m_vid[vidmap[2]] = fi.m_vid[vidmap[2]];
02796 profile_fi.m_eid[eidmap[1]] = fi.m_eid[eidmap[1]];
02797 profile_fi.m_bRev3d[eidmap[1]] = fi.m_bRev3d[eidmap[1]];
02798
02799 if ( 0 == is_capped )
02800 continue;
02801
02802 const ON_BrepLoop* loop = (1 == face->LoopCount()) ? face->OuterLoop() : 0;
02803 if ( 0 == loop || 4 != loop->TrimCount() )
02804 {
02805 is_capped = 0;
02806 cap_count = 0;
02807 continue;
02808 }
02809
02810 const ON_BrepTrim* bottom_trim = loop->Trim(eidmap[0]);
02811 if ( 0 == bottom_trim || ON_BrepTrim::boundary != bottom_trim->m_type )
02812 {
02813 is_capped = 0;
02814 cap_count = 0;
02815 continue;
02816 }
02817
02818 const ON_BrepTrim* top_trim = loop->Trim(eidmap[2]);
02819 if ( 0 == top_trim || ON_BrepTrim::boundary != top_trim->m_type )
02820 {
02821 is_capped = 0;
02822 cap_count = 0;
02823 continue;
02824 }
02825
02826 const ON_BrepEdge* edge0 = bottom_trim->Edge();
02827 const ON_BrepEdge* edge1 = top_trim->Edge();
02828 if ( 0 == edge0 || 0 == edge1 )
02829 {
02830 is_capped = 0;
02831 cap_count = 0;
02832 continue;
02833 }
02834 fi.m_cap_trim_index[0] = bottom_trim->m_trim_index;
02835 fi.m_cap_trim_index[1] = top_trim->m_trim_index;
02836 fi.m_cap_edge_index[0] = edge0->m_edge_index;
02837 fi.m_cap_edge_index[1] = edge1->m_edge_index;
02838 }
02839 }
02840
02841
02842 bool bSetEdgeTolerances = false;
02843
02844 while ( is_capped > 0 && cap_count == ((3 == is_capped) ? 2 : 1) )
02845 {
02846
02847
02848
02849
02850 if ( !MakeCap2dCurvesHelper(finfo,is_capped,scale0,scale1) )
02851 break;
02852
02853 newbrep->m_S.Reserve(newbrep->m_S.Count()+cap_count);
02854 newbrep->m_F.Reserve(newbrep->m_F.Count()+cap_count);
02855 ON_BrepFace* capface0 = 0;
02856 ON_BrepFace* capface1 = 0;
02857 {
02858 ON_PlaneSurface* plane = 0;
02859 int si;
02860 if ( 3 == is_capped || 1 == is_capped )
02861 {
02862
02863 plane = MakeCapPlaneHelper( finfo, 0, rot0 );
02864 if ( plane )
02865 {
02866 si = newbrep->AddSurface(plane);
02867 plane = 0;
02868 capface0 = &newbrep->NewFace(si);
02869 capface0->m_bRev = m_bTransposed ? false : true;
02870 }
02871 }
02872 if ( 3 == is_capped || 2 == is_capped )
02873 {
02874
02875 plane = MakeCapPlaneHelper( finfo, 1, rot1 );
02876 if ( plane )
02877 {
02878 si = newbrep->AddSurface(plane);
02879 plane = 0;
02880 capface1 = &newbrep->NewFace(si);
02881 capface1->m_bRev = m_bTransposed ? true : false;
02882 }
02883 }
02884 }
02885
02886 if ( 0 == capface0 && 0 == capface1 )
02887 break;
02888
02889 newbrep->m_C2.Reserve(newbrep->m_C2.Count()+cap_count*finfo.Count());
02890 newbrep->m_L.Reserve(newbrep->m_L.Count()+cap_count*profile_count);
02891 newbrep->m_T.Reserve(newbrep->m_T.Count()+cap_count*finfo.Count());
02892
02893 int cap_index = 0;
02894 for ( cap_index = 0; cap_index < 2; cap_index++ )
02895 {
02896
02897
02898
02899
02900
02901 ON_BrepFace* capface = ( 0 == cap_index ) ? capface0 : capface1;
02902 if ( 0 == capface )
02903 continue;
02904
02905 fi0 = 0;
02906 int profile_index;
02907 for ( profile_index = 0; profile_index < profile_count && fi0 < finfo.Count(); profile_index++ )
02908 {
02909 if ( finfo[fi0].m_profile_index != profile_index )
02910 break;
02911 ON_BrepLoop::TYPE loop_type = ( 0 == profile_index ) ? ON_BrepLoop::outer : ON_BrepLoop::inner;
02912 fi1 = MakeCapLoopHelper(finfo,fi0,cap_index,capface,loop_type,&bSetEdgeTolerances);
02913 if ( fi1 <= fi0 )
02914 break;
02915 fi0 = fi1;
02916 }
02917
02918 if ( fi0 != finfo.Count() || profile_index != profile_count )
02919 {
02920 ON_ERROR("Failed to add caps to extrusion brep form.");
02921 if ( 0 != capface0 )
02922 newbrep->DeleteFace(*capface0,false);
02923 if ( 0 != capface1 )
02924 newbrep->DeleteFace(*capface1,false);
02925 newbrep->Compact();
02926 break;
02927 }
02928 }
02929
02930 if ( 2 == cap_index && 2 == cap_count && 3 == is_capped )
02931 ((CMyBrepIsSolidSetter*)newbrep)->SetIsSolid(m_bTransposed?2:1);
02932
02933 break;
02934 }
02935
02936 if ( newbrep )
02937 {
02938
02939 ((CMyBrepIsSolidSetter*)newbrep)->SetBBox(*this);
02940 newbrep->SetTrimBoundingBoxes(true);
02941
02942 if ( bSetEdgeTolerances )
02943 newbrep->SetEdgeTolerances(true);
02944 }
02945
02946 #if defined(ON_DEBUG)
02947 if ( !newbrep->IsValid() )
02948 {
02949 newbrep->IsValid();
02950 }
02951 #endif
02952
02953 return newbrep;
02954 }
02955
02956 bool ON_Extrusion::GetBrepFormComponentIndex(
02957 ON_COMPONENT_INDEX extrusion_ci,
02958 ON_COMPONENT_INDEX& brep_ci
02959 ) const
02960 {
02961 const ON_Brep* null_brep_pointer = 0;
02962 return GetBrepFormComponentIndex(extrusion_ci,ON_UNSET_VALUE,*null_brep_pointer,brep_ci);
02963 }
02964
02965 static bool GetBrepFormFaceIndex(
02966 const ON_Extrusion& extrusion,
02967 int extrusion_profile_index,
02968 double extrusion_profile_parameter,
02969 bool bCountProfileDiscontinuities,
02970 int* brep_form_face_index,
02971 ON_Interval* profile_segment_domain
02972 )
02973 {
02974
02975
02976
02977 int profile_segment_count = 0;
02978 const int profile_count = extrusion.ProfileCount();
02979 double t0 = ON_UNSET_VALUE;
02980 double t1 = ON_UNSET_VALUE;
02981 const ON_Curve* profile;
02982 if ( ON_UNSET_VALUE == extrusion_profile_parameter )
02983 {
02984 if ( extrusion_profile_index != profile_count )
02985 {
02986 profile = extrusion.Profile(extrusion_profile_index);
02987 if ( 0 == profile
02988 || !profile->GetDomain(&t0,&t1)
02989 || !ON_IsValid(t0)
02990 || !ON_IsValid(t1)
02991 || !(t0 < t1)
02992 )
02993 {
02994 return false;
02995 }
02996 }
02997 profile_segment_count = extrusion_profile_index;
02998 }
02999 else
03000 {
03001 for ( int i = 0; i < profile_count; i++ )
03002 {
03003 profile = extrusion.Profile(i);
03004 if ( 0 == profile )
03005 return false;
03006
03007
03008
03009
03010 if ( 0 == profile
03011 || !profile->GetDomain(&t0,&t1)
03012 || !ON_IsValid(t0)
03013 || !ON_IsValid(t1)
03014 || !(t0 < t1)
03015 )
03016 {
03017 return false;
03018 }
03019
03020 double t = t1;
03021 if ( bCountProfileDiscontinuities )
03022 {
03023 while ( GetNextProfileSegmentDiscontinuity(profile,t0,t1,&t) )
03024 {
03025 if ( t0 < t && t < t1 )
03026 {
03027 if ( i == extrusion_profile_index
03028 && t0 <= extrusion_profile_parameter
03029 && extrusion_profile_parameter < t
03030 )
03031 {
03032 break;
03033 }
03034 t0 = t;
03035 t = t1;
03036 profile_segment_count++;
03037 continue;
03038 }
03039 break;
03040 }
03041 }
03042 if ( i == extrusion_profile_index )
03043 break;
03044 profile_segment_count++;
03045 }
03046 }
03047
03048 if ( 0 != brep_form_face_index )
03049 *brep_form_face_index = profile_segment_count;
03050
03051 if ( 0 != profile_segment_domain && extrusion_profile_index < profile_count )
03052 profile_segment_domain->Set(t0,t1);
03053
03054 return true;
03055 }
03056
03057 bool ON_Extrusion::GetBrepFormComponentIndex(
03058 ON_COMPONENT_INDEX extrusion_ci,
03059 double extrusion_profile_parameter,
03060 const ON_Brep& brep_form,
03061 ON_COMPONENT_INDEX& brep_ci
03062 ) const
03063 {
03064 brep_ci.UnSet();
03065 int face_index = -1;
03066 ON_Interval face_profile_domain(ON_UNSET_VALUE,ON_UNSET_VALUE);
03067 const ON_Brep* brep = &brep_form;
03068
03069 const int is_capped = IsCapped();
03070 if ( is_capped < 0 || is_capped > 3 )
03071 return false;
03072 const int profile_count = ProfileCount();
03073 if ( profile_count < 1 )
03074 return false;
03075 const ON_Curve* profile0 = Profile(0);
03076 if ( 0 == profile0 )
03077 return false;
03078 const bool bClosedProfile = profile0->IsClosed() ? true : false;
03079 if ( profile_count > 1 && !bClosedProfile )
03080 return false;
03081 const int edges_per_wall_face = bClosedProfile ? 3 : 4;
03082 const int cap_count = (0 == is_capped || !bClosedProfile) ? 0 : ((3==is_capped)?2:1);
03083 int brep_face_count = ( 0 != brep ) ? brep->m_F.Count() : 0;
03084 if ( 0 != brep && brep_face_count < profile_count + cap_count )
03085 {
03086 ON_ERROR("brep_form parameter cannot be extrusion's BrepForm()");
03087 return false;
03088 }
03089 bool bCountProfileDiscontinuities = ( brep_face_count > profile_count + cap_count );
03090
03091 switch(extrusion_ci.m_type)
03092 {
03093 case ON_COMPONENT_INDEX::extrusion_bottom_profile:
03094 case ON_COMPONENT_INDEX::extrusion_top_profile:
03095 if ( extrusion_ci.m_index < 0 || extrusion_ci.m_index >= profile_count )
03096 return false;
03097 if ( !GetBrepFormFaceIndex( *this, extrusion_ci.m_index, extrusion_profile_parameter, bCountProfileDiscontinuities, &face_index, &face_profile_domain ) )
03098 return false;
03099 brep_ci.m_index = edges_per_wall_face*face_index;
03100 if ( ON_COMPONENT_INDEX::extrusion_top_profile == extrusion_ci.m_type )
03101 brep_ci.m_index += 2;
03102 brep_ci.m_type = ON_COMPONENT_INDEX::brep_edge;
03103 break;
03104
03105 case ON_COMPONENT_INDEX::extrusion_wall_edge:
03106 if ( extrusion_ci.m_index < 0 || extrusion_ci.m_index >= 2*profile_count )
03107 return false;
03108 if ( !GetBrepFormFaceIndex( *this, extrusion_ci.m_index/2, extrusion_profile_parameter, bCountProfileDiscontinuities, &face_index, &face_profile_domain ) )
03109 return false;
03110 brep_ci.m_index = edges_per_wall_face*face_index+1;
03111 if ( !bClosedProfile && 1 == (face_index % 1) )
03112 brep_ci.m_index += 2;
03113 brep_ci.m_type = ON_COMPONENT_INDEX::brep_edge;
03114 break;
03115
03116 case ON_COMPONENT_INDEX::extrusion_wall_surface:
03117 if ( extrusion_ci.m_index < 0 || extrusion_ci.m_index >= profile_count )
03118 return false;
03119 if ( !GetBrepFormFaceIndex( *this, extrusion_ci.m_index, extrusion_profile_parameter, bCountProfileDiscontinuities, &face_index, &face_profile_domain ) )
03120 return false;
03121 brep_ci.m_index = face_index;
03122 brep_ci.m_type = ON_COMPONENT_INDEX::brep_face;
03123 break;
03124
03125 case ON_COMPONENT_INDEX::extrusion_cap_surface:
03126 if ( extrusion_ci.m_index < 0 || extrusion_ci.m_index > 2 )
03127 return false;
03128 if ( 1 == extrusion_ci.m_index && (is_capped != 1 && is_capped != 3) )
03129 return false;
03130 if ( 2 == extrusion_ci.m_index && (is_capped != 2 && is_capped != 3) )
03131 return false;
03132 if ( 0 != brep )
03133 {
03134 face_index = brep->m_F.Count()-cap_count;
03135 }
03136 else if ( !GetBrepFormFaceIndex( *this, profile_count, extrusion_profile_parameter, bCountProfileDiscontinuities, &face_index, &face_profile_domain ) )
03137 {
03138 return false;
03139 }
03140
03141 brep_ci.m_index = face_index+extrusion_ci.m_index-1;
03142 brep_ci.m_type = ON_COMPONENT_INDEX::brep_face;
03143 break;
03144
03145 case ON_COMPONENT_INDEX::extrusion_path:
03146
03147 break;
03148
03149 default:
03150
03151 break;
03152 }
03153
03154 if ( !brep_ci.IsBrepComponentIndex() )
03155 {
03156 brep_ci.UnSet();
03157 return false;
03158 }
03159
03160 return true;
03161 }
03162
03163 ON_BOOL32 ON_Extrusion::SetDomain(
03164 int dir,
03165 double t0,
03166 double t1
03167 )
03168 {
03169 bool rc = false;
03170 if ( ON_IsValid(t0) && ON_IsValid(t1) && t0 < t1 )
03171 {
03172 const int path_dir = PathParameter();
03173 if ( path_dir == dir )
03174 {
03175 m_path_domain.Set(t0,t1);
03176 rc = true;
03177 }
03178 else if ( 1-path_dir == dir )
03179 {
03180 rc = m_profile->SetDomain(t0,t1)?true:false;
03181 }
03182 }
03183 return rc;
03184 }
03185
03186 ON_Interval ON_Extrusion::Domain(
03187 int dir
03188 ) const
03189 {
03190 const int path_dir = PathParameter();
03191 return (path_dir == dir )
03192 ? m_path_domain
03193 : ((1-path_dir == dir && m_profile) ? m_profile->Domain() : ON_Interval());
03194 }
03195
03196 ON_BOOL32 ON_Extrusion::GetSurfaceSize(
03197 double* width,
03198 double* height
03199 ) const
03200 {
03201 bool rc = true;
03202
03203 if ( PathParameter() )
03204 {
03205 double* p = width;
03206 width = height;
03207 height = p;
03208 }
03209 if ( width )
03210 {
03211 if ( m_path.IsValid() && m_t.IsIncreasing() )
03212 *width = m_path.Length()*m_t.Length();
03213 else
03214 {
03215 *width = 0.0;
03216 rc = false;
03217 }
03218 }
03219 if (height)
03220 {
03221 if ( m_profile )
03222 {
03223
03224
03225
03226
03227
03228 ON_NurbsCurve nurbs_profile_curve;
03229 if ( m_profile->GetNurbForm(nurbs_profile_curve) <= 0 )
03230 {
03231 *height = 0.0;
03232 rc = false;
03233 }
03234 else
03235 {
03236 *height = nurbs_profile_curve.ControlPolygonLength();
03237 }
03238 }
03239 else
03240 {
03241 rc = false;
03242 *height = 0.0;
03243 }
03244 }
03245 return rc;
03246 }
03247
03248 int ON_Extrusion::SpanCount(
03249 int dir
03250 ) const
03251 {
03252 const int path_dir = PathParameter();
03253 if ( path_dir == dir )
03254 return 1;
03255 if ( 1-path_dir == dir && m_profile )
03256 return m_profile->SpanCount();
03257 return 0;
03258 }
03259
03260 ON_BOOL32 ON_Extrusion::GetSpanVector(
03261 int dir,
03262 double* span_vector
03263 ) const
03264 {
03265 if ( span_vector )
03266 {
03267 const int path_dir = PathParameter();
03268 if ( path_dir == dir )
03269 {
03270 span_vector[0] = m_path_domain[0];
03271 span_vector[1] = m_path_domain[1];
03272 return true;
03273 }
03274 if ( 1-path_dir == dir && m_profile )
03275 {
03276 return m_profile->GetSpanVector(span_vector);
03277 }
03278 }
03279 return false;
03280 }
03281
03282 ON_BOOL32 ON_Extrusion::GetSpanVectorIndex(
03283 int dir ,
03284 double t,
03285 int side,
03286 int* span_vector_index,
03287 ON_Interval* span_interval
03288 ) const
03289 {
03290 const int path_dir = PathParameter();
03291 if ( path_dir == dir )
03292 {
03293 if ( span_vector_index )
03294 *span_vector_index = 0;
03295 if ( span_interval )
03296 *span_interval = m_path_domain;
03297 return true;
03298 }
03299 if ( 1-path_dir == dir && m_profile )
03300 {
03301 return m_profile->GetSpanVectorIndex(t,side,span_vector_index,span_interval);
03302 }
03303 return false;
03304 }
03305
03306 int ON_Extrusion::Degree(
03307
03308 int dir
03309 ) const
03310 {
03311 const int path_dir = PathParameter();
03312 if ( path_dir == dir )
03313 return 1;
03314 if ( 1-path_dir == dir && m_profile )
03315 return m_profile->Degree();
03316 return 0;
03317 }
03318
03319 ON_BOOL32 ON_Extrusion::GetParameterTolerance(
03320 int dir,
03321 double t,
03322 double* tminus,
03323 double* tplus
03324 ) const
03325 {
03326 const int path_dir = PathParameter();
03327 if ( path_dir == dir )
03328 return ON_Surface::GetParameterTolerance(dir,t,tminus,tplus);
03329 if ( 1-path_dir==dir && m_profile)
03330 return m_profile->GetParameterTolerance(t,tminus,tplus);
03331 return false;
03332 }
03333
03334 ON_Surface::ISO ON_Extrusion::IsIsoparametric(
03335 const ON_Curve& curve,
03336 const ON_Interval* curve_domain
03337 ) const
03338 {
03339 return ON_Surface::IsIsoparametric(curve,curve_domain);
03340 }
03341
03342 ON_BOOL32 ON_Extrusion::IsPlanar(
03343 ON_Plane* plane,
03344 double tolerance
03345 ) const
03346 {
03347 if ( m_profile && m_profile->IsLinear(tolerance) )
03348 {
03349 if ( plane )
03350 {
03351 ON_3dPoint P0 = m_profile->PointAtStart();
03352 ON_3dPoint P1 = m_profile->PointAtEnd();
03353 ON_3dVector pathT = m_path.Tangent();
03354 ON_3dVector Y = m_up;
03355 ON_3dVector X = ON_CrossProduct(Y,pathT);
03356 if ( !X.IsUnitVector() )
03357 X.Unitize();
03358 ON_3dPoint Q0 = m_path.from + P0.x*X + P0.y*Y;
03359 ON_3dPoint Q1 = m_path.from + P1.x*X + P1.y*Y;
03360 ON_3dVector N = ON_CrossProduct(pathT,Q1-Q0);
03361 N.Unitize();
03362 plane->origin = Q0;
03363 if ( false == m_bTransposed )
03364 {
03365 plane->yaxis = pathT;
03366 plane->zaxis = -N;
03367 plane->xaxis = ON_CrossProduct(plane->yaxis,plane->zaxis);
03368 plane->xaxis.Unitize();
03369 }
03370 else
03371 {
03372 plane->xaxis = pathT;
03373 plane->zaxis = N;
03374 plane->yaxis = ON_CrossProduct(plane->zaxis,plane->xaxis);
03375 plane->yaxis.Unitize();
03376 }
03377 plane->UpdateEquation();
03378 }
03379 return true;
03380 }
03381 return false;
03382 }
03383
03384 ON_BOOL32 ON_Extrusion::IsClosed(int dir) const
03385 {
03386 const int path_dir = PathParameter();
03387 if ( 1-path_dir == dir && m_profile )
03388 return m_profile->IsClosed();
03389 return false;
03390 }
03391
03392 ON_BOOL32 ON_Extrusion::IsPeriodic( int dir ) const
03393 {
03394 const int path_dir = PathParameter();
03395 if ( 1-path_dir == dir && m_profile )
03396 return m_profile->IsPeriodic();
03397 return false;
03398 }
03399
03400 bool ON_Extrusion::GetNextDiscontinuity(
03401 int dir,
03402 ON::continuity c,
03403 double t0,
03404 double t1,
03405 double* t,
03406 int* hint,
03407 int* dtype,
03408 double cos_angle_tolerance,
03409 double curvature_tolerance
03410 ) const
03411 {
03412 const int path_dir = PathParameter();
03413 if ( path_dir == dir )
03414 {
03415 return ON_Surface::GetNextDiscontinuity(dir,c,t0,t1,t,hint,dtype,cos_angle_tolerance,curvature_tolerance);
03416 }
03417 if ( 1-path_dir==dir && m_profile)
03418 {
03419 return m_profile->GetNextDiscontinuity(c,t0,t1,t,hint,dtype,cos_angle_tolerance,curvature_tolerance);
03420 }
03421 return false;
03422 }
03423
03424 bool ON_Extrusion::IsContinuous(
03425 ON::continuity c,
03426 double s,
03427 double t,
03428 int* hint,
03429 double point_tolerance,
03430 double d1_tolerance,
03431 double d2_tolerance,
03432 double cos_angle_tolerance,
03433 double curvature_tolerance
03434 ) const
03435 {
03436 if ( !m_profile )
03437 return false;
03438 int* crv_hint = 0;
03439 double curvet;
03440 if ( m_bTransposed )
03441 {
03442 curvet = s;
03443 crv_hint = hint;
03444 }
03445 else
03446 {
03447 curvet = t;
03448 crv_hint = hint ? hint+1 : 0;
03449 }
03450 return m_profile->IsContinuous(c,curvet,crv_hint,point_tolerance,d1_tolerance,d2_tolerance,cos_angle_tolerance,curvature_tolerance);
03451 }
03452
03453 ON_Surface::ISO ON_Extrusion::IsIsoparametric(
03454 const ON_BoundingBox& bbox
03455 ) const
03456 {
03457 return ON_Surface::IsIsoparametric(bbox);
03458 }
03459
03460 ON_BOOL32 ON_Extrusion::Reverse( int dir )
03461 {
03462 if ( 0 == m_profile )
03463 return false;
03464
03465 const int path_dir = PathParameter();
03466
03467 if ( path_dir == dir )
03468 {
03469 m_path_domain.Reverse();
03470 m_path.Reverse();
03471
03472
03473
03474
03475
03476
03477
03478
03479
03480
03481
03482
03483
03484 ON_Xform profile_xform(1.0);
03485 profile_xform.m_xform[0][0] = -1.0;
03486 bool bNeedReverse = false;
03487 return Profile2dTransform(*this,profile_xform,bNeedReverse);
03488 }
03489
03490 if ( 1-path_dir == dir )
03491 {
03492 return m_profile->Reverse();
03493
03494
03495
03496
03497
03498
03499
03500
03501
03502
03503
03504 }
03505
03506 return false;
03507 }
03508
03509 ON_BOOL32 ON_Extrusion::Transpose()
03510 {
03511 m_bTransposed = m_bTransposed?false:true;
03512 return true;
03513 }
03514
03515 ON_BOOL32 ON_Extrusion::Evaluate(
03516 double u, double v,
03517 int num_der,
03518 int array_stride,
03519 double* der_array,
03520 int quadrant ,
03521
03522
03523
03524
03525
03526 int* hint
03527
03528 ) const
03529 {
03530 if ( !m_profile )
03531 return false;
03532
03533 double x,y,dx,dy;
03534
03535 if ( m_bTransposed )
03536 {
03537 x = u; u = v; v = x;
03538 if ( 4 == quadrant )
03539 quadrant = 2;
03540 else if ( 2 == quadrant )
03541 quadrant = 4;
03542 }
03543
03544 if ( !m_profile->Evaluate( u, num_der, array_stride, der_array,
03545 (1==quadrant||4==quadrant)?1:((2==quadrant||3==quadrant)?-1:0),
03546 hint)
03547 )
03548 {
03549 return false;
03550 }
03551
03552
03553
03554
03555 const double t1 = m_path_domain.NormalizedParameterAt(v);
03556 const double t0 = 1.0-t1;
03557 ON_Xform xform0, xform1;
03558 const ON_3dVector T = m_path.Tangent();
03559 if ( 0.0 != t0 || num_der > 0 )
03560 {
03561 if ( !ON_GetEndCapTransformation(m_path.PointAt(m_t.m_t[0]),T,m_up,m_bHaveN[0]?&m_N[0]:0,xform0,0,0) )
03562 return false;
03563 }
03564 else
03565 {
03566 xform0.Zero();
03567 }
03568 if ( 0.0 != t1 || num_der > 0 )
03569 {
03570 if ( !ON_GetEndCapTransformation(m_path.PointAt(m_t.m_t[1]),T,m_up,m_bHaveN[1]?&m_N[1]:0,xform1,0,0) )
03571 return false;
03572 }
03573 else
03574 {
03575 xform1.Zero();
03576 }
03577
03578 double xformP[3][3], xformD[3][3];
03579 xformP[0][0] = t0*xform0.m_xform[0][0] + t1*xform1.m_xform[0][0];
03580 xformP[0][1] = t0*xform0.m_xform[0][1] + t1*xform1.m_xform[0][1];
03581 xformP[0][2] = t0*xform0.m_xform[0][3] + t1*xform1.m_xform[0][3];
03582 xformP[1][0] = t0*xform0.m_xform[1][0] + t1*xform1.m_xform[1][0];
03583 xformP[1][1] = t0*xform0.m_xform[1][1] + t1*xform1.m_xform[1][1];
03584 xformP[1][2] = t0*xform0.m_xform[1][3] + t1*xform1.m_xform[1][3];
03585 xformP[2][0] = t0*xform0.m_xform[2][0] + t1*xform1.m_xform[2][0];
03586 xformP[2][1] = t0*xform0.m_xform[2][1] + t1*xform1.m_xform[2][1];
03587 xformP[2][2] = t0*xform0.m_xform[2][3] + t1*xform1.m_xform[2][3];
03588
03589 int i,j;
03590 i = num_der+1;
03591 double* d1 = der_array + array_stride*(i*(i+1)/2 - 1);
03592 double* d0 = der_array + array_stride*(i - 1);
03593 x = d0[0];
03594 y = d0[1];
03595 if ( num_der > 0 )
03596 {
03597 double d = m_path_domain.m_t[1] - m_path_domain.m_t[0];
03598 if ( d > 0.0 )
03599 d = 1.0/d;
03600 xformD[0][0] = d*(xform1.m_xform[0][0] - xform0.m_xform[0][0]);
03601 xformD[0][1] = d*(xform1.m_xform[0][1] - xform0.m_xform[0][1]);
03602 xformD[0][2] = d*(xform1.m_xform[0][3] - xform0.m_xform[0][3]);
03603 xformD[1][0] = d*(xform1.m_xform[1][0] - xform0.m_xform[1][0]);
03604 xformD[1][1] = d*(xform1.m_xform[1][1] - xform0.m_xform[1][1]);
03605 xformD[1][2] = d*(xform1.m_xform[1][3] - xform0.m_xform[1][3]);
03606 xformD[2][0] = d*(xform1.m_xform[2][0] - xform0.m_xform[2][0]);
03607 xformD[2][1] = d*(xform1.m_xform[2][1] - xform0.m_xform[2][1]);
03608 xformD[2][2] = d*(xform1.m_xform[2][3] - xform0.m_xform[2][3]);
03609
03610 for ( i = num_der; i > 0; i-- )
03611 {
03612 dx = x;
03613 dy = y;
03614 d0 -= array_stride;
03615 x = d0[0];
03616 y = d0[1];
03617
03618
03619
03620 j = i;
03621 while ( --j )
03622 {
03623 d1[0] = d1[1] = d1[2] = 0.0;
03624 d1 -= array_stride;
03625 }
03626
03627
03628 if ( 1 == i )
03629 {
03630
03631 d1[0] = xformD[0][0]*x + xformD[0][1]*y + xformD[0][2];
03632 d1[1] = xformD[1][0]*x + xformD[1][1]*y + xformD[1][2];
03633 d1[2] = xformD[2][0]*x + xformD[2][1]*y + xformD[2][2];
03634 }
03635 else
03636 {
03637
03638 d1[0] = xformD[0][0]*x + xformD[0][1]*y;
03639 d1[1] = xformD[1][0]*x + xformD[1][1]*y;
03640 d1[2] = xformD[2][0]*x + xformD[2][1]*y;
03641 }
03642 d1 -= array_stride;
03643
03644
03645
03646 d1[0] = xformP[0][0]*dx + xformP[0][1]*dy;
03647 d1[1] = xformP[1][0]*dx + xformP[1][1]*dy;
03648 d1[2] = xformP[2][0]*dx + xformP[2][1]*dy;
03649 d1 -= array_stride;
03650 }
03651 }
03652
03653 d1[0] = xformP[0][0]*x + xformP[0][1]*y + xformP[0][2];
03654 d1[1] = xformP[1][0]*x + xformP[1][1]*y + xformP[1][2];
03655 d1[2] = xformP[2][0]*x + xformP[2][1]*y + xformP[2][2];
03656
03657 if ( m_bTransposed && num_der > 0)
03658 {
03659
03660 const size_t sz = ((3 <= array_stride)?3:array_stride)*sizeof(double);
03661 void* tmp = ( sz <= sizeof(xform0) )
03662 ? ((void*)&xform0.m_xform[0][0])
03663 : onmalloc(sz);
03664 for ( i = 1; i <= num_der; i++ )
03665 {
03666 d0 = der_array + array_stride*(i*(i+1))/2;
03667 d1 = d0 + array_stride*i;
03668 while ( d0 < d1)
03669 {
03670 memcpy(tmp,d0,sz);
03671 memcpy(d0,d1,sz);
03672 memcpy(d1,tmp,sz);
03673 d0 += array_stride;
03674 d1 -= array_stride;
03675 }
03676 }
03677 if ( tmp != ((void*)&xform0.m_xform[0][0]) )
03678 onfree(tmp);
03679 }
03680
03681 return true;
03682 }
03683
03684 ON_Curve* ON_Extrusion::IsoCurve(
03685 int dir,
03686 double c
03687 ) const
03688 {
03689
03690
03691
03692
03693
03694 if ( !m_profile )
03695 return 0;
03696
03697 if ( m_bTransposed )
03698 dir = 1-dir;
03699 const ON_3dVector T = m_path.Tangent();
03700
03701 ON_Xform xform0, xform1;
03702 if ( !ON_GetEndCapTransformation(m_path.PointAt(m_t.m_t[0]),T,m_up,m_bHaveN[0]?&m_N[0]:0,xform0,0,0) )
03703 return 0;
03704 if ( !ON_GetEndCapTransformation(m_path.PointAt(m_t.m_t[1]),T,m_up,m_bHaveN[1]?&m_N[1]:0,xform1,0,0) )
03705 return 0;
03706
03707 ON_Curve* isocurve = 0;
03708 if ( 1 == dir )
03709 {
03710 ON_3dPoint P = m_profile->PointAt(c);
03711 ON_LineCurve* line_curve = new ON_LineCurve();
03712 line_curve->m_t = m_path_domain;
03713 line_curve->m_dim = 3;
03714 line_curve->m_line.from = xform0*P;
03715 line_curve->m_line.to = xform1*P;
03716 isocurve = line_curve;
03717 }
03718 else if ( 0 == dir )
03719 {
03720 double s1 = m_path_domain.NormalizedParameterAt(c);
03721 const double s0 = 1.0-s1;
03722 xform1.m_xform[0][0] = s0*xform0.m_xform[0][0] + s1*xform1.m_xform[0][0];
03723 xform1.m_xform[0][1] = s0*xform0.m_xform[0][1] + s1*xform1.m_xform[0][1];
03724 xform1.m_xform[0][2] = s0*xform0.m_xform[0][2] + s1*xform1.m_xform[0][2];
03725 xform1.m_xform[0][3] = s0*xform0.m_xform[0][3] + s1*xform1.m_xform[0][3];
03726
03727 xform1.m_xform[1][0] = s0*xform0.m_xform[1][0] + s1*xform1.m_xform[1][0];
03728 xform1.m_xform[1][1] = s0*xform0.m_xform[1][1] + s1*xform1.m_xform[1][1];
03729 xform1.m_xform[1][2] = s0*xform0.m_xform[1][2] + s1*xform1.m_xform[1][2];
03730 xform1.m_xform[1][3] = s0*xform0.m_xform[1][3] + s1*xform1.m_xform[1][3];
03731
03732 xform1.m_xform[2][0] = s0*xform0.m_xform[2][0] + s1*xform1.m_xform[2][0];
03733 xform1.m_xform[2][1] = s0*xform0.m_xform[2][1] + s1*xform1.m_xform[2][1];
03734 xform1.m_xform[2][2] = s0*xform0.m_xform[2][2] + s1*xform1.m_xform[2][2];
03735 xform1.m_xform[2][3] = s0*xform0.m_xform[2][3] + s1*xform1.m_xform[2][3];
03736
03737 xform1.m_xform[3][0] = s0*xform0.m_xform[3][0] + s1*xform1.m_xform[3][0];
03738 xform1.m_xform[3][1] = s0*xform0.m_xform[3][1] + s1*xform1.m_xform[3][1];
03739 xform1.m_xform[3][2] = s0*xform0.m_xform[3][2] + s1*xform1.m_xform[3][2];
03740 xform1.m_xform[3][3] = s0*xform0.m_xform[3][3] + s1*xform1.m_xform[3][3];
03741
03742 isocurve = m_profile->DuplicateCurve();
03743 if ( isocurve )
03744 {
03745 isocurve->ChangeDimension(3);
03746 if ( !isocurve->Transform(xform1) )
03747 {
03748
03749 ON_NurbsCurve* nurbs_curve = isocurve->NurbsCurve();
03750 delete isocurve;
03751 isocurve = nurbs_curve;
03752 nurbs_curve = 0;
03753 if ( isocurve )
03754 isocurve->Transform(xform1);
03755 }
03756 }
03757 }
03758
03759 return isocurve;
03760 }
03761
03762 ON_BOOL32 ON_Extrusion::Trim(
03763 int dir,
03764 const ON_Interval& domain
03765 )
03766 {
03767 bool rc = false;
03768 if (!domain.IsIncreasing())
03769 return false;
03770 if ( m_bTransposed )
03771 dir = 1-dir;
03772 if ( 1 == dir )
03773 {
03774 rc = m_path_domain.IsIncreasing();
03775 if ( rc && m_path_domain != domain )
03776 {
03777 ON_Interval dom;
03778 dom.Intersection(domain,m_path_domain);
03779 rc = dom.IsIncreasing();
03780 if (rc)
03781 {
03782 double s0 = m_path_domain.NormalizedParameterAt(dom[0]);
03783 double s1 = m_path_domain.NormalizedParameterAt(dom[1]);
03784 double t0 = (1.0-s0)*m_t[0] + s0*m_t[1];
03785 double t1 = (1.0-s1)*m_t[0] + s1*m_t[1];
03786 rc = (s0 < s1 && 0.0 <= t0 && t0 < t1 && t1 <= 1.0);
03787 if (rc)
03788 {
03789 bool bChanged = false;
03790 if (t0 != m_t[0] && t0 > 0.0 )
03791 {
03792 bChanged = true;
03793 m_t[0] = t0;
03794 m_bHaveN[0] = false;
03795 }
03796 if ( t1 != m_t[1] && t1 < 1.0 )
03797 {
03798 bChanged = true;
03799 m_t[1] = t1;
03800 m_bHaveN[1] = false;
03801 }
03802 if ( bChanged )
03803 {
03804 m_path_domain = dom;
03805 DestroySurfaceTree();
03806 }
03807 }
03808 }
03809 }
03810 }
03811 else if ( 0 == dir )
03812 {
03813 if ( m_profile )
03814 {
03815 rc = m_profile->Trim(domain)?true:false;
03816 DestroySurfaceTree();
03817 }
03818 }
03819 return rc;
03820 }
03821
03822 bool ON_Extrusion::Extend(
03823 int dir,
03824 const ON_Interval& domain
03825 )
03826 {
03827 bool rc = false;
03828 if ( 1 == dir )
03829 {
03830 rc = domain.IsIncreasing() && m_path_domain.IsIncreasing();
03831 if ( rc )
03832 {
03833 double s0 = m_path_domain.NormalizedParameterAt(domain[0]);
03834 if ( s0 > 0.0 )
03835 s0 = 0.0;
03836 double s1 = m_path_domain.NormalizedParameterAt(domain[1]);
03837 if ( s1 < 1.0 )
03838 s1 = 1.0;
03839 double t0 = (1.0-s0)*m_t[0] + s0*m_t[1];
03840 double t1 = (1.0-s1)*m_t[0] + s1*m_t[1];
03841 bool bChanged = false;
03842 ON_3dPoint P0 = m_path.from;
03843 ON_3dPoint P1 = m_path.to;
03844 if ( t0 < m_t[0] )
03845 {
03846 bChanged = true;
03847 m_path_domain.m_t[0] = domain[0];
03848 if ( t0 < 0.0 )
03849 {
03850 P0 = m_path.PointAt(t0);
03851 m_t[0] = 0.0;
03852 }
03853 else
03854 m_t[0] = t0;
03855 }
03856 if ( t1 > m_t[1] )
03857 {
03858 bChanged = true;
03859 m_path_domain.m_t[1] = domain[1];
03860 if ( t1 > 1.0 )
03861 {
03862 P1 = m_path.PointAt(t1);
03863 m_t[1] = 1.0;
03864 }
03865 else
03866 m_t[1] = t1;
03867 }
03868 if ( bChanged )
03869 {
03870 m_path.from = P0;
03871 m_path.to = P1;
03872 DestroySurfaceTree();
03873 }
03874 }
03875 }
03876 else if ( 0 == dir )
03877 {
03878 if ( m_profile )
03879 {
03880 rc = m_profile->Extend(domain);
03881 if (rc)
03882 DestroySurfaceTree();
03883 }
03884 }
03885 return rc;
03886 }
03887
03888 ON_BOOL32 ON_Extrusion::Split(
03889 int dir,
03890 double c,
03891 ON_Surface*& west_or_south_side,
03892 ON_Surface*& east_or_north_side
03893 ) const
03894 {
03895 if ( dir < 0 || dir > 1 || !ON_IsValid(c) )
03896 return false;
03897 if ( 0 != west_or_south_side && west_or_south_side == east_or_north_side )
03898 return false;
03899
03900 ON_Interval domain = Domain(dir);
03901 double s = domain.NormalizedParameterAt(c);
03902 if ( s <= 0.0 || s >= 1.0 )
03903 return false;
03904 if (c <= domain[0] || c >= domain[1] )
03905 return false;
03906
03907 ON_Extrusion* left = 0;
03908 ON_Extrusion* right = 0;
03909 if ( west_or_south_side )
03910 {
03911 left = ON_Extrusion::Cast(west_or_south_side);
03912 if ( !left )
03913 return false;
03914 }
03915 if ( east_or_north_side )
03916 {
03917 right = ON_Extrusion::Cast(east_or_north_side);
03918 if ( !right )
03919 return false;
03920 }
03921
03922 const int path_dir = PathParameter();
03923 bool rc = false;
03924 if ( dir == path_dir )
03925 {
03926
03927 ON_Line left_path, right_path;
03928 ON_Interval left_domain, right_domain;
03929 ON_Interval left_t, right_t;
03930
03931 const double t0 = m_t[0];
03932 const double t1 = m_t[1];
03933 const double t = (1.0-s)*t0 + s*t1;
03934 if ( !ON_IsValid(t) || t <= t0 || t >= t1 )
03935 return false;
03936
03937 ON_3dPoint P = m_path.PointAt(s);
03938 left_path.from = m_path.from;
03939 left_path.to = P;
03940 right_path.from = P;
03941 right_path.to = m_path.to;
03942 left_domain.Set(domain[0],c);
03943 right_domain.Set(c,domain[1]);
03944 left_t.Set(t0,t);
03945 right_t.Set(t,t1);
03946 if ( !left_path.IsValid() || left_path.Length() <= m_path_length_min )
03947 return false;
03948 if ( !right_path.IsValid() || right_path.Length() <= m_path_length_min )
03949 return false;
03950
03951
03952 if ( !left )
03953 left = new ON_Extrusion(*this);
03954 else if ( left != this )
03955 left->operator =(*this);
03956 else
03957 left->DestroyRuntimeCache();
03958 if ( !right )
03959 right = new ON_Extrusion(*this);
03960 else if ( right != this )
03961 right->operator =(*this);
03962 else
03963 right->DestroyRuntimeCache();
03964 left->m_path = left_path;
03965 left->m_path_domain = left_domain;
03966 left->m_t = left_t;
03967 right->m_path = right_path;
03968 right->m_path_domain = right_domain;
03969 right->m_t = right_t;
03970
03971 west_or_south_side = left;
03972 east_or_north_side = right;
03973 rc = true;
03974 }
03975 else
03976 {
03977 if ( 0 == m_profile )
03978 return false;
03979 ON_Curve* left_profile = 0;
03980 ON_Curve* right_profile = 0;
03981
03982 if ( left == this )
03983 {
03984 left_profile = left->m_profile;
03985 left->DestroyRuntimeCache();
03986 }
03987 else if ( 0 != left && 0 != left->m_profile )
03988 {
03989 delete left->m_profile;
03990 left->m_profile = 0;
03991 }
03992
03993 if ( right == this )
03994 {
03995 right_profile = right->m_profile;
03996 right->DestroyRuntimeCache();
03997 }
03998 else if ( 0 != right && 0 != right->m_profile )
03999 {
04000 delete right->m_profile;
04001 right->m_profile = 0;
04002 }
04003
04004 if ( !m_profile->Split(c,left_profile,right_profile) )
04005 return false;
04006 if ( 0 == left_profile || 0 == right_profile )
04007 {
04008 if ( 0 != left_profile && m_profile != left_profile )
04009 delete left_profile;
04010 if ( 0 != right_profile && m_profile != right_profile )
04011 delete right_profile;
04012 return false;
04013 }
04014
04015 ON_Curve* this_profile = 0;
04016 if ( left_profile != m_profile && right_profile != m_profile )
04017 {
04018 if ( left == this || right == this )
04019 {
04020 delete m_profile;
04021 }
04022 else
04023 {
04024 this_profile = m_profile;
04025 }
04026 }
04027
04028
04029 const_cast<ON_Extrusion*>(this)->m_profile = 0;
04030
04031
04032 if ( !left )
04033 left = new ON_Extrusion(*this);
04034 else if ( left != this )
04035 left->operator =(*this);
04036 if ( !right )
04037 right = new ON_Extrusion(*this);
04038 else if ( right != this )
04039 right->operator =(*this);
04040
04041
04042 const_cast<ON_Extrusion*>(this)->m_profile = this_profile;
04043
04044
04045 left->m_profile = left_profile;
04046 right->m_profile = right_profile;
04047
04048 west_or_south_side = left;
04049 east_or_north_side = right;
04050 rc = true;
04051 }
04052
04053 return rc;
04054 }
04055
04056 int ON_Extrusion::GetNurbForm(
04057 ON_NurbsSurface& nurbs_surface,
04058 double tolerance
04059 ) const
04060 {
04061 if ( !m_profile )
04062 return 0;
04063
04064 ON_Xform xform0,xform1;
04065 if ( !GetProfileTransformation(0,xform0) )
04066 return false;
04067 if ( !GetProfileTransformation(1,xform1) )
04068 return false;
04069
04070 ON_NurbsCurve nc0;
04071 int rc = m_profile->GetNurbForm(nc0,tolerance);
04072 if ( rc <= 0 )
04073 return rc;
04074 if ( 3 != nc0.m_dim )
04075 nc0.ChangeDimension(3);
04076 ON_NurbsCurve nc1 = nc0;
04077 nc0.Transform(xform0);
04078 nc1.Transform(xform1);
04079
04080 nurbs_surface.Create(3,nc0.m_is_rat,nc0.m_order,2,nc0.m_cv_count,2);
04081 memcpy(nurbs_surface.m_knot[0],nc0.m_knot,nurbs_surface.KnotCount(0)*sizeof(nurbs_surface.m_knot[0][0]));
04082 nurbs_surface.m_knot[1][0] = m_path_domain[0];
04083 nurbs_surface.m_knot[1][1] = m_path_domain[1];
04084 for ( int i = 0; i < nurbs_surface.m_cv_count[0]; i++ )
04085 {
04086 nurbs_surface.SetCV(i,0,ON::intrinsic_point_style,nc0.CV(i));
04087 nurbs_surface.SetCV(i,1,ON::intrinsic_point_style,nc1.CV(i));
04088 }
04089
04090 if ( m_bTransposed )
04091 nurbs_surface.Transpose();
04092
04093 return rc;
04094 }
04095
04096 int ON_Extrusion::HasNurbForm() const
04097 {
04098 return m_profile ? m_profile->HasNurbForm() : 0;
04099 }
04100
04101 bool ON_Extrusion::GetSurfaceParameterFromNurbFormParameter(
04102 double nurbs_s, double nurbs_t,
04103 double* surface_s, double* surface_t
04104 ) const
04105 {
04106 bool rc = true;
04107 if ( m_bTransposed )
04108 {
04109 double* p = surface_s;
04110 surface_s = surface_t;
04111 surface_t = p;
04112 double t = nurbs_s;
04113 nurbs_s = nurbs_t;
04114 nurbs_t = t;
04115 }
04116 if ( surface_s )
04117 {
04118 rc = m_profile
04119 ? (m_profile->GetCurveParameterFromNurbFormParameter(nurbs_s,surface_s)?true:false)
04120 : false;
04121 }
04122 if ( surface_t )
04123 *surface_t = nurbs_t;
04124 return rc;
04125 }
04126
04127 bool ON_Extrusion::GetNurbFormParameterFromSurfaceParameter(
04128 double surface_s, double surface_t,
04129 double* nurbs_s, double* nurbs_t
04130 ) const
04131 {
04132 bool rc = true;
04133 if ( m_bTransposed )
04134 {
04135 double p = surface_s;
04136 surface_s = surface_t;
04137 surface_t = p;
04138 double* t = nurbs_s;
04139 nurbs_s = nurbs_t;
04140 nurbs_t = t;
04141 }
04142 if ( nurbs_s )
04143 {
04144 rc = m_profile
04145 ? (m_profile->GetNurbFormParameterFromCurveParameter(surface_s,nurbs_s)?true:false)
04146 : false;
04147 }
04148 if ( nurbs_t )
04149 *nurbs_t = surface_t;
04150 return rc;
04151 }
04152
04153 ON_SumSurface* ON_Extrusion::SumSurfaceForm(
04154 ON_SumSurface* sum_surface
04155 ) const
04156 {
04157 int i;
04158 if ( 0 != sum_surface )
04159 {
04160 for ( i = 0; i < 2; i++ )
04161 {
04162 if ( sum_surface->m_curve[i] )
04163 {
04164 delete sum_surface->m_curve[i];
04165 sum_surface->m_curve[i] = 0;
04166 }
04167 sum_surface->m_basepoint = ON_3dVector::ZeroVector;
04168 sum_surface->m_bbox.Destroy();
04169 }
04170 }
04171
04172 if ( 0 == m_profile || !m_path.IsValid() )
04173 return 0;
04174
04175 if ( IsMitered() )
04176 return 0;
04177
04178 ON_Xform xform0;
04179 if ( !GetProfileTransformation(0.0,xform0) )
04180 return 0;
04181
04182 ON_Curve* profile3d = 0;
04183 ON_LineCurve* path = 0;
04184 ON_Curve* curve0 = 0;
04185 ON_Curve* curve1 = 0;
04186 for(;;)
04187 {
04188 if ( 1 == ProfileCount() )
04189 {
04190 const ON_PolyCurve* polycurve = ON_PolyCurve::Cast(m_profile);
04191 if ( 0 != polycurve && 1 == polycurve->Count() )
04192 {
04193 const ON_Curve* segment = polycurve->SegmentCurve(0);
04194 if ( 0 != segment )
04195 {
04196 profile3d = segment->DuplicateCurve();
04197 profile3d->SetDomain( m_profile->Domain() );
04198 }
04199 }
04200 }
04201 if ( 0 == profile3d )
04202 {
04203 profile3d = m_profile->DuplicateCurve();
04204 if ( 0 == profile3d )
04205 break;
04206 }
04207 if ( profile3d->IsLinear() && 0 == ON_LineCurve::Cast(profile3d) )
04208 {
04209 ON_LineCurve* line_curve = new ON_LineCurve();
04210 line_curve->m_line.from = profile3d->PointAtStart();
04211 line_curve->m_line.to = profile3d->PointAtEnd();
04212 line_curve->ON_Curve::SetDomain(profile3d->Domain());
04213 delete profile3d;
04214 profile3d = line_curve;
04215 }
04216 if ( !profile3d->ChangeDimension(3) )
04217 break;
04218 if ( !xform0.IsIdentity() && !profile3d->Transform(xform0) )
04219 break;
04220
04221 path = new ON_LineCurve();
04222 if ( 0 == path )
04223 break;
04224 path->m_line.from = ON_3dPoint::Origin;
04225 path->m_line.to = (m_path.to - m_path.from);
04226 if ( !path->SetDomain( m_path_domain[0], m_path_domain[1] ) )
04227 break;
04228
04229 curve0 = profile3d;
04230 curve1 = path;
04231 profile3d = 0;
04232 path = 0;
04233 break;
04234 }
04235 if ( 0 == curve0 || 0 == curve1 )
04236 {
04237 if ( 0 != profile3d )
04238 delete profile3d;
04239 if ( 0 != path )
04240 delete path;
04241 return 0;
04242 }
04243
04244 ON_SumSurface* sumsrf = ( 0 != sum_surface ) ? sum_surface : new ON_SumSurface();
04245 if ( 0 == sumsrf )
04246 {
04247 delete curve0;
04248 delete curve1;
04249 return 0;
04250 }
04251
04252 sumsrf->m_curve[0] = curve0;
04253 sumsrf->m_curve[1] = curve1;
04254 sumsrf->m_basepoint = ON_3dVector::ZeroVector;
04255 sumsrf->m_bbox = BoundingBox();
04256
04257 if ( m_bTransposed )
04258 sumsrf->Transpose();
04259
04260 return sumsrf;
04261 }
04262
04263 ON_Extrusion* ON_Extrusion::Cylinder(
04264 const ON_Cylinder& cylinder,
04265 bool bCapBottom,
04266 bool bCapTop,
04267 ON_Extrusion* extrusion
04268 )
04269 {
04270 if ( !cylinder.IsValid() || !cylinder.IsFinite() )
04271 return 0;
04272
04273 ON_Line path;
04274 path.from = cylinder.circle.plane.PointAt(0.0,0.0,cylinder.height[0]);
04275 path.to = cylinder.circle.plane.PointAt(0.0,0.0,cylinder.height[1]);
04276 if ( !path.IsValid() || !(path.Length() > ON_ZERO_TOLERANCE) )
04277 return 0;
04278
04279 ON_3dVector up = cylinder.circle.plane.yaxis;
04280 if ( !up.IsValid()
04281 || !up.IsUnitVector()
04282 || fabs(up*path.Tangent()) > ON_SQRT_EPSILON
04283 )
04284 return 0;
04285
04286 ON_ArcCurve* circle_curve = new ON_ArcCurve(cylinder.circle);
04287 circle_curve->m_arc.plane = ON_Plane::World_xy;
04288 circle_curve->m_dim = 2;
04289 if ( !circle_curve->IsValid() )
04290 {
04291 delete circle_curve;
04292 return 0;
04293 }
04294
04295 ON_Extrusion* extrusion_cylinder = 0;
04296 if ( extrusion )
04297 {
04298 extrusion->Destroy();
04299 extrusion_cylinder = extrusion;
04300 }
04301 else
04302 {
04303 extrusion_cylinder = new ON_Extrusion();
04304 }
04305
04306 if ( !extrusion_cylinder->SetPathAndUp(path.from,path.to,up)
04307 || !extrusion_cylinder->SetOuterProfile(circle_curve,false)
04308 || !extrusion_cylinder->IsValid()
04309 || !extrusion_cylinder->SetDomain(extrusion_cylinder->PathParameter(),cylinder.height[0],cylinder.height[1])
04310 )
04311 {
04312 if ( 0 == extrusion )
04313 delete extrusion_cylinder;
04314 return 0;
04315 }
04316
04317 extrusion_cylinder->m_bCap[0] = bCapBottom ? true : false;
04318 extrusion_cylinder->m_bCap[1] = bCapTop ? true : false;
04319
04320 if ( !extrusion_cylinder->IsValid() )
04321 {
04322 if ( 0 == extrusion )
04323 delete extrusion_cylinder;
04324 return 0;
04325 }
04326
04327 return extrusion_cylinder;
04328 }
04329
04330
04331
04332 ON_Extrusion* ON_Extrusion::Pipe(
04333 const ON_Cylinder& cylinder,
04334 double other_radius,
04335 bool bCapBottom,
04336 bool bCapTop,
04337 ON_Extrusion* extrusion
04338 )
04339 {
04340 if ( !cylinder.IsValid()
04341 || !ON_IsValid(other_radius)
04342 || !(fabs(other_radius - cylinder.circle.Radius()) > ON_ZERO_TOLERANCE)
04343 )
04344 {
04345 return 0;
04346 }
04347
04348 double inner_radius = (other_radius < cylinder.circle.radius)
04349 ? other_radius
04350 : cylinder.circle.radius;
04351 double outer_radius = (other_radius < cylinder.circle.radius)
04352 ? cylinder.circle.radius
04353 : other_radius;
04354 if ( !ON_IsValid(inner_radius)
04355 || !ON_IsValid(outer_radius)
04356 || !(outer_radius - inner_radius > ON_ZERO_TOLERANCE)
04357 )
04358 {
04359 return 0;
04360 }
04361
04362 ON_Cylinder outer_cylinder = cylinder;
04363 outer_cylinder.circle.radius = outer_radius;
04364
04365 ON_Circle inner_circle(ON_Plane::World_xy,inner_radius);
04366 ON_ArcCurve* inner_profile = new ON_ArcCurve(inner_circle);
04367 inner_profile->m_dim = 2;
04368 if ( !inner_profile->IsValid() )
04369 {
04370 delete inner_profile;
04371 return 0;
04372 }
04373
04374 ON_Extrusion* extrusion_pipe = ON_Extrusion::Cylinder(outer_cylinder,bCapBottom,bCapTop,extrusion);
04375 if ( 0 == extrusion_pipe )
04376 {
04377 delete inner_profile;
04378 return 0;
04379 }
04380
04381 if ( !extrusion_pipe->IsValid() )
04382 {
04383 if ( 0 == extrusion )
04384 delete extrusion_pipe;
04385 delete inner_profile;
04386 return 0;
04387 }
04388
04389 if ( !extrusion_pipe->AddInnerProfile(inner_profile) )
04390 {
04391 if ( 0 == extrusion )
04392 delete extrusion_pipe;
04393 delete inner_profile;
04394 return 0;
04395 }
04396
04397 if ( !extrusion_pipe->IsValid() )
04398 {
04399 if ( 0 == extrusion )
04400 delete extrusion_pipe;
04401 return 0;
04402 }
04403
04404 return extrusion_pipe;
04405 }
04406
04407
04408 ON_Extrusion* ON_Extrusion::CreateFrom3dCurve(
04409 const ON_Curve& curve,
04410 const ON_Plane* plane,
04411 double height,
04412 bool bCap,
04413 ON_Extrusion* extrusion
04414 )
04415 {
04416 if ( 0 != extrusion )
04417 extrusion->Destroy();
04418
04419 if ( ON_IsValid(height) && 0.0 == height )
04420 return 0;
04421
04422 ON_Interval z(0.0,height);
04423 if ( z.IsDecreasing() )
04424 z.Swap();
04425 if ( !z.IsIncreasing() )
04426 return 0;
04427
04428 if ( !curve.IsValid() )
04429 return 0;
04430
04431 ON_Plane curve_plane;
04432 if ( 0 == plane )
04433 {
04434 if ( !curve.IsPlanar(&curve_plane) )
04435 return 0;
04436 plane = &curve_plane;
04437 }
04438
04439 if ( !plane->IsValid() )
04440 return 0;
04441
04442 ON_Xform xform2d;
04443 xform2d.ChangeBasis(ON_Plane::World_xy,*plane);
04444
04445 ON_Curve* curve2d = curve.DuplicateCurve();
04446 if ( 0 == curve2d )
04447 return 0;
04448
04449 ON_Extrusion* result = 0;
04450
04451 for (;;)
04452 {
04453 if ( !curve2d->Transform(xform2d) )
04454 break;
04455 curve2d->ChangeDimension(2);
04456
04457 if ( 0 == extrusion )
04458 result = new ON_Extrusion();
04459 else
04460 result = extrusion;
04461
04462 if ( !result->SetPathAndUp(
04463 plane->PointAt(0.0,0.0,z[0]),
04464 plane->PointAt(0.0,0.0,z[1]),
04465 plane->yaxis
04466 ) )
04467 break;
04468
04469 if ( !result->SetOuterProfile(curve2d,bCap) )
04470 break;
04471
04472 if ( !result->IsValid() )
04473 break;
04474
04475
04476 curve2d = 0;
04477
04478 break;
04479 }
04480
04481 if ( 0 != curve2d )
04482 {
04483
04484 delete curve2d;
04485 curve2d = 0;
04486
04487 if ( 0 != result && result != extrusion )
04488 delete result;
04489
04490 if ( extrusion )
04491 extrusion->Destroy();
04492
04493 result = 0;
04494 }
04495
04496 return result;
04497 }