0030940: BRepFilletAPI_MakeFillet algorithm fails on closed shell
[occt.git] / src / ChFi3d / ChFi3d.cxx
1 // Created on: 1993-12-21
2 // Created by: Isabelle GRIGNON
3 // Copyright (c) 1993-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_Tool.hxx>
19 #include <BRepAdaptor_Curve.hxx>
20 #include <BRepAdaptor_Curve2d.hxx>
21 #include <BRepAdaptor_Surface.hxx>
22 #include <ChFi3d.hxx>
23 #include <ChFi3d_Builder_0.hxx>
24 #include <gp_Pnt.hxx>
25 #include <gp_Pnt2d.hxx>
26 #include <gp_Vec.hxx>
27 #include <gp_Vec2d.hxx>
28 #include <Precision.hxx>
29 #include <TopExp_Explorer.hxx>
30 #include <TopoDS.hxx>
31 #include <TopoDS_Edge.hxx>
32 #include <BRepTools.hxx>
33 #include <IntTools_Tools.hxx>
34
35 static void Correct2dPoint(const TopoDS_Face& theF, gp_Pnt2d& theP2d);
36 //
37
38 //=======================================================================
39 //function : DefineConnectType
40 //purpose  : 
41 //=======================================================================
42 ChFiDS_TypeOfConcavity ChFi3d::DefineConnectType(const TopoDS_Edge&     E,
43                                                  const TopoDS_Face&     F1,
44                                                  const TopoDS_Face&     F2,
45                                                  const Standard_Real    SinTol,
46                                                  const Standard_Boolean CorrectPoint)
47 {
48   const Handle(Geom_Surface)& S1 = BRep_Tool::Surface(F1);
49   const Handle(Geom_Surface)& S2 = BRep_Tool::Surface(F2);
50   //
51   Standard_Real   f,l;
52   Handle (Geom2d_Curve) C1 = BRep_Tool::CurveOnSurface(E,F1,f,l);
53   //For the case of seam edge
54   TopoDS_Edge EE = E;
55   if (F1.IsSame(F2))
56     EE.Reverse();
57   Handle (Geom2d_Curve) C2 = BRep_Tool::CurveOnSurface(EE,F2,f,l);
58
59   BRepAdaptor_Curve C(E);
60   f = C.FirstParameter();
61   l = C.LastParameter();
62 //
63   Standard_Real ParOnC = 0.5*(f+l);
64   gp_Vec T1 = C.DN(ParOnC,1);
65   if (T1.SquareMagnitude() <= gp::Resolution())
66   {
67     ParOnC = IntTools_Tools::IntermediatePoint(f,l);
68     T1 = C.DN(ParOnC,1);
69   }
70   if (T1.SquareMagnitude() > gp::Resolution()) {
71     T1.Normalize();
72   }
73   
74   if (BRepTools::OriEdgeInFace(E,F1) == TopAbs_REVERSED) {
75     T1.Reverse();
76   }
77   if (F1.Orientation() == TopAbs_REVERSED) T1.Reverse();
78
79   gp_Pnt2d P  = C1->Value(ParOnC);
80   gp_Pnt   P3;
81   gp_Vec   D1U,D1V;
82   
83   if(CorrectPoint) 
84     Correct2dPoint(F1, P);
85   //
86   S1->D1(P.X(),P.Y(),P3,D1U,D1V);
87   gp_Vec DN1(D1U^D1V);
88   if (F1.Orientation() == TopAbs_REVERSED) DN1.Reverse();
89   
90   P = C2->Value(ParOnC);
91   if(CorrectPoint) 
92     Correct2dPoint(F2, P);
93   S2->D1(P.X(),P.Y(),P3,D1U,D1V);
94   gp_Vec DN2(D1U^D1V);
95   if (F2.Orientation() == TopAbs_REVERSED) DN2.Reverse();
96
97   DN1.Normalize();
98   DN2.Normalize();
99
100   gp_Vec        ProVec     = DN1^DN2;
101   Standard_Real NormProVec = ProVec.Magnitude(); 
102
103   if (NormProVec < SinTol) {
104     // plane
105     if (DN1.Dot(DN2) > 0) {   
106       //Tangent
107       return ChFiDS_Tangential;
108     }
109     else  {                   
110       //Mixed not finished!
111 #ifdef OCCT_DEBUG
112       std::cout <<" faces locally mixed"<<std::endl;
113 #endif
114       return ChFiDS_Convex;
115     }
116   }
117   else {  
118     if (NormProVec > gp::Resolution())
119       ProVec /= NormProVec;
120     Standard_Real Prod  = T1.Dot(ProVec);
121     if (Prod > 0.) {       
122       //
123       return ChFiDS_Convex;
124     }
125     else {                       
126       //reenters
127       return ChFiDS_Concave;
128     }
129   }
130 }
131
132 //=======================================================================
133 //function : ConcaveSide
134 //purpose  : calculate the concave face at the neighborhood of the border of
135 //           2 faces.
136 //=======================================================================
137 Standard_Integer ChFi3d::ConcaveSide(const BRepAdaptor_Surface& S1, 
138                                      const BRepAdaptor_Surface& S2, 
139                                      const TopoDS_Edge& E, 
140                                      TopAbs_Orientation& Or1, 
141                                      TopAbs_Orientation& Or2)
142
143 {
144   Standard_Integer ChoixConge;
145   Or1 = Or2 = TopAbs_FORWARD;
146   BRepAdaptor_Curve CE(E);
147   Standard_Real first = CE.FirstParameter();
148   Standard_Real last = CE.LastParameter();
149   Standard_Real par = 0.691254*first + 0.308746*last;
150
151   gp_Pnt pt, pt1, pt2; gp_Vec tgE, tgE1, tgE2, ns1, ns2, dint1, dint2;
152   TopoDS_Face F1 = S1.Face();
153   TopoDS_Face F2 = S2.Face();
154   //F1.Orientation(TopAbs_FORWARD);
155   //F2.Orientation(TopAbs_FORWARD);
156   
157   CE.D1(par,pt,tgE);
158   tgE.Normalize();
159   tgE2 = tgE1 = tgE;
160   if(E.Orientation() == TopAbs_REVERSED) tgE.Reverse();
161
162   TopoDS_Edge E1 = E, E2 = E;
163   E1.Orientation(TopAbs_FORWARD);
164   E2.Orientation(TopAbs_FORWARD);
165
166   if(F1.IsSame(F2) && BRep_Tool::IsClosed(E,F1)) {
167     E2.Orientation(TopAbs_REVERSED);
168     tgE2.Reverse();
169   }
170   else {
171     TopExp_Explorer Exp;
172     Standard_Boolean found = 0;
173     for (Exp.Init(F1,TopAbs_EDGE); 
174          Exp.More() && !found; 
175          Exp.Next()) {
176       if (E.IsSame(TopoDS::Edge(Exp.Current()))){
177         if(Exp.Current().Orientation() == TopAbs_REVERSED) tgE1.Reverse();
178         found = Standard_True;
179       }
180     }
181     if (!found) { return 0; }
182     found = 0;
183     for (Exp.Init(F2,TopAbs_EDGE); 
184          Exp.More() && !found; 
185          Exp.Next()) {
186       if (E.IsSame(TopoDS::Edge(Exp.Current()))){
187         if(Exp.Current().Orientation() == TopAbs_REVERSED) tgE2.Reverse();
188         found = Standard_True;
189       }
190     }
191     if (!found) { return 0; }
192   }
193   BRepAdaptor_Curve2d pc1(E1,F1);
194   BRepAdaptor_Curve2d pc2(E2,F2);
195   gp_Pnt2d p2d1,p2d2;
196   gp_Vec DU1,DV1,DU2,DV2;
197   p2d1 = pc1.Value(par);
198   p2d2 = pc2.Value(par);
199   S1.D1(p2d1.X(),p2d1.Y(),pt1,DU1,DV1);
200   ns1 = DU1.Crossed(DV1);
201   ns1.Normalize();
202   if (F1.Orientation() == TopAbs_REVERSED)
203     ns1.Reverse();
204   S2.D1(p2d2.X(),p2d2.Y(),pt2,DU2,DV2);
205   ns2 = DU2.Crossed(DV2);
206   ns2.Normalize();
207   if (F2.Orientation() == TopAbs_REVERSED)
208     ns2.Reverse();
209
210   dint1 = ns1.Crossed(tgE1);
211   dint2 = ns2.Crossed(tgE2);
212   Standard_Real ang = ns1.CrossMagnitude(ns2);
213   if(ang > 0.0001*M_PI){
214     Standard_Real scal = ns2.Dot(dint1);
215     if ( scal <= 0. ){
216       ns2.Reverse();
217       Or2 = TopAbs_REVERSED; 
218     }
219     scal = ns1.Dot(dint2);
220     if ( scal <= 0. ){
221       ns1.Reverse();
222       Or1 = TopAbs_REVERSED; 
223     }
224   }
225   else { 
226     //the faces are locally tangent - this is fake!
227     if(dint1.Dot(dint2) < 0.){
228       //This is a forgotten regularity
229       gp_Vec DDU, DDV, DDUV;
230       S1.D2(p2d1.X(),p2d1.Y(),pt1,DU1,DV1,DDU,DDV,DDUV);
231       DU1 += ( DU1 * dint1 < 0) ? -DDU : DDU;
232       DV1 += ( DV1 * dint1 < 0) ? -DDV : DDV;
233       ns1 = DU1.Crossed(DV1);
234       ns1.Normalize();
235       if (F1.Orientation() == TopAbs_REVERSED)
236         ns1.Reverse();
237       S2.D2(p2d2.X(),p2d2.Y(),pt2,DU2,DV2,DDU,DDV,DDUV);
238       DU2 += ( DU2 * dint2 < 0) ? -DDU : DDU;
239       DV2 += ( DV2 * dint2 < 0) ? -DDV : DDV;
240       ns2 = DU2.Crossed(DV2);
241       ns2.Normalize();
242       if (F2.Orientation() == TopAbs_REVERSED)
243         ns2.Reverse();
244       
245       dint1 = ns1.Crossed(tgE1);
246       dint2 = ns2.Crossed(tgE2);
247       ang = ns1.CrossMagnitude(ns2);
248       if(ang > 0.0001*M_PI){
249         Standard_Real scal = ns2.Dot(dint1);
250         if ( scal <= 0. ){
251           ns2.Reverse();
252           Or2 = TopAbs_REVERSED; 
253         }
254         scal = ns1.Dot(dint2);
255         if ( scal <= 0. ){
256           ns1.Reverse();
257           Or1 = TopAbs_REVERSED; 
258         }
259       }
260       else {
261 #ifdef OCCT_DEBUG
262         std::cout<<"ConcaveSide : no concave face"<<std::endl;
263 #endif
264         //This 10 shows that the face at end is in the extension of one of two base faces
265         return 10;
266       }
267     }
268     else {
269       //here it turns back, the points are taken in faces
270       //neither too close nor too far as much as possible.
271       Standard_Real u,v;
272 #ifdef OCCT_DEBUG
273 //      Standard_Real deport = 1000*BRep_Tool::Tolerance(E);
274 #endif
275       ChFi3d_Coefficient(dint1,DU1,DV1,u,v);
276       p2d1.SetX(p2d1.X() + u); p2d1.SetY(p2d1.Y() + v);
277       ChFi3d_Coefficient(dint1,DU2,DV2,u,v);
278       p2d2.SetX(p2d2.X() + u); p2d2.SetY(p2d2.Y() + v);
279       S1.D1(p2d1.X(),p2d1.Y(),pt1,DU1,DV1);
280       ns1 = DU1.Crossed(DV1);
281       if (F1.Orientation() == TopAbs_REVERSED)
282         ns1.Reverse();
283       S2.D1(p2d2.X(),p2d2.Y(),pt2,DU2,DV2);
284       ns2 = DU2.Crossed(DV2);
285       if (F2.Orientation() == TopAbs_REVERSED)
286         ns2.Reverse();
287       gp_Vec vref(pt1,pt2);
288       if(ns1.Dot(vref) < 0.){
289         Or1 = TopAbs_REVERSED;
290       }
291       if(ns2.Dot(vref) > 0.){
292         Or2 = TopAbs_REVERSED;
293       }
294     }
295   }
296
297
298   if (Or1 == TopAbs_FORWARD) {
299     if (Or2 == TopAbs_FORWARD) ChoixConge = 1;
300     else ChoixConge = 7;
301   }
302   else {
303     if (Or2 == TopAbs_FORWARD) ChoixConge = 3;
304     else ChoixConge = 5;
305   }
306   if ((ns1.Crossed(ns2)).Dot(tgE) >= 0.) ChoixConge++ ;
307   return ChoixConge;
308 }
309
310 //=======================================================================
311 //function : NextSide
312 //purpose  : 
313 //           
314 //=======================================================================
315
316 Standard_Integer  ChFi3d::NextSide(TopAbs_Orientation& Or1, 
317                                    TopAbs_Orientation& Or2,
318                                    const TopAbs_Orientation OrSave1, 
319                                    const TopAbs_Orientation OrSave2,
320                                    const Standard_Integer ChoixSave)
321 {
322   if (Or1 == TopAbs_FORWARD){Or1 = OrSave1;}
323   else {
324     Or1 = TopAbs::Reverse(OrSave1);
325   }
326   if (Or2 == TopAbs_FORWARD){Or2 = OrSave2;}
327   else {
328     Or2 = TopAbs::Reverse(OrSave2);
329   }
330
331   Standard_Integer ChoixConge;
332   if (Or1 == TopAbs_FORWARD) {
333     if (Or2 == TopAbs_FORWARD) ChoixConge = 1;
334     else {
335       if(ChoixSave < 0) ChoixConge = 3;
336       else ChoixConge = 7;
337     }
338   }
339   else {
340     if (Or2 == TopAbs_FORWARD) {
341       if(ChoixSave < 0) ChoixConge = 7;
342       else ChoixConge = 3;
343     }
344     else ChoixConge = 5;
345   }
346   if (Abs(ChoixSave)%2 == 0) ChoixConge++;
347   return ChoixConge;
348 }
349
350
351 //=======================================================================
352 //function : NextSide
353 //purpose  : 
354 //           
355 //=======================================================================
356
357 void ChFi3d::NextSide(TopAbs_Orientation& Or, 
358                      const TopAbs_Orientation OrSave, 
359                      const TopAbs_Orientation OrFace) 
360 {
361   if (Or == OrFace){Or = OrSave;}
362   else {
363     Or = TopAbs::Reverse(OrSave);
364   }
365 }
366
367
368
369 //=======================================================================
370 //function : SameSide
371 //purpose  : 
372 //           
373 //=======================================================================
374
375 Standard_Boolean  ChFi3d::SameSide(const TopAbs_Orientation Or, 
376                                    const TopAbs_Orientation OrSave1, 
377                                    const TopAbs_Orientation OrSave2,
378                                    const TopAbs_Orientation OrFace1, 
379                                    const TopAbs_Orientation OrFace2)
380 {
381   TopAbs_Orientation o1,o2;
382   if (Or == OrFace1){o1 = OrSave1;}
383   else {
384     o1 = TopAbs::Reverse(OrSave1);
385   }
386   if (Or == OrFace2){o2 = OrSave2;}
387   else {
388     o2 = TopAbs::Reverse(OrSave2);
389   }
390   return (o1 == o2);
391 }
392
393 //=======================================================================
394 //function : Correct2dPoint
395 //purpose  : 
396 //=======================================================================
397 void Correct2dPoint(const TopoDS_Face& theF, gp_Pnt2d& theP2d)
398 {
399   BRepAdaptor_Surface aBAS(theF, Standard_False);
400   if (aBAS.GetType() < GeomAbs_BezierSurface) {
401     return;
402   }
403   //
404   const Standard_Real coeff = 0.01;
405   Standard_Real eps;
406   Standard_Real u1, u2, v1, v2;
407   //
408   aBAS.Initialize(theF, Standard_True);
409   u1 = aBAS.FirstUParameter();
410   u2 = aBAS.LastUParameter();
411   v1 = aBAS.FirstVParameter();
412   v2 = aBAS.LastVParameter();
413   if (!(Precision::IsInfinite(u1) || Precision::IsInfinite(u2)))
414   {
415     eps = Max(coeff*(u2 - u1), Precision::PConfusion());
416     if (Abs(theP2d.X() - u1) < eps)
417     {
418       theP2d.SetX(u1 + eps);
419     }
420     if (Abs(theP2d.X() - u2) < eps)
421     {
422       theP2d.SetX(u2 - eps);
423     }
424   }
425   if (!(Precision::IsInfinite(v1) || Precision::IsInfinite(v2)))
426   {
427     eps = Max(coeff*(v2 - v1), Precision::PConfusion());
428     if (Abs(theP2d.Y() - v1) < eps)
429     {
430       theP2d.SetY(v1 + eps);
431     }
432     if (Abs(theP2d.Y() - v2) < eps)
433     {
434       theP2d.SetY(v2 - eps);
435     }
436   }
437 }