1 // Copyright (c) 1999-2014 OPEN CASCADE SAS
3 // This file is part of Open CASCADE Technology software library.
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.
11 // Alternatively, this file may be used under the terms of Open CASCADE
12 // commercial license or contractual agreement.
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
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>
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>
35 IMPLEMENT_STANDARD_RTTIEXT(ShapeExtend_WireData,Standard_Transient)
37 //=======================================================================
38 //function : ShapeExtend_WireData
40 //=======================================================================
41 ShapeExtend_WireData::ShapeExtend_WireData()
46 //=======================================================================
47 //function : ShapeExtend_WireData
49 //=======================================================================
51 ShapeExtend_WireData::ShapeExtend_WireData (const TopoDS_Wire& wire,
52 const Standard_Boolean chained,
53 const Standard_Boolean theManifold)
55 Init ( wire, chained ,theManifold);
58 //=======================================================================
61 //=======================================================================
63 void ShapeExtend_WireData::Init (const Handle(ShapeExtend_WireData)& other)
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();
73 //=======================================================================
76 //=======================================================================
78 Standard_Boolean ShapeExtend_WireData::Init (const TopoDS_Wire& wire,
79 const Standard_Boolean chained,
80 const Standard_Boolean theManifold)
83 myManifoldMode = theManifold;
84 Standard_Boolean OK = Standard_True;
86 for ( TopoDS_Iterator it(wire); it.More(); it.Next() ) {
87 TopoDS_Edge E = TopoDS::Edge ( it.Value() );
89 // protect against INTERNAL/EXTERNAL edges
90 if ( (E.Orientation() != TopAbs_REVERSED &&
91 E.Orientation() != TopAbs_FORWARD)) {
92 myNonmanifoldEdges->Append(E);
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;
103 // chainage? Si pas bon et chained False on repart sur WireExplorer
104 if ( ! Vlast.IsNull() && ! Vlast.IsSame ( V1 ) && theManifold) {
106 if ( ! chained ) break;
109 if(wire.Orientation() == TopAbs_REVERSED)
110 myEdges->Prepend( E );
112 myEdges->Append ( E );
115 if(!myManifoldMode) {
116 Standard_Integer nb = myNonmanifoldEdges->Length();
117 Standard_Integer i =1;
119 myEdges->Append(myNonmanifoldEdges->Value(i));
120 myNonmanifoldEdges->Clear();
122 // refaire chainage ? Par WireExplorer
123 if ( OK || chained ) return OK;
126 for ( BRepTools_WireExplorer we(wire); we.More(); we.Next() )
127 myEdges->Append ( TopoDS::Edge ( we.Current() ) );
132 //=======================================================================
135 //=======================================================================
137 void ShapeExtend_WireData::Clear()
139 myEdges = new TopTools_HSequenceOfShape();
140 myNonmanifoldEdges = new TopTools_HSequenceOfShape;
141 mySeamF = mySeamR = -1;
143 myManifoldMode = Standard_True;
146 //=======================================================================
147 //function : ComputeSeams
149 //=======================================================================
151 void ShapeExtend_WireData::ComputeSeams (const Standard_Boolean enforce)
153 if (mySeamF >= 0 && !enforce) return;
155 mySeams = new TColStd_HSequenceOfInteger();
156 mySeamF = mySeamR = 0;
158 Standard_Integer i, nb = NbEdges();
159 TopTools_IndexedMapOfShape ME;
160 Standard_Integer* SE = new Standard_Integer [nb+1];
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 ++) {
166 if (S.Orientation() == TopAbs_REVERSED) {
167 Standard_Integer num = ME.Add (S);
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 ++) {
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] ); }
183 delete [] SE; // ne pas oublier !!
186 //=======================================================================
189 //=======================================================================
191 void ShapeExtend_WireData::SetLast (const Standard_Integer num)
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);
203 //=======================================================================
204 //function : SetDegeneratedLast
206 //=======================================================================
208 void ShapeExtend_WireData::SetDegeneratedLast()
210 Standard_Integer i, nb = NbEdges();
211 for (i = 1; i <= nb; i ++) {
212 if ( BRep_Tool::Degenerated ( Edge(i) ) ) {
219 //=======================================================================
222 //=======================================================================
224 void ShapeExtend_WireData::Add (const TopoDS_Edge& edge,
225 const Standard_Integer atnum)
227 if(edge.Orientation()!= TopAbs_REVERSED &&
228 edge.Orientation() != TopAbs_FORWARD && myManifoldMode) {
229 myNonmanifoldEdges->Append(edge);
233 if (edge.IsNull()) return;
235 myEdges->Append (edge);
238 myEdges->InsertBefore (atnum,edge);
243 //=======================================================================
246 //=======================================================================
248 void ShapeExtend_WireData::Add (const TopoDS_Wire& wire,
249 const Standard_Integer atnum)
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) {
259 myNonmanifoldEdges->Append(edge);
261 aNMEdges.Append(edge);
265 myEdges->Append (edge);
267 myEdges->InsertBefore (n,edge);
271 Standard_Integer i =1, nb = aNMEdges.Length();
272 for( ; i <= nb ; i++)
273 myEdges->Append(aNMEdges.Value(i));
277 //=======================================================================
280 //=======================================================================
282 void ShapeExtend_WireData::Add (const Handle(ShapeExtend_WireData) &wire,
283 const Standard_Integer atnum)
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) {
298 myEdges->Append ( wire->Edge(i) );
301 myEdges->InsertBefore ( n, wire->Edge(i) );
306 //non-manifold edges for non-manifold wire shoud be added at end
307 for (i=1; i <=aNMEdges.Length(); i++)
308 myEdges->Append(aNMEdges.Value(i));
310 for (i=1; i <= wire->NbNonManifoldEdges(); i++) {
312 myNonmanifoldEdges->Append(wire->NonmanifoldEdge(i));
315 myEdges->Append ( wire->Edge(i) );
318 myEdges->InsertBefore ( n, wire->Edge(i) );
327 //=======================================================================
330 //=======================================================================
332 void ShapeExtend_WireData::Add (const TopoDS_Shape& shape,
333 const Standard_Integer atnum)
335 if (shape.ShapeType() == TopAbs_EDGE) Add (TopoDS::Edge (shape), atnum);
336 else if (shape.ShapeType() == TopAbs_WIRE) Add (TopoDS::Wire (shape), atnum);
339 //=======================================================================
340 //function : AddOriented
342 //=======================================================================
344 void ShapeExtend_WireData::AddOriented (const TopoDS_Edge& edge,
345 const Standard_Integer mode)
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
353 //=======================================================================
354 //function : AddOriented
356 //=======================================================================
358 void ShapeExtend_WireData::AddOriented (const TopoDS_Wire& wire,
359 const Standard_Integer mode)
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
367 void ShapeExtend_WireData::AddOriented (const TopoDS_Shape& shape,
368 const Standard_Integer mode)
370 if (shape.ShapeType() == TopAbs_EDGE) AddOriented (TopoDS::Edge (shape), mode);
371 else if (shape.ShapeType() == TopAbs_WIRE) AddOriented (TopoDS::Wire (shape), mode);
374 //=======================================================================
377 //=======================================================================
379 void ShapeExtend_WireData::Remove (const Standard_Integer num)
382 myEdges->Remove ( num > 0 ? num : NbEdges() );
387 //=======================================================================
390 //=======================================================================
392 void ShapeExtend_WireData::Set (const TopoDS_Edge& edge,
393 const Standard_Integer num)
395 if(edge.Orientation()!= TopAbs_REVERSED &&
396 edge.Orientation() != TopAbs_FORWARD && myManifoldMode) {
397 if(num <= myNonmanifoldEdges->Length())
398 myNonmanifoldEdges->SetValue(num,edge);
400 myNonmanifoldEdges->Append(edge);
404 myEdges->SetValue ( ( num > 0 ? num : NbEdges() ), edge);
408 //=======================================================================
410 //purpose : reverse order of edges in the wire
411 //=======================================================================
413 void ShapeExtend_WireData::Reverse ()
415 Standard_Integer i, nb = NbEdges();
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);
424 // nb d edges impair : inverser aussi l edge du milieu (rang inchange)
425 if ( nb % 2 ) { // test impair
427 TopoDS_Shape SI = myEdges->Value(i); SI.Reverse();
428 myEdges->SetValue (i, SI);
433 //=======================================================================
436 //=======================================================================
438 // Fonction auxiliaire SwapSeam pour inverser
439 static void SwapSeam (const TopoDS_Shape& S, const TopoDS_Face& F)
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 !
445 TopoDS_Face theface = F;
446 theface.Orientation(TopAbs_FORWARD);
448 //:S4136 Standard_Real Tol = BRep_Tool::Tolerance(theface);
449 Handle(Geom2d_Curve) c2df,c2dr;
450 Standard_Real uff,ulf,ufr,ulr;
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
458 E.Orientation (TopAbs_FORWARD);
460 B.UpdateEdge (E,c2dr,c2df,theface,0.); //:S4136: Tol
461 B.Range (E,theface,uff,ulf);
464 void ShapeExtend_WireData::Reverse (const TopoDS_Face &face)
467 if ( face.IsNull() ) return;
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);
483 //=======================================================================
486 //=======================================================================
488 Standard_Integer ShapeExtend_WireData::NbEdges() const
490 return myEdges->Length();
493 //=======================================================================
496 //=======================================================================
498 TopoDS_Edge ShapeExtend_WireData::Edge (const Standard_Integer num) const
501 TopoDS_Edge E = Edge (-num);
505 return TopoDS::Edge ( myEdges->Value ( num ) );
507 //=======================================================================
508 //function : NbNonManifoldEdges
510 //=======================================================================
512 Standard_Integer ShapeExtend_WireData::NbNonManifoldEdges() const
514 return myNonmanifoldEdges->Length();
517 //=======================================================================
520 //=======================================================================
522 TopoDS_Edge ShapeExtend_WireData::NonmanifoldEdge (const Standard_Integer num) const
528 return TopoDS::Edge ( myNonmanifoldEdges->Value ( num ) );
530 //=======================================================================
533 //=======================================================================
535 Standard_Integer ShapeExtend_WireData::Index (const TopoDS_Edge& edge)
537 for (Standard_Integer i = 1; i <= NbEdges(); i++)
538 if (Edge (i).IsSame (edge) && (Edge(i).Orientation() == edge.Orientation() || !IsSeam(i)))
543 //=======================================================================
546 //=======================================================================
548 Standard_Boolean ShapeExtend_WireData::IsSeam (const Standard_Integer num)
550 if (mySeamF < 0) ComputeSeams();
551 if (mySeamF == 0) return Standard_False;
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;
559 return Standard_False;
562 //=======================================================================
565 //=======================================================================
567 TopoDS_Wire ShapeExtend_WireData::Wire() const
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;
582 TopoDS_Vertex vf, vl;
583 TopExp::Vertices (W, vf, vl);
584 if (!vf.IsNull() && !vl.IsNull() && vf.IsSame (vl)) W.Closed (Standard_True);
587 nb = NbNonManifoldEdges();
588 for (i = 1; i <= nb; i ++) B.Add (W, NonmanifoldEdge(i));
593 //=======================================================================
596 //=======================================================================
598 TopoDS_Wire ShapeExtend_WireData::WireAPIMake() const
601 BRepBuilderAPI_MakeWire MW;
602 Standard_Integer i, nb = NbEdges();
603 for (i = 1; i <= nb; i ++) MW.Add (Edge(i));
605 nb = NbNonManifoldEdges();
606 for (i = 1; i <= nb; i ++) MW.Add (NonmanifoldEdge(i));
608 if ( MW.IsDone() ) W = MW.Wire();
612 //=======================================================================
613 //function : NonmanifoldEdges
615 //=======================================================================
616 Handle(TopTools_HSequenceOfShape) ShapeExtend_WireData::NonmanifoldEdges() const
618 return myNonmanifoldEdges;
621 //=======================================================================
622 //function : ManifoldMode
624 //=======================================================================
625 Standard_Boolean& ShapeExtend_WireData::ManifoldMode()
627 return myManifoldMode;