0024428: Implementation of LGPL license
[occt.git] / src / BRepLib / BRepLib_FuseEdges.cxx
1 // Created on: 1998-11-26
2 // Created by: Jean-Michel BOULCOURT
3 // Copyright (c) 1998-1999 Matra Datavision
4 // Copyright (c) 1999-2014 OPEN CASCADE SAS
5 //
6 // This file is part of Open CASCADE Technology software library.
7 //
8 // This library is free software; you can redistribute it and / or modify it
9 // under the terms of the GNU Lesser General Public version 2.1 as published
10 // by the Free Software Foundation, with special exception defined in the file
11 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
12 // distribution for complete text of the license and disclaimer of any warranty.
13 //
14 // Alternatively, this file may be used under the terms of Open CASCADE
15 // commercial license or contractual agreement.
16
17 // Modif : Wed Jan 20 15:40:50 1999. In BuildListResultEdges, we 
18 // in UpdatePcurve, problem with location of pcurve (mix between loc and locbid)
19 // Modif : Thu Jan 21 11:40:20 1999. Add trace context #if DEB
20 //           add test to avoid loop while in NextConnexEdge (in case of a closed connex wire)
21
22
23 #include <BRepLib_FuseEdges.ixx>
24
25 #include <TopTools_ListOfShape.hxx>
26 #include <TopTools_ListIteratorOfListOfShape.hxx>
27
28 #include <TopTools_MapOfShape.hxx>
29
30 #include <TopTools_DataMapOfIntegerListOfShape.hxx>
31 #include <TopTools_DataMapIteratorOfDataMapOfIntegerListOfShape.hxx>
32
33 #include <TopExp.hxx>
34 #include <TopExp_Explorer.hxx>
35
36 #include <TopoDS.hxx>
37
38 #include <BRep_Tool.hxx>
39 #include <BRep_Builder.hxx>
40
41
42 #include <GeomLib.hxx>
43 #include <Geom2d_Curve.hxx>
44 #include <Geom_Curve.hxx>
45 #include <Geom_BoundedCurve.hxx>
46 #include <Geom_Plane.hxx>
47 #include <Geom2d_TrimmedCurve.hxx>
48 #include <Geom_TrimmedCurve.hxx>
49 #include <Geom_Line.hxx>
50 #include <Geom_Circle.hxx>
51 #include <Geom_Ellipse.hxx>
52 #include <Geom_BSplineCurve.hxx>
53 #include <Geom_BezierCurve.hxx>
54 #include <TColgp_Array1OfPnt.hxx>
55 #include <TColStd_Array1OfReal.hxx>
56 #include <TColStd_Array1OfInteger.hxx>
57 #include <ElCLib.hxx>
58 #include <ElSLib.hxx>
59 #include <Precision.hxx>
60 #include <gp_Pnt2d.hxx>
61 #include <gp_Dir2d.hxx>
62 #include <gp_Vec2d.hxx>
63 #include <gp_Trsf2d.hxx>
64
65 #include <BRepTools_Substitution.hxx>
66 #include <BRepLib_MakeEdge.hxx>
67 #include <BRepLib.hxx>
68 #include <TopoDS_Face.hxx>
69 #include <TopoDS_Wire.hxx>
70
71 #include <Geom2dConvert_CompCurveToBSplineCurve.hxx>
72 #include <Geom2d_BSplineCurve.hxx>
73 #include <BSplCLib.hxx>
74 #include <GeomConvert_CompCurveToBSplineCurve.hxx>
75 #include <Extrema_LocateExtPC.hxx>
76 #include <GeomAdaptor_Curve.hxx>
77 #include <GeomConvert.hxx>
78
79 //#ifdef DEB
80 //Standard_IMPORT Standard_Boolean TopOpeBRepBuild_GettraceFE();
81 //#endif
82
83 static void BCSmoothing(Handle(Geom_BSplineCurve)& theC,
84                         const Standard_Integer theCont,
85                         const Standard_Real theTol)
86 {
87
88   Standard_Integer aNbIter = 5;
89   Standard_Boolean bContinue = Standard_True;
90   Standard_Integer iter = 1;
91   TColStd_SequenceOfInteger aKnotIndex;
92   TColStd_SequenceOfReal aKnotIns;
93
94   while (bContinue && iter <= aNbIter) {
95
96     Standard_Integer aNbKnots = theC->NbKnots();
97     TColStd_Array1OfInteger aMults(1, aNbKnots);
98     TColStd_Array1OfReal aKnots(1, aNbKnots);
99
100     theC->Multiplicities(aMults);
101     theC->Knots(aKnots);
102     Standard_Integer i, m = theC->Degree();
103     m = m - theCont;
104
105     if(m < 1) return;
106
107     aKnotIndex.Clear();
108
109     for(i = 2; i < aNbKnots; i++) {
110       if(aMults(i) > m) {
111         if(!(theC->RemoveKnot(i, m, theTol))) {
112           aKnotIndex.Append(i);
113         }
114       }
115     }
116
117     //Prepare knots for inserting;
118
119     Standard_Integer aNbAdd = aKnotIndex.Length();
120
121     if(aNbAdd == 0) return;
122
123     aKnotIns.Clear();
124
125     Standard_Real aLastKnot = aKnots(1);
126     for(i = 1; i <= aNbAdd; i++) {
127
128       Standard_Integer anInd = aKnotIndex(i);
129
130       Standard_Real aK1 = 0.5*(aKnots(anInd) + aKnots(anInd-1));
131       if(Abs(aK1 - aLastKnot) > 1.e-3) {
132         aKnotIns.Append(aK1);
133         aLastKnot = aK1;
134       }
135       
136       Standard_Real aK2 = 0.5*(aKnots(anInd+1) + aKnots(anInd));
137
138       if(Abs(aK2 - aLastKnot) > 1.e-3) {
139         aKnotIns.Append(aK2);
140         aLastKnot = aK2;
141       }
142  
143     }
144
145     aNbAdd = aKnotIns.Length();
146     
147     for(i = 1; i <= aNbAdd; i++) {
148       theC->InsertKnot(aKnotIns(i), m, 1.e-3);
149     }
150
151     iter++;
152
153   }
154
155   if(iter > aNbIter) BCSmoothing(theC, theCont, 1.e10);
156
157   return;
158 }
159
160 static void MakeClosedCurve(Handle(Geom_Curve)& C, const gp_Pnt& PF, 
161                             Standard_Real& f, Standard_Real& l)
162 {
163   Handle(Geom_BSplineCurve) aBC = (*((Handle(Geom_BSplineCurve)*)&C));
164   GeomAbs_Shape aCont = aBC->Continuity();
165   //Find new origin
166   aBC->SetPeriodic();
167   Standard_Integer fk = aBC->FirstUKnotIndex();
168   Standard_Integer lk = aBC->LastUKnotIndex();
169   Standard_Integer k;
170   Standard_Real eps = Precision::Confusion();
171   eps *= eps;
172   Standard_Real porig = 2.*l;
173   Standard_Real dmin = 1.e100, pmin = f;
174   for(k = fk; k <= lk; k++) {
175     gp_Pnt aP = aBC->Value(aBC->Knot(k));
176     Standard_Real d = PF.SquareDistance(aP);
177     if(PF.SquareDistance(aP) > eps) {
178       if(d < dmin) {
179         pmin = aBC->Knot(k);
180         dmin = d;
181       }
182       continue;
183     }
184
185     porig = aBC->Knot(k);
186     break;
187   }
188   if(porig > l) {
189     //try to project
190     GeomAdaptor_Curve aGAC(aBC);
191     Extrema_LocateExtPC aPrj(PF, aGAC, pmin, Precision::PConfusion());
192     if(aPrj.IsDone()) {
193       porig = aPrj.Point().Parameter();
194     }
195     else {
196       Standard_ConstructionError::Raise("FuseEdges : Projection failed for closed curve");
197     }
198   }
199             
200   aBC->SetOrigin(porig, Precision::PConfusion());
201   f = aBC->FirstParameter();
202   l = aBC->LastParameter();
203   aBC->Segment(f, l);
204   if(aCont > GeomAbs_C0 && aBC->Continuity() == GeomAbs_C0) {
205     BCSmoothing(aBC, 1, Precision::Confusion());
206   }
207   C = aBC;
208   f = C->FirstParameter();
209   l = C->LastParameter();
210 }
211
212
213
214 //=======================================================================
215 //function : BRepLib_FuseEdges
216 //purpose  : 
217 //=======================================================================
218
219 BRepLib_FuseEdges::BRepLib_FuseEdges(const TopoDS_Shape& theShape,
220 //                                                   const Standard_Boolean PerformNow)
221                                                    const Standard_Boolean )
222 :myShape(theShape),myShapeDone(Standard_False),myEdgesDone(Standard_False),
223  myResultEdgesDone(Standard_False),myNbConnexEdge(0), myConcatBSpl(Standard_False)
224 {
225 //  if (theShape.ShapeType() != TopAbs_SHELL && theShape.ShapeType() != TopAbs_SOLID)
226 //    Standard_ConstructionError::Raise("FuseEdges");
227   Standard_NullObject_Raise_if(theShape.IsNull(),"FuseEdges");
228   myMapFaces.Clear();
229
230 }
231
232 //=======================================================================
233 //function : AvoidEdges
234 //purpose  : set edges to avoid being fused
235 //=======================================================================
236
237 void BRepLib_FuseEdges::AvoidEdges(const TopTools_IndexedMapOfShape& theMapEdg)
238 {
239   myAvoidEdg = theMapEdg;
240 }
241
242 //=======================================================================
243 //function : SetConcatBSpl
244 //purpose  : 
245 //=======================================================================
246
247 void BRepLib_FuseEdges::SetConcatBSpl(const Standard_Boolean theConcatBSpl)
248 {
249   myConcatBSpl = theConcatBSpl;
250 }
251
252 //=======================================================================
253 //function : Edges
254 //purpose  : returns  all the list of edges to be fused each list of the 
255 //           map represent a set of connex edges that can be fused.
256 //=======================================================================
257
258 void BRepLib_FuseEdges::Edges(TopTools_DataMapOfIntegerListOfShape& theMapLstEdg)
259 {
260
261   if (!myEdgesDone) {
262     BuildListEdges();
263   }
264
265   theMapLstEdg = myMapLstEdg;
266 }
267
268
269 //=======================================================================
270 //function : ResultEdges
271 //purpose  : returns  all the fused edges
272 //=======================================================================
273
274 void BRepLib_FuseEdges::ResultEdges(TopTools_DataMapOfIntegerShape& theMapEdg)
275 {
276
277   if (!myEdgesDone) {
278     BuildListEdges();
279   }
280
281   if (!myResultEdgesDone) {
282     BuildListResultEdges();
283   }
284
285   theMapEdg = myMapEdg;
286 }
287
288 //=======================================================================
289 //function : Faces
290 //purpose  : returns  all the faces that have been modified after perform
291 //=======================================================================
292
293 void BRepLib_FuseEdges::Faces(TopTools_DataMapOfShapeShape& theMapFac)
294 {
295
296   if (!myEdgesDone) {
297     BuildListEdges();
298   }
299
300   if (!myResultEdgesDone) {
301     BuildListResultEdges();
302   }
303
304   if (!myShapeDone) {
305     Perform();
306   }
307
308   theMapFac = myMapFaces;
309 }
310
311
312 //=======================================================================
313 //function : NbVertices
314 //purpose  : 
315 //=======================================================================
316
317 const Standard_Integer BRepLib_FuseEdges::NbVertices()
318 {
319
320   Standard_NullObject_Raise_if(myShape.IsNull(),"FuseEdges : No Shape");
321   Standard_Integer nbedges, nbvertices = 0;
322
323   if (!myEdgesDone) {
324     BuildListEdges();
325   }
326
327   if ((nbedges = myMapLstEdg.Extent()) > 0) {
328
329     TopTools_DataMapIteratorOfDataMapOfIntegerListOfShape itEdg;
330     for (itEdg.Initialize(myMapLstEdg); itEdg.More(); itEdg.Next()) {
331       const Standard_Integer& iLst = itEdg.Key();
332       const TopTools_ListOfShape& LmapEdg = myMapLstEdg.Find(iLst);
333       nbvertices += LmapEdg.Extent() - 1;
334     }    
335   }
336
337   return nbvertices;
338
339 }
340
341
342 //=======================================================================
343 //function : Shape
344 //purpose  : 
345 //=======================================================================
346
347 TopoDS_Shape& BRepLib_FuseEdges::Shape()
348 {
349   Standard_NullObject_Raise_if(myShape.IsNull(),"FuseEdges : No Shape");
350
351   if (!myEdgesDone) {
352     BuildListEdges();
353   }
354
355   if (!myResultEdgesDone) {
356     BuildListResultEdges();
357   }
358
359   if (!myShapeDone) {
360     Perform();
361   }
362
363   return myShape;
364 }
365
366
367
368 //=======================================================================
369 //function : BuildListEdges
370 //purpose  : Build the all the lists of edges that are to be fused
371 //=======================================================================
372
373 void BRepLib_FuseEdges::BuildListEdges()
374 {
375
376 //#ifdef DEB
377   //Standard_Boolean tFE = TopOpeBRepBuild_GettraceFE();
378 //#endif
379
380 //#ifdef DEB
381     //if (tFE) cout<<endl<<"FuseEdges : BuildListEdges  "<<endl;
382 //#endif
383
384   //--------------------------------------------------------
385   // Step One : Build the map ancestors
386   //--------------------------------------------------------
387   
388   // Clear the maps
389   myMapLstEdg.Clear();
390   myMapVerLstEdg.Clear();
391   myMapEdgLstFac.Clear();
392   
393   BuildAncestors(myShape,TopAbs_VERTEX,TopAbs_EDGE,myMapVerLstEdg);
394   TopExp::MapShapesAndAncestors(myShape,TopAbs_EDGE,TopAbs_FACE,myMapEdgLstFac);
395
396   Standard_Integer iEdg;
397   TopTools_MapOfShape mapUniqEdg;
398
399   // for each edge of myMapEdgLstFac
400   for (iEdg = 1; iEdg <= myMapEdgLstFac.Extent(); iEdg++) {
401     const TopoDS_Shape& edgecur = myMapEdgLstFac.FindKey(iEdg);
402     TopTools_ListOfShape LstEdg;
403
404     // if edge not already treated
405     if (!mapUniqEdg.Contains(edgecur) 
406         && (edgecur.Orientation() == TopAbs_FORWARD ||edgecur.Orientation() == TopAbs_REVERSED) ) {
407       if (myAvoidEdg.Contains(edgecur))
408         continue;       // edge is not allowed to be fused
409       BuildListConnexEdge(edgecur, mapUniqEdg, LstEdg);
410       if (LstEdg.Extent() > 1) {
411         myNbConnexEdge++;
412         myMapLstEdg.Bind(myNbConnexEdge,LstEdg);
413       }
414     }
415   }
416
417   myEdgesDone = Standard_True;
418   myResultEdgesDone = Standard_False;
419 }
420
421
422 //=======================================================================
423 //function : BuildListResultEdges
424 //purpose  : Build the result fused edges
425 //=======================================================================
426
427 void BRepLib_FuseEdges::BuildListResultEdges()
428 {
429
430 //#ifdef DEB
431   //Standard_Boolean tFE = TopOpeBRepBuild_GettraceFE();
432 //#endif
433
434 //#ifdef DEB
435     //if (tFE) cout<<endl<<"FuseEdges : BuildListResultEdges  "<<endl;
436 //#endif
437
438   // if we have edges to fuse
439   if (myMapLstEdg.Extent() > 0) {
440     TopTools_DataMapIteratorOfDataMapOfIntegerListOfShape itLstEdg;
441     TopoDS_Vertex VF,VL;
442     Handle(Geom_Curve) C;
443     TopLoc_Location loc;
444     Standard_Real f,l;
445     TopoDS_Edge NewEdge;
446
447     myMapEdg.Clear();
448
449     for (itLstEdg.Initialize(myMapLstEdg); itLstEdg.More(); itLstEdg.Next()) {
450       const Standard_Integer& iLst = itLstEdg.Key();
451       const TopTools_ListOfShape& LmapEdg = myMapLstEdg.Find(iLst);
452
453       TopoDS_Edge& OldEdge = TopoDS::Edge(LmapEdg.First());
454
455       // the first edge of the list will be replaced by the result fusion edge
456       if (OldEdge.Orientation()==TopAbs_REVERSED) {
457         VL = TopExp::FirstVertex(TopoDS::Edge(LmapEdg.First()),Standard_True);
458         VF = TopExp::LastVertex(TopoDS::Edge(LmapEdg.Last()),Standard_True);
459       }
460       else {
461         VF = TopExp::FirstVertex(TopoDS::Edge(LmapEdg.First()),Standard_True);
462         VL = TopExp::LastVertex(TopoDS::Edge(LmapEdg.Last()),Standard_True);
463       }
464       C = BRep_Tool::Curve(OldEdge,loc,f,l);
465
466       if (!loc.IsIdentity()) {
467         C = Handle(Geom_Curve)::DownCast(C->Transformed(loc.Transformation()));
468       }
469       // if the curve is trimmed we get the basis curve to fit the new vertices
470       // otherwise the makeedge will fail.
471       if (C->DynamicType() == STANDARD_TYPE(Geom_TrimmedCurve)) {
472         C = (*((Handle(Geom_TrimmedCurve)*)&C))->BasisCurve();
473       }
474
475       if(myConcatBSpl) {
476         //Prepare common BSpline curve
477         if(C->DynamicType() == STANDARD_TYPE(Geom_BSplineCurve)) {
478           TopTools_ListIteratorOfListOfShape anEdgIter(LmapEdg);
479           Handle(Geom_TrimmedCurve) aTC = new Geom_TrimmedCurve(C, f, l);
480           GeomConvert_CompCurveToBSplineCurve Concat( aTC );
481
482           anEdgIter.Next();
483           for(; anEdgIter.More(); anEdgIter.Next()) {
484             Handle(Geom_Curve) aC = BRep_Tool::Curve(TopoDS::Edge(anEdgIter.Value()), f, l);
485             aTC = new Geom_TrimmedCurve(aC, f, l);
486             if (!Concat.Add(aTC, Precision::Confusion())) {
487                   // cannot merge curves
488               Standard_ConstructionError::Raise("FuseEdges : Concatenation failed");
489             }
490           }
491           C = Concat.BSplineCurve();                    
492         }
493       }
494
495   
496 //#ifdef DEB
497     //if (tFE) cout<<endl<<"FuseEdges : Creating New Edge "<<endl;
498 //#endif
499
500       BRepLib_MakeEdge ME;
501       
502       Standard_Boolean isBSpline = C->DynamicType() == STANDARD_TYPE(Geom_BSplineCurve); 
503
504       if(VF.IsSame(VL) && isBSpline) {
505         //closed edge
506         f = C->FirstParameter();
507         l = C->LastParameter();
508         gp_Pnt aPf = C->Value(f);
509         gp_Pnt aPl = C->Value(l);
510         if(aPf.Distance(aPl) > Precision::Confusion()) {
511             Standard_ConstructionError::Raise("FuseEdges : Curve must be closed");
512         }
513         gp_Pnt PF = BRep_Tool::Pnt(VF);
514         if(PF.Distance(aPf) > Precision::Confusion()) {
515           MakeClosedCurve(C, PF, f, l);
516         }
517         //
518         ME.Init(C, VF, VL, f, l);
519         if (!ME.IsDone()) {
520           Standard_ConstructionError::Raise("FuseEdges : MakeEdge failed for closed curve");
521         }
522       }
523       else {
524         ME.Init(C,VF,VL);
525       }
526 //      BRepLib_MakeEdge ME(C,VF,VL);
527
528       if (!ME.IsDone()) {
529         // the MakeEdge has fails, one reason could be that the new Vertices are outside
530         // the curve which is not infinite and limited to old vertices
531         // we try to use ExtendCurveToPoint, then rebuild the NewEdge
532
533 //#ifdef DEB
534         //if (tFE) cout<<endl<<"FuseEdges : MakeEdge failed. Trying to Extend Curve "<<endl;
535 //#endif
536         Handle(Geom_BoundedCurve) ExtC = Handle(Geom_BoundedCurve)::DownCast(C->Copy());
537         if (!ExtC.IsNull()) {
538           gp_Pnt PF = BRep_Tool::Pnt(VF);
539           gp_Pnt PL = BRep_Tool::Pnt(VL);
540           GeomLib::ExtendCurveToPoint(ExtC,PF,1,0);
541           GeomLib::ExtendCurveToPoint(ExtC,PL,1,1); 
542
543           ME.Init(ExtC,VF,VL);
544           if (!ME.IsDone()) 
545             Standard_ConstructionError::Raise("FuseEdges : Fusion failed");
546         }
547         else
548           Standard_ConstructionError::Raise("FuseEdges : Fusion failed");
549       }
550
551       NewEdge = ME.Edge();
552
553 //#ifdef DEB
554       //if (tFE) cout<<endl<<"FuseEdges : Updating pcurve "<<endl;
555 //#endif
556       if (UpdatePCurve(OldEdge,NewEdge,LmapEdg))
557         myMapEdg.Bind(iLst,NewEdge);
558     }
559
560     myResultEdgesDone = Standard_True;
561
562   }
563 }
564
565 //=======================================================================
566 //function : Perform
567 //purpose  : 
568 //=======================================================================
569
570 void BRepLib_FuseEdges::Perform()
571 {
572
573 //#ifdef DEB
574   //Standard_Boolean tFE = TopOpeBRepBuild_GettraceFE();
575 //#endif
576
577   if (!myResultEdgesDone) {
578     BuildListResultEdges();
579   }
580
581 //#ifdef DEB
582     //if (tFE) cout<<endl<<"FuseEdges : Perform  "<<endl;
583 //#endif
584
585   // if we have fused edges
586   if (myMapEdg.Extent() > 0) {
587     TopTools_DataMapIteratorOfDataMapOfIntegerListOfShape itLstEdg;
588     TopTools_ListOfShape EmptyList,EdgeToSubs;
589     BRepTools_Substitution Bsub;
590
591     for (itLstEdg.Initialize(myMapLstEdg); itLstEdg.More(); itLstEdg.Next()) {
592       const Standard_Integer& iLst = itLstEdg.Key();
593       if (!myMapEdg.IsBound(iLst))
594         continue;
595       const TopTools_ListOfShape& LmapEdg = myMapLstEdg.Find(iLst);
596       TopTools_ListIteratorOfListOfShape itEdg; 
597
598       EdgeToSubs.Clear();
599       TopoDS_Edge& OldEdge = TopoDS::Edge(LmapEdg.First());
600
601
602       EdgeToSubs.Append(myMapEdg(iLst));
603       Bsub.Substitute(OldEdge,EdgeToSubs);
604
605       itEdg.Initialize(LmapEdg);
606
607       // the other edges of the list will be removed
608       while (itEdg.More() ) {
609         if (!OldEdge.IsSame(TopoDS::Edge(itEdg.Value()))) {
610           Bsub.Substitute(itEdg.Value(),EmptyList);
611         }
612         itEdg.Next();
613       }      
614     }
615
616 //#ifdef DEB
617     //if (tFE) cout<<endl<<"FuseEdges : Building New Shape  "<<endl;
618 //#endif
619
620     // perform the effective substitution
621     Bsub.Build(myShape);
622
623     // before copying the resulting shape, map the modified faces into myMapFaces
624     TopExp_Explorer exp(myShape,TopAbs_FACE);
625     
626     for (; exp.More(); exp.Next()) {
627       const TopoDS_Shape& facecur = exp.Current();
628       if (Bsub.IsCopied(facecur)) {
629         myMapFaces.Bind(facecur,(Bsub.Copy(facecur)).First());
630       }
631     }
632     
633     if (Bsub.IsCopied(myShape)) {
634       myShape=(Bsub.Copy(myShape)).First();
635     }
636
637 //#ifdef DEB
638     //if (tFE) cout<<endl<<"FuseEdges : "<< NbVertices() <<" vertices removed"<<endl;
639 //#endif
640
641
642   }
643
644
645   myShapeDone = Standard_True;
646 }
647
648
649
650 //=======================================================================
651 //function : BuildListConnexEdge
652 //purpose  : giving one edge, build the list of connex edges which have
653 // vertices that have only two connex edges. All the edges that are addes
654 // to the list must be added also to the mapUniq, in order for the caller
655 // to not treat again theses edges.
656 // This list is always oriented in the "Forward" direction.
657 //=======================================================================
658
659 void BRepLib_FuseEdges::BuildListConnexEdge(const TopoDS_Shape& theEdge, 
660                                                    TopTools_MapOfShape& theMapUniq, 
661                                                    TopTools_ListOfShape& theLstEdg)
662 {
663
664   TopoDS_Vertex VF,VL;
665
666
667   VL = TopExp::LastVertex(TopoDS::Edge(theEdge),Standard_True);
668   TopoDS_Shape edgeconnex;
669   TopoDS_Shape edgecur = theEdge;
670   theLstEdg.Clear();
671   theLstEdg.Append(edgecur);
672   theMapUniq.Add(edgecur);
673   TopAbs_Orientation ori2;
674
675   // we first build the list of edges connex to edgecur by looking from the last Vertex VL
676   while (NextConnexEdge(VL,edgecur,edgeconnex)) {
677     if (theMapUniq.Contains(edgeconnex)) {
678       break;
679     }
680     theLstEdg.Append(edgeconnex);
681     edgecur = edgeconnex;
682     // here take care about internal or external edges. It is non-sense to build
683     // the connex list with such edges.
684     ori2 = edgecur.Orientation();
685     if (ori2 == TopAbs_EXTERNAL || ori2 == TopAbs_INTERNAL) {
686       break;
687     }
688     VL = TopExp::LastVertex(TopoDS::Edge(edgecur),Standard_True);
689     theMapUniq.Add(edgecur);
690   }
691
692   edgecur = theEdge;
693   VF = TopExp::FirstVertex(TopoDS::Edge(theEdge),Standard_True);
694
695   // then we build the list of edges connex to edgecur by looking from the first Vertex VF
696   while (NextConnexEdge(VF,edgecur,edgeconnex)) {
697     if (theMapUniq.Contains(edgeconnex)) {
698       break;
699     }
700     theLstEdg.Prepend(edgeconnex);
701     edgecur = edgeconnex;
702     // here take care about internal or external edges. It is non-sense to build
703     // the connex list with such edges.
704     ori2 = edgecur.Orientation();
705     if (ori2 == TopAbs_EXTERNAL || ori2 == TopAbs_INTERNAL) {
706       break;
707     }
708     VF = TopExp::FirstVertex(TopoDS::Edge(edgecur),Standard_True);
709     theMapUniq.Add(edgecur);
710   }
711
712 }
713
714
715 //=======================================================================
716 //function : NextConnexEdge
717 //purpose  : Look for an edge connex to theEdge at theVertex.
718 // the connex edge must satisfies the following criteria :
719 //   * theVertex must have exactly 2 connex edges.
720 //   * the 2 connex edges must have exactly the 2 same connex faces 
721 //   * the 2 connex edges must lie on the same support.
722 //=======================================================================
723
724 Standard_Boolean BRepLib_FuseEdges::NextConnexEdge(const TopoDS_Vertex& theVertex, 
725                                                           const TopoDS_Shape& theEdge,          
726                                                           TopoDS_Shape& theEdgeConnex) const
727 {
728
729   const TopTools_ListOfShape& LmapEdg = myMapVerLstEdg.FindFromKey(theVertex);
730   Standard_Boolean HasConnex = Standard_True;
731   TopTools_ListIteratorOfListOfShape itEdg,itFac1,itFac2;
732
733   // 1st condition 
734   if (LmapEdg.Extent() == 2) {
735     itEdg.Initialize(LmapEdg);
736     theEdgeConnex = itEdg.Value();
737     if (theEdge.IsSame(theEdgeConnex) ) {
738       itEdg.Next();
739       theEdgeConnex = itEdg.Value();
740     }
741
742     if (myAvoidEdg.Contains(theEdgeConnex))
743       HasConnex = Standard_False;  // edge is not allowed to be fused
744
745     // 2nd condition
746     if (HasConnex) {
747       const TopTools_ListOfShape& LmapFac1 = myMapEdgLstFac.FindFromKey(theEdge);
748       const TopTools_ListOfShape& LmapFac2 = myMapEdgLstFac.FindFromKey(theEdgeConnex);
749       
750       if (LmapFac1.Extent() ==  LmapFac2.Extent() && LmapFac1.Extent() < 3) {
751         itFac1.Initialize(LmapFac1); 
752
753         // for each face in LmapFac1 we look in LmapFac2 if it exists
754         while (itFac1.More() && HasConnex) {
755           const TopoDS_Shape& face1 = itFac1.Value();
756           for (itFac2.Initialize(LmapFac2); itFac2.More(); itFac2.Next()) {
757             const TopoDS_Shape& face2 = itFac2.Value();
758             HasConnex = Standard_False;
759             if (face1.IsSame(face2)) {
760               HasConnex = Standard_True;
761               break;
762             }
763           }
764           itFac1.Next();
765         }
766         
767         // 3rd condition : same suport
768         if (HasConnex) {
769           HasConnex = SameSupport(TopoDS::Edge(theEdge),TopoDS::Edge(theEdgeConnex));
770         }
771       }
772       else
773         HasConnex = Standard_False;
774     }
775   }
776   else
777     HasConnex = Standard_False;
778
779   return HasConnex;
780 }
781
782
783
784 //=======================================================================
785 //function : SameSupport
786 //purpose  : Edges SameSupport ou pas
787 //=======================================================================
788
789 Standard_Boolean BRepLib_FuseEdges::SameSupport(const TopoDS_Edge& E1,
790                                                        const TopoDS_Edge& E2) const
791 {
792
793   if (E1.IsNull() || E2.IsNull()) {
794     return Standard_False;
795   }
796
797
798   Handle(Geom_Curve) C1,C2;
799   TopLoc_Location loc;
800   Standard_Real f1,l1,f2,l2;
801   Handle(Standard_Type) typC1,typC2;
802   
803   C1 = BRep_Tool::Curve(E1,loc,f1,l1);
804   //modified by NIZNHY-PKV Mon Nov 15 16:24:10 1999
805   //degenerated edges has no 3D curve
806   if(C1.IsNull()) return Standard_False;
807
808   if (!loc.IsIdentity()) {
809     Handle(Geom_Geometry) GG1 = C1->Transformed(loc.Transformation());
810     C1 = *((Handle(Geom_Curve)*)&GG1);
811   }
812   C2 = BRep_Tool::Curve(E2,loc,f2,l2);
813   //modified by NIZNHY-PKV Mon Nov 15 16:24:38 1999
814   //degenerated edges has no 3D curve
815   if(C2.IsNull()) return Standard_False;
816
817   if (!loc.IsIdentity()) {
818     Handle(Geom_Geometry) GG2 = C2->Transformed(loc.Transformation());
819     C2 = *((Handle(Geom_Curve)*)&GG2);
820   }
821   
822   typC1 = C1->DynamicType();
823   typC2 = C2->DynamicType();
824   
825   if (typC1 == STANDARD_TYPE(Geom_TrimmedCurve)) {
826     C1 =  (*((Handle(Geom_TrimmedCurve)*)&C1))->BasisCurve();
827     typC1 = C1->DynamicType();
828   }
829   
830   if (typC2 == STANDARD_TYPE(Geom_TrimmedCurve)) {
831     C2 =  (*((Handle(Geom_TrimmedCurve)*)&C2))->BasisCurve();
832     typC2 = C2->DynamicType();
833   }
834   
835   if (typC1 != typC2) {
836     return Standard_False;
837   }
838   
839   if (typC1 != STANDARD_TYPE(Geom_Line) &&
840       typC1 != STANDARD_TYPE(Geom_Circle) &&
841       typC1 != STANDARD_TYPE(Geom_Ellipse) &&
842       typC1 != STANDARD_TYPE(Geom_BSplineCurve) && 
843       typC1 != STANDARD_TYPE(Geom_BezierCurve)) {
844 #ifdef DEB
845     cout << " TopOpeBRepTool_FuseEdge : Type de Support non traite" << endl;
846 #endif
847     return Standard_False;
848   }
849
850   // On a presomption de confusion
851   const Standard_Real tollin = Precision::Confusion();
852   const Standard_Real tolang = Precision::Angular();
853   if (typC1 == STANDARD_TYPE(Geom_Line)) {
854     gp_Lin li1( (*((Handle(Geom_Line)*)&C1))->Lin());
855     gp_Lin li2( (*((Handle(Geom_Line)*)&C2))->Lin());
856     gp_Dir dir1(li1.Direction());
857     gp_Dir dir2(li2.Direction());
858
859     if ( dir1.IsParallel(dir2,tolang) ) {
860       // on verifie que l'on n'a pas de cas degenere. Par exemple E1 et E2 connexes
861       // mais bouclant l'un sur l'autre (cas tres rare)
862       gp_Pnt pf1 = BRep_Tool::Pnt(TopExp::FirstVertex(E1,Standard_True));
863       gp_Pnt pl1 = BRep_Tool::Pnt(TopExp::LastVertex(E1,Standard_True));
864       gp_Pnt pf2 = BRep_Tool::Pnt(TopExp::FirstVertex(E2,Standard_True));
865       gp_Pnt pl2 = BRep_Tool::Pnt(TopExp::LastVertex(E2,Standard_True));
866       if ( pl1.Distance(pf2) < tollin && pl2.Distance(pf1) < tollin)
867         return Standard_False;
868       else
869         return Standard_True;
870     }
871     return Standard_False;
872   } 
873   else if (typC1 == STANDARD_TYPE(Geom_Circle)) {
874     gp_Circ ci1 = (*((Handle(Geom_Circle)*)&C1))->Circ();
875     gp_Circ ci2 = (*((Handle(Geom_Circle)*)&C2))->Circ();
876     if (Abs(ci1.Radius()-ci2.Radius()) <= tollin &&
877         ci1.Location().SquareDistance(ci2.Location()) <= tollin*tollin &&
878         ci1.Axis().IsParallel(ci2.Axis(),tolang) ) {
879       // Point debut, calage dans periode, et detection meme sens
880       return Standard_True;
881     }
882     return Standard_False;
883   }
884   else if (typC1 == STANDARD_TYPE(Geom_Ellipse)) {
885     gp_Elips ci1 = (*((Handle(Geom_Ellipse)*)&C1))->Elips();
886     gp_Elips ci2 = (*((Handle(Geom_Ellipse)*)&C2))->Elips();
887     
888     if (Abs(ci1.MajorRadius()-ci2.MajorRadius()) <= tollin &&
889         Abs(ci1.MinorRadius()-ci2.MinorRadius()) <= tollin &&
890         ci1.Location().SquareDistance(ci2.Location()) <= tollin*tollin &&
891         ci1.Axis().IsParallel(ci2.Axis(),tolang) ) {
892       // Point debut, calage dans periode, et detection meme sens
893       return Standard_True;
894     }
895     return Standard_False;
896   }
897   else if (typC1 == STANDARD_TYPE(Geom_BSplineCurve)) {
898
899     if(myConcatBSpl) {
900       //Check G1 continuity 
901       gp_Pnt aPf1, aPl1, aPf2, aPl2;
902       gp_Vec aDf1, aDl1, aDf2, aDl2;
903
904       C1->D1(f1, aPf1, aDf1);
905       C1->D1(l1, aPl1, aDl1);
906
907       C2->D1(f2, aPf2, aDf2);
908       C2->D1(l2, aPl2, aDl2);
909
910       if(aPl1.Distance(aPf2) <= tollin && aDl1.IsParallel(aDf2, tolang)) return Standard_True;
911       if(aPl2.Distance(aPf1) <= tollin && aDl2.IsParallel(aDf1, tolang)) return Standard_True;
912       if(aPf1.Distance(aPf2) <= tollin && aDf1.IsParallel(aDf2, tolang)) return Standard_True;
913       if(aPl1.Distance(aPl2) <= tollin && aDl1.IsParallel(aDl2, tolang)) return Standard_True;
914
915     }
916     // we must ensure that before fuse two bsplines, the end of one curve does not
917     // corresponds to the beginning of the second.
918     // we could add a special treatment for periodic bspline. This is not done for the moment.
919     if (Abs(f2-l1) > tollin && Abs(f1-l2) > tollin ) {
920       return Standard_False;
921     }
922
923     Handle(Geom_BSplineCurve) B1 = *((Handle(Geom_BSplineCurve)*)&C1);
924     Handle(Geom_BSplineCurve) B2 = *((Handle(Geom_BSplineCurve)*)&C2);
925    
926     Standard_Integer nbpoles = B1->NbPoles();
927     if (nbpoles != B2->NbPoles()) {
928       return Standard_False;
929     }
930    
931     Standard_Integer nbknots = B1->NbKnots();
932     if (nbknots != B2->NbKnots()) {
933       return Standard_False;
934     }
935    
936     TColgp_Array1OfPnt P1(1, nbpoles), P2(1, nbpoles);
937     B1->Poles(P1);
938     B2->Poles(P2);
939    
940     Standard_Real tol3d = BRep_Tool::Tolerance(E1);
941     for (Standard_Integer p = 1; p <= nbpoles; p++) {
942       if ( (P1(p)).Distance(P2(p)) > tol3d) {
943         return Standard_False;
944       }
945     }
946    
947     TColStd_Array1OfReal K1(1, nbknots), K2(1, nbknots);
948     B1->Knots(K1);
949     B2->Knots(K2);
950    
951     TColStd_Array1OfInteger M1(1, nbknots), M2(1, nbknots);
952     B1->Multiplicities(M1);
953     B2->Multiplicities(M2);
954    
955     for (Standard_Integer k = 1; k <= nbknots; k++) {
956       if ((K1(k)-K2(k)) > tollin) {
957         return Standard_False;
958       }
959       if (Abs(M1(k)-M2(k)) > tollin) {
960         return Standard_False;
961       }
962     }
963    
964     if (!B1->IsRational()) {
965       if (B2->IsRational()) {
966         return Standard_False;
967       }
968     }
969     else {
970       if (!B2->IsRational()) {
971         return Standard_False;
972       }
973     }
974     
975     if (B1->IsRational()) {
976       TColStd_Array1OfReal W1(1, nbpoles), W2(1, nbpoles);
977       B1->Weights(W1);
978       B2->Weights(W2);
979    
980       for (Standard_Integer w = 1; w <= nbpoles; w++) {
981         if (Abs(W1(w)-W2(w)) > tollin) {
982           return Standard_False;
983         }
984       }
985     }
986     return Standard_True;
987   }
988   else if (typC1 == STANDARD_TYPE(Geom_BezierCurve)) {
989
990     // we must ensure that before fuse two bezier, the end of one curve does not
991     // corresponds to the beginning of the second.
992     if (Abs(f2-l1) > tollin && Abs(f1-l2) > tollin ) {
993       return Standard_False;
994     }
995
996     Handle(Geom_BezierCurve) B1 = *((Handle(Geom_BezierCurve)*)&C1);
997     Handle(Geom_BezierCurve) B2 = *((Handle(Geom_BezierCurve)*)&C2);
998     
999     Standard_Integer nbpoles = B1->NbPoles();
1000     if (nbpoles != B2->NbPoles()) {
1001       return Standard_False;
1002     }
1003     
1004     TColgp_Array1OfPnt P1(1, nbpoles), P2(1, nbpoles);
1005     B1->Poles(P1);
1006     B2->Poles(P2);
1007     
1008     for (Standard_Integer p = 1; p <= nbpoles; p++) {
1009       if ( (P1(p)).Distance(P2(p)) > tollin) {
1010         return Standard_False;
1011       }
1012     }
1013     
1014     if (!B1->IsRational()) {
1015       if (B2->IsRational()) {
1016         return Standard_False;
1017       }
1018     }
1019     else {
1020       if (!B2->IsRational()) {
1021         return Standard_False;
1022       }
1023     }
1024     
1025     if (B1->IsRational()) {
1026       TColStd_Array1OfReal W1(1, nbpoles), W2(1, nbpoles);
1027       B1->Weights(W1);
1028       B2->Weights(W2);
1029       
1030       for (Standard_Integer w = 1; w <= nbpoles; w++) {
1031         if (Abs(W1(w)-W2(w)) > tollin) {
1032           return Standard_False;
1033         }
1034       }
1035     }
1036     return Standard_True;
1037   }
1038   return Standard_False;
1039 }
1040
1041
1042 //=======================================================================
1043 //function : BuildAncestors
1044 //purpose  : This function is like TopExp::MapShapesAndAncestors except
1045 // that in the list of shape we do not want duplicate shapes.
1046 // if this is useful for other purpose we should create a new method in
1047 // TopExp
1048 //=======================================================================
1049
1050 void BRepLib_FuseEdges::BuildAncestors
1051   (const TopoDS_Shape& S, 
1052    const TopAbs_ShapeEnum TS, 
1053    const TopAbs_ShapeEnum TA, 
1054    TopTools_IndexedDataMapOfShapeListOfShape& M) const
1055 {
1056
1057   TopTools_MapOfShape mapDuplicate;
1058   TopTools_ListIteratorOfListOfShape it;
1059   Standard_Integer iSh;
1060
1061   TopExp::MapShapesAndAncestors(S,TS,TA,M);
1062
1063   // for each shape of M
1064   for (iSh = 1; iSh <= M.Extent(); iSh++) {
1065     TopTools_ListOfShape& Lsh = M(iSh);
1066
1067     mapDuplicate.Clear();
1068     // we check for duplicate in the list of Shape
1069     it.Initialize(Lsh);
1070     while (it.More() ) {
1071       if (!mapDuplicate.Contains(it.Value())) {
1072         mapDuplicate.Add(it.Value());
1073         it.Next();
1074       }
1075       else {
1076         Lsh.Remove(it);
1077       }
1078     }
1079   }  
1080
1081 }
1082
1083
1084 //=======================================================================
1085 //function : UpdatePCurve
1086 //purpose  : 
1087 //=======================================================================
1088
1089 Standard_Boolean BRepLib_FuseEdges::UpdatePCurve(const TopoDS_Edge& theOldEdge,
1090                                             TopoDS_Edge& theNewEdge,
1091                                             const TopTools_ListOfShape& theLstEdg) const
1092 {
1093
1094
1095 // get the pcurve of edge to substitute (theOldEdge) 
1096 // using CurveOnSurface with Index syntax, so we can update the pcurve
1097 // on all the faces
1098   BRep_Builder B;
1099   Handle(Geom2d_Curve) Curv2d;
1100   Handle(Geom_Surface) Surf;
1101   TopLoc_Location loc,locbid;
1102   Standard_Real ef,el,cf,cl;
1103   Standard_Integer iedg = 1;
1104
1105   // take care that we want only Pcurve that maps on the surface where the 3D edges lies.
1106   const TopTools_ListOfShape& LmapFac = myMapEdgLstFac.FindFromKey(theOldEdge);
1107
1108
1109   BRep_Tool::CurveOnSurface(theOldEdge,Curv2d,Surf,loc,cf,cl,iedg);
1110
1111   Standard_Boolean pcurveRebuilt = Standard_False;
1112   
1113   while (!Curv2d.IsNull()) {
1114     
1115     // we look for a face that contains the same surface as the one that cames
1116     // from CurveOnSurface
1117     Standard_Boolean SameSurf = Standard_False;
1118     TopTools_ListIteratorOfListOfShape itFac;
1119
1120     for (itFac.Initialize(LmapFac); itFac.More(); itFac.Next() ) {
1121       const TopoDS_Shape& face = itFac.Value();
1122       Handle (Geom_Surface) S = BRep_Tool::Surface(TopoDS::Face(face),locbid);
1123       if (S == Surf) {
1124         SameSurf = Standard_True;
1125         break;
1126       }
1127     }
1128
1129     if (SameSurf) {
1130
1131       BRep_Tool::Range(theNewEdge,ef,el);
1132
1133         //modified by NIZNHY-PKV Mon Nov 15 14:59:48 1999 _from
1134       TopoDS_Edge aFEdge = theOldEdge;
1135       aFEdge.Orientation(TopAbs_FORWARD);
1136
1137       // take care if the edge is on the closing curve of a closed surface. In that case
1138       // we get the second pcurve by reversing the edge and calling again CurveOnSurface method
1139       
1140       BRep_Tool::CurveOnSurface(aFEdge,Curv2d,Surf,loc,cf,cl,iedg);
1141       if (BRep_Tool::IsClosed(theOldEdge,Surf,loc))  {
1142         aFEdge.Reverse();
1143         TopoDS_Face aFFace = TopoDS::Face(itFac.Value());
1144         aFFace.Orientation(TopAbs_FORWARD);
1145         Handle(Geom2d_Curve) Curv2dR = BRep_Tool::CurveOnSurface(aFEdge,
1146                                                                  aFFace,cf,cl);
1147         if (Curv2d->DynamicType() == STANDARD_TYPE(Geom2d_TrimmedCurve))
1148           Curv2d = (*((Handle(Geom2d_TrimmedCurve)*)&Curv2d))->BasisCurve();
1149         if (Curv2dR->DynamicType() == STANDARD_TYPE(Geom2d_TrimmedCurve))
1150           Curv2dR = (*((Handle(Geom2d_TrimmedCurve)*)&Curv2dR))->BasisCurve();
1151
1152         B.UpdateEdge (theNewEdge,Curv2d,Curv2dR,Surf,loc,BRep_Tool::Tolerance(theNewEdge));
1153       }
1154       else {
1155         // update the new edge 
1156         if (Curv2d->DynamicType() == STANDARD_TYPE(Geom2d_TrimmedCurve))
1157           Curv2d = (*((Handle(Geom2d_TrimmedCurve)*)&Curv2d))->BasisCurve();
1158         Standard_Real f, l;
1159         f = Curv2d->FirstParameter();
1160         l = Curv2d->LastParameter();
1161         if (l-f + 2.* Epsilon(l-f) < el-ef)
1162           {
1163             Handle(Geom2d_BoundedCurve) bcurve = Handle(Geom2d_BoundedCurve)::DownCast(Curv2d);
1164             if (bcurve.IsNull())
1165               bcurve = new Geom2d_TrimmedCurve( Curv2d, cf, cl );
1166             Geom2dConvert_CompCurveToBSplineCurve Concat( bcurve );
1167             TopTools_ListIteratorOfListOfShape iter( theLstEdg );
1168             iter.Next();
1169             for (; iter.More(); iter.Next())
1170               {
1171                 TopoDS_Edge& E = TopoDS::Edge(iter.Value());
1172                 Standard_Real first, last;
1173                 Handle(Geom2d_Curve) C = BRep_Tool::CurveOnSurface( E, Surf, loc, first, last );
1174                 Handle(Geom2d_BoundedCurve) BC = Handle(Geom2d_BoundedCurve)::DownCast(C);
1175                 if (BC.IsNull())
1176                   BC = new Geom2d_TrimmedCurve( C, first, last );
1177                 if (!Concat.Add( BC, Precision::PConfusion() ))
1178                   // cannot merge pcurves
1179                   return Standard_False;
1180               }
1181             Curv2d = Concat.BSplineCurve();
1182
1183             // check that new curve 2d is same range 
1184             Standard_Real first = Curv2d->FirstParameter();
1185             Standard_Real last = Curv2d->LastParameter();
1186             if (Abs (first - ef) > Precision::PConfusion() ||
1187                 Abs (last - el) > Precision::PConfusion())
1188             {
1189               Handle(Geom2d_BSplineCurve) bc = Handle(Geom2d_BSplineCurve)::DownCast(Curv2d);
1190               TColStd_Array1OfReal Knots (1, bc->NbKnots());
1191               bc->Knots(Knots);
1192               BSplCLib::Reparametrize (ef, el, Knots);
1193               bc->SetKnots(Knots);
1194             }
1195             pcurveRebuilt = Standard_True;
1196           }
1197
1198         B.UpdateEdge (theNewEdge,Curv2d,Surf,loc,BRep_Tool::Tolerance(theNewEdge));
1199       }
1200
1201       // the old pcurve range is cf,cl. The new 3d edge range is ef,el. if we want
1202       // the pcurve to be samerange we must adapt the parameter of the edge. In general
1203       // cases cf=ef and cl=el expect for periodic curve if the new edge is going over
1204       // the value 0.
1205       if(!pcurveRebuilt) {
1206         if (theOldEdge.Orientation()== TopAbs_REVERSED) {
1207           B.Range(theNewEdge,cl-el+ef,cl);
1208         }
1209         else {
1210           B.Range(theNewEdge,cf,cf+el-ef);
1211         }
1212       }
1213      } 
1214
1215     // get next pcurve
1216     iedg++;
1217     BRep_Tool::CurveOnSurface(theOldEdge,Curv2d,Surf,loc,cf,cl,iedg);
1218   }
1219
1220   if (pcurveRebuilt)
1221   {
1222     // force same parameter
1223     B.SameParameter (theNewEdge, Standard_False);
1224     BRepLib::SameParameter (theNewEdge, BRep_Tool::Tolerance(theNewEdge));
1225   }
1226
1227   return Standard_True;
1228 }
1229
1230