Salome HOME
Update copyrights 2014.
[modules/geom.git] / src / BlockFix / BlockFix_UnionEdges.cxx
1 // Copyright (C) 2007-2014  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, or (at your option) any later version.
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
23 // File:      BlockFix_UnionEdges.cxx
24 // Created:   07.12.04 15:27:30
25 // Author:    Sergey KUUL
26
27 #include <BlockFix_UnionEdges.hxx>
28
29 #include <ShapeAnalysis_Edge.hxx>
30
31 #include <ShapeBuild_ReShape.hxx>
32
33 #include <ShapeFix_Edge.hxx>
34 #include <ShapeFix_Face.hxx>
35 #include <ShapeFix_Shell.hxx>
36
37 #include <BRep_Builder.hxx>
38 #include <BRep_CurveRepresentation.hxx>
39 #include <BRep_ListIteratorOfListOfCurveRepresentation.hxx>
40 #include <BRep_TEdge.hxx>
41 #include <BRep_Tool.hxx>
42 #include <BRepAdaptor_HCompCurve.hxx>
43 #include <BRepLib.hxx>
44 #include <BRepLib_MakeEdge.hxx>
45
46 #include <TopExp.hxx>
47 #include <TopExp_Explorer.hxx>
48
49 #include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
50 #include <TopTools_IndexedMapOfShape.hxx>
51 #include <TopTools_ListOfShape.hxx>
52 #include <TopTools_MapOfShape.hxx>
53 #include <TopTools_ListIteratorOfListOfShape.hxx>
54 #include <TopTools_SequenceOfShape.hxx>
55
56 #include <TopoDS.hxx>
57 #include <TopoDS_Edge.hxx>
58 #include <TopoDS_Face.hxx>
59 #include <TopoDS_Shell.hxx>
60 #include <TopoDS_Solid.hxx>
61 #include <TopoDS_Vertex.hxx>
62 #include <TopoDS_Iterator.hxx>
63 #include <TopoDS_Shape.hxx>
64
65 #include <Approx_Curve3d.hxx>
66
67 #include <GC_MakeCircle.hxx>
68
69 #include <Geom_BSplineCurve.hxx>
70 #include <Geom_Circle.hxx>
71 #include <Geom_Curve.hxx>
72 #include <Geom_Line.hxx>
73 #include <Geom_TrimmedCurve.hxx>
74 #include <GeomConvert.hxx>
75 #include <GeomConvert_CompCurveToBSplineCurve.hxx>
76
77 #include <Geom2dConvert.hxx>
78 #include <Geom2dConvert_CompCurveToBSplineCurve.hxx>
79 #include <Geom2d_TrimmedCurve.hxx>
80 #include <Geom2d_BSplineCurve.hxx>
81
82 #include <TColGeom_SequenceOfSurface.hxx>
83 #include <TColGeom_Array1OfBSplineCurve.hxx>
84 #include <TColGeom_HArray1OfBSplineCurve.hxx>
85 #include <TColGeom2d_Array1OfBSplineCurve.hxx>
86 #include <TColGeom2d_HArray1OfBSplineCurve.hxx>
87 #include <TColGeom2d_SequenceOfBoundedCurve.hxx>
88 #include <TColgp_SequenceOfPnt.hxx>
89 #include <TColStd_Array1OfReal.hxx>
90 #include <TColStd_MapOfInteger.hxx>
91
92 #include "utilities.h"
93
94 //=======================================================================
95 //function : BlockFix_UnionEdges()
96 //purpose  : Constructor
97 //=======================================================================
98 BlockFix_UnionEdges::BlockFix_UnionEdges (  )
99 {
100 }
101
102 //=======================================================================
103 //function : GlueEdgesWithPCurves
104 //purpose  : Glues the pcurves of the sequence of edges
105 //           and glues their 3d curves
106 //=======================================================================
107 static TopoDS_Edge GlueEdgesWithPCurves(const TopTools_SequenceOfShape& aChain,
108                                         const TopoDS_Vertex& FirstVertex,
109                                         const TopoDS_Vertex& LastVertex)
110 {
111   Standard_Integer i, j;
112
113   TopoDS_Edge FirstEdge = TopoDS::Edge(aChain(1));
114   //TColGeom2d_SequenceOfCurve PCurveSeq;
115   TColGeom_SequenceOfSurface SurfSeq;
116   //TopTools_SequenceOfShape LocSeq;
117   
118   BRep_ListIteratorOfListOfCurveRepresentation itr( (Handle(BRep_TEdge)::DownCast(FirstEdge.TShape()))->Curves() );
119   for (; itr.More(); itr.Next())
120   {
121     Handle(BRep_CurveRepresentation) CurveRep = itr.Value();
122     if (CurveRep->IsCurveOnSurface())
123     {
124       //PCurveSeq.Append(CurveRep->PCurve());
125       SurfSeq.Append(CurveRep->Surface());
126       /*
127       TopoDS_Shape aLocShape;
128       aLocShape.Location(CurveRep->Location());
129       LocSeq.Append(aLocShape);
130       */
131     }
132   }
133
134   Standard_Real fpar, lpar;
135   BRep_Tool::Range(FirstEdge, fpar, lpar);
136   TopoDS_Edge PrevEdge = FirstEdge;
137   TopoDS_Vertex CV;
138   Standard_Real MaxTol = 0.;
139   
140   TopoDS_Edge ResEdge;
141   BRep_Builder BB;
142
143   Standard_Integer nb_curve = aChain.Length();   //number of curves
144   TColGeom_Array1OfBSplineCurve tab_c3d(0,nb_curve-1);                    //array of the curves
145   TColStd_Array1OfReal tabtolvertex(0,nb_curve-1); //(0,nb_curve-2);  //array of the tolerances
146     
147   TopoDS_Vertex PrevVertex = FirstVertex;
148   for (i = 1; i <= nb_curve; i++)
149   {
150     TopoDS_Edge anEdge = TopoDS::Edge(aChain(i));
151     TopoDS_Vertex VF, VL;
152     TopExp::Vertices(anEdge, VF, VL);
153     Standard_Boolean ToReverse = (!VF.IsSame(PrevVertex));
154     
155     Standard_Real Tol1 = BRep_Tool::Tolerance(VF);
156     Standard_Real Tol2 = BRep_Tool::Tolerance(VL);
157     if (Tol1 > MaxTol)
158       MaxTol = Tol1;
159     if (Tol2 > MaxTol)
160       MaxTol = Tol2;
161     
162     if (i > 1)
163     {
164       TopExp::CommonVertex(PrevEdge, anEdge, CV);
165       Standard_Real Tol = BRep_Tool::Tolerance(CV);
166       tabtolvertex(i-2) = Tol;
167     }
168     
169     Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, fpar, lpar);
170     Handle(Geom_TrimmedCurve) aTrCurve = new Geom_TrimmedCurve(aCurve, fpar, lpar);
171     tab_c3d(i-1) = GeomConvert::CurveToBSplineCurve(aTrCurve);
172     GeomConvert::C0BSplineToC1BSplineCurve(tab_c3d(i-1), Precision::Confusion());
173     if (ToReverse)
174       tab_c3d(i-1)->Reverse();
175     PrevVertex = (ToReverse)? VF : VL;
176     PrevEdge = anEdge;
177   }
178   Handle(TColGeom_HArray1OfBSplineCurve)  concatcurve;     //array of the concatenated curves
179   Handle(TColStd_HArray1OfInteger)        ArrayOfIndices;  //array of the remining Vertex
180   GeomConvert::ConcatC1(tab_c3d,
181                         tabtolvertex,
182                         ArrayOfIndices,
183                         concatcurve,
184                         Standard_False,
185                         Precision::Confusion());   //C1 concatenation
186   
187   if (concatcurve->Length() > 1)
188   {
189     GeomConvert_CompCurveToBSplineCurve Concat(concatcurve->Value(concatcurve->Lower()));
190     
191     for (i = concatcurve->Lower()+1; i <= concatcurve->Upper(); i++)
192       Concat.Add( concatcurve->Value(i), MaxTol, Standard_True );
193     
194     concatcurve->SetValue(concatcurve->Lower(), Concat.BSplineCurve());
195   }
196   Handle(Geom_BSplineCurve) ResCurve = concatcurve->Value(concatcurve->Lower());
197   
198   TColGeom2d_SequenceOfBoundedCurve ResPCurves;
199   TopLoc_Location aLoc;
200   for (j = 1; j <= SurfSeq.Length(); j++)
201   {
202     TColGeom2d_Array1OfBSplineCurve tab_c2d(0,nb_curve-1); //array of the pcurves
203     
204     PrevVertex = FirstVertex;
205     PrevEdge = FirstEdge;
206     //TopLoc_Location theLoc = LocSeq(j).Location();
207     for (i = 1; i <= nb_curve; i++)
208     {
209       TopoDS_Edge anEdge = TopoDS::Edge(aChain(i));
210       TopoDS_Vertex VF, VL;
211       TopExp::Vertices(anEdge, VF, VL);
212       Standard_Boolean ToReverse = (!VF.IsSame(PrevVertex));
213
214       /*
215       Handle(Geom2d_Curve) aPCurve =
216         BRep_Tool::CurveOnSurface(anEdge, SurfSeq(j), anEdge.Location()*theLoc, fpar, lpar);
217       */
218       Handle(Geom2d_Curve) aPCurve =
219         BRep_Tool::CurveOnSurface(anEdge, SurfSeq(j), aLoc, fpar, lpar);
220       Handle(Geom2d_TrimmedCurve) aTrPCurve = new Geom2d_TrimmedCurve(aPCurve, fpar, lpar);
221       tab_c2d(i-1) = Geom2dConvert::CurveToBSplineCurve(aTrPCurve);
222       Geom2dConvert::C0BSplineToC1BSplineCurve(tab_c2d(i-1), Precision::Confusion());
223       if (ToReverse)
224         tab_c2d(i-1)->Reverse();
225       PrevVertex = (ToReverse)? VF : VL;
226       PrevEdge = anEdge;
227     }
228     Handle(TColGeom2d_HArray1OfBSplineCurve)  concatc2d;     //array of the concatenated curves
229     Handle(TColStd_HArray1OfInteger)        ArrayOfInd2d;  //array of the remining Vertex
230     Geom2dConvert::ConcatC1(tab_c2d,
231                             tabtolvertex,
232                             ArrayOfInd2d,
233                             concatc2d,
234                             Standard_False,
235                             Precision::Confusion());   //C1 concatenation
236     
237     if (concatc2d->Length() > 1)
238     {
239       Geom2dConvert_CompCurveToBSplineCurve Concat2d(concatc2d->Value(concatc2d->Lower()));
240       
241       for (i = concatc2d->Lower()+1; i <= concatc2d->Upper(); i++)
242         Concat2d.Add( concatc2d->Value(i), MaxTol, Standard_True );
243       
244       concatc2d->SetValue(concatc2d->Lower(), Concat2d.BSplineCurve());
245     }
246     Handle(Geom2d_BSplineCurve) aResPCurve = concatc2d->Value(concatc2d->Lower());
247     ResPCurves.Append(aResPCurve);
248   }
249   
250   ResEdge = BRepLib_MakeEdge(ResCurve,
251                              FirstVertex, LastVertex,
252                              ResCurve->FirstParameter(), ResCurve->LastParameter());
253   BB.SameRange(ResEdge, Standard_False);
254   BB.SameParameter(ResEdge, Standard_False);
255   for (j = 1; j <= ResPCurves.Length(); j++)
256   {
257     BB.UpdateEdge(ResEdge, ResPCurves(j), SurfSeq(j), aLoc, MaxTol);
258     BB.Range(ResEdge, SurfSeq(j), aLoc, ResPCurves(j)->FirstParameter(), ResPCurves(j)->LastParameter());
259   }
260
261   BRepLib::SameParameter(ResEdge, MaxTol, Standard_True);
262   
263   return ResEdge;
264 }
265
266 //=======================================================================
267 //function : IsFixed
268 //purpose  : Returns true if this vertex should be kept in the result.
269 //=======================================================================
270 static Standard_Boolean IsFixed
271          (const TopoDS_Vertex &theVtx,
272           const TopoDS_Face   &theFace,
273           const TopTools_IndexedDataMapOfShapeListOfShape &theMapVtxEdgeOnFace)
274 {
275   Standard_Boolean aResult = Standard_False;
276
277   if (theMapVtxEdgeOnFace.Contains(theVtx)) {
278     const TopTools_ListOfShape& aList = theMapVtxEdgeOnFace.FindFromKey(theVtx);
279     TopTools_ListIteratorOfListOfShape anIter(aList);
280     Standard_Boolean isFirst = Standard_True;
281     Standard_Boolean isSeam  = Standard_False;
282         
283     for ( ; anIter.More(); anIter.Next()) {
284       TopoDS_Edge anEdge = TopoDS::Edge(anIter.Value());
285
286       if (isFirst) {
287         // This is the first treated edge.
288         isFirst = Standard_False;
289         isSeam  = BRep_Tool::IsClosed(anEdge, theFace);
290       } else if (BRep_Tool::IsClosed(anEdge, theFace)) {
291         // Seam edge.
292         if (!isSeam) {
293           // The previous one was not seam.
294           aResult = Standard_True;
295           break;
296         }
297       } else if (isSeam) {
298         // This is not a seam edge however the previous one was seam.
299         aResult = Standard_True;
300         break;
301       }
302     }
303   }
304
305   return aResult;
306 }
307
308 //=======================================================================
309 //function : MergeEdges
310 //purpose  : auxilary
311 //=======================================================================
312 static Standard_Boolean MergeEdges(const TopTools_SequenceOfShape& SeqEdges,
313                                    const TopoDS_Face& theFace1,
314                                    const TopoDS_Face& theFace2,
315                                    const Standard_Real Tol,
316                                    TopoDS_Edge& anEdge)
317 {
318   // make chain for union
319   BRep_Builder B;
320   ShapeAnalysis_Edge sae;
321   TopoDS_Edge FirstE = TopoDS::Edge(SeqEdges.Value(1));
322   TopoDS_Edge LastE = FirstE;
323   TopoDS_Vertex VF = sae.FirstVertex(FirstE);
324   TopoDS_Vertex VL = sae.LastVertex(LastE);
325   TopTools_SequenceOfShape aChain;
326   aChain.Append(FirstE);
327   TColStd_MapOfInteger IndUsedEdges;
328   IndUsedEdges.Add(1);
329   Standard_Integer j;
330   for(j=2; j<=SeqEdges.Length(); j++) {
331     for(Standard_Integer k=2; k<=SeqEdges.Length(); k++) {
332       if(IndUsedEdges.Contains(k)) continue;
333       TopoDS_Edge edge = TopoDS::Edge(SeqEdges.Value(k));
334       TopoDS_Vertex VF2 = sae.FirstVertex(edge);
335       TopoDS_Vertex VL2 = sae.LastVertex(edge);
336       if(sae.FirstVertex(edge).IsSame(VL)) {
337         aChain.Append(edge);
338         LastE = edge;
339         VL = sae.LastVertex(LastE);
340         IndUsedEdges.Add(k);
341       }
342       else if(sae.LastVertex(edge).IsSame(VF)) {
343         aChain.Prepend(edge);
344         FirstE = edge;
345         VF = sae.FirstVertex(FirstE);
346         IndUsedEdges.Add(k);
347       }
348     }
349   }
350   if(aChain.Length()<SeqEdges.Length()) {
351     MESSAGE ("can not create correct chain...");
352     return Standard_False;
353   }
354
355   // Check if there are vertices that should be kept in the result.
356   const Standard_Boolean isClosed = VF.IsSame(VL);
357   TopTools_IndexedDataMapOfShapeListOfShape theMapVtxEdge1;
358   TopTools_IndexedDataMapOfShapeListOfShape theMapVtxEdge2;
359   Standard_Integer jSplit = -1;
360
361   TopExp::MapShapesAndAncestors(theFace1, TopAbs_VERTEX, TopAbs_EDGE, theMapVtxEdge1);
362   TopExp::MapShapesAndAncestors(theFace2, TopAbs_VERTEX, TopAbs_EDGE, theMapVtxEdge2);
363
364   // Check if intermediate vertices should be in the result.
365   for(j = 1; j < aChain.Length(); j++) {
366     TopoDS_Edge   anEdge = TopoDS::Edge(aChain.Value(j));
367     TopoDS_Vertex aVtx   = sae.LastVertex(anEdge);
368
369     if (IsFixed(aVtx, theFace1, theMapVtxEdge1) ||
370         IsFixed(aVtx, theFace2, theMapVtxEdge2)) {
371       // This vertex should be kept.
372       if (jSplit > 0) {
373         // There is already split vertex detected.
374         // It means that these edges can't be merged.
375         MESSAGE ("Two edges on closed contour can't be merged.");
376         return Standard_False;
377       } else if (isClosed) {
378         // This is a closed contour.
379         // It is possible to merge it starting from the next edge.
380         jSplit = j;
381       } else {
382         // The contour is not closed, this vertex sould be kept.
383         // It means that these edges can't be merged.
384         MESSAGE ("Two edges on not closed contour can't be merged.");
385         return Standard_False;
386       }
387     }
388   }
389
390   if (jSplit > 0) {
391     // This is closed contour. Check the last (it is first as well) vertex,
392     // as it becomes intermediate after reordering.
393     TopoDS_Edge   anEdge = TopoDS::Edge(aChain.Last());
394     TopoDS_Vertex aVtx   = sae.LastVertex(anEdge);
395
396     if (IsFixed(aVtx, theFace1, theMapVtxEdge1) ||
397         IsFixed(aVtx, theFace2, theMapVtxEdge2)) {
398       // This vertex should be kept. So we can't merge this contour.
399       MESSAGE ("Two edges on closed contour can't be merged.");
400       return Standard_False;
401     }
402
403     // Reorder edges in the sequence to have jSplit-th edge last.
404     for(j = 1; j <= jSplit; j++) {
405       aChain.Append(aChain.First());
406       aChain.Remove(1);
407     }
408   }
409
410   // union edges in chain
411   // first step: union lines and circles
412   TopLoc_Location Loc;
413   Standard_Real fp1,lp1,fp2,lp2;
414   for(j=1; j<aChain.Length(); j++) {
415     TopoDS_Edge edge1 = TopoDS::Edge(aChain.Value(j));
416     Handle(Geom_Curve) c3d1 = BRep_Tool::Curve(edge1,Loc,fp1,lp1);
417     if(c3d1.IsNull()) break;
418     while(c3d1->IsKind(STANDARD_TYPE(Geom_TrimmedCurve))) {
419       Handle(Geom_TrimmedCurve) tc =
420         Handle(Geom_TrimmedCurve)::DownCast(c3d1);
421       c3d1 = tc->BasisCurve();
422     }
423     TopoDS_Edge edge2 = TopoDS::Edge(aChain.Value(j+1));
424     Handle(Geom_Curve) c3d2 = BRep_Tool::Curve(edge2,Loc,fp2,lp2);
425     if(c3d2.IsNull()) break;
426     while(c3d2->IsKind(STANDARD_TYPE(Geom_TrimmedCurve))) {
427       Handle(Geom_TrimmedCurve) tc =
428         Handle(Geom_TrimmedCurve)::DownCast(c3d2);
429       c3d2 = tc->BasisCurve();
430     }
431     if( c3d1->IsKind(STANDARD_TYPE(Geom_Line)) && c3d2->IsKind(STANDARD_TYPE(Geom_Line)) ) {
432       // union lines
433       Handle(Geom_Line) L1 = Handle(Geom_Line)::DownCast(c3d1);
434       Handle(Geom_Line) L2 = Handle(Geom_Line)::DownCast(c3d2);
435       gp_Dir Dir1 = L1->Position().Direction();
436       gp_Dir Dir2 = L2->Position().Direction();
437       //if(!Dir1.IsEqual(Dir2,Precision::Angular())) {
438       //if(!Dir1.IsParallel(Dir2,Precision::Angular())) {
439       if(!Dir1.IsParallel(Dir2,Tol)) {
440         continue;
441       }
442       // can union lines => create new edge
443       TopoDS_Vertex V1 = sae.FirstVertex(edge1);
444       gp_Pnt PV1 = BRep_Tool::Pnt(V1);
445       TopoDS_Vertex V2 = sae.LastVertex(edge2);
446       gp_Pnt PV2 = BRep_Tool::Pnt(V2);
447       gp_Vec Vec(PV1,PV2);
448       Handle(Geom_Line) L = new Geom_Line(gp_Ax1(PV1,Vec));
449       Standard_Real dist = PV1.Distance(PV2);
450       Handle(Geom_TrimmedCurve) tc = new Geom_TrimmedCurve(L,0.0,dist);
451       TopoDS_Edge E;
452       B.MakeEdge (E,tc,Precision::Confusion());
453       B.Add (E,V1);  B.Add (E,V2);
454       B.UpdateVertex(V1, 0., E, 0.);
455       B.UpdateVertex(V2, dist, E, 0.);
456       //ShapeFix_Edge sfe;
457       //sfe.FixAddPCurve(E,aFace,Standard_False);
458       //sfe.FixSameParameter(E);
459       aChain.Remove(j);
460       aChain.SetValue(j,E);
461       j--;
462     }
463     if( c3d1->IsKind(STANDARD_TYPE(Geom_Circle)) && c3d2->IsKind(STANDARD_TYPE(Geom_Circle)) ) {
464       // union circles
465       Handle(Geom_Circle) C1 = Handle(Geom_Circle)::DownCast(c3d1);
466       Handle(Geom_Circle) C2 = Handle(Geom_Circle)::DownCast(c3d2);
467       gp_Pnt P01 = C1->Location();
468       gp_Pnt P02 = C2->Location();
469       if (P01.Distance(P02) > Precision::Confusion()) continue;
470       // can union circles => create new edge
471       TopoDS_Vertex V1 = sae.FirstVertex(edge1);
472       gp_Pnt PV1 = BRep_Tool::Pnt(V1);
473       TopoDS_Vertex V2 = sae.LastVertex(edge2);
474       gp_Pnt PV2 = BRep_Tool::Pnt(V2);
475       TopoDS_Vertex VM = sae.LastVertex(edge1);
476       gp_Pnt PVM = BRep_Tool::Pnt(VM);
477       GC_MakeCircle MC (PV1,PVM,PV2);
478       Handle(Geom_Circle) C;
479       TopoDS_Edge E;
480
481       if (MC.IsDone()) {
482         C = MC.Value();
483       }
484
485       if (C.IsNull()) {
486         // jfa for Mantis issue 0020228
487         if (PV1.Distance(PV2) > Precision::Confusion()) continue;
488         // closed chain
489         if (edge1.Orientation() == TopAbs_FORWARD) {
490           C = C1;
491         } else {
492           C = Handle(Geom_Circle)::DownCast(C1->Reversed());
493         }
494
495         B.MakeEdge (E,C,Precision::Confusion());
496         B.Add(E,V1);
497         B.Add(E,V2);
498       }
499       else {
500         gp_Pnt P0 = C->Location();
501         gp_Dir D1(gp_Vec(P0,PV1));
502         gp_Dir D2(gp_Vec(P0,PV2));
503         Standard_Real fpar = C->XAxis().Direction().Angle(D1);
504         if(fabs(fpar)>Precision::Confusion()) {
505           // check orientation
506           gp_Dir ND =  C->XAxis().Direction().Crossed(D1);
507           if(ND.IsOpposite(C->Axis().Direction(),Precision::Confusion())) {
508             fpar = -fpar;
509           }
510         }
511         Standard_Real lpar = C->XAxis().Direction().Angle(D2);
512         if(fabs(lpar)>Precision::Confusion()) {
513           // check orientation
514           gp_Dir ND =  C->XAxis().Direction().Crossed(D2);
515           if(ND.IsOpposite(C->Axis().Direction(),Precision::Confusion())) {
516             lpar = -lpar;
517           }
518         }
519         if (lpar < fpar) lpar += 2*M_PI;
520         Handle(Geom_TrimmedCurve) tc = new Geom_TrimmedCurve(C,fpar,lpar);
521         B.MakeEdge (E,tc,Precision::Confusion());
522         B.Add(E,V1);
523         B.Add(E,V2);
524         B.UpdateVertex(V1, fpar, E, 0.);
525         B.UpdateVertex(V2, lpar, E, 0.);
526       }
527       aChain.Remove(j);
528       aChain.SetValue(j,E);
529       j--;
530     }
531   }
532   if (j < aChain.Length()) {
533     MESSAGE ("null curve3d in edge...");
534     return Standard_False;
535   }
536   if (aChain.Length() > 1) {
537     // second step: union edges with various curves
538     // skl for bug 0020052 from Mantis: perform such unions
539     // only if curves are bspline or bezier
540     bool NeedUnion = true;
541     for(j=1; j<=aChain.Length(); j++) {
542       TopoDS_Edge edge = TopoDS::Edge(aChain.Value(j));
543       Handle(Geom_Curve) c3d = BRep_Tool::Curve(edge,Loc,fp1,lp1);
544       if(c3d.IsNull()) continue;
545       while(c3d->IsKind(STANDARD_TYPE(Geom_TrimmedCurve))) {
546         Handle(Geom_TrimmedCurve) tc =
547           Handle(Geom_TrimmedCurve)::DownCast(c3d);
548         c3d = tc->BasisCurve();
549       }
550       if( ( c3d->IsKind(STANDARD_TYPE(Geom_BSplineCurve)) ||
551             c3d->IsKind(STANDARD_TYPE(Geom_BezierCurve)) ) ) continue;
552       NeedUnion = false;
553       break;
554     }
555     if(NeedUnion) {
556       MESSAGE ("can not make analitical union => make approximation");
557       TopoDS_Edge E = GlueEdgesWithPCurves(aChain, VF, VL);
558       /*
559       TopoDS_Wire W;
560       B.MakeWire(W);
561       for(j=1; j<=aChain.Length(); j++) {
562         TopoDS_Edge edge = TopoDS::Edge(aChain.Value(j));
563         B.Add(W,edge);
564       }
565       Handle(BRepAdaptor_HCompCurve) Adapt = new BRepAdaptor_HCompCurve(W);
566       Approx_Curve3d Conv(Adapt,Tol,GeomAbs_C1,9,1000);
567       Handle(Geom_BSplineCurve) bc = Conv.Curve();
568       TopoDS_Edge E;
569       B.MakeEdge (E,bc,Precision::Confusion());
570       B.Add (E,VF);
571       B.Add (E,VL);
572       */
573       aChain.SetValue(1,E);
574     }
575     else {
576       MESSAGE ("can not make approximation for such types of curves");
577       return Standard_False;
578     }
579   }
580
581   anEdge = TopoDS::Edge(aChain.Value(1));
582   return Standard_True;
583 }
584
585 //=======================================================================
586 //function : Perform
587 //purpose  :
588 //=======================================================================
589 TopoDS_Shape BlockFix_UnionEdges::Perform(const TopoDS_Shape& Shape,
590                                           const Standard_Real Tol)
591 {
592   myContext = new ShapeBuild_ReShape;
593   myTolerance = Tol;
594   TopoDS_Shape aResult = myContext->Apply(Shape);
595
596   // processing each solid
597   TopAbs_ShapeEnum aType = TopAbs_SOLID;
598   TopExp_Explorer exps (Shape, aType);
599   if (!exps.More()) {
600     aType = TopAbs_SHELL;
601     exps.Init(Shape, aType);
602   }
603   for (; exps.More(); exps.Next()) {
604     //TopoDS_Solid aSolid = TopoDS::Solid(exps.Current());
605     TopoDS_Shape aSolid = exps.Current();
606
607     TopTools_IndexedMapOfShape ChangedFaces;
608
609     // creating map of edge faces
610     TopTools_IndexedDataMapOfShapeListOfShape aMapEdgeFaces;
611     TopExp::MapShapesAndAncestors(aSolid, TopAbs_EDGE, TopAbs_FACE, aMapEdgeFaces);
612
613     Handle(ShapeBuild_ReShape) aContext = new ShapeBuild_ReShape;
614     TopoDS_Shape aRes = aSolid;
615     aRes = aContext->Apply(aSolid);
616
617     // processing each face
618     TopExp_Explorer exp;
619     for (exp.Init(aRes, TopAbs_FACE); exp.More(); exp.Next()) {
620       TopoDS_Face aFace =
621         TopoDS::Face(aContext->Apply(exp.Current().Oriented(TopAbs_FORWARD)));
622       TopTools_IndexedDataMapOfShapeListOfShape aMapFacesEdges;
623
624       for (TopExp_Explorer expe(aFace,TopAbs_EDGE); expe.More(); expe.Next()) {
625         TopoDS_Edge edge = TopoDS::Edge(expe.Current());
626         if (!aMapEdgeFaces.Contains(edge)) continue;
627         const TopTools_ListOfShape& aList = aMapEdgeFaces.FindFromKey(edge);
628         TopTools_ListIteratorOfListOfShape anIter(aList);
629         for ( ; anIter.More(); anIter.Next()) {
630           TopoDS_Face face = TopoDS::Face(anIter.Value());
631           TopoDS_Face face1 = TopoDS::Face(aContext->Apply(anIter.Value()));
632           if (face1.IsSame(aFace)) continue;
633           if (aMapFacesEdges.Contains(face)) {
634             aMapFacesEdges.ChangeFromKey(face).Append(edge);
635           }
636           else {
637             TopTools_ListOfShape ListEdges;
638             ListEdges.Append(edge);
639             aMapFacesEdges.Add(face,ListEdges);
640           }
641         }
642       }
643
644       for (Standard_Integer i=1; i<=aMapFacesEdges.Extent(); i++) {
645         const TopTools_ListOfShape& ListEdges = aMapFacesEdges.FindFromIndex(i);
646         TopTools_SequenceOfShape SeqEdges;
647         TopTools_ListIteratorOfListOfShape anIter(ListEdges);
648         for ( ; anIter.More(); anIter.Next()) {
649           SeqEdges.Append(anIter.Value());
650         }
651         if (SeqEdges.Length()==1) continue;
652
653         TopoDS_Face aFace2 =
654           TopoDS::Face(aContext->Apply(aMapFacesEdges.FindKey(i)));
655         TopoDS_Edge E;
656         if ( MergeEdges(SeqEdges,aFace,aFace2,Tol,E) ) {
657           // now we have only one edge - aChain.Value(1)
658           // we have to replace old ListEdges with this new edge
659           aContext->Replace(SeqEdges(1),E);
660           for (Standard_Integer j=2; j<=SeqEdges.Length(); j++) {
661             aContext->Remove(SeqEdges(j));
662           }
663           TopoDS_Face tmpF = TopoDS::Face(exp.Current());
664           if ( !ChangedFaces.Contains(tmpF) )
665             ChangedFaces.Add(tmpF);
666           tmpF = TopoDS::Face(aMapFacesEdges.FindKey(i));
667           if ( !ChangedFaces.Contains(tmpF) )
668             ChangedFaces.Add(tmpF);
669         }
670       }
671
672     } // end processing each face
673
674     // fix changed faces and replace them in the local context
675     for (Standard_Integer i=1; i<=ChangedFaces.Extent(); i++) {
676       TopoDS_Face aFace = TopoDS::Face(aContext->Apply(ChangedFaces.FindKey(i)));
677       Handle(ShapeFix_Face) sff = new ShapeFix_Face(aFace);
678       sff->SetContext(myContext);
679       sff->SetPrecision(myTolerance);
680       sff->SetMinTolerance(myTolerance);
681       sff->SetMaxTolerance(Max(1.,myTolerance*1000.));
682       sff->Perform();
683       aContext->Replace(aFace,sff->Face());
684     }
685
686     if (ChangedFaces.Extent() > 0) {
687       // fix changed shell and replace it in the local context
688       TopoDS_Shape aRes1 = aContext->Apply(aRes);
689       TopExp_Explorer expsh;
690       for (expsh.Init(aRes1, TopAbs_SHELL); expsh.More(); expsh.Next()) {
691         TopoDS_Shell aShell = TopoDS::Shell(expsh.Current());
692         Handle(ShapeFix_Shell) sfsh = new ShapeFix_Shell;
693         sfsh->FixFaceOrientation(aShell);
694         aContext->Replace(aShell,sfsh->Shell());
695       }
696       TopoDS_Shape aRes2 = aContext->Apply(aRes1);
697       // put new solid into global context
698       myContext->Replace(aSolid,aRes2);
699     }
700
701   } // end processing each solid
702
703   aResult = myContext->Apply(Shape);
704   return aResult;
705 }