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