Integration of OCCT 6.5.0 from SVN
[occt.git] / src / TopTrans / TopTrans_SurfaceTransition.cxx
1 // File:        TopTrans_SurfaceTransition.cxx
2 // Created:     Tue Mar  4 16:44:54 1997
3 // Author:      Prestataire Xuan PHAM PHU
4 //              <xpu@poulopox.paris1.matra-dtv.fr>
5  
6 // Modified: eap Mar 25 2002 (occ102,occ227), touch case
7 #include <TopTrans_SurfaceTransition.ixx>
8
9 #include <gp_Dir.hxx>
10 #include <TopAbs.hxx>
11 #include <TopAbs_State.hxx>
12 #include <TopAbs_Orientation.hxx>
13 #include <Precision.hxx>
14
15 #define Msr Standard_Real
16 #define Msi Standard_Integer
17 #define Msb Standard_Boolean
18 #define Msf Standard_False
19 #define Mst Standard_True
20 #define MTAo TopAbs_Orientation
21 #define MTAs TopAbs_State
22
23 static Standard_Boolean STATIC_DEFINED = Standard_False;
24
25 //#include <TopOpeBRepTool_EXPORT.hxx>
26 static gp_Dir FUN_nCinsideS(const gp_Dir& tgC, const gp_Dir& ngS)
27 {
28   // Give us a curve C on suface S, <parOnC>, a parameter
29   // Purpose : compute normal vector to C, tangent to S at
30   //           given point , oriented INSIDE S  
31   // <tgC> : geometric tangent at point of <parOnC>
32   // <ngS> : geometric normal at point of <parOnC> 
33   gp_Dir XX(ngS^tgC);
34   return XX;  
35 }
36
37 #define M_REVERSED(st) (st == TopAbs_REVERSED)
38 #define M_INTERNAL(st) (st == TopAbs_INTERNAL)
39 #define M_UNKNOWN(st) (st == TopAbs_UNKNOWN)
40
41 static Standard_Integer FUN_OO(const Standard_Integer i)
42 {
43   if (i == 1) return 2;
44   if (i == 2) return 1;
45   return 0;
46 }
47
48 //static Standard_Real FUN_Ang(const gp_Dir& Normref,
49 static Standard_Real FUN_Ang(const gp_Dir& ,
50                              const gp_Dir& beafter,
51                              const gp_Dir& TgC,
52                              const gp_Dir& Norm,
53                              const TopAbs_Orientation O)
54 {
55   gp_Dir dironF = FUN_nCinsideS(TgC,Norm);
56   if (M_REVERSED(O)) dironF.Reverse();
57
58   Standard_Real ang = beafter.AngleWithRef(dironF,TgC);
59   return ang;
60 }
61
62 static void FUN_getSTA(const Standard_Real Ang, const Standard_Real tola,
63                        Standard_Integer& i, Standard_Integer& j)
64 {
65   Standard_Real cos = Cos(Ang);
66   Standard_Real sin = Sin(Ang);
67   Standard_Boolean nullcos = Abs(cos) < tola;
68   Standard_Boolean nullsin = Abs(sin) < tola;
69   if (nullcos) i = 0;
70   else i = (cos > 0.) ? 1 : 2;
71   if (nullsin) j = 0;
72   else j = (sin > 0.) ? 1 : 2;
73 }
74
75 /*static void FUN_getSTA(const Standard_Real Ang, const Standard_Real tola,
76                        const Standard_Real Curv, const Standard_Real CurvRef,
77                        Standard_Integer& i, Standard_Integer& j)
78 {
79   // Choosing UV referential (beafter,myNorm).
80   // purpose : computes position boundary face relative to the reference surface
81   //  notice : j==0 =>  j==1 : the boundary face is ABOVE the reference surface
82   //                    j==2 : the boundary face is UNDER the reference surface
83   //  - j==0 : the boundary and the reference objects are tangent-       
84
85   FUN_getSTA(Ang,tola,i,j);
86   if (j == 0) {
87       Standard_Real diff = Curv - CurvRef;
88       if (Abs(diff) < tola) {STATIC_DEFINED = Standard_False; return;} // nyi FUN_Raise      
89       j = (diff < 0.) ? 1 : 2; 
90   }
91 }*/
92 #ifndef DEB
93 #define M_Unknown   (-100)
94 #else
95 #define M_Unknown   (-100.)
96 #endif
97 #define M_noupdate  (0)
98 #define M_updateREF (1)
99 #define M_Ointernal (10)
100 static Standard_Integer FUN_refnearest(const Standard_Real Angref, const TopAbs_Orientation Oriref,
101                           const Standard_Real Ang, const TopAbs_Orientation Ori, const Standard_Real tola)
102 {
103   Standard_Boolean undef = (Angref == 100.);
104   if (undef) return M_updateREF;
105
106   Standard_Real cosref = Cos(Angref), cos = Cos(Ang);
107   Standard_Real dcos = Abs(cosref) - Abs(cos);
108   if (Abs(dcos) < tola) {
109     // Analysis for tangent cases : if two boundary faces are same sided
110     // and have tangent normals, if they have opposite orientations
111     // we choose INTERNAL as resulting complex transition (case EXTERNAL
112     // refering to no logical case)
113     if (TopAbs::Complement(Ori) == Oriref) return M_Ointernal;
114     else return (Standard_Integer ) M_Unknown; // nyi FUN_RAISE
115   }
116   Standard_Integer updateref = (dcos > 0.)? M_noupdate : M_updateREF;
117   return updateref;
118 }
119
120 //=======================================================================
121 //function : FUN_refnearest
122 //purpose  : 
123 //=======================================================================
124
125 static Standard_Integer FUN_refnearest(const Standard_Integer i,
126                                        const Standard_Integer j,
127                                        const Standard_Real CurvSref,
128                                        const Standard_Real Angref,
129                                        const TopAbs_Orientation Oriref,
130                                        const Standard_Real Curvref,
131                                        const Standard_Real Ang,
132                                        const TopAbs_Orientation Ori,
133                                        const Standard_Real Curv,
134                                        const Standard_Real tola,
135                                        Standard_Boolean &  TouchFlag) // eap Mar 25 2002 
136 {
137   Standard_Boolean iisj = (i == j);
138   Standard_Real abscos = Abs(Cos(Ang));
139   Standard_Boolean i0 = (Abs(1. - abscos) < tola);
140   Standard_Boolean j0 = (abscos < tola);  
141   Standard_Boolean nullcurv = (Curv == 0.);
142   Standard_Boolean curvpos  = (Curv > tola);
143   Standard_Boolean curvneg  = (Curv < -tola);
144   Standard_Boolean nullcsref = (CurvSref == 0.);
145
146   Standard_Boolean undef = (Angref == 100.);
147   if (undef) {
148     if (i0) {
149       if (iisj  && curvneg) return M_noupdate;
150       if (!iisj && curvpos) return M_noupdate;
151     } 
152     if (j0) {
153       if (!nullcsref && (j == 1) && iisj  && (curvpos || nullcurv)) return M_updateREF;
154       if (!nullcsref && (j == 1) && !iisj && (curvneg || nullcurv)) return M_updateREF;
155       
156       if (iisj  && curvpos) return M_noupdate;
157       if (!iisj && curvneg) return M_noupdate;
158     }
159     return M_updateREF;
160   } // undef
161   
162   Standard_Real cosref = Cos(Angref), cos = Cos(Ang);
163   Standard_Real dcos = Abs(cosref) - Abs(cos); Standard_Boolean samecos = Abs(dcos) < tola;
164   if (samecos) {
165     // Analysis for tangent cases : if two boundary faces are same sided
166     // and have sma dironF.
167     
168     if (Abs(Curvref - Curv) < 1.e-4) {
169       if (TopAbs::Complement(Ori) == Oriref) return M_Ointernal;
170       else return (Standard_Integer ) M_Unknown; // nyi FUN_RAISE
171     }
172
173     Standard_Boolean noupdate = Standard_False;
174     if (iisj  && (Curvref > Curv)) noupdate = Standard_True;
175     if (!iisj && (Curvref < Curv)) noupdate = Standard_True;
176     Standard_Integer updateref = noupdate ? M_noupdate : M_updateREF;
177     if (!j0) return updateref;
178     
179     if (!noupdate && !nullcsref) {
180       // check for (j==1) the face is ABOVE Sref
181       // check for (j==2) the face is BELOW Sref
182       if ((j == 2) && (Abs(Curv) < CurvSref)) updateref = M_noupdate;
183       if ((j == 1) && (Abs(Curv) > CurvSref)) updateref = M_noupdate;
184     }
185     return updateref;
186   } // samecos
187
188   Standard_Integer updateref = (dcos > 0.)? M_noupdate : M_updateREF;
189   if (Oriref != Ori) TouchFlag = Standard_True; // eap Mar 25 2002
190   
191   return updateref;
192 }
193
194 // ============================================================
195 //                       methods
196 // ============================================================
197
198 TopTrans_SurfaceTransition::TopTrans_SurfaceTransition()
199 : myAng(1,2,1,2),myCurv(1,2,1,2),myOri(1,2,1,2)
200 {
201   STATIC_DEFINED = Standard_False;
202 }
203
204 void TopTrans_SurfaceTransition::Reset(const gp_Dir& Tgt,
205                                        const gp_Dir& Norm,
206                                        const gp_Dir& MaxD,const gp_Dir& MinD,
207                                        const Standard_Real MaxCurv,const Standard_Real MinCurv)
208 {
209   STATIC_DEFINED = Standard_True;
210
211   Standard_Real tola = Precision::Angular();
212   Standard_Boolean curismax = (Abs(MaxD.Dot(myTgt)) < tola);
213   Standard_Boolean curismin = (Abs(MinD.Dot(myTgt)) < tola);
214
215   if ((Abs(MaxCurv) < tola) && (Abs(MinCurv) < tola)) {
216     Reset(Tgt,Norm);
217     return;
218   }
219
220   if (!curismax && !curismin) {
221     // In the plane normal to <myTgt>, we see the boundary face as
222     // a boundary curve.
223     // NYIxpu : compute the curvature of the curve if not MaxCurv
224     //          nor MinCurv.
225
226     STATIC_DEFINED = Standard_False;
227     return; 
228   }
229   
230   if (curismax) myCurvRef = Abs(MaxCurv); 
231   if (curismin) myCurvRef = Abs(MinCurv);
232   if (myCurvRef < tola) myCurvRef = 0.;
233
234   // ============================================================
235   // recall : <Norm> is oriented OUTSIDE the "geometric matter" described
236   //          by the surface  
237   //          -  if (myCurvRef != 0.) Sref is UNDER axis (sin = 0)
238   //             referential (beafter,myNorm,myTgt)  -
239   // ============================================================
240
241   // beafter oriented (before, after) the intersection on the reference surface.
242   myNorm = Norm; 
243   myTgt = Tgt;
244   beafter = Norm^Tgt; 
245   for (Standard_Integer i = 1; i <=2; i++)
246     for (Standard_Integer j = 1; j <=2; j++) 
247       myAng(i,j) = 100.;
248
249   myTouchFlag = Standard_False;  // eap Mar 25 2002 
250 }
251
252 void TopTrans_SurfaceTransition::Reset(const gp_Dir& Tgt,
253                                        const gp_Dir& Norm) 
254 {
255   STATIC_DEFINED = Standard_True;
256
257   // beafter oriented (before, after) the intersection on the reference surface.
258   myNorm = Norm; 
259   myTgt = Tgt;
260   beafter = Norm^Tgt; 
261   for (Standard_Integer i = 1; i <=2; i++)
262     for (Standard_Integer j = 1; j <=2; j++) 
263       myAng(i,j) = 100.;
264
265   myCurvRef = 0.;
266   myTouchFlag = Standard_False;  // eap Mar 25 2002 
267 }
268
269 void TopTrans_SurfaceTransition::Compare
270 //(const Standard_Real Tole,
271 (const Standard_Real ,
272  const gp_Dir& Norm,
273  const gp_Dir& MaxD,const gp_Dir& MinD,
274  const Standard_Real MaxCurv,const Standard_Real MinCurv,
275  const TopAbs_Orientation S,
276  const TopAbs_Orientation O) 
277 {
278   if (!STATIC_DEFINED) return;
279
280   Standard_Real Curv=0.; 
281   // ------
282   Standard_Real tola = Precision::Angular();
283   Standard_Boolean curismax = (Abs(MaxD.Dot(myTgt)) < tola);
284   Standard_Boolean curismin = (Abs(MinD.Dot(myTgt)) < tola);
285   if (!curismax && !curismin) {
286     // In the plane normal to <myTgt>, we see the boundary face as
287     // a boundary curve.
288     // NYIxpu : compute the curvature of the curve if not MaxCurv
289     //          nor MinCurv.
290
291     STATIC_DEFINED = Standard_False;
292     return; 
293   }  
294   if (curismax) Curv = Abs(MaxCurv); 
295   if (curismin) Curv = Abs(MinCurv);
296   if (myCurvRef < tola) Curv = 0.;
297   gp_Dir dironF = FUN_nCinsideS(myTgt,Norm);
298   Standard_Real prod = (dironF^Norm).Dot(myTgt);
299   if (prod < 0.) Curv = -Curv;
300
301   Standard_Real Ang;
302   // -----
303   Ang = ::FUN_Ang(myNorm,beafter,myTgt,Norm,O);
304
305   Standard_Integer i,j; 
306   // -----
307   // i = 0,1,2 : cos = 0,>0,<0
308   // j = 0,1,2 : sin = 0,>0,<0
309   ::FUN_getSTA(Ang,tola,i,j);
310
311   // update nearest :
312   // ---------------
313   Standard_Integer kmax = M_INTERNAL(O) ? 2 : 1;
314   for (Standard_Integer k=1; k <=kmax; k++) {
315     if (k == 2) {
316       // get the opposite Ang
317       i = ::FUN_OO(i);
318       j = ::FUN_OO(j);
319     }
320     Standard_Boolean i0 = (i == 0), j0 = (j == 0);
321     Standard_Integer nmax = (i0 || j0) ? 2 : 1;
322     for (Standard_Integer n=1; n<=nmax; n++) { 
323       if (i0) i = n;
324       if (j0) j = n;
325   
326       // if (curvref == 0.) :
327 //      Standard_Boolean iisj = (i == j);
328 //      Standard_Boolean Curvpos = (Curv > 0.);
329 //      if ((Curv != 0.) && i0)  {
330 //      if (iisj  && !Curvpos) continue;
331 //      if (!iisj &&  Curvpos) continue;
332 //      }
333 //      if ((Curv != 0.) && j0)  {
334 //      if (iisj  && Curvpos)  continue;
335 //      if (!iisj && !Curvpos) continue;
336 //      }
337
338       Standard_Integer refn = ::FUN_refnearest(i,j,myCurvRef,myAng(i,j),myOri(i,j),myCurv(i,j),
339                                   Ang,/*O*/S,Curv,tola,myTouchFlag); // eap Mar 25 2002 
340       if (refn == M_Unknown) {STATIC_DEFINED = Standard_False; return;}
341       if (refn > 0) {
342         myAng(i,j)  = Ang;
343         myOri(i,j)  = (refn == M_Ointernal) ? TopAbs_INTERNAL : S;      
344         myCurv(i,j) = Curv;
345       }
346     } // n=1..nmax
347   } // k=1..kmax
348
349 }
350
351 void TopTrans_SurfaceTransition::Compare
352 //(const Standard_Real Tole,
353 (const Standard_Real ,
354  const gp_Dir& Norm,
355  const TopAbs_Orientation S,
356  const TopAbs_Orientation O) 
357 {
358   if (!STATIC_DEFINED) return;
359
360   // oriented Ang(beafter,dironF), 
361   // dironF normal to the curve, oriented INSIDE F, the added oriented support
362   Standard_Real Ang = ::FUN_Ang(myNorm,beafter,myTgt,Norm,O);
363   Standard_Real tola = Precision::Angular(); // nyi in arg
364     
365   // i = 0,1,2 : cos = 0,>0,<0
366   // j = 0,1,2 : sin = 0,>0,<0
367   Standard_Integer i,j; ::FUN_getSTA(Ang,tola,i,j);
368
369   Standard_Integer kmax = M_INTERNAL(O) ? 2 : 1;
370   for (Standard_Integer k=1; k <=kmax; k++) {
371     if (k == 2) {
372       // get the opposite Ang
373       i = ::FUN_OO(i);
374       j = ::FUN_OO(j);
375     }
376
377     Standard_Boolean i0 = (i == 0), j0 = (j == 0);
378     Standard_Integer nmax = (i0 || j0) ? 2 : 1;
379     for (Standard_Integer n=1; n<=nmax; n++) { 
380       if (i0) i = n;
381       if (j0) j = n;
382       
383       Standard_Integer refn = ::FUN_refnearest(myAng(i,j),myOri(i,j),
384                                   Ang,/*O*/S,tola);   // eap
385       if (refn == M_Unknown) {STATIC_DEFINED = Standard_False; return;}
386    
387       if (refn > 0) {
388         myAng(i,j) = Ang;
389         myOri(i,j) = (refn == M_Ointernal) ? TopAbs_INTERNAL : S;       
390       }
391     } // n=1..nmax
392   } // k=1..kmax
393 }
394
395 #define BEFORE (2)
396 #define AFTER  (1)
397 static TopAbs_State FUN_getstate(const TColStd_Array2OfReal& Ang,
398                                  const TopTrans_Array2OfOrientation& Ori,
399                                  const Standard_Integer iSTA,
400                                  const Standard_Integer iINDEX)
401 {       
402   if (!STATIC_DEFINED) return TopAbs_UNKNOWN;
403  
404   Standard_Real a1 = Ang(iSTA,1), a2 = Ang(iSTA,2);
405   Standard_Boolean undef1 = (a1 == 100.), undef2 = (a2 == 100.);
406   Standard_Boolean undef = undef1 && undef2;
407   if (undef) return TopAbs_UNKNOWN;
408   
409   if (undef1 || undef2) {
410     Standard_Integer jok = undef1 ? 2 : 1;
411     TopAbs_Orientation o = Ori(iSTA,jok);
412     TopAbs_State st = (iINDEX == BEFORE) ? TopTrans_SurfaceTransition::GetBefore(o) :
413       TopTrans_SurfaceTransition::GetAfter(o);
414     return st;
415   }
416   
417   TopAbs_Orientation o1 = Ori(iSTA,1), o2 = Ori(iSTA,2);
418   TopAbs_State st1 = (iINDEX == BEFORE) ? TopTrans_SurfaceTransition::GetBefore(o1) : 
419     TopTrans_SurfaceTransition::GetAfter(o1);
420   TopAbs_State st2 = (iINDEX == BEFORE) ? TopTrans_SurfaceTransition::GetBefore(o2) : 
421     TopTrans_SurfaceTransition::GetAfter(o2);
422   if (st1 != st2) return TopAbs_UNKNOWN; // Incoherent data
423   return st1;
424 }
425
426
427 TopAbs_State TopTrans_SurfaceTransition::StateBefore() const
428 {
429   if (!STATIC_DEFINED) return TopAbs_UNKNOWN;
430
431   // we take the state before of before orientations
432   TopAbs_State before = ::FUN_getstate(myAng,myOri,BEFORE,BEFORE);
433   if (M_UNKNOWN(before)) {
434     // looking back in before for defined states
435     // we take the state before of after orientations
436     before = ::FUN_getstate(myAng,myOri,AFTER,BEFORE);
437     // eap Mar 25 2002 
438     if (myTouchFlag)
439       if (before == TopAbs_OUT) before = TopAbs_IN;
440       else if (before == TopAbs_IN) before = TopAbs_OUT;
441   }
442   return before;
443 }
444
445 TopAbs_State TopTrans_SurfaceTransition::StateAfter() const
446 {
447   if (!STATIC_DEFINED) return TopAbs_UNKNOWN;
448
449   TopAbs_State after = ::FUN_getstate(myAng,myOri,AFTER,AFTER);
450   if (M_UNKNOWN(after)) {
451     // looking back in before for defined states
452     after = ::FUN_getstate(myAng,myOri,BEFORE,AFTER);
453     // eap Mar 25 2002 
454     if (myTouchFlag)
455       if (after == TopAbs_OUT) after = TopAbs_IN;
456       else if (after == TopAbs_IN) after = TopAbs_OUT;
457   }
458   return after;
459 }
460
461 TopAbs_State TopTrans_SurfaceTransition::GetBefore
462 (const TopAbs_Orientation Tran)
463 {
464   if (!STATIC_DEFINED) return TopAbs_UNKNOWN;
465
466   switch (Tran)
467     {
468     case TopAbs_FORWARD  :
469     case TopAbs_EXTERNAL :
470       return TopAbs_OUT;
471     case TopAbs_REVERSED :
472     case TopAbs_INTERNAL :
473       return TopAbs_IN;
474     }
475   return TopAbs_OUT;
476 }
477
478 TopAbs_State TopTrans_SurfaceTransition::GetAfter
479 (const TopAbs_Orientation Tran)
480 {
481   if (!STATIC_DEFINED) return TopAbs_UNKNOWN;
482
483   switch (Tran)
484     {
485     case TopAbs_FORWARD  :
486     case TopAbs_INTERNAL :
487       return TopAbs_IN;
488     case TopAbs_REVERSED :
489     case TopAbs_EXTERNAL :
490       return TopAbs_OUT;
491     }
492   return TopAbs_OUT;
493 }