0030686: Visualization, SelectMgr_ViewerSelector - sorting issues of transformation...
[occt.git] / src / ShapeConstruct / ShapeConstruct.cxx
1 // Created on: 1999-06-17
2 // Created by: data exchange team
3 // Copyright (c) 1999-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
18 #include <BRep_Builder.hxx>
19 #include <BRep_Tool.hxx>
20 #include <Geom2d_BSplineCurve.hxx>
21 #include <Geom2d_Conic.hxx>
22 #include <Geom2d_Curve.hxx>
23 #include <Geom2d_TrimmedCurve.hxx>
24 #include <Geom2dConvert.hxx>
25 #include <Geom2dConvert_ApproxCurve.hxx>
26 #include <Geom_BSplineCurve.hxx>
27 #include <Geom_BSplineSurface.hxx>
28 #include <Geom_Conic.hxx>
29 #include <Geom_Curve.hxx>
30 #include <Geom_ElementarySurface.hxx>
31 #include <Geom_OffsetCurve.hxx>
32 #include <Geom_Plane.hxx>
33 #include <Geom_RectangularTrimmedSurface.hxx>
34 #include <Geom_Surface.hxx>
35 #include <Geom_SurfaceOfLinearExtrusion.hxx>
36 #include <Geom_SurfaceOfRevolution.hxx>
37 #include <Geom_TrimmedCurve.hxx>
38 #include <GeomAPI.hxx>
39 #include <GeomConvert.hxx>
40 #include <GeomConvert_ApproxCurve.hxx>
41 #include <GeomConvert_ApproxSurface.hxx>
42 #include <GeomConvert_CompCurveToBSplineCurve.hxx>
43 #include <gp_Pln.hxx>
44 #include <gp_Vec.hxx>
45 #include <Precision.hxx>
46 #include <ShapeAnalysis_Edge.hxx>
47 #include <ShapeConstruct.hxx>
48 #include <ShapeConstruct_Curve.hxx>
49 #include <Standard_ErrorHandler.hxx>
50 #include <Standard_Failure.hxx>
51 #include <TColgp_Array1OfPnt.hxx>
52 #include <TColgp_Array2OfPnt.hxx>
53 #include <TColStd_Array1OfInteger.hxx>
54 #include <TColStd_Array1OfReal.hxx>
55 #include <TColStd_Array2OfReal.hxx>
56 #include <TopAbs_Orientation.hxx>
57 #include <TopoDS.hxx>
58 #include <TopoDS_Edge.hxx>
59 #include <TopoDS_Face.hxx>
60 #include <TopTools_HSequenceOfShape.hxx>
61
62 //=======================================================================
63 //function : ConvertCurveToBSpline
64 //purpose  : 
65 //=======================================================================
66 Handle(Geom_BSplineCurve) ShapeConstruct::ConvertCurveToBSpline(const Handle(Geom_Curve)& C3D,
67                                                                 const Standard_Real First,
68                                                                 const Standard_Real Last,
69                                                                 const Standard_Real Tol3d,
70                                                                 const GeomAbs_Shape Continuity,
71                                                                 const Standard_Integer MaxSegments,
72                                                                 const Standard_Integer MaxDegree)
73 {
74   Standard_Integer MaxDeg = MaxDegree;
75   Handle(Geom_BSplineCurve) aBSpline;
76   if(C3D->IsKind(STANDARD_TYPE(Geom_BSplineCurve))) 
77     aBSpline = Handle(Geom_BSplineCurve)::DownCast(C3D);
78   else {
79     if(C3D->IsKind(STANDARD_TYPE(Geom_Conic))) 
80       MaxDeg = Min(MaxDeg,6);
81  
82     Handle(Geom_Curve) tcurve = new Geom_TrimmedCurve(C3D,First,Last); //protection agains parabols ets
83     try {
84       OCC_CATCH_SIGNALS
85       GeomConvert_ApproxCurve approx (tcurve, Tol3d, Continuity, MaxSegments, MaxDeg);
86       if ( approx.HasResult() )
87         aBSpline = approx.Curve();
88       else
89         aBSpline = GeomConvert::CurveToBSplineCurve(C3D,Convert_QuasiAngular);
90     }
91     catch (Standard_Failure const& anException) {
92 #ifdef OCCT_DEBUG
93             cout << "Warning: GeomConvert_ApproxSurface Exception:  ";
94             anException.Print(cout); cout << endl;
95 #endif 
96             (void)anException;
97             aBSpline = GeomConvert::CurveToBSplineCurve(C3D,Convert_QuasiAngular);    
98           }
99   }
100   return aBSpline;
101 }
102
103 //=======================================================================
104 //function : ConvertCurveToBSpline
105 //purpose  : 
106 //=======================================================================
107
108 Handle(Geom2d_BSplineCurve) ShapeConstruct::ConvertCurveToBSpline(const Handle(Geom2d_Curve)& C2D,
109                                                                   const Standard_Real First,
110                                                                   const Standard_Real Last,
111                                                                   const Standard_Real Tol2d,
112                                                                   const GeomAbs_Shape Continuity,
113                                                                   const Standard_Integer MaxSegments,
114                                                                   const Standard_Integer MaxDegree)
115 {
116   Handle(Geom2d_BSplineCurve) aBSpline2d;
117   if(C2D->IsKind(STANDARD_TYPE(Geom2d_Conic))) {
118     Handle(Geom2d_Curve) tcurve = new Geom2d_TrimmedCurve(C2D,First,Last); //protection agains parabols ets
119     Geom2dConvert_ApproxCurve approx (tcurve, Tol2d, Continuity, MaxSegments, MaxDegree);
120     if ( approx.HasResult() )
121       aBSpline2d = approx.Curve();
122     else 
123       aBSpline2d = Geom2dConvert::CurveToBSplineCurve(tcurve,Convert_QuasiAngular);
124   } 
125   else if(!C2D->IsKind(STANDARD_TYPE(Geom2d_BSplineCurve))) {
126     aBSpline2d = Geom2dConvert::CurveToBSplineCurve(C2D,Convert_QuasiAngular);
127   }
128   else
129     aBSpline2d = Handle(Geom2d_BSplineCurve)::DownCast(C2D);
130   
131   return aBSpline2d;
132 }
133
134 //=======================================================================
135 //function : ConvertSurfaceToBSpline
136 //purpose  : 
137 //=======================================================================
138
139 // Note: this method has the same purpose as GeomConvert::SurfaceToBSplineSurface(),
140 // but treats more correctly offset surfaces and takes parameters such as UV limits 
141 // and degree as arguments instead of deducing them from the surface.
142 // Eventually it may be merged back to GeomConvert.
143
144 Handle(Geom_BSplineSurface) ShapeConstruct::ConvertSurfaceToBSpline(const Handle(Geom_Surface)& surf,
145                                                                     const Standard_Real UF,
146                                                                     const Standard_Real UL,
147                                                                     const Standard_Real VF,
148                                                                     const Standard_Real VL,
149                                                                     const Standard_Real Tol3d,
150                                                                     const GeomAbs_Shape Continuity,
151                                                                     const Standard_Integer MaxSegments,
152                                                                     const Standard_Integer MaxDegree)
153 {
154   Handle(Geom_BSplineSurface) res;
155   
156   Handle(Geom_Surface) S = surf;
157   if(surf->IsKind(STANDARD_TYPE(Geom_RectangularTrimmedSurface))) {
158     Handle(Geom_RectangularTrimmedSurface) RTS = 
159       Handle(Geom_RectangularTrimmedSurface)::DownCast(surf);
160     S = RTS->BasisSurface();
161   }
162   
163   // use GeomConvert for direct conversion of analytic surfaces
164   if (S->IsKind(STANDARD_TYPE(Geom_ElementarySurface))) 
165   {
166     Handle(Geom_RectangularTrimmedSurface) aRTS = 
167       new Geom_RectangularTrimmedSurface(S,UF,UL,VF,VL);
168     return GeomConvert::SurfaceToBSplineSurface(aRTS);
169   }
170
171   if(S->IsKind(STANDARD_TYPE(Geom_SurfaceOfLinearExtrusion))) {
172     Handle(Geom_SurfaceOfLinearExtrusion) extr = Handle(Geom_SurfaceOfLinearExtrusion)::DownCast(S);
173     Handle(Geom_Curve) basis = extr->BasisCurve();
174     //gp_Dir direction = extr->Direction(); // direction not used (skl)
175     
176     GeomAbs_Shape cnt = (Continuity > GeomAbs_C2 ? GeomAbs_C2: Continuity);
177     Handle(Geom_BSplineCurve) bspl = ConvertCurveToBSpline(basis, UF, UL, Tol3d, cnt, MaxSegments, MaxDegree);
178     
179     gp_Trsf shiftF,shiftL;
180     shiftF.SetTranslation(extr->Value(UF,0),extr->Value(UF,VF));
181     shiftL.SetTranslation(extr->Value(UF,0),extr->Value(UF,VL));
182         
183     Standard_Integer nbPoles = bspl->NbPoles();
184     TColgp_Array1OfPnt poles(1,nbPoles);
185     TColStd_Array1OfReal weights(1,nbPoles);
186     Standard_Integer nbKnots = bspl->NbKnots();
187     TColStd_Array1OfReal knots(1,nbKnots);
188     TColStd_Array1OfInteger mults(1,nbKnots);
189     
190     bspl->Poles(poles);
191     bspl->Knots(knots);
192     bspl->Multiplicities(mults);
193     bspl->Weights(weights);
194     
195     TColgp_Array2OfPnt resPoles(1,nbPoles,1,2);
196     TColStd_Array2OfReal resWeigth(1,nbPoles,1,2);
197     for(Standard_Integer j = 1; j <= nbPoles; j++) {
198       resPoles(j,1) = poles(j).Transformed(shiftF);
199       resPoles(j,2) = poles(j).Transformed(shiftL);
200       resWeigth(j,1)= weights(j);
201       resWeigth(j,2)= weights(j);
202     }
203    
204     TColStd_Array1OfReal vknots(1,2);
205     TColStd_Array1OfInteger vmults(1,2);
206     vknots(1) = VF;
207     vknots(2) = VL;
208     vmults(1) = vmults(2) = 2;
209     
210     Handle(Geom_BSplineSurface) bspline = new Geom_BSplineSurface(resPoles, resWeigth, knots, vknots, mults, vmults,
211                                                                   bspl->Degree(),1,bspl->IsPeriodic(),Standard_False);
212     return bspline;
213   }
214   
215   if(S->IsKind(STANDARD_TYPE(Geom_SurfaceOfRevolution))) {
216     Handle(Geom_SurfaceOfRevolution) revol = Handle(Geom_SurfaceOfRevolution)::DownCast(S);
217     Handle(Geom_Curve) basis = revol->BasisCurve();
218     if(basis->IsKind(STANDARD_TYPE(Geom_OffsetCurve))) {
219       GeomAbs_Shape cnt = basis->Continuity();
220       cnt = (cnt > GeomAbs_C2 ? GeomAbs_C2: cnt);
221       Handle(Geom_BSplineCurve) bspl = ConvertCurveToBSpline(basis, VF, VL, Tol3d, cnt, MaxSegments, MaxDegree);
222       gp_Ax1 axis = revol->Axis();
223       Handle(Geom_SurfaceOfRevolution) newRevol = new Geom_SurfaceOfRevolution(bspl,axis);
224 #ifdef OCCT_DEBUG
225       cout <<" Revolution on offset converted" << endl;
226 #endif
227       S = newRevol;
228     }
229   }
230     
231   Handle(Geom_Surface) aSurface = new Geom_RectangularTrimmedSurface(S,UF,UL,VF,VL);
232   Handle(Geom_BSplineSurface) errSpl;
233   for(Standard_Integer cnt = (Continuity > GeomAbs_C3 ? GeomAbs_C3: Continuity); cnt >= 0 ; ) {
234     try {
235       OCC_CATCH_SIGNALS
236       GeomAbs_Shape aCont = (GeomAbs_Shape) cnt;
237       GeomConvert_ApproxSurface anApprox(aSurface,Tol3d/2,aCont,aCont,MaxDegree,MaxDegree,MaxSegments,0);
238       Standard_Boolean Done = anApprox.IsDone();
239       if (anApprox.MaxError() <= Tol3d && Done) {
240         
241 #ifdef OCCT_DEBUG
242         Standard_Integer nbOfSpan = (anApprox.Surface()->NbUKnots()-1)*(anApprox.Surface()->NbVKnots()-1);
243         cout << "\terror = " << anApprox.MaxError() << "\tspans = " << nbOfSpan << endl;
244         cout << " Surface is aproximated with continuity " << (GeomAbs_Shape)cnt <<endl;
245 #endif
246         S = anApprox.Surface();
247         Handle(Geom_BSplineSurface) Bsc = Handle(Geom_BSplineSurface)::DownCast(S);
248         return Bsc;
249       }
250       else {
251         if(anApprox.HasResult()) 
252           errSpl = anApprox.Surface();
253 #ifdef OCCT_DEBUG
254         cout << "\terror = " << anApprox.MaxError() <<endl;
255 #endif
256         break;
257       }
258     }
259         
260     catch (Standard_Failure const& anException) {
261 #ifdef OCCT_DEBUG
262       cout << "Warning: GeomConvert_ApproxSurface Exception: try to decrease continuity ";
263       anException.Print(cout); cout << endl;
264 #endif
265       (void)anException;
266       if(cnt > 0) cnt--;
267       continue;
268     }
269   }
270   
271   return errSpl;
272 }
273 //=======================================================================
274 //function : JoinPCurves
275 //purpose  : 
276 //=======================================================================
277
278 Standard_Boolean ShapeConstruct::JoinPCurves(const Handle(TopTools_HSequenceOfShape)& edges,
279                                              const TopoDS_Face& theFace,
280                                              TopoDS_Edge& theEdge)
281 {
282   ShapeAnalysis_Edge sae;
283   BRep_Builder B;
284   
285   try {
286     OCC_CATCH_SIGNALS
287     // check if current face is plane.
288     Handle(Geom_Surface) aGeomSurf = BRep_Tool::Surface(theFace);
289     while (aGeomSurf->IsKind(STANDARD_TYPE(Geom_RectangularTrimmedSurface)))
290     {
291       
292       aGeomSurf = Handle(Geom_RectangularTrimmedSurface)::DownCast(aGeomSurf)->BasisSurface();
293     }
294     if (aGeomSurf->IsKind(STANDARD_TYPE(Geom_Plane)))
295       return Standard_True;
296     
297     
298     Standard_Boolean IsEdgeSeam = Standard_False;
299     Handle(Geom2d_Curve) aCrvRes1, aCrvRes2;
300     TopAbs_Orientation resOrient;
301     Standard_Real newf = 0.,newl = 0.;
302     // iterates on edges
303     Standard_Integer i = 1;
304     for(; i <= edges->Length(); i++) {
305       TopoDS_Edge Edge = TopoDS::Edge(edges->Value(i));
306       if (i == 1)
307         IsEdgeSeam = sae.IsSeam(Edge,theFace);
308       else if (IsEdgeSeam && (!sae.IsSeam(Edge,theFace)))
309         break; // different cases
310       else if (!IsEdgeSeam && (sae.IsSeam(Edge,theFace)))
311         break; // different cases
312       
313       resOrient = TopAbs_FORWARD;
314       Handle(Geom2d_Curve) c2d,c2d2;
315       Standard_Real first, last,first2, last2;
316       if(!sae.PCurve ( Edge, theFace, c2d, first, last, Standard_False ))
317         break;
318       
319       if(IsEdgeSeam) {
320         TopoDS_Edge tmpE1 =TopoDS::Edge(Edge.Reversed());
321         sae.PCurve ( tmpE1, theFace, c2d2, first2, last2, Standard_False );
322       }
323       
324       if( i == 1) {
325         aCrvRes1 = c2d;
326         if(IsEdgeSeam) {
327           aCrvRes2 = c2d2;
328         }
329         newf = first;
330         newl = last;
331         resOrient = Edge.Orientation();
332       }
333       else {
334         Handle(Geom2d_Curve) newCrv;
335         Standard_Boolean isRev1,isRev2;
336         if(!JoinCurves(aCrvRes1,c2d,resOrient,Edge.Orientation(),newf,newl,first, last,newCrv,isRev1,isRev2)) 
337           break;
338         
339         if(IsEdgeSeam) {
340           Handle(Geom2d_Curve) newCrv2;
341           Standard_Real newf2 = newf,newl2 = newl;
342           
343           if(!JoinCurves(aCrvRes2,c2d2,resOrient,Edge.Orientation(),newf2,newl2,first2, last2,newCrv2,isRev1,isRev2)) 
344           break;
345           aCrvRes2 = newCrv2;
346         }
347         aCrvRes1 = newCrv;
348         Standard_Real fp2d = newCrv->FirstParameter();
349         Standard_Real lp2d = newCrv->LastParameter();
350         newl += (last - first);
351         if(fp2d > newf) newf = fp2d;
352         if(lp2d < newl) newl = lp2d;
353         
354       }
355     }
356     if (IsEdgeSeam)
357       B.UpdateEdge(theEdge,aCrvRes1,aCrvRes2,theFace,0);
358     else
359       B.UpdateEdge(theEdge,aCrvRes1,theFace,0);
360      B.Range(theEdge,theFace,newf,newl);
361     B.SameRange(theEdge,Standard_False);
362     B.SameParameter(theEdge,Standard_False);
363     return (i <= edges->Length());
364   }
365   catch ( Standard_Failure const& anException) {
366 #ifdef OCCT_DEBUG
367     cout<<"Error: ShapeConstruct::JoinPCurves Exception in GeomConvert_CompCurveToBSplineCurve: ";
368     anException.Print(cout); cout<<endl;
369 #endif
370     (void)anException;
371   }
372   return Standard_False;
373 }
374
375 //=======================================================================
376 //function : JoinCurves
377 //purpose  : 
378 //=======================================================================
379
380 template<class HCurve> 
381 static inline HCurve GetCurveCopy(const HCurve& curve, 
382                                   Standard_Real& first, Standard_Real& last, 
383                                   const TopAbs_Orientation &orient)
384 {
385   if ( orient == TopAbs_REVERSED ) {
386     Standard_Real cf = first;
387     first = curve->ReversedParameter ( last );
388     last = curve->ReversedParameter ( cf );
389     return curve->Reversed();
390   }
391   return HCurve::DownCast(curve->Copy());
392 }
393
394 template<class HCurve> 
395 static inline void SegmentCurve (HCurve& curve,
396                                  const Standard_Real first,
397                                  const Standard_Real last)
398 {
399   if(curve->FirstParameter() < first - Precision::PConfusion() || 
400      curve->LastParameter() > last + Precision::PConfusion()) {
401     if(curve->IsPeriodic())
402       curve->Segment(first,last);
403     else curve->Segment(Max(curve->FirstParameter(),first),
404                         Min(curve->LastParameter(),last));
405   } 
406 }
407
408 template<class HPoint> 
409 static inline void GetReversedParameters(const HPoint& p11, 
410                                   const HPoint& p12,
411                                   const HPoint& p21,
412                                   const HPoint& p22,
413                                   Standard_Boolean& isRev1, 
414                                   Standard_Boolean& isRev2)
415 {
416   isRev1 = Standard_False;
417   isRev2 = Standard_False;
418    //gka protection against crossing seem on second face 
419   
420   Standard_Real d11 = p11.Distance(p21);
421   Standard_Real d21 =p12.Distance(p21);
422   
423   Standard_Real d12 = p11.Distance(p22);
424   Standard_Real d22 = p22.Distance(p12);
425   Standard_Real Dmin1 = Min(d11,d21);
426   Standard_Real Dmin2 = Min(d12,d22);
427   if(fabs(Dmin1 - Dmin2) <= Precision::Confusion() || Dmin2 > Dmin1) {
428     isRev1 = (d11 < d21 ? Standard_True : Standard_False);
429   }
430   else if(Dmin2 < Dmin1) {
431     isRev1 = (d12 < d22 ? Standard_True  : Standard_False);
432     isRev2 = Standard_True;
433   }
434  
435   
436 }
437 //=======================================================================
438 //function : JoinCurves
439 //purpose  : 
440 //=======================================================================
441
442 Standard_Boolean ShapeConstruct::JoinCurves(const Handle(Geom_Curve)& ac3d1,
443                                             const Handle(Geom_Curve)& ac3d2,
444                                             const TopAbs_Orientation Orient1,
445                                             const TopAbs_Orientation Orient2,
446                                             Standard_Real& first1,
447                                             Standard_Real& last1,
448                                             Standard_Real& first2,
449                                             Standard_Real& last2,
450                                             Handle(Geom_Curve)& c3dOut,
451                                             Standard_Boolean& isRev1,
452                                             Standard_Boolean& isRev2)
453                                             
454 {
455   Handle(Geom_Curve) c3d1,c3d2;
456  
457   c3d1 = GetCurveCopy ( ac3d1, first1, last1, Orient1 );
458   c3d2 = GetCurveCopy ( ac3d2, first2, last2, Orient2 );
459   ShapeConstruct_Curve scc;
460   Standard_Boolean After =  Standard_True;
461   Handle(Geom_BSplineCurve) bsplc1 = scc.ConvertToBSpline(c3d1,first1, last1,Precision::Confusion());
462   Handle(Geom_BSplineCurve) bsplc2 = scc.ConvertToBSpline(c3d2,first2, last2,Precision::Confusion());
463 //  newf = first1;
464 //  newl = last1 + last2 - first2;
465   
466   if(bsplc1.IsNull() || bsplc2.IsNull()) return Standard_False;
467   
468   SegmentCurve(bsplc1,first1, last1);
469   SegmentCurve(bsplc2,first2, last2);
470   
471   //regression on file 866026_M-f276-f311.brep bug OCC482
472   gp_Pnt pp11 =  bsplc1->Pole(1);
473   gp_Pnt pp12 =  bsplc1->Pole(bsplc1->NbPoles());
474   
475   gp_Pnt pp21 =  bsplc2->Pole(1);
476   gp_Pnt pp22 =  bsplc2->Pole(bsplc2->NbPoles());
477   
478   GetReversedParameters(pp11,pp12,pp21,pp22,isRev1,isRev2);
479   
480   if(isRev1) {
481     bsplc1->Reverse();
482   }
483   if(isRev2)
484     bsplc2->Reverse();
485   
486   gp_Pnt pmid = 0.5 * ( bsplc1->Pole(bsplc1->NbPoles()).XYZ() + bsplc2->Pole(1).XYZ() );
487   bsplc1->SetPole(bsplc1->NbPoles(), pmid);
488   bsplc2->SetPole(1, pmid);
489   GeomConvert_CompCurveToBSplineCurve connect3d(bsplc1);
490   if(!connect3d.Add(bsplc2,Precision::Confusion(), After, Standard_False)) return Standard_False;
491   c3dOut = connect3d.BSplineCurve();
492   return Standard_True;
493 }
494
495 //=======================================================================
496 //function : JoinCurves2d
497 //purpose  : 
498 //=======================================================================
499
500  Standard_Boolean ShapeConstruct::JoinCurves(const Handle(Geom2d_Curve)& aC2d1,
501                                    const Handle(Geom2d_Curve)& aC2d2,
502                                    const TopAbs_Orientation Orient1,
503                                    const TopAbs_Orientation Orient2,
504                                    Standard_Real& first1,
505                                    Standard_Real& last1,
506                                    Standard_Real& first2,
507                                    Standard_Real& last2,
508                                    Handle(Geom2d_Curve)& C2dOut,
509                                    Standard_Boolean& isRev1,
510                                    Standard_Boolean& isRev2,
511                                    const Standard_Boolean isError)
512 {
513    Handle(Geom2d_Curve) c2d1,c2d2;
514   c2d1 = GetCurveCopy ( aC2d1, first1, last1, Orient1 );
515   c2d2 = GetCurveCopy ( aC2d2, first2, last2, Orient2 );
516   ShapeConstruct_Curve scc;
517   Standard_Boolean After =  Standard_True;
518   
519   Handle(Geom2d_BSplineCurve) bsplc12d = scc.ConvertToBSpline(c2d1,first1,last1,Precision::Confusion());
520   Handle(Geom2d_BSplineCurve) bsplc22d = scc.ConvertToBSpline(c2d2,first2,last2,Precision::Confusion());
521   
522   if(bsplc12d.IsNull() || bsplc22d.IsNull()) return Standard_False;
523   
524   SegmentCurve(bsplc12d,first1,last1);
525   SegmentCurve(bsplc22d,first2,last2);
526   //gka protection against crossing seem on second face 
527   gp_Pnt2d pp112d =  bsplc12d->Pole(1).XY();
528   gp_Pnt2d pp122d =  bsplc12d->Pole(bsplc12d->NbPoles()).XY();
529   
530   gp_Pnt2d pp212d =  bsplc22d->Pole(1).XY();
531   gp_Pnt2d pp222d =  bsplc22d->Pole(bsplc22d->NbPoles()).XY();
532   
533   GetReversedParameters(pp112d,pp122d,pp212d,pp222d,isRev1,isRev2);
534   
535   //regression on file 866026_M-f276-f311.brep bug OCC482
536   //if(isRev1 || isRev2)
537   //  return newedge1;
538   if(isRev1) {
539     bsplc12d->Reverse();
540   }
541   if(isRev2)
542     bsplc22d->Reverse(); 
543   
544   
545   //---------------------------------------------------------
546   //protection against invalid topology Housing(sam1296.brep(face 707) - bugmergeedges4.brep)
547   if(isError) {
548     gp_Pnt2d pp1 = bsplc12d->Value(bsplc12d->FirstParameter());
549     gp_Pnt2d pp2 = bsplc12d->Value(bsplc12d->LastParameter());
550     gp_Pnt2d pp3 = bsplc12d->Value((bsplc12d->FirstParameter() + bsplc12d->LastParameter())*0.5);
551     
552     Standard_Real leng = pp1.Distance(pp2);
553     Standard_Boolean isCircle = (leng < pp1.Distance(pp3) + Precision::PConfusion());
554     if((pp1.Distance(bsplc22d->Pole(1)) < leng) && !isCircle) return Standard_False;
555   }
556   //-------------------------------------------------------
557   gp_Pnt2d pmid1 = 0.5 * ( bsplc12d->Pole(bsplc12d->NbPoles()).XY() + bsplc22d->Pole(1).XY() );
558       bsplc12d->SetPole(bsplc12d->NbPoles(), pmid1);
559   bsplc22d->SetPole(1, pmid1);
560   
561   // abv 01 Sep 99: Geom2dConvert ALWAYS performs reparametrisation of the
562   // second curve before merging; this is quite not suitable
563   // Use 3d tool instead
564 //      Geom2dConvert_CompCurveToBSplineCurve connect2d(bsplc12d);
565   gp_Pnt vPnt(0,0,0);
566   gp_Vec vDir(0,0,1);
567   gp_Pln vPln ( vPnt, vDir );
568   Handle(Geom_BSplineCurve) bspl1 = 
569     Handle(Geom_BSplineCurve)::DownCast ( GeomAPI::To3d ( bsplc12d, vPln ) );
570   Handle(Geom_BSplineCurve) bspl2 = 
571     Handle(Geom_BSplineCurve)::DownCast ( GeomAPI::To3d ( bsplc22d, vPln ) );
572   GeomConvert_CompCurveToBSplineCurve connect2d(bspl1);
573   if(!connect2d.Add(bspl2,Precision::PConfusion(), After, Standard_False)) return Standard_False;
574    C2dOut = GeomAPI::To2d ( connect2d.BSplineCurve(), vPln );
575   
576   return Standard_True;
577 }