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