0028838: Configuration - undefine macros coming from X11 headers in place of collision
[occt.git] / src / IntWalk / IntWalk_IWalking_5.gxx
1 // Copyright (c) 1995-1999 Matra Datavision
2 // Copyright (c) 1999-2014 OPEN CASCADE SAS
3 //
4 // This file is part of Open CASCADE Technology software library.
5 //
6 // This library is free software; you can redistribute it and/or modify it under
7 // the terms of the GNU Lesser General Public License version 2.1 as published
8 // by the Free Software Foundation, with special exception defined in the file
9 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
10 // distribution for complete text of the license and disclaimer of any warranty.
11 //
12 // Alternatively, this file may be used under the terms of Open CASCADE
13 // commercial license or contractual agreement.
14
15 namespace {
16   static const Standard_Real CosRef3D = 0.98;// rule by tests in U4 
17                                              // correspond to  11.478 d
18   static const Standard_Real CosRef2D = 0.88; // correspond to 25 d
19   static const Standard_Integer MaxDivision = 60;  // max number of step division 
20                                                    // because the angle is too great in 2d (U4)
21 }
22
23 IntWalk_StatusDeflection IntWalk_IWalking::TestDeflection
24   (TheIWFunction& sp,
25    const Standard_Boolean Finished,
26    const math_Vector& UV,
27    const IntWalk_StatusDeflection StatusPrecedent,
28    Standard_Integer& NbDivision,
29    Standard_Real& Step,
30    const Standard_Integer StepSign)
31 {
32   // Check the step of advancement, AND recalculate this step :
33   //
34   // 1) test point confused
35   //     if yes other tests are not done
36   // 2) test angle 3d too great
37   //     if yes divide the step and leave
38   //     angle3d = angle ((previous point, calculated point),
39   //                       previous tangent)
40   // 3) check step of advancement in 2d
41   // 4) test point confused
42   // 5) test angle 2d too great
43   // 6) test point of tangency 
44   //     if yes leave
45   // 7) calculate the tangent by u,v of the section 
46   // 8) test angle 3d too great  
47   //     angle3d = angle ((previous point, calculated point),  
48   //                       new tangent)
49   // 9) test angle 2d too great
50   //10) test change of side (pass the tangent point not knowing it)
51   //11) calculate the step of advancement depending on the vector
52   //12) adjust the step depending on the previous steps 
53   
54   IntWalk_StatusDeflection aStatus = IntWalk_OK;
55
56   //---------------------------------------------------------------------------------
57   //-- lbr le 4 Avril 95 : it is possible that the status returns points confused
58   //-- if epsilon is great enough (1e-11). In this case one loops 
59   //-- without ever changing the values sent to Rsnld. 
60   //---------------------------------------------------------------------------------
61   Standard_Real Paramu = 0.0, Paramv = 0.0;
62
63   if (!reversed) {
64     previousPoint.ParametersOnS2(Paramu, Paramv);
65   }
66   else
67   {
68     previousPoint.ParametersOnS1(Paramu, Paramv);
69   }
70
71   const Standard_Real Du = UV(1) - Paramu;
72   const Standard_Real Dv = UV(2) - Paramv;
73   const Standard_Real Duv = Du * Du + Dv * Dv;
74
75   gp_Vec Corde(previousPoint.Value(), sp.Point());
76
77   const Standard_Real Norme = Corde.SquareMagnitude(), 
78                       aTol = epsilon*Precision::PConfusion();
79
80   //if ((++NbPointsConfondusConsecutifs < 10) && (Norme <= epsilon)) { // the square is already taken in the constructor
81   if ((Norme <= epsilon) && ((Duv <= aTol) || (StatusPrecedent != IntWalk_OK)))
82   { // the square is already taken in the constructor
83     aStatus = IntWalk_PointConfondu;
84     if (StatusPrecedent == IntWalk_PasTropGrand) {
85       return IntWalk_ArretSurPointPrecedent;
86     }
87   }
88   else {
89     Standard_Real Cosi = Corde * previousd3d;
90     Standard_Real Cosi2 = 0.0;
91
92     if (Cosi*StepSign >= 0.) {// angle 3d <= pi/2 !!!!
93       const Standard_Real aDiv = previousd3d.SquareMagnitude()*Norme;
94       if(aDiv == 0)
95         return aStatus;
96       Cosi2 = Cosi * Cosi / aDiv;
97     }
98     if (Cosi2 < CosRef3D) { //angle 3d too great
99       Step = Step /2.0;
100       Standard_Real StepU = Abs(Step*previousd2d.X()),
101                     StepV = Abs(Step*previousd2d.Y());
102       if (StepU < tolerance(1) && StepV < tolerance(2)) 
103         aStatus = IntWalk_ArretSurPointPrecedent;
104       else 
105         aStatus = IntWalk_PasTropGrand;
106       return aStatus;
107     }
108   }
109
110   const Standard_Real aMinTolU = 0.1*Abs(Step*previousd2d.X()),
111                       aMinTolV = 0.1*Abs(Step*previousd2d.Y());
112   const Standard_Real aTolU = (aMinTolU > 0.0) ? Min(tolerance(1), aMinTolU) : tolerance(1),
113                       aTolV = (aMinTolV > 0.0) ? Min(tolerance(2), aMinTolV) : tolerance(2);
114
115   //If aMinTolU==0.0 then (Abs(Du) < aMinTolU) is equivalent of (Abs(Du) < 0.0).
116   //It is impossible. Therefore, this case should be processed separately.
117   //Analogicaly for aMinTolV.
118
119   if ((Abs(Du) < aTolU) && (Abs(Dv) < aTolV))
120   {
121     //Thin shapes (for which Ulast-Ufirst or/and Vlast-Vfirst is quite small)
122     //exists (see bug #25820). In this case, step is quite small too.
123     //Nevertheless, it not always means that we mark time. Therefore, Du and Dv
124     //must consider step (aMinTolU and aMinTolV parameters).
125
126     return IntWalk_ArretSurPointPrecedent; //confused point 2d
127   }
128
129   Standard_Real Cosi = StepSign * (Du * previousd2d.X() + Dv * previousd2d.Y());
130
131   if (Cosi < 0 && aStatus == IntWalk_PointConfondu)
132     return IntWalk_ArretSurPointPrecedent; // leave as step back  
133                                            // with confused point
134
135   if (sp.IsTangent()) 
136     return IntWalk_ArretSurPoint;       
137
138 //if during routing one has subdivided more than  MaxDivision for each
139 //previous step, bug on the square; do nothing (experience U4)
140
141   if ((NbDivision < MaxDivision) && (aStatus != IntWalk_PointConfondu) &&
142     (StatusPrecedent!= IntWalk_PointConfondu))
143   {
144     Standard_Real Cosi2 = Cosi * Cosi / Duv;
145     if (Cosi2 < CosRef2D || Cosi < 0  ) {
146       Step = Step / 2.0;
147       Standard_Real StepU = Abs(Step*previousd2d.X()),
148                     StepV = Abs(Step*previousd2d.Y());
149
150       if (StepU < tolerance(1) && StepV < tolerance(2))
151         aStatus = IntWalk_ArretSurPointPrecedent;
152       else 
153         aStatus = IntWalk_PasTropGrand;
154       NbDivision = NbDivision + 1;
155       return aStatus;
156     }
157
158     Cosi = Corde * sp.Direction3d(); 
159     Cosi2 = Cosi * Cosi / sp.Direction3d().SquareMagnitude() / Norme;
160     if (Cosi2 < CosRef3D ){ //angle 3d too great
161       Step = Step / 2.;
162       Standard_Real StepU = Abs(Step*previousd2d.X()),
163                     StepV = Abs(Step*previousd2d.Y());
164       if (StepU < tolerance(1) && StepV < tolerance(2))
165         aStatus = IntWalk_ArretSurPoint;
166       else 
167         aStatus = IntWalk_PasTropGrand;
168       return aStatus;
169     }
170     Cosi = Du * sp.Direction2d().X() + 
171       Dv * sp.Direction2d().Y();
172     Cosi2 = Cosi * Cosi / Duv;
173     if (Cosi2 < CosRef2D || 
174       sp.Direction2d() * previousd2d < 0) {
175         //angle 2d too great or change the side       
176         Step  = Step / 2.;
177         Standard_Real StepU = Abs(Step*previousd2d.X()),
178                       StepV = Abs(Step*previousd2d.Y());
179         if (StepU < tolerance(1) && StepV < tolerance(2))
180           aStatus = IntWalk_ArretSurPointPrecedent;
181         else 
182           aStatus = IntWalk_PasTropGrand;
183         return aStatus;
184     }
185   }
186
187   if (!Finished) {
188     if (aStatus == IntWalk_PointConfondu)
189     {
190       Standard_Real StepU = Min(Abs(1.5 * Du),pas*(UM-Um)),
191                     StepV = Min(Abs(1.5 * Dv),pas*(VM-Vm));
192
193       Standard_Real d2dx = Abs(previousd2d.X()); 
194       Standard_Real d2dy = Abs(previousd2d.Y()); 
195
196       if (d2dx < tolerance(1))
197       {
198         Step = StepV/d2dy;
199       }
200       else if (d2dy < tolerance(2))
201       {
202         Step = StepU/d2dx;
203       }
204       else
205       {
206         Step = Min(StepU/d2dx,StepV/d2dy);
207       }
208     }
209     else
210     {
211       //   estimate the current vector.
212       //   if vector/2<=current vector<= vector it is considered that the criterion
213       //   is observed.
214       //   otherwise adjust the step depending on the previous step 
215
216       /*
217         Standard_Real Dist = Sqrt(Norme)/3.;
218         TColgp_Array1OfPnt Poles(1,4);
219         gp_Pnt POnCurv,Milieu;
220         Poles(1) = previousPoint.Value();
221         Poles(4) = sp.Point();
222         Poles(2) = Poles(1).XYZ() + 
223       StepSign * Dist* previousd3d.Normalized().XYZ();
224         Poles(3) = Poles(4).XYZ() - 
225       StepSign * Dist*sp.Direction3d().Normalized().XYZ();
226         BzCLib::PntPole(0.5,Poles,POnCurv);
227         Milieu = (Poles(1).XYZ() + Poles(4).XYZ())*0.5;
228       //      FlecheCourante = Milieu.Distance(POnCurv);
229         Standard_Real FlecheCourante = Milieu.SquareDistance(POnCurv);
230       */
231
232         // Direct calculation : 
233         // POnCurv=(((p1+p2)/2.+(p2+p3)/2.)/2. + ((p2+p3)/2.+(p3+P4)/2.)/2.)/2.
234         // either POnCurv = p1/8. + 3.p2/8. + 3.p3/8. + p4/8.
235         // Or p2 = p1 + lambda*d1 et p3 = p4 - lambda*d4
236         // So POnCurv = (p1 + p4)/2. + 3.*(lambda d1 - lambda d4)/8.
237         // Calculate the deviation with (p1+p4)/2. . So it is just necessary to calculate
238         // the norm (square) of 3.*lambda (d1 - d4)/8.
239         // either the norm of :
240         //    3.*(Sqrt(Norme)/3.)*StepSign*(d1-d4)/8.
241         // which produces, takin the square :
242         //         Norme * (d1-d4).SquareMagnitude()/64.
243
244       Standard_Real FlecheCourante = 
245         (previousd3d.Normalized().XYZ()-sp.Direction3d().Normalized().XYZ()).SquareModulus()*Norme/64.;
246
247   
248 //      if (FlecheCourante <= 0.5*fleche) {
249       if (FlecheCourante <= 0.25*fleche*fleche)
250       {
251         Standard_Real d2dx = Abs(sp.Direction2d().X()); 
252         Standard_Real d2dy = Abs(sp.Direction2d().Y()); 
253         
254         Standard_Real StepU = Min(Abs(1.5*Du),pas*(UM-Um)),
255                       StepV = Min(Abs(1.5*Dv),pas*(VM-Vm));
256
257         if (d2dx < tolerance(1))
258         {
259           Step = StepV/d2dy;
260         }
261         else if (d2dy < tolerance(2))
262         {
263           Step = StepU/d2dx;
264         }
265         else
266         {
267           Step = Min(StepU/d2dx,StepV/d2dy);
268         }       
269       }
270       else
271       {
272         //if (FlecheCourante > fleche) {  // step too great
273         if (FlecheCourante > fleche*fleche)
274         {  // step too great
275           Step = Step /2.;
276           Standard_Real StepU = Abs(Step*previousd2d.X()),
277                         StepV = Abs(Step*previousd2d.Y());
278           
279           if (StepU < tolerance(1) && StepV < tolerance(2)) 
280             aStatus = IntWalk_ArretSurPointPrecedent;
281           else 
282             aStatus = IntWalk_PasTropGrand;
283         }
284         else
285         {
286           Standard_Real d2dx = Abs(sp.Direction2d().X()); 
287           Standard_Real d2dy = Abs(sp.Direction2d().Y()); 
288           
289           Standard_Real StepU = Min(Abs(1.5*Du),pas*(UM-Um)),
290                         StepV = Min(Abs(1.5*Dv),pas*(VM-Vm));
291
292           if (d2dx < tolerance(1))
293           {
294             Step = Min(Step,StepV/d2dy);
295           }
296           else if (d2dy < tolerance(2))
297           {
298             Step = Min(Step,StepU/d2dx);
299           }
300           else
301           {
302             Step = Min(Step,Min(StepU/d2dx,StepV/d2dy));
303           }
304         }
305       }
306     }
307   }
308   return aStatus;
309 }