0031668: Visualization - WebGL sample doesn't work on Emscripten 1.39
[occt.git] / src / LocOpe / LocOpe_BuildShape.cxx
1 // Created on: 1996-09-16
2 // Created by: Jacques GOUSSARD
3 // Copyright (c) 1996-1999 Matra Datavision
4 // Copyright (c) 1999-2014 OPEN CASCADE SAS
5 //
6 // This file is part of Open CASCADE Technology software library.
7 //
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.
13 //
14 // Alternatively, this file may be used under the terms of Open CASCADE
15 // commercial license or contractual agreement.
16
17
18 #include <BRep_Builder.hxx>
19 #include <BRep_Tool.hxx>
20 #include <BRepClass3d_SolidClassifier.hxx>
21 #include <gp_Pnt.hxx>
22 #include <LocOpe_BuildShape.hxx>
23 #include <Precision.hxx>
24 #include <Standard_ConstructionError.hxx>
25 #include <TColStd_MapIteratorOfMapOfInteger.hxx>
26 #include <TColStd_MapOfInteger.hxx>
27 #include <TopAbs.hxx>
28 #include <TopExp.hxx>
29 #include <TopoDS.hxx>
30 #include <TopoDS_Compound.hxx>
31 #include <TopoDS_Edge.hxx>
32 #include <TopoDS_Shape.hxx>
33 #include <TopoDS_Shell.hxx>
34 #include <TopoDS_Solid.hxx>
35 #include <TopTools_DataMapIteratorOfDataMapOfShapeListOfShape.hxx>
36 #include <TopTools_DataMapOfShapeListOfShape.hxx>
37 #include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
38 #include <TopTools_IndexedMapOfShape.hxx>
39 #include <TopTools_ListIteratorOfListOfShape.hxx>
40
41 static void Add(const Standard_Integer,
42                 TColStd_MapOfInteger&,
43                 TopTools_IndexedMapOfShape&,
44                 const TopTools_IndexedDataMapOfShapeListOfShape&);
45
46 static void Propagate(const TopoDS_Shape&, // face
47                       TopoDS_Shape&, // shell
48                       const TopTools_IndexedMapOfShape&,
49                       TColStd_MapOfInteger&);
50                       
51 static Standard_Boolean IsInside(const TopoDS_Shape&,
52                                  const TopoDS_Shape&);
53
54
55 //=======================================================================
56 //function : Perform
57 //purpose  : 
58 //=======================================================================
59
60 void LocOpe_BuildShape::Perform(const TopTools_ListOfShape& L)
61 {
62   Standard_Integer i ;
63   Standard_Integer j ;
64   Standard_Integer k ;
65   myRes.Nullify();
66
67   TopoDS_Compound C;
68   BRep_Builder B;
69   B.MakeCompound(C);
70
71   TopTools_IndexedMapOfShape mapF;
72   TopTools_ListIteratorOfListOfShape itl;
73
74   for (itl.Initialize(L); itl.More(); itl.Next()) {
75     if (itl.Value().ShapeType() == TopAbs_FACE &&
76         !mapF.Contains(itl.Value())) {
77       mapF.Add(itl.Value());
78       B.Add(C,itl.Value());
79     }
80   }
81
82   if (mapF.Extent() == 0) {
83     return; // no face
84   }
85
86   TopTools_IndexedDataMapOfShapeListOfShape theMapEF;
87   TopExp::MapShapesAndAncestors(C,TopAbs_EDGE,TopAbs_FACE,theMapEF);
88
89   TopTools_DataMapOfShapeListOfShape mapSh;
90   TColStd_MapOfInteger mapI,mapIf;
91   Standard_Integer Nbedges = theMapEF.Extent();
92
93   TopTools_ListOfShape lshell;
94   TopTools_ListOfShape lresult;
95
96   do {
97     // Recherche du premier edge non traite
98     for ( i = 1; i <= Nbedges; i++) {
99       if (!mapI.Contains(i)) {
100         break;
101       }
102     }
103     if (i <= Nbedges) {
104       mapF.Clear();
105       mapIf.Clear();
106       Add(i,mapI,mapF,theMapEF);
107       Standard_Boolean Manifold = Standard_True;
108       TopoDS_Shape FaceRef;
109       TopAbs_Orientation orient;
110
111       for ( j = 1; j<= mapF.Extent(); j++) {
112         orient = mapF(j).Orientation();
113         if (orient == TopAbs_INTERNAL || orient == TopAbs_EXTERNAL) {
114           Manifold = Standard_False;
115         }
116         else if (FaceRef.IsNull()) {
117           FaceRef = mapF(j);
118         }
119         mapIf.Add(j);
120       }
121
122       TopoDS_Shell newSh;
123       B.MakeShell(newSh);
124       if (!Manifold && FaceRef.IsNull()) {
125         // on a un paquet de faces. pas d'orientation possible ?
126         for (j = 1; j <= mapF.Extent(); j++) {
127           B.Add(newSh,mapF(j));
128         }
129       }
130       else {
131         // orienter ce qu`on peut
132         if (!Manifold) {
133           for (j = 1; j <= mapF.Extent(); j++) {
134             if (mapF(j).Orientation() == TopAbs_INTERNAL ||
135                 mapF(j).Orientation() == TopAbs_EXTERNAL) {
136               B.Add(newSh,mapF(j));
137               mapIf.Remove(j);
138             }
139           }
140         }
141         
142         B.Add(newSh,FaceRef);
143         Propagate(FaceRef,newSh,mapF,mapIf);
144       }
145       newSh.Closed (BRep_Tool::IsClosed (newSh));
146       if (!Manifold) {
147         lshell.Append(newSh.Oriented(TopAbs_INTERNAL));
148       }
149       else {
150         TopTools_IndexedDataMapOfShapeListOfShape theMapEFbis;
151         TopExp::MapShapesAndAncestors(newSh,TopAbs_EDGE,TopAbs_FACE,theMapEFbis);
152         for ( k = 1; k<=theMapEFbis.Extent(); k++) {
153           const TopoDS_Edge& Ed = TopoDS::Edge(theMapEFbis.FindKey(k));
154           TopAbs_Orientation OriEd = Ed.Orientation();
155           if (OriEd != TopAbs_INTERNAL && OriEd != TopAbs_EXTERNAL) {  
156             Standard_Integer Nbfac = theMapEFbis(k).Extent();
157             if (Nbfac > 2) { // peu probable
158               break;
159             }
160             else if (Nbfac == 1) {
161               if (!BRep_Tool::Degenerated(Ed)) {
162                 break;
163               }
164             }
165           }
166         }
167         if (k > theMapEFbis.Extent()) {
168           TopoDS_Solid newSo;
169           B.MakeSolid(newSo);
170           B.Add(newSo,newSh); // newSh est FORWARD
171           BRepClass3d_SolidClassifier Class(newSo);
172           Class.PerformInfinitePoint(Precision::Confusion());
173           if (Class.State() == TopAbs_IN) {
174             lresult.Append(newSh.Oriented(TopAbs_REVERSED));
175           }
176           else {
177             lresult.Append(newSh);
178           }
179         }
180         else {
181           lshell.Append(newSh.Oriented(TopAbs_INTERNAL));
182         }
183       }
184     }
185   } while (mapI.Extent() < Nbedges);
186
187
188   // on a une list de shells dans lresult. on suppose qu`ils ne s`intersectent pas.
189   // il faut classifier les shells orientes pour en faire des solides...
190   // on n`accepte qu`1 niveau d'imbrication
191
192   TopTools_DataMapOfShapeListOfShape imbSh;
193   TopTools_ListOfShape LIntern;
194
195   for (itl.Initialize(lresult); itl.More(); itl.Next()) {
196     const TopoDS_Shape& sh = itl.Value();
197     TopoDS_Solid tempo;
198     B.MakeSolid(tempo);
199     B.Add(tempo,sh);
200
201     TopTools_ListOfShape thelist;    
202     imbSh.Bind(sh, thelist);
203     TopTools_ListIteratorOfListOfShape itl2;
204     for (itl2.Initialize(lresult);
205 //    for (TopTools_ListIteratorOfListOfShape itl2(lresult);
206          itl2.More(); itl2.Next()) {
207       const TopoDS_Shape& sh2 = itl2.Value();  
208       if (!sh2.IsSame(sh)) {
209         if (IsInside(sh2, tempo)) {
210           LIntern.Append(sh2);
211           imbSh(sh).Append(sh2);
212         }
213       }
214     }
215   }
216   
217
218   // LPA 07/10/98: on vire les shells imbriques comme
219   // etant aussi des solides a part entiere.
220   for (itl.Initialize(LIntern); itl.More(); itl.Next()) {
221     const TopoDS_Shape& sh = itl.Value();
222     if (imbSh.IsBound(sh)) {
223       imbSh.UnBind(sh);
224     }
225   }
226
227
228
229   TopTools_ListOfShape lsolid;
230   do {
231 //    for (TopTools_DataMapIteratorOfDataMapOfShapeListOfShape itdm(imbSh);
232     TopTools_DataMapIteratorOfDataMapOfShapeListOfShape itdm(imbSh);
233     for ( ; itdm.More(); itdm.Next()) {
234       if (itdm.Value().Extent() != 0) {
235         break;
236       }
237     }
238     if (itdm.More()) {
239       TopoDS_Solid newSo;
240       B.MakeSolid(newSo);
241       B.Add(newSo,itdm.Key());
242       for (itl.Initialize(itdm.Value()); itl.More(); itl.Next()) {
243         B.Add(newSo,itl.Value().Reversed());
244       }
245       lsolid.Append(newSo);
246       imbSh.UnBind(itdm.Key());
247     }
248     else {
249       for (itdm.Reset(); itdm.More(); itdm.Next()) {
250         TopoDS_Solid newSo;
251         B.MakeSolid(newSo);
252         B.Add(newSo,itdm.Key());
253         lsolid.Append(newSo);
254       }
255       imbSh.Clear();
256     }
257   } while (imbSh.Extent() != 0);
258
259   Standard_Integer nbsol = lsolid.Extent();
260   Standard_Integer nbshl = lshell.Extent();
261
262   if (nbsol == 1 && nbshl == 0) {
263     myRes = lsolid.First();
264   }
265   else if (nbsol == 0 && nbshl == 1) {
266     myRes = lshell.First();
267   }
268   else {
269     B.MakeCompound(TopoDS::Compound(myRes));
270     for (itl.Initialize(lsolid); itl.More(); itl.Next()) {
271       B.Add(myRes,itl.Value());
272     }
273     for (itl.Initialize(lshell); itl.More(); itl.Next()) {
274       B.Add(myRes,itl.Value());
275     }
276   }
277 }
278
279
280
281
282
283 //=======================================================================
284 //function : Add
285 //purpose  : static function
286 //=======================================================================
287
288 static void Add(const Standard_Integer ind,
289                 TColStd_MapOfInteger& mapI,
290                 TopTools_IndexedMapOfShape& mapF,
291                 const TopTools_IndexedDataMapOfShapeListOfShape& mapEF)
292
293 {
294   if (!mapI.Add(ind)) {
295     throw Standard_ConstructionError();
296   }
297
298   TopTools_ListIteratorOfListOfShape itl(mapEF(ind));
299   for (; itl.More(); itl.Next()) {
300     if (!mapF.Contains(itl.Value())) {
301       mapF.Add(itl.Value());
302       TopExp_Explorer exp;
303       for (exp.Init(itl.Value(),TopAbs_EDGE);
304 //      for (TopExp_Explorer exp(itl.Value(),TopAbs_EDGE);
305            exp.More(); exp.Next()) {
306         const TopoDS_Shape& edg = exp.Current();
307         Standard_Integer indedg = mapEF.FindIndex(edg);
308         if (indedg == 0) {
309           throw Standard_ConstructionError();
310         }
311         if (!mapI.Contains(indedg)) {
312           Add(indedg,mapI,mapF,mapEF);
313         }
314       }
315     }
316   }
317 }
318
319
320 //=======================================================================
321 //function : Propagate
322 //purpose  : static function
323 //=======================================================================
324
325 static void Propagate(const TopoDS_Shape& F,
326                       TopoDS_Shape& Sh,
327                       const TopTools_IndexedMapOfShape& mapF,
328                       TColStd_MapOfInteger& mapIf)
329 {
330   BRep_Builder B;
331   Standard_Integer indf = mapF.FindIndex(F);
332   if (!mapIf.Contains(indf)) {
333     return;
334   }
335   mapIf.Remove(indf);
336   if (mapIf.Extent() == 0) {
337     return;
338   }
339   
340   TopExp_Explorer exp;
341   for (exp.Init(F,TopAbs_EDGE); exp.More(); exp.Next()) {
342 //  for (TopExp_Explorer exp(F,TopAbs_EDGE); exp.More(); exp.Next()) {
343     const TopoDS_Shape& edg = exp.Current();
344
345     TopAbs_Orientation ored1 = edg.Orientation(),ored2 = TopAbs_FORWARD;
346
347     if (ored1 == TopAbs_INTERNAL || ored1 == TopAbs_EXTERNAL) {
348       continue;
349     }
350 //    for (TColStd_MapIteratorOfMapOfInteger itm(mapIf);
351     TColStd_MapIteratorOfMapOfInteger itm(mapIf);
352     for ( ; itm.More(); itm.Next()) {
353       const TopoDS_Shape& newF = mapF(itm.Key());
354 //      for (TopExp_Explorer exp2(newF,TopAbs_EDGE);exp2.More(); exp2.Next()) {
355       TopExp_Explorer exp2(newF,TopAbs_EDGE) ;
356       for ( ;exp2.More(); exp2.Next()) {
357         if (exp2.Current().IsSame(edg)) {
358           break;
359         }
360       }
361       if (exp2.More()) {
362         ored2 = exp2.Current().Orientation();
363         break;
364       }
365     }
366     if (itm.More()) {
367       TopoDS_Shape FtoAdd = mapF(itm.Key());
368       Standard_Boolean added = Standard_False;
369       if (ored2 == ored1) {
370         FtoAdd.Reverse();
371         B.Add(Sh,FtoAdd);
372         added = Standard_True;
373       }
374       else if (ored2 == TopAbs::Reverse(ored1)) {
375         B.Add(Sh,FtoAdd);
376         added = Standard_True;
377       }
378       if (added) {
379         Propagate(FtoAdd,Sh,mapF,mapIf);
380       }
381     }
382   }
383 }
384
385 //=======================================================================
386 //function : IsInside
387 //purpose  : static function
388 //=======================================================================
389
390 static Standard_Boolean IsInside(const TopoDS_Shape& S1,
391                                  const TopoDS_Shape& S2)
392 {
393   BRepClass3d_SolidClassifier Class(S2);
394   TopExp_Explorer exp;
395   for (exp.Init(S1,TopAbs_VERTEX);exp.More(); exp.Next()) {
396 //  for (TopExp_Explorer exp(S1,TopAbs_VERTEX);exp.More(); exp.Next()) {
397     const TopoDS_Vertex& vtx = TopoDS::Vertex(exp.Current());
398     gp_Pnt Pttest = BRep_Tool::Pnt(vtx);
399     Standard_Real Tol = BRep_Tool::Tolerance(vtx);
400     Class.Perform(Pttest,Tol);
401     if (Class.State() == TopAbs_IN) {
402       return Standard_True;
403     }
404     else if (Class.State() == TopAbs_OUT) {
405       return Standard_False;
406     }
407   }
408 #ifdef OCCT_DEBUG
409   std::cout << "Classification impossible sur vertex " << std::endl;
410 #endif
411   
412   return Standard_True;
413   
414 }
415