0023948: Wrong intersection between a surface of revolution and a plane.
[occt.git] / src / ShapeFix / ShapeFix_EdgeProjAux.cxx
1 // Copyright (c) 1999-2014 OPEN CASCADE SAS
2 //
3 // This file is part of Open CASCADE Technology software library.
4 //
5 // This library is free software; you can redistribute it and/or modify it under
6 // the terms of the GNU Lesser General Public License version 2.1 as published
7 // by the Free Software Foundation, with special exception defined in the file
8 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
9 // distribution for complete text of the license and disclaimer of any warranty.
10 //
11 // Alternatively, this file may be used under the terms of Open CASCADE
12 // commercial license or contractual agreement.
13
14 //:r5 abv 06.04.99: ec_turbine-A.stp, #4313: protect against null curve
15 //    abv 09.04.99  S4136: add parameter preci (to eliminate BRepAPI::Precision)
16 #include <ShapeFix_EdgeProjAux.ixx>
17
18 #include <Standard_ErrorHandler.hxx>
19 #include <Standard_Failure.hxx>
20
21 #include <ElCLib.hxx>
22
23 #include <Adaptor3d_CurveOnSurface.hxx>
24 #include <Geom2dAdaptor_Curve.hxx>
25 #include <Geom2dAdaptor_HCurve.hxx>
26 #include <GeomAdaptor_Surface.hxx>
27 #include <GeomAdaptor_HSurface.hxx>
28
29 #include <Geom2d_Curve.hxx>
30 #include <Geom2d_BSplineCurve.hxx>
31 #include <Geom2d_Line.hxx>
32 #include <Geom_Curve.hxx>
33 #include <Geom_Surface.hxx> 
34 #include <Geom_SphericalSurface.hxx>
35
36 #include <BRep_Tool.hxx>
37 #include <Precision.hxx>
38 #include <TopoDS_Vertex.hxx>
39 #include <TopExp.hxx>
40
41 #include <ShapeAnalysis.hxx>
42 #include <ShapeAnalysis_Curve.hxx>
43 #include <ShapeAnalysis_Edge.hxx>
44 #include <ShapeAnalysis_Surface.hxx>
45
46 #include <Extrema_ExtPC.hxx>
47 #include <gp_Pnt.hxx>
48
49 //=======================================================================
50 //function : ShapeFix_EdgeProjAux
51 //purpose  : 
52 //=======================================================================
53
54 ShapeFix_EdgeProjAux::ShapeFix_EdgeProjAux ()
55 {
56   myFirstDone = myLastDone = Standard_False;
57 }
58
59 //=======================================================================
60 //function : ShapeFix_EdgeProjAux
61 //purpose  : 
62 //=======================================================================
63
64 ShapeFix_EdgeProjAux::ShapeFix_EdgeProjAux (const TopoDS_Face& F,
65                                             const TopoDS_Edge& E)
66 {
67   Init (F, E);
68 }
69
70 //=======================================================================
71 //function : Init
72 //purpose  : 
73 //=======================================================================
74
75 void ShapeFix_EdgeProjAux::Init (const TopoDS_Face& F,
76                                  const TopoDS_Edge& E)
77 {
78   myFace = F;
79   myEdge = E;
80   myFirstParam = myLastParam = 0.;
81   myFirstDone = myLastDone = Standard_False;
82 }
83
84 //=======================================================================
85 //function : Compute
86 //purpose  : 
87 //=======================================================================
88
89 void ShapeFix_EdgeProjAux::Compute (const Standard_Real preci) 
90 {
91   myFirstDone = myLastDone = Standard_False;
92     
93   // Project Point3d on Surface
94   // TEMPORARY Call ShapeFix_EdgeProjAux
95   myFirstParam = 0.;
96   myLastParam = 0.;
97   Init2d(preci);
98   if (IsFirstDone() && IsLastDone()) {
99     Standard_Real U1 = FirstParam();
100     Standard_Real U2 = LastParam();
101     if (U1>=U2) {
102 #ifdef DEBUG
103       cout << "Parametres inverses ... " << endl;
104 #endif
105       Standard_Real tmp = U1;
106       U1 = U2; U2 = tmp;
107     }
108     myFirstParam = U1;
109     myFirstDone  = Standard_True;
110     myLastParam  = U2;
111     myLastDone   = Standard_True;
112   }
113 }
114
115 //=======================================================================
116 //function : IsFirstDone
117 //purpose  : 
118 //=======================================================================
119
120 Standard_Boolean ShapeFix_EdgeProjAux::IsFirstDone() const
121 {
122   return myFirstDone;
123 }
124
125 //=======================================================================
126 //function : IsLastDone
127 //purpose  : 
128 //=======================================================================
129
130 Standard_Boolean ShapeFix_EdgeProjAux::IsLastDone() const
131 {
132   return myLastDone;
133 }
134
135 //=======================================================================
136 //function : FirstParam
137 //purpose  : 
138 //=======================================================================
139
140 Standard_Real ShapeFix_EdgeProjAux::FirstParam() const
141 {
142   return myFirstParam;
143 }
144
145 //=======================================================================
146 //function : LastParam
147 //purpose  : 
148 //=======================================================================
149
150 Standard_Real ShapeFix_EdgeProjAux::LastParam() const
151 {
152   return myLastParam;
153 }
154
155 //=======================================================================
156 //function : IsIso
157 //purpose  : 
158 //=======================================================================
159
160 Standard_Boolean ShapeFix_EdgeProjAux::IsIso (const Handle(Geom2d_Curve)& /*theCurve2d*/)
161 {
162   // Until an ISO is recognized by Adaptor3d_Curve
163 /*  
164   if (theCurve2d->IsKind(STANDARD_TYPE(Geom2d_Line))) {
165     Handle(Geom2d_Line) theLine2d = Handle(Geom2d_Line)::DownCast(theCurve2d);
166     gp_Dir2d theDir2d = theLine2d->Direction();
167     
168     gp_Dir2d dir1(0.,1.);
169     gp_Dir2d dir2(0.,-1.);
170     
171     return (theDir2d.IsEqual(dir1,Precision::Angular()) ||
172             theDir2d.IsEqual(dir2,Precision::Angular()) ||
173             theDir2d.IsNormal(dir1,Precision::Angular()) ||
174             theDir2d.IsNormal(dir2,Precision::Angular()) );
175   }
176 */
177   return Standard_False;
178 }
179
180 // ----------------------------------------------------------------------------
181 // static  : FindParameterWithExt
182 // Purpose : Computes the trimming parameter of Pt1 on COnS
183 // ----------------------------------------------------------------------------
184
185 static Standard_Boolean FindParameterWithExt (const gp_Pnt& Pt1, 
186                                               const Adaptor3d_CurveOnSurface& COnS,
187                                               const Standard_Real Uinf,
188                                               const Standard_Real Usup, 
189                                               const Standard_Real preci,
190                                               Standard_Real& w1)
191 {
192   try {  // et allez donc !
193     OCC_CATCH_SIGNALS
194     Extrema_ExtPC myExtPC (Pt1, COnS, Uinf, Usup, preci);
195
196     //ShapeFix_ExtPCOnS myExtPCOnS1 = 
197     //ShapeFix_ExtPCOnS(Pt1, COnS, Uinf, Usup, preci);
198   
199     if (myExtPC.IsDone()) {
200       Standard_Integer NbExt1 = myExtPC.NbExt();
201       for (Standard_Integer i=1; i<=NbExt1; i++) {
202         if (myExtPC.IsMin(i)) {
203           //Standard_Real dist = myExtPC.Value(i); //szv#4:S4163:12Mar99 debug mode only
204           w1   = myExtPC.Point(i).Parameter();
205         }
206       }
207       return Standard_True;
208     }
209     else return Standard_False;
210   }  // end try
211   catch(Standard_Failure) {
212 #ifdef DEB //:s5
213     cout << "Warning: ShapeFix_EdgeProjAux, FindParameterWithExt(): Exception: ";
214     Standard_Failure::Caught()->Print(cout); cout << endl;
215 #endif
216     return Standard_False;
217   }
218 }
219
220 //=======================================================================
221 //function : Init2d
222 //purpose  : 
223 //=======================================================================
224
225 void ShapeFix_EdgeProjAux::Init2d (const Standard_Real preci) 
226 {
227   Standard_Real cl = 0., cf = 0.;
228     // Extract Geometries
229   myFirstDone = myLastDone = Standard_False;
230   Handle(Geom_Surface) theSurface = BRep_Tool::Surface(myFace);
231   Handle(Geom2d_Curve) theCurve2d = BRep_Tool::CurveOnSurface(myEdge, myFace, cf, cl);
232   if ( theCurve2d.IsNull() ) return; //:r5 abv 6 Apr 99:  ec_turbine-A.stp, #4313
233   myFirstParam = 0.;
234   myLastParam  = 0.;
235   TopoDS_Vertex V1,V2;
236   TopExp::Vertices(myEdge, V1, V2);
237   gp_Pnt Pt1,Pt2;
238   // pdn 28.12.98: r_39-db.stp #605: use ends of 3d curve instead of vertices 
239   ShapeAnalysis_Edge sae;
240   Standard_Real a,b;
241   Handle(Geom_Curve) C3d;
242   if(sae.Curve3d(myEdge,C3d,a,b,Standard_False)) {
243     Pt1 = C3d->Value(a);
244     Pt2 = C3d->Value(b);
245   } 
246   else {
247     Pt1 = BRep_Tool::Pnt(V1);
248     Pt2 = BRep_Tool::Pnt(V2);
249   }
250   //:S4136  Standard_Real preci = BRepAPI::Precision();
251   //pdn to manage degenerated case
252   if (V1.IsSame(V2)) {
253     Handle(ShapeAnalysis_Surface) stsu = new ShapeAnalysis_Surface (theSurface);
254     gp_Pnt2d aPt1,aPt2;
255     Standard_Real firstpar,lastpar;
256     if (stsu->DegeneratedValues(Pt1,preci,aPt1,aPt2,firstpar,lastpar)){
257
258       if(theCurve2d->IsKind(STANDARD_TYPE(Geom2d_Line))) {
259         if (aPt1.IsEqual(theCurve2d->Value(firstpar),preci) && 
260           aPt2.IsEqual(theCurve2d->Value(lastpar),preci)){
261             myFirstParam = firstpar;
262             myLastParam  = lastpar;
263             myFirstDone = myLastDone = Standard_True;
264             return;
265         }
266       } 
267 #ifdef DEBUG
268       else cout <<"Other type of deg curve"<<endl;
269 #endif
270
271     }
272   }
273
274   Standard_Boolean parU = Standard_False, parV = Standard_False;
275   GeomAdaptor_Surface          SA     = GeomAdaptor_Surface(theSurface);
276   Handle(GeomAdaptor_HSurface) myHSur = new GeomAdaptor_HSurface(SA);
277
278   cf = theCurve2d->FirstParameter();
279   cl = theCurve2d->LastParameter();
280   //pdn cutting pcurve by suface bounds
281   if (Precision::IsInfinite(cf)||Precision::IsInfinite(cl)) {
282     if(theCurve2d->IsKind(STANDARD_TYPE(Geom2d_Line))) {
283       Standard_Real uf,ul,vf,vl;
284       theSurface->Bounds(uf,ul,vf,vl);
285       if(!Precision::IsInfinite(uf)&&!Precision::IsInfinite(ul)&&
286         !Precision::IsInfinite(vf)&&!Precision::IsInfinite(vl)) {
287           Standard_Real cfi,cli;
288           Handle(Geom2d_Line) lin = Handle(Geom2d_Line)::DownCast(theCurve2d);
289           gp_Pnt2d pnt = lin->Location();
290           gp_Dir2d dir = lin->Direction();
291           if (dir.Y()==0) {
292             parU = Standard_True;
293             cfi = (uf-pnt.X())/dir.X();
294             cli = (ul-pnt.X())/dir.X();
295           } 
296           else if (dir.X()==0) {
297             parV = Standard_True;
298             cfi = (vf-pnt.Y())/dir.Y();
299             cli = (vl-pnt.Y())/dir.Y();
300           } 
301           else {//common case
302             Standard_Real xfi, xli, yfi, yli;
303             xfi = (uf-pnt.X())/dir.X();
304             xli = (ul-pnt.X())/dir.X();
305             yfi = (vf-pnt.Y())/dir.Y();
306             yli = (vl-pnt.Y())/dir.Y();
307             if (dir.X()*dir.Y() > 0) {
308               cfi = (Abs(xli-xfi) < Abs(xli-yfi)? xfi : yfi);
309               cli = (Abs(xfi-xli) < Abs(xfi-yli)? xli : yli);
310             } else {
311               cfi = (Abs(xli-xfi) < Abs(xli-yli)? xfi : yli);
312               cli = (Abs(yli-xli) < Abs(yli-yfi)? xli : yfi);
313             }
314           }
315           if (cfi < cli) { cf = cfi; cl = cli; }
316           else { cf = cli; cl = cfi; }
317       } 
318       else if(!Precision::IsInfinite(uf)&&!Precision::IsInfinite(ul)){
319         Handle(Geom2d_Line) lin = Handle(Geom2d_Line)::DownCast(theCurve2d);
320         gp_Dir2d dir = lin->Direction();
321         if (dir.X()!=0) {
322           if (dir.Y()==0) parU = Standard_True;
323           gp_Pnt2d pnt = lin->Location(); //szv#4:S4163:12Mar99 moved
324           Standard_Real cfi = (uf-pnt.X())/dir.X();
325           Standard_Real cli = (ul-pnt.X())/dir.X();
326           if (cfi < cli) { cf = cfi; cl = cli; }
327           else { cf = cli; cl = cfi; }
328         }
329         else {
330           cf=-10000;
331           cl= 10000;
332         }
333       }
334       else {
335         cf=-10000;
336         cl= 10000;
337         //pdn not cutted by bounds
338 #ifdef DEBUG
339         cout<<"Infinite Surface"<<endl;
340 #endif  
341       }
342     }
343     else {
344       //pdn not linear case not managed
345       cf=-10000;
346       cl= 10000;
347 #ifdef DEBUG     
348       cout<<"Some infinite curve"<<endl;
349 #endif 
350     }
351   }
352
353   Geom2dAdaptor_Curve          CA     = Geom2dAdaptor_Curve(theCurve2d,cf,cl);
354   Handle(Geom2dAdaptor_HCurve) myHCur = new Geom2dAdaptor_HCurve(CA);
355
356   Adaptor3d_CurveOnSurface COnS = Adaptor3d_CurveOnSurface(myHCur, myHSur);
357
358   // ----------------------------------------------
359   // --- topological limit == geometric limit ? ---
360   // ----------------------------------------------
361   Standard_Real Uinf = COnS.FirstParameter();
362   Standard_Real Usup = COnS.LastParameter();
363  
364   Standard_Real w1 = 0., w2 = 0.;
365   ShapeAnalysis_Curve sac;
366   gp_Pnt pnt;
367   Standard_Real dist = sac.Project(COnS,Pt1,preci,pnt,w1,Standard_False);
368   //if distance is infinite then projection is not performed
369   if( Precision::IsInfinite(dist))
370     return;
371   
372   myFirstDone = Standard_True;
373   myFirstParam = w1;
374  
375   dist = sac.Project(COnS,Pt2,preci,pnt,w2,Standard_False);
376   
377   if( Precision::IsInfinite(dist))
378     return;
379   
380   myLastDone = Standard_True;
381   myLastParam  = w2;
382     
383   if(fabs(w1 - w2) < Precision::PConfusion())
384   {
385     if(!theSurface->IsUPeriodic() && !theSurface->IsVPeriodic())
386       return;
387   }
388     
389   if ( myFirstParam == Uinf && myLastParam == Usup ) return;
390   if ( myFirstParam == Usup && myLastParam == Uinf ) {
391     myFirstParam = theCurve2d->ReversedParameter(Usup);
392     myLastParam  = theCurve2d->ReversedParameter(Uinf);
393     theCurve2d->Reverse();
394 #ifdef DEB
395     cout << "Warning: ShapeFix_EdgeProjAux: pcurve reversed" << endl;
396 #endif
397     return;
398   }
399   //:abv 29.08.01: SAT: fix for closed case
400   if ( COnS.Value(Uinf).Distance ( COnS.Value(Usup) ) < Precision::Confusion() ) {
401     // 18.11.2002 SKL OCC630 compare values with tolerance Precision::PConfusion() instead of "=="
402     if ( Abs(myFirstParam-Uinf) < ::Precision::PConfusion() &&
403       Abs(myLastParam-Uinf) < ::Precision::PConfusion() )
404       myLastParam = w2 = Usup;
405     // 18.11.2002 SKL OCC630 compare values with tolerance Precision::PConfusion() instead of "=="
406     else if ( Abs(myFirstParam-Usup) < ::Precision::PConfusion() && 
407       Abs(myLastParam-Usup) < ::Precision::PConfusion() )
408       myFirstParam = w1 = Uinf;
409   }
410
411   //pdn adjust parameters in periodic case
412   if(parU || parV) {
413     Standard_Real uf,ul,vf,vl;
414     theSurface->Bounds(uf,ul,vf,vl);
415     Standard_Real period = (parU ? ul-uf : vl-vf);
416     w1+=ShapeAnalysis::AdjustToPeriod(w1,0,period);
417     myFirstParam = w1;
418     w2+=ShapeAnalysis::AdjustToPeriod(w2,0,period);
419     myLastParam = w2;
420     Handle(Geom_Curve) C3d1;
421     if(!sae.Curve3d (myEdge, C3d1, cf, cl, Standard_False )) {
422       UpdateParam2d(theCurve2d);
423       return;
424     }
425     gp_Pnt mid = C3d1->Value((cf+cl)/2);
426     Standard_Real wmid;
427     sac.Project(COnS,mid,preci,pnt,wmid,Standard_False);
428     wmid+=ShapeAnalysis::AdjustToPeriod(wmid,0,period);
429     if(w1>w2) {
430       if(w2 > wmid) myFirstParam -= period;
431       else if (w1 > wmid)
432         UpdateParam2d(theCurve2d);
433       else {
434         myLastParam+=period;
435 #ifdef DEBUG
436         cout <<" Added"<<endl;
437 #endif  
438       }
439     }
440     else {
441       if(w1 > wmid) {
442         myLastParam -=period;
443         UpdateParam2d(theCurve2d);
444 #ifdef DEBUG
445         cout <<" Added & Inverted"<<endl;
446 #endif  
447       } else if (w2 < wmid) {
448         myFirstParam += period;
449         UpdateParam2d(theCurve2d);
450       }
451     }
452   }
453   UpdateParam2d(theCurve2d);
454   return;
455 }
456
457 //=======================================================================
458 //function : Init3d
459 //purpose  : 
460 //=======================================================================
461
462 void ShapeFix_EdgeProjAux::Init3d (const Standard_Real preci) 
463 {
464   Standard_Real cl, cf;
465
466   // Extract Geometries
467   Handle(Geom_Surface) theSurface = BRep_Tool::Surface(myFace);
468   Handle(Geom2d_Curve) theCurve2d = BRep_Tool::CurveOnSurface(myEdge, myFace, cf, cl);
469   if ( theCurve2d.IsNull() ) return; //:r5 abv 6 Apr 99:  ec_turbine-A.stp, #4313
470   TopoDS_Vertex V1,V2;
471
472   V1 = TopExp::FirstVertex(myEdge);
473   V2 = TopExp::LastVertex(myEdge);
474   gp_Pnt Pt1 = BRep_Tool::Pnt(V1);
475   gp_Pnt Pt2 = BRep_Tool::Pnt(V2);
476
477
478   GeomAdaptor_Surface          SA     = GeomAdaptor_Surface(theSurface);  
479   Handle(GeomAdaptor_HSurface) myHSur = new GeomAdaptor_HSurface(SA);
480
481   Geom2dAdaptor_Curve          CA     = Geom2dAdaptor_Curve(theCurve2d);
482   Handle(Geom2dAdaptor_HCurve) myHCur = new Geom2dAdaptor_HCurve(CA);
483
484   Adaptor3d_CurveOnSurface COnS = Adaptor3d_CurveOnSurface(myHCur, myHSur);
485   
486 //:S4136  Standard_Real preci = BRepAPI::Precision();
487   Standard_Real Uinf = theCurve2d->FirstParameter();
488   Standard_Real Usup = theCurve2d->LastParameter();
489
490   // ----------------------------------------------
491   // --- topological limit == geometric limit ? ---
492   // ----------------------------------------------
493   
494   if (theCurve2d->IsKind(STANDARD_TYPE(Geom2d_BoundedCurve))) {
495     
496     gp_Pnt Pdeb = COnS.Value(Uinf);
497     gp_Pnt Pfin = COnS.Value(Usup);
498     
499     //szv#4:S4163:12Mar99 optimized
500     if ( Pdeb.IsEqual(Pt1, preci) && Pfin.IsEqual(Pt2, preci) ) {
501       myFirstParam = Uinf;
502       myLastParam  = Usup;
503       myFirstDone = myLastDone = Standard_True;
504       return;
505     }
506   }
507
508   // ------------------------------------------
509   // --- The CurveOnSurface is not infinite ---
510   // ---          Try with Extrema          ---
511   // ------------------------------------------
512
513   Standard_Real w1 = COnS.FirstParameter();
514   Standard_Real w2 = COnS.LastParameter();
515
516   if ((!Precision::IsInfinite(w1) &&
517        !Precision::IsInfinite(w2) &&
518        theCurve2d->Continuity() != GeomAbs_C0) ||
519       IsIso(theCurve2d))  {
520
521     //szv#4:S4163:12Mar99 optimized
522     if ( FindParameterWithExt(Pt1, COnS, Uinf, Usup, preci, w1) &&
523          FindParameterWithExt(Pt2, COnS, Uinf, Usup, preci, w2) ) {
524       myFirstParam = w1;
525       myLastParam  = w2;
526       UpdateParam2d(theCurve2d);
527       myFirstDone = myLastDone = Standard_True;
528       return;
529     }
530   }
531   myFirstDone = myLastDone = Standard_True;
532 }
533
534 //=======================================================================
535 //function : UpdateParam2d
536 //purpose  : 
537 //=======================================================================
538
539 void ShapeFix_EdgeProjAux::UpdateParam2d (const Handle(Geom2d_Curve)& theCurve2d)
540 {
541   if (myFirstParam < myLastParam)  return;
542
543   Standard_Real cf = theCurve2d->FirstParameter();
544   Standard_Real cl = theCurve2d->LastParameter();
545 //:S4136  Standard_Real preci = BRepAPI::Precision();
546   Standard_Real preci2d = Precision::PConfusion(); //:S4136: Parametric(preci, 0.01);
547
548   // 15.11.2002 PTV OCC966
549   if (ShapeAnalysis_Curve::IsPeriodic(theCurve2d)) {
550     ElCLib::AdjustPeriodic(cf,cl,preci2d,myFirstParam,myLastParam);
551   }
552   else if (theCurve2d->IsClosed()) {
553     //szv#4:S4163:12Mar99 optimized
554     if      ( Abs ( myFirstParam - cl ) <= preci2d ) myFirstParam = cf;
555     else if ( Abs ( myLastParam  - cf ) <= preci2d ) myLastParam  = cl;
556     else {
557 #ifdef DEBUG
558       cout << "Error : curve 2d range crossing non periodic curve origin";
559       cout <<  endl;
560 #endif
561       // add fail result;
562       return;
563     }
564   }
565   // the curve is closed within the 'file' 2D tolerance 
566   else if (theCurve2d->IsKind(STANDARD_TYPE(Geom2d_BSplineCurve))) {
567     Handle(Geom2d_BSplineCurve) aBSpline2d =
568       Handle(Geom2d_BSplineCurve)::DownCast(theCurve2d);
569     if (aBSpline2d->StartPoint().Distance(aBSpline2d->EndPoint()) <= preci2d) {
570       if      ( Abs ( myFirstParam - cl ) <= preci2d ) myFirstParam = cf;
571       else if ( Abs ( myLastParam  - cf ) <= preci2d ) myLastParam  = cl;
572     }
573   }
574   else {
575 #ifdef DEBUG
576     cout << "Warning : non increasing parameters for 2d curve." << endl;
577     cout << "          update parameter 2d uncertain." << endl;
578 #endif
579     Standard_Real tmp1 = myFirstParam, tmp2 = myLastParam;
580     myFirstParam = theCurve2d->ReversedParameter(tmp1);
581     myLastParam = theCurve2d->ReversedParameter(tmp2);
582     theCurve2d->Reverse();
583     //cout<<"Reversed case 2"<<endl;
584   }
585 }