Block-Structured AMR Software Framework
AMReX_EB_triGeomOps_K.H
Go to the documentation of this file.
1 #ifndef AMREX_EB_TRIGEOMOPS_K_H_
2 #define AMREX_EB_TRIGEOMOPS_K_H_
3 #include <AMReX_Config.H>
4 #include <AMReX_Math.H>
5 #include <AMReX_REAL.H>
6 
8 {
9  //================================================================================
10  AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE Real Distance2(const Real P1[3],const Real P2[3])
11  {
12  return( (P1[0]-P2[0])*(P1[0]-P2[0]) +
13  (P1[1]-P2[1])*(P1[1]-P2[1]) +
14  (P1[2]-P2[2])*(P1[2]-P2[2]) );
15  }
16  //================================================================================
17  AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE Real DotProd(const Real v1[3],const Real v2[3])
18  {
19  return(v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2]);
20  }
21  //================================================================================
22  // If this is zero, the two lines either intersect or are parallel.
23  AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE Real side_op(const Real L1[6],const Real L2[6])
24  {
25  return( L1[0]*L2[4]
26  + L1[1]*L2[5]
27  + L1[2]*L2[3]
28  + L1[3]*L2[2]
29  + L1[4]*L2[0]
30  + L1[5]*L2[1] );
31  }
32  //================================================================================
33  AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void getvec(const Real P1[3],const Real P2[3],Real v[3])
34  {
35  v[0]=P2[0]-P1[0];
36  v[1]=P2[1]-P1[1];
37  v[2]=P2[2]-P1[2];
38  }
39  //================================================================================
40  AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void getunitvec(const Real v[3],Real vu[3])
41  {
42  Real vmag;
43  vmag=std::sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]);
44  vu[0]=v[0]/vmag;
45  vu[1]=v[1]/vmag;
46  vu[2]=v[2]/vmag;
47  }
48  //================================================================================
49  AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void CrossProd(const Real v1[3],const Real v2[3],Real v[3])
50  {
51  v[0]=v1[1]*v2[2]-v1[2]*v2[1];
52  v[1]=v1[2]*v2[0]-v1[0]*v2[2];
53  v[2]=v1[0]*v2[1]-v1[1]*v2[0];
54  }
55  //================================================================================
56  AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void get_plucker_coords(const Real v1[3],const Real v2[3],Real L[6])
57  {
58  L[0] = v1[0]*v2[1] - v1[1]*v2[0];
59  L[1] = v1[0]*v2[2] - v1[2]*v2[0];
60  L[2] = v1[0] - v2[0];
61  L[3] = v1[1]*v2[2] - v1[2]*v2[1];
62  L[4] = v1[2] - v2[2];
63  L[5] = v2[1] - v1[1];
64  }
65  //================================================================================
66  AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void side_op3(const Real v1[3], const Real v2[3],
67  const Real t1[3], const Real t2[3], const Real t3[3],
68  Real &S1, Real &S2, Real &S3)
69  {
70 
71  Real L[6],e1[6],e2[6],e3[6];
72 
73  get_plucker_coords(v1,v2,L);
74  get_plucker_coords(t1,t2,e1);
75  get_plucker_coords(t2,t3,e2);
76  get_plucker_coords(t3,t1,e3);
77 
78  S1=side_op(L,e1);
79  S2=side_op(L,e2);
80  S3=side_op(L,e3);
81  }
82  //================================================================================
83  //get normal of triangle pointing at a test-point
84  AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void tri_n(const Real P1[3], const Real P2[3], const Real P3[3],
85  const Real testp[3], Real n[3])
86  {
87  Real v1[3],v2[3],magn;
88  Real centr[3],c_tp_vec[3];
89 
90  getvec(P1,P2,v1);
91  getvec(P1,P3,v2);
92  CrossProd(v1,v2,n);
93 
94 
95  centr[0]=Real(1./3.)*(P1[0]+P2[0]+P3[0]);
96  centr[1]=Real(1./3.)*(P1[1]+P2[1]+P3[1]);
97  centr[2]=Real(1./3.)*(P1[2]+P2[2]+P3[2]);
98 
99  getvec(centr,testp,c_tp_vec);
100  magn=std::sqrt(n[0]*n[0]+n[1]*n[1]+n[2]*n[2]);
101 
102  if(DotProd(c_tp_vec,n) < Real(0.0))
103  {
104  magn=-magn;
105  }
106 
107  n[0]=n[0]/magn;
108  n[1]=n[1]/magn;
109  n[2]=n[2]/magn;
110  }
111  //================================================================================
112  AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE Real triangle_area(const Real P1[3], const Real P2[3], const Real P3[3])
113  {
114  Real v1[3],v2[3],area[3];
115 
116  getvec(P1,P2,v1);
117  getvec(P1,P3,v2);
118  CrossProd(v1,v2,area);
119  return(Real(0.5) * std::sqrt(DotProd(area,area)) );
120  }
121  //================================================================================
122  //this is only useful when v1-v2 segment intersects the triangle
123  AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE bool find_intersection_point(const Real v1[3],const Real v2[3],
124  const Real t1[3], const Real t2[3], const Real t3[3], Real ip[3],int bisect_iters=20,Real tol=1e-6)
125  {
126  Real plane_eq_mid,plane_eq1,plane_eq2;
127 
128  Real ab[3],ac[3],n[3],magn;
129  Real midp[3],p1[3],p2[3];
130 
131  getvec(t1,t2,ab);
132  getvec(t1,t3,ac);
133 
134  CrossProd(ab,ac,n);
135  magn=std::sqrt(n[0]*n[0]+n[1]*n[1]+n[2]*n[2]);
136 
137  n[0]=n[0]/magn;
138  n[1]=n[1]/magn;
139  n[2]=n[2]/magn;
140 
141  p1[0]=v1[0];
142  p1[1]=v1[1];
143  p1[2]=v1[2];
144 
145  p2[0]=v2[0];
146  p2[1]=v2[1];
147  p2[2]=v2[2];
148 
149 
150  bool all_ok=true;
151 
152  for(int i=0;i<bisect_iters;i++)
153  {
154  midp[0]=Real(0.5)*(p1[0]+p2[0]);
155  midp[1]=Real(0.5)*(p1[1]+p2[1]);
156  midp[2]=Real(0.5)*(p1[2]+p2[2]);
157 
158  plane_eq_mid= (midp[0]-t1[0])*n[0] + (midp[1]-t1[1])*n[1] + (midp[2]-t1[2])*n[2];
159  plane_eq1 = (p1[0] -t1[0])*n[0] + (p1[1] -t1[1])*n[1] + (p1[2] -t1[2])*n[2];
160  plane_eq2 = (p2[0] -t1[0])*n[0] + (p2[1] -t1[1])*n[1] + (p2[2] -t1[2])*n[2];
161 
162  //Print()<<"midp:"<<midp[0]<<"\t"<<midp[1]<<"\t"<<midp[2]<<"\t"<<plane_eq_mid<<"\n";
163 
164  if(std::abs(plane_eq_mid) < tol)
165  {
166  break;
167  }
168 
169  if(plane_eq_mid*plane_eq1 < Real(0.0))
170  {
171  p2[0]=midp[0];
172  p2[1]=midp[1];
173  p2[2]=midp[2];
174  }
175  else if(plane_eq_mid*plane_eq2 < Real(0.0))
176  {
177  p1[0]=midp[0];
178  p1[1]=midp[1];
179  p1[2]=midp[2];
180  }
181  else //plane_eq_mid is 0
182  //or error: p1,midp and p2 are on the same side
183  //which is not what this function is meant for
184  {
185  if(plane_eq_mid*plane_eq1 > Real(0.0) && plane_eq_mid*plane_eq2 > Real(0.0))
186  {
187  all_ok=false;
188  }
189  break;
190  }
191  }
192 
193  ip[0]=midp[0];
194  ip[1]=midp[1];
195  ip[2]=midp[2];
196 
197  return(all_ok);
198  }
199  //================================================================================
200  AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE int lineseg_tri_intersect(const Real v1[3], const Real v2[3],
201  const Real t1[3], const Real t2[3], const Real t3[3])
202  {
203  //see plucker coordinates based method
204  //https://members.loria.fr/SLazard/ARC-Visi3D/Pant-project/files/Line_Triangle.html
205 
206  Real S1,S2,S3;
207  Real tri_area,area1,area2;
208  Real L2[6],L3[6],L4[6],ls_s1,ls_s2;
209 
210  side_op3(v1,v2,t1,t2,t3,S1,S2,S3);
211 
212  //we are assuming there are no intersections initially
213  int no_intersections=1;
214 
215  Real eps = std::numeric_limits<Real>::epsilon();
216 
217  //coplanar (S1,S2,S3 = 0)
218  if(std::abs(S1) < eps && std::abs(S2) < eps && std::abs(S3) < eps)
219  {
220  //Print()<<"line segment and triangle are in the same plane\t"<<S1<<"\t"<<S2<<"\t"<<S3<<"\n";
221  tri_area=triangle_area(t1,t2,t3);
222 
223  /*if(tri_area == 0)
224  {
225  amrex::Abort("problem with triangle\n");
226  }*/
227  area1=(triangle_area(t1,t2,v1)+triangle_area(t2,t3,v1)+triangle_area(t3,t1,v1));
228  area2=(triangle_area(t1,t2,v2)+triangle_area(t2,t3,v2)+triangle_area(t3,t1,v2));
229 
230  if( std::abs(area1-tri_area)>eps || std::abs(area2-tri_area)>eps )
231  {
232  no_intersections = 0;
233  }
234  }
235  //proper and edge intersection
236  else if( (S1 < Real(0.0) && S2 < Real(0.0) && S3 < Real(0.0)) ||
237  (S1 > Real(0.0) && S2 > Real(0.0) && S3 > Real(0.0)) ||
238  (std::abs(S1) < eps && S2*S3 > Real(0.0)) || //S1=0
239  (std::abs(S2) < eps && S3*S1 > Real(0.0)) || //S2=0
240  (std::abs(S3) < eps && S1*S2 > Real(0.0)) ) //S3=0
241  {
242 
243  get_plucker_coords(v1,t1,L2);
244  get_plucker_coords(t1,v2,L3);
245  get_plucker_coords(t2,t3,L4);
246 
247  /*if(std::abs(S1*S2*S3) < eps)
248  {
249  Print()<<"edge intersection S1,S2,S3:"
250  <<S1<<"\t"<<S2<<"\t"<<S3<<"\n";
251  }*/
252 
253  ls_s1 = side_op(L4,L3);
254  ls_s2 = side_op(L4,L2);
255 
256  if(ls_s1*ls_s2 > Real(0.0))
257  {
258  no_intersections = 0;
259  }
260  }
261  //vertex intersection
262  else if( (std::abs(S1) < eps && std::abs(S2) < eps) || //S1,S2=0
263  (std::abs(S2) < eps && std::abs(S3) < eps) ) //S2,S3=0
264  {
265 
266  //Print()<<"vertex intersection type 1\n";
267  //don't chose vertex 2 or 3
268  get_plucker_coords(v2,t1,L2);
269  get_plucker_coords(t1,v1,L3);
270  get_plucker_coords(t2,t3,L4);
271 
272  ls_s1=side_op(L4,L3);
273  ls_s2=side_op(L4,L2);
274 
275  if(ls_s1*ls_s2 > 0)
276  {
277  no_intersections = 0;
278  }
279  }
280  else if(std::abs(S3) < eps && std::abs(S1) < eps) //S3,S1=0
281  {
282 
283  //Print()<<"vertex intersection type 2\n";
284  //don't chose vertex 1
285  get_plucker_coords(v2,t2,L2);
286  get_plucker_coords(t2,v1,L3);
287  get_plucker_coords(t3,t1,L4);
288 
289  ls_s1=side_op(L4,L3);
290  ls_s2=side_op(L4,L2);
291 
292  if(ls_s1*ls_s2 > 0)
293  {
294  no_intersections=0;
295  }
296  }
297 
298  return(no_intersections);
299 
300  }
301  //================================================================================
302 }
303 #endif
#define AMREX_FORCE_INLINE
Definition: AMReX_Extension.H:119
#define AMREX_GPU_HOST_DEVICE
Definition: AMReX_GpuQualifiers.H:20
constexpr double eps
Definition: AMReX_MLNodeLap_K.H:19
Definition: AMReX_EB_triGeomOps_K.H:8
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE Real side_op(const Real L1[6], const Real L2[6])
Definition: AMReX_EB_triGeomOps_K.H:23
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE Real DotProd(const Real v1[3], const Real v2[3])
Definition: AMReX_EB_triGeomOps_K.H:17
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE int lineseg_tri_intersect(const Real v1[3], const Real v2[3], const Real t1[3], const Real t2[3], const Real t3[3])
Definition: AMReX_EB_triGeomOps_K.H:200
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void CrossProd(const Real v1[3], const Real v2[3], Real v[3])
Definition: AMReX_EB_triGeomOps_K.H:49
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void get_plucker_coords(const Real v1[3], const Real v2[3], Real L[6])
Definition: AMReX_EB_triGeomOps_K.H:56
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void getvec(const Real P1[3], const Real P2[3], Real v[3])
Definition: AMReX_EB_triGeomOps_K.H:33
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void side_op3(const Real v1[3], const Real v2[3], const Real t1[3], const Real t2[3], const Real t3[3], Real &S1, Real &S2, Real &S3)
Definition: AMReX_EB_triGeomOps_K.H:66
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE Real Distance2(const Real P1[3], const Real P2[3])
Definition: AMReX_EB_triGeomOps_K.H:10
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void getunitvec(const Real v[3], Real vu[3])
Definition: AMReX_EB_triGeomOps_K.H:40
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void tri_n(const Real P1[3], const Real P2[3], const Real P3[3], const Real testp[3], Real n[3])
Definition: AMReX_EB_triGeomOps_K.H:84
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE Real triangle_area(const Real P1[3], const Real P2[3], const Real P3[3])
Definition: AMReX_EB_triGeomOps_K.H:112
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE bool find_intersection_point(const Real v1[3], const Real v2[3], const Real t1[3], const Real t2[3], const Real t3[3], Real ip[3], int bisect_iters=20, Real tol=1e-6)
Definition: AMReX_EB_triGeomOps_K.H:123
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE T abs(const GpuComplex< T > &a_z) noexcept
Return the absolute value of a complex number.
Definition: AMReX_GpuComplex.H:356
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE GpuComplex< T > sqrt(const GpuComplex< T > &a_z) noexcept
Return the square root of a complex number.
Definition: AMReX_GpuComplex.H:373