opennurbs_brep.cpp
Go to the documentation of this file.
00001 /* $NoKeywords: $ */
00002 /*
00003 //
00004 // Copyright (c) 1993-2012 Robert McNeel & Associates. All rights reserved.
00005 // OpenNURBS, Rhinoceros, and Rhino3D are registered trademarks of Robert
00006 // McNeel & Associates.
00007 //
00008 // THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY.
00009 // ALL IMPLIED WARRANTIES OF FITNESS FOR ANY PARTICULAR PURPOSE AND OF
00010 // MERCHANTABILITY ARE HEREBY DISCLAIMED.
00011 //                              
00012 // For complete openNURBS copyright information see <http://www.opennurbs.org>.
00013 //
00015 */
00016 
00017 #include "pcl/surface/3rdparty/opennurbs/opennurbs.h"
00018 
00019 
00021 //   Class ON_BrepVertex
00023 
00024 ON_OBJECT_IMPLEMENT(ON_BrepVertex,ON_Point,"60B5DBC0-E660-11d3-BFE4-0010830122F0");
00025 
00026 static bool ON_BrepIsNotValid()
00027 {
00028   return ON_IsNotValid(); // <-- good place for a breakpoint
00029 }
00030 
00031 
00032 ON_BrepVertex::ON_BrepVertex()
00033               : m_vertex_index(-1),
00034                 m_tolerance(ON_UNSET_VALUE)
00035 {
00036   memset(&m_vertex_user,0,sizeof(m_vertex_user));
00037 }
00038 
00039 ON_BrepVertex::ON_BrepVertex( int vertex_index ) 
00040               : m_vertex_index(vertex_index),
00041                 m_tolerance(ON_UNSET_VALUE)
00042 {
00043   memset(&m_vertex_user,0,sizeof(m_vertex_user));
00044 }
00045 
00046 unsigned int ON_BrepVertex::SizeOf() const
00047 {
00048   unsigned int sz = ON_Geometry::SizeOf();
00049   sz += (sizeof(*this) - sizeof(ON_Geometry));
00050   sz += m_ei.SizeOfArray();
00051   return sz;
00052 }
00053 
00054 ON_BrepVertex& ON_BrepVertex::operator=(const ON_BrepVertex& src)
00055 {
00056   if ( &src != this ) {
00057     ON_Point::operator=(src);
00058     m_vertex_user   = src.m_vertex_user;
00059     m_vertex_index  = src.m_vertex_index;
00060     m_ei            = src.m_ei;
00061     m_tolerance     = src.m_tolerance;
00062   }
00063   return *this;
00064 }
00065 
00066 ON_BOOL32 
00067 ON_BrepVertex::IsValid( ON_TextLog* text_log ) const
00068 {
00069   if (m_vertex_index < 0)
00070   {
00071     if ( text_log )
00072       text_log->Print("ON_BrepVertex m_vertex_index = %d.  Should be >= 0\n",m_vertex_index);
00073     return ON_BrepIsNotValid();
00074   }
00075   const int ve_count = EdgeCount();
00076   int vei, ei;
00077   for ( vei = 0; vei < ve_count; vei++ ) {
00078     ei = m_ei[vei];
00079     if ( ei < 0 )
00080     {
00081       if ( text_log )
00082         text_log->Print("ON_BrepVertex m_ei[%d] = %d.  m_ei[] values should be >= 0\n",vei,ei);
00083       return ON_BrepIsNotValid();
00084     }
00085   }
00086   return ON_Point::IsValid(text_log);
00087 }
00088 
00089 void 
00090 ON_BrepVertex::Dump( ON_TextLog& dump ) const
00091 {
00092   dump.Print("ON_BrepVertex[%d]: ",m_vertex_index);
00093   dump.Print( point );
00094   dump.Print("\n");
00095 }
00096 
00097 
00098 bool
00099 ON_BrepVertex::SetPoint( const ON_3dPoint& p )
00100 {
00101   point = p;
00102   m_tolerance = ON_UNSET_VALUE;
00103   return true;
00104 }
00105 
00106 ON_3dPoint
00107 ON_BrepVertex::Point() const
00108 {
00109   return point;
00110 }
00111 
00112 double
00113 ON_BrepVertex::Tolerance() const
00114 {
00115   return m_tolerance;
00116 }
00117 
00118 int
00119 ON_BrepVertex::EdgeCount() const
00120 {
00121   return m_ei.Count();
00122 }
00123 
00125 //   Class ON_BrepEdge
00127 
00128 ON_OBJECT_IMPLEMENT(ON_BrepEdge,ON_CurveProxy,"60B5DBC1-E660-11d3-BFE4-0010830122F0");
00129 
00130 ON_BrepEdge::ON_BrepEdge() : ON_CurveProxy(0),
00131                          m_edge_index(-1),
00132                          m_c3i(-1),
00133                          m_tolerance(ON_UNSET_VALUE),
00134                          m_brep(0)
00135 {
00136   memset(&m_edge_user,0,sizeof(m_edge_user));
00137   m_vi[0] = m_vi[1] = -1;
00138 }
00139 
00140 ON_BrepEdge::ON_BrepEdge(int edge_index ) : ON_CurveProxy(0),
00141                          m_edge_index(edge_index),
00142                          m_c3i(-1),
00143                          m_tolerance(ON_UNSET_VALUE),
00144                          m_brep(0)
00145 {
00146   memset(&m_edge_user,0,sizeof(m_edge_user));
00147   m_vi[0] = m_vi[1] = -1;
00148 }
00149 
00150 ON::object_type ON_BrepEdge::ObjectType() const
00151 {
00152   // This MUST return ON::curve_object.
00153   // NEVER change this to ON::edge_object.
00154   return ON::curve_object;
00155 }
00156 
00157 unsigned int ON_BrepEdge::SizeOf() const
00158 {
00159   unsigned int sz = ON_CurveProxy::SizeOf();
00160   sz = (sizeof(*this) - sizeof(ON_CurveProxy));
00161   sz += m_ti.SizeOfArray();
00162   return sz;
00163 }
00164 
00165 ON_BrepEdge& ON_BrepEdge::operator=(const ON_BrepEdge& src)
00166 {
00167   if ( &src != this ) 
00168   {
00169     // do not copy m_brep pointer
00170     ON_CurveProxy::operator=(src);
00171     m_edge_user   = src.m_edge_user;
00172     m_edge_index  = src.m_edge_index;
00173     m_c3i         = src.m_c3i;
00174     m_vi[0]       = src.m_vi[0];
00175     m_vi[1]       = src.m_vi[1];
00176     m_ti          = src.m_ti;
00177     m_tolerance   = src.m_tolerance;
00178   }
00179   return *this;
00180 }
00181 
00182 ON_BOOL32 ON_BrepEdge::IsValid( ON_TextLog* text_log ) const
00183 {
00184   bool rc = ON_CurveProxy::IsValid(text_log) ? true : false;
00185 
00186   if ( !rc )
00187   {
00188     if ( text_log )
00189     {
00190       text_log->Print("ON_BrepEdge is not a valid curve proxy\n");
00191     }
00192   }
00193   else if (m_edge_index < 0)
00194   {
00195     if ( text_log )
00196     {
00197       text_log->Print("ON_BrepEdge.m_edge_index = %d (should be >= 0 )\n",m_edge_index);
00198     }
00199     rc = false;
00200   }
00201   else if ( m_c3i < 0 )
00202   {
00203     if ( text_log )
00204     {
00205       text_log->Print("ON_BrepEdge.m_c3i = %d (should be >= 0 )\n",m_c3i);
00206     }
00207     rc = false;
00208   }
00209   else if ( m_vi[0] < 0 )
00210   {
00211     if ( text_log )
00212     {
00213       text_log->Print("ON_BrepEdge.m_vi[0] = %d (should be >= 0 )\n",m_vi[0]);
00214     }
00215     rc = false;
00216   }
00217   else if ( m_vi[1] < 0 )
00218   {
00219     if ( text_log )
00220     {
00221       text_log->Print("ON_BrepEdge.m_vi[1] = %d (should be >= 0 )\n",m_vi[1]);
00222     }
00223     rc = false;
00224   }
00225   else if ( !m_brep )
00226   {
00227     if ( text_log )
00228     {
00229       text_log->Print("ON_BrepEdge.m_brep = NULL (should point to parent ON_Brep)\n");
00230     }
00231     rc = false;
00232   }
00233 
00234   return rc;
00235 
00236 }
00237 
00238 ON_BOOL32 ON_BrepEdge::IsClosed() const
00239 {
00240   // This function must return true if ON_CurveProxy::IsClosed() is true.
00241   ON_BOOL32 rc = ON_CurveProxy::IsClosed();
00242   if ( 0 == rc 
00243        && m_vi[0] >= 0 
00244        && m_vi[0] == m_vi[1]
00245        && 0 != ProxyCurve()
00246        && ProxyCurveDomain() == ProxyCurve()->Domain()
00247        && 0 != m_brep
00248        && m_vi[0] < m_brep->m_V.Count()
00249        )
00250   {
00251     // When ON_CurveProxy::IsClosed() is false and the topology
00252     // indicates the edge is closed, we need to verify that its
00253     // geometry is within tolerance of being closed.
00254     const ON_BrepVertex& v = m_brep->m_V[m_vi[0]];
00255     ON_3dPoint P = PointAtStart();
00256     ON_3dPoint Q = PointAtEnd();
00257     ON_3dPoint V = v.point;
00258     double vtx_tol = v.m_tolerance;
00259     if ( P.DistanceTo(Q) <= m_tolerance 
00260          && V.DistanceTo(P) <= vtx_tol
00261          && V.DistanceTo(Q) <= vtx_tol )
00262       rc = true;
00263   }
00264   return rc;
00265 }
00266 
00267 ON_Brep* ON_BrepEdge::Brep() const
00268 {
00269   return m_brep;
00270 }
00271 
00272 ON_BrepTrim* ON_BrepEdge::Trim( int eti ) const
00273 {
00274   return (m_brep && eti >= 0 && eti < m_ti.Count()) ? m_brep->Trim(m_ti[eti]) : 0;
00275 }
00276 
00277 int ON_BrepEdge::TrimCount() const
00278 {
00279   return m_ti.Count();
00280 }
00281 
00282 void ON_BrepEdge::Dump( ON_TextLog& dump ) const
00283 {
00284   dump.Print("ON_BrepEdge[%d]: ",m_edge_index);
00285 }
00286 
00287 
00288 // virtual ON_Curve::Reverse override
00289 ON_BOOL32 ON_BrepEdge::Reverse()
00290 {
00291   ON_BOOL32 rc = false;
00292   if ( m_brep )
00293   {
00294     ON_Interval edge_domain = Domain();
00295     if ( m_brep->StandardizeEdgeCurve( m_edge_index, false ) )
00296     {
00297       ON_Curve* c3 = const_cast<ON_Curve*>(EdgeCurveOf());
00298       if ( c3 )
00299       {
00300         rc = c3->Reverse();
00301         edge_domain.Reverse();
00302         c3->SetDomain(edge_domain);
00303         SetProxyCurve(c3);
00304       }
00305     }
00306   }
00307 
00308   if ( !rc )
00309     rc = ON_CurveProxy::Reverse();
00310 
00311   if (rc)
00312   {
00313     int i = m_vi[0];
00314     m_vi[0] = m_vi[1];
00315     m_vi[1] = i;
00316     if ( m_brep )
00317     {
00318       const int tcount = m_brep->m_T.Count();
00319       int ti, eti;
00320       for ( eti = m_ti.Count()-1; eti >= 0; eti-- ) {
00321         ti = m_ti[eti];
00322         if ( ti >= 0 && ti < tcount ) 
00323         {
00324           ON_BrepTrim& trim = m_brep->m_T[ti];
00325           trim.m_bRev3d = trim.m_bRev3d ? false : true;
00326           trim.UnsetPlineEdgeParameters();
00327         }
00328       }
00329     }
00330   }
00331 
00332   return rc;
00333 }
00334 
00336 //   Class ON_BrepTrim
00338 
00339 ON_OBJECT_IMPLEMENT(ON_BrepTrim,ON_CurveProxy,"60B5DBC2-E660-11d3-BFE4-0010830122F0");
00340 
00341 ON_BrepTrim::ON_BrepTrim()
00342               : m_trim_index(-1), 
00343                 m_c2i(-1), 
00344                 m_ei(-1), 
00345                 m_bRev3d(false), 
00346                 m_type(ON_BrepTrim::unknown), 
00347                 m_iso(ON_Surface::not_iso),
00348                 m_li(-1),
00349                 m__legacy_2d_tol(ON_UNSET_VALUE), 
00350                 m__legacy_3d_tol(ON_UNSET_VALUE),
00351                 m__legacy_flags(0),
00352                 m_brep(0)
00353 {
00354   memset(&m_trim_user,0,sizeof(m_trim_user));
00355   m_vi[0] = m_vi[1] = -1; 
00356   m_tolerance[0] = m_tolerance[1] = ON_UNSET_VALUE;
00357   m_pline.Reserve(4); // This is a stopgap fix to insures the memory 
00358                       // pool used for pline segments is the same as
00359                       // the memory pool used for the rest of this brep.
00360   //m_P[0] = ON_UNSET_POINT;
00361   //m_P[1] = ON_UNSET_POINT;
00362 }
00363 
00364 ON_BrepTrim::ON_BrepTrim(int trim_index) 
00365               : m_trim_index(trim_index), 
00366                 m_c2i(-1), 
00367                 m_ei(-1), 
00368                 m_bRev3d(false), 
00369                 m_type(ON_BrepTrim::unknown), 
00370                 m_iso(ON_Surface::not_iso),
00371                 m_li(-1),
00372                 m__legacy_2d_tol(ON_UNSET_VALUE), 
00373                 m__legacy_3d_tol(ON_UNSET_VALUE),
00374                 m__legacy_flags(0),
00375                 m_brep(0)
00376 {
00377   memset(&m_trim_user,0,sizeof(m_trim_user));
00378   m_vi[0] = m_vi[1] = -1; 
00379   m_tolerance[0] = m_tolerance[1] = ON_UNSET_VALUE;
00380   m_pline.Reserve(4); // This is a stopgap fix to insures the memory 
00381                       // pool used for pline segments is the same as
00382                       // the memory pool used for the rest of this brep.
00383   //m_P[0] = ON_UNSET_POINT;
00384   //m_P[1] = ON_UNSET_POINT;
00385 }
00386 
00387 
00388 unsigned int ON_BrepTrim::SizeOf() const
00389 {
00390   unsigned int sz = ON_CurveProxy::SizeOf();
00391   sz = (sizeof(*this) - sizeof(ON_CurveProxy));
00392   // runtime m_pline is not counted
00393   return sz;
00394 }
00395 
00396 
00397 ON_BrepTrim& ON_BrepTrim::operator=(const ON_BrepTrim& src)
00398 {
00399   if ( &src != this ) 
00400   {
00401     // do not copy m_brep pointer
00402     ON_CurveProxy::operator=(src);
00403     m_trim_user   = src.m_trim_user;
00404     m_trim_index  = src.m_trim_index;
00405     m_c2i    = src.m_c2i;
00406     //m_t      = src.m_t;
00407     m_ei     = src.m_ei;
00408     m_vi[0]  = src.m_vi[0];
00409     m_vi[1]  = src.m_vi[1];
00410     m_bRev3d = src.m_bRev3d;
00411     m_type   = src.m_type;
00412     m_iso    = src.m_iso;
00413     m_li     = src.m_li;
00414     m_tolerance[0] = src.m_tolerance[0];
00415     m_tolerance[1] = src.m_tolerance[1];
00416     //m_P[0] = src.m_P[0];
00417     //m_P[1] = src.m_P[1];
00418     m__legacy_2d_tol = src.m__legacy_2d_tol;
00419     m__legacy_3d_tol = src.m__legacy_3d_tol;
00420     m__legacy_flags = src.m__legacy_flags;
00421     m_pline = src.m_pline;
00422     m_pbox = src.m_pbox;
00423   }
00424   return *this;
00425 }
00426 
00427 ON_Brep* ON_BrepTrim::Brep() const
00428 {
00429   return m_brep;
00430 }
00431 
00432 ON_BrepLoop* ON_BrepTrim::Loop() const
00433 {
00434   ON_BrepLoop* loop = 0;
00435   if ( m_brep && m_li >= 0 && m_li < m_brep->m_L.Count() )
00436     loop = &m_brep->m_L[m_li];
00437   return loop;  
00438 }
00439 
00440 ON_BrepFace* ON_BrepTrim::Face() const
00441 {
00442   ON_BrepFace* face = 0;
00443   if ( m_brep && m_li >= 0 && m_li < m_brep->m_L.Count() )
00444   {
00445     int fi = m_brep->m_L[m_li].m_fi;
00446     if ( fi >= 0 && fi < m_brep->m_F.Count() )
00447       face = &m_brep->m_F[fi];
00448   }
00449   return face;
00450 }
00451 
00452 ON_BrepEdge* ON_BrepTrim::Edge() const
00453 {
00454   ON_BrepEdge* edge = 0;
00455   if ( m_brep && m_ei >= 0 && m_ei < m_brep->m_E.Count() )
00456     edge = &m_brep->m_E[m_ei];
00457   return edge;  
00458 }
00459 
00460 ON_BrepVertex* ON_BrepTrim::Vertex(int tvi) const
00461 {
00462   ON_BrepVertex* vertex = 0;
00463   if ( 0 != m_brep && 0 <= tvi && tvi <= 1 )
00464   {
00465     int vi = m_vi[tvi];
00466     if ( 0 <= vi && vi < m_brep->m_V.Count() )
00467     {
00468       vertex = &m_brep->m_V[vi];
00469     }
00470   }
00471   return vertex;  
00472 }
00473 
00474 ON_BrepVertex* ON_BrepEdge::Vertex(int evi) const
00475 {
00476   ON_BrepVertex* vertex = 0;
00477   if ( 0 != m_brep && 0 <= evi && evi <= 1 )
00478   {
00479     int vi = m_vi[evi];
00480     if ( 0 <= vi && vi < m_brep->m_V.Count() )
00481     {
00482       vertex = &m_brep->m_V[vi];
00483     }
00484   }
00485   return vertex;  
00486 }
00487 
00488 
00489 ON_BOOL32 ON_BrepTrim::IsValid( ON_TextLog* text_log ) const
00490 {
00491   if ( m_trim_index < 0 )
00492   {
00493     if ( text_log )
00494     {
00495       text_log->Print("trim.m_trim_index < 0.\n");
00496     }
00497     return ON_BrepIsNotValid();
00498   }
00499 
00500   if ( m_c2i < 0 )
00501   {
00502     if ( text_log )
00503     {
00504       text_log->Print("trim.m_c2i = %d is not valid\n",m_c2i);
00505     }
00506     return ON_BrepIsNotValid();
00507   }
00508 
00509   if ( !ON_CurveProxy::IsValid(text_log) )
00510   {
00511     if ( text_log )
00512     {
00513       text_log->Print("trim curve proxy settings are not valid.\n");
00514     }
00515     return ON_BrepIsNotValid();
00516   }
00517 
00518   if ( m_ei < 0 ) 
00519   {
00520     if ( m_type != singular )
00521     {
00522       if ( text_log )
00523       {
00524         text_log->Print("trim.m_ei = %d but trim.mtype != singular\n",m_ei);
00525       }
00526       return ON_BrepIsNotValid();
00527     }
00528   }
00529 
00530   if ( m_vi[0] < 0 )
00531   {
00532     if ( text_log )
00533     {
00534       text_log->Print("trim.m_v[0] = %d is not valid\n",m_vi[0]);
00535     }
00536     return ON_BrepIsNotValid();
00537   }
00538 
00539   if ( m_vi[1] < 0 )
00540   {
00541     if ( text_log )
00542     {
00543       text_log->Print("trim.m_v[1] = %d is not valid\n",m_vi[1]);
00544     }
00545     return ON_BrepIsNotValid();
00546   }
00547 
00548   unsigned int i = m_type;
00549   if ( i >= trim_type_count )
00550   {
00551     if ( text_log )
00552     {
00553       text_log->Print("trim.m_type = %d is not valid\n",i);
00554     }
00555     return ON_BrepIsNotValid();
00556   }
00557 
00558   if ( i == ON_BrepTrim::slit )
00559   {
00560     if ( text_log )
00561     {
00562       text_log->Print("trim.m_type = ON_BrepTrim::slit is not valid. REserved for future use.\n",i);
00563     }
00564     return ON_BrepIsNotValid();
00565   }
00566 
00567   i = m_iso;
00568   if ( i >= ON_Surface::iso_count )
00569   {
00570     if ( text_log )
00571     {
00572       text_log->Print("trim.m_iso = %d is not valid\n",i);
00573     }
00574     return ON_BrepIsNotValid();
00575   }
00576 
00577   if ( m_li < 0 )
00578   {
00579     if ( text_log )
00580     {
00581       text_log->Print("trim.m_li = %d is not valid\n",m_li);
00582     }
00583     return ON_BrepIsNotValid();
00584   }
00585 
00586   if ( !m_brep )
00587   {
00588     if ( text_log )
00589     {
00590       text_log->Print("trim.m_brep is null.\n");
00591     }
00592     return ON_BrepIsNotValid();
00593   }
00594 
00595   return true;
00596 }
00597 
00598 void ON_BrepTrim::Dump( ON_TextLog& dump ) const
00599 {
00600   dump.Print("ON_BrepTrim[%d]:\n",m_trim_index);
00601 }
00602 
00603 ON_BOOL32 ON_BrepTrim::Reverse()
00604 {
00605   m_pline.Destroy();
00606   DestroyCurveTree();
00607 
00608   ON_BOOL32 rc = false;
00609   if ( m_brep )
00610   {
00611     ON_Interval trim_domain = Domain();
00612     if ( m_brep->StandardizeTrimCurve( m_trim_index ) )
00613     {
00614       ON_Curve* c2 = const_cast<ON_Curve*>(TrimCurveOf());
00615       if ( c2 )
00616       {
00617         rc = c2->Reverse();
00618         trim_domain.Reverse();
00619         c2->SetDomain(trim_domain);
00620         SetProxyCurve(c2);
00621       }
00622     }
00623   }
00624 
00625   if ( !rc )
00626     rc = ON_CurveProxy::Reverse();
00627 
00628   if (rc)
00629   {
00630     int i = m_vi[0];
00631     m_vi[0] = m_vi[1];
00632     m_vi[1] = i;
00633     if ( m_ei >= 0 )
00634       m_bRev3d = m_bRev3d ? false : true;
00635   }
00636   return rc;
00637 }
00638 
00639 
00641 //   Class ON_BrepLoop
00643 
00644 ON_OBJECT_IMPLEMENT(ON_BrepLoop,ON_Geometry,"60B5DBC3-E660-11d3-BFE4-0010830122F0");
00645 
00646 ON_BrepLoop::ON_BrepLoop()
00647               : m_loop_index(-1), 
00648                 m_type(ON_BrepLoop::unknown), 
00649                 m_fi(-1),
00650                 m_brep(0)
00651 {
00652   memset(&m_loop_user,0,sizeof(m_loop_user));
00653 }
00654 
00655 ON_BrepLoop::ON_BrepLoop(int loop_index) 
00656               : m_loop_index(loop_index), 
00657                 m_type(ON_BrepLoop::unknown), 
00658                 m_fi(-1),
00659                 m_brep(0)
00660 {
00661   memset(&m_loop_user,0,sizeof(m_loop_user));
00662 }
00663 
00664 ON_Brep* ON_BrepLoop::Brep() const
00665 {
00666   return m_brep;
00667 }
00668 
00669 ON_BrepFace* ON_BrepLoop::Face() const
00670 {
00671   return m_brep ? m_brep->Face(m_fi) : 0;
00672 }
00673 
00674 
00675 unsigned int ON_BrepLoop::SizeOf() const
00676 {
00677   unsigned int sz = ON_Object::SizeOf();
00678   sz += (sizeof(ON_BrepLoop) - sizeof(ON_Object));
00679   sz += m_ti.SizeOfArray();
00680   return sz;
00681 }
00682 
00683 ON_BrepTrim* ON_BrepLoop::Trim( int lti ) const
00684 {
00685   ON_BrepTrim* trim = ( m_brep && lti >= 0 && lti < m_ti.Count() )
00686                     ? m_brep->Trim(m_ti[lti])
00687                     : 0;
00688   return trim;
00689 }
00690 
00691 int ON_BrepLoop::TrimCount() const
00692 {
00693   return m_ti.Count();
00694 }
00695 
00696 ON_BrepLoop& ON_BrepLoop::operator=(const ON_BrepLoop& src)
00697 {
00698   if ( &src != this ) 
00699   {
00700     // do not copy m_brep pointer
00701     ON_Object::operator=(src);
00702     m_loop_user   = src.m_loop_user;
00703     m_loop_index  = src.m_loop_index;
00704     m_ti    = src.m_ti;
00705     m_type  = src.m_type;
00706     m_fi    = src.m_fi;
00707     m_pbox  = src.m_pbox;
00708   }
00709   return *this;
00710 }
00711 
00712 static void BadLoopMessage( int loop_index, ON_TextLog* text_log )
00713 {
00714   if ( text_log )
00715   {
00716     text_log->Print("brep.m_L[%d] loop is not valid.\n",loop_index);
00717   }
00718 }
00719 
00720 ON_BOOL32 ON_BrepLoop::IsValid( ON_TextLog* text_log ) const
00721 {
00722   if ( m_loop_index < 0 )
00723   {
00724     BadLoopMessage(m_loop_index,text_log);
00725     if ( text_log )
00726       text_log->Print("loop.m_loop_index < 0.\n");
00727     return ON_BrepIsNotValid();
00728   }
00729 
00730   if ( m_ti.Count() < 1 )
00731   {
00732     BadLoopMessage(m_loop_index,text_log);
00733     if ( text_log )
00734       text_log->Print("loop.m_ti[] is empty.\n");
00735     return ON_BrepIsNotValid();
00736   }
00737   int i = m_type;
00738   if ( i < 0 || i > type_count )
00739   {
00740     BadLoopMessage(m_loop_index,text_log);
00741     if ( text_log )
00742       text_log->Print("loop.m_type = %d is not a valid value.\n",i);
00743     return ON_BrepIsNotValid();
00744   }
00745   if ( m_fi < 0 )
00746   {
00747     BadLoopMessage(m_loop_index,text_log);
00748     if ( text_log )
00749       text_log->Print("loop.m_fi = %d (should be >= 0 ).\n",m_fi);
00750     return ON_BrepIsNotValid();
00751   }
00752   if ( !m_brep )
00753   {
00754     BadLoopMessage(m_loop_index,text_log);
00755     if ( text_log )
00756       text_log->Print("loop.m_brep is NULL.\n");
00757     return ON_BrepIsNotValid();
00758   }
00759   return true;
00760 }
00761 
00762 void ON_BrepLoop::Dump( ON_TextLog& dump ) const
00763 {
00764   dump.Print("ON_BrepLoop[%d]: m_fi = %d, m_type = %d m_ti.Count() = %d\n",
00765              m_loop_index,m_fi,m_type,m_ti.Count()
00766              );
00767 }
00768 
00769 int ON_BrepLoop::IndexOfTrim( const ON_BrepTrim& trim ) const
00770 {
00771   const int count = m_ti.Count();
00772   int lti;
00773   for ( lti = 0; lti < count; lti++ )
00774   {
00775     if ( m_ti[lti] == trim.m_trim_index )
00776       return lti;
00777   }
00778   return -1;
00779 }
00780 
00782 //   Class ON_BrepFace
00784 
00785 ON_OBJECT_IMPLEMENT(ON_BrepFace,ON_SurfaceProxy,"60B5DBC4-E660-11d3-BFE4-0010830122F0");
00786 
00787 ON_BrepFace::ON_BrepFace() : ON_SurfaceProxy(0),
00788                 m_face_index(-1), 
00789                 m_si(-1), 
00790                 m_bRev(false),
00791                 m_face_material_channel(0),
00792                 m_render_mesh(0),
00793                 m_analysis_mesh(0),
00794                 m_preview_mesh(0),
00795                 m_brep(0)
00796 {
00797   m_face_uuid = ON_nil_uuid;
00798   memset(&m_face_user,0,sizeof(m_face_user));
00799 }
00800 
00801 ON_BrepFace::ON_BrepFace(int face_index) : ON_SurfaceProxy(0),
00802                 m_face_index(face_index),
00803                 m_si(-1), 
00804                 m_bRev(false),
00805                 m_face_material_channel(0),
00806                 m_render_mesh(0),
00807                 m_analysis_mesh(0),
00808                 m_preview_mesh(0),
00809                 m_brep(0)
00810 {
00811   m_face_uuid = ON_nil_uuid;
00812   memset(&m_face_user,0,sizeof(m_face_user));
00813 }
00814 
00815 
00816 unsigned int ON_BrepFace::SizeOf() const
00817 {
00818   unsigned int sz = ON_SurfaceProxy::SizeOf();
00819   sz += (sizeof(*this) - sizeof(ON_SurfaceProxy));
00820   sz += m_li.SizeOfArray();
00821   if ( m_render_mesh )
00822     sz += m_render_mesh->SizeOf();
00823   if ( m_analysis_mesh )
00824     sz += m_analysis_mesh->SizeOf();
00825   if ( m_preview_mesh )
00826     sz += m_preview_mesh->SizeOf();
00827   return sz;
00828 }
00829 
00830 
00831 ON_BrepFace& ON_BrepFace::operator=(const ON_BrepFace& src)
00832 {
00833   if ( &src != this ) 
00834   {
00835     // do not copy m_brep pointer
00836     ON_SurfaceProxy::operator=(src);
00837     m_face_user   = src.m_face_user;
00838     m_face_index  = src.m_face_index;
00839     m_li    = src.m_li;
00840     m_si    = src.m_si;
00841     m_bRev  = src.m_bRev;
00842     m_face_material_channel = src.m_face_material_channel;
00843     m_face_uuid = src.m_face_uuid;
00844     if ( m_render_mesh ) {
00845       delete m_render_mesh;
00846       m_render_mesh = 0;
00847     }
00848     if ( src.m_render_mesh ) {
00849       m_render_mesh = new ON_Mesh(*src.m_render_mesh);
00850     }    
00851     if ( m_analysis_mesh ) {
00852       delete m_analysis_mesh;
00853       m_analysis_mesh = 0;
00854     }
00855     if ( src.m_analysis_mesh ) {
00856       m_analysis_mesh = new ON_Mesh(*src.m_analysis_mesh);
00857     }    
00858     if ( m_preview_mesh ) {
00859       delete m_preview_mesh;
00860       m_preview_mesh = 0;
00861     }
00862     if ( src.m_preview_mesh ) {
00863       m_preview_mesh = new ON_Mesh(*src.m_preview_mesh);
00864     }    
00865     //m_material_index = src.m_material_index;
00866   }
00867   return *this;
00868 }
00869 
00870 ON_BrepFace::~ON_BrepFace()
00871 {
00872   DestroyMesh(ON::any_mesh);
00873   m_li.Destroy();
00874 }
00875 
00876 ON_Brep* ON_BrepFace::Brep() const
00877 {
00878   return m_brep;
00879 }
00880 
00881 ON_BrepLoop* ON_BrepFace::Loop( int lti ) const
00882 {
00883   return (m_brep && lti >= 0 && lti < m_li.Count()) ? m_brep->Loop( m_li[lti]) : 0;
00884 }
00885 
00886 int ON_BrepFace::LoopCount() const
00887 {
00888   return m_li.Count();
00889 }
00890 
00891 ON_BrepLoop* ON_BrepFace::OuterLoop() const
00892 {
00893   int li, lti;
00894   for ( lti = 0; lti < m_li.Count(); lti++ )
00895   {
00896     li = m_li[lti];
00897     if ( li >= 0 && li < m_brep->m_L.Count() )
00898     {
00899       if ( ON_BrepLoop::outer == m_brep->m_L[li].m_type  )
00900       {
00901         return &m_brep->m_L[li];
00902       }
00903     }
00904   }
00905   return 0;
00906 }
00907 
00908 
00909 ON_BOOL32 ON_BrepFace::IsValid( ON_TextLog* text_log ) const
00910 {
00911   if ( m_face_index < 0 )
00912   {
00913     if ( 0 != text_log )
00914       text_log->Print("ON_BrepFace m_face_index = %d.  Should be >= 0.\n",m_face_index);
00915     return false;
00916   }
00917 
00918   if ( m_li.Count() < 1 )
00919   {
00920     if ( 0 != text_log )
00921       text_log->Print("ON_BrepFace m_li.Count() = 0  Should be > 0.\n");
00922     return false;
00923   }
00924 
00925   if ( m_si < 0 )
00926   {
00927     if ( 0 != text_log )
00928       text_log->Print("ON_BrepFace m_si = %d.  Should be >= 0.\n",m_si);
00929     return false;
00930   }
00931 
00932   if ( 0 == m_brep )
00933   {
00934     if ( 0 != text_log )
00935       text_log->Print("ON_BrepFace m_brep = 0.  Should point to parent brep.\n");
00936     return false;
00937 
00938   }
00939 
00940   return true;
00941 }
00942 
00943 void ON_BrepFace::Dump( ON_TextLog& dump ) const
00944 {
00945   dump.Print("ON_BrepFace[%d]:",m_face_index);
00946   if ( ON_UuidCompare(m_face_uuid,ON_nil_uuid) )
00947   {
00948     dump.Print(" (");
00949     dump.Print(m_face_uuid);
00950     dump.Print(" )");
00951   }
00952   dump.Print("\n");
00953 }
00954 
00955 
00956 /*
00957 int ON_BrepFace::MaterialIndex() const
00958 {
00959   return m_material_index;
00960 }
00961 
00962 void ON_BrepFace::SetMaterialIndex(int mi)
00963 {
00964   m_material_index = (mi>0) ? mi : -1;
00965 }
00966 */
00967 
00968 const ON_Mesh* ON_BrepFace::Mesh( ON::mesh_type mt ) const
00969 {
00970   ON_Mesh* m = 0;
00971   switch(mt) {
00972   case ON::render_mesh:
00973     m = m_render_mesh;
00974     break;
00975   case ON::analysis_mesh:
00976     m = m_analysis_mesh;
00977     break;
00978   case ON::preview_mesh:
00979     m = m_preview_mesh;
00980     break;
00981   default:
00982     m = m_render_mesh ? m_render_mesh : m_analysis_mesh;
00983     if ( !m )
00984       m = m_preview_mesh;
00985     break;
00986   }
00987   if ( m ) {
00988     m->m_parent = this;
00989     //m->m_material_index = m_material_index;
00990   }
00991   return m;
00992 }
00993 
00994 void ON_BrepFace::DestroyMesh( ON::mesh_type mt, bool bDeleteMesh )
00995 {
00996   switch(mt) {
00997   case ON::render_mesh:
00998     if ( m_render_mesh ) 
00999     {
01000       if ( bDeleteMesh )
01001         delete m_render_mesh;
01002       m_render_mesh = 0;
01003     }
01004     break;
01005   case ON::analysis_mesh:
01006     if (m_analysis_mesh) 
01007     {
01008       if ( bDeleteMesh )
01009         delete m_analysis_mesh;
01010       m_analysis_mesh = 0;
01011     }
01012     break;
01013   case ON::preview_mesh:
01014     if (m_preview_mesh) 
01015     {
01016       if ( bDeleteMesh )
01017         delete m_preview_mesh;
01018       m_preview_mesh = 0;
01019     }
01020     break;
01021   default:
01022     DestroyMesh( ON::render_mesh );
01023     DestroyMesh( ON::analysis_mesh );
01024     DestroyMesh( ON::preview_mesh );
01025     break;
01026   }
01027 }
01028 
01029 
01030 unsigned int ON_BrepVertexArray::SizeOf() const
01031 {
01032   unsigned int sz = 0;
01033   int i, count = Count();
01034   for ( i = 0; i < count; i++ )
01035   {
01036     sz += m_a[i].SizeOf();
01037   }
01038   sz += (m_capacity - m_count)*sizeof(m_a[0]);
01039   return sz;
01040 }
01041 
01042 unsigned int ON_BrepEdgeArray::SizeOf() const
01043 {
01044   unsigned int sz = 0;
01045   int i, count = Count();
01046   for ( i = 0; i < count; i++ )
01047   {
01048     sz += m_a[i].SizeOf();
01049   }
01050   sz += (m_capacity - m_count)*sizeof(m_a[0]);
01051   return sz;
01052 }
01053 
01054 unsigned int ON_BrepTrimArray::SizeOf() const
01055 {
01056   unsigned int sz = 0;
01057   int i, count = Count();
01058   for ( i = 0; i < count; i++ )
01059   {
01060     sz += m_a[i].SizeOf();
01061   }
01062   sz += (m_capacity - m_count)*sizeof(m_a[0]);
01063   return sz;
01064 }
01065 
01066 unsigned int ON_BrepLoopArray::SizeOf() const
01067 {
01068   unsigned int sz = 0;
01069   int i, count = Count();
01070   for ( i = 0; i < count; i++ )
01071   {
01072     sz += m_a[i].SizeOf();
01073   }
01074   sz += (m_capacity - m_count)*sizeof(m_a[0]);
01075   return sz;
01076 }
01077 
01078 unsigned int ON_BrepFaceArray::SizeOf() const
01079 {
01080   unsigned int sz = 0;
01081   int i, count = Count();
01082   for ( i = 0; i < count; i++ )
01083   {
01084     sz += m_a[i].SizeOf();
01085   }
01086   sz += (m_capacity - m_count)*sizeof(m_a[0]);
01087   return sz;
01088 }
01089 
01091 //   Class ON_Brep
01093 
01094 ON_BrepVertexArray::ON_BrepVertexArray()
01095 {}
01096 
01097 ON_BrepVertexArray::~ON_BrepVertexArray()
01098 {}
01099 
01100 
01101 ON_BrepEdgeArray::ON_BrepEdgeArray()
01102 {}
01103 
01104 ON_BrepEdgeArray::~ON_BrepEdgeArray()
01105 {}
01106 
01107 
01108 ON_BrepTrimArray::ON_BrepTrimArray()
01109 {}
01110 
01111 ON_BrepTrimArray::~ON_BrepTrimArray()
01112 {}
01113 
01114 
01115 ON_BrepLoopArray::ON_BrepLoopArray()
01116 {}
01117 
01118 ON_BrepLoopArray::~ON_BrepLoopArray()
01119 {}
01120 
01121 ON_BrepFaceArray::ON_BrepFaceArray()
01122 {}
01123 
01124 ON_BrepFaceArray::~ON_BrepFaceArray()
01125 {}
01126 
01127 
01128 ON_OBJECT_IMPLEMENT(ON_Brep,ON_Geometry,"60B5DBC5-E660-11d3-BFE4-0010830122F0");
01129 
01130 void ON_Brep::Initialize()
01131 {
01132   memset(&m_brep_user,0,sizeof(m_brep_user));
01133   m_is_solid = 0;
01134   m_bbox.Destroy();
01135 }
01136 
01137 ON_Brep* ON_Brep::New() 
01138 {
01139   // use instead of new ON_Brep()
01140   // (When openNURBS is used as a Windows DLL, 
01141   // this forces the call to new to happen in the openNURBS DLL.)
01142   return new ON_Brep();
01143 }
01144 
01145 ON_Brep* ON_Brep::New(const ON_Brep& src) 
01146 {
01147   // use instead of new ON_Brep(const ON_Brep&)
01148   // (When openNURBS is used as a Windows DLL, 
01149   // this forces the call to new to happen in the openNURBS DLL.)
01150   return new ON_Brep(src);
01151 }
01152 
01153 ON_Brep::ON_Brep()
01154 { 
01155   ON__SET__THIS__PTR(m_s_ON_Brep_ptr);
01156   Initialize();
01157 }
01158 
01159 ON_Brep::ON_Brep(const ON_Brep& src) : ON_Geometry(src)
01160 {
01161   ON__SET__THIS__PTR(m_s_ON_Brep_ptr);
01162   Initialize();
01163   *this = src;
01164 }
01165 
01166 ON_Brep::~ON_Brep()
01167 { 
01168   DestroyMesh(ON::any_mesh,true);
01169   // everything is in array classes that destroy themselves.
01170 }
01171 
01172 unsigned int ON_Brep::SizeOf() const
01173 {
01174   int i, count;
01175 
01176   unsigned int sz = ON_Geometry::SizeOf();
01177   sz += (sizeof(*this) - sizeof(ON_Geometry));
01178   sz += m_C2.SizeOfArray();
01179   sz += m_C3.SizeOfArray();
01180   sz += m_S.SizeOfArray();
01181 
01182   count = m_C2.Count();
01183   for ( i = 0; i < count; i++ )
01184   {
01185     const ON_Curve* c2 = m_C2[i];
01186     if ( c2 )
01187       sz += c2->SizeOf();
01188   }
01189 
01190   count = m_C3.Count();
01191   for ( i = 0; i < count; i++ )
01192   {
01193     const ON_Curve* c3 = m_C3[i];
01194     if ( c3 )
01195       sz += c3->SizeOf();
01196   }
01197 
01198   count = m_S.Count();
01199   for ( i = 0; i < count; i++ )
01200   {
01201     const ON_Surface* s = m_S[i];
01202     if ( s )
01203       sz += s->SizeOf();
01204   }
01205 
01206   sz += m_V.SizeOf();
01207   sz += m_E.SizeOf();
01208   sz += m_T.SizeOf();
01209   sz += m_L.SizeOf();
01210   sz += m_F.SizeOf();
01211 
01212   return sz;
01213 }
01214 
01215 ON__UINT32 ON_BrepVertex::DataCRC(ON__UINT32 current_remainder) const
01216 {
01217   current_remainder = ON_CRC32(current_remainder,sizeof(m_vertex_index),&m_vertex_index);
01218   current_remainder = ON_CRC32(current_remainder,sizeof(m_tolerance),&m_tolerance);
01219   current_remainder = m_ei.DataCRC(current_remainder);
01220   return current_remainder;
01221 }
01222 
01223 ON__UINT32 ON_BrepEdge::DataCRC(ON__UINT32 current_remainder) const
01224 {
01225   current_remainder = ON_CurveProxy::DataCRC(current_remainder);
01226   current_remainder = ON_CRC32(current_remainder,sizeof(m_edge_index),&m_edge_index);
01227   current_remainder = ON_CRC32(current_remainder,sizeof(m_c3i),&m_c3i);
01228   current_remainder = ON_CRC32(current_remainder,2*sizeof(m_vi[0]),&m_vi[0]);
01229   current_remainder = m_ti.DataCRC(current_remainder);
01230   current_remainder = ON_CRC32(current_remainder,sizeof(m_tolerance),&m_tolerance);
01231 
01232   return current_remainder;
01233 }
01234 
01235 ON__UINT32 ON_BrepFace::DataCRC(ON__UINT32 current_remainder) const
01236 {
01237   current_remainder = ON_SurfaceProxy::DataCRC(current_remainder);
01238   current_remainder = ON_CRC32(current_remainder,sizeof(m_face_index),&m_face_index);
01239   current_remainder = ON_CRC32(current_remainder,sizeof(m_bRev),&m_bRev);
01240   current_remainder = m_li.DataCRC(current_remainder);
01241 
01242   return current_remainder;
01243 }
01244 
01245 ON__UINT32 ON_Brep::DataCRC(ON__UINT32 current_remainder) const
01246 {
01247   current_remainder = m_V.DataCRC(current_remainder);
01248   current_remainder = m_E.DataCRC(current_remainder);
01249   current_remainder = m_F.DataCRC(current_remainder);
01250   return current_remainder;
01251 }
01252 
01253 void ON_Brep::DestroyMesh( ON::mesh_type mt, bool bDeleteMesh )
01254 {
01255   const int fcnt = m_F.Count();
01256   int fi;
01257   for ( fi = 0; fi < fcnt; fi++ ) {
01258     m_F[fi].DestroyMesh(mt,bDeleteMesh);
01259   }
01260 }
01261 
01262 int ON_Brep::GetMesh( ON::mesh_type mt, ON_SimpleArray<const ON_Mesh*>& meshes ) const
01263 {
01264   int fcnt = m_F.Count();
01265   int fi;
01266   int null_count = 0;
01267   meshes.Reserve( meshes.Count() + fcnt );
01268   for ( fi = 0; fi < fcnt; fi++ )
01269   {
01270     const ON_Mesh* mesh = m_F[fi].Mesh(mt);
01271     meshes.Append( mesh );
01272     if ( !mesh )
01273     {
01274       // If some meshes are missing, we have to put
01275       // a null in the return array so the face-to-mesh
01276       // correspondence is preserved.
01277       null_count++;
01278     }
01279   }
01280   if ( null_count == fcnt )
01281   {
01282     // If ALL the meshes are missing, return 0.
01283     meshes.SetCount(meshes.Count()-fcnt);
01284     fcnt = 0;
01285   }
01286   return fcnt;
01287 }
01288 
01289 
01290 int ON_Brep::Dimension() const
01291 {
01292   return (m_V.Count() > 0) ? 3 : 0;
01293 }
01294 
01295 static void ON_BrepTransformSwapSrfHelper( ON_Brep& brep, ON_NurbsSurface* nurbs_srf, int si )
01296 {
01297   // Replace plane surface which could not be properly transformed
01298   // with nurbs_surface.
01299   ON_Surface* old_srf = brep.m_S[si];
01300   ON_UserDataHolder udholder;
01301   udholder.MoveUserDataFrom(*old_srf);
01302   udholder.MoveUserDataTo(*nurbs_srf,false);
01303   brep.m_S[si] = nurbs_srf;
01304   
01305   // Update faces to use new surface.
01306   const int fcount = brep.m_F.Count();
01307   ON_BrepFace* f = brep.m_F.Array();
01308   for ( int fi = 0; fi < fcount; fi++ )
01309   {
01310     if (f[fi].m_si == si || f[fi].ProxySurface() == old_srf )
01311     {
01312       const bool bIsTransposed = f[fi].ProxySurfaceIsTransposed();
01313       f[fi].SetProxySurface(nurbs_srf);
01314       if (bIsTransposed)
01315         f[fi].ON_SurfaceProxy::Transpose();
01316     }
01317   }
01318 
01319   delete old_srf;
01320 }
01321 
01322 ON_BOOL32 ON_Brep::Transform( const ON_Xform& xform )
01323 {
01324   int i, count;
01325   ON_BOOL32 rc = true;
01326   
01327   DestroyRuntimeCache();
01328 
01329   int is_similarity = xform.IsSimilarity();
01330   double det = xform.Determinant();
01331 
01332   if ( 1 != is_similarity )
01333   {
01334     // this will cause the solid flag to be
01335     // recaclulated the next time it is needed.
01336     m_is_solid = 0;
01337   }
01338 
01339 
01340   // 13 Feb 2003 Dale Lear:
01341   // Transforming the bbox makes it grow too large under repeated
01342   // rotations.  So, we will destroy it here and reset it below.
01343   //m_bbox.Transform(xform);
01344   m_bbox.Destroy();
01345 
01346   count = m_C3.Count();
01347   for ( i = 0; i < count; i++ ) 
01348   {
01349     if ( m_C3[i] ) 
01350     {
01351       if ( !m_C3[i]->Transform(xform) )
01352         rc = false;
01353     }
01354   }
01355 
01356   count = m_S.Count();
01357   for ( i = 0; i < count; i++ ) {
01358     if ( m_S[i] ) 
01359     
01360     {
01361       ON_NurbsSurface* nurbs_srf = 0;
01362       if ( !is_similarity )
01363       {
01364         if (    1 == m_S[i]->Degree(0) // degree tests reduce calls to
01365              && 1 == m_S[i]->Degree(1) // slow ON_PlaneSurface::Cast()
01366              && 0 != ON_PlaneSurface::Cast(m_S[i]) )
01367         {
01368           nurbs_srf = ON_NurbsSurface::New();
01369           if ( !m_S[i]->GetNurbForm(*nurbs_srf) )
01370           {
01371             delete nurbs_srf;
01372             nurbs_srf = 0;
01373           }
01374           else if ( !nurbs_srf->Transform(xform) )
01375           {
01376             delete nurbs_srf;
01377             nurbs_srf = 0;
01378           }
01379         }
01380       }
01381 
01382       if ( !m_S[i]->Transform(xform) )
01383       {
01384         if ( nurbs_srf )
01385         {
01386           ON_BrepTransformSwapSrfHelper(*this,nurbs_srf,i);
01387           nurbs_srf = 0;
01388         }
01389         else
01390         {
01391           rc = false;
01392         }
01393       }
01394       else if ( nurbs_srf )
01395       {
01396         // make sure transformation was good
01397         ON_Interval u = nurbs_srf->Domain(0);
01398         ON_Interval v = nurbs_srf->Domain(1);
01399         for ( int ui = 0; ui < 2 && nurbs_srf; ui++ ) for (int vi = 0; vi < 2 && nurbs_srf; vi++)
01400         {
01401           ON_3dPoint P = nurbs_srf->PointAt(u[ui],v[vi]);
01402           ON_3dPoint Q = m_S[i]->PointAt(u[ui],v[vi]);
01403           if ( P.DistanceTo(Q) > ON_ZERO_TOLERANCE )
01404           {
01405             ON_BrepTransformSwapSrfHelper(*this,nurbs_srf,i);
01406             nurbs_srf = 0;
01407             break;
01408           }
01409         }
01410         if ( nurbs_srf )
01411         {
01412           delete nurbs_srf;
01413           nurbs_srf = 0;
01414         }
01415       }
01416     }
01417   }
01418 
01419   count = m_V.Count();
01420   for ( i = 0; i < count; i++ ) {
01421     if ( !m_V[i].Transform(xform) )
01422       rc = false;
01423   }
01424 
01425   count = m_E.Count();
01426   for ( i = 0; i < count; i++ ) {
01427     m_E[i].TransformUserData(xform);
01428   }
01429 
01430   count = m_F.Count();
01431   for ( i = 0; i < count; i++ ) 
01432   {
01433     ON_BrepFace& face = m_F[i];
01434     face.TransformUserData(xform);
01435 
01436     // 13 Feb 2003 Dale Lear:
01437     // Transforming the bbox makes it grow too large under repeated
01438     // rotations.  So, we need to reset it.
01439     face.m_bbox.Destroy();
01440     const ON_Surface* srf = face.SurfaceOf();
01441     if ( 0 != srf )
01442     {
01443       face.m_bbox = srf->BoundingBox();
01444       if ( face.m_face_index != -1 )
01445         m_bbox.Union( face.m_bbox );
01446     }
01447 
01448     // 12 May 2003 Dale Lear - RR 10528
01449     //     Use surface evaluation to update rendermesh when 
01450     //     calling ON_Mesh::Transform() will map mesh normals
01451     //     to some thing different that the "true" surface
01452     //     normal.
01453     bool bEvMesh = ( fabs(det) <= ON_SQRT_EPSILON
01454                      || xform[3][0] != 0.0
01455                      || xform[3][1] != 0.0
01456                      || xform[3][2] != 0.0
01457                      || xform[3][3] != 1.0
01458                      );
01459     if ( 0 == srf )
01460       bEvMesh = false;
01461 
01462     if ( 0 != face.m_render_mesh )
01463     {
01464       if ( bEvMesh && face.m_render_mesh->EvaluateMeshGeometry(*srf) )
01465       {
01466         if ( face.m_bRev )
01467         {
01468           // 29 September 2003 Dale Lear
01469           //     Normals on render meshes (and face orientations)
01470           //     take face.m_bRev into account so that two sided
01471           //     materials work as expected.  EvaluateMeshGeometry()
01472           //     does not take face.m_bRev into account, so we need
01473           //     to reverse the face normals here.
01474           int ni, ncnt = face.m_render_mesh->m_N.Count();
01475           for ( ni = 0; ni < ncnt; ni++ )
01476           {
01477             face.m_render_mesh->m_N[ni].Reverse();
01478           }
01479         }
01480       }
01481       else
01482         face.m_render_mesh->Transform(xform);
01483     }
01484 
01485     if ( 0 != face.m_analysis_mesh )
01486     {
01487       // Dale Lear 30 March 2009 - bug 46766
01488       //   Evaluate analysis meshes when the transform involves scaling
01489       //   so curvature values are properly updated.
01490       bool bEvAnalysisMesh = bEvMesh;
01491       if ( !bEvAnalysisMesh )
01492       {
01493         ON_Xform tmp(xform);
01494         tmp.m_xform[0][3] = 0.0;
01495         tmp.m_xform[1][3] = 0.0;
01496         tmp.m_xform[2][3] = 0.0;
01497         if ( 1 != tmp.IsSimilarity() )
01498           bEvAnalysisMesh = true;
01499       }
01500       if ( !bEvAnalysisMesh || !face.m_analysis_mesh->EvaluateMeshGeometry(*srf) )
01501         face.m_analysis_mesh->Transform(xform);
01502     }
01503 
01504     if ( 0 != face.m_preview_mesh )
01505     {
01506       if ( !bEvMesh || !face.m_preview_mesh->EvaluateMeshGeometry(*srf) )
01507         face.m_preview_mesh->Transform(xform);
01508     }
01509   }
01510 
01511   // The call to transform user data needs to be last
01512   // so that the rest of the brep is in position.
01513   // In particular, ON_BrepRegionTopologyUserData::Transform
01514   // assumes the face bounding boxes are up to date.
01515   TransformUserData(xform);
01516 
01517   return rc;
01518 }
01519 
01521 // ON_Brep Creation Interface
01522 
01523 int 
01524 ON_Brep::AddTrimCurve( ON_Curve* pC )
01525 {
01526   int c2i = -1;
01527 
01528   if ( 0 != pC )
01529   {
01530     // 7 April 2003 Dale Lear:
01531     //    There are too many cases where bugs are caused by
01532     //    people attempting to use 3d curves for trims.  In
01533     //    all the cases encountered so far, the intent was
01534     //    to pass in a 2d curve, so...
01535 
01536     int dim = pC->Dimension();
01537 
01538     if ( dim != 2 )
01539     {
01540       ON_ERROR("ON_Brep::AddTrimCurve() go a non-2d curve - changing dim to 2.");
01541       pC->ChangeDimension(2);
01542       dim = pC->Dimension();
01543     }
01544 
01545     if ( 2 == dim )
01546     {
01547       c2i = m_C2.Count();
01548       m_C2.Append(pC);
01549     }
01550   }
01551   return c2i;
01552 }
01553 
01554 int 
01555 ON_Brep::AddEdgeCurve( ON_Curve* pC )
01556 {
01557   int c3i = -1;
01558   if ( 0 != pC )
01559   {
01560 
01561     int dim = pC->Dimension();
01562 
01563     if ( dim != 3 )
01564     {
01565       // 7 April 2003 Dale Lear: (See comment in ON_Brep::AddTrimCurve().)
01566       ON_ERROR("ON_Brep::AddEdgeCurve() got a non-3d curve - changing dim to 3.");
01567       pC->ChangeDimension(3);
01568       dim = pC->Dimension();
01569     }
01570     
01571     if ( 3 == dim )
01572     {
01573       c3i = m_C3.Count();
01574       m_C3.Append(pC);
01575     }
01576   }
01577   return c3i;
01578 }
01579 
01580 int 
01581 ON_Brep::AddSurface( ON_Surface* pS )
01582 {
01583   int si = -1;
01584   if ( pS && pS->Dimension() == 3 ) 
01585   {
01586     si = m_S.Count();
01587     m_S.Append(pS);
01588   }
01589   m_bbox.Destroy();
01590   m_is_solid = 0;
01591   return si;
01592 }
01593 
01594 ON_BrepVertex& 
01595 ON_Brep::NewVertex()
01596 {
01597   int vi = m_V.Count();
01598   m_V.Reserve(vi+1);
01599   m_V.SetCount(vi+1);
01600   ON_BrepVertex& vertex = m_V.Array()[vi];
01601   vertex.m_vertex_index = vi;
01602   vertex.point = ON_UNSET_POINT;
01603   vertex.m_tolerance = ON_UNSET_VALUE;
01604   return vertex;
01605 }
01606 
01607 ON_BrepVertex& 
01608 ON_Brep::NewVertex( ON_3dPoint vertex_point, double vertex_tolerance )
01609 {
01610   ON_BrepVertex& vertex = NewVertex();
01611   vertex.point = vertex_point;
01612   vertex.m_tolerance = vertex_tolerance;
01613   return vertex;
01614 }
01615 
01616 ON_BrepEdge& 
01617 ON_Brep::NewEdge( int c3i )
01618 {
01619   int ei = m_E.Count();
01620   ON_BrepEdge& edge = m_E.AppendNew();
01621   edge.m_tolerance = ON_UNSET_VALUE;
01622   edge.m_edge_index = ei;
01623   edge.m_c3i = c3i;
01624   if ( edge.m_c3i >= 0 && edge.m_c3i < m_C3.Count() ) 
01625   {
01626     edge.SetProxyCurve(m_C3[edge.m_c3i]);
01627   }
01628   edge.m_brep = this;
01629   return edge;
01630 }
01631 
01632 ON_BrepEdge& 
01633 ON_Brep::NewEdge( ON_BrepVertex& v0, ON_BrepVertex& v1, 
01634                   int c3i, const ON_Interval* edomain,
01635                   double edge_tolerance )
01636 {
01637   ON_BrepEdge& edge = NewEdge(c3i);
01638   edge.m_vi[0] = v0.m_vertex_index;
01639   edge.m_vi[1] = v1.m_vertex_index;
01640   v0.m_ei.Append(edge.m_edge_index);
01641   v1.m_ei.Append(edge.m_edge_index);
01642   if ( edomain && edomain->IsIncreasing() ) {
01643     ON_Interval edom;
01644     edom.Intersection( edge.ProxyCurveDomain(), *edomain );
01645     if ( edom.IsIncreasing() )
01646       edge.SetProxyCurveDomain(edom);
01647   }
01648   edge.m_tolerance = edge_tolerance;
01649   return edge;
01650 }
01651 
01652 bool ON_Brep::SetEdgeCurve( 
01653   ON_BrepEdge& edge,
01654   int c3_index,
01655   const ON_Interval* sub_domain
01656   )
01657 {
01658   bool rc = false;
01659   if ( c3_index == - 1 && !sub_domain )
01660   {
01661     edge.m_c3i = -1;
01662     edge.SetProxyCurve(0);
01663     rc = true;
01664   }
01665   else if ( c3_index >= 0 && c3_index <= m_C3.Count() && m_C3[c3_index] )
01666   {
01667     ON_Interval curve_domain = m_C3[c3_index]->Domain();
01668     if ( !sub_domain || (sub_domain->IsIncreasing() && curve_domain.Includes(*sub_domain)) )
01669     {
01670       edge.m_c3i = c3_index;
01671       edge.SetProxyCurve( m_C3[c3_index], 
01672                           (sub_domain) ? *sub_domain : curve_domain
01673                           );
01674       rc = true;
01675     }
01676   }
01677   return rc;
01678 }
01679 
01680 bool ON_Brep::SetTrimCurve( 
01681   ON_BrepTrim& trim,
01682   int c2_index,
01683   const ON_Interval* sub_domain
01684   )
01685 {
01686   bool rc = false;
01687   if ( c2_index == - 1 && !sub_domain )
01688   {
01689     trim.m_c2i = -1;
01690     trim.SetProxyCurve(0);
01691     rc = true;
01692   }
01693   else if ( c2_index >= 0 && c2_index <= m_C2.Count() && m_C2[c2_index] )
01694   {
01695     ON_Interval curve_domain = m_C2[c2_index]->Domain();
01696     if ( !sub_domain || (sub_domain->IsIncreasing() && curve_domain.Includes(*sub_domain)) )
01697     {
01698       trim.m_c2i = c2_index;
01699       trim.SetProxyCurve( m_C2[trim.m_c2i], (sub_domain) ? *sub_domain : curve_domain );
01700       trim.m_pbox = m_C2[trim.m_c2i]->BoundingBox();
01701       trim.m_pbox.m_min.z = 0.0;
01702       trim.m_pbox.m_max.z = 0.0;
01703       rc = true;
01704     }
01705   }
01706   return rc;
01707 }
01708 
01709 ON_BrepTrim& 
01710 ON_Brep::NewTrim( int c2i )
01711 {
01712   m_is_solid = 0;
01713   int ti = m_T.Count();
01714   ON_BrepTrim& trim = m_T.AppendNew();
01715   trim.m_brep = this;
01716   trim.m_trim_index = ti;
01717   trim.m_ei = -1;
01718   trim.m_type = ON_BrepTrim::unknown;
01719   trim.m_bRev3d = false;
01720   trim.m_c2i = c2i;
01721   trim.m_iso = ON_Surface::not_iso;
01722   trim.m_li = -1;
01723   trim.m_tolerance[0] = ON_UNSET_VALUE;
01724   trim.m_tolerance[1] = ON_UNSET_VALUE;
01725   trim.m__legacy_2d_tol = ON_UNSET_VALUE;
01726   trim.m__legacy_3d_tol = ON_UNSET_VALUE;
01727   trim.m__legacy_flags = 0;
01728   const ON_Curve* c2 = (c2i >= 0 && c2i < m_C2.Count()) 
01729                      ? m_C2[c2i] 
01730                      : 0;
01731   if ( c2 ) 
01732   {
01733     trim.SetProxyCurve( c2 );
01734     trim.m_pbox = c2->BoundingBox();
01735     trim.m_pbox.m_min.z = 0.0;
01736     trim.m_pbox.m_max.z = 0.0;
01737   }
01738 
01739   return trim;
01740 }
01741 
01742 ON_BrepTrim& 
01743 ON_Brep::NewTrim( ON_BrepEdge& edge, ON_BOOL32 bRev3d, int c2i )
01744 {
01745   m_is_solid = 0;
01746   ON_BrepTrim& trim = NewTrim( c2i );
01747   trim.m_ei = edge.m_edge_index;
01748   edge.m_ti.Append(trim.m_trim_index);
01749   trim.m_vi[0] = edge.m_vi[bRev3d?1:0];
01750   trim.m_vi[1] = edge.m_vi[bRev3d?0:1];
01751   trim.m_bRev3d = bRev3d?true:false;
01752   return trim;
01753 }
01754 
01755 
01756 ON_BrepTrim& 
01757 ON_Brep::NewTrim( ON_BrepEdge& edge, ON_BOOL32 bRev3d, ON_BrepLoop& loop, int c2i )
01758 {
01759   m_is_solid = 0;
01760   const int edge_trim_count0 = edge.m_ti.Count();
01761   ON_BrepTrim& trim = NewTrim( edge, bRev3d, c2i );
01762   trim.m_li = loop.m_loop_index;
01763   loop.m_ti.Append(trim.m_trim_index);
01764   if ( c2i >= 0 && c2i < m_C2.Count() )
01765   {
01766     ON_Curve* c2 = m_C2[c2i];
01767     if ( c2 )
01768     {
01769       ON_BoundingBox c2_bbox;
01770       if ( c2->GetBoundingBox(c2_bbox) )
01771       {
01772         c2_bbox.m_min.z = 0.0;
01773         c2_bbox.m_max.z = 0.0;
01774         if ( loop.m_ti.Count() == 1 )
01775           loop.m_pbox = c2_bbox;
01776         else
01777           loop.m_pbox.Union(c2_bbox);
01778       }
01779     }
01780   }
01781 
01782   if ( edge_trim_count0 == 0 )
01783   {
01784     // This is the only trim using this edge.
01785     //
01786     // At the moment it's a boundary trim.  The type
01787     // will be changed to seam or mated when
01788     // another trim is added that uses this edge.
01789     trim.m_type = ON_BrepTrim::boundary;
01790   }
01791   else if ( edge_trim_count0 == 1 )
01792   {
01793     // there are now two trims using this edge
01794     ON_BrepTrim::TYPE trim_type = ON_BrepTrim::mated;
01795     ON_BrepTrim& other_trim = m_T[edge.m_ti[0]];
01796     if ( other_trim.m_li == loop.m_loop_index )
01797       trim_type = ON_BrepTrim::seam;
01798     else 
01799       trim_type = ON_BrepTrim::mated;
01800     trim.m_type = trim_type;
01801     other_trim.m_type = trim_type;
01802   }
01803   else
01804   {
01805     // non-manifold edge - need to check for mated or seam
01806     ON_BrepTrim::TYPE trim_type = ON_BrepTrim::mated;
01807     for ( int eti = 0; eti < edge_trim_count0; eti++ )
01808     {
01809       ON_BrepTrim& other_trim = m_T[edge.m_ti[eti]];
01810       if ( other_trim.m_li == loop.m_loop_index )
01811       {
01812         other_trim.m_type = ON_BrepTrim::seam;
01813         trim_type = ON_BrepTrim::seam;
01814         break;
01815       }
01816     }
01817     trim.m_type = trim_type;
01818   }
01819   return trim;
01820 }
01821 
01822 
01823 ON_BrepTrim& 
01824 ON_Brep::NewTrim( ON_BOOL32 bRev3d, ON_BrepLoop& loop, int c2i )
01825 {
01826   m_is_solid = 0;
01827   ON_BrepTrim& trim = NewTrim( c2i );
01828   trim.m_bRev3d = bRev3d ? true : false;
01829   trim.m_li = loop.m_loop_index;
01830   loop.m_ti.Append(trim.m_trim_index);
01831   if ( c2i >= 0 && c2i < m_C2.Count() )
01832   {
01833     const ON_Curve* c2 = m_C2[c2i];
01834     if ( c2 )
01835     {
01836       ON_BoundingBox c2_bbox;
01837       if ( c2->GetBoundingBox(c2_bbox) )
01838       {
01839         c2_bbox.m_min.z = 0.0;
01840         c2_bbox.m_max.z = 0.0;
01841         if ( loop.m_ti.Count() == 1 )
01842           loop.m_pbox = c2_bbox;
01843         else
01844           loop.m_pbox.Union( c2_bbox );
01845       }
01846     }
01847   }
01848   return trim;
01849 }
01850 
01851 ON_BrepTrim&
01852 ON_Brep::NewSingularTrim(const ON_BrepVertex& vertex,ON_BrepLoop& loop, ON_Surface::ISO iso, int c2i)
01853 {
01854   ON_BrepTrim& trim = NewTrim(false,loop,c2i);
01855   trim.m_vi[0] = vertex.m_vertex_index;
01856   trim.m_vi[1] = trim.m_vi[0];
01857   trim.m_type = ON_BrepTrim::singular;
01858   trim.m_iso = iso;
01859   trim.m_tolerance[0] = 0.0;
01860   trim.m_tolerance[1] = 0.0;
01861   trim.m__legacy_2d_tol = 0.0;
01862   trim.m__legacy_3d_tol = 0.0;
01863   trim.m__legacy_flags_Set(-1,1);
01864   return trim;
01865 }
01866 
01867 void ON_Brep::Append( const ON_Brep& b )
01868 {
01869   int i, j, jcnt;
01870 
01871   const int vcount0  = m_V.Count();
01872   const int ecount0  = m_E.Count();
01873   const int fcount0  = m_F.Count();
01874   const int tcount0  = m_T.Count();
01875   const int lcount0  = m_L.Count();
01876   const int c2count0 = m_C2.Count();
01877   const int c3count0 = m_C3.Count();
01878   const int scount0  = m_S.Count();
01879 
01880   const int vcount1  = b.m_V.Count();
01881   const int ecount1  = b.m_E.Count();
01882   const int fcount1  = b.m_F.Count();
01883   const int tcount1  = b.m_T.Count();
01884   const int lcount1  = b.m_L.Count();
01885   const int c2count1 = b.m_C2.Count();
01886   const int c3count1 = b.m_C3.Count();
01887   const int scount1  = b.m_S.Count();
01888 
01889   // need to duplicate geometry
01890   ON_Object* obj;
01891   ON_Curve* c;
01892   ON_Surface* s;
01893   for ( i = 0; i < scount1; i++ ) {
01894     s = b.m_S[i];
01895     if ( s ) {
01896       obj = s->Duplicate();
01897       s = ON_Surface::Cast(obj);
01898       if ( !s )
01899         delete obj;
01900     }
01901     m_S.Append(s);
01902   }
01903   for ( i = 0; i < c2count1; i++ ) {
01904     c = b.m_C2[i];
01905     if ( c ) {
01906       obj = c->Duplicate();
01907       c = ON_Curve::Cast(obj);
01908       if ( !c )
01909         delete obj;
01910     }
01911     m_C2.Append(c);
01912   }
01913   for ( i = 0; i < c3count1; i++ ) {
01914     c = b.m_C3[i];
01915     if ( c ) {
01916       obj = c->Duplicate();
01917       c = ON_Curve::Cast(obj);
01918       if ( !c )
01919         delete obj;
01920     }
01921     m_C3.Append(c);
01922   }
01923 
01924   // copy topology info
01925   m_V.Append( b.m_V.Count(), b.m_V.Array() );
01926   m_E.Append( b.m_E.Count(), b.m_E.Array() );
01927   m_F.Append( b.m_F.Count(), b.m_F.Array() );
01928   m_T.Append( b.m_T.Count(), b.m_T.Array() );
01929   m_L.Append( b.m_L.Count(), b.m_L.Array() );
01930 
01931   // update indices
01932   for ( i = 0; i < vcount1; i++ ) {
01933     ON_BrepVertex& vertex = m_V[vcount0+i];
01934     if ( vertex.m_vertex_index >= 0 )
01935       vertex.m_vertex_index += vcount0;
01936     else
01937       vertex.m_vertex_index = -1;
01938     jcnt = vertex.m_ei.Count();
01939     for ( j = 0; j < jcnt; j++ ) {
01940       if ( vertex.m_ei[j] >=0 )
01941         vertex.m_ei[j] += ecount0;
01942     }
01943   }
01944 
01945   for ( i = 0; i < ecount1; i++ ) 
01946   {
01947     ON_BrepEdge& edge = m_E[ecount0+i];
01948     if ( edge.m_edge_index >= 0 )
01949       edge.m_edge_index += ecount0;
01950     else
01951       edge.m_edge_index = -1;
01952     if ( edge.m_c3i >= 0 ) 
01953       edge.m_c3i += c3count0;
01954     if ( edge.m_vi[0] >= 0 )
01955       edge.m_vi[0] += vcount0;
01956     if ( edge.m_vi[1] >= 0 )
01957       edge.m_vi[1] += vcount0;
01958     jcnt = edge.m_ti.Count();
01959     for ( j = 0; j < jcnt; j++ ) {
01960       if ( edge.m_ti[j] >= 0 )
01961         edge.m_ti[j] += tcount0;
01962     }
01963     edge.m_brep = this;
01964     if (edge.m_c3i >= 0)
01965       edge.SetProxyCurve( m_C3[edge.m_c3i], b.m_E[i].ProxyCurveDomain() );
01966     else 
01967       edge.SetProxyCurve( 0, b.m_E[i].ProxyCurveDomain() );
01968     if ( b.m_E[i].ProxyCurveIsReversed() != edge.ProxyCurveIsReversed() )
01969       edge.ON_CurveProxy::Reverse();
01970     edge.SetDomain( b.m_E[i].Domain() );
01971   }
01972 
01973   for ( i = 0; i < tcount1; i++ ) {
01974     ON_BrepTrim& trim = m_T[tcount0+i];
01975     trim.m_brep = this;
01976     if ( trim.m_trim_index == i )
01977       trim.m_trim_index = tcount0+i;
01978     else
01979       trim.m_trim_index = -1;
01980     if ( trim.m_c2i >= 0 )
01981       trim.m_c2i += c2count0;
01982     if ( trim.m_ei >= 0 )
01983       trim.m_ei += ecount0;
01984     if ( trim.m_vi[0] >= 0 )
01985       trim.m_vi[0] += vcount0;
01986     if ( trim.m_vi[1] >= 0 )
01987       trim.m_vi[1] += vcount0;
01988     if ( trim.m_li >= 0 )
01989       trim.m_li += lcount0;
01990     if (trim.m_c2i >= 0)
01991       trim.SetProxyCurve( m_C2[trim.m_c2i], b.m_T[i].ProxyCurveDomain() );
01992     else 
01993       trim.SetProxyCurve( 0, b.m_T[i].ProxyCurveDomain() );
01994     if ( b.m_T[i].ProxyCurveIsReversed() != trim.ProxyCurveIsReversed() )
01995       trim.ON_CurveProxy::Reverse();
01996     trim.SetDomain( b.m_T[i].Domain() );
01997   }
01998 
01999   for ( i = 0; i < lcount1; i++ ) 
02000   {
02001     ON_BrepLoop& loop = m_L[lcount0+i];
02002     if ( loop.m_loop_index >= 0 )
02003       loop.m_loop_index += lcount0;
02004     else
02005       loop.m_loop_index = -1;
02006     jcnt = loop.m_ti.Count();
02007     for ( j = 0; j < jcnt; j++ ) {
02008       if ( loop.m_ti[j] >= 0)
02009         loop.m_ti[j] += tcount0;
02010     }
02011     if ( loop.m_fi >= 0 )
02012       loop.m_fi += fcount0;
02013     loop.m_brep = this;
02014   }
02015 
02016   for ( i = 0; i < fcount1; i++ ) {
02017     ON_BrepFace& face = m_F[fcount0+i];
02018     if ( face.m_face_index >= 0 )
02019       face.m_face_index += fcount0;
02020     else
02021       face.m_face_index = -1;
02022     jcnt = face.m_li.Count();
02023     for ( j = 0; j < jcnt; j++ ) {
02024       if ( face.m_li[j] >= 0 )
02025         face.m_li[j] += lcount0;
02026     }
02027     if ( face.m_si >= 0 )
02028     {
02029       face.m_si += scount0;
02030       face.SetProxySurface(m_S[face.m_si]);
02031     }
02032     else
02033     {
02034       face.SetProxySurface( 0 );
02035     }
02036     face.m_brep = this;
02037   }
02038 
02039   //grow bounding box if possible.  otherwise invalidate it.
02040   if (m_bbox.IsValid() && b.BoundingBox().IsValid())
02041     m_bbox.Union(b.BoundingBox());
02042   else m_bbox.Destroy();
02043 
02044   m_is_solid = 0;
02045 
02046   DestroyMesh(ON::any_mesh);
02047 
02048   return;
02049 }
02050 
02051 ON_BrepLoop& 
02052 ON_Brep::NewLoop( ON_BrepLoop::TYPE looptype )
02053 {
02054   m_is_solid = 0;
02055   int li = m_L.Count();
02056   m_L.Reserve(li+1);
02057   m_L.SetCount(li+1);
02058   ON_BrepLoop& loop =  m_L.Array()[li];
02059   loop.m_loop_index = li;
02060   loop.m_type = looptype;
02061   loop.m_brep = this;
02062   return loop;
02063 }
02064 
02065 ON_BrepLoop& 
02066 ON_Brep::NewLoop( ON_BrepLoop::TYPE looptype, ON_BrepFace& face )
02067 {
02068   m_is_solid = 0;
02069   ON_BrepLoop& loop = NewLoop( looptype );
02070   loop.m_fi = face.m_face_index;
02071   if ( ON_BrepLoop::outer == looptype )
02072   {
02073     // the index of the outer loop is always 
02074     // in face.m_li[0]
02075     face.m_li.Insert(0,loop.m_loop_index);
02076   }
02077   else
02078   {
02079     face.m_li.Append(loop.m_loop_index);
02080   }
02081   loop.m_brep = this;
02082   return loop;
02083 }
02084 
02085 ON_BrepLoop* ON_Brep::NewOuterLoop( int face_index )
02086 {
02087   m_is_solid = 0;
02088   int vid[4] = {-1,-1,-1,-1};
02089   int eid[4] = {-1,-1,-1,-1};
02090   ON_BOOL32 bRev3d[4] = {0,0,0,0};
02091   return NewOuterLoop( face_index,vid,eid,bRev3d);
02092 }
02093 
02094 ON_BrepFace& ON_Brep::NewFace( int si )
02095 {
02096   m_bbox.Destroy();
02097   m_is_solid = 0;
02098   int fi = m_F.Count();
02099   m_F.Reserve(fi+1);
02100   m_F.SetCount(fi+1);
02101   ON_BrepFace& face = m_F.Array()[fi];
02102   face.m_face_index = fi;
02103   face.m_si = si;
02104   face.m_brep = this;
02105   if ( si >= 0 && si < m_S.Count() )
02106   {
02107     face.SetProxySurface(m_S[si]);
02108     if ( face.ProxySurface() )
02109       face.m_bbox = face.ProxySurface()->BoundingBox();
02110   }
02111   return face;
02112 }
02113 
02114 ON_BrepFace* ON_Brep::NewFace( const ON_Surface& surface )
02115 {
02116   m_bbox.Destroy();
02117   m_is_solid = 0;
02118   ON_BrepFace* face = NULL;
02119   ON_Surface* pSurface = surface.DuplicateSurface();
02120   if ( pSurface )
02121   {
02122     int vid[4] = {-1,-1,-1,-1};
02123     int eid[4] = {-1,-1,-1,-1};
02124     ON_BOOL32 bRev3d[4] = {0,0,0,0};
02125     face = NewFace(pSurface,vid,eid,bRev3d);
02126   }
02127   return face;
02128 }
02129 
02130 
02131 
02132 bool
02133 ON_Brep::SetTrimIsoFlags()
02134 {
02135   bool rc = true;
02136   int fi;
02137   const int fcnt = m_F.Count();
02138   for ( fi = 0; fi < fcnt; fi++ ) {
02139     if ( !SetTrimIsoFlags( m_F[fi] ) )
02140       rc = false;
02141   }
02142   return rc;
02143 }
02144 
02145 bool
02146 ON_Brep::SetTrimIsoFlags( ON_BrepFace& face )
02147 {
02148   bool rc = true;
02149   int fli;
02150   const int face_loop_count = face.m_li.Count();
02151   for ( fli = 0; fli < face_loop_count; fli++ ) {
02152     if ( !SetTrimIsoFlags( m_L[face.m_li[fli]] ) )
02153       rc = false;
02154   }
02155   return rc;
02156 }
02157 
02158 bool
02159 ON_Brep::SetTrimIsoFlags( ON_BrepLoop& loop )
02160 {
02161   bool rc = true;
02162   int lti;
02163   const int loop_trim_count = loop.m_ti.Count();
02164   for ( lti = 0; lti < loop_trim_count; lti++ ) {
02165     if ( !SetTrimIsoFlags( m_T[loop.m_ti[lti]] ) )
02166       rc = false;
02167   }
02168   return rc;
02169 }
02170 
02171 bool
02172 ON_Brep::SetTrimIsoFlags( ON_BrepTrim& trim )
02173 {
02174   bool rc = false;
02175   if ( trim.m_li >= 0 && trim.m_li < m_L.Count() )
02176   {
02177     const int fi = m_L[trim.m_li].m_fi;
02178     if ( fi >= 0 && fi < m_F.Count() )
02179     {
02180       const ON_Surface* pS = m_F[fi].SurfaceOf();
02181       if ( pS )
02182       {
02183         const ON_Curve* pC = (trim.m_c2i >= 0 && trim.m_c2i < m_C2.Count()) 
02184                            ? m_C2[trim.m_c2i]
02185                            : 0;
02186         if ( pC ) 
02187         {
02188           ON_Interval PD = trim.ProxyCurveDomain(); 
02189           trim.m_iso = pS->IsIsoparametric( *pC, &PD);
02190           rc = true;
02191         }
02192       }
02193     }
02194   }
02195   return rc;
02196 }
02197 
02198 bool
02199 ON_Brep::SetTrimTypeFlags( ON_BOOL32 bLazy )
02200 {
02201   bool rc = true;
02202   int fi;
02203   const int fcnt = m_F.Count();
02204   for ( fi = 0; fi < fcnt; fi++ ) {
02205     if ( !SetTrimTypeFlags( m_F[fi], bLazy ) )
02206       rc = false;
02207   }
02208   return rc;
02209 }
02210 
02211 bool
02212 ON_Brep::SetTrimTypeFlags( ON_BrepFace& face, ON_BOOL32 bLazy )
02213 {
02214   bool rc = true;
02215   int fli;
02216   const int face_loop_count = face.m_li.Count();
02217   for ( fli = 0; fli < face_loop_count; fli++ ) {
02218     if ( !SetTrimTypeFlags( m_L[face.m_li[fli]], bLazy ) )
02219       rc = false;
02220   }
02221   return rc;
02222 }
02223 
02224 bool
02225 ON_Brep::SetTrimTypeFlags( ON_BrepLoop& loop, ON_BOOL32 bLazy )
02226 {
02227   bool rc = true;
02228   int lti;
02229   const int loop_trim_count = loop.m_ti.Count();
02230   for ( lti = 0; lti < loop_trim_count; lti++ ) {
02231     if ( !SetTrimTypeFlags( m_T[loop.m_ti[lti]], bLazy ) )
02232       rc = false;
02233   }
02234   return rc;
02235 }
02236 
02237 ON_BrepTrim::TYPE ON_Brep::TrimType( const ON_BrepTrim& trim, ON_BOOL32 bLazy ) const
02238 {
02239   ON_BrepTrim::TYPE trim_type = bLazy ? trim.m_type : ON_BrepTrim::unknown;
02240   int eti, other_ti;
02241 
02242   if ( trim_type == ON_BrepTrim::unknown && trim.m_li >= 0 && trim.m_li < m_L.Count() ) 
02243   {
02244     const ON_BrepLoop& loop = m_L[trim.m_li];
02245     if ( loop.m_type == ON_BrepLoop::ptonsrf )
02246       trim_type = ON_BrepTrim::ptonsrf;
02247     else if (loop.m_type == ON_BrepLoop::crvonsrf )
02248       trim_type = ON_BrepTrim::crvonsrf;
02249     else if ( trim.m_ei == -1 ) 
02250     {
02251       trim_type = ON_BrepTrim::singular;
02252     }
02253     else if ( trim.m_ei >= 0 && trim.m_ei < m_E.Count() ) 
02254     {
02255       const ON_BrepEdge& edge = m_E[trim.m_ei];
02256       if ( edge.m_ti.Count() == 1 && edge.m_ti[0] == trim.m_trim_index ) 
02257       {
02258         trim_type = ON_BrepTrim::boundary;
02259       }
02260       else if ( edge.m_ti.Count() > 1 ) 
02261       {
02262         trim_type = ON_BrepTrim::mated;
02263         // check for seam
02264         for ( eti = 0; eti < edge.m_ti.Count(); eti++ ) 
02265         {
02266           other_ti = edge.m_ti[eti];
02267           if ( other_ti != trim.m_trim_index && other_ti >= 0 && other_ti < m_T.Count() ) 
02268           {
02269             if ( m_T[other_ti].m_li == trim.m_li ) 
02270             {
02271               trim_type = ON_BrepTrim::seam;
02272               break;
02273             }
02274           }
02275         }
02276       }
02277     }
02278   }
02279   return trim_type;
02280 }
02281 
02282 bool
02283 ON_Brep::SetTrimTypeFlags( ON_BrepTrim& trim, ON_BOOL32 bLazy )
02284 {
02285   if ( !bLazy || trim.m_type == ON_BrepTrim::unknown)
02286     trim.m_type = TrimType(trim,false);
02287   return ((trim.m_type != ON_BrepTrim::unknown)?true:false);
02288 }
02289 
02290 bool
02291 ON_Brep::GetTrim2dStart(int trim_index,
02292                         ON_2dPoint& P
02293                         ) const
02294 
02295 {
02296   if (trim_index < 0 || trim_index >= m_T.Count())
02297     return false;
02298   const ON_BrepTrim& trim = m_T[trim_index];
02299   ON_3dPoint pp;
02300   if (!trim.EvPoint(trim.Domain()[0], pp)) 
02301     return false;
02302   P = pp;
02303   return true;
02304 }
02305 
02306 bool
02307 ON_Brep::GetTrim2dEnd(int trim_index,
02308                         ON_2dPoint& P
02309                         ) const
02310 
02311 {
02312   if (trim_index < 0 || trim_index >= m_T.Count())
02313     return false;
02314   const ON_BrepTrim& trim = m_T[trim_index];
02315   ON_3dPoint pp;
02316   if (!trim.EvPoint(trim.Domain()[1], pp))
02317     return false;
02318   P = pp;
02319   return true;
02320 }
02321 
02322 bool
02323 ON_Brep::GetTrim3dStart(int trim_index,
02324                         ON_3dPoint& P
02325                         ) const
02326 {
02327   const ON_Surface* srf = 0;
02328   ON_3dPoint uv;
02329   if ( trim_index >= 0 && trim_index < m_T.Count() )
02330   {
02331     const ON_BrepTrim& trim = m_T[trim_index];
02332     if ( trim.m_li >= 0 && trim.m_li < m_L.Count() )
02333     {
02334       const int fi = m_L[trim.m_li].m_fi;
02335       if ( fi >= 0 && fi < m_F.Count() )
02336       {
02337         if ( trim.Evaluate(trim.Domain()[0],0,3,&uv.x) )
02338         {
02339           srf = m_F[fi].SurfaceOf();
02340         }
02341       }
02342     }
02343   }
02344   return (srf && srf->EvPoint(uv.x, uv.y, P) ? true : false);
02345 }
02346 
02347 bool
02348 ON_Brep::GetTrim3dEnd(int trim_index,
02349                         ON_3dPoint& P
02350                         ) const
02351 
02352 {
02353   const ON_Surface* srf = 0;
02354   ON_3dPoint uv;
02355   if ( trim_index >= 0 && trim_index < m_T.Count() )
02356   {
02357     const ON_BrepTrim& trim = m_T[trim_index];
02358     if ( trim.m_li >= 0 && trim.m_li < m_L.Count() )
02359     {
02360       const int fi = m_L[trim.m_li].m_fi;
02361       if ( fi >= 0 && fi < m_F.Count() )
02362       {
02363         if ( trim.Evaluate(trim.Domain()[1],0,3,&uv.x) )
02364         {
02365           srf = m_F[fi].SurfaceOf();
02366         }
02367       }
02368     }
02369   }
02370   return (srf && srf->EvPoint(uv.x, uv.y, P) ? true : false);
02371 }
02372 
02373 
02374 ON_BrepLoop::TYPE 
02375 ON_Brep::ComputeLoopType( const ON_BrepLoop& loop ) const
02376 {
02377   // This function must always compute the type from the
02378   // 2d trim geometry.  NEVER modify this function to
02379   // return the input value of loop.m_type.
02380 
02381   ON_BrepLoop::TYPE loop_type = ON_BrepLoop::unknown;
02382 
02383   int loop_dir =  LoopDirection( loop );
02384   if ( 1 == loop_dir )
02385     loop_type = ON_BrepLoop::outer;
02386   else if ( -1 == loop_dir )
02387     loop_type = ON_BrepLoop::inner;
02388 
02389   // TODO check for gaps, slits, etc.
02390 
02391   /*
02392   int ugap_count = 0;
02393   int vgap_count = 0;
02394   double d, utol0, vtol0, loop_start_utol, loop_start_vtol;
02395   ON_3dPoint p0, p1, loop_start;
02396   ON_Interval srf_domain[2];
02397   if ( loop.m_fi >= 0 && loop.m_fi < m_F.Count() ) {
02398     const ON_BrepFace& face = m_F[loop.m_fi];
02399     if ( face.m_si >= 0 && face.m_si < m_S.Count() ) {
02400       ON_Surface* srf = m_S[face.m_si];
02401       srf_domain[0] = srf->Domain(0);
02402       srf_domain[1] = srf->Domain(1);
02403     }
02404   }
02405   const ON_2dPoint basePt( srf_domain[0].ParameterAt(0.5), srf_domain[1].ParameterAt(0.5) );
02406 
02407   const int trim_count = loop.m_ti.Count();
02408   for ( lti = 0; lti < trim_count; lti++ ) 
02409   {
02410     ti = loop.m_ti[lti];
02411     const ON_BrepTrim& trim = m_T[ti];
02412     p0 = trim.PointAtStart();
02413     u_tol0 = trim.m_tolerance[0];
02414     v_tol0 = trim.m_tolerance[1];
02415     if ( !lti ) 
02416     {
02417       loop_start = p0;
02418       loop_start_utol = trim.m_tolerance[0];
02419       loop_start_vtol = trim.m_tolerance[1];
02420     }
02421     else 
02422     {
02423       d = fabs(p0.x-p1.x);
02424       if ( d > utol0 + trim.m_tolerance[0] )
02425         ugap_count++;
02426       d = fabs(p0.y-p1.y);
02427       if ( d > vtol0 + trim.m_tolerance[1] )
02428         vgap_count++;
02429     }
02430     p1 = c2->PointAtEnd();
02431   }
02432   */
02433 
02434   return loop_type;
02435 }
02436 
02437 
02438 bool
02439 ON_Brep::IsValidTrim( int trim_index, ON_TextLog* text_log ) const
02440 {
02441   if ( trim_index < 0 || trim_index >= m_T.Count() )
02442   {
02443     if ( text_log )
02444     {
02445       text_log->Print("brep trim_index = %d (should be >=0 and <%d=brep.m_T.Count()).\n",
02446                       trim_index, m_T.Count());
02447     }
02448     return ON_BrepIsNotValid();
02449   }
02450   const ON_BrepTrim& trim = m_T[trim_index];
02451   if ( trim.m_trim_index != trim_index )
02452   {
02453     if ( text_log )
02454     {
02455       text_log->Print("brep.m_T[%d] trim is not valid.\n",trim_index);
02456       text_log->PushIndent();
02457       text_log->Print("trim.m_trim_index = %d (should be %d).\n",
02458                        trim.m_trim_index, trim_index );
02459       text_log->PopIndent();
02460     }
02461     return ON_BrepIsNotValid();
02462   }
02463   if ( !trim.IsValid(text_log) )
02464   {
02465     if ( text_log )
02466       text_log->Print("brep.m_T[%d] trim is not valid.\n",trim_index);
02467     return ON_BrepIsNotValid();
02468   }
02469   if ( trim.m_c2i < 0 || trim.m_c2i >= m_C2.Count() )
02470   {
02471     if ( text_log )
02472     {
02473       text_log->Print("brep.m_T[%d] trim is not valid.\n",trim_index);
02474       text_log->PushIndent();
02475       text_log->Print( "trim.m_c2i = %d (should be >=0 and <%d).\n", trim.m_c2i, 0, m_C2.Count() );
02476       text_log->PopIndent();
02477     }
02478     return ON_BrepIsNotValid();
02479   }
02480   const ON_Curve* pC = m_C2[trim.m_c2i];
02481   if ( !pC )
02482   {
02483     if ( text_log )
02484     {
02485       text_log->Print("brep.m_T[%d] trim is not valid.\n",trim_index);
02486       text_log->PushIndent();
02487       text_log->Print("trim.m_c2i = %d and ON_Brep.m_C2[%d] is NULL\n", trim.m_c2i, trim.m_c2i );
02488       text_log->PopIndent();
02489     }
02490     return ON_BrepIsNotValid();
02491   }
02492   int c2_dim = pC->Dimension();
02493   if ( c2_dim != 2 )
02494   {
02495     if ( text_log )
02496     {
02497       text_log->Print("brep.m_T[%d] trim is not valid.\n",trim_index);
02498       text_log->PushIndent();
02499       text_log->Print("trim.m_c2i = %d and ON_Brep.m_C2[%d]->Dimension() = %d (should be 2).\n", trim.m_c2i, trim.m_c2i, c2_dim );
02500       text_log->PopIndent();
02501     }
02502     return ON_BrepIsNotValid();
02503   }
02504 
02505   if ( pC != trim.ProxyCurve() )
02506   {
02507     if ( text_log )
02508     {
02509       text_log->Print("brep.m_T[%d] trim is not valid.\n",trim_index);
02510       text_log->PushIndent();
02511       text_log->Print("trim.ProxyCurve() != m_C2[trim.m_c2i].\n");
02512       text_log->PopIndent();
02513     }
02514     return ON_BrepIsNotValid();
02515   }
02516 
02517   //if ( trim.ProxyCurveIsReversed() )
02518   //{
02519   //  if ( text_log )
02520   //  {
02521   //    text_log->Print("brep.m_T[%d] trim is not valid.\n",trim_index);
02522   //    text_log->PushIndent();
02523   //    text_log->Print("trim.ProxyCurveIsReversed() is true\n");
02524   //    text_log->PopIndent();
02525   //  }
02526   //  return ON_BrepIsNotValid();
02527   //}
02528 
02529   ON_Interval trim_domain = trim.Domain();
02530   ON_Interval c2_domain = pC->Domain();
02531   if ( !trim_domain.IsIncreasing() )
02532   {
02533     if ( text_log )
02534     {
02535       text_log->Print("brep.m_T[%d] trim is not valid.\n",trim_index);
02536       text_log->PushIndent();
02537       text_log->Print("trim.Domain() = (%g,%g) (should be an increasing interval).\n", trim_domain[0], trim_domain[1] );
02538       text_log->PopIndent();
02539     }
02540     return ON_BrepIsNotValid();
02541   }
02542   if ( !c2_domain.Includes(trim_domain) )
02543   {
02544     if ( text_log )
02545     {
02546       text_log->Print("brep.m_T[%d] trim is not valid.\n",trim_index);
02547       text_log->PushIndent();
02548       text_log->Print("trim.Domain() = (%g,%g) is not included in brep.m_C2[trim.m_c2i=%d]->Domain() = (%g,%g)\n",
02549                       trim_domain[0], trim_domain[1], trim.m_c2i, c2_domain[0], c2_domain[1] );
02550       text_log->PopIndent();
02551     }
02552     return ON_BrepIsNotValid();
02553   }
02554   int vi0 = trim.m_vi[0];
02555   int vi1 = trim.m_vi[1];
02556   if ( vi0 < 0 || vi0 >= m_V.Count() )
02557   {
02558     if ( text_log )
02559     {
02560       text_log->Print("brep.m_T[%d] trim is not valid.\n",trim_index);
02561       text_log->PushIndent();
02562       text_log->Print("trim.m_vi[0] = %d (should be >= 0 and < %d=brep.m_V.Count()).\n",
02563                        trim_index, vi0, m_V.Count() );
02564       text_log->PopIndent();
02565     }
02566     return ON_BrepIsNotValid();
02567   }
02568   if ( vi1 < 0 || vi1 >= m_V.Count() )
02569   {
02570     if ( text_log )
02571     {
02572       text_log->Print("brep.m_T[%d] trim is not valid.\n",trim_index);
02573       text_log->PushIndent();
02574       text_log->Print("trim.m_vi[1] = %d (should be >= 0 and < %d=brep.m_V.Count()).\n",
02575                        trim_index, vi1, m_V.Count() );
02576       text_log->PopIndent();
02577     }
02578     return ON_BrepIsNotValid();
02579   }
02580   const int ei = trim.m_ei;
02581   int trim_eti = -1;
02582   if ( trim.m_type == ON_BrepTrim::singular ) 
02583   {
02584     // singular trim - no edge and 3d v0 = 3d v1
02585     if ( ei != -1 )
02586     {
02587       if ( text_log )
02588       {
02589         text_log->Print("brep.m_T[%d] trim is not valid.\n",trim_index);
02590         text_log->PushIndent();
02591         text_log->Print("trim.m_type = singular but trim.m_ei = %d (should be -1)\n",ei);
02592         text_log->PopIndent();
02593       }
02594       return ON_BrepIsNotValid();
02595     }
02596     if ( vi0 != vi1 )
02597     {
02598       if ( text_log )
02599       {
02600         text_log->Print("brep.m_T[%d] trim is not valid.\n",trim_index);
02601         text_log->PushIndent();
02602         text_log->Print("trim.m_type = singular but trim.m_vi[] = [%d,%d] (the m_vi[] values should be equal).\n",
02603                         vi0,vi1);
02604         text_log->PopIndent();
02605       }
02606       return ON_BrepIsNotValid();
02607     }
02608     if ( pC->IsClosed() )
02609     {
02610       if ( text_log )
02611       {
02612         text_log->Print("brep.m_T[%d] trim is not valid.\n",trim_index);
02613         text_log->PushIndent();
02614         text_log->Print("trim.m_type = singular but brep.m_C2[trim.m_c2i=%d]->IsClosed() is true.\n",
02615                         trim.m_c2i,trim.m_c2i);
02616         text_log->PopIndent();
02617       }
02618       return ON_BrepIsNotValid();
02619     }
02620   }
02621   else if ( trim.m_type != ON_BrepTrim::ptonsrf )
02622   {
02623     // non-singular non-ptonsrf trim must have valid edge
02624     if ( ei < 0 || ei >= m_E.Count() )
02625     {
02626       if ( text_log )
02627       {
02628         text_log->Print("brep.m_T[%d] trim is not valid.\n",trim_index);
02629         text_log->PushIndent();
02630         text_log->Print("trim.m_type != singular and trim.m_ei = %d (m_ei should be >=0 and <brep.m_E.Count()=%d\n",
02631                         trim.m_ei,m_E.Count());
02632         text_log->PopIndent();
02633       }
02634       return ON_BrepIsNotValid();
02635     }
02636     const ON_BrepEdge& edge = m_E[ei];
02637     if ( edge.m_vi[trim.m_bRev3d?1:0] != vi0 )
02638     {
02639       if ( text_log )
02640       {
02641         text_log->Print("brep.m_T[%d] trim is not valid.\n",trim_index);
02642         text_log->PushIndent();
02643         text_log->Print("trim.m_vi[0] != brep.m_E[trim.m_ei=%d].m_vi[trim.m_bRev3d?1:0]\n",ei);
02644         text_log->PopIndent();
02645       }
02646       return ON_BrepIsNotValid();
02647     }
02648     if ( edge.m_vi[trim.m_bRev3d?0:1] != vi1 )
02649     {
02650       if ( text_log )
02651       {
02652         text_log->Print("brep.m_T[%d] trim is not valid.\n",trim_index);
02653         text_log->PushIndent();
02654         text_log->Print("trim.m_vi[1] != brep.m_E[trim.m_ei=%d].m_vi[trim.m_bRev3d?0:1]\n",ei);
02655         text_log->PopIndent();
02656       }
02657       return ON_BrepIsNotValid();
02658     }
02659     if ( trim_domain == c2_domain && pC->IsClosed() ) 
02660     {
02661       // (open 2d trims can still have vi0 = vi1 on closed surfaces)
02662       if ( vi0 != vi1 )
02663       {
02664         if ( text_log )
02665         {
02666           text_log->Print("brep.m_T[%d] trim is not valid.\n",trim_index);
02667           text_log->PushIndent();
02668           text_log->Print("trim.m_vi[] = [%d,%d] but brep.m_C2[trim.m_c2i=%d]->IsClosed()=true\n",
02669                           vi0, vi1, trim.m_c2i );
02670           text_log->PopIndent();
02671         }
02672         return ON_BrepIsNotValid();
02673       }
02674     }
02675     else if ( vi0 == vi1 )
02676     {
02677       // TODO: check that trim start/end is a closed surface seam point.
02678     }
02679     else
02680     {
02681       // vi0 != vi1
02682       // TODO: check that trim start/end is not a closed surface seam point.
02683     }
02684     int i;
02685     for ( i = 0; i < edge.m_ti.Count(); i++ ) 
02686     {
02687       if ( edge.m_ti[i] == trim_index )
02688       {
02689         trim_eti = i;
02690         break;
02691       }
02692     }
02693 
02694     if ( trim_eti < 0 )
02695     {
02696       if ( text_log )
02697       {
02698         text_log->Print("brep.m_T[%d] trim is not valid.\n",trim_index);
02699         text_log->PushIndent();
02700         text_log->Print("trim index %d is not in brep.m_E[trim.m_ei=%d].m_ti[]\n",
02701                         trim_index, trim.m_ei );
02702         text_log->PopIndent();
02703       }
02704       return ON_BrepIsNotValid();
02705     }
02706 
02707     if ( edge.m_ti.Count() == 2 )
02708     {
02709       int other_ti = edge.m_ti[ (edge.m_ti[0]==trim_index)?1:0 ];
02710       if ( other_ti >= 0 && other_ti < m_T.Count() && other_ti != trim_index )
02711       {
02712         const ON_BrepTrim& other_trim = m_T[other_ti];
02713         if ( other_trim.m_li == trim.m_li )
02714         {
02715           if ( trim.m_type != ON_BrepTrim::seam )
02716           {
02717             if ( text_log )
02718             {
02719               text_log->Print("brep.m_T[%d] trim is not valid.\n",trim_index);
02720               text_log->PushIndent();
02721               text_log->Print("trim.m_type!=seam but brep.m_E[trim.m_ei=%d] references two trims in loop trim.m_li=%d.\n",
02722                               trim.m_ei,trim.m_li);
02723               text_log->PopIndent();
02724             }
02725             return ON_BrepIsNotValid();
02726           }
02727         }
02728       }
02729     }
02730   }
02731   if ( trim.m_li < 0 || trim.m_li >= m_L.Count() )
02732   {
02733     if ( text_log )
02734     {
02735       text_log->Print("brep.m_T[%d] trim is not valid.\n",trim_index);
02736       text_log->PushIndent();
02737       text_log->Print("trim.m_li = %d (should be >= 0 and <brep.m_L.Count()=%d\n", trim.m_li,m_L.Count() );
02738       text_log->PopIndent();
02739     }
02740     return ON_BrepIsNotValid();
02741   }
02742 
02743   if ( trim.m_ei >= 0 && trim_eti < 0 )
02744   {
02745     if ( text_log )
02746     {
02747       text_log->Print("brep.m_T[%d] trim is not valid.\n",trim_index);
02748       text_log->PushIndent();
02749       text_log->Print("brep.m_E[trim.m_ei=%d].m_ti[] does not reference the trim.\n",trim.m_ei);
02750       text_log->PopIndent();
02751     }
02752     return ON_BrepIsNotValid();
02753   }
02754 
02755 
02756   switch ( trim.m_type )
02757   {
02758   case ON_BrepTrim::unknown:
02759     {
02760       if ( text_log )
02761       {
02762         text_log->Print("brep.m_T[%d] trim is not valid.\n",trim_index);
02763         text_log->PushIndent();
02764         text_log->Print("trim.m_type = unknown (should be set to the correct ON_BrepTrim::TYPE value)\n");
02765         text_log->PopIndent();
02766       }
02767       return ON_BrepIsNotValid();
02768     }
02769     break;
02770   case ON_BrepTrim::boundary:
02771     {
02772       const ON_BrepLoop& loop = m_L[trim.m_li];
02773       const ON_BrepEdge& edge = m_E[trim.m_ei];
02774       if ( edge.m_ti.Count() > 1 )
02775       {
02776         if ( text_log )
02777         {
02778           text_log->Print("brep.m_T[%d] trim is not valid.\n",trim_index);
02779           text_log->PushIndent();
02780           text_log->Print("trim.m_type = boundary but brep.m_E[trim.m_ei=%d] has 2 or more trims.\n",trim.m_ei);
02781           text_log->PopIndent();
02782         }
02783         return ON_BrepIsNotValid();
02784       }
02785       if ( loop.m_type != ON_BrepLoop::outer && loop.m_type != ON_BrepLoop::inner )
02786       {
02787         if ( text_log )
02788         {
02789           text_log->Print("brep.m_T[%d] trim is not valid.\n",trim_index);
02790           text_log->PushIndent();
02791           text_log->Print("trim.m_type = boundary but brep.m_L[trim.m_li=%d].m_type is not inner or outer.\n",trim.m_li);
02792           text_log->PopIndent();
02793         }
02794         return ON_BrepIsNotValid();
02795       }
02796     }
02797     break;
02798   case ON_BrepTrim::mated:
02799     {
02800       const ON_BrepLoop& loop = m_L[trim.m_li];
02801       const ON_BrepEdge& edge = m_E[trim.m_ei];
02802       if ( edge.m_ti.Count() < 2 )
02803       {
02804         if ( text_log )
02805         {
02806           text_log->Print("brep.m_T[%d] trim is not valid.\n",trim_index);
02807           text_log->PushIndent();
02808           text_log->Print("trim.m_type = mated but brep.m_E[trim.m_ei=%d] only references this trim.\n",trim.m_ei);
02809           text_log->PopIndent();
02810         }
02811         return ON_BrepIsNotValid();
02812       }
02813       if ( loop.m_type != ON_BrepLoop::outer && loop.m_type != ON_BrepLoop::inner )
02814       {
02815         if ( text_log )
02816         {
02817           text_log->Print("brep.m_T[%d] trim is not valid.\n",trim_index);
02818           text_log->PushIndent();
02819           text_log->Print("trim.m_type = mated but brep.m_L[trim.m_li=%d].m_type is not inner or outer.\n",trim.m_li);
02820           text_log->PopIndent();
02821         }
02822         return ON_BrepIsNotValid();
02823       }
02824     }
02825     break;
02826   case ON_BrepTrim::seam:
02827     {
02828       const ON_BrepLoop& loop = m_L[trim.m_li];
02829       const ON_BrepEdge& edge = m_E[trim.m_ei];
02830       if ( edge.m_ti.Count() < 2 )
02831       {
02832         if ( text_log )
02833         {
02834           text_log->Print("brep.m_T[%d] trim is not valid.\n",trim_index);
02835           text_log->PushIndent();
02836           text_log->Print("trim.m_type = seam but brep.m_E[trim.m_ei=%d] < 2.\n",trim.m_ei);
02837           text_log->PopIndent();
02838         }
02839         return ON_BrepIsNotValid();
02840       }
02841       int other_ti = -1;
02842       for ( int eti = 0; eti < edge.m_ti.Count(); eti++ ) 
02843       {
02844         if ( trim_eti == eti )
02845           continue;
02846         int i = edge.m_ti[eti];
02847         if ( i == trim_index )
02848         {
02849           if ( text_log )
02850           {
02851             text_log->Print("brep.m_E[%d] trim is not valid.\n",trim.m_ei);
02852             text_log->PushIndent();
02853             text_log->Print("edge.m_ti[%d] = m_ti[%d] = %d.\n",trim_eti,eti,trim_index);
02854             text_log->PopIndent();
02855           }
02856           return ON_BrepIsNotValid();
02857         }
02858 
02859         if ( i < 0 || i >= m_T.Count() )
02860         {
02861           if ( text_log )
02862           {
02863             text_log->Print("brep.m_E[%d] trim is not valid.\n",trim.m_ei);
02864             text_log->PushIndent();
02865             text_log->Print("edge.m_ti[%d]=%d is not a valid m_T[] index.\n",eti,i);
02866             text_log->PopIndent();
02867           }
02868           return ON_BrepIsNotValid();
02869         }
02870 
02871         const ON_BrepTrim& other_trim = m_T[i];
02872         if ( other_trim.m_type == ON_BrepTrim::seam && other_trim.m_li == trim.m_li )
02873         {
02874           if ( other_ti < 0 )
02875             other_ti = i;
02876           else
02877           {
02878             if ( text_log )
02879             {
02880               text_log->Print("brep.m_T[%d,%d, or %d] trim is not valid.\n",trim_index,other_ti,i);
02881               text_log->PushIndent();
02882               text_log->Print("All three trims have m_type = seam m_ei=%d and m_li = %d.\n",trim.m_ei,trim.m_li);
02883               text_log->PopIndent();
02884             }
02885             return ON_BrepIsNotValid();
02886           }
02887         }
02888       }
02889 
02890       if ( other_ti < 0 )
02891       {
02892         if ( text_log )
02893         {
02894           text_log->Print("brep.m_T[%d] trim is not valid.\n",trim_index);
02895           text_log->PushIndent();
02896           text_log->Print("trim.m_type = seam but its other trim is not in the loop.\n");
02897           text_log->PopIndent();
02898         }
02899         return ON_BrepIsNotValid();
02900       }
02901 
02902       if ( loop.m_type != ON_BrepLoop::outer && edge.m_ti.Count() <= 2 )
02903       {
02904         if ( text_log )
02905         {
02906           text_log->Print("brep.m_T[%d] trim is not valid.\n",trim_index);
02907           text_log->PushIndent();
02908           text_log->Print("trim.m_type = seam, the edge is manifold, but brep.m_L[trim.m_li=%d].m_type is not outer.\n",trim.m_li);
02909           text_log->PopIndent();
02910         }
02911         return ON_BrepIsNotValid();
02912       }
02913       // 31 Jan 2002 - The definition of a seam trim is a trim that is connected to
02914       //               an edge, is part of loop, and exactly one other trim in the
02915       //               same loop is connected to the same edge.  This can happen
02916       //               on the interior of a surface (like an annulus in a plane)
02917       //               and on non-manifold edges.
02918       //if ( trim.m_iso != ON_Surface::W_iso && trim.m_iso != ON_Surface::N_iso &&
02919       //     trim.m_iso != ON_Surface::E_iso && trim.m_iso != ON_Surface::S_iso )
02920       //{
02921       //  if ( text_log )
02922       //  {
02923       //    text_log->Print("brep.m_T[%d] trim is not valid.\n",trim_index);
02924       //    text_log->PushIndent();
02925       //    text_log->Print("trim.m_type = seam but trim.m_iso != N/S/E/W_iso\n");
02926       //    text_log->PopIndent();
02927       //  }
02928       //  return ON_BrepIsNotValid();
02929       //}
02930     }
02931     break;
02932   case ON_BrepTrim::singular:
02933     // most requirements are checked above
02934     if ( trim.m_iso != ON_Surface::W_iso && trim.m_iso != ON_Surface::N_iso &&
02935          trim.m_iso != ON_Surface::E_iso && trim.m_iso != ON_Surface::S_iso )
02936     {
02937       if ( text_log )
02938       {
02939         text_log->Print("brep.m_T[%d] trim is not valid.\n",trim_index);
02940         text_log->PushIndent();
02941         text_log->Print("trim.m_type = singular but trim.m_iso != N/S/E/W_iso\n");
02942         text_log->PopIndent();
02943       }
02944       return ON_BrepIsNotValid();
02945     }
02946     break;
02947   case ON_BrepTrim::crvonsrf:
02948     {
02949       const ON_BrepLoop& loop = m_L[trim.m_li];
02950       if ( loop.m_type != ON_BrepLoop::crvonsrf )
02951       {
02952         return ON_BrepIsNotValid();
02953       }
02954       if ( trim.m_c2i < 0 || trim.m_c2i >= m_C2.Count() )
02955       {
02956         return ON_BrepIsNotValid();
02957       }
02958       if ( trim.m_ei < 0 || trim.m_ei >= m_E.Count() )
02959       {
02960         return ON_BrepIsNotValid();
02961       }
02962     }
02963     break;
02964   case ON_BrepTrim::ptonsrf:
02965     {
02966       const ON_BrepLoop& loop = m_L[trim.m_li];
02967       if ( loop.m_type != ON_BrepLoop::ptonsrf )
02968       {
02969         return ON_BrepIsNotValid();
02970       }
02971       if ( trim.m_ei != -1 )
02972       {
02973         return ON_BrepIsNotValid();
02974       }
02975       if ( trim.m_c2i != -1 )
02976       {
02977         return ON_BrepIsNotValid();
02978       }
02979       if ( trim.m_pbox.m_min.x != trim.m_pbox.m_max.x || trim.m_pbox.m_min.y != trim.m_pbox.m_max.y || trim.m_pbox.m_min.z != trim.m_pbox.m_max.z ) 
02980       {
02981         // m_pbox must be a single point that defines surface parameters of the point.
02982         return ON_BrepIsNotValid();
02983       }
02984       if ( trim.m_pbox.m_min.x == ON_UNSET_VALUE || trim.m_pbox.m_min.y == ON_UNSET_VALUE || trim.m_pbox.m_min.z != 0.0 ) 
02985       {
02986         // m_pbox must be a single point that defines surface parameters of the point.
02987         return ON_BrepIsNotValid();
02988       }
02989     }
02990     break;
02991 
02992   case ON_BrepTrim::slit:
02993     {
02994       if ( text_log )
02995       {
02996         text_log->Print("brep.m_T[%d] trim is not valid.\n",trim_index);
02997         text_log->PushIndent();
02998         text_log->Print("trim.m_type = ON_BrepTrim::slit (should be set to the correct ON_BrepTrim::TYPE value)\n");
02999         text_log->PopIndent();
03000       }
03001       return ON_BrepIsNotValid();
03002     }
03003     break;
03004 
03005   case ON_BrepTrim::trim_type_count:
03006     {
03007       if ( text_log )
03008       {
03009         text_log->Print("brep.m_T[%d] trim is not valid.\n",trim_index);
03010         text_log->PushIndent();
03011         text_log->Print("trim.m_type = type_count (should be set to the correct ON_BrepTrim::TYPE value)\n");
03012         text_log->PopIndent();
03013       }
03014       return ON_BrepIsNotValid();
03015     }
03016     break;
03017 
03018   default:
03019     {
03020       if ( text_log )
03021       {
03022         text_log->Print("brep.m_T[%d] trim is not valid.\n",trim_index);
03023         text_log->PushIndent();
03024         text_log->Print("trim.m_type = garbage (should be set to the correct ON_BrepTrim::TYPE value)\n");
03025         text_log->PopIndent();
03026       }
03027       return ON_BrepIsNotValid();
03028     }
03029     break;
03030   }
03031 
03032   if ( trim.m_tolerance[0] < 0.0 )
03033   {
03034     if ( text_log )
03035     {
03036       text_log->Print("brep.m_T[%d] trim is not valid.\n",trim_index);
03037       text_log->PushIndent();
03038       text_log->Print("trim.m_tolerance[0] = %g (should be >= 0.0)\n",trim.m_tolerance[0]);
03039       text_log->PopIndent();
03040     }
03041     return ON_BrepIsNotValid();
03042   }
03043   if ( trim.m_tolerance[1] < 0.0 )
03044   {
03045     if ( text_log )
03046     {
03047       text_log->Print("brep.m_T[%d] trim is not valid.\n",trim_index);
03048       text_log->PushIndent();
03049       text_log->Print("trim.m_tolerance[1] = %g (should be >= 0.0)\n",trim.m_tolerance[1]);
03050       text_log->PopIndent();
03051     }
03052     return ON_BrepIsNotValid();
03053   }
03054 
03055   if ( !trim.m_pbox.IsValid() )
03056   {
03057     if ( text_log )
03058     {
03059       text_log->Print("brep.m_T[%d] trim is not valid.\n",trim_index);
03060       text_log->PushIndent();
03061       text_log->Print("trim.m_pbox is not valid.\n");
03062       text_log->PopIndent();
03063     }
03064     return ON_BrepIsNotValid();
03065   }
03066 
03067   if ( trim.m_brep != this )
03068   {
03069     if ( text_log )
03070     {
03071       text_log->Print("brep.m_T[%d] trim is not valid.\n",trim_index);
03072       text_log->PushIndent();
03073       text_log->Print("trim.m_brep does not point to parent brep.\n");
03074       text_log->PopIndent();
03075     }
03076     return ON_BrepIsNotValid();
03077   }
03078 
03079   return true;
03080 }
03081 
03082 bool
03083 ON_Brep::IsValidLoop( int loop_index, ON_TextLog* text_log  ) const
03084 {
03085   if ( loop_index < 0 || loop_index >= m_L.Count() )
03086   {
03087     if ( text_log )
03088     {
03089       text_log->Print("brep loop_index = %d (should be >=0 and <%d=brep.m_L.Count()).\n",
03090                       loop_index, m_L.Count());
03091     }
03092     return ON_BrepIsNotValid();
03093   }
03094   const ON_BrepLoop& loop = m_L[loop_index];
03095   if ( loop.m_loop_index != loop_index )
03096   {
03097     if ( text_log )
03098     {
03099       text_log->Print("brep.m_L[%d] loop is not valid.\n",loop_index);
03100       text_log->PushIndent();
03101       text_log->Print("loop.m_loop_index = %d (should be %d).\n",
03102                        loop.m_loop_index, loop_index );
03103       text_log->PopIndent();
03104     }
03105     return ON_BrepIsNotValid();
03106   }
03107   if ( loop.m_fi < 0 || loop.m_fi >= m_F.Count() )
03108   {
03109     if ( text_log )
03110     {
03111       text_log->Print("brep.m_L[%d] loop is not valid.\n",loop_index);
03112       text_log->PushIndent();
03113       text_log->Print("loop.m_fi = %d (should be >= 0 and <brep.m_F.Count()=%d\n", loop.m_fi, m_F.Count() );
03114       text_log->PopIndent();
03115     }
03116     return ON_BrepIsNotValid();
03117   }
03118   const int loop_trim_count = loop.m_ti.Count();
03119   if ( loop_trim_count <= 0 )
03120   {
03121     if ( text_log )
03122     {
03123       text_log->Print("brep.m_L[%d] loop is not valid.\n",loop_index);
03124       text_log->PushIndent();
03125       text_log->Print("loop.m_ti.Count() is <= 0  (should be > 0)\n");
03126       text_log->PopIndent();
03127     }
03128     return ON_BrepIsNotValid();
03129   }
03130 
03131   if (    loop.m_type != ON_BrepLoop::outer 
03132        && loop.m_type != ON_BrepLoop::inner 
03133        && loop.m_type != ON_BrepLoop::slit 
03134        )
03135   {
03136     if ( text_log )
03137     {
03138       text_log->Print("brep.m_L[%d] loop is not valid.\n",loop_index);
03139       text_log->PushIndent();
03140       text_log->Print("loop.m_type = %d (must be %d=outer, %d=inner, or %d=slit)\n",
03141                       loop.m_type,ON_BrepLoop::outer,ON_BrepLoop::inner,ON_BrepLoop::slit);
03142       text_log->PopIndent();
03143     }
03144     return ON_BrepIsNotValid();
03145   }
03146 
03147 
03148   if ( loop.m_brep != this )
03149   {
03150     if ( text_log )
03151     {
03152       text_log->Print("loop.m_L[%d] loop is not valid.\n",loop_index);
03153       text_log->PushIndent();
03154       text_log->Print("loop.m_brep does not point to parent brep.\n");
03155       text_log->PopIndent();
03156     }
03157     return ON_BrepIsNotValid();
03158   }
03159 
03160   // make sure trims are valid
03161   int i, lti, ti;
03162   for ( lti = 0; lti < loop_trim_count; lti++ ) {
03163     ti = loop.m_ti[lti];
03164     for ( i = 0; i < lti; i++ ) {
03165       if ( loop.m_ti[i] == ti )
03166       {
03167         if ( text_log )
03168         {
03169           text_log->Print("brep.m_L[%d] loop is not valid.\n",loop_index);
03170           text_log->PushIndent();
03171           text_log->Print("loop.m_ti[%d] = loop.m_ti[%d] = %d (trim index can only appear once)\n",
03172                           lti, i, ti);
03173           text_log->PopIndent();
03174         }
03175         return ON_BrepIsNotValid();
03176       }
03177     }
03178     if ( !IsValidTrim( ti, text_log ) )
03179     {
03180       if ( text_log )
03181       {
03182         text_log->Print("brep.m_L[%d] loop is not valid.\n",loop_index);
03183         text_log->PushIndent();
03184         text_log->Print("brep.m_T[loop.m_ti[%d]=%d] is not valid.\n",
03185                         lti, ti);
03186         text_log->PopIndent();
03187       }
03188       return ON_BrepIsNotValid();
03189     }
03190     if ( m_T[ti].m_li != loop_index )
03191     {
03192       if ( text_log )
03193       {
03194         text_log->Print("brep.m_L[%d] loop is not valid.\n",loop_index);
03195         text_log->PushIndent();
03196         text_log->Print("brep.m_T[loop.m_ti[%d]=%d].m_li=%d (m_li should be %d).\n",
03197                         lti, ti, m_T[ti].m_li, loop_index );
03198         text_log->PopIndent();
03199       }
03200       return ON_BrepIsNotValid();
03201     }
03202   }
03203 
03204 
03205   if ( ON_BrepLoop::slit == loop.m_type )
03206   {
03207     if ( loop.m_ti.Count() < 2 || 0 != (loop.m_ti.Count() % 2) )
03208     {
03209       if ( text_log )
03210       {
03211         text_log->Print("brep.m_L[%d] loop is not valid.\n",loop_index);
03212         text_log->PushIndent();
03213         text_log->Print("loop.m_type = slit but loop has %d trims\n",loop.m_ti.Count());
03214         text_log->PopIndent();
03215       }
03216       return ON_BrepIsNotValid();
03217     }
03218 
03219     for ( int lti = 0; lti < loop.m_ti.Count(); lti++ )
03220     {
03221       int ti = loop.m_ti[lti];
03222       const ON_BrepTrim& trim = m_T[ti];
03223       if ( trim.m_type != ON_BrepTrim::seam )
03224       {
03225         if ( text_log )
03226         {
03227           text_log->Print("brep.m_L[%d] slit loop is not valid.\n",loop_index);
03228           text_log->PushIndent();
03229           text_log->Print("brep.m_T[loop.m_ti[%d]=%d].m_type = %d (should be %d = seam)\n",
03230                           lti,ti,trim.m_type,ON_BrepTrim::seam);
03231           text_log->PopIndent();
03232         }
03233         return ON_BrepIsNotValid();
03234       }
03235       switch( trim.m_iso )
03236       {
03237       case ON_Surface::W_iso:
03238       case ON_Surface::E_iso:
03239       case ON_Surface::S_iso:
03240       case ON_Surface::N_iso:
03241         {
03242           if ( text_log )
03243           {
03244             text_log->Print("brep.m_L[%d] slit loop is not valid.\n",loop_index);
03245             text_log->PushIndent();
03246             text_log->Print("brep.m_T[loop.m_ti[%d]=%d].m_iso = E/W/N/S_iso (should be interior)\n",
03247                             lti,ti);
03248             text_log->PopIndent();
03249           }
03250           return ON_BrepIsNotValid();
03251         }
03252         break;
03253 
03254       case ON_Surface::not_iso:
03255       case ON_Surface::x_iso:
03256       case ON_Surface::y_iso:
03257       case ON_Surface::iso_count:
03258         break;
03259       }
03260     }   
03261   }
03262 
03263 
03264   // make sure ends of trims jibe
03265   int ci0, ci1, next_lti;
03266   ON_3dPoint P0, P1;
03267   const ON_Curve *pC0, *pC1;
03268   for ( lti = 0; lti < loop_trim_count; lti++ ) 
03269   {
03270     //double x_tol = ON_ZERO_TOLERANCE;
03271     //double y_tol = ON_ZERO_TOLERANCE;
03272     const ON_BrepTrim& trim0 = m_T[loop.m_ti[lti]];
03273     next_lti = (lti+1)%loop_trim_count;
03274     const ON_BrepTrim& trim1 = m_T[loop.m_ti[next_lti]];
03275     ON_Interval trim0_domain = trim0.Domain();
03276     ON_Interval trim1_domain = trim1.Domain();
03277     ci0 = trim0.m_c2i;
03278     ci1 = trim1.m_c2i;
03279     pC0 = m_C2[ci0];
03280     pC1 = m_C2[ci1];
03281     P0 = pC0->PointAt( trim0_domain[1] ); // end of this 2d trim
03282     P1 = pC1->PointAt( trim1_domain[0] ); // start of next 2d trim
03283     if ( !(P0-P1).IsTiny() )
03284     {
03285       // 16 September 2003 Dale Lear - RR 11319
03286       //    Added relative tol check so cases with huge
03287       //    coordinate values that agreed to 10 places
03288       //    didn't get flagged as bad.
03289       double xtol = (fabs(P0.x) + fabs(P1.x))*1.0e-10;
03290       double ytol = (fabs(P0.y) + fabs(P1.y))*1.0e-10;
03291       if ( xtol < ON_ZERO_TOLERANCE )
03292         xtol = ON_ZERO_TOLERANCE;
03293       if ( ytol < ON_ZERO_TOLERANCE )
03294         ytol = ON_ZERO_TOLERANCE;
03295       double dx = fabs(P0.x-P1.x);
03296       double dy = fabs(P0.y-P1.y);
03297       if ( dx > xtol || dy > ytol )
03298       {
03299         if ( text_log )
03300         {
03301           text_log->Print("brep.m_L[%d] loop is not valid.\n",loop_index);
03302           text_log->PushIndent();
03303           text_log->Print("end of brep.m_T[loop.m_ti[%d]=%d]=(%g,%g) and start \n", lti, loop.m_ti[lti],P0.x,P0.y);
03304           text_log->Print("of brep.m_T[loop.m_ti[%d]=%d]=(%g,%g) do not match.\n",next_lti, loop.m_ti[next_lti],P1.x,P1.y);
03305           text_log->PopIndent();
03306         }
03307         return ON_BrepIsNotValid();
03308       }
03309     }
03310   }
03311 
03312   if ( !loop.m_pbox.IsValid() )
03313   {
03314     if ( text_log )
03315     {
03316       text_log->Print("brep.m_L[%d] loop is not valid.\n",loop_index);
03317       text_log->PushIndent();
03318       text_log->Print("loop.m_pbox is not valid\n");
03319       text_log->PopIndent();
03320     }
03321     return ON_BrepIsNotValid();
03322   }
03323 
03324   return true; 
03325 }
03326 
03327 
03328 bool
03329 ON_Brep::IsValidFace( int face_index, ON_TextLog* text_log  ) const
03330 {
03331   if ( face_index < 0 || face_index >= m_F.Count() )
03332   {
03333     if ( text_log )
03334     {
03335       text_log->Print("brep face_index = %d (should be >=0 and <%d=brep.m_F.Count()).\n",
03336                       face_index, m_F.Count());
03337     }
03338     return ON_BrepIsNotValid();
03339   }
03340   const ON_BrepFace& face = m_F[face_index];
03341   if ( face.m_face_index != face_index )
03342   {
03343     if ( text_log )
03344     {
03345       text_log->Print("brep.m_F[%d] face is not valid.\n",face_index);
03346       text_log->PushIndent();
03347       text_log->Print("face.m_face_index = %d (should be %d).\n",
03348                        face.m_face_index, face_index );
03349       text_log->PopIndent();
03350     }
03351     return ON_BrepIsNotValid();
03352   }
03353   if ( face.m_brep != this )
03354   {
03355     if ( text_log )
03356     {
03357       text_log->Print("brep.m_F[%d] face is not valid.\n",face_index);
03358       text_log->PushIndent();
03359       text_log->Print("face.m_brep does not point to parent brep.\n");
03360       text_log->PopIndent();
03361     }
03362     return ON_BrepIsNotValid();
03363   }
03364 
03365   const int face_loop_count = face.m_li.Count();
03366   if ( face_loop_count <= 0 )
03367   {
03368     if ( text_log )
03369     {
03370       text_log->Print("brep.m_F[%d] face is not valid.\n",face_index);
03371       text_log->PushIndent();
03372       text_log->Print("face.m_li.Count() <= 0 (should be >= 1)\n");
03373       text_log->PopIndent();
03374     }
03375     return ON_BrepIsNotValid();
03376   }
03377 
03378   int i, fli, li;
03379   for ( fli = 0; fli < face_loop_count; fli++ ) 
03380   {
03381     li = face.m_li[fli];
03382     for ( i = 0; i < fli; i++ ) 
03383     {
03384       if ( face.m_li[i] == li )
03385       {
03386         if ( text_log )
03387         {
03388           text_log->Print("brep.m_F[%d] face is not valid.\n",face_index);
03389           text_log->PushIndent();
03390           text_log->Print("face.m_li[%d]=face.m_li[%d]=%d (a loop index should appear once in face.m_li[])\n",
03391                           fli,i,li);
03392           text_log->PopIndent();
03393         }
03394         return ON_BrepIsNotValid();
03395       }
03396     }
03397     if ( !IsValidLoop( li, text_log ) )
03398     {
03399       if ( text_log )
03400       {
03401         text_log->Print("brep.m_F[%d] face is not valid.\n",face_index);
03402         text_log->PushIndent();
03403         text_log->Print("brep.m_L[face.m_li[%d]=%d] is not valid.\n",fli,li);
03404         text_log->PopIndent();
03405       }
03406       return ON_BrepIsNotValid();
03407     }
03408     const ON_BrepLoop& loop = m_L[li];
03409     if ( loop.m_loop_index != li )
03410     {
03411       if ( text_log )
03412       {
03413         text_log->Print("brep.m_F[%d] face is not valid.\n",face_index);
03414         text_log->PushIndent();
03415         text_log->Print("face.m_li[%d]=%d is a deleted loop\n",
03416                         fli,li);
03417         text_log->PopIndent();
03418       }
03419       return ON_BrepIsNotValid();
03420     }
03421     if ( loop.m_fi != face_index )
03422     {
03423       if ( text_log )
03424       {
03425         text_log->Print("brep.m_F[%d] face is not valid.\n",face_index);
03426         text_log->PushIndent();
03427         text_log->Print("face.m_li[%d]=%d but brep.m_L[%d].m_fi=%d (m_fi should be %d)\n",
03428                         fli,li,li,loop.m_fi,face_index);
03429         text_log->PopIndent();
03430       }
03431       return ON_BrepIsNotValid();
03432     }
03433     if ( fli == 0 ) 
03434     {
03435       if ( loop.m_type != ON_BrepLoop::outer )
03436       {
03437         if ( text_log )
03438         {
03439           text_log->Print("brep.m_F[%d] face is not valid.\n",face_index);
03440           text_log->PushIndent();
03441           text_log->Print("brep.m_L[face.m_li[0]=%d].m_type is not outer.\n",li);
03442           text_log->PopIndent();
03443         }
03444         return ON_BrepIsNotValid();
03445       }
03446     }
03447     else
03448     {
03449       if (   loop.m_type != ON_BrepLoop::slit 
03450            && loop.m_type != ON_BrepLoop::inner 
03451          )
03452       {
03453         if ( text_log )
03454         {
03455           text_log->Print("brep.m_F[%d] face is not valid.\n",face_index);
03456           text_log->PushIndent();
03457           text_log->Print("brep.m_L[face.m_li[%d]=%d].m_type is not inner or slit.\n",fli,li);
03458           text_log->PopIndent();
03459         }
03460         return ON_BrepIsNotValid();
03461       }
03462     }
03463   }
03464 
03465   const int si = face.m_si;
03466   if ( si < 0 || si >= m_S.Count() )
03467   {
03468     if ( text_log )
03469     {
03470       text_log->Print("brep.m_F[%d] face is not valid.\n",face_index);
03471       text_log->PushIndent();
03472       text_log->Print("face.m_si=%d (should be >=0 and <%d=m_S.Count())\n",
03473                       face.m_si,m_S.Count());                      
03474       text_log->PopIndent();
03475     }
03476     return ON_BrepIsNotValid();
03477   }
03478 
03479   if ( !m_S[si] )
03480   {
03481     if ( text_log )
03482     {
03483       text_log->Print("brep.m_F[%d] face is not valid.\n",face_index);
03484       text_log->PushIndent();
03485       text_log->Print("brep.m_S[face.m_si=%d] is NULL\n",face.m_si);
03486       text_log->PopIndent();
03487     }
03488     return ON_BrepIsNotValid();
03489   }
03490 
03491   if ( m_S[si] != face.ProxySurface() )
03492   {
03493     if ( text_log )
03494     {
03495       text_log->Print("brep.m_F[%d] face is not valid.\n",face_index);
03496       text_log->PushIndent();
03497       text_log->Print("brep.m_S[face.m_si=%d] != face.ProxySurface().\n",si);
03498       text_log->PopIndent();
03499     }
03500     return ON_BrepIsNotValid();
03501   }
03502 
03503   if ( face.ProxySurfaceIsTransposed() )
03504   {
03505     if ( text_log )
03506     {
03507       text_log->Print("brep.m_F[%d] face is not valid.\n",face_index);
03508       text_log->PushIndent();
03509       text_log->Print("face.ProxySurfaceIsTransposed() is true.\n");
03510       text_log->PopIndent();
03511     }
03512     return ON_BrepIsNotValid();
03513   }
03514 
03515   return true; 
03516 }
03517 
03518 bool
03519 ON_Brep::IsValidEdge( int edge_index, ON_TextLog* text_log ) const
03520 {
03521   if ( edge_index < 0 || edge_index >= m_E.Count() )
03522   {
03523     if ( text_log )
03524       text_log->Print("brep edge_index = %d (should be >=0 and <%d=brep.m_E.Count() ).\n",
03525                       edge_index, m_E.Count());
03526     return ON_BrepIsNotValid();
03527   }
03528   const ON_BrepEdge& edge = m_E[edge_index];
03529   if ( edge.m_brep != this )
03530   {
03531     if ( text_log )
03532     {
03533       text_log->Print("brep.m_E[%d] edge is not valid.\n",edge_index);
03534       text_log->PushIndent();
03535       text_log->Print("edge.m_brep does not point to parent brep\n");
03536       text_log->PopIndent();
03537     }
03538     return ON_BrepIsNotValid();
03539   }
03540   if ( edge.m_edge_index != edge_index )
03541   {
03542     if ( text_log )
03543     {
03544       text_log->Print("brep.m_E[%d] edge is not valid.\n",edge_index);
03545       text_log->PushIndent();
03546       text_log->Print("edge.m_edge_index = %d (should be %d).\n",
03547                        edge.m_edge_index, edge_index );
03548       text_log->PopIndent();
03549     }
03550     return ON_BrepIsNotValid();
03551   }
03552   if ( !edge.IsValid(text_log) )
03553   {
03554     if ( text_log )
03555     {
03556       text_log->Print("brep.m_E[%d] edge is not valid.\n",edge_index);
03557       text_log->PushIndent();
03558       text_log->Print("edge is not a valid.\n");
03559       text_log->PopIndent();
03560     }
03561     return ON_BrepIsNotValid();
03562   }
03563 
03564   const int ci = edge.m_c3i;
03565   if ( ci < 0 || ci >= m_C3.Count() )
03566   {
03567     if ( text_log )
03568     {
03569       text_log->Print("brep.m_E[%d] edge is not valid.\n",edge_index);
03570       text_log->PushIndent();
03571       text_log->Print("edge.m_c3i = %d (should be >=0 and <%d=m_C3.Count()\n",
03572                       edge.m_c3i,m_C3.Count() );
03573       text_log->PopIndent();
03574     }
03575     return ON_BrepIsNotValid();
03576   }
03577   
03578   if ( m_C3[ci] != edge.ProxyCurve() || 0 == m_C3[ci] )
03579   {
03580     if ( text_log )
03581     {
03582       text_log->Print("brep.m_E[%d] edge is not valid.\n",edge_index);
03583       text_log->PushIndent();
03584       text_log->Print("edge.m_curve != brep.m_C3[edge.m_c3i=%d]\n", edge.m_c3i );
03585       text_log->PopIndent();
03586     }
03587     return ON_BrepIsNotValid();
03588   }
03589   
03590   //if ( edge.ProxyCurveIsReversed() )
03591   //{
03592   //  if ( text_log )
03593   //  {
03594   //    text_log->Print("brep.m_E[%d] edge is not valid.\n",edge_index);
03595   //    text_log->PushIndent();
03596   //    text_log->Print("edge.ProxyCurveIsReversed() is true.\n" );
03597   //    text_log->PopIndent();
03598   //  }
03599   //  return ON_BrepIsNotValid();
03600   //}
03601 
03602   double t0, t1;
03603   if ( !edge.GetDomain( &t0, &t1 ) )
03604   {
03605     if ( text_log )
03606     {
03607       ON_Interval edom = edge.ProxyCurveDomain();
03608       text_log->Print("brep.m_E[%d] edge is not valid.\n",edge_index);
03609       text_log->PushIndent();
03610       text_log->Print( "edge.m_domain=(%g,%g) is not valid\n", edom[0], edom[1]);
03611       text_log->PopIndent();
03612     }
03613     return ON_BrepIsNotValid();
03614   }
03615   const int vi0 = edge.m_vi[0];
03616   const int vi1 = edge.m_vi[1];
03617   if ( vi0 < 0 || vi0 >= m_V.Count() )
03618   {
03619     if ( text_log )
03620     {
03621       text_log->Print("brep.m_E[%d] edge is not valid.\n",edge_index);
03622       text_log->PushIndent();
03623       text_log->Print("edge.m_vi[0]=%d (should be >=0 and <%d=m_V.Count()\n",
03624                        vi0, m_V.Count() );
03625       text_log->PopIndent();
03626     }
03627     return ON_BrepIsNotValid();
03628   }
03629   if ( vi1 < 0 || vi1 >= m_V.Count() )
03630   {
03631     if ( text_log )
03632     {
03633       text_log->Print("brep.m_E[%d] edge is not valid.\n",edge_index);
03634       text_log->PushIndent();
03635       text_log->Print("edge.m_vi[1]=%d (should be >=0 and <%d=m_V.Count()\n",
03636                        vi1, m_V.Count() );
03637       text_log->PopIndent();
03638     }
03639     return ON_BrepIsNotValid();
03640   }
03641   int evi;
03642   for ( evi = 0; evi < 2; evi++ ) 
03643   {
03644     const ON_BrepVertex& vertex = m_V[edge.m_vi[evi]];
03645 
03646     if ( edge.m_vi[evi] != vertex.m_vertex_index )
03647     {
03648       if ( text_log )
03649       {
03650         text_log->Print("brep.m_E[%d] edge is not valid.\n",edge_index);
03651         text_log->PushIndent();
03652         text_log->Print("edge.m_vi[%d]=%d is a deleted vertex\n",
03653                          evi,edge.m_vi[evi] );
03654         text_log->PopIndent();
03655       }
03656       return ON_BrepIsNotValid();
03657     }
03658 
03659 
03660     const int vertex_edge_count = vertex.m_ei.Count();
03661     ON_BOOL32 bFoundIt = false;
03662     int vei;
03663     for ( vei = 0; vei < vertex_edge_count && !bFoundIt; vei++ ) {
03664       bFoundIt = (vertex.m_ei[vei] == edge_index);
03665     }
03666     if ( !bFoundIt )
03667     {
03668       if ( text_log )
03669       {
03670         text_log->Print("brep.m_E[%d] edge is not valid.\n",edge_index);
03671         text_log->PushIndent();
03672         text_log->Print("edge.m_vi[%d]=%d but edge is not referenced in m_V[%d].m_ei[]\n",
03673                          evi,edge.m_vi[evi],edge.m_vi[evi] );
03674         text_log->PopIndent();
03675       }
03676       return ON_BrepIsNotValid();
03677     }
03678   }
03679 
03680   if ( edge.IsClosed() ) {
03681     if ( vi0 != vi1 )
03682     {
03683       if ( text_log )
03684       {
03685         text_log->Print("brep.m_E[%d] edge is not valid.\n",edge_index);
03686         text_log->PushIndent();
03687         text_log->Print("edge.m_vi[]=(%d,%d) but edge.IsClosed() is true\n",
03688                          vi0,vi1);
03689         text_log->PopIndent();
03690       }
03691       return ON_BrepIsNotValid();
03692     }
03693   }
03694   else {
03695     if ( vi0 == vi1 )
03696     {
03697       if ( text_log )
03698       {
03699         text_log->Print("brep.m_E[%d] edge is not valid.\n",edge_index);
03700         text_log->PushIndent();
03701         text_log->Print("edge.m_vi[0]=edge.m_vi[1]=%d but edge.IsClosed() is false.\n",
03702                          vi0);
03703         text_log->PopIndent();
03704       }
03705       return ON_BrepIsNotValid();
03706     }
03707   }
03708 
03709   const int edge_trim_count = edge.m_ti.Count();
03710   if ( edge_trim_count < 0 )
03711   {
03712     if ( text_log )
03713     {
03714       text_log->Print("brep.m_E[%d] edge is not valid.\n",edge_index);
03715       text_log->PushIndent();
03716       text_log->Print("edge.m_ti.Count() < 0\n");
03717       text_log->PopIndent();
03718     }
03719     return ON_BrepIsNotValid();
03720   }
03721   int i, eti, ti;
03722   for (eti = 0; eti < edge_trim_count; eti++ )
03723   {
03724     ti = edge.m_ti[eti];
03725     if ( ti < 0 || ti >= m_T.Count() )
03726     {
03727       if ( text_log )
03728       {
03729         text_log->Print("brep.m_E[%d] edge is not valid.\n",edge_index);
03730         text_log->PushIndent();
03731         text_log->Print("edge.m_ti[%d]=%d (should be >=0 and <%d=m_T.Count())\n",eti,ti);
03732         text_log->PopIndent();
03733       }
03734       return ON_BrepIsNotValid();
03735     }
03736     if ( m_T[ti].m_trim_index != ti )
03737     {
03738       if ( text_log )
03739       {
03740         text_log->Print("brep.m_E[%d] edge is not valid.\n",edge_index);
03741         text_log->PushIndent();
03742         text_log->Print("edge.m_ti[%d]=%d is a deleted trim\n",eti,ti);
03743         text_log->PopIndent();
03744       }
03745       return ON_BrepIsNotValid();
03746     }
03747     for ( i = 0; i < eti; i++ ) 
03748     {
03749       if ( edge.m_ti[i] == ti )
03750       {
03751         if ( text_log )
03752         {
03753           text_log->Print("brep.m_E[%d] edge is not valid.\n",edge_index);
03754           text_log->PushIndent();
03755           text_log->Print("edge.m_ti[%d]=edge.m_ti[%d]=%d (a trim should be referenced once).\n",i,eti,ti);
03756           text_log->PopIndent();
03757         }
03758         return ON_BrepIsNotValid();
03759       }
03760     }
03761     const ON_BrepTrim& trim = m_T[ti];
03762     if ( trim.m_ei != edge_index )
03763     {
03764       if ( text_log )
03765       {
03766         text_log->Print("brep.m_E[%d] edge is not valid.\n",edge_index);
03767         text_log->PushIndent();
03768         text_log->Print("edge.m_ti[%d]=%d but brep.m_T[%d].m_ei=%d\n",eti,ti,ti,trim.m_ei);
03769         text_log->PopIndent();
03770       }
03771       return ON_BrepIsNotValid();
03772     }
03773   }
03774 
03775   if ( edge.m_tolerance < 0.0 )
03776   {
03777     if ( text_log )
03778     {
03779       text_log->Print("brep.m_E[%d] edge is not valid.\n",edge_index);
03780       text_log->PushIndent();
03781       text_log->Print("edge.m_tolerance=%g (should be >= 0.0)\n",edge.m_tolerance);
03782       text_log->PopIndent();
03783     }
03784     return ON_BrepIsNotValid();
03785   }
03786 
03787   return true;
03788 }
03789 
03790 bool
03791 ON_Brep::IsValidVertex( int vertex_index, ON_TextLog* text_log ) const
03792 {
03793   if ( vertex_index < 0 || vertex_index >= m_V.Count() )
03794   {
03795     if ( text_log )
03796       text_log->Print("brep vertex_index = %d (should be >=0 and <%d=brep.m_V.Count() ).\n",
03797                       vertex_index, m_V.Count());
03798     return ON_BrepIsNotValid();
03799   }
03800   const ON_BrepVertex& vertex = m_V[vertex_index];
03801   if ( vertex.m_vertex_index != vertex_index )
03802   {
03803     if ( text_log )
03804     {
03805       text_log->Print("brep.m_V[%d] vertex is not valid.\n",vertex_index);
03806       text_log->PushIndent();
03807       text_log->Print("vertex.m_vertex_index = %d (should be %d).\n",
03808                        vertex.m_vertex_index, vertex_index );
03809       text_log->PopIndent();
03810     }
03811     return ON_BrepIsNotValid();
03812   }
03813 
03814   const int vertex_edge_count = vertex.m_ei.Count();
03815   int i, j, vei, ei;
03816   for ( vei = 0; vei < vertex_edge_count; vei++ ) {
03817     ei = vertex.m_ei[vei];
03818     if ( ei < 0 || ei >= m_E.Count() )
03819     {
03820       if ( text_log )
03821       {
03822         text_log->Print("brep.m_V[%d] vertex is not valid.\n",vertex_index);
03823         text_log->PushIndent();
03824         text_log->Print("vertex.m_ei[%d] = %d (should be >=0 and <%d).\n", vei, ei, m_E.Count());
03825         text_log->PopIndent();
03826       }
03827       return ON_BrepIsNotValid();
03828     }
03829     const ON_BrepEdge& edge = m_E[ei];
03830     if ( ei != edge.m_edge_index )
03831     {
03832       if ( text_log )
03833       {
03834         text_log->Print("brep.m_V[%d] vertex is not valid.\n",vertex_index);
03835         text_log->PushIndent();
03836         text_log->Print("vertex.m_ei[%d] = %d is a deleted edge.\n", vei, ei);
03837         text_log->PopIndent();
03838       }
03839       return ON_BrepIsNotValid();
03840     }
03841     for ( i = 0; i < vei; i++ ) 
03842     {
03843       if ( vertex.m_ei[i] == ei ) 
03844       {
03845         // edge should be closed
03846         if ( edge.m_vi[0] != vertex_index || edge.m_vi[1] != vertex_index )
03847         {
03848           if ( text_log )
03849           {
03850             text_log->Print("brep.m_V[%d] vertex is not valid.\n",vertex_index);
03851             text_log->PushIndent();
03852             text_log->Print("vertex.m_ei[%d] and vertex.m_ei[%d] = %d but brep.m_E[%d].m_vi[0] = %d",
03853                              i,vei,ei,ei,edge.m_vi[0]);
03854             text_log->Print("and ON_Brep.m_E[%d].m_vi[1] = %d (both m_vi[] values should be %d).\n",
03855                             ei,edge.m_vi[1],vertex_index);
03856             text_log->PopIndent();
03857           }
03858           return ON_BrepIsNotValid();
03859         }
03860         for (j = i+1; j < vei; j++ ) 
03861         {
03862           if ( vertex.m_ei[j] == ei )
03863           {
03864             if ( text_log )
03865             {
03866               text_log->Print("brep.m_V[%d] vertex is not valid.\n",vertex_index);
03867               text_log->PushIndent();
03868               text_log->Print("vertex.m_ei[%d,%d,%d] = %d. An open edge index should appear once\n",i,vei,j,ei);
03869               text_log->Print("in vertex.m_ei[] and a closed edge index should appear twice.\n");
03870               text_log->PopIndent();
03871             }
03872             return ON_BrepIsNotValid();
03873           }
03874         }
03875         break;
03876       }
03877     }
03878     if ( edge.m_vi[0] != vertex_index && edge.m_vi[1] != vertex_index )
03879     {
03880       if ( text_log )
03881       {
03882         text_log->Print("brep.m_V[%d] vertex is not valid.\n",vertex_index);
03883         text_log->PushIndent();
03884         text_log->Print("vertex.m_ei[%d] = %d but ON_Brep.m_E[%d].m_vi[] = [%d,%d]. "
03885                         "At least one edge m_vi[] value should be %d.\n",
03886                         vei,ei,ei,edge.m_vi[0],edge.m_vi[1],vertex_index);
03887         text_log->PopIndent();
03888       }
03889       return ON_BrepIsNotValid();
03890     }
03891   }
03892 
03893   if ( vertex.m_tolerance < 0.0 )
03894   {
03895     if ( text_log )
03896     {
03897       text_log->Print("brep.m_V[%d] vertex is not valid.\n",vertex_index);
03898       text_log->PushIndent();
03899       text_log->Print("vertex.m_tolerace = %g (should be >= 0.0)\n",vertex.m_tolerance);
03900       text_log->PopIndent();
03901     }
03902     return ON_BrepIsNotValid();
03903   }
03904   return true;
03905 }
03906 
03907 
03908 
03909 static
03910 bool TestTrimPBox( const ON_BrepTrim& trim, ON_TextLog* text_log )
03911 {
03912   ON_3dPoint pt;
03913   double d;
03914   ON_BoundingBox pbox = trim.m_pbox;
03915 
03916   
03917   d = ON_SQRT_EPSILON*(fabs(pbox.m_min.x)+fabs(pbox.m_max.x));
03918   if ( d < ON_ZERO_TOLERANCE )
03919     d = ON_ZERO_TOLERANCE;
03920   pbox.m_min.x -= d;
03921   pbox.m_max.x += d;
03922 
03923   d = ON_SQRT_EPSILON*(fabs(pbox.m_min.y)+fabs(pbox.m_max.y));
03924   if ( d < ON_ZERO_TOLERANCE )
03925     d = ON_ZERO_TOLERANCE;
03926   pbox.m_min.y -= d;
03927   pbox.m_max.y += d;
03928 
03929   pt = trim.PointAtStart();
03930   if ( !pbox.IsPointIn(pt) )
03931   {
03932     if ( text_log )
03933        text_log->Print("ON_Brep.m_T[%d].m_pbox does not contain start of trim.\n",trim.m_trim_index);
03934     return false;
03935   }
03936 
03937   pt = trim.PointAtEnd();
03938 
03939   if ( !pbox.IsPointIn(pt) )
03940   {
03941     if ( text_log )
03942        text_log->Print("ON_Brep.m_T[%d].m_pbox does not contain end of trim.\n",trim.m_trim_index);
03943     return false;
03944   }
03945 
03946   pt = trim.PointAt(trim.Domain().ParameterAt(0.5));
03947   if ( !pbox.IsPointIn(pt) )
03948   {
03949     if ( text_log )
03950        text_log->Print("ON_Brep.m_T[%d].m_pbox does not contain middle of trim.\n",trim.m_trim_index);
03951     return false;
03952   }
03953 
03954   return true;
03955 }
03956 
03957 static
03958 bool CheckTrimOnSrfHelper( const ON_Interval& srf_domain0,
03959                            const ON_Interval& srf_domain1,
03960                            const ON_BrepTrim& trim,
03961                            ON_TextLog* text_log
03962                            )
03963 {
03964   // this check only works if the pline exists.
03965   const ON_BrepTrimPoint* tp = trim.m_pline.Array();
03966   int i, count = trim.m_pline.Count();
03967 
03968   /*
03969   June 08 2012 - Chuck - Changing a and b to -ON_ZERO_TOLERANCE and 1+ON_ZERO_TOLERANCE. Done so RR 106304 is considered a bad object.  Split, Trim, etc expect uv curves to
03970   be on the surface.  If you get a Check error here and feel the need to change this, 
03971   discuss first with Chuck or Dale L and document with RR item numbers. 
03972   const double a = -0.01;
03973   const double b =  1.01;
03974 
03975   26 June 2012 Chuck and Dale Lear
03976     Concerning bugs 
03977       http://dev.mcneel.com/bugtrack/?q=106304
03978       http://dev.mcneel.com/bugtrack/?q=107842
03979 
03980     We are moving the relative fuzz back to 1%
03981     because making it smaller is generating
03982     more tech support than it is worth at this 
03983     point.
03984 
03985     We did learn that 2d trim curves leak off the
03986     surface domain a bit fairly often and that
03987     forcing the 2d pline to be in the surface domain
03988     but leaving the 2d trim curve as is does not
03989     fix the bugs cited above.
03990   */
03991   const double a = -0.01;
03992   const double b =  1.01;
03993 
03994   double s,t;
03995   for ( i = 0; i < count; i++ )
03996   {
03997     s = srf_domain0.NormalizedParameterAt(tp[i].p.x);
03998     t = srf_domain1.NormalizedParameterAt(tp[i].p.y);
03999     if ( s < a || s > b || t < a || t > b )
04000     {
04001       if ( text_log )
04002       {
04003         text_log->Print("ON_Brep.m_T[%d] 2d curve is not inside surface domain.\n",trim.m_trim_index);
04004       }
04005       return false;
04006     }
04007   }
04008   return true;
04009 }
04010 
04011 static
04012 bool CheckLoopOnSrfHelper( const ON_Brep& brep, 
04013                            const ON_Interval& srf_domain0,
04014                            const ON_Interval& srf_domain1,
04015                            const ON_BrepLoop& loop,
04016                            ON_TextLog* text_log
04017                            )
04018 {
04019   for ( int lti = 0; lti < loop.m_ti.Count(); lti++ )
04020   {
04021     int ti = loop.m_ti[lti];
04022     if ( ti < 0 || ti >= brep.m_T.Count() )
04023       continue;
04024     if ( ! CheckTrimOnSrfHelper( srf_domain0, srf_domain1, brep.m_T[ti], text_log ) )
04025       return false;
04026   }
04027   return true;
04028 }
04029 
04030 ON_BOOL32
04031 ON_Brep::IsValid( ON_TextLog* text_log ) const
04032 {
04033   const int curve2d_count = m_C2.Count();
04034   const int curve3d_count = m_C3.Count();
04035   const int surface_count = m_S.Count();
04036   const int vertex_count  = m_V.Count();
04037   const int edge_count    = m_E.Count();
04038   const int trim_count    = m_T.Count();
04039   const int loop_count    = m_L.Count();
04040   const int face_count    = m_F.Count();
04041 
04042   int c2i, c3i, si, vi, ei, fi, ti, li;
04043 
04044   if ( 0 == face_count && 0 == edge_count && 0 == vertex_count )
04045   {
04046     if ( text_log )
04047       text_log->Print( "ON_Brep has no faces, edges, or vertices\n");
04048     return ON_BrepIsNotValid();
04049   }
04050 
04051   if ( 0 != face_count )
04052   {
04053     if ( 0 == edge_count )
04054     {
04055       if ( text_log )
04056         text_log->Print( "ON_Brep has no edges.\n");
04057       return ON_BrepIsNotValid();
04058     }
04059     if ( 0 == loop_count )
04060     {
04061       if ( text_log )
04062         text_log->Print( "ON_Brep has no loops.\n");
04063       return ON_BrepIsNotValid();
04064     }
04065     if ( 0 == surface_count )
04066     {
04067       if ( text_log )
04068         text_log->Print( "ON_Brep has no surfaces.\n");
04069       return ON_BrepIsNotValid();
04070     }
04071     if ( 0 == trim_count )
04072     {
04073       if ( text_log )
04074         text_log->Print( "ON_Brep has no trims.\n");
04075       return ON_BrepIsNotValid();
04076     }
04077     if ( 0 == curve2d_count )
04078     {
04079       if ( text_log )
04080         text_log->Print( "ON_Brep has no 2d curves.\n");
04081       return ON_BrepIsNotValid();
04082     }
04083   }
04084 
04085   if ( 0 != edge_count )
04086   {
04087     if ( 0 == curve3d_count )
04088     {
04089       if ( text_log )
04090         text_log->Print( "ON_Brep has no 3d curves.\n");
04091       return ON_BrepIsNotValid();
04092     }
04093     if ( 0 == vertex_count )
04094     {
04095       if ( text_log )
04096         text_log->Print( "ON_Brep has no vertices.\n");
04097       return ON_BrepIsNotValid();
04098     }
04099   }
04100 
04101   // check element indices match array positions
04102   for ( vi = 0; vi < vertex_count; vi++ ) 
04103   {
04104     if ( m_V[vi].m_vertex_index == -1 )
04105     {
04106       const ON_BrepVertex& vertex = m_V[vi];
04107       if ( vertex.m_ei.Count() > 0 )
04108       {
04109         if ( text_log )
04110           text_log->Print( "ON_Brep.m_V[%d] is deleted (m_vertex_index = -1) but vertex.m_ei.Count() = %d.\n",
04111                            vi, vertex.m_ei.Count() );
04112         return ON_BrepIsNotValid();
04113       }
04114     }
04115     else if ( m_V[vi].m_vertex_index != vi )
04116     {
04117       if ( text_log )
04118         text_log->Print( "ON_Brep.m_V[%d].m_vertex_index = %d (should be %d)\n",
04119                          vi, m_V[vi].m_vertex_index, vi );
04120       return ON_BrepIsNotValid();
04121     }
04122   }
04123 
04124   for ( ei = 0; ei < edge_count; ei++ ) 
04125   {
04126     if ( m_E[ei].m_edge_index == -1 )
04127     {
04128       const ON_BrepEdge& edge = m_E[ei];
04129       if ( edge.m_ti.Count() > 0 )
04130       {
04131         if ( text_log )
04132           text_log->Print( "ON_Brep.m_E[%d] is deleted (m_edge_index = -1) but edge.m_ti.Count() = %d.\n",
04133                            ei, edge.m_ti.Count() );
04134         return ON_BrepIsNotValid();
04135       }
04136       if ( edge.m_c3i != -1 )
04137       {
04138         if ( text_log )
04139           text_log->Print( "ON_Brep.m_E[%d] is deleted (m_edge_index = -1) but edge.m_c3i=%d (should be -1).\n",
04140                            ei, edge.m_c3i );
04141         return ON_BrepIsNotValid();
04142       }
04143       if ( edge.ProxyCurve() )
04144       {
04145         if ( text_log )
04146           text_log->Print( "ON_Brep.m_E[%d] is deleted (m_edge_index = -1) but edge.m_curve is not NULL.\n",
04147                            ei );
04148         return ON_BrepIsNotValid();
04149       }
04150       if ( edge.m_vi[0] != -1 )
04151       {
04152         if ( text_log )
04153           text_log->Print( "ON_Brep.m_E[%d] is deleted (m_edge_index = -1) but edge.m_vi[0]=%d (should be -1).\n",
04154                            ei, edge.m_vi[0] );
04155         return ON_BrepIsNotValid();
04156       }
04157       if ( edge.m_vi[1] != -1 )
04158       {
04159         if ( text_log )
04160           text_log->Print( "ON_Brep.m_E[%d] is deleted (m_edge_index = -1) but edge.m_vi[1]=%d (should be -1).\n",
04161                            ei, edge.m_vi[1] );
04162         return ON_BrepIsNotValid();
04163       }
04164     }
04165     else if ( m_E[ei].m_edge_index != ei )
04166     {
04167       if ( text_log )
04168         text_log->Print( "ON_Brep.m_E[%d].m_edge_index = %d (should be %d)\n",
04169                          ei, m_E[ei].m_edge_index, ei );
04170       return ON_BrepIsNotValid();
04171     }
04172   }
04173 
04174   for ( ti = 0; ti < trim_count; ti++ ) 
04175   {
04176     if ( m_T[ti].m_trim_index == -1 )
04177     {
04178       const ON_BrepTrim& trim = m_T[ti];
04179       if ( trim.m_ei != -1 )
04180       {
04181         if ( text_log )
04182           text_log->Print( "ON_Brep.m_T[%d] is deleted (m_trim_index = -1) but trim.m_ei=%d (should be -1).\n",
04183                            ti, trim.m_ei );
04184         return ON_BrepIsNotValid();
04185       }
04186       if ( trim.m_li != -1 )
04187       {
04188         if ( text_log )
04189           text_log->Print( "ON_Brep.m_T[%d] is deleted (m_trim_index = -1) but trim.m_li=%d (should be -1).\n",
04190                            ti, trim.m_li );
04191         return ON_BrepIsNotValid();
04192       }
04193       if ( trim.m_c2i != -1 )
04194       {
04195         if ( text_log )
04196           text_log->Print( "ON_Brep.m_T[%d] is deleted (m_trim_index = -1) but trim.m_c2i=%d (should be -1).\n",
04197                            ti, trim.m_c2i );
04198         return ON_BrepIsNotValid();
04199       }
04200       if ( trim.m_vi[0] != -1 )
04201       {
04202         if ( text_log )
04203           text_log->Print( "ON_Brep.m_T[%d] is deleted (m_trim_index = -1) but trim.m_vi[0]=%d (should be -1).\n",
04204                            ti, trim.m_vi[0] );
04205         return ON_BrepIsNotValid();
04206       }
04207       if ( trim.m_vi[1] != -1 )
04208       {
04209         if ( text_log )
04210           text_log->Print( "ON_Brep.m_T[%d] is deleted (m_trim_index = -1) but trim.m_vi[1]=%d (should be -1).\n",
04211                            ti, trim.m_vi[1] );
04212         return ON_BrepIsNotValid();
04213       }
04214     }
04215     else if ( m_T[ti].m_trim_index != ti  )
04216     {
04217       if ( text_log )
04218         text_log->Print( "ON_Brep.m_T[%d].m_trim_index = %d (should be %d)\n",
04219                          ti, m_T[ti].m_trim_index, ti );
04220       return ON_BrepIsNotValid();
04221     }
04222     else if ( !m_T[ti].IsValid( text_log ) )
04223     {
04224       if ( text_log )
04225         text_log->Print( "ON_Brep.m_T[%d] is not valid\n",ti );
04226       return ON_BrepIsNotValid();
04227     }
04228   }
04229 
04230   for ( li = 0; li < loop_count; li++ ) 
04231   {
04232     if ( m_L[li].m_loop_index == -1 )
04233     {
04234       const ON_BrepLoop& loop = m_L[li];
04235       if ( loop.m_fi != -1 )
04236       {
04237         if ( text_log )
04238           text_log->Print( "ON_Brep.m_L[%d] is deleted (m_loop_index = -1) but loop.m_fi=%d (should be -1).\n",
04239                            li, loop.m_fi );
04240         return ON_BrepIsNotValid();
04241       }
04242       if ( loop.m_ti.Count() > 0 )
04243       {
04244         if ( text_log )
04245           text_log->Print( "ON_Brep.m_L[%d] is deleted (m_loop_index = -1) but loop.m_ti.Count()=%d.\n",
04246                            li, loop.m_ti.Count() );
04247         return ON_BrepIsNotValid();
04248       }
04249     }
04250     else if ( m_L[li].m_loop_index != li )
04251     {
04252       if ( text_log )
04253         text_log->Print( "ON_Brep.m_L[%d].m_loop_index = %d (should be %d)\n",
04254                          li, m_L[li].m_loop_index, li );
04255       return ON_BrepIsNotValid();
04256     }
04257   }
04258 
04259   for ( fi = 0; fi < face_count; fi++ ) 
04260   {
04261     if ( m_F[fi].m_face_index == -1 )
04262     {
04263       const ON_BrepFace& face = m_F[fi];
04264       if ( face.m_si != -1 )
04265       {
04266         if ( text_log )
04267           text_log->Print( "ON_Brep.m_F[%d] is deleted (m_face_index = -1) but face.m_si=%d (should be -1).\n",
04268                            fi, face.m_si );
04269         return ON_BrepIsNotValid();
04270       }
04271       if ( face.ProxySurface() )
04272       {
04273         if ( text_log )
04274           text_log->Print( "ON_Brep.m_F[%d] is deleted (m_face_index = -1) but face.ProxySurface() is not NULL.\n",
04275                            fi );
04276         return ON_BrepIsNotValid();
04277       }
04278       if ( face.m_li.Count() > 0 )
04279       {
04280         if ( text_log )
04281           text_log->Print( "ON_Brep.m_F[%d] is deleted (m_face_index = -1) but face.m_li.Count()=%d.\n",
04282                            fi, face.m_li.Count() );
04283         return ON_BrepIsNotValid();
04284       }
04285     }
04286     else if ( m_F[fi].m_face_index != fi )
04287     {
04288       if ( text_log )
04289         text_log->Print( "ON_Brep.m_F[%d].m_face_index = %d (should be %d)\n",
04290                          fi, m_F[fi].m_face_index, fi );
04291       return ON_BrepIsNotValid();
04292     }
04293   }
04294 
04295   // check 2d curve geometry
04296   for ( c2i = 0; c2i < curve2d_count; c2i++ ) {
04297     if ( !m_C2[c2i] )
04298     {
04299       continue;
04300       // NULL 2d curves are ok if they are not referenced
04301       //if ( text_log )
04302       //  text_log->Print("ON_Brep.m_C2[%d] is NULL.\n",c2i);
04303       //return ON_BrepIsNotValid();
04304     }
04305     if ( !m_C2[c2i]->IsValid(text_log) )
04306     {
04307       if ( text_log )
04308         text_log->Print("ON_Brep.m_C2[%d] is invalid.\n",c2i);
04309       return ON_BrepIsNotValid();
04310     }
04311     int c2_dim = m_C2[c2i]->Dimension();
04312     if ( c2_dim != 2 )
04313     {
04314       if ( text_log )
04315         text_log->Print("ON_Brep.m_C2[%d]->Dimension() = %d (should be 2).\n", c2i, c2_dim );
04316       return ON_BrepIsNotValid();
04317     }
04318     const ON_PolyCurve* polycurve = ON_PolyCurve::Cast(m_C2[c2i]);
04319     if ( polycurve && polycurve->IsNested() )
04320     {
04321       if ( text_log )
04322         text_log->Print("ON_Brep.m_C2[%d] is a nested polycurve.\n", c2i );
04323       return ON_BrepIsNotValid();
04324     }
04325   }
04326 
04327   // check 3d curve geometry
04328   for ( c3i = 0; c3i < curve3d_count; c3i++ ) {
04329     if ( !m_C3[c3i] )
04330     {
04331       continue;
04332       // NULL 3d curves are ok if they are not referenced
04333       //if ( text_log )
04334       //  text_log->Print("ON_Brep.m_C3[%d] is NULL.\n",c3i);
04335       //return ON_BrepIsNotValid();
04336     }
04337     if ( !m_C3[c3i]->IsValid(text_log) )
04338     {
04339       if ( text_log )
04340         text_log->Print("ON_Brep.m_C3[%d] is invalid.\n",c3i);
04341       return ON_BrepIsNotValid();
04342     }
04343     int c3_dim = m_C3[c3i]->Dimension();
04344     if ( c3_dim != 3 )
04345     {
04346       if ( text_log )
04347         text_log->Print("ON_Brep.m_C3[%d]->Dimension() = %d (should be 3).\n", c3i, c3_dim );
04348       return ON_BrepIsNotValid();
04349     }
04350     const ON_PolyCurve* polycurve = ON_PolyCurve::Cast(m_C3[c3i]);
04351     if ( polycurve && polycurve->IsNested() )
04352     {
04353       if ( text_log )
04354         text_log->Print("ON_Brep.m_C3[%d] is a nested polycurve.\n", c3i );
04355       return ON_BrepIsNotValid();
04356     }
04357   }
04358 
04359   // check 3d surface geometry
04360   for ( si = 0; si < surface_count; si++ ) {
04361     if ( !m_S[si] )
04362     {
04363       continue;
04364       // NULL 3d surfaces are ok if they are not referenced
04365       //if ( text_log )
04366       //  text_log->Print("ON_Brep.m_S[%d] is NULL.\n",si);
04367       //return ON_BrepIsNotValid();
04368     }
04369     if ( !m_S[si]->IsValid(text_log) )
04370     {
04371       if ( text_log )
04372         text_log->Print("ON_Brep.m_S[%d] is invalid.\n",si);
04373       return ON_BrepIsNotValid();
04374     }
04375     int dim = m_S[si]->Dimension();
04376     if ( dim != 3 )
04377     {
04378       if ( text_log )
04379         text_log->Print("ON_Brep.m_S[%d]->Dimension() = %d (should be 3).\n", si, dim );
04380       return ON_BrepIsNotValid();
04381     }
04382   }
04383 
04384   // check vertices
04385   for ( vi = 0; vi < vertex_count; vi++ ) {
04386     if ( m_V[vi].m_vertex_index == -1 )
04387       continue;
04388     if ( !IsValidVertex( vi, text_log ) ) {
04389       if ( text_log )
04390         text_log->Print("ON_Brep.m_V[%d] is invalid.\n",vi);
04391       return ON_BrepIsNotValid();
04392     }
04393   }
04394 
04395   // check edges
04396   for ( ei = 0; ei < edge_count; ei++ ) 
04397   {
04398     if ( m_E[ei].m_edge_index == -1 )
04399       continue;
04400     if ( !IsValidEdge( ei, text_log ) ) {
04401       if ( text_log )
04402         text_log->Print("ON_Brep.m_E[%d] is invalid.\n",ei);
04403       return ON_BrepIsNotValid();
04404     }
04405   }
04406 
04407   // check faces
04408   for ( fi = 0; fi < face_count; fi++ ) 
04409   {
04410     if ( m_F[fi].m_face_index == -1 )
04411       continue;
04412     if ( !IsValidFace( fi, text_log ) ) {
04413       if ( text_log )
04414         text_log->Print("ON_Brep.m_F[%d] is invalid.\n",fi);
04415       return ON_BrepIsNotValid();
04416     }
04417   }
04418 
04419   // Check loops - this check is necessary at the brep level
04420   // to make sure there are no orphaned loops.
04421   // ON_Brep::IsValidLoop(), which is called by ON_Brep::IsValidFace(),
04422   // performs loop-trim bookkeeping checks on all loops that are referenced
04423   // by a face.
04424   for ( li = 0; li < loop_count; li++ )
04425   {
04426     const ON_BrepLoop& loop = m_L[li];
04427     if ( m_L[li].m_loop_index == -1 )
04428       continue;
04429     if ( loop.m_fi < 0 || loop.m_fi >= m_F.Count() )
04430     {
04431       if ( text_log )
04432         text_log->Print("ON_Brep.m_L[%d].m_fi = %d is not invalid.\n",li,loop.m_fi);
04433       return ON_BrepIsNotValid();
04434     }
04435     if ( m_F[loop.m_fi].m_face_index != loop.m_fi )
04436     {
04437       if ( text_log )
04438         text_log->Print("ON_Brep.m_L[%d].m_fi = %d is a deleted face.\n",li,loop.m_fi);
04439       return ON_BrepIsNotValid();
04440     }
04441 
04442     // This for() loop check is performed in IsValidLoop() which is 
04443     // called by IsValidFace() in the "check faces" loop above.  
04444     // I think it can be removed.  If anybody every sees this code
04445     // find a flaw, please tell Dale Lear.
04446     for ( int lti = 0; lti < loop.m_ti.Count(); lti++ )
04447     {
04448       ti = loop.m_ti[lti];
04449       if ( ti < 0 || ti >= m_T.Count() )
04450       {
04451         if ( text_log )
04452           text_log->Print("ON_Brep.m_L[%d].m_ti[%d] = %d is not invalid.\n",li,lti,ti);
04453         return ON_BrepIsNotValid();
04454       }
04455       if ( m_T[ti].m_trim_index != ti )
04456       {
04457         if ( text_log )
04458           text_log->Print("ON_Brep.m_L[%d].m_ti[%d] = %d is a deleted trim.\n",li,lti,ti);
04459         return ON_BrepIsNotValid();
04460       }
04461     }
04462   }
04463 
04464   // check trims - this check is necessary at the brep 
04465   // level to make sure there are no orphan trims and 
04466   // to test tolerances.  Most of these tests are duplicates 
04467   // of ones in ON_Brep::IsValidTrim, which is called by 
04468   // ON_Brep::IsValidLoop, which is called by ON_Brep::IsValidFace.
04469   int seam_trim_count = 0;
04470   for ( ti = 0; ti < trim_count; ti++ )
04471   {
04472     const ON_BrepTrim& trim = m_T[ti];
04473     if ( trim.m_trim_index == -1 )
04474       continue;
04475 
04476     if ( trim.m_vi[0] < 0 || trim.m_vi[0] >= m_V.Count() )
04477     {
04478       if ( text_log )
04479         text_log->Print("ON_Brep.m_T[%d].m_vi[0] = %d is not invalid.\n",ti,trim.m_vi[0]);
04480       return ON_BrepIsNotValid();
04481     }
04482     if ( trim.m_vi[1] < 0 || trim.m_vi[1] >= m_V.Count() )
04483     {
04484       if ( text_log )
04485         text_log->Print("ON_Brep.m_T[%d].m_vi[1] = %d is not invalid.\n",ti,trim.m_vi[1]);
04486       return ON_BrepIsNotValid();
04487     }
04488 
04489     if ( m_V[trim.m_vi[0]].m_vertex_index != trim.m_vi[0] )
04490     {
04491       if ( text_log )
04492         text_log->Print("ON_Brep.m_T[%d].m_vi[0] is deleted.\n",ti);
04493       return ON_BrepIsNotValid();
04494     }
04495     if ( m_V[trim.m_vi[1]].m_vertex_index != trim.m_vi[1] )
04496     {
04497       if ( text_log )
04498         text_log->Print("ON_Brep.m_T[%d].m_vi[1] is deleted.\n",ti);
04499       return ON_BrepIsNotValid();
04500     }
04501 
04502     if ( trim.m_c2i < 0 || trim.m_c2i >= m_C2.Count() )
04503     {
04504       if ( text_log )
04505         text_log->Print("ON_Brep.m_T[%d].m_c2i = %d is not valid.\n",ti,trim.m_c2i);
04506       return ON_BrepIsNotValid();
04507     }
04508 
04509     if ( 0 == m_C2[trim.m_c2i] )
04510     {
04511       if ( text_log )
04512         text_log->Print("ON_Brep.m_T[%d].m_c2i = %d, but m_C2[%d] is NULL.\n",ti,trim.m_c2i,trim.m_c2i);
04513       return ON_BrepIsNotValid();
04514     }
04515 
04516     if ( trim.m_li < 0 || trim.m_li >= m_L.Count() )
04517     {
04518       if ( text_log )
04519         text_log->Print("ON_Brep.m_T[%d].m_li = %d is not valid.\n",ti,trim.m_li);
04520       return ON_BrepIsNotValid();
04521     }
04522 
04523     if ( m_L[trim.m_li].m_loop_index != trim.m_li )
04524     {
04525       if ( text_log )
04526         text_log->Print("ON_Brep.m_T[%d].m_li = %d is a deleted loop.\n",ti,trim.m_li);
04527       return ON_BrepIsNotValid();
04528     }
04529 
04530     {
04531       const ON_Curve* c2 = m_C2[trim.m_c2i];
04532       const ON_Surface* srf = m_S[m_F[m_L[trim.m_li].m_fi].m_si];
04533       if ( srf )
04534       {
04535         ON_Interval PD = trim.ProxyCurveDomain();
04536         ON_Surface::ISO iso = srf->IsIsoparametric(*c2, &PD);
04537         if ( trim.m_iso != iso )
04538         {
04539           if ( text_log )
04540             text_log->Print("ON_Brep.m_T[%d].m_iso = %d and it should be %d\n",ti,trim.m_iso,iso);
04541           return ON_BrepIsNotValid();
04542         }
04543       }
04544     }
04545 
04546     if ( trim.m_type == ON_BrepTrim::singular )
04547     {
04548       if ( trim.m_ei != -1 )
04549       {
04550         if ( text_log )
04551           text_log->Print("ON_Brep.m_T[%d].m_type = singular, but m_ei = %d (should be -1).\n",ti,trim.m_ei);
04552         return ON_BrepIsNotValid();
04553       }
04554       continue;
04555     }
04556 
04557     if ( trim.m_ei < 0 || trim.m_ei >= m_E.Count() )
04558     {
04559       if ( text_log )
04560         text_log->Print("ON_Brep.m_T[%d].m_ei = %d is not invalid.\n",ti,trim.m_ei);
04561       return ON_BrepIsNotValid();
04562     }
04563     
04564     const ON_BrepEdge& edge = m_E[trim.m_ei];
04565     if ( edge.m_edge_index != trim.m_ei )
04566     {
04567       if ( text_log )
04568         text_log->Print("ON_Brep.m_T[%d].m_ei is deleted.\n",ti);
04569       return ON_BrepIsNotValid();
04570     }
04571 
04572     const int evi0 = trim.m_bRev3d ? 1 : 0;
04573     const int evi1 = trim.m_bRev3d ? 0 : 1;
04574     if ( trim.m_vi[0] != edge.m_vi[evi0] )
04575     {
04576       if ( text_log )
04577         text_log->Print("ON_Brep.m_T[%d].m_bRev3d = %d, but m_vi[0] != m_E[m_ei].m_vi[%d].\n",ti,trim.m_bRev3d,evi0);
04578       return ON_BrepIsNotValid();
04579     }
04580     if ( trim.m_vi[1] != edge.m_vi[evi1] )
04581     {
04582       if ( text_log )
04583         text_log->Print("ON_Brep.m_T[%d].m_bRev3d = %d, but m_vi[0] != m_E[m_ei].m_vi[%d].\n",ti,trim.m_bRev3d,evi1);
04584       return ON_BrepIsNotValid();
04585     }
04586 
04587     // check tolerances and closed curve directions
04588     {
04589       ON_3dPoint trim_pt0, trim_pt1, srf_pt0, srf_pt1;
04590       ON_3dVector trim_der0, trim_der1, srf_du0, srf_dv0, srf_du1, srf_dv1;
04591       ON_Interval trim_domain = trim.Domain();
04592       // trim_pt0 should be closed to trim_pt1 except when
04593       // trim starts and ends on opposite sides of a surface 
04594       // seam.  Even when the trim curve is closed, the 
04595       // derivatives can be different when there is
04596       // a kink at the start/end of a trim.
04597       trim.Ev1Der( trim_domain[0], trim_pt0, trim_der0 );
04598       trim.Ev1Der( trim_domain[1], trim_pt1, trim_der1 );
04599 
04600       const ON_Surface* trim_srf = m_F[ m_L[trim.m_li].m_fi ].SurfaceOf();
04601       trim_srf->Ev1Der( trim_pt0.x, trim_pt0.y, srf_pt0, srf_du0, srf_dv0 );
04602       trim_srf->Ev1Der( trim_pt1.x, trim_pt1.y, srf_pt1, srf_du1, srf_dv1 );
04603 
04604       // estimate 3d tolerances from 2d trim tolerances
04605       double t0_tol = srf_du0.Length()*trim.m_tolerance[0] + srf_dv0.Length()*trim.m_tolerance[1];
04606       double t1_tol = srf_du1.Length()*trim.m_tolerance[0] + srf_dv1.Length()*trim.m_tolerance[1];
04607       ON_3dVector trim_tangent0 = trim_der0.x*srf_du0 + trim_der0.y*srf_dv0;
04608       trim_tangent0.Unitize();
04609       ON_3dVector trim_tangent1 = trim_der1.x*srf_du1 + trim_der1.y*srf_dv1;
04610       trim_tangent1.Unitize();
04611       ON_3dVector edge_tangent0 = edge.TangentAt( edge.Domain()[trim.m_bRev3d ? 1 : 0] );
04612       ON_3dVector edge_tangent1 = edge.TangentAt( edge.Domain()[trim.m_bRev3d ? 0 : 1] );
04613       double d0 = trim_tangent0*edge_tangent0;
04614       double d1 = trim_tangent1*edge_tangent1;
04615       if ( trim.m_bRev3d )
04616       {
04617         d0 = -d0;
04618         d1 = -d1;
04619       }
04620       if (    trim.m_vi[0] == trim.m_vi[1] 
04621            && edge.m_vi[0] == edge.m_vi[1] 
04622            && trim.m_vi[0] == edge.m_vi[0] 
04623            )
04624       {
04625         // For high quality models, d0 and d1 should be close to +1.
04626         // If both are close to -1, the trim.m_bRev3d flag is most
04627         // likely set opposite of what it should be.
04628 
04629         // check start tangent to see if m_bRev3d is set correctly
04630         if ( d0 < 0.0 || d1 < 0.0)
04631         {
04632           if ( text_log )
04633           {
04634             if ( trim.m_bRev3d )
04635               text_log->Print("ON_Brep.m_T[%d].m_bRev3d = true, but closed curve directions are the same.\n",ti);
04636             else
04637               text_log->Print("ON_Brep.m_T[%d].m_bRev3d = false, but closed curve directions are opposite.\n",ti);
04638           }
04639           return ON_BrepIsNotValid();
04640         }
04641       }
04642 
04643       // Make sure edge and tolerances are realistic
04644       ON_3dPoint EdgeEnd[2];
04645       EdgeEnd[trim.m_bRev3d?1:0] = edge.PointAtStart();
04646       EdgeEnd[trim.m_bRev3d?0:1] = edge.PointAtEnd();
04647       d0 = EdgeEnd[0].DistanceTo(srf_pt0);
04648       d1 = EdgeEnd[1].DistanceTo(srf_pt1);
04649       double etol = edge.m_tolerance;
04650       double dtol = 10.0*(etol + t0_tol + t1_tol);
04651       if ( dtol < 0.01 )
04652         dtol = 0.01;
04653       if ( d0 > dtol  )
04654       {
04655         if ( text_log )
04656         {
04657           text_log->Print("Distance from start of ON_Brep.m_T[%d] to 3d edge is %g.  (edge tol = %g, trim tol ~ %g).\n",
04658                           ti, d0, etol,t0_tol);
04659         }
04660         return ON_BrepIsNotValid();
04661       }
04662       if ( d1 > dtol )
04663       {
04664         if ( text_log )
04665         {
04666           text_log->Print("Distance from end of ON_Brep.m_T[%d] to 3d edge is %g.  (edge tol = %g, trim tol ~ %g).\n",
04667                           ti, d1, etol,t1_tol);
04668         }
04669         return ON_BrepIsNotValid();
04670       }
04671     }
04672 
04673     // check trim's m_pbox
04674     {
04675       if ( trim.m_pbox.m_min.z != 0.0 )
04676       {
04677         if ( text_log )
04678            text_log->Print("ON_Brep.m_T[%d].m_pbox.m_min.z = %g (should be zero).\n",ti,trim.m_pbox.m_min.z);
04679         return ON_BrepIsNotValid();
04680       }
04681       if ( trim.m_pbox.m_max.z != 0.0 )
04682       {
04683         if ( text_log )
04684            text_log->Print("ON_Brep.m_T[%d].m_pbox.m_max.z = %g (should be zero).\n",ti,trim.m_pbox.m_max.z);
04685         return ON_BrepIsNotValid();
04686       }
04687       
04688       if ( !TestTrimPBox( trim, text_log ) )
04689         return ON_BrepIsNotValid();
04690 
04691     }
04692 
04693     if ( ON_BrepTrim::seam == trim.m_type )
04694     {
04695       // trim must be on a surface edge
04696       switch ( trim.m_iso )
04697       {
04698       case ON_Surface::S_iso:
04699         break;
04700       case ON_Surface::E_iso:
04701         break;
04702       case ON_Surface::N_iso:
04703         break;
04704       case ON_Surface::W_iso:
04705         break;
04706       default:
04707         if ( text_log )
04708           text_log->Print("ON_Brep.m_T[%d].m_type = ON_BrepTrim::seam but m_iso is not N/E/W/S_iso.\n",ti);
04709         return ON_BrepIsNotValid();
04710       }
04711       seam_trim_count++;
04712     }
04713   }
04714 
04715   // check loop m_pboxes
04716   for ( li = 0; li < loop_count; li++ )
04717   {
04718     const ON_BrepLoop& loop = m_L[li];
04719     if ( loop.m_loop_index != li )
04720       continue;
04721     if ( loop.m_pbox.m_min.z != 0.0 )
04722     {
04723       if ( text_log )
04724          text_log->Print("ON_Brep.m_L[%d].m_pbox.m_min.z = %g (should be zero).\n",li,loop.m_pbox.m_min.z);
04725       return ON_BrepIsNotValid();
04726     }
04727     if ( loop.m_pbox.m_max.z != 0.0 )
04728     {
04729       if ( text_log )
04730          text_log->Print("ON_Brep.m_L[%d].m_pbox.m_max.z = %g (should be zero).\n",li,loop.m_pbox.m_max.z);
04731       return ON_BrepIsNotValid();
04732     }
04733     int first_trim_ti = -4;
04734     int first_trim_vi0 = -3;
04735     int prev_trim_vi1 = -2;
04736     int prev_trim_ti=-9;
04737     int lti;
04738     for ( lti = 0; lti < loop.m_ti.Count(); lti++ )
04739     {
04740       const ON_BrepTrim& trim = m_T[loop.m_ti[lti]];
04741       if ( !loop.m_pbox.IsPointIn(trim.m_pbox.m_min) || !loop.m_pbox.IsPointIn(trim.m_pbox.m_max) )
04742       {
04743         if ( text_log )
04744            text_log->Print("ON_Brep.m_L[%d].m_pbox does not contain m_T[loop.m_ti[%d]].m_pbox.\n",li,lti);
04745         return ON_BrepIsNotValid();
04746       }
04747       if ( 0 == lti )
04748       {
04749         first_trim_ti = loop.m_ti[lti];
04750         first_trim_vi0 = trim.m_vi[0];
04751       }
04752       else if ( prev_trim_vi1 != trim.m_vi[0] )
04753       {
04754         // 23 May 2003 Dale Lear
04755         //     Added this test to make sure adjacent trims
04756         //     in a loop shared vertices.
04757         if ( text_log )
04758            text_log->Print("ON_Brep.m_L[%d] loop has trim vertex mismatch:\n  m_T[loop.m_ti[%d]=%d].m_vi[1] = %d != m_T[loop.m_ti[%d]=%d].m_vi[0]=%d.\n",li,lti-1,prev_trim_ti,prev_trim_vi1,lti,loop.m_ti[lti],trim.m_vi[0]);
04759         return ON_BrepIsNotValid();
04760       }
04761       prev_trim_ti = loop.m_ti[lti];
04762       prev_trim_vi1 = trim.m_vi[1];
04763     }
04764 
04765     if ( first_trim_ti >= 0 && first_trim_vi0 != prev_trim_vi1 )
04766     {
04767       // 23 May 2003 Dale Lear
04768       //     Added this test to make sure adjacent trims
04769       //     in a loop shared vertices.
04770       if ( text_log )
04771          text_log->Print("ON_Brep.m_L[%d] loop has trim vertex mismatch:\n  m_T[loop.m_ti[%d]=%d].m_vi[1] = %d != m_T[loop.m_ti[%d]=%d].m_vi[0]=%d.\n",
04772                          li,lti-1,prev_trim_ti,prev_trim_vi1,0,first_trim_ti,first_trim_vi0);
04773       return ON_BrepIsNotValid();
04774     }
04775   }
04776 
04777   // 21 October 2003 Dale Lear - fix RR 11980 - check for split seams
04778   // This block of code assumes the preceding checks have all passed.
04779   // It looks for boundary trims on seams that should be joined as a seam trim.
04780   ON_Interval srf_domain[2];
04781   for ( fi = 0; fi < face_count; fi++ )
04782   {
04783     const ON_BrepFace& face = m_F[fi];
04784     if ( face.m_face_index < 0 )
04785       continue;
04786     const ON_Surface* srf = m_S[face.m_si];
04787     if ( 0 == srf )
04788       continue;
04789 
04790     srf_domain[0] = srf->Domain(0);
04791     srf_domain[1] = srf->Domain(1);
04792     for ( int fli = 0; fli < face.m_li.Count(); fli++ )
04793     {
04794       int li = face.m_li[fli];
04795       if ( li < 0 || li >= m_L.Count() )
04796         continue;
04797       if ( !CheckLoopOnSrfHelper(*this,srf_domain[0],srf_domain[1],m_L[li],text_log) )
04798         return ON_BrepIsNotValid();
04799     }
04800 
04801     const ON_BrepLoop* outer_loop = face.OuterLoop();
04802     if ( 0 == outer_loop )
04803       continue;
04804 
04805     ON_BOOL32 bClosed[2];
04806     bClosed[0] = srf->IsClosed(0);
04807     bClosed[1] = srf->IsClosed(1);
04808     if ( !bClosed[0] && !bClosed[1] )
04809       continue;
04810 
04811     const int outer_trim_count = outer_loop->m_ti.Count();
04812     int lti, lti1;
04813     int endpt_index = 0;
04814     ON_Surface::ISO iso_type;
04815     ON_Interval side_interval;
04816     double s0, s1;
04817     const double side_tol = 1.0e-4;
04818 
04819     for ( lti = 0; lti < outer_trim_count; lti++ )
04820     {
04821       const ON_BrepTrim& trim = m_T[outer_loop->m_ti[lti]];
04822       if ( ON_BrepTrim::boundary !=  trim.m_type )
04823         continue;
04824       if ( ON_Surface::E_iso == trim.m_iso && bClosed[0] )
04825       {
04826         iso_type = ON_Surface::W_iso;
04827         endpt_index = 1;
04828       }
04829       else if ( ON_Surface::W_iso == trim.m_iso && bClosed[0] )
04830       {
04831         iso_type = ON_Surface::E_iso;
04832         endpt_index = 1;
04833       }
04834       else if( ON_Surface::S_iso == trim.m_iso && bClosed[1] )
04835       {
04836         iso_type = ON_Surface::N_iso;
04837         endpt_index = 0;
04838       }
04839       else if( ON_Surface::N_iso == trim.m_iso && bClosed[1] )
04840       {
04841         iso_type = ON_Surface::S_iso;
04842         endpt_index = 0;
04843       }
04844       else
04845         continue;
04846 
04847       side_interval.Set(trim.PointAtStart()[endpt_index],trim.PointAtEnd()[endpt_index]);
04848       if ( ON_Surface::N_iso == iso_type || ON_Surface::W_iso == iso_type )
04849       {
04850         if ( !side_interval.IsIncreasing() )
04851           continue;
04852       }
04853       else
04854       {
04855         if ( !side_interval.IsDecreasing() )
04856           continue;
04857       }
04858 
04859       // search for seam
04860       for ( lti1 = 0; lti1 < outer_trim_count; lti1++ )
04861       {
04862         if ( lti1 == lti )
04863           continue;
04864         const ON_BrepTrim& trim1 = m_T[outer_loop->m_ti[lti1]];
04865         if ( iso_type != trim1.m_iso )
04866           continue;
04867         if ( ON_BrepTrim::boundary != trim1.m_type )
04868           continue;
04869         
04870         s1 = side_interval.NormalizedParameterAt(trim1.PointAtStart()[endpt_index]);
04871         if ( fabs(s1-1.0) > side_tol )
04872           continue;
04873         s0 = side_interval.NormalizedParameterAt(trim1.PointAtEnd()[endpt_index]);
04874         if ( fabs(s0) > side_tol )
04875           continue;
04876 
04877         if ( text_log )
04878         {
04879          text_log->Print("ON_Brep.m_F[%d] is on a closed surface. Outer loop m_L[%d] contains boundary trims %d and %d.  They should be seam trims connected to the same edge.\n",
04880                          face.m_face_index,outer_loop->m_loop_index,
04881                          trim.m_trim_index,trim1.m_trim_index
04882                          );
04883         }
04884         return ON_BrepIsNotValid();                
04885       }
04886     }
04887   }
04888 
04889   // make sure seam trims are properly matched.
04890   for ( ti = 0; seam_trim_count > 0 && ti < trim_count; ti++ )
04891   {
04892     const ON_BrepTrim& trim = m_T[ti];
04893     if ( trim.m_trim_index == -1 )
04894       continue;
04895     if ( ON_BrepTrim::seam != trim.m_type )
04896       continue;
04897     seam_trim_count--;
04898     if ( trim.m_ei < 0 || trim.m_ei >= edge_count )
04899     {
04900       if ( text_log )
04901       {
04902         text_log->Print("ON_Brep.m_T[%d] is a seam trim with an invalid m_ei.\n",ti);
04903         return ON_BrepIsNotValid();
04904       }
04905     }
04906 
04907     const ON_BrepEdge& edge = m_E[trim.m_ei];
04908     int trim1_index = -1;
04909     for ( int eti = 0; eti < edge.m_ti.Count(); eti++ )
04910     {
04911       const int ti1 = edge.m_ti[eti];
04912       if ( ti1 == ti 
04913            || ti < 0
04914            || ti >= trim_count 
04915          )
04916       {
04917         continue;
04918       }
04919       const ON_BrepTrim& trim1 = m_T[ti1];
04920       if ( trim1.m_trim_index == -1 )
04921         continue;
04922       if ( ON_BrepTrim::seam != trim1.m_type )
04923         continue;
04924       if ( trim1.m_li != trim.m_li )
04925         continue;
04926       if ( -1 == trim1_index )
04927       {
04928         trim1_index = ti1;
04929         continue;
04930       }
04931       text_log->Print("ON_Brep.m_T[%d,%d,%d] are three seam trims with the same edge in the same loop.\n",ti,trim1_index,ti1);
04932       return ON_BrepIsNotValid();
04933     }
04934 
04935     if ( trim1_index < 0 || trim1_index >= trim_count )
04936     {
04937       text_log->Print("ON_Brep.m_T[%d] is a seam trim with no matching seam trim in the same loop.\n",ti);
04938       return ON_BrepIsNotValid();
04939     }
04940 
04941     // previous validation step insures trim.m_iso = N/S/E/W_iso
04942     switch(trim.m_iso)
04943     {
04944     case ON_Surface::S_iso:
04945       if ( ON_Surface::N_iso != m_T[trim1_index].m_iso )
04946       {
04947         if (text_log )
04948           text_log->Print("Seam trim ON_Brep.m_T[%d].m_iso = S_iso but matching seam ON_Brep.m_T[%d].m_iso != N_iso.\n",ti,trim1_index);
04949         return ON_BrepIsNotValid();
04950       }
04951       break;
04952 
04953     case ON_Surface::E_iso:
04954       if ( ON_Surface::W_iso != m_T[trim1_index].m_iso )
04955       {
04956         if (text_log )
04957           text_log->Print("Seam trim ON_Brep.m_T[%d].m_iso = E_iso but matching seam ON_Brep.m_T[%d].m_iso != W_iso.\n",ti,trim1_index);
04958         return ON_BrepIsNotValid();
04959       }
04960       break;
04961 
04962     case ON_Surface::N_iso:
04963       if ( ON_Surface::S_iso != m_T[trim1_index].m_iso )
04964       {
04965         if (text_log )
04966           text_log->Print("Seam trim ON_Brep.m_T[%d].m_iso = N_iso but matching seam ON_Brep.m_T[%d].m_iso != S_iso.\n",ti,trim1_index);
04967         return ON_BrepIsNotValid();
04968       }
04969       break;
04970 
04971     case ON_Surface::W_iso:
04972       if ( ON_Surface::E_iso != m_T[trim1_index].m_iso )
04973       {
04974         if (text_log )
04975           text_log->Print("Seam trim ON_Brep.m_T[%d].m_iso = W_iso but matching seam ON_Brep.m_T[%d].m_iso != E_iso.\n",ti,trim1_index);
04976         return ON_BrepIsNotValid();
04977       }
04978       break;
04979 
04980     case ON_Surface::not_iso:
04981     case ON_Surface::x_iso:
04982     case ON_Surface::y_iso:
04983     case ON_Surface::iso_count:
04984       break; // keep gcc quiet
04985     }
04986 
04987   }
04988 
04989 #if 0
04990   // validate ON_BrepTrim.m_pline
04991   for ( ti = 0; ti < trim_count; ti++ )
04992   {
04993     const ON_BrepTrim& trim = m_T[ti];
04994     if ( trim.m_trim_index == -1 )
04995       continue;
04996     const int pline_count = trim.m_pline.Count();
04997     if ( 0 == pline_count )
04998       continue;
04999     if ( pline_count <= 1 )
05000     {
05001       if (text_log )
05002         text_log->Print("ON_Brep.m_T[%d].m_pline.Count() = 1. It should be 0 or >= 2\n",ti);
05003       return ON_BrepIsNotValid();
05004     }
05005 
05006     const ON_Interval trim_domain = trim.Domain();
05007     if ( !(trim.m_pline[0].t == trim_domain[0]) )
05008     {
05009       if (text_log )
05010         text_log->Print("ON_Brep.m_T[%d].m_pline[0].t != start of trim domain.\n",ti);
05011       return ON_BrepIsNotValid();
05012     }
05013     if ( !(trim.m_pline[pline_count-1].t == trim_domain[1]) )
05014     {
05015       if (text_log )
05016         text_log->Print("ON_Brep.m_T[%d].m_pline[%d].t != end of trim domain.\n",ti,pline_count-1);
05017       return ON_BrepIsNotValid();
05018     }
05019     for ( int i = 1; i < pline_count; i++ )
05020     {
05021       // pline trim "t" values must be valid
05022       if ( !ON_IsValid(trim.m_pline[i].t) )
05023       {
05024         if (text_log )
05025           text_log->Print("ON_Brep.m_T[%d].m_pline[%d].t is not a valid double.\n",ti,i);
05026         return ON_BrepIsNotValid();
05027       }
05028       if ( !(trim.m_pline[i-1].t < trim.m_pline[i].t) )
05029       {
05030         if (text_log )
05031           text_log->Print("ON_Brep.m_T[%d].m_pline[%d].t must be < m_pline[%d].t.\n",ti,i-1,i);
05032         return ON_BrepIsNotValid();
05033       }
05034     }
05035 
05036     if (    ON_UNSET_VALUE == trim.m_pline[0].e 
05037          && ON_UNSET_VALUE == trim.m_pline[pline_count-1].e 
05038        )
05039     {
05040       // the "e" values are not set.
05041       // This is permitted. The are set when extensive
05042       // trim-edge parameter correspondence is needed.
05043       // Meshing is an example of a calculation that sets
05044       // the "e" paramters.
05045       continue;
05046     }
05047 
05048     if ( trim.m_ei < 0 || trim.m_ei >= m_E.Count() )
05049     {
05050       if (text_log )
05051         text_log->Print("ON_Brep.m_T[%d].m_pline has e parameters but trim.m_ei is not valid.\n",ti);
05052       return ON_BrepIsNotValid();
05053     }
05054     const ON_BrepEdge& edge = m_E[trim.m_ei];
05055     const ON_Interval edge_domain = edge.Domain();
05056     const int i0 = trim.m_bRev3d ? pline_count-1 : 0;
05057     const int i1 = trim.m_bRev3d ? 0 : pline_count-1;
05058     const int di = trim.m_bRev3d ? -1 : 1;
05059     if ( !(trim.m_pline[i0].e == edge_domain[0]) )
05060     {
05061       if (text_log )
05062         text_log->Print("ON_Brep.m_T[%d].m_pline[%d].e != start of edge domain.\n",ti,i0);
05063       return ON_BrepIsNotValid();
05064     }
05065     if ( !(trim.m_pline[i1].e == edge_domain[1]) )
05066     {
05067       if (text_log )
05068         text_log->Print("ON_Brep.m_T[%d].m_pline[%d].e != end of edge domain.\n",ti,i1);
05069       return ON_BrepIsNotValid();
05070     }
05071     int prev_valid_i = i0;
05072     for ( int i = i0+di; i >= 0 && i < pline_count && i-di >= 0 && i-di < pline_count; i += di )
05073     {
05074       if ( !ON_IsValid(trim.m_pline[i].e) )
05075       {
05076         // internal "e" may be invalid when the setter
05077         // had troubles.  This is a symptom of a 
05078         // bad trim or edge curve, but is not conclusive
05079         // proof.
05080         continue;
05081       }
05082       if ( !(trim.m_pline[prev_valid_i].e < trim.m_pline[i].e) )
05083       {
05084         if (text_log )
05085           text_log->Print("ON_Brep.m_T[%d].m_pline[%d].t must be < m_pline[%d].t.\n",ti,prev_valid_i,i);
05086         return ON_BrepIsNotValid();
05087       }
05088       prev_valid_i = i;
05089     }
05090   }
05091 #endif
05092 
05093   return true;
05094 }
05095 
05096 
05097 
05098 bool ON_Brep::SetEdgeVertex( const int ei, const int evi, const int vi )
05099 {
05100   if ( ei < 0 || vi < 0 || evi < 0 || evi > 1 )
05101     return false;
05102   ON_BrepEdge& edge = m_E[ei];
05103   if ( edge.m_vi[evi] != vi ) {
05104     edge.m_vi[evi] = vi;
05105     ON_BrepVertex& vertex = m_V[vi];
05106     vertex.m_ei.Append(ei);
05107   }
05108   const int trim_count = edge.m_ti.Count();
05109   int eti, ti, tvi;
05110   for ( eti = 0; eti < trim_count; eti++ ) {
05111     ti = edge.m_ti[eti];
05112     if ( ti < 0 )
05113       continue;
05114     ON_BrepTrim& trim = m_T[ti];
05115     tvi = trim.m_bRev3d ? 1-evi : evi;
05116     trim.m_vi[tvi] = vi;
05117   }
05118   return true;
05119 }
05120 
05121 bool ON_Brep::HopAcrossEdge( int& ti, int& tvi ) const
05122 {
05123   // Tf ti is a trim associated with an interior manifold edge,
05124   // then ti is set to twin.
05125   int ei, evi, new_ti, new_tvi;
05126   if ( ti < 0 )
05127     return false;
05128   ei = m_T[ti].m_ei;
05129   if ( ei < 0 )
05130     return false;
05131   const ON_BrepEdge& edge = m_E[ei];
05132   if ( edge.m_ti.Count() < 2 )
05133     return false;
05134   evi = (m_T[ti].m_bRev3d) ? 1-tvi : tvi;
05135   new_ti = edge.m_ti[(edge.m_ti[0] == ti)?1:0];
05136   if ( new_ti < 0 )
05137     return false;
05138   new_tvi = (m_T[new_ti].m_bRev3d) ? 1-evi : evi;
05139   ti = new_ti;
05140   tvi = new_tvi;
05141   return true;
05142 }
05143 
05144 bool ON_Brep::SetTrimStartVertex( const int ti0, const int vi )
05145 {
05146   // Do not use NextEdge(), PrevEdge() because they require
05147   // the information we are in the act of creating.
05148   if ( ti0 < 0 || vi < 0 )
05149     return false;
05150   int next_ti, ti, ei, evi, tvi, counter;
05151 
05152   // Step counter clockwise around vertex until we hit a boundary
05153   // or we get back to where we started.
05154   for ( ti = ti0, tvi = 0, counter = 0; ti >= 0 && counter < 512; counter++ ) {
05155     if ( counter > 0 ) {
05156       if ( ti == ti0 && tvi == 0 )
05157         return true; // vertex was interior
05158     }
05159     ON_BrepTrim& trim = m_T[ti];
05160     if ( trim.m_type == ON_BrepTrim::singular ) {
05161       trim.m_vi[0] = trim.m_vi[1] = vi;
05162       tvi = 1-tvi;
05163       next_ti = (tvi) ? NextTrim(ti) : PrevTrim(ti);
05164       ti = next_ti;
05165       tvi = 1-tvi;
05166       if ( ti == ti0 && tvi == 0 )
05167         return true; // vertex was interior
05168       if ( m_T[ti].m_type != ON_BrepTrim::singular )
05169         HopAcrossEdge( ti, tvi ); // OK if hop fails because ti is a boundary
05170       continue;
05171     }
05172 
05173     ei = trim.m_ei;
05174     evi = (trim.m_bRev3d) ? 1-tvi : tvi;
05175     if ( !SetEdgeVertex( ei, evi, vi ) )
05176       return false;
05177     next_ti = (tvi) ? NextTrim(ti) : PrevTrim(ti);
05178     ti = next_ti;
05179     tvi = 1-tvi;
05180     if ( ti < 0 )
05181       return false; // should not happen
05182 
05183     if ( m_T[ti].m_type == ON_BrepTrim::singular )
05184       continue;
05185     ei = m_T[ti].m_ei;
05186     if ( ei < 0 )
05187       return false; // should not happen
05188     evi = (m_T[ti].m_bRev3d) ? 1-tvi : tvi;
05189     const int edge_trim_count = m_E[ei].m_ti.Count();
05190     if ( edge_trim_count < 1 )
05191       break; // should not happen
05192     if ( edge_trim_count == 1 ) {
05193       SetEdgeVertex( ei, evi, vi );
05194       break; // ran into boundary
05195     }
05196     if ( !HopAcrossEdge( ti, tvi ) )
05197       return false;
05198   }
05199 
05200 
05201   // Get ready to step counter clockwise around vertex until
05202   // we hit a boundary.
05203   ti = ti0;
05204   tvi = 0;
05205   if ( m_T[ti].m_type == ON_BrepTrim::singular ) {
05206     // back up until we get to a non-singular trim
05207     while ( m_T[ti].m_type == ON_BrepTrim::singular ) {
05208       if ( ti != ti0 ) {
05209         m_T[ti].m_vi[0] = vi;
05210         m_T[ti].m_vi[1] = vi;
05211       }
05212       ti = PrevTrim(ti);
05213       tvi = 1;
05214       if ( ti == ti0 )
05215         break;
05216     }
05217     ei = m_T[ti].m_ei;
05218     if ( ei >= 0 ) {
05219       evi = (m_T[ti].m_bRev3d) ? 1-tvi : tvi;
05220       SetEdgeVertex( ei, evi, vi );
05221     }
05222   }
05223   else {
05224     ei = m_T[ti].m_ei;
05225   }
05226   if ( ei < 0 ) {
05227     // did the best we could - return true so setter keeps going
05228     // but the fact we are here means the brep is bogus.
05229     return true;
05230   }
05231   if ( m_E[ei].m_ti.Count() < 2 )
05232     return true; // ti0 is a boundary - we're done.
05233   if ( !HopAcrossEdge( ti, tvi ) )
05234     return false;
05235   next_ti = (tvi) ? NextTrim(ti) : PrevTrim(ti);
05236   if ( next_ti < 0 )
05237     return false;
05238   ti = next_ti;
05239   tvi = 1-tvi;
05240   if ( m_T[ti].m_type != ON_BrepTrim::singular ) {
05241     ei = m_T[ti].m_ei;
05242     if ( ei < 0 )
05243       return false;
05244     if ( m_E[ei].m_ti.Count() == 1 ) {
05245       evi = (m_T[ti].m_bRev3d)? 1-tvi : tvi;
05246       SetEdgeVertex( ei, evi, vi );
05247       return true;
05248     }
05249     if ( !HopAcrossEdge( ti, tvi ) )
05250       return false;
05251   }
05252 
05253   const int ti1 = ti;
05254   const int tvi1 = tvi;
05255   
05256   for ( ti = ti1, tvi = tvi1, counter = 0; ti >= 0 && counter < 512; counter++ ) {
05257     if ( counter > 0 ) {
05258       if ( ti == ti1 && tvi == tvi1 )
05259         return false; // vertex is not interior - so this should not happen
05260     }
05261     ON_BrepTrim& trim = m_T[ti];
05262     if ( trim.m_type == ON_BrepTrim::singular ) {
05263       trim.m_vi[0] = trim.m_vi[1] = vi;
05264       tvi = 1-tvi;
05265       next_ti = (tvi) ? NextTrim(ti) : PrevTrim(ti);
05266       ti = next_ti;
05267       tvi = 1-tvi;
05268       if ( ti == ti1 && tvi == tvi1 )
05269         return false; // vertex is not interior - so this should not happen
05270       if ( m_T[ti].m_type != ON_BrepTrim::singular )
05271         HopAcrossEdge( ti, tvi );  // OK if hop fails because ti is a boundary
05272       continue;
05273     }
05274 
05275     ei = trim.m_ei;
05276     evi = (trim.m_bRev3d) ? 1-tvi : tvi;
05277     if ( !SetEdgeVertex( ei, evi, vi ) )
05278       return false;
05279     next_ti = (tvi) ? NextTrim(ti) : PrevTrim(ti);
05280     ti = next_ti;
05281     tvi = 1-tvi;
05282     if ( ti < 0 )
05283       return false; // should not happen
05284     
05285     if ( m_T[ti].m_type == ON_BrepTrim::singular )
05286       continue;
05287     ei = m_T[ti].m_ei;
05288     if ( ei < 0 )
05289       return false; // should not happen
05290     evi = (m_T[ti].m_bRev3d) ? 1-tvi : tvi;
05291     const int edge_trim_count = m_E[ei].m_ti.Count();
05292     if ( edge_trim_count < 1 )
05293       break; // should not happen
05294     if ( edge_trim_count == 1 ) {
05295       SetEdgeVertex( ei, evi, vi );
05296       return true; // ran into boundary - expected
05297     }
05298     if ( !HopAcrossEdge( ti, tvi ) )
05299       return false;
05300   }
05301 
05302   return false; // should have exited by hitting "expected" boundary ~10 lines above
05303 }
05304 
05305 void ON_Brep::SetLoopVertices( const int li )
05306 {
05307   ON_BrepLoop& loop = m_L[li];
05308   const int loop_trim_count = loop.m_ti.Count();
05309   int lti;
05310   for ( lti = 0; lti < loop_trim_count; lti++ ) {
05311     const int ti = loop.m_ti[lti];
05312     ON_BrepTrim& trim = m_T[ti];
05313     int vi = trim.m_vi[0];
05314     if ( vi >= 0 )
05315       continue;
05316     ON_BrepVertex& v = NewVertex();
05317     SetTrimStartVertex( ti, v.m_vertex_index );
05318   }
05319 }
05320 
05321 void ON_Brep::ClearTrimVertices()
05322 {
05323   int ti;
05324   const int tcnt = m_T.Count();
05325   for ( ti = 0; ti < tcnt; ti++ ) {
05326     ON_BrepTrim& trim = m_T[ti];
05327     trim.m_vi[0] = -1;
05328     trim.m_vi[1] = -1;
05329   }
05330 }
05331 
05332 void ON_Brep::ClearEdgeVertices()
05333 {
05334   int ei;
05335   const int ecnt = m_E.Count();
05336   for ( ei = 0; ei < ecnt; ei++ ) {
05337     ON_BrepEdge& edge = m_E[ei];
05338     edge.m_vi[0] = -1;
05339     edge.m_vi[1] = -1;
05340   }
05341 }
05342 
05343 int ON_Brep::NextTrim(int ti) const
05344 {
05345   const ON_BrepTrim& trim = m_T[ti];
05346   const int li = trim.m_li;
05347   const ON_BrepLoop& loop = m_L[li];
05348   const int trim_count = loop.m_ti.Count();
05349   int lti;
05350   for ( lti = 0;  lti < trim_count && loop.m_ti[lti] != ti; lti++)
05351     ;/* empty for*/
05352   if ( lti < 0 || lti >= trim_count )
05353     return -1;
05354   return loop.m_ti[(lti+1)%trim_count];
05355 }
05356 
05357 int ON_Brep::PrevTrim(int ti) const
05358 {
05359   const ON_BrepTrim& trim = m_T[ti];
05360   const int li = trim.m_li;
05361   const ON_BrepLoop& loop = m_L[li];
05362   const int trim_count = loop.m_ti.Count();
05363   int lti;
05364   for ( lti = 0; loop.m_ti[lti] != ti && lti < trim_count; lti++)
05365     ;/* empty for*/
05366   if ( lti < 0 || lti >= trim_count )
05367     return -1;
05368   return loop.m_ti[(lti+trim_count-1)%trim_count];
05369 }
05370 
05371 int ON_Brep::NextEdge(int ei, int endi, int* next_endi ) const
05372 {
05373   const ON_BrepEdge& edge = m_E[ei];
05374   const int vi = edge.m_vi[endi];
05375   const ON_BrepVertex& vertex = m_V[vi];
05376   const int edge_count = vertex.m_ei.Count();
05377   int vei;
05378   if ( edge_count < 2 )
05379     return -1;
05380   if ( next_endi )
05381     *next_endi = 0;
05382   for ( vei = 0; vertex.m_ei[vei] != ei && vei < edge_count; vei++)
05383     ;/* empty for*/
05384   if ( edge.m_vi[0] == edge.m_vi[1]  && endi ) {
05385     // get next occurance of edge index
05386     //
05387     // On closed edges, edge.m_vi[0] = edge.m_vi[1] and edge.edge_index 
05388     // appears TWICE in vertex.m_ei[].  The first occurance of edge.edge_index
05389     // in vertex.m_ei[] corresponds to edge.m_vi[0].  The second occurance
05390     // of edge.edge_index in vertex.m_ei[] corresponds to edge.m_vi[1].
05391     vei++;
05392     while ( vei < edge_count && vertex.m_ei[vei] != ei )
05393       vei++;
05394   }
05395   if ( vei < 0 || vei >= edge_count )
05396     return -1;
05397   vei = (vei+1)%edge_count;
05398   const int next_ei = vertex.m_ei[vei];
05399   if ( next_endi ) {
05400     if ( m_E[next_ei].m_vi[0] == m_E[next_ei].m_vi[1] ) {
05401       *next_endi = 1;
05402       for ( vei++; vei < edge_count; vei++ ) {
05403         if ( vertex.m_ei[vei] == next_ei ) {
05404           *next_endi = 0;
05405           break;
05406         }
05407       }
05408     }
05409     else if ( m_E[next_ei].m_vi[1] == vi )
05410       *next_endi = 1;
05411   }
05412   return next_ei;
05413 }
05414 
05415 int ON_Brep::PrevEdge(int ei, int endi, int* prev_endi ) const
05416 {
05417   const ON_BrepEdge& edge = m_E[ei];
05418   const int vi = edge.m_vi[endi];
05419   const ON_BrepVertex& vertex = m_V[vi];
05420   const int edge_count = vertex.m_ei.Count();
05421   if ( edge_count < 2 )
05422     return -1;
05423   int vei;
05424   if ( prev_endi )
05425     *prev_endi = 0;
05426   for ( vei = 0; vertex.m_ei[vei] != ei && vei < edge_count; vei++)
05427     ;/* empty for*/
05428   if ( edge.m_vi[0] == edge.m_vi[1] && endi ) {
05429     // get next occurance of edge index
05430     //
05431     // On closed edges, edge.m_vi[0] = edge.m_vi[1] and edge.edge_index 
05432     // appears TWICE in vertex.m_ei[].  The first occurance of edge.edge_index
05433     // in vertex.m_ei[] corresponds to edge.m_vi[0].  The second occurance
05434     // of edge.edge_index in vertex.m_ei[] corresponds to edge.m_vi[1].
05435     vei++;
05436     while ( vei < edge_count && vertex.m_ei[vei] != ei )
05437       vei++;
05438   }
05439   if ( vei < 0 || vei >= edge_count )
05440     return -1;
05441   vei = (vei+edge_count-1)%edge_count;
05442   const int prev_ei = vertex.m_ei[(vei+edge_count-1)%edge_count];
05443   if ( prev_endi ) {
05444     if ( m_E[prev_ei].m_vi[0] == m_E[prev_ei].m_vi[1] ) {
05445       *prev_endi = 1;
05446       for ( vei++; vei < edge_count; vei++ ) {
05447         if ( vertex.m_ei[vei] == prev_ei ) {
05448           *prev_endi = 0;
05449           break;
05450         }
05451       }
05452     }
05453     else if ( m_E[prev_ei].m_vi[1] == vi ) {
05454       *prev_endi = 1;
05455     }
05456   }
05457   return prev_ei;
05458 }
05459 
05460 // HELPER CLASS - DO NOT PUT DEFINITION IN A HEADER FILE
05461 class ON__EDGE_ENDS
05462 {
05463 public:
05464   // used to sort vertices of closed edges that need
05465   // to be combined.
05466   int vi0; // smallest edge vertex index
05467   int vi1; // largest edge vertex index
05468   int ei;  // index of closed edge
05469   bool operator<(const ON__EDGE_ENDS& other) const
05470   {
05471     int i = other.vi0 - vi0;
05472     if ( i < 0 ) return true;
05473     if ( i > 0 ) return false;
05474     i = other.vi1 - vi1;
05475     if ( i < 0 ) return true;
05476     if ( i > 0 ) return false;
05477     i = other.ei - ei;
05478     if ( i < 0 ) return true;
05479     return false;
05480   }
05481 };
05482 
05483 void ON_Brep::SetVertices(void)
05484 {
05485   const int face_count = m_F.Count();
05486   int fi;
05487   
05488   ClearEdgeVertices();
05489   ClearTrimVertices();
05490   m_V.Empty();
05491   m_V.Shrink();
05492   fi = m_E.Count() - m_F.Count() + 8;
05493   if ( fi < 32 )
05494     fi = 32;
05495   m_V.Reserve( fi );
05496   for ( fi = 0; fi < face_count; fi++ ) {
05497     ON_BrepFace& face = m_F[fi];
05498     const int loop_count = face.m_li.Count();
05499     int fli;
05500     for ( fli = 0; fli < loop_count; fli++ ) {
05501       SetLoopVertices( face.m_li[fli] );
05502     }
05503   }
05504 
05505   // average edges' end location to get vertex location
05506   const int vertex_count = m_V.Count();
05507   int vi;
05508   ON_3dPoint VP, EP;
05509   for ( vi = 0; vi < vertex_count; vi++ ) 
05510   {
05511     VP.Zero();
05512     double d = 0.0;
05513     ON_BrepVertex& vertex = m_V[vi];
05514     const int edge_count = vertex.m_ei.Count();
05515     int vei;
05516     for ( vei = 0; vei < edge_count; vei++ ) 
05517     {
05518       const int ei = vertex.m_ei[vei];
05519       if ( ei < 0 ) 
05520         continue;
05521       const ON_BrepEdge& edge = m_E[ei];
05522       if ( edge.m_c3i < 0 )
05523         continue;
05524       const ON_Curve* pC = edge.EdgeCurveOf();
05525       if ( !pC )
05526         continue;
05527       if ( edge.m_vi[0] == vi )
05528         EP = edge.PointAtStart();
05529       else if ( edge.m_vi[1] == vi )
05530         EP = edge.PointAtEnd();
05531       else
05532         continue;
05533       VP.x += EP.x;
05534       VP.y += EP.y;
05535       VP.z += EP.z;
05536       d += 1.0;
05537     }
05538     if ( d > 0.0 ) 
05539     {
05540       d = 1.0/d;
05541       vertex.point = d*VP;
05542     }
05543   }
05544 
05545   const int edge_count = m_E.Count();
05546   int ei;
05547   ON_SimpleArray<ON__EDGE_ENDS> edge_ends(edge_count/4 + 2);
05548   for ( ei = 0; ei < edge_count; ei++ )
05549   {
05550     // see if we have any 3d edges that are closed as 3d curves
05551     // but have distinct end vertices
05552     const ON_BrepEdge& edge = m_E[ei];
05553     if (    edge.m_vi[0] >= 0 
05554          && edge.m_vi[1] >= 0
05555          && edge.m_vi[0] != edge.m_vi[1]
05556          && 0 != edge.EdgeCurveOf()
05557          && edge.IsClosed() )
05558     {
05559       ON__EDGE_ENDS& ee = edge_ends.AppendNew();
05560       if ( edge.m_vi[0] < edge.m_vi[1] )
05561       {
05562         ee.vi0 = edge.m_vi[0];
05563         ee.vi1 = edge.m_vi[1];
05564       }
05565       else
05566       {
05567         ee.vi0 = edge.m_vi[1];
05568         ee.vi1 = edge.m_vi[0];
05569       }
05570       ee.ei = ei;
05571     }
05572   }
05573 
05574   if ( edge_ends.Count() > 0 )
05575   {
05576     // we need to combine some vertices and the ends of closed edges
05577     edge_ends.QuickSort( ON_CompareIncreasing<ON__EDGE_ENDS> );
05578     int edge_ends_count = edge_ends.Count();
05579     int i0, i1, vi0, vi1, i;
05580 
05581     // adjust indices of chained closed edges
05582     for ( i = 1; i < edge_ends_count; i++ )
05583     {
05584       bool bSortAgain = false;
05585       for ( i0 = 0; i0 < edge_ends_count; i0++ )
05586       {
05587         vi0 = edge_ends[i0].vi0;
05588         vi1 = edge_ends[i0].vi1;
05589         for ( i1 = i0+1; i1 < edge_ends_count; i1++ )
05590         {
05591           ON__EDGE_ENDS& ee = edge_ends[i1];
05592           if ( ee.vi0 == vi1 )
05593           {
05594             ee.vi0 = vi0;
05595             bSortAgain = true;
05596           }
05597           if ( ee.vi1 == vi1 )
05598           {
05599             ee.vi1 = ee.vi0;
05600             ee.vi0 = vi0;
05601             bSortAgain = true;
05602           }
05603         }
05604       }
05605       if ( bSortAgain )
05606       {
05607         edge_ends.QuickSort( ON_CompareIncreasing<ON__EDGE_ENDS> );
05608       }
05609       else
05610         break;
05611     }
05612 
05613     // combine vertices at ends of closed edges into a single vertex
05614     bool bCullUnusedVertices = false;
05615     for ( i0 = 0, i1 = 1; i0 < edge_ends.Count(); i0 = i1 )
05616     {
05617       vi0 = edge_ends[i0].vi0;
05618       for ( i1 = i0+1; i1 < edge_ends.Count() && vi0 == edge_ends[i1].vi0; i1++ )
05619       {
05620         // empty body
05621       }
05622       vi1 = vi0;
05623       for ( i = i0; i < i1; i++ )
05624       {
05625         if ( edge_ends[i].vi1 > vi1 )
05626         {
05627           vi1 = edge_ends[i].vi1;
05628           if ( 0 <= vi0 && vi0 < vi1 && vi1 < m_V.Count())
05629           {
05630             CombineCoincidentVertices(m_V[vi0],m_V[vi1] );
05631             bCullUnusedVertices = true;
05632           }
05633         }
05634       }
05635     }
05636     if ( bCullUnusedVertices )
05637       CullUnusedVertices();
05638   }
05639 }
05640 
05641 void ON_BrepTrim::m__legacy_flags_Set(int gcon, int mono)
05642 {
05643   m__legacy_flags = 0;
05644   switch(gcon)
05645   {
05646   case -1:
05647     m__legacy_flags |= 1;
05648     break;
05649   case 0:
05650     m__legacy_flags |= 2;
05651     break;
05652   case 1:
05653     m__legacy_flags |= 3;
05654     break;
05655   case 2:
05656     m__legacy_flags |= 4;
05657     break;
05658   }
05659   if (mono)
05660     m__legacy_flags |= 8;
05661   else
05662     m__legacy_flags |= 16;
05663 }
05664 
05665 bool ON_BrepTrim::m__legacy_flags_Get(int* gcon, int* mono) const
05666 {
05667   if ( gcon ) {
05668     switch ( m__legacy_flags & 7 )
05669     {
05670     case 1:
05671       *gcon = -1;
05672       break;
05673     case 2:
05674       *gcon = 0;
05675       break;
05676     case 3:
05677       *gcon = 1;
05678       break;
05679     case 4:
05680       *gcon = 2;
05681       break;
05682     default:
05683       *gcon = -1;
05684     }
05685   }
05686   if ( mono ) {
05687     if ( 0 != (m__legacy_flags&8) )
05688       *mono = 1;
05689     else
05690       *mono = 0;
05691   }
05692   return m__legacy_flags ? true : false;
05693 }
05694 void ON_Brep::SetTolsFromLegacyValues()
05695 {
05696   // use m_2d_tol and m_3d_tol read from file to set public tolerances
05697   const int vcnt = m_V.Count();
05698   const int tcnt = m_T.Count();
05699   ON_3dPoint endP;
05700   double d;
05701   int vi, ti, vei, evi, vecnt;
05702   
05703   // set trim and edge tolerances from values in file
05704   for ( ti = 0; ti < tcnt; ti++ ) {
05705     ON_BrepTrim& trim = m_T[ti];
05706     trim.m_tolerance[0] = trim.m__legacy_2d_tol; // "pe_tol"
05707     trim.m_tolerance[1] = trim.m__legacy_2d_tol; // "pe_tol"
05708     if ( trim.m_ei >= 0 ) {
05709       ON_BrepEdge& edge = m_E[trim.m_ei];
05710       if ( edge.m_tolerance < trim.m__legacy_3d_tol )
05711         edge.m_tolerance = trim.m__legacy_3d_tol; // "e_tol"
05712     }
05713   }
05714 
05715   // set vertex tolerances from edge tols and end evaluations
05716   for ( vi = 0; vi < vcnt; vi++ ) {
05717     ON_BrepVertex& vertex = m_V[vi];
05718     vecnt = vertex.m_ei.Count();
05719     for ( vei = 0; vei < vecnt; vei++ ) {
05720       const ON_BrepEdge& edge = m_E[vertex.m_ei[vei]];
05721       if ( vertex.m_tolerance < edge.m_tolerance )
05722         vertex.m_tolerance = edge.m_tolerance;
05723       const ON_Curve* c = m_C3[edge.m_c3i];
05724       evi = 0;
05725       if ( edge.m_vi[0] != vi )
05726         evi = 1;
05727       if ( edge.m_vi[evi] == vi ) {
05728         endP = c->PointAt( c->Domain()[evi] );
05729         d = vertex.point.DistanceTo( endP );
05730         if ( d > vertex.m_tolerance ) {
05731           vertex.m_tolerance = d;      
05732         }
05733       }
05734     }
05735   }
05736 }
05737 
05738 ON::object_type ON_Brep::ObjectType() const
05739 {
05740   // This must ALWAYS return ON::brep_object.
05741   // NEVER modify this function to return any
05742   // other value.
05743   return ON::brep_object;
05744 }
05745 
05746 void ON_Brep::ClearBoundingBox()
05747 {
05748   m_bbox.Destroy();
05749 }
05750 
05751 void ON_BrepFace::ClearBoundingBox()
05752 {
05753   m_bbox.Destroy();
05754 }
05755 
05756 ON_BOOL32
05757 ON_BrepFace::GetBBox(
05758           double* box_min, // [3],
05759           double* box_max, // [3],
05760           ON_BOOL32 bGrowBox     // = false
05761           ) const
05762 {
05763   if ( !m_bbox.IsValid() 
05764        && 0 != m_brep 
05765        && m_face_index >= 0 
05766        && m_face_index < m_brep->m_F.Count()
05767        && &m_brep->m_F[m_face_index] == this 
05768        )
05769   {
05770     const ON_Surface* srf = ProxySurface();
05771     if ( srf && srf != this )
05772     {
05773       srf->GetBoundingBox( const_cast<ON_BrepFace*>(this)->m_bbox, false );
05774     }
05775   }
05776 
05777   ON_BOOL32 rc = m_bbox.IsValid();
05778   if (rc)
05779   {
05780     ON_BoundingBox bbox = m_bbox;
05781     if ( bGrowBox && box_min && box_max && box_min[0] <= box_max[0] )
05782     {
05783       bbox.Union( ON_BoundingBox( ON_3dPoint(box_min), ON_3dPoint(box_max) ) );
05784     }
05785     if ( box_min )
05786     {
05787       box_min[0] = bbox.m_min.x;
05788       box_min[1] = bbox.m_min.y;
05789       box_min[2] = bbox.m_min.z;
05790     }
05791     if ( box_max )
05792     {
05793       box_max[0] = bbox.m_max.x;
05794       box_max[1] = bbox.m_max.y;
05795       box_max[2] = bbox.m_max.z;
05796     }
05797   }
05798   return rc;
05799 }
05800 
05801 
05802 ON_BOOL32
05803 ON_Brep::GetBBox(
05804           double* box_min, // [3],
05805           double* box_max, // [3],
05806           ON_BOOL32 bGrowBox     // = false
05807           ) const
05808 {
05809   ON_BoundingBox bbox;
05810   if ( !m_bbox.IsValid() )
05811   {
05812     const int face_count = m_F.Count();
05813     int fi;
05814     for ( fi = 0; fi < face_count; fi++ ) 
05815     {
05816       if ( m_F[fi].m_face_index == -1 )
05817         continue;
05818       const ON_Surface* srf = m_F[fi].ProxySurface();
05819       if ( !srf )
05820         continue;
05821       srf->GetBoundingBox( bbox, bbox.IsValid() );
05822     }
05823     ON_Brep* ptr = const_cast<ON_Brep*>(this);
05824     ptr->m_bbox = bbox;
05825   }
05826 
05827   ON_BOOL32 rc = m_bbox.IsValid();
05828   if (rc)
05829   {
05830     bbox = m_bbox;
05831     if ( bGrowBox && box_min && box_max && box_min[0] <= box_max[0] )
05832     {
05833       bbox.Union( ON_BoundingBox( ON_3dPoint(box_min), ON_3dPoint(box_max) ) );
05834     }
05835     if ( box_min )
05836     {
05837       box_min[0] = bbox.m_min.x;
05838       box_min[1] = bbox.m_min.y;
05839       box_min[2] = bbox.m_min.z;
05840     }
05841     if ( box_max )
05842     {
05843       box_max[0] = bbox.m_max.x;
05844       box_max[1] = bbox.m_max.y;
05845       box_max[2] = bbox.m_max.z;
05846     }
05847   }
05848   return rc;
05849 }
05850 
05851 ON_BOOL32
05852 ON_Brep::SwapCoordinates( int i, int j )
05853 {
05854   ON_BOOL32 rc = false;
05855   // swap surface coordinates
05856   const int srf_count = m_S.Count();
05857   int si;
05858   for ( si = 0; si < srf_count; si++ ) {
05859     if ( !m_S[si] ) 
05860       continue;
05861     rc = m_S[si]->SwapCoordinates(i,j);
05862     if ( !rc ) {
05863       while ( --si >= 0 ) {
05864         // undo any changes;
05865         if ( m_S[si] )
05866           m_S[si]->SwapCoordinates(i,j);
05867       }
05868       return false;
05869     }
05870   }
05871   // swap 3d curve coordinates
05872   const int crv_count = m_S.Count();
05873   int ci;
05874   for ( ci = 0; ci < crv_count; ci++ ) {
05875     if ( !m_C3[ci] ) 
05876       continue;
05877     rc = m_C3[ci]->SwapCoordinates(i,j);
05878     if ( !rc ) {
05879       // undo any changes;
05880       while ( --ci >= 0 ) {
05881         if ( m_C3[ci] )
05882           m_C3[ci]->SwapCoordinates(i,j);
05883         for ( si = 0; si < srf_count; si++ ) {
05884           if ( m_S[si] )
05885             m_S[si]->SwapCoordinates(i,j);
05886         }
05887       }
05888       return false;
05889     }
05890   }
05891   return rc;
05892 }
05893 
05894 bool
05895 ON_Brep::SwapTrimParameters(
05896         int trim_index
05897         )
05898 {
05899   // helper for SwapLoopParameters
05900   if ( trim_index < 0 || trim_index >= m_T.Count() )
05901     return false;
05902   ON_BrepTrim& trim = m_T[trim_index];
05903 
05904   StandardizeTrimCurve(trim_index);
05905 
05906   const int ci = trim.m_c2i;
05907   if ( ci < 0 || ci >= m_C2.Count() )
05908     return false;
05909   ON_Curve* pC = m_C2[ci];
05910   if ( !pC )
05911     return false;
05912 
05913   ON_Interval pdom = trim.ProxyCurveDomain();
05914   ON_Interval trimdom = trim.Domain();
05915 
05916   // have to call SwapCoordinates on pC because
05917   // ON_CurveProxy does not permit modification
05918   // of "real" curve.
05919   ON_BOOL32 rc = pC->SwapCoordinates(0,1); // "u" <-> "v"
05920   if ( !rc )
05921     return false;
05922 
05923   // reverse 2d curve
05924   rc = pC->Reverse();
05925   if (rc)
05926   {
05927     // take care of proxy house keeping, m_vi[] swapping, and toggle m_bRev3d.
05928     trim.SetProxyCurve(pC);
05929     int i = trim.m_vi[0];
05930     trim.m_vi[0] = trim.m_vi[1];
05931     trim.m_vi[1] = i;
05932     if ( trim.m_ei >= 0 )
05933       trim.m_bRev3d = trim.m_bRev3d ? false : true;
05934   }
05935   else
05936   {
05937     // undo changes
05938     rc = pC->SwapCoordinates(0,1); // "u" <-> "v"
05939     return false;
05940   }
05941 
05942   // reflect iso type
05943   switch ( trim.m_iso ) 
05944   {
05945   case ON_Surface::not_iso:
05946     trim.m_iso = ON_Surface::not_iso;
05947     break;
05948   case ON_Surface::x_iso:
05949     trim.m_iso = ON_Surface::y_iso;
05950     break;
05951   case ON_Surface::y_iso:
05952     trim.m_iso = ON_Surface::x_iso;
05953     break;
05954   case ON_Surface::W_iso:
05955     trim.m_iso = ON_Surface::S_iso;
05956     break;
05957   case ON_Surface::S_iso:
05958     trim.m_iso = ON_Surface::W_iso;
05959     break;
05960   case ON_Surface::E_iso:
05961     trim.m_iso = ON_Surface::N_iso;
05962     break;
05963   case ON_Surface::N_iso:
05964     trim.m_iso = ON_Surface::E_iso;
05965     break;
05966   default:
05967     trim.m_iso = ON_Surface::not_iso;
05968     break;
05969   }
05970 
05971   return true;
05972 }
05973 
05974 bool
05975 ON_Brep::SwapLoopParameters(
05976         int loop_index
05977         )
05978 {
05979   bool rc = false;
05980   if ( loop_index < 0 || loop_index >= m_L.Count() )
05981     return false;
05982   ON_BrepLoop& L = m_L[loop_index];
05983   const int loop_trim_count = L.m_ti.Count();
05984   if ( loop_trim_count < 1 )
05985     return false;
05986   int lti, ti;
05987   for ( lti = 0; lti < loop_trim_count; lti++ ) {
05988     ti = L.m_ti[lti];
05989     rc = SwapTrimParameters( ti );
05990     if ( !rc ) {
05991       while ( --lti >= 0 ) {
05992         // undo any changes
05993         ti = L.m_ti[lti];
05994         SwapTrimParameters( ti );
05995       }
05996       return false;
05997     }
05998   }
05999 
06000   // reverse order of trimming curves
06001   if ( rc )
06002     L.m_ti.Reverse();
06003   return rc;
06004 }
06005 
06006 bool
06007 ON_Brep::IsSolid() const
06008 {
06009   ON_BOOL32 bIsOriented = false;
06010   ON_BOOL32 bHasBoundary = true;
06011   bool bIsManifold = IsManifold( &bIsOriented, &bHasBoundary );
06012   return (bIsManifold && bIsOriented && !bHasBoundary) ? true : false;
06013 }
06014 
06015 int ON_Brep::SolidOrientation() const
06016 {
06017   // m_is_solid values:
06018   //   0 = unset
06019   //   1 = solid with normals pointing out
06020   //   2 = solid with normals pointing in
06021   //   3 = not solid
06022   int rc = 0;
06023   switch( m_is_solid )
06024   {
06025   case 1: // solid with normals pointing out
06026     rc = 1;
06027     break;
06028   case 2: // solid with normals pointing in
06029     rc = -1;
06030     break;
06031   case 3: // not a solid
06032     rc = 0;
06033     break;
06034   
06035   default:
06036     if ( IsSolid() )
06037     {
06038       // this virtual function is overridden in Rhino SDK
06039       // and sets m_is_solid to appropriate values.  This
06040       // stand-alone version cannot tell the difference
06041       // between solids with inward pointing normals and
06042       // solids with outwards pointing normals.
06043       //ON_Brep* p = const_cast<ON_Brep*>(this);
06044       //p->m_is_solid = 1;
06045       rc = 2;
06046     }
06047     else
06048     {
06049       ON_Brep* p = const_cast<ON_Brep*>(this);
06050       p->m_is_solid = 3;
06051       rc = 0;
06052     }
06053   }
06054   return rc;
06055 }
06056 
06057 bool
06058 ON_Brep::IsManifold( ON_BOOL32* pbIsOriented, ON_BOOL32* pbHasBoundary ) const
06059 {
06060   const int fcnt = m_F.Count();
06061   bool bIsManifold = (fcnt > 0) ? true : false;
06062   bool bIsOriented = bIsManifold;
06063   bool bHasBoundary = false;
06064   int fi, other_ti, lcnt, tcnt, fli, lti;
06065   if ( pbIsOriented )
06066     *pbIsOriented = bIsOriented;
06067   if ( pbHasBoundary )
06068     *pbHasBoundary = bHasBoundary;
06069   const int brep_loop_count = m_L.Count();
06070   const int brep_trim_count = m_T.Count();
06071   const int brep_edge_count = m_E.Count();
06072   for ( fi = 0; fi < fcnt && bIsManifold; fi++ ) 
06073   {
06074     const ON_BrepFace& face = m_F[fi];
06075     if ( -1 == face.m_face_index )
06076     {
06077       // 28 October 2010 - Dale Lear and Chuck
06078       //    Do not test deleted faces. The join
06079       //    command calls is manifold with some
06080       //    deleted faces to avoid calling Compact
06081       //    lots of times during a join.
06082       continue;
06083     }
06084 
06085     lcnt = face.m_li.Count();
06086     if ( lcnt < 1 ) {
06087       bIsManifold = false;
06088     }
06089 
06090     for ( fli = 0; fli < lcnt && bIsManifold; fli++ ) 
06091     {
06092       const int li = face.m_li[fli];
06093       if ( li < 0 || li >= brep_loop_count )
06094       {
06095         ON_ERROR("Bogus loop index in face.m_li[]");
06096         continue;
06097       }
06098       const ON_BrepLoop& loop = m_L[li];
06099       tcnt = loop.m_ti.Count();
06100       if (tcnt < 1 ) {
06101         bIsManifold = false;
06102       }
06103       for ( lti = 0; lti < tcnt && bIsManifold; lti++ ) 
06104       {
06105         const int ti = loop.m_ti[lti];
06106         if ( ti < 0 || ti >= brep_trim_count )
06107         {
06108           ON_ERROR("Bogus loop index in loop.m_ti[]");
06109           continue;
06110         }
06111         const ON_BrepTrim& trim = m_T[ti];
06112         switch ( trim.m_type ) 
06113         {
06114         case ON_BrepTrim::boundary:
06115           bHasBoundary = true;
06116           break;
06117         case ON_BrepTrim::mated:
06118         case ON_BrepTrim::seam:
06119           // make sure we have a manifold join
06120           if ( trim.m_ei >= 0 && trim.m_ei < brep_edge_count )
06121           {
06122             const ON_BrepEdge& edge = m_E[trim.m_ei];
06123             if ( edge.m_ti.Count() != 2 ) {
06124               bIsManifold = false;
06125             }
06126             else 
06127             {
06128               other_ti = edge.m_ti[0];
06129               if ( other_ti == ti )
06130                 other_ti = edge.m_ti[1];
06131               if ( other_ti == ti )
06132               {
06133                 bIsManifold = false;
06134               }
06135               else 
06136               {
06137                 const ON_BrepTrim& other_trim = m_T[other_ti];
06138 
06139                 // Nov 9, 2011 Tim - Fix for crash bug RR 93743
06140                 // Better index checking.
06141 
06142                 ON_BOOL32 bFlipTrim = trim.m_bRev3d;
06143                 if (0 <= trim.m_li && brep_loop_count > trim.m_li)
06144                 {
06145                   if ( m_F[m_L[trim.m_li].m_fi].m_bRev )
06146                     bFlipTrim = !bFlipTrim;
06147                 }
06148                 else
06149                 {
06150                   ON_ERROR("Bogus loop index in trim.m_li");
06151                   continue;
06152                 }
06153 
06154                 ON_BOOL32 bFlipOther = other_trim.m_bRev3d;
06155                 if (0 <= other_trim.m_li && brep_loop_count > other_trim.m_li)
06156                 {
06157                   if ( m_F[m_L[other_trim.m_li].m_fi].m_bRev )
06158                     bFlipOther = !bFlipOther;
06159                 }
06160                 else
06161                 {
06162                   ON_ERROR("Bogus loop index in other_trim.m_li");
06163                   continue;
06164                 }
06165 
06166                 if ( bFlipTrim && bFlipOther )
06167                 {
06168                   bIsOriented = false;
06169                 }
06170                 else if ( !bFlipTrim && !bFlipOther )
06171                 {
06172                   bIsOriented = false;
06173                 }
06174               }
06175             }
06176           }
06177           else
06178           {
06179             ON_ERROR("Bogus trim.m_ei or trim.m_type value");
06180           }
06181           break;
06182         case ON_BrepTrim::singular:
06183           // nothing to check here
06184           break;
06185         default:
06186           bIsManifold = false;
06187           break;
06188         }
06189       }
06190     }
06191   }
06192   if ( !bIsManifold ) {
06193     bIsOriented = false;
06194     bHasBoundary = false;
06195   }
06196   if ( pbIsOriented )
06197     *pbIsOriented = bIsOriented;
06198   if ( pbHasBoundary )
06199     *pbHasBoundary = bHasBoundary;
06200   if ( !bIsManifold || bHasBoundary )
06201   {
06202     if ( m_is_solid != 3 )
06203     {
06204       // lazy evaluation used on m_is_solid
06205       const_cast<ON_Brep*>(this)->m_is_solid = 3;
06206     }
06207   }
06208 
06209   return bIsManifold;
06210 }
06211 
06212 
06213 bool
06214 ON_Brep::IsSurface() const
06215 {
06216   // returns true if the b-rep has a single face
06217   // and that face is geometrically the same
06218   // as the underlying surface.  I.e., the face
06219   // has trivial trimming.  In this case, the
06220   // surface is m_S[0].
06221   return (m_F.Count() == 1 && FaceIsSurface(0));
06222 }
06223 
06224 bool 
06225 ON_Brep::FaceIsSurface( int face_index ) const
06226 {
06227   // returns true if the face has a single
06228   // outer boundary and that boundary runs
06229   // along the edges of the underlying surface.
06230   // In this case the geometry of the surface
06231   // is the same as the geometry of the face.
06232 
06233   bool bTrivialFace = false;
06234   if ( face_index >= 0 && face_index < m_F.Count() ) {
06235     const ON_BrepFace& face = m_F[face_index];
06236     if ( face.m_li.Count() == 1 ) {
06237       bTrivialFace = LoopIsSurfaceBoundary( face.m_li[0] );
06238     }
06239   }
06240   return bTrivialFace;
06241 }
06242 
06243 bool 
06244 ON_Brep::LoopIsSurfaceBoundary( int loop_index ) const
06245 {
06246   // returns true if the loop's trims run along the underlying surface boundary
06247   bool bTrivialLoop = false;
06248   if ( loop_index >= 0 && loop_index < m_L.Count() ) {
06249     const ON_BrepLoop& loop = m_L[loop_index];
06250     const int trim_count = loop.m_ti.Count();
06251     if ( trim_count > 0 ) {
06252       bTrivialLoop = true;
06253       for ( int lti = 0; lti < trim_count && bTrivialLoop; lti++ ) 
06254       {
06255         int ti = loop.m_ti[lti];
06256         if ( ti < 0 || ti >= m_T.Count() )
06257         {
06258           ON_ERROR("Bogus trim index in loop.m_ti[]");
06259           return false;
06260         }
06261         const ON_BrepTrim& trim = m_T[ti];
06262         if ( trim.m_iso == ON_Surface::W_iso )
06263           continue;
06264         if ( trim.m_iso == ON_Surface::S_iso )
06265           continue;
06266         if ( trim.m_iso == ON_Surface::N_iso )
06267           continue;
06268         if ( trim.m_iso == ON_Surface::E_iso )
06269           continue;
06270         bTrivialLoop = false;
06271       }
06272     }
06273   }
06274   return bTrivialLoop;
06275 }
06276 
06277 bool
06278 ON_Brep::FlipReversedSurfaces()
06279 {
06280   // Clears all ON_BrepFace.m_bRev flags
06281   // by calling SwapFaceParameters() on each
06282   // face with a true m_bRev.
06283   //
06284   // Returns true if successful.
06285 
06286   // 11 April 2008 Dale Lear and Tim:
06287   //   face.Transpose() is clearing the m_is_solid
06288   //   flag but we are not changing the orientation
06289   //   of the brep.  This prevents having to perform
06290   //   the expensive step of calculating this flag
06291   //   again.
06292   int saved_is_solid = m_is_solid;
06293 
06294   const int face_count = m_F.Count();
06295 
06296   bool rc = true;
06297   int fi;
06298   for ( fi = 0; fi < face_count; fi++ ) 
06299   {
06300     ON_BrepFace& face = m_F[fi];
06301     if ( face.m_bRev )
06302     {
06303       if ( !face.Transpose() )
06304         rc = false;
06305     }
06306   }
06307 
06308   m_is_solid = saved_is_solid;
06309 
06310   return rc;
06311 }
06312 
06314 // Change the domain of a trim
06315 bool ON_Brep::SetTrimDomain(
06316        int trim_index, // index of trim in m_T[] array
06317        const ON_Interval& domain
06318        )
06319 {
06320   bool rc = false;
06321   if ( trim_index >= 0 && trim_index < m_T.Count() && domain.IsIncreasing() ) 
06322   {
06323     ON_BrepTrim& trim = m_T[trim_index];
06324     rc = trim.SetDomain(domain);
06325   }
06326   return rc;
06327 }
06328 
06330 // Change the domain of an edge
06331 bool ON_Brep::SetEdgeDomain(
06332        int edge_index, // index of edge in m_E[] array
06333        const ON_Interval& domain
06334        )
06335 {
06336   bool rc = false;
06337   if ( edge_index >= 0 && edge_index < m_E.Count() && domain.IsIncreasing() ) 
06338   {
06339     ON_BrepEdge& edge = m_E[edge_index];
06340     rc = edge.SetDomain(domain);
06341   }
06342   return rc;
06343 }
06344 
06345 ON_BOOL32 ON_BrepFace::Reverse(int dir)
06346 {
06347   if ( dir < 0 || dir > 1 || 0 == m_brep )
06348     return false;
06349   ON_Surface* srf = const_cast<ON_Surface*>(SurfaceOf());
06350   if ( !srf )
06351     return false;
06352   ON_Interval dom0 = srf->Domain(dir);
06353   if ( !dom0.IsIncreasing() )
06354     return false;
06355 
06356 // 2/18/03 GBA.  Destroy surface cache on face.
06357         DestroyRuntimeCache(true);
06358 
06359   if ( m_brep->SurfaceUseCount( m_si, 2 ) > 1 )
06360   {
06361     srf = srf->DuplicateSurface();
06362     m_si = m_brep->AddSurface( srf );
06363     SetProxySurface(srf);
06364   }
06365 
06366   if ( !srf->Reverse(dir) )
06367     return false;
06368 
06369   ON_Interval dom1 = dom0;
06370   dom1.Reverse();
06371   if ( dom1 != srf->Domain(dir) )
06372   {
06373     srf->SetDomain( dir, dom1 );
06374     dom1 = srf->Domain(dir);
06375   }
06376 
06377   // adjust location of 2d trim curves
06378   ON_Xform xform(1);
06379   xform.IntervalChange(dir,dom0,ON_Interval(dom1[1],dom1[0]));
06380   TransformTrim(xform);
06381 
06382   // reverse loop orientations.
06383   int fli;
06384   for ( fli = 0; fli < m_li.Count(); fli++ )
06385   {
06386     ON_BrepLoop* loop = m_brep->Loop(m_li[fli]);
06387     if ( loop )
06388       m_brep->FlipLoop( *loop );
06389   }
06390   
06391   m_bRev = m_bRev ? false : true;
06392 
06393   if (m_brep->m_is_solid == 1 || m_brep->m_is_solid == 2) m_brep->m_is_solid = 0;
06394 
06395         // Greg Arden 10 April 2003.  Fix TRR#9624.  
06396         // Update analysis and render meshes.
06397         if(m_render_mesh)
06398   {
06399     m_render_mesh->ReverseSurfaceParameters(dir);
06400     m_render_mesh->ReverseTextureCoordinates(dir);
06401   }
06402         if(m_analysis_mesh)
06403   {
06404     m_analysis_mesh->ReverseSurfaceParameters(dir);
06405                 m_analysis_mesh->ReverseTextureCoordinates(dir);
06406   }
06407 
06408   return true;
06409 }
06410 
06411 ON_BOOL32 ON_BrepFace::Transpose()
06412 {
06413   if ( 0 == m_brep )
06414     return false;
06415 
06416   ON_Surface* srf = const_cast<ON_Surface*>(SurfaceOf());
06417   if ( 0 == srf )
06418     return false;
06419 
06420   // 2/18/03 GBA.  Destroy cache on the face.
06421         DestroyRuntimeCache(true);
06422 
06423   // make sure only one face uses this surface
06424   if ( m_brep->SurfaceUseCount( m_si, 2 ) > 1 )
06425   {
06426     srf = srf->DuplicateSurface();
06427     m_si = m_brep->AddSurface(srf);
06428     SetProxySurface(srf);
06429   }
06430 
06431   ON_Interval u0 = srf->Domain(0);
06432   ON_Interval v0 = srf->Domain(1);
06433 
06434   // swap surface "u" and "v"
06435   ON_BOOL32 rc = srf->Transpose();
06436   if ( !rc )
06437     return false;
06438 
06439   ON_Interval u1 = srf->Domain(0);
06440   ON_Interval v1 = srf->Domain(1);
06441 
06442   ON_Xform xform(1);
06443   xform[0][0] = 0.0;
06444   xform[0][1] = 1.0;
06445   xform[1][0] = 1.0;
06446   xform[1][1] = 0.0;
06447 
06448   TransformTrim(xform);
06449 
06450   // reverse loop orientations.
06451   int fli;
06452   for ( fli = 0; fli < m_li.Count(); fli++ )
06453   {
06454     ON_BrepLoop* loop = m_brep->Loop(m_li[fli]);
06455     if ( loop )
06456       m_brep->FlipLoop( *loop );
06457   }
06458   
06459   m_bRev = m_bRev ? false : true;
06460 
06461   
06462   // 11 April 2008 Dale Lear:
06463   //    Transposing the surface and then toggling the m_bRev
06464   //    does not alter the brep's orientation.  Setting this flag
06465   //    to zero means we will have to do an unnecessary and
06466   //    expensive calculation in the future.
06467   //if (m_brep->m_is_solid == 1 || m_brep->m_is_solid == 2) m_brep->m_is_solid = 0;
06468 
06469         // Update analysis mesh and render mesh.
06470   // (Greg Arden 10 April 2003.  Fix TRR#9624.)
06471         if(m_render_mesh)
06472   {
06473                 m_render_mesh->TransposeSurfaceParameters();
06474                 m_render_mesh->TransposeTextureCoordinates();
06475   }
06476         if(m_analysis_mesh)
06477   {
06478                 m_analysis_mesh->TransposeSurfaceParameters();
06479                 m_analysis_mesh->TransposeTextureCoordinates();
06480   }
06481 
06482   return true;
06483 }
06484 
06485 bool ON_BrepFace::SetDomain(
06486        ON_Interval u_dom,
06487        ON_Interval v_dom
06488        )
06489 {
06490   if ( 0 == m_brep )
06491     return false;
06492   if ( !u_dom.IsIncreasing() )
06493     return false;
06494   if ( !v_dom.IsIncreasing() )
06495     return false;
06496   
06497   ON_Surface* srf = const_cast<ON_Surface*>(SurfaceOf());
06498   if ( 0 == srf )
06499     return false;
06500 
06501   ON_Interval u0_dom = srf->Domain(0);
06502   ON_Interval v0_dom = srf->Domain(1);
06503   if ( u0_dom == u_dom && v0_dom == v_dom )
06504     return true;
06505 
06506   ON_Xform xform(1);
06507   {
06508     ON_Xform ux(1), vx(1);
06509     if ( u0_dom != u_dom )
06510     {
06511       if ( !ux.IntervalChange(0,u0_dom,u_dom) )
06512         return false;
06513     }
06514     if ( v0_dom != v_dom )
06515     {
06516       if ( !vx.IntervalChange(1,v0_dom,v_dom) )
06517         return false;
06518     }
06519     xform = ux*vx;
06520   }
06521 
06522 // 2/18/03 GBA.  Destroy cache on the face.
06523         DestroyRuntimeCache(true);
06524 
06525   if ( m_brep->SurfaceUseCount( m_si, 2 ) > 1 )
06526   {
06527     srf = srf->DuplicateSurface();
06528     m_si = m_brep->AddSurface(srf);
06529     SetProxySurface(srf);
06530   }
06531 
06532   if ( u_dom != u0_dom )
06533   {
06534     if ( !srf->SetDomain( 0, u_dom ) )
06535       return false;
06536   }
06537 
06538   if ( v_dom != v0_dom )
06539   {
06540     if ( !srf->SetDomain( 1, v_dom ) )
06541     {
06542       srf->SetDomain(0,u0_dom );
06543       return false;
06544     }
06545   }
06546 
06547   // just to be sure 2d curves are in synch with actual surface
06548   // domain in case srf->SetDomain() does something weird.
06549   u_dom = srf->Domain(0);
06550   v_dom = srf->Domain(1);
06551   {
06552     ON_Xform ux(1), vx(1);
06553     if ( u0_dom != u_dom )
06554     {
06555       if ( !ux.IntervalChange(0,u0_dom,u_dom) )
06556         return false;
06557     }
06558     if ( v0_dom != v_dom )
06559     {
06560       if ( !vx.IntervalChange(1,v0_dom,v_dom) )
06561         return false;
06562     }
06563     xform = ux*vx;
06564   }
06565 
06566   if ( !TransformTrim(xform) )
06567     return false;
06568 
06569   ON_Mesh* mesh[3] = {m_analysis_mesh,m_render_mesh,m_preview_mesh};
06570   for ( int i = 0; i < 3; i++ )
06571   {
06572     if ( 0 == mesh[i] )
06573       continue;
06574     for ( int dir = 0; dir < 2; dir++ )
06575     {
06576       ON_Interval& mdom = mesh[i]->m_srf_domain[dir];
06577       ON_Interval dom0 = dir ? v0_dom : u0_dom;
06578       ON_Interval dom1 = dir ? v_dom : u_dom;
06579       if ( mdom.IsIncreasing() && dom0 != dom1 )
06580       {
06581         if ( mdom == dom0 )
06582           mdom = dom1;
06583         else
06584         {
06585           double t0 = dom1.ParameterAt(dom0.NormalizedParameterAt(mdom[0]));
06586           double t1 = dom1.ParameterAt(dom0.NormalizedParameterAt(mdom[1]));
06587           mdom.Set(t0,t1);
06588         }        
06589       }
06590     }
06591   }
06592 
06593   return true;
06594 }
06595 
06596 ON_BOOL32 ON_BrepFace::SetDomain( 
06597     int dir, // 0 sets first parameter's domain, 1 gets second parameter's domain
06598     double t0, 
06599     double t1
06600     )
06601 {
06602   if (    dir < 0 
06603        || dir > 1 
06604        || t0 == ON_UNSET_VALUE 
06605        || t1 == ON_UNSET_VALUE 
06606        || t0 >= t1
06607        || 0 == m_brep )
06608     return false;
06609 
06610   ON_Surface* srf = const_cast<ON_Surface*>(SurfaceOf());
06611   if ( 0 == srf )
06612     return false;
06613   ON_Interval udom = srf->Domain(0);
06614   ON_Interval vdom = srf->Domain(1);
06615   if ( dir )
06616     vdom.Set(t0,t1);
06617   else
06618     udom.Set(t0,t1);
06619 
06620   return SetDomain( udom, vdom );
06621 }
06622 
06623 
06624 
06625 //bool ON_Brep::ReverseFaceParameter(
06626 //      int face_index, // index of face
06627 //      int dir // dir = 0 reverse "u", 1 reverse "v"
06628 //      )
06629 //{
06630 //  // OBSOLETE - use ON_BrepFace::Reverse(dir)
06631 //  bool rc = false;
06632 //  ON_BrepFace* face = Face(face_index);
06633 //  if ( face )
06634 //    rc = face->Reverse(dir)?true:false;
06635 //  return rc;
06636 //}
06637 
06638 int ON_Brep::TrimCurveUseCount( int c2_index, int max_count ) const
06639 {
06640   int ti, use_count = 0;
06641   if ( max_count < 1 )
06642     max_count = m_T.Count();
06643   for ( ti = 0; ti < m_T.Count() && use_count < max_count; ti++ )
06644   {
06645     if ( m_T[ti].m_c2i == c2_index )
06646       use_count++;
06647   }
06648   return use_count;
06649 }
06650 
06651 int ON_Brep::EdgeCurveUseCount( int c3_index, int max_count ) const
06652 {
06653   int ei, use_count = 0;
06654   if ( max_count < 1 )
06655     max_count = m_T.Count();
06656   for ( ei = 0; ei < m_E.Count() && use_count < max_count; ei++ )
06657   {
06658     if ( m_E[ei].m_c3i == c3_index )
06659       use_count++;
06660   }
06661   return use_count;
06662 }
06663 
06664 int ON_Brep::SurfaceUseCount( int surface_index, int max_count ) const
06665 {
06666   int fi, use_count = 0;
06667   if ( max_count < 1 )
06668     max_count = m_F.Count();
06669   for ( fi = 0; fi < m_F.Count() && use_count < max_count; fi++ )
06670   {
06671     if ( m_F[fi].m_si == surface_index )
06672       use_count++;
06673   }
06674   return use_count;
06675 }
06676 
06678 // Change the domain of a face
06679 // This also transforms the "u" and "v" coordinates of all the 
06680 // face's parameter space trimming curves.
06681 //bool ON_Brep::SetFaceDomain(
06682 //       int face_index, // index of face in m_F[] array
06683 //       const ON_Interval& u_dom,
06684 //       const ON_Interval& v_dom
06685 //       )
06686 //{
06687 //  // OBSOLETE
06688 //  bool rc = false;
06689 //  ON_BrepFace* face = Face(face_index);
06690 //  if ( face )
06691 //    rc = face->SetDomain(u_dom,v_dom);
06692 //  return rc;
06693 //}
06694 
06695 //bool
06696 //ON_Brep::SwapFaceParameters( int face_index )
06697 //{
06698 //  // OBSOLETE
06699 //  bool rc = false;
06700 //  ON_BrepFace* face = Face(face_index);
06701 //  if ( face )
06702 //    rc = face->Transpose()?true:false;
06703 //  return rc;
06704 //}
06705 
06706 void
06707 ON_Brep::Flip()
06708 {
06709   const int fcnt = m_F.Count();
06710   int fi;
06711   int missolid = m_is_solid;
06712   for ( fi = 0; fi < fcnt; fi++ ) {
06713     FlipFace(m_F[fi]);
06714   }
06715   if (missolid==1) m_is_solid = 2;
06716   else if (missolid==2) m_is_solid = 1;
06717 }
06718 
06719 //void
06720 //ON_Brep::FlipEdge( ON_BrepEdge& edge )
06721 //{
06722 //  edge.Reverse();
06723 //}
06724 
06725 void
06726 ON_Brep::FlipFace( ON_BrepFace& face )
06727 {
06728   face.m_bRev = (face.m_bRev) ? false : true;
06729   if ( face.m_analysis_mesh )
06730     face.m_analysis_mesh->Flip();
06731   if ( face.m_render_mesh )
06732     face.m_render_mesh->Flip();
06733   if ( face.m_preview_mesh )
06734     face.m_preview_mesh->Flip();
06735   //Jun 16 2011 - Chuck - m_is_solid==3 for a brep with inconsistent normals. 
06736   //Flipping a face could make the normals consistent.
06737   //if (m_is_solid == 1 || m_is_solid == 2)
06738   if (0 != m_is_solid)
06739     m_is_solid = 0;
06740 }
06741 
06742 //void 
06743 //ON_Brep::FlipTrim(ON_BrepTrim& trim)
06744 //{
06745 //  trim.Reverse();
06746 //}
06747 
06748 void 
06749 ON_Brep::FlipLoop(ON_BrepLoop& loop)
06750 {
06751   int ti, lti;
06752   const int brep_trim_count = m_T.Count();
06753   const int loop_trim_count = loop.m_ti.Count();
06754 
06755   // reverse order of trimming curves
06756   loop.m_ti.Reverse();
06757   // reverse direction of individual trimming curves
06758   for ( lti = 0; lti < loop_trim_count; lti++ ) 
06759   {
06760     ti = loop.m_ti[lti];
06761     if ( ti >= 0 && ti < brep_trim_count ) 
06762     {
06763       m_T[ti].Reverse();
06764     }
06765   }
06766 }
06767 
06768 static int curve_area( ON_3dPoint& start_point, const ON_Curve* curve, const ON_Interval& curve_domain, const ON_Xform* xform, double *area )
06769 {
06770   // ges a CRUDE approximation of curve area to use for
06771   // determining if a simple closed curve 2d has 
06772   // clockwise or couterclockwise orientation.
06773   ON_Workspace ws;
06774   ON_Interval span_domain;
06775   double *span_vector, *t, twice_area = 0.0;
06776   ON_3dPoint p0, p1;
06777   int degree, span_count, span_i, j;
06778   if ( !area )
06779     return false;
06780   *area = 0;
06781   if ( !curve )
06782     return false;
06783   const ON_PolyCurve* polycurve = ON_PolyCurve::Cast(curve);
06784   if ( polycurve )
06785   {
06786     span_count = polycurve->Count();  
06787     ON_Interval span_domain, segment_curve_domain;
06788     double s0, s1;
06789     for ( span_i = 0; span_i < span_count; span_i++ )
06790     {
06791       span_domain = polycurve->SegmentDomain(span_i);
06792       if ( span_domain[1] <= curve_domain[0] )
06793         continue;
06794       if ( span_domain[0] >= curve_domain[1] )
06795         break;
06796       const ON_Curve* segment_curve = polycurve->SegmentCurve(span_i);
06797       segment_curve_domain = segment_curve->Domain();
06798       if ( curve_domain[0] > span_domain[0] || curve_domain[1] < span_domain[1] )
06799       {
06800         s0 = (curve_domain[0] > span_domain[0]) ? curve_domain[0] : span_domain[0];
06801         s1 = (curve_domain[1] < span_domain[1]) ? curve_domain[1] : span_domain[1];
06802         if ( segment_curve_domain != span_domain )
06803         {
06804           s0 = span_domain.NormalizedParameterAt(s0);
06805           s1 = span_domain.NormalizedParameterAt(s1);
06806           s0 = segment_curve_domain.ParameterAt(s0);
06807           s1 = segment_curve_domain.ParameterAt(s1);
06808         }
06809         segment_curve_domain.Set(s0,s1);
06810       }
06811       if ( !curve_area( start_point, segment_curve, segment_curve_domain, xform, &twice_area ) )
06812       {
06813         *area = 0.0;
06814         return false;
06815       }
06816       *area += twice_area;
06817     }
06818   }
06819   else 
06820   {
06821     span_count = curve->SpanCount();
06822     if ( span_count < 1 )
06823       return false;
06824     degree = curve->Degree();
06825     if ( degree <= 1 )
06826     {
06827       degree = 1;
06828     }
06829     else if ( degree < 4)
06830     {
06831       degree = 4;
06832       // 6 January 2006 Dale Lear
06833       //     Every time you find a closed curve that
06834       //     gets the wrong dir, increase the number
06835       //     after the < by one until it works.  Add
06836       //     the curve to RR and list the RR number here.
06837       while ( span_count*degree < 16 )
06838         degree *= 2;
06839     }
06840 
06841     span_vector = ws.GetDoubleMemory(span_count+1+degree);
06842     t = span_vector+(span_count+1);
06843     t[0] = 0.0;
06844     for ( j = 1; j < degree; j++ ) {
06845       t[j] = ((double)(j))/(degree);
06846     }
06847     if ( !curve->GetSpanVector( span_vector ) )
06848       return false;
06849 
06850     p1 = xform ? (*xform)*start_point : start_point;
06851     for ( span_i = 0; span_i < span_count; span_i++ ) {
06852       span_domain.Set( span_vector[span_i], span_vector[span_i+1] );
06853       if ( span_domain[1] <= curve_domain[0] )
06854         continue;
06855       if ( span_domain[0] >= curve_domain[1] )
06856         break;
06857       if ( span_domain[1] > curve_domain[1] )
06858         span_domain.m_t[1] = curve_domain[1];
06859       if ( span_domain[0] < curve_domain[0] )
06860         span_domain.m_t[0] = curve_domain[0];
06861       if ( span_domain[0] >= span_domain[1] )
06862         continue;
06863       for ( j = 0; j < degree; j++ ) {
06864         p0 = p1;
06865         p1 = curve->PointAt(span_domain.ParameterAt(t[j]));
06866         if ( xform )
06867           p1 = (*xform)*p1;
06868         twice_area += (p0.x-p1.x)*(p0.y+p1.y);
06869         if ( !span_i && !j ) {
06870           // check gap
06871         }
06872       }
06873     }
06874     p0 = p1;
06875     p1 = curve->PointAt(curve_domain[1]);
06876     twice_area += (p0.x-p1.x)*(p0.y+p1.y);
06877     start_point = p1;
06878     *area = 0.5*twice_area;
06879   }  
06880   
06881   return true;
06882 }
06883 
06884 int ON_ClosedCurveOrientation( const ON_Curve& curve, const ON_Xform* xform )
06885 {
06886   int curve_orientation = 0;
06887   double area = 0.0;
06888   ON_3dPoint start_point = curve.PointAtEnd();
06889   const ON_Interval curve_domain = curve.Domain();
06890   if ( xform && xform->IsIdentity() )
06891     xform = 0;
06892   if (curve_area( start_point, &curve, curve_domain, xform, &area ))
06893   {
06894     double noise = 0.0;
06895     if ( area > noise )
06896       curve_orientation = 1;
06897     else if (area < noise )
06898       curve_orientation = -1;
06899   }
06900   return curve_orientation;
06901 }
06902 
06903 static int loop_type_compar(const ON_BrepLoop *const* ppLoopA, const ON_BrepLoop *const* ppLoopB )
06904 {
06905   const ON_BrepLoop* loopA = *ppLoopA;
06906   const ON_BrepLoop* loopB = *ppLoopB;
06907   if ( loopA->m_type == loopB->m_type )
06908     return 0;
06909   if ( loopA->m_type == ON_BrepLoop::unknown )
06910     return 1;
06911   if ( loopB->m_type == ON_BrepLoop::unknown )
06912     return -1;
06913   if ( loopA->m_type < loopB->m_type )
06914     return -1;
06915   if ( loopA->m_type > loopB->m_type )
06916     return 1;
06917   return 0;
06918 }
06919 
06920 bool ON_Brep::SortFaceLoops( ON_BrepFace& face ) const
06921 {
06922   int fli, li, loop_type;
06923   const int face_loop_count = face.m_li.Count();
06924   const int loop_count = m_L.Count();
06925   if ( face_loop_count < 1 || loop_count < 1 )
06926     return false;
06927   bool rc = true;
06928   ON_SimpleArray<const ON_BrepLoop*> loop_ptr(face_loop_count);
06929   for ( fli = 0; fli < face_loop_count; fli++ )
06930   {
06931     li = face.m_li[fli];
06932     if ( li < 0 || li >= loop_count )
06933       return false;
06934     const ON_BrepLoop& loop = m_L[li];
06935     if ( loop.m_loop_index != li )
06936       return false;
06937     loop_type = loop.m_type;
06938     if ( loop_type <= ON_BrepLoop::unknown || loop_type >= ON_BrepLoop::type_count )
06939       rc = false;
06940     loop_ptr.Append( &m_L[li] );
06941   }
06942   loop_ptr.QuickSort( loop_type_compar );
06943   for ( fli = 0; fli < face_loop_count; fli++ )
06944   {
06945     face.m_li[fli] = loop_ptr[fli]->m_loop_index;
06946   }
06947   return rc;
06948 }
06949 
06950 
06951 int 
06952 ON_Brep::LoopDirection( const ON_BrepLoop& loop ) const
06953 {
06954   ON_3dPoint start_point;
06955   double d, a = 0.0;
06956   int ti, lti, c2i;
06957   const int brep_trim_count = m_T.Count();
06958   const int brep_C2_count = m_C2.Count();
06959   const int loop_trim_count = loop.m_ti.Count();
06960 
06961   double noise = 0.0;
06962 
06963   // reverse direction of individual trimming curves
06964   for ( lti = 0; lti < loop_trim_count; lti++ ) {
06965     ti = loop.m_ti[lti];
06966     if ( ti < 0 || ti >= brep_trim_count ) {
06967       a = 0.0;
06968       break;
06969     }
06970     c2i =  m_T[ti].m_c2i;
06971     if ( c2i < 0 || c2i >= brep_C2_count ) {
06972       a = 0.0;
06973       break;
06974     }
06975     if ( lti == 0 ) 
06976     {
06977       // evaluate start of first trim
06978       if ( m_C2[c2i] )
06979         start_point = m_T[ti].PointAtStart(); //m_C2[c2i]->PointAt(m_T[ti].m_t[0]);
06980     }
06981     if ( !curve_area( start_point, &m_T[ti], m_T[ti].Domain(), 0, &d ) ) {
06982       a = 0.0;
06983       break;
06984     }
06985     //noise += fabs(d);
06986     a += d;
06987   }
06988 
06989   //this fixes trr 9351.  Change at your own risk.
06990   //noise *= 10.0*ON_EPSILON;
06991 
06992   if (a > noise)
06993     return 1;
06994   else if (a < -noise)
06995     return -1;
06996   return 0;
06997 }
06998 
06999 bool ON_Brep::SetVertexTolerances( ON_BOOL32 bLazy )
07000 {
07001   bool rc = true;
07002   int vi, vertex_count = m_V.Count();
07003   for ( vi = 0; vi < vertex_count; vi++ )
07004   {
07005     if ( !SetVertexTolerance( m_V[vi], bLazy ) )
07006       rc = false;
07007   }
07008   return rc;
07009 }
07010 
07011 bool
07012 ON_Brep::SetVertexTolerance( ON_BrepVertex& vertex,
07013   ON_BOOL32 bLazySet // default = false
07014                 // false: recompute tolerance even if
07015                 //        its current value is positive
07016                 // true:  recompute tolerance only if
07017                 //        its current value is nonpositive
07018   ) const
07019 {
07020   if ( vertex.m_tolerance < 0.0 || !bLazySet ) {
07021     const int vertex_edge_count = vertex.EdgeCount();
07022     if ( vertex_edge_count < 1 ) {
07023       vertex.m_tolerance = 0.0;
07024     }
07025     else {
07026       vertex.m_tolerance = ON_UNSET_VALUE;
07027       double tolerance = 0.0;
07028       double d;
07029       ON_3dPoint uv;
07030       ON_Interval edge_domain;
07031       //const ON_Curve* c=0;
07032       const ON_Surface* s=0;
07033       int vei, ei, eti, endi;
07034       const int vertex_index = vertex.m_vertex_index;
07035       for ( vei = 0; vei < vertex_edge_count; vei++ ) 
07036       {
07037         ei = vertex.m_ei[vei];
07038         if ( ei < 0 )
07039           return false;
07040         const ON_BrepEdge& edge = m_E[ei];
07041         if ( !edge.ProxyCurve() )
07042           return false;
07043         edge_domain = edge.Domain();
07044         for ( endi = 0; endi < 2; endi++ )
07045         {
07046           if ( edge.m_vi[endi] == vertex_index ) 
07047           {
07048             d = vertex.point.DistanceTo( edge.PointAt(edge_domain[endi]) );
07049             if ( tolerance < d )
07050               tolerance = d;
07051           }
07052         }
07053         const int edge_trim_count = edge.m_ti.Count();
07054         for ( eti = 0; eti < edge_trim_count; eti++ ) 
07055         {
07056           const ON_BrepTrim* trim = Trim(edge.m_ti[eti]);
07057           if ( 0 == trim )
07058             continue;
07059           if ( 0 == trim->TrimCurveOf() )
07060             continue;
07061           s = trim->SurfaceOf();
07062           if ( 0 == s )
07063             continue;
07064           for ( endi = 0; endi < 2; endi++ ) {
07065             if ( edge.m_vi[endi] == vertex_index ) {
07066               uv = trim->PointAt( trim->Domain()[trim->m_bRev3d?1-endi:endi] );
07067               d = vertex.point.DistanceTo( s->PointAt(uv.x,uv.y) );
07068               if ( tolerance < d )
07069                 tolerance = d;
07070             }
07071           }
07072         }
07073       }
07074       vertex.m_tolerance = (tolerance <= ON_ZERO_TOLERANCE) ? 0.0 : 1.001*tolerance;
07075     }
07076   }
07077   return (vertex.m_tolerance >= 0.0) ? true : false;
07078 }
07079 
07080 bool
07081 ON_Brep::SetTrimTolerance( ON_BrepTrim& trim, ON_BOOL32 bLazy ) const
07082 {
07083   // The TL_Brep::SetTrimTolerance override of this virtual function
07084   // sets ON_BrepTrim::m_tolerance[] correctly.
07085   double ds, de, d;
07086   int dir, lti, prev_ti, next_ti;
07087   if ( trim.m_tolerance[0] < 0.0 || trim.m_tolerance[1] < 0.0 || !bLazy )
07088   {
07089     // set trim tolerance
07090     if ( trim.m_li >= 0 && trim.m_li < m_L.Count() )
07091     {
07092       const ON_BrepLoop& loop = m_L[trim.m_li];
07093       const int loop_trim_count = loop.m_ti.Count();
07094       for ( lti = 0; lti < loop_trim_count; lti++ )
07095       {
07096         if ( loop.m_ti[lti] == trim.m_trim_index )
07097         {
07098           prev_ti = loop.m_ti[(lti-1+loop_trim_count)%loop_trim_count];
07099           next_ti = loop.m_ti[(lti+1)%loop_trim_count];
07100           if ( prev_ti >= 0 && next_ti >= 0 && prev_ti < m_T.Count() && next_ti < m_T.Count() )
07101           {
07102             const ON_BrepTrim& prev_trim = m_T[prev_ti];
07103             const ON_BrepTrim& next_trim = m_T[next_ti];
07104             const ON_Curve* prev_c2 = prev_trim.TrimCurveOf();
07105             const ON_Curve* next_c2 = next_trim.TrimCurveOf();
07106             const ON_Curve* c2 = trim.TrimCurveOf();
07107             if ( prev_c2 && c2 && next_c2 )
07108             {
07109               ON_3dPoint prev_end = prev_trim.PointAtEnd(); //prev_c2->PointAt( prev_trim.m_t[1] );
07110               ON_3dPoint this_start = trim.PointAtStart(); //c2->PointAt( trim.m_t[0] );
07111               ON_3dPoint this_end = trim.PointAtEnd(); // c2->PointAt( trim.m_t[1] );
07112               ON_3dPoint next_start = next_trim.PointAtStart(); //prev_c2->PointAt( next_trim.m_t[0] );
07113               for ( dir = 0; dir < 2; dir++ )
07114               {
07115                 if ( trim.m_tolerance[dir] < 0.0 || !bLazy )
07116                 {
07117                   ds = fabs(prev_end[dir] - this_start[dir] );
07118                   de = fabs(this_end[dir] - next_start[dir] );
07119                   d = (ds >= de) ? ds : de;
07120                   trim.m_tolerance[dir] = ( d > ON_ZERO_TOLERANCE ) ? 1.001*d : 0.0;
07121                 }
07122               }
07123             }
07124           }
07125           break;
07126         }
07127       }
07128     }
07129   }
07130   return (trim.m_tolerance[0] >= 0.0 && trim.m_tolerance[1] >= 0.0) ? true : false;
07131 }
07132 
07133 bool
07134 ON_Brep::SetEdgeTolerance( ON_BrepEdge& edge, ON_BOOL32 bLazySet ) const
07135 {
07136   if ( edge.m_tolerance < 0.0 || !bLazySet ) 
07137   {
07138     const int edge_trim_count = edge.m_ti.Count();
07139     if ( edge_trim_count < 1 ) 
07140     {
07141       edge.m_tolerance = 0.0;
07142     }
07143     else 
07144     {
07145       edge.m_tolerance = ON_UNSET_VALUE;
07146       // TL_Brep::SetEdgeTolerance overrides ON_Brep::SetEdgeTolerance
07147       // and sets teh tolerance correctly.
07148     }
07149   }
07150   return (edge.m_tolerance >= 0.0) ? true : false;
07151 }
07152 
07153 bool ON_Brep::SetTrimTolerances( ON_BOOL32 bLazy )
07154 {
07155   bool rc = true;
07156   int ti, trim_count = m_T.Count();
07157   for ( ti = 0; ti < trim_count; ti++ )
07158   {
07159     if ( !SetTrimTolerance( m_T[ti], bLazy ) )
07160       rc = false;
07161   }
07162   return rc;
07163 }
07164 
07165 bool ON_Brep::SetEdgeTolerances( ON_BOOL32 bLazy )
07166 {
07167   bool rc = true;
07168   int ei, edge_count = m_E.Count();
07169   for ( ei = 0; ei < edge_count; ei++ )
07170   {
07171     if ( !SetEdgeTolerance( m_E[ei], bLazy ) )
07172       rc = false;
07173   }
07174   return rc;
07175 }
07176 
07177 
07178 void ON_Brep::Dump( ON_TextLog& dump ) const
07179 {
07180   dump.Print("ON_Brep:\n");
07181 
07182   if ( IsSurface() ) {
07183     dump.Print("(B-rep geometry is the same as underlying surface.)\n");
07184   }
07185 
07186   dump.Print("surfaces:  %d\n",m_S.Count());
07187   dump.Print("3d curve:  %d\n",m_C3.Count());
07188   dump.Print("2d curves: %d\n",m_C2.Count());
07189   dump.Print("vertices:  %d\n",m_V.Count());
07190   dump.Print("edges:     %d\n",m_E.Count());
07191   dump.Print("trims:     %d\n",m_T.Count());
07192   dump.Print("loops:     %d\n",m_L.Count());
07193   dump.Print("faces:     %d\n",m_F.Count());
07194 
07195   int c2i;
07196   for ( c2i = 0; c2i < m_C2.Count(); c2i++ )
07197   {
07198     const ON_Curve* c2 = m_C2[c2i];
07199     if ( c2 )
07200     {
07201       ON_Interval cdom = c2->Domain();
07202       ON_3dPoint c_start, c_end;
07203       c_start = c2->PointAtStart();
07204       c_end = c2->PointAtEnd();
07205       const char* s = c2->ClassId()->ClassName();
07206       if ( !s )
07207         s = "";
07208       dump.Print("curve2d[%2d]: %s domain(%g,%g) start(%g,%g) end(%g,%g)\n",
07209                   c2i, s, cdom[0], cdom[1],
07210                   c_start.x, c_start.y,
07211                   c_end.x, c_end.y);
07212     }
07213     else
07214     {
07215       dump.Print("curve2d[%2d]: NULL\n",c2i);
07216     }
07217   }
07218 
07219   int c3i;
07220   for ( c3i = 0; c3i < m_C3.Count(); c3i++ )
07221   {
07222     const ON_Curve* c3 = m_C3[c3i];
07223     if ( c3 )
07224     {
07225       ON_Interval cdom = c3->Domain();
07226       ON_3dPoint c_start, c_end;
07227       c_start = c3->PointAtStart();
07228       c_end = c3->PointAtEnd();
07229       const char* s = c3->ClassId()->ClassName();
07230       if ( !s )
07231         s = "";
07232       dump.Print("curve3d[%2d]: %s domain(%g,%g) start(%g,%g,%g) end(%g,%g,%g)\n",
07233                  c3i, s, cdom[0], cdom[1],
07234                  c_start.x, c_start.y, c_start.z,
07235                  c_end.x, c_end.y, c_end.z);
07236     }
07237     else
07238     {
07239       dump.Print("curve2d[%2d]: NULL\n",c3i);
07240     }
07241   }
07242 
07243   int si;
07244   for ( si = 0; si < m_S.Count(); si++ )
07245   {
07246     const ON_Surface* srf = m_S[si];
07247     if ( srf )
07248     {
07249       ON_Interval udom = srf->Domain(0);
07250       ON_Interval vdom = srf->Domain(1);
07251       const char* s = srf->ClassId()->ClassName();
07252       if ( !s )
07253         s = "";
07254       dump.Print("surface[%2d]: %s u(%g,%g) v(%g,%g)\n",
07255                  si, s, 
07256                  udom[0], udom[1], 
07257                  vdom[0], vdom[1]
07258                  );
07259       if ( m_S.Count() == 1 && IsSurface() )
07260       {
07261         dump.PushIndent();
07262         dump.Print("surface details:\n");
07263         dump.PushIndent();
07264         srf->Dump(dump);
07265         dump.PopIndent();
07266         dump.PopIndent();
07267       }
07268     }
07269     else
07270     {
07271       dump.Print("surface[%2d]: NULL\n",si);
07272     }
07273   }
07274 
07275   int vi;
07276   for ( vi = 0; vi < m_V.Count(); vi++ ) {
07277     const ON_BrepVertex& vertex = m_V[vi];
07278     dump.Print("vertex[%2d]: (%f %f %f) tolerance(%g)\n",
07279                vi,vertex.point.x,vertex.point.y,vertex.point.z,
07280                vertex.m_tolerance);
07281     if ( vertex.m_ei.Count() > 0 ) {
07282       int vei;
07283       dump.PushIndent();
07284       dump.Print("edges (");
07285       for ( vei = 0; vei < vertex.m_ei.Count(); vei++ ) {
07286         dump.Print( (vei)?",%d":"%d", vertex.m_ei[vei] );
07287       }
07288       dump.PopIndent();
07289       dump.Print(")\n");
07290     }
07291   }
07292 
07293   int ei,ti;
07294   for ( ei = 0; ei < m_E.Count(); ei++ ) {
07295     const ON_BrepEdge& edge = m_E[ei];
07296     dump.Print("edge[%2d]: v0(%2d) v1(%2d) 3d_curve(%d) tolerance(%g)\n",
07297                ei,edge.m_vi[0],edge.m_vi[1],edge.m_c3i,edge.m_tolerance);
07298 
07299     dump.PushIndent();
07300 
07301     const ON_Curve* c3 = edge.EdgeCurveOf();
07302     if ( c3 )
07303     {
07304       ON_3dPoint edge_start = edge.PointAtStart();
07305       ON_3dPoint edge_end = edge.PointAtEnd();
07306       dump.Print("domain(%g,%g) start(%g,%g,%g) end(%g,%g,%g)\n",
07307            edge.Domain()[0],edge.Domain()[1],
07308            edge_start.x,edge_start.y,edge_start.z,
07309            edge_end.x,edge_end.y,edge_end.z
07310            );
07311     }
07312     else
07313     {
07314       dump.Print("domain(%g,%g) start(?,?,?) end(?,?,?)\n",
07315            edge.Domain()[0],edge.Domain()[1]);
07316     }
07317 
07318     if ( edge.m_ti.Count() > 0 ) 
07319     {
07320 
07321       dump.Print("trims (",edge.m_ti.Count());
07322       int eti;
07323       for ( eti = 0; eti < edge.m_ti.Count(); eti++ )
07324       {
07325         ti = edge.m_ti[eti];
07326         const char* sign = "?";
07327         if ( ti >= 0 && ti < m_T.Count() ) {
07328           sign = m_T[ti].m_bRev3d ? "-" : "+";
07329         }
07330         dump.Print( (eti)?",%s%d":"%s%d", sign,edge.m_ti[eti]);
07331       }
07332 
07333       dump.Print(")\n");
07334     }
07335 
07336     dump.PopIndent();
07337   }
07338 
07339   int fi;
07340   for ( fi = 0; fi < m_F.Count(); fi++ ) {
07341     const ON_BrepFace& face = m_F[fi];
07342     const ON_Surface* face_srf = face.SurfaceOf();
07343     dump.Print("face[%2d]: surface(%d) reverse(%d) loops(",
07344                fi,face.m_si,face.m_bRev);
07345     int fli;
07346     for ( fli = 0; fli < face.m_li.Count(); fli++ ) {
07347       dump.Print( (fli)?",%d":"%d", face.m_li[fli]);
07348     }
07349     dump.Print(")\n");
07350     dump.PushIndent();
07351     if ( face.m_render_mesh ) 
07352     {
07353       const char* mp_style = "Custom";
07354       const ON_MeshParameters* mp = face.m_render_mesh->MeshParameters();
07355       if ( mp )
07356       {
07357         if ( 0 == mp->CompareGeometrySettings(ON_MeshParameters::FastRenderMesh) )
07358           mp_style = "Fast";
07359         else if ( 0 == mp->CompareGeometrySettings(ON_MeshParameters::QualityRenderMesh) )
07360           mp_style = "Quality";
07361       }
07362       dump.Print("%s render mesh: %d polygons\n",mp_style,face.m_render_mesh->FaceCount());
07363     }
07364     if ( face.m_analysis_mesh ) {
07365       dump.Print("Analysis mesh: %d polygons\n",face.m_analysis_mesh->FaceCount());
07366     }
07367     if ( FaceIsSurface(fi) ) {
07368       dump.Print("(Face geometry is the same as underlying surface.)\n");
07369     }
07370 
07371 
07372     for ( fli = 0; fli < face.m_li.Count(); fli++ ) 
07373     {
07374       const int li = face.m_li[fli];
07375       const ON_BrepLoop& loop = m_L[li];
07376       const char* sLoopType = 0;
07377       switch( loop.m_type ) 
07378       {
07379       case ON_BrepLoop::unknown:
07380         sLoopType = "unknown";
07381         break;
07382       case ON_BrepLoop::outer:
07383         sLoopType = "outer";
07384         break;
07385       case ON_BrepLoop::inner:
07386         sLoopType = "inner";
07387         break;
07388       case ON_BrepLoop::slit:
07389         sLoopType = "slit";
07390         break;
07391       case ON_BrepLoop::crvonsrf:
07392         sLoopType = "crvonsrf";
07393         break;
07394       default:
07395         sLoopType = "unknown";
07396         break;
07397       }
07398       dump.Print("loop[%2d]: type(%s) %d trims(",
07399                  li, sLoopType, loop.m_ti.Count());
07400       int lti;
07401       for ( lti = 0; lti < loop.m_ti.Count(); lti++ ) 
07402       {
07403         dump.Print( (lti)?",%d":"%d", loop.m_ti[lti]);
07404       }
07405       dump.Print(")\n");
07406       dump.PushIndent();
07407       for ( lti = 0; lti < loop.m_ti.Count(); lti++ ) 
07408       {
07409         const int ti = loop.m_ti[lti];
07410         const ON_BrepTrim& trim = m_T[ti];
07411         const char* sTrimType = "?";
07412         const char* sTrimIso = "-?";
07413         const ON_Curve* c2 = trim.TrimCurveOf();
07414         ON_3dPoint trim_start, trim_end;
07415         switch( trim.m_type ) {
07416         case ON_BrepTrim::unknown:
07417           sTrimType = "unknown ";
07418           break;
07419         case ON_BrepTrim::boundary:
07420           sTrimType = "boundary";
07421           break;
07422         case ON_BrepTrim::mated:
07423           sTrimType = "mated   ";
07424           break;
07425         case ON_BrepTrim::seam:
07426           sTrimType = "seam    ";
07427           break;
07428         case ON_BrepTrim::singular:
07429           sTrimType = "singular";
07430           break;
07431         case ON_BrepTrim::crvonsrf:
07432           sTrimType = "crvonsrf";
07433           break;
07434         default:
07435           sTrimType = "unknown";
07436           break;
07437         }
07438         switch( trim.m_iso ) {
07439         case ON_Surface::not_iso:
07440           sTrimIso = "";
07441           break;
07442         case ON_Surface::x_iso:
07443           sTrimIso = "-u iso";
07444           break;
07445         case ON_Surface::W_iso:
07446           sTrimIso = "-west side iso";
07447           break;
07448         case ON_Surface::E_iso:
07449           sTrimIso = "-east side iso";
07450           break;
07451         case ON_Surface::y_iso:
07452           sTrimIso = "-v iso";
07453           break;
07454         case ON_Surface::S_iso:
07455           sTrimIso = "-south side iso";
07456           break;
07457         case ON_Surface::N_iso:
07458           sTrimIso = "-north side iso";
07459           break;
07460         default:
07461           sTrimIso = "-unknown_iso_flag";
07462           break;
07463         }
07464         dump.Print("trim[%2d]: edge(%2d) v0(%2d) v1(%2d) tolerance(%g,%g)\n",
07465                    ti,
07466                    trim.m_ei,trim.m_vi[0],trim.m_vi[1],
07467                    trim.m_tolerance[0],trim.m_tolerance[1]);
07468         dump.PushIndent();
07469         dump.Print("type(%s%s) rev3d(%d) 2d_curve(%d)\n",
07470                    sTrimType, sTrimIso, trim.m_bRev3d, trim.m_c2i);
07471         if ( c2 )
07472         {
07473           trim_start = trim.PointAtStart();
07474           trim_end = trim.PointAtEnd();
07475           dump.Print("domain(%g,%g) start(%g,%g) end(%g,%g)\n",
07476                trim.Domain()[0],trim.Domain()[1],
07477                trim_start.x,trim_start.y,
07478                trim_end.x,trim_end.y);
07479           if ( 0 != face_srf )
07480           {
07481             ON_3dPoint trim_srfstart = face_srf->PointAt(trim_start.x,trim_start.y);
07482             ON_3dPoint trim_srfend = face_srf->PointAt(trim_end.x,trim_end.y);
07483             dump.Print("surface points start(%g,%g,%g) end(%g,%g,%g)\n",
07484                  trim_srfstart.x,trim_srfstart.y,trim_srfstart.z,
07485                  trim_srfend.x,trim_srfend.y,trim_srfend.z);
07486           }
07487         }
07488         else
07489         {
07490           dump.Print("domain(%g,%g) start(?,?) end(?,?)\n",
07491                trim.Domain()[0],trim.Domain()[1]);
07492         }
07493         dump.PopIndent();
07494       }
07495       dump.PopIndent();
07496     }
07497     dump.PopIndent();
07498   }
07499 
07500   //int si;
07501   //for ( si = 0; si < m_S.Count(); si++ ) {
07502   //  dump.Print("surface[%d]:\n",si);
07503   //  dump.PushIndent();
07504   //  if ( m_S[si] )
07505   //    m_S[si]->Dump(dump);
07506   //  else
07507   //    dump.Print("NULL\n");
07508   //  dump.PopIndent();
07509   //}
07510 
07511 }
07512 
07513 
07514 
07515 //int ON_Brep::FaceIndexOf( const ON_BrepTrim& trim ) const
07516 //{
07517 //  int fi = -1;
07518 //  if ( trim.m_li >= 0 && trim.m_li < m_L.Count() )
07519 //  {
07520 //    fi = m_L[trim.m_li].m_fi;
07521 //    if ( fi < 0 || fi >= m_F.Count() )
07522 //      fi = -1;
07523 //  }
07524 //  return fi;
07525 //}
07526 
07527 //int ON_Brep::FaceIndexOf( const ON_BrepLoop& loop ) const
07528 //{
07529 //  int fi = -1;
07530 //  if ( loop.m_fi >= 0 && loop.m_fi < m_F.Count() )
07531 //    fi = loop.m_fi;
07532 //  return fi;
07533 //}
07534 
07535 //const ON_BrepFace* ON_Brep::FaceOf( const ON_BrepTrim& trim ) const
07536 //{
07537 //  // OBSOLETE
07538 //  return trim.Face();
07539 //}
07540 
07541 //const ON_BrepFace* ON_Brep::FaceOf( const ON_BrepLoop& loop ) const
07542 //{
07543 //  // OBSOLETE
07544 //  return loop.Face();
07545 //}
07546 
07547 
07548 //int ON_Brep::SurfaceIndexOf( const ON_BrepTrim& trim ) const
07549 //{
07550 //  // OBSOLETE
07551 //  return trim.SurfaceIndexOf();
07552 //}
07553 
07554 //int ON_Brep::SurfaceIndexOf( const ON_BrepLoop& loop ) const
07555 //{
07556 //  // OBSOLETE
07557 //  return loop.SurfaceIndexOf();
07558 //}
07559 
07560 //int ON_Brep::SurfaceIndexOf( const ON_BrepFace& face ) const
07561 //{
07562 //  // OBSOLETE FUNCTION
07563 //  return face.m_si;
07564 //}
07565 
07566 //ON_Surface* ON_Brep::SurfaceOf( const ON_BrepTrim& trim ) const
07567 //{
07568 //  // OBSOLETE FUNCTION
07569 //  const int si = trim.SurfaceIndexOf();
07570 //  return (si>=0)?m_S[si]:0;
07571 //}
07572 
07573 //ON_Surface* ON_Brep::SurfaceOf( const ON_BrepLoop& loop ) const
07574 //{
07575 //  // OBSOLETE FUNCTION
07576 //  return const_cast<ON_Surface*>(loop.SurfaceOf());
07577 //}
07578 
07579 //ON_Surface* ON_Brep::SurfaceOf( const ON_BrepFace& face ) const
07580 //{
07581 //  // OBSOLETE FUNCTION
07582 //  return const_cast<ON_Surface*>(face.SurfaceOf());
07583 //}
07584 
07585 //int ON_Brep::EdgeCurveIndexOf( const ON_BrepTrim& trim ) const
07586 //{
07587 //  // OBSOLETE FUNCTION
07588 //  return trim.EdgeCurveIndexOf();
07589 //}
07590 
07591 //int ON_Brep::EdgeCurveIndexOf( const ON_BrepEdge& edge ) const
07592 //{
07593 //  // OBSOLETE FUNCTION
07594 //  return edge.m_c3i;
07595 //}
07596 
07597 //ON_Curve* ON_Brep::EdgeCurveOf( const ON_BrepTrim& trim ) const
07598 //{
07599 //  // OBSOLETE FUNCTION
07600 //  return const_cast<ON_Curve*>(trim.EdgeCurveOf());
07601 //}
07602 
07603 //ON_Curve* ON_Brep::EdgeCurveOf( const ON_BrepEdge& edge ) const
07604 //{
07605 //  return ((edge.m_c3i>=0&&edge.m_c3i<m_C3.Count())?m_C3[edge.m_c3i]:0);
07606 //}
07607 
07608 //int ON_Brep::TrimCurveIndexOf( const ON_BrepTrim& trim ) const
07609 //{
07610 //  return trim.m_c2i;
07611 //}
07612 
07613 //ON_Curve* ON_Brep::TrimCurveOf( const ON_BrepTrim& trim ) const
07614 //{
07615 //  return ((trim.m_c2i>=0&&trim.m_c2i<m_C2.Count())?m_C2[trim.m_c2i]:0);
07616 //}
07617 
07618 void ON_Brep::DeleteVertex(ON_BrepVertex& vertex)
07619 {
07620   const int vi = vertex.m_vertex_index;
07621   vertex.m_vertex_index = -1;
07622   if ( vi >= 0 && vi < m_V.Count() ) {
07623     int vei, ei;
07624     for ( vei = vertex.m_ei.Count()-1; vei>=0; vei-- ) {
07625       ei = vertex.m_ei[vei];
07626       if ( ei >= 0 && ei < m_E.Count() ) {
07627         ON_BrepEdge& edge = m_E[ei];
07628         if ( edge.m_vi[0] == vi )
07629           edge.m_vi[0] = -1;
07630         if ( edge.m_vi[1] == vi )
07631           edge.m_vi[1] = -1;
07632         DeleteEdge( edge, false );
07633       }
07634     }
07635   }
07636   vertex.m_ei.Empty();
07637   vertex.m_tolerance = ON_UNSET_VALUE;
07638 }
07639 
07640 int ON_Brep::Loop3dCurve( 
07641   const ON_BrepLoop& loop,
07642   ON_SimpleArray<ON_Curve*>& curve_list,
07643   ON_BOOL32 bRevCurveIfFaceRevIsTrue
07644   ) const
07645 {
07646   int curve_list_count0 = curve_list.Count();
07647   ON_PolyCurve* poly_curve = NULL;
07648   ON_Curve* loop_curve = NULL;
07649   ON_SimpleArray<int> trim_index( 2*loop.m_ti.Count() + 8);
07650   int i, lti, ti;
07651   int loop_trim_count = loop.m_ti.Count();
07652   if ( loop_trim_count < 1 )
07653     return 0;
07654 
07655 
07656   int seam_lti = -1; // index of first seam
07657   int wire_lti = -1;
07658   for ( lti = 0; lti < loop_trim_count; lti++ )
07659   {
07660     ti = loop.m_ti[lti];
07661     if ( ti >= 0 && ti < m_T.Count() )
07662     {
07663       const ON_BrepTrim& trim = m_T[ti];
07664       if ( seam_lti < 0 && trim.m_type == ON_BrepTrim::seam )
07665         seam_lti = lti;
07666       else if ( wire_lti < 0 && trim.m_type != ON_BrepTrim::singular )
07667         wire_lti = lti;
07668     }
07669   }
07670 
07671   if ( wire_lti < 0 )
07672     return 0; // sphere boundary, torus boundary, etc.
07673 
07674   if ( seam_lti < 0 )
07675   {
07676     // simple case;
07677     loop_curve = Loop3dCurve(loop,bRevCurveIfFaceRevIsTrue);
07678     if ( loop_curve )
07679       curve_list.Append(loop_curve);
07680     return curve_list.Count() - curve_list_count0;
07681   }
07682 
07683   bool bOnSeam = true;
07684   for ( lti = seam_lti; lti < seam_lti+loop_trim_count; lti++ )
07685   {
07686     ti = loop.m_ti[lti%loop_trim_count];
07687 
07688     if ( ti < 0 || ti >= m_T.Count() )
07689       ti = loop.m_ti[seam_lti]; // treat bogus indices as trims
07690 
07691     const ON_BrepTrim& trim = m_T[ti];
07692     if ( trim.m_type == ON_BrepTrim::seam )
07693     {
07694       if (!bOnSeam)
07695       {
07696         trim_index.Append(-1);
07697         bOnSeam = true;
07698       }
07699       continue;
07700     }
07701     // 10-1-03 Lowell - fixed typo
07702     if ( trim.m_type == ON_BrepTrim::singular )
07703       continue;
07704     bOnSeam = false;
07705     trim_index.Append(ti);
07706   }
07707 
07708   for ( i = 0; i < trim_index.Count(); i++ )
07709   {
07710     ti = trim_index[i];
07711     if ( ti < 0 )
07712     {
07713       if ( loop_curve )
07714         curve_list.Append(loop_curve);
07715       loop_curve = 0;
07716       poly_curve = 0;
07717       continue;
07718     }
07719 
07720     // get 3d curve associated with this trim's edge
07721     const ON_BrepTrim& trim = m_T[ti];
07722     const ON_BrepEdge& edge = m_E[trim.m_ei];
07723     ON_Curve* segment_curve = edge.DuplicateCurve();
07724     if ( !segment_curve )
07725       continue;
07726     if ( trim.m_bRev3d )
07727       segment_curve->Reverse();
07728 
07729     if ( !loop_curve )
07730       loop_curve = segment_curve;
07731     else if ( !poly_curve )
07732     {
07733       poly_curve = new ON_PolyCurve();
07734       poly_curve->Append(loop_curve);
07735       poly_curve->Append(segment_curve);
07736       loop_curve = poly_curve;
07737     }
07738     else
07739       poly_curve->Append( segment_curve );
07740   }
07741 
07742   // 10-1-03 Lowell - add the last non-seam segment
07743   if ( loop_curve )
07744     curve_list.Append(loop_curve);
07745 
07746   if ( bRevCurveIfFaceRevIsTrue )
07747   {
07748     int fi = loop.m_fi;
07749     if ( fi >= 0 && fi < m_F.Count() && m_F[fi].m_bRev )
07750     {
07751       for ( i = curve_list_count0; i < curve_list.Count(); i++ )
07752         curve_list[i]->Reverse();
07753     }
07754   }
07755 
07756   return curve_list.Count() - curve_list_count0;
07757 }
07758 
07759 
07760 ON_Curve* ON_Brep::Loop3dCurve( const ON_BrepLoop& loop, ON_BOOL32 bRevCurveIfFaceRevIsTrue ) const
07761 {
07762   ON_PolyCurve* poly_curve = NULL;
07763   ON_Curve* loop_curve = NULL;
07764   ON_SimpleArray<int> trim_index( loop.m_ti.Count() );
07765   int i, lti, ti;
07766   for ( lti = 0; lti < loop.m_ti.Count(); lti++ )
07767   {
07768     ti = loop.m_ti[lti];
07769     if ( ti >= 0 && ti < m_T.Count() )
07770     {
07771       const ON_BrepTrim& trim = m_T[ti];
07772       if ( trim.EdgeCurveOf() )
07773         trim_index.Append(ti);
07774     }
07775   }
07776 
07777   for ( i = 0; i < trim_index.Count(); i++ )
07778   {
07779     // get 3d curve associated with this trim's edge
07780     const ON_BrepTrim& trim = m_T[trim_index[i]];
07781     const ON_BrepEdge& edge = m_E[trim.m_ei];
07782     ON_Curve* segment_curve = edge.DuplicateCurve();
07783     if ( !segment_curve )
07784       continue;
07785     if ( trim.m_bRev3d )
07786       segment_curve->Reverse();
07787 
07788     if ( !loop_curve )
07789       loop_curve = segment_curve;
07790     else if ( !poly_curve )
07791     {
07792       poly_curve = new ON_PolyCurve();
07793       poly_curve->Append(loop_curve);
07794       poly_curve->Append(segment_curve);
07795       loop_curve = poly_curve;
07796     }
07797     else
07798       poly_curve->Append( segment_curve );
07799   }
07800   if ( loop_curve && bRevCurveIfFaceRevIsTrue )
07801   {
07802     int fi = loop.m_fi;
07803     if ( fi >= 0 && fi < m_F.Count() && m_F[fi].m_bRev )
07804     {
07805       loop_curve->Reverse();
07806     }
07807   }
07808   return loop_curve;
07809 }
07810 
07811 ON_Curve* ON_Brep::Loop2dCurve( const ON_BrepLoop& loop ) const
07812 {
07813   ON_PolyCurve* poly_curve = NULL;
07814   ON_Curve* loop_curve = NULL;
07815   ON_SimpleArray<int> trim_index( loop.m_ti.Count() );
07816   int i, lti, ti;
07817   for ( lti = 0; lti < loop.m_ti.Count(); lti++ )
07818   {
07819     ti = loop.m_ti[lti];
07820     if ( ti >= 0 && ti < m_T.Count() )
07821     {
07822       const ON_BrepTrim& trim = m_T[ti];
07823       if ( trim.TrimCurveOf() )
07824         trim_index.Append(ti);
07825     }
07826   }
07827   for ( i = 0; i < trim_index.Count(); i++ )
07828   {
07829     // get 2d curve associated with this trim's edge
07830     const ON_BrepTrim& trim = m_T[trim_index[i]];
07831     ON_Curve* segment_curve = trim.DuplicateCurve();
07832     if ( !segment_curve )
07833       continue;
07834 
07835     if ( !loop_curve )
07836       loop_curve = segment_curve;
07837     else if ( !poly_curve )
07838     {
07839       poly_curve = new ON_PolyCurve();
07840       poly_curve->Append(loop_curve);
07841       poly_curve->Append(segment_curve);
07842       loop_curve = poly_curve;
07843     }
07844     else
07845       poly_curve->Append( segment_curve );
07846   }
07847   return loop_curve;
07848 }
07849 
07850 
07851 
07852 void ON_Brep::DeleteEdge(ON_BrepEdge& edge, ON_BOOL32 bDeleteEdgeVertices )
07853 {
07854   const int ei = edge.m_edge_index;
07855   edge.m_edge_index = -1;
07856 
07857   if ( ei >= 0 && ei < m_E.Count() ) {
07858     int eti, ti, evi, vei, vi;
07859     for ( eti = edge.m_ti.Count()-1; eti >= 0; eti-- ) {
07860       ti = edge.m_ti[eti];
07861       if ( ti >= 0 && ti < m_T.Count() ) {
07862         ON_BrepTrim& trim = m_T[ti];
07863         trim.m_ei = -1;
07864         if ( trim.m_li >= 0 && trim.m_li < m_L.Count() ) {
07865           ON_BrepLoop& loop = m_L[trim.m_li];
07866           if ( loop.m_fi >= 0 && loop.m_fi < m_F.Count() ) {
07867             DeleteFace( m_F[loop.m_fi], bDeleteEdgeVertices );
07868           }
07869         }
07870         DeleteTrim(trim,false);
07871       }
07872     }
07873 
07874     for (evi = 0; evi < 2; evi++ ) 
07875     {
07876       vi = edge.m_vi[evi];
07877       if ( vi >= 0 && vi < m_V.Count() ) 
07878       {
07879         ON_BrepVertex& v = m_V[vi];
07880         for ( vei = v.m_ei.Count()-1; vei >= 0; vei-- ) 
07881         {
07882           if ( v.m_ei[vei] == ei )
07883             v.m_ei.Remove(vei);
07884         }
07885         if ( bDeleteEdgeVertices && v.m_ei.Count() <= 0 )
07886         {
07887           v.m_ei.Destroy();
07888           DeleteVertex(v);
07889         }
07890       }
07891     }
07892   }
07893 
07894   edge.m_c3i = -1;
07895   edge.m_vi[0] = -1;
07896   edge.m_vi[1] = -1;
07897   edge.m_ti.Empty();
07898   edge.m_tolerance = ON_UNSET_VALUE;
07899   edge.m_brep = 0;
07900   edge.SetProxyCurve(0);
07901 }
07902 
07903 void ON_Brep::DeleteTrim(ON_BrepTrim& trim, ON_BOOL32 bDeleteTrimEdges )
07904 {
07905   m_is_solid = 0;
07906 
07907   const int ti = trim.m_trim_index;
07908   trim.m_trim_index = -1;
07909 
07910   if ( ti >= 0 && ti < m_T.Count() ) 
07911   {
07912     const int ei = trim.m_ei;
07913     if ( ei >= 0 && ei < m_E.Count() ) 
07914     {
07915       ON_BrepEdge& edge = m_E[ei];
07916       if ( bDeleteTrimEdges && edge.m_ti.Count() == 1 && edge.m_ti[0] == ti ) 
07917       {
07918         edge.m_ti.Empty();
07919         DeleteEdge(edge,bDeleteTrimEdges);
07920       }
07921       else 
07922       {
07923         int mate_ti = (trim.m_type == ON_BrepTrim::mated) ? -1 : -2; // set to >= 0 if a single mate exists
07924         int seam_ti = (trim.m_type == ON_BrepTrim::seam) ? -1 : -2; // set to >= 0 if a single seam partner exists
07925         int eti;
07926         for ( eti = edge.m_ti.Count()-1; eti >= 0; eti-- ) 
07927         {
07928           int other_ti = edge.m_ti[eti];
07929           if ( other_ti == ti ) 
07930           {
07931             edge.m_ti.Remove(eti);
07932             if ( edge.m_ti.Count() == 0 )
07933               edge.m_tolerance = 0.0;
07934             continue;
07935           }
07936           
07937           if ( (mate_ti >= -1 || seam_ti >= -1 ) && other_ti >= 0 && other_ti < m_T.Count() )
07938           {
07939             const ON_BrepTrim& other_trim = m_T[other_ti];
07940             if ( other_trim.m_trim_index != other_ti )
07941               continue;
07942             if ( mate_ti >= -1 && other_trim.m_type == ON_BrepTrim::mated )
07943             {
07944               // see if other_trim is the only mate of trim
07945               if ( mate_ti == -1 )
07946                 mate_ti = other_ti;
07947               else
07948                 mate_ti = -2;
07949             }
07950             else if ( seam_ti >= -1 && other_trim.m_type == ON_BrepTrim::seam && other_trim.m_li == trim.m_li )
07951             {
07952               // trim and other_trim are both seam trims in the same loop connected
07953               // to the same edge.
07954               if ( seam_ti == -1 )
07955                 seam_ti = other_ti;
07956               else
07957                 seam_ti = -2;
07958             }
07959           }
07960         }
07961 
07962         if ( seam_ti >= 0  )
07963         {
07964           // m_T[seam_ti] used to be a seam partner with trim.
07965           // Now it is either a boundary trim or is mated to m_T[mate_ti]
07966           m_T[seam_ti].m_type = (mate_ti>=0) 
07967                               ? ON_BrepTrim::mated     // m_T[mate_ti] is mated to m_T[seam_ti]
07968                               : ON_BrepTrim::boundary; // m_T[seam_ti] is all alone
07969         }
07970         else if ( mate_ti >= 0 )
07971         {
07972           // m_T[mate_ti] just lost its only mate and is now a boundary
07973           m_T[mate_ti].m_type = ON_BrepTrim::boundary;
07974         }
07975       }
07976     }
07977 
07978     const int li = trim.m_li;
07979     if ( li >= 0 && li < m_L.Count() ) {
07980       ON_BrepLoop& loop = m_L[li];
07981       int lti;
07982       for ( lti = loop.m_ti.Count()-1; lti >= 0; lti-- ) {
07983         if ( loop.m_ti[lti] == ti )
07984           loop.m_ti.Remove(lti);
07985       }
07986     }
07987   }
07988 
07989   trim.m_c2i = -1;
07990   trim.m_ei = -1;
07991   trim.m_vi[0] = -1;
07992   trim.m_vi[1] = -1;
07993   trim.m_bRev3d = 0;
07994   trim.m_type = ON_BrepTrim::unknown;
07995   trim.m_iso = ON_Surface::not_iso;
07996   trim.m_li = -1;
07997   trim.m_tolerance[0] = ON_UNSET_VALUE;
07998   trim.m_tolerance[1] = ON_UNSET_VALUE;
07999   trim.m__legacy_2d_tol = ON_UNSET_VALUE;
08000   trim.m__legacy_3d_tol = ON_UNSET_VALUE;
08001   trim.m__legacy_flags = 0;
08002   trim.m_pbox.Destroy();
08003   trim.m_brep = 0;
08004   trim.SetProxyCurve(0);
08005 }
08006 
08007 void ON_Brep::DeleteLoop(ON_BrepLoop& loop,  ON_BOOL32 bDeleteLoopEdges  )
08008 {
08009   m_is_solid = 0;
08010 
08011   const int li = loop.m_loop_index;
08012   loop.m_loop_index = -1;
08013 
08014   if ( loop.m_fi >= 0 )
08015     DestroyMesh(ON::any_mesh,true);
08016 
08017   if ( li >= 0 && li < m_L.Count() ) 
08018   {
08019     const int tcount = m_T.Count();
08020     int lti, ti;
08021     for ( lti = loop.m_ti.Count()-1; lti >= 0; lti-- )
08022     {
08023       ti = loop.m_ti[lti];
08024       if ( ti >= 0 && ti < tcount )
08025       {
08026         ON_BrepTrim& trim = m_T[ti];
08027         trim.m_li = -1;
08028         DeleteTrim(trim,bDeleteLoopEdges);
08029       }
08030     }
08031 
08032     const int fi = loop.m_fi;
08033     if ( fi >= 0 && fi < m_F.Count() ) 
08034     {
08035       ON_BrepFace& face = m_F[fi];
08036       int fli;
08037       for ( fli = face.m_li.Count()-1; fli >= 0; fli-- )
08038       {
08039         if ( face.m_li[fli] == li ) 
08040         {
08041           face.m_li.Remove(fli);
08042         }
08043       }
08044     }
08045   }
08046 
08047   loop.m_type = ON_BrepLoop::unknown;
08048   loop.m_ti.Empty();
08049   loop.m_fi = -1;
08050   loop.m_pbox.Destroy();
08051   loop.m_brep = 0;
08052 }
08053 
08054 void ON_Brep::DeleteFace(ON_BrepFace& face, ON_BOOL32 bDeleteFaceEdges )
08055 {
08056   m_bbox.Destroy();
08057   m_is_solid = 0;
08058 
08059   const int fi = face.m_face_index;
08060   face.m_face_index = -1;
08061 
08062   if ( fi >= 0 && fi < m_F.Count() ) {
08063     const int lcount = m_L.Count();
08064     int fli, li;
08065     for ( fli = face.m_li.Count()-1; fli >= 0; fli-- ) {
08066       li = face.m_li[fli];
08067       if ( li >= 0 && li < lcount ) {
08068         ON_BrepLoop& loop = m_L[li];
08069         loop.m_fi = -1;
08070         DeleteLoop(loop,bDeleteFaceEdges);
08071       }
08072     }
08073   }
08074 
08075   face.m_si = -1;
08076   face.m_li.Empty();
08077   face.SetProxySurface(0);
08078   face.m_brep = 0;
08079   face.m_bbox.Destroy();
08080 }
08081 
08082 static void PropagateLabel(ON_Brep& B, 
08083                            ON_SimpleArray<int>& fids,
08084                            int label
08085                            )
08086 //on input, each face in fids must have m_face_user.i = label
08087 {
08088   if (fids.Count() == 0) return;
08089   ON_SimpleArray<int> new_fids(B.m_F.Count());
08090   for (int face_i=0; face_i<fids.Count(); face_i++)
08091   {
08092     const ON_BrepFace& F = B.m_F[fids[face_i]];
08093     for (int loop_i=0; loop_i<F.m_li.Count(); loop_i++)
08094     {
08095       ON_BrepLoop& L = B.m_L[F.m_li[loop_i]];
08096       memset(&L.m_loop_user,0,sizeof(L.m_loop_user));
08097       L.m_loop_user.i = label;
08098       for (int edge_i=0; edge_i<L.m_ti.Count(); edge_i++)
08099       {
08100         ON_BrepTrim& T = B.m_T[L.m_ti[edge_i]];
08101         memset(&T.m_trim_user,0,sizeof(T.m_trim_user));
08102         T.m_trim_user.i = label;
08103         if (T.m_ei < 0) 
08104           continue;
08105         ON_BrepEdge& E = B.m_E[T.m_ei];
08106         memset(&E.m_edge_user,0,sizeof(E.m_edge_user));
08107         E.m_edge_user.i = label;
08108         for (int vertex_i=0; vertex_i<2; vertex_i++)
08109         {
08110           if (E.m_vi[vertex_i] >= 0) 
08111           {
08112             ON_BrepVertex& V = B.m_V[E.m_vi[vertex_i]];
08113             memset(&V.m_vertex_user,0,sizeof(V.m_vertex_user));
08114             V.m_vertex_user.i = label;
08115           }
08116         }
08117 
08118         for (int trim_i=0; trim_i<E.m_ti.Count(); trim_i++)
08119         {
08120           int fi = B.m_T[E.m_ti[trim_i]].FaceIndexOf();
08121           if (fi < 0 || B.m_F[fi].m_face_user.i == label) 
08122             continue;
08123           ON_BrepFace& F = B.m_F[fi];
08124           memset(&F.m_face_user,0,sizeof(F.m_face_user));
08125           F.m_face_user.i = label;
08126           new_fids.Append(fi);
08127         }
08128       }
08129     }
08130   }
08131   PropagateLabel(B, new_fids, label);
08132   return;
08133 }
08134 
08135 
08136 void ON_Brep::LabelConnectedComponent(int face_index, int label)
08137 
08138 {
08139   if (face_index < 0 || face_index >= m_F.Count())
08140     return;
08141 
08142   ON_SimpleArray<int> fids(1);
08143   fids.Append(face_index);
08144   ON_BrepFace& F = m_F[face_index];
08145   memset(&F.m_face_user,0,sizeof(F.m_face_user));
08146   F.m_face_user.i = label;
08147   PropagateLabel(*this, fids, label);
08148   return;
08149 }
08150 
08151 int ON_Brep::LabelConnectedComponents()
08152 
08153 {
08154   Clear_user_i();
08155   int i;
08156   for (i=0; i<m_F.Count(); i++){
08157     if (m_F[i].m_face_index < 0)
08158       m_F[i].m_face_user.i = -1;
08159   }
08160 
08161   int label = 0;
08162   bool keep_going = true;
08163   while (keep_going)
08164   {
08165     int face_index = -1;
08166     for (int j=0; j<m_F.Count(); j++)
08167     {
08168       if (m_F[j].m_face_user.i == 0)
08169       {
08170         face_index = j;
08171         break;
08172       }
08173     }
08174     if (face_index == -1)
08175     {
08176       keep_going = false;
08177       continue;
08178     }
08179     label++;
08180     LabelConnectedComponent(face_index, label);
08181   }
08182   return label;
08183 }
08184 
08185 int ON_Brep::GetConnectedComponents( ON_SimpleArray< ON_Brep* >& components, bool bDuplicateMeshes ) const
08186 {
08187   const int count0 = components.Count();
08188   ON_Brep brep(*this);
08189   int count = brep.LabelConnectedComponents();
08190   if ( count > 1 )
08191   {
08192     int cci;
08193     ON_SimpleArray<int> fi(brep.m_F.Count());
08194     for ( cci = 1; cci <= count; cci++ )
08195     {
08196       fi.SetCount(0);
08197       for ( int j = 0; j < brep.m_F.Count(); j++ )
08198       {
08199         if ( brep.m_F[j].m_face_user.i == cci )
08200           fi.Append(j);
08201       }
08202       if ( fi.Count() > 0 )
08203       {
08204         ON_Brep* cc = brep.DuplicateFaces( fi.Count(), fi.Array(), bDuplicateMeshes );
08205         if ( cc )
08206           components.Append(cc);
08207       }
08208     }
08209   }
08210 
08211   return components.Count() - count0;
08212 }
08213 
08214 ON_Brep* ON_Brep::DuplicateFace( int face_index, ON_BOOL32 bDuplicateMeshes ) const
08215 {
08216   return DuplicateFaces( 1, &face_index, bDuplicateMeshes );
08217 }
08218 
08219 ON_Brep* ON_Brep::DuplicateFaces( int face_count, const int* face_index, ON_BOOL32 bDuplicateMeshes ) const
08220 {
08221   int fi, si, fli, lti, li, ti, i;
08222   ON_BOOL32 rc = false;
08223   ON_Brep* brep_copy = 0;
08224   ON_Object* dup = 0;
08225 
08226   // mark vertices, edges, faces, surfaces, and curves to duplicate
08227   ON_SimpleArray<int> s_remap(m_S.Count());
08228   s_remap.SetCount(m_S.Count());
08229   s_remap.Zero();
08230   ON_SimpleArray<int> f_remap(m_F.Count());
08231   f_remap.SetCount(m_F.Count());
08232   f_remap.Zero();
08233   ON_SimpleArray<int> c2_remap(m_C2.Count());
08234   c2_remap.SetCount(m_C2.Count());
08235   c2_remap.Zero();
08236   ON_SimpleArray<int> c3_remap(m_C3.Count());
08237   c3_remap.SetCount(m_C3.Count());
08238   c3_remap.Zero();
08239   ON_SimpleArray<int> e_remap(m_E.Count());
08240   e_remap.SetCount(m_E.Count());
08241   e_remap.Zero();
08242   ON_SimpleArray<int> v_remap(m_V.Count());
08243   v_remap.SetCount(m_V.Count());
08244   v_remap.Zero();
08245   for (i = 0; i < face_count; i++ ) {
08246     fi = face_index[i];
08247     if (fi >= 0 && fi < m_F.Count() ) {
08248       const ON_BrepFace& face = m_F[fi];
08249       rc = true;
08250       f_remap[fi] = 1;
08251       si = face.m_si;
08252       if ( si >= 0 && si < m_S.Count() ) {
08253         s_remap[si] = 1;
08254       }
08255       for ( fli = 0; fli < face.m_li.Count(); fli++ ) 
08256       {
08257         li = face.m_li[fli];
08258         if ( li < 0 || li >= m_L.Count() )
08259           continue;
08260         const ON_BrepLoop& loop = m_L[li];
08261         for ( lti = 0; lti < loop.m_ti.Count(); lti++ ) 
08262         {
08263           ti = loop.m_ti[lti];
08264           if ( ti < 0 || ti >= m_T.Count() )
08265             continue;
08266           const ON_BrepTrim& trim = m_T[ti];
08267           if ( trim.m_ei >= 0 && trim.m_ei < m_E.Count() ) 
08268           {
08269             int vi;
08270             e_remap[trim.m_ei] = 1;
08271             vi = m_E[trim.m_ei].m_vi[0];
08272             if ( vi >= 0 )
08273               v_remap[vi] = 1;
08274             vi = m_E[trim.m_ei].m_vi[1];
08275             if ( vi >= 0 )
08276               v_remap[vi] = 1;
08277           }
08278           if ( trim.m_vi[0] >= 0 )
08279             v_remap[trim.m_vi[0]] = 1;
08280           if ( trim.m_vi[1] >= 0 )
08281             v_remap[trim.m_vi[1]] = 1;
08282           int ci = trim.EdgeCurveIndexOf();
08283           if ( ci >= 0 ) {
08284             c3_remap[ci] = 1;
08285           }
08286           ci = trim.TrimCurveIndexOf();
08287           if ( ci >= 0 )
08288             c2_remap[ci] = 1;
08289         }
08290       }
08291     }
08292   }
08293   if ( !rc )
08294     return NULL;
08295 
08296   brep_copy = new ON_Brep();
08297 
08298   // duplicate surfaces
08299   for ( i = 0; i < m_S.Count() && rc; i++ )
08300   {
08301     if ( s_remap[i] ) {
08302       if ( !m_S[i] )
08303         break;
08304       dup = m_S[i]->Duplicate();
08305       ON_Surface* srf_copy = ON_Surface::Cast(dup);
08306       if ( !srf_copy )
08307         break;
08308       s_remap[i] = brep_copy->AddSurface(srf_copy);
08309       dup = 0;
08310     }
08311     else
08312       s_remap[i] = -1;
08313   }
08314   rc = ( rc && i == m_S.Count() );
08315 
08316   // duplicate 2d curves
08317   for ( i = 0; i < m_C2.Count() && rc; i++ )
08318   {
08319     if ( c2_remap[i] ) {
08320       if ( !m_C2[i] )
08321         break;
08322       dup = m_C2[i]->Duplicate();
08323       ON_Curve* crv_copy = ON_Curve::Cast(dup);
08324       if ( !crv_copy )
08325         break;
08326       c2_remap[i] = brep_copy->AddTrimCurve(crv_copy);
08327       dup = 0;
08328     }
08329     else
08330       c2_remap[i] = -1;
08331   }
08332   rc = ( rc && i == m_C2.Count() );
08333 
08334   // duplicate 3d curves
08335   for ( i = 0; i < m_C3.Count() && rc; i++ )
08336   {
08337     if ( c3_remap[i] ) {
08338       if ( !m_C3[i] )
08339         break;
08340       dup = m_C3[i]->Duplicate();
08341       ON_Curve* crv_copy = ON_Curve::Cast(dup);
08342       if ( !crv_copy )
08343         break;
08344       c3_remap[i] = brep_copy->AddEdgeCurve(crv_copy);
08345       dup = 0;
08346     }
08347     else
08348       c3_remap[i] = -1;
08349   }
08350   rc = ( rc && i == m_C3.Count() );
08351 
08352   // duplicate vertices
08353   for (i = 0; i < m_V.Count() && rc; i++ ) 
08354   {
08355     if (v_remap[i]) 
08356     {
08357       ON_BrepVertex& vertex_copy = brep_copy->NewVertex(m_V[i].point);
08358       memset(&vertex_copy.m_vertex_user,0,sizeof(vertex_copy.m_vertex_user));
08359       vertex_copy.m_vertex_user.i = i;
08360       v_remap[i] = vertex_copy.m_vertex_index;
08361     }
08362     else
08363       v_remap[i] = -1;
08364   }
08365   rc = ( rc && i == m_V.Count() );
08366 
08367   // duplicate edges
08368   for (i = 0; i < m_E.Count() && rc; i++ ) 
08369   {
08370     if (e_remap[i]) 
08371     {
08372       const ON_BrepEdge& edge = m_E[i];
08373       //int vi0 = edge.m_vi[0];
08374       if ( edge.m_vi[0] < 0 || edge.m_vi[1] < 0 || edge.m_c3i < 0 )
08375         break;
08376       if ( v_remap[edge.m_vi[0]] < 0 || v_remap[edge.m_vi[1]] < 0 || c3_remap[edge.m_c3i] < 0)
08377         break;
08378       ON_BrepEdge& edge_copy = brep_copy->NewEdge( brep_copy->m_V[v_remap[edge.m_vi[0]]], 
08379                                                    brep_copy->m_V[v_remap[edge.m_vi[1]]], 
08380                                                    c3_remap[edge.m_c3i]
08381                                                    );
08382       edge_copy.SetProxyCurveDomain( edge.ProxyCurveDomain());
08383       if ( edge.ProxyCurveIsReversed() )
08384         edge_copy.ON_CurveProxy::Reverse();
08385       edge_copy.SetDomain(edge.Domain());
08386 
08387       memset(&edge_copy.m_edge_user,0,sizeof(edge_copy.m_edge_user));
08388       edge_copy.m_edge_user.i = i;
08389       edge_copy.m_tolerance = edge.m_tolerance;
08390       e_remap[i] = edge_copy.m_edge_index;
08391     }
08392     else
08393       e_remap[i] = -1;
08394   }
08395   rc = ( rc && i == m_E.Count() );
08396 
08397   //03/11/2010 Tim
08398   //More checking to prevent crashes
08399   //from bogus array indices
08400   bool bFoundBadIdx = false;
08401 
08402   // duplicate faces
08403   for ( fi = 0; rc && fi < m_F.Count() && rc && !bFoundBadIdx; fi++ )
08404   {
08405     if ( f_remap[fi] == 0 )
08406       continue;
08407     rc = false;
08408     const ON_BrepFace& face = m_F[fi];
08409 
08410     // duplicate face
08411     si = (face.m_si>=0) ? s_remap[face.m_si] : -1;
08412     if ( si < 0 )
08413       break;
08414 
08415     ON_BrepFace& face_copy = brep_copy->NewFace(si);
08416     memset(&face_copy.m_face_user,0,sizeof(face_copy.m_face_user));
08417     face_copy.m_face_user.i = fi;
08418     face_copy.m_bRev = face.m_bRev;
08419     face_copy.m_bbox = face.m_bbox;
08420     face_copy.m_domain[0] = face.m_domain[0];
08421     face_copy.m_domain[1] = face.m_domain[1];
08422     //face_copy.m_material_index = face.m_material_index;
08423     // do NOT duplicate meshes here
08424 
08425     // duplicate loops and trims
08426     for ( fli = 0; fli < face.m_li.Count() && !bFoundBadIdx; fli++ )
08427     {
08428       li = face.m_li[fli];
08429       if (0 > li || m_L.Count() <= li)
08430       {
08431         bFoundBadIdx = true;
08432         break;
08433       }
08434 
08435       const ON_BrepLoop& loop = m_L[li];
08436       ON_BrepLoop& loop_copy = brep_copy->NewLoop( loop.m_type, face_copy );
08437       memset(&loop_copy.m_loop_user,0,sizeof(loop_copy.m_loop_user));
08438       loop_copy.m_loop_user.i = li;
08439       for ( lti = 0; lti < loop.m_ti.Count() && !bFoundBadIdx; lti++ )
08440       {
08441         ti = loop.m_ti[lti];
08442         if (0 > ti || m_T.Count() <= ti)
08443         {
08444           bFoundBadIdx = true;
08445           break;
08446         }
08447         const ON_BrepTrim& trim = m_T[ti];
08448         i = (trim.m_c2i>=0) ? c2_remap[trim.m_c2i] : -1;
08449         if ( trim.m_ei >= 0 ) {
08450           i = brep_copy->NewTrim( brep_copy->m_E[e_remap[trim.m_ei]], trim.m_bRev3d, loop_copy, i ).m_trim_index;
08451         }
08452         else {
08453           i = brep_copy->NewTrim( trim.m_bRev3d, loop_copy, i ).m_trim_index;
08454           int vi0 = (trim.m_vi[0]>=0) ? v_remap[trim.m_vi[0]] : -1;
08455           int vi1 = (trim.m_vi[1]>=0) ? v_remap[trim.m_vi[1]] : -1;
08456           brep_copy->m_T[i].m_vi[0] = vi0;
08457           brep_copy->m_T[i].m_vi[1] = vi1;
08458         }
08459         ON_BrepTrim& trim_copy = brep_copy->m_T[i];
08460         
08461         //trim_copy.m_t = trim.m_t;
08462         trim_copy.SetProxyCurveDomain( trim.ProxyCurveDomain());
08463         if ( trim.ProxyCurveIsReversed() )
08464           trim_copy.ON_CurveProxy::Reverse();
08465         trim_copy.SetDomain(trim.Domain());
08466 
08467         memset(&trim_copy.m_trim_user,0,sizeof(trim_copy.m_trim_user));
08468         trim_copy.m_trim_user.i = ti;
08469         trim_copy.m_iso = trim.m_iso;
08470         trim_copy.m_tolerance[0] = trim.m_tolerance[0];
08471         trim_copy.m_tolerance[1] = trim.m_tolerance[1];
08472         trim_copy.m_pline = trim.m_pline;
08473         trim_copy.m_pbox = trim.m_pbox;
08474         trim_copy.m__legacy_2d_tol = trim.m__legacy_2d_tol;
08475         trim_copy.m__legacy_3d_tol = trim.m__legacy_3d_tol;
08476         trim_copy.m__legacy_flags = trim.m__legacy_flags;
08477       }
08478 
08479       if (bFoundBadIdx)
08480         break;
08481       
08482       loop_copy.m_pbox = loop.m_pbox;
08483     }
08484 
08485     if (bFoundBadIdx)
08486       break;
08487 
08488     if ( bDuplicateMeshes ) 
08489     {
08490       if ( face.m_render_mesh )
08491         face_copy.m_render_mesh = face.m_render_mesh->Duplicate();
08492       if ( face.m_analysis_mesh )
08493         face_copy.m_analysis_mesh = face.m_analysis_mesh->Duplicate();
08494       if ( face.m_preview_mesh )
08495         face_copy.m_preview_mesh = face.m_preview_mesh->Duplicate();
08496     }
08497 
08498     rc = true;
08499   }
08500   rc = ( rc && fi == m_F.Count() );
08501   
08502   if ( !rc ) {
08503     if ( dup ) {
08504       delete dup;
08505       dup = 0;
08506     }
08507     if ( brep_copy ) {
08508       delete brep_copy;
08509       brep_copy = 0;
08510     }
08511   }
08512   else 
08513   {
08514     // set flags, tolerances, etc. that have changed
08515     brep_copy->SetTrimTypeFlags();
08516     brep_copy->SetVertexTolerances();
08517   }
08518   return brep_copy;
08519 }
08520 
08521 ON_Brep* ON_Brep::ExtractFace( int face_index )
08522 {
08523   ON_Brep* brep_copy = DuplicateFace(face_index,false);
08524   if ( brep_copy ) {
08525     ON_BrepFace& face = m_F[face_index];
08526     ON_BrepFace& face_copy = brep_copy->m_F[0];
08527     face_copy.m_render_mesh = face.m_render_mesh; face.m_render_mesh = 0;
08528     face_copy.m_analysis_mesh = face.m_analysis_mesh; face.m_analysis_mesh = 0;
08529     face_copy.m_preview_mesh = face.m_preview_mesh; face.m_preview_mesh = 0;
08530     DeleteFace( face, true );
08531   }
08532   return brep_copy;
08533 }
08534 
08535 void ON_Brep::DeleteSurface(int si)
08536 {
08537   if ( si >= 0 && si < m_S.Count() ) {
08538     delete m_S[si];
08539     m_S[si] = 0;
08540   }
08541 }
08542 
08543 void ON_Brep::Delete2dCurve(int c2i)
08544 {
08545   if ( c2i >= 0 && c2i < m_C2.Count() ) {
08546     delete m_C2[c2i];
08547     m_C2[c2i] = 0;
08548   }
08549 }
08550 
08551 void ON_Brep::Delete3dCurve(int c3i)
08552 {
08553   if ( c3i >= 0 && c3i < m_C3.Count() ) {
08554     delete m_C3[c3i];
08555     m_C3[c3i] = 0;
08556   }
08557 }
08558 
08559 
08560 bool ON_Brep::CullUnusedFaces()
08561 {
08562   bool rc = true;
08563   int fcount = m_F.Count();
08564   if (fcount > 0 ) {
08565     ON_Workspace ws;
08566     int *fmap = ws.GetIntMemory(fcount+1);
08567     *fmap++ = -1;
08568     memset( fmap, 0, fcount*sizeof(*fmap) );
08569     const int lcount = m_L.Count();
08570     int fi, li, mi = 0;
08571 
08572     // if face.m_face_index is -1, cull face
08573     for ( fi = 0; fi < fcount; fi++ ) {
08574       ON_BrepFace& face = m_F[fi];
08575       if ( face.m_face_index == -1)
08576         fmap[fi] = -1;
08577       else if ( face.m_face_index == fi )
08578         fmap[fi] = face.m_face_index = mi++;
08579       else {
08580         ON_ERROR("Brep face has illegal m_face_index.");
08581         rc = false;
08582         fmap[fi] = face.m_face_index;
08583       }
08584     }
08585 
08586     if ( mi == 0 ) {
08587       m_F.Destroy();
08588     }
08589     else if ( mi < fcount ) {
08590       // set new face indices
08591       mi = 0;
08592       for ( fi = fcount-1; fi >= 0; fi-- ) {
08593         if ( m_F[fi].m_face_index  == -1 )
08594           m_F.Remove(fi);
08595         else
08596           m_F[fi].m_face_index = fmap[fi];
08597       }
08598 
08599       // remap loop.m_fi indices
08600       for ( li = 0; li < lcount; li++ ) {
08601         ON_BrepLoop& loop = m_L[li];
08602         fi = loop.m_fi;
08603         if ( fi < -1 || fi >= fcount ) {
08604           ON_ERROR("Brep loop has illegal m_fi.");
08605           rc = false;
08606         }
08607         else 
08608           loop.m_fi = fmap[fi];
08609       }
08610 
08611     }
08612   }
08613   m_F.Shrink();
08614   return rc;
08615 }
08616 
08617 bool ON_Brep::CullUnusedSurfaces()
08618 {
08619   // remove unused surfaces
08620   bool rc = true;
08621   const int fcount = m_F.Count();
08622   int scount = m_S.Count();
08623   int si, fi, mi;
08624 
08625   if ( scount > 0 ) {
08626     ON_Workspace ws;
08627     int* smap = ws.GetIntMemory(scount+1);
08628     *smap++ = -1;
08629     memset(smap,0,scount*sizeof(*smap));
08630     mi = 0;
08631     for ( fi = 0; fi < fcount; fi++ ) {
08632       ON_BrepFace& face = m_F[fi];
08633       if ( face.m_face_index == -1 ) {
08634         face.m_si = -1;
08635         continue;
08636       }
08637       si = face.m_si;
08638       if ( si == -1 )
08639         continue;
08640       if ( si < 0 || si >= scount ) {
08641         ON_ERROR("Brep face has illegal m_si.");
08642         rc = false;
08643       }
08644       else {
08645         if ( !smap[si] )
08646           mi++;
08647         smap[si]++;
08648       }
08649     }
08650 
08651     if ( mi == 0 ) {
08652       m_S.Destroy();
08653     }
08654     else if ( mi < scount ) {
08655       mi = 0;
08656       for ( si = 0; si < scount; si++ ) {
08657         if ( smap[si] )
08658           smap[si] = mi++;
08659         else {
08660           delete m_S[si];
08661           m_S[si] = 0;
08662           smap[si] = -1;
08663         }
08664       }
08665 
08666       for ( fi = 0; fi < fcount; fi++ ) {
08667         ON_BrepFace& face = m_F[fi];
08668         si = face.m_si;
08669         if ( si >= 0 && si < scount )
08670           face.m_si = smap[si];
08671       }
08672 
08673       for ( si = scount-1; si >= 0; si-- ) {
08674         if ( smap[si] < 0 ) {
08675           m_S.Remove(si);
08676           scount--;
08677         }
08678       }
08679     }
08680   }
08681   m_S.Shrink();
08682   return rc;
08683 }
08684 
08685 bool ON_Brep::CullUnused3dCurves()
08686 {
08687   // remove unused surfaces
08688   bool rc = true;
08689   const int ecount = m_E.Count();
08690   int c3count = m_C3.Count();
08691   int c3i, ei, mi;
08692 
08693   if ( c3count > 0 ) {
08694     ON_Workspace ws;
08695     int* c3map = ws.GetIntMemory(c3count+1);
08696     *c3map++ = -1;
08697     memset(c3map,0,c3count*sizeof(*c3map));
08698     mi = 0;
08699     for ( ei = 0; ei < ecount; ei++ ) {
08700       ON_BrepEdge& edge = m_E[ei];
08701       if ( edge.m_edge_index == -1 ) {
08702         edge.m_c3i = -1;
08703         continue;
08704       }
08705       c3i = edge.m_c3i;
08706       if ( c3i == -1 )
08707         continue;
08708       if ( c3i < -1 || c3i >= c3count ) {
08709         ON_ERROR("Brep edge has illegal m_c3i.");
08710         rc = false;
08711       }
08712       else {
08713         if ( !c3map[c3i] )
08714           mi++;
08715         c3map[c3i]++;
08716       }
08717     }
08718 
08719     if ( mi == 0 ) {
08720       m_C3.Destroy();
08721     }
08722     else if ( mi < c3count ) {
08723       mi = 0;
08724       for ( c3i = 0; c3i < c3count; c3i++ ) {
08725         if ( c3map[c3i] )
08726           c3map[c3i] = mi++;
08727         else {
08728           delete m_C3[c3i];
08729           m_C3[c3i] = 0;
08730           c3map[c3i] = -1;
08731         }
08732       }
08733 
08734       for ( ei = 0; ei < ecount; ei++ ) {
08735         ON_BrepEdge& edge = m_E[ei];
08736         c3i = edge.m_c3i;
08737         if ( c3i >= 0 && c3i < c3count )
08738           edge.m_c3i = c3map[c3i];
08739       }
08740 
08741       for ( c3i = c3count-1; c3i >= 0; c3i-- ) {
08742         if ( c3map[c3i] < 0 ) {
08743           m_C3.Remove(c3i);
08744           c3count--;
08745         }
08746       }
08747     }
08748   }
08749   m_C3.Shrink();
08750   return rc;
08751 }
08752 
08753 
08754 bool ON_Brep::CullUnused2dCurves()
08755 {
08756   // remove unused surfaces
08757   bool rc = true;
08758   const int tcount = m_T.Count();
08759   int c2count = m_C2.Count();
08760   int c2i, ti, mi;
08761 
08762   if ( c2count > 0 ) 
08763   {
08764     ON_Workspace ws;
08765     int* c2map = ws.GetIntMemory(c2count+1);
08766     *c2map++ = -1;
08767     memset(c2map,0,c2count*sizeof(*c2map));
08768     mi = 0;
08769     for ( ti = 0; ti < tcount; ti++ ) {
08770       ON_BrepTrim& trim = m_T[ti];
08771       if ( trim.m_trim_index == -1 ) {
08772         trim.m_c2i = -1;
08773         continue;
08774       }
08775       c2i = trim.m_c2i;
08776       if ( c2i == -1 )
08777         continue;
08778       if ( c2i < -1 || c2i >= c2count ) {
08779         ON_ERROR("Brep trim has illegal m_c2i.");
08780         rc = false;
08781       }
08782       else {
08783         if ( !c2map[c2i] )
08784           mi++;
08785         c2map[c2i]++;
08786       }
08787     }
08788 
08789     if ( mi == 0 ) {
08790       m_C2.Destroy();
08791     }
08792     else if ( mi < c2count ) {
08793       mi = 0;
08794       for ( c2i = 0; c2i < c2count; c2i++ ) {
08795         if ( c2map[c2i] )
08796           c2map[c2i] = mi++;
08797         else {
08798           delete m_C2[c2i];
08799           m_C2[c2i] = 0;
08800           c2map[c2i] = -1;
08801         }
08802       }
08803 
08804       for ( ti = 0; ti < tcount; ti++ ) {
08805         ON_BrepTrim& trim = m_T[ti];
08806         c2i = trim.m_c2i;
08807         if ( c2i >= 0 && c2i < c2count )
08808           trim.m_c2i = c2map[c2i];
08809       }
08810 
08811       for ( c2i = c2count-1; c2i >= 0; c2i-- ) {
08812         if ( c2map[c2i] < 0 ) {
08813           m_C2.Remove(c2i);
08814           c2count--;
08815         }
08816       }
08817     }
08818   }
08819   m_C2.Shrink();
08820   return rc;
08821 }
08822 
08823 
08824 bool ON_Brep::CullUnusedLoops()
08825 {
08826   bool rc = true;
08827   const int lcount = m_L.Count();
08828   if ( lcount > 0 ) {
08829     ON_Workspace ws;
08830     int* lmap = ws.GetIntMemory(lcount+1);
08831     *lmap++ = -1;
08832     memset( lmap, 0, lcount*sizeof(*lmap) );
08833     const int fcount = m_F.Count();
08834     const int tcount = m_T.Count();
08835     int li, fli, flcnt, fi, ti, mi;
08836 
08837     mi = 0;
08838     for ( li = 0; li < lcount; li++ ) {
08839       ON_BrepLoop& loop = m_L[li];
08840       if ( loop.m_loop_index == -1)
08841         lmap[li] = -1;
08842       else if ( loop.m_loop_index == li )
08843         lmap[li] = loop.m_loop_index = mi++;
08844       else {
08845         ON_ERROR("Brep loop has illegal m_loop_index.");
08846         rc = false;
08847         lmap[li] = loop.m_loop_index;
08848       }
08849     }
08850 
08851     if ( mi == 0 ) {
08852       m_L.Destroy();
08853     }
08854     else if ( mi < lcount ) {
08855 
08856       // remap loops
08857       for ( li = lcount-1; li >= 0; li-- ) {
08858         if ( m_L[li].m_loop_index == -1 )
08859           m_L.Remove(li);
08860         else
08861           m_L[li].m_loop_index = lmap[li];
08862       }
08863 
08864       // remap ON_BrepFace.m_li[] indices
08865       for ( fi = 0; fi < fcount; fi++ ) {
08866         ON_BrepFace& face = m_F[fi];
08867         flcnt = face.m_li.Count();
08868         for ( fli = flcnt-1; fli >= 0; fli-- ) {
08869           li = face.m_li[fli];
08870           if ( li < -1 || li >= lcount ) {
08871             ON_ERROR("Brep face m_li[] has illegal loop index.");
08872             rc = false;
08873           }
08874           else {
08875             li = lmap[li];
08876             if (li >= 0 ) {
08877               face.m_li[fli] = li;
08878             }
08879             else {
08880               face.m_li.Remove(fli);
08881             }
08882           }
08883         }
08884       }
08885 
08886       // remap ON_BrepTrim.m_li indices
08887       for ( ti = 0; ti < tcount; ti++ ) {
08888         ON_BrepTrim& trim = m_T[ti];
08889         li = trim.m_li;
08890         if ( li < -1 || li >= lcount ) {
08891           ON_ERROR("Brep trim has illegal m_li.");
08892           rc = false;
08893         }
08894         else {
08895           trim.m_li = lmap[li];
08896         }
08897       }
08898     }
08899   }
08900   m_L.Shrink();
08901   return rc;
08902 }
08903 
08904 bool ON_Brep::CullUnusedTrims()
08905 {
08906   bool rc = true;
08907   const int tcount = m_T.Count();
08908   if ( tcount > 0 ) {
08909     ON_Workspace ws;
08910     int *tmap = ws.GetIntMemory(tcount+1);
08911     *tmap++ = -1;
08912     memset( tmap, 0, tcount*sizeof(*tmap));
08913     const int lcount = m_L.Count();
08914     const int ecount = m_E.Count();
08915     int ti, li, ei, mi, ltcnt, lti, etcnt, eti;
08916 
08917     mi = 0;
08918     for ( ti = 0; ti < tcount; ti++ ) {
08919       ON_BrepTrim& trim = m_T[ti];
08920       if ( trim.m_trim_index == -1)
08921         tmap[ti] = -1;
08922       else if ( trim.m_trim_index == ti )
08923         tmap[ti] = trim.m_trim_index = mi++;
08924       else {
08925         ON_ERROR("Brep trim has illegal m_trim_index.");
08926         rc = false;
08927         tmap[ti] = trim.m_trim_index;
08928       }
08929     }
08930 
08931     if ( mi == 0 ) {
08932       m_T.Destroy();
08933     }
08934     else if ( mi < tcount ) {
08935       // remap trim indices
08936       for ( ti = tcount-1; ti >= 0; ti-- ) {
08937         if ( m_T[ti].m_trim_index == -1 ) {
08938           m_T.Remove(ti);
08939         }
08940         else {
08941           m_T[ti].m_trim_index = tmap[ti];
08942         }
08943       }
08944 
08945       // remap loop.m_ti[] indicies
08946       for ( li = 0; li < lcount; li++ ) {
08947         ON_BrepLoop& loop = m_L[li];
08948         ltcnt = loop.m_ti.Count();
08949         for ( lti = ltcnt-1; lti >= 0; lti-- ) {
08950           ti = loop.m_ti[lti];
08951           if ( ti < -1 || ti >= tcount ) {
08952             ON_ERROR("Brep loop.m_ti[] has illegal index.");
08953             rc = false;
08954           }
08955           else {
08956             ti = tmap[ti];
08957             if (ti >= 0 ) {
08958               loop.m_ti[lti] = ti;
08959             }
08960             else {
08961               loop.m_ti.Remove(lti);
08962             }
08963           }
08964         }
08965       }
08966 
08967       // remap edge.m_ti[] indicies
08968       for ( ei = 0; ei < ecount; ei++ ) {
08969         ON_BrepEdge& edge = m_E[ei];
08970         etcnt = edge.m_ti.Count();
08971         for ( eti = etcnt-1; eti >= 0; eti-- ) {
08972           ti = edge.m_ti[eti];
08973           if ( ti < -1 || ti >= tcount ) {
08974             ON_ERROR("Brep edge.m_ti[] has illegal index.");
08975             rc = false;
08976           }
08977           else {
08978             ti = tmap[ti];
08979             if (ti >= 0 ) {
08980               edge.m_ti[eti] = ti;
08981             }
08982             else {
08983               edge.m_ti.Remove(eti);
08984             }
08985           }
08986         }
08987       }
08988     }
08989   }
08990   m_T.Shrink();
08991   return rc;
08992 }
08993 
08994 bool ON_Brep::CullUnusedEdges()
08995 {
08996   bool rc = true;
08997   const int ecount = m_E.Count();
08998   if ( ecount > 0 ) {
08999     ON_Workspace ws;
09000     int* emap = ws.GetIntMemory(ecount+1);
09001     *emap++ = -1;
09002     memset( emap, 0, ecount*sizeof(*emap) );
09003     const int vcount = m_V.Count();
09004     const int tcount = m_T.Count();
09005     int ei, ti, vi, mi, vecnt, vei;
09006 
09007     mi = 0;
09008     for ( ei = 0; ei < ecount; ei++ ) {
09009       ON_BrepEdge& edge = m_E[ei];
09010       if ( edge.m_edge_index == -1)
09011         emap[ei] = -1;
09012       else if ( edge.m_edge_index == ei )
09013         emap[ei] = edge.m_edge_index = mi++;
09014       else {
09015         ON_ERROR("Brep edge has illegal m_edge_index.");
09016         rc = false;
09017         emap[ei] = edge.m_edge_index;
09018       }
09019     }
09020 
09021     if ( mi == 0 ) {
09022       m_E.Destroy();
09023     }
09024     else if ( mi < ecount ) 
09025     {
09026       // remap edge indices
09027       for ( ei = ecount-1; ei >= 0; ei-- ) {
09028         if ( m_E[ei].m_edge_index == -1 ) {
09029           m_E.Remove(ei);
09030         }
09031         else {
09032           m_E[ei].m_edge_index = emap[ei];
09033         }
09034       }
09035 
09036       // remap trim.m_ei
09037       for ( ti = 0; ti < tcount; ti++ ) {
09038         ON_BrepTrim& trim = m_T[ti];
09039         ei = trim.m_ei;
09040         if ( ei < -1 || ei >= ecount ) {
09041           ON_ERROR("Brep trim.m_ei has illegal index.");
09042           rc = false;
09043         }
09044         else {
09045           trim.m_ei = emap[ei];
09046         }
09047       }
09048 
09049       // remap vertex.m_ei[]
09050       for ( vi = 0; vi < vcount; vi++ ) {
09051         ON_BrepVertex& vertex = m_V[vi];
09052         vecnt = vertex.m_ei.Count();
09053         for ( vei = vecnt-1; vei >= 0; vei-- ) {
09054           ei = vertex.m_ei[vei];
09055           if ( ei < -1 || ei >= ecount ) {
09056             ON_ERROR("Brep vertex.m_ei[] has illegal index.");
09057             rc = false;
09058           }
09059           else {
09060             ei = emap[ei];
09061             if (ei >= 0 ) {
09062               vertex.m_ei[vei] = ei;
09063             }
09064             else {
09065               vertex.m_ei.Remove(vei);
09066             }
09067           }
09068         }
09069       }
09070     }
09071   }
09072   m_E.Shrink();
09073   return rc;
09074 }
09075 
09076 
09077 bool ON_Brep::CullUnusedVertices()
09078 {
09079   bool rc = true;
09080   const int vcount = m_V.Count();
09081   if ( vcount > 0 ) 
09082   {
09083     ON_Workspace ws;
09084     int* vmap = ws.GetIntMemory(vcount+1);
09085     *vmap++ = -1;
09086     memset(vmap,0,vcount*sizeof(*vmap));
09087     const int tcount = m_T.Count();
09088     const int ecount = m_E.Count();
09089     int vi, ei, ti, mi, j;
09090 
09091     if ( tcount > 0 )
09092     {
09093       // 11 Nov 2009 Dale Lear
09094       //  I added this code to fix bugs 55879 and 56191.
09095       for ( ti = 0; ti < tcount; ti++ )
09096       {
09097         const ON_BrepTrim& trim = m_T[ti];
09098         if ( -1 == trim.m_trim_index )
09099           continue;
09100         vi = trim.m_vi[0];
09101         if ( vi >= 0 && vi < vcount && -1 == m_V[vi].m_vertex_index )
09102         {
09103           // undelete this vertex
09104           // This error happens when the ON_Brep is invalid to begin with.
09105           // However, in order to prevent crashes, we have to refuse to delete
09106           // the vertex.  See bugs 55879 and 56191.
09107           ON_ERROR("ON_Brep::CullUnusedVertices() - deleted vertex referenced by trim.m_vi[0]");
09108           m_V[vi].m_vertex_index = vi;
09109         }
09110         vi = trim.m_vi[1];
09111         if ( vi >= 0 && vi < vcount && -1 == m_V[vi].m_vertex_index )
09112         {
09113           // undelete this vertex
09114           // This error happens when the ON_Brep is invalid to begin with.
09115           // However, in order to prevent crashes, we have to refuse to delete
09116           // the vertex.  See bugs 55879 and 56191.
09117           ON_ERROR("ON_Brep::CullUnusedVertices() - deleted vertex referenced by trim.m_vi[1]");
09118           m_V[vi].m_vertex_index = vi;
09119         }
09120       }
09121     }
09122 
09123     mi = 0;
09124     for ( vi = 0; vi < vcount; vi++ ) {
09125       ON_BrepVertex& vertex = m_V[vi];
09126       if ( vertex.m_vertex_index == -1)
09127         vmap[vi] = -1;
09128       else if ( vertex.m_vertex_index == vi )
09129         vmap[vi] = vertex.m_vertex_index = mi++;
09130       else {
09131         ON_ERROR("Brep vertex has illegal m_vertex_index.");
09132         rc = false;
09133         vmap[vi] = vertex.m_vertex_index;
09134       }
09135     }
09136 
09137     if ( mi == 0 ) 
09138     {
09139       m_V.Destroy();
09140     }
09141     else if ( mi < vcount ) 
09142     {
09143       // remap vertex indices
09144       for ( vi = vcount-1; vi >= 0; vi-- ) 
09145       {
09146         if ( m_V[vi].m_vertex_index == -1 )
09147         {
09148           m_V.Remove(vi);
09149         }
09150         else {
09151           m_V[vi].m_vertex_index = vmap[vi];
09152         }
09153       }
09154 
09155       // remap edge indices
09156       for ( ei = 0; ei < ecount; ei++ ) 
09157       {
09158         ON_BrepEdge& edge = m_E[ei];
09159         for ( j = 0; j < 2; j++ ) 
09160         {
09161           vi = edge.m_vi[j];
09162           if ( vi < -1 || vi >= vcount ) 
09163           {
09164             ON_ERROR("Brep edge.m_vi[] has illegal index.");
09165             rc = false;
09166           }
09167           else {
09168             edge.m_vi[j] = vmap[vi];
09169           }
09170         }
09171       }
09172 
09173       // remap trim indices
09174       for ( ti = 0; ti < tcount; ti++ )
09175       {
09176         ON_BrepTrim& trim = m_T[ti];
09177         for ( j = 0; j < 2; j++ ) 
09178         {
09179           vi = trim.m_vi[j];
09180           if ( vi < -1 || vi >= vcount ) 
09181           {
09182             ON_ERROR("Brep trim.m_vi[] has illegal index.");
09183             rc = false;
09184           }
09185           else {
09186             trim.m_vi[j] = vmap[vi];
09187           }
09188         }
09189       }
09190 
09191     }
09192   }
09193   m_V.Shrink();
09194   return rc;
09195 }
09196 
09197 bool ON_Brep::Compact()
09198 {
09199   // Removes any unreferenced objects from arrays,
09200   // reindexes as needed, and shrinks arrays to
09201   // minimum required size.
09202 
09203   bool rc = true;
09204   if (!CullUnusedFaces())
09205     rc = false;
09206   if (!CullUnusedEdges())
09207     rc = false;
09208   if (!CullUnusedVertices())
09209     rc = false;
09210   if (!CullUnusedLoops())
09211     rc = false;
09212   if (!CullUnusedTrims())
09213     rc = false;
09214 
09215   if (!CullUnusedSurfaces())
09216     rc = false;
09217   if (!CullUnused3dCurves())
09218     rc = false;
09219   if (!CullUnused2dCurves())
09220     rc = false;
09221 
09222   // If 1-1 relationships exist between geometry and topology,
09223   // the synchronize the geometry and topology indices.  This
09224   // helps confused users of breps not have to understand the
09225   // differences between geometry and topology data.
09226   ON_SimpleArray<bool> used;
09227   bool bSyncUp;
09228 
09229   if ( m_C2.Count() == m_T.Count() )
09230   {
09231     int i, count = m_C2.Count();
09232     used.Reserve(count);
09233     used.SetCount(count);
09234     used.Zero();
09235     bSyncUp = true;
09236     for ( i = 0; i < count && bSyncUp; i++ )
09237     {
09238       const ON_BrepTrim& trim = m_T[i];
09239       if ( trim.m_trim_index != i || trim.m_c2i < 0 || trim.m_c2i >= count )
09240         bSyncUp = false;
09241       else
09242       {
09243         if (used[trim.m_c2i])
09244           bSyncUp = false;
09245         else
09246           used[trim.m_c2i] = true;
09247       }
09248     }
09249     if ( bSyncUp )
09250     {
09251       ON_SimpleArray< ON_Curve* > ptr(count);
09252       for( i = 0; i < count; i++ )
09253       {
09254         ON_BrepTrim& trim = m_T[i];
09255         ptr[i] = m_C2[trim.m_c2i];
09256         trim.m_c2i = i;
09257       }
09258       for( i = 0; i < count; i++ )
09259       {
09260         m_C2[i] = ptr[i];
09261       }
09262     }
09263   }
09264 
09265   if ( m_C3.Count() == m_E.Count() )
09266   {
09267     int i, count = m_C3.Count();
09268     used.Reserve(count);
09269     used.SetCount(count);
09270     used.Zero();
09271     bSyncUp = true;
09272     for ( i = 0; i < count && bSyncUp; i++ )
09273     {
09274       const ON_BrepEdge& edge = m_E[i];
09275       if ( edge.m_edge_index != i || edge.m_c3i < 0 || edge.m_c3i >= count )
09276         bSyncUp = false;
09277       else
09278       {
09279         if (used[edge.m_c3i])
09280           bSyncUp = false;
09281         else
09282           used[edge.m_c3i] = true;
09283       }
09284     }
09285     if ( bSyncUp )
09286     {
09287       ON_SimpleArray< ON_Curve* > ptr(count);
09288       for( i = 0; i < count; i++ )
09289       {
09290         ON_BrepEdge& edge = m_E[i];
09291         ptr[i] = m_C3[edge.m_c3i];
09292         edge.m_c3i = i;
09293       }
09294       for( i = 0; i < count; i++ )
09295       {
09296         m_C3[i] = ptr[i];
09297       }
09298     }
09299   }
09300 
09301   if ( m_S.Count() == m_F.Count() )
09302   {
09303     int i, count = m_S.Count();
09304     used.Reserve(count);
09305     used.SetCount(count);
09306     used.Zero();
09307     bSyncUp = true;
09308     for ( i = 0; i < count && bSyncUp; i++ )
09309     {
09310       const ON_BrepFace& face = m_F[i];
09311       if ( face.m_face_index != i || face.m_si < 0 || face.m_si >= count )
09312         bSyncUp = false;
09313       else
09314       {
09315         if (used[face.m_si])
09316           bSyncUp = false;
09317         else
09318           used[face.m_si] = true;
09319       }
09320     }
09321     if ( bSyncUp )
09322     {
09323       ON_SimpleArray< ON_Surface* > ptr(count);
09324       for( i = 0; i < count; i++ )
09325       {
09326         ON_BrepFace& face = m_F[i];
09327         ptr[i] = m_S[face.m_si];
09328         face.m_si = i;
09329       }
09330       for( i = 0; i < count; i++ )
09331       {
09332         m_S[i] = ptr[i];
09333       }
09334     }
09335   }
09336 
09337   return rc;
09338 }
09339 
09340 
09341 ON_Brep& ON_Brep::operator=(const ON_Brep& src)
09342 {
09343   if ( this != &src ) 
09344   {
09345     Destroy();
09346     ON_Geometry::operator=(src);
09347 
09348     m_V.SetCapacity(src.m_V.Count());
09349     m_E.SetCapacity(src.m_E.Count());
09350     m_F.SetCapacity(src.m_F.Count());
09351     m_T.SetCapacity(src.m_T.Count());
09352     m_L.SetCapacity(src.m_L.Count());
09353 
09354     m_V.SetCount(src.m_V.Count());
09355     m_E.SetCount(src.m_E.Count());
09356     m_F.SetCount(src.m_F.Count());
09357     m_T.SetCount(src.m_T.Count());
09358     m_L.SetCount(src.m_L.Count());
09359 
09360     src.m_C2.Duplicate( m_C2 );
09361     src.m_C3.Duplicate( m_C3 );
09362     src.m_S.Duplicate( m_S );
09363 
09364     int i, count = m_V.Count();
09365     for ( i = 0; i < count; i++ ) 
09366     {
09367       m_V[i] = src.m_V[i];
09368     }
09369 
09370     count = m_E.Count();
09371     for ( i = 0; i < count; i++ ) 
09372     {
09373       m_E[i] = src.m_E[i];
09374       ON_BrepEdge& e = m_E[i];
09375       e.m_brep = this;
09376 
09377       // update curve proxy info to point at 3d curve in this brep
09378       e.SetProxyCurve( ( e.m_c3i >= 0 ) ? m_C3[e.m_c3i] : 0, 
09379                        src.m_E[i].ProxyCurveDomain()
09380                        );
09381       if ( src.m_E[i].ProxyCurveIsReversed() )
09382         e.ON_CurveProxy::Reverse();
09383       e.SetDomain( src.m_E[i].Domain() );
09384     }
09385 
09386     count = m_L.Count();
09387     for ( i = 0; i < count; i++ ) 
09388     {
09389       m_L[i].m_brep = this;
09390     }
09391 
09392     count = m_F.Count();
09393     for ( i = 0; i < count; i++ ) 
09394     {
09395       m_F[i] = src.m_F[i];
09396       ON_BrepFace& f = m_F[i];
09397       f.m_brep = this;
09398       // update surface proxy info to point at 3d surface in this brep
09399       f.SetProxySurface(( f.m_si >= 0 ) ? m_S[f.m_si] : 0);
09400       f.m_bbox = src.m_F[i].m_bbox; // because SetProxySurface destroys it
09401     }
09402 
09403     count = m_T.Count();
09404     for ( i = 0; i < count; i++ ) 
09405     {
09406       m_T[i] = src.m_T[i];
09407       ON_BrepTrim& trim = m_T[i];
09408       trim.m_brep = this;
09409 
09410       // update curve proxy info to point at 2d curve in this brep
09411       trim.SetProxyCurve( ( trim.m_c2i >= 0 ) ? m_C2[trim.m_c2i] : 0, 
09412                           src.m_T[i].ProxyCurveDomain()
09413                          );
09414       if ( src.m_T[i].ProxyCurveIsReversed() )
09415         trim.ON_CurveProxy::Reverse();
09416       trim.SetDomain( src.m_T[i].Domain() );
09417     }
09418 
09419     count = m_L.Count();
09420     for ( i = 0; i < count; i++ ) 
09421     {
09422       m_L[i] = src.m_L[i];
09423     }
09424 
09425     m_bbox = src.m_bbox;
09426     m_is_solid = src.m_is_solid;
09427   }
09428   return *this;
09429 }
09430 
09431 void ON_Brep::Destroy()
09432 {
09433   m_V.Empty();
09434   m_E.Empty();
09435   m_F.Empty();
09436   m_T.Empty();
09437   m_L.Empty();
09438 
09439   int i, count = m_C2.Count();
09440   for ( i = 0; i < count; i++ ) {
09441     delete m_C2[i];
09442     m_C2[i] = 0;
09443   }
09444   m_C2.Empty();
09445   m_C2.Zero();
09446 
09447   count = m_C3.Count();
09448   for ( i = 0; i < count; i++ ) {
09449     delete m_C3[i];
09450     m_C3[i] = 0;
09451   }
09452   m_C3.Empty();
09453   m_C3.Zero();
09454 
09455   count = m_S.Count();
09456   for ( i = 0; i < count; i++ ) {
09457     delete m_S[i];
09458     m_S[i] = 0;
09459   }
09460   m_S.Empty();
09461   m_S.Zero();
09462 
09463   m_bbox.Destroy();
09464   m_is_solid = 0;
09465   // returns Brep to state it has after default construction
09466 }
09467 
09468 void ON_Brep::EmergencyDestroy()
09469 { 
09470   // call if memory pool used by b-rep members becomes invalid
09471   // but ON_Brep class memory is in a valid pool
09472   m_V.EmergencyDestroy();
09473   m_E.EmergencyDestroy();
09474   m_F.EmergencyDestroy();
09475   m_T.EmergencyDestroy();
09476   m_L.EmergencyDestroy();
09477   m_C2.EmergencyDestroy();
09478   m_C3.EmergencyDestroy();
09479   m_S.EmergencyDestroy();
09480   m_bbox.Destroy();
09481   m_is_solid = 0;
09482 }
09483 
09484 bool ON_Brep::CombineCoincidentVertices(ON_BrepVertex& vertex0, ON_BrepVertex& vertex1)
09485 {
09486 
09487   bool rc = false;
09488   if (&vertex0 == &vertex1) {
09489     ON_ERROR("ON_Brep::CombineCoincidentVertices - vertex0 = vertex1.");
09490     return rc;
09491   }
09492   // moves information to vertex0 and deletes vertex1
09493   int runaway, vei, vecnt, ei, eti, etcnt, ti, prev_ti, next_ti;
09494 
09495   if ( vertex0.m_vertex_index >= 0 && vertex1.m_vertex_index != vertex0.m_vertex_index ) {
09496     rc = true;
09497     // update edges and trim references from vertex0 to vertex1
09498     vecnt = vertex1.m_ei.Count();
09499     for ( vei = 0; vei < vecnt; vei++ ) {
09500       ei = vertex1.m_ei[vei];
09501       if ( ei >= 0 ) {
09502         // update edge vertex indices
09503         ON_BrepEdge& edge = m_E[ei];
09504         if ( edge.m_vi[0] == vertex1.m_vertex_index )
09505           edge.m_vi[0] = vertex0.m_vertex_index;
09506         if ( edge.m_vi[1] == vertex1.m_vertex_index )
09507           edge.m_vi[1] = vertex0.m_vertex_index;
09508 
09509         // update trim vertex indices
09510         etcnt = edge.m_ti.Count();
09511         for (eti = 0; eti < etcnt; eti++ ) {
09512           ti = edge.m_ti[eti];
09513           if (ti >= 0 ) {
09514             ON_BrepTrim& trim = m_T[ti];
09515             if ( trim.m_vi[0] == vertex1.m_vertex_index ) {
09516               trim.m_vi[0] = vertex0.m_vertex_index;
09517               // check for previous singular trims using vertex0
09518               for (prev_ti = PrevTrim(ti), runaway=0;prev_ti >= 0 && prev_ti != ti && runaway < 1024;prev_ti=PrevTrim(prev_ti),runaway++) {
09519                 ON_BrepTrim& prevtrim = m_T[prev_ti];
09520                 if ( prevtrim.m_ei >= 0 )
09521                   break;
09522                 if ( prevtrim.m_vi[0] == vertex1.m_vertex_index )
09523                   prevtrim.m_vi[0] = vertex0.m_vertex_index;
09524                 if ( prevtrim.m_vi[1] == vertex1.m_vertex_index )
09525                   prevtrim.m_vi[1] = vertex0.m_vertex_index;
09526               }
09527             }
09528             if ( trim.m_vi[1] == vertex1.m_vertex_index ) {
09529               trim.m_vi[1] = vertex0.m_vertex_index;
09530                // check for previous singular trims using vertex0
09531               for (next_ti = NextTrim(ti), runaway=0;next_ti >= 0 && next_ti != ti && runaway < 1024;next_ti=NextTrim(next_ti),runaway++) {
09532                 ON_BrepTrim& nexttrim = m_T[next_ti];
09533                 if ( nexttrim.m_ei >= 0 )
09534                   break;
09535                 if ( nexttrim.m_vi[0] == vertex1.m_vertex_index )
09536                   nexttrim.m_vi[0] = vertex0.m_vertex_index;
09537                 if ( nexttrim.m_vi[1] == vertex1.m_vertex_index )
09538                   nexttrim.m_vi[1] = vertex0.m_vertex_index;
09539               }
09540             }
09541           }
09542         }
09543         vertex0.m_ei.Append(ei);
09544       }
09545     }
09546   }
09547 
09548   // update vertex tolerances
09549   if ( vertex0.m_tolerance != ON_UNSET_VALUE) 
09550     SetVertexTolerance(vertex0);
09551 
09552   vertex1.m_vertex_index = -1;
09553   vertex1.m_ei.Destroy();
09554   DeleteVertex(vertex1);
09555 
09556   return rc;
09557 }
09558 
09559 
09560 ON_BrepEdge* ON_Brep::CombineContiguousEdges( 
09561   int ei0, 
09562   int ei1, 
09563   double angle_tolerance_radians
09564   )
09565 {
09566   // Bug fixers:
09567   //
09568   // Lots of (fast)testing is done to ensure the brep is
09569   // 100% valid at the merge vertex.  Do not change the
09570   // return 0 bail outs unless you are 100% sure of what
09571   // you are doing.
09572 
09573   // get edges to be merged
09574   const ON_BrepEdge* edge0 = Edge(ei0);
09575   const ON_BrepEdge* edge1 = Edge(ei1);
09576   if ( !edge0 || !edge1 )
09577     return 0;
09578 
09579   // clear any component index bits
09580   ei0 = edge0->m_edge_index;
09581   ei1 = edge1->m_edge_index;
09582   if ( ei0 < 0 || ei1 < 0 || ei0 == ei1 )
09583     return 0;
09584 
09585   // make sure edges have same number of trims
09586   if ( edge0->m_ti.Count() != edge1->m_ti.Count() )
09587     return 0;
09588 
09589   // figure out which edge ends to merge
09590         // GBA 1/6/03 Fixed TRR#8951.
09591         // Check that the vertex to be eliminated has exactly 2 incident edges.
09592   int end0 = 1, end1 = 0;
09593         bool MatchFound = false;                        
09594         for(end0=1; !MatchFound && end0>=0; /* empty */){
09595                 int vi = edge0->m_vi[end0];
09596                 const ON_BrepVertex* v =  Vertex(vi);
09597                 if(v && v->m_ei.Count()==2 ){
09598                         for(end1=0; !MatchFound && end1<2; /*empty*/){
09599                                 MatchFound = (vi == edge1->m_vi[end1]);
09600                                 if(!MatchFound)
09601                                         end1++; 
09602                         }       
09603                 }
09604                 if(!MatchFound)
09605                         end0--;
09606         }
09607         if(!MatchFound)
09608                 return 0;
09609 
09610   // vi_mid = index of vertex to be eliminated
09611   const int vi_mid = edge0->m_vi[end0];
09612   {
09613     const ON_BrepVertex* v = Vertex(vi_mid);
09614     if ( !v )
09615       return 0;
09616     if ( v->m_ei.Count() != 2 )
09617       return 0;
09618     if ( v->m_ei[0] != ei0 && v->m_ei[1] != ei0 )
09619       return 0;
09620     if ( v->m_ei[0] != ei1 && v->m_ei[1] != ei1 )
09621       return 0;
09622   }
09623 
09624   // evi0 = vertex index and other end of edge0
09625   const int evi0 = edge0->m_vi[1-end0];
09626 
09627   // evi = vertex index and other end of edge1
09628   const int evi1 = edge1->m_vi[1-end1];
09629   if ( evi0 == vi_mid )
09630     return 0;
09631   if ( evi1 == vi_mid )
09632     return 0;
09633 
09634   // new edge will start at vi0 and end at vi1
09635   const int vi0 = (end0==1) ? evi0 : evi1;
09636   const int vi1 = (end0==1) ? evi1 : evi0;
09637 
09638   // make sure the 3d kink angle at the merge point is <= angle_tolerance
09639   {
09640     ON_3dVector tan0 = edge0->TangentAt( edge0->Domain()[end0] );
09641     if ( end0 == 0 )
09642       tan0.Reverse();
09643     ON_3dVector tan1 = edge1->TangentAt( edge1->Domain()[end1] );
09644     if ( end1 == 1 )
09645       tan1.Reverse();
09646     double d = tan0*tan1;
09647     if ( d < cos(angle_tolerance_radians) )
09648       return 0;
09649   }
09650 
09651   // get corresponding pairs of trims to merge
09652   int trim_count = edge0->m_ti.Count();
09653   ON_SimpleArray<int> trim0_index(trim_count);
09654   ON_SimpleArray<int> trim1_index(trim_count);
09655   ON_SimpleArray<int> loop_lti0(trim_count);
09656   ON_SimpleArray<int> loop_lti1(trim_count);
09657 
09658   int eti;
09659   for ( eti = 0; eti < trim_count; eti++ )
09660   {
09661     const ON_BrepTrim* trim0 = Trim( edge0->m_ti[eti] );
09662     if ( !trim0 )
09663       return 0;
09664     int ti0 = trim0->m_trim_index;
09665     const ON_BrepLoop* loop = trim0->Loop();
09666     if ( !loop )
09667       return 0;
09668     if ( loop->m_ti.Count() < 2 )
09669       return 0;
09670 
09671     // get index of next/prev trim that corresponds to edge1
09672     bool bRev = (end0==0);
09673     if ( trim0->m_bRev3d )
09674       bRev = !bRev;
09675     int lti1 = -1;
09676     int lti0 = loop->m_ti.Search( &ti0, ON_CompareIncreasing<int> );
09677     if ( lti0 < 0 )
09678       return 0;
09679     if ( bRev )
09680       lti1 = lti0 - 1 + loop->m_ti.Count();
09681     else
09682       lti1 = lti0 +1;
09683     lti1 %= loop->m_ti.Count();
09684     const ON_BrepTrim* trim1 = loop->Trim(lti1);
09685     if ( !trim1 )
09686       return 0;
09687     if ( trim1->m_ei != ei1 )
09688       return 0;
09689     if ( trim0->m_trim_index == trim1->m_trim_index )
09690       return 0;
09691 
09692     // test for valid trim vertices and orientations
09693     int tend0 = trim0->m_bRev3d ? (1-end0) : end0;
09694     int tend1 = trim1->m_bRev3d ? (1-end1) : end1;
09695     if ( tend0 == tend1 )
09696       return 0;
09697     if ( trim0->m_vi[tend0] != vi_mid )
09698       return 0;
09699     if ( trim1->m_vi[tend1] != vi_mid )
09700       return 0;
09701     if ( trim0->m_vi[1-tend0] != evi0 )
09702       return 0;
09703     if ( trim1->m_vi[1-tend1] != evi1 )
09704       return 0;
09705     trim0_index.Append(trim0->m_trim_index);
09706     trim1_index.Append(trim1->m_trim_index);
09707     loop_lti0.Append(lti0);
09708     loop_lti1.Append(lti1);
09709   }
09710 
09711   // create new 3d edge curve geometry
09712   // new edge goes same direction as edge0
09713   ON_PolyCurve* ec = 0;
09714   {
09715     ON_Curve* ec0 = edge0->DuplicateCurve();
09716     if ( !ec0 )
09717       return 0;
09718     ON_Curve* ec1 = edge1->DuplicateCurve();
09719     if ( !ec1 )
09720     {
09721       delete ec0;
09722       return 0;
09723     }
09724     if ( end0 == end1 )
09725     {
09726       if ( !ec1->Reverse() )
09727       {
09728         delete ec0;
09729         delete ec1;
09730         return 0;
09731       }
09732     }
09733     ec = new ON_PolyCurve();
09734     if ( end0 == 1 )
09735     {
09736       ec->Append(ec0);
09737       ec->AppendAndMatch(ec1);
09738     }
09739     else
09740     {
09741       ec->Append(ec1);
09742       ec->AppendAndMatch(ec0);
09743     }
09744     ec->RemoveNesting();
09745   }
09746 
09747   // create new 2d trim curve geometry
09748   ON_SimpleArray<ON_Curve*> tc(trim_count);
09749   for ( eti = 0; eti < trim_count; eti++ )
09750   {
09751     const ON_BrepTrim* trim0 = Trim(trim0_index[eti]);
09752     if ( !trim0 )
09753       break;
09754     const ON_BrepTrim* trim1 = Trim(trim1_index[eti]);
09755     if ( !trim1 )
09756       break;
09757     ON_NurbsCurve* c0 = trim0->NurbsCurve();
09758     if ( !c0 )
09759       break;
09760     ON_NurbsCurve* c1 = trim1->NurbsCurve();
09761     if ( !c1 )
09762     {
09763       delete c0;
09764       break;
09765     }
09766     if ( trim0->m_vi[1] == vi_mid && trim1->m_vi[0] == vi_mid )
09767     {
09768       if ( !c0->Append(*c1) )
09769       {
09770         delete c0;
09771         delete c1;
09772         break;
09773       }
09774       delete c1;
09775       c1 = 0;
09776       tc.Append(c0);
09777     }
09778     else if ( trim0->m_vi[0] == vi_mid && trim1->m_vi[1] == vi_mid )
09779     {
09780       if ( !c1->Append(*c0) )
09781       {
09782         delete c0;
09783         delete c1;
09784         break;
09785       }
09786       delete c0;
09787       c0 = c1;
09788       c1 = 0;
09789       tc.Append(c0);
09790     }
09791   }
09792 
09793   if ( eti < trim_count )
09794   {
09795     delete ec;
09796     for ( eti = 0; eti < tc.Count(); eti++ )
09797       delete tc[eti];
09798     return 0;
09799   }
09800 
09801   // Add new edge from vi0 to vi1 that has the same orientation
09802   // as edge0.  Adding the new edge may change pointer values,
09803   // so the edge0 and edge1 pointers are reset.
09804   edge0 = 0;
09805   edge1 = 0;
09806   const int c3i = AddEdgeCurve(ec);
09807   ON_BrepEdge& edge = NewEdge( m_V[vi0], m_V[vi1], c3i );
09808   edge0 = Edge(ei0);
09809   edge1 = Edge(ei1);
09810 
09811         // Set edge tolerance
09812         if(edge0->m_tolerance<0 || edge1->m_tolerance<0)
09813                 edge.m_tolerance= ON_UNSET_VALUE;
09814         else if ( edge0->m_tolerance> edge1->m_tolerance)
09815                 edge.m_tolerance= edge0->m_tolerance;
09816         else    
09817                 edge.m_tolerance= edge1->m_tolerance;
09818                 
09819 
09820   // dynamic m_T[] is grown to full size here.
09821   // Trim refs are good after NewTrim()
09822   m_T.Reserve( m_T.Count() + trim_count );
09823   for ( eti = 0; eti < trim_count; eti++ )
09824   {
09825     int c2i = AddTrimCurve( tc[eti] );
09826     ON_BrepTrim& trim0 = m_T[trim0_index[eti]];
09827     ON_BrepTrim& trim1 = m_T[trim1_index[eti]];
09828     ON_BrepTrim& trim = NewTrim( edge, trim0.m_bRev3d, c2i );
09829                 // Set trim tolerance
09830                 for(int i=0; i<2; i++){
09831                         if( trim0.m_tolerance[i]<0 || trim1.m_tolerance[i]<0)
09832                                 trim.m_tolerance[i] = ON_UNSET_VALUE;
09833                         else if(trim0.m_tolerance[i]>trim1.m_tolerance[i])
09834                                 trim.m_tolerance[i] = trim0.m_tolerance[i];
09835                         else
09836                                 trim.m_tolerance[i] = trim1.m_tolerance[i];
09837                 }
09838     trim.m_li = trim0.m_li;
09839     ON_BrepLoop& loop = m_L[trim.m_li];
09840     loop.m_ti[loop_lti0[eti]] = trim.m_trim_index;
09841     loop.m_ti.Remove( loop_lti1[eti] );
09842 
09843                 //GBA 1/29/03 Fixes TRR#9233.  Removing an item from loop.m_ti
09844                 //will cause loop indicies stored in loop_lti0[] and loop_lti1[]
09845                 //to be wrong. So they must be reindexed
09846                 int ri = loop_lti1[eti];                        // removed index
09847     int li = loop.m_loop_index;
09848                 for(int ii=0; ii<trim_count; ii++){
09849       if(loop_lti0[ii]>ri && m_T[trim0_index[ii]].m_li == li) 
09850         loop_lti0[ii]--;
09851                         if(loop_lti1[ii]>ri && m_T[trim1_index[ii]].m_li == li) 
09852         loop_lti1[ii]--;
09853                 }
09854                 
09855                     
09856                 trim.m_type = trim0.m_type;
09857                 trim.m_iso = ON_Surface::not_iso;
09858                 if( trim0.m_iso==trim1.m_iso) 
09859                         trim.m_iso = trim0.m_iso;
09860     trim0.m_li = -1;
09861     trim1.m_li = -1;
09862   }
09863 
09864   // delete old edges
09865   DeleteEdge(m_E[ei0],true);
09866   DeleteEdge(m_E[ei1],true);
09867 
09868   return &m_E[edge.m_edge_index];
09869 }
09870 
09871 bool ON_Brep::CombineCoincidentEdges(ON_BrepEdge& edge0, ON_BrepEdge& edge1)
09872 {
09873   bool rc = false;
09874   if ( edge0.m_edge_index == edge1.m_edge_index ) 
09875   {
09876     ON_ERROR("ON_Brep::CombineCoincidentEdges - edge0 = edge1.");
09877     return rc;
09878   }
09879   int ti, eti, etcnt;
09880   if (    edge0.m_edge_index >= 0 
09881        && edge1.m_edge_index >= 0 
09882        && edge0.m_edge_index != edge1.m_edge_index
09883        && edge0.m_vi[0] == edge1.m_vi[0] 
09884        && edge0.m_vi[1] == edge1.m_vi[1] ) 
09885   {
09886     bool bIsGoodIso0 = false;
09887     if (edge0.m_tolerance == 0.0){
09888       for (eti=0; eti<edge0.m_ti.Count(); eti++){
09889         const ON_BrepTrim& T = m_T[edge0.m_ti[eti]];
09890         if (T.m_iso)
09891         {
09892           bIsGoodIso0 = true;
09893           break;
09894         }
09895       }
09896     }
09897     bool bIsGoodIso1 = false;
09898     if (edge1.m_tolerance == 0.0){
09899       for (eti=0; eti<edge1.m_ti.Count(); eti++){
09900         const ON_BrepTrim& T = m_T[edge1.m_ti[eti]];
09901         if (T.m_iso)
09902         {
09903           bIsGoodIso1 = true;
09904           break;
09905         }
09906       }
09907     }
09908     bool bKeep0 = (edge0.m_tolerance <= edge1.m_tolerance) ? true : false;
09909     if (edge0.m_tolerance == edge1.m_tolerance && edge0.m_tolerance == 0.0){
09910       if (bIsGoodIso1){
09911         if (!bIsGoodIso0)
09912           bKeep0 = false;
09913         else {//both are good.  Take the one with the lowest degree.
09914           if (edge1.Degree() < edge0.Degree())
09915             bKeep0 = false;
09916           else if (edge1.Degree() == edge0.Degree() && edge1.SpanCount() < edge0.SpanCount())
09917             bKeep0 = false;
09918         }
09919       }
09920     }
09921 
09922     ON_BrepEdge& EKeep = (bKeep0) ? edge0 : edge1;
09923     ON_BrepEdge& EToss = (bKeep0) ? edge1 : edge0;
09924 
09925     /*
09926     rc = true;
09927     etcnt = edge1.m_ti.Count();
09928     int tcount = m_T.Count();
09929     for ( eti = 0; eti < etcnt; eti++ ) {
09930       ti = edge1.m_ti[eti];
09931       if ( ti >= 0 && ti < tcount ) {
09932         ON_BrepTrim& trim = m_T[ti];
09933         trim.m_ei = edge0.m_edge_index;
09934         edge0.m_ti.Append(ti);
09935         // TODO - tolerances ?
09936 
09937         //set edge tolerance
09938         if (edge0.m_tolerance != ON_UNSET_VALUE && edge1.m_tolerance != ON_UNSET_VALUE)
09939           SetEdgeTolerance(edge0, false); 
09940         else edge0.m_tolerance = ON_UNSET_VALUE;
09941       }
09942     }
09943     edge1.m_ti.Destroy();
09944     DeleteEdge( edge1, false );
09945 
09946     etcnt =  edge0.m_ti.Count();
09947     if ( etcnt >= 2 ) for ( eti = 0; eti < etcnt; eti++ )
09948     {
09949       ti = edge0.m_ti[eti];
09950       if ( ti >= 0 && ti < tcount ) 
09951       {
09952         ON_BrepTrim& trim = m_T[ti];
09953         if ( trim.m_type == ON_BrepTrim::boundary )
09954           trim.m_type = ON_BrepTrim::mated;
09955       }
09956     }
09957     */
09958     rc = true;
09959     etcnt = EToss.m_ti.Count();
09960     int tcount = m_T.Count();
09961     for ( eti = 0; eti < etcnt; eti++ ) {
09962       ti = EToss.m_ti[eti];
09963       if ( ti >= 0 && ti < tcount ) {
09964         ON_BrepTrim& trim = m_T[ti];
09965         trim.m_ei = EKeep.m_edge_index;
09966         EKeep.m_ti.Append(ti);
09967         trim.UnsetPlineEdgeParameters();  
09968         // TODO - tolerances ?
09969 
09970         //set edge tolerance
09971         if (EKeep.m_tolerance != ON_UNSET_VALUE && EToss.m_tolerance != ON_UNSET_VALUE)
09972           SetEdgeTolerance(EKeep, false); 
09973         else EKeep.m_tolerance = ON_UNSET_VALUE;
09974       }
09975     }
09976     EToss.m_ti.Destroy();
09977     DeleteEdge( EToss, false );
09978 
09979     etcnt =  EKeep.m_ti.Count();
09980     if ( etcnt >= 2 ) for ( eti = 0; eti < etcnt; eti++ )
09981     {
09982       ti = EKeep.m_ti[eti];
09983       if ( ti >= 0 && ti < tcount ) 
09984       {
09985         ON_BrepTrim& trim = m_T[ti];
09986         if ( trim.m_type == ON_BrepTrim::boundary )
09987           trim.m_type = ON_BrepTrim::mated;
09988       }
09989     }
09990   }
09991   return rc;
09992 }
09993 
09994 bool ON_Brep::Create( ON_Surface*& pS )
09995 {
09996   bool rc = false;
09997   Destroy();
09998   ON_Surface* p = pS;
09999   if (p)
10000   {
10001     int vid[4] = {-1,-1,-1,-1};
10002     int eid[4] = {-1,-1,-1,-1};
10003     ON_BOOL32 bRev3d[4] = {0,0,0,0};
10004     ON_BrepFace* face = NewFace(p,vid,eid,bRev3d);
10005     if ( face )
10006     {
10007       rc = true;
10008       pS = 0;
10009     }
10010   }
10011   return rc;
10012 }
10013 
10014 /*
10015 ON_BOOL32 ON_Brep::FaceTool( ON_Surface* pS )
10016 {
10017   // private face adding tool
10018   if (!pS) 
10019     return false;
10020   double u[2], v[2];
10021   if (!pS->GetDomain(0, &u[0], &u[1])) 
10022       return false;
10023   if (!pS->GetDomain(1, &v[0], &v[1])) 
10024       return false;
10025 
10026   ON_3dPoint srf_P[2][2];
10027   if ( !pS->EvPoint(u[0],v[0],srf_P[0][0] )
10028     return false;
10029   if ( !pS->EvPoint(u[1],v[0],srf_P[1][0] )
10030     return false;
10031   if ( !pS->EvPoint(u[0],v[1],srf_P[0][1] )
10032     return false;
10033   if ( !pS->EvPoint(u[1],v[1],srf_P[1][1] )
10034     return false;
10035 
10036   int sw_vi, se_vi, ne_vi, nw_vi;
10037 
10038   m_F.Reserve( m_F.Count() + 1 );
10039   m_T.Reserve( m_T.Count() + 4 );
10040   m_L.Reserve( m_L.Count() + 1 );
10041   m_V.Reserve( m_V.Count() + 4 );
10042   m_E.Reserve( m_E.Count() + 4 );
10043   m_S.Reserve( m_S.Count() + 1 );
10044   m_C2.Reserve( m_C2.Count() + 1 );
10045   m_C3.Reserve( m_C3.Count() + 1 );
10046 
10047   sw_vi = NewVertex( srf_P[0][0], 0.0 ).m_vertex_index;
10048 
10049   ON_BOOL32 bIsClosed[2];
10050   bIsClosed[0] = pS->IsClosed(0);
10051   bIsClosed[1] = pS->IsClosed(1);
10052 
10053   ON_BOOL32 bIsSingular[4];
10054   bIsSingular[0] = pS->IsSingular(0);
10055   bIsSingular[1] = pS->IsSingular(1);
10056   bIsSingular[2] = pS->IsSingular(2);
10057   bIsSingular[3] = pS->IsSingular(3);
10058 
10059 
10060   if (bIsSingular[0] || bIsClosed[0]) 
10061     se_vi = sw_vi;
10062   else 
10063     se_vi = NewVertex( srf_P[1][0], 0.0 ).m_vertex_index;
10064 
10065   if (bIsSingular[1] || bIsClosed[1]) 
10066     ne_vi = se_vi;
10067   else 
10068     ne_vi = NewVertex( srf_P[1][1], 0.0 ).m_vertex_index;
10069 
10070   if (bIsSingular[2] || bIsClosed[0]) 
10071     nw_vi = ne_vi;
10072   else if (bIsSingular[3] || bIsClosed[1]) 
10073     nw_vi = sw_vi;
10074   else 
10075     nw_vi = NewVertex( srf_P[0][1], 0.0 ).m_vertex_index;
10076 
10077   ON_BrepVertex& sw_vertex = m_V[sw_vi];
10078   ON_BrepVertex& se_vertex = m_V[se_vi];
10079   ON_BrepVertex& ne_vertex = m_V[ne_vi];
10080   ON_BrepVertex& nw_vertex = m_V[nw_vi];
10081 
10082   ON_BrepFace& face = NewFace(AddSurface(pS));
10083   ON_BrepLoop& loop = NewLoop(ON_BrepLoop::outer, face);
10084 
10085   loop.m_pbox.m_min.x = u[0];
10086   loop.m_pbox.m_min.y = v[0];
10087   loop.m_pbox.m_min.z = 0.0;
10088 
10089   loop.m_pbox.m_max.x = u[1];
10090   loop.m_pbox.m_max.y = v[1];
10091   loop.m_pbox.m_max.z = 0.0;
10092 
10093   int id3[4] = {-1,-1,-1,-1};
10094   int eid[4] = {-1,-1,-1,-1};
10095   int c2i;
10096 
10097   ON_2dPoint sw_corner(u[0],v[0]);
10098   ON_2dPoint se_corner(u[1],v[0]);
10099   ON_2dPoint ne_corner(u[1],v[1]);
10100   ON_2dPoint nw_corner(u[0],v[1]);
10101 
10102   {//south side
10103     c2i = AddTrimCurve(new ON_LineCurve(sw_corner,se_corner));
10104     if (bIsSingular[0]) {
10105       NewSingularTrim(sw_vertex,loop,ON_Surface::S_iso,c2i);
10106     }
10107     else {
10108       id3[0] = AddEdgeCurve( pS->IsoCurve(0, v[0]) );
10109       ON_BrepEdge& edge = NewEdge(sw_vertex, se_vertex, id3[0]);
10110       edge.m_tolerance = 0.0;
10111       eid[0] = edge.m_edge_index;
10112       ON_BrepTrim& trim = NewTrim(edge, false, loop, c2i);
10113       trim.m_iso = ON_Surface::S_iso;
10114       if (bIsClosed[1]) 
10115         trim.m_type = ON_BrepTrim::seam;
10116       else 
10117         trim.m_type = ON_BrepTrim::boundary;
10118     }
10119   }
10120 
10121   { //east side
10122     c2i = AddTrimCurve(new ON_LineCurve(se_corner,ne_corner));
10123     if (bIsSingular[1]) {
10124       NewSingularTrim(se_vertex,loop,ON_Surface::E_iso,c2i);
10125     }
10126     else {
10127       id3[1] = AddEdgeCurve(pS->IsoCurve(1, u[1]));
10128       ON_BrepEdge& edge = NewEdge(se_vertex, ne_vertex, id3[1]);
10129       edge.m_tolerance = 0.0;
10130       eid[1] = edge.m_edge_index;
10131       ON_BrepTrim& trim = NewTrim(edge, false, loop, c2i);
10132       trim.m_iso = ON_Surface::E_iso;
10133       if (bIsClosed[0]) 
10134         trim.m_type = ON_BrepTrim::seam;
10135       else 
10136         trim.m_type = ON_BrepTrim::boundary;
10137     }
10138   }
10139 
10140   { //north side
10141     c2i = AddTrimCurve(new ON_LineCurve(ne_corner,nw_corner));
10142     ON_BOOL32 rev = false;
10143     if (bIsSingular[2]) {
10144       NewSingularTrim(ne_vertex,loop,ON_Surface::N_iso,c2i);
10145     }
10146     else{
10147       if (bIsClosed[1]) {
10148         id3[2] = id3[0];
10149         eid[2] = eid[0];
10150         rev = true;
10151       }
10152       else {
10153         ON_Curve* pC3 = pS->IsoCurve(0, v[1]);
10154         if (pC3) pC3->Reverse();
10155         id3[2] = AddEdgeCurve(pC3);
10156         ON_BrepEdge& edge = NewEdge(ne_vertex, nw_vertex, id3[2]);
10157         edge.m_tolerance = 0.0;
10158         eid[2] = edge.m_edge_index;
10159       }
10160       ON_BrepTrim& trim = NewTrim(m_E[eid[2]], rev, loop, c2i);
10161       trim.m_iso = ON_Surface::N_iso;
10162       if (bIsClosed[1]) 
10163         trim.m_type = ON_BrepTrim::seam;
10164       else 
10165         trim.m_type = ON_BrepTrim::boundary;
10166     }
10167   }
10168 
10169   { //west side
10170     c2i = AddTrimCurve(new ON_LineCurve(nw_corner,sw_corner));
10171     ON_BOOL32 rev = false;
10172     if (bIsSingular[3]){
10173       NewSingularTrim(nw_vertex,loop,ON_Surface::W_iso,c2i);
10174     }
10175     else {
10176       if (bIsClosed[0]){
10177       id3[3] = id3[1];
10178         eid[3] = eid[1];
10179         rev = true;
10180       }
10181       else {
10182         ON_Curve* pC3 = pS->IsoCurve(1, u[0]);
10183         if (pC3) pC3->Reverse();
10184         id3[3] = AddEdgeCurve(pC3);
10185         ON_BrepEdge& edge = NewEdge(nw_vertex, sw_vertex, id3[3]);
10186         edge.m_tolerance = 0.0;
10187         eid[3] = edge.m_edge_index;
10188       }
10189       ON_BrepTrim& trim = NewTrim( m_E[eid[3]], rev, loop, c2i );
10190       trim.m_iso = ON_Surface::W_iso;
10191       if (bIsClosed[0]) 
10192         trim.m_type = ON_BrepTrim::seam;
10193       else 
10194         trim.m_type = ON_BrepTrim::boundary;
10195     }
10196   }
10197 
10198   for ( int lti = 0; lti < 4; lti++ )
10199   {
10200     ti = loop.m_ti[lti];
10201     ON_BrepTrim& trim = m_T[ti];
10202     trim.m_tolerance[0] = 0.0;
10203     trim.m_tolerance[1] = 0.0;
10204     trim.m__legacy_2d_tol = 0.0;
10205     trim.m__legacy_3d_tol = 0.0;
10206     trim.m__legacy_flags_Set(-1,1);
10207   }
10208 
10209   return true;
10210 }
10211 */
10212 
10213 bool ON_Brep::Create( ON_NurbsSurface*& pNurbsSurface )
10214 {
10215   ON_Surface* pSurface = pNurbsSurface;
10216   bool rc = Create(pSurface);
10217   if ( !pSurface )
10218     pNurbsSurface = 0;
10219   return rc;
10220 }
10221 
10222 bool ON_Brep::Create( ON_PlaneSurface*& pPlaneSurface )
10223 {
10224   ON_Surface* pSurface = pPlaneSurface;
10225   bool rc = Create(pSurface);
10226   if ( !pSurface )
10227     pPlaneSurface = 0;
10228   return rc;
10229 }
10230 
10231 bool ON_Brep::Create( ON_RevSurface*& pRevSurface )
10232 {
10233   ON_Surface* pSurface = pRevSurface;
10234   bool rc = Create(pSurface);
10235   if ( !pSurface )
10236     pRevSurface = 0;
10237   return rc;
10238 }
10239 
10240 bool ON_Brep::Create( ON_SumSurface*& pSumSurface )
10241 {
10242   ON_Surface* pSurface = pSumSurface;
10243   bool rc = Create(pSurface);
10244   if ( !pSurface )
10245     pSumSurface = 0;
10246   return rc;
10247 }
10248 
10249 
10250 ON_BOOL32 ON_Brep::HasBrepForm() const
10251 {
10252   return true;
10253 }
10254 
10255 ON_Brep* ON_Brep::BrepForm( ON_Brep* brep ) const
10256 {
10257   if ( brep )
10258   {
10259     if ( brep != this )
10260       *brep = *this;      
10261   }
10262   else
10263   {
10264     brep = new ON_Brep(*this);
10265   }
10266   return brep;
10267 }
10268 
10269 void ON_Brep::Clear_vertex_user_i()
10270 {
10271   int vi;
10272   int vertex_count = m_V.Count();
10273   for ( vi = 0; vi < vertex_count; vi++ ) 
10274   {
10275     memset(&m_V[vi].m_vertex_user,0,sizeof(ON_U));
10276   }
10277 }
10278 
10279 void ON_Brep::Clear_edge_user_i()
10280 {
10281   int ei;
10282   int edge_count = m_E.Count();
10283   for ( ei = 0; ei < edge_count; ei++ ) 
10284   {
10285     memset(&m_E[ei].m_edge_user,0,sizeof(ON_U));
10286   }
10287 }
10288 
10289 void ON_Brep::Clear_edge_user_i(int i)
10290 {
10291   int ei;
10292   int edge_count = m_E.Count();
10293   for ( ei = 0; ei < edge_count; ei++ ) 
10294   {
10295     memset(&m_E[ei].m_edge_user,0,sizeof(ON_U));
10296     m_E[ei].m_edge_user.i = i;
10297   }
10298 }
10299 
10300 void ON_Brep::Clear_trim_user_i()
10301 {
10302   int ti;
10303   int trim_count = m_T.Count();
10304   for ( ti = 0; ti < trim_count; ti++ ) {
10305     memset(&m_T[ti].m_trim_user,0,sizeof(ON_U));
10306   }
10307 }
10308 
10309 void ON_Brep::Clear_loop_user_i()
10310 {
10311   int li;
10312   int loop_count = m_L.Count();
10313   for ( li = 0; li < loop_count; li++ ) {
10314     memset(&m_L[li].m_loop_user,0,sizeof(ON_U));
10315   }
10316 }
10317 
10318 void ON_Brep::Clear_face_user_i()
10319 {
10320   int fi;
10321   int face_count = m_F.Count();
10322   for ( fi = 0; fi < face_count; fi++ ) {
10323     memset(&m_F[fi].m_face_user,0,sizeof(ON_U));
10324   }
10325 }
10326 
10327 void ON_Brep::Clear_user_i()
10328 {
10329   memset(&m_brep_user,0,sizeof(m_brep_user));
10330   Clear_vertex_user_i();
10331   Clear_edge_user_i();
10332   Clear_trim_user_i();
10333   Clear_loop_user_i();
10334   Clear_face_user_i();
10335 }
10336 
10337 void ON_Brep::Set_user(ON_U u)
10338 {
10339   int i, count;
10340   m_brep_user=u;
10341   
10342   count = m_V.Count();
10343   ON_BrepVertex* V = m_V.Array();
10344   for ( i = 0; i < count; i++ )
10345   {
10346     V[i].m_vertex_user = u;
10347   }
10348   
10349   count = m_E.Count();
10350   ON_BrepEdge* E = m_E.Array();
10351   for ( i = 0; i < count; i++ )
10352   {
10353     E[i].m_edge_user = u;
10354   }
10355 
10356   
10357   count = m_T.Count();
10358   ON_BrepTrim* T = m_T.Array();
10359   for ( i = 0; i < count; i++ )
10360   {
10361     T[i].m_trim_user = u;
10362   }
10363   
10364   count = m_L.Count();
10365   ON_BrepLoop* L = m_L.Array();
10366   for ( i = 0; i < count; i++ )
10367   {
10368     L[i].m_loop_user = u;
10369   }
10370   
10371   count = m_F.Count();
10372   ON_BrepFace* F = m_F.Array();
10373   for ( i = 0; i < count; i++ )
10374   {
10375     F[i].m_face_user = u;
10376   }
10377 }
10378 
10379 
10380 
10381 ON_BrepVertex& ON_Brep::NewPointOnFace( 
10382   ON_BrepFace& face,
10383   double s,
10384   double t
10385   )
10386 {
10387   ON_3dPoint point = face.PointAt(s,t);
10388   
10389   ON_BrepVertex& vertex = NewVertex( point );
10390   ON_BrepLoop& loop = NewLoop( ON_BrepLoop::ptonsrf, face );
10391   ON_BrepTrim& trim = NewTrim(false,loop,-1);
10392 
10393   vertex.m_tolerance = 0.0;
10394   trim.m_type = ON_BrepTrim::ptonsrf;
10395   trim.m_pbox.m_min.Set(s,t,0.0);
10396   trim.m_pbox.m_max.Set(s,t,0.0);
10397   trim.m_tolerance[0] = 0.0;
10398   trim.m_tolerance[1] = 0.0;
10399   loop.m_pbox = trim.m_pbox;
10400   trim.m_vi[0] = trim.m_vi[1] = vertex.m_vertex_index;
10401 
10402   return vertex;
10403 }
10404 
10405 
10406 ON_BrepTrim& ON_Brep::NewCurveOnFace( ON_BrepFace& face, ON_BrepEdge& edge, ON_BOOL32 bRev3d, int c2i )
10407 {
10408   ON_BrepLoop& loop = NewLoop( ON_BrepLoop::crvonsrf, face );
10409   ON_BrepTrim& trim = NewTrim( edge, bRev3d, loop, c2i );
10410   trim.m_type = ON_BrepTrim::crvonsrf;
10411   const ON_Curve* trimcurve = trim.TrimCurveOf();
10412   if (trimcurve)
10413   {
10414     trimcurve->GetBoundingBox( trim.m_pbox );
10415     loop.m_pbox = trim.m_pbox;
10416   }
10417   return trim;
10418 }
10419 
10420 //For each i, let ti be the parameter along the chord (Points[0], Points[last])
10421 //of the closest point to Points[i], and let di be the distance to the chord.
10422 //Transform Points so that Points[0] = P0, Points[last] = P1, 
10423 //and the new ti and di remain the same.  Don't do anything if the chord is short 
10424 //relative to the cummulative dist between consecutive points on input.
10425 
10426 static bool AdjustPointListAlongChord(ON_3dPointArray& Points, 
10427                                       const ON_3dPoint& P0, 
10428                                       const ON_3dPoint& P1)
10429 
10430 {
10431   int count = Points.Count();
10432   if (count < 2)
10433     return false;
10434 
10435   ON_3dPoint A0 = Points[0];
10436   ON_3dPoint A1 = Points[count-1];
10437   double chord_dist = A0.DistanceTo(A1);
10438   if (chord_dist < ON_SQRT_EPSILON)
10439     return false;
10440   double cum_dist = 0.0;
10441   int i; 
10442   for (i=1; i<count; i++)
10443     cum_dist += Points[i-1].DistanceTo(Points[i]);
10444   if (chord_dist < 0.01*cum_dist)
10445     return false;
10446   ON_3dVector V0 = P0-A0;
10447   ON_3dVector V1 = P1-A1;
10448   ON_Line Aline(A0, A1);
10449   Points[0] = P0;
10450   Points[count-1] = P1;
10451   for (i=1; i<count-1; i++){
10452     double t;
10453     Aline.ClosestPointTo(Points[i], &t);
10454     Points[i] = Points[i] + (1.0-t)*V0 + t*V1;
10455   }
10456   return true;
10457 }
10458 
10459 static void AdjustNurbsCurve(ON_NurbsCurve& crv,
10460                              const ON_3dPoint& P0, 
10461                              const ON_3dPoint& P1)
10462 
10463 {
10464   if (crv.Dimension() > 3)
10465     return;
10466 
10467   crv.ClampEnd(2);
10468   int cvc = crv.CVCount();
10469   ON_3dPointArray Points(cvc);
10470   int i;
10471   for (i=0; i<cvc; i++)
10472     crv.GetCV(i, Points.AppendNew());
10473 
10474   if (!AdjustPointListAlongChord(Points, P0, P1)){
10475     crv.SetStartPoint(P0);
10476     crv.SetEndPoint(P1);
10477     return;
10478   }
10479 
10480   bool rat = crv.IsRational();
10481   for (i=0; i<cvc; i++){
10482     double w = 1.0;
10483     if (rat){
10484       w = crv.Weight(i);
10485       Points[i] *= w;
10486     }
10487     crv.SetCV(i, Points[i]);
10488     if (rat)
10489       crv.SetWeight(i, w);
10490   }
10491   
10492   return;
10493 }
10494 
10495 static void AdjustPolylineCurve(ON_PolylineCurve& crv,
10496                              const ON_3dPoint& P0, 
10497                              const ON_3dPoint& P1)
10498 
10499 {
10500   AdjustPointListAlongChord(crv.m_pline, P0, P1);
10501   crv.SetStartPoint(P0);
10502   crv.SetEndPoint(P1);
10503   return;
10504 }
10505 
10506 static void AdjustCurve(ON_Curve& crv, 
10507                         const ON_3dPoint& P0,
10508                         const ON_3dPoint& P1);
10509 
10510 static void AdjustPolyCurve(ON_PolyCurve& crv,
10511                              const ON_3dPoint& P0, 
10512                              const ON_3dPoint& P1)
10513 
10514 {
10515 
10516   if (crv.Count() == 1){
10517     ON_Curve* pSeg = crv.SegmentCurve(0);
10518     if (!pSeg)
10519       return;
10520     AdjustCurve(*pSeg, P0, P1);
10521     return;
10522   }
10523 
10524   ON_3dPointArray Points(crv.Count() + 1);
10525   Points.Append(crv.PointAtStart());
10526 
10527   int i;
10528   for (i=0; i<crv.Count(); i++)
10529     Points.Append(crv.SegmentCurve(i)->PointAtEnd());
10530 
10531   if (!AdjustPointListAlongChord(Points, P0, P1)){
10532     crv.SetStartPoint(P0);
10533     crv.SetEndPoint(P1);
10534     return;
10535   }
10536 
10537   for (i=0; i<crv.Count(); i++){
10538     ON_Curve* pSeg = crv.SegmentCurve(i);
10539     if (!pSeg)
10540       return;
10541     AdjustCurve(*pSeg, Points[i], Points[i+1]);
10542     Points[i+1] = pSeg->PointAtEnd();
10543   }
10544 
10545   return;
10546 }
10547 
10548 //Afterwards it is up to caller to check to see if the endpoints are where they should be.
10549 static void AdjustCurve(ON_Curve& crv, 
10550                         const ON_3dPoint& P0,
10551                         const ON_3dPoint& P1)
10552 
10553 {
10554   ON_LineCurve* lc = ON_LineCurve::Cast(&crv);
10555   if (lc){
10556     lc->SetStartPoint(P0);
10557     lc->SetEndPoint(P1);
10558     return;
10559   }
10560 
10561   ON_CurveProxy* pc = ON_CurveProxy::Cast(&crv);
10562   if (pc)
10563     return;
10564 
10565   if (crv.IsClosed()){
10566     if (P0 != P1)
10567       return;
10568     ON_3dPoint P = crv.PointAtStart();
10569     ON_3dVector TVec = P0-P;
10570     if (TVec.Length() > ON_SQRT_EPSILON){
10571       ON_Xform T;
10572       T.Translation(TVec);
10573       crv.Transform(T);
10574     }
10575     return;
10576   }
10577 
10578   ON_PolylineCurve* plc = ON_PolylineCurve::Cast(&crv);
10579   if (plc) {
10580     AdjustPolylineCurve(*plc, P0, P1);
10581     return;
10582   }
10583 
10584   ON_NurbsCurve* nc = ON_NurbsCurve::Cast(&crv);
10585   if (nc){
10586     AdjustNurbsCurve(*nc, P0, P1);
10587     return;
10588   }
10589 
10590   ON_PolyCurve* plyc = ON_PolyCurve::Cast(&crv);
10591   if (plyc){
10592     AdjustPolyCurve(*plyc, P0, P1);
10593     return;
10594   }
10595 
10596   ON_3dPoint A0 = crv.PointAtStart();
10597   ON_3dPoint A1 = crv.PointAtEnd();
10598 
10599   if (A0.DistanceTo(P0) < ON_SQRT_EPSILON && A1.DistanceTo(P1) < ON_SQRT_EPSILON){
10600     crv.SetStartPoint(P0);
10601     crv.SetEndPoint(P1);
10602     return;
10603   }
10604 
10605   double alen = A0.DistanceTo(A1);
10606   double plen = P0.DistanceTo(P1);
10607   if (alen < 0.1*plen || plen < 0.1*alen){
10608     crv.SetStartPoint(P0);
10609     crv.SetEndPoint(P1);
10610     return;
10611   }
10612 
10613   ON_3dPoint Ac = 0.5*(A0+A1);
10614   ON_3dPoint Pc = 0.5*(P0+P1);
10615   ON_3dVector TVec = Pc-Ac;
10616   if (TVec.Length() > ON_SQRT_EPSILON){
10617     ON_Xform T;
10618     T.Translation(TVec);
10619     crv.Transform(T);
10620   }
10621 
10622   A0 = crv.PointAtStart();
10623   A1 = crv.PointAtEnd();
10624   if (A0.DistanceTo(P0) < ON_SQRT_EPSILON && A1.DistanceTo(P1) < ON_SQRT_EPSILON){
10625     crv.SetStartPoint(P0);
10626     crv.SetEndPoint(P1);
10627     return;
10628   }
10629 
10630   if (fabs(plen - alen) > ON_SQRT_EPSILON){
10631     double scale = plen/alen;
10632     Ac = 0.5*(A0+A1);
10633     ON_Xform T;
10634     T.Scale(Ac, scale);
10635     crv.Transform(T);
10636   }
10637 
10638   A0 = crv.PointAtStart();
10639   A1 = crv.PointAtEnd();
10640   if (A0.DistanceTo(P0) < ON_SQRT_EPSILON && A1.DistanceTo(P1) < ON_SQRT_EPSILON){
10641     crv.SetStartPoint(P0);
10642     crv.SetEndPoint(P1);
10643     return;
10644   }
10645 
10646   if (plen < ON_SQRT_EPSILON){
10647     crv.SetStartPoint(P0);
10648     crv.SetEndPoint(P1);
10649     return;
10650   }
10651 
10652   ON_3dPoint C = 0.5*(Pc+Ac);
10653   ON_3dVector VA = A0-C;
10654   VA.Unitize();
10655   ON_3dVector VP = P0-C;
10656   VP.Unitize();
10657 
10658   ON_3dVector Axis = ON_CrossProduct(VA, VP);
10659   double sina = Axis.Length();
10660   if (sina < ON_SQRT_EPSILON){
10661     crv.SetStartPoint(P0);
10662     crv.SetEndPoint(P1);
10663     return;
10664   }
10665   Axis.Unitize();
10666   double cosa = VA*VP;
10667 
10668   ON_Xform T;
10669   T.Rotation(sina, cosa, Axis, C);
10670   crv.Transform(T);
10671   crv.SetStartPoint(P0);
10672   crv.SetEndPoint(P1);
10673   return;
10674   }
10675 
10676 static void AdjustEdgeEnds(ON_BrepEdge& edge)
10677 
10678 {
10679   ON_Brep* pB = edge.Brep();
10680   if (!pB)
10681     return;
10682   ON_Curve* c3 = const_cast<ON_Curve*>(edge.EdgeCurveOf());
10683   if( c3 )
10684   {
10685     ON_3dPoint A0 = c3->PointAtStart();
10686     ON_3dPoint P0 = A0;
10687     if (edge.m_vi[0] >= 0){
10688       ON_BrepVertex& V = pB->m_V[edge.m_vi[0]];
10689       if (V.IsValid())
10690         P0 = V.Point();
10691     }
10692     ON_3dPoint A1 = c3->PointAtEnd();
10693     ON_3dPoint P1 = A1;
10694     if (edge.m_vi[1] >= 0){
10695       ON_BrepVertex& V = pB->m_V[edge.m_vi[1]];
10696       if (V.IsValid())
10697         P1 = V.Point();
10698     }
10699 
10700     bool bQuit = true;
10701     if (P0 != A0 && edge.m_vi[0] >= 0){
10702       ON_BrepVertex& V = pB->m_V[edge.m_vi[0]];
10703       V.m_tolerance = ON_UNSET_VALUE;
10704       bQuit = false;
10705     }
10706     if (P1 != A1 && edge.m_vi[1] >= 0){
10707       ON_BrepVertex& V = pB->m_V[edge.m_vi[1]];
10708       V.m_tolerance = ON_UNSET_VALUE;
10709       bQuit = false;
10710     }
10711     if (bQuit)
10712       return;
10713 
10714     edge.m_tolerance = ON_UNSET_VALUE;
10715     AdjustCurve(*c3, P0, P1);
10716   }
10717   return;
10718 }
10719 
10720 bool ON_Brep::StandardizeEdgeCurve( int edge_index, bool bAdjustEnds )
10721 {
10722   return StandardizeEdgeCurve(edge_index, bAdjustEnds, 0);
10723 }
10724 
10725 bool ON_Brep::StandardizeEdgeCurve( int edge_index, bool bAdjustEnds, int EdgeCurveUse )
10726 {
10727   bool rc = false;
10728   ON_BrepEdge* edge = Edge(edge_index);
10729   if ( 0 != edge && edge->m_edge_index >= 0 )
10730   {
10731     edge_index = edge->m_edge_index;
10732     const ON_Curve* c3 = edge->EdgeCurveOf();
10733     if( c3 )
10734     {
10735       ON_Interval c3dom = c3->Domain();
10736       ON_Interval pdom = edge->ProxyCurveDomain();
10737       ON_Interval edom = edge->Domain();
10738       bool bNewCurve = false;
10739       if ( edge->ProxyCurveIsReversed() )
10740         bNewCurve = true;
10741       else if ( c3dom != pdom )
10742         bNewCurve = true; // curve proxy is trimmed
10743       else if ( EdgeCurveUse > 1 || (EdgeCurveUse < 1 && EdgeCurveUseCount( edge->m_c3i,2 ) > 1 ))
10744         bNewCurve = true; // 2 or more edges use c3
10745       else if ( edom != c3dom )
10746       {
10747         // can fix this problem by changing c3 domain
10748         // and proxy settings
10749         if ( m_C3[edge->m_c3i]->SetDomain(edom) )
10750         {
10751           edge->SetProxyCurveDomain(edom);
10752           edge->SetDomain(edom);
10753           rc = true;
10754         }
10755         else
10756         {
10757           bNewCurve = true;
10758         }
10759       }
10760       else
10761         rc = true;
10762       
10763       if ( bNewCurve )
10764       {
10765         ON_Curve* newc3 = c3->Duplicate();
10766         if ( !newc3 )
10767           return false;
10768         if ( !newc3->Trim(pdom) )
10769         {
10770           delete newc3;
10771           return false;
10772         }
10773         if ( edge->ProxyCurveIsReversed() )
10774         {
10775           if ( !newc3->Reverse() )
10776           {
10777             delete newc3;
10778             return false;
10779           }
10780         }
10781         newc3->SetDomain(edom);
10782         if ( newc3->Domain() != edom )
10783         {
10784           delete newc3;
10785           return false;
10786         }
10787         int c3i = AddEdgeCurve(newc3);
10788         edge->m_c3i = c3i;
10789         edge->SetProxyCurve(newc3);
10790       }
10791     }
10792   }
10793   if (rc && bAdjustEnds)
10794     AdjustEdgeEnds(*edge);
10795     /*
10796   {
10797     ON_Curve* c3 = const_cast<ON_Curve*>(edge->EdgeCurveOf());
10798     if( c3 )
10799     {
10800       if (edge->m_vi[0] >= 0)
10801       {
10802         const ON_BrepVertex& V = m_V[edge->m_vi[0]];
10803         if (V.IsValid())
10804           c3->SetStartPoint(V.Point());
10805       }
10806       if (edge->m_vi[1] >= 0)
10807       {
10808         const ON_BrepVertex& V = m_V[edge->m_vi[1]];
10809         if (V.IsValid())
10810           c3->SetEndPoint(V.Point());
10811       }
10812     }
10813   }
10814   */
10815 
10816   return rc;
10817 } 
10818 
10819 static int sort_ci(const ON_BrepEdge* E0, const ON_BrepEdge* E1)
10820 
10821 {
10822   if (E0->m_c3i < E1->m_c3i)
10823     return -1;
10824   if (E0->m_c3i < E1->m_c3i)
10825     return 1;
10826   return 0;
10827 }
10828 
10829 
10830 void ON_Brep::StandardizeEdgeCurves( bool bAdjustEnds)
10831 {
10832 
10833   //The ends will not adjust properly unless 
10834   //all of the edge curves have been standardized first.
10835   //So call standardize on all edges without adjusting, then do the adjusting
10836   //chuck - 9/5/2006
10837   int ei, edge_count = m_E.Count();
10838 
10839 
10840   //chuck - 10/13/2008.  The edge curve use counter called in StandardizeEdgeCurves(int,bool)
10841   //searches through the entire edge array.  In huge breps, this takes a long time.
10842   int* index = (int*)onmalloc(edge_count*sizeof(int));
10843   m_E.Sort(ON::quick_sort, index, sort_ci);
10844 
10845   for ( ei = 0; ei < edge_count; ei++ ){
10846     int ecc = (ei==edge_count-1 || m_E[index[ei+1]].m_c3i == m_E[index[ei]].m_c3i) ? 2 : 1;
10847     StandardizeEdgeCurve( index[ei], false, ecc);
10848   }
10849 
10850   onfree((void*)index);
10851 
10852   /*
10853   for ( ei = 0; ei < edge_count; ei++ )
10854   {
10855     StandardizeEdgeCurve( ei, false );
10856   }
10857   */
10858 
10859   if (bAdjustEnds){
10860     for ( ei = 0; ei < edge_count; ei++ )
10861       AdjustEdgeEnds(m_E[ei]);
10862     SetVertexTolerances(true);
10863     SetEdgeTolerances(true);
10864   }
10865 }
10866 
10867 bool ON_Brep::StandardizeTrimCurve( int trim_index )
10868 {
10869   bool rc = false;
10870   ON_BrepTrim* trim = Trim(trim_index);
10871   if ( 0 != trim && trim->m_trim_index >= 0 )
10872   {
10873     trim_index = trim->m_trim_index;
10874     const ON_Curve* c2 = trim->TrimCurveOf();
10875     if( c2 )
10876     {
10877       ON_Interval c2dom = c2->Domain();
10878       ON_Interval pdom = trim->ProxyCurveDomain();
10879       ON_Interval tdom = trim->Domain();
10880       bool bNewCurve = false;
10881       if ( trim->ProxyCurveIsReversed() )
10882         bNewCurve = true;
10883       else if ( c2dom != pdom )
10884         bNewCurve = true; // curve proxy is trimmed
10885       else if ( TrimCurveUseCount( trim->m_c2i, 2 ) > 1 )
10886         bNewCurve = true; // 2 or more edges use c3
10887       else if ( tdom != c2dom )
10888       {
10889         // can fix this problem by changing c3 domain
10890         // and proxy settings
10891         if ( m_C2[trim->m_c2i]->SetDomain(tdom) )
10892         {
10893           trim->SetProxyCurveDomain(tdom);
10894           trim->SetDomain(tdom);
10895           rc = true;
10896         }
10897         else
10898         {
10899           bNewCurve = true;
10900         }
10901       }
10902       else
10903         rc = true;
10904       
10905       if ( bNewCurve )
10906       {
10907         ON_Curve* newc2 = c2->Duplicate();
10908         if ( !newc2 )
10909           return false;
10910         if ( !newc2->Trim(pdom) )
10911         {
10912           delete newc2;
10913           return false;
10914         }
10915         if ( trim->ProxyCurveIsReversed() )
10916         {
10917           if ( !newc2->Reverse() )
10918           {
10919             delete newc2;
10920             return false;
10921           }
10922         }
10923         newc2->SetDomain(tdom);
10924         if ( newc2->Domain() != tdom )
10925         {
10926           delete newc2;
10927           return false;
10928         }
10929         int c2i = AddTrimCurve(newc2);
10930         trim->m_c2i = c2i;
10931         trim->SetProxyCurve(newc2);
10932         rc = true;
10933       }
10934     }
10935   }
10936   return rc;
10937 }
10938 
10939 void ON_Brep::StandardizeTrimCurves()
10940 {
10941   int ti, trim_count = m_T.Count();
10942   for ( ti = 0; ti < trim_count; ti++ )
10943   {
10944     StandardizeTrimCurve( ti );
10945   }
10946 }
10947 
10948 bool ON_Brep::StandardizeFaceSurface( int face_index )
10949 {
10950   bool rc = false;
10951   ON_BrepFace* face = Face(face_index);
10952   if ( 0 != face && face->m_face_index >= 0 )
10953   {
10954     face_index = face->m_face_index;
10955     const ON_Surface* srf = face->SurfaceOf();
10956     if ( srf )
10957     {
10958       if ( face->m_bRev )
10959       {
10960         if ( SurfaceUseCount( face->m_si, 2 ) >= 2 )
10961         {
10962           ON_Surface* newsrf = srf->Duplicate();
10963           face->m_si = AddSurface(newsrf);
10964           face->SetProxySurface(m_S[face->m_si]);
10965           srf = newsrf;
10966         }
10967         rc = face->Transpose() ? true : false;
10968       }
10969       else
10970         rc = true;
10971     }
10972   }
10973   return rc;
10974 }
10975 
10976 void ON_Brep::StardardizeFaceSurfaces()
10977 {
10978   // StardardizeFaceSurfaces() - misspelled function is obsolte
10979   // but left here to avoid breaking the SDK.
10980   StandardizeFaceSurfaces();
10981 }
10982 
10983 void ON_Brep::StandardizeFaceSurfaces()
10984 {
10985   int fi, face_count = m_F.Count();
10986   for ( fi = 0; fi < face_count; fi++ )
10987   {
10988     StandardizeFaceSurface( fi );
10989   }
10990 }
10991 
10992 void ON_Brep::Standardize()
10993 {
10994   StandardizeFaceSurfaces();
10995   StandardizeEdgeCurves(true);
10996   StandardizeTrimCurves();
10997 }
10998 
10999 
11000 
11001 bool ON_Brep::ShrinkSurface( ON_BrepFace& face, int DisableMask )
11002 {
11003   ON_Surface* srf = const_cast<ON_Surface*>(face.SurfaceOf());
11004   if ( !srf )
11005     return false;
11006 
11007   ON_Interval srf_udom = srf->Domain(0);
11008   ON_Interval srf_vdom = srf->Domain(1);
11009 
11010   int fli, li, si=-1;
11011   int lti, ti;
11012   int outer_loop_li=-1;
11013   const int loop_count = m_L.Count();
11014   const int trim_count = m_T.Count();
11015   ON_BoundingBox outer_pbox;
11016 
11017   bool bAllTrimsAreIsoTrims = true; 
11018   bool bSomeTrimsAreIsoTrims = false;
11019 
11020   // 4 April 2003 Dale Lear:
11021   //    Shrink srf fix.
11022   ON_BoundingBox trim_iso_endbox; // bounding box of iso curve trim ends
11023 
11024   int face_loop_count = face.m_li.Count();
11025   bool bIsSrfEdge[4];
11026   int sei;
11027   for (sei=0; sei<4; sei++)
11028     bIsSrfEdge[sei] = false;
11029   for ( fli = 0; fli < face_loop_count; fli++ )
11030   {
11031     li = face.m_li[fli];
11032     if ( li < 0 )
11033       continue;
11034     if ( li >= loop_count )
11035       continue;
11036     const ON_BrepLoop& loop = m_L[li];
11037     if ( loop.m_type == ON_BrepLoop::outer )
11038     {
11039       // may be more than one outer loop
11040       if ( outer_loop_li )
11041         outer_loop_li = li;
11042       outer_pbox.Union( loop.m_pbox );
11043 
11044       int loop_trim_count = loop.m_ti.Count();
11045       for ( lti = 0; lti < loop_trim_count; lti++ )
11046       {
11047         ti = loop.m_ti[lti];
11048         if ( ti >= 0 && ti < trim_count )
11049         {
11050           bool bIsIso = false;
11051           switch( m_T[ti].m_iso )
11052           {
11053           case ON_Surface::x_iso:
11054           case ON_Surface::y_iso:
11055             bIsIso = true;
11056             break;
11057           case ON_Surface::W_iso:
11058             bIsIso = true;
11059             bIsSrfEdge[0] = true;
11060             break;
11061           case ON_Surface::S_iso:
11062             bIsIso = true;
11063             bIsSrfEdge[1] = true;
11064             break;
11065           case ON_Surface::E_iso:
11066             bIsIso = true;
11067             bIsSrfEdge[2] = true;
11068             break;
11069           case ON_Surface::N_iso:
11070             bIsIso = true;
11071             bIsSrfEdge[3] = true;
11072             break;
11073           default:
11074             // it's not an iso curve trim
11075             bAllTrimsAreIsoTrims = false;
11076           }
11077           if (bIsIso){
11078             // it's an iso curve trim
11079             trim_iso_endbox.Set( m_T[ti].PointAtStart(), true );
11080             trim_iso_endbox.Set( m_T[ti].PointAtEnd(), true );
11081             bSomeTrimsAreIsoTrims = true;
11082           }
11083         }
11084       }
11085 
11086     }
11087   }
11088 
11089   if ( !outer_pbox.IsValid() )
11090     return false;
11091   
11092   bool rc = false;
11093   ON_Interval outer_udom( outer_pbox.m_min.x, outer_pbox.m_max.x );
11094   ON_Interval outer_vdom( outer_pbox.m_min.y, outer_pbox.m_max.y );
11095 
11096   if ( !bAllTrimsAreIsoTrims )
11097   {
11098     // 4 April 2003 Dale Lear:
11099     //    Prevent shrinking surface to
11100     //    interior edge of wiggly trims so that
11101     //    3d edge curves will pullback correctly and
11102     //    brep-brep intersections will be
11103     //    transverse along complicated trims.
11104     double d;
11105 
11106     d = outer_udom.Length()*0.01;
11107     if ( (!bSomeTrimsAreIsoTrims || outer_udom[0] < trim_iso_endbox.m_min.x) && !bIsSrfEdge[0] )
11108       outer_udom[0] -= d;
11109     if ( (!bSomeTrimsAreIsoTrims || outer_udom[1] > trim_iso_endbox.m_max.x) && !bIsSrfEdge[2])
11110       outer_udom[1] += d;
11111 
11112     d = outer_vdom.Length()*0.01;
11113     if ( (!bSomeTrimsAreIsoTrims || outer_vdom[0] < trim_iso_endbox.m_min.y) && !bIsSrfEdge[1] )
11114       outer_vdom[0] -= d;
11115     if ( (!bSomeTrimsAreIsoTrims || outer_vdom[1] > trim_iso_endbox.m_max.y) && !bIsSrfEdge[3] )
11116       outer_vdom[1] += d;
11117   }
11118 
11119   outer_udom.Intersection( srf_udom );
11120   outer_vdom.Intersection( srf_vdom );
11121 
11122   bool bShrinkIt = false;
11123 
11124   /*
11125   // removed 4 April 2003 Dale Lear
11126   if ( outer_udom.IsIncreasing() && outer_vdom.IsIncreasing() )
11127   {
11128     if ( outer_udom.Length() < 0.99*srf_udom.Length() || outer_vdom.Length() < 0.99*srf_vdom.Length())
11129     {
11130       bShrinkIt = true;
11131     }
11132     else if ( outer_udom.Length() < srf_udom.Length() || outer_vdom.Length() < srf_vdom.Length())
11133     {
11134       // 13 Feb 2003 Dale Lear added this --
11135       // if all trims are isos, then perform micro shrink
11136       // so iso trims will lie on surface boundaries
11137       bShrinkIt = bAllTrimsAreIsoTrims;
11138     }
11139   }
11140   */
11141 
11142   // GBA 8 May 2006.  Added DiasbleMask 
11143   if( DisableMask & 0x0001)     // West
11144     outer_udom[0] = srf_udom[0];
11145   if( DisableMask & 0x0002)     // South
11146     outer_vdom[0] = srf_vdom[0];
11147   if( DisableMask & 0x0004)     // East
11148     outer_udom[1] = srf_udom[1];
11149   if( DisableMask & 0x0008)     // North
11150     outer_vdom[1] = srf_vdom[1];
11151 
11152 
11153   // added 4 April 2003 Dale Lear
11154   if ( outer_udom.IsIncreasing() && outer_vdom.IsIncreasing() )
11155   {
11156     //TRR #33381 28-April-08 GBA
11157     //  Make sure we don't keep allowing the surface to be shrunk.
11158     if ( outer_udom.Length()*ON_ZERO_TOLERANCE < (srf_udom.Length() - outer_udom.Length()) || 
11159          outer_vdom.Length()*ON_ZERO_TOLERANCE < (srf_vdom.Length() - outer_vdom.Length())  )  
11160       bShrinkIt = true;
11161   }
11162 
11163   if ( bShrinkIt )
11164   {
11165     int srf_use = SurfaceUseCount( face.m_si, 2);
11166     ON_Surface* small_srf = srf->Duplicate();
11167     if ( small_srf->Trim( 0, outer_udom ) )
11168     {
11169       if ( small_srf->Trim( 1, outer_vdom) )
11170         si = AddSurface(small_srf);
11171       if ( si >= 0 )
11172       {
11173                                 int srf_index = face.m_si;
11174         face.m_si = si;
11175         face.SetProxySurface( m_S[face.m_si] );
11176 
11177         // 5 Dec 2002 Chuck - dont delete original surface if used by more than one face
11178                                 if (srf_use == 1) DeleteSurface(srf_index);
11179 
11180         // 1 Nov 2002 Dale Lear - reset face bbox and destroy brep too big bounding box
11181         face.m_bbox = small_srf->BoundingBox();
11182         m_bbox.Destroy();
11183 
11184                                 // Set trim.m_iso flags
11185                                 for(int li=0; li<face.LoopCount(); li++){
11186                                         ON_BrepLoop& loop = *face.Loop(li);
11187                                         for(int ti=0; ti<loop.TrimCount(); ti++){
11188                                                 ON_BrepTrim& trim = *loop.Trim(ti);
11189             //Since the slop used in calculating m_iso depends on the srf domain
11190             //all isos should be rechecked after shrinking
11191 
11192             /*
11193                                                 if(     trim.m_iso==ON_Surface::x_iso || 
11194                                                                 trim.m_iso==ON_Surface::y_iso )
11195                 */
11196             if (trim.m_iso != ON_Surface::not_iso)
11197                                                         trim.m_iso = face.IsIsoparametric(trim);        
11198                                         }
11199                                 }
11200         rc = true;
11201       }
11202     }
11203     if ( !rc )
11204       delete small_srf;
11205   }
11206 
11207   return rc;
11208 }
11209 
11210 bool ON_Brep::ShrinkSurfaces()
11211 {
11212   bool rc = true;
11213   int fi, face_count = m_F.Count();
11214   for ( fi = 0; fi < face_count; fi++ )
11215   {
11216     if ( !ShrinkSurface( m_F[fi] ) )
11217       rc = false;
11218   }
11219         Compact();
11220   return rc;
11221 }
11222 
11223 /*
11224 int ON_Brep::ComponentIndex( const ON_BrepVertex& vertex ) const
11225 {
11226   int component_index = vertex.m_vertex_index;
11227   if ( component_index >= 0 )
11228     component_index += brep_vertex;
11229   else
11230     component_index = -1;
11231   return component_index;
11232 }
11233 
11234 int ON_Brep::ComponentIndex( const ON_BrepEdge& edge ) const
11235 {
11236   int component_index = edge.m_edge_index;
11237   if ( component_index >= 0 )
11238     component_index += brep_edge;
11239   else
11240     component_index = -1;
11241   return component_index;
11242 }
11243 
11244 int ON_Brep::ComponentIndex( const ON_BrepTrim& trim ) const
11245 {
11246   int component_index = trim.m_trim_index;
11247   if ( component_index >= 0 )
11248     component_index += brep_trim;
11249   else
11250     component_index = -1;
11251   return component_index;
11252 }
11253 
11254 int ON_Brep::ComponentIndex( const ON_BrepLoop& loop ) const
11255 {
11256   int component_index = loop.m_loop_index;
11257   if ( component_index >= 0 )
11258     component_index += brep_loop;
11259   else
11260     component_index = -1;
11261   return component_index;
11262 }
11263 
11264 int ON_Brep::ComponentIndex( const ON_BrepFace& face ) const
11265 {
11266   int component_index = face.m_face_index;
11267   if ( component_index >= 0 )
11268     component_index += brep_face;
11269   else
11270     component_index = -1;
11271   return component_index;
11272 }
11273 
11274 ON_Brep::COMPONENT_TYPE ON_Brep::ComponentIndexType( int component_index )
11275 {
11276   switch( brep_component_mask & component_index )
11277   {
11278   case brep_vertex: return brep_vertex;
11279   case brep_edge: return brep_edge;
11280   case brep_trim: return brep_trim;
11281   case brep_loop: return brep_loop;
11282   case brep_face: return brep_face;
11283   }
11284   return brep_component_unset;
11285 }
11286 */
11287 
11288 const ON_Geometry* ON_Brep::BrepComponent( 
11289   ON_COMPONENT_INDEX ci
11290   ) const
11291 {
11292   const ON_Geometry* component = 0;
11293   switch ( ci.m_type )
11294   {
11295   case ON_COMPONENT_INDEX::brep_vertex:
11296     component = Vertex(ci.m_index);
11297     break;
11298   case ON_COMPONENT_INDEX::brep_edge:
11299     component = Edge(ci.m_index);
11300     break;
11301   case ON_COMPONENT_INDEX::brep_face:
11302     component = Face(ci.m_index);
11303     break;
11304   case ON_COMPONENT_INDEX::brep_trim:
11305     component = Trim(ci.m_index);
11306     break;
11307   case ON_COMPONENT_INDEX::brep_loop:
11308     component = Loop(ci.m_index);
11309     break;
11310   default:
11311     // other enum values skipped on purpose
11312     break;
11313   }
11314   return component;
11315 }
11316 
11317 /*
11318 const ON_Geometry* ON_Brep::BrepComponent( 
11319   int component_index
11320   ) const
11321 {
11322   const ON_Geometry* component = 0;
11323   if ( -1 != component_index && 0 != component_index)
11324   {
11325     switch( ON_Brep::ComponentIndexType(component_index) )
11326     {
11327     case brep_vertex: 
11328       component = Vertex(component_index);
11329       break;
11330     case brep_edge:
11331       component = Edge(component_index);
11332       break;
11333     case brep_trim:
11334       component = Trim(component_index);
11335       break;
11336     case brep_loop:
11337       component = Loop(component_index);
11338       break;
11339     case brep_face:
11340       component = Face(component_index);
11341       break;
11342     }
11343   }
11344   return component;
11345 }
11346 */
11347 
11348 
11349 ON_BrepVertex* ON_Brep::Vertex( int vertex_index ) const
11350 {
11351   ON_BrepVertex* vertex = 0;
11352   if ( vertex_index>=0 && vertex_index < m_V.Count() )
11353     vertex = const_cast<ON_BrepVertex*>(&m_V[vertex_index]);
11354   return vertex;
11355 }
11356 
11357 ON_BrepVertex* ON_Brep::Vertex( ON_COMPONENT_INDEX vertex_index ) const
11358 {
11359   ON_BrepVertex* vertex = 0;
11360   if ( ON_COMPONENT_INDEX::brep_vertex == vertex_index.m_type 
11361        && vertex_index.m_index >= 0 
11362        && vertex_index.m_index < m_V.Count() )
11363   {
11364     vertex = const_cast<ON_BrepVertex*>(&m_V[vertex_index.m_index]);
11365   }
11366   return vertex;
11367 }
11368 
11369 
11370 ON_BrepEdge* ON_Brep::Edge( int edge_index ) const
11371 {
11372   ON_BrepEdge* edge = 0;
11373   if ( edge_index>=0 && edge_index < m_E.Count() )
11374     edge = const_cast<ON_BrepEdge*>(&m_E[edge_index]);
11375   return edge;
11376 }
11377 
11378 ON_BrepEdge* ON_Brep::Edge( ON_COMPONENT_INDEX edge_index ) const
11379 {
11380   ON_BrepEdge* edge = 0;
11381   if ( ON_COMPONENT_INDEX::brep_edge == edge_index.m_type 
11382        && edge_index.m_index >= 0 
11383        && edge_index.m_index < m_E.Count() )
11384   {
11385     edge = const_cast<ON_BrepEdge*>(&m_E[edge_index.m_index]);
11386   }
11387   return edge;
11388 }
11389 
11390 ON_BrepTrim* ON_Brep::Trim( int trim_index ) const
11391 {
11392   ON_BrepTrim* trim = 0;
11393   if ( trim_index>=0 && trim_index < m_T.Count() )
11394     trim = const_cast<ON_BrepTrim*>(&m_T[trim_index]);
11395   return trim;
11396 }
11397 
11398 ON_BrepTrim* ON_Brep::Trim( ON_COMPONENT_INDEX trim_index ) const
11399 {
11400   ON_BrepTrim* trim = 0;
11401   if ( ON_COMPONENT_INDEX::brep_trim == trim_index.m_type 
11402        && trim_index.m_index >= 0 
11403        && trim_index.m_index < m_T.Count() )
11404   {
11405     trim = const_cast<ON_BrepTrim*>(&m_T[trim_index.m_index]);
11406   }
11407   return trim;
11408 }
11409 
11410 ON_BrepLoop* ON_Brep::Loop( int loop_index ) const
11411 {
11412   ON_BrepLoop* loop = 0;
11413   if ( loop_index>=0 && loop_index < m_L.Count() )
11414     loop = const_cast<ON_BrepLoop*>(&m_L[loop_index]);
11415   return loop;
11416 }
11417 
11418 ON_BrepLoop* ON_Brep::Loop( ON_COMPONENT_INDEX loop_index ) const
11419 {
11420   ON_BrepLoop* loop = 0;
11421   if ( ON_COMPONENT_INDEX::brep_loop == loop_index.m_type 
11422        && loop_index.m_index >= 0 
11423        && loop_index.m_index < m_L.Count() )
11424   {
11425     loop = const_cast<ON_BrepLoop*>(&m_L[loop_index.m_index]);
11426   }
11427   return loop;
11428 }
11429 
11430 ON_BrepFace* ON_Brep::Face( int face_index ) const
11431 {
11432   ON_BrepFace* face = 0;
11433   if ( face_index>=0 && face_index < m_F.Count() )
11434     face = const_cast<ON_BrepFace*>(&m_F[face_index]);
11435   return face;
11436 }
11437 
11438 ON_BrepFace* ON_Brep::Face( ON_COMPONENT_INDEX face_index ) const
11439 {
11440   ON_BrepFace* face = 0;
11441   if ( ON_COMPONENT_INDEX::brep_face == face_index.m_type 
11442        && face_index.m_index >= 0 
11443        && face_index.m_index < m_F.Count() )
11444   {
11445     face = const_cast<ON_BrepFace*>(&m_F[face_index.m_index]);
11446   }
11447   return face;
11448 }
11449 
11450 const ON_Surface* ON_BrepFace::SurfaceOf() const
11451 {
11452   const ON_Surface* srf = ProxySurface();
11453   if ( 0 == srf && 0 != m_brep && m_si >= 0 && m_si < m_brep->m_S.Count() )
11454   {
11455     srf = m_brep->m_S[m_si];
11456   }
11457   return srf;
11458 }
11459 
11460 
11461 
11462 void ON_BrepTrim::DestroyPspaceInformation()
11463 {
11464   m_pline.Destroy();
11465   m_pbox.Destroy();
11466 }
11467 
11468 bool ON_BrepTrim::ChangeTrimCurve( int c2i )
11469 {
11470   if ( 0 == m_brep )
11471     return 0;
11472   if ( c2i < 0 || c2i >= m_brep->m_C2.Count() )
11473     return 0;
11474   const ON_Curve* c2 = m_brep->m_C2[c2i];
11475   m_c2i = c2i;
11476   DestroyPspaceInformation();
11477   SetProxyCurve(c2);
11478   if ( c2 )
11479   {
11480     m_pbox = c2->BoundingBox();
11481     m_pbox.m_min.z = 0.0;
11482     m_pbox.m_max.z = 0.0;
11483   }
11484   return true;
11485 }
11486 
11487 bool ON_BrepTrim::RemoveFromEdge( 
11488       bool bRemoveFromStartVertex,
11489       bool bRemoveFromEndVertex
11490       )
11491 {
11492   bool rc = false;
11493   if ( 0 != m_brep || m_ei < 0  )
11494   {
11495     UnsetPlineEdgeParameters();
11496     if ( 0 != m_brep )
11497     {
11498       ON_BrepEdge* edge = m_brep->Edge(m_ei);
11499       if ( 0 != edge )
11500       {
11501         int eti = 0;
11502         while( eti < edge->m_ti.Count() )
11503         {
11504           if ( edge->m_ti[eti] == m_trim_index )
11505             edge->m_ti.Remove(eti);
11506           else
11507             eti++;
11508         }
11509       }
11510     }
11511     m_ei = -1;
11512     if (bRemoveFromStartVertex)
11513       m_vi[0] = -1;
11514     if (bRemoveFromEndVertex)
11515       m_vi[1] = -1;
11516     rc = true;
11517   }
11518   return rc;
11519 }
11520 
11521 bool ON_BrepTrim::AttachToEdge(
11522       int edge_index,
11523       bool bRev3d
11524       )
11525 {
11526   bool rc = false;
11527   if ( 0 != m_brep )
11528   {
11529     ON_BrepEdge* edge = m_brep->Edge(edge_index);
11530     if ( 0 != edge )
11531     {
11532       rc = RemoveFromEdge(true,true);
11533       if (rc)
11534       {
11535         edge->m_ti.Append(m_trim_index);
11536         m_ei = edge->m_edge_index;
11537         m_bRev3d = bRev3d ? true : false;
11538         m_vi[0] = edge->m_vi[bRev3d?1:0];
11539         m_vi[1] = edge->m_vi[bRev3d?0:1];
11540       }
11541     }
11542   }
11543   return rc;
11544 }
11545 
11546 
11547 
11548 const ON_Curve* ON_BrepEdge::EdgeCurveOf() const
11549 {
11550   const ON_Curve* c3 = ProxyCurve();
11551   if ( !c3 && m_brep && m_c3i >= 0 && m_c3i < m_brep->m_C3.Count())
11552   {
11553     // fallback to get answer if developer forgot to
11554     // set proxy ptr.
11555     c3 = m_brep->m_C3[m_c3i];
11556     if ( c3 )
11557     {
11558       ON_ERROR("ON_BrepEdge ProxyCurve() is NULL but m_c3i is valid");
11559     }
11560   }
11561   return c3;
11562 }
11563 
11564 int ON_BrepEdge::EdgeCurveIndexOf() const
11565 {
11566   return (m_brep && m_c3i >= 0 && m_c3i < m_brep->m_C3.Count()) ? m_c3i : -1;
11567 }
11568 
11569 int ON_BrepTrim::EdgeCurveIndexOf() const
11570 {
11571   int c3i = -1;
11572   if ( m_brep && m_ei >= 0 && m_ei < m_brep->m_E.Count() )
11573   {
11574     c3i = m_brep->m_E[m_ei].m_c3i;
11575     if ( c3i < 0 || c3i >= m_brep->m_C3.Count() )
11576       c3i = -1;
11577   }
11578   return c3i;
11579 }
11580 
11581 int ON_BrepTrim::TrimCurveIndexOf() const
11582 {
11583   return ((m_brep && m_c2i >= 0 && m_c2i < m_brep->m_C2.Count()) ? m_c2i : -1);
11584 }
11585 
11586 const ON_Curve* ON_BrepTrim::EdgeCurveOf() const
11587 {
11588   const ON_Curve* c3 = 0;
11589   if ( m_brep && m_ei >= 0 && m_ei < m_brep->m_C3.Count() )
11590   {
11591     c3 = m_brep->m_E[m_ei].EdgeCurveOf();
11592   }
11593   return c3;
11594 }
11595 
11596 bool ON_BrepEdge::ChangeEdgeCurve( int c3i )
11597 {
11598   if ( 0 == m_brep )
11599     return 0;
11600   if ( c3i < 0 || c3i >= m_brep->m_C3.Count() )
11601     return 0;
11602   const ON_Curve* c3 = m_brep->m_C3[c3i];
11603   m_c3i = c3i;
11604   SetProxyCurve(c3);
11605   UnsetPlineEdgeParameters();
11606   return true;
11607 }
11608 
11609 const ON_Curve* ON_BrepTrim::TrimCurveOf() const
11610 {
11611   const ON_Curve* c2 = ProxyCurve();
11612   if ( !c2 && m_brep && m_c2i >= 0 && m_c2i < m_brep->m_C2.Count() )
11613   {
11614     // fallback to get answer if developer forgot to
11615     // set proxy ptr.
11616     c2 = m_brep->m_C2[m_c2i];
11617     if ( c2 )
11618     {
11619       ON_ERROR("ON_BrepTrim ProxyCurve() = NULL but m_c2i is valid");
11620     }
11621   }
11622   return c2;
11623 }
11624 
11625 const ON_Surface* ON_BrepTrim::SurfaceOf() const
11626 {
11627   const ON_Surface* srf = 0;
11628   if ( m_brep && m_li >= 0 && m_li < m_brep->m_L.Count() )
11629   {
11630     const int fi = m_brep->m_L[m_li].m_fi;
11631     if ( fi >= 0 && fi < m_brep->m_F.Count() )
11632     {
11633       srf = m_brep->m_F[fi].SurfaceOf();
11634     }
11635   }
11636   return srf;
11637 }
11638 
11639 const ON_Surface* ON_BrepLoop::SurfaceOf() const
11640 {
11641   const ON_Surface* srf = 0;
11642   if ( m_brep && m_fi >= 0 && m_fi < m_brep->m_F.Count() )
11643   {
11644     srf = m_brep->m_F[m_fi].SurfaceOf();
11645   }
11646   return srf;
11647 }
11648 
11649 int ON_BrepTrim::SurfaceIndexOf() const
11650 {
11651   int si = -1;
11652   if ( m_brep && m_li >= 0 && m_li < m_brep->m_L.Count() )
11653   {
11654     const int fi = m_brep->m_L[m_li].m_fi;
11655     if ( fi >= 0 && fi < m_brep->m_F.Count() )
11656     {
11657       si = m_brep->m_F[fi].m_si;
11658       if ( si < 0 || si >= m_brep->m_S.Count() )
11659         si = -1;
11660     }
11661   }
11662   return si;
11663 }
11664 
11665 
11666 int ON_BrepTrim::FaceIndexOf() const
11667 {
11668   int fi = -1;
11669   if ( m_brep && m_li >= 0 && m_li < m_brep->m_L.Count() )
11670   {
11671     fi = m_brep->m_L[m_li].m_fi;
11672     if ( fi< 0 || fi >= m_brep->m_F.Count() )
11673     {
11674       fi = -1;
11675     }
11676   }
11677   return fi;
11678 }
11679 
11680 static
11681 const ON_BrepTrim* SlitSeamMateHelper( const ON_BrepTrim& trim )
11682 {
11683   if ( ON_BrepTrim::seam  != trim.m_type )
11684     return 0;
11685   if ( trim.m_li < 0 )
11686     return 0;
11687   if ( trim.m_ei < 0 )
11688     return 0;
11689   const ON_Brep* brep = trim.Brep();
11690   if ( !brep )
11691     return 0;
11692   if ( trim.m_ei >= brep->m_E.Count() )
11693     return 0;
11694   const ON_BrepEdge& edge = brep->m_E[trim.m_ei];
11695   int other_ti = -1;
11696   for ( int eti = 0; eti < edge.m_ti.Count(); eti++ )
11697   {
11698     int ti = edge.m_ti[eti];
11699     if ( trim.m_trim_index == ti )
11700       continue;
11701     if ( ti < 0 || ti >= brep->m_T.Count() )
11702       continue;
11703     if ( trim.m_li == brep->m_T[ti].m_li )
11704     {
11705       if (other_ti >= 0 )
11706         return 0;
11707       other_ti = ti;
11708     }
11709   }
11710   if ( other_ti < 0 )
11711     return 0;
11712   return &brep->m_T[other_ti];
11713 }
11714 
11715 bool ON_BrepTrim::IsSlit() const
11716 {
11717   // 17 Nov 2006
11718   //     At this point in the development cycle, I cannot
11719   //     add a "slit" type to trim.  So, I will use this 
11720   //     function to distinguish between "slit" and "seam"
11721   //     trims.
11722   switch(m_iso)
11723   {
11724   case ON_Surface::E_iso:
11725   case ON_Surface::N_iso:
11726   case ON_Surface::S_iso:
11727   case ON_Surface::W_iso:
11728     return false;
11729     break;
11730 
11731   case ON_Surface::not_iso:
11732   case ON_Surface::x_iso:
11733   case ON_Surface::y_iso:
11734   case ON_Surface::iso_count:
11735     // anything else might be a slit
11736     break;
11737   }
11738   const ON_BrepTrim* other_trim = SlitSeamMateHelper(*this);
11739   if ( !other_trim )
11740     return false;
11741   return ( other_trim->m_iso == m_iso );
11742 }
11743 
11744 bool ON_BrepTrim::IsSeam() const
11745 {
11746   // 17 Nov 2006
11747   //     At this point in the development cycle, I cannot
11748   //     add a "slit" type to trim.  So, I will use this 
11749   //     function to distinguish between "slit" and "seam"
11750   //     trims.
11751   ON_Surface::ISO other_iso = ON_Surface::not_iso;
11752   switch(m_iso)
11753   {
11754   case ON_Surface::E_iso:
11755     other_iso = ON_Surface::W_iso;
11756     break;
11757   case ON_Surface::N_iso:
11758     other_iso = ON_Surface::S_iso;
11759     break;
11760   case ON_Surface::S_iso:
11761     other_iso = ON_Surface::N_iso;
11762     break;
11763   case ON_Surface::W_iso:
11764     other_iso = ON_Surface::E_iso;
11765     break;
11766   default:
11767     return false;
11768   }
11769   const ON_BrepTrim* other_trim = SlitSeamMateHelper(*this);
11770   if ( !other_trim )
11771     return false;
11772 
11773   return ( other_trim->m_iso == other_iso );
11774 }
11775 
11776 
11777 int ON_BrepLoop::SurfaceIndexOf() const
11778 {
11779   const ON_BrepFace* face = Face();
11780   return face ? face->m_si : -1;
11781 }
11782 
11783 int ON_BrepFace::SurfaceIndexOf() const
11784 {
11785   return (m_brep && m_si >= 0 && m_si < m_brep->m_S.Count()) ? m_si : 0;
11786 }
11787 
11788 void ON_BrepTrim::UnsetPlineEdgeParameters()
11789 {
11790   int count = m_pline.Count();
11791   if ( count > 0 )
11792   {
11793     ON_BrepTrimPoint* pline = m_pline.Array();
11794     while ( count-- )
11795       (pline++)->e = ON_UNSET_VALUE;
11796   }
11797 }
11798 
11799 void ON_BrepEdge::UnsetPlineEdgeParameters()
11800 {
11801   int edge_trim_count, brep_trim_count, eti, ti;
11802   if ( 0 != m_brep )
11803   {
11804     edge_trim_count = m_ti.Count();
11805     if ( edge_trim_count > 0 )
11806     {
11807       brep_trim_count = m_brep->m_T.Count();
11808       for ( eti = 0; eti < edge_trim_count; eti++ )
11809       {
11810         ti = m_ti[eti];
11811         if ( ti >= 0 && ti < brep_trim_count )
11812         {
11813           m_brep->m_T[ti].UnsetPlineEdgeParameters();
11814         }
11815       }
11816     }
11817   }
11818 }
11819 
11820 bool ON_BrepFace::TransformTrim( const ON_Xform& xform )
11821 {
11822   if ( !m_brep )
11823     return false;
11824   int fli;
11825   for ( fli = 0; fli < m_li.Count(); fli++ )
11826   {
11827     ON_BrepLoop* loop = m_brep->Loop( m_li[fli] );
11828     if ( loop )
11829     {
11830       if ( !loop->TransformTrim(xform) )
11831         return false;
11832     }
11833   }
11834   return true;
11835 }
11836 
11837 bool ON_BrepLoop::TransformTrim( const ON_Xform& xform )
11838 {
11839   if ( !m_brep )
11840     return false;
11841   int lti;
11842   m_pbox.Destroy();
11843   for ( lti = 0; lti < m_ti.Count(); lti++ )
11844   {
11845     ON_BrepTrim* trim = m_brep->Trim( m_ti[lti] );
11846     if ( trim )
11847     {
11848       if ( !trim->TransformTrim(xform) )
11849         return false;
11850       m_pbox.Union( trim->m_pbox );
11851     }
11852   }
11853   return true;
11854 }
11855 
11856 bool ON_BrepTrim::TransformTrim( const ON_Xform& xform )
11857 {
11858   // destroy cached information used to accelerate calculations
11859   DestroyCurveTree();
11860   m_pline.Destroy();
11861 
11862   if ( !m_brep )
11863     return false;
11864 
11865   // make sure only one trim uses the 2d curve
11866   if ( !m_brep->StandardizeTrimCurve( m_trim_index ) )
11867     return false;
11868 
11869   // transform 2d curve geometry
11870   ON_Curve* c2 = const_cast<ON_Curve*>(TrimCurveOf());
11871   if ( !c2 )
11872     return true;
11873   if ( !c2->Transform(xform) )
11874     return false;
11875 
11876   // update bounding box stored on trim
11877   m_pbox = c2->BoundingBox();
11878   m_pbox.m_min.z = 0.0;
11879   m_pbox.m_max.z = 0.0;
11880 
11881   // update 2d tolerances
11882   // Trim transforms can translate, scale and/or swap parameters.
11883   // The tolerances need to be adjusted for scaling and swapping.
11884   // Since the determinant can be < 0, fabs() must be applied.
11885   double tol0 = xform[0][0]*m_tolerance[0] + xform[0][1]*m_tolerance[1];
11886   double tol1 = xform[1][0]*m_tolerance[0] + xform[1][1]*m_tolerance[1];
11887   m_tolerance[0] = fabs(tol0);
11888   m_tolerance[1] = fabs(tol1);
11889 
11890   if ( m_iso != ON_Surface::not_iso )
11891   {
11892     m_iso = ON_Surface::not_iso;
11893     m_brep->SetTrimIsoFlags(*this);
11894   }
11895 
11896   return true;
11897 }
11898 
11899 
11900 void ON_BrepTrim::DestroyRuntimeCache( bool bDelete )
11901 {
11902   ON_CurveProxy::DestroyRuntimeCache(bDelete);
11903 
11904   // This doesn't work right as of 30 Oct 2002 because
11905   // the pline is getting destroyed while it is still
11906   // valid and needed due to excessive calling
11907   // of DestroyRuntimeCache();
11908 
11909   //if ( bDelete )
11910   //  m_pline.Destroy();
11911   //else
11912   //  m_pline.EmergencyDestroy();
11913 
11914   // m_pbox.Destroy(); do not do this - it is not a runtime setting
11915   //                   and you will break the copy operators
11916 }
11917 
11918 void ON_BrepLoop::DestroyRuntimeCache( bool bDelete )
11919 {
11920   ON_Object::DestroyRuntimeCache(bDelete);
11921 
11922   // m_pbox.Destroy(); do not do this - it is not a runtime setting
11923   //                   and you will break the copy operators
11924 }
11925 
11926 void ON_BrepFace::DestroyRuntimeCache( bool bDelete )
11927 {
11928   ON_SurfaceProxy::DestroyRuntimeCache(bDelete);
11929 
11930   // 15 August 2003 Dale Lear:
11931   //    I added the line to destroy the face's m_bbox.
11932   //    Since m_bbox is private, it will be recalculated
11933   //    when it is needed.  (We hope.)  The fact the face
11934   //    m_bbox is private and recalculated as needed makes
11935   //    it different than the m_pbox info on trims and loops.
11936   m_bbox.Destroy();
11937 }
11938 
11939 
11940 /*
11941 bool ON_Surface::AreaMassProperties(
11942   ON_MassProperties& mp,
11943   bool bArea,
11944   bool bFirstMoments,
11945   bool bSecondMoments,
11946   bool bProductMoments,
11947   double rel_tol,
11948   double abs_tol
11949   ) const
11950 {
11951   bool rc = false;
11952   // The _MassPropertiesSurface() function is provided by the Rhino SDK.
11953   if ( 0 != _MassPropertiesSurface )
11954   {
11955     int mprc = _MassPropertiesSurface( 
11956             *this, NULL, 2, ON_UNSET_POINT, mp, 
11957             bArea, bFirstMoments, bSecondMoments, bProductMoments, 
11958             rel_tol, abs_tol );
11959     rc = (mprc != 0);
11960   }
11961   return rc;
11962 }
11963 
11964 bool ON_Surface::VolumeMassProperties(
11965   ON_MassProperties& mp, 
11966   bool bVolume,
11967   bool bFirstMoments,
11968   bool bSecondMoments,
11969   bool bProductMoments,
11970   ON_3dPoint base_point,
11971   double rel_tol,
11972   double abs_tol
11973   ) const
11974 {
11975   bool rc = false;
11976   // The _MassPropertiesSurface() function is provided by the Rhino SDK.
11977   if ( 0 != _MassPropertiesSurface )
11978   {
11979     int mprc = _MassPropertiesSurface( 
11980             *this, NULL, 3, base_point, mp, 
11981             bVolume, bFirstMoments, bSecondMoments, bProductMoments, 
11982             rel_tol, abs_tol );
11983     rc = (mprc != 0);
11984   }
11985   return rc;
11986 }
11987 */
11988 
11989 
11990 int ON_BrepLoop::Dimension() const
11991 {
11992   return 2;
11993 }
11994 
11995 ON_BOOL32 ON_BrepLoop::GetBBox(
11996         double* boxmin,
11997         double* boxmax,
11998         ON_BOOL32 bGrowBox
11999         ) const
12000 {
12001   bool rc = m_pbox.IsValid();
12002   if (rc)
12003   {
12004     ON_BoundingBox bbox;
12005     if ( bGrowBox )
12006     {
12007       bbox.m_min.x = boxmin[0];
12008       bbox.m_min.y = boxmin[1];
12009       bbox.m_min.z = 0.0;
12010       bbox.m_max.x = boxmax[0];
12011       bbox.m_max.y = boxmax[1];
12012       bbox.m_max.z = 0.0;
12013       bbox.Union(m_pbox);
12014       boxmin[0] = bbox.m_min.x;
12015       boxmin[1] = bbox.m_min.y;
12016       boxmax[0] = bbox.m_max.x;
12017       boxmax[1] = bbox.m_max.y;
12018     }
12019     else
12020     {
12021       boxmin[0] = m_pbox.m_min.x;
12022       boxmin[1] = m_pbox.m_min.y;
12023       boxmax[0] = m_pbox.m_max.x;
12024       boxmax[1] = m_pbox.m_max.y;
12025     }
12026   }
12027   return rc;
12028 }
12029 
12030 ON_BOOL32 ON_BrepLoop::Transform( const ON_Xform& )
12031 {
12032   return false;
12033 }
12034 
12035 ON_COMPONENT_INDEX ON_BrepVertex::ComponentIndex() const
12036 {
12037   ON_COMPONENT_INDEX ci(ON_COMPONENT_INDEX::brep_vertex,m_vertex_index);
12038   return ci;
12039 }
12040 
12041 ON_COMPONENT_INDEX ON_BrepEdge::ComponentIndex() const
12042 {
12043   ON_COMPONENT_INDEX ci(ON_COMPONENT_INDEX::brep_edge,m_edge_index);
12044   return ci;
12045 }
12046 
12047 ON_COMPONENT_INDEX ON_BrepFace::ComponentIndex() const
12048 {
12049   ON_COMPONENT_INDEX ci(ON_COMPONENT_INDEX::brep_face,m_face_index);
12050   return ci;
12051 }
12052 
12053 
12054 ON_COMPONENT_INDEX ON_BrepTrim::ComponentIndex() const
12055 {
12056   ON_COMPONENT_INDEX ci(ON_COMPONENT_INDEX::brep_trim,m_trim_index);
12057   return ci;
12058 }
12059 
12060 
12061 
12062 ON_COMPONENT_INDEX ON_BrepLoop::ComponentIndex() const
12063 {
12064   ON_COMPONENT_INDEX ci(ON_COMPONENT_INDEX::brep_loop,m_loop_index);
12065   return ci;
12066 }
12067 


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