Salome HOME
Modified a method createAndDisplayGO
[modules/geom.git] / src / ShHealOper / ShHealOper_CloseContour.cxx
1 // File:      ShHealOper_CloseContour.cxx
2 // Created:   20.04.04 11:36:01
3 // Author:    Galina KULIKOVA
4 // Copyright: Airbus Industries 2004
5
6
7 #include <ShHealOper_CloseContour.hxx>
8 #include <ShapeExtend_WireData.hxx>
9 #include <ShapeFix_Wire.hxx>
10 #include <TopoDS_Face.hxx>
11 #include <ShapeFix_Edge.hxx>
12 #include <TopoDS_Iterator.hxx>
13 #include <ShapeAnalysis_Wire.hxx>
14 #include <TColStd_SequenceOfInteger.hxx>
15 #include <TopTools_IndexedMapOfShape.hxx>
16 #include <TopoDS_Edge.hxx>
17 #include <TopTools_ListOfShape.hxx>
18 #include <TopTools_ListIteratorOfListOfShape.hxx>
19 #include <TColStd_MapOfInteger.hxx>
20 #include <TopExp.hxx>
21 #include <TopoDS.hxx>
22 #include <TColStd_MapIteratorOfMapOfInteger.hxx>
23 #include <ShapeAnalysis_Edge.hxx>
24 #include <BRep_Builder.hxx>
25 #include <TopoDS_Edge.hxx>
26 #include <TopoDS_Vertex.hxx>
27 #include <BRepBuilderAPI_MakeVertex.hxx>
28 #include <ShapeAnalysis_Edge.hxx>
29 #include <gp_Pnt.hxx>
30 #include <gp_Vec2d.hxx>
31 #include <gp_Vec.hxx>
32 #include <Geom_Line.hxx>
33 #include <Geom2d_Line.hxx>
34 #include <TopoDS_Compound.hxx>
35 #include <BRep_Tool.hxx>
36 #include <ShapeBuild_Edge.hxx>
37 #include <TopExp_Explorer.hxx>
38 //=======================================================================
39 //function : ShHealOper_CloseContour()
40 //purpose  : Constructor
41 //=======================================================================
42
43 ShHealOper_CloseContour::ShHealOper_CloseContour (const TopoDS_Shape& theShape  ) 
44 {
45   Init(theShape);
46 }
47 //=======================================================================
48 //function : Init
49 //purpose  : 
50 //=======================================================================
51
52 void ShHealOper_CloseContour::Init(const TopoDS_Shape& theShape)
53 {
54   ShHealOper_Tool::Init(theShape);
55   myTolerance = Precision::Confusion();
56   myMaxTolerance = 1.0;
57   TopExp::MapShapesAndAncestors(theShape,TopAbs_EDGE,TopAbs_FACE,myMapEdgesFace);
58 }
59 //=======================================================================
60 //function : Perform
61 //purpose  : 
62 //=======================================================================
63
64 Standard_Boolean ShHealOper_CloseContour::Perform(const TopTools_SequenceOfShape& theSeqEdges,
65                                                   const Standard_Boolean theModeVertex,
66                                                   const Standard_Boolean theModeFixGapsCurves)
67 {
68   myFreeEdges.Clear();
69   myDone = Standard_False;
70   myErrorStatus =ShHealOper_NotError;
71   if(myInitShape.IsNull()) {
72     myErrorStatus = ShHealOper_InvalidParameters;
73     return myDone;
74   }
75   Handle(ShapeExtend_WireData) asewd = new ShapeExtend_WireData;
76   Standard_Integer i =1;
77   for ( ; i <= theSeqEdges.Length(); i++)
78     asewd->Add(theSeqEdges.Value(i));
79
80   myModeVertex = theModeVertex;
81   myModeFixGapsCurves = theModeFixGapsCurves;
82
83   build(asewd);
84   
85   return myDone;
86 }
87 //=======================================================================
88 //function : Perform
89 //purpose  : 
90 //=======================================================================
91
92 Standard_Boolean ShHealOper_CloseContour::Perform(const TopoDS_Wire& theWire,
93                                                   const Standard_Boolean theModeVertex,
94                                                   const Standard_Boolean theModeFixGapsCurves)
95 {
96   myFreeEdges.Clear();
97   myDone = Standard_False;
98   if(myInitShape.IsNull()) {
99     myErrorStatus = ShHealOper_InvalidParameters;
100     return myDone;
101   }
102   Handle(ShapeExtend_WireData) asewd = new ShapeExtend_WireData(theWire);
103   myModeVertex = theModeVertex;
104   myModeFixGapsCurves = theModeFixGapsCurves;
105   build(asewd);
106   return myDone;
107 }
108 //=======================================================================
109 //function : Build
110 //purpose  : 
111 //=======================================================================
112
113 void ShHealOper_CloseContour::build(Handle(ShapeExtend_WireData)& theSewd)
114 {
115   TopTools_SequenceOfShape aCommonFaces;
116   //checks that all specified edges belong the one face or not.
117   Standard_Boolean isOneFace = checkOneFace(theSewd,aCommonFaces);
118
119   //add edge or increase max tolerance in dependance on specified VertexMode.
120   //if all edges belong the one face that gap will be closed in the 2D by line
121   //else gap will be closed in the 3D by line.
122   myDone = fixGaps(theSewd,aCommonFaces);
123   updateWire(theSewd);
124   Handle(ShapeFix_Wire) sfw = new ShapeFix_Wire;
125   sfw->SetContext(myContext);
126   sfw->Load(theSewd);
127
128   sfw->ClosedWireMode() = Standard_True;
129   sfw->SetPrecision(myTolerance);
130   sfw->SetMaxTolerance(myMaxTolerance);
131   
132   if(isOneFace) {
133     Standard_Integer ii =1;
134     for( ; ii <= aCommonFaces.Length(); ii++) {
135       TopoDS_Face aFace = TopoDS::Face(aCommonFaces.Value(ii));
136       sfw->SetFace(aFace);
137       myDone = (sfw->Perform() || myDone);
138       //if Mode for fix gaps is equal to true that
139       //curve 3D and curve 2D will be pull to each other.
140       if(myModeFixGapsCurves) {
141         Standard_Boolean isFixgaps = Standard_False;
142         if(ii ==1) {
143           sfw->FixGaps3d();
144           isFixgaps = sfw->StatusGaps3d(ShapeExtend_DONE);
145           if(!isFixgaps && sfw->StatusGaps3d(ShapeExtend_FAIL))
146              myErrorStatus = ShHealOper_ErrorExecution;
147         }
148         if(sfw->FixGaps2d())
149           sfw->FixSelfIntersection();
150         else if(sfw->StatusGaps2d(ShapeExtend_FAIL))
151           myErrorStatus = ShHealOper_ErrorExecution;
152
153         isFixgaps = (isFixgaps || sfw->StatusGaps2d(ShapeExtend_DONE));
154         myDone = (myDone || isFixgaps);
155         if(isFixgaps) {
156           Handle(ShapeExtend_WireData) sbwd = sfw->WireData();
157           Handle(ShapeFix_Edge) sfe = new ShapeFix_Edge;
158           for (Standard_Integer iedge = 1; iedge <= sbwd->NbEdges(); iedge++) {
159             TopoDS_Edge aEdge = TopoDS::Edge(sbwd->Edge(iedge));
160             sfe->FixVertexTolerance(aEdge,aFace);
161             sfe->FixSameParameter(aEdge);
162           }
163         }
164       }
165     }
166   }
167   else {
168     myDone = (sfw->Perform() || myDone);
169     if(myModeFixGapsCurves) {
170       //if Mode for fix gaps is equal to true that
171       //curve 3D will be pull to each other.
172       if(sfw->FixGaps3d()) {
173         Handle(ShapeExtend_WireData) sbwd = sfw->WireData();
174         Handle(ShapeFix_Edge) sfe = new ShapeFix_Edge;
175         for (Standard_Integer iedge = 1; iedge <= sbwd->NbEdges(); iedge++) {
176           TopoDS_Edge aEdge = TopoDS::Edge(sbwd->Edge(iedge));
177           sfe->FixVertexTolerance(aEdge);
178           sfe->FixSameParameter(aEdge);
179         }
180       }
181       else if(sfw->StatusGaps3d(ShapeExtend_FAIL))
182         myErrorStatus = ShHealOper_ErrorExecution;
183       myDone = (sfw->StatusGaps3d(ShapeExtend_DONE) || myDone);
184     }
185   }
186
187   if(myDone) {
188     TopoDS_Shape aoldShape = myInitShape;
189     //if free edges were added they will be added to the result shape
190     //and type of result shape should be change if initial shape is not COMPOUND.
191     if( myFreeEdges.Length()) {
192       BRep_Builder aB;
193       TopoDS_Compound aComp;
194       aB.MakeCompound(aComp);
195       if(aoldShape.ShapeType() == TopAbs_COMPOUND) {
196         TopoDS_Iterator aIt(aoldShape);
197         for( ;aIt.More();aIt.Next() )
198            aB.Add(aComp,aIt.Value());
199       }
200       else
201         aB.Add(aComp,aoldShape);
202
203       Standard_Integer i=1;
204       for ( ; i <= myFreeEdges.Length(); i++ ) 
205         aB.Add(aComp,myFreeEdges.Value(i));
206       aoldShape = aComp;
207       
208     }
209     myResultShape = myContext->Apply(aoldShape);
210   }
211   return;
212 }
213 //=======================================================================
214 //function : checkGaps
215 //purpose  : 
216 //=======================================================================
217
218 Standard_Boolean ShHealOper_CloseContour::fixGaps(const Handle(ShapeExtend_WireData)& theWire,
219                                                   const TopTools_SequenceOfShape& theCommonFaces) 
220 {
221   Handle(ShapeAnalysis_Wire) asaw = new ShapeAnalysis_Wire;
222   asaw->Load(theWire);
223   
224   Standard_Integer i =1;
225   Standard_Boolean hasGaps = Standard_False;
226   for ( ; i <= asaw->NbEdges(); i++) {
227     if(asaw->CheckGap3d(i)) {
228       Standard_Real dist = asaw->MinDistance3d();
229       if(dist > myMaxTolerance) {
230         hasGaps = Standard_True;
231         Standard_Integer ind2 = (i ==0 ? theWire->NbEdges() :i);
232         Standard_Integer ind1 = (ind2 >1 ? ind2 -1 : theWire->NbEdges());
233         TopoDS_Edge aE1= theWire->Edge(ind1);
234         TopoDS_Edge aE2= theWire->Edge(ind2);
235         if(!myModeVertex)
236           buildEdge(aE1,aE2,theCommonFaces);
237         else
238           myMaxTolerance = RealLast();
239         if(ind2 == ind1) break;
240       }
241     }
242     
243   }
244   return  hasGaps;
245 }
246
247 //=======================================================================
248 //function : checkOneFace
249 //purpose  : 
250 //=======================================================================
251
252 Standard_Boolean ShHealOper_CloseContour::checkOneFace(const Handle(ShapeExtend_WireData)& theSewd,
253                                                        TopTools_SequenceOfShape& theCommonFaces) const
254 {
255   
256   TopTools_IndexedMapOfShape amapfaces;
257   TopoDS_Edge aEdge1 = theSewd->Edge(1);
258   Standard_Boolean isOneFace = myMapEdgesFace.Contains(aEdge1 );
259   if(!isOneFace)
260     return isOneFace;
261
262   //check that all specified edges belong to one face. 
263   const TopTools_ListOfShape& alfaces = myMapEdgesFace.FindFromKey(aEdge1);
264   isOneFace = isOneFace && (!alfaces.IsEmpty());
265   if(!isOneFace)
266     return Standard_False;
267
268   TopTools_ListIteratorOfListOfShape litr(alfaces);
269   for( ; litr.More();litr.Next() ) 
270     amapfaces.Add(litr.Value());
271   
272   TColStd_MapOfInteger amapIndex;
273   Standard_Integer ind  =0;
274   Standard_Integer i =2;
275   for( ; i <= theSewd->NbEdges() && isOneFace; i++) {
276     isOneFace = myMapEdgesFace.Contains(theSewd->Edge(i));
277     if(isOneFace) {
278       const TopTools_ListOfShape& alfaces1 = myMapEdgesFace.FindFromKey(theSewd->Edge(i));
279       
280         TColStd_MapOfInteger aTmpInd;
281         for(litr.Initialize(alfaces1) ; litr.More() ;litr.Next() ) {
282           if(amapfaces.Contains(litr.Value())) {
283             ind = amapfaces.FindIndex(litr.Value());
284             if( i == 2) 
285               amapIndex.Add(ind);
286             else 
287               aTmpInd.Add(ind);
288           }
289         }
290       if(i ==2) {
291         isOneFace = (amapIndex.Extent());
292         continue;
293       }
294       else {
295         TColStd_MapIteratorOfMapOfInteger aMi(amapIndex);
296         for( ;  aMi.More();aMi.Next()) {
297           if(!aTmpInd.Contains(aMi.Key()))
298             amapIndex.Remove(aMi.Key());
299         }
300         isOneFace = (amapIndex.Extent()); 
301         
302       }
303     }
304   }
305   if(theSewd->NbEdges() >1) {
306     Standard_Integer j =1;
307     for( ; j <= amapfaces.Extent(); j++) {
308       if(!amapIndex.Contains(j)) continue;
309       TopoDS_Shape aF = amapfaces.FindKey(j);
310       theCommonFaces.Append(aF);
311     }
312   }
313   return isOneFace;  
314 }
315 //=======================================================================
316 //function : buildEdge
317 //purpose  : 
318 //=======================================================================
319
320 void ShHealOper_CloseContour::buildEdge(const TopoDS_Edge& aE1, 
321                                         const TopoDS_Edge& aE2,
322                                         const TopTools_SequenceOfShape& theCommonFaces) 
323 {
324   ShapeAnalysis_Edge asae;
325   TopoDS_Vertex aV1 = asae.LastVertex(aE1);
326   TopoDS_Vertex aV2 = asae.FirstVertex(aE2);
327   gp_Pnt p1 = BRep_Tool::Pnt(aV1);
328   gp_Pnt p2 = BRep_Tool::Pnt(aV2);
329   BRepBuilderAPI_MakeVertex mkver1( p1 );
330   TopoDS_Vertex newV1 = mkver1.Vertex();
331   
332   BRepBuilderAPI_MakeVertex mkver2( p2 );
333   TopoDS_Vertex newV2 = mkver2.Vertex();
334   BRep_Builder B;
335   B.UpdateVertex ( newV1,Precision::Confusion());
336   B.UpdateVertex ( newV2, Precision::Confusion());
337   Standard_Boolean isBuild = Standard_False;
338   TopoDS_Edge edge;
339   B.MakeEdge ( edge );
340   ShapeBuild_Edge sbe;
341   //if all edges belong to one face that gap will be closed in the 2D by line
342   //than 3D curve will be built by 2D curve
343   if(theCommonFaces.Length()) {
344     
345     TopoDS_Face aF1 = TopoDS::Face(theCommonFaces.Value(1));
346     Handle(Geom2d_Curve) c2d1,c2d2;
347     gp_Pnt2d p2d1,p2d2;
348     Standard_Real a1, b1,a2, b2;
349     if (  asae.PCurve ( aE1, aF1, c2d1, a1, b1, Standard_True )  && 
350         asae.PCurve ( aE2, aF1, c2d2, a2, b2, Standard_True )) {
351       
352       c2d1->D0 ( b1, p2d1);
353       c2d2->D0 ( a2, p2d2);
354       gp_Vec2d v12 ( p2d1, p2d2 );
355       
356       Handle(Geom2d_Line) aLine2d = new Geom2d_Line ( p2d1, gp_Dir2d ( v12 ) );
357       B.UpdateEdge ( edge, aLine2d, aF1, ::Precision::Confusion() );
358       B.Range ( edge, aF1, 0.0, v12.Magnitude() );
359       
360       isBuild = sbe.BuildCurve3d ( edge );
361     }
362   }
363   //else gap will be closed in the 3D by line.
364   if(!isBuild) {
365     gp_Vec v1 ( p1, p2 );
366     Handle(Geom_Line) aLine = new Geom_Line ( p1, gp_Dir ( v1 ) );
367     B.UpdateEdge ( edge, aLine, ::Precision::Confusion() );
368     B.Range ( edge,0.0, v1.Magnitude());
369   }
370   B.Add ( edge, newV1.Oriented ( TopAbs_FORWARD ) );
371   B.Add ( edge, newV2.Oriented ( TopAbs_REVERSED ) );
372   myContext->Replace(aV1, newV1.Oriented (aV1.Orientation()));
373   myContext->Replace(aV2, newV2.Oriented (aV2.Orientation()));
374   if(isBuild) {
375     newV1.Orientation(aV1.Orientation());
376     TopoDS_Edge newEdge = sbe.CopyReplaceVertices ( aE1,TopoDS_Vertex(), newV1);
377     TopoDS_Wire aw;
378     B.MakeWire(aw);
379     B.Add(aw,newEdge);
380     B.Add(aw,edge);
381     TopoDS_Shape anE1 = myContext->Apply(aE1);
382     myContext->Replace(anE1,aw);
383   }
384   else {
385     myFreeEdges.Append(edge);
386   }
387 }
388 //=======================================================================
389 //function : UpdateWire
390 //purpose  : 
391 //=======================================================================
392
393 void ShHealOper_CloseContour::updateWire (Handle(ShapeExtend_WireData)& sbwd) 
394 {
395   Standard_Integer i=1;
396   for ( ; i <= sbwd->NbEdges(); i++ ) {
397     TopoDS_Edge E = sbwd->Edge(i);
398     TopoDS_Shape S = myContext->Apply ( E );
399     if ( S == E ) continue;
400     for ( TopExp_Explorer exp(S,TopAbs_EDGE); exp.More(); exp.Next() )
401       sbwd->Add ( exp.Current(), i++ );
402     sbwd->Remove ( i-- );
403   }
404   for ( i =1; i <= myFreeEdges.Length(); i++ ) {
405     sbwd->Add(TopoDS::Edge(myFreeEdges.Value(i)));
406   }
407 }