Imported Upstream version 2.81
[platform/upstream/libbullet.git] / src / BulletCollision / Gimpact / gim_tri_collision.cpp
1
2 /*! \file gim_tri_collision.h
3 \author Francisco Leon Najera
4 */
5 /*
6 -----------------------------------------------------------------------------
7 This source file is part of GIMPACT Library.
8
9 For the latest info, see http://gimpact.sourceforge.net/
10
11 Copyright (c) 2006 Francisco Leon Najera. C.C. 80087371.
12 email: projectileman@yahoo.com
13
14  This library is free software; you can redistribute it and/or
15  modify it under the terms of EITHER:
16    (1) The GNU Lesser General Public License as published by the Free
17        Software Foundation; either version 2.1 of the License, or (at
18        your option) any later version. The text of the GNU Lesser
19        General Public License is included with this library in the
20        file GIMPACT-LICENSE-LGPL.TXT.
21    (2) The BSD-style license that is included with this library in
22        the file GIMPACT-LICENSE-BSD.TXT.
23    (3) The zlib/libpng license that is included with this library in
24        the file GIMPACT-LICENSE-ZLIB.TXT.
25
26  This library is distributed in the hope that it will be useful,
27  but WITHOUT ANY WARRANTY; without even the implied warranty of
28  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files
29  GIMPACT-LICENSE-LGPL.TXT, GIMPACT-LICENSE-ZLIB.TXT and GIMPACT-LICENSE-BSD.TXT for more details.
30
31 -----------------------------------------------------------------------------
32 */
33
34 #include "gim_tri_collision.h"
35
36
37 #define TRI_LOCAL_EPSILON 0.000001f
38 #define MIN_EDGE_EDGE_DIS 0.00001f
39
40
41 class GIM_TRIANGLE_CALCULATION_CACHE
42 {
43 public:
44         GREAL margin;   
45         btVector3 tu_vertices[3];
46         btVector3 tv_vertices[3];
47         btVector4 tu_plane;
48         btVector4 tv_plane;
49         btVector3 closest_point_u;
50         btVector3 closest_point_v;
51         btVector3 edge_edge_dir;
52         btVector3 distances;
53         GREAL du[4];
54         GREAL du0du1;
55         GREAL du0du2;
56         GREAL dv[4];
57         GREAL dv0dv1;
58         GREAL dv0dv2;   
59         btVector3 temp_points[MAX_TRI_CLIPPING];
60         btVector3 temp_points1[MAX_TRI_CLIPPING];
61         btVector3 contact_points[MAX_TRI_CLIPPING];
62         
63
64
65         //! if returns false, the faces are paralele
66         SIMD_FORCE_INLINE bool compute_intervals(
67                                         const GREAL &D0,
68                                         const GREAL &D1,
69                                         const GREAL &D2,
70                                         const GREAL &D0D1,
71                                         const GREAL &D0D2,
72                                         GREAL & scale_edge0,
73                                         GREAL & scale_edge1,
74                                         GUINT &edge_index0,
75                                         GUINT &edge_index1)
76         {
77                 if(D0D1>0.0f)
78                 {
79                         /* here we know that D0D2<=0.0 */
80                         /* that is D0, D1 are on the same side, D2 on the other or on the plane */
81                         scale_edge0 = -D2/(D0-D2);
82                         scale_edge1 = -D1/(D2-D1);
83                         edge_index0 = 2;edge_index1 = 1;
84                 }
85                 else if(D0D2>0.0f)
86                 {
87                         /* here we know that d0d1<=0.0 */
88                         scale_edge0 = -D0/(D1-D0);
89                         scale_edge1 = -D1/(D2-D1);
90                         edge_index0 = 0;edge_index1 = 1;
91                 }
92                 else if(D1*D2>0.0f || D0!=0.0f)
93                 {
94                         /* here we know that d0d1<=0.0 or that D0!=0.0 */
95                         scale_edge0 = -D0/(D1-D0);
96                         scale_edge1 = -D2/(D0-D2);
97                         edge_index0 = 0 ;edge_index1 = 2;
98                 }
99                 else
100                 {
101                         return false;
102                 }
103                 return true;
104         }
105
106
107         //! clip triangle
108         /*!
109         */
110         SIMD_FORCE_INLINE GUINT clip_triangle(
111                 const btVector4 & tri_plane,
112                 const btVector3 * tripoints,
113                 const btVector3 * srcpoints,
114                 btVector3 * clip_points)
115         {
116                 // edge 0
117
118                 btVector4 edgeplane;
119
120                 EDGE_PLANE(tripoints[0],tripoints[1],tri_plane,edgeplane);
121
122                 GUINT clipped_count = PLANE_CLIP_TRIANGLE3D(
123                         edgeplane,srcpoints[0],srcpoints[1],srcpoints[2],temp_points);
124
125                 if(clipped_count == 0) return 0;
126
127                 // edge 1
128
129                 EDGE_PLANE(tripoints[1],tripoints[2],tri_plane,edgeplane);
130
131                 clipped_count = PLANE_CLIP_POLYGON3D(
132                         edgeplane,temp_points,clipped_count,temp_points1);
133
134                 if(clipped_count == 0) return 0;
135
136                 // edge 2
137
138                 EDGE_PLANE(tripoints[2],tripoints[0],tri_plane,edgeplane);
139
140                 clipped_count = PLANE_CLIP_POLYGON3D(
141                         edgeplane,temp_points1,clipped_count,clip_points);
142
143                 return clipped_count;
144
145
146                 /*GUINT i0 = (tri_plane.closestAxis()+1)%3;
147                 GUINT i1 = (i0+1)%3;
148                 // edge 0
149                 btVector3 temp_points[MAX_TRI_CLIPPING];
150                 btVector3 temp_points1[MAX_TRI_CLIPPING];
151
152                 GUINT clipped_count= PLANE_CLIP_TRIANGLE_GENERIC(
153                         0,srcpoints[0],srcpoints[1],srcpoints[2],temp_points,
154                         DISTANCE_EDGE(tripoints[0],tripoints[1],i0,i1));
155                 
156                 
157                 if(clipped_count == 0) return 0;
158
159                 // edge 1
160                 clipped_count = PLANE_CLIP_POLYGON_GENERIC(
161                         0,temp_points,clipped_count,temp_points1,
162                         DISTANCE_EDGE(tripoints[1],tripoints[2],i0,i1));
163
164                 if(clipped_count == 0) return 0;
165
166                 // edge 2
167                 clipped_count = PLANE_CLIP_POLYGON_GENERIC(
168                         0,temp_points1,clipped_count,clipped_points,
169                         DISTANCE_EDGE(tripoints[2],tripoints[0],i0,i1));
170
171                 return clipped_count;*/
172         }
173
174         SIMD_FORCE_INLINE void sort_isect(
175                 GREAL & isect0,GREAL & isect1,GUINT &e0,GUINT &e1,btVector3 & vec0,btVector3 & vec1)
176         {
177                 if(isect1<isect0)
178                 {
179                         //swap
180                         GIM_SWAP_NUMBERS(isect0,isect1);
181                         GIM_SWAP_NUMBERS(e0,e1);
182                         btVector3 tmp = vec0;
183                         vec0 = vec1;
184                         vec1 = tmp;
185                 }
186         }
187
188         //! Test verifying interval intersection with the direction between planes
189         /*!
190         \pre tv_plane and tu_plane must be set
191         \post
192         distances[2] is set with the distance
193         closest_point_u, closest_point_v, edge_edge_dir are set too
194         \return
195         - 0: faces are paralele
196         - 1: face U casts face V
197         - 2: face V casts face U
198         - 3: nearest edges
199         */
200         SIMD_FORCE_INLINE GUINT cross_line_intersection_test()
201         {
202                 // Compute direction of intersection line
203                 edge_edge_dir = tu_plane.cross(tv_plane);
204                 GREAL Dlen;
205                 VEC_LENGTH(edge_edge_dir,Dlen);
206
207                 if(Dlen<0.0001)
208                 {
209                         return 0; //faces near paralele
210                 }
211
212                 edge_edge_dir*= 1/Dlen;//normalize
213
214
215                 // Compute interval for triangle 1
216                 GUINT tu_e0,tu_e1;//edge indices
217                 GREAL tu_scale_e0,tu_scale_e1;//edge scale
218                 if(!compute_intervals(du[0],du[1],du[2],
219                         du0du1,du0du2,tu_scale_e0,tu_scale_e1,tu_e0,tu_e1)) return 0;
220
221                 // Compute interval for triangle 2
222                 GUINT tv_e0,tv_e1;//edge indices
223                 GREAL tv_scale_e0,tv_scale_e1;//edge scale
224
225                 if(!compute_intervals(dv[0],dv[1],dv[2],
226                         dv0dv1,dv0dv2,tv_scale_e0,tv_scale_e1,tv_e0,tv_e1)) return 0;
227
228                 //proyected vertices
229                 btVector3 up_e0 = tu_vertices[tu_e0].lerp(tu_vertices[(tu_e0+1)%3],tu_scale_e0);
230                 btVector3 up_e1 = tu_vertices[tu_e1].lerp(tu_vertices[(tu_e1+1)%3],tu_scale_e1);
231
232                 btVector3 vp_e0 = tv_vertices[tv_e0].lerp(tv_vertices[(tv_e0+1)%3],tv_scale_e0);
233                 btVector3 vp_e1 = tv_vertices[tv_e1].lerp(tv_vertices[(tv_e1+1)%3],tv_scale_e1);
234
235                 //proyected intervals
236                 GREAL isect_u[] = {up_e0.dot(edge_edge_dir),up_e1.dot(edge_edge_dir)};
237                 GREAL isect_v[] = {vp_e0.dot(edge_edge_dir),vp_e1.dot(edge_edge_dir)};
238
239                 sort_isect(isect_u[0],isect_u[1],tu_e0,tu_e1,up_e0,up_e1);
240                 sort_isect(isect_v[0],isect_v[1],tv_e0,tv_e1,vp_e0,vp_e1);
241
242                 const GREAL midpoint_u = 0.5f*(isect_u[0]+isect_u[1]); // midpoint
243                 const GREAL midpoint_v = 0.5f*(isect_v[0]+isect_v[1]); // midpoint
244
245                 if(midpoint_u<midpoint_v)
246                 {
247                         if(isect_u[1]>=isect_v[1]) // face U casts face V
248                         {
249                                 return 1;
250                         }
251                         else if(isect_v[0]<=isect_u[0]) // face V casts face U
252                         {
253                                 return 2;
254                         }
255                         // closest points
256                         closest_point_u = up_e1;
257                         closest_point_v = vp_e0;
258                         // calc edges and separation
259
260                         if(isect_u[1]+ MIN_EDGE_EDGE_DIS<isect_v[0]) //calc distance between two lines instead
261                         {
262                                 SEGMENT_COLLISION(
263                                         tu_vertices[tu_e1],tu_vertices[(tu_e1+1)%3],
264                                         tv_vertices[tv_e0],tv_vertices[(tv_e0+1)%3],
265                                         closest_point_u,
266                                         closest_point_v);
267
268                                 edge_edge_dir = closest_point_u-closest_point_v;
269                                 VEC_LENGTH(edge_edge_dir,distances[2]);
270                                 edge_edge_dir *= 1.0f/distances[2];// normalize
271                         }
272                         else
273                         {
274                                 distances[2] = isect_v[0]-isect_u[1];//distance negative
275                                 //edge_edge_dir *= -1.0f; //normal pointing from V to U
276                         }
277
278                 }
279                 else
280                 {
281                         if(isect_v[1]>=isect_u[1]) // face V casts face U
282                         {
283                                 return 2;
284                         }
285                         else if(isect_u[0]<=isect_v[0]) // face U casts face V
286                         {
287                                 return 1;
288                         }
289                         // closest points
290                         closest_point_u = up_e0;
291                         closest_point_v = vp_e1;
292                         // calc edges and separation
293
294                         if(isect_v[1]+MIN_EDGE_EDGE_DIS<isect_u[0]) //calc distance between two lines instead
295                         {
296                                 SEGMENT_COLLISION(
297                                         tu_vertices[tu_e0],tu_vertices[(tu_e0+1)%3],
298                                         tv_vertices[tv_e1],tv_vertices[(tv_e1+1)%3],
299                                         closest_point_u,
300                                         closest_point_v);
301
302                                 edge_edge_dir = closest_point_u-closest_point_v;
303                                 VEC_LENGTH(edge_edge_dir,distances[2]);
304                                 edge_edge_dir *= 1.0f/distances[2];// normalize
305                         }
306                         else
307                         {
308                                 distances[2] = isect_u[0]-isect_v[1];//distance negative
309                                 //edge_edge_dir *= -1.0f; //normal pointing from V to U
310                         }
311                 }
312                 return 3;
313         }
314
315
316         //! collides by two sides
317         SIMD_FORCE_INLINE bool triangle_collision(
318                                         const btVector3 & u0,
319                                         const btVector3 & u1,
320                                         const btVector3 & u2,
321                                         GREAL margin_u,
322                                         const btVector3 & v0,
323                                         const btVector3 & v1,
324                                         const btVector3 & v2,
325                                         GREAL margin_v,
326                                         GIM_TRIANGLE_CONTACT_DATA & contacts)
327         {
328
329                 margin = margin_u + margin_v;
330
331                 tu_vertices[0] = u0;
332                 tu_vertices[1] = u1;
333                 tu_vertices[2] = u2;
334
335                 tv_vertices[0] = v0;
336                 tv_vertices[1] = v1;
337                 tv_vertices[2] = v2;
338
339                 //create planes
340                 // plane v vs U points
341
342                 TRIANGLE_PLANE(tv_vertices[0],tv_vertices[1],tv_vertices[2],tv_plane);
343
344                 du[0] = DISTANCE_PLANE_POINT(tv_plane,tu_vertices[0]);
345                 du[1] = DISTANCE_PLANE_POINT(tv_plane,tu_vertices[1]);
346                 du[2] = DISTANCE_PLANE_POINT(tv_plane,tu_vertices[2]);
347
348
349                 du0du1 = du[0] * du[1];
350                 du0du2 = du[0] * du[2];
351
352
353                 if(du0du1>0.0f && du0du2>0.0f)  // same sign on all of them + not equal 0 ?
354                 {
355                         if(du[0]<0) //we need test behind the triangle plane
356                         {
357                                 distances[0] = GIM_MAX3(du[0],du[1],du[2]);
358                                 distances[0] = -distances[0];
359                                 if(distances[0]>margin) return false; //never intersect
360
361                                 //reorder triangle v
362                                 VEC_SWAP(tv_vertices[0],tv_vertices[1]);
363                                 VEC_SCALE_4(tv_plane,-1.0f,tv_plane);
364                         }
365                         else
366                         {
367                                 distances[0] = GIM_MIN3(du[0],du[1],du[2]);
368                                 if(distances[0]>margin) return false; //never intersect
369                         }
370                 }
371                 else
372                 {
373                         //Look if we need to invert the triangle
374                         distances[0] = (du[0]+du[1]+du[2])/3.0f; //centroid
375
376                         if(distances[0]<0.0f)
377                         {
378                                 //reorder triangle v
379                                 VEC_SWAP(tv_vertices[0],tv_vertices[1]);
380                                 VEC_SCALE_4(tv_plane,-1.0f,tv_plane);
381
382                                 distances[0] = GIM_MAX3(du[0],du[1],du[2]);
383                                 distances[0] = -distances[0];
384                         }
385                         else
386                         {
387                                 distances[0] = GIM_MIN3(du[0],du[1],du[2]);
388                         }
389                 }
390
391
392                 // plane U vs V points
393
394                 TRIANGLE_PLANE(tu_vertices[0],tu_vertices[1],tu_vertices[2],tu_plane);
395
396                 dv[0] = DISTANCE_PLANE_POINT(tu_plane,tv_vertices[0]);
397                 dv[1] = DISTANCE_PLANE_POINT(tu_plane,tv_vertices[1]);
398                 dv[2] = DISTANCE_PLANE_POINT(tu_plane,tv_vertices[2]);
399
400                 dv0dv1 = dv[0] * dv[1];
401                 dv0dv2 = dv[0] * dv[2];
402
403
404                 if(dv0dv1>0.0f && dv0dv2>0.0f)  // same sign on all of them + not equal 0 ?
405                 {
406                         if(dv[0]<0) //we need test behind the triangle plane
407                         {
408                                 distances[1] = GIM_MAX3(dv[0],dv[1],dv[2]);
409                                 distances[1] = -distances[1];
410                                 if(distances[1]>margin) return false; //never intersect
411
412                                 //reorder triangle u
413                                 VEC_SWAP(tu_vertices[0],tu_vertices[1]);
414                                 VEC_SCALE_4(tu_plane,-1.0f,tu_plane);
415                         }
416                         else
417                         {
418                                 distances[1] = GIM_MIN3(dv[0],dv[1],dv[2]);
419                                 if(distances[1]>margin) return false; //never intersect
420                         }
421                 }
422                 else
423                 {
424                         //Look if we need to invert the triangle
425                         distances[1] = (dv[0]+dv[1]+dv[2])/3.0f; //centroid
426
427                         if(distances[1]<0.0f)
428                         {
429                                 //reorder triangle v
430                                 VEC_SWAP(tu_vertices[0],tu_vertices[1]);
431                                 VEC_SCALE_4(tu_plane,-1.0f,tu_plane);
432
433                                 distances[1] = GIM_MAX3(dv[0],dv[1],dv[2]);
434                                 distances[1] = -distances[1];
435                         }
436                         else
437                         {
438                                 distances[1] = GIM_MIN3(dv[0],dv[1],dv[2]);
439                         }
440                 }
441
442                 GUINT bl;
443                 /* bl = cross_line_intersection_test();
444                 if(bl==3)
445                 {
446                         //take edge direction too
447                         bl = distances.maxAxis();
448                 }
449                 else
450                 {*/
451                         bl = 0;
452                         if(distances[0]<distances[1]) bl = 1;
453                 //}
454
455                 if(bl==2) //edge edge separation
456                 {
457                         if(distances[2]>margin) return false;
458
459                         contacts.m_penetration_depth = -distances[2] + margin;
460                         contacts.m_points[0] = closest_point_v;
461                         contacts.m_point_count = 1;
462                         VEC_COPY(contacts.m_separating_normal,edge_edge_dir);
463
464                         return true;
465                 }
466
467                 //clip face against other
468
469                 
470                 GUINT point_count;
471                 //TODO
472                 if(bl == 0) //clip U points against V
473                 {
474                         point_count = clip_triangle(tv_plane,tv_vertices,tu_vertices,contact_points);
475                         if(point_count == 0) return false;                                              
476                         contacts.merge_points(tv_plane,margin,contact_points,point_count);                      
477                 }
478                 else //clip V points against U
479                 {
480                         point_count = clip_triangle(tu_plane,tu_vertices,tv_vertices,contact_points);
481                         if(point_count == 0) return false;                      
482                         contacts.merge_points(tu_plane,margin,contact_points,point_count);
483                         contacts.m_separating_normal *= -1.f;
484                 }
485                 if(contacts.m_point_count == 0) return false;
486                 return true;
487         }
488
489 };
490
491
492 /*class GIM_TRIANGLE_CALCULATION_CACHE
493 {
494 public:
495         GREAL margin;
496         GUINT clipped_count;
497         btVector3 tu_vertices[3];
498         btVector3 tv_vertices[3];
499         btVector3 temp_points[MAX_TRI_CLIPPING];
500         btVector3 temp_points1[MAX_TRI_CLIPPING];
501         btVector3 clipped_points[MAX_TRI_CLIPPING];
502         GIM_TRIANGLE_CONTACT_DATA contacts1;
503         GIM_TRIANGLE_CONTACT_DATA contacts2;
504
505
506         //! clip triangle
507         GUINT clip_triangle(
508                 const btVector4 & tri_plane,
509                 const btVector3 * tripoints,
510                 const btVector3 * srcpoints,
511                 btVector3 * clipped_points)
512         {
513                 // edge 0
514
515                 btVector4 edgeplane;
516
517                 EDGE_PLANE(tripoints[0],tripoints[1],tri_plane,edgeplane);
518
519                 GUINT clipped_count = PLANE_CLIP_TRIANGLE3D(
520                         edgeplane,srcpoints[0],srcpoints[1],srcpoints[2],temp_points);
521
522                 if(clipped_count == 0) return 0;
523
524                 // edge 1
525
526                 EDGE_PLANE(tripoints[1],tripoints[2],tri_plane,edgeplane);
527
528                 clipped_count = PLANE_CLIP_POLYGON3D(
529                         edgeplane,temp_points,clipped_count,temp_points1);
530
531                 if(clipped_count == 0) return 0;
532
533                 // edge 2
534
535                 EDGE_PLANE(tripoints[2],tripoints[0],tri_plane,edgeplane);
536
537                 clipped_count = PLANE_CLIP_POLYGON3D(
538                         edgeplane,temp_points1,clipped_count,clipped_points);
539
540                 return clipped_count;
541         }
542
543
544
545
546         //! collides only on one side
547         bool triangle_collision(
548                                         const btVector3 & u0,
549                                         const btVector3 & u1,
550                                         const btVector3 & u2,
551                                         GREAL margin_u,
552                                         const btVector3 & v0,
553                                         const btVector3 & v1,
554                                         const btVector3 & v2,
555                                         GREAL margin_v,
556                                         GIM_TRIANGLE_CONTACT_DATA & contacts)
557         {
558
559                 margin = margin_u + margin_v;
560
561                 
562                 tu_vertices[0] = u0;
563                 tu_vertices[1] = u1;
564                 tu_vertices[2] = u2;
565
566                 tv_vertices[0] = v0;
567                 tv_vertices[1] = v1;
568                 tv_vertices[2] = v2;
569
570                 //create planes
571                 // plane v vs U points
572
573
574                 TRIANGLE_PLANE(tv_vertices[0],tv_vertices[1],tv_vertices[2],contacts1.m_separating_normal);
575
576                 clipped_count = clip_triangle(
577                         contacts1.m_separating_normal,tv_vertices,tu_vertices,clipped_points);
578
579                 if(clipped_count == 0 )
580                 {
581                          return false;//Reject
582                 }
583
584                 //find most deep interval face1
585                 contacts1.merge_points(contacts1.m_separating_normal,margin,clipped_points,clipped_count);
586                 if(contacts1.m_point_count == 0) return false; // too far
587
588                 //Normal pointing to triangle1
589                 //contacts1.m_separating_normal *= -1.f;
590
591                 //Clip tri1 by tri2 edges
592
593                 TRIANGLE_PLANE(tu_vertices[0],tu_vertices[1],tu_vertices[2],contacts2.m_separating_normal);
594
595                 clipped_count = clip_triangle(
596                         contacts2.m_separating_normal,tu_vertices,tv_vertices,clipped_points);
597
598                 if(clipped_count == 0 )
599                 {
600                          return false;//Reject
601                 }
602
603                 //find most deep interval face1
604                 contacts2.merge_points(contacts2.m_separating_normal,margin,clipped_points,clipped_count);
605                 if(contacts2.m_point_count == 0) return false; // too far
606
607                 contacts2.m_separating_normal *= -1.f;
608
609                 ////check most dir for contacts
610                 if(contacts2.m_penetration_depth<contacts1.m_penetration_depth)
611                 {
612                         contacts.copy_from(contacts2);
613                 }
614                 else
615                 {
616                         contacts.copy_from(contacts1);
617                 }
618                 return true;
619         }
620
621
622 };*/
623
624
625
626 bool GIM_TRIANGLE::collide_triangle_hard_test(
627                 const GIM_TRIANGLE & other,
628                 GIM_TRIANGLE_CONTACT_DATA & contact_data) const
629 {
630         GIM_TRIANGLE_CALCULATION_CACHE calc_cache;      
631         return calc_cache.triangle_collision(
632                                         m_vertices[0],m_vertices[1],m_vertices[2],m_margin,
633                                         other.m_vertices[0],other.m_vertices[1],other.m_vertices[2],other.m_margin,
634                                         contact_data);
635
636 }
637
638
639
640