0025520: To provide info on what has been done by Shape Process and Shape Fix
[occt.git] / src / ShapeFix / ShapeFix_FixSmallFace.cxx
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 #include <ShapeFix_FixSmallFace.ixx>
15 #include <TopoDS.hxx>
16 #include <TopoDS_Shell.hxx>
17 #include <TopoDS_Edge.hxx>
18 #include <TopoDS_Vertex.hxx>
19 #include <TopoDS_Iterator.hxx>
20 #include <TopExp_Explorer.hxx>
21 #include <TopExp.hxx>
22 #include <BRep_Tool.hxx>
23
24 #include <Geom_Curve.hxx>
25 #include <Geom_Surface.hxx>
26 #include <Geom_BSplineSurface.hxx>
27 #include <Geom_BezierSurface.hxx>
28
29 #include <ShapeAnalysis_Curve.hxx>
30 //#include <GeomLProp_SLProps.hxx>
31 #include <GeomAdaptor_Surface.hxx>
32 #include <Geom_ElementarySurface.hxx>
33 //#include <TColStd_Array2OfReal.hxx>
34 #include <gp_Dir.hxx>
35 #include <gp_Vec.hxx>
36 //#include <TColStd_Array1OfReal.hxx>
37 #include <TColgp_Array1OfPnt.hxx>
38 #include <TopTools_Array1OfShape.hxx>
39
40 #include <TColgp_Array2OfPnt.hxx>
41
42 #include <TColgp_SequenceOfXYZ.hxx>
43 #include <BRep_Builder.hxx>
44 #include <ShapeBuild_ReShape.hxx>
45 #include <BRepTools.hxx>
46 #include <ShapeFix_Edge.hxx>
47 #include <Precision.hxx>
48 #include <TopoDS_Wire.hxx>
49 #include <ShapeFix_Wire.hxx>
50 #include <Geom_Line.hxx>
51 #include <TopExp.hxx>
52 #include <ElCLib.hxx>
53 #include <TopoDS_Builder.hxx>
54 #include <TopoDS_Compound.hxx>
55 #include <Poly_Polygon3D.hxx>
56 #include <Geom2d_Curve.hxx>
57 #include <BRepLib.hxx>
58 #include <GeomLib.hxx>
59 #include <ShapeFix_Face.hxx>
60 #include <ShapeFix_Wire.hxx>
61 #include <Geom_TrimmedCurve.hxx>
62 #include <GeomAdaptor_Curve.hxx>
63 #include <ShapeFix_Shape.hxx>
64 #include <Precision.hxx>
65 #include <TopExp_Explorer.hxx>
66 #include <TopTools_DataMapOfShapeListOfShape.hxx>
67 #include <ShapeAnalysis_DataMapOfShapeListOfReal.hxx>
68 #include <TopoDS_Compound.hxx>
69 #include <TopoDS_Iterator.hxx>
70 #include <Message_Msg.hxx>
71
72 ShapeFix_FixSmallFace::ShapeFix_FixSmallFace()
73 {
74   myStatus = ShapeExtend::EncodeStatus ( ShapeExtend_OK );
75   SetPrecision(Precision::Confusion());
76
77 }
78
79  void ShapeFix_FixSmallFace::Init(const TopoDS_Shape& S) 
80 {
81   myShape = S;
82   if ( Context().IsNull() ) 
83     SetContext ( new ShapeBuild_ReShape );
84   myResult = myShape;
85   Context()->Apply(myShape);
86 }
87
88
89  void ShapeFix_FixSmallFace::Perform() 
90 {
91   FixSpotFace();
92   FixStripFace();
93 }
94
95  TopoDS_Shape ShapeFix_FixSmallFace::FixSpotFace() 
96 {
97  
98   // gp_Pnt spot;
99   // Standard_Real spotol;
100   Standard_Boolean done = Standard_False;
101   TopAbs_ShapeEnum st = myShape.ShapeType();
102   if (st == TopAbs_COMPOUND || st == TopAbs_COMPSOLID || st == TopAbs_SOLID || st == TopAbs_SHELL ||  st == TopAbs_FACE) { 
103     for (TopExp_Explorer itf (myShape,TopAbs_FACE); itf.More(); itf.Next()) {
104 //smh#8
105       TopoDS_Shape tmpFace = Context()->Apply(itf.Current());
106       TopoDS_Face F = TopoDS::Face (tmpFace);
107       if(F.IsNull()) continue;
108       if (myAnalyzer.CheckSpotFace (F,Precision())) 
109         {
110           ReplaceVerticesInCaseOfSpot(F,Precision());
111           RemoveFacesInCaseOfSpot(F);
112           myStatus = ShapeExtend::EncodeStatus ( ShapeExtend_DONE1 );
113           done = Standard_True;
114         }
115     }
116     myShape = Context()->Apply(myShape);
117     Handle(ShapeFix_Wire) sfw = new ShapeFix_Wire;
118     if (done)
119       {
120         if (myShape.IsNull()) return myShape;
121         /*ShapeFix_Wire sfw;
122         sfw.SetContext(Context());
123         sfw.SetPrecision(Precision::Confusion());
124         if (myShape.IsNull()) return myShape;
125         for (TopExp_Explorer itfw (myShape,TopAbs_FACE); itfw.More(); itfw.Next()) {
126           for (TopExp_Explorer itw (myShape,TopAbs_WIRE); itw.More(); itw.Next()) {
127             TopoDS_Wire w = TopoDS::Wire(itw.Current());
128             sfw.Init(w, TopoDS::Face(itfw.Current()), Precision::Confusion());
129             sfw->FixNotchedEdgesMode() = 0;
130             if(sfw.Perform())
131                 Context()->Replace(w, sfw.Wire());
132           }                      
133         }*/
134         myShape = FixShape();
135       }
136   
137   //myShape = Context()->Apply(myShape);
138   myResult = myShape;
139   }
140   return myShape;
141 }
142
143  Standard_Boolean ShapeFix_FixSmallFace::ReplaceVerticesInCaseOfSpot(TopoDS_Face& F,const Standard_Real /*tol*/) const
144 {
145
146   TColgp_SequenceOfXYZ thePositions;
147   gp_XYZ thePosition;
148   BRep_Builder theBuilder;
149   Standard_Real theMaxDev;
150   Standard_Real theMaxTol = 0.0;
151   thePositions.Clear();
152   gp_Pnt thePoint;
153 //smh#8
154   TopoDS_Shape tmpFace = Context()->Apply(F);
155   F = TopoDS::Face(tmpFace);
156   // gka Mar2000 Protection against faces without wires
157   // but they occur due to bugs in the algorithm itself, it needs to be fixed
158   Standard_Boolean isWir = Standard_False;
159   for(TopoDS_Iterator itw(F,Standard_False) ; itw.More();itw.Next()) {
160     if(itw.Value().ShapeType() != TopAbs_WIRE)
161       continue;
162     TopoDS_Wire w1 = TopoDS::Wire(itw.Value());
163     if (!w1.IsNull()) {isWir = Standard_True; break;}
164   }
165   if(!isWir) return Standard_True;
166   //Accumulating positions and maximal vertex tolerance
167   for (TopExp_Explorer iter_vertex(F,TopAbs_VERTEX); iter_vertex.More(); iter_vertex.Next()) {
168     TopoDS_Vertex V = TopoDS::Vertex (iter_vertex.Current());
169     thePoint = BRep_Tool::Pnt(V);
170     if (theMaxTol <= (BRep_Tool::Tolerance(V))) theMaxTol = BRep_Tool::Tolerance(V);
171     thePositions.Append(thePoint.XYZ());
172   } 
173   //Calculate common vertex position
174   thePosition = gp_XYZ(0.,0.,0.);
175   Standard_Integer theNbPos = thePositions.Length();
176   Standard_Integer i; // svv Jan11 2000 : porting on DEC
177   for (  i = 1; i <= theNbPos; i++ ) thePosition += thePositions.Value(i);
178   if ( theNbPos > 1 ) thePosition /= theNbPos;
179    
180   // Calculate maximal deviation
181   theMaxDev = 0.;
182   for (  i = 1; i <= theNbPos; i++ ) {
183     Standard_Real theDeviation = (thePosition-thePositions.Value(i)).Modulus();
184     if ( theDeviation > theMaxDev ) theMaxDev = theDeviation;
185   }
186   theMaxDev *= 1.00001; 
187   
188   //Cretate new vertex with mean point
189   TopoDS_Vertex theSharedVertex;
190   theBuilder.MakeVertex(theSharedVertex);
191   theBuilder.UpdateVertex( theSharedVertex, gp_Pnt(thePosition), theMaxDev+theMaxTol/2 );
192   //Use external tolerance
193 //   if (tol!=-1.0) theBuilder.UpdateVertex( theSharedVertex, tol);
194   //Replacing all vertices in the face by new one
195   TopoDS_Vertex theNewVertex;
196   for ( TopExp_Explorer iter_vert(F,TopAbs_VERTEX); iter_vert.More(); iter_vert.Next()) {
197     TopoDS_Vertex V = TopoDS::Vertex (iter_vert.Current());
198     if (V.Orientation()==TopAbs_FORWARD)  
199 //smh#8
200       {
201         TopoDS_Shape tmpVertexFwd = theSharedVertex.Oriented(TopAbs_FORWARD);
202         theNewVertex = TopoDS::Vertex(tmpVertexFwd);
203       }
204     else 
205 //smh#8
206       {
207         TopoDS_Shape tmpVertexRev = theSharedVertex.Oriented(TopAbs_REVERSED);
208         theNewVertex = TopoDS::Vertex(tmpVertexRev);
209       }
210     Context()->Replace(V, theNewVertex);
211   }
212   return Standard_True;
213 }
214
215  Standard_Boolean ShapeFix_FixSmallFace::RemoveFacesInCaseOfSpot(const TopoDS_Face& F) const
216 {
217   for ( TopExp_Explorer iter_vert(F,TopAbs_EDGE); iter_vert.More(); iter_vert.Next()) {
218     TopoDS_Edge Ed = TopoDS::Edge (iter_vert.Current());
219     Context()->Remove(Ed);
220   }
221   Context()->Remove(F);
222   SendWarning( F, Message_Msg( "FixAdvFace.FixSpotFace.MSG0" ));
223   return Standard_True;
224
225
226 }
227
228  TopoDS_Shape ShapeFix_FixSmallFace::FixStripFace(const Standard_Boolean wasdone) 
229 {
230   if(myShape.IsNull()) return myShape;
231   TopAbs_ShapeEnum st = myShape.ShapeType();
232   // BRep_Builder theBuilder;
233   Standard_Boolean done = wasdone;
234   if (st == TopAbs_COMPOUND || st == TopAbs_COMPSOLID ||st == TopAbs_SOLID || st == TopAbs_SHELL || st == TopAbs_FACE) {
235     for (TopExp_Explorer itf (myShape,TopAbs_FACE); itf.More(); itf.Next()) {
236       TopoDS_Face F = TopoDS::Face (itf.Current());
237 //smh#8
238       TopoDS_Shape tmpFace = Context()->Apply(F);
239       F= TopoDS::Face(tmpFace);
240       if(F.IsNull()) continue;
241       // Standard_Real dmax = 1;
242       TopoDS_Edge E1,E2;
243       if (myAnalyzer.CheckStripFace (F, E1,E2,Precision()))  
244         {
245           if(ReplaceInCaseOfStrip(F,E1,E2, Precision()))
246             RemoveFacesInCaseOfStrip(F);
247           myStatus = ShapeExtend::EncodeStatus ( ShapeExtend_DONE2 );
248           done = Standard_True;
249         }
250     }
251     myShape = Context()->Apply(myShape);
252     //Particular case of empty shell
253     if (!myShape.IsNull())
254       {
255         for (TopExp_Explorer exp_s (myShape,TopAbs_SHELL); exp_s.More(); exp_s.Next()) {
256           TopoDS_Shell Sh = TopoDS::Shell (exp_s.Current());
257           TopExp_Explorer ex_sh(Sh,TopAbs_FACE);
258           if (!ex_sh.More())  { Context()->Remove(Sh);
259 //                              cout << "Empty shell was removed" << endl; 
260                               }
261         }
262         myShape = Context()->Apply(myShape);
263     //Fixing of missing pcurves on new edges, if thay were inserted
264         if (done)
265           {
266             if (myShape.IsNull()) return myShape;
267             TopoDS_Shape theResult;
268             myShape = FixShape();
269             //myShape = Context()->Apply(myShape);
270             myResult = myShape;
271           }
272         
273       }
274   }
275   return myShape; 
276
277 }
278
279  Standard_Boolean ShapeFix_FixSmallFace::ReplaceInCaseOfStrip(TopoDS_Face& F,TopoDS_Edge& E1,TopoDS_Edge& E2, const Standard_Real tol) const
280 {
281   if(E1.IsNull() || E2.IsNull()) return Standard_False;
282   TopoDS_Edge theSharedEdge;
283   TopoDS_Face F1,F2;
284 //smh#8
285   TopoDS_Shape tmpFace = Context()->Apply(F);
286   F= TopoDS::Face(tmpFace);
287   for(TopExp_Explorer expf(myShape,TopAbs_FACE); expf.More(); expf.Next()) {
288 //smh#8
289     TopoDS_Shape tmpShape = Context()->Apply(expf.Current());
290     TopoDS_Face tempF = TopoDS::Face (tmpShape);
291     if(tempF.IsNull() || tempF.IsSame(F)) continue;
292     for(TopExp_Explorer expe(tempF,TopAbs_EDGE); expe.More(); expe.Next()) {
293       TopoDS_Edge tempE = TopoDS::Edge (expe.Current());
294       if(tempE.IsSame(E1)) F1 = tempF;
295       if(tempE.IsSame(E2)) F2 = tempF; 
296       if(!F1.IsNull()) break; // && !F2.IsNull()) break;
297     }
298   }
299   
300   //Compute shared edge for this face
301   if(F1.IsNull() && F2.IsNull()) return Standard_True;
302   TopoDS_Edge E1tmp = E1;
303   TopoDS_Edge E2tmp = E2;
304   if(F1.IsNull()) {
305     E1tmp = E2;
306     E2tmp = E1;
307     F1 = F2;
308   }
309   theSharedEdge = ComputeSharedEdgeForStripFace(F, E1tmp, E2tmp, F1, tol);
310   //Replace two long edges by new one
311   if (theSharedEdge.IsNull()) return Standard_False;
312   if (E1.Orientation()==TopAbs_REVERSED) {
313       Context()->Replace(E1tmp, theSharedEdge.Oriented(TopAbs_REVERSED));
314       if(F.Orientation() == F1.Orientation())
315         Context()->Replace(E2tmp, theSharedEdge);
316       else 
317        Context()->Replace(E2tmp, theSharedEdge.Oriented(TopAbs_REVERSED));
318     }
319   else 
320     {
321       Context()->Replace(E1tmp, theSharedEdge);
322      if(F.Orientation() == F1.Orientation())
323       Context()->Replace(E2tmp, theSharedEdge.Oriented(TopAbs_REVERSED));
324      else
325       Context()->Replace(E2tmp, theSharedEdge);
326     }
327     
328   //Remove short edges
329   for (TopExp_Explorer exp_e (F,TopAbs_EDGE); exp_e.More(); exp_e.Next()) {
330     TopoDS_Edge shortedge = TopoDS::Edge (exp_e.Current());
331     if (!shortedge.IsSame(E1tmp) && !shortedge.IsSame(E2tmp)) Context()->Remove(shortedge); 
332   }
333   
334   return Standard_True;
335 }
336
337  Standard_Boolean ShapeFix_FixSmallFace::RemoveFacesInCaseOfStrip(const TopoDS_Face& F) const
338 {
339   Context()->Remove(F);
340   SendWarning( F, Message_Msg( "FixAdvFace.FixStripFace.MSG0" ));
341   return Standard_True;
342 }
343
344  TopoDS_Edge ShapeFix_FixSmallFace::ComputeSharedEdgeForStripFace(const TopoDS_Face& /*F*/,const TopoDS_Edge& E1,const TopoDS_Edge& E2,const TopoDS_Face& F1,const Standard_Real tol) const
345 {
346
347   BRep_Builder theBuilder;
348   //Compute deviation between two vertices and create new vertices
349   TopoDS_Edge theNewEdge;
350   TopoDS_Vertex V1,V2, V3, V4;
351   TopExp::Vertices (E1,V1,V2);
352   TopExp::Vertices (E2,V3,V4);
353   gp_Pnt p1, p2;
354   Standard_Real dev;
355   p1 = BRep_Tool::Pnt(V1);
356   p2 =  BRep_Tool::Pnt(V3);
357   dev = p1.Distance(p2);
358   TopoDS_Vertex theFirstVer;
359   TopoDS_Vertex theSecondVer;
360   theBuilder.MakeVertex(theFirstVer);
361   theBuilder.MakeVertex(theSecondVer);
362   gp_XYZ thePosition;
363   TopoDS_Shape temp;
364   
365   if ((dev<=BRep_Tool::Tolerance (V1)) || (dev<=BRep_Tool::Tolerance (V3)) || (dev<=tol)) {
366       if (V1.IsSame(V3))  
367 // #ifdef AIX  CKY : applies to all platforms
368         theFirstVer = V1; 
369 //      theFirstVer = TopoDS::Vertex(V1); 
370
371       else {
372         dev = (dev/2)*1.0001;
373         thePosition = (p1.XYZ()+p2.XYZ())/2;  
374         theBuilder.UpdateVertex(theFirstVer, gp_Pnt(thePosition), dev );
375         //if(Context()->Status(V1, temp) != 0) theFirstVer = TopoDS::Vertex (temp); //If this vertex already recorded in map
376         //else                                                                       //take recorded vertex 
377         //  if(theRepVert->Status(V3, temp) != 0) theFirstVer = TopoDS::Vertex (temp);
378         if (V1.Orientation()==TopAbs_FORWARD) Context()->Replace(V1, theFirstVer.Oriented(TopAbs_FORWARD));
379         else Context()->Replace(V1, theFirstVer.Oriented(TopAbs_REVERSED));
380         if (V3.Orientation()==TopAbs_FORWARD) Context()->Replace(V3, theFirstVer.Oriented(TopAbs_FORWARD));
381         else Context()->Replace(V3, theFirstVer.Oriented(TopAbs_REVERSED));
382         
383      }
384       if(V1.IsSame(V2) || V3.IsSame(V4))
385         theSecondVer = theFirstVer; 
386       else {
387         if (!V2.IsSame(V4))   {
388           // #ifdef AIX  CKY : applies to all platforms
389           
390           p1 = BRep_Tool::Pnt(V2);
391           p2 =  BRep_Tool::Pnt(V4);
392           dev = p1.Distance(p2);
393           thePosition = (p1.XYZ()+p2.XYZ())/2;  
394           theBuilder.UpdateVertex(theSecondVer, gp_Pnt(thePosition), dev );
395           //if(theRepVert->Status(V2, temp) != 0) theSecondVer = TopoDS::Vertex (temp); //If this vertex already recorded in map
396           //else 
397           //  if(theRepVert->Status(V4, temp) != 0) theSecondVer = TopoDS::Vertex (temp);
398         }
399         else theSecondVer = V2;
400         
401       }
402       if (!V2.IsSame(theSecondVer))   {
403         if (V2.Orientation()==TopAbs_FORWARD) Context()->Replace(V2, theSecondVer.Oriented(TopAbs_FORWARD));
404         else Context()->Replace(V2, theSecondVer.Oriented(TopAbs_REVERSED));
405         if (V4.Orientation()==TopAbs_FORWARD) Context()->Replace(V4, theSecondVer.Oriented(TopAbs_FORWARD));
406         else Context()->Replace(V4, theSecondVer.Oriented(TopAbs_REVERSED));
407       }
408     }
409   else   {
410       p2 =  BRep_Tool::Pnt(V4);  
411       dev = p1.Distance(p2);
412       if ((dev<=BRep_Tool::Tolerance (V1)) || (dev<=BRep_Tool::Tolerance (V4)) || (dev<=tol)) {
413           if (V1.IsSame(V4))  
414 // #ifdef AIX  CKY : applies to all platforms
415             theFirstVer = V1;
416 //          theFirstVer = TopoDS::Vertex(V1);
417
418           else {
419             dev = (dev/2)*1.0001;
420             thePosition = (p1.XYZ()+p2.XYZ())/2;  
421             theBuilder.UpdateVertex(theFirstVer, gp_Pnt(thePosition), dev );
422         //    if(theRepVert->Status(V1, temp) != 0) theFirstVer = TopoDS::Vertex (temp); //If this vertex already recorded in map
423           //  else 
424           //    if(theRepVert->Status(V4, temp) != 0) theFirstVer = TopoDS::Vertex (temp);
425             if (V1.Orientation()==TopAbs_FORWARD) Context()->Replace(V1, theFirstVer.Oriented(TopAbs_FORWARD));
426             else Context()->Replace(V1, theFirstVer.Oriented(TopAbs_REVERSED));
427             if (V4.Orientation()==TopAbs_FORWARD) Context()->Replace(V4, theFirstVer.Oriented(TopAbs_FORWARD));
428             else Context()->Replace(V4, theFirstVer.Oriented(TopAbs_REVERSED));
429           }
430           if(V1.IsSame(V2) || V3.IsSame(V4))
431             theSecondVer = theFirstVer; 
432           else {
433             
434             if (!V2.IsSame(V3)) {
435               p1 = BRep_Tool::Pnt(V2);
436               p2 =  BRep_Tool::Pnt(V3);
437               dev = p1.Distance(p2);
438               thePosition = (p1.XYZ()+p2.XYZ())/2;  
439               theBuilder.UpdateVertex(theSecondVer, gp_Pnt(thePosition), dev );
440             }
441             else theSecondVer = V2;
442           }
443               //  if(theRepVert->Status(V2, temp) != 0) theSecondVer = TopoDS::Vertex (temp); //If this vertex already recorded in map
444               // else 
445               //  if(theRepVert->Status(V3, temp) != 0) theSecondVer = TopoDS::Vertex (temp);
446           if (!V2.IsSame(theSecondVer)) {
447               if (V2.Orientation()==TopAbs_FORWARD) Context()->Replace(V2, theSecondVer.Oriented(TopAbs_FORWARD));
448             else Context()->Replace(V2, theSecondVer.Oriented(TopAbs_REVERSED));
449             if (V3.Orientation()==TopAbs_FORWARD) Context()->Replace(V3, theSecondVer.Oriented(TopAbs_FORWARD));
450             else Context()->Replace(V3, theSecondVer.Oriented(TopAbs_REVERSED));
451           }
452           
453         } 
454       else {
455 #ifdef OCCT_DEBUG
456         cout << "The face is not strip face"  << endl;
457 #endif
458         return theNewEdge;
459       }
460     }
461   if (theFirstVer.IsNull() || theSecondVer.IsNull()) return theNewEdge;
462   //Cretate new edge 
463   theBuilder.MakeEdge(theNewEdge);
464   Standard_Real f, l, fp1, lp1/*, fp2, lp2*/;
465   TopLoc_Location loc;
466   Handle(Geom_Curve) the3dcurve;
467   the3dcurve = BRep_Tool::Curve(E1, f, l);
468   Handle(Geom2d_Curve) the2dcurve1, the2dcurve2, thenew1, thenew2;
469   if (!F1.IsNull())   
470     {
471       the2dcurve1 = BRep_Tool::CurveOnSurface(E1, F1, fp1, lp1);
472       if(!the2dcurve1.IsNull() && fp1!=f && lp1!=l) GeomLib::SameRange(Precision::Confusion(), the2dcurve1, fp1, lp1, f, l, thenew1);  
473     }
474       
475  /* if (!F2.IsNull())   
476     {
477       the2dcurve2 = BRep_Tool::CurveOnSurface(E2, F2, fp2, lp2);
478       if(!the2dcurve2.IsNull()) GeomLib::SameRange(Precision::Confusion(), the2dcurve2, fp2, lp2, f, l, thenew2); 
479     }*/
480   
481   Standard_Real maxdev; 
482   if ((BRep_Tool::Tolerance(theFirstVer))<=(BRep_Tool::Tolerance(theSecondVer))) 
483     maxdev = (BRep_Tool::Tolerance(theSecondVer));
484   else  maxdev = (BRep_Tool::Tolerance(theFirstVer));
485   theBuilder.UpdateVertex(theFirstVer, maxdev);
486   theBuilder.UpdateVertex(theSecondVer, maxdev);
487   //Standard_Boolean IsFree = Standard_True;
488   theBuilder.SameParameter(theNewEdge, Standard_False);
489   the3dcurve = BRep_Tool::Curve(E1, f, l);
490   theBuilder.UpdateEdge(theNewEdge, the3dcurve, maxdev);
491   theBuilder.Range(theNewEdge, f, l);
492   if (!F1.IsNull() && !thenew1.IsNull())  
493     {
494       theBuilder.UpdateEdge(theNewEdge, thenew1, F1, maxdev); 
495       //IsFree = Standard_False;
496     }
497   /*if (!F2.IsNull() && !thenew2.IsNull())
498     {
499       theBuilder.UpdateEdge(theNewEdge, thenew2, F2, maxdev);
500       IsFree = Standard_False;
501     }*/
502   theBuilder.Add(theNewEdge, theFirstVer.Oriented(TopAbs_FORWARD));
503   theBuilder.Add(theNewEdge, theSecondVer.Oriented(TopAbs_REVERSED));
504   //Call fixsameparameter for computing distance between 3d and pcurves, if edge is not free
505 //   if (!IsFree)
506 //     {
507 //       ShapeFix_Edge sfe;
508 //       if (!F1.IsNull() && !thenew1.IsNull()) sfe.FixReversed2d(theNewEdge, F1);
509 //       if (!F2.IsNull() && !thenew2.IsNull()) sfe.FixReversed2d(theNewEdge, F2);
510 //       sfe.FixSameParameter(theNewEdge, maxdev);
511 //     }
512   return theNewEdge;
513
514
515 }
516
517  TopoDS_Shape ShapeFix_FixSmallFace::FixSplitFace(const TopoDS_Shape& /*S*/) 
518 {
519   if (myShape.IsNull()) return myShape;
520   TopAbs_ShapeEnum st = myShape.ShapeType();
521   Standard_Boolean done = Standard_False;
522   TopoDS_Compound theSplittedFaces;
523   BRep_Builder theBuilder;
524   if (st == TopAbs_COMPOUND || st == TopAbs_COMPSOLID ||
525       st == TopAbs_SOLID || st ==  TopAbs_SHELL || st ==  TopAbs_FACE) {
526     for (TopExp_Explorer itf (myShape,TopAbs_FACE); itf.More(); itf.Next()) {
527       TopoDS_Face F = TopoDS::Face (itf.Current());
528       TopoDS_Compound CompSplittedFaces;
529       theBuilder.MakeCompound(CompSplittedFaces);
530       if(SplitOneFace(F, CompSplittedFaces)) {
531         done = Standard_True;
532         Context()->Replace(F, CompSplittedFaces);
533       }
534     }
535   }
536   if(done) myStatus = ShapeExtend::EncodeStatus ( ShapeExtend_DONE3 );
537   myShape = Context()->Apply(myShape);
538   myResult = myShape;
539   return myShape;
540 }
541
542  TopoDS_Shape ShapeFix_FixSmallFace::SplitFaces() 
543 {
544    myShape = RemoveSmallFaces();
545    myResult = myShape;
546   return myShape;
547
548 }
549
550  Standard_Boolean ShapeFix_FixSmallFace::SplitOneFace(TopoDS_Face& F,TopoDS_Compound& theSplittedFaces) 
551 {
552   TopTools_DataMapOfShapeListOfShape MapEdges; 
553   ShapeAnalysis_DataMapOfShapeListOfReal MapParam;
554   TopoDS_Compound theAllVert;
555   BRep_Builder theBuilder;
556   theBuilder.MakeCompound(theAllVert);
557 //smh#8
558   TopoDS_Shape tmpShape = Context()->Apply(F);
559   F = TopoDS::Face(tmpShape);
560   if (myAnalyzer.CheckSplittingVertices(F,MapEdges,MapParam,theAllVert) != 0) 
561     {
562       TopoDS_Wire tempwire;
563       //Take information about splitting vertices
564       if (theAllVert.IsNull()) return Standard_False;
565       //Standard_Integer i;
566       TopoDS_Vertex V;
567       TopExp_Explorer itc(theAllVert,TopAbs_VERTEX); V = TopoDS::Vertex (itc.Current());
568       if (V.IsNull()) return Standard_False;
569       gp_Pnt proj;
570       gp_Pnt vp = BRep_Tool::Pnt(V);
571       TopoDS_Vertex theNewVertex;
572       TopoDS_Edge E;
573       TopoDS_Edge theFirstEdge, theSecondEdge;
574       
575       {
576         //If one vertex presents do splitting by two faces
577         ShapeAnalysis_Curve SAC;
578         for (TopExp_Explorer ite(F,TopAbs_EDGE); ite.More(); ite.Next()) {
579           E = TopoDS::Edge (ite.Current());
580           TopoDS_Vertex V1,V2;
581           TopExp::Vertices (E,V1,V2);
582           Standard_Real cf,cl;
583           Handle(Geom_Curve) C3D = BRep_Tool::Curve (E,cf,cl);
584           if (C3D.IsNull()) continue;
585           if (V.IsSame(V1) || V.IsSame(V2)) continue;
586           Standard_Real vt = BRep_Tool::Tolerance (V);
587           Standard_Real param;
588           Standard_Real dist = SAC.Project (C3D,vp,vt*10.,proj,param,cf,cl);
589           if (dist==0) continue; //Projection on same curve but on other edge ?
590           if ( dist <= vt ) 
591             {
592               theBuilder.MakeVertex(theNewVertex);
593               theBuilder.UpdateVertex(theNewVertex, proj, Precision::Confusion());
594               theBuilder.MakeEdge(theFirstEdge);
595               theBuilder.MakeEdge(theSecondEdge);
596               Standard_Real f, l;
597               Handle(Geom_Curve) the3dcurve = BRep_Tool::Curve(E, f, l);
598               theBuilder.UpdateEdge(theFirstEdge, the3dcurve,Precision::Confusion());
599               theBuilder.UpdateEdge(theSecondEdge, the3dcurve,Precision::Confusion());
600               if (V1.Orientation()==TopAbs_FORWARD) 
601                 {
602                   theBuilder.Add(theFirstEdge, V1);
603                   theBuilder.Add(theFirstEdge,theNewVertex.Oriented(TopAbs_REVERSED));
604                   theBuilder.Add(theSecondEdge,theNewVertex.Oriented(TopAbs_FORWARD));
605                   theBuilder.Add(theSecondEdge, V2);
606                 }
607               else {
608                 theBuilder.Add(theFirstEdge,V2);
609                 theBuilder.Add(theFirstEdge,theNewVertex.Oriented(TopAbs_REVERSED));
610                 theBuilder.Add(theSecondEdge,theNewVertex.Oriented(TopAbs_FORWARD));
611                 theBuilder.Add(theSecondEdge, V1);
612               }
613               theBuilder.Range(theFirstEdge, cf, param);
614               theBuilder.Range(theSecondEdge, param, cl);
615               //Replace old edge by two new edges
616               TopoDS_Wire twoedges;
617               theBuilder.MakeWire(twoedges);
618               if (E.Orientation() == TopAbs_FORWARD)
619                 {
620                   theBuilder.Add(twoedges, theFirstEdge.Oriented(TopAbs_FORWARD));
621                   theBuilder.Add(twoedges, theSecondEdge.Oriented(TopAbs_FORWARD));
622                 }
623               else 
624                 {
625                   theBuilder.Add(twoedges, theFirstEdge.Oriented(TopAbs_REVERSED));
626                   theBuilder.Add(twoedges, theSecondEdge.Oriented(TopAbs_REVERSED));
627                 }
628               Context()->Replace(E, twoedges);
629               break;
630             }
631         }
632         if (theNewVertex.IsNull()) return Standard_False;
633         //Create split edge
634         TopoDS_Edge theSplitEdge;
635         gp_Lin lin(vp, gp_Dir(gp_Vec( vp, proj)));
636         Standard_Real firstparam = ElCLib::Parameter(lin, vp);
637         Standard_Real lastparam = ElCLib::Parameter(lin, proj);
638         Handle(Geom_Line) L = new Geom_Line( vp, gp_Vec( vp, proj));
639         Handle(Geom_Curve) the3dc = L;
640         theBuilder.MakeEdge(theSplitEdge, the3dc, Precision::Confusion());
641         theBuilder.Add(theSplitEdge, V.Oriented(TopAbs_FORWARD));
642         theBuilder.Add(theSplitEdge, theNewVertex.Oriented(TopAbs_REVERSED));  
643         theBuilder.Range(theSplitEdge, firstparam, lastparam);
644         //Add pcurve in new edge
645         Handle(ShapeFix_Edge) sfe = new ShapeFix_Edge;
646         sfe->FixAddPCurve(theSplitEdge, F, Standard_False);
647         //Reorder the wire 
648         TopoDS_Wire wireonface;
649         //Inher loop is not support yet !!!
650         TopExp_Explorer itw(F,TopAbs_WIRE);
651         wireonface = TopoDS::Wire (itw.Current());
652         itw.Next();
653         if (itw.More()) return Standard_False; //if face contains more than one wire  
654         Handle(ShapeFix_Wire) sfw = new ShapeFix_Wire;
655         sfw->Init(wireonface, F, Precision::Confusion());
656         sfw->FixReorder();
657         wireonface = sfw->Wire();
658         
659         //Create two new wires
660         TopoDS_Wire w1, w2;
661         theBuilder.MakeWire(w1);
662         theBuilder.MakeWire(w2);
663         theBuilder.MakeWire(tempwire);
664         for (TopExp_Explorer itnew(wireonface, TopAbs_EDGE ); itnew.More(); itnew.Next()) 
665           {
666             TopoDS_Edge ce = TopoDS::Edge (itnew.Current());
667             if (ce.IsSame(E)) 
668               { 
669                 theBuilder.Remove(wireonface, ce);
670                 theBuilder.Add(wireonface, theFirstEdge.Oriented(TopAbs_FORWARD)); 
671                 theBuilder.Add(wireonface, theSecondEdge.Oriented(TopAbs_FORWARD)); 
672               }
673           }
674         sfw->Init(wireonface, F, Precision::Confusion());
675         sfw->FixReorder();
676         wireonface = sfw->Wire();
677           
678         for (TopExp_Explorer itere(wireonface, TopAbs_EDGE); itere.More(); itere.Next()) 
679           {
680             TopoDS_Edge ce = TopoDS::Edge (itere.Current());
681             TopoDS_Vertex thecontrol;
682             if (ce.Orientation () == TopAbs_FORWARD) thecontrol = TopExp::LastVertex(ce);  
683             else thecontrol = TopExp::FirstVertex(ce);
684             theBuilder.Add(w1, ce);
685             if (thecontrol.IsSame(V))
686               {
687                 theBuilder.Add(w1, theSplitEdge.Oriented(TopAbs_FORWARD));
688                 TopoDS_Wire wtemp = w1;
689                 w1 = w2;
690                 w2 = wtemp;
691               }
692             if (thecontrol.IsSame(theNewVertex))
693               {
694                 theBuilder.Add(w1, theSplitEdge.Oriented(TopAbs_REVERSED));
695                 TopoDS_Wire wtemp = w1;
696                 w1 = w2;
697                 w2 = wtemp;
698               }
699           }
700         if ( w1.IsNull()|| w2.IsNull() ) return Standard_False;
701         //Create two new faces and replace old one
702         TopoDS_Face F1;
703         TopoDS_Face F2;
704         theBuilder.MakeFace(F1, BRep_Tool::Surface(F), Precision::Confusion());
705         theBuilder.MakeFace(F2, BRep_Tool::Surface(F), Precision::Confusion());      
706         theBuilder.Add(F1, w1);
707         theBuilder.Add(F2, w2);
708         TopoDS_Compound tf;
709         theBuilder.MakeCompound(tf);
710         theBuilder.Add(tf,F1);
711         theBuilder.Add(tf, F2);
712  //Call recursive spliteoneface() for each face     
713         if(!SplitOneFace(F1, theSplittedFaces)) theBuilder.Add(theSplittedFaces, F1);
714         if(!SplitOneFace(F2, theSplittedFaces)) theBuilder.Add(theSplittedFaces, F2);
715       }
716       return Standard_True ;
717     }
718   return Standard_False ;
719 }
720
721
722  TopoDS_Shape ShapeFix_FixSmallFace::RemoveSmallFaces() 
723 {
724    myShape = SplitFaces();
725    myShape = FixSpotFace();
726    myShape = FixStripFace ();
727    return myShape;
728
729 }
730
731  TopoDS_Face ShapeFix_FixSmallFace::FixFace(const TopoDS_Face& F) 
732 {
733 //smh#8
734   TopoDS_Shape emptyCopied = F.EmptyCopied();
735   TopoDS_Face theFixedFace = TopoDS::Face(emptyCopied);
736  // BRep_Builder theBuilder;
737   
738  // Handle(ShapeFix_Wire) sfw = new ShapeFix_Wire;
739  // sfw->SetContext(Context());
740  // for (TopExp_Explorer exp_w (F,TopAbs_WIRE); exp_w.More(); exp_w.Next()) {
741  //   TopoDS_Wire theCurWire = TopoDS::Wire (exp_w.Current());
742     
743  //   sfw->Init(theCurWire,  F, Precision::Confusion());
744  //   if(sfw->NbEdges() == 0) continue;
745  //   sfw->FixNotchedEdgesMode() = 0;
746  //   sfw->Perform();
747  //   theCurWire = sfw->Wire();
748  //   theBuilder.Add(theFixedFace, theCurWire);
749  // }
750   Handle(ShapeFix_Face) sff = new ShapeFix_Face;
751   sff->SetContext(Context());
752   sff->Init(F);
753   sff->Perform();
754   //sff->Init(theFixedFace);
755   //sff->FixOrientation();
756   theFixedFace = sff->Face();
757   return theFixedFace; 
758 }
759
760  TopoDS_Shape ShapeFix_FixSmallFace::FixShape() 
761 {
762   TopoDS_Shape FixSh;
763   if(myShape.IsNull()) return FixSh;
764   /*ShapeFix_Shape sfs;
765   sfs.SetContext(Context());
766
767   sfs.SetPrecision(Precision::Confusion());
768   sfs.Init(myShape);
769   sfs.Perform();
770   FixSh = sfs.Shape();*/
771   for(TopExp_Explorer expf(myShape,TopAbs_FACE) ; expf.More(); expf.Next()) {
772    TopoDS_Face F = TopoDS::Face(expf.Current());
773 //smh#8
774    TopoDS_Shape tmpFace = Context()->Apply(F);
775    F= TopoDS::Face(tmpFace);
776    TopoDS_Face newF = FixFace(F);
777    Context()->Replace(F,newF);
778   }
779   FixSh = Context()->Apply(myShape);  
780   return FixSh;
781
782 }
783  TopoDS_Shape ShapeFix_FixSmallFace::Shape() 
784 {
785   return myShape;
786 }
787
788 Standard_Boolean ShapeFix_FixSmallFace::FixPinFace (TopoDS_Face& /*F*/)
789 {
790   return Standard_True;
791 }