1 // Created on: 1994-12-23
2 // Created by: Remi LEQUETTE
3 // Copyright (c) 1994-1999 Matra Datavision
4 // Copyright (c) 1999-2014 OPEN CASCADE SAS
6 // This file is part of Open CASCADE Technology software library.
8 // This library is free software; you can redistribute it and/or modify it under
9 // the terms of the GNU Lesser General Public License version 2.1 as published
10 // by the Free Software Foundation, with special exception defined in the file
11 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
12 // distribution for complete text of the license and disclaimer of any warranty.
14 // Alternatively, this file may be used under the terms of Open CASCADE
15 // commercial license or contractual agreement.
18 #include <BRep_Builder.hxx>
19 #include <BRep_Tool.hxx>
20 #include <BRepTools_Quilt.hxx>
21 #include <Geom2d_Curve.hxx>
22 #include <Standard_NoSuchObject.hxx>
23 #include <TopExp_Explorer.hxx>
25 #include <TopoDS_Compound.hxx>
26 #include <TopoDS_Edge.hxx>
27 #include <TopoDS_Face.hxx>
28 #include <TopoDS_Iterator.hxx>
29 #include <TopoDS_Shape.hxx>
30 #include <TopoDS_Shell.hxx>
31 #include <TopoDS_Vertex.hxx>
32 #include <TopoDS_Wire.hxx>
33 #include <TopTools_DataMapIteratorOfDataMapOfShapeShape.hxx>
34 #include <TopTools_DataMapOfShapeShape.hxx>
35 #include <TopTools_IndexedDataMapOfShapeShape.hxx>
36 #include <TopTools_ListOfShape.hxx>
37 #include <TopTools_MapIteratorOfMapOfShape.hxx>
38 #include <TopTools_MapOfShape.hxx>
40 //=======================================================================
41 //function : BRepTools_Quilt
43 //=======================================================================
44 BRepTools_Quilt::BRepTools_Quilt() : hasCopy(Standard_False)
48 //=======================================================================
51 //=======================================================================
52 static Standard_Boolean NeedCopied(const TopoDS_Shape& theShape,const TopTools_IndexedDataMapOfShapeShape& myBounds)
54 // test if the shape must be copied
55 // i.e. it contains a bound subshape
56 Standard_Boolean IsCopied = Standard_False;
57 TopoDS_Iterator itv(theShape) ;
58 for ( ; itv.More(); itv.Next()) {
59 if (myBounds.Contains(itv.Value())) {
60 IsCopied = Standard_True;
66 static void CopyShape(const TopoDS_Edge& E,TopTools_IndexedDataMapOfShapeShape& myBounds)
70 NE.Orientation(TopAbs_FORWARD);
74 itv.Initialize(E,Standard_False) ; //TCollection_DataMap
75 for ( ; itv.More(); itv.Next()) {
76 const TopoDS_Shape& V = itv.Value();
77 if (myBounds.Contains(V)) {
78 B.Add(NE,myBounds.FindFromKey(V).Oriented(V.Orientation()));
86 BRep_Tool::Range(E,f,l);
88 myBounds.Add(E,NE.Oriented(TopAbs_FORWARD));
90 /*static void CopyShape(const TopoDS_Wire& W,TopTools_DataMapOfShapeShape& myBounds)
94 TopoDS_Iterator ite(W,Standard_False);
95 for ( ; ite.More(); ite.Next()){
96 const TopoDS_Edge& E = TopoDS::Edge(ite.Value());
97 TopAbs_Orientation OE = E.Orientation();
98 if (myBounds.IsBound(E)) {
99 TopoDS_Edge& NE = TopoDS::Edge(myBounds(E));
100 B.Add(NW,NE.Oriented(OE));
105 NW.Orientation(W.Orientation());
108 void BRepTools_Quilt::Add(const TopoDS_Shape& S)
110 //cout <<" Version of sewing with free edges"<<endl;
111 // Binds all the faces of S
112 // - to the face itself if it is not copied
113 // - to the copy if it is copied
114 if(myBounds.Contains(S)) return;
116 for (TopExp_Explorer wex(S,TopAbs_WIRE,TopAbs_FACE); wex.More(); wex.Next())
117 myBounds.Add(wex.Current(),wex.Current());
119 for (TopExp_Explorer eex(S,TopAbs_EDGE,TopAbs_WIRE); eex.More(); eex.Next())
120 myBounds.Add(eex.Current(),eex.Current());
122 for (TopExp_Explorer vex(S,TopAbs_VERTEX,TopAbs_EDGE); vex.More(); vex.Next())
123 myBounds.Add(vex.Current(),vex.Current());
126 for (TopExp_Explorer fex(S,TopAbs_FACE); fex.More(); fex.Next()) {
128 // explore the edges of the face and try to copy them
129 // if one edge is bound the face must be copied
131 Standard_Boolean copyFace = Standard_False;
132 const TopoDS_Face& F = TopoDS::Face(fex.Current());
134 if (hasCopy) { // if their is no binding, do not test for copy
136 for (TopExp_Explorer fed(F,TopAbs_EDGE); fed.More(); fed.Next()) {
138 if (myBounds.Contains(fed.Current())) {
139 copyFace = Standard_True;
142 // test if the edge must be copied
143 // i.e. it contains a bound vertex
145 Standard_Boolean copyEdge = NeedCopied(fed.Current(),myBounds);
146 //Standard_Boolean copyEdge = Standard_False;
147 const TopoDS_Edge& E = TopoDS::Edge(fed.Current());
149 // TopoDS_Iterator itv(E) ;
150 // for ( ; itv.More(); itv.Next()) {
151 // if (myBounds.IsBound(itv.Value())) {
152 // copyEdge = Standard_True;
161 copyFace = Standard_True;
162 CopyShape(E,myBounds);
163 //TopoDS_Edge NE = E; //gka version for free edges
166 //NE.Orientation(TopAbs_FORWARD);
168 //itv.Initialize(E,Standard_False) ;
169 //for ( ; itv.More(); itv.Next()) {
170 //const TopoDS_Shape& V = itv.Value();
171 //if (myBounds.IsBound(V)) {
172 // B.Add(NE,myBounds(V).Oriented(V.Orientation()));
180 //BRep_Tool::Range(E,f,l);
183 //myBounds.Bind(E,NE.Oriented(TopAbs_FORWARD));
189 // NF will be the copy of F or F itself
197 NF.Orientation(TopAbs_FORWARD);
199 for (TopoDS_Iterator itw(F,Standard_False); itw.More(); itw.Next()) {
200 const TopoDS_Wire& W = TopoDS::Wire(itw.Value());
204 TopoDS_Iterator ite(W,Standard_False);
205 Standard_Real UFirst,ULast;
207 // Reconstruction des wires.
209 for ( ; ite.More(); ite.Next()){
210 const TopoDS_Edge& E = TopoDS::Edge(ite.Value());
211 TopAbs_Orientation OE = E.Orientation();
212 if (myBounds.Contains(E)) {
213 const TopoDS_Edge& NE = TopoDS::Edge(myBounds.FindFromKey(E));
215 if (NE.Orientation() == TopAbs_FORWARD) {
217 BRep_Tool::CurveOnSurface(E,F,UFirst,ULast),
218 F,BRep_Tool::Tolerance(E));
221 // Si NE est REVERSED
222 // => les curve3d n ont pas la meme orientation.
223 // ( C est une convention cf BRepTools_Quilt.cdl. et la methode
225 // => la PCurve de E sur F doit etre inversee.
227 OE = TopAbs::Reverse(OE);
228 Handle(Geom2d_Curve) CE =
229 BRep_Tool::CurveOnSurface(E,F,UFirst,ULast);
230 Handle(Geom2d_Curve) NCE = CE->Reversed();
231 B.UpdateEdge(NE,NCE,F,BRep_Tool::Tolerance(E));
232 Standard_Real tmp = UFirst;
233 UFirst = CE->ReversedParameter(ULast);
234 ULast = CE->ReversedParameter(tmp);
237 B.Range(NE,F,UFirst,ULast);
239 B.Add(NW,NE.Oriented(OE));
245 NW.Orientation(W.Orientation());
248 NF.Orientation(F.Orientation());
251 // binds the face to itself or its copy
257 //=======================================================================
260 //=======================================================================
262 void BRepTools_Quilt::Bind(const TopoDS_Vertex& Vold,
263 const TopoDS_Vertex& Vnew)
265 if (!myBounds.Contains(Vold)) {
266 myBounds.Add(Vold,Vnew);
270 //=======================================================================
273 //=======================================================================
275 void BRepTools_Quilt::Bind(const TopoDS_Edge& Eold, const TopoDS_Edge& Enew)
277 if (!myBounds.Contains(Eold)) {
278 TopoDS_Edge ENew = Enew;
279 if (IsCopied(Enew)) {
280 ENew = TopoDS::Edge(Copy(Enew));
281 ENew.Orientation(Enew.Orientation());
284 if (Eold.Orientation() != ENew.Orientation()) {
285 myBounds.Add(Eold.Oriented(TopAbs_FORWARD),
286 ENew.Oriented(TopAbs_REVERSED));
289 myBounds.Add(Eold.Oriented(TopAbs_FORWARD),
290 ENew.Oriented(TopAbs_FORWARD));
292 // if new binding bind also the vertices
293 TopoDS_Iterator itold(Eold);
294 while (itold.More()) {
295 if (!myBounds.Contains(itold.Value())) {
296 // find the vertex of Enew with same orientation
297 TopAbs_Orientation anOrien = itold.Value().Orientation();
298 TopoDS_Iterator itnew(ENew);
299 while (itnew.More()) {
300 if (itnew.Value().Orientation() == anOrien) {
301 TopoDS_Vertex VNew = TopoDS::Vertex(itnew.Value());
302 if (IsCopied(VNew)) {
303 // if VNew has been copied take the copy
304 VNew = TopoDS::Vertex(Copy(VNew));
306 myBounds.Add(itold.Value(),VNew);
314 hasCopy = Standard_True;
318 //=======================================================================
321 //=======================================================================
323 Standard_Boolean BRepTools_Quilt::IsCopied(const TopoDS_Shape& S) const
325 if (myBounds.Contains(S)) {
326 return !S.IsSame(myBounds.FindFromKey(S));
329 return Standard_False;
332 //=======================================================================
335 //=======================================================================
337 const TopoDS_Shape& BRepTools_Quilt::Copy(const TopoDS_Shape& S) const
339 Standard_NoSuchObject_Raise_if(!IsCopied(S),"BRepTools_Quilt::Copy");
340 return myBounds.FindFromKey(S);
343 //=======================================================================
346 //=======================================================================
348 TopoDS_Shape BRepTools_Quilt::Shells() const
350 // Outline of the algorithm
352 // In the map M we bind the free edges to their shells
353 // We explore all the faces in myBounds
354 // For each one we search the edges in the map and either :
356 // - Start a new shell if no edge is a free edge.
357 // - Add the face to an existing shell
358 // - Connect other shells if the face touch more than one shell
360 // In the Map M the Shell is bound withe the relative orientation of E
362 // In the map MF we binb the face to its shell.
363 // In the Map MF the Shell is bound with the relative orientation of F
366 TopTools_DataMapOfShapeShape M, MF;
368 TopoDS_Compound result;
370 B.MakeCompound(result);
372 TopTools_MapOfShape MapOtherShape; //gka
373 TopTools_MapOfShape EdgesFaces;
375 // loop on the face in myBounds
376 //TopTools_DataMapIteratorOfDataMapOfShapeShape it(myBounds);
379 for(Standard_Integer ii =1; ii <= myBounds.Extent(); ii++) {
380 const TopoDS_Shape& Shape = myBounds.FindFromIndex(ii); //it.Value();
381 if (Shape.ShapeType() == TopAbs_FACE) {
382 for(TopExp_Explorer aExpEdg(Shape,TopAbs_EDGE); aExpEdg.More(); aExpEdg.Next()) //gka
383 EdgesFaces.Add(aExpEdg.Current());
386 TopAbs_Orientation NewO;
388 TopExp_Explorer itf1( Shape,TopAbs_EDGE);
389 for ( ; itf1.More(); itf1.Next()) {
390 const TopoDS_Shape& E = itf1.Current();
392 SH = TopoDS::Shell(M(E));
393 if (SH.Orientation() == E.Orientation())
394 NewO = TopAbs::Reverse(Shape.Orientation());
396 NewO = Shape.Orientation();
398 MF.Bind (Shape,SH.Oriented(NewO));
404 // Create a new shell, closed. Add it to the result.
406 SH.Closed(Standard_True);
408 MF.Bind (Shape,SH.Oriented(Shape.Orientation()));
412 // Add the face to the shell
413 SH.Free(Standard_True);
414 // B.Add(SH.Oriented(TopAbs_FORWARD), F .Oriented(MF(F).Orientation()));
415 TopoDS_Shape arefShape = SH.Oriented(TopAbs_FORWARD) ;
416 B.Add( arefShape , Shape.Oriented(MF(Shape).Orientation()));
418 TopExp_Explorer itf(Shape.Oriented(TopAbs_FORWARD),TopAbs_EDGE);
420 for ( ;itf.More(); itf.Next()) {
421 const TopoDS_Edge& E = TopoDS::Edge(itf.Current());
424 const TopoDS_Shape oldShell = M(E);
425 if (!oldShell.IsSame(SH)) {
426 // Fuse the old shell with the new one
427 // Compare the orientation of E in SH and in oldshell.
428 TopAbs_Orientation anOrien = E.Orientation();
429 if (MF(Shape).Orientation() == TopAbs_REVERSED)
430 anOrien = TopAbs::Reverse(anOrien);
432 Standard_Boolean Rev = (anOrien == oldShell.Orientation());
433 //if rev = True oldShell has to be reversed.
435 // Add the faces of oldShell in SH.
436 for (TopoDS_Iterator its(oldShell); its.More(); its.Next()) {
437 const TopoDS_Face Fo = TopoDS::Face(its.Value());
438 TopAbs_Orientation NewOFo;
439 // update the orientation of Fo in SH.
441 NewOFo = TopAbs::Reverse(MF(Fo).Orientation());
443 NewOFo = MF(Fo).Orientation();
445 MF.Bind(Fo,SH.Oriented(NewOFo));
446 // B.Add (SH.Oriented(TopAbs_FORWARD),Fo.Oriented(NewO));
447 TopoDS_Shape arefShapeFo = SH.Oriented(TopAbs_FORWARD) ;
448 B.Add ( arefShapeFo,Fo.Oriented(NewOFo));
450 // Rebind the free edges of the old shell to the new shell
452 TopExp_Explorer aexp(SH,TopAbs_EDGE);
453 for( ; aexp.More(); aexp.Next()) {
454 //for (TopTools_DataMapIteratorOfDataMapOfShapeShape itm(M);
456 if(!M.IsBound(aexp.Current()))
458 TopoDS_Shape ae = aexp.Current();
459 TopoDS_Shape as = M.Find(ae);
460 if (as.IsSame(oldShell)) {
461 // update the orientation of free edges in SH.
463 NewO = TopAbs::Reverse(as.Orientation());
465 NewO = as.Orientation();
467 M.Bind(ae,SH.Oriented(NewO));
470 // remove the old shell from the result
471 B.Remove(result,oldShell.Oriented(TopAbs_FORWARD));
473 // Test if SH is always orientable.
474 TopAbs_Orientation anOrien = E.Orientation();
475 if (MF(Shape).Orientation() == TopAbs_REVERSED)
476 anOrien = TopAbs::Reverse(anOrien);
478 if (M(E).Orientation() == anOrien)
479 SH.Orientable(Standard_False);
481 // remove the edge from M (no more a free edge)
485 NewO = E.Orientation();
486 if (MF(Shape).Orientation() == TopAbs_REVERSED)
487 NewO = TopAbs::Reverse(NewO);
489 M.Bind(E,SH.Oriented(NewO));
496 SH.Free(Standard_False);
499 MapOtherShape.Add(Shape);
504 // Unclose all shells having free edges
505 for (TopTools_DataMapIteratorOfDataMapOfShapeShape it(M); it.More(); it.Next()) {
506 TopoDS_Shape S = it.Value();
507 S.Closed(Standard_Boolean(Standard_False));
510 TopTools_MapIteratorOfMapOfShape itother(MapOtherShape); //gka version for free edges
511 for( ; itother.More() ; itother.Next()) {
512 if(!EdgesFaces.Contains(itother.Key()) && myBounds.Contains(itother.Key())) {
513 TopoDS_Shape aSh = myBounds.FindFromKey(itother.Key());