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