1 #ifndef GIM_BASIC_GEOMETRY_OPERATIONS_H_INCLUDED
2 #define GIM_BASIC_GEOMETRY_OPERATIONS_H_INCLUDED
4 /*! \file gim_basic_geometry_operations.h
5 *\author Francisco Leon Najera
6 type independant geometry routines
10 -----------------------------------------------------------------------------
11 This source file is part of GIMPACT Library.
13 For the latest info, see http://gimpact.sourceforge.net/
15 Copyright (c) 2006 Francisco Leon Najera. C.C. 80087371.
16 email: projectileman@yahoo.com
18 This library is free software; you can redistribute it and/or
19 modify it under the terms of EITHER:
20 (1) The GNU Lesser General Public License as published by the Free
21 Software Foundation; either version 2.1 of the License, or (at
22 your option) any later version. The text of the GNU Lesser
23 General Public License is included with this library in the
24 file GIMPACT-LICENSE-LGPL.TXT.
25 (2) The BSD-style license that is included with this library in
26 the file GIMPACT-LICENSE-BSD.TXT.
27 (3) The zlib/libpng license that is included with this library in
28 the file GIMPACT-LICENSE-ZLIB.TXT.
30 This library is distributed in the hope that it will be useful,
31 but WITHOUT ANY WARRANTY; without even the implied warranty of
32 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files
33 GIMPACT-LICENSE-LGPL.TXT, GIMPACT-LICENSE-ZLIB.TXT and GIMPACT-LICENSE-BSD.TXT for more details.
35 -----------------------------------------------------------------------------
39 #include "gim_linear_math.h"
45 #define PLANEDIREPSILON 0.0000001f
46 #define PARALELENORMALS 0.000001f
49 #define TRIANGLE_NORMAL(v1,v2,v3,n)\
52 VEC_DIFF(_dif1,v2,v1);\
53 VEC_DIFF(_dif2,v3,v1);\
54 VEC_CROSS(n,_dif1,_dif2);\
58 #define TRIANGLE_NORMAL_FAST(v1,v2,v3,n){\
60 VEC_DIFF(_dif1,v2,v1); \
61 VEC_DIFF(_dif2,v3,v1); \
62 VEC_CROSS(n,_dif1,_dif2); \
66 #define TRIANGLE_PLANE(v1,v2,v3,plane) {\
67 TRIANGLE_NORMAL(v1,v2,v3,plane);\
68 plane[3] = VEC_DOT(v1,plane);\
72 #define TRIANGLE_PLANE_FAST(v1,v2,v3,plane) {\
73 TRIANGLE_NORMAL_FAST(v1,v2,v3,plane);\
74 plane[3] = VEC_DOT(v1,plane);\
77 /// Calc a plane from an edge an a normal. plane is a vec4f
78 #define EDGE_PLANE(e1,e2,n,plane) {\
80 VEC_DIFF(_dif,e2,e1); \
81 VEC_CROSS(plane,_dif,n); \
82 VEC_NORMALIZE(plane); \
83 plane[3] = VEC_DOT(e1,plane);\
86 #define DISTANCE_PLANE_POINT(plane,point) (VEC_DOT(plane,point) - plane[3])
88 #define PROJECT_POINT_PLANE(point,plane,projected) {\
90 _dis = DISTANCE_PLANE_POINT(plane,point);\
91 VEC_SCALE(projected,-_dis,plane);\
92 VEC_SUM(projected,projected,point); \
95 //! Verifies if a point is in the plane hull
96 template<typename CLASS_POINT,typename CLASS_PLANE>
97 SIMD_FORCE_INLINE bool POINT_IN_HULL(
98 const CLASS_POINT& point,const CLASS_PLANE * planes,GUINT plane_count)
101 for (GUINT _i = 0;_i< plane_count;++_i)
103 _dis = DISTANCE_PLANE_POINT(planes[_i],point);
104 if(_dis>0.0f) return false;
109 template<typename CLASS_POINT,typename CLASS_PLANE>
110 SIMD_FORCE_INLINE void PLANE_CLIP_SEGMENT(
111 const CLASS_POINT& s1,
112 const CLASS_POINT &s2,const CLASS_PLANE &plane,CLASS_POINT &clipped)
115 _dis1 = DISTANCE_PLANE_POINT(plane,s1);
116 VEC_DIFF(clipped,s2,s1);
117 _dis2 = VEC_DOT(clipped,plane);
118 VEC_SCALE(clipped,-_dis1/_dis2,clipped);
119 VEC_SUM(clipped,clipped,s1);
122 enum ePLANE_INTERSECTION_TYPE
129 enum eLINE_PLANE_INTERSECTION_TYPE
131 G_FRONT_PLANE_S1 = 0,
139 //! Confirms if the plane intersect the edge or nor
141 intersection type must have the following values
143 <li> 0 : Segment in front of plane, s1 closest
144 <li> 1 : Segment in front of plane, s2 closest
145 <li> 2 : Segment in back of plane, s1 closest
146 <li> 3 : Segment in back of plane, s2 closest
147 <li> 4 : Segment collides plane, s1 in back
148 <li> 5 : Segment collides plane, s2 in back
152 template<typename CLASS_POINT,typename CLASS_PLANE>
153 SIMD_FORCE_INLINE eLINE_PLANE_INTERSECTION_TYPE PLANE_CLIP_SEGMENT2(
154 const CLASS_POINT& s1,
155 const CLASS_POINT &s2,
156 const CLASS_PLANE &plane,CLASS_POINT &clipped)
158 GREAL _dis1 = DISTANCE_PLANE_POINT(plane,s1);
159 GREAL _dis2 = DISTANCE_PLANE_POINT(plane,s2);
160 if(_dis1 >-G_EPSILON && _dis2 >-G_EPSILON)
162 if(_dis1<_dis2) return G_FRONT_PLANE_S1;
163 return G_FRONT_PLANE_S2;
165 else if(_dis1 <G_EPSILON && _dis2 <G_EPSILON)
167 if(_dis1>_dis2) return G_BACK_PLANE_S1;
168 return G_BACK_PLANE_S2;
171 VEC_DIFF(clipped,s2,s1);
172 _dis2 = VEC_DOT(clipped,plane);
173 VEC_SCALE(clipped,-_dis1/_dis2,clipped);
174 VEC_SUM(clipped,clipped,s1);
175 if(_dis1<_dis2) return G_COLLIDE_PLANE_S1;
176 return G_COLLIDE_PLANE_S2;
179 //! Confirms if the plane intersect the edge or not
181 clipped1 and clipped2 are the vertices behind the plane.
182 clipped1 is the closest
184 intersection_type must have the following values
186 <li> 0 : Segment in front of plane, s1 closest
187 <li> 1 : Segment in front of plane, s2 closest
188 <li> 2 : Segment in back of plane, s1 closest
189 <li> 3 : Segment in back of plane, s2 closest
190 <li> 4 : Segment collides plane, s1 in back
191 <li> 5 : Segment collides plane, s2 in back
194 template<typename CLASS_POINT,typename CLASS_PLANE>
195 SIMD_FORCE_INLINE eLINE_PLANE_INTERSECTION_TYPE PLANE_CLIP_SEGMENT_CLOSEST(
196 const CLASS_POINT& s1,
197 const CLASS_POINT &s2,
198 const CLASS_PLANE &plane,
199 CLASS_POINT &clipped1,CLASS_POINT &clipped2)
201 eLINE_PLANE_INTERSECTION_TYPE intersection_type = PLANE_CLIP_SEGMENT2(s1,s2,plane,clipped1);
202 switch(intersection_type)
204 case G_FRONT_PLANE_S1:
205 VEC_COPY(clipped1,s1);
206 VEC_COPY(clipped2,s2);
208 case G_FRONT_PLANE_S2:
209 VEC_COPY(clipped1,s2);
210 VEC_COPY(clipped2,s1);
212 case G_BACK_PLANE_S1:
213 VEC_COPY(clipped1,s1);
214 VEC_COPY(clipped2,s2);
216 case G_BACK_PLANE_S2:
217 VEC_COPY(clipped1,s2);
218 VEC_COPY(clipped2,s1);
220 case G_COLLIDE_PLANE_S1:
221 VEC_COPY(clipped2,s1);
223 case G_COLLIDE_PLANE_S2:
224 VEC_COPY(clipped2,s2);
227 return intersection_type;
231 //! Finds the 2 smallest cartesian coordinates of a plane normal
232 #define PLANE_MINOR_AXES(plane, i0, i1) VEC_MINOR_AXES(plane, i0, i1)
234 //! Ray plane collision in one way
236 Intersects plane in one way only. The ray must face the plane (normals must be in opossite directions).<br/>
237 It uses the PLANEDIREPSILON constant.
239 template<typename T,typename CLASS_POINT,typename CLASS_PLANE>
240 SIMD_FORCE_INLINE bool RAY_PLANE_COLLISION(
241 const CLASS_PLANE & plane,
242 const CLASS_POINT & vDir,
243 const CLASS_POINT & vPoint,
244 CLASS_POINT & pout,T &tparam)
247 _dotdir = VEC_DOT(plane,vDir);
248 if(_dotdir<PLANEDIREPSILON)
252 _dis = DISTANCE_PLANE_POINT(plane,vPoint);
253 tparam = -_dis/_dotdir;
254 VEC_SCALE(pout,tparam,vDir);
255 VEC_SUM(pout,vPoint,pout);
262 -0 if the ray never intersects
263 -1 if the ray collides in front
264 -2 if the ray collides in back
266 template<typename T,typename CLASS_POINT,typename CLASS_PLANE>
267 SIMD_FORCE_INLINE GUINT LINE_PLANE_COLLISION(
268 const CLASS_PLANE & plane,
269 const CLASS_POINT & vDir,
270 const CLASS_POINT & vPoint,
276 _dotdir = VEC_DOT(plane,vDir);
277 if(btFabs(_dotdir)<PLANEDIREPSILON)
282 _dis = DISTANCE_PLANE_POINT(plane,vPoint);
283 char returnvalue = _dis<0.0f?2:1;
284 tparam = -_dis/_dotdir;
297 VEC_SCALE(pout,tparam,vDir);
298 VEC_SUM(pout,vPoint,pout);
302 /*! \brief Returns the Ray on which 2 planes intersect if they do.
303 Written by Rodrigo Hernandez on ODE convex collision
307 \param p Contains the origin of the ray upon returning if planes intersect
308 \param d Contains the direction of the ray upon returning if planes intersect
309 \return true if the planes intersect, 0 if paralell.
312 template<typename CLASS_POINT,typename CLASS_PLANE>
313 SIMD_FORCE_INLINE bool INTERSECT_PLANES(
314 const CLASS_PLANE &p1,
315 const CLASS_PLANE &p2,
320 GREAL denom = VEC_DOT(d, d);
321 if(GIM_IS_ZERO(denom)) return false;
323 _n[0]=p1[3]*p2[0] - p2[3]*p1[0];
324 _n[1]=p1[3]*p2[1] - p2[3]*p1[1];
325 _n[2]=p1[3]*p2[2] - p2[3]*p1[2];
333 //***************** SEGMENT and LINE FUNCTIONS **********************************///
335 /*! Finds the closest point(cp) to (v) on a segment (e1,e2)
337 template<typename CLASS_POINT>
338 SIMD_FORCE_INLINE void CLOSEST_POINT_ON_SEGMENT(
339 CLASS_POINT & cp, const CLASS_POINT & v,
340 const CLASS_POINT &e1,const CLASS_POINT &e2)
345 GREAL _scalar = VEC_DOT(cp, _n);
346 _scalar/= VEC_DOT(_n, _n);
351 else if(_scalar >1.0f)
357 VEC_SCALE(cp,_scalar,_n);
363 /*! \brief Finds the line params where these lines intersect.
365 \param dir1 Direction of line 1
366 \param point1 Point of line 1
367 \param dir2 Direction of line 2
368 \param point2 Point of line 2
369 \param t1 Result Parameter for line 1
370 \param t2 Result Parameter for line 2
371 \param dointersect 0 if the lines won't intersect, else 1
374 template<typename T,typename CLASS_POINT>
375 SIMD_FORCE_INLINE bool LINE_INTERSECTION_PARAMS(
376 const CLASS_POINT & dir1,
377 CLASS_POINT & point1,
378 const CLASS_POINT & dir2,
379 CLASS_POINT & point2,
383 GREAL e1e1 = VEC_DOT(dir1,dir1);
384 GREAL e1e2 = VEC_DOT(dir1,dir2);
385 GREAL e2e2 = VEC_DOT(dir2,dir2);
387 VEC_DIFF(p1p2,point1,point2);
388 GREAL p1p2e1 = VEC_DOT(p1p2,dir1);
389 GREAL p1p2e2 = VEC_DOT(p1p2,dir2);
390 det = e1e2*e1e2 - e1e1*e2e2;
391 if(GIM_IS_ZERO(det)) return false;
392 t1 = (e1e2*p1p2e2 - e2e2*p1p2e1)/det;
393 t2 = (e1e1*p1p2e2 - e1e2*p1p2e1)/det;
397 //! Find closest points on segments
398 template<typename CLASS_POINT>
399 SIMD_FORCE_INLINE void SEGMENT_COLLISION(
400 const CLASS_POINT & vA1,
401 const CLASS_POINT & vA2,
402 const CLASS_POINT & vB1,
403 const CLASS_POINT & vB2,
404 CLASS_POINT & vPointA,
405 CLASS_POINT & vPointB)
407 CLASS_POINT _AD,_BD,_N;
409 VEC_DIFF(_AD,vA2,vA1);
410 VEC_DIFF(_BD,vB2,vB1);
411 VEC_CROSS(_N,_AD,_BD);
412 GREAL _tp = VEC_DOT(_N,_N);
413 if(_tp<G_EPSILON)//ARE PARALELE
416 bool invert_b_order = false;
417 _M[0] = VEC_DOT(vB1,_AD);
418 _M[1] = VEC_DOT(vB2,_AD);
421 invert_b_order = true;
422 GIM_SWAP_NUMBERS(_M[0],_M[1]);
424 _M[2] = VEC_DOT(vA1,_AD);
425 _M[3] = VEC_DOT(vA2,_AD);
427 _N[0] = (_M[0]+_M[1])*0.5f;
428 _N[1] = (_M[2]+_M[3])*0.5f;
434 vPointB = invert_b_order?vB1:vB2;
439 vPointB = invert_b_order?vB1:vB2;
440 CLOSEST_POINT_ON_SEGMENT(vPointA,vPointB,vA1,vA2);
445 CLOSEST_POINT_ON_SEGMENT(vPointB,vPointA,vB1,vB2);
452 vPointB = invert_b_order?vB2:vB1;
458 CLOSEST_POINT_ON_SEGMENT(vPointB,vPointA,vB1,vB2);
462 vPointB = invert_b_order?vB1:vB2;
463 CLOSEST_POINT_ON_SEGMENT(vPointA,vPointB,vA1,vA2);
470 VEC_CROSS(_M,_N,_BD);
471 _M[3] = VEC_DOT(_M,vB1);
473 LINE_PLANE_COLLISION(_M,_AD,vA1,vPointA,_tp,btScalar(0), btScalar(1));
474 /*Closest point on segment*/
475 VEC_DIFF(vPointB,vPointA,vB1);
476 _tp = VEC_DOT(vPointB, _BD);
477 _tp/= VEC_DOT(_BD, _BD);
478 _tp = GIM_CLAMP(_tp,0.0f,1.0f);
479 VEC_SCALE(vPointB,_tp,_BD);
480 VEC_SUM(vPointB,vPointB,vB1);
486 //! Line box intersection in one dimension
489 *\param pos Position of the ray
490 *\param dir Projection of the Direction of the ray
491 *\param bmin Minimum bound of the box
492 *\param bmax Maximum bound of the box
493 *\param tfirst the minimum projection. Assign to 0 at first.
494 *\param tlast the maximum projection. Assign to INFINITY at first.
495 *\return true if there is an intersection.
498 SIMD_FORCE_INLINE bool BOX_AXIS_INTERSECT(T pos, T dir,T bmin, T bmax, T & tfirst, T & tlast)
502 return !(pos < bmin || pos > bmax);
504 GREAL a0 = (bmin - pos) / dir;
505 GREAL a1 = (bmax - pos) / dir;
506 if(a0 > a1) GIM_SWAP_NUMBERS(a0, a1);
507 tfirst = GIM_MAX(a0, tfirst);
508 tlast = GIM_MIN(a1, tlast);
509 if (tlast < tfirst) return false;
514 //! Sorts 3 componets
516 SIMD_FORCE_INLINE void SORT_3_INDICES(
518 GUINT * order_indices)
521 order_indices[0] = values[0] < values[1] ? (values[0] < values[2] ? 0 : 2) : (values[1] < values[2] ? 1 : 2);
523 //get second and third
524 GUINT i0 = (order_indices[0] + 1)%3;
525 GUINT i1 = (i0 + 1)%3;
527 if(values[i0] < values[i1])
529 order_indices[1] = i0;
530 order_indices[2] = i1;
534 order_indices[1] = i1;
535 order_indices[2] = i0;
543 #endif // GIM_VECTOR_H_INCLUDED