1 /* $NoKeywords: $ */
2 /*
3 //
4 // Copyright (c) 1993-2012 Robert McNeel & Associates. All rights reserved.
5 // OpenNURBS, Rhinoceros, and Rhino3D are registered trademarks of Robert
6 // McNeel & Associates.
7 //
8 // THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY.
9 // ALL IMPLIED WARRANTIES OF FITNESS FOR ANY PARTICULAR PURPOSE AND OF
10 // MERCHANTABILITY ARE HEREBY DISCLAIMED.
11 //
12 // For complete openNURBS copyright information see <http://www.opennurbs.org>.
13 //
14 ////////////////////////////////////////////////////////////////
15 */
16 
17 #include "opennurbs.h"
18 
19 
20 ////////////////////////////////////////////////////////////////
21 //   Class ON_BrepVertex
22 ////////////////////////////////////////////////////////////////
23 
24 ON_OBJECT_IMPLEMENT(ON_BrepVertex,ON_Point,"60B5DBC0-E660-11d3-BFE4-0010830122F0");
25 
ON_BrepIsNotValid()26 static bool ON_BrepIsNotValid()
27 {
28   return ON_IsNotValid(); // <-- good place for a breakpoint
29 }
30 
31 
ON_BrepVertex()32 ON_BrepVertex::ON_BrepVertex()
33               : m_vertex_index(-1),
34                 m_tolerance(ON_UNSET_VALUE)
35 {
36   memset(&m_vertex_user,0,sizeof(m_vertex_user));
37 }
38 
ON_BrepVertex(int vertex_index)39 ON_BrepVertex::ON_BrepVertex( int vertex_index )
40               : m_vertex_index(vertex_index),
41                 m_tolerance(ON_UNSET_VALUE)
42 {
43   memset(&m_vertex_user,0,sizeof(m_vertex_user));
44 }
45 
SizeOf() const46 unsigned int ON_BrepVertex::SizeOf() const
47 {
48   unsigned int sz = ON_Geometry::SizeOf();
49   sz += (sizeof(*this) - sizeof(ON_Geometry));
50   sz += m_ei.SizeOfArray();
51   return sz;
52 }
53 
operator =(const ON_BrepVertex & src)54 ON_BrepVertex& ON_BrepVertex::operator=(const ON_BrepVertex& src)
55 {
56   if ( &src != this ) {
57     ON_Point::operator=(src);
58     m_vertex_user   = src.m_vertex_user;
59     m_vertex_index  = src.m_vertex_index;
60     m_ei            = src.m_ei;
61     m_tolerance     = src.m_tolerance;
62   }
63   return *this;
64 }
65 
66 ON_BOOL32
IsValid(ON_TextLog * text_log) const67 ON_BrepVertex::IsValid( ON_TextLog* text_log ) const
68 {
69   if (m_vertex_index < 0)
70   {
71     if ( text_log )
72       text_log->Print("ON_BrepVertex m_vertex_index = %d.  Should be >= 0\n",m_vertex_index);
73     return ON_BrepIsNotValid();
74   }
75   const int ve_count = EdgeCount();
76   int vei, ei;
77   for ( vei = 0; vei < ve_count; vei++ ) {
78     ei = m_ei[vei];
79     if ( ei < 0 )
80     {
81       if ( text_log )
82         text_log->Print("ON_BrepVertex m_ei[%d] = %d.  m_ei[] values should be >= 0\n",vei,ei);
83       return ON_BrepIsNotValid();
84     }
85   }
86   return ON_Point::IsValid(text_log);
87 }
88 
89 void
Dump(ON_TextLog & dump) const90 ON_BrepVertex::Dump( ON_TextLog& dump ) const
91 {
92   dump.Print("ON_BrepVertex[%d]: ",m_vertex_index);
93   dump.Print( point );
94   dump.Print("\n");
95 }
96 
97 
98 bool
SetPoint(const ON_3dPoint & p)99 ON_BrepVertex::SetPoint( const ON_3dPoint& p )
100 {
101   point = p;
102   m_tolerance = ON_UNSET_VALUE;
103   return true;
104 }
105 
106 ON_3dPoint
Point() const107 ON_BrepVertex::Point() const
108 {
109   return point;
110 }
111 
112 double
Tolerance() const113 ON_BrepVertex::Tolerance() const
114 {
115   return m_tolerance;
116 }
117 
118 int
EdgeCount() const119 ON_BrepVertex::EdgeCount() const
120 {
121   return m_ei.Count();
122 }
123 
124 ////////////////////////////////////////////////////////////////
125 //   Class ON_BrepEdge
126 ////////////////////////////////////////////////////////////////
127 
128 ON_OBJECT_IMPLEMENT(ON_BrepEdge,ON_CurveProxy,"60B5DBC1-E660-11d3-BFE4-0010830122F0");
129 
ON_BrepEdge()130 ON_BrepEdge::ON_BrepEdge() : ON_CurveProxy(0),
131                          m_edge_index(-1),
132                          m_c3i(-1),
133                          m_tolerance(ON_UNSET_VALUE),
134                          m_brep(0)
135 {
136   memset(&m_edge_user,0,sizeof(m_edge_user));
137   m_vi[0] = m_vi[1] = -1;
138 }
139 
ON_BrepEdge(int edge_index)140 ON_BrepEdge::ON_BrepEdge(int edge_index ) : ON_CurveProxy(0),
141                          m_edge_index(edge_index),
142                          m_c3i(-1),
143                          m_tolerance(ON_UNSET_VALUE),
144                          m_brep(0)
145 {
146   memset(&m_edge_user,0,sizeof(m_edge_user));
147   m_vi[0] = m_vi[1] = -1;
148 }
149 
ObjectType() const150 ON::object_type ON_BrepEdge::ObjectType() const
151 {
152   // This MUST return ON::curve_object.
153   // NEVER change this to ON::edge_object.
154   return ON::curve_object;
155 }
156 
SizeOf() const157 unsigned int ON_BrepEdge::SizeOf() const
158 {
159   unsigned int sz = ON_CurveProxy::SizeOf();
160   sz = (sizeof(*this) - sizeof(ON_CurveProxy));
161   sz += m_ti.SizeOfArray();
162   return sz;
163 }
164 
operator =(const ON_BrepEdge & src)165 ON_BrepEdge& ON_BrepEdge::operator=(const ON_BrepEdge& src)
166 {
167   if ( &src != this )
168   {
169     // do not copy m_brep pointer
170     ON_CurveProxy::operator=(src);
171     m_edge_user   = src.m_edge_user;
172     m_edge_index  = src.m_edge_index;
173     m_c3i         = src.m_c3i;
174     m_vi[0]       = src.m_vi[0];
175     m_vi[1]       = src.m_vi[1];
176     m_ti          = src.m_ti;
177     m_tolerance   = src.m_tolerance;
178   }
179   return *this;
180 }
181 
IsValid(ON_TextLog * text_log) const182 ON_BOOL32 ON_BrepEdge::IsValid( ON_TextLog* text_log ) const
183 {
184   bool rc = ON_CurveProxy::IsValid(text_log) ? true : false;
185 
186   if ( !rc )
187   {
188     if ( text_log )
189     {
190       text_log->Print("ON_BrepEdge is not a valid curve proxy\n");
191     }
192   }
193   else if (m_edge_index < 0)
194   {
195     if ( text_log )
196     {
197       text_log->Print("ON_BrepEdge.m_edge_index = %d (should be >= 0 )\n",m_edge_index);
198     }
199     rc = false;
200   }
201   else if ( m_c3i < 0 )
202   {
203     if ( text_log )
204     {
205       text_log->Print("ON_BrepEdge.m_c3i = %d (should be >= 0 )\n",m_c3i);
206     }
207     rc = false;
208   }
209   else if ( m_vi[0] < 0 )
210   {
211     if ( text_log )
212     {
213       text_log->Print("ON_BrepEdge.m_vi[0] = %d (should be >= 0 )\n",m_vi[0]);
214     }
215     rc = false;
216   }
217   else if ( m_vi[1] < 0 )
218   {
219     if ( text_log )
220     {
221       text_log->Print("ON_BrepEdge.m_vi[1] = %d (should be >= 0 )\n",m_vi[1]);
222     }
223     rc = false;
224   }
225   else if ( !m_brep )
226   {
227     if ( text_log )
228     {
229       text_log->Print("ON_BrepEdge.m_brep = NULL (should point to parent ON_Brep)\n");
230     }
231     rc = false;
232   }
233 
234   return rc;
235 
236 }
237 
IsClosed() const238 ON_BOOL32 ON_BrepEdge::IsClosed() const
239 {
240   // This function must return true if ON_CurveProxy::IsClosed() is true.
241   ON_BOOL32 rc = ON_CurveProxy::IsClosed();
242   if ( 0 == rc
243        && m_vi[0] >= 0
244        && m_vi[0] == m_vi[1]
245        && 0 != ProxyCurve()
246        && ProxyCurveDomain() == ProxyCurve()->Domain()
247        && 0 != m_brep
248        && m_vi[0] < m_brep->m_V.Count()
249        )
250   {
251     // When ON_CurveProxy::IsClosed() is false and the topology
252     // indicates the edge is closed, we need to verify that its
253     // geometry is within tolerance of being closed.
254     const ON_BrepVertex& v = m_brep->m_V[m_vi[0]];
255     ON_3dPoint P = PointAtStart();
256     ON_3dPoint Q = PointAtEnd();
257     ON_3dPoint V = v.point;
258     double vtx_tol = v.m_tolerance;
259     if ( P.DistanceTo(Q) <= m_tolerance
260          && V.DistanceTo(P) <= vtx_tol
261          && V.DistanceTo(Q) <= vtx_tol )
262       rc = true;
263   }
264   return rc;
265 }
266 
Brep() const267 ON_Brep* ON_BrepEdge::Brep() const
268 {
269   return m_brep;
270 }
271 
Trim(int eti) const272 ON_BrepTrim* ON_BrepEdge::Trim( int eti ) const
273 {
274   return (m_brep && eti >= 0 && eti < m_ti.Count()) ? m_brep->Trim(m_ti[eti]) : 0;
275 }
276 
TrimCount() const277 int ON_BrepEdge::TrimCount() const
278 {
279   return m_ti.Count();
280 }
281 
Dump(ON_TextLog & dump) const282 void ON_BrepEdge::Dump( ON_TextLog& dump ) const
283 {
284   dump.Print("ON_BrepEdge[%d]: ",m_edge_index);
285 }
286 
287 
288 // virtual ON_Curve::Reverse override
Reverse()289 ON_BOOL32 ON_BrepEdge::Reverse()
290 {
291   ON_BOOL32 rc = false;
292   if ( m_brep )
293   {
294     ON_Interval edge_domain = Domain();
295     if ( m_brep->StandardizeEdgeCurve( m_edge_index, false ) )
296     {
297       ON_Curve* c3 = const_cast<ON_Curve*>(EdgeCurveOf());
298       if ( c3 )
299       {
300         rc = c3->Reverse();
301         edge_domain.Reverse();
302         c3->SetDomain(edge_domain);
303         SetProxyCurve(c3);
304       }
305     }
306   }
307 
308   if ( !rc )
309     rc = ON_CurveProxy::Reverse();
310 
311   if (rc)
312   {
313     int i = m_vi[0];
314     m_vi[0] = m_vi[1];
315     m_vi[1] = i;
316     if ( m_brep )
317     {
318       const int tcount = m_brep->m_T.Count();
319       int ti, eti;
320       for ( eti = m_ti.Count()-1; eti >= 0; eti-- ) {
321         ti = m_ti[eti];
322         if ( ti >= 0 && ti < tcount )
323         {
324           ON_BrepTrim& trim = m_brep->m_T[ti];
325           trim.m_bRev3d = trim.m_bRev3d ? false : true;
326           trim.UnsetPlineEdgeParameters();
327         }
328       }
329     }
330   }
331 
332   return rc;
333 }
334 
335 ////////////////////////////////////////////////////////////////
336 //   Class ON_BrepTrim
337 ////////////////////////////////////////////////////////////////
338 
339 ON_OBJECT_IMPLEMENT(ON_BrepTrim,ON_CurveProxy,"60B5DBC2-E660-11d3-BFE4-0010830122F0");
340 
ON_BrepTrim()341 ON_BrepTrim::ON_BrepTrim()
342               : m_trim_index(-1),
343                 m_c2i(-1),
344                 m_ei(-1),
345                 m_bRev3d(false),
346                 m_type(ON_BrepTrim::unknown),
347                 m_iso(ON_Surface::not_iso),
348                 m_li(-1),
349                 m__legacy_2d_tol(ON_UNSET_VALUE),
350                 m__legacy_3d_tol(ON_UNSET_VALUE),
351                 m__legacy_flags(0),
352                 m_brep(0)
353 {
354   memset(&m_trim_user,0,sizeof(m_trim_user));
355   m_vi[0] = m_vi[1] = -1;
356   m_tolerance[0] = m_tolerance[1] = ON_UNSET_VALUE;
357   m_pline.Reserve(4); // This is a stopgap fix to insures the memory
358                       // pool used for pline segments is the same as
359                       // the memory pool used for the rest of this brep.
360   //m_P[0] = ON_UNSET_POINT;
361   //m_P[1] = ON_UNSET_POINT;
362 }
363 
ON_BrepTrim(int trim_index)364 ON_BrepTrim::ON_BrepTrim(int trim_index)
365               : m_trim_index(trim_index),
366                 m_c2i(-1),
367                 m_ei(-1),
368                 m_bRev3d(false),
369                 m_type(ON_BrepTrim::unknown),
370                 m_iso(ON_Surface::not_iso),
371                 m_li(-1),
372                 m__legacy_2d_tol(ON_UNSET_VALUE),
373                 m__legacy_3d_tol(ON_UNSET_VALUE),
374                 m__legacy_flags(0),
375                 m_brep(0)
376 {
377   memset(&m_trim_user,0,sizeof(m_trim_user));
378   m_vi[0] = m_vi[1] = -1;
379   m_tolerance[0] = m_tolerance[1] = ON_UNSET_VALUE;
380   m_pline.Reserve(4); // This is a stopgap fix to insures the memory
381                       // pool used for pline segments is the same as
382                       // the memory pool used for the rest of this brep.
383   //m_P[0] = ON_UNSET_POINT;
384   //m_P[1] = ON_UNSET_POINT;
385 }
386 
387 
SizeOf() const388 unsigned int ON_BrepTrim::SizeOf() const
389 {
390   unsigned int sz = ON_CurveProxy::SizeOf();
391   sz = (sizeof(*this) - sizeof(ON_CurveProxy));
392   // runtime m_pline is not counted
393   return sz;
394 }
395 
396 
operator =(const ON_BrepTrim & src)397 ON_BrepTrim& ON_BrepTrim::operator=(const ON_BrepTrim& src)
398 {
399   if ( &src != this )
400   {
401     // do not copy m_brep pointer
402     ON_CurveProxy::operator=(src);
403     m_trim_user   = src.m_trim_user;
404     m_trim_index  = src.m_trim_index;
405     m_c2i    = src.m_c2i;
406     //m_t      = src.m_t;
407     m_ei     = src.m_ei;
408     m_vi[0]  = src.m_vi[0];
409     m_vi[1]  = src.m_vi[1];
410     m_bRev3d = src.m_bRev3d;
411     m_type   = src.m_type;
412     m_iso    = src.m_iso;
413     m_li     = src.m_li;
414     m_tolerance[0] = src.m_tolerance[0];
415     m_tolerance[1] = src.m_tolerance[1];
416     //m_P[0] = src.m_P[0];
417     //m_P[1] = src.m_P[1];
418     m__legacy_2d_tol = src.m__legacy_2d_tol;
419     m__legacy_3d_tol = src.m__legacy_3d_tol;
420     m__legacy_flags = src.m__legacy_flags;
421     m_pline = src.m_pline;
422     m_pbox = src.m_pbox;
423   }
424   return *this;
425 }
426 
Brep() const427 ON_Brep* ON_BrepTrim::Brep() const
428 {
429   return m_brep;
430 }
431 
Loop() const432 ON_BrepLoop* ON_BrepTrim::Loop() const
433 {
434   ON_BrepLoop* loop = 0;
435   if ( m_brep && m_li >= 0 && m_li < m_brep->m_L.Count() )
436     loop = &m_brep->m_L[m_li];
437   return loop;
438 }
439 
Face() const440 ON_BrepFace* ON_BrepTrim::Face() const
441 {
442   ON_BrepFace* face = 0;
443   if ( m_brep && m_li >= 0 && m_li < m_brep->m_L.Count() )
444   {
445     int fi = m_brep->m_L[m_li].m_fi;
446     if ( fi >= 0 && fi < m_brep->m_F.Count() )
447       face = &m_brep->m_F[fi];
448   }
449   return face;
450 }
451 
Edge() const452 ON_BrepEdge* ON_BrepTrim::Edge() const
453 {
454   ON_BrepEdge* edge = 0;
455   if ( m_brep && m_ei >= 0 && m_ei < m_brep->m_E.Count() )
456     edge = &m_brep->m_E[m_ei];
457   return edge;
458 }
459 
Vertex(int tvi) const460 ON_BrepVertex* ON_BrepTrim::Vertex(int tvi) const
461 {
462   ON_BrepVertex* vertex = 0;
463   if ( 0 != m_brep && 0 <= tvi && tvi <= 1 )
464   {
465     int vi = m_vi[tvi];
466     if ( 0 <= vi && vi < m_brep->m_V.Count() )
467     {
468       vertex = &m_brep->m_V[vi];
469     }
470   }
471   return vertex;
472 }
473 
Vertex(int evi) const474 ON_BrepVertex* ON_BrepEdge::Vertex(int evi) const
475 {
476   ON_BrepVertex* vertex = 0;
477   if ( 0 != m_brep && 0 <= evi && evi <= 1 )
478   {
479     int vi = m_vi[evi];
480     if ( 0 <= vi && vi < m_brep->m_V.Count() )
481     {
482       vertex = &m_brep->m_V[vi];
483     }
484   }
485   return vertex;
486 }
487 
488 
IsValid(ON_TextLog * text_log) const489 ON_BOOL32 ON_BrepTrim::IsValid( ON_TextLog* text_log ) const
490 {
491   if ( m_trim_index < 0 )
492   {
493     if ( text_log )
494     {
495       text_log->Print("trim.m_trim_index < 0.\n");
496     }
497     return ON_BrepIsNotValid();
498   }
499 
500   if ( m_c2i < 0 )
501   {
502     if ( text_log )
503     {
504       text_log->Print("trim.m_c2i = %d is not valid\n",m_c2i);
505     }
506     return ON_BrepIsNotValid();
507   }
508 
509   if ( !ON_CurveProxy::IsValid(text_log) )
510   {
511     if ( text_log )
512     {
513       text_log->Print("trim curve proxy settings are not valid.\n");
514     }
515     return ON_BrepIsNotValid();
516   }
517 
518   if ( m_ei < 0 )
519   {
520     if ( m_type != singular )
521     {
522       if ( text_log )
523       {
524         text_log->Print("trim.m_ei = %d but trim.mtype != singular\n",m_ei);
525       }
526       return ON_BrepIsNotValid();
527     }
528   }
529 
530   if ( m_vi[0] < 0 )
531   {
532     if ( text_log )
533     {
534       text_log->Print("trim.m_v[0] = %d is not valid\n",m_vi[0]);
535     }
536     return ON_BrepIsNotValid();
537   }
538 
539   if ( m_vi[1] < 0 )
540   {
541     if ( text_log )
542     {
543       text_log->Print("trim.m_v[1] = %d is not valid\n",m_vi[1]);
544     }
545     return ON_BrepIsNotValid();
546   }
547 
548   unsigned int i = m_type;
549   if ( i >= trim_type_count )
550   {
551     if ( text_log )
552     {
553       text_log->Print("trim.m_type = %d is not valid\n",i);
554     }
555     return ON_BrepIsNotValid();
556   }
557 
558   if ( i == ON_BrepTrim::slit )
559   {
560     if ( text_log )
561     {
562       text_log->Print("trim.m_type = ON_BrepTrim::slit is not valid. REserved for future use.\n",i);
563     }
564     return ON_BrepIsNotValid();
565   }
566 
567   i = m_iso;
568   if ( i >= ON_Surface::iso_count )
569   {
570     if ( text_log )
571     {
572       text_log->Print("trim.m_iso = %d is not valid\n",i);
573     }
574     return ON_BrepIsNotValid();
575   }
576 
577   if ( m_li < 0 )
578   {
579     if ( text_log )
580     {
581       text_log->Print("trim.m_li = %d is not valid\n",m_li);
582     }
583     return ON_BrepIsNotValid();
584   }
585 
586   if ( !m_brep )
587   {
588     if ( text_log )
589     {
590       text_log->Print("trim.m_brep is null.\n");
591     }
592     return ON_BrepIsNotValid();
593   }
594 
595   return true;
596 }
597 
Dump(ON_TextLog & dump) const598 void ON_BrepTrim::Dump( ON_TextLog& dump ) const
599 {
600   dump.Print("ON_BrepTrim[%d]:\n",m_trim_index);
601 }
602 
Reverse()603 ON_BOOL32 ON_BrepTrim::Reverse()
604 {
605   m_pline.Destroy();
606   DestroyCurveTree();
607 
608   ON_BOOL32 rc = false;
609   if ( m_brep )
610   {
611     ON_Interval trim_domain = Domain();
612     if ( m_brep->StandardizeTrimCurve( m_trim_index ) )
613     {
614       ON_Curve* c2 = const_cast<ON_Curve*>(TrimCurveOf());
615       if ( c2 )
616       {
617         rc = c2->Reverse();
618         trim_domain.Reverse();
619         c2->SetDomain(trim_domain);
620         SetProxyCurve(c2);
621       }
622     }
623   }
624 
625   if ( !rc )
626     rc = ON_CurveProxy::Reverse();
627 
628   if (rc)
629   {
630     int i = m_vi[0];
631     m_vi[0] = m_vi[1];
632     m_vi[1] = i;
633     if ( m_ei >= 0 )
634       m_bRev3d = m_bRev3d ? false : true;
635   }
636   return rc;
637 }
638 
639 
640 ////////////////////////////////////////////////////////////////
641 //   Class ON_BrepLoop
642 ////////////////////////////////////////////////////////////////
643 
644 ON_OBJECT_IMPLEMENT(ON_BrepLoop,ON_Geometry,"60B5DBC3-E660-11d3-BFE4-0010830122F0");
645 
ON_BrepLoop()646 ON_BrepLoop::ON_BrepLoop()
647               : m_loop_index(-1),
648                 m_type(ON_BrepLoop::unknown),
649                 m_fi(-1),
650                 m_brep(0)
651 {
652   memset(&m_loop_user,0,sizeof(m_loop_user));
653 }
654 
ON_BrepLoop(int loop_index)655 ON_BrepLoop::ON_BrepLoop(int loop_index)
656               : m_loop_index(loop_index),
657                 m_type(ON_BrepLoop::unknown),
658                 m_fi(-1),
659                 m_brep(0)
660 {
661   memset(&m_loop_user,0,sizeof(m_loop_user));
662 }
663 
Brep() const664 ON_Brep* ON_BrepLoop::Brep() const
665 {
666   return m_brep;
667 }
668 
Face() const669 ON_BrepFace* ON_BrepLoop::Face() const
670 {
671   return m_brep ? m_brep->Face(m_fi) : 0;
672 }
673 
674 
SizeOf() const675 unsigned int ON_BrepLoop::SizeOf() const
676 {
677   unsigned int sz = ON_Object::SizeOf();
678   sz += (sizeof(ON_BrepLoop) - sizeof(ON_Object));
679   sz += m_ti.SizeOfArray();
680   return sz;
681 }
682 
Trim(int lti) const683 ON_BrepTrim* ON_BrepLoop::Trim( int lti ) const
684 {
685   ON_BrepTrim* trim = ( m_brep && lti >= 0 && lti < m_ti.Count() )
686                     ? m_brep->Trim(m_ti[lti])
687                     : 0;
688   return trim;
689 }
690 
TrimCount() const691 int ON_BrepLoop::TrimCount() const
692 {
693   return m_ti.Count();
694 }
695 
operator =(const ON_BrepLoop & src)696 ON_BrepLoop& ON_BrepLoop::operator=(const ON_BrepLoop& src)
697 {
698   if ( &src != this )
699   {
700     // do not copy m_brep pointer
701     ON_Object::operator=(src);
702     m_loop_user   = src.m_loop_user;
703     m_loop_index  = src.m_loop_index;
704     m_ti    = src.m_ti;
705     m_type  = src.m_type;
706     m_fi    = src.m_fi;
707     m_pbox  = src.m_pbox;
708   }
709   return *this;
710 }
711 
BadLoopMessage(int loop_index,ON_TextLog * text_log)712 static void BadLoopMessage( int loop_index, ON_TextLog* text_log )
713 {
714   if ( text_log )
715   {
716     text_log->Print("brep.m_L[%d] loop is not valid.\n",loop_index);
717   }
718 }
719 
IsValid(ON_TextLog * text_log) const720 ON_BOOL32 ON_BrepLoop::IsValid( ON_TextLog* text_log ) const
721 {
722   if ( m_loop_index < 0 )
723   {
724     BadLoopMessage(m_loop_index,text_log);
725     if ( text_log )
726       text_log->Print("loop.m_loop_index < 0.\n");
727     return ON_BrepIsNotValid();
728   }
729 
730   if ( m_ti.Count() < 1 )
731   {
732     BadLoopMessage(m_loop_index,text_log);
733     if ( text_log )
734       text_log->Print("loop.m_ti[] is empty.\n");
735     return ON_BrepIsNotValid();
736   }
737   int i = m_type;
738   if ( i < 0 || i > type_count )
739   {
740     BadLoopMessage(m_loop_index,text_log);
741     if ( text_log )
742       text_log->Print("loop.m_type = %d is not a valid value.\n",i);
743     return ON_BrepIsNotValid();
744   }
745   if ( m_fi < 0 )
746   {
747     BadLoopMessage(m_loop_index,text_log);
748     if ( text_log )
749       text_log->Print("loop.m_fi = %d (should be >= 0 ).\n",m_fi);
750     return ON_BrepIsNotValid();
751   }
752   if ( !m_brep )
753   {
754     BadLoopMessage(m_loop_index,text_log);
755     if ( text_log )
756       text_log->Print("loop.m_brep is NULL.\n");
757     return ON_BrepIsNotValid();
758   }
759   return true;
760 }
761 
Dump(ON_TextLog & dump) const762 void ON_BrepLoop::Dump( ON_TextLog& dump ) const
763 {
764   dump.Print("ON_BrepLoop[%d]: m_fi = %d, m_type = %d m_ti.Count() = %d\n",
765              m_loop_index,m_fi,m_type,m_ti.Count()
766              );
767 }
768 
IndexOfTrim(const ON_BrepTrim & trim) const769 int ON_BrepLoop::IndexOfTrim( const ON_BrepTrim& trim ) const
770 {
771   const int count = m_ti.Count();
772   int lti;
773   for ( lti = 0; lti < count; lti++ )
774   {
775     if ( m_ti[lti] == trim.m_trim_index )
776       return lti;
777   }
778   return -1;
779 }
780 
781 ////////////////////////////////////////////////////////////////
782 //   Class ON_BrepFace
783 ////////////////////////////////////////////////////////////////
784 
785 ON_OBJECT_IMPLEMENT(ON_BrepFace,ON_SurfaceProxy,"60B5DBC4-E660-11d3-BFE4-0010830122F0");
786 
ON_BrepFace()787 ON_BrepFace::ON_BrepFace() : ON_SurfaceProxy(0),
788                 m_face_index(-1),
789                 m_si(-1),
790                 m_bRev(false),
791                 m_face_material_channel(0),
792                 m_render_mesh(0),
793                 m_analysis_mesh(0),
794                 m_preview_mesh(0),
795                 m_brep(0)
796 {
797   m_face_uuid = ON_nil_uuid;
798   memset(&m_face_user,0,sizeof(m_face_user));
799 }
800 
ON_BrepFace(int face_index)801 ON_BrepFace::ON_BrepFace(int face_index) : ON_SurfaceProxy(0),
802                 m_face_index(face_index),
803                 m_si(-1),
804                 m_bRev(false),
805                 m_face_material_channel(0),
806                 m_render_mesh(0),
807                 m_analysis_mesh(0),
808                 m_preview_mesh(0),
809                 m_brep(0)
810 {
811   m_face_uuid = ON_nil_uuid;
812   memset(&m_face_user,0,sizeof(m_face_user));
813 }
814 
815 
SizeOf() const816 unsigned int ON_BrepFace::SizeOf() const
817 {
818   unsigned int sz = ON_SurfaceProxy::SizeOf();
819   sz += (sizeof(*this) - sizeof(ON_SurfaceProxy));
820   sz += m_li.SizeOfArray();
821   if ( m_render_mesh )
822     sz += m_render_mesh->SizeOf();
823   if ( m_analysis_mesh )
824     sz += m_analysis_mesh->SizeOf();
825   if ( m_preview_mesh )
826     sz += m_preview_mesh->SizeOf();
827   return sz;
828 }
829 
830 
operator =(const ON_BrepFace & src)831 ON_BrepFace& ON_BrepFace::operator=(const ON_BrepFace& src)
832 {
833   if ( &src != this )
834   {
835     // do not copy m_brep pointer
836     ON_SurfaceProxy::operator=(src);
837     m_face_user   = src.m_face_user;
838     m_face_index  = src.m_face_index;
839     m_li    = src.m_li;
840     m_si    = src.m_si;
841     m_bRev  = src.m_bRev;
842     m_face_material_channel = src.m_face_material_channel;
843     m_face_uuid = src.m_face_uuid;
844     if ( m_render_mesh ) {
845       delete m_render_mesh;
846       m_render_mesh = 0;
847     }
848     if ( src.m_render_mesh ) {
849       m_render_mesh = new ON_Mesh(*src.m_render_mesh);
850     }
851     if ( m_analysis_mesh ) {
852       delete m_analysis_mesh;
853       m_analysis_mesh = 0;
854     }
855     if ( src.m_analysis_mesh ) {
856       m_analysis_mesh = new ON_Mesh(*src.m_analysis_mesh);
857     }
858     if ( m_preview_mesh ) {
859       delete m_preview_mesh;
860       m_preview_mesh = 0;
861     }
862     if ( src.m_preview_mesh ) {
863       m_preview_mesh = new ON_Mesh(*src.m_preview_mesh);
864     }
865     //m_material_index = src.m_material_index;
866   }
867   return *this;
868 }
869 
~ON_BrepFace()870 ON_BrepFace::~ON_BrepFace()
871 {
872   DestroyMesh(ON::any_mesh);
873   m_li.Destroy();
874 }
875 
Brep() const876 ON_Brep* ON_BrepFace::Brep() const
877 {
878   return m_brep;
879 }
880 
Loop(int lti) const881 ON_BrepLoop* ON_BrepFace::Loop( int lti ) const
882 {
883   return (m_brep && lti >= 0 && lti < m_li.Count()) ? m_brep->Loop( m_li[lti]) : 0;
884 }
885 
LoopCount() const886 int ON_BrepFace::LoopCount() const
887 {
888   return m_li.Count();
889 }
890 
OuterLoop() const891 ON_BrepLoop* ON_BrepFace::OuterLoop() const
892 {
893   int li, lti;
894   for ( lti = 0; lti < m_li.Count(); lti++ )
895   {
896     li = m_li[lti];
897     if ( li >= 0 && li < m_brep->m_L.Count() )
898     {
899       if ( ON_BrepLoop::outer == m_brep->m_L[li].m_type  )
900       {
901         return &m_brep->m_L[li];
902       }
903     }
904   }
905   return 0;
906 }
907 
908 
IsValid(ON_TextLog * text_log) const909 ON_BOOL32 ON_BrepFace::IsValid( ON_TextLog* text_log ) const
910 {
911   if ( m_face_index < 0 )
912   {
913     if ( 0 != text_log )
914       text_log->Print("ON_BrepFace m_face_index = %d.  Should be >= 0.\n",m_face_index);
915     return false;
916   }
917 
918   if ( m_li.Count() < 1 )
919   {
920     if ( 0 != text_log )
921       text_log->Print("ON_BrepFace m_li.Count() = 0  Should be > 0.\n");
922     return false;
923   }
924 
925   if ( m_si < 0 )
926   {
927     if ( 0 != text_log )
928       text_log->Print("ON_BrepFace m_si = %d.  Should be >= 0.\n",m_si);
929     return false;
930   }
931 
932   if ( 0 == m_brep )
933   {
934     if ( 0 != text_log )
935       text_log->Print("ON_BrepFace m_brep = 0.  Should point to parent brep.\n");
936     return false;
937 
938   }
939 
940   return true;
941 }
942 
Dump(ON_TextLog & dump) const943 void ON_BrepFace::Dump( ON_TextLog& dump ) const
944 {
945   dump.Print("ON_BrepFace[%d]:",m_face_index);
946   if ( ON_UuidCompare(m_face_uuid,ON_nil_uuid) )
947   {
948     dump.Print(" (");
949     dump.Print(m_face_uuid);
950     dump.Print(" )");
951   }
952   dump.Print("\n");
953 }
954 
955 
956 /*
957 int ON_BrepFace::MaterialIndex() const
958 {
959   return m_material_index;
960 }
961 
962 void ON_BrepFace::SetMaterialIndex(int mi)
963 {
964   m_material_index = (mi>0) ? mi : -1;
965 }
966 */
967 
Mesh(ON::mesh_type mt) const968 const ON_Mesh* ON_BrepFace::Mesh( ON::mesh_type mt ) const
969 {
970   ON_Mesh* m = 0;
971   switch(mt) {
972   case ON::render_mesh:
973     m = m_render_mesh;
974     break;
975   case ON::analysis_mesh:
976     m = m_analysis_mesh;
977     break;
978   case ON::preview_mesh:
979     m = m_preview_mesh;
980     break;
981   default:
982     m = m_render_mesh ? m_render_mesh : m_analysis_mesh;
983     if ( !m )
984       m = m_preview_mesh;
985     break;
986   }
987   if ( m ) {
988     m->m_parent = this;
989     //m->m_material_index = m_material_index;
990   }
991   return m;
992 }
993 
DestroyMesh(ON::mesh_type mt,bool bDeleteMesh)994 void ON_BrepFace::DestroyMesh( ON::mesh_type mt, bool bDeleteMesh )
995 {
996   switch(mt) {
997   case ON::render_mesh:
998     if ( m_render_mesh )
999     {
1000       if ( bDeleteMesh )
1001         delete m_render_mesh;
1002       m_render_mesh = 0;
1003     }
1004     break;
1005   case ON::analysis_mesh:
1006     if (m_analysis_mesh)
1007     {
1008       if ( bDeleteMesh )
1009         delete m_analysis_mesh;
1010       m_analysis_mesh = 0;
1011     }
1012     break;
1013   case ON::preview_mesh:
1014     if (m_preview_mesh)
1015     {
1016       if ( bDeleteMesh )
1017         delete m_preview_mesh;
1018       m_preview_mesh = 0;
1019     }
1020     break;
1021   default:
1022     DestroyMesh( ON::render_mesh );
1023     DestroyMesh( ON::analysis_mesh );
1024     DestroyMesh( ON::preview_mesh );
1025     break;
1026   }
1027 }
1028 
1029 
SizeOf() const1030 unsigned int ON_BrepVertexArray::SizeOf() const
1031 {
1032   unsigned int sz = 0;
1033   int i, count = Count();
1034   for ( i = 0; i < count; i++ )
1035   {
1036     sz += m_a[i].SizeOf();
1037   }
1038   sz += (m_capacity - m_count)*sizeof(m_a[0]);
1039   return sz;
1040 }
1041 
SizeOf() const1042 unsigned int ON_BrepEdgeArray::SizeOf() const
1043 {
1044   unsigned int sz = 0;
1045   int i, count = Count();
1046   for ( i = 0; i < count; i++ )
1047   {
1048     sz += m_a[i].SizeOf();
1049   }
1050   sz += (m_capacity - m_count)*sizeof(m_a[0]);
1051   return sz;
1052 }
1053 
SizeOf() const1054 unsigned int ON_BrepTrimArray::SizeOf() const
1055 {
1056   unsigned int sz = 0;
1057   int i, count = Count();
1058   for ( i = 0; i < count; i++ )
1059   {
1060     sz += m_a[i].SizeOf();
1061   }
1062   sz += (m_capacity - m_count)*sizeof(m_a[0]);
1063   return sz;
1064 }
1065 
SizeOf() const1066 unsigned int ON_BrepLoopArray::SizeOf() const
1067 {
1068   unsigned int sz = 0;
1069   int i, count = Count();
1070   for ( i = 0; i < count; i++ )
1071   {
1072     sz += m_a[i].SizeOf();
1073   }
1074   sz += (m_capacity - m_count)*sizeof(m_a[0]);
1075   return sz;
1076 }
1077 
SizeOf() const1078 unsigned int ON_BrepFaceArray::SizeOf() const
1079 {
1080   unsigned int sz = 0;
1081   int i, count = Count();
1082   for ( i = 0; i < count; i++ )
1083   {
1084     sz += m_a[i].SizeOf();
1085   }
1086   sz += (m_capacity - m_count)*sizeof(m_a[0]);
1087   return sz;
1088 }
1089 
1090 ////////////////////////////////////////////////////////////////
1091 //   Class ON_Brep
1092 ////////////////////////////////////////////////////////////////
1093 
ON_BrepVertexArray()1094 ON_BrepVertexArray::ON_BrepVertexArray()
1095 {}
1096 
~ON_BrepVertexArray()1097 ON_BrepVertexArray::~ON_BrepVertexArray()
1098 {}
1099 
1100 
ON_BrepEdgeArray()1101 ON_BrepEdgeArray::ON_BrepEdgeArray()
1102 {}
1103 
~ON_BrepEdgeArray()1104 ON_BrepEdgeArray::~ON_BrepEdgeArray()
1105 {}
1106 
1107 
ON_BrepTrimArray()1108 ON_BrepTrimArray::ON_BrepTrimArray()
1109 {}
1110 
~ON_BrepTrimArray()1111 ON_BrepTrimArray::~ON_BrepTrimArray()
1112 {}
1113 
1114 
ON_BrepLoopArray()1115 ON_BrepLoopArray::ON_BrepLoopArray()
1116 {}
1117 
~ON_BrepLoopArray()1118 ON_BrepLoopArray::~ON_BrepLoopArray()
1119 {}
1120 
ON_BrepFaceArray()1121 ON_BrepFaceArray::ON_BrepFaceArray()
1122 {}
1123 
~ON_BrepFaceArray()1124 ON_BrepFaceArray::~ON_BrepFaceArray()
1125 {}
1126 
1127 
1128 ON_OBJECT_IMPLEMENT(ON_Brep,ON_Geometry,"60B5DBC5-E660-11d3-BFE4-0010830122F0");
1129 
Initialize()1130 void ON_Brep::Initialize()
1131 {
1132   memset(&m_brep_user,0,sizeof(m_brep_user));
1133   m_is_solid = 0;
1134   m_bbox.Destroy();
1135 }
1136 
New()1137 ON_Brep* ON_Brep::New()
1138 {
1139   // use instead of new ON_Brep()
1140   // (When openNURBS is used as a Windows DLL,
1141   // this forces the call to new to happen in the openNURBS DLL.)
1142   return new ON_Brep();
1143 }
1144 
New(const ON_Brep & src)1145 ON_Brep* ON_Brep::New(const ON_Brep& src)
1146 {
1147   // use instead of new ON_Brep(const ON_Brep&)
1148   // (When openNURBS is used as a Windows DLL,
1149   // this forces the call to new to happen in the openNURBS DLL.)
1150   return new ON_Brep(src);
1151 }
1152 
ON_Brep()1153 ON_Brep::ON_Brep()
1154 {
1155   ON__SET__THIS__PTR(m_s_ON_Brep_ptr);
1156   Initialize();
1157 }
1158 
ON_Brep(const ON_Brep & src)1159 ON_Brep::ON_Brep(const ON_Brep& src) : ON_Geometry(src)
1160 {
1161   ON__SET__THIS__PTR(m_s_ON_Brep_ptr);
1162   Initialize();
1163   *this = src;
1164 }
1165 
~ON_Brep()1166 ON_Brep::~ON_Brep()
1167 {
1168   DestroyMesh(ON::any_mesh,true);
1169   // everything is in array classes that destroy themselves.
1170 }
1171 
SizeOf() const1172 unsigned int ON_Brep::SizeOf() const
1173 {
1174   int i, count;
1175 
1176   unsigned int sz = ON_Geometry::SizeOf();
1177   sz += (sizeof(*this) - sizeof(ON_Geometry));
1178   sz += m_C2.SizeOfArray();
1179   sz += m_C3.SizeOfArray();
1180   sz += m_S.SizeOfArray();
1181 
1182   count = m_C2.Count();
1183   for ( i = 0; i < count; i++ )
1184   {
1185     const ON_Curve* c2 = m_C2[i];
1186     if ( c2 )
1187       sz += c2->SizeOf();
1188   }
1189 
1190   count = m_C3.Count();
1191   for ( i = 0; i < count; i++ )
1192   {
1193     const ON_Curve* c3 = m_C3[i];
1194     if ( c3 )
1195       sz += c3->SizeOf();
1196   }
1197 
1198   count = m_S.Count();
1199   for ( i = 0; i < count; i++ )
1200   {
1201     const ON_Surface* s = m_S[i];
1202     if ( s )
1203       sz += s->SizeOf();
1204   }
1205 
1206   sz += m_V.SizeOf();
1207   sz += m_E.SizeOf();
1208   sz += m_T.SizeOf();
1209   sz += m_L.SizeOf();
1210   sz += m_F.SizeOf();
1211 
1212   return sz;
1213 }
1214 
DataCRC(ON__UINT32 current_remainder) const1215 ON__UINT32 ON_BrepVertex::DataCRC(ON__UINT32 current_remainder) const
1216 {
1217   current_remainder = ON_CRC32(current_remainder,sizeof(m_vertex_index),&m_vertex_index);
1218   current_remainder = ON_CRC32(current_remainder,sizeof(m_tolerance),&m_tolerance);
1219   current_remainder = m_ei.DataCRC(current_remainder);
1220   return current_remainder;
1221 }
1222 
DataCRC(ON__UINT32 current_remainder) const1223 ON__UINT32 ON_BrepEdge::DataCRC(ON__UINT32 current_remainder) const
1224 {
1225   current_remainder = ON_CurveProxy::DataCRC(current_remainder);
1226   current_remainder = ON_CRC32(current_remainder,sizeof(m_edge_index),&m_edge_index);
1227   current_remainder = ON_CRC32(current_remainder,sizeof(m_c3i),&m_c3i);
1228   current_remainder = ON_CRC32(current_remainder,2*sizeof(m_vi[0]),&m_vi[0]);
1229   current_remainder = m_ti.DataCRC(current_remainder);
1230   current_remainder = ON_CRC32(current_remainder,sizeof(m_tolerance),&m_tolerance);
1231 
1232   return current_remainder;
1233 }
1234 
DataCRC(ON__UINT32 current_remainder) const1235 ON__UINT32 ON_BrepFace::DataCRC(ON__UINT32 current_remainder) const
1236 {
1237   current_remainder = ON_SurfaceProxy::DataCRC(current_remainder);
1238   current_remainder = ON_CRC32(current_remainder,sizeof(m_face_index),&m_face_index);
1239   current_remainder = ON_CRC32(current_remainder,sizeof(m_bRev),&m_bRev);
1240   current_remainder = m_li.DataCRC(current_remainder);
1241 
1242   return current_remainder;
1243 }
1244 
DataCRC(ON__UINT32 current_remainder) const1245 ON__UINT32 ON_Brep::DataCRC(ON__UINT32 current_remainder) const
1246 {
1247   current_remainder = m_V.DataCRC(current_remainder);
1248   current_remainder = m_E.DataCRC(current_remainder);
1249   current_remainder = m_F.DataCRC(current_remainder);
1250   return current_remainder;
1251 }
1252 
DestroyMesh(ON::mesh_type mt,bool bDeleteMesh)1253 void ON_Brep::DestroyMesh( ON::mesh_type mt, bool bDeleteMesh )
1254 {
1255   const int fcnt = m_F.Count();
1256   int fi;
1257   for ( fi = 0; fi < fcnt; fi++ ) {
1258     m_F[fi].DestroyMesh(mt,bDeleteMesh);
1259   }
1260 }
1261 
GetMesh(ON::mesh_type mt,ON_SimpleArray<const ON_Mesh * > & meshes) const1262 int ON_Brep::GetMesh( ON::mesh_type mt, ON_SimpleArray<const ON_Mesh*>& meshes ) const
1263 {
1264   int fcnt = m_F.Count();
1265   int fi;
1266   int null_count = 0;
1267   meshes.Reserve( meshes.Count() + fcnt );
1268   for ( fi = 0; fi < fcnt; fi++ )
1269   {
1270     const ON_Mesh* mesh = m_F[fi].Mesh(mt);
1271     meshes.Append( mesh );
1272     if ( !mesh )
1273     {
1274       // If some meshes are missing, we have to put
1275       // a null in the return array so the face-to-mesh
1276       // correspondence is preserved.
1277       null_count++;
1278     }
1279   }
1280   if ( null_count == fcnt )
1281   {
1282     // If ALL the meshes are missing, return 0.
1283     meshes.SetCount(meshes.Count()-fcnt);
1284     fcnt = 0;
1285   }
1286   return fcnt;
1287 }
1288 
1289 
Dimension() const1290 int ON_Brep::Dimension() const
1291 {
1292   return (m_V.Count() > 0) ? 3 : 0;
1293 }
1294 
ON_BrepTransformSwapSrfHelper(ON_Brep & brep,ON_NurbsSurface * nurbs_srf,int si)1295 static void ON_BrepTransformSwapSrfHelper( ON_Brep& brep, ON_NurbsSurface* nurbs_srf, int si )
1296 {
1297   // Replace plane surface which could not be properly transformed
1298   // with nurbs_surface.
1299   ON_Surface* old_srf = brep.m_S[si];
1300   ON_UserDataHolder udholder;
1301   udholder.MoveUserDataFrom(*old_srf);
1302   udholder.MoveUserDataTo(*nurbs_srf,false);
1303   brep.m_S[si] = nurbs_srf;
1304 
1305   // Update faces to use new surface.
1306   const int fcount = brep.m_F.Count();
1307   ON_BrepFace* f = brep.m_F.Array();
1308   for ( int fi = 0; fi < fcount; fi++ )
1309   {
1310     if (f[fi].m_si == si || f[fi].ProxySurface() == old_srf )
1311     {
1312       const bool bIsTransposed = f[fi].ProxySurfaceIsTransposed();
1313       f[fi].SetProxySurface(nurbs_srf);
1314       if (bIsTransposed)
1315         f[fi].ON_SurfaceProxy::Transpose();
1316     }
1317   }
1318 
1319   delete old_srf;
1320 }
1321 
Transform(const ON_Xform & xform)1322 ON_BOOL32 ON_Brep::Transform( const ON_Xform& xform )
1323 {
1324   int i, count;
1325   ON_BOOL32 rc = true;
1326 
1327   DestroyRuntimeCache();
1328 
1329   int is_similarity = xform.IsSimilarity();
1330   double det = xform.Determinant();
1331 
1332   if ( 1 != is_similarity )
1333   {
1334     // this will cause the solid flag to be
1335     // recaclulated the next time it is needed.
1336     m_is_solid = 0;
1337   }
1338 
1339 
1340   // 13 Feb 2003 Dale Lear:
1341   // Transforming the bbox makes it grow too large under repeated
1342   // rotations.  So, we will destroy it here and reset it below.
1343   //m_bbox.Transform(xform);
1344   m_bbox.Destroy();
1345 
1346   count = m_C3.Count();
1347   for ( i = 0; i < count; i++ )
1348   {
1349     if ( m_C3[i] )
1350     {
1351       if ( !m_C3[i]->Transform(xform) )
1352         rc = false;
1353     }
1354   }
1355 
1356   count = m_S.Count();
1357   for ( i = 0; i < count; i++ ) {
1358     if ( m_S[i] )
1359 
1360     {
1361       ON_NurbsSurface* nurbs_srf = 0;
1362       if ( !is_similarity )
1363       {
1364         if (    1 == m_S[i]->Degree(0) // degree tests reduce calls to
1365              && 1 == m_S[i]->Degree(1) // slow ON_PlaneSurface::Cast()
1366              && 0 != ON_PlaneSurface::Cast(m_S[i]) )
1367         {
1368           nurbs_srf = ON_NurbsSurface::New();
1369           if ( !m_S[i]->GetNurbForm(*nurbs_srf) )
1370           {
1371             delete nurbs_srf;
1372             nurbs_srf = 0;
1373           }
1374           else if ( !nurbs_srf->Transform(xform) )
1375           {
1376             delete nurbs_srf;
1377             nurbs_srf = 0;
1378           }
1379         }
1380       }
1381 
1382       if ( !m_S[i]->Transform(xform) )
1383       {
1384         if ( nurbs_srf )
1385         {
1386           ON_BrepTransformSwapSrfHelper(*this,nurbs_srf,i);
1387           nurbs_srf = 0;
1388         }
1389         else
1390         {
1391           rc = false;
1392         }
1393       }
1394       else if ( nurbs_srf )
1395       {
1396         // make sure transformation was good
1397         ON_Interval u = nurbs_srf->Domain(0);
1398         ON_Interval v = nurbs_srf->Domain(1);
1399         for ( int ui = 0; ui < 2 && nurbs_srf; ui++ ) for (int vi = 0; vi < 2 && nurbs_srf; vi++)
1400         {
1401           ON_3dPoint P = nurbs_srf->PointAt(u[ui],v[vi]);
1402           ON_3dPoint Q = m_S[i]->PointAt(u[ui],v[vi]);
1403           if ( P.DistanceTo(Q) > ON_ZERO_TOLERANCE )
1404           {
1405             ON_BrepTransformSwapSrfHelper(*this,nurbs_srf,i);
1406             nurbs_srf = 0;
1407             break;
1408           }
1409         }
1410         if ( nurbs_srf )
1411         {
1412           delete nurbs_srf;
1413           nurbs_srf = 0;
1414         }
1415       }
1416     }
1417   }
1418 
1419   count = m_V.Count();
1420   for ( i = 0; i < count; i++ ) {
1421     if ( !m_V[i].Transform(xform) )
1422       rc = false;
1423   }
1424 
1425   count = m_E.Count();
1426   for ( i = 0; i < count; i++ ) {
1427     m_E[i].TransformUserData(xform);
1428   }
1429 
1430   count = m_F.Count();
1431   for ( i = 0; i < count; i++ )
1432   {
1433     ON_BrepFace& face = m_F[i];
1434     face.TransformUserData(xform);
1435 
1436     // 13 Feb 2003 Dale Lear:
1437     // Transforming the bbox makes it grow too large under repeated
1438     // rotations.  So, we need to reset it.
1439     face.m_bbox.Destroy();
1440     const ON_Surface* srf = face.SurfaceOf();
1441     if ( 0 != srf )
1442     {
1443       face.m_bbox = srf->BoundingBox();
1444       if ( face.m_face_index != -1 )
1445         m_bbox.Union( face.m_bbox );
1446     }
1447 
1448     // 12 May 2003 Dale Lear - RR 10528
1449     //     Use surface evaluation to update rendermesh when
1450     //     calling ON_Mesh::Transform() will map mesh normals
1451     //     to some thing different that the "true" surface
1452     //     normal.
1453     bool bEvMesh = ( fabs(det) <= ON_SQRT_EPSILON
1454                      || xform[3][0] != 0.0
1455                      || xform[3][1] != 0.0
1456                      || xform[3][2] != 0.0
1457                      || xform[3][3] != 1.0
1458                      );
1459     if ( 0 == srf )
1460       bEvMesh = false;
1461 
1462     if ( 0 != face.m_render_mesh )
1463     {
1464       if ( bEvMesh && face.m_render_mesh->EvaluateMeshGeometry(*srf) )
1465       {
1466         if ( face.m_bRev )
1467         {
1468           // 29 September 2003 Dale Lear
1469           //     Normals on render meshes (and face orientations)
1470           //     take face.m_bRev into account so that two sided
1471           //     materials work as expected.  EvaluateMeshGeometry()
1472           //     does not take face.m_bRev into account, so we need
1473           //     to reverse the face normals here.
1474           int ni, ncnt = face.m_render_mesh->m_N.Count();
1475           for ( ni = 0; ni < ncnt; ni++ )
1476           {
1477             face.m_render_mesh->m_N[ni].Reverse();
1478           }
1479         }
1480       }
1481       else
1482         face.m_render_mesh->Transform(xform);
1483     }
1484 
1485     if ( 0 != face.m_analysis_mesh )
1486     {
1487       // Dale Lear 30 March 2009 - bug 46766
1488       //   Evaluate analysis meshes when the transform involves scaling
1489       //   so curvature values are properly updated.
1490       bool bEvAnalysisMesh = bEvMesh;
1491       if ( !bEvAnalysisMesh )
1492       {
1493         ON_Xform tmp(xform);
1494         tmp.m_xform[0][3] = 0.0;
1495         tmp.m_xform[1][3] = 0.0;
1496         tmp.m_xform[2][3] = 0.0;
1497         if ( 1 != tmp.IsSimilarity() )
1498           bEvAnalysisMesh = true;
1499       }
1500       if ( bEvAnalysisMesh && face.m_analysis_mesh->EvaluateMeshGeometry(*srf) )
1501       {
1502         // 28 Sept 2012, Mikko:
1503         // Apply the "29 September 2003 Dale Lear" fix above also to analysis meshes.
1504         if ( face.m_bRev )
1505         {
1506           int ni, ncnt = face.m_analysis_mesh->m_N.Count();
1507           for ( ni = 0; ni < ncnt; ni++ )
1508           {
1509             face.m_analysis_mesh->m_N[ni].Reverse();
1510           }
1511         }
1512       }
1513       else
1514         face.m_analysis_mesh->Transform(xform);
1515     }
1516 
1517     if ( 0 != face.m_preview_mesh )
1518     {
1519       if ( bEvMesh && face.m_preview_mesh->EvaluateMeshGeometry(*srf) )
1520       {
1521         if ( face.m_bRev )
1522         {
1523           int ni, ncnt = face.m_analysis_mesh->m_N.Count();
1524           for ( ni = 0; ni < ncnt; ni++ )
1525           {
1526             face.m_analysis_mesh->m_N[ni].Reverse();
1527           }
1528         }
1529       }
1530       else
1531         face.m_preview_mesh->Transform(xform);
1532 
1533     }
1534   }
1535 
1536   // The call to transform user data needs to be last
1537   // so that the rest of the brep is in position.
1538   // In particular, ON_BrepRegionTopologyUserData::Transform
1539   // assumes the face bounding boxes are up to date.
1540   TransformUserData(xform);
1541 
1542   return rc;
1543 }
1544 
1545 /////////////////////////////////////////////////////////////////
1546 // ON_Brep Creation Interface
1547 
1548 int
AddTrimCurve(ON_Curve * pC)1549 ON_Brep::AddTrimCurve( ON_Curve* pC )
1550 {
1551   int c2i = -1;
1552 
1553   if ( 0 != pC )
1554   {
1555     // 7 April 2003 Dale Lear:
1556     //    There are too many cases where bugs are caused by
1557     //    people attempting to use 3d curves for trims.  In
1558     //    all the cases encountered so far, the intent was
1559     //    to pass in a 2d curve, so...
1560 
1561     int dim = pC->Dimension();
1562 
1563     if ( dim != 2 )
1564     {
1565       ON_ERROR("ON_Brep::AddTrimCurve() go a non-2d curve - changing dim to 2.");
1566       pC->ChangeDimension(2);
1567       dim = pC->Dimension();
1568     }
1569 
1570     if ( 2 == dim )
1571     {
1572       c2i = m_C2.Count();
1573       m_C2.Append(pC);
1574     }
1575   }
1576   return c2i;
1577 }
1578 
1579 int
AddEdgeCurve(ON_Curve * pC)1580 ON_Brep::AddEdgeCurve( ON_Curve* pC )
1581 {
1582   int c3i = -1;
1583   if ( 0 != pC )
1584   {
1585 
1586     int dim = pC->Dimension();
1587 
1588     if ( dim != 3 )
1589     {
1590       // 7 April 2003 Dale Lear: (See comment in ON_Brep::AddTrimCurve().)
1591       ON_ERROR("ON_Brep::AddEdgeCurve() got a non-3d curve - changing dim to 3.");
1592       pC->ChangeDimension(3);
1593       dim = pC->Dimension();
1594     }
1595 
1596     if ( 3 == dim )
1597     {
1598       c3i = m_C3.Count();
1599       m_C3.Append(pC);
1600     }
1601   }
1602   return c3i;
1603 }
1604 
1605 int
AddSurface(ON_Surface * pS)1606 ON_Brep::AddSurface( ON_Surface* pS )
1607 {
1608   int si = -1;
1609   if ( pS && pS->Dimension() == 3 )
1610   {
1611     si = m_S.Count();
1612     m_S.Append(pS);
1613   }
1614   m_bbox.Destroy();
1615   m_is_solid = 0;
1616   return si;
1617 }
1618 
1619 ON_BrepVertex&
NewVertex()1620 ON_Brep::NewVertex()
1621 {
1622   int vi = m_V.Count();
1623   m_V.Reserve(vi+1);
1624   m_V.SetCount(vi+1);
1625   ON_BrepVertex& vertex = m_V.Array()[vi];
1626   vertex.m_vertex_index = vi;
1627   vertex.point = ON_UNSET_POINT;
1628   vertex.m_tolerance = ON_UNSET_VALUE;
1629   return vertex;
1630 }
1631 
1632 ON_BrepVertex&
NewVertex(ON_3dPoint vertex_point,double vertex_tolerance)1633 ON_Brep::NewVertex( ON_3dPoint vertex_point, double vertex_tolerance )
1634 {
1635   ON_BrepVertex& vertex = NewVertex();
1636   vertex.point = vertex_point;
1637   vertex.m_tolerance = vertex_tolerance;
1638   return vertex;
1639 }
1640 
1641 ON_BrepEdge&
NewEdge(int c3i)1642 ON_Brep::NewEdge( int c3i )
1643 {
1644   int ei = m_E.Count();
1645   ON_BrepEdge& edge = m_E.AppendNew();
1646   edge.m_tolerance = ON_UNSET_VALUE;
1647   edge.m_edge_index = ei;
1648   edge.m_c3i = c3i;
1649   if ( edge.m_c3i >= 0 && edge.m_c3i < m_C3.Count() )
1650   {
1651     edge.SetProxyCurve(m_C3[edge.m_c3i]);
1652   }
1653   edge.m_brep = this;
1654   return edge;
1655 }
1656 
1657 ON_BrepEdge&
NewEdge(ON_BrepVertex & v0,ON_BrepVertex & v1,int c3i,const ON_Interval * edomain,double edge_tolerance)1658 ON_Brep::NewEdge( ON_BrepVertex& v0, ON_BrepVertex& v1,
1659                   int c3i, const ON_Interval* edomain,
1660                   double edge_tolerance )
1661 {
1662   ON_BrepEdge& edge = NewEdge(c3i);
1663   edge.m_vi[0] = v0.m_vertex_index;
1664   edge.m_vi[1] = v1.m_vertex_index;
1665   v0.m_ei.Append(edge.m_edge_index);
1666   v1.m_ei.Append(edge.m_edge_index);
1667   if ( edomain && edomain->IsIncreasing() ) {
1668     ON_Interval edom;
1669     edom.Intersection( edge.ProxyCurveDomain(), *edomain );
1670     if ( edom.IsIncreasing() )
1671       edge.SetProxyCurveDomain(edom);
1672   }
1673   edge.m_tolerance = edge_tolerance;
1674   return edge;
1675 }
1676 
SetEdgeCurve(ON_BrepEdge & edge,int c3_index,const ON_Interval * sub_domain)1677 bool ON_Brep::SetEdgeCurve(
1678   ON_BrepEdge& edge,
1679   int c3_index,
1680   const ON_Interval* sub_domain
1681   )
1682 {
1683   bool rc = false;
1684   if ( c3_index == - 1 && !sub_domain )
1685   {
1686     edge.m_c3i = -1;
1687     edge.SetProxyCurve(0);
1688     rc = true;
1689   }
1690   else if ( c3_index >= 0 && c3_index <= m_C3.Count() && m_C3[c3_index] )
1691   {
1692     ON_Interval curve_domain = m_C3[c3_index]->Domain();
1693     if ( !sub_domain || (sub_domain->IsIncreasing() && curve_domain.Includes(*sub_domain)) )
1694     {
1695       edge.m_c3i = c3_index;
1696       edge.SetProxyCurve( m_C3[c3_index],
1697                           (sub_domain) ? *sub_domain : curve_domain
1698                           );
1699       rc = true;
1700     }
1701   }
1702   return rc;
1703 }
1704 
SetTrimCurve(ON_BrepTrim & trim,int c2_index,const ON_Interval * sub_domain)1705 bool ON_Brep::SetTrimCurve(
1706   ON_BrepTrim& trim,
1707   int c2_index,
1708   const ON_Interval* sub_domain
1709   )
1710 {
1711   bool rc = false;
1712   if ( c2_index == - 1 && !sub_domain )
1713   {
1714     trim.m_c2i = -1;
1715     trim.SetProxyCurve(0);
1716     rc = true;
1717   }
1718   else if ( c2_index >= 0 && c2_index <= m_C2.Count() && m_C2[c2_index] )
1719   {
1720     ON_Interval curve_domain = m_C2[c2_index]->Domain();
1721     if ( !sub_domain || (sub_domain->IsIncreasing() && curve_domain.Includes(*sub_domain)) )
1722     {
1723       trim.m_c2i = c2_index;
1724       trim.SetProxyCurve( m_C2[trim.m_c2i], (sub_domain) ? *sub_domain : curve_domain );
1725       trim.m_pbox = m_C2[trim.m_c2i]->BoundingBox();
1726       trim.m_pbox.m_min.z = 0.0;
1727       trim.m_pbox.m_max.z = 0.0;
1728       rc = true;
1729     }
1730   }
1731   return rc;
1732 }
1733 
1734 ON_BrepTrim&
NewTrim(int c2i)1735 ON_Brep::NewTrim( int c2i )
1736 {
1737   m_is_solid = 0;
1738   int ti = m_T.Count();
1739   ON_BrepTrim& trim = m_T.AppendNew();
1740   trim.m_brep = this;
1741   trim.m_trim_index = ti;
1742   trim.m_ei = -1;
1743   trim.m_type = ON_BrepTrim::unknown;
1744   trim.m_bRev3d = false;
1745   trim.m_c2i = c2i;
1746   trim.m_iso = ON_Surface::not_iso;
1747   trim.m_li = -1;
1748   trim.m_tolerance[0] = ON_UNSET_VALUE;
1749   trim.m_tolerance[1] = ON_UNSET_VALUE;
1750   trim.m__legacy_2d_tol = ON_UNSET_VALUE;
1751   trim.m__legacy_3d_tol = ON_UNSET_VALUE;
1752   trim.m__legacy_flags = 0;
1753   const ON_Curve* c2 = (c2i >= 0 && c2i < m_C2.Count())
1754                      ? m_C2[c2i]
1755                      : 0;
1756   if ( c2 )
1757   {
1758     trim.SetProxyCurve( c2 );
1759     trim.m_pbox = c2->BoundingBox();
1760     trim.m_pbox.m_min.z = 0.0;
1761     trim.m_pbox.m_max.z = 0.0;
1762   }
1763 
1764   return trim;
1765 }
1766 
1767 ON_BrepTrim&
NewTrim(ON_BrepEdge & edge,ON_BOOL32 bRev3d,int c2i)1768 ON_Brep::NewTrim( ON_BrepEdge& edge, ON_BOOL32 bRev3d, int c2i )
1769 {
1770   m_is_solid = 0;
1771   ON_BrepTrim& trim = NewTrim( c2i );
1772   trim.m_ei = edge.m_edge_index;
1773   edge.m_ti.Append(trim.m_trim_index);
1774   trim.m_vi[0] = edge.m_vi[bRev3d?1:0];
1775   trim.m_vi[1] = edge.m_vi[bRev3d?0:1];
1776   trim.m_bRev3d = bRev3d?true:false;
1777   return trim;
1778 }
1779 
1780 
1781 ON_BrepTrim&
NewTrim(ON_BrepEdge & edge,ON_BOOL32 bRev3d,ON_BrepLoop & loop,int c2i)1782 ON_Brep::NewTrim( ON_BrepEdge& edge, ON_BOOL32 bRev3d, ON_BrepLoop& loop, int c2i )
1783 {
1784   m_is_solid = 0;
1785   const int edge_trim_count0 = edge.m_ti.Count();
1786   ON_BrepTrim& trim = NewTrim( edge, bRev3d, c2i );
1787   trim.m_li = loop.m_loop_index;
1788   loop.m_ti.Append(trim.m_trim_index);
1789   if ( c2i >= 0 && c2i < m_C2.Count() )
1790   {
1791     ON_Curve* c2 = m_C2[c2i];
1792     if ( c2 )
1793     {
1794       ON_BoundingBox c2_bbox;
1795       if ( c2->GetBoundingBox(c2_bbox) )
1796       {
1797         c2_bbox.m_min.z = 0.0;
1798         c2_bbox.m_max.z = 0.0;
1799         if ( loop.m_ti.Count() == 1 )
1800           loop.m_pbox = c2_bbox;
1801         else
1802           loop.m_pbox.Union(c2_bbox);
1803       }
1804     }
1805   }
1806 
1807   if ( edge_trim_count0 == 0 )
1808   {
1809     // This is the only trim using this edge.
1810     //
1811     // At the moment it's a boundary trim.  The type
1812     // will be changed to seam or mated when
1813     // another trim is added that uses this edge.
1814     trim.m_type = ON_BrepTrim::boundary;
1815   }
1816   else if ( edge_trim_count0 == 1 )
1817   {
1818     // there are now two trims using this edge
1819     ON_BrepTrim::TYPE trim_type = ON_BrepTrim::mated;
1820     ON_BrepTrim& other_trim = m_T[edge.m_ti[0]];
1821     if ( other_trim.m_li == loop.m_loop_index )
1822       trim_type = ON_BrepTrim::seam;
1823     else
1824       trim_type = ON_BrepTrim::mated;
1825     trim.m_type = trim_type;
1826     other_trim.m_type = trim_type;
1827   }
1828   else
1829   {
1830     // non-manifold edge - need to check for mated or seam
1831     ON_BrepTrim::TYPE trim_type = ON_BrepTrim::mated;
1832     for ( int eti = 0; eti < edge_trim_count0; eti++ )
1833     {
1834       ON_BrepTrim& other_trim = m_T[edge.m_ti[eti]];
1835       if ( other_trim.m_li == loop.m_loop_index )
1836       {
1837         other_trim.m_type = ON_BrepTrim::seam;
1838         trim_type = ON_BrepTrim::seam;
1839         break;
1840       }
1841     }
1842     trim.m_type = trim_type;
1843   }
1844   return trim;
1845 }
1846 
1847 
1848 ON_BrepTrim&
NewTrim(ON_BOOL32 bRev3d,ON_BrepLoop & loop,int c2i)1849 ON_Brep::NewTrim( ON_BOOL32 bRev3d, ON_BrepLoop& loop, int c2i )
1850 {
1851   m_is_solid = 0;
1852   ON_BrepTrim& trim = NewTrim( c2i );
1853   trim.m_bRev3d = bRev3d ? true : false;
1854   trim.m_li = loop.m_loop_index;
1855   loop.m_ti.Append(trim.m_trim_index);
1856   if ( c2i >= 0 && c2i < m_C2.Count() )
1857   {
1858     const ON_Curve* c2 = m_C2[c2i];
1859     if ( c2 )
1860     {
1861       ON_BoundingBox c2_bbox;
1862       if ( c2->GetBoundingBox(c2_bbox) )
1863       {
1864         c2_bbox.m_min.z = 0.0;
1865         c2_bbox.m_max.z = 0.0;
1866         if ( loop.m_ti.Count() == 1 )
1867           loop.m_pbox = c2_bbox;
1868         else
1869           loop.m_pbox.Union( c2_bbox );
1870       }
1871     }
1872   }
1873   return trim;
1874 }
1875 
1876 ON_BrepTrim&
NewSingularTrim(const ON_BrepVertex & vertex,ON_BrepLoop & loop,ON_Surface::ISO iso,int c2i)1877 ON_Brep::NewSingularTrim(const ON_BrepVertex& vertex,ON_BrepLoop& loop, ON_Surface::ISO iso, int c2i)
1878 {
1879   ON_BrepTrim& trim = NewTrim(false,loop,c2i);
1880   trim.m_vi[0] = vertex.m_vertex_index;
1881   trim.m_vi[1] = trim.m_vi[0];
1882   trim.m_type = ON_BrepTrim::singular;
1883   trim.m_iso = iso;
1884   trim.m_tolerance[0] = 0.0;
1885   trim.m_tolerance[1] = 0.0;
1886   trim.m__legacy_2d_tol = 0.0;
1887   trim.m__legacy_3d_tol = 0.0;
1888   trim.m__legacy_flags_Set(-1,1);
1889   return trim;
1890 }
1891 
Append(const ON_Brep & b)1892 void ON_Brep::Append( const ON_Brep& b )
1893 {
1894   int i, j, jcnt;
1895 
1896   const int vcount0  = m_V.Count();
1897   const int ecount0  = m_E.Count();
1898   const int fcount0  = m_F.Count();
1899   const int tcount0  = m_T.Count();
1900   const int lcount0  = m_L.Count();
1901   const int c2count0 = m_C2.Count();
1902   const int c3count0 = m_C3.Count();
1903   const int scount0  = m_S.Count();
1904 
1905   const int vcount1  = b.m_V.Count();
1906   const int ecount1  = b.m_E.Count();
1907   const int fcount1  = b.m_F.Count();
1908   const int tcount1  = b.m_T.Count();
1909   const int lcount1  = b.m_L.Count();
1910   const int c2count1 = b.m_C2.Count();
1911   const int c3count1 = b.m_C3.Count();
1912   const int scount1  = b.m_S.Count();
1913 
1914   // need to duplicate geometry
1915   ON_Object* obj;
1916   ON_Curve* c;
1917   ON_Surface* s;
1918   for ( i = 0; i < scount1; i++ ) {
1919     s = b.m_S[i];
1920     if ( s ) {
1921       obj = s->Duplicate();
1922       s = ON_Surface::Cast(obj);
1923       if ( !s )
1924         delete obj;
1925     }
1926     m_S.Append(s);
1927   }
1928   for ( i = 0; i < c2count1; i++ ) {
1929     c = b.m_C2[i];
1930     if ( c ) {
1931       obj = c->Duplicate();
1932       c = ON_Curve::Cast(obj);
1933       if ( !c )
1934         delete obj;
1935     }
1936     m_C2.Append(c);
1937   }
1938   for ( i = 0; i < c3count1; i++ ) {
1939     c = b.m_C3[i];
1940     if ( c ) {
1941       obj = c->Duplicate();
1942       c = ON_Curve::Cast(obj);
1943       if ( !c )
1944         delete obj;
1945     }
1946     m_C3.Append(c);
1947   }
1948 
1949   // copy topology info
1950   m_V.Append( b.m_V.Count(), b.m_V.Array() );
1951   m_E.Append( b.m_E.Count(), b.m_E.Array() );
1952   m_F.Append( b.m_F.Count(), b.m_F.Array() );
1953   m_T.Append( b.m_T.Count(), b.m_T.Array() );
1954   m_L.Append( b.m_L.Count(), b.m_L.Array() );
1955 
1956   // update indices
1957   for ( i = 0; i < vcount1; i++ ) {
1958     ON_BrepVertex& vertex = m_V[vcount0+i];
1959     if ( vertex.m_vertex_index >= 0 )
1960       vertex.m_vertex_index += vcount0;
1961     else
1962       vertex.m_vertex_index = -1;
1963     jcnt = vertex.m_ei.Count();
1964     for ( j = 0; j < jcnt; j++ ) {
1965       if ( vertex.m_ei[j] >=0 )
1966         vertex.m_ei[j] += ecount0;
1967     }
1968   }
1969 
1970   for ( i = 0; i < ecount1; i++ )
1971   {
1972     ON_BrepEdge& edge = m_E[ecount0+i];
1973     if ( edge.m_edge_index >= 0 )
1974       edge.m_edge_index += ecount0;
1975     else
1976       edge.m_edge_index = -1;
1977     if ( edge.m_c3i >= 0 )
1978       edge.m_c3i += c3count0;
1979     if ( edge.m_vi[0] >= 0 )
1980       edge.m_vi[0] += vcount0;
1981     if ( edge.m_vi[1] >= 0 )
1982       edge.m_vi[1] += vcount0;
1983     jcnt = edge.m_ti.Count();
1984     for ( j = 0; j < jcnt; j++ ) {
1985       if ( edge.m_ti[j] >= 0 )
1986         edge.m_ti[j] += tcount0;
1987     }
1988     edge.m_brep = this;
1989     if (edge.m_c3i >= 0)
1990       edge.SetProxyCurve( m_C3[edge.m_c3i], b.m_E[i].ProxyCurveDomain() );
1991     else
1992       edge.SetProxyCurve( 0, b.m_E[i].ProxyCurveDomain() );
1993     if ( b.m_E[i].ProxyCurveIsReversed() != edge.ProxyCurveIsReversed() )
1994       edge.ON_CurveProxy::Reverse();
1995     edge.SetDomain( b.m_E[i].Domain() );
1996   }
1997 
1998   for ( i = 0; i < tcount1; i++ ) {
1999     ON_BrepTrim& trim = m_T[tcount0+i];
2000     trim.m_brep = this;
2001     if ( trim.m_trim_index == i )
2002       trim.m_trim_index = tcount0+i;
2003     else
2004       trim.m_trim_index = -1;
2005     if ( trim.m_c2i >= 0 )
2006       trim.m_c2i += c2count0;
2007     if ( trim.m_ei >= 0 )
2008       trim.m_ei += ecount0;
2009     if ( trim.m_vi[0] >= 0 )
2010       trim.m_vi[0] += vcount0;
2011     if ( trim.m_vi[1] >= 0 )
2012       trim.m_vi[1] += vcount0;
2013     if ( trim.m_li >= 0 )
2014       trim.m_li += lcount0;
2015     if (trim.m_c2i >= 0)
2016       trim.SetProxyCurve( m_C2[trim.m_c2i], b.m_T[i].ProxyCurveDomain() );
2017     else
2018       trim.SetProxyCurve( 0, b.m_T[i].ProxyCurveDomain() );
2019     if ( b.m_T[i].ProxyCurveIsReversed() != trim.ProxyCurveIsReversed() )
2020       trim.ON_CurveProxy::Reverse();
2021     trim.SetDomain( b.m_T[i].Domain() );
2022   }
2023 
2024   for ( i = 0; i < lcount1; i++ )
2025   {
2026     ON_BrepLoop& loop = m_L[lcount0+i];
2027     if ( loop.m_loop_index >= 0 )
2028       loop.m_loop_index += lcount0;
2029     else
2030       loop.m_loop_index = -1;
2031     jcnt = loop.m_ti.Count();
2032     for ( j = 0; j < jcnt; j++ ) {
2033       if ( loop.m_ti[j] >= 0)
2034         loop.m_ti[j] += tcount0;
2035     }
2036     if ( loop.m_fi >= 0 )
2037       loop.m_fi += fcount0;
2038     loop.m_brep = this;
2039   }
2040 
2041   for ( i = 0; i < fcount1; i++ ) {
2042     ON_BrepFace& face = m_F[fcount0+i];
2043     if ( face.m_face_index >= 0 )
2044       face.m_face_index += fcount0;
2045     else
2046       face.m_face_index = -1;
2047     jcnt = face.m_li.Count();
2048     for ( j = 0; j < jcnt; j++ ) {
2049       if ( face.m_li[j] >= 0 )
2050         face.m_li[j] += lcount0;
2051     }
2052     if ( face.m_si >= 0 )
2053     {
2054       face.m_si += scount0;
2055       face.SetProxySurface(m_S[face.m_si]);
2056     }
2057     else
2058     {
2059       face.SetProxySurface( 0 );
2060     }
2061     face.m_brep = this;
2062   }
2063 
2064   //grow bounding box if possible.  otherwise invalidate it.
2065   if (m_bbox.IsValid() && b.BoundingBox().IsValid())
2066     m_bbox.Union(b.BoundingBox());
2067   else m_bbox.Destroy();
2068 
2069   m_is_solid = 0;
2070 
2071   DestroyMesh(ON::any_mesh);
2072 
2073   return;
2074 }
2075 
2076 ON_BrepLoop&
NewLoop(ON_BrepLoop::TYPE looptype)2077 ON_Brep::NewLoop( ON_BrepLoop::TYPE looptype )
2078 {
2079   m_is_solid = 0;
2080   int li = m_L.Count();
2081   m_L.Reserve(li+1);
2082   m_L.SetCount(li+1);
2083   ON_BrepLoop& loop =  m_L.Array()[li];
2084   loop.m_loop_index = li;
2085   loop.m_type = looptype;
2086   loop.m_brep = this;
2087   return loop;
2088 }
2089 
2090 ON_BrepLoop&
NewLoop(ON_BrepLoop::TYPE looptype,ON_BrepFace & face)2091 ON_Brep::NewLoop( ON_BrepLoop::TYPE looptype, ON_BrepFace& face )
2092 {
2093   m_is_solid = 0;
2094   ON_BrepLoop& loop = NewLoop( looptype );
2095   loop.m_fi = face.m_face_index;
2096   if ( ON_BrepLoop::outer == looptype )
2097   {
2098     // the index of the outer loop is always
2099     // in face.m_li[0]
2100     face.m_li.Insert(0,loop.m_loop_index);
2101   }
2102   else
2103   {
2104     face.m_li.Append(loop.m_loop_index);
2105   }
2106   loop.m_brep = this;
2107   return loop;
2108 }
2109 
NewOuterLoop(int face_index)2110 ON_BrepLoop* ON_Brep::NewOuterLoop( int face_index )
2111 {
2112   m_is_solid = 0;
2113   int vid[4] = {-1,-1,-1,-1};
2114   int eid[4] = {-1,-1,-1,-1};
2115   ON_BOOL32 bRev3d[4] = {0,0,0,0};
2116   return NewOuterLoop( face_index,vid,eid,bRev3d);
2117 }
2118 
NewFace(int si)2119 ON_BrepFace& ON_Brep::NewFace( int si )
2120 {
2121   m_bbox.Destroy();
2122   m_is_solid = 0;
2123   int fi = m_F.Count();
2124   m_F.Reserve(fi+1);
2125   m_F.SetCount(fi+1);
2126   ON_BrepFace& face = m_F.Array()[fi];
2127   face.m_face_index = fi;
2128   face.m_si = si;
2129   face.m_brep = this;
2130   if ( si >= 0 && si < m_S.Count() )
2131   {
2132     face.SetProxySurface(m_S[si]);
2133     if ( face.ProxySurface() )
2134       face.m_bbox = face.ProxySurface()->BoundingBox();
2135   }
2136   return face;
2137 }
2138 
NewFace(const ON_Surface & surface)2139 ON_BrepFace* ON_Brep::NewFace( const ON_Surface& surface )
2140 {
2141   m_bbox.Destroy();
2142   m_is_solid = 0;
2143   ON_BrepFace* face = NULL;
2144   ON_Surface* pSurface = surface.DuplicateSurface();
2145   if ( pSurface )
2146   {
2147     int vid[4] = {-1,-1,-1,-1};
2148     int eid[4] = {-1,-1,-1,-1};
2149     ON_BOOL32 bRev3d[4] = {0,0,0,0};
2150     face = NewFace(pSurface,vid,eid,bRev3d);
2151   }
2152   return face;
2153 }
2154 
2155 
2156 
2157 bool
SetTrimIsoFlags()2158 ON_Brep::SetTrimIsoFlags()
2159 {
2160   bool rc = true;
2161   int fi;
2162   const int fcnt = m_F.Count();
2163   for ( fi = 0; fi < fcnt; fi++ ) {
2164     if ( !SetTrimIsoFlags( m_F[fi] ) )
2165       rc = false;
2166   }
2167   return rc;
2168 }
2169 
2170 bool
SetTrimIsoFlags(ON_BrepFace & face)2171 ON_Brep::SetTrimIsoFlags( ON_BrepFace& face )
2172 {
2173   bool rc = true;
2174   int fli;
2175   const int face_loop_count = face.m_li.Count();
2176   for ( fli = 0; fli < face_loop_count; fli++ ) {
2177     if ( !SetTrimIsoFlags( m_L[face.m_li[fli]] ) )
2178       rc = false;
2179   }
2180   return rc;
2181 }
2182 
2183 bool
SetTrimIsoFlags(ON_BrepLoop & loop)2184 ON_Brep::SetTrimIsoFlags( ON_BrepLoop& loop )
2185 {
2186   bool rc = true;
2187   int lti;
2188   const int loop_trim_count = loop.m_ti.Count();
2189   for ( lti = 0; lti < loop_trim_count; lti++ ) {
2190     if ( !SetTrimIsoFlags( m_T[loop.m_ti[lti]] ) )
2191       rc = false;
2192   }
2193   return rc;
2194 }
2195 
2196 bool
SetTrimIsoFlags(ON_BrepTrim & trim)2197 ON_Brep::SetTrimIsoFlags( ON_BrepTrim& trim )
2198 {
2199   bool rc = false;
2200   if ( trim.m_li >= 0 && trim.m_li < m_L.Count() )
2201   {
2202     const int fi = m_L[trim.m_li].m_fi;
2203     if ( fi >= 0 && fi < m_F.Count() )
2204     {
2205       const ON_Surface* pS = m_F[fi].SurfaceOf();
2206       if ( pS )
2207       {
2208         const ON_Curve* pC = (trim.m_c2i >= 0 && trim.m_c2i < m_C2.Count())
2209                            ? m_C2[trim.m_c2i]
2210                            : 0;
2211         if ( pC )
2212         {
2213           ON_Interval PD = trim.ProxyCurveDomain();
2214           trim.m_iso = pS->IsIsoparametric( *pC, &PD);
2215           rc = true;
2216         }
2217       }
2218     }
2219   }
2220   return rc;
2221 }
2222 
2223 bool
SetTrimTypeFlags(ON_BOOL32 bLazy)2224 ON_Brep::SetTrimTypeFlags( ON_BOOL32 bLazy )
2225 {
2226   bool rc = true;
2227   int fi;
2228   const int fcnt = m_F.Count();
2229   for ( fi = 0; fi < fcnt; fi++ ) {
2230     if ( !SetTrimTypeFlags( m_F[fi], bLazy ) )
2231       rc = false;
2232   }
2233   return rc;
2234 }
2235 
2236 bool
SetTrimTypeFlags(ON_BrepFace & face,ON_BOOL32 bLazy)2237 ON_Brep::SetTrimTypeFlags( ON_BrepFace& face, ON_BOOL32 bLazy )
2238 {
2239   bool rc = true;
2240   int fli;
2241   const int face_loop_count = face.m_li.Count();
2242   for ( fli = 0; fli < face_loop_count; fli++ ) {
2243     if ( !SetTrimTypeFlags( m_L[face.m_li[fli]], bLazy ) )
2244       rc = false;
2245   }
2246   return rc;
2247 }
2248 
2249 bool
SetTrimTypeFlags(ON_BrepLoop & loop,ON_BOOL32 bLazy)2250 ON_Brep::SetTrimTypeFlags( ON_BrepLoop& loop, ON_BOOL32 bLazy )
2251 {
2252   bool rc = true;
2253   int lti;
2254   const int loop_trim_count = loop.m_ti.Count();
2255   for ( lti = 0; lti < loop_trim_count; lti++ ) {
2256     if ( !SetTrimTypeFlags( m_T[loop.m_ti[lti]], bLazy ) )
2257       rc = false;
2258   }
2259   return rc;
2260 }
2261 
TrimType(const ON_BrepTrim & trim,ON_BOOL32 bLazy) const2262 ON_BrepTrim::TYPE ON_Brep::TrimType( const ON_BrepTrim& trim, ON_BOOL32 bLazy ) const
2263 {
2264   ON_BrepTrim::TYPE trim_type = bLazy ? trim.m_type : ON_BrepTrim::unknown;
2265   int eti, other_ti;
2266 
2267   if ( trim_type == ON_BrepTrim::unknown && trim.m_li >= 0 && trim.m_li < m_L.Count() )
2268   {
2269     const ON_BrepLoop& loop = m_L[trim.m_li];
2270     if ( loop.m_type == ON_BrepLoop::ptonsrf )
2271       trim_type = ON_BrepTrim::ptonsrf;
2272     else if (loop.m_type == ON_BrepLoop::crvonsrf )
2273       trim_type = ON_BrepTrim::crvonsrf;
2274     else if ( trim.m_ei == -1 )
2275     {
2276       trim_type = ON_BrepTrim::singular;
2277     }
2278     else if ( trim.m_ei >= 0 && trim.m_ei < m_E.Count() )
2279     {
2280       const ON_BrepEdge& edge = m_E[trim.m_ei];
2281       if ( edge.m_ti.Count() == 1 && edge.m_ti[0] == trim.m_trim_index )
2282       {
2283         trim_type = ON_BrepTrim::boundary;
2284       }
2285       else if ( edge.m_ti.Count() > 1 )
2286       {
2287         trim_type = ON_BrepTrim::mated;
2288         // check for seam
2289         for ( eti = 0; eti < edge.m_ti.Count(); eti++ )
2290         {
2291           other_ti = edge.m_ti[eti];
2292           if ( other_ti != trim.m_trim_index && other_ti >= 0 && other_ti < m_T.Count() )
2293           {
2294             if ( m_T[other_ti].m_li == trim.m_li )
2295             {
2296               trim_type = ON_BrepTrim::seam;
2297               break;
2298             }
2299           }
2300         }
2301       }
2302     }
2303   }
2304   return trim_type;
2305 }
2306 
2307 bool
SetTrimTypeFlags(ON_BrepTrim & trim,ON_BOOL32 bLazy)2308 ON_Brep::SetTrimTypeFlags( ON_BrepTrim& trim, ON_BOOL32 bLazy )
2309 {
2310   if ( !bLazy || trim.m_type == ON_BrepTrim::unknown)
2311     trim.m_type = TrimType(trim,false);
2312   return ((trim.m_type != ON_BrepTrim::unknown)?true:false);
2313 }
2314 
2315 bool
GetTrim2dStart(int trim_index,ON_2dPoint & P) const2316 ON_Brep::GetTrim2dStart(int trim_index,
2317                         ON_2dPoint& P
2318                         ) const
2319 
2320 {
2321   if (trim_index < 0 || trim_index >= m_T.Count())
2322     return false;
2323   const ON_BrepTrim& trim = m_T[trim_index];
2324   ON_3dPoint pp;
2325   if (!trim.EvPoint(trim.Domain()[0], pp))
2326     return false;
2327   P = pp;
2328   return true;
2329 }
2330 
2331 bool
GetTrim2dEnd(int trim_index,ON_2dPoint & P) const2332 ON_Brep::GetTrim2dEnd(int trim_index,
2333                         ON_2dPoint& P
2334                         ) const
2335 
2336 {
2337   if (trim_index < 0 || trim_index >= m_T.Count())
2338     return false;
2339   const ON_BrepTrim& trim = m_T[trim_index];
2340   ON_3dPoint pp;
2341   if (!trim.EvPoint(trim.Domain()[1], pp))
2342     return false;
2343   P = pp;
2344   return true;
2345 }
2346 
2347 bool
GetTrim3dStart(int trim_index,ON_3dPoint & P) const2348 ON_Brep::GetTrim3dStart(int trim_index,
2349                         ON_3dPoint& P
2350                         ) const
2351 {
2352   const ON_Surface* srf = 0;
2353   ON_3dPoint uv;
2354   if ( trim_index >= 0 && trim_index < m_T.Count() )
2355   {
2356     const ON_BrepTrim& trim = m_T[trim_index];
2357     if ( trim.m_li >= 0 && trim.m_li < m_L.Count() )
2358     {
2359       const int fi = m_L[trim.m_li].m_fi;
2360       if ( fi >= 0 && fi < m_F.Count() )
2361       {
2362         if ( trim.Evaluate(trim.Domain()[0],0,3,&uv.x) )
2363         {
2364           srf = m_F[fi].SurfaceOf();
2365         }
2366       }
2367     }
2368   }
2369   return (srf && srf->EvPoint(uv.x, uv.y, P) ? true : false);
2370 }
2371 
2372 bool
GetTrim3dEnd(int trim_index,ON_3dPoint & P) const2373 ON_Brep::GetTrim3dEnd(int trim_index,
2374                         ON_3dPoint& P
2375                         ) const
2376 
2377 {
2378   const ON_Surface* srf = 0;
2379   ON_3dPoint uv;
2380   if ( trim_index >= 0 && trim_index < m_T.Count() )
2381   {
2382     const ON_BrepTrim& trim = m_T[trim_index];
2383     if ( trim.m_li >= 0 && trim.m_li < m_L.Count() )
2384     {
2385       const int fi = m_L[trim.m_li].m_fi;
2386       if ( fi >= 0 && fi < m_F.Count() )
2387       {
2388         if ( trim.Evaluate(trim.Domain()[1],0,3,&uv.x) )
2389         {
2390           srf = m_F[fi].SurfaceOf();
2391         }
2392       }
2393     }
2394   }
2395   return (srf && srf->EvPoint(uv.x, uv.y, P) ? true : false);
2396 }
2397 
2398 
2399 ON_BrepLoop::TYPE
ComputeLoopType(const ON_BrepLoop & loop) const2400 ON_Brep::ComputeLoopType( const ON_BrepLoop& loop ) const
2401 {
2402   // This function must always compute the type from the
2403   // 2d trim geometry.  NEVER modify this function to
2404   // return the input value of loop.m_type.
2405 
2406   ON_BrepLoop::TYPE loop_type = ON_BrepLoop::unknown;
2407 
2408   int loop_dir =  LoopDirection( loop );
2409   if ( 1 == loop_dir )
2410     loop_type = ON_BrepLoop::outer;
2411   else if ( -1 == loop_dir )
2412     loop_type = ON_BrepLoop::inner;
2413 
2414   // TODO check for gaps, slits, etc.
2415 
2416   /*
2417   int ugap_count = 0;
2418   int vgap_count = 0;
2419   double d, utol0, vtol0, loop_start_utol, loop_start_vtol;
2420   ON_3dPoint p0, p1, loop_start;
2421   ON_Interval srf_domain[2];
2422   if ( loop.m_fi >= 0 && loop.m_fi < m_F.Count() ) {
2423     const ON_BrepFace& face = m_F[loop.m_fi];
2424     if ( face.m_si >= 0 && face.m_si < m_S.Count() ) {
2425       ON_Surface* srf = m_S[face.m_si];
2426       srf_domain[0] = srf->Domain(0);
2427       srf_domain[1] = srf->Domain(1);
2428     }
2429   }
2430   const ON_2dPoint basePt( srf_domain[0].ParameterAt(0.5), srf_domain[1].ParameterAt(0.5) );
2431 
2432   const int trim_count = loop.m_ti.Count();
2433   for ( lti = 0; lti < trim_count; lti++ )
2434   {
2435     ti = loop.m_ti[lti];
2436     const ON_BrepTrim& trim = m_T[ti];
2437     p0 = trim.PointAtStart();
2438     u_tol0 = trim.m_tolerance[0];
2439     v_tol0 = trim.m_tolerance[1];
2440     if ( !lti )
2441     {
2442       loop_start = p0;
2443       loop_start_utol = trim.m_tolerance[0];
2444       loop_start_vtol = trim.m_tolerance[1];
2445     }
2446     else
2447     {
2448       d = fabs(p0.x-p1.x);
2449       if ( d > utol0 + trim.m_tolerance[0] )
2450         ugap_count++;
2451       d = fabs(p0.y-p1.y);
2452       if ( d > vtol0 + trim.m_tolerance[1] )
2453         vgap_count++;
2454     }
2455     p1 = c2->PointAtEnd();
2456   }
2457   */
2458 
2459   return loop_type;
2460 }
2461 
2462 
2463 bool
IsValidTrim(int trim_index,ON_TextLog * text_log) const2464 ON_Brep::IsValidTrim( int trim_index, ON_TextLog* text_log ) const
2465 {
2466   if ( trim_index < 0 || trim_index >= m_T.Count() )
2467   {
2468     if ( text_log )
2469     {
2470       text_log->Print("brep trim_index = %d (should be >=0 and <%d=brep.m_T.Count()).\n",
2471                       trim_index, m_T.Count());
2472     }
2473     return ON_BrepIsNotValid();
2474   }
2475   const ON_BrepTrim& trim = m_T[trim_index];
2476   if ( trim.m_trim_index != trim_index )
2477   {
2478     if ( text_log )
2479     {
2480       text_log->Print("brep.m_T[%d] trim is not valid.\n",trim_index);
2481       text_log->PushIndent();
2482       text_log->Print("trim.m_trim_index = %d (should be %d).\n",
2483                        trim.m_trim_index, trim_index );
2484       text_log->PopIndent();
2485     }
2486     return ON_BrepIsNotValid();
2487   }
2488   if ( !trim.IsValid(text_log) )
2489   {
2490     if ( text_log )
2491       text_log->Print("brep.m_T[%d] trim is not valid.\n",trim_index);
2492     return ON_BrepIsNotValid();
2493   }
2494   if ( trim.m_c2i < 0 || trim.m_c2i >= m_C2.Count() )
2495   {
2496     if ( text_log )
2497     {
2498       text_log->Print("brep.m_T[%d] trim is not valid.\n",trim_index);
2499       text_log->PushIndent();
2500       text_log->Print( "trim.m_c2i = %d (should be >=0 and <%d).\n", trim.m_c2i, 0, m_C2.Count() );
2501       text_log->PopIndent();
2502     }
2503     return ON_BrepIsNotValid();
2504   }
2505   const ON_Curve* pC = m_C2[trim.m_c2i];
2506   if ( !pC )
2507   {
2508     if ( text_log )
2509     {
2510       text_log->Print("brep.m_T[%d] trim is not valid.\n",trim_index);
2511       text_log->PushIndent();
2512       text_log->Print("trim.m_c2i = %d and ON_Brep.m_C2[%d] is NULL\n", trim.m_c2i, trim.m_c2i );
2513       text_log->PopIndent();
2514     }
2515     return ON_BrepIsNotValid();
2516   }
2517   int c2_dim = pC->Dimension();
2518   if ( c2_dim != 2 )
2519   {
2520     if ( text_log )
2521     {
2522       text_log->Print("brep.m_T[%d] trim is not valid.\n",trim_index);
2523       text_log->PushIndent();
2524       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 );
2525       text_log->PopIndent();
2526     }
2527     return ON_BrepIsNotValid();
2528   }
2529 
2530   if ( pC != trim.ProxyCurve() )
2531   {
2532     if ( text_log )
2533     {
2534       text_log->Print("brep.m_T[%d] trim is not valid.\n",trim_index);
2535       text_log->PushIndent();
2536       text_log->Print("trim.ProxyCurve() != m_C2[trim.m_c2i].\n");
2537       text_log->PopIndent();
2538     }
2539     return ON_BrepIsNotValid();
2540   }
2541 
2542   //if ( trim.ProxyCurveIsReversed() )
2543   //{
2544   //  if ( text_log )
2545   //  {
2546   //    text_log->Print("brep.m_T[%d] trim is not valid.\n",trim_index);
2547   //    text_log->PushIndent();
2548   //    text_log->Print("trim.ProxyCurveIsReversed() is true\n");
2549   //    text_log->PopIndent();
2550   //  }
2551   //  return ON_BrepIsNotValid();
2552   //}
2553 
2554   ON_Interval trim_domain = trim.Domain();
2555   ON_Interval c2_domain = pC->Domain();
2556   if ( !trim_domain.IsIncreasing() )
2557   {
2558     if ( text_log )
2559     {
2560       text_log->Print("brep.m_T[%d] trim is not valid.\n",trim_index);
2561       text_log->PushIndent();
2562       text_log->Print("trim.Domain() = (%g,%g) (should be an increasing interval).\n", trim_domain[0], trim_domain[1] );
2563       text_log->PopIndent();
2564     }
2565     return ON_BrepIsNotValid();
2566   }
2567   if ( !c2_domain.Includes(trim_domain) )
2568   {
2569     if ( text_log )
2570     {
2571       text_log->Print("brep.m_T[%d] trim is not valid.\n",trim_index);
2572       text_log->PushIndent();
2573       text_log->Print("trim.Domain() = (%g,%g) is not included in brep.m_C2[trim.m_c2i=%d]->Domain() = (%g,%g)\n",
2574                       trim_domain[0], trim_domain[1], trim.m_c2i, c2_domain[0], c2_domain[1] );
2575       text_log->PopIndent();
2576     }
2577     return ON_BrepIsNotValid();
2578   }
2579   int vi0 = trim.m_vi[0];
2580   int vi1 = trim.m_vi[1];
2581   if ( vi0 < 0 || vi0 >= m_V.Count() )
2582   {
2583     if ( text_log )
2584     {
2585       text_log->Print("brep.m_T[%d] trim is not valid.\n",trim_index);
2586       text_log->PushIndent();
2587       text_log->Print("trim.m_vi[0] = %d (should be >= 0 and < %d=brep.m_V.Count()).\n",
2588                        trim_index, vi0, m_V.Count() );
2589       text_log->PopIndent();
2590     }
2591     return ON_BrepIsNotValid();
2592   }
2593   if ( vi1 < 0 || vi1 >= m_V.Count() )
2594   {
2595     if ( text_log )
2596     {
2597       text_log->Print("brep.m_T[%d] trim is not valid.\n",trim_index);
2598       text_log->PushIndent();
2599       text_log->Print("trim.m_vi[1] = %d (should be >= 0 and < %d=brep.m_V.Count()).\n",
2600                        trim_index, vi1, m_V.Count() );
2601       text_log->PopIndent();
2602     }
2603     return ON_BrepIsNotValid();
2604   }
2605   const int ei = trim.m_ei;
2606   int trim_eti = -1;
2607   if ( trim.m_type == ON_BrepTrim::singular )
2608   {
2609     // singular trim - no edge and 3d v0 = 3d v1
2610     if ( ei != -1 )
2611     {
2612       if ( text_log )
2613       {
2614         text_log->Print("brep.m_T[%d] trim is not valid.\n",trim_index);
2615         text_log->PushIndent();
2616         text_log->Print("trim.m_type = singular but trim.m_ei = %d (should be -1)\n",ei);
2617         text_log->PopIndent();
2618       }
2619       return ON_BrepIsNotValid();
2620     }
2621     if ( vi0 != vi1 )
2622     {
2623       if ( text_log )
2624       {
2625         text_log->Print("brep.m_T[%d] trim is not valid.\n",trim_index);
2626         text_log->PushIndent();
2627         text_log->Print("trim.m_type = singular but trim.m_vi[] = [%d,%d] (the m_vi[] values should be equal).\n",
2628                         vi0,vi1);
2629         text_log->PopIndent();
2630       }
2631       return ON_BrepIsNotValid();
2632     }
2633     if ( pC->IsClosed() )
2634     {
2635       if ( text_log )
2636       {
2637         text_log->Print("brep.m_T[%d] trim is not valid.\n",trim_index);
2638         text_log->PushIndent();
2639         text_log->Print("trim.m_type = singular but brep.m_C2[trim.m_c2i=%d]->IsClosed() is true.\n",
2640                         trim.m_c2i,trim.m_c2i);
2641         text_log->PopIndent();
2642       }
2643       return ON_BrepIsNotValid();
2644     }
2645   }
2646   else if ( trim.m_type != ON_BrepTrim::ptonsrf )
2647   {
2648     // non-singular non-ptonsrf trim must have valid edge
2649     if ( ei < 0 || ei >= m_E.Count() )
2650     {
2651       if ( text_log )
2652       {
2653         text_log->Print("brep.m_T[%d] trim is not valid.\n",trim_index);
2654         text_log->PushIndent();
2655         text_log->Print("trim.m_type != singular and trim.m_ei = %d (m_ei should be >=0 and <brep.m_E.Count()=%d\n",
2656                         trim.m_ei,m_E.Count());
2657         text_log->PopIndent();
2658       }
2659       return ON_BrepIsNotValid();
2660     }
2661     const ON_BrepEdge& edge = m_E[ei];
2662     if ( edge.m_vi[trim.m_bRev3d?1:0] != vi0 )
2663     {
2664       if ( text_log )
2665       {
2666         text_log->Print("brep.m_T[%d] trim is not valid.\n",trim_index);
2667         text_log->PushIndent();
2668         text_log->Print("trim.m_vi[0] != brep.m_E[trim.m_ei=%d].m_vi[trim.m_bRev3d?1:0]\n",ei);
2669         text_log->PopIndent();
2670       }
2671       return ON_BrepIsNotValid();
2672     }
2673     if ( edge.m_vi[trim.m_bRev3d?0:1] != vi1 )
2674     {
2675       if ( text_log )
2676       {
2677         text_log->Print("brep.m_T[%d] trim is not valid.\n",trim_index);
2678         text_log->PushIndent();
2679         text_log->Print("trim.m_vi[1] != brep.m_E[trim.m_ei=%d].m_vi[trim.m_bRev3d?0:1]\n",ei);
2680         text_log->PopIndent();
2681       }
2682       return ON_BrepIsNotValid();
2683     }
2684     if ( trim_domain == c2_domain && pC->IsClosed() )
2685     {
2686       // (open 2d trims can still have vi0 = vi1 on closed surfaces)
2687       if ( vi0 != vi1 )
2688       {
2689         if ( text_log )
2690         {
2691           text_log->Print("brep.m_T[%d] trim is not valid.\n",trim_index);
2692           text_log->PushIndent();
2693           text_log->Print("trim.m_vi[] = [%d,%d] but brep.m_C2[trim.m_c2i=%d]->IsClosed()=true\n",
2694                           vi0, vi1, trim.m_c2i );
2695           text_log->PopIndent();
2696         }
2697         return ON_BrepIsNotValid();
2698       }
2699     }
2700     else if ( vi0 == vi1 )
2701     {
2702       // TODO: check that trim start/end is a closed surface seam point.
2703     }
2704     else
2705     {
2706       // vi0 != vi1
2707       // TODO: check that trim start/end is not a closed surface seam point.
2708     }
2709     int i;
2710     for ( i = 0; i < edge.m_ti.Count(); i++ )
2711     {
2712       if ( edge.m_ti[i] == trim_index )
2713       {
2714         trim_eti = i;
2715         break;
2716       }
2717     }
2718 
2719     if ( trim_eti < 0 )
2720     {
2721       if ( text_log )
2722       {
2723         text_log->Print("brep.m_T[%d] trim is not valid.\n",trim_index);
2724         text_log->PushIndent();
2725         text_log->Print("trim index %d is not in brep.m_E[trim.m_ei=%d].m_ti[]\n",
2726                         trim_index, trim.m_ei );
2727         text_log->PopIndent();
2728       }
2729       return ON_BrepIsNotValid();
2730     }
2731 
2732     if ( edge.m_ti.Count() == 2 )
2733     {
2734       int other_ti = edge.m_ti[ (edge.m_ti[0]==trim_index)?1:0 ];
2735       if ( other_ti >= 0 && other_ti < m_T.Count() && other_ti != trim_index )
2736       {
2737         const ON_BrepTrim& other_trim = m_T[other_ti];
2738         if ( other_trim.m_li == trim.m_li )
2739         {
2740           if ( trim.m_type != ON_BrepTrim::seam )
2741           {
2742             if ( text_log )
2743             {
2744               text_log->Print("brep.m_T[%d] trim is not valid.\n",trim_index);
2745               text_log->PushIndent();
2746               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",
2747                               trim.m_ei,trim.m_li);
2748               text_log->PopIndent();
2749             }
2750             return ON_BrepIsNotValid();
2751           }
2752         }
2753       }
2754     }
2755   }
2756   if ( trim.m_li < 0 || trim.m_li >= m_L.Count() )
2757   {
2758     if ( text_log )
2759     {
2760       text_log->Print("brep.m_T[%d] trim is not valid.\n",trim_index);
2761       text_log->PushIndent();
2762       text_log->Print("trim.m_li = %d (should be >= 0 and <brep.m_L.Count()=%d\n", trim.m_li,m_L.Count() );
2763       text_log->PopIndent();
2764     }
2765     return ON_BrepIsNotValid();
2766   }
2767 
2768   if ( trim.m_ei >= 0 && trim_eti < 0 )
2769   {
2770     if ( text_log )
2771     {
2772       text_log->Print("brep.m_T[%d] trim is not valid.\n",trim_index);
2773       text_log->PushIndent();
2774       text_log->Print("brep.m_E[trim.m_ei=%d].m_ti[] does not reference the trim.\n",trim.m_ei);
2775       text_log->PopIndent();
2776     }
2777     return ON_BrepIsNotValid();
2778   }
2779 
2780 
2781   switch ( trim.m_type )
2782   {
2783   case ON_BrepTrim::unknown:
2784     {
2785       if ( text_log )
2786       {
2787         text_log->Print("brep.m_T[%d] trim is not valid.\n",trim_index);
2788         text_log->PushIndent();
2789         text_log->Print("trim.m_type = unknown (should be set to the correct ON_BrepTrim::TYPE value)\n");
2790         text_log->PopIndent();
2791       }
2792       return ON_BrepIsNotValid();
2793     }
2794     break;
2795   case ON_BrepTrim::boundary:
2796     {
2797       const ON_BrepLoop& loop = m_L[trim.m_li];
2798       const ON_BrepEdge& edge = m_E[trim.m_ei];
2799       if ( edge.m_ti.Count() > 1 )
2800       {
2801         if ( text_log )
2802         {
2803           text_log->Print("brep.m_T[%d] trim is not valid.\n",trim_index);
2804           text_log->PushIndent();
2805           text_log->Print("trim.m_type = boundary but brep.m_E[trim.m_ei=%d] has 2 or more trims.\n",trim.m_ei);
2806           text_log->PopIndent();
2807         }
2808         return ON_BrepIsNotValid();
2809       }
2810       if ( loop.m_type != ON_BrepLoop::outer && loop.m_type != ON_BrepLoop::inner )
2811       {
2812         if ( text_log )
2813         {
2814           text_log->Print("brep.m_T[%d] trim is not valid.\n",trim_index);
2815           text_log->PushIndent();
2816           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);
2817           text_log->PopIndent();
2818         }
2819         return ON_BrepIsNotValid();
2820       }
2821     }
2822     break;
2823   case ON_BrepTrim::mated:
2824     {
2825       const ON_BrepLoop& loop = m_L[trim.m_li];
2826       const ON_BrepEdge& edge = m_E[trim.m_ei];
2827       if ( edge.m_ti.Count() < 2 )
2828       {
2829         if ( text_log )
2830         {
2831           text_log->Print("brep.m_T[%d] trim is not valid.\n",trim_index);
2832           text_log->PushIndent();
2833           text_log->Print("trim.m_type = mated but brep.m_E[trim.m_ei=%d] only references this trim.\n",trim.m_ei);
2834           text_log->PopIndent();
2835         }
2836         return ON_BrepIsNotValid();
2837       }
2838       if ( loop.m_type != ON_BrepLoop::outer && loop.m_type != ON_BrepLoop::inner )
2839       {
2840         if ( text_log )
2841         {
2842           text_log->Print("brep.m_T[%d] trim is not valid.\n",trim_index);
2843           text_log->PushIndent();
2844           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);
2845           text_log->PopIndent();
2846         }
2847         return ON_BrepIsNotValid();
2848       }
2849     }
2850     break;
2851   case ON_BrepTrim::seam:
2852     {
2853       const ON_BrepLoop& loop = m_L[trim.m_li];
2854       const ON_BrepEdge& edge = m_E[trim.m_ei];
2855       if ( edge.m_ti.Count() < 2 )
2856       {
2857         if ( text_log )
2858         {
2859           text_log->Print("brep.m_T[%d] trim is not valid.\n",trim_index);
2860           text_log->PushIndent();
2861           text_log->Print("trim.m_type = seam but brep.m_E[trim.m_ei=%d] < 2.\n",trim.m_ei);
2862           text_log->PopIndent();
2863         }
2864         return ON_BrepIsNotValid();
2865       }
2866       int other_ti = -1;
2867       for ( int eti = 0; eti < edge.m_ti.Count(); eti++ )
2868       {
2869         if ( trim_eti == eti )
2870           continue;
2871         int i = edge.m_ti[eti];
2872         if ( i == trim_index )
2873         {
2874           if ( text_log )
2875           {
2876             text_log->Print("brep.m_E[%d] trim is not valid.\n",trim.m_ei);
2877             text_log->PushIndent();
2878             text_log->Print("edge.m_ti[%d] = m_ti[%d] = %d.\n",trim_eti,eti,trim_index);
2879             text_log->PopIndent();
2880           }
2881           return ON_BrepIsNotValid();
2882         }
2883 
2884         if ( i < 0 || i >= m_T.Count() )
2885         {
2886           if ( text_log )
2887           {
2888             text_log->Print("brep.m_E[%d] trim is not valid.\n",trim.m_ei);
2889             text_log->PushIndent();
2890             text_log->Print("edge.m_ti[%d]=%d is not a valid m_T[] index.\n",eti,i);
2891             text_log->PopIndent();
2892           }
2893           return ON_BrepIsNotValid();
2894         }
2895 
2896         const ON_BrepTrim& other_trim = m_T[i];
2897         if ( other_trim.m_type == ON_BrepTrim::seam && other_trim.m_li == trim.m_li )
2898         {
2899           if ( other_ti < 0 )
2900             other_ti = i;
2901           else
2902           {
2903             if ( text_log )
2904             {
2905               text_log->Print("brep.m_T[%d,%d, or %d] trim is not valid.\n",trim_index,other_ti,i);
2906               text_log->PushIndent();
2907               text_log->Print("All three trims have m_type = seam m_ei=%d and m_li = %d.\n",trim.m_ei,trim.m_li);
2908               text_log->PopIndent();
2909             }
2910             return ON_BrepIsNotValid();
2911           }
2912         }
2913       }
2914 
2915       if ( other_ti < 0 )
2916       {
2917         if ( text_log )
2918         {
2919           text_log->Print("brep.m_T[%d] trim is not valid.\n",trim_index);
2920           text_log->PushIndent();
2921           text_log->Print("trim.m_type = seam but its other trim is not in the loop.\n");
2922           text_log->PopIndent();
2923         }
2924         return ON_BrepIsNotValid();
2925       }
2926 
2927       if ( loop.m_type != ON_BrepLoop::outer && edge.m_ti.Count() <= 2 )
2928       {
2929         if ( text_log )
2930         {
2931           text_log->Print("brep.m_T[%d] trim is not valid.\n",trim_index);
2932           text_log->PushIndent();
2933           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);
2934           text_log->PopIndent();
2935         }
2936         return ON_BrepIsNotValid();
2937       }
2938       // 31 Jan 2002 - The definition of a seam trim is a trim that is connected to
2939       //               an edge, is part of loop, and exactly one other trim in the
2940       //               same loop is connected to the same edge.  This can happen
2941       //               on the interior of a surface (like an annulus in a plane)
2942       //               and on non-manifold edges.
2943       //if ( trim.m_iso != ON_Surface::W_iso && trim.m_iso != ON_Surface::N_iso &&
2944       //     trim.m_iso != ON_Surface::E_iso && trim.m_iso != ON_Surface::S_iso )
2945       //{
2946       //  if ( text_log )
2947       //  {
2948       //    text_log->Print("brep.m_T[%d] trim is not valid.\n",trim_index);
2949       //    text_log->PushIndent();
2950       //    text_log->Print("trim.m_type = seam but trim.m_iso != N/S/E/W_iso\n");
2951       //    text_log->PopIndent();
2952       //  }
2953       //  return ON_BrepIsNotValid();
2954       //}
2955     }
2956     break;
2957   case ON_BrepTrim::singular:
2958     // most requirements are checked above
2959     if ( trim.m_iso != ON_Surface::W_iso && trim.m_iso != ON_Surface::N_iso &&
2960          trim.m_iso != ON_Surface::E_iso && trim.m_iso != ON_Surface::S_iso )
2961     {
2962       if ( text_log )
2963       {
2964         text_log->Print("brep.m_T[%d] trim is not valid.\n",trim_index);
2965         text_log->PushIndent();
2966         text_log->Print("trim.m_type = singular but trim.m_iso != N/S/E/W_iso\n");
2967         text_log->PopIndent();
2968       }
2969       return ON_BrepIsNotValid();
2970     }
2971     break;
2972   case ON_BrepTrim::crvonsrf:
2973     {
2974       const ON_BrepLoop& loop = m_L[trim.m_li];
2975       if ( loop.m_type != ON_BrepLoop::crvonsrf )
2976       {
2977         return ON_BrepIsNotValid();
2978       }
2979       if ( trim.m_c2i < 0 || trim.m_c2i >= m_C2.Count() )
2980       {
2981         return ON_BrepIsNotValid();
2982       }
2983       if ( trim.m_ei < 0 || trim.m_ei >= m_E.Count() )
2984       {
2985         return ON_BrepIsNotValid();
2986       }
2987     }
2988     break;
2989   case ON_BrepTrim::ptonsrf:
2990     {
2991       const ON_BrepLoop& loop = m_L[trim.m_li];
2992       if ( loop.m_type != ON_BrepLoop::ptonsrf )
2993       {
2994         return ON_BrepIsNotValid();
2995       }
2996       if ( trim.m_ei != -1 )
2997       {
2998         return ON_BrepIsNotValid();
2999       }
3000       if ( trim.m_c2i != -1 )
3001       {
3002         return ON_BrepIsNotValid();
3003       }
3004       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 )
3005       {
3006         // m_pbox must be a single point that defines surface parameters of the point.
3007         return ON_BrepIsNotValid();
3008       }
3009       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 )
3010       {
3011         // m_pbox must be a single point that defines surface parameters of the point.
3012         return ON_BrepIsNotValid();
3013       }
3014     }
3015     break;
3016 
3017   case ON_BrepTrim::slit:
3018     {
3019       if ( text_log )
3020       {
3021         text_log->Print("brep.m_T[%d] trim is not valid.\n",trim_index);
3022         text_log->PushIndent();
3023         text_log->Print("trim.m_type = ON_BrepTrim::slit (should be set to the correct ON_BrepTrim::TYPE value)\n");
3024         text_log->PopIndent();
3025       }
3026       return ON_BrepIsNotValid();
3027     }
3028     break;
3029 
3030   case ON_BrepTrim::trim_type_count:
3031     {
3032       if ( text_log )
3033       {
3034         text_log->Print("brep.m_T[%d] trim is not valid.\n",trim_index);
3035         text_log->PushIndent();
3036         text_log->Print("trim.m_type = type_count (should be set to the correct ON_BrepTrim::TYPE value)\n");
3037         text_log->PopIndent();
3038       }
3039       return ON_BrepIsNotValid();
3040     }
3041     break;
3042 
3043   default:
3044     {
3045       if ( text_log )
3046       {
3047         text_log->Print("brep.m_T[%d] trim is not valid.\n",trim_index);
3048         text_log->PushIndent();
3049         text_log->Print("trim.m_type = garbage (should be set to the correct ON_BrepTrim::TYPE value)\n");
3050         text_log->PopIndent();
3051       }
3052       return ON_BrepIsNotValid();
3053     }
3054     break;
3055   }
3056 
3057   if ( trim.m_tolerance[0] < 0.0 )
3058   {
3059     if ( text_log )
3060     {
3061       text_log->Print("brep.m_T[%d] trim is not valid.\n",trim_index);
3062       text_log->PushIndent();
3063       text_log->Print("trim.m_tolerance[0] = %g (should be >= 0.0)\n",trim.m_tolerance[0]);
3064       text_log->PopIndent();
3065     }
3066     return ON_BrepIsNotValid();
3067   }
3068   if ( trim.m_tolerance[1] < 0.0 )
3069   {
3070     if ( text_log )
3071     {
3072       text_log->Print("brep.m_T[%d] trim is not valid.\n",trim_index);
3073       text_log->PushIndent();
3074       text_log->Print("trim.m_tolerance[1] = %g (should be >= 0.0)\n",trim.m_tolerance[1]);
3075       text_log->PopIndent();
3076     }
3077     return ON_BrepIsNotValid();
3078   }
3079 
3080   if ( !trim.m_pbox.IsValid() )
3081   {
3082     if ( text_log )
3083     {
3084       text_log->Print("brep.m_T[%d] trim is not valid.\n",trim_index);
3085       text_log->PushIndent();
3086       text_log->Print("trim.m_pbox is not valid.\n");
3087       text_log->PopIndent();
3088     }
3089     return ON_BrepIsNotValid();
3090   }
3091 
3092   if ( trim.m_brep != this )
3093   {
3094     if ( text_log )
3095     {
3096       text_log->Print("brep.m_T[%d] trim is not valid.\n",trim_index);
3097       text_log->PushIndent();
3098       text_log->Print("trim.m_brep does not point to parent brep.\n");
3099       text_log->PopIndent();
3100     }
3101     return ON_BrepIsNotValid();
3102   }
3103 
3104   return true;
3105 }
3106 
3107 bool
IsValidLoop(int loop_index,ON_TextLog * text_log) const3108 ON_Brep::IsValidLoop( int loop_index, ON_TextLog* text_log  ) const
3109 {
3110   if ( loop_index < 0 || loop_index >= m_L.Count() )
3111   {
3112     if ( text_log )
3113     {
3114       text_log->Print("brep loop_index = %d (should be >=0 and <%d=brep.m_L.Count()).\n",
3115                       loop_index, m_L.Count());
3116     }
3117     return ON_BrepIsNotValid();
3118   }
3119   const ON_BrepLoop& loop = m_L[loop_index];
3120   if ( loop.m_loop_index != loop_index )
3121   {
3122     if ( text_log )
3123     {
3124       text_log->Print("brep.m_L[%d] loop is not valid.\n",loop_index);
3125       text_log->PushIndent();
3126       text_log->Print("loop.m_loop_index = %d (should be %d).\n",
3127                        loop.m_loop_index, loop_index );
3128       text_log->PopIndent();
3129     }
3130     return ON_BrepIsNotValid();
3131   }
3132   if ( loop.m_fi < 0 || loop.m_fi >= m_F.Count() )
3133   {
3134     if ( text_log )
3135     {
3136       text_log->Print("brep.m_L[%d] loop is not valid.\n",loop_index);
3137       text_log->PushIndent();
3138       text_log->Print("loop.m_fi = %d (should be >= 0 and <brep.m_F.Count()=%d\n", loop.m_fi, m_F.Count() );
3139       text_log->PopIndent();
3140     }
3141     return ON_BrepIsNotValid();
3142   }
3143   const int loop_trim_count = loop.m_ti.Count();
3144   if ( loop_trim_count <= 0 )
3145   {
3146     if ( text_log )
3147     {
3148       text_log->Print("brep.m_L[%d] loop is not valid.\n",loop_index);
3149       text_log->PushIndent();
3150       text_log->Print("loop.m_ti.Count() is <= 0  (should be > 0)\n");
3151       text_log->PopIndent();
3152     }
3153     return ON_BrepIsNotValid();
3154   }
3155 
3156   if (    loop.m_type != ON_BrepLoop::outer
3157        && loop.m_type != ON_BrepLoop::inner
3158        && loop.m_type != ON_BrepLoop::slit
3159        )
3160   {
3161     if ( text_log )
3162     {
3163       text_log->Print("brep.m_L[%d] loop is not valid.\n",loop_index);
3164       text_log->PushIndent();
3165       text_log->Print("loop.m_type = %d (must be %d=outer, %d=inner, or %d=slit)\n",
3166                       loop.m_type,ON_BrepLoop::outer,ON_BrepLoop::inner,ON_BrepLoop::slit);
3167       text_log->PopIndent();
3168     }
3169     return ON_BrepIsNotValid();
3170   }
3171 
3172 
3173   if ( loop.m_brep != this )
3174   {
3175     if ( text_log )
3176     {
3177       text_log->Print("loop.m_L[%d] loop is not valid.\n",loop_index);
3178       text_log->PushIndent();
3179       text_log->Print("loop.m_brep does not point to parent brep.\n");
3180       text_log->PopIndent();
3181     }
3182     return ON_BrepIsNotValid();
3183   }
3184 
3185   // make sure trims are valid
3186   int i, lti, ti;
3187   for ( lti = 0; lti < loop_trim_count; lti++ ) {
3188     ti = loop.m_ti[lti];
3189     for ( i = 0; i < lti; i++ ) {
3190       if ( loop.m_ti[i] == ti )
3191       {
3192         if ( text_log )
3193         {
3194           text_log->Print("brep.m_L[%d] loop is not valid.\n",loop_index);
3195           text_log->PushIndent();
3196           text_log->Print("loop.m_ti[%d] = loop.m_ti[%d] = %d (trim index can only appear once)\n",
3197                           lti, i, ti);
3198           text_log->PopIndent();
3199         }
3200         return ON_BrepIsNotValid();
3201       }
3202     }
3203     if ( !IsValidTrim( ti, text_log ) )
3204     {
3205       if ( text_log )
3206       {
3207         text_log->Print("brep.m_L[%d] loop is not valid.\n",loop_index);
3208         text_log->PushIndent();
3209         text_log->Print("brep.m_T[loop.m_ti[%d]=%d] is not valid.\n",
3210                         lti, ti);
3211         text_log->PopIndent();
3212       }
3213       return ON_BrepIsNotValid();
3214     }
3215     if ( m_T[ti].m_li != loop_index )
3216     {
3217       if ( text_log )
3218       {
3219         text_log->Print("brep.m_L[%d] loop is not valid.\n",loop_index);
3220         text_log->PushIndent();
3221         text_log->Print("brep.m_T[loop.m_ti[%d]=%d].m_li=%d (m_li should be %d).\n",
3222                         lti, ti, m_T[ti].m_li, loop_index );
3223         text_log->PopIndent();
3224       }
3225       return ON_BrepIsNotValid();
3226     }
3227   }
3228 
3229 
3230   if ( ON_BrepLoop::slit == loop.m_type )
3231   {
3232     if ( loop.m_ti.Count() < 2 || 0 != (loop.m_ti.Count() % 2) )
3233     {
3234       if ( text_log )
3235       {
3236         text_log->Print("brep.m_L[%d] loop is not valid.\n",loop_index);
3237         text_log->PushIndent();
3238         text_log->Print("loop.m_type = slit but loop has %d trims\n",loop.m_ti.Count());
3239         text_log->PopIndent();
3240       }
3241       return ON_BrepIsNotValid();
3242     }
3243 
3244     for ( int lti = 0; lti < loop.m_ti.Count(); lti++ )
3245     {
3246       int ti = loop.m_ti[lti];
3247       const ON_BrepTrim& trim = m_T[ti];
3248       if ( trim.m_type != ON_BrepTrim::seam )
3249       {
3250         if ( text_log )
3251         {
3252           text_log->Print("brep.m_L[%d] slit loop is not valid.\n",loop_index);
3253           text_log->PushIndent();
3254           text_log->Print("brep.m_T[loop.m_ti[%d]=%d].m_type = %d (should be %d = seam)\n",
3255                           lti,ti,trim.m_type,ON_BrepTrim::seam);
3256           text_log->PopIndent();
3257         }
3258         return ON_BrepIsNotValid();
3259       }
3260       switch( trim.m_iso )
3261       {
3262       case ON_Surface::W_iso:
3263       case ON_Surface::E_iso:
3264       case ON_Surface::S_iso:
3265       case ON_Surface::N_iso:
3266         {
3267           if ( text_log )
3268           {
3269             text_log->Print("brep.m_L[%d] slit loop is not valid.\n",loop_index);
3270             text_log->PushIndent();
3271             text_log->Print("brep.m_T[loop.m_ti[%d]=%d].m_iso = E/W/N/S_iso (should be interior)\n",
3272                             lti,ti);
3273             text_log->PopIndent();
3274           }
3275           return ON_BrepIsNotValid();
3276         }
3277         break;
3278 
3279       case ON_Surface::not_iso:
3280       case ON_Surface::x_iso:
3281       case ON_Surface::y_iso:
3282       case ON_Surface::iso_count:
3283         break;
3284       }
3285     }
3286   }
3287 
3288 
3289   // make sure ends of trims jibe
3290   int ci0, ci1, next_lti;
3291   ON_3dPoint P0, P1;
3292   const ON_Curve *pC0, *pC1;
3293   for ( lti = 0; lti < loop_trim_count; lti++ )
3294   {
3295     //double x_tol = ON_ZERO_TOLERANCE;
3296     //double y_tol = ON_ZERO_TOLERANCE;
3297     const ON_BrepTrim& trim0 = m_T[loop.m_ti[lti]];
3298     next_lti = (lti+1)%loop_trim_count;
3299     const ON_BrepTrim& trim1 = m_T[loop.m_ti[next_lti]];
3300     ON_Interval trim0_domain = trim0.Domain();
3301     ON_Interval trim1_domain = trim1.Domain();
3302     ci0 = trim0.m_c2i;
3303     ci1 = trim1.m_c2i;
3304     pC0 = m_C2[ci0];
3305     pC1 = m_C2[ci1];
3306     P0 = pC0->PointAt( trim0_domain[1] ); // end of this 2d trim
3307     P1 = pC1->PointAt( trim1_domain[0] ); // start of next 2d trim
3308     if ( !(P0-P1).IsTiny() )
3309     {
3310       // 16 September 2003 Dale Lear - RR 11319
3311       //    Added relative tol check so cases with huge
3312       //    coordinate values that agreed to 10 places
3313       //    didn't get flagged as bad.
3314       double xtol = (fabs(P0.x) + fabs(P1.x))*1.0e-10;
3315       double ytol = (fabs(P0.y) + fabs(P1.y))*1.0e-10;
3316       if ( xtol < ON_ZERO_TOLERANCE )
3317         xtol = ON_ZERO_TOLERANCE;
3318       if ( ytol < ON_ZERO_TOLERANCE )
3319         ytol = ON_ZERO_TOLERANCE;
3320       double dx = fabs(P0.x-P1.x);
3321       double dy = fabs(P0.y-P1.y);
3322       if ( dx > xtol || dy > ytol )
3323       {
3324         if ( text_log )
3325         {
3326           text_log->Print("brep.m_L[%d] loop is not valid.\n",loop_index);
3327           text_log->PushIndent();
3328           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);
3329           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);
3330           text_log->PopIndent();
3331         }
3332         return ON_BrepIsNotValid();
3333       }
3334     }
3335   }
3336 
3337   if ( !loop.m_pbox.IsValid() )
3338   {
3339     if ( text_log )
3340     {
3341       text_log->Print("brep.m_L[%d] loop is not valid.\n",loop_index);
3342       text_log->PushIndent();
3343       text_log->Print("loop.m_pbox is not valid\n");
3344       text_log->PopIndent();
3345     }
3346     return ON_BrepIsNotValid();
3347   }
3348 
3349   return true;
3350 }
3351 
3352 
3353 bool
IsValidFace(int face_index,ON_TextLog * text_log) const3354 ON_Brep::IsValidFace( int face_index, ON_TextLog* text_log  ) const
3355 {
3356   if ( face_index < 0 || face_index >= m_F.Count() )
3357   {
3358     if ( text_log )
3359     {
3360       text_log->Print("brep face_index = %d (should be >=0 and <%d=brep.m_F.Count()).\n",
3361                       face_index, m_F.Count());
3362     }
3363     return ON_BrepIsNotValid();
3364   }
3365   const ON_BrepFace& face = m_F[face_index];
3366   if ( face.m_face_index != face_index )
3367   {
3368     if ( text_log )
3369     {
3370       text_log->Print("brep.m_F[%d] face is not valid.\n",face_index);
3371       text_log->PushIndent();
3372       text_log->Print("face.m_face_index = %d (should be %d).\n",
3373                        face.m_face_index, face_index );
3374       text_log->PopIndent();
3375     }
3376     return ON_BrepIsNotValid();
3377   }
3378   if ( face.m_brep != this )
3379   {
3380     if ( text_log )
3381     {
3382       text_log->Print("brep.m_F[%d] face is not valid.\n",face_index);
3383       text_log->PushIndent();
3384       text_log->Print("face.m_brep does not point to parent brep.\n");
3385       text_log->PopIndent();
3386     }
3387     return ON_BrepIsNotValid();
3388   }
3389 
3390   const int face_loop_count = face.m_li.Count();
3391   if ( face_loop_count <= 0 )
3392   {
3393     if ( text_log )
3394     {
3395       text_log->Print("brep.m_F[%d] face is not valid.\n",face_index);
3396       text_log->PushIndent();
3397       text_log->Print("face.m_li.Count() <= 0 (should be >= 1)\n");
3398       text_log->PopIndent();
3399     }
3400     return ON_BrepIsNotValid();
3401   }
3402 
3403   int i, fli, li;
3404   for ( fli = 0; fli < face_loop_count; fli++ )
3405   {
3406     li = face.m_li[fli];
3407     for ( i = 0; i < fli; i++ )
3408     {
3409       if ( face.m_li[i] == li )
3410       {
3411         if ( text_log )
3412         {
3413           text_log->Print("brep.m_F[%d] face is not valid.\n",face_index);
3414           text_log->PushIndent();
3415           text_log->Print("face.m_li[%d]=face.m_li[%d]=%d (a loop index should appear once in face.m_li[])\n",
3416                           fli,i,li);
3417           text_log->PopIndent();
3418         }
3419         return ON_BrepIsNotValid();
3420       }
3421     }
3422     if ( !IsValidLoop( li, text_log ) )
3423     {
3424       if ( text_log )
3425       {
3426         text_log->Print("brep.m_F[%d] face is not valid.\n",face_index);
3427         text_log->PushIndent();
3428         text_log->Print("brep.m_L[face.m_li[%d]=%d] is not valid.\n",fli,li);
3429         text_log->PopIndent();
3430       }
3431       return ON_BrepIsNotValid();
3432     }
3433     const ON_BrepLoop& loop = m_L[li];
3434     if ( loop.m_loop_index != li )
3435     {
3436       if ( text_log )
3437       {
3438         text_log->Print("brep.m_F[%d] face is not valid.\n",face_index);
3439         text_log->PushIndent();
3440         text_log->Print("face.m_li[%d]=%d is a deleted loop\n",
3441                         fli,li);
3442         text_log->PopIndent();
3443       }
3444       return ON_BrepIsNotValid();
3445     }
3446     if ( loop.m_fi != face_index )
3447     {
3448       if ( text_log )
3449       {
3450         text_log->Print("brep.m_F[%d] face is not valid.\n",face_index);
3451         text_log->PushIndent();
3452         text_log->Print("face.m_li[%d]=%d but brep.m_L[%d].m_fi=%d (m_fi should be %d)\n",
3453                         fli,li,li,loop.m_fi,face_index);
3454         text_log->PopIndent();
3455       }
3456       return ON_BrepIsNotValid();
3457     }
3458     if ( fli == 0 )
3459     {
3460       if ( loop.m_type != ON_BrepLoop::outer )
3461       {
3462         if ( text_log )
3463         {
3464           text_log->Print("brep.m_F[%d] face is not valid.\n",face_index);
3465           text_log->PushIndent();
3466           text_log->Print("brep.m_L[face.m_li[0]=%d].m_type is not outer.\n",li);
3467           text_log->PopIndent();
3468         }
3469         return ON_BrepIsNotValid();
3470       }
3471     }
3472     else
3473     {
3474       if (   loop.m_type != ON_BrepLoop::slit
3475            && loop.m_type != ON_BrepLoop::inner
3476          )
3477       {
3478         if ( text_log )
3479         {
3480           text_log->Print("brep.m_F[%d] face is not valid.\n",face_index);
3481           text_log->PushIndent();
3482           text_log->Print("brep.m_L[face.m_li[%d]=%d].m_type is not inner or slit.\n",fli,li);
3483           text_log->PopIndent();
3484         }
3485         return ON_BrepIsNotValid();
3486       }
3487     }
3488   }
3489 
3490   const int si = face.m_si;
3491   if ( si < 0 || si >= m_S.Count() )
3492   {
3493     if ( text_log )
3494     {
3495       text_log->Print("brep.m_F[%d] face is not valid.\n",face_index);
3496       text_log->PushIndent();
3497       text_log->Print("face.m_si=%d (should be >=0 and <%d=m_S.Count())\n",
3498                       face.m_si,m_S.Count());
3499       text_log->PopIndent();
3500     }
3501     return ON_BrepIsNotValid();
3502   }
3503 
3504   if ( !m_S[si] )
3505   {
3506     if ( text_log )
3507     {
3508       text_log->Print("brep.m_F[%d] face is not valid.\n",face_index);
3509       text_log->PushIndent();
3510       text_log->Print("brep.m_S[face.m_si=%d] is NULL\n",face.m_si);
3511       text_log->PopIndent();
3512     }
3513     return ON_BrepIsNotValid();
3514   }
3515 
3516   if ( m_S[si] != face.ProxySurface() )
3517   {
3518     if ( text_log )
3519     {
3520       text_log->Print("brep.m_F[%d] face is not valid.\n",face_index);
3521       text_log->PushIndent();
3522       text_log->Print("brep.m_S[face.m_si=%d] != face.ProxySurface().\n",si);
3523       text_log->PopIndent();
3524     }
3525     return ON_BrepIsNotValid();
3526   }
3527 
3528   if ( face.ProxySurfaceIsTransposed() )
3529   {
3530     if ( text_log )
3531     {
3532       text_log->Print("brep.m_F[%d] face is not valid.\n",face_index);
3533       text_log->PushIndent();
3534       text_log->Print("face.ProxySurfaceIsTransposed() is true.\n");
3535       text_log->PopIndent();
3536     }
3537     return ON_BrepIsNotValid();
3538   }
3539 
3540   return true;
3541 }
3542 
3543 bool
IsValidEdge(int edge_index,ON_TextLog * text_log) const3544 ON_Brep::IsValidEdge( int edge_index, ON_TextLog* text_log ) const
3545 {
3546   if ( edge_index < 0 || edge_index >= m_E.Count() )
3547   {
3548     if ( text_log )
3549       text_log->Print("brep edge_index = %d (should be >=0 and <%d=brep.m_E.Count() ).\n",
3550                       edge_index, m_E.Count());
3551     return ON_BrepIsNotValid();
3552   }
3553   const ON_BrepEdge& edge = m_E[edge_index];
3554   if ( edge.m_brep != this )
3555   {
3556     if ( text_log )
3557     {
3558       text_log->Print("brep.m_E[%d] edge is not valid.\n",edge_index);
3559       text_log->PushIndent();
3560       text_log->Print("edge.m_brep does not point to parent brep\n");
3561       text_log->PopIndent();
3562     }
3563     return ON_BrepIsNotValid();
3564   }
3565   if ( edge.m_edge_index != edge_index )
3566   {
3567     if ( text_log )
3568     {
3569       text_log->Print("brep.m_E[%d] edge is not valid.\n",edge_index);
3570       text_log->PushIndent();
3571       text_log->Print("edge.m_edge_index = %d (should be %d).\n",
3572                        edge.m_edge_index, edge_index );
3573       text_log->PopIndent();
3574     }
3575     return ON_BrepIsNotValid();
3576   }
3577   if ( !edge.IsValid(text_log) )
3578   {
3579     if ( text_log )
3580     {
3581       text_log->Print("brep.m_E[%d] edge is not valid.\n",edge_index);
3582       text_log->PushIndent();
3583       text_log->Print("edge is not a valid.\n");
3584       text_log->PopIndent();
3585     }
3586     return ON_BrepIsNotValid();
3587   }
3588 
3589   const int ci = edge.m_c3i;
3590   if ( ci < 0 || ci >= m_C3.Count() )
3591   {
3592     if ( text_log )
3593     {
3594       text_log->Print("brep.m_E[%d] edge is not valid.\n",edge_index);
3595       text_log->PushIndent();
3596       text_log->Print("edge.m_c3i = %d (should be >=0 and <%d=m_C3.Count()\n",
3597                       edge.m_c3i,m_C3.Count() );
3598       text_log->PopIndent();
3599     }
3600     return ON_BrepIsNotValid();
3601   }
3602 
3603   if ( m_C3[ci] != edge.ProxyCurve() || 0 == m_C3[ci] )
3604   {
3605     if ( text_log )
3606     {
3607       text_log->Print("brep.m_E[%d] edge is not valid.\n",edge_index);
3608       text_log->PushIndent();
3609       text_log->Print("edge.m_curve != brep.m_C3[edge.m_c3i=%d]\n", edge.m_c3i );
3610       text_log->PopIndent();
3611     }
3612     return ON_BrepIsNotValid();
3613   }
3614 
3615   //if ( edge.ProxyCurveIsReversed() )
3616   //{
3617   //  if ( text_log )
3618   //  {
3619   //    text_log->Print("brep.m_E[%d] edge is not valid.\n",edge_index);
3620   //    text_log->PushIndent();
3621   //    text_log->Print("edge.ProxyCurveIsReversed() is true.\n" );
3622   //    text_log->PopIndent();
3623   //  }
3624   //  return ON_BrepIsNotValid();
3625   //}
3626 
3627   double t0, t1;
3628   if ( !edge.GetDomain( &t0, &t1 ) )
3629   {
3630     if ( text_log )
3631     {
3632       ON_Interval edom = edge.ProxyCurveDomain();
3633       text_log->Print("brep.m_E[%d] edge is not valid.\n",edge_index);
3634       text_log->PushIndent();
3635       text_log->Print( "edge.m_domain=(%g,%g) is not valid\n", edom[0], edom[1]);
3636       text_log->PopIndent();
3637     }
3638     return ON_BrepIsNotValid();
3639   }
3640   const int vi0 = edge.m_vi[0];
3641   const int vi1 = edge.m_vi[1];
3642   if ( vi0 < 0 || vi0 >= m_V.Count() )
3643   {
3644     if ( text_log )
3645     {
3646       text_log->Print("brep.m_E[%d] edge is not valid.\n",edge_index);
3647       text_log->PushIndent();
3648       text_log->Print("edge.m_vi[0]=%d (should be >=0 and <%d=m_V.Count()\n",
3649                        vi0, m_V.Count() );
3650       text_log->PopIndent();
3651     }
3652     return ON_BrepIsNotValid();
3653   }
3654   if ( vi1 < 0 || vi1 >= m_V.Count() )
3655   {
3656     if ( text_log )
3657     {
3658       text_log->Print("brep.m_E[%d] edge is not valid.\n",edge_index);
3659       text_log->PushIndent();
3660       text_log->Print("edge.m_vi[1]=%d (should be >=0 and <%d=m_V.Count()\n",
3661                        vi1, m_V.Count() );
3662       text_log->PopIndent();
3663     }
3664     return ON_BrepIsNotValid();
3665   }
3666   int evi;
3667   for ( evi = 0; evi < 2; evi++ )
3668   {
3669     const ON_BrepVertex& vertex = m_V[edge.m_vi[evi]];
3670 
3671     if ( edge.m_vi[evi] != vertex.m_vertex_index )
3672     {
3673       if ( text_log )
3674       {
3675         text_log->Print("brep.m_E[%d] edge is not valid.\n",edge_index);
3676         text_log->PushIndent();
3677         text_log->Print("edge.m_vi[%d]=%d is a deleted vertex\n",
3678                          evi,edge.m_vi[evi] );
3679         text_log->PopIndent();
3680       }
3681       return ON_BrepIsNotValid();
3682     }
3683 
3684 
3685     const int vertex_edge_count = vertex.m_ei.Count();
3686     ON_BOOL32 bFoundIt = false;
3687     int vei;
3688     for ( vei = 0; vei < vertex_edge_count && !bFoundIt; vei++ ) {
3689       bFoundIt = (vertex.m_ei[vei] == edge_index);
3690     }
3691     if ( !bFoundIt )
3692     {
3693       if ( text_log )
3694       {
3695         text_log->Print("brep.m_E[%d] edge is not valid.\n",edge_index);
3696         text_log->PushIndent();
3697         text_log->Print("edge.m_vi[%d]=%d but edge is not referenced in m_V[%d].m_ei[]\n",
3698                          evi,edge.m_vi[evi],edge.m_vi[evi] );
3699         text_log->PopIndent();
3700       }
3701       return ON_BrepIsNotValid();
3702     }
3703   }
3704 
3705   if ( edge.IsClosed() ) {
3706     if ( vi0 != vi1 )
3707     {
3708       if ( text_log )
3709       {
3710         text_log->Print("brep.m_E[%d] edge is not valid.\n",edge_index);
3711         text_log->PushIndent();
3712         text_log->Print("edge.m_vi[]=(%d,%d) but edge.IsClosed() is true\n",
3713                          vi0,vi1);
3714         text_log->PopIndent();
3715       }
3716       return ON_BrepIsNotValid();
3717     }
3718   }
3719   else {
3720     if ( vi0 == vi1 )
3721     {
3722       if ( text_log )
3723       {
3724         text_log->Print("brep.m_E[%d] edge is not valid.\n",edge_index);
3725         text_log->PushIndent();
3726         text_log->Print("edge.m_vi[0]=edge.m_vi[1]=%d but edge.IsClosed() is false.\n",
3727                          vi0);
3728         text_log->PopIndent();
3729       }
3730       return ON_BrepIsNotValid();
3731     }
3732   }
3733 
3734   const int edge_trim_count = edge.m_ti.Count();
3735   if ( edge_trim_count < 0 )
3736   {
3737     if ( text_log )
3738     {
3739       text_log->Print("brep.m_E[%d] edge is not valid.\n",edge_index);
3740       text_log->PushIndent();
3741       text_log->Print("edge.m_ti.Count() < 0\n");
3742       text_log->PopIndent();
3743     }
3744     return ON_BrepIsNotValid();
3745   }
3746   int i, eti, ti;
3747   for (eti = 0; eti < edge_trim_count; eti++ )
3748   {
3749     ti = edge.m_ti[eti];
3750     if ( ti < 0 || ti >= m_T.Count() )
3751     {
3752       if ( text_log )
3753       {
3754         text_log->Print("brep.m_E[%d] edge is not valid.\n",edge_index);
3755         text_log->PushIndent();
3756         text_log->Print("edge.m_ti[%d]=%d (should be >=0 and <%d=m_T.Count())\n",eti,ti);
3757         text_log->PopIndent();
3758       }
3759       return ON_BrepIsNotValid();
3760     }
3761     if ( m_T[ti].m_trim_index != ti )
3762     {
3763       if ( text_log )
3764       {
3765         text_log->Print("brep.m_E[%d] edge is not valid.\n",edge_index);
3766         text_log->PushIndent();
3767         text_log->Print("edge.m_ti[%d]=%d is a deleted trim\n",eti,ti);
3768         text_log->PopIndent();
3769       }
3770       return ON_BrepIsNotValid();
3771     }
3772     for ( i = 0; i < eti; i++ )
3773     {
3774       if ( edge.m_ti[i] == ti )
3775       {
3776         if ( text_log )
3777         {
3778           text_log->Print("brep.m_E[%d] edge is not valid.\n",edge_index);
3779           text_log->PushIndent();
3780           text_log->Print("edge.m_ti[%d]=edge.m_ti[%d]=%d (a trim should be referenced once).\n",i,eti,ti);
3781           text_log->PopIndent();
3782         }
3783         return ON_BrepIsNotValid();
3784       }
3785     }
3786     const ON_BrepTrim& trim = m_T[ti];
3787     if ( trim.m_ei != edge_index )
3788     {
3789       if ( text_log )
3790       {
3791         text_log->Print("brep.m_E[%d] edge is not valid.\n",edge_index);
3792         text_log->PushIndent();
3793         text_log->Print("edge.m_ti[%d]=%d but brep.m_T[%d].m_ei=%d\n",eti,ti,ti,trim.m_ei);
3794         text_log->PopIndent();
3795       }
3796       return ON_BrepIsNotValid();
3797     }
3798   }
3799 
3800   if ( edge.m_tolerance < 0.0 )
3801   {
3802     if ( text_log )
3803     {
3804       text_log->Print("brep.m_E[%d] edge is not valid.\n",edge_index);
3805       text_log->PushIndent();
3806       text_log->Print("edge.m_tolerance=%g (should be >= 0.0)\n",edge.m_tolerance);
3807       text_log->PopIndent();
3808     }
3809     return ON_BrepIsNotValid();
3810   }
3811 
3812   return true;
3813 }
3814 
3815 bool
IsValidVertex(int vertex_index,ON_TextLog * text_log) const3816 ON_Brep::IsValidVertex( int vertex_index, ON_TextLog* text_log ) const
3817 {
3818   if ( vertex_index < 0 || vertex_index >= m_V.Count() )
3819   {
3820     if ( text_log )
3821       text_log->Print("brep vertex_index = %d (should be >=0 and <%d=brep.m_V.Count() ).\n",
3822                       vertex_index, m_V.Count());
3823     return ON_BrepIsNotValid();
3824   }
3825   const ON_BrepVertex& vertex = m_V[vertex_index];
3826   if ( vertex.m_vertex_index != vertex_index )
3827   {
3828     if ( text_log )
3829     {
3830       text_log->Print("brep.m_V[%d] vertex is not valid.\n",vertex_index);
3831       text_log->PushIndent();
3832       text_log->Print("vertex.m_vertex_index = %d (should be %d).\n",
3833                        vertex.m_vertex_index, vertex_index );
3834       text_log->PopIndent();
3835     }
3836     return ON_BrepIsNotValid();
3837   }
3838 
3839   const int vertex_edge_count = vertex.m_ei.Count();
3840   int i, j, vei, ei;
3841   for ( vei = 0; vei < vertex_edge_count; vei++ ) {
3842     ei = vertex.m_ei[vei];
3843     if ( ei < 0 || ei >= m_E.Count() )
3844     {
3845       if ( text_log )
3846       {
3847         text_log->Print("brep.m_V[%d] vertex is not valid.\n",vertex_index);
3848         text_log->PushIndent();
3849         text_log->Print("vertex.m_ei[%d] = %d (should be >=0 and <%d).\n", vei, ei, m_E.Count());
3850         text_log->PopIndent();
3851       }
3852       return ON_BrepIsNotValid();
3853     }
3854     const ON_BrepEdge& edge = m_E[ei];
3855     if ( ei != edge.m_edge_index )
3856     {
3857       if ( text_log )
3858       {
3859         text_log->Print("brep.m_V[%d] vertex is not valid.\n",vertex_index);
3860         text_log->PushIndent();
3861         text_log->Print("vertex.m_ei[%d] = %d is a deleted edge.\n", vei, ei);
3862         text_log->PopIndent();
3863       }
3864       return ON_BrepIsNotValid();
3865     }
3866     for ( i = 0; i < vei; i++ )
3867     {
3868       if ( vertex.m_ei[i] == ei )
3869       {
3870         // edge should be closed
3871         if ( edge.m_vi[0] != vertex_index || edge.m_vi[1] != vertex_index )
3872         {
3873           if ( text_log )
3874           {
3875             text_log->Print("brep.m_V[%d] vertex is not valid.\n",vertex_index);
3876             text_log->PushIndent();
3877             text_log->Print("vertex.m_ei[%d] and vertex.m_ei[%d] = %d but brep.m_E[%d].m_vi[0] = %d",
3878                              i,vei,ei,ei,edge.m_vi[0]);
3879             text_log->Print("and ON_Brep.m_E[%d].m_vi[1] = %d (both m_vi[] values should be %d).\n",
3880                             ei,edge.m_vi[1],vertex_index);
3881             text_log->PopIndent();
3882           }
3883           return ON_BrepIsNotValid();
3884         }
3885         for (j = i+1; j < vei; j++ )
3886         {
3887           if ( vertex.m_ei[j] == ei )
3888           {
3889             if ( text_log )
3890             {
3891               text_log->Print("brep.m_V[%d] vertex is not valid.\n",vertex_index);
3892               text_log->PushIndent();
3893               text_log->Print("vertex.m_ei[%d,%d,%d] = %d. An open edge index should appear once\n",i,vei,j,ei);
3894               text_log->Print("in vertex.m_ei[] and a closed edge index should appear twice.\n");
3895               text_log->PopIndent();
3896             }
3897             return ON_BrepIsNotValid();
3898           }
3899         }
3900         break;
3901       }
3902     }
3903     if ( edge.m_vi[0] != vertex_index && edge.m_vi[1] != vertex_index )
3904     {
3905       if ( text_log )
3906       {
3907         text_log->Print("brep.m_V[%d] vertex is not valid.\n",vertex_index);
3908         text_log->PushIndent();
3909         text_log->Print("vertex.m_ei[%d] = %d but ON_Brep.m_E[%d].m_vi[] = [%d,%d]. "
3910                         "At least one edge m_vi[] value should be %d.\n",
3911                         vei,ei,ei,edge.m_vi[0],edge.m_vi[1],vertex_index);
3912         text_log->PopIndent();
3913       }
3914       return ON_BrepIsNotValid();
3915     }
3916   }
3917 
3918   if ( vertex.m_tolerance < 0.0 )
3919   {
3920     if ( text_log )
3921     {
3922       text_log->Print("brep.m_V[%d] vertex is not valid.\n",vertex_index);
3923       text_log->PushIndent();
3924       text_log->Print("vertex.m_tolerace = %g (should be >= 0.0)\n",vertex.m_tolerance);
3925       text_log->PopIndent();
3926     }
3927     return ON_BrepIsNotValid();
3928   }
3929   return true;
3930 }
3931 
3932 
3933 
3934 static
TestTrimPBox(const ON_BrepTrim & trim,ON_TextLog * text_log)3935 bool TestTrimPBox( const ON_BrepTrim& trim, ON_TextLog* text_log )
3936 {
3937   ON_3dPoint pt;
3938   double d;
3939   ON_BoundingBox pbox = trim.m_pbox;
3940 
3941 
3942   d = ON_SQRT_EPSILON*(fabs(pbox.m_min.x)+fabs(pbox.m_max.x));
3943   if ( d < ON_ZERO_TOLERANCE )
3944     d = ON_ZERO_TOLERANCE;
3945   pbox.m_min.x -= d;
3946   pbox.m_max.x += d;
3947 
3948   d = ON_SQRT_EPSILON*(fabs(pbox.m_min.y)+fabs(pbox.m_max.y));
3949   if ( d < ON_ZERO_TOLERANCE )
3950     d = ON_ZERO_TOLERANCE;
3951   pbox.m_min.y -= d;
3952   pbox.m_max.y += d;
3953 
3954   pt = trim.PointAtStart();
3955   if ( !pbox.IsPointIn(pt) )
3956   {
3957     if ( text_log )
3958        text_log->Print("ON_Brep.m_T[%d].m_pbox does not contain start of trim.\n",trim.m_trim_index);
3959     return false;
3960   }
3961 
3962   pt = trim.PointAtEnd();
3963 
3964   if ( !pbox.IsPointIn(pt) )
3965   {
3966     if ( text_log )
3967        text_log->Print("ON_Brep.m_T[%d].m_pbox does not contain end of trim.\n",trim.m_trim_index);
3968     return false;
3969   }
3970 
3971   pt = trim.PointAt(trim.Domain().ParameterAt(0.5));
3972   if ( !pbox.IsPointIn(pt) )
3973   {
3974     if ( text_log )
3975        text_log->Print("ON_Brep.m_T[%d].m_pbox does not contain middle of trim.\n",trim.m_trim_index);
3976     return false;
3977   }
3978 
3979   return true;
3980 }
3981 
3982 static
CheckTrimOnSrfHelper(const ON_Interval & srf_domain0,const ON_Interval & srf_domain1,const ON_BrepTrim & trim,ON_TextLog * text_log)3983 bool CheckTrimOnSrfHelper( const ON_Interval& srf_domain0,
3984                            const ON_Interval& srf_domain1,
3985                            const ON_BrepTrim& trim,
3986                            ON_TextLog* text_log
3987                            )
3988 {
3989   // this check only works if the pline exists.
3990   const ON_BrepTrimPoint* tp = trim.m_pline.Array();
3991   int i, count = trim.m_pline.Count();
3992 
3993   /*
3994   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
3995   be on the surface.  If you get a Check error here and feel the need to change this,
3996   discuss first with Chuck or Dale L and document with RR item numbers.
3997   const double a = -0.01;
3998   const double b =  1.01;
3999 
4000   26 June 2012 Chuck and Dale Lear
4001     Concerning bugs
4002       http://dev.mcneel.com/bugtrack/?q=106304
4003       http://dev.mcneel.com/bugtrack/?q=107842
4004 
4005     We are moving the relative fuzz back to 1%
4006     because making it smaller is generating
4007     more tech support than it is worth at this
4008     point.
4009 
4010     We did learn that 2d trim curves leak off the
4011     surface domain a bit fairly often and that
4012     forcing the 2d pline to be in the surface domain
4013     but leaving the 2d trim curve as is does not
4014     fix the bugs cited above.
4015   */
4016   const double a = -0.01;
4017   const double b =  1.01;
4018 
4019   double s,t;
4020   for ( i = 0; i < count; i++ )
4021   {
4022     s = srf_domain0.NormalizedParameterAt(tp[i].p.x);
4023     t = srf_domain1.NormalizedParameterAt(tp[i].p.y);
4024     if ( s < a || s > b || t < a || t > b )
4025     {
4026       if ( text_log )
4027       {
4028         text_log->Print("ON_Brep.m_T[%d] 2d curve is not inside surface domain.\n",trim.m_trim_index);
4029       }
4030       return false;
4031     }
4032   }
4033   return true;
4034 }
4035 
4036 static
CheckLoopOnSrfHelper(const ON_Brep & brep,const ON_Interval & srf_domain0,const ON_Interval & srf_domain1,const ON_BrepLoop & loop,ON_TextLog * text_log)4037 bool CheckLoopOnSrfHelper( const ON_Brep& brep,
4038                            const ON_Interval& srf_domain0,
4039                            const ON_Interval& srf_domain1,
4040                            const ON_BrepLoop& loop,
4041                            ON_TextLog* text_log
4042                            )
4043 {
4044   for ( int lti = 0; lti < loop.m_ti.Count(); lti++ )
4045   {
4046     int ti = loop.m_ti[lti];
4047     if ( ti < 0 || ti >= brep.m_T.Count() )
4048       continue;
4049     if ( ! CheckTrimOnSrfHelper( srf_domain0, srf_domain1, brep.m_T[ti], text_log ) )
4050       return false;
4051   }
4052   return true;
4053 }
4054 
4055 ON_BOOL32
IsValid(ON_TextLog * text_log) const4056 ON_Brep::IsValid( ON_TextLog* text_log ) const
4057 {
4058   const int curve2d_count = m_C2.Count();
4059   const int curve3d_count = m_C3.Count();
4060   const int surface_count = m_S.Count();
4061   const int vertex_count  = m_V.Count();
4062   const int edge_count    = m_E.Count();
4063   const int trim_count    = m_T.Count();
4064   const int loop_count    = m_L.Count();
4065   const int face_count    = m_F.Count();
4066 
4067   int c2i, c3i, si, vi, ei, fi, ti, li;
4068 
4069   if ( 0 == face_count && 0 == edge_count && 0 == vertex_count )
4070   {
4071     if ( text_log )
4072       text_log->Print( "ON_Brep has no faces, edges, or vertices\n");
4073     return ON_BrepIsNotValid();
4074   }
4075 
4076   if ( 0 != face_count )
4077   {
4078     if ( 0 == edge_count )
4079     {
4080       if ( text_log )
4081         text_log->Print( "ON_Brep has no edges.\n");
4082       return ON_BrepIsNotValid();
4083     }
4084     if ( 0 == loop_count )
4085     {
4086       if ( text_log )
4087         text_log->Print( "ON_Brep has no loops.\n");
4088       return ON_BrepIsNotValid();
4089     }
4090     if ( 0 == surface_count )
4091     {
4092       if ( text_log )
4093         text_log->Print( "ON_Brep has no surfaces.\n");
4094       return ON_BrepIsNotValid();
4095     }
4096     if ( 0 == trim_count )
4097     {
4098       if ( text_log )
4099         text_log->Print( "ON_Brep has no trims.\n");
4100       return ON_BrepIsNotValid();
4101     }
4102     if ( 0 == curve2d_count )
4103     {
4104       if ( text_log )
4105         text_log->Print( "ON_Brep has no 2d curves.\n");
4106       return ON_BrepIsNotValid();
4107     }
4108   }
4109 
4110   if ( 0 != edge_count )
4111   {
4112     if ( 0 == curve3d_count )
4113     {
4114       if ( text_log )
4115         text_log->Print( "ON_Brep has no 3d curves.\n");
4116       return ON_BrepIsNotValid();
4117     }
4118     if ( 0 == vertex_count )
4119     {
4120       if ( text_log )
4121         text_log->Print( "ON_Brep has no vertices.\n");
4122       return ON_BrepIsNotValid();
4123     }
4124   }
4125 
4126   // check element indices match array positions
4127   for ( vi = 0; vi < vertex_count; vi++ )
4128   {
4129     if ( m_V[vi].m_vertex_index == -1 )
4130     {
4131       const ON_BrepVertex& vertex = m_V[vi];
4132       if ( vertex.m_ei.Count() > 0 )
4133       {
4134         if ( text_log )
4135           text_log->Print( "ON_Brep.m_V[%d] is deleted (m_vertex_index = -1) but vertex.m_ei.Count() = %d.\n",
4136                            vi, vertex.m_ei.Count() );
4137         return ON_BrepIsNotValid();
4138       }
4139     }
4140     else if ( m_V[vi].m_vertex_index != vi )
4141     {
4142       if ( text_log )
4143         text_log->Print( "ON_Brep.m_V[%d].m_vertex_index = %d (should be %d)\n",
4144                          vi, m_V[vi].m_vertex_index, vi );
4145       return ON_BrepIsNotValid();
4146     }
4147   }
4148 
4149   for ( ei = 0; ei < edge_count; ei++ )
4150   {
4151     if ( m_E[ei].m_edge_index == -1 )
4152     {
4153       const ON_BrepEdge& edge = m_E[ei];
4154       if ( edge.m_ti.Count() > 0 )
4155       {
4156         if ( text_log )
4157           text_log->Print( "ON_Brep.m_E[%d] is deleted (m_edge_index = -1) but edge.m_ti.Count() = %d.\n",
4158                            ei, edge.m_ti.Count() );
4159         return ON_BrepIsNotValid();
4160       }
4161       if ( edge.m_c3i != -1 )
4162       {
4163         if ( text_log )
4164           text_log->Print( "ON_Brep.m_E[%d] is deleted (m_edge_index = -1) but edge.m_c3i=%d (should be -1).\n",
4165                            ei, edge.m_c3i );
4166         return ON_BrepIsNotValid();
4167       }
4168       if ( edge.ProxyCurve() )
4169       {
4170         if ( text_log )
4171           text_log->Print( "ON_Brep.m_E[%d] is deleted (m_edge_index = -1) but edge.m_curve is not NULL.\n",
4172                            ei );
4173         return ON_BrepIsNotValid();
4174       }
4175       if ( edge.m_vi[0] != -1 )
4176       {
4177         if ( text_log )
4178           text_log->Print( "ON_Brep.m_E[%d] is deleted (m_edge_index = -1) but edge.m_vi[0]=%d (should be -1).\n",
4179                            ei, edge.m_vi[0] );
4180         return ON_BrepIsNotValid();
4181       }
4182       if ( edge.m_vi[1] != -1 )
4183       {
4184         if ( text_log )
4185           text_log->Print( "ON_Brep.m_E[%d] is deleted (m_edge_index = -1) but edge.m_vi[1]=%d (should be -1).\n",
4186                            ei, edge.m_vi[1] );
4187         return ON_BrepIsNotValid();
4188       }
4189     }
4190     else if ( m_E[ei].m_edge_index != ei )
4191     {
4192       if ( text_log )
4193         text_log->Print( "ON_Brep.m_E[%d].m_edge_index = %d (should be %d)\n",
4194                          ei, m_E[ei].m_edge_index, ei );
4195       return ON_BrepIsNotValid();
4196     }
4197   }
4198 
4199   for ( ti = 0; ti < trim_count; ti++ )
4200   {
4201     if ( m_T[ti].m_trim_index == -1 )
4202     {
4203       const ON_BrepTrim& trim = m_T[ti];
4204       if ( trim.m_ei != -1 )
4205       {
4206         if ( text_log )
4207           text_log->Print( "ON_Brep.m_T[%d] is deleted (m_trim_index = -1) but trim.m_ei=%d (should be -1).\n",
4208                            ti, trim.m_ei );
4209         return ON_BrepIsNotValid();
4210       }
4211       if ( trim.m_li != -1 )
4212       {
4213         if ( text_log )
4214           text_log->Print( "ON_Brep.m_T[%d] is deleted (m_trim_index = -1) but trim.m_li=%d (should be -1).\n",
4215                            ti, trim.m_li );
4216         return ON_BrepIsNotValid();
4217       }
4218       if ( trim.m_c2i != -1 )
4219       {
4220         if ( text_log )
4221           text_log->Print( "ON_Brep.m_T[%d] is deleted (m_trim_index = -1) but trim.m_c2i=%d (should be -1).\n",
4222                            ti, trim.m_c2i );
4223         return ON_BrepIsNotValid();
4224       }
4225       if ( trim.m_vi[0] != -1 )
4226       {
4227         if ( text_log )
4228           text_log->Print( "ON_Brep.m_T[%d] is deleted (m_trim_index = -1) but trim.m_vi[0]=%d (should be -1).\n",
4229                            ti, trim.m_vi[0] );
4230         return ON_BrepIsNotValid();
4231       }
4232       if ( trim.m_vi[1] != -1 )
4233       {
4234         if ( text_log )
4235           text_log->Print( "ON_Brep.m_T[%d] is deleted (m_trim_index = -1) but trim.m_vi[1]=%d (should be -1).\n",
4236                            ti, trim.m_vi[1] );
4237         return ON_BrepIsNotValid();
4238       }
4239     }
4240     else if ( m_T[ti].m_trim_index != ti  )
4241     {
4242       if ( text_log )
4243         text_log->Print( "ON_Brep.m_T[%d].m_trim_index = %d (should be %d)\n",
4244                          ti, m_T[ti].m_trim_index, ti );
4245       return ON_BrepIsNotValid();
4246     }
4247     else if ( !m_T[ti].IsValid( text_log ) )
4248     {
4249       if ( text_log )
4250         text_log->Print( "ON_Brep.m_T[%d] is not valid\n",ti );
4251       return ON_BrepIsNotValid();
4252     }
4253   }
4254 
4255   for ( li = 0; li < loop_count; li++ )
4256   {
4257     if ( m_L[li].m_loop_index == -1 )
4258     {
4259       const ON_BrepLoop& loop = m_L[li];
4260       if ( loop.m_fi != -1 )
4261       {
4262         if ( text_log )
4263           text_log->Print( "ON_Brep.m_L[%d] is deleted (m_loop_index = -1) but loop.m_fi=%d (should be -1).\n",
4264                            li, loop.m_fi );
4265         return ON_BrepIsNotValid();
4266       }
4267       if ( loop.m_ti.Count() > 0 )
4268       {
4269         if ( text_log )
4270           text_log->Print( "ON_Brep.m_L[%d] is deleted (m_loop_index = -1) but loop.m_ti.Count()=%d.\n",
4271                            li, loop.m_ti.Count() );
4272         return ON_BrepIsNotValid();
4273       }
4274     }
4275     else if ( m_L[li].m_loop_index != li )
4276     {
4277       if ( text_log )
4278         text_log->Print( "ON_Brep.m_L[%d].m_loop_index = %d (should be %d)\n",
4279                          li, m_L[li].m_loop_index, li );
4280       return ON_BrepIsNotValid();
4281     }
4282   }
4283 
4284   for ( fi = 0; fi < face_count; fi++ )
4285   {
4286     if ( m_F[fi].m_face_index == -1 )
4287     {
4288       const ON_BrepFace& face = m_F[fi];
4289       if ( face.m_si != -1 )
4290       {
4291         if ( text_log )
4292           text_log->Print( "ON_Brep.m_F[%d] is deleted (m_face_index = -1) but face.m_si=%d (should be -1).\n",
4293                            fi, face.m_si );
4294         return ON_BrepIsNotValid();
4295       }
4296       if ( face.ProxySurface() )
4297       {
4298         if ( text_log )
4299           text_log->Print( "ON_Brep.m_F[%d] is deleted (m_face_index = -1) but face.ProxySurface() is not NULL.\n",
4300                            fi );
4301         return ON_BrepIsNotValid();
4302       }
4303       if ( face.m_li.Count() > 0 )
4304       {
4305         if ( text_log )
4306           text_log->Print( "ON_Brep.m_F[%d] is deleted (m_face_index = -1) but face.m_li.Count()=%d.\n",
4307                            fi, face.m_li.Count() );
4308         return ON_BrepIsNotValid();
4309       }
4310     }
4311     else if ( m_F[fi].m_face_index != fi )
4312     {
4313       if ( text_log )
4314         text_log->Print( "ON_Brep.m_F[%d].m_face_index = %d (should be %d)\n",
4315                          fi, m_F[fi].m_face_index, fi );
4316       return ON_BrepIsNotValid();
4317     }
4318   }
4319 
4320   // check 2d curve geometry
4321   for ( c2i = 0; c2i < curve2d_count; c2i++ ) {
4322     if ( !m_C2[c2i] )
4323     {
4324       continue;
4325       // NULL 2d curves are ok if they are not referenced
4326       //if ( text_log )
4327       //  text_log->Print("ON_Brep.m_C2[%d] is NULL.\n",c2i);
4328       //return ON_BrepIsNotValid();
4329     }
4330     if ( !m_C2[c2i]->IsValid(text_log) )
4331     {
4332       if ( text_log )
4333         text_log->Print("ON_Brep.m_C2[%d] is invalid.\n",c2i);
4334       return ON_BrepIsNotValid();
4335     }
4336     int c2_dim = m_C2[c2i]->Dimension();
4337     if ( c2_dim != 2 )
4338     {
4339       if ( text_log )
4340         text_log->Print("ON_Brep.m_C2[%d]->Dimension() = %d (should be 2).\n", c2i, c2_dim );
4341       return ON_BrepIsNotValid();
4342     }
4343     const ON_PolyCurve* polycurve = ON_PolyCurve::Cast(m_C2[c2i]);
4344     if ( polycurve && polycurve->IsNested() )
4345     {
4346       if ( text_log )
4347         text_log->Print("ON_Brep.m_C2[%d] is a nested polycurve.\n", c2i );
4348       return ON_BrepIsNotValid();
4349     }
4350   }
4351 
4352   // check 3d curve geometry
4353   for ( c3i = 0; c3i < curve3d_count; c3i++ ) {
4354     if ( !m_C3[c3i] )
4355     {
4356       continue;
4357       // NULL 3d curves are ok if they are not referenced
4358       //if ( text_log )
4359       //  text_log->Print("ON_Brep.m_C3[%d] is NULL.\n",c3i);
4360       //return ON_BrepIsNotValid();
4361     }
4362     if ( !m_C3[c3i]->IsValid(text_log) )
4363     {
4364       if ( text_log )
4365         text_log->Print("ON_Brep.m_C3[%d] is invalid.\n",c3i);
4366       return ON_BrepIsNotValid();
4367     }
4368     int c3_dim = m_C3[c3i]->Dimension();
4369     if ( c3_dim != 3 )
4370     {
4371       if ( text_log )
4372         text_log->Print("ON_Brep.m_C3[%d]->Dimension() = %d (should be 3).\n", c3i, c3_dim );
4373       return ON_BrepIsNotValid();
4374     }
4375     const ON_PolyCurve* polycurve = ON_PolyCurve::Cast(m_C3[c3i]);
4376     if ( polycurve && polycurve->IsNested() )
4377     {
4378       if ( text_log )
4379         text_log->Print("ON_Brep.m_C3[%d] is a nested polycurve.\n", c3i );
4380       return ON_BrepIsNotValid();
4381     }
4382   }
4383 
4384   // check 3d surface geometry
4385   for ( si = 0; si < surface_count; si++ ) {
4386     if ( !m_S[si] )
4387     {
4388       continue;
4389       // NULL 3d surfaces are ok if they are not referenced
4390       //if ( text_log )
4391       //  text_log->Print("ON_Brep.m_S[%d] is NULL.\n",si);
4392       //return ON_BrepIsNotValid();
4393     }
4394     if ( !m_S[si]->IsValid(text_log) )
4395     {
4396       if ( text_log )
4397         text_log->Print("ON_Brep.m_S[%d] is invalid.\n",si);
4398       return ON_BrepIsNotValid();
4399     }
4400     int dim = m_S[si]->Dimension();
4401     if ( dim != 3 )
4402     {
4403       if ( text_log )
4404         text_log->Print("ON_Brep.m_S[%d]->Dimension() = %d (should be 3).\n", si, dim );
4405       return ON_BrepIsNotValid();
4406     }
4407   }
4408 
4409   // check vertices
4410   for ( vi = 0; vi < vertex_count; vi++ ) {
4411     if ( m_V[vi].m_vertex_index == -1 )
4412       continue;
4413     if ( !IsValidVertex( vi, text_log ) ) {
4414       if ( text_log )
4415         text_log->Print("ON_Brep.m_V[%d] is invalid.\n",vi);
4416       return ON_BrepIsNotValid();
4417     }
4418   }
4419 
4420   // check edges
4421   for ( ei = 0; ei < edge_count; ei++ )
4422   {
4423     if ( m_E[ei].m_edge_index == -1 )
4424       continue;
4425     if ( !IsValidEdge( ei, text_log ) ) {
4426       if ( text_log )
4427         text_log->Print("ON_Brep.m_E[%d] is invalid.\n",ei);
4428       return ON_BrepIsNotValid();
4429     }
4430   }
4431 
4432   // check faces
4433   for ( fi = 0; fi < face_count; fi++ )
4434   {
4435     if ( m_F[fi].m_face_index == -1 )
4436       continue;
4437     if ( !IsValidFace( fi, text_log ) ) {
4438       if ( text_log )
4439         text_log->Print("ON_Brep.m_F[%d] is invalid.\n",fi);
4440       return ON_BrepIsNotValid();
4441     }
4442   }
4443 
4444   // Check loops - this check is necessary at the brep level
4445   // to make sure there are no orphaned loops.
4446   // ON_Brep::IsValidLoop(), which is called by ON_Brep::IsValidFace(),
4447   // performs loop-trim bookkeeping checks on all loops that are referenced
4448   // by a face.
4449   for ( li = 0; li < loop_count; li++ )
4450   {
4451     const ON_BrepLoop& loop = m_L[li];
4452     if ( m_L[li].m_loop_index == -1 )
4453       continue;
4454     if ( loop.m_fi < 0 || loop.m_fi >= m_F.Count() )
4455     {
4456       if ( text_log )
4457         text_log->Print("ON_Brep.m_L[%d].m_fi = %d is not invalid.\n",li,loop.m_fi);
4458       return ON_BrepIsNotValid();
4459     }
4460     if ( m_F[loop.m_fi].m_face_index != loop.m_fi )
4461     {
4462       if ( text_log )
4463         text_log->Print("ON_Brep.m_L[%d].m_fi = %d is a deleted face.\n",li,loop.m_fi);
4464       return ON_BrepIsNotValid();
4465     }
4466 
4467     // This for() loop check is performed in IsValidLoop() which is
4468     // called by IsValidFace() in the "check faces" loop above.
4469     // I think it can be removed.  If anybody every sees this code
4470     // find a flaw, please tell Dale Lear.
4471     for ( int lti = 0; lti < loop.m_ti.Count(); lti++ )
4472     {
4473       ti = loop.m_ti[lti];
4474       if ( ti < 0 || ti >= m_T.Count() )
4475       {
4476         if ( text_log )
4477           text_log->Print("ON_Brep.m_L[%d].m_ti[%d] = %d is not invalid.\n",li,lti,ti);
4478         return ON_BrepIsNotValid();
4479       }
4480       if ( m_T[ti].m_trim_index != ti )
4481       {
4482         if ( text_log )
4483           text_log->Print("ON_Brep.m_L[%d].m_ti[%d] = %d is a deleted trim.\n",li,lti,ti);
4484         return ON_BrepIsNotValid();
4485       }
4486     }
4487   }
4488 
4489   // check trims - this check is necessary at the brep
4490   // level to make sure there are no orphan trims and
4491   // to test tolerances.  Most of these tests are duplicates
4492   // of ones in ON_Brep::IsValidTrim, which is called by
4493   // ON_Brep::IsValidLoop, which is called by ON_Brep::IsValidFace.
4494   int seam_trim_count = 0;
4495   for ( ti = 0; ti < trim_count; ti++ )
4496   {
4497     const ON_BrepTrim& trim = m_T[ti];
4498     if ( trim.m_trim_index == -1 )
4499       continue;
4500 
4501     if ( trim.m_vi[0] < 0 || trim.m_vi[0] >= m_V.Count() )
4502     {
4503       if ( text_log )
4504         text_log->Print("ON_Brep.m_T[%d].m_vi[0] = %d is not invalid.\n",ti,trim.m_vi[0]);
4505       return ON_BrepIsNotValid();
4506     }
4507     if ( trim.m_vi[1] < 0 || trim.m_vi[1] >= m_V.Count() )
4508     {
4509       if ( text_log )
4510         text_log->Print("ON_Brep.m_T[%d].m_vi[1] = %d is not invalid.\n",ti,trim.m_vi[1]);
4511       return ON_BrepIsNotValid();
4512     }
4513 
4514     if ( m_V[trim.m_vi[0]].m_vertex_index != trim.m_vi[0] )
4515     {
4516       if ( text_log )
4517         text_log->Print("ON_Brep.m_T[%d].m_vi[0] is deleted.\n",ti);
4518       return ON_BrepIsNotValid();
4519     }
4520     if ( m_V[trim.m_vi[1]].m_vertex_index != trim.m_vi[1] )
4521     {
4522       if ( text_log )
4523         text_log->Print("ON_Brep.m_T[%d].m_vi[1] is deleted.\n",ti);
4524       return ON_BrepIsNotValid();
4525     }
4526 
4527     if ( trim.m_c2i < 0 || trim.m_c2i >= m_C2.Count() )
4528     {
4529       if ( text_log )
4530         text_log->Print("ON_Brep.m_T[%d].m_c2i = %d is not valid.\n",ti,trim.m_c2i);
4531       return ON_BrepIsNotValid();
4532     }
4533 
4534     if ( 0 == m_C2[trim.m_c2i] )
4535     {
4536       if ( text_log )
4537         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);
4538       return ON_BrepIsNotValid();
4539     }
4540 
4541     if ( trim.m_li < 0 || trim.m_li >= m_L.Count() )
4542     {
4543       if ( text_log )
4544         text_log->Print("ON_Brep.m_T[%d].m_li = %d is not valid.\n",ti,trim.m_li);
4545       return ON_BrepIsNotValid();
4546     }
4547 
4548     if ( m_L[trim.m_li].m_loop_index != trim.m_li )
4549     {
4550       if ( text_log )
4551         text_log->Print("ON_Brep.m_T[%d].m_li = %d is a deleted loop.\n",ti,trim.m_li);
4552       return ON_BrepIsNotValid();
4553     }
4554 
4555     {
4556       const ON_Curve* c2 = m_C2[trim.m_c2i];
4557       const ON_Surface* srf = m_S[m_F[m_L[trim.m_li].m_fi].m_si];
4558       if ( srf )
4559       {
4560         ON_Interval PD = trim.ProxyCurveDomain();
4561         ON_Surface::ISO iso = srf->IsIsoparametric(*c2, &PD);
4562         if ( trim.m_iso != iso )
4563         {
4564           if ( text_log )
4565             text_log->Print("ON_Brep.m_T[%d].m_iso = %d and it should be %d\n",ti,trim.m_iso,iso);
4566           return ON_BrepIsNotValid();
4567         }
4568       }
4569     }
4570 
4571     if ( trim.m_type == ON_BrepTrim::singular )
4572     {
4573       if ( trim.m_ei != -1 )
4574       {
4575         if ( text_log )
4576           text_log->Print("ON_Brep.m_T[%d].m_type = singular, but m_ei = %d (should be -1).\n",ti,trim.m_ei);
4577         return ON_BrepIsNotValid();
4578       }
4579       continue;
4580     }
4581 
4582     if ( trim.m_ei < 0 || trim.m_ei >= m_E.Count() )
4583     {
4584       if ( text_log )
4585         text_log->Print("ON_Brep.m_T[%d].m_ei = %d is not invalid.\n",ti,trim.m_ei);
4586       return ON_BrepIsNotValid();
4587     }
4588 
4589     const ON_BrepEdge& edge = m_E[trim.m_ei];
4590     if ( edge.m_edge_index != trim.m_ei )
4591     {
4592       if ( text_log )
4593         text_log->Print("ON_Brep.m_T[%d].m_ei is deleted.\n",ti);
4594       return ON_BrepIsNotValid();
4595     }
4596 
4597     const int evi0 = trim.m_bRev3d ? 1 : 0;
4598     const int evi1 = trim.m_bRev3d ? 0 : 1;
4599     if ( trim.m_vi[0] != edge.m_vi[evi0] )
4600     {
4601       if ( text_log )
4602         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);
4603       return ON_BrepIsNotValid();
4604     }
4605     if ( trim.m_vi[1] != edge.m_vi[evi1] )
4606     {
4607       if ( text_log )
4608         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);
4609       return ON_BrepIsNotValid();
4610     }
4611 
4612     // check tolerances and closed curve directions
4613     {
4614       ON_3dPoint trim_pt0, trim_pt1, srf_pt0, srf_pt1;
4615       ON_3dVector trim_der0, trim_der1, srf_du0, srf_dv0, srf_du1, srf_dv1;
4616       ON_Interval trim_domain = trim.Domain();
4617       // trim_pt0 should be closed to trim_pt1 except when
4618       // trim starts and ends on opposite sides of a surface
4619       // seam.  Even when the trim curve is closed, the
4620       // derivatives can be different when there is
4621       // a kink at the start/end of a trim.
4622       trim.Ev1Der( trim_domain[0], trim_pt0, trim_der0 );
4623       trim.Ev1Der( trim_domain[1], trim_pt1, trim_der1 );
4624 
4625       const ON_Surface* trim_srf = m_F[ m_L[trim.m_li].m_fi ].SurfaceOf();
4626       trim_srf->Ev1Der( trim_pt0.x, trim_pt0.y, srf_pt0, srf_du0, srf_dv0 );
4627       trim_srf->Ev1Der( trim_pt1.x, trim_pt1.y, srf_pt1, srf_du1, srf_dv1 );
4628 
4629       // estimate 3d tolerances from 2d trim tolerances
4630       double t0_tol = srf_du0.Length()*trim.m_tolerance[0] + srf_dv0.Length()*trim.m_tolerance[1];
4631       double t1_tol = srf_du1.Length()*trim.m_tolerance[0] + srf_dv1.Length()*trim.m_tolerance[1];
4632       ON_3dVector trim_tangent0 = trim_der0.x*srf_du0 + trim_der0.y*srf_dv0;
4633       trim_tangent0.Unitize();
4634       ON_3dVector trim_tangent1 = trim_der1.x*srf_du1 + trim_der1.y*srf_dv1;
4635       trim_tangent1.Unitize();
4636       ON_3dVector edge_tangent0 = edge.TangentAt( edge.Domain()[trim.m_bRev3d ? 1 : 0] );
4637       ON_3dVector edge_tangent1 = edge.TangentAt( edge.Domain()[trim.m_bRev3d ? 0 : 1] );
4638       double d0 = trim_tangent0*edge_tangent0;
4639       double d1 = trim_tangent1*edge_tangent1;
4640       if ( trim.m_bRev3d )
4641       {
4642         d0 = -d0;
4643         d1 = -d1;
4644       }
4645       if (    trim.m_vi[0] == trim.m_vi[1]
4646            && edge.m_vi[0] == edge.m_vi[1]
4647            && trim.m_vi[0] == edge.m_vi[0]
4648            )
4649       {
4650         // For high quality models, d0 and d1 should be close to +1.
4651         // If both are close to -1, the trim.m_bRev3d flag is most
4652         // likely set opposite of what it should be.
4653 
4654         // check start tangent to see if m_bRev3d is set correctly
4655         if ( d0 < 0.0 || d1 < 0.0)
4656         {
4657           if ( text_log )
4658           {
4659             if ( trim.m_bRev3d )
4660               text_log->Print("ON_Brep.m_T[%d].m_bRev3d = true, but closed curve directions are the same.\n",ti);
4661             else
4662               text_log->Print("ON_Brep.m_T[%d].m_bRev3d = false, but closed curve directions are opposite.\n",ti);
4663           }
4664           return ON_BrepIsNotValid();
4665         }
4666       }
4667 
4668       // Make sure edge and tolerances are realistic
4669       ON_3dPoint EdgeEnd[2];
4670       EdgeEnd[trim.m_bRev3d?1:0] = edge.PointAtStart();
4671       EdgeEnd[trim.m_bRev3d?0:1] = edge.PointAtEnd();
4672       d0 = EdgeEnd[0].DistanceTo(srf_pt0);
4673       d1 = EdgeEnd[1].DistanceTo(srf_pt1);
4674       double etol = edge.m_tolerance;
4675       double dtol = 10.0*(etol + t0_tol + t1_tol);
4676       if ( dtol < 0.01 )
4677         dtol = 0.01;
4678       if ( d0 > dtol  )
4679       {
4680         if ( text_log )
4681         {
4682           text_log->Print("Distance from start of ON_Brep.m_T[%d] to 3d edge is %g.  (edge tol = %g, trim tol ~ %g).\n",
4683                           ti, d0, etol,t0_tol);
4684         }
4685         return ON_BrepIsNotValid();
4686       }
4687       if ( d1 > dtol )
4688       {
4689         if ( text_log )
4690         {
4691           text_log->Print("Distance from end of ON_Brep.m_T[%d] to 3d edge is %g.  (edge tol = %g, trim tol ~ %g).\n",
4692                           ti, d1, etol,t1_tol);
4693         }
4694         return ON_BrepIsNotValid();
4695       }
4696     }
4697 
4698     // check trim's m_pbox
4699     {
4700       if ( trim.m_pbox.m_min.z != 0.0 )
4701       {
4702         if ( text_log )
4703            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);
4704         return ON_BrepIsNotValid();
4705       }
4706       if ( trim.m_pbox.m_max.z != 0.0 )
4707       {
4708         if ( text_log )
4709            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);
4710         return ON_BrepIsNotValid();
4711       }
4712 
4713       if ( !TestTrimPBox( trim, text_log ) )
4714         return ON_BrepIsNotValid();
4715 
4716     }
4717 
4718     if ( ON_BrepTrim::seam == trim.m_type )
4719     {
4720       // trim must be on a surface edge
4721       switch ( trim.m_iso )
4722       {
4723       case ON_Surface::S_iso:
4724         break;
4725       case ON_Surface::E_iso:
4726         break;
4727       case ON_Surface::N_iso:
4728         break;
4729       case ON_Surface::W_iso:
4730         break;
4731       default:
4732         if ( text_log )
4733           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);
4734         return ON_BrepIsNotValid();
4735       }
4736       seam_trim_count++;
4737     }
4738   }
4739 
4740   // check loop m_pboxes
4741   for ( li = 0; li < loop_count; li++ )
4742   {
4743     const ON_BrepLoop& loop = m_L[li];
4744     if ( loop.m_loop_index != li )
4745       continue;
4746     if ( loop.m_pbox.m_min.z != 0.0 )
4747     {
4748       if ( text_log )
4749          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);
4750       return ON_BrepIsNotValid();
4751     }
4752     if ( loop.m_pbox.m_max.z != 0.0 )
4753     {
4754       if ( text_log )
4755          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);
4756       return ON_BrepIsNotValid();
4757     }
4758     int first_trim_ti = -4;
4759     int first_trim_vi0 = -3;
4760     int prev_trim_vi1 = -2;
4761     int prev_trim_ti=-9;
4762     int lti;
4763     for ( lti = 0; lti < loop.m_ti.Count(); lti++ )
4764     {
4765       const ON_BrepTrim& trim = m_T[loop.m_ti[lti]];
4766       if ( !loop.m_pbox.IsPointIn(trim.m_pbox.m_min) || !loop.m_pbox.IsPointIn(trim.m_pbox.m_max) )
4767       {
4768         if ( text_log )
4769            text_log->Print("ON_Brep.m_L[%d].m_pbox does not contain m_T[loop.m_ti[%d]].m_pbox.\n",li,lti);
4770         return ON_BrepIsNotValid();
4771       }
4772       if ( 0 == lti )
4773       {
4774         first_trim_ti = loop.m_ti[lti];
4775         first_trim_vi0 = trim.m_vi[0];
4776       }
4777       else if ( prev_trim_vi1 != trim.m_vi[0] )
4778       {
4779         // 23 May 2003 Dale Lear
4780         //     Added this test to make sure adjacent trims
4781         //     in a loop shared vertices.
4782         if ( text_log )
4783            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]);
4784         return ON_BrepIsNotValid();
4785       }
4786       prev_trim_ti = loop.m_ti[lti];
4787       prev_trim_vi1 = trim.m_vi[1];
4788     }
4789 
4790     if ( first_trim_ti >= 0 && first_trim_vi0 != prev_trim_vi1 )
4791     {
4792       // 23 May 2003 Dale Lear
4793       //     Added this test to make sure adjacent trims
4794       //     in a loop shared vertices.
4795       if ( text_log )
4796          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",
4797                          li,lti-1,prev_trim_ti,prev_trim_vi1,0,first_trim_ti,first_trim_vi0);
4798       return ON_BrepIsNotValid();
4799     }
4800   }
4801 
4802   // 21 October 2003 Dale Lear - fix RR 11980 - check for split seams
4803   // This block of code assumes the preceding checks have all passed.
4804   // It looks for boundary trims on seams that should be joined as a seam trim.
4805   ON_Interval srf_domain[2];
4806   for ( fi = 0; fi < face_count; fi++ )
4807   {
4808     const ON_BrepFace& face = m_F[fi];
4809     if ( face.m_face_index < 0 )
4810       continue;
4811     const ON_Surface* srf = m_S[face.m_si];
4812     if ( 0 == srf )
4813       continue;
4814 
4815     srf_domain[0] = srf->Domain(0);
4816     srf_domain[1] = srf->Domain(1);
4817     for ( int fli = 0; fli < face.m_li.Count(); fli++ )
4818     {
4819       int li = face.m_li[fli];
4820       if ( li < 0 || li >= m_L.Count() )
4821         continue;
4822       if ( !CheckLoopOnSrfHelper(*this,srf_domain[0],srf_domain[1],m_L[li],text_log) )
4823         return ON_BrepIsNotValid();
4824     }
4825 
4826     const ON_BrepLoop* outer_loop = face.OuterLoop();
4827     if ( 0 == outer_loop )
4828       continue;
4829 
4830     ON_BOOL32 bClosed[2];
4831     bClosed[0] = srf->IsClosed(0);
4832     bClosed[1] = srf->IsClosed(1);
4833     if ( !bClosed[0] && !bClosed[1] )
4834       continue;
4835 
4836     const int outer_trim_count = outer_loop->m_ti.Count();
4837     int lti, lti1;
4838     int endpt_index = 0;
4839     ON_Surface::ISO iso_type;
4840     ON_Interval side_interval;
4841     double s0, s1;
4842     const double side_tol = 1.0e-4;
4843 
4844     for ( lti = 0; lti < outer_trim_count; lti++ )
4845     {
4846       const ON_BrepTrim& trim = m_T[outer_loop->m_ti[lti]];
4847       if ( ON_BrepTrim::boundary !=  trim.m_type )
4848         continue;
4849       if ( ON_Surface::E_iso == trim.m_iso && bClosed[0] )
4850       {
4851         iso_type = ON_Surface::W_iso;
4852         endpt_index = 1;
4853       }
4854       else if ( ON_Surface::W_iso == trim.m_iso && bClosed[0] )
4855       {
4856         iso_type = ON_Surface::E_iso;
4857         endpt_index = 1;
4858       }
4859       else if( ON_Surface::S_iso == trim.m_iso && bClosed[1] )
4860       {
4861         iso_type = ON_Surface::N_iso;
4862         endpt_index = 0;
4863       }
4864       else if( ON_Surface::N_iso == trim.m_iso && bClosed[1] )
4865       {
4866         iso_type = ON_Surface::S_iso;
4867         endpt_index = 0;
4868       }
4869       else
4870         continue;
4871 
4872       side_interval.Set(trim.PointAtStart()[endpt_index],trim.PointAtEnd()[endpt_index]);
4873       if ( ON_Surface::N_iso == iso_type || ON_Surface::W_iso == iso_type )
4874       {
4875         if ( !side_interval.IsIncreasing() )
4876           continue;
4877       }
4878       else
4879       {
4880         if ( !side_interval.IsDecreasing() )
4881           continue;
4882       }
4883 
4884       // search for seam
4885       for ( lti1 = 0; lti1 < outer_trim_count; lti1++ )
4886       {
4887         if ( lti1 == lti )
4888           continue;
4889         const ON_BrepTrim& trim1 = m_T[outer_loop->m_ti[lti1]];
4890         if ( iso_type != trim1.m_iso )
4891           continue;
4892         if ( ON_BrepTrim::boundary != trim1.m_type )
4893           continue;
4894 
4895         s1 = side_interval.NormalizedParameterAt(trim1.PointAtStart()[endpt_index]);
4896         if ( fabs(s1-1.0) > side_tol )
4897           continue;
4898         s0 = side_interval.NormalizedParameterAt(trim1.PointAtEnd()[endpt_index]);
4899         if ( fabs(s0) > side_tol )
4900           continue;
4901 
4902         if ( text_log )
4903         {
4904          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",
4905                          face.m_face_index,outer_loop->m_loop_index,
4906                          trim.m_trim_index,trim1.m_trim_index
4907                          );
4908         }
4909         return ON_BrepIsNotValid();
4910       }
4911     }
4912   }
4913 
4914   // make sure seam trims are properly matched.
4915   for ( ti = 0; seam_trim_count > 0 && ti < trim_count; ti++ )
4916   {
4917     const ON_BrepTrim& trim = m_T[ti];
4918     if ( trim.m_trim_index == -1 )
4919       continue;
4920     if ( ON_BrepTrim::seam != trim.m_type )
4921       continue;
4922     seam_trim_count--;
4923     if ( trim.m_ei < 0 || trim.m_ei >= edge_count )
4924     {
4925       if ( text_log )
4926       {
4927         text_log->Print("ON_Brep.m_T[%d] is a seam trim with an invalid m_ei.\n",ti);
4928         return ON_BrepIsNotValid();
4929       }
4930     }
4931 
4932     const ON_BrepEdge& edge = m_E[trim.m_ei];
4933     int trim1_index = -1;
4934     for ( int eti = 0; eti < edge.m_ti.Count(); eti++ )
4935     {
4936       const int ti1 = edge.m_ti[eti];
4937       if ( ti1 == ti
4938            || ti < 0
4939            || ti >= trim_count
4940          )
4941       {
4942         continue;
4943       }
4944       const ON_BrepTrim& trim1 = m_T[ti1];
4945       if ( trim1.m_trim_index == -1 )
4946         continue;
4947       if ( ON_BrepTrim::seam != trim1.m_type )
4948         continue;
4949       if ( trim1.m_li != trim.m_li )
4950         continue;
4951       if ( -1 == trim1_index )
4952       {
4953         trim1_index = ti1;
4954         continue;
4955       }
4956       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);
4957       return ON_BrepIsNotValid();
4958     }
4959 
4960     if ( trim1_index < 0 || trim1_index >= trim_count )
4961     {
4962       text_log->Print("ON_Brep.m_T[%d] is a seam trim with no matching seam trim in the same loop.\n",ti);
4963       return ON_BrepIsNotValid();
4964     }
4965 
4966     // previous validation step insures trim.m_iso = N/S/E/W_iso
4967     switch(trim.m_iso)
4968     {
4969     case ON_Surface::S_iso:
4970       if ( ON_Surface::N_iso != m_T[trim1_index].m_iso )
4971       {
4972         if (text_log )
4973           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);
4974         return ON_BrepIsNotValid();
4975       }
4976       break;
4977 
4978     case ON_Surface::E_iso:
4979       if ( ON_Surface::W_iso != m_T[trim1_index].m_iso )
4980       {
4981         if (text_log )
4982           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);
4983         return ON_BrepIsNotValid();
4984       }
4985       break;
4986 
4987     case ON_Surface::N_iso:
4988       if ( ON_Surface::S_iso != m_T[trim1_index].m_iso )
4989       {
4990         if (text_log )
4991           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);
4992         return ON_BrepIsNotValid();
4993       }
4994       break;
4995 
4996     case ON_Surface::W_iso:
4997       if ( ON_Surface::E_iso != m_T[trim1_index].m_iso )
4998       {
4999         if (text_log )
5000           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);
5001         return ON_BrepIsNotValid();
5002       }
5003       break;
5004 
5005     case ON_Surface::not_iso:
5006     case ON_Surface::x_iso:
5007     case ON_Surface::y_iso:
5008     case ON_Surface::iso_count:
5009       break; // keep gcc quiet
5010     }
5011 
5012   }
5013 
5014 #if 0
5015   // validate ON_BrepTrim.m_pline
5016   for ( ti = 0; ti < trim_count; ti++ )
5017   {
5018     const ON_BrepTrim& trim = m_T[ti];
5019     if ( trim.m_trim_index == -1 )
5020       continue;
5021     const int pline_count = trim.m_pline.Count();
5022     if ( 0 == pline_count )
5023       continue;
5024     if ( pline_count <= 1 )
5025     {
5026       if (text_log )
5027         text_log->Print("ON_Brep.m_T[%d].m_pline.Count() = 1. It should be 0 or >= 2\n",ti);
5028       return ON_BrepIsNotValid();
5029     }
5030 
5031     const ON_Interval trim_domain = trim.Domain();
5032     if ( !(trim.m_pline[0].t == trim_domain[0]) )
5033     {
5034       if (text_log )
5035         text_log->Print("ON_Brep.m_T[%d].m_pline[0].t != start of trim domain.\n",ti);
5036       return ON_BrepIsNotValid();
5037     }
5038     if ( !(trim.m_pline[pline_count-1].t == trim_domain[1]) )
5039     {
5040       if (text_log )
5041         text_log->Print("ON_Brep.m_T[%d].m_pline[%d].t != end of trim domain.\n",ti,pline_count-1);
5042       return ON_BrepIsNotValid();
5043     }
5044     for ( int i = 1; i < pline_count; i++ )
5045     {
5046       // pline trim "t" values must be valid
5047       if ( !ON_IsValid(trim.m_pline[i].t) )
5048       {
5049         if (text_log )
5050           text_log->Print("ON_Brep.m_T[%d].m_pline[%d].t is not a valid double.\n",ti,i);
5051         return ON_BrepIsNotValid();
5052       }
5053       if ( !(trim.m_pline[i-1].t < trim.m_pline[i].t) )
5054       {
5055         if (text_log )
5056           text_log->Print("ON_Brep.m_T[%d].m_pline[%d].t must be < m_pline[%d].t.\n",ti,i-1,i);
5057         return ON_BrepIsNotValid();
5058       }
5059     }
5060 
5061     if (    ON_UNSET_VALUE == trim.m_pline[0].e
5062          && ON_UNSET_VALUE == trim.m_pline[pline_count-1].e
5063        )
5064     {
5065       // the "e" values are not set.
5066       // This is permitted. The are set when extensive
5067       // trim-edge parameter correspondence is needed.
5068       // Meshing is an example of a calculation that sets
5069       // the "e" paramters.
5070       continue;
5071     }
5072 
5073     if ( trim.m_ei < 0 || trim.m_ei >= m_E.Count() )
5074     {
5075       if (text_log )
5076         text_log->Print("ON_Brep.m_T[%d].m_pline has e parameters but trim.m_ei is not valid.\n",ti);
5077       return ON_BrepIsNotValid();
5078     }
5079     const ON_BrepEdge& edge = m_E[trim.m_ei];
5080     const ON_Interval edge_domain = edge.Domain();
5081     const int i0 = trim.m_bRev3d ? pline_count-1 : 0;
5082     const int i1 = trim.m_bRev3d ? 0 : pline_count-1;
5083     const int di = trim.m_bRev3d ? -1 : 1;
5084     if ( !(trim.m_pline[i0].e == edge_domain[0]) )
5085     {
5086       if (text_log )
5087         text_log->Print("ON_Brep.m_T[%d].m_pline[%d].e != start of edge domain.\n",ti,i0);
5088       return ON_BrepIsNotValid();
5089     }
5090     if ( !(trim.m_pline[i1].e == edge_domain[1]) )
5091     {
5092       if (text_log )
5093         text_log->Print("ON_Brep.m_T[%d].m_pline[%d].e != end of edge domain.\n",ti,i1);
5094       return ON_BrepIsNotValid();
5095     }
5096     int prev_valid_i = i0;
5097     for ( int i = i0+di; i >= 0 && i < pline_count && i-di >= 0 && i-di < pline_count; i += di )
5098     {
5099       if ( !ON_IsValid(trim.m_pline[i].e) )
5100       {
5101         // internal "e" may be invalid when the setter
5102         // had troubles.  This is a symptom of a
5103         // bad trim or edge curve, but is not conclusive
5104         // proof.
5105         continue;
5106       }
5107       if ( !(trim.m_pline[prev_valid_i].e < trim.m_pline[i].e) )
5108       {
5109         if (text_log )
5110           text_log->Print("ON_Brep.m_T[%d].m_pline[%d].t must be < m_pline[%d].t.\n",ti,prev_valid_i,i);
5111         return ON_BrepIsNotValid();
5112       }
5113       prev_valid_i = i;
5114     }
5115   }
5116 #endif
5117 
5118   return true;
5119 }
5120 
5121 
5122 
SetEdgeVertex(const int ei,const int evi,const int vi)5123 bool ON_Brep::SetEdgeVertex( const int ei, const int evi, const int vi )
5124 {
5125   if ( ei < 0 || vi < 0 || evi < 0 || evi > 1 )
5126     return false;
5127   ON_BrepEdge& edge = m_E[ei];
5128   if ( edge.m_vi[evi] != vi ) {
5129     edge.m_vi[evi] = vi;
5130     ON_BrepVertex& vertex = m_V[vi];
5131     vertex.m_ei.Append(ei);
5132   }
5133   const int trim_count = edge.m_ti.Count();
5134   int eti, ti, tvi;
5135   for ( eti = 0; eti < trim_count; eti++ ) {
5136     ti = edge.m_ti[eti];
5137     if ( ti < 0 )
5138       continue;
5139     ON_BrepTrim& trim = m_T[ti];
5140     tvi = trim.m_bRev3d ? 1-evi : evi;
5141     trim.m_vi[tvi] = vi;
5142   }
5143   return true;
5144 }
5145 
HopAcrossEdge(int & ti,int & tvi) const5146 bool ON_Brep::HopAcrossEdge( int& ti, int& tvi ) const
5147 {
5148   // Tf ti is a trim associated with an interior manifold edge,
5149   // then ti is set to twin.
5150   int ei, evi, new_ti, new_tvi;
5151   if ( ti < 0 )
5152     return false;
5153   ei = m_T[ti].m_ei;
5154   if ( ei < 0 )
5155     return false;
5156   const ON_BrepEdge& edge = m_E[ei];
5157   if ( edge.m_ti.Count() < 2 )
5158     return false;
5159   evi = (m_T[ti].m_bRev3d) ? 1-tvi : tvi;
5160   new_ti = edge.m_ti[(edge.m_ti[0] == ti)?1:0];
5161   if ( new_ti < 0 )
5162     return false;
5163   new_tvi = (m_T[new_ti].m_bRev3d) ? 1-evi : evi;
5164   ti = new_ti;
5165   tvi = new_tvi;
5166   return true;
5167 }
5168 
SetTrimStartVertex(const int ti0,const int vi)5169 bool ON_Brep::SetTrimStartVertex( const int ti0, const int vi )
5170 {
5171   // Do not use NextEdge(), PrevEdge() because they require
5172   // the information we are in the act of creating.
5173   if ( ti0 < 0 || vi < 0 )
5174     return false;
5175   int next_ti, ti, ei, evi, tvi, counter;
5176   bool bEncounteredBoundaryTrim =  false;
5177 
5178   // Step counter clockwise around vertex until we hit a boundary
5179   // or we get back to where we started.
5180   for ( ti = ti0, tvi = 0, counter = 0; ti >= 0 && counter < 512; counter++ ) {
5181     if ( counter > 0 ) {
5182       if ( ti == ti0 && tvi == 0 )
5183         return true; // vertex was interior
5184     }
5185     ON_BrepTrim& trim = m_T[ti];
5186     if ( trim.m_type == ON_BrepTrim::singular ) {
5187       trim.m_vi[0] = trim.m_vi[1] = vi;
5188       tvi = 1-tvi;
5189       next_ti = (tvi) ? NextTrim(ti) : PrevTrim(ti);
5190       ti = next_ti;
5191       tvi = 1-tvi;
5192       if ( ti == ti0 && tvi == 0 )
5193       {
5194         if (bEncounteredBoundaryTrim)
5195           break;
5196         return true; // vertex was interior
5197       }
5198       if ( m_T[ti].m_type != ON_BrepTrim::singular )
5199       {
5200         // When ti is a boundary trim, then it is OK if hop fails.
5201         if ( !HopAcrossEdge( ti, tvi ) )
5202         {
5203           bEncounteredBoundaryTrim = true;
5204         }
5205       }
5206       continue;
5207     }
5208 
5209     ei = trim.m_ei;
5210     evi = (trim.m_bRev3d) ? 1-tvi : tvi;
5211     if ( !SetEdgeVertex( ei, evi, vi ) )
5212       return false;
5213     next_ti = (tvi) ? NextTrim(ti) : PrevTrim(ti);
5214     ti = next_ti;
5215     tvi = 1-tvi;
5216     if ( ti < 0 )
5217       return false; // should not happen
5218 
5219     if ( m_T[ti].m_type == ON_BrepTrim::singular )
5220       continue;
5221     ei = m_T[ti].m_ei;
5222     if ( ei < 0 )
5223       return false; // should not happen
5224     evi = (m_T[ti].m_bRev3d) ? 1-tvi : tvi;
5225     const int edge_trim_count = m_E[ei].m_ti.Count();
5226     if ( edge_trim_count < 1 )
5227       break; // should not happen
5228     if ( edge_trim_count == 1 ) {
5229       SetEdgeVertex( ei, evi, vi );
5230       bEncounteredBoundaryTrim = true;
5231       break; // ran into boundary
5232     }
5233     if ( !HopAcrossEdge( ti, tvi ) )
5234       return false;
5235   }
5236 
5237 
5238   // Get ready to step counter clockwise around vertex until
5239   // we hit a boundary.
5240   ti = ti0;
5241   tvi = 0;
5242   if ( m_T[ti].m_type == ON_BrepTrim::singular ) {
5243     // back up until we get to a non-singular trim
5244     while ( m_T[ti].m_type == ON_BrepTrim::singular ) {
5245       if ( ti != ti0 ) {
5246         m_T[ti].m_vi[0] = vi;
5247         m_T[ti].m_vi[1] = vi;
5248       }
5249       ti = PrevTrim(ti);
5250       tvi = 1;
5251       if ( ti == ti0 )
5252         break;
5253     }
5254     ei = m_T[ti].m_ei;
5255     if ( ei >= 0 ) {
5256       evi = (m_T[ti].m_bRev3d) ? 1-tvi : tvi;
5257       SetEdgeVertex( ei, evi, vi );
5258     }
5259   }
5260   else {
5261     ei = m_T[ti].m_ei;
5262   }
5263   if ( ei < 0 ) {
5264     // did the best we could - return true so setter keeps going
5265     // but the fact we are here means the brep is bogus.
5266     return true;
5267   }
5268   if ( m_E[ei].m_ti.Count() < 2 )
5269     return true; // ti0 is a boundary - we're done.
5270   if ( !HopAcrossEdge( ti, tvi ) )
5271     return false;
5272   next_ti = (tvi) ? NextTrim(ti) : PrevTrim(ti);
5273   if ( next_ti < 0 )
5274     return false;
5275   ti = next_ti;
5276   tvi = 1-tvi;
5277   if ( m_T[ti].m_type != ON_BrepTrim::singular ) {
5278     ei = m_T[ti].m_ei;
5279     if ( ei < 0 )
5280       return false;
5281     if ( m_E[ei].m_ti.Count() == 1 ) {
5282       evi = (m_T[ti].m_bRev3d)? 1-tvi : tvi;
5283       SetEdgeVertex( ei, evi, vi );
5284       return true;
5285     }
5286     if ( !HopAcrossEdge( ti, tvi ) )
5287       return false;
5288   }
5289 
5290   const int ti1 = ti;
5291   const int tvi1 = tvi;
5292 
5293   for ( ti = ti1, tvi = tvi1, counter = 0; ti >= 0 && counter < 512; counter++ ) {
5294     if ( counter > 0 ) {
5295       if ( ti == ti1 && tvi == tvi1 )
5296         return false; // vertex is not interior - so this should not happen
5297     }
5298     ON_BrepTrim& trim = m_T[ti];
5299     if ( trim.m_type == ON_BrepTrim::singular ) {
5300       trim.m_vi[0] = trim.m_vi[1] = vi;
5301       tvi = 1-tvi;
5302       next_ti = (tvi) ? NextTrim(ti) : PrevTrim(ti);
5303       ti = next_ti;
5304       tvi = 1-tvi;
5305       if ( ti == ti1 && tvi == tvi1 )
5306         return false; // vertex is not interior - so this should not happen
5307       if ( m_T[ti].m_type != ON_BrepTrim::singular )
5308         HopAcrossEdge( ti, tvi );  // OK if hop fails because ti is a boundary
5309       continue;
5310     }
5311 
5312     ei = trim.m_ei;
5313     evi = (trim.m_bRev3d) ? 1-tvi : tvi;
5314     if ( !SetEdgeVertex( ei, evi, vi ) )
5315       return false;
5316     next_ti = (tvi) ? NextTrim(ti) : PrevTrim(ti);
5317     ti = next_ti;
5318     tvi = 1-tvi;
5319     if ( ti < 0 )
5320       return false; // should not happen
5321 
5322     if ( m_T[ti].m_type == ON_BrepTrim::singular )
5323       continue;
5324     ei = m_T[ti].m_ei;
5325     if ( ei < 0 )
5326       return false; // should not happen
5327     evi = (m_T[ti].m_bRev3d) ? 1-tvi : tvi;
5328     const int edge_trim_count = m_E[ei].m_ti.Count();
5329     if ( edge_trim_count < 1 )
5330       break; // should not happen
5331     if ( edge_trim_count == 1 ) {
5332       SetEdgeVertex( ei, evi, vi );
5333       return true; // ran into boundary - expected
5334     }
5335     if ( !HopAcrossEdge( ti, tvi ) )
5336       return false;
5337   }
5338 
5339   return false; // should have exited by hitting "expected" boundary ~10 lines above
5340 }
5341 
SetLoopVertices(const int li)5342 void ON_Brep::SetLoopVertices( const int li )
5343 {
5344   ON_BrepLoop& loop = m_L[li];
5345   const int loop_trim_count = loop.m_ti.Count();
5346   int lti;
5347   for ( lti = 0; lti < loop_trim_count; lti++ ) {
5348     const int ti = loop.m_ti[lti];
5349     ON_BrepTrim& trim = m_T[ti];
5350     int vi = trim.m_vi[0];
5351     if ( vi >= 0 )
5352       continue;
5353     ON_BrepVertex& v = NewVertex();
5354     SetTrimStartVertex( ti, v.m_vertex_index );
5355   }
5356 }
5357 
ClearTrimVertices()5358 void ON_Brep::ClearTrimVertices()
5359 {
5360   int ti;
5361   const int tcnt = m_T.Count();
5362   for ( ti = 0; ti < tcnt; ti++ ) {
5363     ON_BrepTrim& trim = m_T[ti];
5364     trim.m_vi[0] = -1;
5365     trim.m_vi[1] = -1;
5366   }
5367 }
5368 
ClearEdgeVertices()5369 void ON_Brep::ClearEdgeVertices()
5370 {
5371   int ei;
5372   const int ecnt = m_E.Count();
5373   for ( ei = 0; ei < ecnt; ei++ ) {
5374     ON_BrepEdge& edge = m_E[ei];
5375     edge.m_vi[0] = -1;
5376     edge.m_vi[1] = -1;
5377   }
5378 }
5379 
NextTrim(int ti) const5380 int ON_Brep::NextTrim(int ti) const
5381 {
5382   const ON_BrepTrim& trim = m_T[ti];
5383   const int li = trim.m_li;
5384   const ON_BrepLoop& loop = m_L[li];
5385   const int trim_count = loop.m_ti.Count();
5386   int lti;
5387   for ( lti = 0;  lti < trim_count && loop.m_ti[lti] != ti; lti++)
5388     ;/* empty for*/
5389   if ( lti < 0 || lti >= trim_count )
5390     return -1;
5391   return loop.m_ti[(lti+1)%trim_count];
5392 }
5393 
PrevTrim(int ti) const5394 int ON_Brep::PrevTrim(int ti) const
5395 {
5396   const ON_BrepTrim& trim = m_T[ti];
5397   const int li = trim.m_li;
5398   const ON_BrepLoop& loop = m_L[li];
5399   const int trim_count = loop.m_ti.Count();
5400   int lti;
5401   for ( lti = 0; loop.m_ti[lti] != ti && lti < trim_count; lti++)
5402     ;/* empty for*/
5403   if ( lti < 0 || lti >= trim_count )
5404     return -1;
5405   return loop.m_ti[(lti+trim_count-1)%trim_count];
5406 }
5407 
NextEdge(int ei,int endi,int * next_endi) const5408 int ON_Brep::NextEdge(int ei, int endi, int* next_endi ) const
5409 {
5410   const ON_BrepEdge& edge = m_E[ei];
5411   const int vi = edge.m_vi[endi];
5412   const ON_BrepVertex& vertex = m_V[vi];
5413   const int edge_count = vertex.m_ei.Count();
5414   int vei;
5415   if ( edge_count < 2 )
5416     return -1;
5417   if ( next_endi )
5418     *next_endi = 0;
5419   for ( vei = 0; vertex.m_ei[vei] != ei && vei < edge_count; vei++)
5420     ;/* empty for*/
5421   if ( edge.m_vi[0] == edge.m_vi[1]  && endi ) {
5422     // get next occurance of edge index
5423     //
5424     // On closed edges, edge.m_vi[0] = edge.m_vi[1] and edge.edge_index
5425     // appears TWICE in vertex.m_ei[].  The first occurance of edge.edge_index
5426     // in vertex.m_ei[] corresponds to edge.m_vi[0].  The second occurance
5427     // of edge.edge_index in vertex.m_ei[] corresponds to edge.m_vi[1].
5428     vei++;
5429     while ( vei < edge_count && vertex.m_ei[vei] != ei )
5430       vei++;
5431   }
5432   if ( vei < 0 || vei >= edge_count )
5433     return -1;
5434   vei = (vei+1)%edge_count;
5435   const int next_ei = vertex.m_ei[vei];
5436   if ( next_endi ) {
5437     if ( m_E[next_ei].m_vi[0] == m_E[next_ei].m_vi[1] ) {
5438       *next_endi = 1;
5439       for ( vei++; vei < edge_count; vei++ ) {
5440         if ( vertex.m_ei[vei] == next_ei ) {
5441           *next_endi = 0;
5442           break;
5443         }
5444       }
5445     }
5446     else if ( m_E[next_ei].m_vi[1] == vi )
5447       *next_endi = 1;
5448   }
5449   return next_ei;
5450 }
5451 
PrevEdge(int ei,int endi,int * prev_endi) const5452 int ON_Brep::PrevEdge(int ei, int endi, int* prev_endi ) const
5453 {
5454   const ON_BrepEdge& edge = m_E[ei];
5455   const int vi = edge.m_vi[endi];
5456   const ON_BrepVertex& vertex = m_V[vi];
5457   const int edge_count = vertex.m_ei.Count();
5458   if ( edge_count < 2 )
5459     return -1;
5460   int vei;
5461   if ( prev_endi )
5462     *prev_endi = 0;
5463   for ( vei = 0; vertex.m_ei[vei] != ei && vei < edge_count; vei++)
5464     ;/* empty for*/
5465   if ( edge.m_vi[0] == edge.m_vi[1] && endi ) {
5466     // get next occurance of edge index
5467     //
5468     // On closed edges, edge.m_vi[0] = edge.m_vi[1] and edge.edge_index
5469     // appears TWICE in vertex.m_ei[].  The first occurance of edge.edge_index
5470     // in vertex.m_ei[] corresponds to edge.m_vi[0].  The second occurance
5471     // of edge.edge_index in vertex.m_ei[] corresponds to edge.m_vi[1].
5472     vei++;
5473     while ( vei < edge_count && vertex.m_ei[vei] != ei )
5474       vei++;
5475   }
5476   if ( vei < 0 || vei >= edge_count )
5477     return -1;
5478   vei = (vei+edge_count-1)%edge_count;
5479   const int prev_ei = vertex.m_ei[(vei+edge_count-1)%edge_count];
5480   if ( prev_endi ) {
5481     if ( m_E[prev_ei].m_vi[0] == m_E[prev_ei].m_vi[1] ) {
5482       *prev_endi = 1;
5483       for ( vei++; vei < edge_count; vei++ ) {
5484         if ( vertex.m_ei[vei] == prev_ei ) {
5485           *prev_endi = 0;
5486           break;
5487         }
5488       }
5489     }
5490     else if ( m_E[prev_ei].m_vi[1] == vi ) {
5491       *prev_endi = 1;
5492     }
5493   }
5494   return prev_ei;
5495 }
5496 
5497 // HELPER CLASS - DO NOT PUT DEFINITION IN A HEADER FILE
5498 class ON__EDGE_ENDS
5499 {
5500 public:
5501   // used to sort vertices of closed edges that need
5502   // to be combined.
5503   int vi0; // smallest edge vertex index
5504   int vi1; // largest edge vertex index
5505   int ei;  // index of closed edge
operator <(const ON__EDGE_ENDS & other) const5506   bool operator<(const ON__EDGE_ENDS& other) const
5507   {
5508     int i = other.vi0 - vi0;
5509     if ( i < 0 ) return true;
5510     if ( i > 0 ) return false;
5511     i = other.vi1 - vi1;
5512     if ( i < 0 ) return true;
5513     if ( i > 0 ) return false;
5514     i = other.ei - ei;
5515     if ( i < 0 ) return true;
5516     return false;
5517   }
5518 };
5519 
SetVertices(void)5520 void ON_Brep::SetVertices(void)
5521 {
5522   const int face_count = m_F.Count();
5523   int fi;
5524 
5525   ClearEdgeVertices();
5526   ClearTrimVertices();
5527   m_V.Empty();
5528   m_V.Shrink();
5529   fi = m_E.Count() - m_F.Count() + 8;
5530   if ( fi < 32 )
5531     fi = 32;
5532   m_V.Reserve( fi );
5533   for ( fi = 0; fi < face_count; fi++ ) {
5534     ON_BrepFace& face = m_F[fi];
5535     const int loop_count = face.m_li.Count();
5536     int fli;
5537     for ( fli = 0; fli < loop_count; fli++ ) {
5538       SetLoopVertices( face.m_li[fli] );
5539     }
5540   }
5541 
5542   // average edges' end location to get vertex location
5543   const int vertex_count = m_V.Count();
5544   int vi;
5545   ON_3dPoint VP, EP;
5546   for ( vi = 0; vi < vertex_count; vi++ )
5547   {
5548     VP.Zero();
5549     double d = 0.0;
5550     ON_BrepVertex& vertex = m_V[vi];
5551     const int edge_count = vertex.m_ei.Count();
5552     int vei;
5553     for ( vei = 0; vei < edge_count; vei++ )
5554     {
5555       const int ei = vertex.m_ei[vei];
5556       if ( ei < 0 )
5557         continue;
5558       const ON_BrepEdge& edge = m_E[ei];
5559       if ( edge.m_c3i < 0 )
5560         continue;
5561       const ON_Curve* pC = edge.EdgeCurveOf();
5562       if ( !pC )
5563         continue;
5564       if ( edge.m_vi[0] == vi )
5565         EP = edge.PointAtStart();
5566       else if ( edge.m_vi[1] == vi )
5567         EP = edge.PointAtEnd();
5568       else
5569         continue;
5570       VP.x += EP.x;
5571       VP.y += EP.y;
5572       VP.z += EP.z;
5573       d += 1.0;
5574     }
5575     if ( d > 0.0 )
5576     {
5577       d = 1.0/d;
5578       vertex.point = d*VP;
5579     }
5580   }
5581 
5582   const int edge_count = m_E.Count();
5583   int ei;
5584   ON_SimpleArray<ON__EDGE_ENDS> edge_ends(edge_count/4 + 2);
5585   for ( ei = 0; ei < edge_count; ei++ )
5586   {
5587     // see if we have any 3d edges that are closed as 3d curves
5588     // but have distinct end vertices
5589     const ON_BrepEdge& edge = m_E[ei];
5590     if (    edge.m_vi[0] >= 0
5591          && edge.m_vi[1] >= 0
5592          && edge.m_vi[0] != edge.m_vi[1]
5593          && 0 != edge.EdgeCurveOf()
5594          && edge.IsClosed() )
5595     {
5596       ON__EDGE_ENDS& ee = edge_ends.AppendNew();
5597       if ( edge.m_vi[0] < edge.m_vi[1] )
5598       {
5599         ee.vi0 = edge.m_vi[0];
5600         ee.vi1 = edge.m_vi[1];
5601       }
5602       else
5603       {
5604         ee.vi0 = edge.m_vi[1];
5605         ee.vi1 = edge.m_vi[0];
5606       }
5607       ee.ei = ei;
5608     }
5609   }
5610 
5611   if ( edge_ends.Count() > 0 )
5612   {
5613     // we need to combine some vertices and the ends of closed edges
5614     edge_ends.QuickSort( ON_CompareIncreasing<ON__EDGE_ENDS> );
5615     int edge_ends_count = edge_ends.Count();
5616     int i0, i1, vi0, vi1, i;
5617 
5618     // adjust indices of chained closed edges
5619     for ( i = 1; i < edge_ends_count; i++ )
5620     {
5621       bool bSortAgain = false;
5622       for ( i0 = 0; i0 < edge_ends_count; i0++ )
5623       {
5624         vi0 = edge_ends[i0].vi0;
5625         vi1 = edge_ends[i0].vi1;
5626         for ( i1 = i0+1; i1 < edge_ends_count; i1++ )
5627         {
5628           ON__EDGE_ENDS& ee = edge_ends[i1];
5629           if ( ee.vi0 == vi1 )
5630           {
5631             ee.vi0 = vi0;
5632             bSortAgain = true;
5633           }
5634           if ( ee.vi1 == vi1 )
5635           {
5636             ee.vi1 = ee.vi0;
5637             ee.vi0 = vi0;
5638             bSortAgain = true;
5639           }
5640         }
5641       }
5642       if ( bSortAgain )
5643       {
5644         edge_ends.QuickSort( ON_CompareIncreasing<ON__EDGE_ENDS> );
5645       }
5646       else
5647         break;
5648     }
5649 
5650     // combine vertices at ends of closed edges into a single vertex
5651     bool bCullUnusedVertices = false;
5652     for ( i0 = 0, i1 = 1; i0 < edge_ends.Count(); i0 = i1 )
5653     {
5654       vi0 = edge_ends[i0].vi0;
5655       for ( i1 = i0+1; i1 < edge_ends.Count() && vi0 == edge_ends[i1].vi0; i1++ )
5656       {
5657         // empty body
5658       }
5659       vi1 = vi0;
5660       for ( i = i0; i < i1; i++ )
5661       {
5662         if ( edge_ends[i].vi1 > vi1 )
5663         {
5664           vi1 = edge_ends[i].vi1;
5665           if ( 0 <= vi0 && vi0 < vi1 && vi1 < m_V.Count())
5666           {
5667             CombineCoincidentVertices(m_V[vi0],m_V[vi1] );
5668             bCullUnusedVertices = true;
5669           }
5670         }
5671       }
5672     }
5673     if ( bCullUnusedVertices )
5674       CullUnusedVertices();
5675   }
5676 }
5677 
m__legacy_flags_Set(int gcon,int mono)5678 void ON_BrepTrim::m__legacy_flags_Set(int gcon, int mono)
5679 {
5680   m__legacy_flags = 0;
5681   switch(gcon)
5682   {
5683   case -1:
5684     m__legacy_flags |= 1;
5685     break;
5686   case 0:
5687     m__legacy_flags |= 2;
5688     break;
5689   case 1:
5690     m__legacy_flags |= 3;
5691     break;
5692   case 2:
5693     m__legacy_flags |= 4;
5694     break;
5695   }
5696   if (mono)
5697     m__legacy_flags |= 8;
5698   else
5699     m__legacy_flags |= 16;
5700 }
5701 
m__legacy_flags_Get(int * gcon,int * mono) const5702 bool ON_BrepTrim::m__legacy_flags_Get(int* gcon, int* mono) const
5703 {
5704   if ( gcon ) {
5705     switch ( m__legacy_flags & 7 )
5706     {
5707     case 1:
5708       *gcon = -1;
5709       break;
5710     case 2:
5711       *gcon = 0;
5712       break;
5713     case 3:
5714       *gcon = 1;
5715       break;
5716     case 4:
5717       *gcon = 2;
5718       break;
5719     default:
5720       *gcon = -1;
5721     }
5722   }
5723   if ( mono ) {
5724     if ( 0 != (m__legacy_flags&8) )
5725       *mono = 1;
5726     else
5727       *mono = 0;
5728   }
5729   return m__legacy_flags ? true : false;
5730 }
SetTolsFromLegacyValues()5731 void ON_Brep::SetTolsFromLegacyValues()
5732 {
5733   // use m_2d_tol and m_3d_tol read from file to set public tolerances
5734   const int vcnt = m_V.Count();
5735   const int tcnt = m_T.Count();
5736   ON_3dPoint endP;
5737   double d;
5738   int vi, ti, vei, evi, vecnt;
5739 
5740   // set trim and edge tolerances from values in file
5741   for ( ti = 0; ti < tcnt; ti++ ) {
5742     ON_BrepTrim& trim = m_T[ti];
5743     trim.m_tolerance[0] = trim.m__legacy_2d_tol; // "pe_tol"
5744     trim.m_tolerance[1] = trim.m__legacy_2d_tol; // "pe_tol"
5745     if ( trim.m_ei >= 0 ) {
5746       ON_BrepEdge& edge = m_E[trim.m_ei];
5747       if ( edge.m_tolerance < trim.m__legacy_3d_tol )
5748         edge.m_tolerance = trim.m__legacy_3d_tol; // "e_tol"
5749     }
5750   }
5751 
5752   // set vertex tolerances from edge tols and end evaluations
5753   for ( vi = 0; vi < vcnt; vi++ ) {
5754     ON_BrepVertex& vertex = m_V[vi];
5755     vecnt = vertex.m_ei.Count();
5756     for ( vei = 0; vei < vecnt; vei++ ) {
5757       const ON_BrepEdge& edge = m_E[vertex.m_ei[vei]];
5758       if ( vertex.m_tolerance < edge.m_tolerance )
5759         vertex.m_tolerance = edge.m_tolerance;
5760       const ON_Curve* c = m_C3[edge.m_c3i];
5761       evi = 0;
5762       if ( edge.m_vi[0] != vi )
5763         evi = 1;
5764       if ( edge.m_vi[evi] == vi ) {
5765         endP = c->PointAt( c->Domain()[evi] );
5766         d = vertex.point.DistanceTo( endP );
5767         if ( d > vertex.m_tolerance ) {
5768           vertex.m_tolerance = d;
5769         }
5770       }
5771     }
5772   }
5773 }
5774 
ObjectType() const5775 ON::object_type ON_Brep::ObjectType() const
5776 {
5777   // This must ALWAYS return ON::brep_object.
5778   // NEVER modify this function to return any
5779   // other value.
5780   return ON::brep_object;
5781 }
5782 
ClearBoundingBox()5783 void ON_Brep::ClearBoundingBox()
5784 {
5785   m_bbox.Destroy();
5786 }
5787 
ClearBoundingBox()5788 void ON_BrepFace::ClearBoundingBox()
5789 {
5790   m_bbox.Destroy();
5791 }
5792 
5793 ON_BOOL32
GetBBox(double * box_min,double * box_max,ON_BOOL32 bGrowBox) const5794 ON_BrepFace::GetBBox(
5795           double* box_min, // [3],
5796           double* box_max, // [3],
5797           ON_BOOL32 bGrowBox     // = false
5798           ) const
5799 {
5800   if ( !m_bbox.IsValid()
5801        && 0 != m_brep
5802        && m_face_index >= 0
5803        && m_face_index < m_brep->m_F.Count()
5804        && &m_brep->m_F[m_face_index] == this
5805        )
5806   {
5807     const ON_Surface* srf = ProxySurface();
5808     if ( srf && srf != this )
5809     {
5810       srf->GetBoundingBox( const_cast<ON_BrepFace*>(this)->m_bbox, false );
5811     }
5812   }
5813 
5814   ON_BOOL32 rc = m_bbox.IsValid();
5815   if (rc)
5816   {
5817     ON_BoundingBox bbox = m_bbox;
5818     if ( bGrowBox && box_min && box_max && box_min[0] <= box_max[0] )
5819     {
5820       bbox.Union( ON_BoundingBox( ON_3dPoint(box_min), ON_3dPoint(box_max) ) );
5821     }
5822     if ( box_min )
5823     {
5824       box_min[0] = bbox.m_min.x;
5825       box_min[1] = bbox.m_min.y;
5826       box_min[2] = bbox.m_min.z;
5827     }
5828     if ( box_max )
5829     {
5830       box_max[0] = bbox.m_max.x;
5831       box_max[1] = bbox.m_max.y;
5832       box_max[2] = bbox.m_max.z;
5833     }
5834   }
5835   return rc;
5836 }
5837 
5838 
5839 ON_BOOL32
GetBBox(double * box_min,double * box_max,ON_BOOL32 bGrowBox) const5840 ON_Brep::GetBBox(
5841           double* box_min, // [3],
5842           double* box_max, // [3],
5843           ON_BOOL32 bGrowBox     // = false
5844           ) const
5845 {
5846   ON_BoundingBox bbox;
5847   if ( !m_bbox.IsValid() )
5848   {
5849     const int face_count = m_F.Count();
5850     int fi;
5851     for ( fi = 0; fi < face_count; fi++ )
5852     {
5853       if ( m_F[fi].m_face_index == -1 )
5854         continue;
5855       const ON_Surface* srf = m_F[fi].ProxySurface();
5856       if ( !srf )
5857         continue;
5858       srf->GetBoundingBox( bbox, bbox.IsValid() );
5859     }
5860     ON_Brep* ptr = const_cast<ON_Brep*>(this);
5861     ptr->m_bbox = bbox;
5862   }
5863 
5864   ON_BOOL32 rc = m_bbox.IsValid();
5865   if (rc)
5866   {
5867     bbox = m_bbox;
5868     if ( bGrowBox && box_min && box_max && box_min[0] <= box_max[0] )
5869     {
5870       bbox.Union( ON_BoundingBox( ON_3dPoint(box_min), ON_3dPoint(box_max) ) );
5871     }
5872     if ( box_min )
5873     {
5874       box_min[0] = bbox.m_min.x;
5875       box_min[1] = bbox.m_min.y;
5876       box_min[2] = bbox.m_min.z;
5877     }
5878     if ( box_max )
5879     {
5880       box_max[0] = bbox.m_max.x;
5881       box_max[1] = bbox.m_max.y;
5882       box_max[2] = bbox.m_max.z;
5883     }
5884   }
5885   return rc;
5886 }
5887 
5888 ON_BOOL32
SwapCoordinates(int i,int j)5889 ON_Brep::SwapCoordinates( int i, int j )
5890 {
5891   ON_BOOL32 rc = false;
5892   // swap surface coordinates
5893   const int srf_count = m_S.Count();
5894   int si;
5895   for ( si = 0; si < srf_count; si++ ) {
5896     if ( !m_S[si] )
5897       continue;
5898     rc = m_S[si]->SwapCoordinates(i,j);
5899     if ( !rc ) {
5900       while ( --si >= 0 ) {
5901         // undo any changes;
5902         if ( m_S[si] )
5903           m_S[si]->SwapCoordinates(i,j);
5904       }
5905       return false;
5906     }
5907   }
5908   // swap 3d curve coordinates
5909   const int crv_count = m_S.Count();
5910   int ci;
5911   for ( ci = 0; ci < crv_count; ci++ ) {
5912     if ( !m_C3[ci] )
5913       continue;
5914     rc = m_C3[ci]->SwapCoordinates(i,j);
5915     if ( !rc ) {
5916       // undo any changes;
5917       while ( --ci >= 0 ) {
5918         if ( m_C3[ci] )
5919           m_C3[ci]->SwapCoordinates(i,j);
5920         for ( si = 0; si < srf_count; si++ ) {
5921           if ( m_S[si] )
5922             m_S[si]->SwapCoordinates(i,j);
5923         }
5924       }
5925       return false;
5926     }
5927   }
5928   return rc;
5929 }
5930 
5931 bool
SwapTrimParameters(int trim_index)5932 ON_Brep::SwapTrimParameters(
5933         int trim_index
5934         )
5935 {
5936   // helper for SwapLoopParameters
5937   if ( trim_index < 0 || trim_index >= m_T.Count() )
5938     return false;
5939   ON_BrepTrim& trim = m_T[trim_index];
5940 
5941   StandardizeTrimCurve(trim_index);
5942 
5943   const int ci = trim.m_c2i;
5944   if ( ci < 0 || ci >= m_C2.Count() )
5945     return false;
5946   ON_Curve* pC = m_C2[ci];
5947   if ( !pC )
5948     return false;
5949 
5950   ON_Interval pdom = trim.ProxyCurveDomain();
5951   ON_Interval trimdom = trim.Domain();
5952 
5953   // have to call SwapCoordinates on pC because
5954   // ON_CurveProxy does not permit modification
5955   // of "real" curve.
5956   ON_BOOL32 rc = pC->SwapCoordinates(0,1); // "u" <-> "v"
5957   if ( !rc )
5958     return false;
5959 
5960   // reverse 2d curve
5961   rc = pC->Reverse();
5962   if (rc)
5963   {
5964     // take care of proxy house keeping, m_vi[] swapping, and toggle m_bRev3d.
5965     trim.SetProxyCurve(pC);
5966     int i = trim.m_vi[0];
5967     trim.m_vi[0] = trim.m_vi[1];
5968     trim.m_vi[1] = i;
5969     if ( trim.m_ei >= 0 )
5970       trim.m_bRev3d = trim.m_bRev3d ? false : true;
5971   }
5972   else
5973   {
5974     // undo changes
5975     rc = pC->SwapCoordinates(0,1); // "u" <-> "v"
5976     return false;
5977   }
5978 
5979   // reflect iso type
5980   switch ( trim.m_iso )
5981   {
5982   case ON_Surface::not_iso:
5983     trim.m_iso = ON_Surface::not_iso;
5984     break;
5985   case ON_Surface::x_iso:
5986     trim.m_iso = ON_Surface::y_iso;
5987     break;
5988   case ON_Surface::y_iso:
5989     trim.m_iso = ON_Surface::x_iso;
5990     break;
5991   case ON_Surface::W_iso:
5992     trim.m_iso = ON_Surface::S_iso;
5993     break;
5994   case ON_Surface::S_iso:
5995     trim.m_iso = ON_Surface::W_iso;
5996     break;
5997   case ON_Surface::E_iso:
5998     trim.m_iso = ON_Surface::N_iso;
5999     break;
6000   case ON_Surface::N_iso:
6001     trim.m_iso = ON_Surface::E_iso;
6002     break;
6003   default:
6004     trim.m_iso = ON_Surface::not_iso;
6005     break;
6006   }
6007 
6008   return true;
6009 }
6010 
6011 bool
SwapLoopParameters(int loop_index)6012 ON_Brep::SwapLoopParameters(
6013         int loop_index
6014         )
6015 {
6016   bool rc = false;
6017   if ( loop_index < 0 || loop_index >= m_L.Count() )
6018     return false;
6019   ON_BrepLoop& L = m_L[loop_index];
6020   const int loop_trim_count = L.m_ti.Count();
6021   if ( loop_trim_count < 1 )
6022     return false;
6023   int lti, ti;
6024   for ( lti = 0; lti < loop_trim_count; lti++ ) {
6025     ti = L.m_ti[lti];
6026     rc = SwapTrimParameters( ti );
6027     if ( !rc ) {
6028       while ( --lti >= 0 ) {
6029         // undo any changes
6030         ti = L.m_ti[lti];
6031         SwapTrimParameters( ti );
6032       }
6033       return false;
6034     }
6035   }
6036 
6037   // reverse order of trimming curves
6038   if ( rc )
6039     L.m_ti.Reverse();
6040   return rc;
6041 }
6042 
6043 bool
IsSolid() const6044 ON_Brep::IsSolid() const
6045 {
6046   ON_BOOL32 bIsOriented = false;
6047   ON_BOOL32 bHasBoundary = true;
6048   bool bIsManifold = IsManifold( &bIsOriented, &bHasBoundary );
6049   return (bIsManifold && bIsOriented && !bHasBoundary) ? true : false;
6050 }
6051 
SolidOrientation() const6052 int ON_Brep::SolidOrientation() const
6053 {
6054   // m_is_solid values:
6055   //   0 = unset
6056   //   1 = solid with normals pointing out
6057   //   2 = solid with normals pointing in
6058   //   3 = not solid
6059   int rc = 0;
6060   switch( m_is_solid )
6061   {
6062   case 1: // solid with normals pointing out
6063     rc = 1;
6064     break;
6065   case 2: // solid with normals pointing in
6066     rc = -1;
6067     break;
6068   case 3: // not a solid
6069     rc = 0;
6070     break;
6071 
6072   default:
6073     if ( IsSolid() )
6074     {
6075       // this virtual function is overridden in Rhino SDK
6076       // and sets m_is_solid to appropriate values.  This
6077       // stand-alone version cannot tell the difference
6078       // between solids with inward pointing normals and
6079       // solids with outwards pointing normals.
6080       //ON_Brep* p = const_cast<ON_Brep*>(this);
6081       //p->m_is_solid = 1;
6082       rc = 2;
6083     }
6084     else
6085     {
6086       ON_Brep* p = const_cast<ON_Brep*>(this);
6087       p->m_is_solid = 3;
6088       rc = 0;
6089     }
6090   }
6091   return rc;
6092 }
6093 
6094 bool
IsManifold(ON_BOOL32 * pbIsOriented,ON_BOOL32 * pbHasBoundary) const6095 ON_Brep::IsManifold( ON_BOOL32* pbIsOriented, ON_BOOL32* pbHasBoundary ) const
6096 {
6097   const int fcnt = m_F.Count();
6098   bool bIsManifold = (fcnt > 0) ? true : false;
6099   bool bIsOriented = bIsManifold;
6100   bool bHasBoundary = false;
6101   int fi, other_ti, lcnt, tcnt, fli, lti;
6102   if ( pbIsOriented )
6103     *pbIsOriented = bIsOriented;
6104   if ( pbHasBoundary )
6105     *pbHasBoundary = bHasBoundary;
6106   const int brep_loop_count = m_L.Count();
6107   const int brep_trim_count = m_T.Count();
6108   const int brep_edge_count = m_E.Count();
6109   for ( fi = 0; fi < fcnt && bIsManifold; fi++ )
6110   {
6111     const ON_BrepFace& face = m_F[fi];
6112     if ( -1 == face.m_face_index )
6113     {
6114       // 28 October 2010 - Dale Lear and Chuck
6115       //    Do not test deleted faces. The join
6116       //    command calls is manifold with some
6117       //    deleted faces to avoid calling Compact
6118       //    lots of times during a join.
6119       continue;
6120     }
6121 
6122     lcnt = face.m_li.Count();
6123     if ( lcnt < 1 ) {
6124       bIsManifold = false;
6125     }
6126 
6127     for ( fli = 0; fli < lcnt && bIsManifold; fli++ )
6128     {
6129       const int li = face.m_li[fli];
6130       if ( li < 0 || li >= brep_loop_count )
6131       {
6132         ON_ERROR("Bogus loop index in face.m_li[]");
6133         continue;
6134       }
6135       const ON_BrepLoop& loop = m_L[li];
6136       tcnt = loop.m_ti.Count();
6137       if (tcnt < 1 ) {
6138         bIsManifold = false;
6139       }
6140       for ( lti = 0; lti < tcnt && bIsManifold; lti++ )
6141       {
6142         const int ti = loop.m_ti[lti];
6143         if ( ti < 0 || ti >= brep_trim_count )
6144         {
6145           ON_ERROR("Bogus loop index in loop.m_ti[]");
6146           continue;
6147         }
6148         const ON_BrepTrim& trim = m_T[ti];
6149         switch ( trim.m_type )
6150         {
6151         case ON_BrepTrim::boundary:
6152           bHasBoundary = true;
6153           break;
6154         case ON_BrepTrim::mated:
6155         case ON_BrepTrim::seam:
6156           // make sure we have a manifold join
6157           if ( trim.m_ei >= 0 && trim.m_ei < brep_edge_count )
6158           {
6159             const ON_BrepEdge& edge = m_E[trim.m_ei];
6160             if ( edge.m_ti.Count() != 2 ) {
6161               bIsManifold = false;
6162             }
6163             else
6164             {
6165               other_ti = edge.m_ti[0];
6166               if ( other_ti == ti )
6167                 other_ti = edge.m_ti[1];
6168               if ( other_ti == ti )
6169               {
6170                 bIsManifold = false;
6171               }
6172               else
6173               {
6174                 const ON_BrepTrim& other_trim = m_T[other_ti];
6175 
6176                 // Nov 9, 2011 Tim - Fix for crash bug RR 93743
6177                 // Better index checking.
6178 
6179                 ON_BOOL32 bFlipTrim = trim.m_bRev3d;
6180                 if (0 <= trim.m_li && brep_loop_count > trim.m_li)
6181                 {
6182                   if ( m_F[m_L[trim.m_li].m_fi].m_bRev )
6183                     bFlipTrim = !bFlipTrim;
6184                 }
6185                 else
6186                 {
6187                   ON_ERROR("Bogus loop index in trim.m_li");
6188                   continue;
6189                 }
6190 
6191                 ON_BOOL32 bFlipOther = other_trim.m_bRev3d;
6192                 if (0 <= other_trim.m_li && brep_loop_count > other_trim.m_li)
6193                 {
6194                   if ( m_F[m_L[other_trim.m_li].m_fi].m_bRev )
6195                     bFlipOther = !bFlipOther;
6196                 }
6197                 else
6198                 {
6199                   ON_ERROR("Bogus loop index in other_trim.m_li");
6200                   continue;
6201                 }
6202 
6203                 if ( bFlipTrim && bFlipOther )
6204                 {
6205                   bIsOriented = false;
6206                 }
6207                 else if ( !bFlipTrim && !bFlipOther )
6208                 {
6209                   bIsOriented = false;
6210                 }
6211               }
6212             }
6213           }
6214           else
6215           {
6216             ON_ERROR("Bogus trim.m_ei or trim.m_type value");
6217           }
6218           break;
6219         case ON_BrepTrim::singular:
6220           // nothing to check here
6221           break;
6222         default:
6223           bIsManifold = false;
6224           break;
6225         }
6226       }
6227     }
6228   }
6229   if ( !bIsManifold ) {
6230     bIsOriented = false;
6231     bHasBoundary = false;
6232   }
6233   if ( pbIsOriented )
6234     *pbIsOriented = bIsOriented;
6235   if ( pbHasBoundary )
6236     *pbHasBoundary = bHasBoundary;
6237   if ( !bIsManifold || bHasBoundary )
6238   {
6239     if ( m_is_solid != 3 )
6240     {
6241       // lazy evaluation used on m_is_solid
6242       const_cast<ON_Brep*>(this)->m_is_solid = 3;
6243     }
6244   }
6245 
6246   return bIsManifold;
6247 }
6248 
6249 
6250 bool
IsSurface() const6251 ON_Brep::IsSurface() const
6252 {
6253   // returns true if the b-rep has a single face
6254   // and that face is geometrically the same
6255   // as the underlying surface.  I.e., the face
6256   // has trivial trimming.  In this case, the
6257   // surface is m_S[0].
6258   return (m_F.Count() == 1 && FaceIsSurface(0));
6259 }
6260 
6261 bool
FaceIsSurface(int face_index) const6262 ON_Brep::FaceIsSurface( int face_index ) const
6263 {
6264   // returns true if the face has a single
6265   // outer boundary and that boundary runs
6266   // along the edges of the underlying surface.
6267   // In this case the geometry of the surface
6268   // is the same as the geometry of the face.
6269 
6270   bool bTrivialFace = false;
6271   if ( face_index >= 0 && face_index < m_F.Count() ) {
6272     const ON_BrepFace& face = m_F[face_index];
6273     if ( face.m_li.Count() == 1 ) {
6274       bTrivialFace = LoopIsSurfaceBoundary( face.m_li[0] );
6275     }
6276   }
6277   return bTrivialFace;
6278 }
6279 
6280 bool
LoopIsSurfaceBoundary(int loop_index) const6281 ON_Brep::LoopIsSurfaceBoundary( int loop_index ) const
6282 {
6283   // returns true if the loop's trims run along the underlying surface boundary
6284   bool bTrivialLoop = false;
6285   if ( loop_index >= 0 && loop_index < m_L.Count() ) {
6286     const ON_BrepLoop& loop = m_L[loop_index];
6287     const int trim_count = loop.m_ti.Count();
6288     if ( trim_count > 0 ) {
6289       bTrivialLoop = true;
6290       for ( int lti = 0; lti < trim_count && bTrivialLoop; lti++ )
6291       {
6292         int ti = loop.m_ti[lti];
6293         if ( ti < 0 || ti >= m_T.Count() )
6294         {
6295           ON_ERROR("Bogus trim index in loop.m_ti[]");
6296           return false;
6297         }
6298         const ON_BrepTrim& trim = m_T[ti];
6299         if ( trim.m_iso == ON_Surface::W_iso )
6300           continue;
6301         if ( trim.m_iso == ON_Surface::S_iso )
6302           continue;
6303         if ( trim.m_iso == ON_Surface::N_iso )
6304           continue;
6305         if ( trim.m_iso == ON_Surface::E_iso )
6306           continue;
6307         bTrivialLoop = false;
6308       }
6309     }
6310   }
6311   return bTrivialLoop;
6312 }
6313 
6314 bool
FlipReversedSurfaces()6315 ON_Brep::FlipReversedSurfaces()
6316 {
6317   // Clears all ON_BrepFace.m_bRev flags
6318   // by calling SwapFaceParameters() on each
6319   // face with a true m_bRev.
6320   //
6321   // Returns true if successful.
6322 
6323   // 11 April 2008 Dale Lear and Tim:
6324   //   face.Transpose() is clearing the m_is_solid
6325   //   flag but we are not changing the orientation
6326   //   of the brep.  This prevents having to perform
6327   //   the expensive step of calculating this flag
6328   //   again.
6329   int saved_is_solid = m_is_solid;
6330 
6331   const int face_count = m_F.Count();
6332 
6333   bool rc = true;
6334   int fi;
6335   for ( fi = 0; fi < face_count; fi++ )
6336   {
6337     ON_BrepFace& face = m_F[fi];
6338     if ( face.m_bRev )
6339     {
6340       if ( !face.Transpose() )
6341         rc = false;
6342     }
6343   }
6344 
6345   m_is_solid = saved_is_solid;
6346 
6347   return rc;
6348 }
6349 
6350 ////////
6351 // Change the domain of a trim
SetTrimDomain(int trim_index,const ON_Interval & domain)6352 bool ON_Brep::SetTrimDomain(
6353        int trim_index, // index of trim in m_T[] array
6354        const ON_Interval& domain
6355        )
6356 {
6357   bool rc = false;
6358   if ( trim_index >= 0 && trim_index < m_T.Count() && domain.IsIncreasing() )
6359   {
6360     ON_BrepTrim& trim = m_T[trim_index];
6361     rc = trim.SetDomain(domain);
6362   }
6363   return rc;
6364 }
6365 
6366 ////////
6367 // Change the domain of an edge
SetEdgeDomain(int edge_index,const ON_Interval & domain)6368 bool ON_Brep::SetEdgeDomain(
6369        int edge_index, // index of edge in m_E[] array
6370        const ON_Interval& domain
6371        )
6372 {
6373   bool rc = false;
6374   if ( edge_index >= 0 && edge_index < m_E.Count() && domain.IsIncreasing() )
6375   {
6376     ON_BrepEdge& edge = m_E[edge_index];
6377     rc = edge.SetDomain(domain);
6378   }
6379   return rc;
6380 }
6381 
Reverse(int dir)6382 ON_BOOL32 ON_BrepFace::Reverse(int dir)
6383 {
6384   if ( dir < 0 || dir > 1 || 0 == m_brep )
6385     return false;
6386   ON_Surface* srf = const_cast<ON_Surface*>(SurfaceOf());
6387   if ( !srf )
6388     return false;
6389   ON_Interval dom0 = srf->Domain(dir);
6390   if ( !dom0.IsIncreasing() )
6391     return false;
6392 
6393 // 2/18/03 GBA.  Destroy surface cache on face.
6394 	DestroyRuntimeCache(true);
6395 
6396   if ( m_brep->SurfaceUseCount( m_si, 2 ) > 1 )
6397   {
6398     srf = srf->DuplicateSurface();
6399     m_si = m_brep->AddSurface( srf );
6400     SetProxySurface(srf);
6401   }
6402 
6403   if ( !srf->Reverse(dir) )
6404     return false;
6405 
6406   ON_Interval dom1 = dom0;
6407   dom1.Reverse();
6408   if ( dom1 != srf->Domain(dir) )
6409   {
6410     srf->SetDomain( dir, dom1 );
6411     dom1 = srf->Domain(dir);
6412   }
6413 
6414   // adjust location of 2d trim curves
6415   ON_Xform xform(1);
6416   xform.IntervalChange(dir,dom0,ON_Interval(dom1[1],dom1[0]));
6417   TransformTrim(xform);
6418 
6419   // reverse loop orientations.
6420   int fli;
6421   for ( fli = 0; fli < m_li.Count(); fli++ )
6422   {
6423     ON_BrepLoop* loop = m_brep->Loop(m_li[fli]);
6424     if ( loop )
6425       m_brep->FlipLoop( *loop );
6426   }
6427 
6428   m_bRev = m_bRev ? false : true;
6429 
6430   if (m_brep->m_is_solid == 1 || m_brep->m_is_solid == 2) m_brep->m_is_solid = 0;
6431 
6432 	// Greg Arden 10 April 2003.  Fix TRR#9624.
6433 	// Update analysis and render meshes.
6434 	if(m_render_mesh)
6435   {
6436     m_render_mesh->ReverseSurfaceParameters(dir);
6437     m_render_mesh->ReverseTextureCoordinates(dir);
6438   }
6439 	if(m_analysis_mesh)
6440   {
6441     m_analysis_mesh->ReverseSurfaceParameters(dir);
6442 		m_analysis_mesh->ReverseTextureCoordinates(dir);
6443   }
6444 
6445   return true;
6446 }
6447 
Transpose()6448 ON_BOOL32 ON_BrepFace::Transpose()
6449 {
6450   if ( 0 == m_brep )
6451     return false;
6452 
6453   ON_Surface* srf = const_cast<ON_Surface*>(SurfaceOf());
6454   if ( 0 == srf )
6455     return false;
6456 
6457   // 2/18/03 GBA.  Destroy cache on the face.
6458 	DestroyRuntimeCache(true);
6459 
6460   // make sure only one face uses this surface
6461   if ( m_brep->SurfaceUseCount( m_si, 2 ) > 1 )
6462   {
6463     srf = srf->DuplicateSurface();
6464     m_si = m_brep->AddSurface(srf);
6465     SetProxySurface(srf);
6466   }
6467 
6468   ON_Interval u0 = srf->Domain(0);
6469   ON_Interval v0 = srf->Domain(1);
6470 
6471   // swap surface "u" and "v"
6472   ON_BOOL32 rc = srf->Transpose();
6473   if ( !rc )
6474     return false;
6475 
6476   ON_Interval u1 = srf->Domain(0);
6477   ON_Interval v1 = srf->Domain(1);
6478 
6479   ON_Xform xform(1);
6480   xform[0][0] = 0.0;
6481   xform[0][1] = 1.0;
6482   xform[1][0] = 1.0;
6483   xform[1][1] = 0.0;
6484 
6485   TransformTrim(xform);
6486 
6487   // reverse loop orientations.
6488   int fli;
6489   for ( fli = 0; fli < m_li.Count(); fli++ )
6490   {
6491     ON_BrepLoop* loop = m_brep->Loop(m_li[fli]);
6492     if ( loop )
6493       m_brep->FlipLoop( *loop );
6494   }
6495 
6496   m_bRev = m_bRev ? false : true;
6497 
6498 
6499   // 11 April 2008 Dale Lear:
6500   //    Transposing the surface and then toggling the m_bRev
6501   //    does not alter the brep's orientation.  Setting this flag
6502   //    to zero means we will have to do an unnecessary and
6503   //    expensive calculation in the future.
6504   //if (m_brep->m_is_solid == 1 || m_brep->m_is_solid == 2) m_brep->m_is_solid = 0;
6505 
6506 	// Update analysis mesh and render mesh.
6507   // (Greg Arden 10 April 2003.  Fix TRR#9624.)
6508 	if(m_render_mesh)
6509   {
6510 		m_render_mesh->TransposeSurfaceParameters();
6511 		m_render_mesh->TransposeTextureCoordinates();
6512   }
6513 	if(m_analysis_mesh)
6514   {
6515 		m_analysis_mesh->TransposeSurfaceParameters();
6516 		m_analysis_mesh->TransposeTextureCoordinates();
6517   }
6518 
6519   return true;
6520 }
6521 
SetDomain(ON_Interval u_dom,ON_Interval v_dom)6522 bool ON_BrepFace::SetDomain(
6523        ON_Interval u_dom,
6524        ON_Interval v_dom
6525        )
6526 {
6527   if ( 0 == m_brep )
6528     return false;
6529   if ( !u_dom.IsIncreasing() )
6530     return false;
6531   if ( !v_dom.IsIncreasing() )
6532     return false;
6533 
6534   ON_Surface* srf = const_cast<ON_Surface*>(SurfaceOf());
6535   if ( 0 == srf )
6536     return false;
6537 
6538   ON_Interval u0_dom = srf->Domain(0);
6539   ON_Interval v0_dom = srf->Domain(1);
6540   if ( u0_dom == u_dom && v0_dom == v_dom )
6541     return true;
6542 
6543   ON_Xform xform(1);
6544   {
6545     ON_Xform ux(1), vx(1);
6546     if ( u0_dom != u_dom )
6547     {
6548       if ( !ux.IntervalChange(0,u0_dom,u_dom) )
6549         return false;
6550     }
6551     if ( v0_dom != v_dom )
6552     {
6553       if ( !vx.IntervalChange(1,v0_dom,v_dom) )
6554         return false;
6555     }
6556     xform = ux*vx;
6557   }
6558 
6559 // 2/18/03 GBA.  Destroy cache on the face.
6560 	DestroyRuntimeCache(true);
6561 
6562   if ( m_brep->SurfaceUseCount( m_si, 2 ) > 1 )
6563   {
6564     srf = srf->DuplicateSurface();
6565     m_si = m_brep->AddSurface(srf);
6566     SetProxySurface(srf);
6567   }
6568 
6569   if ( u_dom != u0_dom )
6570   {
6571     if ( !srf->SetDomain( 0, u_dom ) )
6572       return false;
6573   }
6574 
6575   if ( v_dom != v0_dom )
6576   {
6577     if ( !srf->SetDomain( 1, v_dom ) )
6578     {
6579       srf->SetDomain(0,u0_dom );
6580       return false;
6581     }
6582   }
6583 
6584   // just to be sure 2d curves are in synch with actual surface
6585   // domain in case srf->SetDomain() does something weird.
6586   u_dom = srf->Domain(0);
6587   v_dom = srf->Domain(1);
6588   {
6589     ON_Xform ux(1), vx(1);
6590     if ( u0_dom != u_dom )
6591     {
6592       if ( !ux.IntervalChange(0,u0_dom,u_dom) )
6593         return false;
6594     }
6595     if ( v0_dom != v_dom )
6596     {
6597       if ( !vx.IntervalChange(1,v0_dom,v_dom) )
6598         return false;
6599     }
6600     xform = ux*vx;
6601   }
6602 
6603   if ( !TransformTrim(xform) )
6604     return false;
6605 
6606   ON_Mesh* mesh[3] = {m_analysis_mesh,m_render_mesh,m_preview_mesh};
6607   for ( int i = 0; i < 3; i++ )
6608   {
6609     if ( 0 == mesh[i] )
6610       continue;
6611     for ( int dir = 0; dir < 2; dir++ )
6612     {
6613       ON_Interval& mdom = mesh[i]->m_srf_domain[dir];
6614       ON_Interval dom0 = dir ? v0_dom : u0_dom;
6615       ON_Interval dom1 = dir ? v_dom : u_dom;
6616       if ( mdom.IsIncreasing() && dom0 != dom1 )
6617       {
6618         if ( mdom == dom0 )
6619           mdom = dom1;
6620         else
6621         {
6622           double t0 = dom1.ParameterAt(dom0.NormalizedParameterAt(mdom[0]));
6623           double t1 = dom1.ParameterAt(dom0.NormalizedParameterAt(mdom[1]));
6624           mdom.Set(t0,t1);
6625         }
6626       }
6627     }
6628   }
6629 
6630   return true;
6631 }
6632 
SetDomain(int dir,double t0,double t1)6633 ON_BOOL32 ON_BrepFace::SetDomain(
6634     int dir, // 0 sets first parameter's domain, 1 gets second parameter's domain
6635     double t0,
6636     double t1
6637     )
6638 {
6639   if (    dir < 0
6640        || dir > 1
6641        || t0 == ON_UNSET_VALUE
6642        || t1 == ON_UNSET_VALUE
6643        || t0 >= t1
6644        || 0 == m_brep )
6645     return false;
6646 
6647   ON_Surface* srf = const_cast<ON_Surface*>(SurfaceOf());
6648   if ( 0 == srf )
6649     return false;
6650   ON_Interval udom = srf->Domain(0);
6651   ON_Interval vdom = srf->Domain(1);
6652   if ( dir )
6653     vdom.Set(t0,t1);
6654   else
6655     udom.Set(t0,t1);
6656 
6657   return SetDomain( udom, vdom );
6658 }
6659 
6660 
6661 
6662 //bool ON_Brep::ReverseFaceParameter(
6663 //      int face_index, // index of face
6664 //      int dir // dir = 0 reverse "u", 1 reverse "v"
6665 //      )
6666 //{
6667 //  // OBSOLETE - use ON_BrepFace::Reverse(dir)
6668 //  bool rc = false;
6669 //  ON_BrepFace* face = Face(face_index);
6670 //  if ( face )
6671 //    rc = face->Reverse(dir)?true:false;
6672 //  return rc;
6673 //}
6674 
TrimCurveUseCount(int c2_index,int max_count) const6675 int ON_Brep::TrimCurveUseCount( int c2_index, int max_count ) const
6676 {
6677   int ti, use_count = 0;
6678   if ( max_count < 1 )
6679     max_count = m_T.Count();
6680   for ( ti = 0; ti < m_T.Count() && use_count < max_count; ti++ )
6681   {
6682     if ( m_T[ti].m_c2i == c2_index )
6683       use_count++;
6684   }
6685   return use_count;
6686 }
6687 
EdgeCurveUseCount(int c3_index,int max_count) const6688 int ON_Brep::EdgeCurveUseCount( int c3_index, int max_count ) const
6689 {
6690   int ei, use_count = 0;
6691   if ( max_count < 1 )
6692     max_count = m_T.Count();
6693   for ( ei = 0; ei < m_E.Count() && use_count < max_count; ei++ )
6694   {
6695     if ( m_E[ei].m_c3i == c3_index )
6696       use_count++;
6697   }
6698   return use_count;
6699 }
6700 
SurfaceUseCount(int surface_index,int max_count) const6701 int ON_Brep::SurfaceUseCount( int surface_index, int max_count ) const
6702 {
6703   int fi, use_count = 0;
6704   if ( max_count < 1 )
6705     max_count = m_F.Count();
6706   for ( fi = 0; fi < m_F.Count() && use_count < max_count; fi++ )
6707   {
6708     if ( m_F[fi].m_si == surface_index )
6709       use_count++;
6710   }
6711   return use_count;
6712 }
6713 
6714 ////////
6715 // Change the domain of a face
6716 // This also transforms the "u" and "v" coordinates of all the
6717 // face's parameter space trimming curves.
6718 //bool ON_Brep::SetFaceDomain(
6719 //       int face_index, // index of face in m_F[] array
6720 //       const ON_Interval& u_dom,
6721 //       const ON_Interval& v_dom
6722 //       )
6723 //{
6724 //  // OBSOLETE
6725 //  bool rc = false;
6726 //  ON_BrepFace* face = Face(face_index);
6727 //  if ( face )
6728 //    rc = face->SetDomain(u_dom,v_dom);
6729 //  return rc;
6730 //}
6731 
6732 //bool
6733 //ON_Brep::SwapFaceParameters( int face_index )
6734 //{
6735 //  // OBSOLETE
6736 //  bool rc = false;
6737 //  ON_BrepFace* face = Face(face_index);
6738 //  if ( face )
6739 //    rc = face->Transpose()?true:false;
6740 //  return rc;
6741 //}
6742 
6743 void
Flip()6744 ON_Brep::Flip()
6745 {
6746   const int fcnt = m_F.Count();
6747   int fi;
6748   int missolid = m_is_solid;
6749   for ( fi = 0; fi < fcnt; fi++ ) {
6750     FlipFace(m_F[fi]);
6751   }
6752   if (missolid==1) m_is_solid = 2;
6753   else if (missolid==2) m_is_solid = 1;
6754 }
6755 
6756 //void
6757 //ON_Brep::FlipEdge( ON_BrepEdge& edge )
6758 //{
6759 //  edge.Reverse();
6760 //}
6761 
6762 void
FlipFace(ON_BrepFace & face)6763 ON_Brep::FlipFace( ON_BrepFace& face )
6764 {
6765   face.m_bRev = (face.m_bRev) ? false : true;
6766   if ( face.m_analysis_mesh )
6767     face.m_analysis_mesh->Flip();
6768   if ( face.m_render_mesh )
6769     face.m_render_mesh->Flip();
6770   if ( face.m_preview_mesh )
6771     face.m_preview_mesh->Flip();
6772   //Jun 16 2011 - Chuck - m_is_solid==3 for a brep with inconsistent normals.
6773   //Flipping a face could make the normals consistent.
6774   //if (m_is_solid == 1 || m_is_solid == 2)
6775   if (0 != m_is_solid)
6776     m_is_solid = 0;
6777 }
6778 
6779 //void
6780 //ON_Brep::FlipTrim(ON_BrepTrim& trim)
6781 //{
6782 //  trim.Reverse();
6783 //}
6784 
6785 void
FlipLoop(ON_BrepLoop & loop)6786 ON_Brep::FlipLoop(ON_BrepLoop& loop)
6787 {
6788   int ti, lti;
6789   const int brep_trim_count = m_T.Count();
6790   const int loop_trim_count = loop.m_ti.Count();
6791 
6792   // reverse order of trimming curves
6793   loop.m_ti.Reverse();
6794   // reverse direction of individual trimming curves
6795   for ( lti = 0; lti < loop_trim_count; lti++ )
6796   {
6797     ti = loop.m_ti[lti];
6798     if ( ti >= 0 && ti < brep_trim_count )
6799     {
6800       m_T[ti].Reverse();
6801     }
6802   }
6803 }
6804 
curve_area(ON_3dPoint & start_point,const ON_Curve * curve,const ON_Interval & curve_domain,const ON_Xform * xform,double * area)6805 static int curve_area( ON_3dPoint& start_point, const ON_Curve* curve, const ON_Interval& curve_domain, const ON_Xform* xform, double *area )
6806 {
6807   // ges a CRUDE approximation of curve area to use for
6808   // determining if a simple closed curve 2d has
6809   // clockwise or couterclockwise orientation.
6810   ON_Workspace ws;
6811   ON_Interval span_domain;
6812   double *span_vector, *t, twice_area = 0.0;
6813   ON_3dPoint p0, p1;
6814   int degree, span_count, span_i, j;
6815   if ( !area )
6816     return false;
6817   *area = 0;
6818   if ( !curve )
6819     return false;
6820   const ON_PolyCurve* polycurve = ON_PolyCurve::Cast(curve);
6821   if ( polycurve )
6822   {
6823     span_count = polycurve->Count();
6824     ON_Interval span_domain, segment_curve_domain;
6825     double s0, s1;
6826     for ( span_i = 0; span_i < span_count; span_i++ )
6827     {
6828       span_domain = polycurve->SegmentDomain(span_i);
6829       if ( span_domain[1] <= curve_domain[0] )
6830         continue;
6831       if ( span_domain[0] >= curve_domain[1] )
6832         break;
6833       const ON_Curve* segment_curve = polycurve->SegmentCurve(span_i);
6834       segment_curve_domain = segment_curve->Domain();
6835       if ( curve_domain[0] > span_domain[0] || curve_domain[1] < span_domain[1] )
6836       {
6837         s0 = (curve_domain[0] > span_domain[0]) ? curve_domain[0] : span_domain[0];
6838         s1 = (curve_domain[1] < span_domain[1]) ? curve_domain[1] : span_domain[1];
6839         if ( segment_curve_domain != span_domain )
6840         {
6841           s0 = span_domain.NormalizedParameterAt(s0);
6842           s1 = span_domain.NormalizedParameterAt(s1);
6843           s0 = segment_curve_domain.ParameterAt(s0);
6844           s1 = segment_curve_domain.ParameterAt(s1);
6845         }
6846         segment_curve_domain.Set(s0,s1);
6847       }
6848       if ( !curve_area( start_point, segment_curve, segment_curve_domain, xform, &twice_area ) )
6849       {
6850         *area = 0.0;
6851         return false;
6852       }
6853       *area += twice_area;
6854     }
6855   }
6856   else
6857   {
6858     span_count = curve->SpanCount();
6859     if ( span_count < 1 )
6860       return false;
6861     degree = curve->Degree();
6862     if ( degree <= 1 )
6863     {
6864       degree = 1;
6865     }
6866     else if ( degree < 4)
6867     {
6868       degree = 4;
6869       // 6 January 2006 Dale Lear
6870       //     Every time you find a closed curve that
6871       //     gets the wrong dir, increase the number
6872       //     after the < by one until it works.  Add
6873       //     the curve to RR and list the RR number here.
6874 
6875       // 17 October 2012 Dale Lear
6876       //   To fix http://dev.mcneel.com/bugtrack/?q=113316
6877       //   I changed "< 16" to "< 17".
6878       while ( span_count*degree < 17 )
6879         degree *= 2;
6880     }
6881 
6882     span_vector = ws.GetDoubleMemory(span_count+1+degree);
6883     t = span_vector+(span_count+1);
6884     t[0] = 0.0;
6885     for ( j = 1; j < degree; j++ ) {
6886       t[j] = ((double)(j))/(degree);
6887     }
6888     if ( !curve->GetSpanVector( span_vector ) )
6889       return false;
6890 
6891     p1 = xform ? (*xform)*start_point : start_point;
6892     for ( span_i = 0; span_i < span_count; span_i++ ) {
6893       span_domain.Set( span_vector[span_i], span_vector[span_i+1] );
6894       if ( span_domain[1] <= curve_domain[0] )
6895         continue;
6896       if ( span_domain[0] >= curve_domain[1] )
6897         break;
6898       if ( span_domain[1] > curve_domain[1] )
6899         span_domain.m_t[1] = curve_domain[1];
6900       if ( span_domain[0] < curve_domain[0] )
6901         span_domain.m_t[0] = curve_domain[0];
6902       if ( span_domain[0] >= span_domain[1] )
6903         continue;
6904       for ( j = 0; j < degree; j++ ) {
6905         p0 = p1;
6906         p1 = curve->PointAt(span_domain.ParameterAt(t[j]));
6907         if ( xform )
6908           p1 = (*xform)*p1;
6909         twice_area += (p0.x-p1.x)*(p0.y+p1.y);
6910         if ( !span_i && !j ) {
6911           // check gap
6912         }
6913       }
6914     }
6915     p0 = p1;
6916     p1 = curve->PointAt(curve_domain[1]);
6917     start_point = p1;
6918     if ( xform )
6919       p1 = (*xform)*p1;
6920     twice_area += (p0.x-p1.x)*(p0.y+p1.y);
6921     *area = 0.5*twice_area;
6922   }
6923 
6924   return true;
6925 }
6926 
ON_ClosedCurveOrientation(const ON_Curve & curve,const ON_Xform * xform)6927 int ON_ClosedCurveOrientation( const ON_Curve& curve, const ON_Xform* xform )
6928 {
6929   int curve_orientation = 0;
6930   double area = 0.0;
6931   ON_3dPoint start_point = curve.PointAtEnd();
6932   const ON_Interval curve_domain = curve.Domain();
6933   if ( xform && xform->IsIdentity() )
6934     xform = 0;
6935   if (curve_area( start_point, &curve, curve_domain, xform, &area ))
6936   {
6937     double noise = 0.0;
6938     if ( area > noise )
6939       curve_orientation = 1;
6940     else if (area < noise )
6941       curve_orientation = -1;
6942   }
6943   return curve_orientation;
6944 }
6945 
6946 
ON_CurveOrientationArea(const ON_Curve * curve,const ON_Interval * domain,const ON_Xform * xform,bool bReverseCurve)6947 double ON_CurveOrientationArea(
6948   const ON_Curve* curve,
6949   const ON_Interval* domain,
6950   const ON_Xform* xform,
6951   bool bReverseCurve
6952   )
6953 {
6954   if ( 0 == curve )
6955     return 0.0;
6956 
6957   ON_Interval local_domain = curve->Domain();
6958   if ( 0 != domain && domain->IsIncreasing() )
6959     local_domain.Intersection(*domain);
6960 
6961   ON_3dPoint start_point = curve->PointAt(local_domain[0]);
6962   double a = 0.0;
6963   if ( !curve_area( start_point, curve, local_domain, xform, &a ) )
6964     a = 0.0;
6965   else if ( bReverseCurve && 0.0 != a )
6966     a = -a;
6967 
6968   return a;
6969 }
6970 
6971 
loop_type_compar(const ON_BrepLoop * const * ppLoopA,const ON_BrepLoop * const * ppLoopB)6972 static int loop_type_compar(const ON_BrepLoop *const* ppLoopA, const ON_BrepLoop *const* ppLoopB )
6973 {
6974   const ON_BrepLoop* loopA = *ppLoopA;
6975   const ON_BrepLoop* loopB = *ppLoopB;
6976   if ( loopA->m_type == loopB->m_type )
6977     return 0;
6978   if ( loopA->m_type == ON_BrepLoop::unknown )
6979     return 1;
6980   if ( loopB->m_type == ON_BrepLoop::unknown )
6981     return -1;
6982   if ( loopA->m_type < loopB->m_type )
6983     return -1;
6984   if ( loopA->m_type > loopB->m_type )
6985     return 1;
6986   return 0;
6987 }
6988 
SortFaceLoops(ON_BrepFace & face) const6989 bool ON_Brep::SortFaceLoops( ON_BrepFace& face ) const
6990 {
6991   int fli, li, loop_type;
6992   const int face_loop_count = face.m_li.Count();
6993   const int loop_count = m_L.Count();
6994   if ( face_loop_count < 1 || loop_count < 1 )
6995     return false;
6996   bool rc = true;
6997   ON_SimpleArray<const ON_BrepLoop*> loop_ptr(face_loop_count);
6998   for ( fli = 0; fli < face_loop_count; fli++ )
6999   {
7000     li = face.m_li[fli];
7001     if ( li < 0 || li >= loop_count )
7002       return false;
7003     const ON_BrepLoop& loop = m_L[li];
7004     if ( loop.m_loop_index != li )
7005       return false;
7006     loop_type = loop.m_type;
7007     if ( loop_type <= ON_BrepLoop::unknown || loop_type >= ON_BrepLoop::type_count )
7008       rc = false;
7009     loop_ptr.Append( &m_L[li] );
7010   }
7011   loop_ptr.QuickSort( loop_type_compar );
7012   for ( fli = 0; fli < face_loop_count; fli++ )
7013   {
7014     face.m_li[fli] = loop_ptr[fli]->m_loop_index;
7015   }
7016   return rc;
7017 }
7018 
7019 
7020 int
LoopDirection(const ON_BrepLoop & loop) const7021 ON_Brep::LoopDirection( const ON_BrepLoop& loop ) const
7022 {
7023   ON_3dPoint start_point;
7024   double d, a = 0.0;
7025   int ti, lti, c2i;
7026   const int brep_trim_count = m_T.Count();
7027   const int brep_C2_count = m_C2.Count();
7028   const int loop_trim_count = loop.m_ti.Count();
7029 
7030   double noise = 0.0;
7031 
7032   // reverse direction of individual trimming curves
7033   for ( lti = 0; lti < loop_trim_count; lti++ ) {
7034     ti = loop.m_ti[lti];
7035     if ( ti < 0 || ti >= brep_trim_count ) {
7036       a = 0.0;
7037       break;
7038     }
7039     c2i =  m_T[ti].m_c2i;
7040     if ( c2i < 0 || c2i >= brep_C2_count ) {
7041       a = 0.0;
7042       break;
7043     }
7044     if ( lti == 0 )
7045     {
7046       // evaluate start of first trim
7047       if ( m_C2[c2i] )
7048         start_point = m_T[ti].PointAtStart(); //m_C2[c2i]->PointAt(m_T[ti].m_t[0]);
7049     }
7050     if ( !curve_area( start_point, &m_T[ti], m_T[ti].Domain(), 0, &d ) ) {
7051       a = 0.0;
7052       break;
7053     }
7054     //noise += fabs(d);
7055     a += d;
7056   }
7057 
7058   //this fixes trr 9351.  Change at your own risk.
7059   //noise *= 10.0*ON_EPSILON;
7060 
7061   if (a > noise)
7062     return 1;
7063   else if (a < -noise)
7064     return -1;
7065   return 0;
7066 }
7067 
SetVertexTolerances(ON_BOOL32 bLazy)7068 bool ON_Brep::SetVertexTolerances( ON_BOOL32 bLazy )
7069 {
7070   bool rc = true;
7071   int vi, vertex_count = m_V.Count();
7072   for ( vi = 0; vi < vertex_count; vi++ )
7073   {
7074     if ( !SetVertexTolerance( m_V[vi], bLazy ) )
7075       rc = false;
7076   }
7077   return rc;
7078 }
7079 
7080 bool
SetVertexTolerance(ON_BrepVertex & vertex,ON_BOOL32 bLazySet) const7081 ON_Brep::SetVertexTolerance( ON_BrepVertex& vertex,
7082   ON_BOOL32 bLazySet // default = false
7083                 // false: recompute tolerance even if
7084                 //        its current value is positive
7085                 // true:  recompute tolerance only if
7086                 //        its current value is nonpositive
7087   ) const
7088 {
7089   if ( vertex.m_tolerance < 0.0 || !bLazySet ) {
7090     const int vertex_edge_count = vertex.EdgeCount();
7091     if ( vertex_edge_count < 1 ) {
7092       vertex.m_tolerance = 0.0;
7093     }
7094     else {
7095       vertex.m_tolerance = ON_UNSET_VALUE;
7096       double tolerance = 0.0;
7097       double d;
7098       ON_3dPoint uv;
7099       ON_Interval edge_domain;
7100       //const ON_Curve* c=0;
7101       const ON_Surface* s=0;
7102       int vei, ei, eti, endi;
7103       const int vertex_index = vertex.m_vertex_index;
7104       for ( vei = 0; vei < vertex_edge_count; vei++ )
7105       {
7106         ei = vertex.m_ei[vei];
7107         if ( ei < 0 )
7108           return false;
7109         const ON_BrepEdge& edge = m_E[ei];
7110         if ( !edge.ProxyCurve() )
7111           return false;
7112         edge_domain = edge.Domain();
7113         for ( endi = 0; endi < 2; endi++ )
7114         {
7115           if ( edge.m_vi[endi] == vertex_index )
7116           {
7117             d = vertex.point.DistanceTo( edge.PointAt(edge_domain[endi]) );
7118             if ( tolerance < d )
7119               tolerance = d;
7120           }
7121         }
7122         const int edge_trim_count = edge.m_ti.Count();
7123         for ( eti = 0; eti < edge_trim_count; eti++ )
7124         {
7125           const ON_BrepTrim* trim = Trim(edge.m_ti[eti]);
7126           if ( 0 == trim )
7127             continue;
7128           if ( 0 == trim->TrimCurveOf() )
7129             continue;
7130           s = trim->SurfaceOf();
7131           if ( 0 == s )
7132             continue;
7133           for ( endi = 0; endi < 2; endi++ ) {
7134             if ( edge.m_vi[endi] == vertex_index ) {
7135               uv = trim->PointAt( trim->Domain()[trim->m_bRev3d?1-endi:endi] );
7136               d = vertex.point.DistanceTo( s->PointAt(uv.x,uv.y) );
7137               if ( tolerance < d )
7138                 tolerance = d;
7139             }
7140           }
7141         }
7142       }
7143       vertex.m_tolerance = (tolerance <= ON_ZERO_TOLERANCE) ? 0.0 : 1.001*tolerance;
7144     }
7145   }
7146   return (vertex.m_tolerance >= 0.0) ? true : false;
7147 }
7148 
7149 bool
SetTrimTolerance(ON_BrepTrim & trim,ON_BOOL32 bLazy) const7150 ON_Brep::SetTrimTolerance( ON_BrepTrim& trim, ON_BOOL32 bLazy ) const
7151 {
7152   // The TL_Brep::SetTrimTolerance override of this virtual function
7153   // sets ON_BrepTrim::m_tolerance[] correctly.
7154   double ds, de, d;
7155   int dir, lti, prev_ti, next_ti;
7156   if ( trim.m_tolerance[0] < 0.0 || trim.m_tolerance[1] < 0.0 || !bLazy )
7157   {
7158     // set trim tolerance
7159     if ( trim.m_li >= 0 && trim.m_li < m_L.Count() )
7160     {
7161       const ON_BrepLoop& loop = m_L[trim.m_li];
7162       const int loop_trim_count = loop.m_ti.Count();
7163       for ( lti = 0; lti < loop_trim_count; lti++ )
7164       {
7165         if ( loop.m_ti[lti] == trim.m_trim_index )
7166         {
7167           prev_ti = loop.m_ti[(lti-1+loop_trim_count)%loop_trim_count];
7168           next_ti = loop.m_ti[(lti+1)%loop_trim_count];
7169           if ( prev_ti >= 0 && next_ti >= 0 && prev_ti < m_T.Count() && next_ti < m_T.Count() )
7170           {
7171             const ON_BrepTrim& prev_trim = m_T[prev_ti];
7172             const ON_BrepTrim& next_trim = m_T[next_ti];
7173             const ON_Curve* prev_c2 = prev_trim.TrimCurveOf();
7174             const ON_Curve* next_c2 = next_trim.TrimCurveOf();
7175             const ON_Curve* c2 = trim.TrimCurveOf();
7176             if ( prev_c2 && c2 && next_c2 )
7177             {
7178               ON_3dPoint prev_end = prev_trim.PointAtEnd(); //prev_c2->PointAt( prev_trim.m_t[1] );
7179               ON_3dPoint this_start = trim.PointAtStart(); //c2->PointAt( trim.m_t[0] );
7180               ON_3dPoint this_end = trim.PointAtEnd(); // c2->PointAt( trim.m_t[1] );
7181               ON_3dPoint next_start = next_trim.PointAtStart(); //prev_c2->PointAt( next_trim.m_t[0] );
7182               for ( dir = 0; dir < 2; dir++ )
7183               {
7184                 if ( trim.m_tolerance[dir] < 0.0 || !bLazy )
7185                 {
7186                   ds = fabs(prev_end[dir] - this_start[dir] );
7187                   de = fabs(this_end[dir] - next_start[dir] );
7188                   d = (ds >= de) ? ds : de;
7189                   trim.m_tolerance[dir] = ( d > ON_ZERO_TOLERANCE ) ? 1.001*d : 0.0;
7190                 }
7191               }
7192             }
7193           }
7194           break;
7195         }
7196       }
7197     }
7198   }
7199   return (trim.m_tolerance[0] >= 0.0 && trim.m_tolerance[1] >= 0.0) ? true : false;
7200 }
7201 
7202 bool
SetEdgeTolerance(ON_BrepEdge & edge,ON_BOOL32 bLazySet) const7203 ON_Brep::SetEdgeTolerance( ON_BrepEdge& edge, ON_BOOL32 bLazySet ) const
7204 {
7205   if ( edge.m_tolerance < 0.0 || !bLazySet )
7206   {
7207     const int edge_trim_count = edge.m_ti.Count();
7208     if ( edge_trim_count < 1 )
7209     {
7210       edge.m_tolerance = 0.0;
7211     }
7212     else
7213     {
7214       edge.m_tolerance = ON_UNSET_VALUE;
7215       // TL_Brep::SetEdgeTolerance overrides ON_Brep::SetEdgeTolerance
7216       // and sets teh tolerance correctly.
7217     }
7218   }
7219   return (edge.m_tolerance >= 0.0) ? true : false;
7220 }
7221 
SetTrimTolerances(ON_BOOL32 bLazy)7222 bool ON_Brep::SetTrimTolerances( ON_BOOL32 bLazy )
7223 {
7224   bool rc = true;
7225   int ti, trim_count = m_T.Count();
7226   for ( ti = 0; ti < trim_count; ti++ )
7227   {
7228     if ( !SetTrimTolerance( m_T[ti], bLazy ) )
7229       rc = false;
7230   }
7231   return rc;
7232 }
7233 
SetEdgeTolerances(ON_BOOL32 bLazy)7234 bool ON_Brep::SetEdgeTolerances( ON_BOOL32 bLazy )
7235 {
7236   bool rc = true;
7237   int ei, edge_count = m_E.Count();
7238   for ( ei = 0; ei < edge_count; ei++ )
7239   {
7240     if ( !SetEdgeTolerance( m_E[ei], bLazy ) )
7241       rc = false;
7242   }
7243   return rc;
7244 }
7245 
7246 
Dump(ON_TextLog & dump) const7247 void ON_Brep::Dump( ON_TextLog& dump ) const
7248 {
7249   dump.Print("ON_Brep:\n");
7250 
7251   if ( IsSurface() ) {
7252     dump.Print("(B-rep geometry is the same as underlying surface.)\n");
7253   }
7254 
7255   dump.Print("surfaces:  %d\n",m_S.Count());
7256   dump.Print("3d curve:  %d\n",m_C3.Count());
7257   dump.Print("2d curves: %d\n",m_C2.Count());
7258   dump.Print("vertices:  %d\n",m_V.Count());
7259   dump.Print("edges:     %d\n",m_E.Count());
7260   dump.Print("trims:     %d\n",m_T.Count());
7261   dump.Print("loops:     %d\n",m_L.Count());
7262   dump.Print("faces:     %d\n",m_F.Count());
7263 
7264   int c2i;
7265   for ( c2i = 0; c2i < m_C2.Count(); c2i++ )
7266   {
7267     const ON_Curve* c2 = m_C2[c2i];
7268     if ( c2 )
7269     {
7270       ON_Interval cdom = c2->Domain();
7271       ON_3dPoint c_start, c_end;
7272       c_start = c2->PointAtStart();
7273       c_end = c2->PointAtEnd();
7274       const char* s = c2->ClassId()->ClassName();
7275       if ( !s )
7276         s = "";
7277       dump.Print("curve2d[%2d]: %s domain(%g,%g) start(%g,%g) end(%g,%g)\n",
7278                   c2i, s, cdom[0], cdom[1],
7279                   c_start.x, c_start.y,
7280                   c_end.x, c_end.y);
7281     }
7282     else
7283     {
7284       dump.Print("curve2d[%2d]: NULL\n",c2i);
7285     }
7286   }
7287 
7288   int c3i;
7289   for ( c3i = 0; c3i < m_C3.Count(); c3i++ )
7290   {
7291     const ON_Curve* c3 = m_C3[c3i];
7292     if ( c3 )
7293     {
7294       ON_Interval cdom = c3->Domain();
7295       ON_3dPoint c_start, c_end;
7296       c_start = c3->PointAtStart();
7297       c_end = c3->PointAtEnd();
7298       const char* s = c3->ClassId()->ClassName();
7299       if ( !s )
7300         s = "";
7301       dump.Print("curve3d[%2d]: %s domain(%g,%g) start(%g,%g,%g) end(%g,%g,%g)\n",
7302                  c3i, s, cdom[0], cdom[1],
7303                  c_start.x, c_start.y, c_start.z,
7304                  c_end.x, c_end.y, c_end.z);
7305     }
7306     else
7307     {
7308       dump.Print("curve2d[%2d]: NULL\n",c3i);
7309     }
7310   }
7311 
7312   int si;
7313   for ( si = 0; si < m_S.Count(); si++ )
7314   {
7315     const ON_Surface* srf = m_S[si];
7316     if ( srf )
7317     {
7318       ON_Interval udom = srf->Domain(0);
7319       ON_Interval vdom = srf->Domain(1);
7320       const char* s = srf->ClassId()->ClassName();
7321       if ( !s )
7322         s = "";
7323       dump.Print("surface[%2d]: %s u(%g,%g) v(%g,%g)\n",
7324                  si, s,
7325                  udom[0], udom[1],
7326                  vdom[0], vdom[1]
7327                  );
7328       if ( m_S.Count() == 1 && IsSurface() )
7329       {
7330         dump.PushIndent();
7331         dump.Print("surface details:\n");
7332         dump.PushIndent();
7333         srf->Dump(dump);
7334         dump.PopIndent();
7335         dump.PopIndent();
7336       }
7337     }
7338     else
7339     {
7340       dump.Print("surface[%2d]: NULL\n",si);
7341     }
7342   }
7343 
7344   int vi;
7345   for ( vi = 0; vi < m_V.Count(); vi++ ) {
7346     const ON_BrepVertex& vertex = m_V[vi];
7347     dump.Print("vertex[%2d]: (%f %f %f) tolerance(%g)\n",
7348                vi,vertex.point.x,vertex.point.y,vertex.point.z,
7349                vertex.m_tolerance);
7350     if ( vertex.m_ei.Count() > 0 ) {
7351       int vei;
7352       dump.PushIndent();
7353       dump.Print("edges (");
7354       for ( vei = 0; vei < vertex.m_ei.Count(); vei++ ) {
7355         dump.Print( (vei)?",%d":"%d", vertex.m_ei[vei] );
7356       }
7357       dump.PopIndent();
7358       dump.Print(")\n");
7359     }
7360   }
7361 
7362   int ei,ti;
7363   for ( ei = 0; ei < m_E.Count(); ei++ ) {
7364     const ON_BrepEdge& edge = m_E[ei];
7365     dump.Print("edge[%2d]: v0(%2d) v1(%2d) 3d_curve(%d) tolerance(%g)\n",
7366                ei,edge.m_vi[0],edge.m_vi[1],edge.m_c3i,edge.m_tolerance);
7367 
7368     dump.PushIndent();
7369 
7370     const ON_Curve* c3 = edge.EdgeCurveOf();
7371     if ( c3 )
7372     {
7373       ON_3dPoint edge_start = edge.PointAtStart();
7374       ON_3dPoint edge_end = edge.PointAtEnd();
7375       dump.Print("domain(%g,%g) start(%g,%g,%g) end(%g,%g,%g)\n",
7376            edge.Domain()[0],edge.Domain()[1],
7377            edge_start.x,edge_start.y,edge_start.z,
7378            edge_end.x,edge_end.y,edge_end.z
7379            );
7380     }
7381     else
7382     {
7383       dump.Print("domain(%g,%g) start(?,?,?) end(?,?,?)\n",
7384            edge.Domain()[0],edge.Domain()[1]);
7385     }
7386 
7387     if ( edge.m_ti.Count() > 0 )
7388     {
7389 
7390       dump.Print("trims (",edge.m_ti.Count());
7391       int eti;
7392       for ( eti = 0; eti < edge.m_ti.Count(); eti++ )
7393       {
7394         ti = edge.m_ti[eti];
7395         const char* sign = "?";
7396         if ( ti >= 0 && ti < m_T.Count() ) {
7397           sign = m_T[ti].m_bRev3d ? "-" : "+";
7398         }
7399         dump.Print( (eti)?",%s%d":"%s%d", sign,edge.m_ti[eti]);
7400       }
7401 
7402       dump.Print(")\n");
7403     }
7404 
7405     dump.PopIndent();
7406   }
7407 
7408   int fi;
7409   for ( fi = 0; fi < m_F.Count(); fi++ ) {
7410     const ON_BrepFace& face = m_F[fi];
7411     const ON_Surface* face_srf = face.SurfaceOf();
7412     dump.Print("face[%2d]: surface(%d) reverse(%d) loops(",
7413                fi,face.m_si,face.m_bRev);
7414     int fli;
7415     for ( fli = 0; fli < face.m_li.Count(); fli++ ) {
7416       dump.Print( (fli)?",%d":"%d", face.m_li[fli]);
7417     }
7418     dump.Print(")\n");
7419     dump.PushIndent();
7420     if ( face.m_render_mesh )
7421     {
7422       const char* mp_style = "Custom";
7423       const ON_MeshParameters* mp = face.m_render_mesh->MeshParameters();
7424       if ( mp )
7425       {
7426         if ( 0 == mp->CompareGeometrySettings(ON_MeshParameters::FastRenderMesh) )
7427           mp_style = "Fast";
7428         else if ( 0 == mp->CompareGeometrySettings(ON_MeshParameters::QualityRenderMesh) )
7429           mp_style = "Quality";
7430       }
7431       dump.Print("%s render mesh: %d polygons\n",mp_style,face.m_render_mesh->FaceCount());
7432     }
7433     if ( face.m_analysis_mesh ) {
7434       dump.Print("Analysis mesh: %d polygons\n",face.m_analysis_mesh->FaceCount());
7435     }
7436     if ( FaceIsSurface(fi) ) {
7437       dump.Print("(Face geometry is the same as underlying surface.)\n");
7438     }
7439 
7440 
7441     for ( fli = 0; fli < face.m_li.Count(); fli++ )
7442     {
7443       const int li = face.m_li[fli];
7444       const ON_BrepLoop& loop = m_L[li];
7445       const char* sLoopType = 0;
7446       switch( loop.m_type )
7447       {
7448       case ON_BrepLoop::unknown:
7449         sLoopType = "unknown";
7450         break;
7451       case ON_BrepLoop::outer:
7452         sLoopType = "outer";
7453         break;
7454       case ON_BrepLoop::inner:
7455         sLoopType = "inner";
7456         break;
7457       case ON_BrepLoop::slit:
7458         sLoopType = "slit";
7459         break;
7460       case ON_BrepLoop::crvonsrf:
7461         sLoopType = "crvonsrf";
7462         break;
7463       default:
7464         sLoopType = "unknown";
7465         break;
7466       }
7467       dump.Print("loop[%2d]: type(%s) %d trims(",
7468                  li, sLoopType, loop.m_ti.Count());
7469       int lti;
7470       for ( lti = 0; lti < loop.m_ti.Count(); lti++ )
7471       {
7472         dump.Print( (lti)?",%d":"%d", loop.m_ti[lti]);
7473       }
7474       dump.Print(")\n");
7475       dump.PushIndent();
7476       for ( lti = 0; lti < loop.m_ti.Count(); lti++ )
7477       {
7478         const int ti = loop.m_ti[lti];
7479         const ON_BrepTrim& trim = m_T[ti];
7480         const char* sTrimType = "?";
7481         const char* sTrimIso = "-?";
7482         const ON_Curve* c2 = trim.TrimCurveOf();
7483         ON_3dPoint trim_start, trim_end;
7484         switch( trim.m_type ) {
7485         case ON_BrepTrim::unknown:
7486           sTrimType = "unknown ";
7487           break;
7488         case ON_BrepTrim::boundary:
7489           sTrimType = "boundary";
7490           break;
7491         case ON_BrepTrim::mated:
7492           sTrimType = "mated   ";
7493           break;
7494         case ON_BrepTrim::seam:
7495           sTrimType = "seam    ";
7496           break;
7497         case ON_BrepTrim::singular:
7498           sTrimType = "singular";
7499           break;
7500         case ON_BrepTrim::crvonsrf:
7501           sTrimType = "crvonsrf";
7502           break;
7503         default:
7504           sTrimType = "unknown";
7505           break;
7506         }
7507         switch( trim.m_iso ) {
7508         case ON_Surface::not_iso:
7509           sTrimIso = "";
7510           break;
7511         case ON_Surface::x_iso:
7512           sTrimIso = "-u iso";
7513           break;
7514         case ON_Surface::W_iso:
7515           sTrimIso = "-west side iso";
7516           break;
7517         case ON_Surface::E_iso:
7518           sTrimIso = "-east side iso";
7519           break;
7520         case ON_Surface::y_iso:
7521           sTrimIso = "-v iso";
7522           break;
7523         case ON_Surface::S_iso:
7524           sTrimIso = "-south side iso";
7525           break;
7526         case ON_Surface::N_iso:
7527           sTrimIso = "-north side iso";
7528           break;
7529         default:
7530           sTrimIso = "-unknown_iso_flag";
7531           break;
7532         }
7533         dump.Print("trim[%2d]: edge(%2d) v0(%2d) v1(%2d) tolerance(%g,%g)\n",
7534                    ti,
7535                    trim.m_ei,trim.m_vi[0],trim.m_vi[1],
7536                    trim.m_tolerance[0],trim.m_tolerance[1]);
7537         dump.PushIndent();
7538         dump.Print("type(%s%s) rev3d(%d) 2d_curve(%d)\n",
7539                    sTrimType, sTrimIso, trim.m_bRev3d, trim.m_c2i);
7540         if ( c2 )
7541         {
7542           trim_start = trim.PointAtStart();
7543           trim_end = trim.PointAtEnd();
7544           dump.Print("domain(%g,%g) start(%g,%g) end(%g,%g)\n",
7545                trim.Domain()[0],trim.Domain()[1],
7546                trim_start.x,trim_start.y,
7547                trim_end.x,trim_end.y);
7548           if ( 0 != face_srf )
7549           {
7550             ON_3dPoint trim_srfstart = face_srf->PointAt(trim_start.x,trim_start.y);
7551             ON_3dPoint trim_srfend = face_srf->PointAt(trim_end.x,trim_end.y);
7552             dump.Print("surface points start(%g,%g,%g) end(%g,%g,%g)\n",
7553                  trim_srfstart.x,trim_srfstart.y,trim_srfstart.z,
7554                  trim_srfend.x,trim_srfend.y,trim_srfend.z);
7555           }
7556         }
7557         else
7558         {
7559           dump.Print("domain(%g,%g) start(?,?) end(?,?)\n",
7560                trim.Domain()[0],trim.Domain()[1]);
7561         }
7562         dump.PopIndent();
7563       }
7564       dump.PopIndent();
7565     }
7566     dump.PopIndent();
7567   }
7568 
7569   //int si;
7570   //for ( si = 0; si < m_S.Count(); si++ ) {
7571   //  dump.Print("surface[%d]:\n",si);
7572   //  dump.PushIndent();
7573   //  if ( m_S[si] )
7574   //    m_S[si]->Dump(dump);
7575   //  else
7576   //    dump.Print("NULL\n");
7577   //  dump.PopIndent();
7578   //}
7579 
7580 }
7581 
7582 
7583 
7584 //int ON_Brep::FaceIndexOf( const ON_BrepTrim& trim ) const
7585 //{
7586 //  int fi = -1;
7587 //  if ( trim.m_li >= 0 && trim.m_li < m_L.Count() )
7588 //  {
7589 //    fi = m_L[trim.m_li].m_fi;
7590 //    if ( fi < 0 || fi >= m_F.Count() )
7591 //      fi = -1;
7592 //  }
7593 //  return fi;
7594 //}
7595 
7596 //int ON_Brep::FaceIndexOf( const ON_BrepLoop& loop ) const
7597 //{
7598 //  int fi = -1;
7599 //  if ( loop.m_fi >= 0 && loop.m_fi < m_F.Count() )
7600 //    fi = loop.m_fi;
7601 //  return fi;
7602 //}
7603 
7604 //const ON_BrepFace* ON_Brep::FaceOf( const ON_BrepTrim& trim ) const
7605 //{
7606 //  // OBSOLETE
7607 //  return trim.Face();
7608 //}
7609 
7610 //const ON_BrepFace* ON_Brep::FaceOf( const ON_BrepLoop& loop ) const
7611 //{
7612 //  // OBSOLETE
7613 //  return loop.Face();
7614 //}
7615 
7616 
7617 //int ON_Brep::SurfaceIndexOf( const ON_BrepTrim& trim ) const
7618 //{
7619 //  // OBSOLETE
7620 //  return trim.SurfaceIndexOf();
7621 //}
7622 
7623 //int ON_Brep::SurfaceIndexOf( const ON_BrepLoop& loop ) const
7624 //{
7625 //  // OBSOLETE
7626 //  return loop.SurfaceIndexOf();
7627 //}
7628 
7629 //int ON_Brep::SurfaceIndexOf( const ON_BrepFace& face ) const
7630 //{
7631 //  // OBSOLETE FUNCTION
7632 //  return face.m_si;
7633 //}
7634 
7635 //ON_Surface* ON_Brep::SurfaceOf( const ON_BrepTrim& trim ) const
7636 //{
7637 //  // OBSOLETE FUNCTION
7638 //  const int si = trim.SurfaceIndexOf();
7639 //  return (si>=0)?m_S[si]:0;
7640 //}
7641 
7642 //ON_Surface* ON_Brep::SurfaceOf( const ON_BrepLoop& loop ) const
7643 //{
7644 //  // OBSOLETE FUNCTION
7645 //  return const_cast<ON_Surface*>(loop.SurfaceOf());
7646 //}
7647 
7648 //ON_Surface* ON_Brep::SurfaceOf( const ON_BrepFace& face ) const
7649 //{
7650 //  // OBSOLETE FUNCTION
7651 //  return const_cast<ON_Surface*>(face.SurfaceOf());
7652 //}
7653 
7654 //int ON_Brep::EdgeCurveIndexOf( const ON_BrepTrim& trim ) const
7655 //{
7656 //  // OBSOLETE FUNCTION
7657 //  return trim.EdgeCurveIndexOf();
7658 //}
7659 
7660 //int ON_Brep::EdgeCurveIndexOf( const ON_BrepEdge& edge ) const
7661 //{
7662 //  // OBSOLETE FUNCTION
7663 //  return edge.m_c3i;
7664 //}
7665 
7666 //ON_Curve* ON_Brep::EdgeCurveOf( const ON_BrepTrim& trim ) const
7667 //{
7668 //  // OBSOLETE FUNCTION
7669 //  return const_cast<ON_Curve*>(trim.EdgeCurveOf());
7670 //}
7671 
7672 //ON_Curve* ON_Brep::EdgeCurveOf( const ON_BrepEdge& edge ) const
7673 //{
7674 //  return ((edge.m_c3i>=0&&edge.m_c3i<m_C3.Count())?m_C3[edge.m_c3i]:0);
7675 //}
7676 
7677 //int ON_Brep::TrimCurveIndexOf( const ON_BrepTrim& trim ) const
7678 //{
7679 //  return trim.m_c2i;
7680 //}
7681 
7682 //ON_Curve* ON_Brep::TrimCurveOf( const ON_BrepTrim& trim ) const
7683 //{
7684 //  return ((trim.m_c2i>=0&&trim.m_c2i<m_C2.Count())?m_C2[trim.m_c2i]:0);
7685 //}
7686 
DeleteVertex(ON_BrepVertex & vertex)7687 void ON_Brep::DeleteVertex(ON_BrepVertex& vertex)
7688 {
7689   const int vi = vertex.m_vertex_index;
7690   vertex.m_vertex_index = -1;
7691   if ( vi >= 0 && vi < m_V.Count() ) {
7692     int vei, ei;
7693     for ( vei = vertex.m_ei.Count()-1; vei>=0; vei-- ) {
7694       ei = vertex.m_ei[vei];
7695       if ( ei >= 0 && ei < m_E.Count() ) {
7696         ON_BrepEdge& edge = m_E[ei];
7697         if ( edge.m_vi[0] == vi )
7698           edge.m_vi[0] = -1;
7699         if ( edge.m_vi[1] == vi )
7700           edge.m_vi[1] = -1;
7701         DeleteEdge( edge, false );
7702       }
7703     }
7704   }
7705   vertex.m_ei.Empty();
7706   vertex.m_tolerance = ON_UNSET_VALUE;
7707 }
7708 
Loop3dCurve(const ON_BrepLoop & loop,ON_SimpleArray<ON_Curve * > & curve_list,ON_BOOL32 bRevCurveIfFaceRevIsTrue) const7709 int ON_Brep::Loop3dCurve(
7710   const ON_BrepLoop& loop,
7711   ON_SimpleArray<ON_Curve*>& curve_list,
7712   ON_BOOL32 bRevCurveIfFaceRevIsTrue
7713   ) const
7714 {
7715   int curve_list_count0 = curve_list.Count();
7716   ON_PolyCurve* poly_curve = NULL;
7717   ON_Curve* loop_curve = NULL;
7718   ON_SimpleArray<int> trim_index( 2*loop.m_ti.Count() + 8);
7719   int i, lti, ti;
7720   int loop_trim_count = loop.m_ti.Count();
7721   if ( loop_trim_count < 1 )
7722     return 0;
7723 
7724 
7725   int seam_lti = -1; // index of first seam
7726   int wire_lti = -1;
7727   for ( lti = 0; lti < loop_trim_count; lti++ )
7728   {
7729     ti = loop.m_ti[lti];
7730     if ( ti >= 0 && ti < m_T.Count() )
7731     {
7732       const ON_BrepTrim& trim = m_T[ti];
7733       if ( seam_lti < 0 && trim.m_type == ON_BrepTrim::seam )
7734         seam_lti = lti;
7735       else if ( wire_lti < 0 && trim.m_type != ON_BrepTrim::singular )
7736         wire_lti = lti;
7737     }
7738   }
7739 
7740   if ( wire_lti < 0 )
7741     return 0; // sphere boundary, torus boundary, etc.
7742 
7743   if ( seam_lti < 0 )
7744   {
7745     // simple case;
7746     loop_curve = Loop3dCurve(loop,bRevCurveIfFaceRevIsTrue);
7747     if ( loop_curve )
7748       curve_list.Append(loop_curve);
7749     return curve_list.Count() - curve_list_count0;
7750   }
7751 
7752   bool bOnSeam = true;
7753   for ( lti = seam_lti; lti < seam_lti+loop_trim_count; lti++ )
7754   {
7755     ti = loop.m_ti[lti%loop_trim_count];
7756 
7757     if ( ti < 0 || ti >= m_T.Count() )
7758       ti = loop.m_ti[seam_lti]; // treat bogus indices as trims
7759 
7760     const ON_BrepTrim& trim = m_T[ti];
7761     if ( trim.m_type == ON_BrepTrim::seam )
7762     {
7763       if (!bOnSeam)
7764       {
7765         trim_index.Append(-1);
7766         bOnSeam = true;
7767       }
7768       continue;
7769     }
7770     // 10-1-03 Lowell - fixed typo
7771     if ( trim.m_type == ON_BrepTrim::singular )
7772       continue;
7773     bOnSeam = false;
7774     trim_index.Append(ti);
7775   }
7776 
7777   for ( i = 0; i < trim_index.Count(); i++ )
7778   {
7779     ti = trim_index[i];
7780     if ( ti < 0 )
7781     {
7782       if ( loop_curve )
7783         curve_list.Append(loop_curve);
7784       loop_curve = 0;
7785       poly_curve = 0;
7786       continue;
7787     }
7788 
7789     // get 3d curve associated with this trim's edge
7790     const ON_BrepTrim& trim = m_T[ti];
7791     const ON_BrepEdge& edge = m_E[trim.m_ei];
7792     ON_Curve* segment_curve = edge.DuplicateCurve();
7793     if ( !segment_curve )
7794       continue;
7795     if ( trim.m_bRev3d )
7796       segment_curve->Reverse();
7797 
7798     if ( !loop_curve )
7799       loop_curve = segment_curve;
7800     else if ( !poly_curve )
7801     {
7802       poly_curve = new ON_PolyCurve();
7803       poly_curve->Append(loop_curve);
7804       poly_curve->Append(segment_curve);
7805       loop_curve = poly_curve;
7806     }
7807     else
7808       poly_curve->Append( segment_curve );
7809   }
7810 
7811   // 10-1-03 Lowell - add the last non-seam segment
7812   if ( loop_curve )
7813     curve_list.Append(loop_curve);
7814 
7815   if ( bRevCurveIfFaceRevIsTrue )
7816   {
7817     int fi = loop.m_fi;
7818     if ( fi >= 0 && fi < m_F.Count() && m_F[fi].m_bRev )
7819     {
7820       for ( i = curve_list_count0; i < curve_list.Count(); i++ )
7821         curve_list[i]->Reverse();
7822     }
7823   }
7824 
7825   return curve_list.Count() - curve_list_count0;
7826 }
7827 
7828 
Loop3dCurve(const ON_BrepLoop & loop,ON_BOOL32 bRevCurveIfFaceRevIsTrue) const7829 ON_Curve* ON_Brep::Loop3dCurve( const ON_BrepLoop& loop, ON_BOOL32 bRevCurveIfFaceRevIsTrue ) const
7830 {
7831   ON_PolyCurve* poly_curve = NULL;
7832   ON_Curve* loop_curve = NULL;
7833   ON_SimpleArray<int> trim_index( loop.m_ti.Count() );
7834   int i, lti, ti;
7835   for ( lti = 0; lti < loop.m_ti.Count(); lti++ )
7836   {
7837     ti = loop.m_ti[lti];
7838     if ( ti >= 0 && ti < m_T.Count() )
7839     {
7840       const ON_BrepTrim& trim = m_T[ti];
7841       if ( trim.EdgeCurveOf() )
7842         trim_index.Append(ti);
7843     }
7844   }
7845 
7846   for ( i = 0; i < trim_index.Count(); i++ )
7847   {
7848     // get 3d curve associated with this trim's edge
7849     const ON_BrepTrim& trim = m_T[trim_index[i]];
7850     const ON_BrepEdge& edge = m_E[trim.m_ei];
7851     ON_Curve* segment_curve = edge.DuplicateCurve();
7852     if ( !segment_curve )
7853       continue;
7854     if ( trim.m_bRev3d )
7855       segment_curve->Reverse();
7856 
7857     if ( !loop_curve )
7858       loop_curve = segment_curve;
7859     else if ( !poly_curve )
7860     {
7861       poly_curve = new ON_PolyCurve();
7862       poly_curve->Append(loop_curve);
7863       poly_curve->Append(segment_curve);
7864       loop_curve = poly_curve;
7865     }
7866     else
7867       poly_curve->Append( segment_curve );
7868   }
7869   if ( loop_curve && bRevCurveIfFaceRevIsTrue )
7870   {
7871     int fi = loop.m_fi;
7872     if ( fi >= 0 && fi < m_F.Count() && m_F[fi].m_bRev )
7873     {
7874       loop_curve->Reverse();
7875     }
7876   }
7877   return loop_curve;
7878 }
7879 
Loop2dCurve(const ON_BrepLoop & loop) const7880 ON_Curve* ON_Brep::Loop2dCurve( const ON_BrepLoop& loop ) const
7881 {
7882   ON_PolyCurve* poly_curve = NULL;
7883   ON_Curve* loop_curve = NULL;
7884   ON_SimpleArray<int> trim_index( loop.m_ti.Count() );
7885   int i, lti, ti;
7886   for ( lti = 0; lti < loop.m_ti.Count(); lti++ )
7887   {
7888     ti = loop.m_ti[lti];
7889     if ( ti >= 0 && ti < m_T.Count() )
7890     {
7891       const ON_BrepTrim& trim = m_T[ti];
7892       if ( trim.TrimCurveOf() )
7893         trim_index.Append(ti);
7894     }
7895   }
7896   for ( i = 0; i < trim_index.Count(); i++ )
7897   {
7898     // get 2d curve associated with this trim's edge
7899     const ON_BrepTrim& trim = m_T[trim_index[i]];
7900     ON_Curve* segment_curve = trim.DuplicateCurve();
7901     if ( !segment_curve )
7902       continue;
7903 
7904     if ( !loop_curve )
7905       loop_curve = segment_curve;
7906     else if ( !poly_curve )
7907     {
7908       poly_curve = new ON_PolyCurve();
7909       poly_curve->Append(loop_curve);
7910       poly_curve->Append(segment_curve);
7911       loop_curve = poly_curve;
7912     }
7913     else
7914       poly_curve->Append( segment_curve );
7915   }
7916   return loop_curve;
7917 }
7918 
7919 
7920 
DeleteEdge(ON_BrepEdge & edge,ON_BOOL32 bDeleteEdgeVertices)7921 void ON_Brep::DeleteEdge(ON_BrepEdge& edge, ON_BOOL32 bDeleteEdgeVertices )
7922 {
7923   const int ei = edge.m_edge_index;
7924   edge.m_edge_index = -1;
7925 
7926   if ( ei >= 0 && ei < m_E.Count() ) {
7927     int eti, ti, evi, vei, vi;
7928     for ( eti = edge.m_ti.Count()-1; eti >= 0; eti-- ) {
7929       ti = edge.m_ti[eti];
7930       if ( ti >= 0 && ti < m_T.Count() ) {
7931         ON_BrepTrim& trim = m_T[ti];
7932         trim.m_ei = -1;
7933         if ( trim.m_li >= 0 && trim.m_li < m_L.Count() ) {
7934           ON_BrepLoop& loop = m_L[trim.m_li];
7935           if ( loop.m_fi >= 0 && loop.m_fi < m_F.Count() ) {
7936             DeleteFace( m_F[loop.m_fi], bDeleteEdgeVertices );
7937           }
7938         }
7939         DeleteTrim(trim,false);
7940       }
7941     }
7942 
7943     for (evi = 0; evi < 2; evi++ )
7944     {
7945       vi = edge.m_vi[evi];
7946       if ( vi >= 0 && vi < m_V.Count() )
7947       {
7948         ON_BrepVertex& v = m_V[vi];
7949         for ( vei = v.m_ei.Count()-1; vei >= 0; vei-- )
7950         {
7951           if ( v.m_ei[vei] == ei )
7952             v.m_ei.Remove(vei);
7953         }
7954         if ( bDeleteEdgeVertices && v.m_ei.Count() <= 0 )
7955         {
7956           v.m_ei.Destroy();
7957           DeleteVertex(v);
7958         }
7959       }
7960     }
7961   }
7962 
7963   edge.m_c3i = -1;
7964   edge.m_vi[0] = -1;
7965   edge.m_vi[1] = -1;
7966   edge.m_ti.Empty();
7967   edge.m_tolerance = ON_UNSET_VALUE;
7968   edge.m_brep = 0;
7969   edge.SetProxyCurve(0);
7970 }
7971 
DeleteTrim(ON_BrepTrim & trim,ON_BOOL32 bDeleteTrimEdges)7972 void ON_Brep::DeleteTrim(ON_BrepTrim& trim, ON_BOOL32 bDeleteTrimEdges )
7973 {
7974   m_is_solid = 0;
7975 
7976   const int ti = trim.m_trim_index;
7977   trim.m_trim_index = -1;
7978 
7979   if ( ti >= 0 && ti < m_T.Count() )
7980   {
7981     const int ei = trim.m_ei;
7982     if ( ei >= 0 && ei < m_E.Count() )
7983     {
7984       ON_BrepEdge& edge = m_E[ei];
7985       if ( bDeleteTrimEdges && edge.m_ti.Count() == 1 && edge.m_ti[0] == ti )
7986       {
7987         edge.m_ti.Empty();
7988         DeleteEdge(edge,bDeleteTrimEdges);
7989       }
7990       else
7991       {
7992         int mate_ti = (trim.m_type == ON_BrepTrim::mated) ? -1 : -2; // set to >= 0 if a single mate exists
7993         int seam_ti = (trim.m_type == ON_BrepTrim::seam) ? -1 : -2; // set to >= 0 if a single seam partner exists
7994         int eti;
7995         for ( eti = edge.m_ti.Count()-1; eti >= 0; eti-- )
7996         {
7997           int other_ti = edge.m_ti[eti];
7998           if ( other_ti == ti )
7999           {
8000             edge.m_ti.Remove(eti);
8001             if ( edge.m_ti.Count() == 0 )
8002               edge.m_tolerance = 0.0;
8003             continue;
8004           }
8005 
8006           if ( (mate_ti >= -1 || seam_ti >= -1 ) && other_ti >= 0 && other_ti < m_T.Count() )
8007           {
8008             const ON_BrepTrim& other_trim = m_T[other_ti];
8009             if ( other_trim.m_trim_index != other_ti )
8010               continue;
8011             if ( mate_ti >= -1 && other_trim.m_type == ON_BrepTrim::mated )
8012             {
8013               // see if other_trim is the only mate of trim
8014               if ( mate_ti == -1 )
8015                 mate_ti = other_ti;
8016               else
8017                 mate_ti = -2;
8018             }
8019             else if ( seam_ti >= -1 && other_trim.m_type == ON_BrepTrim::seam && other_trim.m_li == trim.m_li )
8020             {
8021               // trim and other_trim are both seam trims in the same loop connected
8022               // to the same edge.
8023               if ( seam_ti == -1 )
8024                 seam_ti = other_ti;
8025               else
8026                 seam_ti = -2;
8027             }
8028           }
8029         }
8030 
8031         if ( seam_ti >= 0  )
8032         {
8033           // m_T[seam_ti] used to be a seam partner with trim.
8034           // Now it is either a boundary trim or is mated to m_T[mate_ti]
8035           m_T[seam_ti].m_type = (mate_ti>=0)
8036                               ? ON_BrepTrim::mated     // m_T[mate_ti] is mated to m_T[seam_ti]
8037                               : ON_BrepTrim::boundary; // m_T[seam_ti] is all alone
8038         }
8039         else if ( mate_ti >= 0 )
8040         {
8041           // m_T[mate_ti] just lost its only mate and is now a boundary
8042           m_T[mate_ti].m_type = ON_BrepTrim::boundary;
8043         }
8044       }
8045     }
8046 
8047     const int li = trim.m_li;
8048     if ( li >= 0 && li < m_L.Count() ) {
8049       ON_BrepLoop& loop = m_L[li];
8050       int lti;
8051       for ( lti = loop.m_ti.Count()-1; lti >= 0; lti-- ) {
8052         if ( loop.m_ti[lti] == ti )
8053           loop.m_ti.Remove(lti);
8054       }
8055     }
8056   }
8057 
8058   trim.m_c2i = -1;
8059   trim.m_ei = -1;
8060   trim.m_vi[0] = -1;
8061   trim.m_vi[1] = -1;
8062   trim.m_bRev3d = 0;
8063   trim.m_type = ON_BrepTrim::unknown;
8064   trim.m_iso = ON_Surface::not_iso;
8065   trim.m_li = -1;
8066   trim.m_tolerance[0] = ON_UNSET_VALUE;
8067   trim.m_tolerance[1] = ON_UNSET_VALUE;
8068   trim.m__legacy_2d_tol = ON_UNSET_VALUE;
8069   trim.m__legacy_3d_tol = ON_UNSET_VALUE;
8070   trim.m__legacy_flags = 0;
8071   trim.m_pbox.Destroy();
8072   trim.m_brep = 0;
8073   trim.SetProxyCurve(0);
8074 }
8075 
DeleteLoop(ON_BrepLoop & loop,ON_BOOL32 bDeleteLoopEdges)8076 void ON_Brep::DeleteLoop(ON_BrepLoop& loop,  ON_BOOL32 bDeleteLoopEdges  )
8077 {
8078   m_is_solid = 0;
8079 
8080   const int li = loop.m_loop_index;
8081   loop.m_loop_index = -1;
8082 
8083   if ( loop.m_fi >= 0 )
8084     DestroyMesh(ON::any_mesh,true);
8085 
8086   if ( li >= 0 && li < m_L.Count() )
8087   {
8088     const int tcount = m_T.Count();
8089     int lti, ti;
8090     for ( lti = loop.m_ti.Count()-1; lti >= 0; lti-- )
8091     {
8092       ti = loop.m_ti[lti];
8093       if ( ti >= 0 && ti < tcount )
8094       {
8095         ON_BrepTrim& trim = m_T[ti];
8096         trim.m_li = -1;
8097         DeleteTrim(trim,bDeleteLoopEdges);
8098       }
8099     }
8100 
8101     const int fi = loop.m_fi;
8102     if ( fi >= 0 && fi < m_F.Count() )
8103     {
8104       ON_BrepFace& face = m_F[fi];
8105       int fli;
8106       for ( fli = face.m_li.Count()-1; fli >= 0; fli-- )
8107       {
8108         if ( face.m_li[fli] == li )
8109         {
8110           face.m_li.Remove(fli);
8111         }
8112       }
8113     }
8114   }
8115 
8116   loop.m_type = ON_BrepLoop::unknown;
8117   loop.m_ti.Empty();
8118   loop.m_fi = -1;
8119   loop.m_pbox.Destroy();
8120   loop.m_brep = 0;
8121 }
8122 
DeleteFace(ON_BrepFace & face,ON_BOOL32 bDeleteFaceEdges)8123 void ON_Brep::DeleteFace(ON_BrepFace& face, ON_BOOL32 bDeleteFaceEdges )
8124 {
8125   m_bbox.Destroy();
8126   m_is_solid = 0;
8127 
8128   const int fi = face.m_face_index;
8129   face.m_face_index = -1;
8130 
8131   if ( fi >= 0 && fi < m_F.Count() ) {
8132     const int lcount = m_L.Count();
8133     int fli, li;
8134     for ( fli = face.m_li.Count()-1; fli >= 0; fli-- ) {
8135       li = face.m_li[fli];
8136       if ( li >= 0 && li < lcount ) {
8137         ON_BrepLoop& loop = m_L[li];
8138         loop.m_fi = -1;
8139         DeleteLoop(loop,bDeleteFaceEdges);
8140       }
8141     }
8142   }
8143 
8144   face.m_si = -1;
8145   face.m_li.Empty();
8146   face.SetProxySurface(0);
8147   face.m_brep = 0;
8148   face.m_bbox.Destroy();
8149 }
8150 
PropagateLabel(ON_Brep & B,ON_SimpleArray<int> & fids,int label)8151 static void PropagateLabel(ON_Brep& B,
8152                            ON_SimpleArray<int>& fids,
8153                            int label
8154                            )
8155 //on input, each face in fids must have m_face_user.i = label
8156 {
8157   if (fids.Count() == 0) return;
8158   ON_SimpleArray<int> new_fids(B.m_F.Count());
8159   for (int face_i=0; face_i<fids.Count(); face_i++)
8160   {
8161     const ON_BrepFace& F = B.m_F[fids[face_i]];
8162     for (int loop_i=0; loop_i<F.m_li.Count(); loop_i++)
8163     {
8164       ON_BrepLoop& L = B.m_L[F.m_li[loop_i]];
8165       memset(&L.m_loop_user,0,sizeof(L.m_loop_user));
8166       L.m_loop_user.i = label;
8167       for (int edge_i=0; edge_i<L.m_ti.Count(); edge_i++)
8168       {
8169         ON_BrepTrim& T = B.m_T[L.m_ti[edge_i]];
8170         memset(&T.m_trim_user,0,sizeof(T.m_trim_user));
8171         T.m_trim_user.i = label;
8172         if (T.m_ei < 0)
8173           continue;
8174         ON_BrepEdge& E = B.m_E[T.m_ei];
8175         memset(&E.m_edge_user,0,sizeof(E.m_edge_user));
8176         E.m_edge_user.i = label;
8177         for (int vertex_i=0; vertex_i<2; vertex_i++)
8178         {
8179           if (E.m_vi[vertex_i] >= 0)
8180           {
8181             ON_BrepVertex& V = B.m_V[E.m_vi[vertex_i]];
8182             memset(&V.m_vertex_user,0,sizeof(V.m_vertex_user));
8183             V.m_vertex_user.i = label;
8184           }
8185         }
8186 
8187         for (int trim_i=0; trim_i<E.m_ti.Count(); trim_i++)
8188         {
8189           int fi = B.m_T[E.m_ti[trim_i]].FaceIndexOf();
8190           if (fi < 0 || B.m_F[fi].m_face_user.i == label)
8191             continue;
8192           ON_BrepFace& F = B.m_F[fi];
8193           memset(&F.m_face_user,0,sizeof(F.m_face_user));
8194           F.m_face_user.i = label;
8195           new_fids.Append(fi);
8196         }
8197       }
8198     }
8199   }
8200   PropagateLabel(B, new_fids, label);
8201   return;
8202 }
8203 
8204 
LabelConnectedComponent(int face_index,int label)8205 void ON_Brep::LabelConnectedComponent(int face_index, int label)
8206 
8207 {
8208   if (face_index < 0 || face_index >= m_F.Count())
8209     return;
8210 
8211   ON_SimpleArray<int> fids(1);
8212   fids.Append(face_index);
8213   ON_BrepFace& F = m_F[face_index];
8214   memset(&F.m_face_user,0,sizeof(F.m_face_user));
8215   F.m_face_user.i = label;
8216   PropagateLabel(*this, fids, label);
8217   return;
8218 }
8219 
LabelConnectedComponents()8220 int ON_Brep::LabelConnectedComponents()
8221 
8222 {
8223   Clear_user_i();
8224   int i;
8225   for (i=0; i<m_F.Count(); i++){
8226     if (m_F[i].m_face_index < 0)
8227       m_F[i].m_face_user.i = -1;
8228   }
8229 
8230   int label = 0;
8231   bool keep_going = true;
8232   while (keep_going)
8233   {
8234     int face_index = -1;
8235     for (int j=0; j<m_F.Count(); j++)
8236     {
8237       if (m_F[j].m_face_user.i == 0)
8238       {
8239         face_index = j;
8240         break;
8241       }
8242     }
8243     if (face_index == -1)
8244     {
8245       keep_going = false;
8246       continue;
8247     }
8248     label++;
8249     LabelConnectedComponent(face_index, label);
8250   }
8251   return label;
8252 }
8253 
GetConnectedComponents(ON_SimpleArray<ON_Brep * > & components,bool bDuplicateMeshes) const8254 int ON_Brep::GetConnectedComponents( ON_SimpleArray< ON_Brep* >& components, bool bDuplicateMeshes ) const
8255 {
8256   const int count0 = components.Count();
8257   ON_Brep brep(*this);
8258   int count = brep.LabelConnectedComponents();
8259   if ( count > 1 )
8260   {
8261     int cci;
8262     ON_SimpleArray<int> fi(brep.m_F.Count());
8263     for ( cci = 1; cci <= count; cci++ )
8264     {
8265       fi.SetCount(0);
8266       for ( int j = 0; j < brep.m_F.Count(); j++ )
8267       {
8268         if ( brep.m_F[j].m_face_user.i == cci )
8269           fi.Append(j);
8270       }
8271       if ( fi.Count() > 0 )
8272       {
8273         ON_Brep* cc = brep.DuplicateFaces( fi.Count(), fi.Array(), bDuplicateMeshes );
8274         if ( cc )
8275           components.Append(cc);
8276       }
8277     }
8278   }
8279 
8280   return components.Count() - count0;
8281 }
8282 
DuplicateFace(int face_index,ON_BOOL32 bDuplicateMeshes) const8283 ON_Brep* ON_Brep::DuplicateFace( int face_index, ON_BOOL32 bDuplicateMeshes ) const
8284 {
8285   return DuplicateFaces( 1, &face_index, bDuplicateMeshes );
8286 }
8287 
DuplicateFaces(int face_count,const int * face_index,ON_BOOL32 bDuplicateMeshes) const8288 ON_Brep* ON_Brep::DuplicateFaces( int face_count, const int* face_index, ON_BOOL32 bDuplicateMeshes ) const
8289 {
8290   int fi, si, fli, lti, li, ti, i;
8291   ON_BOOL32 rc = false;
8292   ON_Brep* brep_copy = 0;
8293   ON_Object* dup = 0;
8294 
8295   // mark vertices, edges, faces, surfaces, and curves to duplicate
8296   ON_SimpleArray<int> s_remap(m_S.Count());
8297   s_remap.SetCount(m_S.Count());
8298   s_remap.Zero();
8299   ON_SimpleArray<int> f_remap(m_F.Count());
8300   f_remap.SetCount(m_F.Count());
8301   f_remap.Zero();
8302   ON_SimpleArray<int> c2_remap(m_C2.Count());
8303   c2_remap.SetCount(m_C2.Count());
8304   c2_remap.Zero();
8305   ON_SimpleArray<int> c3_remap(m_C3.Count());
8306   c3_remap.SetCount(m_C3.Count());
8307   c3_remap.Zero();
8308   ON_SimpleArray<int> e_remap(m_E.Count());
8309   e_remap.SetCount(m_E.Count());
8310   e_remap.Zero();
8311   ON_SimpleArray<int> v_remap(m_V.Count());
8312   v_remap.SetCount(m_V.Count());
8313   v_remap.Zero();
8314   for (i = 0; i < face_count; i++ ) {
8315     fi = face_index[i];
8316     if (fi >= 0 && fi < m_F.Count() ) {
8317       const ON_BrepFace& face = m_F[fi];
8318       rc = true;
8319       f_remap[fi] = 1;
8320       si = face.m_si;
8321       if ( si >= 0 && si < m_S.Count() ) {
8322         s_remap[si] = 1;
8323       }
8324       for ( fli = 0; fli < face.m_li.Count(); fli++ )
8325       {
8326         li = face.m_li[fli];
8327         if ( li < 0 || li >= m_L.Count() )
8328           continue;
8329         const ON_BrepLoop& loop = m_L[li];
8330         for ( lti = 0; lti < loop.m_ti.Count(); lti++ )
8331         {
8332           ti = loop.m_ti[lti];
8333           if ( ti < 0 || ti >= m_T.Count() )
8334             continue;
8335           const ON_BrepTrim& trim = m_T[ti];
8336           if ( trim.m_ei >= 0 && trim.m_ei < m_E.Count() )
8337           {
8338             int vi;
8339             e_remap[trim.m_ei] = 1;
8340             vi = m_E[trim.m_ei].m_vi[0];
8341             if ( vi >= 0 )
8342               v_remap[vi] = 1;
8343             vi = m_E[trim.m_ei].m_vi[1];
8344             if ( vi >= 0 )
8345               v_remap[vi] = 1;
8346           }
8347           if ( trim.m_vi[0] >= 0 )
8348             v_remap[trim.m_vi[0]] = 1;
8349           if ( trim.m_vi[1] >= 0 )
8350             v_remap[trim.m_vi[1]] = 1;
8351           int ci = trim.EdgeCurveIndexOf();
8352           if ( ci >= 0 ) {
8353             c3_remap[ci] = 1;
8354           }
8355           ci = trim.TrimCurveIndexOf();
8356           if ( ci >= 0 )
8357             c2_remap[ci] = 1;
8358         }
8359       }
8360     }
8361   }
8362   if ( !rc )
8363     return NULL;
8364 
8365   brep_copy = new ON_Brep();
8366 
8367   // duplicate surfaces
8368   for ( i = 0; i < m_S.Count() && rc; i++ )
8369   {
8370     if ( s_remap[i] ) {
8371       if ( !m_S[i] )
8372         break;
8373       dup = m_S[i]->Duplicate();
8374       ON_Surface* srf_copy = ON_Surface::Cast(dup);
8375       if ( !srf_copy )
8376         break;
8377       s_remap[i] = brep_copy->AddSurface(srf_copy);
8378       dup = 0;
8379     }
8380     else
8381       s_remap[i] = -1;
8382   }
8383   rc = ( rc && i == m_S.Count() );
8384 
8385   // duplicate 2d curves
8386   for ( i = 0; i < m_C2.Count() && rc; i++ )
8387   {
8388     if ( c2_remap[i] ) {
8389       if ( !m_C2[i] )
8390         break;
8391       dup = m_C2[i]->Duplicate();
8392       ON_Curve* crv_copy = ON_Curve::Cast(dup);
8393       if ( !crv_copy )
8394         break;
8395       c2_remap[i] = brep_copy->AddTrimCurve(crv_copy);
8396       dup = 0;
8397     }
8398     else
8399       c2_remap[i] = -1;
8400   }
8401   rc = ( rc && i == m_C2.Count() );
8402 
8403   // duplicate 3d curves
8404   for ( i = 0; i < m_C3.Count() && rc; i++ )
8405   {
8406     if ( c3_remap[i] ) {
8407       if ( !m_C3[i] )
8408         break;
8409       dup = m_C3[i]->Duplicate();
8410       ON_Curve* crv_copy = ON_Curve::Cast(dup);
8411       if ( !crv_copy )
8412         break;
8413       c3_remap[i] = brep_copy->AddEdgeCurve(crv_copy);
8414       dup = 0;
8415     }
8416     else
8417       c3_remap[i] = -1;
8418   }
8419   rc = ( rc && i == m_C3.Count() );
8420 
8421   // duplicate vertices
8422   for (i = 0; i < m_V.Count() && rc; i++ )
8423   {
8424     if (v_remap[i])
8425     {
8426       ON_BrepVertex& vertex_copy = brep_copy->NewVertex(m_V[i].point);
8427       memset(&vertex_copy.m_vertex_user,0,sizeof(vertex_copy.m_vertex_user));
8428       vertex_copy.m_vertex_user.i = i;
8429       v_remap[i] = vertex_copy.m_vertex_index;
8430     }
8431     else
8432       v_remap[i] = -1;
8433   }
8434   rc = ( rc && i == m_V.Count() );
8435 
8436   // duplicate edges
8437   for (i = 0; i < m_E.Count() && rc; i++ )
8438   {
8439     if (e_remap[i])
8440     {
8441       const ON_BrepEdge& edge = m_E[i];
8442       //int vi0 = edge.m_vi[0];
8443       if ( edge.m_vi[0] < 0 || edge.m_vi[1] < 0 || edge.m_c3i < 0 )
8444         break;
8445       if ( v_remap[edge.m_vi[0]] < 0 || v_remap[edge.m_vi[1]] < 0 || c3_remap[edge.m_c3i] < 0)
8446         break;
8447       ON_BrepEdge& edge_copy = brep_copy->NewEdge( brep_copy->m_V[v_remap[edge.m_vi[0]]],
8448                                                    brep_copy->m_V[v_remap[edge.m_vi[1]]],
8449                                                    c3_remap[edge.m_c3i]
8450                                                    );
8451       edge_copy.SetProxyCurveDomain( edge.ProxyCurveDomain());
8452       if ( edge.ProxyCurveIsReversed() )
8453         edge_copy.ON_CurveProxy::Reverse();
8454       edge_copy.SetDomain(edge.Domain());
8455 
8456       memset(&edge_copy.m_edge_user,0,sizeof(edge_copy.m_edge_user));
8457       edge_copy.m_edge_user.i = i;
8458       edge_copy.m_tolerance = edge.m_tolerance;
8459       e_remap[i] = edge_copy.m_edge_index;
8460     }
8461     else
8462       e_remap[i] = -1;
8463   }
8464   rc = ( rc && i == m_E.Count() );
8465 
8466   //03/11/2010 Tim
8467   //More checking to prevent crashes
8468   //from bogus array indices
8469   bool bFoundBadIdx = false;
8470 
8471   // duplicate faces
8472   for ( fi = 0; rc && fi < m_F.Count() && rc && !bFoundBadIdx; fi++ )
8473   {
8474     if ( f_remap[fi] == 0 )
8475       continue;
8476     rc = false;
8477     const ON_BrepFace& face = m_F[fi];
8478 
8479     // duplicate face
8480     si = (face.m_si>=0) ? s_remap[face.m_si] : -1;
8481     if ( si < 0 )
8482       break;
8483 
8484     ON_BrepFace& face_copy = brep_copy->NewFace(si);
8485     memset(&face_copy.m_face_user,0,sizeof(face_copy.m_face_user));
8486     face_copy.m_face_user.i = fi;
8487     face_copy.m_bRev = face.m_bRev;
8488     face_copy.m_bbox = face.m_bbox;
8489     face_copy.m_domain[0] = face.m_domain[0];
8490     face_copy.m_domain[1] = face.m_domain[1];
8491     //face_copy.m_material_index = face.m_material_index;
8492     // do NOT duplicate meshes here
8493 
8494     // duplicate loops and trims
8495     for ( fli = 0; fli < face.m_li.Count() && !bFoundBadIdx; fli++ )
8496     {
8497       li = face.m_li[fli];
8498       if (0 > li || m_L.Count() <= li)
8499       {
8500         bFoundBadIdx = true;
8501         break;
8502       }
8503 
8504       const ON_BrepLoop& loop = m_L[li];
8505       ON_BrepLoop& loop_copy = brep_copy->NewLoop( loop.m_type, face_copy );
8506       memset(&loop_copy.m_loop_user,0,sizeof(loop_copy.m_loop_user));
8507       loop_copy.m_loop_user.i = li;
8508       for ( lti = 0; lti < loop.m_ti.Count() && !bFoundBadIdx; lti++ )
8509       {
8510         ti = loop.m_ti[lti];
8511         if (0 > ti || m_T.Count() <= ti)
8512         {
8513           bFoundBadIdx = true;
8514           break;
8515         }
8516         const ON_BrepTrim& trim = m_T[ti];
8517         i = (trim.m_c2i>=0) ? c2_remap[trim.m_c2i] : -1;
8518         if ( trim.m_ei >= 0 ) {
8519           i = brep_copy->NewTrim( brep_copy->m_E[e_remap[trim.m_ei]], trim.m_bRev3d, loop_copy, i ).m_trim_index;
8520         }
8521         else {
8522           i = brep_copy->NewTrim( trim.m_bRev3d, loop_copy, i ).m_trim_index;
8523           int vi0 = (trim.m_vi[0]>=0) ? v_remap[trim.m_vi[0]] : -1;
8524           int vi1 = (trim.m_vi[1]>=0) ? v_remap[trim.m_vi[1]] : -1;
8525           brep_copy->m_T[i].m_vi[0] = vi0;
8526           brep_copy->m_T[i].m_vi[1] = vi1;
8527         }
8528         ON_BrepTrim& trim_copy = brep_copy->m_T[i];
8529 
8530         //trim_copy.m_t = trim.m_t;
8531         trim_copy.SetProxyCurveDomain( trim.ProxyCurveDomain());
8532         if ( trim.ProxyCurveIsReversed() )
8533           trim_copy.ON_CurveProxy::Reverse();
8534         trim_copy.SetDomain(trim.Domain());
8535 
8536         memset(&trim_copy.m_trim_user,0,sizeof(trim_copy.m_trim_user));
8537         trim_copy.m_trim_user.i = ti;
8538         trim_copy.m_iso = trim.m_iso;
8539         trim_copy.m_tolerance[0] = trim.m_tolerance[0];
8540         trim_copy.m_tolerance[1] = trim.m_tolerance[1];
8541         trim_copy.m_pline = trim.m_pline;
8542         trim_copy.m_pbox = trim.m_pbox;
8543         trim_copy.m__legacy_2d_tol = trim.m__legacy_2d_tol;
8544         trim_copy.m__legacy_3d_tol = trim.m__legacy_3d_tol;
8545         trim_copy.m__legacy_flags = trim.m__legacy_flags;
8546       }
8547 
8548       if (bFoundBadIdx)
8549         break;
8550 
8551       loop_copy.m_pbox = loop.m_pbox;
8552     }
8553 
8554     if (bFoundBadIdx)
8555       break;
8556 
8557     if ( bDuplicateMeshes )
8558     {
8559       if ( face.m_render_mesh )
8560         face_copy.m_render_mesh = face.m_render_mesh->Duplicate();
8561       if ( face.m_analysis_mesh )
8562         face_copy.m_analysis_mesh = face.m_analysis_mesh->Duplicate();
8563       if ( face.m_preview_mesh )
8564         face_copy.m_preview_mesh = face.m_preview_mesh->Duplicate();
8565     }
8566 
8567     rc = true;
8568   }
8569   rc = ( rc && fi == m_F.Count() );
8570 
8571   if ( !rc ) {
8572     if ( dup ) {
8573       delete dup;
8574       dup = 0;
8575     }
8576     if ( brep_copy ) {
8577       delete brep_copy;
8578       brep_copy = 0;
8579     }
8580   }
8581   else
8582   {
8583     // set flags, tolerances, etc. that have changed
8584     brep_copy->SetTrimTypeFlags();
8585     brep_copy->SetVertexTolerances();
8586   }
8587   return brep_copy;
8588 }
8589 
ExtractFace(int face_index)8590 ON_Brep* ON_Brep::ExtractFace( int face_index )
8591 {
8592   ON_Brep* brep_copy = DuplicateFace(face_index,false);
8593   if ( brep_copy ) {
8594     ON_BrepFace& face = m_F[face_index];
8595     ON_BrepFace& face_copy = brep_copy->m_F[0];
8596     face_copy.m_render_mesh = face.m_render_mesh; face.m_render_mesh = 0;
8597     face_copy.m_analysis_mesh = face.m_analysis_mesh; face.m_analysis_mesh = 0;
8598     face_copy.m_preview_mesh = face.m_preview_mesh; face.m_preview_mesh = 0;
8599     DeleteFace( face, true );
8600   }
8601   return brep_copy;
8602 }
8603 
DeleteSurface(int si)8604 void ON_Brep::DeleteSurface(int si)
8605 {
8606   if ( si >= 0 && si < m_S.Count() ) {
8607     delete m_S[si];
8608     m_S[si] = 0;
8609   }
8610 }
8611 
Delete2dCurve(int c2i)8612 void ON_Brep::Delete2dCurve(int c2i)
8613 {
8614   if ( c2i >= 0 && c2i < m_C2.Count() ) {
8615     delete m_C2[c2i];
8616     m_C2[c2i] = 0;
8617   }
8618 }
8619 
Delete3dCurve(int c3i)8620 void ON_Brep::Delete3dCurve(int c3i)
8621 {
8622   if ( c3i >= 0 && c3i < m_C3.Count() ) {
8623     delete m_C3[c3i];
8624     m_C3[c3i] = 0;
8625   }
8626 }
8627 
8628 
CullUnusedFaces()8629 bool ON_Brep::CullUnusedFaces()
8630 {
8631   bool rc = true;
8632   int fcount = m_F.Count();
8633   if (fcount > 0 ) {
8634     ON_Workspace ws;
8635     int *fmap = ws.GetIntMemory(fcount+1);
8636     *fmap++ = -1;
8637     memset( fmap, 0, fcount*sizeof(*fmap) );
8638     const int lcount = m_L.Count();
8639     int fi, li, mi = 0;
8640 
8641     // if face.m_face_index is -1, cull face
8642     for ( fi = 0; fi < fcount; fi++ ) {
8643       ON_BrepFace& face = m_F[fi];
8644       if ( face.m_face_index == -1)
8645         fmap[fi] = -1;
8646       else if ( face.m_face_index == fi )
8647         fmap[fi] = face.m_face_index = mi++;
8648       else {
8649         ON_ERROR("Brep face has illegal m_face_index.");
8650         rc = false;
8651         fmap[fi] = face.m_face_index;
8652       }
8653     }
8654 
8655     if ( mi == 0 ) {
8656       m_F.Destroy();
8657     }
8658     else if ( mi < fcount ) {
8659       // set new face indices
8660       mi = 0;
8661       for ( fi = fcount-1; fi >= 0; fi-- ) {
8662         if ( m_F[fi].m_face_index  == -1 )
8663           m_F.Remove(fi);
8664         else
8665           m_F[fi].m_face_index = fmap[fi];
8666       }
8667 
8668       // remap loop.m_fi indices
8669       for ( li = 0; li < lcount; li++ ) {
8670         ON_BrepLoop& loop = m_L[li];
8671         fi = loop.m_fi;
8672         if ( fi < -1 || fi >= fcount ) {
8673           ON_ERROR("Brep loop has illegal m_fi.");
8674           rc = false;
8675         }
8676         else
8677           loop.m_fi = fmap[fi];
8678       }
8679 
8680     }
8681   }
8682   m_F.Shrink();
8683   return rc;
8684 }
8685 
CullUnusedSurfaces()8686 bool ON_Brep::CullUnusedSurfaces()
8687 {
8688   // remove unused surfaces
8689   bool rc = true;
8690   const int fcount = m_F.Count();
8691   int scount = m_S.Count();
8692   int si, fi, mi;
8693 
8694   if ( scount > 0 ) {
8695     ON_Workspace ws;
8696     int* smap = ws.GetIntMemory(scount+1);
8697     *smap++ = -1;
8698     memset(smap,0,scount*sizeof(*smap));
8699     mi = 0;
8700     for ( fi = 0; fi < fcount; fi++ ) {
8701       ON_BrepFace& face = m_F[fi];
8702       if ( face.m_face_index == -1 ) {
8703         face.m_si = -1;
8704         continue;
8705       }
8706       si = face.m_si;
8707       if ( si == -1 )
8708         continue;
8709       if ( si < 0 || si >= scount ) {
8710         ON_ERROR("Brep face has illegal m_si.");
8711         rc = false;
8712       }
8713       else {
8714         if ( !smap[si] )
8715           mi++;
8716         smap[si]++;
8717       }
8718     }
8719 
8720     if ( mi == 0 ) {
8721       m_S.Destroy();
8722     }
8723     else if ( mi < scount ) {
8724       mi = 0;
8725       for ( si = 0; si < scount; si++ ) {
8726         if ( smap[si] )
8727           smap[si] = mi++;
8728         else {
8729           delete m_S[si];
8730           m_S[si] = 0;
8731           smap[si] = -1;
8732         }
8733       }
8734 
8735       for ( fi = 0; fi < fcount; fi++ ) {
8736         ON_BrepFace& face = m_F[fi];
8737         si = face.m_si;
8738         if ( si >= 0 && si < scount )
8739           face.m_si = smap[si];
8740       }
8741 
8742       for ( si = scount-1; si >= 0; si-- ) {
8743         if ( smap[si] < 0 ) {
8744           m_S.Remove(si);
8745           scount--;
8746         }
8747       }
8748     }
8749   }
8750   m_S.Shrink();
8751   return rc;
8752 }
8753 
CullUnused3dCurves()8754 bool ON_Brep::CullUnused3dCurves()
8755 {
8756   // remove unused surfaces
8757   bool rc = true;
8758   const int ecount = m_E.Count();
8759   int c3count = m_C3.Count();
8760   int c3i, ei, mi;
8761 
8762   if ( c3count > 0 ) {
8763     ON_Workspace ws;
8764     int* c3map = ws.GetIntMemory(c3count+1);
8765     *c3map++ = -1;
8766     memset(c3map,0,c3count*sizeof(*c3map));
8767     mi = 0;
8768     for ( ei = 0; ei < ecount; ei++ ) {
8769       ON_BrepEdge& edge = m_E[ei];
8770       if ( edge.m_edge_index == -1 ) {
8771         edge.m_c3i = -1;
8772         continue;
8773       }
8774       c3i = edge.m_c3i;
8775       if ( c3i == -1 )
8776         continue;
8777       if ( c3i < -1 || c3i >= c3count ) {
8778         ON_ERROR("Brep edge has illegal m_c3i.");
8779         rc = false;
8780       }
8781       else {
8782         if ( !c3map[c3i] )
8783           mi++;
8784         c3map[c3i]++;
8785       }
8786     }
8787 
8788     if ( mi == 0 ) {
8789       m_C3.Destroy();
8790     }
8791     else if ( mi < c3count ) {
8792       mi = 0;
8793       for ( c3i = 0; c3i < c3count; c3i++ ) {
8794         if ( c3map[c3i] )
8795           c3map[c3i] = mi++;
8796         else {
8797           delete m_C3[c3i];
8798           m_C3[c3i] = 0;
8799           c3map[c3i] = -1;
8800         }
8801       }
8802 
8803       for ( ei = 0; ei < ecount; ei++ ) {
8804         ON_BrepEdge& edge = m_E[ei];
8805         c3i = edge.m_c3i;
8806         if ( c3i >= 0 && c3i < c3count )
8807           edge.m_c3i = c3map[c3i];
8808       }
8809 
8810       for ( c3i = c3count-1; c3i >= 0; c3i-- ) {
8811         if ( c3map[c3i] < 0 ) {
8812           m_C3.Remove(c3i);
8813           c3count--;
8814         }
8815       }
8816     }
8817   }
8818   m_C3.Shrink();
8819   return rc;
8820 }
8821 
8822 
CullUnused2dCurves()8823 bool ON_Brep::CullUnused2dCurves()
8824 {
8825   // remove unused surfaces
8826   bool rc = true;
8827   const int tcount = m_T.Count();
8828   int c2count = m_C2.Count();
8829   int c2i, ti, mi;
8830 
8831   if ( c2count > 0 )
8832   {
8833     ON_Workspace ws;
8834     int* c2map = ws.GetIntMemory(c2count+1);
8835     *c2map++ = -1;
8836     memset(c2map,0,c2count*sizeof(*c2map));
8837     mi = 0;
8838     for ( ti = 0; ti < tcount; ti++ ) {
8839       ON_BrepTrim& trim = m_T[ti];
8840       if ( trim.m_trim_index == -1 ) {
8841         trim.m_c2i = -1;
8842         continue;
8843       }
8844       c2i = trim.m_c2i;
8845       if ( c2i == -1 )
8846         continue;
8847       if ( c2i < -1 || c2i >= c2count ) {
8848         ON_ERROR("Brep trim has illegal m_c2i.");
8849         rc = false;
8850       }
8851       else {
8852         if ( !c2map[c2i] )
8853           mi++;
8854         c2map[c2i]++;
8855       }
8856     }
8857 
8858     if ( mi == 0 ) {
8859       m_C2.Destroy();
8860     }
8861     else if ( mi < c2count ) {
8862       mi = 0;
8863       for ( c2i = 0; c2i < c2count; c2i++ ) {
8864         if ( c2map[c2i] )
8865           c2map[c2i] = mi++;
8866         else {
8867           delete m_C2[c2i];
8868           m_C2[c2i] = 0;
8869           c2map[c2i] = -1;
8870         }
8871       }
8872 
8873       for ( ti = 0; ti < tcount; ti++ ) {
8874         ON_BrepTrim& trim = m_T[ti];
8875         c2i = trim.m_c2i;
8876         if ( c2i >= 0 && c2i < c2count )
8877           trim.m_c2i = c2map[c2i];
8878       }
8879 
8880       for ( c2i = c2count-1; c2i >= 0; c2i-- ) {
8881         if ( c2map[c2i] < 0 ) {
8882           m_C2.Remove(c2i);
8883           c2count--;
8884         }
8885       }
8886     }
8887   }
8888   m_C2.Shrink();
8889   return rc;
8890 }
8891 
8892 
CullUnusedLoops()8893 bool ON_Brep::CullUnusedLoops()
8894 {
8895   bool rc = true;
8896   const int lcount = m_L.Count();
8897   if ( lcount > 0 ) {
8898     ON_Workspace ws;
8899     int* lmap = ws.GetIntMemory(lcount+1);
8900     *lmap++ = -1;
8901     memset( lmap, 0, lcount*sizeof(*lmap) );
8902     const int fcount = m_F.Count();
8903     const int tcount = m_T.Count();
8904     int li, fli, flcnt, fi, ti, mi;
8905 
8906     mi = 0;
8907     for ( li = 0; li < lcount; li++ ) {
8908       ON_BrepLoop& loop = m_L[li];
8909       if ( loop.m_loop_index == -1)
8910         lmap[li] = -1;
8911       else if ( loop.m_loop_index == li )
8912         lmap[li] = loop.m_loop_index = mi++;
8913       else {
8914         ON_ERROR("Brep loop has illegal m_loop_index.");
8915         rc = false;
8916         lmap[li] = loop.m_loop_index;
8917       }
8918     }
8919 
8920     if ( mi == 0 ) {
8921       m_L.Destroy();
8922     }
8923     else if ( mi < lcount ) {
8924 
8925       // remap loops
8926       for ( li = lcount-1; li >= 0; li-- ) {
8927         if ( m_L[li].m_loop_index == -1 )
8928           m_L.Remove(li);
8929         else
8930           m_L[li].m_loop_index = lmap[li];
8931       }
8932 
8933       // remap ON_BrepFace.m_li[] indices
8934       for ( fi = 0; fi < fcount; fi++ ) {
8935         ON_BrepFace& face = m_F[fi];
8936         flcnt = face.m_li.Count();
8937         for ( fli = flcnt-1; fli >= 0; fli-- ) {
8938           li = face.m_li[fli];
8939           if ( li < -1 || li >= lcount ) {
8940             ON_ERROR("Brep face m_li[] has illegal loop index.");
8941             rc = false;
8942           }
8943           else {
8944             li = lmap[li];
8945             if (li >= 0 ) {
8946               face.m_li[fli] = li;
8947             }
8948             else {
8949               face.m_li.Remove(fli);
8950             }
8951           }
8952         }
8953       }
8954 
8955       // remap ON_BrepTrim.m_li indices
8956       for ( ti = 0; ti < tcount; ti++ ) {
8957         ON_BrepTrim& trim = m_T[ti];
8958         li = trim.m_li;
8959         if ( li < -1 || li >= lcount ) {
8960           ON_ERROR("Brep trim has illegal m_li.");
8961           rc = false;
8962         }
8963         else {
8964           trim.m_li = lmap[li];
8965         }
8966       }
8967     }
8968   }
8969   m_L.Shrink();
8970   return rc;
8971 }
8972 
CullUnusedTrims()8973 bool ON_Brep::CullUnusedTrims()
8974 {
8975   bool rc = true;
8976   const int tcount = m_T.Count();
8977   if ( tcount > 0 ) {
8978     ON_Workspace ws;
8979     int *tmap = ws.GetIntMemory(tcount+1);
8980     *tmap++ = -1;
8981     memset( tmap, 0, tcount*sizeof(*tmap));
8982     const int lcount = m_L.Count();
8983     const int ecount = m_E.Count();
8984     int ti, li, ei, mi, ltcnt, lti, etcnt, eti;
8985 
8986     mi = 0;
8987     for ( ti = 0; ti < tcount; ti++ ) {
8988       ON_BrepTrim& trim = m_T[ti];
8989       if ( trim.m_trim_index == -1)
8990         tmap[ti] = -1;
8991       else if ( trim.m_trim_index == ti )
8992         tmap[ti] = trim.m_trim_index = mi++;
8993       else {
8994         ON_ERROR("Brep trim has illegal m_trim_index.");
8995         rc = false;
8996         tmap[ti] = trim.m_trim_index;
8997       }
8998     }
8999 
9000     if ( mi == 0 ) {
9001       m_T.Destroy();
9002     }
9003     else if ( mi < tcount ) {
9004       // remap trim indices
9005       for ( ti = tcount-1; ti >= 0; ti-- ) {
9006         if ( m_T[ti].m_trim_index == -1 ) {
9007           m_T.Remove(ti);
9008         }
9009         else {
9010           m_T[ti].m_trim_index = tmap[ti];
9011         }
9012       }
9013 
9014       // remap loop.m_ti[] indicies
9015       for ( li = 0; li < lcount; li++ ) {
9016         ON_BrepLoop& loop = m_L[li];
9017         ltcnt = loop.m_ti.Count();
9018         for ( lti = ltcnt-1; lti >= 0; lti-- ) {
9019           ti = loop.m_ti[lti];
9020           if ( ti < -1 || ti >= tcount ) {
9021             ON_ERROR("Brep loop.m_ti[] has illegal index.");
9022             rc = false;
9023           }
9024           else {
9025             ti = tmap[ti];
9026             if (ti >= 0 ) {
9027               loop.m_ti[lti] = ti;
9028             }
9029             else {
9030               loop.m_ti.Remove(lti);
9031             }
9032           }
9033         }
9034       }
9035 
9036       // remap edge.m_ti[] indicies
9037       for ( ei = 0; ei < ecount; ei++ ) {
9038         ON_BrepEdge& edge = m_E[ei];
9039         etcnt = edge.m_ti.Count();
9040         for ( eti = etcnt-1; eti >= 0; eti-- ) {
9041           ti = edge.m_ti[eti];
9042           if ( ti < -1 || ti >= tcount ) {
9043             ON_ERROR("Brep edge.m_ti[] has illegal index.");
9044             rc = false;
9045           }
9046           else {
9047             ti = tmap[ti];
9048             if (ti >= 0 ) {
9049               edge.m_ti[eti] = ti;
9050             }
9051             else {
9052               edge.m_ti.Remove(eti);
9053             }
9054           }
9055         }
9056       }
9057     }
9058   }
9059   m_T.Shrink();
9060   return rc;
9061 }
9062 
CullUnusedEdges()9063 bool ON_Brep::CullUnusedEdges()
9064 {
9065   bool rc = true;
9066   const int ecount = m_E.Count();
9067   if ( ecount > 0 ) {
9068     ON_Workspace ws;
9069     int* emap = ws.GetIntMemory(ecount+1);
9070     *emap++ = -1;
9071     memset( emap, 0, ecount*sizeof(*emap) );
9072     const int vcount = m_V.Count();
9073     const int tcount = m_T.Count();
9074     int ei, ti, vi, mi, vecnt, vei;
9075 
9076     mi = 0;
9077     for ( ei = 0; ei < ecount; ei++ ) {
9078       ON_BrepEdge& edge = m_E[ei];
9079       if ( edge.m_edge_index == -1)
9080         emap[ei] = -1;
9081       else if ( edge.m_edge_index == ei )
9082         emap[ei] = edge.m_edge_index = mi++;
9083       else {
9084         ON_ERROR("Brep edge has illegal m_edge_index.");
9085         rc = false;
9086         emap[ei] = edge.m_edge_index;
9087       }
9088     }
9089 
9090     if ( mi == 0 ) {
9091       m_E.Destroy();
9092     }
9093     else if ( mi < ecount )
9094     {
9095       // remap edge indices
9096       for ( ei = ecount-1; ei >= 0; ei-- ) {
9097         if ( m_E[ei].m_edge_index == -1 ) {
9098           m_E.Remove(ei);
9099         }
9100         else {
9101           m_E[ei].m_edge_index = emap[ei];
9102         }
9103       }
9104 
9105       // remap trim.m_ei
9106       for ( ti = 0; ti < tcount; ti++ ) {
9107         ON_BrepTrim& trim = m_T[ti];
9108         ei = trim.m_ei;
9109         if ( ei < -1 || ei >= ecount ) {
9110           ON_ERROR("Brep trim.m_ei has illegal index.");
9111           rc = false;
9112         }
9113         else {
9114           trim.m_ei = emap[ei];
9115         }
9116       }
9117 
9118       // remap vertex.m_ei[]
9119       for ( vi = 0; vi < vcount; vi++ ) {
9120         ON_BrepVertex& vertex = m_V[vi];
9121         vecnt = vertex.m_ei.Count();
9122         for ( vei = vecnt-1; vei >= 0; vei-- ) {
9123           ei = vertex.m_ei[vei];
9124           if ( ei < -1 || ei >= ecount ) {
9125             ON_ERROR("Brep vertex.m_ei[] has illegal index.");
9126             rc = false;
9127           }
9128           else {
9129             ei = emap[ei];
9130             if (ei >= 0 ) {
9131               vertex.m_ei[vei] = ei;
9132             }
9133             else {
9134               vertex.m_ei.Remove(vei);
9135             }
9136           }
9137         }
9138       }
9139     }
9140   }
9141   m_E.Shrink();
9142   return rc;
9143 }
9144 
9145 
CullUnusedVertices()9146 bool ON_Brep::CullUnusedVertices()
9147 {
9148   bool rc = true;
9149   const int vcount = m_V.Count();
9150   if ( vcount > 0 )
9151   {
9152     ON_Workspace ws;
9153     int* vmap = ws.GetIntMemory(vcount+1);
9154     *vmap++ = -1;
9155     memset(vmap,0,vcount*sizeof(*vmap));
9156     const int tcount = m_T.Count();
9157     const int ecount = m_E.Count();
9158     int vi, ei, ti, mi, j;
9159 
9160     if ( tcount > 0 )
9161     {
9162       // 11 Nov 2009 Dale Lear
9163       //  I added this code to fix bugs 55879 and 56191.
9164       for ( ti = 0; ti < tcount; ti++ )
9165       {
9166         const ON_BrepTrim& trim = m_T[ti];
9167         if ( -1 == trim.m_trim_index )
9168           continue;
9169         vi = trim.m_vi[0];
9170         if ( vi >= 0 && vi < vcount && -1 == m_V[vi].m_vertex_index )
9171         {
9172           // undelete this vertex
9173           // This error happens when the ON_Brep is invalid to begin with.
9174           // However, in order to prevent crashes, we have to refuse to delete
9175           // the vertex.  See bugs 55879 and 56191.
9176           ON_ERROR("ON_Brep::CullUnusedVertices() - deleted vertex referenced by trim.m_vi[0]");
9177           m_V[vi].m_vertex_index = vi;
9178         }
9179         vi = trim.m_vi[1];
9180         if ( vi >= 0 && vi < vcount && -1 == m_V[vi].m_vertex_index )
9181         {
9182           // undelete this vertex
9183           // This error happens when the ON_Brep is invalid to begin with.
9184           // However, in order to prevent crashes, we have to refuse to delete
9185           // the vertex.  See bugs 55879 and 56191.
9186           ON_ERROR("ON_Brep::CullUnusedVertices() - deleted vertex referenced by trim.m_vi[1]");
9187           m_V[vi].m_vertex_index = vi;
9188         }
9189       }
9190     }
9191 
9192     mi = 0;
9193     for ( vi = 0; vi < vcount; vi++ ) {
9194       ON_BrepVertex& vertex = m_V[vi];
9195       if ( vertex.m_vertex_index == -1)
9196         vmap[vi] = -1;
9197       else if ( vertex.m_vertex_index == vi )
9198         vmap[vi] = vertex.m_vertex_index = mi++;
9199       else {
9200         ON_ERROR("Brep vertex has illegal m_vertex_index.");
9201         rc = false;
9202         vmap[vi] = vertex.m_vertex_index;
9203       }
9204     }
9205 
9206     if ( mi == 0 )
9207     {
9208       m_V.Destroy();
9209     }
9210     else if ( mi < vcount )
9211     {
9212       // remap vertex indices
9213       for ( vi = vcount-1; vi >= 0; vi-- )
9214       {
9215         if ( m_V[vi].m_vertex_index == -1 )
9216         {
9217           m_V.Remove(vi);
9218         }
9219         else {
9220           m_V[vi].m_vertex_index = vmap[vi];
9221         }
9222       }
9223 
9224       // remap edge indices
9225       for ( ei = 0; ei < ecount; ei++ )
9226       {
9227         ON_BrepEdge& edge = m_E[ei];
9228         for ( j = 0; j < 2; j++ )
9229         {
9230           vi = edge.m_vi[j];
9231           if ( vi < -1 || vi >= vcount )
9232           {
9233             ON_ERROR("Brep edge.m_vi[] has illegal index.");
9234             rc = false;
9235           }
9236           else {
9237             edge.m_vi[j] = vmap[vi];
9238           }
9239         }
9240       }
9241 
9242       // remap trim indices
9243       for ( ti = 0; ti < tcount; ti++ )
9244       {
9245         ON_BrepTrim& trim = m_T[ti];
9246         for ( j = 0; j < 2; j++ )
9247         {
9248           vi = trim.m_vi[j];
9249           if ( vi < -1 || vi >= vcount )
9250           {
9251             ON_ERROR("Brep trim.m_vi[] has illegal index.");
9252             rc = false;
9253           }
9254           else {
9255             trim.m_vi[j] = vmap[vi];
9256           }
9257         }
9258       }
9259 
9260     }
9261   }
9262   m_V.Shrink();
9263   return rc;
9264 }
9265 
Compact()9266 bool ON_Brep::Compact()
9267 {
9268   // Removes any unreferenced objects from arrays,
9269   // reindexes as needed, and shrinks arrays to
9270   // minimum required size.
9271 
9272   bool rc = true;
9273   if (!CullUnusedFaces())
9274     rc = false;
9275   if (!CullUnusedEdges())
9276     rc = false;
9277   if (!CullUnusedVertices())
9278     rc = false;
9279   if (!CullUnusedLoops())
9280     rc = false;
9281   if (!CullUnusedTrims())
9282     rc = false;
9283 
9284   if (!CullUnusedSurfaces())
9285     rc = false;
9286   if (!CullUnused3dCurves())
9287     rc = false;
9288   if (!CullUnused2dCurves())
9289     rc = false;
9290 
9291   // If 1-1 relationships exist between geometry and topology,
9292   // the synchronize the geometry and topology indices.  This
9293   // helps confused users of breps not have to understand the
9294   // differences between geometry and topology data.
9295   ON_SimpleArray<bool> used;
9296   bool bSyncUp;
9297 
9298   if ( m_C2.Count() == m_T.Count() )
9299   {
9300     int i, count = m_C2.Count();
9301     used.Reserve(count);
9302     used.SetCount(count);
9303     used.Zero();
9304     bSyncUp = true;
9305     for ( i = 0; i < count && bSyncUp; i++ )
9306     {
9307       const ON_BrepTrim& trim = m_T[i];
9308       if ( trim.m_trim_index != i || trim.m_c2i < 0 || trim.m_c2i >= count )
9309         bSyncUp = false;
9310       else
9311       {
9312         if (used[trim.m_c2i])
9313           bSyncUp = false;
9314         else
9315           used[trim.m_c2i] = true;
9316       }
9317     }
9318     if ( bSyncUp )
9319     {
9320       ON_SimpleArray< ON_Curve* > ptr(count);
9321       for( i = 0; i < count; i++ )
9322       {
9323         ON_BrepTrim& trim = m_T[i];
9324         ptr[i] = m_C2[trim.m_c2i];
9325         trim.m_c2i = i;
9326       }
9327       for( i = 0; i < count; i++ )
9328       {
9329         m_C2[i] = ptr[i];
9330       }
9331     }
9332   }
9333 
9334   if ( m_C3.Count() == m_E.Count() )
9335   {
9336     int i, count = m_C3.Count();
9337     used.Reserve(count);
9338     used.SetCount(count);
9339     used.Zero();
9340     bSyncUp = true;
9341     for ( i = 0; i < count && bSyncUp; i++ )
9342     {
9343       const ON_BrepEdge& edge = m_E[i];
9344       if ( edge.m_edge_index != i || edge.m_c3i < 0 || edge.m_c3i >= count )
9345         bSyncUp = false;
9346       else
9347       {
9348         if (used[edge.m_c3i])
9349           bSyncUp = false;
9350         else
9351           used[edge.m_c3i] = true;
9352       }
9353     }
9354     if ( bSyncUp )
9355     {
9356       ON_SimpleArray< ON_Curve* > ptr(count);
9357       for( i = 0; i < count; i++ )
9358       {
9359         ON_BrepEdge& edge = m_E[i];
9360         ptr[i] = m_C3[edge.m_c3i];
9361         edge.m_c3i = i;
9362       }
9363       for( i = 0; i < count; i++ )
9364       {
9365         m_C3[i] = ptr[i];
9366       }
9367     }
9368   }
9369 
9370   if ( m_S.Count() == m_F.Count() )
9371   {
9372     int i, count = m_S.Count();
9373     used.Reserve(count);
9374     used.SetCount(count);
9375     used.Zero();
9376     bSyncUp = true;
9377     for ( i = 0; i < count && bSyncUp; i++ )
9378     {
9379       const ON_BrepFace& face = m_F[i];
9380       if ( face.m_face_index != i || face.m_si < 0 || face.m_si >= count )
9381         bSyncUp = false;
9382       else
9383       {
9384         if (used[face.m_si])
9385           bSyncUp = false;
9386         else
9387           used[face.m_si] = true;
9388       }
9389     }
9390     if ( bSyncUp )
9391     {
9392       ON_SimpleArray< ON_Surface* > ptr(count);
9393       for( i = 0; i < count; i++ )
9394       {
9395         ON_BrepFace& face = m_F[i];
9396         ptr[i] = m_S[face.m_si];
9397         face.m_si = i;
9398       }
9399       for( i = 0; i < count; i++ )
9400       {
9401         m_S[i] = ptr[i];
9402       }
9403     }
9404   }
9405 
9406   return rc;
9407 }
9408 
9409 
operator =(const ON_Brep & src)9410 ON_Brep& ON_Brep::operator=(const ON_Brep& src)
9411 {
9412   if ( this != &src )
9413   {
9414     Destroy();
9415     ON_Geometry::operator=(src);
9416 
9417     m_V.SetCapacity(src.m_V.Count());
9418     m_E.SetCapacity(src.m_E.Count());
9419     m_F.SetCapacity(src.m_F.Count());
9420     m_T.SetCapacity(src.m_T.Count());
9421     m_L.SetCapacity(src.m_L.Count());
9422 
9423     m_V.SetCount(src.m_V.Count());
9424     m_E.SetCount(src.m_E.Count());
9425     m_F.SetCount(src.m_F.Count());
9426     m_T.SetCount(src.m_T.Count());
9427     m_L.SetCount(src.m_L.Count());
9428 
9429     src.m_C2.Duplicate( m_C2 );
9430     src.m_C3.Duplicate( m_C3 );
9431     src.m_S.Duplicate( m_S );
9432 
9433     int i, count = m_V.Count();
9434     for ( i = 0; i < count; i++ )
9435     {
9436       m_V[i] = src.m_V[i];
9437     }
9438 
9439     count = m_E.Count();
9440     for ( i = 0; i < count; i++ )
9441     {
9442       m_E[i] = src.m_E[i];
9443       ON_BrepEdge& e = m_E[i];
9444       e.m_brep = this;
9445 
9446       // update curve proxy info to point at 3d curve in this brep
9447       e.SetProxyCurve( ( e.m_c3i >= 0 ) ? m_C3[e.m_c3i] : 0,
9448                        src.m_E[i].ProxyCurveDomain()
9449                        );
9450       if ( src.m_E[i].ProxyCurveIsReversed() )
9451         e.ON_CurveProxy::Reverse();
9452       e.SetDomain( src.m_E[i].Domain() );
9453     }
9454 
9455     count = m_L.Count();
9456     for ( i = 0; i < count; i++ )
9457     {
9458       m_L[i].m_brep = this;
9459     }
9460 
9461     count = m_F.Count();
9462     for ( i = 0; i < count; i++ )
9463     {
9464       m_F[i] = src.m_F[i];
9465       ON_BrepFace& f = m_F[i];
9466       f.m_brep = this;
9467       // update surface proxy info to point at 3d surface in this brep
9468       f.SetProxySurface(( f.m_si >= 0 ) ? m_S[f.m_si] : 0);
9469       f.m_bbox = src.m_F[i].m_bbox; // because SetProxySurface destroys it
9470     }
9471 
9472     count = m_T.Count();
9473     for ( i = 0; i < count; i++ )
9474     {
9475       m_T[i] = src.m_T[i];
9476       ON_BrepTrim& trim = m_T[i];
9477       trim.m_brep = this;
9478 
9479       // update curve proxy info to point at 2d curve in this brep
9480       trim.SetProxyCurve( ( trim.m_c2i >= 0 ) ? m_C2[trim.m_c2i] : 0,
9481                           src.m_T[i].ProxyCurveDomain()
9482                          );
9483       if ( src.m_T[i].ProxyCurveIsReversed() )
9484         trim.ON_CurveProxy::Reverse();
9485       trim.SetDomain( src.m_T[i].Domain() );
9486     }
9487 
9488     count = m_L.Count();
9489     for ( i = 0; i < count; i++ )
9490     {
9491       m_L[i] = src.m_L[i];
9492     }
9493 
9494     m_bbox = src.m_bbox;
9495     m_is_solid = src.m_is_solid;
9496   }
9497   return *this;
9498 }
9499 
Destroy()9500 void ON_Brep::Destroy()
9501 {
9502   m_V.Empty();
9503   m_E.Empty();
9504   m_F.Empty();
9505   m_T.Empty();
9506   m_L.Empty();
9507 
9508   int i, count = m_C2.Count();
9509   for ( i = 0; i < count; i++ ) {
9510     delete m_C2[i];
9511     m_C2[i] = 0;
9512   }
9513   m_C2.Empty();
9514   m_C2.Zero();
9515 
9516   count = m_C3.Count();
9517   for ( i = 0; i < count; i++ ) {
9518     delete m_C3[i];
9519     m_C3[i] = 0;
9520   }
9521   m_C3.Empty();
9522   m_C3.Zero();
9523 
9524   count = m_S.Count();
9525   for ( i = 0; i < count; i++ ) {
9526     delete m_S[i];
9527     m_S[i] = 0;
9528   }
9529   m_S.Empty();
9530   m_S.Zero();
9531 
9532   m_bbox.Destroy();
9533   m_is_solid = 0;
9534   // returns Brep to state it has after default construction
9535 }
9536 
EmergencyDestroy()9537 void ON_Brep::EmergencyDestroy()
9538 {
9539   // call if memory pool used by b-rep members becomes invalid
9540   // but ON_Brep class memory is in a valid pool
9541   m_V.EmergencyDestroy();
9542   m_E.EmergencyDestroy();
9543   m_F.EmergencyDestroy();
9544   m_T.EmergencyDestroy();
9545   m_L.EmergencyDestroy();
9546   m_C2.EmergencyDestroy();
9547   m_C3.EmergencyDestroy();
9548   m_S.EmergencyDestroy();
9549   m_bbox.Destroy();
9550   m_is_solid = 0;
9551 }
9552 
CombineCoincidentVertices(ON_BrepVertex & vertex0,ON_BrepVertex & vertex1)9553 bool ON_Brep::CombineCoincidentVertices(ON_BrepVertex& vertex0, ON_BrepVertex& vertex1)
9554 {
9555 
9556   bool rc = false;
9557   if (&vertex0 == &vertex1) {
9558     ON_ERROR("ON_Brep::CombineCoincidentVertices - vertex0 = vertex1.");
9559     return rc;
9560   }
9561   // moves information to vertex0 and deletes vertex1
9562   int runaway, vei, vecnt, ei, eti, etcnt, ti, prev_ti, next_ti;
9563 
9564   if ( vertex0.m_vertex_index >= 0 && vertex1.m_vertex_index != vertex0.m_vertex_index ) {
9565     rc = true;
9566     // update edges and trim references from vertex0 to vertex1
9567     vecnt = vertex1.m_ei.Count();
9568     for ( vei = 0; vei < vecnt; vei++ ) {
9569       ei = vertex1.m_ei[vei];
9570       if ( ei >= 0 ) {
9571         // update edge vertex indices
9572         ON_BrepEdge& edge = m_E[ei];
9573         if ( edge.m_vi[0] == vertex1.m_vertex_index )
9574           edge.m_vi[0] = vertex0.m_vertex_index;
9575         if ( edge.m_vi[1] == vertex1.m_vertex_index )
9576           edge.m_vi[1] = vertex0.m_vertex_index;
9577 
9578         // update trim vertex indices
9579         etcnt = edge.m_ti.Count();
9580         for (eti = 0; eti < etcnt; eti++ ) {
9581           ti = edge.m_ti[eti];
9582           if (ti >= 0 ) {
9583             ON_BrepTrim& trim = m_T[ti];
9584             if ( trim.m_vi[0] == vertex1.m_vertex_index ) {
9585               trim.m_vi[0] = vertex0.m_vertex_index;
9586               // check for previous singular trims using vertex0
9587               for (prev_ti = PrevTrim(ti), runaway=0;prev_ti >= 0 && prev_ti != ti && runaway < 1024;prev_ti=PrevTrim(prev_ti),runaway++) {
9588                 ON_BrepTrim& prevtrim = m_T[prev_ti];
9589                 if ( prevtrim.m_ei >= 0 )
9590                   break;
9591                 if ( prevtrim.m_vi[0] == vertex1.m_vertex_index )
9592                   prevtrim.m_vi[0] = vertex0.m_vertex_index;
9593                 if ( prevtrim.m_vi[1] == vertex1.m_vertex_index )
9594                   prevtrim.m_vi[1] = vertex0.m_vertex_index;
9595               }
9596             }
9597             if ( trim.m_vi[1] == vertex1.m_vertex_index ) {
9598               trim.m_vi[1] = vertex0.m_vertex_index;
9599                // check for previous singular trims using vertex0
9600               for (next_ti = NextTrim(ti), runaway=0;next_ti >= 0 && next_ti != ti && runaway < 1024;next_ti=NextTrim(next_ti),runaway++) {
9601                 ON_BrepTrim& nexttrim = m_T[next_ti];
9602                 if ( nexttrim.m_ei >= 0 )
9603                   break;
9604                 if ( nexttrim.m_vi[0] == vertex1.m_vertex_index )
9605                   nexttrim.m_vi[0] = vertex0.m_vertex_index;
9606                 if ( nexttrim.m_vi[1] == vertex1.m_vertex_index )
9607                   nexttrim.m_vi[1] = vertex0.m_vertex_index;
9608               }
9609             }
9610           }
9611         }
9612         vertex0.m_ei.Append(ei);
9613       }
9614     }
9615   }
9616 
9617   // update vertex tolerances
9618   if ( vertex0.m_tolerance != ON_UNSET_VALUE)
9619     SetVertexTolerance(vertex0);
9620 
9621   vertex1.m_vertex_index = -1;
9622   vertex1.m_ei.Destroy();
9623   DeleteVertex(vertex1);
9624 
9625   return rc;
9626 }
9627 
9628 
CombineContiguousEdges(int ei0,int ei1,double angle_tolerance_radians)9629 ON_BrepEdge* ON_Brep::CombineContiguousEdges(
9630   int ei0,
9631   int ei1,
9632   double angle_tolerance_radians
9633   )
9634 {
9635   // Bug fixers:
9636   //
9637   // Lots of (fast)testing is done to ensure the brep is
9638   // 100% valid at the merge vertex.  Do not change the
9639   // return 0 bail outs unless you are 100% sure of what
9640   // you are doing.
9641 
9642   // get edges to be merged
9643   const ON_BrepEdge* edge0 = Edge(ei0);
9644   const ON_BrepEdge* edge1 = Edge(ei1);
9645   if ( !edge0 || !edge1 )
9646     return 0;
9647 
9648   // clear any component index bits
9649   ei0 = edge0->m_edge_index;
9650   ei1 = edge1->m_edge_index;
9651   if ( ei0 < 0 || ei1 < 0 || ei0 == ei1 )
9652     return 0;
9653 
9654   // make sure edges have same number of trims
9655   if ( edge0->m_ti.Count() != edge1->m_ti.Count() )
9656     return 0;
9657 
9658   // figure out which edge ends to merge
9659 	// GBA 1/6/03 Fixed TRR#8951.
9660 	// Check that the vertex to be eliminated has exactly 2 incident edges.
9661   int end0 = 1, end1 = 0;
9662 	bool MatchFound = false;
9663 	for(end0=1; !MatchFound && end0>=0; /* empty */){
9664 		int vi = edge0->m_vi[end0];
9665 		const ON_BrepVertex* v =  Vertex(vi);
9666 		if(v && v->m_ei.Count()==2 ){
9667 			for(end1=0; !MatchFound && end1<2; /*empty*/){
9668 				MatchFound = (vi == edge1->m_vi[end1]);
9669 				if(!MatchFound)
9670 					end1++;
9671 			}
9672 		}
9673 		if(!MatchFound)
9674 			end0--;
9675 	}
9676 	if(!MatchFound)
9677 		return 0;
9678 
9679   // vi_mid = index of vertex to be eliminated
9680   const int vi_mid = edge0->m_vi[end0];
9681   {
9682     const ON_BrepVertex* v = Vertex(vi_mid);
9683     if ( !v )
9684       return 0;
9685     if ( v->m_ei.Count() != 2 )
9686       return 0;
9687     if ( v->m_ei[0] != ei0 && v->m_ei[1] != ei0 )
9688       return 0;
9689     if ( v->m_ei[0] != ei1 && v->m_ei[1] != ei1 )
9690       return 0;
9691   }
9692 
9693   // evi0 = vertex index and other end of edge0
9694   const int evi0 = edge0->m_vi[1-end0];
9695 
9696   // evi = vertex index and other end of edge1
9697   const int evi1 = edge1->m_vi[1-end1];
9698   if ( evi0 == vi_mid )
9699     return 0;
9700   if ( evi1 == vi_mid )
9701     return 0;
9702 
9703   // new edge will start at vi0 and end at vi1
9704   const int vi0 = (end0==1) ? evi0 : evi1;
9705   const int vi1 = (end0==1) ? evi1 : evi0;
9706 
9707   // make sure the 3d kink angle at the merge point is <= angle_tolerance
9708   {
9709     ON_3dVector tan0 = edge0->TangentAt( edge0->Domain()[end0] );
9710     if ( end0 == 0 )
9711       tan0.Reverse();
9712     ON_3dVector tan1 = edge1->TangentAt( edge1->Domain()[end1] );
9713     if ( end1 == 1 )
9714       tan1.Reverse();
9715     double d = tan0*tan1;
9716     if ( d < cos(angle_tolerance_radians) )
9717       return 0;
9718   }
9719 
9720   // get corresponding pairs of trims to merge
9721   int trim_count = edge0->m_ti.Count();
9722   ON_SimpleArray<int> trim0_index(trim_count);
9723   ON_SimpleArray<int> trim1_index(trim_count);
9724   ON_SimpleArray<int> loop_lti0(trim_count);
9725   ON_SimpleArray<int> loop_lti1(trim_count);
9726 
9727   int eti;
9728   for ( eti = 0; eti < trim_count; eti++ )
9729   {
9730     const ON_BrepTrim* trim0 = Trim( edge0->m_ti[eti] );
9731     if ( !trim0 )
9732       return 0;
9733     int ti0 = trim0->m_trim_index;
9734     const ON_BrepLoop* loop = trim0->Loop();
9735     if ( !loop )
9736       return 0;
9737     if ( loop->m_ti.Count() < 2 )
9738       return 0;
9739 
9740     // get index of next/prev trim that corresponds to edge1
9741     bool bRev = (end0==0);
9742     if ( trim0->m_bRev3d )
9743       bRev = !bRev;
9744     int lti1 = -1;
9745     int lti0 = loop->m_ti.Search( &ti0, ON_CompareIncreasing<int> );
9746     if ( lti0 < 0 )
9747       return 0;
9748     if ( bRev )
9749       lti1 = lti0 - 1 + loop->m_ti.Count();
9750     else
9751       lti1 = lti0 +1;
9752     lti1 %= loop->m_ti.Count();
9753     const ON_BrepTrim* trim1 = loop->Trim(lti1);
9754     if ( !trim1 )
9755       return 0;
9756     if ( trim1->m_ei != ei1 )
9757       return 0;
9758     if ( trim0->m_trim_index == trim1->m_trim_index )
9759       return 0;
9760 
9761     // test for valid trim vertices and orientations
9762     int tend0 = trim0->m_bRev3d ? (1-end0) : end0;
9763     int tend1 = trim1->m_bRev3d ? (1-end1) : end1;
9764     if ( tend0 == tend1 )
9765       return 0;
9766     if ( trim0->m_vi[tend0] != vi_mid )
9767       return 0;
9768     if ( trim1->m_vi[tend1] != vi_mid )
9769       return 0;
9770     if ( trim0->m_vi[1-tend0] != evi0 )
9771       return 0;
9772     if ( trim1->m_vi[1-tend1] != evi1 )
9773       return 0;
9774     trim0_index.Append(trim0->m_trim_index);
9775     trim1_index.Append(trim1->m_trim_index);
9776     loop_lti0.Append(lti0);
9777     loop_lti1.Append(lti1);
9778   }
9779 
9780   // create new 3d edge curve geometry
9781   // new edge goes same direction as edge0
9782   ON_PolyCurve* ec = 0;
9783   {
9784     ON_Curve* ec0 = edge0->DuplicateCurve();
9785     if ( !ec0 )
9786       return 0;
9787     ON_Curve* ec1 = edge1->DuplicateCurve();
9788     if ( !ec1 )
9789     {
9790       delete ec0;
9791       return 0;
9792     }
9793     if ( end0 == end1 )
9794     {
9795       if ( !ec1->Reverse() )
9796       {
9797         delete ec0;
9798         delete ec1;
9799         return 0;
9800       }
9801     }
9802     ec = new ON_PolyCurve();
9803     if ( end0 == 1 )
9804     {
9805       ec->Append(ec0);
9806       ec->AppendAndMatch(ec1);
9807     }
9808     else
9809     {
9810       ec->Append(ec1);
9811       ec->AppendAndMatch(ec0);
9812     }
9813     ec->RemoveNesting();
9814   }
9815 
9816   // create new 2d trim curve geometry
9817   ON_SimpleArray<ON_Curve*> tc(trim_count);
9818   for ( eti = 0; eti < trim_count; eti++ )
9819   {
9820     const ON_BrepTrim* trim0 = Trim(trim0_index[eti]);
9821     if ( !trim0 )
9822       break;
9823     const ON_BrepTrim* trim1 = Trim(trim1_index[eti]);
9824     if ( !trim1 )
9825       break;
9826     ON_NurbsCurve* c0 = trim0->NurbsCurve();
9827     if ( !c0 )
9828       break;
9829     ON_NurbsCurve* c1 = trim1->NurbsCurve();
9830     if ( !c1 )
9831     {
9832       delete c0;
9833       break;
9834     }
9835     if ( trim0->m_vi[1] == vi_mid && trim1->m_vi[0] == vi_mid )
9836     {
9837       if ( !c0->Append(*c1) )
9838       {
9839         delete c0;
9840         delete c1;
9841         break;
9842       }
9843       delete c1;
9844       c1 = 0;
9845       tc.Append(c0);
9846     }
9847     else if ( trim0->m_vi[0] == vi_mid && trim1->m_vi[1] == vi_mid )
9848     {
9849       if ( !c1->Append(*c0) )
9850       {
9851         delete c0;
9852         delete c1;
9853         break;
9854       }
9855       delete c0;
9856       c0 = c1;
9857       c1 = 0;
9858       tc.Append(c0);
9859     }
9860   }
9861 
9862   if ( eti < trim_count )
9863   {
9864     delete ec;
9865     for ( eti = 0; eti < tc.Count(); eti++ )
9866       delete tc[eti];
9867     return 0;
9868   }
9869 
9870   // Add new edge from vi0 to vi1 that has the same orientation
9871   // as edge0.  Adding the new edge may change pointer values,
9872   // so the edge0 and edge1 pointers are reset.
9873   edge0 = 0;
9874   edge1 = 0;
9875   const int c3i = AddEdgeCurve(ec);
9876   ON_BrepEdge& edge = NewEdge( m_V[vi0], m_V[vi1], c3i );
9877   edge0 = Edge(ei0);
9878   edge1 = Edge(ei1);
9879 
9880 	// Set edge tolerance
9881 	if(edge0->m_tolerance<0 || edge1->m_tolerance<0)
9882 		edge.m_tolerance= ON_UNSET_VALUE;
9883 	else if ( edge0->m_tolerance> edge1->m_tolerance)
9884 		edge.m_tolerance= edge0->m_tolerance;
9885 	else
9886 		edge.m_tolerance= edge1->m_tolerance;
9887 
9888 
9889   // dynamic m_T[] is grown to full size here.
9890   // Trim refs are good after NewTrim()
9891   m_T.Reserve( m_T.Count() + trim_count );
9892   for ( eti = 0; eti < trim_count; eti++ )
9893   {
9894     int c2i = AddTrimCurve( tc[eti] );
9895     ON_BrepTrim& trim0 = m_T[trim0_index[eti]];
9896     ON_BrepTrim& trim1 = m_T[trim1_index[eti]];
9897     ON_BrepTrim& trim = NewTrim( edge, trim0.m_bRev3d, c2i );
9898 		// Set trim tolerance
9899 		for(int i=0; i<2; i++){
9900 			if( trim0.m_tolerance[i]<0 || trim1.m_tolerance[i]<0)
9901 				trim.m_tolerance[i] = ON_UNSET_VALUE;
9902 			else if(trim0.m_tolerance[i]>trim1.m_tolerance[i])
9903 				trim.m_tolerance[i] = trim0.m_tolerance[i];
9904 			else
9905 				trim.m_tolerance[i] = trim1.m_tolerance[i];
9906 		}
9907     trim.m_li = trim0.m_li;
9908     ON_BrepLoop& loop = m_L[trim.m_li];
9909     loop.m_ti[loop_lti0[eti]] = trim.m_trim_index;
9910     loop.m_ti.Remove( loop_lti1[eti] );
9911 
9912 		//GBA 1/29/03 Fixes TRR#9233.  Removing an item from loop.m_ti
9913 		//will cause loop indicies stored in loop_lti0[] and loop_lti1[]
9914 		//to be wrong. So they must be reindexed
9915 		int ri = loop_lti1[eti];			// removed index
9916     int li = loop.m_loop_index;
9917 		for(int ii=0; ii<trim_count; ii++){
9918       if(loop_lti0[ii]>ri && m_T[trim0_index[ii]].m_li == li)
9919         loop_lti0[ii]--;
9920 			if(loop_lti1[ii]>ri && m_T[trim1_index[ii]].m_li == li)
9921         loop_lti1[ii]--;
9922 		}
9923 
9924 
9925 		trim.m_type = trim0.m_type;
9926 		trim.m_iso = ON_Surface::not_iso;
9927 		if( trim0.m_iso==trim1.m_iso)
9928 			trim.m_iso = trim0.m_iso;
9929     trim0.m_li = -1;
9930     trim1.m_li = -1;
9931   }
9932 
9933   // delete old edges
9934   DeleteEdge(m_E[ei0],true);
9935   DeleteEdge(m_E[ei1],true);
9936 
9937   return &m_E[edge.m_edge_index];
9938 }
9939 
CombineCoincidentEdges(ON_BrepEdge & edge0,ON_BrepEdge & edge1)9940 bool ON_Brep::CombineCoincidentEdges(ON_BrepEdge& edge0, ON_BrepEdge& edge1)
9941 {
9942   bool rc = false;
9943   if ( edge0.m_edge_index == edge1.m_edge_index )
9944   {
9945     ON_ERROR("ON_Brep::CombineCoincidentEdges - edge0 = edge1.");
9946     return rc;
9947   }
9948   int ti, eti, etcnt;
9949   if (    edge0.m_edge_index >= 0
9950        && edge1.m_edge_index >= 0
9951        && edge0.m_edge_index != edge1.m_edge_index
9952        && edge0.m_vi[0] == edge1.m_vi[0]
9953        && edge0.m_vi[1] == edge1.m_vi[1] )
9954   {
9955     bool bIsGoodIso0 = false;
9956     if (edge0.m_tolerance == 0.0){
9957       for (eti=0; eti<edge0.m_ti.Count(); eti++){
9958         const ON_BrepTrim& T = m_T[edge0.m_ti[eti]];
9959         if (T.m_iso)
9960         {
9961           bIsGoodIso0 = true;
9962           break;
9963         }
9964       }
9965     }
9966     bool bIsGoodIso1 = false;
9967     if (edge1.m_tolerance == 0.0){
9968       for (eti=0; eti<edge1.m_ti.Count(); eti++){
9969         const ON_BrepTrim& T = m_T[edge1.m_ti[eti]];
9970         if (T.m_iso)
9971         {
9972           bIsGoodIso1 = true;
9973           break;
9974         }
9975       }
9976     }
9977     bool bKeep0 = (edge0.m_tolerance <= edge1.m_tolerance) ? true : false;
9978     if (edge0.m_tolerance == edge1.m_tolerance && edge0.m_tolerance == 0.0){
9979       if (bIsGoodIso1){
9980         if (!bIsGoodIso0)
9981           bKeep0 = false;
9982         else {//both are good.  Take the one with the lowest degree.
9983           if (edge1.Degree() < edge0.Degree())
9984             bKeep0 = false;
9985           else if (edge1.Degree() == edge0.Degree() && edge1.SpanCount() < edge0.SpanCount())
9986             bKeep0 = false;
9987         }
9988       }
9989     }
9990 
9991     ON_BrepEdge& EKeep = (bKeep0) ? edge0 : edge1;
9992     ON_BrepEdge& EToss = (bKeep0) ? edge1 : edge0;
9993 
9994     /*
9995     rc = true;
9996     etcnt = edge1.m_ti.Count();
9997     int tcount = m_T.Count();
9998     for ( eti = 0; eti < etcnt; eti++ ) {
9999       ti = edge1.m_ti[eti];
10000       if ( ti >= 0 && ti < tcount ) {
10001         ON_BrepTrim& trim = m_T[ti];
10002         trim.m_ei = edge0.m_edge_index;
10003         edge0.m_ti.Append(ti);
10004         // TODO - tolerances ?
10005 
10006         //set edge tolerance
10007         if (edge0.m_tolerance != ON_UNSET_VALUE && edge1.m_tolerance != ON_UNSET_VALUE)
10008           SetEdgeTolerance(edge0, false);
10009         else edge0.m_tolerance = ON_UNSET_VALUE;
10010       }
10011     }
10012     edge1.m_ti.Destroy();
10013     DeleteEdge( edge1, false );
10014 
10015     etcnt =  edge0.m_ti.Count();
10016     if ( etcnt >= 2 ) for ( eti = 0; eti < etcnt; eti++ )
10017     {
10018       ti = edge0.m_ti[eti];
10019       if ( ti >= 0 && ti < tcount )
10020       {
10021         ON_BrepTrim& trim = m_T[ti];
10022         if ( trim.m_type == ON_BrepTrim::boundary )
10023           trim.m_type = ON_BrepTrim::mated;
10024       }
10025     }
10026     */
10027     rc = true;
10028     etcnt = EToss.m_ti.Count();
10029     int tcount = m_T.Count();
10030     for ( eti = 0; eti < etcnt; eti++ ) {
10031       ti = EToss.m_ti[eti];
10032       if ( ti >= 0 && ti < tcount ) {
10033         ON_BrepTrim& trim = m_T[ti];
10034         trim.m_ei = EKeep.m_edge_index;
10035         EKeep.m_ti.Append(ti);
10036         trim.UnsetPlineEdgeParameters();
10037         // TODO - tolerances ?
10038 
10039         //set edge tolerance
10040         if (EKeep.m_tolerance != ON_UNSET_VALUE && EToss.m_tolerance != ON_UNSET_VALUE)
10041           SetEdgeTolerance(EKeep, false);
10042         else EKeep.m_tolerance = ON_UNSET_VALUE;
10043       }
10044     }
10045     EToss.m_ti.Destroy();
10046     DeleteEdge( EToss, false );
10047 
10048     etcnt =  EKeep.m_ti.Count();
10049     if ( etcnt >= 2 ) for ( eti = 0; eti < etcnt; eti++ )
10050     {
10051       ti = EKeep.m_ti[eti];
10052       if ( ti >= 0 && ti < tcount )
10053       {
10054         ON_BrepTrim& trim = m_T[ti];
10055         if ( trim.m_type == ON_BrepTrim::boundary )
10056           trim.m_type = ON_BrepTrim::mated;
10057       }
10058     }
10059   }
10060   return rc;
10061 }
10062 
Create(ON_Surface * & pS)10063 bool ON_Brep::Create( ON_Surface*& pS )
10064 {
10065   bool rc = false;
10066   Destroy();
10067   ON_Surface* p = pS;
10068   if (p)
10069   {
10070     int vid[4] = {-1,-1,-1,-1};
10071     int eid[4] = {-1,-1,-1,-1};
10072     ON_BOOL32 bRev3d[4] = {0,0,0,0};
10073     ON_BrepFace* face = NewFace(p,vid,eid,bRev3d);
10074     if ( face )
10075     {
10076       rc = true;
10077       pS = 0;
10078     }
10079   }
10080   return rc;
10081 }
10082 
10083 /*
10084 ON_BOOL32 ON_Brep::FaceTool( ON_Surface* pS )
10085 {
10086   // private face adding tool
10087   if (!pS)
10088     return false;
10089   double u[2], v[2];
10090   if (!pS->GetDomain(0, &u[0], &u[1]))
10091       return false;
10092   if (!pS->GetDomain(1, &v[0], &v[1]))
10093       return false;
10094 
10095   ON_3dPoint srf_P[2][2];
10096   if ( !pS->EvPoint(u[0],v[0],srf_P[0][0] )
10097     return false;
10098   if ( !pS->EvPoint(u[1],v[0],srf_P[1][0] )
10099     return false;
10100   if ( !pS->EvPoint(u[0],v[1],srf_P[0][1] )
10101     return false;
10102   if ( !pS->EvPoint(u[1],v[1],srf_P[1][1] )
10103     return false;
10104 
10105   int sw_vi, se_vi, ne_vi, nw_vi;
10106 
10107   m_F.Reserve( m_F.Count() + 1 );
10108   m_T.Reserve( m_T.Count() + 4 );
10109   m_L.Reserve( m_L.Count() + 1 );
10110   m_V.Reserve( m_V.Count() + 4 );
10111   m_E.Reserve( m_E.Count() + 4 );
10112   m_S.Reserve( m_S.Count() + 1 );
10113   m_C2.Reserve( m_C2.Count() + 1 );
10114   m_C3.Reserve( m_C3.Count() + 1 );
10115 
10116   sw_vi = NewVertex( srf_P[0][0], 0.0 ).m_vertex_index;
10117 
10118   ON_BOOL32 bIsClosed[2];
10119   bIsClosed[0] = pS->IsClosed(0);
10120   bIsClosed[1] = pS->IsClosed(1);
10121 
10122   ON_BOOL32 bIsSingular[4];
10123   bIsSingular[0] = pS->IsSingular(0);
10124   bIsSingular[1] = pS->IsSingular(1);
10125   bIsSingular[2] = pS->IsSingular(2);
10126   bIsSingular[3] = pS->IsSingular(3);
10127 
10128 
10129   if (bIsSingular[0] || bIsClosed[0])
10130     se_vi = sw_vi;
10131   else
10132     se_vi = NewVertex( srf_P[1][0], 0.0 ).m_vertex_index;
10133 
10134   if (bIsSingular[1] || bIsClosed[1])
10135     ne_vi = se_vi;
10136   else
10137     ne_vi = NewVertex( srf_P[1][1], 0.0 ).m_vertex_index;
10138 
10139   if (bIsSingular[2] || bIsClosed[0])
10140     nw_vi = ne_vi;
10141   else if (bIsSingular[3] || bIsClosed[1])
10142     nw_vi = sw_vi;
10143   else
10144     nw_vi = NewVertex( srf_P[0][1], 0.0 ).m_vertex_index;
10145 
10146   ON_BrepVertex& sw_vertex = m_V[sw_vi];
10147   ON_BrepVertex& se_vertex = m_V[se_vi];
10148   ON_BrepVertex& ne_vertex = m_V[ne_vi];
10149   ON_BrepVertex& nw_vertex = m_V[nw_vi];
10150 
10151   ON_BrepFace& face = NewFace(AddSurface(pS));
10152   ON_BrepLoop& loop = NewLoop(ON_BrepLoop::outer, face);
10153 
10154   loop.m_pbox.m_min.x = u[0];
10155   loop.m_pbox.m_min.y = v[0];
10156   loop.m_pbox.m_min.z = 0.0;
10157 
10158   loop.m_pbox.m_max.x = u[1];
10159   loop.m_pbox.m_max.y = v[1];
10160   loop.m_pbox.m_max.z = 0.0;
10161 
10162   int id3[4] = {-1,-1,-1,-1};
10163   int eid[4] = {-1,-1,-1,-1};
10164   int c2i;
10165 
10166   ON_2dPoint sw_corner(u[0],v[0]);
10167   ON_2dPoint se_corner(u[1],v[0]);
10168   ON_2dPoint ne_corner(u[1],v[1]);
10169   ON_2dPoint nw_corner(u[0],v[1]);
10170 
10171   {//south side
10172     c2i = AddTrimCurve(new ON_LineCurve(sw_corner,se_corner));
10173     if (bIsSingular[0]) {
10174       NewSingularTrim(sw_vertex,loop,ON_Surface::S_iso,c2i);
10175     }
10176     else {
10177       id3[0] = AddEdgeCurve( pS->IsoCurve(0, v[0]) );
10178       ON_BrepEdge& edge = NewEdge(sw_vertex, se_vertex, id3[0]);
10179       edge.m_tolerance = 0.0;
10180       eid[0] = edge.m_edge_index;
10181       ON_BrepTrim& trim = NewTrim(edge, false, loop, c2i);
10182       trim.m_iso = ON_Surface::S_iso;
10183       if (bIsClosed[1])
10184         trim.m_type = ON_BrepTrim::seam;
10185       else
10186         trim.m_type = ON_BrepTrim::boundary;
10187     }
10188   }
10189 
10190   { //east side
10191     c2i = AddTrimCurve(new ON_LineCurve(se_corner,ne_corner));
10192     if (bIsSingular[1]) {
10193       NewSingularTrim(se_vertex,loop,ON_Surface::E_iso,c2i);
10194     }
10195     else {
10196       id3[1] = AddEdgeCurve(pS->IsoCurve(1, u[1]));
10197       ON_BrepEdge& edge = NewEdge(se_vertex, ne_vertex, id3[1]);
10198       edge.m_tolerance = 0.0;
10199       eid[1] = edge.m_edge_index;
10200       ON_BrepTrim& trim = NewTrim(edge, false, loop, c2i);
10201       trim.m_iso = ON_Surface::E_iso;
10202       if (bIsClosed[0])
10203         trim.m_type = ON_BrepTrim::seam;
10204       else
10205         trim.m_type = ON_BrepTrim::boundary;
10206     }
10207   }
10208 
10209   { //north side
10210     c2i = AddTrimCurve(new ON_LineCurve(ne_corner,nw_corner));
10211     ON_BOOL32 rev = false;
10212     if (bIsSingular[2]) {
10213       NewSingularTrim(ne_vertex,loop,ON_Surface::N_iso,c2i);
10214     }
10215     else{
10216       if (bIsClosed[1]) {
10217         id3[2] = id3[0];
10218         eid[2] = eid[0];
10219         rev = true;
10220       }
10221       else {
10222         ON_Curve* pC3 = pS->IsoCurve(0, v[1]);
10223         if (pC3) pC3->Reverse();
10224         id3[2] = AddEdgeCurve(pC3);
10225         ON_BrepEdge& edge = NewEdge(ne_vertex, nw_vertex, id3[2]);
10226         edge.m_tolerance = 0.0;
10227         eid[2] = edge.m_edge_index;
10228       }
10229       ON_BrepTrim& trim = NewTrim(m_E[eid[2]], rev, loop, c2i);
10230       trim.m_iso = ON_Surface::N_iso;
10231       if (bIsClosed[1])
10232         trim.m_type = ON_BrepTrim::seam;
10233       else
10234         trim.m_type = ON_BrepTrim::boundary;
10235     }
10236   }
10237 
10238   { //west side
10239     c2i = AddTrimCurve(new ON_LineCurve(nw_corner,sw_corner));
10240     ON_BOOL32 rev = false;
10241     if (bIsSingular[3]){
10242       NewSingularTrim(nw_vertex,loop,ON_Surface::W_iso,c2i);
10243     }
10244     else {
10245       if (bIsClosed[0]){
10246       id3[3] = id3[1];
10247         eid[3] = eid[1];
10248         rev = true;
10249       }
10250       else {
10251         ON_Curve* pC3 = pS->IsoCurve(1, u[0]);
10252         if (pC3) pC3->Reverse();
10253         id3[3] = AddEdgeCurve(pC3);
10254         ON_BrepEdge& edge = NewEdge(nw_vertex, sw_vertex, id3[3]);
10255         edge.m_tolerance = 0.0;
10256         eid[3] = edge.m_edge_index;
10257       }
10258       ON_BrepTrim& trim = NewTrim( m_E[eid[3]], rev, loop, c2i );
10259       trim.m_iso = ON_Surface::W_iso;
10260       if (bIsClosed[0])
10261         trim.m_type = ON_BrepTrim::seam;
10262       else
10263         trim.m_type = ON_BrepTrim::boundary;
10264     }
10265   }
10266 
10267   for ( int lti = 0; lti < 4; lti++ )
10268   {
10269     ti = loop.m_ti[lti];
10270     ON_BrepTrim& trim = m_T[ti];
10271     trim.m_tolerance[0] = 0.0;
10272     trim.m_tolerance[1] = 0.0;
10273     trim.m__legacy_2d_tol = 0.0;
10274     trim.m__legacy_3d_tol = 0.0;
10275     trim.m__legacy_flags_Set(-1,1);
10276   }
10277 
10278   return true;
10279 }
10280 */
10281 
Create(ON_NurbsSurface * & pNurbsSurface)10282 bool ON_Brep::Create( ON_NurbsSurface*& pNurbsSurface )
10283 {
10284   ON_Surface* pSurface = pNurbsSurface;
10285   bool rc = Create(pSurface);
10286   if ( !pSurface )
10287     pNurbsSurface = 0;
10288   return rc;
10289 }
10290 
Create(ON_PlaneSurface * & pPlaneSurface)10291 bool ON_Brep::Create( ON_PlaneSurface*& pPlaneSurface )
10292 {
10293   ON_Surface* pSurface = pPlaneSurface;
10294   bool rc = Create(pSurface);
10295   if ( !pSurface )
10296     pPlaneSurface = 0;
10297   return rc;
10298 }
10299 
Create(ON_RevSurface * & pRevSurface)10300 bool ON_Brep::Create( ON_RevSurface*& pRevSurface )
10301 {
10302   ON_Surface* pSurface = pRevSurface;
10303   bool rc = Create(pSurface);
10304   if ( !pSurface )
10305     pRevSurface = 0;
10306   return rc;
10307 }
10308 
Create(ON_SumSurface * & pSumSurface)10309 bool ON_Brep::Create( ON_SumSurface*& pSumSurface )
10310 {
10311   ON_Surface* pSurface = pSumSurface;
10312   bool rc = Create(pSurface);
10313   if ( !pSurface )
10314     pSumSurface = 0;
10315   return rc;
10316 }
10317 
10318 
HasBrepForm() const10319 ON_BOOL32 ON_Brep::HasBrepForm() const
10320 {
10321   return true;
10322 }
10323 
BrepForm(ON_Brep * brep) const10324 ON_Brep* ON_Brep::BrepForm( ON_Brep* brep ) const
10325 {
10326   if ( brep )
10327   {
10328     if ( brep != this )
10329     {
10330       *brep = *this;
10331       brep->DestroyMesh(ON::any_mesh);
10332     }
10333   }
10334   else
10335   {
10336     brep = new ON_Brep(*this);
10337     brep->DestroyMesh(ON::any_mesh);
10338   }
10339   return brep;
10340 }
10341 
Clear_vertex_user_i()10342 void ON_Brep::Clear_vertex_user_i()
10343 {
10344   int vi;
10345   int vertex_count = m_V.Count();
10346   for ( vi = 0; vi < vertex_count; vi++ )
10347   {
10348     memset(&m_V[vi].m_vertex_user,0,sizeof(ON_U));
10349   }
10350 }
10351 
Clear_edge_user_i()10352 void ON_Brep::Clear_edge_user_i()
10353 {
10354   int ei;
10355   int edge_count = m_E.Count();
10356   for ( ei = 0; ei < edge_count; ei++ )
10357   {
10358     memset(&m_E[ei].m_edge_user,0,sizeof(ON_U));
10359   }
10360 }
10361 
Clear_edge_user_i(int i)10362 void ON_Brep::Clear_edge_user_i(int i)
10363 {
10364   int ei;
10365   int edge_count = m_E.Count();
10366   for ( ei = 0; ei < edge_count; ei++ )
10367   {
10368     memset(&m_E[ei].m_edge_user,0,sizeof(ON_U));
10369     m_E[ei].m_edge_user.i = i;
10370   }
10371 }
10372 
Clear_trim_user_i()10373 void ON_Brep::Clear_trim_user_i()
10374 {
10375   int ti;
10376   int trim_count = m_T.Count();
10377   for ( ti = 0; ti < trim_count; ti++ ) {
10378     memset(&m_T[ti].m_trim_user,0,sizeof(ON_U));
10379   }
10380 }
10381 
Clear_loop_user_i()10382 void ON_Brep::Clear_loop_user_i()
10383 {
10384   int li;
10385   int loop_count = m_L.Count();
10386   for ( li = 0; li < loop_count; li++ ) {
10387     memset(&m_L[li].m_loop_user,0,sizeof(ON_U));
10388   }
10389 }
10390 
Clear_face_user_i()10391 void ON_Brep::Clear_face_user_i()
10392 {
10393   int fi;
10394   int face_count = m_F.Count();
10395   for ( fi = 0; fi < face_count; fi++ ) {
10396     memset(&m_F[fi].m_face_user,0,sizeof(ON_U));
10397   }
10398 }
10399 
Clear_user_i()10400 void ON_Brep::Clear_user_i()
10401 {
10402   memset(&m_brep_user,0,sizeof(m_brep_user));
10403   Clear_vertex_user_i();
10404   Clear_edge_user_i();
10405   Clear_trim_user_i();
10406   Clear_loop_user_i();
10407   Clear_face_user_i();
10408 }
10409 
Set_user(ON_U u)10410 void ON_Brep::Set_user(ON_U u)
10411 {
10412   int i, count;
10413   m_brep_user=u;
10414 
10415   count = m_V.Count();
10416   ON_BrepVertex* V = m_V.Array();
10417   for ( i = 0; i < count; i++ )
10418   {
10419     V[i].m_vertex_user = u;
10420   }
10421 
10422   count = m_E.Count();
10423   ON_BrepEdge* E = m_E.Array();
10424   for ( i = 0; i < count; i++ )
10425   {
10426     E[i].m_edge_user = u;
10427   }
10428 
10429 
10430   count = m_T.Count();
10431   ON_BrepTrim* T = m_T.Array();
10432   for ( i = 0; i < count; i++ )
10433   {
10434     T[i].m_trim_user = u;
10435   }
10436 
10437   count = m_L.Count();
10438   ON_BrepLoop* L = m_L.Array();
10439   for ( i = 0; i < count; i++ )
10440   {
10441     L[i].m_loop_user = u;
10442   }
10443 
10444   count = m_F.Count();
10445   ON_BrepFace* F = m_F.Array();
10446   for ( i = 0; i < count; i++ )
10447   {
10448     F[i].m_face_user = u;
10449   }
10450 }
10451 
10452 
10453 
NewPointOnFace(ON_BrepFace & face,double s,double t)10454 ON_BrepVertex& ON_Brep::NewPointOnFace(
10455   ON_BrepFace& face,
10456   double s,
10457   double t
10458   )
10459 {
10460   ON_3dPoint point = face.PointAt(s,t);
10461 
10462   ON_BrepVertex& vertex = NewVertex( point );
10463   ON_BrepLoop& loop = NewLoop( ON_BrepLoop::ptonsrf, face );
10464   ON_BrepTrim& trim = NewTrim(false,loop,-1);
10465 
10466   vertex.m_tolerance = 0.0;
10467   trim.m_type = ON_BrepTrim::ptonsrf;
10468   trim.m_pbox.m_min.Set(s,t,0.0);
10469   trim.m_pbox.m_max.Set(s,t,0.0);
10470   trim.m_tolerance[0] = 0.0;
10471   trim.m_tolerance[1] = 0.0;
10472   loop.m_pbox = trim.m_pbox;
10473   trim.m_vi[0] = trim.m_vi[1] = vertex.m_vertex_index;
10474 
10475   return vertex;
10476 }
10477 
10478 
NewCurveOnFace(ON_BrepFace & face,ON_BrepEdge & edge,ON_BOOL32 bRev3d,int c2i)10479 ON_BrepTrim& ON_Brep::NewCurveOnFace( ON_BrepFace& face, ON_BrepEdge& edge, ON_BOOL32 bRev3d, int c2i )
10480 {
10481   ON_BrepLoop& loop = NewLoop( ON_BrepLoop::crvonsrf, face );
10482   ON_BrepTrim& trim = NewTrim( edge, bRev3d, loop, c2i );
10483   trim.m_type = ON_BrepTrim::crvonsrf;
10484   const ON_Curve* trimcurve = trim.TrimCurveOf();
10485   if (trimcurve)
10486   {
10487     trimcurve->GetBoundingBox( trim.m_pbox );
10488     loop.m_pbox = trim.m_pbox;
10489   }
10490   return trim;
10491 }
10492 
10493 //For each i, let ti be the parameter along the chord (Points[0], Points[last])
10494 //of the closest point to Points[i], and let di be the distance to the chord.
10495 //Transform Points so that Points[0] = P0, Points[last] = P1,
10496 //and the new ti and di remain the same.  Don't do anything if the chord is short
10497 //relative to the cummulative dist between consecutive points on input.
10498 
AdjustPointListAlongChord(ON_3dPointArray & Points,const ON_3dPoint & P0,const ON_3dPoint & P1)10499 static bool AdjustPointListAlongChord(ON_3dPointArray& Points,
10500                                       const ON_3dPoint& P0,
10501                                       const ON_3dPoint& P1)
10502 
10503 {
10504   int count = Points.Count();
10505   if (count < 2)
10506     return false;
10507 
10508   ON_3dPoint A0 = Points[0];
10509   ON_3dPoint A1 = Points[count-1];
10510   double chord_dist = A0.DistanceTo(A1);
10511   if (chord_dist < ON_SQRT_EPSILON)
10512     return false;
10513   double cum_dist = 0.0;
10514   int i;
10515   for (i=1; i<count; i++)
10516     cum_dist += Points[i-1].DistanceTo(Points[i]);
10517   if (chord_dist < 0.01*cum_dist)
10518     return false;
10519   ON_3dVector V0 = P0-A0;
10520   ON_3dVector V1 = P1-A1;
10521   ON_Line Aline(A0, A1);
10522   Points[0] = P0;
10523   Points[count-1] = P1;
10524   for (i=1; i<count-1; i++){
10525     double t;
10526     Aline.ClosestPointTo(Points[i], &t);
10527     Points[i] = Points[i] + (1.0-t)*V0 + t*V1;
10528   }
10529   return true;
10530 }
10531 
AdjustNurbsCurve(ON_NurbsCurve & crv,const ON_3dPoint & P0,const ON_3dPoint & P1)10532 static void AdjustNurbsCurve(ON_NurbsCurve& crv,
10533                              const ON_3dPoint& P0,
10534                              const ON_3dPoint& P1)
10535 
10536 {
10537   if (crv.Dimension() > 3)
10538     return;
10539 
10540   crv.ClampEnd(2);
10541   int cvc = crv.CVCount();
10542   ON_3dPointArray Points(cvc);
10543   int i;
10544   for (i=0; i<cvc; i++)
10545     crv.GetCV(i, Points.AppendNew());
10546 
10547   if (!AdjustPointListAlongChord(Points, P0, P1)){
10548     crv.SetStartPoint(P0);
10549     crv.SetEndPoint(P1);
10550     return;
10551   }
10552 
10553   bool rat = crv.IsRational();
10554   for (i=0; i<cvc; i++){
10555     double w = 1.0;
10556     if (rat){
10557       w = crv.Weight(i);
10558       Points[i] *= w;
10559     }
10560     crv.SetCV(i, Points[i]);
10561     if (rat)
10562       crv.SetWeight(i, w);
10563   }
10564 
10565   return;
10566 }
10567 
AdjustPolylineCurve(ON_PolylineCurve & crv,const ON_3dPoint & P0,const ON_3dPoint & P1)10568 static void AdjustPolylineCurve(ON_PolylineCurve& crv,
10569                              const ON_3dPoint& P0,
10570                              const ON_3dPoint& P1)
10571 
10572 {
10573   AdjustPointListAlongChord(crv.m_pline, P0, P1);
10574   crv.SetStartPoint(P0);
10575   crv.SetEndPoint(P1);
10576   return;
10577 }
10578 
10579 static void AdjustCurve(ON_Curve& crv,
10580                         const ON_3dPoint& P0,
10581                         const ON_3dPoint& P1);
10582 
AdjustPolyCurve(ON_PolyCurve & crv,const ON_3dPoint & P0,const ON_3dPoint & P1)10583 static void AdjustPolyCurve(ON_PolyCurve& crv,
10584                              const ON_3dPoint& P0,
10585                              const ON_3dPoint& P1)
10586 
10587 {
10588 
10589   if (crv.Count() == 1){
10590     ON_Curve* pSeg = crv.SegmentCurve(0);
10591     if (!pSeg)
10592       return;
10593     AdjustCurve(*pSeg, P0, P1);
10594     return;
10595   }
10596 
10597   ON_3dPointArray Points(crv.Count() + 1);
10598   Points.Append(crv.PointAtStart());
10599 
10600   int i;
10601   for (i=0; i<crv.Count(); i++)
10602     Points.Append(crv.SegmentCurve(i)->PointAtEnd());
10603 
10604   if (!AdjustPointListAlongChord(Points, P0, P1)){
10605     crv.SetStartPoint(P0);
10606     crv.SetEndPoint(P1);
10607     return;
10608   }
10609 
10610   for (i=0; i<crv.Count(); i++){
10611     ON_Curve* pSeg = crv.SegmentCurve(i);
10612     if (!pSeg)
10613       return;
10614     AdjustCurve(*pSeg, Points[i], Points[i+1]);
10615     Points[i+1] = pSeg->PointAtEnd();
10616   }
10617 
10618   return;
10619 }
10620 
10621 //Afterwards it is up to caller to check to see if the endpoints are where they should be.
AdjustCurve(ON_Curve & crv,const ON_3dPoint & P0,const ON_3dPoint & P1)10622 static void AdjustCurve(ON_Curve& crv,
10623                         const ON_3dPoint& P0,
10624                         const ON_3dPoint& P1)
10625 
10626 {
10627   ON_LineCurve* lc = ON_LineCurve::Cast(&crv);
10628   if (lc){
10629     lc->SetStartPoint(P0);
10630     lc->SetEndPoint(P1);
10631     return;
10632   }
10633 
10634   ON_CurveProxy* pc = ON_CurveProxy::Cast(&crv);
10635   if (pc)
10636     return;
10637 
10638   if (crv.IsClosed()){
10639     if (P0 != P1)
10640       return;
10641     ON_3dPoint P = crv.PointAtStart();
10642     ON_3dVector TVec = P0-P;
10643     if (TVec.Length() > ON_SQRT_EPSILON){
10644       ON_Xform T;
10645       T.Translation(TVec);
10646       crv.Transform(T);
10647     }
10648     return;
10649   }
10650 
10651   ON_PolylineCurve* plc = ON_PolylineCurve::Cast(&crv);
10652   if (plc) {
10653     AdjustPolylineCurve(*plc, P0, P1);
10654     return;
10655   }
10656 
10657   ON_NurbsCurve* nc = ON_NurbsCurve::Cast(&crv);
10658   if (nc){
10659     AdjustNurbsCurve(*nc, P0, P1);
10660     return;
10661   }
10662 
10663   ON_PolyCurve* plyc = ON_PolyCurve::Cast(&crv);
10664   if (plyc){
10665     AdjustPolyCurve(*plyc, P0, P1);
10666     return;
10667   }
10668 
10669   ON_3dPoint A0 = crv.PointAtStart();
10670   ON_3dPoint A1 = crv.PointAtEnd();
10671 
10672   if (A0.DistanceTo(P0) < ON_SQRT_EPSILON && A1.DistanceTo(P1) < ON_SQRT_EPSILON){
10673     crv.SetStartPoint(P0);
10674     crv.SetEndPoint(P1);
10675     return;
10676   }
10677 
10678   double alen = A0.DistanceTo(A1);
10679   double plen = P0.DistanceTo(P1);
10680   if (alen < 0.1*plen || plen < 0.1*alen){
10681     crv.SetStartPoint(P0);
10682     crv.SetEndPoint(P1);
10683     return;
10684   }
10685 
10686   ON_3dPoint Ac = 0.5*(A0+A1);
10687   ON_3dPoint Pc = 0.5*(P0+P1);
10688   ON_3dVector TVec = Pc-Ac;
10689   if (TVec.Length() > ON_SQRT_EPSILON){
10690     ON_Xform T;
10691     T.Translation(TVec);
10692     crv.Transform(T);
10693   }
10694 
10695   A0 = crv.PointAtStart();
10696   A1 = crv.PointAtEnd();
10697   if (A0.DistanceTo(P0) < ON_SQRT_EPSILON && A1.DistanceTo(P1) < ON_SQRT_EPSILON){
10698     crv.SetStartPoint(P0);
10699     crv.SetEndPoint(P1);
10700     return;
10701   }
10702 
10703   if (fabs(plen - alen) > ON_SQRT_EPSILON){
10704     double scale = plen/alen;
10705     Ac = 0.5*(A0+A1);
10706     ON_Xform T;
10707     T.Scale(Ac, scale);
10708     crv.Transform(T);
10709   }
10710 
10711   A0 = crv.PointAtStart();
10712   A1 = crv.PointAtEnd();
10713   if (A0.DistanceTo(P0) < ON_SQRT_EPSILON && A1.DistanceTo(P1) < ON_SQRT_EPSILON){
10714     crv.SetStartPoint(P0);
10715     crv.SetEndPoint(P1);
10716     return;
10717   }
10718 
10719   if (plen < ON_SQRT_EPSILON){
10720     crv.SetStartPoint(P0);
10721     crv.SetEndPoint(P1);
10722     return;
10723   }
10724 
10725   ON_3dPoint C = 0.5*(Pc+Ac);
10726   ON_3dVector VA = A0-C;
10727   VA.Unitize();
10728   ON_3dVector VP = P0-C;
10729   VP.Unitize();
10730 
10731   ON_3dVector Axis = ON_CrossProduct(VA, VP);
10732   double sina = Axis.Length();
10733   if (sina < ON_SQRT_EPSILON){
10734     crv.SetStartPoint(P0);
10735     crv.SetEndPoint(P1);
10736     return;
10737   }
10738   Axis.Unitize();
10739   double cosa = VA*VP;
10740 
10741   ON_Xform T;
10742   T.Rotation(sina, cosa, Axis, C);
10743   crv.Transform(T);
10744   crv.SetStartPoint(P0);
10745   crv.SetEndPoint(P1);
10746   return;
10747   }
10748 
AdjustEdgeEnds(ON_BrepEdge & edge)10749 static void AdjustEdgeEnds(ON_BrepEdge& edge)
10750 
10751 {
10752   ON_Brep* pB = edge.Brep();
10753   if (!pB)
10754     return;
10755   ON_Curve* c3 = const_cast<ON_Curve*>(edge.EdgeCurveOf());
10756   if( c3 )
10757   {
10758     ON_3dPoint A0 = c3->PointAtStart();
10759     ON_3dPoint P0 = A0;
10760     if (edge.m_vi[0] >= 0){
10761       ON_BrepVertex& V = pB->m_V[edge.m_vi[0]];
10762       if (V.IsValid())
10763         P0 = V.Point();
10764     }
10765     ON_3dPoint A1 = c3->PointAtEnd();
10766     ON_3dPoint P1 = A1;
10767     if (edge.m_vi[1] >= 0){
10768       ON_BrepVertex& V = pB->m_V[edge.m_vi[1]];
10769       if (V.IsValid())
10770         P1 = V.Point();
10771     }
10772 
10773     bool bQuit = true;
10774     if (P0 != A0 && edge.m_vi[0] >= 0){
10775       ON_BrepVertex& V = pB->m_V[edge.m_vi[0]];
10776       V.m_tolerance = ON_UNSET_VALUE;
10777       bQuit = false;
10778     }
10779     if (P1 != A1 && edge.m_vi[1] >= 0){
10780       ON_BrepVertex& V = pB->m_V[edge.m_vi[1]];
10781       V.m_tolerance = ON_UNSET_VALUE;
10782       bQuit = false;
10783     }
10784     if (bQuit)
10785       return;
10786 
10787     edge.m_tolerance = ON_UNSET_VALUE;
10788     AdjustCurve(*c3, P0, P1);
10789   }
10790   return;
10791 }
10792 
StandardizeEdgeCurve(int edge_index,bool bAdjustEnds)10793 bool ON_Brep::StandardizeEdgeCurve( int edge_index, bool bAdjustEnds )
10794 {
10795   return StandardizeEdgeCurve(edge_index, bAdjustEnds, 0);
10796 }
10797 
StandardizeEdgeCurve(int edge_index,bool bAdjustEnds,int EdgeCurveUse)10798 bool ON_Brep::StandardizeEdgeCurve( int edge_index, bool bAdjustEnds, int EdgeCurveUse )
10799 {
10800   bool rc = false;
10801   ON_BrepEdge* edge = Edge(edge_index);
10802   if ( 0 != edge && edge->m_edge_index >= 0 )
10803   {
10804     edge_index = edge->m_edge_index;
10805     const ON_Curve* c3 = edge->EdgeCurveOf();
10806     if( c3 )
10807     {
10808       ON_Interval c3dom = c3->Domain();
10809       ON_Interval pdom = edge->ProxyCurveDomain();
10810       ON_Interval edom = edge->Domain();
10811       bool bNewCurve = false;
10812       if ( edge->ProxyCurveIsReversed() )
10813         bNewCurve = true;
10814       else if ( c3dom != pdom )
10815         bNewCurve = true; // curve proxy is trimmed
10816       else if ( EdgeCurveUse > 1 || (EdgeCurveUse < 1 && EdgeCurveUseCount( edge->m_c3i,2 ) > 1 ))
10817         bNewCurve = true; // 2 or more edges use c3
10818       else if ( edom != c3dom )
10819       {
10820         // can fix this problem by changing c3 domain
10821         // and proxy settings
10822         if ( m_C3[edge->m_c3i]->SetDomain(edom) )
10823         {
10824           edge->SetProxyCurveDomain(edom);
10825           edge->SetDomain(edom);
10826           rc = true;
10827         }
10828         else
10829         {
10830           bNewCurve = true;
10831         }
10832       }
10833       else
10834         rc = true;
10835 
10836       if ( bNewCurve )
10837       {
10838         ON_Curve* newc3 = c3->Duplicate();
10839         if ( !newc3 )
10840           return false;
10841         if ( !newc3->Trim(pdom) )
10842         {
10843           delete newc3;
10844           return false;
10845         }
10846         if ( edge->ProxyCurveIsReversed() )
10847         {
10848           if ( !newc3->Reverse() )
10849           {
10850             delete newc3;
10851             return false;
10852           }
10853         }
10854         newc3->SetDomain(edom);
10855         if ( newc3->Domain() != edom )
10856         {
10857           delete newc3;
10858           return false;
10859         }
10860         int c3i = AddEdgeCurve(newc3);
10861         edge->m_c3i = c3i;
10862         edge->SetProxyCurve(newc3);
10863       }
10864     }
10865   }
10866   if (rc && bAdjustEnds)
10867     AdjustEdgeEnds(*edge);
10868     /*
10869   {
10870     ON_Curve* c3 = const_cast<ON_Curve*>(edge->EdgeCurveOf());
10871     if( c3 )
10872     {
10873       if (edge->m_vi[0] >= 0)
10874       {
10875         const ON_BrepVertex& V = m_V[edge->m_vi[0]];
10876         if (V.IsValid())
10877           c3->SetStartPoint(V.Point());
10878       }
10879       if (edge->m_vi[1] >= 0)
10880       {
10881         const ON_BrepVertex& V = m_V[edge->m_vi[1]];
10882         if (V.IsValid())
10883           c3->SetEndPoint(V.Point());
10884       }
10885     }
10886   }
10887   */
10888 
10889   return rc;
10890 }
10891 
sort_ci(const ON_BrepEdge * E0,const ON_BrepEdge * E1)10892 static int sort_ci(const ON_BrepEdge* E0, const ON_BrepEdge* E1)
10893 
10894 {
10895   if (E0->m_c3i < E1->m_c3i)
10896     return -1;
10897   if (E0->m_c3i < E1->m_c3i)
10898     return 1;
10899   return 0;
10900 }
10901 
10902 
StandardizeEdgeCurves(bool bAdjustEnds)10903 void ON_Brep::StandardizeEdgeCurves( bool bAdjustEnds)
10904 {
10905 
10906   //The ends will not adjust properly unless
10907   //all of the edge curves have been standardized first.
10908   //So call standardize on all edges without adjusting, then do the adjusting
10909   //chuck - 9/5/2006
10910   int ei, edge_count = m_E.Count();
10911 
10912 
10913   //chuck - 10/13/2008.  The edge curve use counter called in StandardizeEdgeCurves(int,bool)
10914   //searches through the entire edge array.  In huge breps, this takes a long time.
10915   int* index = (int*)onmalloc(edge_count*sizeof(int));
10916   m_E.Sort(ON::quick_sort, index, sort_ci);
10917 
10918   for ( ei = 0; ei < edge_count; ei++ ){
10919     int ecc = (ei==edge_count-1 || m_E[index[ei+1]].m_c3i == m_E[index[ei]].m_c3i) ? 2 : 1;
10920     StandardizeEdgeCurve( index[ei], false, ecc);
10921   }
10922 
10923   onfree((void*)index);
10924 
10925   /*
10926   for ( ei = 0; ei < edge_count; ei++ )
10927   {
10928     StandardizeEdgeCurve( ei, false );
10929   }
10930   */
10931 
10932   if (bAdjustEnds){
10933     for ( ei = 0; ei < edge_count; ei++ )
10934       AdjustEdgeEnds(m_E[ei]);
10935     SetVertexTolerances(true);
10936     SetEdgeTolerances(true);
10937   }
10938 }
10939 
StandardizeTrimCurve(int trim_index)10940 bool ON_Brep::StandardizeTrimCurve( int trim_index )
10941 {
10942   bool rc = false;
10943   ON_BrepTrim* trim = Trim(trim_index);
10944   if ( 0 != trim && trim->m_trim_index >= 0 )
10945   {
10946     trim_index = trim->m_trim_index;
10947     const ON_Curve* c2 = trim->TrimCurveOf();
10948     if( c2 )
10949     {
10950       ON_Interval c2dom = c2->Domain();
10951       ON_Interval pdom = trim->ProxyCurveDomain();
10952       ON_Interval tdom = trim->Domain();
10953       bool bNewCurve = false;
10954       if ( trim->ProxyCurveIsReversed() )
10955         bNewCurve = true;
10956       else if ( c2dom != pdom )
10957         bNewCurve = true; // curve proxy is trimmed
10958       else if ( TrimCurveUseCount( trim->m_c2i, 2 ) > 1 )
10959         bNewCurve = true; // 2 or more edges use c3
10960       else if ( tdom != c2dom )
10961       {
10962         // can fix this problem by changing c3 domain
10963         // and proxy settings
10964         if ( m_C2[trim->m_c2i]->SetDomain(tdom) )
10965         {
10966           trim->SetProxyCurveDomain(tdom);
10967           trim->SetDomain(tdom);
10968           rc = true;
10969         }
10970         else
10971         {
10972           bNewCurve = true;
10973         }
10974       }
10975       else
10976         rc = true;
10977 
10978       if ( bNewCurve )
10979       {
10980         ON_Curve* newc2 = c2->Duplicate();
10981         if ( !newc2 )
10982           return false;
10983         if ( !newc2->Trim(pdom) )
10984         {
10985           delete newc2;
10986           return false;
10987         }
10988         if ( trim->ProxyCurveIsReversed() )
10989         {
10990           if ( !newc2->Reverse() )
10991           {
10992             delete newc2;
10993             return false;
10994           }
10995         }
10996         newc2->SetDomain(tdom);
10997         if ( newc2->Domain() != tdom )
10998         {
10999           delete newc2;
11000           return false;
11001         }
11002         int c2i = AddTrimCurve(newc2);
11003         trim->m_c2i = c2i;
11004         trim->SetProxyCurve(newc2);
11005         rc = true;
11006       }
11007     }
11008   }
11009   return rc;
11010 }
11011 
StandardizeTrimCurves()11012 void ON_Brep::StandardizeTrimCurves()
11013 {
11014   int ti, trim_count = m_T.Count();
11015   for ( ti = 0; ti < trim_count; ti++ )
11016   {
11017     StandardizeTrimCurve( ti );
11018   }
11019 }
11020 
StandardizeFaceSurface(int face_index)11021 bool ON_Brep::StandardizeFaceSurface( int face_index )
11022 {
11023   bool rc = false;
11024   ON_BrepFace* face = Face(face_index);
11025   if ( 0 != face && face->m_face_index >= 0 )
11026   {
11027     face_index = face->m_face_index;
11028     const ON_Surface* srf = face->SurfaceOf();
11029     if ( srf )
11030     {
11031       //Feb 9 2013 - Chuck - Old code doesn't do anything if bRev is false
11032       /*
11033       if ( face->m_bRev )
11034       {
11035         if ( SurfaceUseCount( face->m_si, 2 ) >= 2 )
11036         {
11037           ON_Surface* newsrf = srf->Duplicate();
11038           face->m_si = AddSurface(newsrf);
11039           face->SetProxySurface(m_S[face->m_si]);
11040           srf = newsrf;
11041         }
11042         rc = face->Transpose() ? true : false;
11043       }
11044       else
11045         rc = true;
11046         */
11047       if ( face->m_bRev )
11048         rc = face->Transpose() ? true : false; //Transpose does the SurfaceUseCount check
11049       else
11050       {
11051         if ( SurfaceUseCount( face->m_si, 2 ) >= 2 )
11052         {
11053           ON_Surface* newsrf = srf->Duplicate();
11054           face->m_si = AddSurface(newsrf);
11055           face->SetProxySurface(m_S[face->m_si]);
11056           srf = newsrf;
11057         }
11058         rc = true;
11059       }
11060     }
11061   }
11062   return rc;
11063 }
11064 
StardardizeFaceSurfaces()11065 void ON_Brep::StardardizeFaceSurfaces()
11066 {
11067   // StardardizeFaceSurfaces() - misspelled function is obsolte
11068   // but left here to avoid breaking the SDK.
11069   StandardizeFaceSurfaces();
11070 }
11071 
StandardizeFaceSurfaces()11072 void ON_Brep::StandardizeFaceSurfaces()
11073 {
11074   int fi, face_count = m_F.Count();
11075   for ( fi = 0; fi < face_count; fi++ )
11076   {
11077     StandardizeFaceSurface( fi );
11078   }
11079 }
11080 
Standardize()11081 void ON_Brep::Standardize()
11082 {
11083   StandardizeFaceSurfaces();
11084   StandardizeEdgeCurves(true);
11085   StandardizeTrimCurves();
11086 }
11087 
11088 
11089 
ShrinkSurface(ON_BrepFace & face,int DisableMask)11090 bool ON_Brep::ShrinkSurface( ON_BrepFace& face, int DisableMask )
11091 {
11092   ON_Surface* srf = const_cast<ON_Surface*>(face.SurfaceOf());
11093   if ( !srf )
11094     return false;
11095 
11096   ON_Interval srf_udom = srf->Domain(0);
11097   ON_Interval srf_vdom = srf->Domain(1);
11098 
11099   int fli, li, si=-1;
11100   int lti, ti;
11101   int outer_loop_li=-1;
11102   const int loop_count = m_L.Count();
11103   const int trim_count = m_T.Count();
11104   ON_BoundingBox outer_pbox;
11105 
11106   bool bAllTrimsAreIsoTrims = true;
11107   bool bSomeTrimsAreIsoTrims = false;
11108 
11109   // 4 April 2003 Dale Lear:
11110   //    Shrink srf fix.
11111   ON_BoundingBox trim_iso_endbox; // bounding box of iso curve trim ends
11112 
11113   int face_loop_count = face.m_li.Count();
11114   bool bIsSrfEdge[4];
11115   int sei;
11116   for (sei=0; sei<4; sei++)
11117     bIsSrfEdge[sei] = false;
11118   for ( fli = 0; fli < face_loop_count; fli++ )
11119   {
11120     li = face.m_li[fli];
11121     if ( li < 0 )
11122       continue;
11123     if ( li >= loop_count )
11124       continue;
11125     const ON_BrepLoop& loop = m_L[li];
11126     if ( loop.m_type == ON_BrepLoop::outer )
11127     {
11128       // may be more than one outer loop
11129       if ( outer_loop_li )
11130         outer_loop_li = li;
11131       outer_pbox.Union( loop.m_pbox );
11132 
11133       int loop_trim_count = loop.m_ti.Count();
11134       for ( lti = 0; lti < loop_trim_count; lti++ )
11135       {
11136         ti = loop.m_ti[lti];
11137         if ( ti >= 0 && ti < trim_count )
11138         {
11139           bool bIsIso = false;
11140           switch( m_T[ti].m_iso )
11141           {
11142           case ON_Surface::x_iso:
11143           case ON_Surface::y_iso:
11144             bIsIso = true;
11145             break;
11146           case ON_Surface::W_iso:
11147             bIsIso = true;
11148             bIsSrfEdge[0] = true;
11149             break;
11150           case ON_Surface::S_iso:
11151             bIsIso = true;
11152             bIsSrfEdge[1] = true;
11153             break;
11154           case ON_Surface::E_iso:
11155             bIsIso = true;
11156             bIsSrfEdge[2] = true;
11157             break;
11158           case ON_Surface::N_iso:
11159             bIsIso = true;
11160             bIsSrfEdge[3] = true;
11161             break;
11162           default:
11163             // it's not an iso curve trim
11164             bAllTrimsAreIsoTrims = false;
11165           }
11166           if (bIsIso){
11167             // it's an iso curve trim
11168             trim_iso_endbox.Set( m_T[ti].PointAtStart(), true );
11169             trim_iso_endbox.Set( m_T[ti].PointAtEnd(), true );
11170             bSomeTrimsAreIsoTrims = true;
11171           }
11172         }
11173       }
11174 
11175     }
11176   }
11177 
11178   if ( !outer_pbox.IsValid() )
11179     return false;
11180 
11181   bool rc = false;
11182   ON_Interval outer_udom( outer_pbox.m_min.x, outer_pbox.m_max.x );
11183   ON_Interval outer_vdom( outer_pbox.m_min.y, outer_pbox.m_max.y );
11184 
11185   if ( !bAllTrimsAreIsoTrims )
11186   {
11187     // 4 April 2003 Dale Lear:
11188     //    Prevent shrinking surface to
11189     //    interior edge of wiggly trims so that
11190     //    3d edge curves will pullback correctly and
11191     //    brep-brep intersections will be
11192     //    transverse along complicated trims.
11193     double d;
11194 
11195     d = outer_udom.Length()*0.01;
11196     if ( (!bSomeTrimsAreIsoTrims || outer_udom[0] < trim_iso_endbox.m_min.x) && !bIsSrfEdge[0] )
11197       outer_udom[0] -= d;
11198     if ( (!bSomeTrimsAreIsoTrims || outer_udom[1] > trim_iso_endbox.m_max.x) && !bIsSrfEdge[2])
11199       outer_udom[1] += d;
11200 
11201     d = outer_vdom.Length()*0.01;
11202     if ( (!bSomeTrimsAreIsoTrims || outer_vdom[0] < trim_iso_endbox.m_min.y) && !bIsSrfEdge[1] )
11203       outer_vdom[0] -= d;
11204     if ( (!bSomeTrimsAreIsoTrims || outer_vdom[1] > trim_iso_endbox.m_max.y) && !bIsSrfEdge[3] )
11205       outer_vdom[1] += d;
11206   }
11207 
11208   outer_udom.Intersection( srf_udom );
11209   outer_vdom.Intersection( srf_vdom );
11210 
11211   bool bShrinkIt = false;
11212 
11213   /*
11214   // removed 4 April 2003 Dale Lear
11215   if ( outer_udom.IsIncreasing() && outer_vdom.IsIncreasing() )
11216   {
11217     if ( outer_udom.Length() < 0.99*srf_udom.Length() || outer_vdom.Length() < 0.99*srf_vdom.Length())
11218     {
11219       bShrinkIt = true;
11220     }
11221     else if ( outer_udom.Length() < srf_udom.Length() || outer_vdom.Length() < srf_vdom.Length())
11222     {
11223       // 13 Feb 2003 Dale Lear added this --
11224       // if all trims are isos, then perform micro shrink
11225       // so iso trims will lie on surface boundaries
11226       bShrinkIt = bAllTrimsAreIsoTrims;
11227     }
11228   }
11229   */
11230 
11231   // GBA 8 May 2006.  Added DiasbleMask
11232   if( DisableMask & 0x0001)     // West
11233     outer_udom[0] = srf_udom[0];
11234   if( DisableMask & 0x0002)     // South
11235     outer_vdom[0] = srf_vdom[0];
11236   if( DisableMask & 0x0004)     // East
11237     outer_udom[1] = srf_udom[1];
11238   if( DisableMask & 0x0008)     // North
11239     outer_vdom[1] = srf_vdom[1];
11240 
11241 
11242   // added 4 April 2003 Dale Lear
11243   if ( outer_udom.IsIncreasing() && outer_vdom.IsIncreasing() )
11244   {
11245     //TRR #33381 28-April-08 GBA
11246     //  Make sure we don't keep allowing the surface to be shrunk.
11247     if ( outer_udom.Length()*ON_ZERO_TOLERANCE < (srf_udom.Length() - outer_udom.Length()) ||
11248          outer_vdom.Length()*ON_ZERO_TOLERANCE < (srf_vdom.Length() - outer_vdom.Length())  )
11249       bShrinkIt = true;
11250   }
11251 
11252   if ( bShrinkIt )
11253   {
11254     int srf_use = SurfaceUseCount( face.m_si, 2);
11255     ON_Surface* small_srf = srf->Duplicate();
11256     if ( small_srf->Trim( 0, outer_udom ) )
11257     {
11258       if ( small_srf->Trim( 1, outer_vdom) )
11259         si = AddSurface(small_srf);
11260       if ( si >= 0 )
11261       {
11262 				int srf_index = face.m_si;
11263         face.m_si = si;
11264         face.SetProxySurface( m_S[face.m_si] );
11265 
11266         // 5 Dec 2002 Chuck - dont delete original surface if used by more than one face
11267 				if (srf_use == 1) DeleteSurface(srf_index);
11268 
11269         // 1 Nov 2002 Dale Lear - reset face bbox and destroy brep too big bounding box
11270         face.m_bbox = small_srf->BoundingBox();
11271         m_bbox.Destroy();
11272 
11273 				// Set trim.m_iso flags
11274 				for(int li=0; li<face.LoopCount(); li++){
11275 					ON_BrepLoop& loop = *face.Loop(li);
11276 					for(int ti=0; ti<loop.TrimCount(); ti++){
11277 						ON_BrepTrim& trim = *loop.Trim(ti);
11278             //Since the slop used in calculating m_iso depends on the srf domain
11279             //all isos should be rechecked after shrinking
11280 
11281             /*
11282 						if(	trim.m_iso==ON_Surface::x_iso ||
11283 								trim.m_iso==ON_Surface::y_iso )
11284                 */
11285             if (trim.m_iso != ON_Surface::not_iso)
11286 							trim.m_iso = face.IsIsoparametric(trim);
11287 					}
11288 				}
11289         rc = true;
11290       }
11291     }
11292     if ( !rc )
11293       delete small_srf;
11294   }
11295 
11296   return rc;
11297 }
11298 
ShrinkSurfaces()11299 bool ON_Brep::ShrinkSurfaces()
11300 {
11301   bool rc = true;
11302   int fi, face_count = m_F.Count();
11303   for ( fi = 0; fi < face_count; fi++ )
11304   {
11305     if ( !ShrinkSurface( m_F[fi] ) )
11306       rc = false;
11307   }
11308 	Compact();
11309   return rc;
11310 }
11311 
11312 /*
11313 int ON_Brep::ComponentIndex( const ON_BrepVertex& vertex ) const
11314 {
11315   int component_index = vertex.m_vertex_index;
11316   if ( component_index >= 0 )
11317     component_index += brep_vertex;
11318   else
11319     component_index = -1;
11320   return component_index;
11321 }
11322 
11323 int ON_Brep::ComponentIndex( const ON_BrepEdge& edge ) const
11324 {
11325   int component_index = edge.m_edge_index;
11326   if ( component_index >= 0 )
11327     component_index += brep_edge;
11328   else
11329     component_index = -1;
11330   return component_index;
11331 }
11332 
11333 int ON_Brep::ComponentIndex( const ON_BrepTrim& trim ) const
11334 {
11335   int component_index = trim.m_trim_index;
11336   if ( component_index >= 0 )
11337     component_index += brep_trim;
11338   else
11339     component_index = -1;
11340   return component_index;
11341 }
11342 
11343 int ON_Brep::ComponentIndex( const ON_BrepLoop& loop ) const
11344 {
11345   int component_index = loop.m_loop_index;
11346   if ( component_index >= 0 )
11347     component_index += brep_loop;
11348   else
11349     component_index = -1;
11350   return component_index;
11351 }
11352 
11353 int ON_Brep::ComponentIndex( const ON_BrepFace& face ) const
11354 {
11355   int component_index = face.m_face_index;
11356   if ( component_index >= 0 )
11357     component_index += brep_face;
11358   else
11359     component_index = -1;
11360   return component_index;
11361 }
11362 
11363 ON_Brep::COMPONENT_TYPE ON_Brep::ComponentIndexType( int component_index )
11364 {
11365   switch( brep_component_mask & component_index )
11366   {
11367   case brep_vertex: return brep_vertex;
11368   case brep_edge: return brep_edge;
11369   case brep_trim: return brep_trim;
11370   case brep_loop: return brep_loop;
11371   case brep_face: return brep_face;
11372   }
11373   return brep_component_unset;
11374 }
11375 */
11376 
BrepComponent(ON_COMPONENT_INDEX ci) const11377 const ON_Geometry* ON_Brep::BrepComponent(
11378   ON_COMPONENT_INDEX ci
11379   ) const
11380 {
11381   const ON_Geometry* component = 0;
11382   switch ( ci.m_type )
11383   {
11384   case ON_COMPONENT_INDEX::brep_vertex:
11385     component = Vertex(ci.m_index);
11386     break;
11387   case ON_COMPONENT_INDEX::brep_edge:
11388     component = Edge(ci.m_index);
11389     break;
11390   case ON_COMPONENT_INDEX::brep_face:
11391     component = Face(ci.m_index);
11392     break;
11393   case ON_COMPONENT_INDEX::brep_trim:
11394     component = Trim(ci.m_index);
11395     break;
11396   case ON_COMPONENT_INDEX::brep_loop:
11397     component = Loop(ci.m_index);
11398     break;
11399   default:
11400     // other enum values skipped on purpose
11401     break;
11402   }
11403   return component;
11404 }
11405 
11406 /*
11407 const ON_Geometry* ON_Brep::BrepComponent(
11408   int component_index
11409   ) const
11410 {
11411   const ON_Geometry* component = 0;
11412   if ( -1 != component_index && 0 != component_index)
11413   {
11414     switch( ON_Brep::ComponentIndexType(component_index) )
11415     {
11416     case brep_vertex:
11417       component = Vertex(component_index);
11418       break;
11419     case brep_edge:
11420       component = Edge(component_index);
11421       break;
11422     case brep_trim:
11423       component = Trim(component_index);
11424       break;
11425     case brep_loop:
11426       component = Loop(component_index);
11427       break;
11428     case brep_face:
11429       component = Face(component_index);
11430       break;
11431     }
11432   }
11433   return component;
11434 }
11435 */
11436 
11437 
Vertex(int vertex_index) const11438 ON_BrepVertex* ON_Brep::Vertex( int vertex_index ) const
11439 {
11440   ON_BrepVertex* vertex = 0;
11441   if ( vertex_index>=0 && vertex_index < m_V.Count() )
11442     vertex = const_cast<ON_BrepVertex*>(&m_V[vertex_index]);
11443   return vertex;
11444 }
11445 
Vertex(ON_COMPONENT_INDEX vertex_index) const11446 ON_BrepVertex* ON_Brep::Vertex( ON_COMPONENT_INDEX vertex_index ) const
11447 {
11448   ON_BrepVertex* vertex = 0;
11449   if ( ON_COMPONENT_INDEX::brep_vertex == vertex_index.m_type
11450        && vertex_index.m_index >= 0
11451        && vertex_index.m_index < m_V.Count() )
11452   {
11453     vertex = const_cast<ON_BrepVertex*>(&m_V[vertex_index.m_index]);
11454   }
11455   return vertex;
11456 }
11457 
11458 
Edge(int edge_index) const11459 ON_BrepEdge* ON_Brep::Edge( int edge_index ) const
11460 {
11461   ON_BrepEdge* edge = 0;
11462   if ( edge_index>=0 && edge_index < m_E.Count() )
11463     edge = const_cast<ON_BrepEdge*>(&m_E[edge_index]);
11464   return edge;
11465 }
11466 
Edge(ON_COMPONENT_INDEX edge_index) const11467 ON_BrepEdge* ON_Brep::Edge( ON_COMPONENT_INDEX edge_index ) const
11468 {
11469   ON_BrepEdge* edge = 0;
11470   if ( ON_COMPONENT_INDEX::brep_edge == edge_index.m_type
11471        && edge_index.m_index >= 0
11472        && edge_index.m_index < m_E.Count() )
11473   {
11474     edge = const_cast<ON_BrepEdge*>(&m_E[edge_index.m_index]);
11475   }
11476   return edge;
11477 }
11478 
Trim(int trim_index) const11479 ON_BrepTrim* ON_Brep::Trim( int trim_index ) const
11480 {
11481   ON_BrepTrim* trim = 0;
11482   if ( trim_index>=0 && trim_index < m_T.Count() )
11483     trim = const_cast<ON_BrepTrim*>(&m_T[trim_index]);
11484   return trim;
11485 }
11486 
Trim(ON_COMPONENT_INDEX trim_index) const11487 ON_BrepTrim* ON_Brep::Trim( ON_COMPONENT_INDEX trim_index ) const
11488 {
11489   ON_BrepTrim* trim = 0;
11490   if ( ON_COMPONENT_INDEX::brep_trim == trim_index.m_type
11491        && trim_index.m_index >= 0
11492        && trim_index.m_index < m_T.Count() )
11493   {
11494     trim = const_cast<ON_BrepTrim*>(&m_T[trim_index.m_index]);
11495   }
11496   return trim;
11497 }
11498 
Loop(int loop_index) const11499 ON_BrepLoop* ON_Brep::Loop( int loop_index ) const
11500 {
11501   ON_BrepLoop* loop = 0;
11502   if ( loop_index>=0 && loop_index < m_L.Count() )
11503     loop = const_cast<ON_BrepLoop*>(&m_L[loop_index]);
11504   return loop;
11505 }
11506 
Loop(ON_COMPONENT_INDEX loop_index) const11507 ON_BrepLoop* ON_Brep::Loop( ON_COMPONENT_INDEX loop_index ) const
11508 {
11509   ON_BrepLoop* loop = 0;
11510   if ( ON_COMPONENT_INDEX::brep_loop == loop_index.m_type
11511        && loop_index.m_index >= 0
11512        && loop_index.m_index < m_L.Count() )
11513   {
11514     loop = const_cast<ON_BrepLoop*>(&m_L[loop_index.m_index]);
11515   }
11516   return loop;
11517 }
11518 
Face(int face_index) const11519 ON_BrepFace* ON_Brep::Face( int face_index ) const
11520 {
11521   ON_BrepFace* face = 0;
11522   if ( face_index>=0 && face_index < m_F.Count() )
11523     face = const_cast<ON_BrepFace*>(&m_F[face_index]);
11524   return face;
11525 }
11526 
Face(ON_COMPONENT_INDEX face_index) const11527 ON_BrepFace* ON_Brep::Face( ON_COMPONENT_INDEX face_index ) const
11528 {
11529   ON_BrepFace* face = 0;
11530   if ( ON_COMPONENT_INDEX::brep_face == face_index.m_type
11531        && face_index.m_index >= 0
11532        && face_index.m_index < m_F.Count() )
11533   {
11534     face = const_cast<ON_BrepFace*>(&m_F[face_index.m_index]);
11535   }
11536   return face;
11537 }
11538 
SurfaceOf() const11539 const ON_Surface* ON_BrepFace::SurfaceOf() const
11540 {
11541   const ON_Surface* srf = ProxySurface();
11542   if ( 0 == srf && 0 != m_brep && m_si >= 0 && m_si < m_brep->m_S.Count() )
11543   {
11544     srf = m_brep->m_S[m_si];
11545   }
11546   return srf;
11547 }
11548 
11549 
11550 
DestroyPspaceInformation()11551 void ON_BrepTrim::DestroyPspaceInformation()
11552 {
11553   m_pline.Destroy();
11554   m_pbox.Destroy();
11555 }
11556 
ChangeTrimCurve(int c2i)11557 bool ON_BrepTrim::ChangeTrimCurve( int c2i )
11558 {
11559   if ( 0 == m_brep )
11560     return 0;
11561   if ( c2i < 0 || c2i >= m_brep->m_C2.Count() )
11562     return 0;
11563   const ON_Curve* c2 = m_brep->m_C2[c2i];
11564   m_c2i = c2i;
11565   DestroyPspaceInformation();
11566   SetProxyCurve(c2);
11567   if ( c2 )
11568   {
11569     m_pbox = c2->BoundingBox();
11570     m_pbox.m_min.z = 0.0;
11571     m_pbox.m_max.z = 0.0;
11572   }
11573   return true;
11574 }
11575 
RemoveFromEdge(bool bRemoveFromStartVertex,bool bRemoveFromEndVertex)11576 bool ON_BrepTrim::RemoveFromEdge(
11577       bool bRemoveFromStartVertex,
11578       bool bRemoveFromEndVertex
11579       )
11580 {
11581   bool rc = false;
11582   if ( 0 != m_brep || m_ei < 0  )
11583   {
11584     UnsetPlineEdgeParameters();
11585     if ( 0 != m_brep )
11586     {
11587       ON_BrepEdge* edge = m_brep->Edge(m_ei);
11588       if ( 0 != edge )
11589       {
11590         int eti = 0;
11591         while( eti < edge->m_ti.Count() )
11592         {
11593           if ( edge->m_ti[eti] == m_trim_index )
11594             edge->m_ti.Remove(eti);
11595           else
11596             eti++;
11597         }
11598       }
11599     }
11600     m_ei = -1;
11601     if (bRemoveFromStartVertex)
11602       m_vi[0] = -1;
11603     if (bRemoveFromEndVertex)
11604       m_vi[1] = -1;
11605     rc = true;
11606   }
11607   return rc;
11608 }
11609 
AttachToEdge(int edge_index,bool bRev3d)11610 bool ON_BrepTrim::AttachToEdge(
11611       int edge_index,
11612       bool bRev3d
11613       )
11614 {
11615   bool rc = false;
11616   if ( 0 != m_brep )
11617   {
11618     ON_BrepEdge* edge = m_brep->Edge(edge_index);
11619     if ( 0 != edge )
11620     {
11621       rc = RemoveFromEdge(true,true);
11622       if (rc)
11623       {
11624         edge->m_ti.Append(m_trim_index);
11625         m_ei = edge->m_edge_index;
11626         m_bRev3d = bRev3d ? true : false;
11627         m_vi[0] = edge->m_vi[bRev3d?1:0];
11628         m_vi[1] = edge->m_vi[bRev3d?0:1];
11629       }
11630     }
11631   }
11632   return rc;
11633 }
11634 
11635 
11636 
EdgeCurveOf() const11637 const ON_Curve* ON_BrepEdge::EdgeCurveOf() const
11638 {
11639   const ON_Curve* c3 = ProxyCurve();
11640   if ( !c3 && m_brep && m_c3i >= 0 && m_c3i < m_brep->m_C3.Count())
11641   {
11642     // fallback to get answer if developer forgot to
11643     // set proxy ptr.
11644     c3 = m_brep->m_C3[m_c3i];
11645     if ( c3 )
11646     {
11647       ON_ERROR("ON_BrepEdge ProxyCurve() is NULL but m_c3i is valid");
11648     }
11649   }
11650   return c3;
11651 }
11652 
EdgeCurveIndexOf() const11653 int ON_BrepEdge::EdgeCurveIndexOf() const
11654 {
11655   return (m_brep && m_c3i >= 0 && m_c3i < m_brep->m_C3.Count()) ? m_c3i : -1;
11656 }
11657 
EdgeCurveIndexOf() const11658 int ON_BrepTrim::EdgeCurveIndexOf() const
11659 {
11660   int c3i = -1;
11661   if ( m_brep && m_ei >= 0 && m_ei < m_brep->m_E.Count() )
11662   {
11663     c3i = m_brep->m_E[m_ei].m_c3i;
11664     if ( c3i < 0 || c3i >= m_brep->m_C3.Count() )
11665       c3i = -1;
11666   }
11667   return c3i;
11668 }
11669 
TrimCurveIndexOf() const11670 int ON_BrepTrim::TrimCurveIndexOf() const
11671 {
11672   return ((m_brep && m_c2i >= 0 && m_c2i < m_brep->m_C2.Count()) ? m_c2i : -1);
11673 }
11674 
EdgeCurveOf() const11675 const ON_Curve* ON_BrepTrim::EdgeCurveOf() const
11676 {
11677   const ON_Curve* c3 = 0;
11678   if ( m_brep && m_ei >= 0 && m_ei < m_brep->m_C3.Count() )
11679   {
11680     c3 = m_brep->m_E[m_ei].EdgeCurveOf();
11681   }
11682   return c3;
11683 }
11684 
ChangeEdgeCurve(int c3i)11685 bool ON_BrepEdge::ChangeEdgeCurve( int c3i )
11686 {
11687   if ( 0 == m_brep )
11688     return 0;
11689   if ( c3i < 0 || c3i >= m_brep->m_C3.Count() )
11690     return 0;
11691   const ON_Curve* c3 = m_brep->m_C3[c3i];
11692   m_c3i = c3i;
11693   SetProxyCurve(c3);
11694   UnsetPlineEdgeParameters();
11695   return true;
11696 }
11697 
TrimCurveOf() const11698 const ON_Curve* ON_BrepTrim::TrimCurveOf() const
11699 {
11700   const ON_Curve* c2 = ProxyCurve();
11701   if ( !c2 && m_brep && m_c2i >= 0 && m_c2i < m_brep->m_C2.Count() )
11702   {
11703     // fallback to get answer if developer forgot to
11704     // set proxy ptr.
11705     c2 = m_brep->m_C2[m_c2i];
11706     if ( c2 )
11707     {
11708       ON_ERROR("ON_BrepTrim ProxyCurve() = NULL but m_c2i is valid");
11709     }
11710   }
11711   return c2;
11712 }
11713 
SurfaceOf() const11714 const ON_Surface* ON_BrepTrim::SurfaceOf() const
11715 {
11716   const ON_Surface* srf = 0;
11717   if ( m_brep && m_li >= 0 && m_li < m_brep->m_L.Count() )
11718   {
11719     const int fi = m_brep->m_L[m_li].m_fi;
11720     if ( fi >= 0 && fi < m_brep->m_F.Count() )
11721     {
11722       srf = m_brep->m_F[fi].SurfaceOf();
11723     }
11724   }
11725   return srf;
11726 }
11727 
SurfaceOf() const11728 const ON_Surface* ON_BrepLoop::SurfaceOf() const
11729 {
11730   const ON_Surface* srf = 0;
11731   if ( m_brep && m_fi >= 0 && m_fi < m_brep->m_F.Count() )
11732   {
11733     srf = m_brep->m_F[m_fi].SurfaceOf();
11734   }
11735   return srf;
11736 }
11737 
SurfaceIndexOf() const11738 int ON_BrepTrim::SurfaceIndexOf() const
11739 {
11740   int si = -1;
11741   if ( m_brep && m_li >= 0 && m_li < m_brep->m_L.Count() )
11742   {
11743     const int fi = m_brep->m_L[m_li].m_fi;
11744     if ( fi >= 0 && fi < m_brep->m_F.Count() )
11745     {
11746       si = m_brep->m_F[fi].m_si;
11747       if ( si < 0 || si >= m_brep->m_S.Count() )
11748         si = -1;
11749     }
11750   }
11751   return si;
11752 }
11753 
11754 
FaceIndexOf() const11755 int ON_BrepTrim::FaceIndexOf() const
11756 {
11757   int fi = -1;
11758   if ( m_brep && m_li >= 0 && m_li < m_brep->m_L.Count() )
11759   {
11760     fi = m_brep->m_L[m_li].m_fi;
11761     if ( fi< 0 || fi >= m_brep->m_F.Count() )
11762     {
11763       fi = -1;
11764     }
11765   }
11766   return fi;
11767 }
11768 
11769 static
SlitSeamMateHelper(const ON_BrepTrim & trim)11770 const ON_BrepTrim* SlitSeamMateHelper( const ON_BrepTrim& trim )
11771 {
11772   if ( ON_BrepTrim::seam  != trim.m_type )
11773     return 0;
11774   if ( trim.m_li < 0 )
11775     return 0;
11776   if ( trim.m_ei < 0 )
11777     return 0;
11778   const ON_Brep* brep = trim.Brep();
11779   if ( !brep )
11780     return 0;
11781   if ( trim.m_ei >= brep->m_E.Count() )
11782     return 0;
11783   const ON_BrepEdge& edge = brep->m_E[trim.m_ei];
11784   int other_ti = -1;
11785   for ( int eti = 0; eti < edge.m_ti.Count(); eti++ )
11786   {
11787     int ti = edge.m_ti[eti];
11788     if ( trim.m_trim_index == ti )
11789       continue;
11790     if ( ti < 0 || ti >= brep->m_T.Count() )
11791       continue;
11792     if ( trim.m_li == brep->m_T[ti].m_li )
11793     {
11794       if (other_ti >= 0 )
11795         return 0;
11796       other_ti = ti;
11797     }
11798   }
11799   if ( other_ti < 0 )
11800     return 0;
11801   return &brep->m_T[other_ti];
11802 }
11803 
IsSlit() const11804 bool ON_BrepTrim::IsSlit() const
11805 {
11806   // 17 Nov 2006
11807   //     At this point in the development cycle, I cannot
11808   //     add a "slit" type to trim.  So, I will use this
11809   //     function to distinguish between "slit" and "seam"
11810   //     trims.
11811   switch(m_iso)
11812   {
11813   case ON_Surface::E_iso:
11814   case ON_Surface::N_iso:
11815   case ON_Surface::S_iso:
11816   case ON_Surface::W_iso:
11817     return false;
11818     break;
11819 
11820   case ON_Surface::not_iso:
11821   case ON_Surface::x_iso:
11822   case ON_Surface::y_iso:
11823   case ON_Surface::iso_count:
11824     // anything else might be a slit
11825     break;
11826   }
11827   const ON_BrepTrim* other_trim = SlitSeamMateHelper(*this);
11828   if ( !other_trim )
11829     return false;
11830   return ( other_trim->m_iso == m_iso );
11831 }
11832 
IsSeam() const11833 bool ON_BrepTrim::IsSeam() const
11834 {
11835   // 17 Nov 2006
11836   //     At this point in the development cycle, I cannot
11837   //     add a "slit" type to trim.  So, I will use this
11838   //     function to distinguish between "slit" and "seam"
11839   //     trims.
11840   ON_Surface::ISO other_iso = ON_Surface::not_iso;
11841   switch(m_iso)
11842   {
11843   case ON_Surface::E_iso:
11844     other_iso = ON_Surface::W_iso;
11845     break;
11846   case ON_Surface::N_iso:
11847     other_iso = ON_Surface::S_iso;
11848     break;
11849   case ON_Surface::S_iso:
11850     other_iso = ON_Surface::N_iso;
11851     break;
11852   case ON_Surface::W_iso:
11853     other_iso = ON_Surface::E_iso;
11854     break;
11855   default:
11856     return false;
11857   }
11858   const ON_BrepTrim* other_trim = SlitSeamMateHelper(*this);
11859   if ( !other_trim )
11860     return false;
11861 
11862   return ( other_trim->m_iso == other_iso );
11863 }
11864 
11865 
SurfaceIndexOf() const11866 int ON_BrepLoop::SurfaceIndexOf() const
11867 {
11868   const ON_BrepFace* face = Face();
11869   return face ? face->m_si : -1;
11870 }
11871 
SurfaceIndexOf() const11872 int ON_BrepFace::SurfaceIndexOf() const
11873 {
11874   return (m_brep && m_si >= 0 && m_si < m_brep->m_S.Count()) ? m_si : 0;
11875 }
11876 
UnsetPlineEdgeParameters()11877 void ON_BrepTrim::UnsetPlineEdgeParameters()
11878 {
11879   int count = m_pline.Count();
11880   if ( count > 0 )
11881   {
11882     ON_BrepTrimPoint* pline = m_pline.Array();
11883     while ( count-- )
11884       (pline++)->e = ON_UNSET_VALUE;
11885   }
11886 }
11887 
UnsetPlineEdgeParameters()11888 void ON_BrepEdge::UnsetPlineEdgeParameters()
11889 {
11890   int edge_trim_count, brep_trim_count, eti, ti;
11891   if ( 0 != m_brep )
11892   {
11893     edge_trim_count = m_ti.Count();
11894     if ( edge_trim_count > 0 )
11895     {
11896       brep_trim_count = m_brep->m_T.Count();
11897       for ( eti = 0; eti < edge_trim_count; eti++ )
11898       {
11899         ti = m_ti[eti];
11900         if ( ti >= 0 && ti < brep_trim_count )
11901         {
11902           m_brep->m_T[ti].UnsetPlineEdgeParameters();
11903         }
11904       }
11905     }
11906   }
11907 }
11908 
TransformTrim(const ON_Xform & xform)11909 bool ON_BrepFace::TransformTrim( const ON_Xform& xform )
11910 {
11911   if ( !m_brep )
11912     return false;
11913   int fli;
11914   for ( fli = 0; fli < m_li.Count(); fli++ )
11915   {
11916     ON_BrepLoop* loop = m_brep->Loop( m_li[fli] );
11917     if ( loop )
11918     {
11919       if ( !loop->TransformTrim(xform) )
11920         return false;
11921     }
11922   }
11923   return true;
11924 }
11925 
TransformTrim(const ON_Xform & xform)11926 bool ON_BrepLoop::TransformTrim( const ON_Xform& xform )
11927 {
11928   if ( !m_brep )
11929     return false;
11930   int lti;
11931   m_pbox.Destroy();
11932   for ( lti = 0; lti < m_ti.Count(); lti++ )
11933   {
11934     ON_BrepTrim* trim = m_brep->Trim( m_ti[lti] );
11935     if ( trim )
11936     {
11937       if ( !trim->TransformTrim(xform) )
11938         return false;
11939       m_pbox.Union( trim->m_pbox );
11940     }
11941   }
11942   return true;
11943 }
11944 
TransformTrim(const ON_Xform & xform)11945 bool ON_BrepTrim::TransformTrim( const ON_Xform& xform )
11946 {
11947   // destroy cached information used to accelerate calculations
11948   DestroyCurveTree();
11949   m_pline.Destroy();
11950 
11951   if ( !m_brep )
11952     return false;
11953 
11954   // make sure only one trim uses the 2d curve
11955   if ( !m_brep->StandardizeTrimCurve( m_trim_index ) )
11956     return false;
11957 
11958   // transform 2d curve geometry
11959   ON_Curve* c2 = const_cast<ON_Curve*>(TrimCurveOf());
11960   if ( !c2 )
11961     return true;
11962   if ( !c2->Transform(xform) )
11963     return false;
11964 
11965   // update bounding box stored on trim
11966   m_pbox = c2->BoundingBox();
11967   m_pbox.m_min.z = 0.0;
11968   m_pbox.m_max.z = 0.0;
11969 
11970   // update 2d tolerances
11971   // Trim transforms can translate, scale and/or swap parameters.
11972   // The tolerances need to be adjusted for scaling and swapping.
11973   // Since the determinant can be < 0, fabs() must be applied.
11974   double tol0 = xform[0][0]*m_tolerance[0] + xform[0][1]*m_tolerance[1];
11975   double tol1 = xform[1][0]*m_tolerance[0] + xform[1][1]*m_tolerance[1];
11976   m_tolerance[0] = fabs(tol0);
11977   m_tolerance[1] = fabs(tol1);
11978 
11979   if ( m_iso != ON_Surface::not_iso )
11980   {
11981     m_iso = ON_Surface::not_iso;
11982     m_brep->SetTrimIsoFlags(*this);
11983   }
11984 
11985   return true;
11986 }
11987 
11988 
DestroyRuntimeCache(bool bDelete)11989 void ON_BrepTrim::DestroyRuntimeCache( bool bDelete )
11990 {
11991   ON_CurveProxy::DestroyRuntimeCache(bDelete);
11992 
11993   // This doesn't work right as of 30 Oct 2002 because
11994   // the pline is getting destroyed while it is still
11995   // valid and needed due to excessive calling
11996   // of DestroyRuntimeCache();
11997 
11998   //if ( bDelete )
11999   //  m_pline.Destroy();
12000   //else
12001   //  m_pline.EmergencyDestroy();
12002 
12003   // m_pbox.Destroy(); do not do this - it is not a runtime setting
12004   //                   and you will break the copy operators
12005 }
12006 
DestroyRuntimeCache(bool bDelete)12007 void ON_BrepLoop::DestroyRuntimeCache( bool bDelete )
12008 {
12009   ON_Object::DestroyRuntimeCache(bDelete);
12010 
12011   // m_pbox.Destroy(); do not do this - it is not a runtime setting
12012   //                   and you will break the copy operators
12013 }
12014 
DestroyRuntimeCache(bool bDelete)12015 void ON_BrepFace::DestroyRuntimeCache( bool bDelete )
12016 {
12017   ON_SurfaceProxy::DestroyRuntimeCache(bDelete);
12018 
12019   // 15 August 2003 Dale Lear:
12020   //    I added the line to destroy the face's m_bbox.
12021   //    Since m_bbox is private, it will be recalculated
12022   //    when it is needed.  (We hope.)  The fact the face
12023   //    m_bbox is private and recalculated as needed makes
12024   //    it different than the m_pbox info on trims and loops.
12025   m_bbox.Destroy();
12026 }
12027 
12028 
12029 /*
12030 bool ON_Surface::AreaMassProperties(
12031   ON_MassProperties& mp,
12032   bool bArea,
12033   bool bFirstMoments,
12034   bool bSecondMoments,
12035   bool bProductMoments,
12036   double rel_tol,
12037   double abs_tol
12038   ) const
12039 {
12040   bool rc = false;
12041   // The _MassPropertiesSurface() function is provided by the Rhino SDK.
12042   if ( 0 != _MassPropertiesSurface )
12043   {
12044     int mprc = _MassPropertiesSurface(
12045             *this, NULL, 2, ON_UNSET_POINT, mp,
12046             bArea, bFirstMoments, bSecondMoments, bProductMoments,
12047             rel_tol, abs_tol );
12048     rc = (mprc != 0);
12049   }
12050   return rc;
12051 }
12052 
12053 bool ON_Surface::VolumeMassProperties(
12054   ON_MassProperties& mp,
12055   bool bVolume,
12056   bool bFirstMoments,
12057   bool bSecondMoments,
12058   bool bProductMoments,
12059   ON_3dPoint base_point,
12060   double rel_tol,
12061   double abs_tol
12062   ) const
12063 {
12064   bool rc = false;
12065   // The _MassPropertiesSurface() function is provided by the Rhino SDK.
12066   if ( 0 != _MassPropertiesSurface )
12067   {
12068     int mprc = _MassPropertiesSurface(
12069             *this, NULL, 3, base_point, mp,
12070             bVolume, bFirstMoments, bSecondMoments, bProductMoments,
12071             rel_tol, abs_tol );
12072     rc = (mprc != 0);
12073   }
12074   return rc;
12075 }
12076 */
12077 
12078 
Dimension() const12079 int ON_BrepLoop::Dimension() const
12080 {
12081   return 2;
12082 }
12083 
GetBBox(double * boxmin,double * boxmax,ON_BOOL32 bGrowBox) const12084 ON_BOOL32 ON_BrepLoop::GetBBox(
12085         double* boxmin,
12086         double* boxmax,
12087         ON_BOOL32 bGrowBox
12088         ) const
12089 {
12090   bool rc = m_pbox.IsValid();
12091   if (rc)
12092   {
12093     ON_BoundingBox bbox;
12094     if ( bGrowBox )
12095     {
12096       bbox.m_min.x = boxmin[0];
12097       bbox.m_min.y = boxmin[1];
12098       bbox.m_min.z = 0.0;
12099       bbox.m_max.x = boxmax[0];
12100       bbox.m_max.y = boxmax[1];
12101       bbox.m_max.z = 0.0;
12102       bbox.Union(m_pbox);
12103       boxmin[0] = bbox.m_min.x;
12104       boxmin[1] = bbox.m_min.y;
12105       boxmax[0] = bbox.m_max.x;
12106       boxmax[1] = bbox.m_max.y;
12107     }
12108     else
12109     {
12110       boxmin[0] = m_pbox.m_min.x;
12111       boxmin[1] = m_pbox.m_min.y;
12112       boxmax[0] = m_pbox.m_max.x;
12113       boxmax[1] = m_pbox.m_max.y;
12114     }
12115   }
12116   return rc;
12117 }
12118 
Transform(const ON_Xform &)12119 ON_BOOL32 ON_BrepLoop::Transform( const ON_Xform& )
12120 {
12121   return false;
12122 }
12123 
ComponentIndex() const12124 ON_COMPONENT_INDEX ON_BrepVertex::ComponentIndex() const
12125 {
12126   ON_COMPONENT_INDEX ci(ON_COMPONENT_INDEX::brep_vertex,m_vertex_index);
12127   return ci;
12128 }
12129 
ComponentIndex() const12130 ON_COMPONENT_INDEX ON_BrepEdge::ComponentIndex() const
12131 {
12132   ON_COMPONENT_INDEX ci(ON_COMPONENT_INDEX::brep_edge,m_edge_index);
12133   return ci;
12134 }
12135 
ComponentIndex() const12136 ON_COMPONENT_INDEX ON_BrepFace::ComponentIndex() const
12137 {
12138   ON_COMPONENT_INDEX ci(ON_COMPONENT_INDEX::brep_face,m_face_index);
12139   return ci;
12140 }
12141 
12142 
ComponentIndex() const12143 ON_COMPONENT_INDEX ON_BrepTrim::ComponentIndex() const
12144 {
12145   ON_COMPONENT_INDEX ci(ON_COMPONENT_INDEX::brep_trim,m_trim_index);
12146   return ci;
12147 }
12148 
12149 
12150 
ComponentIndex() const12151 ON_COMPONENT_INDEX ON_BrepLoop::ComponentIndex() const
12152 {
12153   ON_COMPONENT_INDEX ci(ON_COMPONENT_INDEX::brep_loop,m_loop_index);
12154   return ci;
12155 }
12156 
12157