Salome HOME
Bug 0020228: [CEA 331] the geompy.RemoveExtraEdges crash with the attached brep shape...
[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
195     // count faces
196     int nbf = 0;
197     TopExp_Explorer exp;
198     TopTools_MapOfShape mapF;
199     for (exp.Init(aSolid, TopAbs_FACE); exp.More(); exp.Next()) {
200       if (mapF.Add(exp.Current()))
201         nbf++;
202     }
203
204     // processing each face
205     mapF.Clear();
206     for (exp.Init(aSolid, TopAbs_FACE); exp.More() && nbf > 6; exp.Next()) {
207       TopoDS_Face aFace = TopoDS::Face(exp.Current().Oriented(TopAbs_FORWARD));
208
209       if (aProcessed.Contains(aFace))
210         continue;
211
212       Standard_Integer dummy;
213       TopTools_SequenceOfShape edges;
214       AddOrdinaryEdges(edges,aFace,dummy);
215
216       TopTools_SequenceOfShape faces;
217       faces.Append(aFace);
218
219       //surface and location to construct result
220       TopLoc_Location aBaseLocation;
221       Handle(Geom_Surface) aBaseSurface = BRep_Tool::Surface(aFace,aBaseLocation);
222       aBaseSurface = ClearRts(aBaseSurface);
223
224       // find adjacent faces to union
225       Standard_Integer i;
226       for (i = 1; i <= edges.Length(); i++) {
227         TopoDS_Edge edge = TopoDS::Edge(edges(i));
228         if (BRep_Tool::Degenerated(edge))
229           continue;
230       
231         const TopTools_ListOfShape& aList = aMapEdgeFaces.FindFromKey(edge);
232         TopTools_ListIteratorOfListOfShape anIter(aList);
233         for (; anIter.More(); anIter.Next()) {
234           TopoDS_Face anCheckedFace = TopoDS::Face(anIter.Value().Oriented(TopAbs_FORWARD));
235           if (anCheckedFace.IsSame(aFace))
236             continue;
237         
238           if (aProcessed.Contains(anCheckedFace))
239             continue;
240         
241           if (IsSameDomain(aFace,anCheckedFace)) {
242           
243             if (aList.Extent() != 2) {
244               // non mainfold case is not processed
245               continue;
246             }
247           
248             // replacing pcurves
249             TopoDS_Face aMockUpFace;
250             BRep_Builder B;
251             B.MakeFace(aMockUpFace,aBaseSurface,aBaseLocation,0.);
252             MovePCurves(aMockUpFace,anCheckedFace);
253             
254             if (AddOrdinaryEdges(edges,aMockUpFace,dummy)) {
255               // sequence edges is modified
256               i = dummy;
257             }
258             
259             faces.Append(anCheckedFace);
260             aProcessed.Add(anCheckedFace);
261             break;
262           }
263         }
264       }
265     
266       // all faces collected in the sequence. Perform union of faces
267       if (faces.Length() > 1) {
268         NbModif++;
269         TopoDS_Face aResult;
270         BRep_Builder B;
271         B.MakeFace(aResult,aBaseSurface,aBaseLocation,0);
272         Standard_Integer nbWires = 0;
273       
274         // connecting wires
275         while (edges.Length()>0) {
276         
277           Standard_Boolean isEdge3d = Standard_False;
278           nbWires++;
279           TopTools_MapOfShape aVertices;
280           TopoDS_Wire aWire;
281           B.MakeWire(aWire);
282         
283           TopoDS_Edge anEdge = TopoDS::Edge(edges(1));
284           edges.Remove(1);
285         
286           isEdge3d |= !BRep_Tool::Degenerated(anEdge);
287           B.Add(aWire,anEdge);
288           TopoDS_Vertex V1,V2;
289           TopExp::Vertices(anEdge,V1,V2);
290           aVertices.Add(V1);
291           aVertices.Add(V2);
292         
293           Standard_Boolean isNewFound = Standard_False;
294           do {
295             isNewFound = Standard_False;
296             for(Standard_Integer j = 1; j <= edges.Length(); j++) {
297               anEdge = TopoDS::Edge(edges(j));
298               TopExp::Vertices(anEdge,V1,V2);
299               if(aVertices.Contains(V1) || aVertices.Contains(V2)) {
300                 isEdge3d |= !BRep_Tool::Degenerated(anEdge);
301                 aVertices.Add(V1);
302                 aVertices.Add(V2);
303                 B.Add(aWire,anEdge);
304                 edges.Remove(j);
305                 j--;
306                 isNewFound = Standard_True;
307               }
308             }
309           } while (isNewFound);
310         
311           // sorting any type of edges
312           aWire = TopoDS::Wire(aContext->Apply(aWire));
313                 
314           TopoDS_Face tmpF = TopoDS::Face(aContext->Apply(faces(1).Oriented(TopAbs_FORWARD)));
315           Handle(ShapeFix_Wire) sfw = new ShapeFix_Wire(aWire,tmpF,Precision::Confusion());
316           sfw->FixReorder();
317           Standard_Boolean isDegRemoved = Standard_False;
318           if(!sfw->StatusReorder ( ShapeExtend_FAIL )) {
319             // clear degenerated edges if at least one with 3d curve exist
320             if(isEdge3d) {
321               Handle(ShapeExtend_WireData) sewd = sfw->WireData();
322               for(Standard_Integer j = 1; j<=sewd->NbEdges();j++) {
323                 TopoDS_Edge E = sewd->Edge(j);
324                 if(BRep_Tool::Degenerated(E)) {
325                   sewd->Remove(j);
326                   isDegRemoved = Standard_True;
327                   j--;
328                 }
329               }
330             }
331             sfw->FixShifted();
332             if(isDegRemoved)
333               sfw->FixDegenerated();
334           }
335           TopoDS_Wire aWireFixed = sfw->Wire();
336           aContext->Replace(aWire,aWireFixed);
337           // add resulting wire
338           if(isEdge3d) {
339             B.Add(aResult,aWireFixed);
340           }
341           else  {
342             // sorting edges
343             Handle(ShapeExtend_WireData) sbwd = sfw->WireData();
344             Standard_Integer nbEdges = sbwd->NbEdges();
345             // sort degenerated edges and create one edge instead of several ones
346             ShapeAnalysis_WireOrder sawo(Standard_False, 0);
347             ShapeAnalysis_Edge sae;
348             Standard_Integer aLastEdge = nbEdges;
349             for(Standard_Integer j = 1; j <= nbEdges; j++) {
350               Standard_Real f,l;
351               //smh protection on NULL pcurve
352               Handle(Geom2d_Curve) c2d;
353               if(!sae.PCurve(sbwd->Edge(j),tmpF,c2d,f,l)) {
354                 aLastEdge--;
355                 continue;
356               }
357               sawo.Add(c2d->Value(f).XY(),c2d->Value(l).XY());
358             }
359             sawo.Perform();
360             
361             // constructind one degenerative edge
362             gp_XY aStart, anEnd, tmp;
363             Standard_Integer nbFirst = sawo.Ordered(1);
364             TopoDS_Edge anOrigE = TopoDS::Edge(sbwd->Edge(nbFirst).Oriented(TopAbs_FORWARD));
365             ShapeBuild_Edge sbe;
366             TopoDS_Vertex aDummyV;
367             TopoDS_Edge E = sbe.CopyReplaceVertices(anOrigE,aDummyV,aDummyV);
368             sawo.XY(nbFirst,aStart,tmp);
369             sawo.XY(sawo.Ordered(aLastEdge),tmp,anEnd);
370           
371             gp_XY aVec = anEnd-aStart;
372             Handle(Geom2d_Line) aLine = new Geom2d_Line(aStart,gp_Dir2d(anEnd-aStart));
373
374             B.UpdateEdge(E,aLine,tmpF,0.);
375             B.Range(E,tmpF,0.,aVec.Modulus());
376             Handle(Geom_Curve) C3d;
377             B.UpdateEdge(E,C3d,0.);
378             B.Degenerated(E,Standard_True);
379             TopoDS_Wire aW;
380             B.MakeWire(aW);
381             B.Add(aW,E);
382             B.Add(aResult,aW);
383           }
384         }
385
386         // perform substitution of face
387         aContext->Replace(aContext->Apply(aFace),aResult);
388
389         ShapeFix_Face sff (aResult);
390         //Intializing by tolerances
391         sff.SetPrecision(myTolerance);
392         sff.SetMinTolerance(tol);
393         sff.SetMaxTolerance(Max(1.,myTolerance*1000.));
394         //Setting modes
395         sff.FixOrientationMode() = 0;
396         //sff.FixWireMode() = 0;
397         sff.SetContext(aContext);
398         // Applying the fixes
399         sff.Perform();
400         if(sff.Status(ShapeExtend_FAIL)) 
401         hasFailed = Standard_True;
402       
403         // breaking down to several faces
404         TopoDS_Shape theResult = aContext->Apply(aResult);
405         for (TopExp_Explorer aFaceExp (theResult,TopAbs_FACE); aFaceExp.More(); aFaceExp.Next()) {
406           TopoDS_Face aCurrent = TopoDS::Face(aFaceExp.Current().Oriented(TopAbs_FORWARD));
407           Handle(TColGeom_HArray2OfSurface) grid = new TColGeom_HArray2OfSurface ( 1, 1, 1, 1 );
408           grid->SetValue ( 1, 1, aBaseSurface );
409           Handle(ShapeExtend_CompositeSurface) G = new ShapeExtend_CompositeSurface ( grid );
410           ShapeFix_ComposeShell CompShell;
411           CompShell.Init ( G, aBaseLocation, aCurrent, ::Precision::Confusion() );//myPrecision 
412           CompShell.SetContext( aContext );
413           
414           TopTools_SequenceOfShape parts;
415           ShapeFix_SequenceOfWireSegment wires;
416           for(TopExp_Explorer W_Exp(aCurrent,TopAbs_WIRE);W_Exp.More();W_Exp.Next()) {
417             Handle(ShapeExtend_WireData) sbwd = 
418               new ShapeExtend_WireData ( TopoDS::Wire(W_Exp.Current() ));
419             ShapeFix_WireSegment seg ( sbwd, TopAbs_REVERSED );
420             wires.Append(seg);
421           }
422                 
423           CompShell.DispatchWires ( parts,wires );
424           for (Standard_Integer j=1; j <= parts.Length(); j++ ) {
425             ShapeFix_Face aFixOrient(TopoDS::Face(parts(j)));
426             aFixOrient.SetContext(aContext);
427             aFixOrient.FixOrientation();
428           }
429         
430           TopoDS_Shape CompRes;
431           if ( faces.Length() !=1 ) {
432             TopoDS_Shell S;
433             B.MakeShell ( S );
434             for ( i=1; i <= parts.Length(); i++ ) 
435               B.Add ( S, parts(i) );
436             CompRes = S;
437           }
438           else CompRes = parts(1);
439           
440           aContext->Replace(aCurrent,CompRes);
441         }
442       
443         // remove the remaining faces
444         for(i = 2; i <= faces.Length(); i++)
445           aContext->Remove(faces(i));
446       }
447     } // end processing each face
448
449     //TopoDS_Shape aResult = Shape;
450     if (NbModif > 0 && !hasFailed) {
451       TopoDS_Shape aResult = aContext->Apply(aSolid);
452
453       ShapeFix_Edge sfe;
454       for (exp.Init(aResult,TopAbs_EDGE); exp.More(); exp.Next()) {
455         TopoDS_Edge E = TopoDS::Edge(exp.Current());
456         sfe.FixVertexTolerance (E);
457         // ptv add fix same parameter
458         sfe.FixSameParameter(E, myTolerance);
459       }
460
461       myContext->Replace(aSolid, aResult);
462     }
463     //else
464     {
465       for (exp.Init(aSolid, TopAbs_FACE); exp.More(); exp.Next()) {
466         TopoDS_Face aFace = TopoDS::Face(exp.Current().Oriented(TopAbs_FORWARD));
467         Handle(ShapeFix_Wire) sfw = new ShapeFix_Wire;
468         sfw->SetContext(myContext);
469         sfw->SetPrecision(myTolerance);
470         sfw->SetMinTolerance(myTolerance);
471         sfw->SetMaxTolerance(Max(1.,myTolerance*1000.));
472         sfw->SetFace(aFace);
473         for (TopoDS_Iterator iter (aFace,Standard_False); iter.More(); iter.Next()) { 
474           TopoDS_Wire wire = TopoDS::Wire(iter.Value());
475           sfw->Load(wire);
476           sfw->FixReorder();
477           sfw->FixShifted();
478         }
479       }
480     }
481   } // end processing each solid
482
483   aResShape = myContext->Apply(Shape);
484   return aResShape;
485 }
486
487
488 //=======================================================================
489 //function : IsSameDomain
490 //purpose  : 
491 //=======================================================================
492
493 Standard_Boolean BlockFix_UnionFaces::IsSameDomain(const TopoDS_Face& aFace,
494                                                    const TopoDS_Face& aCheckedFace) const
495 {
496   //checking the same handless
497   TopLoc_Location L1, L2;
498   Handle(Geom_Surface) S1, S2;
499   
500   S1 = BRep_Tool::Surface(aFace,L1);
501   S2 = BRep_Tool::Surface(aCheckedFace,L2);
502   
503   if (S1 == S2 && L1 == L2)
504     return true;
505
506   // begin: planar case (improvement 20052)
507   S1 = BRep_Tool::Surface(aFace);
508   S2 = BRep_Tool::Surface(aCheckedFace);
509
510   Handle(Geom_Plane) aGP1, aGP2;
511   Handle(Geom_RectangularTrimmedSurface) aGRTS1, aGRTS2;
512   Handle(Geom_OffsetSurface) aGOFS1, aGOFS2;
513
514   aGRTS1 = Handle(Geom_RectangularTrimmedSurface)::DownCast(S1);
515   aGRTS2 = Handle(Geom_RectangularTrimmedSurface)::DownCast(S2);
516
517   aGOFS1 = Handle(Geom_OffsetSurface)::DownCast(S1);
518   aGOFS2 = Handle(Geom_OffsetSurface)::DownCast(S2);
519
520   if (!aGOFS1.IsNull()) {
521     aGP1 = Handle(Geom_Plane)::DownCast(aGOFS1->BasisSurface());
522   }
523   else if (!aGRTS1.IsNull()) {
524     aGP1 = Handle(Geom_Plane)::DownCast(aGRTS1->BasisSurface());
525   }
526   else {
527     aGP1 = Handle(Geom_Plane)::DownCast(S1);
528   }
529
530   if (!aGOFS2.IsNull()) {
531     aGP2 = Handle(Geom_Plane)::DownCast(aGOFS2->BasisSurface());
532   }
533   else if (!aGRTS2.IsNull()) {
534     aGP2 = Handle(Geom_Plane)::DownCast(aGRTS2->BasisSurface());
535   }
536   else {
537     aGP2 = Handle(Geom_Plane)::DownCast(S2);
538   }
539
540   if (!aGP1.IsNull() && !aGP2.IsNull()) {
541     // both surfaces are planar, check equality
542     Standard_Real A1, B1, C1, D1;
543     Standard_Real A2, B2, C2, D2;
544     aGP1->Coefficients(A1, B1, C1, D1);
545     aGP2->Coefficients(A2, B2, C2, D2);
546
547     if (fabs(A1) > Precision::Confusion()) {
548       A1 = 1.0;
549       B1 /= A1;
550       C1 /= A1;
551       D1 /= A1;
552     }
553     else if (fabs(B1) > Precision::Confusion()) {
554       B1 = 1.0;
555       C1 /= B1;
556       D1 /= B1;
557     }
558     else {
559       C1 = 1.0;
560       D1 /= C1;
561     }
562
563     if (fabs(A2) > Precision::Confusion()) {
564       A2 = 1.0;
565       B2 /= A2;
566       C2 /= A2;
567       D2 /= A2;
568     }
569     else if (fabs(B2) > Precision::Confusion()) {
570       B2 = 1.0;
571       C2 /= B2;
572       D2 /= B2;
573     }
574     else {
575       C2 = 1.0;
576       D2 /= C2;
577     }
578
579     if (fabs(A1 - A2) < Precision::Confusion() &&
580         fabs(B1 - B2) < Precision::Confusion() &&
581         fabs(C1 - C2) < Precision::Confusion() &&
582         fabs(D1 - D2) < Precision::Confusion())
583       return true;
584   }
585   // end: planar case (improvement 20052)
586
587   return false;
588 }
589
590
591 //=======================================================================
592 //function : MovePCurves
593 //purpose  : 
594 //=======================================================================
595
596 void BlockFix_UnionFaces::MovePCurves(TopoDS_Face& aTarget,
597                                       const TopoDS_Face& aSource) const
598 {
599   BRep_Builder B;
600   for(TopExp_Explorer wexp(aSource,TopAbs_WIRE);wexp.More();wexp.Next()) {
601     Handle(ShapeFix_Wire) sfw = new ShapeFix_Wire(TopoDS::Wire(wexp.Current()), 
602                                                   aTarget, Precision::Confusion());
603     sfw->FixReorder();
604     Standard_Boolean isReoredFailed = sfw->StatusReorder ( ShapeExtend_FAIL );
605     sfw->FixEdgeCurves();
606     if(isReoredFailed)
607       continue;
608     
609     sfw->FixShifted();
610     sfw->FixDegenerated();
611     
612     // remove degenerated edges from not degenerated points
613     ShapeAnalysis_Edge sae;
614     Handle(ShapeExtend_WireData) sewd = sfw->WireData();
615     for(Standard_Integer i = 1; i<=sewd->NbEdges();i++) {
616       TopoDS_Edge E = sewd->Edge(i);
617       if(BRep_Tool::Degenerated(E)&&!sae.HasPCurve(E,aTarget)) {
618         sewd->Remove(i);
619         i--;
620       }
621     }
622     
623     TopoDS_Wire ResWire = sfw->Wire();
624     B.Add(aTarget,ResWire);
625   }
626 }