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