1 // Copyright (c) 1999-2014 OPEN CASCADE SAS
2 //
3 // This file is part of Open CASCADE Technology software library.
4 //
5 // This library is free software; you can redistribute it and/or modify it under
6 // the terms of the GNU Lesser General Public License version 2.1 as published
7 // by the Free Software Foundation, with special exception defined in the file
8 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
9 // distribution for complete text of the license and disclaimer of any warranty.
10 //
11 // Alternatively, this file may be used under the terms of Open CASCADE
12 // commercial license or contractual agreement.
13
14 //:q0 abv 12.03.99: mat-a.stp: protection against no pcurves in SwapSeam()
15 // abv 28.04.99 S4137: added method Add(WireData), method SetLast fixed
16 // abv 05.05.99 S4174: protection against INTERNAL/EXTERNAL edges
17
18 #include <BRep_Builder.hxx>
19 #include <BRep_Tool.hxx>
20 #include <BRepBuilderAPI_MakeWire.hxx>
21 #include <BRepTools_WireExplorer.hxx>
22 #include <Geom2d_Curve.hxx>
23 #include <ShapeExtend_WireData.hxx>
24 #include <Standard_Type.hxx>
25 #include <TopExp.hxx>
26 #include <TopoDS.hxx>
27 #include <TopoDS_Edge.hxx>
28 #include <TopoDS_Face.hxx>
29 #include <TopoDS_Iterator.hxx>
30 #include <TopoDS_Shape.hxx>
31 #include <TopoDS_Vertex.hxx>
32 #include <TopoDS_Wire.hxx>
33 #include <TopTools_IndexedMapOfShape.hxx>
34
IMPLEMENT_STANDARD_RTTIEXT(ShapeExtend_WireData,Standard_Transient)35 IMPLEMENT_STANDARD_RTTIEXT(ShapeExtend_WireData,Standard_Transient)
36
37 //=======================================================================
38 //function : ShapeExtend_WireData
39 //purpose :
40 //=======================================================================
41 ShapeExtend_WireData::ShapeExtend_WireData()
42 {
43 Clear();
44 }
45
46 //=======================================================================
47 //function : ShapeExtend_WireData
48 //purpose :
49 //=======================================================================
50
ShapeExtend_WireData(const TopoDS_Wire & wire,const Standard_Boolean chained,const Standard_Boolean theManifold)51 ShapeExtend_WireData::ShapeExtend_WireData (const TopoDS_Wire& wire,
52 const Standard_Boolean chained,
53 const Standard_Boolean theManifold)
54 {
55 Init ( wire, chained ,theManifold);
56 }
57
58 //=======================================================================
59 //function : Init
60 //purpose :
61 //=======================================================================
62
Init(const Handle (ShapeExtend_WireData)& other)63 void ShapeExtend_WireData::Init (const Handle(ShapeExtend_WireData)& other)
64 {
65 Clear();
66 Standard_Integer i, nb = other->NbEdges();
67 for (i = 1; i <= nb; i++) Add ( other->Edge(i) );
68 nb = other->NbNonManifoldEdges();
69 for (i = 1; i <= nb; i++) Add ( other->NonmanifoldEdge(i) );
70 myManifoldMode = other->ManifoldMode();
71 }
72
73 //=======================================================================
74 //function : Init
75 //purpose :
76 //=======================================================================
77
Init(const TopoDS_Wire & wire,const Standard_Boolean chained,const Standard_Boolean theManifold)78 Standard_Boolean ShapeExtend_WireData::Init (const TopoDS_Wire& wire,
79 const Standard_Boolean chained,
80 const Standard_Boolean theManifold)
81 {
82 Clear();
83 myManifoldMode = theManifold;
84 Standard_Boolean OK = Standard_True;
85 TopoDS_Vertex Vlast;
86 for ( TopoDS_Iterator it(wire); it.More(); it.Next() ) {
87 TopoDS_Edge E = TopoDS::Edge ( it.Value() );
88
89 // protect against INTERNAL/EXTERNAL edges
90 if ( (E.Orientation() != TopAbs_REVERSED &&
91 E.Orientation() != TopAbs_FORWARD)) {
92 myNonmanifoldEdges->Append(E);
93 continue;
94 }
95
96 TopoDS_Vertex V1, V2;
97 for ( TopoDS_Iterator itv(E); itv.More(); itv.Next() ) {
98 TopoDS_Vertex V = TopoDS::Vertex ( itv.Value() );
99 if ( V.Orientation() == TopAbs_FORWARD ) V1 = V;
100 else if ( V.Orientation() == TopAbs_REVERSED ) V2 = V;
101 }
102
103 // chainage? Si pas bon et chained False on repart sur WireExplorer
104 if ( ! Vlast.IsNull() && ! Vlast.IsSame ( V1 ) && theManifold) {
105 OK = Standard_False;
106 if ( ! chained ) break;
107 }
108 Vlast = V2;
109 if(wire.Orientation() == TopAbs_REVERSED)
110 myEdges->Prepend( E );
111 else
112 myEdges->Append ( E );
113 }
114
115 if(!myManifoldMode) {
116 Standard_Integer nb = myNonmanifoldEdges->Length();
117 Standard_Integer i =1;
118 for( ; i <= nb; i++)
119 myEdges->Append(myNonmanifoldEdges->Value(i));
120 myNonmanifoldEdges->Clear();
121 }
122 // refaire chainage ? Par WireExplorer
123 if ( OK || chained ) return OK;
124
125 Clear();
126 for ( BRepTools_WireExplorer we(wire); we.More(); we.Next() )
127 myEdges->Append ( TopoDS::Edge ( we.Current() ) );
128
129 return OK;
130 }
131
132 //=======================================================================
133 //function : Clear
134 //purpose :
135 //=======================================================================
136
Clear()137 void ShapeExtend_WireData::Clear()
138 {
139 myEdges = new TopTools_HSequenceOfShape();
140 myNonmanifoldEdges = new TopTools_HSequenceOfShape;
141 mySeamF = mySeamR = -1;
142 mySeams.Nullify();
143 myManifoldMode = Standard_True;
144 }
145
146 //=======================================================================
147 //function : ComputeSeams
148 //purpose :
149 //=======================================================================
150
ComputeSeams(const Standard_Boolean enforce)151 void ShapeExtend_WireData::ComputeSeams (const Standard_Boolean enforce)
152 {
153 if (mySeamF >= 0 && !enforce) return;
154
155 mySeams = new TColStd_HSequenceOfInteger();
156 mySeamF = mySeamR = 0;
157 TopoDS_Shape S;
158 Standard_Integer i, nb = NbEdges();
159 TopTools_IndexedMapOfShape ME;
160 Standard_Integer* SE = new Standard_Integer [nb+1];
161
162 // deux passes : d abord on mappe les Edges REVERSED
163 // Pour chacune, on note aussi son RANG dans la liste
164 for (i = 1; i <= nb; i ++) {
165 S = Edge(i);
166 if (S.Orientation() == TopAbs_REVERSED) {
167 Standard_Integer num = ME.Add (S);
168 SE[num] = i;
169 }
170 }
171
172 // ensuite on voit les Edges FORWARD qui y seraient deja -> on note leur n0
173 // c-a-d le n0 de la directe ET de la reverse
174 for (i = 1; i <= nb; i ++) {
175 S = Edge(i);
176 if (S.Orientation() == TopAbs_REVERSED) continue;
177 Standard_Integer num = ME.FindIndex (S);
178 if (num <= 0) continue;
179 if (mySeamF == 0) { mySeamF = i; mySeamR = SE[num]; }
180 else { mySeams->Append(i); mySeams->Append( SE[num] ); }
181 }
182
183 delete [] SE; // ne pas oublier !!
184 }
185
186 //=======================================================================
187 //function : SetLast
188 //purpose :
189 //=======================================================================
190
SetLast(const Standard_Integer num)191 void ShapeExtend_WireData::SetLast (const Standard_Integer num)
192 {
193 if (num == 0) return;
194 Standard_Integer i, nb = NbEdges();
195 for (i = nb; i > num; i--) {
196 TopoDS_Edge edge = TopoDS::Edge ( myEdges->Value(nb) );
197 myEdges->Remove (nb);
198 myEdges->InsertBefore (1, edge);
199 }
200 mySeamF = -1;
201 }
202
203 //=======================================================================
204 //function : SetDegeneratedLast
205 //purpose :
206 //=======================================================================
207
SetDegeneratedLast()208 void ShapeExtend_WireData::SetDegeneratedLast()
209 {
210 Standard_Integer i, nb = NbEdges();
211 for (i = 1; i <= nb; i ++) {
212 if ( BRep_Tool::Degenerated ( Edge(i) ) ) {
213 SetLast ( i );
214 return;
215 }
216 }
217 }
218
219 //=======================================================================
220 //function : Add
221 //purpose :
222 //=======================================================================
223
Add(const TopoDS_Edge & edge,const Standard_Integer atnum)224 void ShapeExtend_WireData::Add (const TopoDS_Edge& edge,
225 const Standard_Integer atnum)
226 {
227 if(edge.Orientation()!= TopAbs_REVERSED &&
228 edge.Orientation() != TopAbs_FORWARD && myManifoldMode) {
229 myNonmanifoldEdges->Append(edge);
230 return;
231 }
232
233 if (edge.IsNull()) return;
234 if (atnum == 0) {
235 myEdges->Append (edge);
236 }
237 else {
238 myEdges->InsertBefore (atnum,edge);
239 }
240 mySeamF = -1;
241 }
242
243 //=======================================================================
244 //function : Add
245 //purpose :
246 //=======================================================================
247
Add(const TopoDS_Wire & wire,const Standard_Integer atnum)248 void ShapeExtend_WireData::Add (const TopoDS_Wire& wire,
249 const Standard_Integer atnum)
250 {
251 if (wire.IsNull()) return;
252 Standard_Integer n = atnum;
253 TopTools_SequenceOfShape aNMEdges;
254 for (TopoDS_Iterator it(wire); it.More(); it.Next()) {
255 TopoDS_Edge edge = TopoDS::Edge (it.Value());
256 if(edge.Orientation()!= TopAbs_REVERSED &&
257 edge.Orientation() != TopAbs_FORWARD) {
258 if(myManifoldMode)
259 myNonmanifoldEdges->Append(edge);
260 else
261 aNMEdges.Append(edge);
262 continue;
263 }
264 if (n == 0) {
265 myEdges->Append (edge);
266 } else {
267 myEdges->InsertBefore (n,edge);
268 n++;
269 }
270 }
271 Standard_Integer i =1, nb = aNMEdges.Length();
272 for( ; i <= nb ; i++)
273 myEdges->Append(aNMEdges.Value(i));
274 mySeamF = -1;
275 }
276
277 //=======================================================================
278 //function : Add
279 //purpose :
280 //=======================================================================
281
Add(const Handle (ShapeExtend_WireData)& wire,const Standard_Integer atnum)282 void ShapeExtend_WireData::Add (const Handle(ShapeExtend_WireData) &wire,
283 const Standard_Integer atnum)
284 {
285 if ( wire.IsNull() ) return;
286 TopTools_SequenceOfShape aNMEdges;
287 Standard_Integer n = atnum;
288 Standard_Integer i=1;
289 for (; i <= wire->NbEdges(); i++ ) {
290 TopoDS_Edge aE = wire->Edge(i);
291 if(aE.Orientation() == TopAbs_INTERNAL ||
292 aE.Orientation() == TopAbs_EXTERNAL) {
293 aNMEdges.Append(aE);
294 continue;
295 }
296
297 if (n == 0 ) {
298 myEdges->Append ( wire->Edge(i) );
299 }
300 else {
301 myEdges->InsertBefore ( n, wire->Edge(i) );
302 n++;
303 }
304 }
305
306 //non-manifold edges for non-manifold wire should be added at end
307 for (i=1; i <=aNMEdges.Length(); i++)
308 myEdges->Append(aNMEdges.Value(i));
309
310 for (i=1; i <= wire->NbNonManifoldEdges(); i++) {
311 if( myManifoldMode)
312 myNonmanifoldEdges->Append(wire->NonmanifoldEdge(i));
313 else {
314 if (n == 0)
315 myEdges->Append ( wire->Edge(i) );
316
317 else {
318 myEdges->InsertBefore ( n, wire->Edge(i) );
319 n++;
320 }
321 }
322 }
323
324 mySeamF = -1;
325 }
326
327 //=======================================================================
328 //function : Add
329 //purpose :
330 //=======================================================================
331
Add(const TopoDS_Shape & shape,const Standard_Integer atnum)332 void ShapeExtend_WireData::Add (const TopoDS_Shape& shape,
333 const Standard_Integer atnum)
334 {
335 if (shape.ShapeType() == TopAbs_EDGE) Add (TopoDS::Edge (shape), atnum);
336 else if (shape.ShapeType() == TopAbs_WIRE) Add (TopoDS::Wire (shape), atnum);
337 }
338
339 //=======================================================================
340 //function : AddOriented
341 //purpose :
342 //=======================================================================
343
AddOriented(const TopoDS_Edge & edge,const Standard_Integer mode)344 void ShapeExtend_WireData::AddOriented (const TopoDS_Edge& edge,
345 const Standard_Integer mode)
346 {
347 if (edge.IsNull() || mode < 0) return;
348 TopoDS_Edge E = edge;
349 if (mode == 1 || mode == 3) E.Reverse();
350 Add (E, mode/2); // mode = 0,1 -> 0 mode = 2,3 -> 1
351 }
352
353 //=======================================================================
354 //function : AddOriented
355 //purpose :
356 //=======================================================================
357
AddOriented(const TopoDS_Wire & wire,const Standard_Integer mode)358 void ShapeExtend_WireData::AddOriented (const TopoDS_Wire& wire,
359 const Standard_Integer mode)
360 {
361 if (wire.IsNull() || mode < 0) return;
362 TopoDS_Wire W = wire;
363 if (mode == 1 || mode == 3) W.Reverse();
364 Add (W, mode/2); // mode = 0,1 -> 0 mode = 2,3 -> 1
365 }
366
AddOriented(const TopoDS_Shape & shape,const Standard_Integer mode)367 void ShapeExtend_WireData::AddOriented (const TopoDS_Shape& shape,
368 const Standard_Integer mode)
369 {
370 if (shape.ShapeType() == TopAbs_EDGE) AddOriented (TopoDS::Edge (shape), mode);
371 else if (shape.ShapeType() == TopAbs_WIRE) AddOriented (TopoDS::Wire (shape), mode);
372 }
373
374 //=======================================================================
375 //function : Remove
376 //purpose :
377 //=======================================================================
378
Remove(const Standard_Integer num)379 void ShapeExtend_WireData::Remove (const Standard_Integer num)
380 {
381
382 myEdges->Remove ( num > 0 ? num : NbEdges() );
383
384 mySeamF = -1;
385 }
386
387 //=======================================================================
388 //function : Set
389 //purpose :
390 //=======================================================================
391
Set(const TopoDS_Edge & edge,const Standard_Integer num)392 void ShapeExtend_WireData::Set (const TopoDS_Edge& edge,
393 const Standard_Integer num)
394 {
395 if(edge.Orientation()!= TopAbs_REVERSED &&
396 edge.Orientation() != TopAbs_FORWARD && myManifoldMode) {
397 if(num <= myNonmanifoldEdges->Length())
398 myNonmanifoldEdges->SetValue(num,edge);
399 else
400 myNonmanifoldEdges->Append(edge);
401 }
402
403 else
404 myEdges->SetValue ( ( num > 0 ? num : NbEdges() ), edge);
405 mySeamF = -1;
406 }
407
408 //=======================================================================
409 //function : Reverse
410 //purpose : reverse order of edges in the wire
411 //=======================================================================
412
Reverse()413 void ShapeExtend_WireData::Reverse ()
414 {
415 Standard_Integer i, nb = NbEdges();
416
417 // inverser les edges + les permuter pour inverser le wire
418 for (i = 1; i <= nb/2; i ++) {
419 TopoDS_Shape S1 = myEdges->Value(i); S1.Reverse();
420 TopoDS_Shape S2 = myEdges->Value(nb+1-i); S2.Reverse();
421 myEdges->SetValue (i, S2);
422 myEdges->SetValue (nb+1-i, S1);
423 }
424 // nb d edges impair : inverser aussi l edge du milieu (rang inchange)
425 if ( nb % 2 ) { // test impair
426 i = (nb+1)/2;
427 TopoDS_Shape SI = myEdges->Value(i); SI.Reverse();
428 myEdges->SetValue (i, SI);
429 }
430 mySeamF = -1;
431 }
432
433 //=======================================================================
434 //function : Reverse
435 //purpose :
436 //=======================================================================
437
438 // Fonction auxiliaire SwapSeam pour inverser
SwapSeam(const TopoDS_Shape & S,const TopoDS_Face & F)439 static void SwapSeam (const TopoDS_Shape& S, const TopoDS_Face& F)
440 {
441 TopoDS_Edge E = TopoDS::Edge (S);
442 if ( E.IsNull() || F.IsNull() ) return;
443 if ( E.Orientation() == TopAbs_REVERSED ) return; // ne le faire qu une fois !
444
445 TopoDS_Face theface = F;
446 theface.Orientation(TopAbs_FORWARD);
447
448 //:S4136 Standard_Real Tol = BRep_Tool::Tolerance(theface);
449 Handle(Geom2d_Curve) c2df,c2dr;
450 Standard_Real uff,ulf,ufr,ulr;
451
452 // d abord FWD puis REV
453 c2df = BRep_Tool::CurveOnSurface (E,theface,uff,ulf);
454 E.Orientation (TopAbs_REVERSED);
455 c2dr = BRep_Tool::CurveOnSurface (E,theface,ufr,ulr);
456 if ( c2df.IsNull() || c2dr.IsNull() ) return; //:q0
457 // On permute
458 E.Orientation (TopAbs_FORWARD);
459 BRep_Builder B;
460 B.UpdateEdge (E,c2dr,c2df,theface,0.); //:S4136: Tol
461 B.Range (E,theface,uff,ulf);
462 }
463
Reverse(const TopoDS_Face & face)464 void ShapeExtend_WireData::Reverse (const TopoDS_Face &face)
465 {
466 Reverse();
467 if ( face.IsNull() ) return;
468
469 // ATTENTION aux coutures
470 // Une edge de couture est presente deux fois, FWD et REV
471 // Les inverser revient a permuter leur role ... donc ne rien faire
472 // Il faut donc aussi permuter leurs pcurves
473 ComputeSeams(Standard_True);
474 if (mySeamF > 0) SwapSeam (myEdges->Value(mySeamF),face);
475 if (mySeamR > 0) SwapSeam (myEdges->Value(mySeamR),face);
476 Standard_Integer nb = (mySeams.IsNull() ? 0 : mySeams->Length());
477 for ( Standard_Integer i = 1; i <= nb; i ++) {
478 SwapSeam (myEdges->Value(mySeams->Value(i)),face);
479 }
480 mySeamF = -1;
481 }
482
483 //=======================================================================
484 //function : NbEdges
485 //purpose :
486 //=======================================================================
487
NbEdges() const488 Standard_Integer ShapeExtend_WireData::NbEdges() const
489 {
490 return myEdges->Length();
491 }
492
493 //=======================================================================
494 //function : Edge
495 //purpose :
496 //=======================================================================
497
Edge(const Standard_Integer num) const498 TopoDS_Edge ShapeExtend_WireData::Edge (const Standard_Integer num) const
499 {
500 if (num < 0) {
501 TopoDS_Edge E = Edge (-num);
502 E.Reverse();
503 return E;
504 }
505 return TopoDS::Edge ( myEdges->Value ( num ) );
506 }
507 //=======================================================================
508 //function : NbNonManifoldEdges
509 //purpose :
510 //=======================================================================
511
NbNonManifoldEdges() const512 Standard_Integer ShapeExtend_WireData::NbNonManifoldEdges() const
513 {
514 return myNonmanifoldEdges->Length();
515 }
516
517 //=======================================================================
518 //function : Edge
519 //purpose :
520 //=======================================================================
521
NonmanifoldEdge(const Standard_Integer num) const522 TopoDS_Edge ShapeExtend_WireData::NonmanifoldEdge (const Standard_Integer num) const
523 {
524 TopoDS_Edge E;
525 if (num < 0)
526 return E;
527
528 return TopoDS::Edge ( myNonmanifoldEdges->Value ( num ) );
529 }
530 //=======================================================================
531 //function : Index
532 //purpose :
533 //=======================================================================
534
Index(const TopoDS_Edge & edge)535 Standard_Integer ShapeExtend_WireData::Index (const TopoDS_Edge& edge)
536 {
537 for (Standard_Integer i = 1; i <= NbEdges(); i++)
538 if (Edge (i).IsSame (edge) && (Edge(i).Orientation() == edge.Orientation() || !IsSeam(i)))
539 return i;
540 return 0;
541 }
542
543 //=======================================================================
544 //function : IsSeam
545 //purpose :
546 //=======================================================================
547
IsSeam(const Standard_Integer num)548 Standard_Boolean ShapeExtend_WireData::IsSeam (const Standard_Integer num)
549 {
550 if (mySeamF < 0) ComputeSeams();
551 if (mySeamF == 0) return Standard_False;
552
553 if (num == mySeamF || num == mySeamR) return Standard_True;
554 // Pas suffisant : on regarde dans la liste
555 Standard_Integer i, nb = mySeams->Length();
556 for (i = 1; i <= nb; i ++) {
557 if (num == mySeams->Value(i)) return Standard_True;
558 }
559 return Standard_False;
560 }
561
562 //=======================================================================
563 //function : Make
564 //purpose :
565 //=======================================================================
566
Wire() const567 TopoDS_Wire ShapeExtend_WireData::Wire() const
568 {
569 TopoDS_Wire W;
570 BRep_Builder B;
571 B.MakeWire (W);
572 Standard_Integer i, nb = NbEdges();
573 Standard_Boolean ismanifold = Standard_True;
574 for (i = 1; i <= nb; i ++) {
575 TopoDS_Edge aE = Edge(i);
576 if (aE.Orientation() != TopAbs_FORWARD &&
577 aE.Orientation() != TopAbs_REVERSED)
578 ismanifold = Standard_False;
579 B.Add (W, aE);
580 }
581 if(ismanifold) {
582 TopoDS_Vertex vf, vl;
583 TopExp::Vertices (W, vf, vl);
584 if (!vf.IsNull() && !vl.IsNull() && vf.IsSame (vl)) W.Closed (Standard_True);
585 }
586 if(myManifoldMode) {
587 nb = NbNonManifoldEdges();
588 for (i = 1; i <= nb; i ++) B.Add (W, NonmanifoldEdge(i));
589 }
590 return W;
591 }
592
593 //=======================================================================
594 //function : APIMake
595 //purpose :
596 //=======================================================================
597
WireAPIMake() const598 TopoDS_Wire ShapeExtend_WireData::WireAPIMake() const
599 {
600 TopoDS_Wire W;
601 BRepBuilderAPI_MakeWire MW;
602 Standard_Integer i, nb = NbEdges();
603 for (i = 1; i <= nb; i ++) MW.Add (Edge(i));
604 if(myManifoldMode) {
605 nb = NbNonManifoldEdges();
606 for (i = 1; i <= nb; i ++) MW.Add (NonmanifoldEdge(i));
607 }
608 if ( MW.IsDone() ) W = MW.Wire();
609 return W;
610 }
611
612 //=======================================================================
613 //function : NonmanifoldEdges
614 //purpose :
615 //=======================================================================
Handle(TopTools_HSequenceOfShape)616 Handle(TopTools_HSequenceOfShape) ShapeExtend_WireData::NonmanifoldEdges() const
617 {
618 return myNonmanifoldEdges;
619 }
620
621 //=======================================================================
622 //function : ManifoldMode
623 //purpose :
624 //=======================================================================
ManifoldMode()625 Standard_Boolean& ShapeExtend_WireData::ManifoldMode()
626 {
627 return myManifoldMode;
628 }
629