Home | History | Annotate | Download | only in Gimpact
      1 #ifndef GIM_BASIC_GEOMETRY_OPERATIONS_H_INCLUDED
      2 #define GIM_BASIC_GEOMETRY_OPERATIONS_H_INCLUDED
      3 
      4 /*! \file gim_basic_geometry_operations.h
      5 *\author Francisco Leon Najera
      6 type independant geometry routines
      7 
      8 */
      9 /*
     10 -----------------------------------------------------------------------------
     11 This source file is part of GIMPACT Library.
     12 
     13 For the latest info, see http://gimpact.sourceforge.net/
     14 
     15 Copyright (c) 2006 Francisco Leon Najera. C.C. 80087371.
     16 email: projectileman (at) yahoo.com
     17 
     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.
     29 
     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.
     34 
     35 -----------------------------------------------------------------------------
     36 */
     37 
     38 
     39 #include "gim_linear_math.h"
     40 
     41 
     42 
     43 
     44 
     45 #define PLANEDIREPSILON 0.0000001f
     46 #define PARALELENORMALS 0.000001f
     47 
     48 
     49 #define TRIANGLE_NORMAL(v1,v2,v3,n)\
     50 {\
     51 	vec3f _dif1,_dif2;\
     52     VEC_DIFF(_dif1,v2,v1);\
     53     VEC_DIFF(_dif2,v3,v1);\
     54     VEC_CROSS(n,_dif1,_dif2);\
     55     VEC_NORMALIZE(n);\
     56 }\
     57 
     58 #define TRIANGLE_NORMAL_FAST(v1,v2,v3,n){\
     59     vec3f _dif1,_dif2; \
     60     VEC_DIFF(_dif1,v2,v1); \
     61     VEC_DIFF(_dif2,v3,v1); \
     62     VEC_CROSS(n,_dif1,_dif2); \
     63 }\
     64 
     65 /// plane is a vec4f
     66 #define TRIANGLE_PLANE(v1,v2,v3,plane) {\
     67     TRIANGLE_NORMAL(v1,v2,v3,plane);\
     68     plane[3] = VEC_DOT(v1,plane);\
     69 }\
     70 
     71 /// plane is a vec4f
     72 #define TRIANGLE_PLANE_FAST(v1,v2,v3,plane) {\
     73     TRIANGLE_NORMAL_FAST(v1,v2,v3,plane);\
     74     plane[3] = VEC_DOT(v1,plane);\
     75 }\
     76 
     77 /// Calc a plane from an edge an a normal. plane is a vec4f
     78 #define EDGE_PLANE(e1,e2,n,plane) {\
     79     vec3f _dif; \
     80     VEC_DIFF(_dif,e2,e1); \
     81     VEC_CROSS(plane,_dif,n); \
     82     VEC_NORMALIZE(plane); \
     83     plane[3] = VEC_DOT(e1,plane);\
     84 }\
     85 
     86 #define DISTANCE_PLANE_POINT(plane,point) (VEC_DOT(plane,point) - plane[3])
     87 
     88 #define PROJECT_POINT_PLANE(point,plane,projected) {\
     89 	GREAL _dis;\
     90 	_dis = DISTANCE_PLANE_POINT(plane,point);\
     91 	VEC_SCALE(projected,-_dis,plane);\
     92 	VEC_SUM(projected,projected,point);	\
     93 }\
     94 
     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)
     99 {
    100 	GREAL _dis;
    101 	for (GUINT _i = 0;_i< plane_count;++_i)
    102 	{
    103 		_dis = DISTANCE_PLANE_POINT(planes[_i],point);
    104 	    if(_dis>0.0f) return false;
    105 	}
    106 	return true;
    107 }
    108 
    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)
    113 {
    114 	GREAL _dis1,_dis2;
    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);
    120 }
    121 
    122 enum ePLANE_INTERSECTION_TYPE
    123 {
    124 	G_BACK_PLANE = 0,
    125 	G_COLLIDE_PLANE,
    126 	G_FRONT_PLANE
    127 };
    128 
    129 enum eLINE_PLANE_INTERSECTION_TYPE
    130 {
    131 	G_FRONT_PLANE_S1 = 0,
    132 	G_FRONT_PLANE_S2,
    133 	G_BACK_PLANE_S1,
    134 	G_BACK_PLANE_S2,
    135 	G_COLLIDE_PLANE_S1,
    136 	G_COLLIDE_PLANE_S2
    137 };
    138 
    139 //! Confirms if the plane intersect the edge or nor
    140 /*!
    141 intersection type must have the following values
    142 <ul>
    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
    149 </ul>
    150 */
    151 
    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)
    157 {
    158 	GREAL _dis1 = DISTANCE_PLANE_POINT(plane,s1);
    159 	GREAL _dis2 = DISTANCE_PLANE_POINT(plane,s2);
    160 	if(_dis1 >-G_EPSILON && _dis2 >-G_EPSILON)
    161 	{
    162 	    if(_dis1<_dis2) return G_FRONT_PLANE_S1;
    163 	    return G_FRONT_PLANE_S2;
    164 	}
    165 	else if(_dis1 <G_EPSILON && _dis2 <G_EPSILON)
    166 	{
    167 	    if(_dis1>_dis2) return G_BACK_PLANE_S1;
    168 	    return G_BACK_PLANE_S2;
    169 	}
    170 
    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;
    177 }
    178 
    179 //! Confirms if the plane intersect the edge or not
    180 /*!
    181 clipped1 and clipped2 are the vertices behind the plane.
    182 clipped1 is the closest
    183 
    184 intersection_type must have the following values
    185 <ul>
    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
    192 </ul>
    193 */
    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)
    200 {
    201 	eLINE_PLANE_INTERSECTION_TYPE intersection_type = PLANE_CLIP_SEGMENT2(s1,s2,plane,clipped1);
    202 	switch(intersection_type)
    203 	{
    204 	case G_FRONT_PLANE_S1:
    205 		VEC_COPY(clipped1,s1);
    206 	    VEC_COPY(clipped2,s2);
    207 		break;
    208 	case G_FRONT_PLANE_S2:
    209 		VEC_COPY(clipped1,s2);
    210 	    VEC_COPY(clipped2,s1);
    211 		break;
    212 	case G_BACK_PLANE_S1:
    213 		VEC_COPY(clipped1,s1);
    214 	    VEC_COPY(clipped2,s2);
    215 		break;
    216 	case G_BACK_PLANE_S2:
    217 		VEC_COPY(clipped1,s2);
    218 	    VEC_COPY(clipped2,s1);
    219 		break;
    220 	case G_COLLIDE_PLANE_S1:
    221 		VEC_COPY(clipped2,s1);
    222 		break;
    223 	case G_COLLIDE_PLANE_S2:
    224 		VEC_COPY(clipped2,s2);
    225 		break;
    226 	}
    227 	return intersection_type;
    228 }
    229 
    230 
    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)
    233 
    234 //! Ray plane collision in one way
    235 /*!
    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.
    238 */
    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)
    245 {
    246 	GREAL _dis,_dotdir;
    247 	_dotdir = VEC_DOT(plane,vDir);
    248 	if(_dotdir<PLANEDIREPSILON)
    249 	{
    250 	    return false;
    251 	}
    252 	_dis = DISTANCE_PLANE_POINT(plane,vPoint);
    253 	tparam = -_dis/_dotdir;
    254 	VEC_SCALE(pout,tparam,vDir);
    255 	VEC_SUM(pout,vPoint,pout);
    256 	return true;
    257 }
    258 
    259 //! line collision
    260 /*!
    261 *\return
    262 	-0  if the ray never intersects
    263 	-1 if the ray collides in front
    264 	-2 if the ray collides in back
    265 */
    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,
    271 	CLASS_POINT & pout,
    272 	T &tparam,
    273 	T tmin, T tmax)
    274 {
    275 	GREAL _dis,_dotdir;
    276 	_dotdir = VEC_DOT(plane,vDir);
    277 	if(btFabs(_dotdir)<PLANEDIREPSILON)
    278 	{
    279 		tparam = tmax;
    280 	    return 0;
    281 	}
    282 	_dis = DISTANCE_PLANE_POINT(plane,vPoint);
    283 	char returnvalue = _dis<0.0f?2:1;
    284 	tparam = -_dis/_dotdir;
    285 
    286 	if(tparam<tmin)
    287 	{
    288 		returnvalue = 0;
    289 		tparam = tmin;
    290 	}
    291 	else if(tparam>tmax)
    292 	{
    293 		returnvalue = 0;
    294 		tparam = tmax;
    295 	}
    296 
    297 	VEC_SCALE(pout,tparam,vDir);
    298 	VEC_SUM(pout,vPoint,pout);
    299 	return returnvalue;
    300 }
    301 
    302 /*! \brief Returns the Ray on which 2 planes intersect if they do.
    303     Written by Rodrigo Hernandez on ODE convex collision
    304 
    305   \param p1 Plane 1
    306   \param p2 Plane 2
    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.
    310 
    311 */
    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,
    316 		CLASS_POINT &p,
    317 		CLASS_POINT &d)
    318 {
    319 	VEC_CROSS(d,p1,p2);
    320   	GREAL denom = VEC_DOT(d, d);
    321   	if(GIM_IS_ZERO(denom)) return false;
    322 	vec3f _n;
    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];
    326 	VEC_CROSS(p,_n,d);
    327 	p[0]/=denom;
    328 	p[1]/=denom;
    329 	p[2]/=denom;
    330 	return true;
    331 }
    332 
    333 //***************** SEGMENT and LINE FUNCTIONS **********************************///
    334 
    335 /*! Finds the closest point(cp) to (v) on a segment (e1,e2)
    336  */
    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)
    341 {
    342     vec3f _n;
    343     VEC_DIFF(_n,e2,e1);
    344     VEC_DIFF(cp,v,e1);
    345 	GREAL _scalar = VEC_DOT(cp, _n);
    346 	_scalar/= VEC_DOT(_n, _n);
    347 	if(_scalar <0.0f)
    348 	{
    349 	    VEC_COPY(cp,e1);
    350 	}
    351 	else if(_scalar >1.0f)
    352 	{
    353 	    VEC_COPY(cp,e2);
    354 	}
    355 	else
    356 	{
    357         VEC_SCALE(cp,_scalar,_n);
    358         VEC_SUM(cp,cp,e1);
    359 	}
    360 }
    361 
    362 
    363 /*! \brief Finds the line params where these lines intersect.
    364 
    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
    372 
    373 */
    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,
    380 	T& t1,T& t2)
    381 {
    382     GREAL det;
    383 	GREAL e1e1 = VEC_DOT(dir1,dir1);
    384 	GREAL e1e2 = VEC_DOT(dir1,dir2);
    385 	GREAL e2e2 = VEC_DOT(dir2,dir2);
    386 	vec3f p1p2;
    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;
    394 	return true;
    395 }
    396 
    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)
    406 {
    407     CLASS_POINT _AD,_BD,n;
    408     vec4f _M;//plane
    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
    414     {
    415     	//project B over A
    416     	bool invert_b_order = false;
    417     	_M[0] = VEC_DOT(vB1,_AD);
    418     	_M[1] = VEC_DOT(vB2,_AD);
    419     	if(_M[0]>_M[1])
    420     	{
    421     		invert_b_order  = true;
    422     		GIM_SWAP_NUMBERS(_M[0],_M[1]);
    423     	}
    424     	_M[2] = VEC_DOT(vA1,_AD);
    425     	_M[3] = VEC_DOT(vA2,_AD);
    426     	//mid points
    427     	n[0] = (_M[0]+_M[1])*0.5f;
    428     	n[1] = (_M[2]+_M[3])*0.5f;
    429 
    430     	if(n[0]<n[1])
    431     	{
    432     		if(_M[1]<_M[2])
    433     		{
    434     			vPointB = invert_b_order?vB1:vB2;
    435     			vPointA = vA1;
    436     		}
    437     		else if(_M[1]<_M[3])
    438     		{
    439     			vPointB = invert_b_order?vB1:vB2;
    440     			CLOSEST_POINT_ON_SEGMENT(vPointA,vPointB,vA1,vA2);
    441     		}
    442     		else
    443     		{
    444     			vPointA = vA2;
    445     			CLOSEST_POINT_ON_SEGMENT(vPointB,vPointA,vB1,vB2);
    446     		}
    447     	}
    448     	else
    449     	{
    450     		if(_M[3]<_M[0])
    451     		{
    452     			vPointB = invert_b_order?vB2:vB1;
    453     			vPointA = vA2;
    454     		}
    455     		else if(_M[3]<_M[1])
    456     		{
    457     			vPointA = vA2;
    458     			CLOSEST_POINT_ON_SEGMENT(vPointB,vPointA,vB1,vB2);
    459     		}
    460     		else
    461     		{
    462     			vPointB = invert_b_order?vB1:vB2;
    463     			CLOSEST_POINT_ON_SEGMENT(vPointA,vPointB,vA1,vA2);
    464     		}
    465     	}
    466     	return;
    467     }
    468 
    469 
    470     VEC_CROSS(_M,n,_BD);
    471     _M[3] = VEC_DOT(_M,vB1);
    472 
    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);
    481 }
    482 
    483 
    484 
    485 
    486 //! Line box intersection in one dimension
    487 /*!
    488 
    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.
    496 */
    497 template<typename T>
    498 SIMD_FORCE_INLINE bool BOX_AXIS_INTERSECT(T pos, T dir,T bmin, T bmax, T & tfirst, T & tlast)
    499 {
    500 	if(GIM_IS_ZERO(dir))
    501 	{
    502         return !(pos < bmin || pos > bmax);
    503 	}
    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;
    510 	return true;
    511 }
    512 
    513 
    514 //! Sorts 3 componets
    515 template<typename T>
    516 SIMD_FORCE_INLINE void SORT_3_INDICES(
    517 		const T * values,
    518 		GUINT * order_indices)
    519 {
    520 	//get minimum
    521 	order_indices[0] = values[0] < values[1] ? (values[0] < values[2] ? 0 : 2) : (values[1] < values[2] ? 1 : 2);
    522 
    523 	//get second and third
    524 	GUINT i0 = (order_indices[0] + 1)%3;
    525 	GUINT i1 = (i0 + 1)%3;
    526 
    527 	if(values[i0] < values[i1])
    528 	{
    529 		order_indices[1] = i0;
    530 		order_indices[2] = i1;
    531 	}
    532 	else
    533 	{
    534 		order_indices[1] = i1;
    535 		order_indices[2] = i0;
    536 	}
    537 }
    538 
    539 
    540 
    541 
    542 
    543 #endif // GIM_VECTOR_H_INCLUDED
    544