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