Salome HOME
e513cbe59dfadf8f2515e8bcd04e85ef61021ffa
[modules/geom.git] / src / GEOMAlgo / BlockFix_UnionFaces.cxx
1 //  Copyright (C) 2007-2008  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 //  Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 //  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 //  This library is free software; you can redistribute it and/or
7 //  modify it under the terms of the GNU Lesser General Public
8 //  License as published by the Free Software Foundation; either
9 //  version 2.1 of the License.
10 //
11 //  This library is distributed in the hope that it will be useful,
12 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 //  Lesser General Public License for more details.
15 //
16 //  You should have received a copy of the GNU Lesser General Public
17 //  License along with this library; if not, write to the Free Software
18 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 //  See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22 // File:        BlockFix_UnionFaces.cxx
23 // Created:     Tue Dec  7 17:15:42 2004
24 // Author:      Pavel DURANDIN
25 //
26
27 #include <BlockFix_UnionFaces.ixx>
28
29 #include <ShapeAnalysis_WireOrder.hxx>
30 #include <ShapeAnalysis_Edge.hxx>
31
32 #include <ShapeBuild_Edge.hxx>
33 #include <ShapeBuild_ReShape.hxx>
34
35 #include <ShapeExtend_WireData.hxx>
36 #include <ShapeExtend_CompositeSurface.hxx>
37
38 #include <ShapeFix_Face.hxx>
39 #include <ShapeFix_ComposeShell.hxx>
40 #include <ShapeFix_SequenceOfWireSegment.hxx>
41 #include <ShapeFix_WireSegment.hxx>
42 #include <ShapeFix_Wire.hxx>
43 #include <ShapeFix_Edge.hxx>
44
45 #include <BRep_Tool.hxx>
46 #include <BRep_Builder.hxx>
47 #include <BRepTools.hxx>
48
49 #include <TopExp.hxx>
50 #include <TopExp_Explorer.hxx>
51
52 #include <TopTools_SequenceOfShape.hxx>
53 #include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
54 #include <TopTools_ListOfShape.hxx>
55 #include <TopTools_ListIteratorOfListOfShape.hxx>
56 #include <TopTools_MapOfShape.hxx>
57 #include <TopTools_MapIteratorOfMapOfShape.hxx>
58
59 #include <TopoDS.hxx>
60 #include <TopoDS_Edge.hxx>
61 #include <TopoDS_Wire.hxx>
62 #include <TopoDS_Face.hxx>  
63 #include <TopoDS_Solid.hxx>
64 #include <TopoDS_Vertex.hxx>
65 #include <TopoDS_Shell.hxx>
66 #include <TopoDS_Iterator.hxx>
67
68 #include <TColGeom_HArray2OfSurface.hxx>
69
70 #include <Geom_Plane.hxx>
71 #include <Geom_OffsetSurface.hxx>
72 #include <Geom_CylindricalSurface.hxx>
73 #include <Geom_SphericalSurface.hxx>
74 #include <Geom_Surface.hxx>
75 #include <Geom_Curve.hxx>
76 #include <Geom_RectangularTrimmedSurface.hxx>
77
78 #include <Geom2d_Line.hxx>
79
80 #include <gp_XY.hxx>
81 #include <gp_Pnt2d.hxx>
82   
83 //=======================================================================
84 //function : BlockFix_UnionFaces
85 //purpose  : 
86 //=======================================================================
87
88 BlockFix_UnionFaces::BlockFix_UnionFaces()
89      : myTolerance(Precision::Confusion())
90 {
91 }
92
93
94 //=======================================================================
95 //function : GetTolearnce
96 //purpose  : 
97 //=======================================================================
98
99 Standard_Real& BlockFix_UnionFaces::GetTolerance()
100 {
101   return myTolerance;
102 }
103
104
105 //=======================================================================
106 //function : AddOrdinaryEdges
107 //purpose  : auxilary
108 //=======================================================================
109 // adds edges from the shape to the sequence
110 // seams and equal edges are dropped
111 // Returns true if one of original edges dropped
112 static Standard_Boolean AddOrdinaryEdges(TopTools_SequenceOfShape& edges,
113                                          const TopoDS_Shape aShape,
114                                          Standard_Integer& anIndex)
115 {
116   //map of edges
117   TopTools_MapOfShape aNewEdges;
118   //add edges without seams
119   for(TopExp_Explorer exp(aShape,TopAbs_EDGE); exp.More(); exp.Next()) {
120     TopoDS_Shape edge = exp.Current();
121     if(aNewEdges.Contains(edge))
122       aNewEdges.Remove(edge);
123     else
124       aNewEdges.Add(edge);
125   }
126
127   Standard_Boolean isDropped = Standard_False;
128   //merge edges and drop seams
129   for(Standard_Integer i = 1; i <= edges.Length(); i++) {
130     TopoDS_Shape current = edges(i);
131     if(aNewEdges.Contains(current)) {
132                
133       aNewEdges.Remove(current);
134       edges.Remove(i);
135       i--;
136       
137       if(!isDropped) {
138         isDropped = Standard_True;
139         anIndex = i;
140       }
141     }
142   }
143           
144   //add edges to the sequemce
145   for(TopTools_MapIteratorOfMapOfShape anIter(aNewEdges); anIter.More(); anIter.Next())
146     edges.Append(anIter.Key());
147   
148   return isDropped;
149 }
150
151
152 //=======================================================================
153 //function : ClearRts
154 //purpose  : auxilary
155 //=======================================================================
156 static Handle(Geom_Surface) ClearRts(const Handle(Geom_Surface)& aSurface)
157 {
158   if(aSurface->IsKind(STANDARD_TYPE(Geom_RectangularTrimmedSurface))) {
159     Handle(Geom_RectangularTrimmedSurface) rts = 
160       Handle(Geom_RectangularTrimmedSurface)::DownCast(aSurface);
161     return rts->BasisSurface();
162   }
163   return aSurface;
164 }
165
166
167 //=======================================================================
168 //function : Perform
169 //purpose  : 
170 //=======================================================================
171
172 TopoDS_Shape BlockFix_UnionFaces::Perform(const TopoDS_Shape& Shape)
173 {
174   Handle(ShapeBuild_ReShape) myContext = new ShapeBuild_ReShape;
175   TopoDS_Shape aResShape = myContext->Apply(Shape);
176
177   // processing each solid
178   TopExp_Explorer exps;
179   for(exps.Init(Shape, TopAbs_SOLID); exps.More(); exps.Next()) {
180     TopoDS_Solid aSolid = TopoDS::Solid(exps.Current());
181
182     // creating map of edge faces
183     TopTools_IndexedDataMapOfShapeListOfShape aMapEdgeFaces;
184     TopExp::MapShapesAndAncestors(aSolid, TopAbs_EDGE, TopAbs_FACE, aMapEdgeFaces);
185
186     // map of processed shapes
187     TopTools_MapOfShape aProcessed;
188   
189     Handle(ShapeBuild_ReShape) aContext = new ShapeBuild_ReShape;
190
191     Standard_Integer NbModif=0;
192     Standard_Boolean hasFailed = Standard_False;
193     Standard_Real tol = Min(Max(Precision::Confusion(), myTolerance/10.),0.1);
194     // processing each face
195     TopExp_Explorer exp;
196     //for( exp.Init(Shape, TopAbs_FACE); exp.More(); exp.Next()) {
197     for( exp.Init(aSolid, TopAbs_FACE); exp.More(); exp.Next()) {
198       TopoDS_Face aFace = TopoDS::Face(exp.Current().Oriented(TopAbs_FORWARD));
199       
200       if(aProcessed.Contains(aFace))
201         continue;
202     
203       Standard_Integer dummy;
204       TopTools_SequenceOfShape edges;
205       AddOrdinaryEdges(edges,aFace,dummy);
206     
207       TopTools_SequenceOfShape faces;
208       faces.Append(aFace);
209     
210       //surface and location to construct result
211       TopLoc_Location aBaseLocation;
212       Handle(Geom_Surface) aBaseSurface = BRep_Tool::Surface(aFace,aBaseLocation);
213       aBaseSurface = ClearRts(aBaseSurface);
214
215       // find adjacent faces to union
216       Standard_Integer i;
217       for( i = 1; i <= edges.Length(); i++) {
218         TopoDS_Edge edge = TopoDS::Edge(edges(i));
219         if(BRep_Tool::Degenerated(edge))
220           continue;
221       
222         const TopTools_ListOfShape& aList = aMapEdgeFaces.FindFromKey(edge);
223         TopTools_ListIteratorOfListOfShape anIter(aList);
224         for( ; anIter.More(); anIter.Next()) {
225           TopoDS_Face anCheckedFace = TopoDS::Face(anIter.Value().Oriented(TopAbs_FORWARD));
226           if(anCheckedFace.IsSame(aFace))
227             continue;
228         
229           if(aProcessed.Contains(anCheckedFace))
230             continue;
231         
232           if(IsSameDomain(aFace,anCheckedFace)) {
233           
234             if(aList.Extent() != 2) {
235               // non mainfold case is not processed
236               continue;
237             }
238           
239             // replacing pcurves
240             TopoDS_Face aMockUpFace;
241             BRep_Builder B;
242             B.MakeFace(aMockUpFace,aBaseSurface,aBaseLocation,0.);
243             MovePCurves(aMockUpFace,anCheckedFace);
244             
245             if(AddOrdinaryEdges(edges,aMockUpFace,dummy)) {
246               // sequence edges is modified
247               i = dummy;
248             }
249             
250             faces.Append(anCheckedFace);
251             aProcessed.Add(anCheckedFace);
252             break;
253           }
254         }
255       }
256     
257       // all faces collected in the sequence. Perform union of faces
258       if(faces.Length() > 1) {
259         NbModif++;
260         TopoDS_Face aResult;
261         BRep_Builder B;
262         B.MakeFace(aResult,aBaseSurface,aBaseLocation,0);
263         Standard_Integer nbWires = 0;
264       
265         // connecting wires
266         while(edges.Length()>0) {
267         
268           Standard_Boolean isEdge3d = Standard_False;
269           nbWires++;
270           TopTools_MapOfShape aVertices;
271           TopoDS_Wire aWire;
272           B.MakeWire(aWire);
273         
274           TopoDS_Edge anEdge = TopoDS::Edge(edges(1));
275           edges.Remove(1);
276         
277           isEdge3d |= !BRep_Tool::Degenerated(anEdge);
278           B.Add(aWire,anEdge);
279           TopoDS_Vertex V1,V2;
280           TopExp::Vertices(anEdge,V1,V2);
281           aVertices.Add(V1);
282           aVertices.Add(V2);
283         
284           Standard_Boolean isNewFound = Standard_False;
285           do {
286             isNewFound = Standard_False;
287             for(Standard_Integer j = 1; j <= edges.Length(); j++) {
288               anEdge = TopoDS::Edge(edges(j));
289               TopExp::Vertices(anEdge,V1,V2);
290               if(aVertices.Contains(V1) || aVertices.Contains(V2)) {
291                 isEdge3d |= !BRep_Tool::Degenerated(anEdge);
292                 aVertices.Add(V1);
293                 aVertices.Add(V2);
294                 B.Add(aWire,anEdge);
295                 edges.Remove(j);
296                 j--;
297                 isNewFound = Standard_True;
298               }
299             }
300           } while (isNewFound);
301         
302           // sorting any type of edges
303           aWire = TopoDS::Wire(aContext->Apply(aWire));
304                 
305           TopoDS_Face tmpF = TopoDS::Face(aContext->Apply(faces(1).Oriented(TopAbs_FORWARD)));
306           Handle(ShapeFix_Wire) sfw = new ShapeFix_Wire(aWire,tmpF,Precision::Confusion());
307           sfw->FixReorder();
308           Standard_Boolean isDegRemoved = Standard_False;
309           if(!sfw->StatusReorder ( ShapeExtend_FAIL )) {
310             // clear degenerated edges if at least one with 3d curve exist
311             if(isEdge3d) {
312               Handle(ShapeExtend_WireData) sewd = sfw->WireData();
313               for(Standard_Integer j = 1; j<=sewd->NbEdges();j++) {
314                 TopoDS_Edge E = sewd->Edge(j);
315                 if(BRep_Tool::Degenerated(E)) {
316                   sewd->Remove(j);
317                   isDegRemoved = Standard_True;
318                   j--;
319                 }
320               }
321             }
322             sfw->FixShifted();
323             if(isDegRemoved)
324               sfw->FixDegenerated();
325           }
326           TopoDS_Wire aWireFixed = sfw->Wire();
327           aContext->Replace(aWire,aWireFixed);
328           // add resulting wire
329           if(isEdge3d) {
330             B.Add(aResult,aWireFixed);
331           }
332           else  {
333             // sorting edges
334             Handle(ShapeExtend_WireData) sbwd = sfw->WireData();
335             Standard_Integer nbEdges = sbwd->NbEdges();
336             // sort degenerated edges and create one edge instead of several ones
337             ShapeAnalysis_WireOrder sawo(Standard_False, 0);
338             ShapeAnalysis_Edge sae;
339             Standard_Integer aLastEdge = nbEdges;
340             for(Standard_Integer j = 1; j <= nbEdges; j++) {
341               Standard_Real f,l;
342               //smh protection on NULL pcurve
343               Handle(Geom2d_Curve) c2d;
344               if(!sae.PCurve(sbwd->Edge(j),tmpF,c2d,f,l)) {
345                 aLastEdge--;
346                 continue;
347               }
348               sawo.Add(c2d->Value(f).XY(),c2d->Value(l).XY());
349             }
350             sawo.Perform();
351             
352             // constructind one degenerative edge
353             gp_XY aStart, anEnd, tmp;
354             Standard_Integer nbFirst = sawo.Ordered(1);
355             TopoDS_Edge anOrigE = TopoDS::Edge(sbwd->Edge(nbFirst).Oriented(TopAbs_FORWARD));
356             ShapeBuild_Edge sbe;
357             TopoDS_Vertex aDummyV;
358             TopoDS_Edge E = sbe.CopyReplaceVertices(anOrigE,aDummyV,aDummyV);
359             sawo.XY(nbFirst,aStart,tmp);
360             sawo.XY(sawo.Ordered(aLastEdge),tmp,anEnd);
361           
362             gp_XY aVec = anEnd-aStart;
363             Handle(Geom2d_Line) aLine = new Geom2d_Line(aStart,gp_Dir2d(anEnd-aStart));
364
365             B.UpdateEdge(E,aLine,tmpF,0.);
366             B.Range(E,tmpF,0.,aVec.Modulus());
367             Handle(Geom_Curve) C3d;
368             B.UpdateEdge(E,C3d,0.);
369             B.Degenerated(E,Standard_True);
370             TopoDS_Wire aW;
371             B.MakeWire(aW);
372             B.Add(aW,E);
373             B.Add(aResult,aW);
374           }
375         
376         }
377       
378         // perform substitution of face
379         aContext->Replace(aContext->Apply(aFace),aResult);
380       
381       
382         ShapeFix_Face sff (aResult);
383         //Intializing by tolerances
384         sff.SetPrecision(myTolerance);
385         sff.SetMinTolerance(tol);
386         sff.SetMaxTolerance(Max(1.,myTolerance*1000.));
387         //Setting modes
388         sff.FixOrientationMode() = 0;
389         //sff.FixWireMode() = 0;
390         sff.SetContext(aContext);
391         // Applying the fixes
392         sff.Perform();
393         if(sff.Status(ShapeExtend_FAIL)) 
394         hasFailed = Standard_True;
395       
396         // breaking down to several faces
397         TopoDS_Shape theResult = aContext->Apply(aResult);
398         for(TopExp_Explorer aFaceExp(theResult,TopAbs_FACE);aFaceExp.More();aFaceExp.Next()) {
399           TopoDS_Face aCurrent = TopoDS::Face(aFaceExp.Current().Oriented(TopAbs_FORWARD));
400           Handle(TColGeom_HArray2OfSurface) grid = new TColGeom_HArray2OfSurface ( 1, 1, 1, 1 );
401           grid->SetValue ( 1, 1, aBaseSurface );
402           Handle(ShapeExtend_CompositeSurface) G = new ShapeExtend_CompositeSurface ( grid );
403           ShapeFix_ComposeShell CompShell;
404           CompShell.Init ( G, aBaseLocation, aCurrent, ::Precision::Confusion() );//myPrecision 
405           CompShell.SetContext( aContext );
406           
407           TopTools_SequenceOfShape parts;
408           ShapeFix_SequenceOfWireSegment wires;
409           for(TopExp_Explorer W_Exp(aCurrent,TopAbs_WIRE);W_Exp.More();W_Exp.Next()) {
410             Handle(ShapeExtend_WireData) sbwd = 
411               new ShapeExtend_WireData ( TopoDS::Wire(W_Exp.Current() ));
412             ShapeFix_WireSegment seg ( sbwd, TopAbs_REVERSED );
413             wires.Append(seg);
414           }
415                 
416           CompShell.DispatchWires ( parts,wires );
417           for (Standard_Integer j=1; j <= parts.Length(); j++ ) {
418             ShapeFix_Face aFixOrient(TopoDS::Face(parts(j)));
419             aFixOrient.SetContext(aContext);
420             aFixOrient.FixOrientation();
421           }
422         
423           TopoDS_Shape CompRes;
424           if ( faces.Length() !=1 ) {
425             TopoDS_Shell S;
426             B.MakeShell ( S );
427             for ( i=1; i <= parts.Length(); i++ ) 
428               B.Add ( S, parts(i) );
429             CompRes = S;
430           }
431           else CompRes = parts(1);
432           
433           aContext->Replace(aCurrent,CompRes);
434         }
435       
436         // remove the remaining faces
437         for(i = 2; i <= faces.Length(); i++)
438           aContext->Remove(faces(i));
439       }
440     }
441   
442     //TopoDS_Shape aResult = Shape;
443     if(NbModif>0) {
444       TopoDS_Shape aResult = aSolid;
445       if(!hasFailed) {
446         aResult = aContext->Apply(aSolid);
447     
448         ShapeFix_Edge sfe;
449         for(exp.Init(aResult,TopAbs_EDGE); exp.More(); exp.Next()) {
450           TopoDS_Edge E = TopoDS::Edge(exp.Current());
451           sfe.FixVertexTolerance (E);
452           // ptv add fix same parameter
453           sfe.FixSameParameter(E, myTolerance);
454         }
455         
456         myContext->Replace(aSolid,aResult);
457       }
458     }
459 //    else {
460       for( exp.Init(aSolid, TopAbs_FACE); exp.More(); exp.Next()) {
461         TopoDS_Face aFace = TopoDS::Face(exp.Current().Oriented(TopAbs_FORWARD));
462         Handle(ShapeFix_Wire) sfw = new ShapeFix_Wire;
463         sfw->SetContext(myContext);
464         sfw->SetPrecision(myTolerance);
465         sfw->SetMinTolerance(myTolerance);
466         sfw->SetMaxTolerance(Max(1.,myTolerance*1000.));
467         sfw->SetFace(aFace);
468         for ( TopoDS_Iterator iter(aFace,Standard_False); iter.More(); iter.Next()) { 
469           TopoDS_Wire wire = TopoDS::Wire ( iter.Value() );
470           sfw->Load(wire);
471           sfw->FixReorder();
472           sfw->FixShifted();
473         }
474       }
475 //    }
476
477   } // end processing each solid
478
479   aResShape = myContext->Apply(Shape);
480   return aResShape;
481 }
482
483
484 //=======================================================================
485 //function : IsSameDomain
486 //purpose  : 
487 //=======================================================================
488
489 Standard_Boolean BlockFix_UnionFaces::IsSameDomain(const TopoDS_Face& aFace,
490                                                    const TopoDS_Face& aCheckedFace) const
491 {
492   //checking the same handless
493   TopLoc_Location L1, L2;
494   Handle(Geom_Surface) S1, S2;
495   
496   S1 = BRep_Tool::Surface(aFace,L1);
497   S2 = BRep_Tool::Surface(aCheckedFace,L2);
498   
499   if (S1 == S2 && L1 == L2)
500     return true;
501
502   // begin: planar case (improvement 20052)
503   S1 = BRep_Tool::Surface(aFace);
504   S2 = BRep_Tool::Surface(aCheckedFace);
505
506   Handle(Geom_Plane) aGP1, aGP2;
507   Handle(Geom_RectangularTrimmedSurface) aGRTS1, aGRTS2;
508   Handle(Geom_OffsetSurface) aGOFS1, aGOFS2;
509
510   aGRTS1 = Handle(Geom_RectangularTrimmedSurface)::DownCast(S1);
511   aGRTS2 = Handle(Geom_RectangularTrimmedSurface)::DownCast(S2);
512
513   aGOFS1 = Handle(Geom_OffsetSurface)::DownCast(S1);
514   aGOFS2 = Handle(Geom_OffsetSurface)::DownCast(S2);
515
516   if (!aGOFS1.IsNull()) {
517     aGP1 = Handle(Geom_Plane)::DownCast(aGOFS1->BasisSurface());
518   }
519   else if (!aGRTS1.IsNull()) {
520     aGP1 = Handle(Geom_Plane)::DownCast(aGRTS1->BasisSurface());
521   }
522   else {
523     aGP1 = Handle(Geom_Plane)::DownCast(S1);
524   }
525
526   if (!aGOFS2.IsNull()) {
527     aGP2 = Handle(Geom_Plane)::DownCast(aGOFS2->BasisSurface());
528   }
529   else if (!aGRTS2.IsNull()) {
530     aGP2 = Handle(Geom_Plane)::DownCast(aGRTS2->BasisSurface());
531   }
532   else {
533     aGP2 = Handle(Geom_Plane)::DownCast(S2);
534   }
535
536   if (!aGP1.IsNull() && !aGP2.IsNull()) {
537     // both surfaces are planar, check equality
538     Standard_Real A1, B1, C1, D1;
539     Standard_Real A2, B2, C2, D2;
540     aGP1->Coefficients(A1, B1, C1, D1);
541     aGP2->Coefficients(A2, B2, C2, D2);
542
543     if (fabs(A1) > Precision::Confusion()) {
544       A1 = 1.0;
545       B1 /= A1;
546       C1 /= A1;
547       D1 /= A1;
548     }
549     else if (fabs(B1) > Precision::Confusion()) {
550       B1 = 1.0;
551       C1 /= B1;
552       D1 /= B1;
553     }
554     else {
555       C1 = 1.0;
556       D1 /= C1;
557     }
558
559     if (fabs(A2) > Precision::Confusion()) {
560       A2 = 1.0;
561       B2 /= A2;
562       C2 /= A2;
563       D2 /= A2;
564     }
565     else if (fabs(B2) > Precision::Confusion()) {
566       B2 = 1.0;
567       C2 /= B2;
568       D2 /= B2;
569     }
570     else {
571       C2 = 1.0;
572       D2 /= C2;
573     }
574
575     if (fabs(A1 - A2) < Precision::Confusion() &&
576         fabs(B1 - B2) < Precision::Confusion() &&
577         fabs(C1 - C2) < Precision::Confusion() &&
578         fabs(D1 - D2) < Precision::Confusion())
579       return true;
580   }
581   // end: planar case (improvement 20052)
582
583   return false;
584 }
585
586
587 //=======================================================================
588 //function : MovePCurves
589 //purpose  : 
590 //=======================================================================
591
592 void BlockFix_UnionFaces::MovePCurves(TopoDS_Face& aTarget,
593                                       const TopoDS_Face& aSource) const
594 {
595   BRep_Builder B;
596   for(TopExp_Explorer wexp(aSource,TopAbs_WIRE);wexp.More();wexp.Next()) {
597     Handle(ShapeFix_Wire) sfw = new ShapeFix_Wire(TopoDS::Wire(wexp.Current()), 
598                                                   aTarget, Precision::Confusion());
599     sfw->FixReorder();
600     Standard_Boolean isReoredFailed = sfw->StatusReorder ( ShapeExtend_FAIL );
601     sfw->FixEdgeCurves();
602     if(isReoredFailed)
603       continue;
604     
605     sfw->FixShifted();
606     sfw->FixDegenerated();
607     
608     // remove degenerated edges from not degenerated points
609     ShapeAnalysis_Edge sae;
610     Handle(ShapeExtend_WireData) sewd = sfw->WireData();
611     for(Standard_Integer i = 1; i<=sewd->NbEdges();i++) {
612       TopoDS_Edge E = sewd->Edge(i);
613       if(BRep_Tool::Degenerated(E)&&!sae.HasPCurve(E,aTarget)) {
614         sewd->Remove(i);
615         i--;
616       }
617     }
618     
619     TopoDS_Wire ResWire = sfw->Wire();
620     B.Add(aTarget,ResWire);
621   }
622 }