Salome HOME
Merge with PAL/SALOME 2.1.0d
[modules/geom.git] / src / GEOMImpl / GEOMImpl_GlueDriver.cxx
1
2 using namespace std;
3 #include "GEOMImpl_GlueDriver.hxx"
4 #include "GEOMImpl_IGlue.hxx"
5 #include "GEOMImpl_Types.hxx"
6 #include "GEOM_Function.hxx"
7
8 #include <BRep_Tool.hxx>
9 #include <BRep_Builder.hxx>
10 #include <BRepLib.hxx>
11 #include <BRepBndLib.hxx>
12 #include <BRepTools_Quilt.hxx>
13 #include <BRepClass3d_SolidClassifier.hxx>
14
15 #include <TopExp.hxx>
16 #include <TopExp_Explorer.hxx>
17 #include <TopAbs.hxx>
18 #include <TopoDS.hxx>
19 #include <TopoDS_Shape.hxx>
20 #include <TopoDS_Face.hxx>
21 #include <TopoDS_Edge.hxx>
22 #include <TopoDS_Vertex.hxx>
23 #include <TopoDS_Compound.hxx>
24 #include <TopoDS_Shell.hxx>
25 #include <TopoDS_Solid.hxx>
26 #include <TopTools_ListOfShape.hxx>
27 #include <TopTools_ListIteratorOfListOfShape.hxx>
28
29 #include <gp_Pnt.hxx>
30 #include <Bnd_Box.hxx>
31 #include <Precision.hxx>
32 #include <Standard_NullObject.hxx>
33 #include <Standard_ConstructionError.hxx>
34
35 //=======================================================================
36 //function : GetID
37 //purpose  :
38 //=======================================================================
39 const Standard_GUID& GEOMImpl_GlueDriver::GetID()
40 {
41   static Standard_GUID aGlueDriver("FF1BBB63-5D14-4df2-980B-3A668264EA16");
42   return aGlueDriver;
43 }
44
45
46 //=======================================================================
47 //function : GEOMImpl_GlueDriver
48 //purpose  :
49 //=======================================================================
50 GEOMImpl_GlueDriver::GEOMImpl_GlueDriver()
51 {
52 }
53
54 //=======================================================================
55 //function : FindSameFace
56 //purpose  : for GLUE_FACES
57 //=======================================================================
58 static TopoDS_Face FindSameFace (const TopoDS_Shape& aShape,
59                                  const TopoDS_Face&  F,
60                                  const double        tol3d)
61 {
62   TopoDS_Face aFace;
63   bool isSame = false;
64   for (TopExp_Explorer exf (aShape, TopAbs_FACE); exf.More(); exf.Next()) {
65     // test a face
66     int nbFound = 0;
67     aFace = TopoDS::Face(exf.Current());
68     TopTools_ListOfShape liste1;
69     TopTools_ListOfShape liste2;
70     for (TopExp_Explorer exp (aFace, TopAbs_VERTEX); exp.More(); exp.Next()) {
71       const TopoDS_Vertex& V = TopoDS::Vertex(exp.Current());
72       liste1.Append(V);
73     }
74     for (TopExp_Explorer exp (F, TopAbs_VERTEX); exp.More(); exp.Next()) {
75       const TopoDS_Vertex& V = TopoDS::Vertex(exp.Current());
76       liste2.Append(V);
77     }
78     isSame = false;
79     if (liste1.Extent() == liste2.Extent())
80     {
81       TopTools_ListIteratorOfListOfShape it1 (liste1);
82       isSame = true;
83       for (; it1.More(); it1.Next())
84       {
85         bool foundSamePoint = false;
86         gp_Pnt P1 = BRep_Tool::Pnt(TopoDS::Vertex(it1.Value()));
87         TopTools_ListIteratorOfListOfShape it2 (liste2);
88         for (; it2.More(); it2.Next()) {
89           gp_Pnt P2 = BRep_Tool::Pnt(TopoDS::Vertex(it2.Value()));
90           double d = P1.Distance(P2);
91           if (d < tol3d) {
92             nbFound++;
93             // found Same Point : P1
94             foundSamePoint = true;
95             break;
96           }
97         }
98         isSame = isSame && foundSamePoint;
99         if (! isSame) break; // a vertex does not correspond : not same face
100       }
101     }
102     if (isSame) {
103       // Found Same Face
104       break; // a face corresponding to F is found
105     }
106   }
107   if (!isSame) aFace.Nullify(); // return null face
108   return aFace;
109 }
110
111 //=======================================================================
112 //function : FindSameEdge
113 //purpose  : for GLUE_FACES
114 //=======================================================================
115 static TopoDS_Edge FindSameEdge (const TopoDS_Face& nf,
116                                  TopoDS_Edge&       Eold,
117                                  const double       tol3d)
118 {
119   TopoDS_Face newFace = TopoDS::Face(nf.Oriented(TopAbs_REVERSED));
120   TopoDS_Vertex VFirst, VLast;
121   TopExp::Vertices(Eold, VFirst, VLast);
122   gp_Pnt Pf = BRep_Tool::Pnt(VFirst);
123   gp_Pnt Pl = BRep_Tool::Pnt(VLast);
124   TopoDS_Edge Enew;
125   for (TopExp_Explorer ee (newFace, TopAbs_EDGE); ee.More(); ee.Next()) {
126     const TopoDS_Edge& E = TopoDS::Edge(ee.Current());
127     TopoDS_Vertex VFn, VLn;
128     TopExp::Vertices(E, VFn, VLn);
129     gp_Pnt Pfn = BRep_Tool::Pnt(VFn);
130     gp_Pnt Pln = BRep_Tool::Pnt(VLn);
131     double dff = Pf.Distance(Pfn);
132     double dfl = Pf.Distance(Pln);
133     double dlf = Pl.Distance(Pfn);
134     double dll = Pl.Distance(Pln);
135     if ((dff < tol3d) && (dll <tol3d)) {
136       // edge forward : Pf - Pl
137       Enew = TopoDS::Edge(E.Oriented(TopAbs_FORWARD));
138       Eold = TopoDS::Edge(Eold.Oriented(TopAbs_FORWARD));
139       break;
140     }
141     if ((dfl < tol3d) && (dlf <tol3d)) {
142       // edge reversed : Pf - Pl
143       Enew = TopoDS::Edge(E.Oriented(TopAbs_REVERSED));
144       Eold = TopoDS::Edge(Eold.Oriented(TopAbs_FORWARD));
145       break;
146     }
147   }
148   return Enew;
149 }
150
151 //=======================================================================
152 //function : GlueFaces
153 //purpose  :
154 //=======================================================================
155 TopoDS_Shape GEOMImpl_GlueDriver::GlueFaces (const TopoDS_Shape& theShape,
156                                              const Standard_Real theTolerance)
157 {
158   // prendre un premier shell dans la liste des shells
159   // initialiser un compshell avec ce shell
160   // tant qu'il reste des shells dans la liste
161   //   chercher un shell qui a des faces en  commun avec le compshell
162   //   creer un BRepTools_Quilt
163   //   recenser les faces communes issues du compshell, les ajouter au quilt
164   //   recenser les faces restantes du shell a inclure, les ajouter au quilt
165   //   recenser les edges en double, a remplacer
166   //   pour chaque paire d'edge
167   //     tester l'orientation relative des aretes
168   //     bind dans le quilt de Eold.Forward et Enew.Forward (ou reverse)
169   //   recuperer le nouveau shell
170   // l'incorporer dans le compshell
171   // appliquer BRepTools_SameParameter au compshell
172   // (rendre parametres 2D des edges identiques aux parametres 3D)
173
174   TopoDS_Shape aShape;
175
176   TopoDS_Compound C;
177   BRep_Builder bu;
178   bu.MakeCompound(C); // empty compound;
179   TopTools_ListOfShape shellList;
180   for (TopExp_Explorer exp (theShape, TopAbs_SHELL); exp.More(); exp.Next()) {
181     const TopoDS_Shell& S = TopoDS::Shell(exp.Current());
182     shellList.Append(S);
183   }
184   TopTools_ListIteratorOfListOfShape its (shellList);
185   if (!its.More()) {
186     Standard_ConstructionError::Raise("Glue aborted : no shell in shape");
187   }
188
189   TopoDS_Shell S = TopoDS::Shell(its.Value());
190   bu.Add(C, S); // add first shell to compound
191   shellList.Remove(its);
192   bool shellAdded = true;
193   bool bigTolerance = false;
194
195   while ((shellList.Extent() > 0) && shellAdded) {
196     shellAdded = false;
197     its.Initialize(shellList);
198     for (; its.More(); its.Next()) {
199       S = TopoDS::Shell(its.Value());
200
201       // compare tolerance with shape's size
202       Bnd_Box aBox;
203       BRepBndLib::Add(S, aBox);
204       Standard_Real Xmin, Ymin, Zmin, Xmax, Ymax, Zmax;
205       aBox.Get(Xmin, Ymin, Zmin, Xmax, Ymax, Zmax);
206       Standard_Real aTolerance = theTolerance;
207       if (aBox.IsXThin(100. * aTolerance))
208         aTolerance = 0.01 * (Xmax - Xmin);
209       if (aBox.IsYThin(100. * aTolerance))
210         aTolerance = 0.01 * (Ymax - Ymin);
211       if (aBox.IsZThin(100. * aTolerance))
212         aTolerance = 0.01 * (Zmax - Zmin);
213       if (theTolerance > aTolerance)
214         bigTolerance = true;
215
216       bool isConnected = false;
217       TopTools_ListOfShape newEdges; // common edges from new compound
218       TopTools_ListOfShape oldEdges; // common edges from face to add
219       TopoDS_Compound CFN;
220       TopoDS_Compound CFO;
221       bu.MakeCompound(CFN);       // empty compound for new faces
222       bu.MakeCompound(CFO);       // empty compound for old faces
223
224       for (TopExp_Explorer exp (S, TopAbs_FACE); exp.More(); exp.Next()) {
225         // try to find corresponding face in new compound
226         TopoDS_Face F = TopoDS::Face(exp.Current());
227         TopoDS_Face newFace = FindSameFace(C,F,aTolerance);
228         if (! newFace.IsNull())
229         {
230           // face found
231           isConnected = true;
232           bu.Add(CFN, newFace); // common faces from new compound
233           for (TopExp_Explorer ee (F, TopAbs_EDGE); ee.More(); ee.Next()) {
234             // find edge pair
235             TopoDS_Edge Eold = TopoDS::Edge(ee.Current());
236             TopoDS_Edge Enew = FindSameEdge(newFace, Eold, aTolerance);
237             if (Enew.IsNull()) {
238               Standard_ConstructionError::Raise("Glue aborted : no same edge in same face");
239             }
240             oldEdges.Append(Eold);
241             newEdges.Append(Enew);
242           }
243         } else {
244           bu.Add(CFO, F); // not common faces from shell to add
245         }
246       }
247       if (isConnected) {
248         // some faces found
249         shellAdded = true;
250         BRepTools_Quilt glue;
251         glue.Add(CFN);
252         TopTools_ListIteratorOfListOfShape ito (oldEdges);
253         TopTools_ListIteratorOfListOfShape itn (newEdges);
254         for (; ito.More(); ito.Next()) {
255           // bind
256           glue.Bind(TopoDS::Edge(ito.Value()), TopoDS::Edge(itn.Value()));
257           itn.Next();
258         }
259         glue.Add(CFO);
260         TopoDS_Compound newc = TopoDS::Compound(glue.Shells());
261         for (TopExp_Explorer exs (newc, TopAbs_SHELL); exs.More(); exs.Next()) {
262           TopoDS_Shell NS = TopoDS::Shell(exs.Current());
263           bu.Add(C, NS);
264         }
265         shellList.Remove(its);
266         // remove shell from list
267         break;
268       }
269     }
270   }
271
272   if (shellList.Extent() > 0) {
273     TCollection_AsciiString aMsg
274       ("Some shapes can not be glued with others, because they are too far from them.");
275     if (bigTolerance) {
276       aMsg += "\n\nWarning: The tolerance is too big for some sub-shapes, 1% of sub-shape size is given instead.";
277     }
278     Standard_ConstructionError::Raise(aMsg.ToCString());
279   }
280
281   TopExp_Explorer exp (C, TopAbs_SHELL);
282   Standard_Integer ish = 0;
283   TopoDS_Compound  Res;
284   TopoDS_Solid     Sol;
285   BRep_Builder     B;
286   B.MakeCompound(Res);
287
288   for (; exp.More(); exp.Next()) {
289     TopoDS_Shape Sh = exp.Current();
290     B.MakeSolid(Sol);
291     B.Add(Sol,Sh);
292     BRepClass3d_SolidClassifier SC(Sol);
293     SC.PerformInfinitePoint(1.E-6); // cf. BRepFill_Confusion() - BRepFill_Evolved.cxx
294     if (SC.State() == TopAbs_IN) {
295       B.MakeSolid(Sol);
296       B.Add(Sol,Sh.Reversed());
297     }
298     B.Add(Res,Sol);
299     ish++;
300   }
301   if (ish == 1) {
302     aShape = Sol;
303   } else {
304     aShape = Res;
305   }
306
307   BRepLib::SameParameter(aShape, 1.E-5, Standard_True);
308   return aShape;
309 }
310
311 //=======================================================================
312 //function : Execute
313 //purpose  :
314 //=======================================================================
315 Standard_Integer GEOMImpl_GlueDriver::Execute(TFunction_Logbook& log) const
316 {
317   if (Label().IsNull()) return 0;
318   Handle(GEOM_Function) aFunction = GEOM_Function::GetFunction(Label());
319
320   GEOMImpl_IGlue aCI (aFunction);
321   Standard_Integer aType = aFunction->GetType();
322
323   TopoDS_Shape aShape;
324
325   if (aType == GLUE_FACES) {
326     Handle(GEOM_Function) aRefBase = aCI.GetBase();
327     TopoDS_Shape aShapeBase = aRefBase->GetValue();
328     if (aShapeBase.IsNull()) {
329       Standard_NullObject::Raise("Shape for gluing is null");
330     }
331
332     Standard_Real tol3d = aCI.GetTolerance();
333     aShape = GlueFaces(aShapeBase, tol3d);
334
335   } else {
336   }
337
338   if (aShape.IsNull()) return 0;
339
340   aFunction->SetValue(aShape);
341
342   log.SetTouched(Label());
343
344   return 1;
345 }
346
347
348 //=======================================================================
349 //function :  GEOMImpl_GlueDriver_Type_
350 //purpose  :
351 //=======================================================================
352 Standard_EXPORT Handle_Standard_Type& GEOMImpl_GlueDriver_Type_()
353 {
354
355   static Handle_Standard_Type aType1 = STANDARD_TYPE(TFunction_Driver);
356   if ( aType1.IsNull()) aType1 = STANDARD_TYPE(TFunction_Driver);
357   static Handle_Standard_Type aType2 = STANDARD_TYPE(MMgt_TShared);
358   if ( aType2.IsNull()) aType2 = STANDARD_TYPE(MMgt_TShared);
359   static Handle_Standard_Type aType3 = STANDARD_TYPE(Standard_Transient);
360   if ( aType3.IsNull()) aType3 = STANDARD_TYPE(Standard_Transient);
361
362
363   static Handle_Standard_Transient _Ancestors[]= {aType1,aType2,aType3,NULL};
364   static Handle_Standard_Type _aType = new Standard_Type("GEOMImpl_GlueDriver",
365                                                          sizeof(GEOMImpl_GlueDriver),
366                                                          1,
367                                                          (Standard_Address)_Ancestors,
368                                                          (Standard_Address)NULL);
369
370   return _aType;
371 }
372
373 //=======================================================================
374 //function : DownCast
375 //purpose  :
376 //=======================================================================
377 const Handle(GEOMImpl_GlueDriver) Handle(GEOMImpl_GlueDriver)::DownCast(const Handle(Standard_Transient)& AnObject)
378 {
379   Handle(GEOMImpl_GlueDriver) _anOtherObject;
380
381   if (!AnObject.IsNull()) {
382      if (AnObject->IsKind(STANDARD_TYPE(GEOMImpl_GlueDriver))) {
383        _anOtherObject = Handle(GEOMImpl_GlueDriver)((Handle(GEOMImpl_GlueDriver)&)AnObject);
384      }
385   }
386
387   return _anOtherObject ;
388 }