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