| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543 |
- #ifndef GIM_BASIC_GEOMETRY_OPERATIONS_H_INCLUDED
- #define GIM_BASIC_GEOMETRY_OPERATIONS_H_INCLUDED
- /*! \file gim_basic_geometry_operations.h
- *\author Francisco Leon Najera
- type independant geometry routines
- */
- /*
- -----------------------------------------------------------------------------
- This source file is part of GIMPACT Library.
- For the latest info, see http://gimpact.sourceforge.net/
- Copyright (c) 2006 Francisco Leon Najera. C.C. 80087371.
- email: [email protected]
- This library is free software; you can redistribute it and/or
- modify it under the terms of EITHER:
- (1) The GNU Lesser General Public License as published by the Free
- Software Foundation; either version 2.1 of the License, or (at
- your option) any later version. The text of the GNU Lesser
- General Public License is included with this library in the
- file GIMPACT-LICENSE-LGPL.TXT.
- (2) The BSD-style license that is included with this library in
- the file GIMPACT-LICENSE-BSD.TXT.
- (3) The zlib/libpng license that is included with this library in
- the file GIMPACT-LICENSE-ZLIB.TXT.
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files
- GIMPACT-LICENSE-LGPL.TXT, GIMPACT-LICENSE-ZLIB.TXT and GIMPACT-LICENSE-BSD.TXT for more details.
- -----------------------------------------------------------------------------
- */
- #include "gim_linear_math.h"
- #define PLANEDIREPSILON 0.0000001f
- #define PARALELENORMALS 0.000001f
- #define TRIANGLE_NORMAL(v1,v2,v3,n)\
- {\
- vec3f _dif1,_dif2;\
- VEC_DIFF(_dif1,v2,v1);\
- VEC_DIFF(_dif2,v3,v1);\
- VEC_CROSS(n,_dif1,_dif2);\
- VEC_NORMALIZE(n);\
- }\
- #define TRIANGLE_NORMAL_FAST(v1,v2,v3,n){\
- vec3f _dif1,_dif2; \
- VEC_DIFF(_dif1,v2,v1); \
- VEC_DIFF(_dif2,v3,v1); \
- VEC_CROSS(n,_dif1,_dif2); \
- }\
- /// plane is a vec4f
- #define TRIANGLE_PLANE(v1,v2,v3,plane) {\
- TRIANGLE_NORMAL(v1,v2,v3,plane);\
- plane[3] = VEC_DOT(v1,plane);\
- }\
- /// plane is a vec4f
- #define TRIANGLE_PLANE_FAST(v1,v2,v3,plane) {\
- TRIANGLE_NORMAL_FAST(v1,v2,v3,plane);\
- plane[3] = VEC_DOT(v1,plane);\
- }\
- /// Calc a plane from an edge an a normal. plane is a vec4f
- #define EDGE_PLANE(e1,e2,n,plane) {\
- vec3f _dif; \
- VEC_DIFF(_dif,e2,e1); \
- VEC_CROSS(plane,_dif,n); \
- VEC_NORMALIZE(plane); \
- plane[3] = VEC_DOT(e1,plane);\
- }\
- #define DISTANCE_PLANE_POINT(plane,point) (VEC_DOT(plane,point) - plane[3])
- #define PROJECT_POINT_PLANE(point,plane,projected) {\
- GREAL _dis;\
- _dis = DISTANCE_PLANE_POINT(plane,point);\
- VEC_SCALE(projected,-_dis,plane);\
- VEC_SUM(projected,projected,point); \
- }\
- //! Verifies if a point is in the plane hull
- template<typename CLASS_POINT,typename CLASS_PLANE>
- SIMD_FORCE_INLINE bool POINT_IN_HULL(
- const CLASS_POINT& point,const CLASS_PLANE * planes,GUINT plane_count)
- {
- GREAL _dis;
- for (GUINT _i = 0;_i< plane_count;++_i)
- {
- _dis = DISTANCE_PLANE_POINT(planes[_i],point);
- if(_dis>0.0f) return false;
- }
- return true;
- }
- template<typename CLASS_POINT,typename CLASS_PLANE>
- SIMD_FORCE_INLINE void PLANE_CLIP_SEGMENT(
- const CLASS_POINT& s1,
- const CLASS_POINT &s2,const CLASS_PLANE &plane,CLASS_POINT &clipped)
- {
- GREAL _dis1,_dis2;
- _dis1 = DISTANCE_PLANE_POINT(plane,s1);
- VEC_DIFF(clipped,s2,s1);
- _dis2 = VEC_DOT(clipped,plane);
- VEC_SCALE(clipped,-_dis1/_dis2,clipped);
- VEC_SUM(clipped,clipped,s1);
- }
- enum ePLANE_INTERSECTION_TYPE
- {
- G_BACK_PLANE = 0,
- G_COLLIDE_PLANE,
- G_FRONT_PLANE
- };
- enum eLINE_PLANE_INTERSECTION_TYPE
- {
- G_FRONT_PLANE_S1 = 0,
- G_FRONT_PLANE_S2,
- G_BACK_PLANE_S1,
- G_BACK_PLANE_S2,
- G_COLLIDE_PLANE_S1,
- G_COLLIDE_PLANE_S2
- };
- //! Confirms if the plane intersect the edge or nor
- /*!
- intersection type must have the following values
- <ul>
- <li> 0 : Segment in front of plane, s1 closest
- <li> 1 : Segment in front of plane, s2 closest
- <li> 2 : Segment in back of plane, s1 closest
- <li> 3 : Segment in back of plane, s2 closest
- <li> 4 : Segment collides plane, s1 in back
- <li> 5 : Segment collides plane, s2 in back
- </ul>
- */
- template<typename CLASS_POINT,typename CLASS_PLANE>
- SIMD_FORCE_INLINE eLINE_PLANE_INTERSECTION_TYPE PLANE_CLIP_SEGMENT2(
- const CLASS_POINT& s1,
- const CLASS_POINT &s2,
- const CLASS_PLANE &plane,CLASS_POINT &clipped)
- {
- GREAL _dis1 = DISTANCE_PLANE_POINT(plane,s1);
- GREAL _dis2 = DISTANCE_PLANE_POINT(plane,s2);
- if(_dis1 >-G_EPSILON && _dis2 >-G_EPSILON)
- {
- if(_dis1<_dis2) return G_FRONT_PLANE_S1;
- return G_FRONT_PLANE_S2;
- }
- else if(_dis1 <G_EPSILON && _dis2 <G_EPSILON)
- {
- if(_dis1>_dis2) return G_BACK_PLANE_S1;
- return G_BACK_PLANE_S2;
- }
- VEC_DIFF(clipped,s2,s1);
- _dis2 = VEC_DOT(clipped,plane);
- VEC_SCALE(clipped,-_dis1/_dis2,clipped);
- VEC_SUM(clipped,clipped,s1);
- if(_dis1<_dis2) return G_COLLIDE_PLANE_S1;
- return G_COLLIDE_PLANE_S2;
- }
- //! Confirms if the plane intersect the edge or not
- /*!
- clipped1 and clipped2 are the vertices behind the plane.
- clipped1 is the closest
- intersection_type must have the following values
- <ul>
- <li> 0 : Segment in front of plane, s1 closest
- <li> 1 : Segment in front of plane, s2 closest
- <li> 2 : Segment in back of plane, s1 closest
- <li> 3 : Segment in back of plane, s2 closest
- <li> 4 : Segment collides plane, s1 in back
- <li> 5 : Segment collides plane, s2 in back
- </ul>
- */
- template<typename CLASS_POINT,typename CLASS_PLANE>
- SIMD_FORCE_INLINE eLINE_PLANE_INTERSECTION_TYPE PLANE_CLIP_SEGMENT_CLOSEST(
- const CLASS_POINT& s1,
- const CLASS_POINT &s2,
- const CLASS_PLANE &plane,
- CLASS_POINT &clipped1,CLASS_POINT &clipped2)
- {
- eLINE_PLANE_INTERSECTION_TYPE intersection_type = PLANE_CLIP_SEGMENT2(s1,s2,plane,clipped1);
- switch(intersection_type)
- {
- case G_FRONT_PLANE_S1:
- VEC_COPY(clipped1,s1);
- VEC_COPY(clipped2,s2);
- break;
- case G_FRONT_PLANE_S2:
- VEC_COPY(clipped1,s2);
- VEC_COPY(clipped2,s1);
- break;
- case G_BACK_PLANE_S1:
- VEC_COPY(clipped1,s1);
- VEC_COPY(clipped2,s2);
- break;
- case G_BACK_PLANE_S2:
- VEC_COPY(clipped1,s2);
- VEC_COPY(clipped2,s1);
- break;
- case G_COLLIDE_PLANE_S1:
- VEC_COPY(clipped2,s1);
- break;
- case G_COLLIDE_PLANE_S2:
- VEC_COPY(clipped2,s2);
- break;
- }
- return intersection_type;
- }
- //! Finds the 2 smallest cartesian coordinates of a plane normal
- #define PLANE_MINOR_AXES(plane, i0, i1) VEC_MINOR_AXES(plane, i0, i1)
- //! Ray plane collision in one way
- /*!
- Intersects plane in one way only. The ray must face the plane (normals must be in opossite directions).<br/>
- It uses the PLANEDIREPSILON constant.
- */
- template<typename T,typename CLASS_POINT,typename CLASS_PLANE>
- SIMD_FORCE_INLINE bool RAY_PLANE_COLLISION(
- const CLASS_PLANE & plane,
- const CLASS_POINT & vDir,
- const CLASS_POINT & vPoint,
- CLASS_POINT & pout,T &tparam)
- {
- GREAL _dis,_dotdir;
- _dotdir = VEC_DOT(plane,vDir);
- if(_dotdir<PLANEDIREPSILON)
- {
- return false;
- }
- _dis = DISTANCE_PLANE_POINT(plane,vPoint);
- tparam = -_dis/_dotdir;
- VEC_SCALE(pout,tparam,vDir);
- VEC_SUM(pout,vPoint,pout);
- return true;
- }
- //! line collision
- /*!
- *\return
- -0 if the ray never intersects
- -1 if the ray collides in front
- -2 if the ray collides in back
- */
- template<typename T,typename CLASS_POINT,typename CLASS_PLANE>
- SIMD_FORCE_INLINE GUINT LINE_PLANE_COLLISION(
- const CLASS_PLANE & plane,
- const CLASS_POINT & vDir,
- const CLASS_POINT & vPoint,
- CLASS_POINT & pout,
- T &tparam,
- T tmin, T tmax)
- {
- GREAL _dis,_dotdir;
- _dotdir = VEC_DOT(plane,vDir);
- if(btFabs(_dotdir)<PLANEDIREPSILON)
- {
- tparam = tmax;
- return 0;
- }
- _dis = DISTANCE_PLANE_POINT(plane,vPoint);
- char returnvalue = _dis<0.0f?2:1;
- tparam = -_dis/_dotdir;
- if(tparam<tmin)
- {
- returnvalue = 0;
- tparam = tmin;
- }
- else if(tparam>tmax)
- {
- returnvalue = 0;
- tparam = tmax;
- }
- VEC_SCALE(pout,tparam,vDir);
- VEC_SUM(pout,vPoint,pout);
- return returnvalue;
- }
- /*! \brief Returns the Ray on which 2 planes intersect if they do.
- Written by Rodrigo Hernandez on ODE convex collision
- \param p1 Plane 1
- \param p2 Plane 2
- \param p Contains the origin of the ray upon returning if planes intersect
- \param d Contains the direction of the ray upon returning if planes intersect
- \return true if the planes intersect, 0 if paralell.
- */
- template<typename CLASS_POINT,typename CLASS_PLANE>
- SIMD_FORCE_INLINE bool INTERSECT_PLANES(
- const CLASS_PLANE &p1,
- const CLASS_PLANE &p2,
- CLASS_POINT &p,
- CLASS_POINT &d)
- {
- VEC_CROSS(d,p1,p2);
- GREAL denom = VEC_DOT(d, d);
- if(GIM_IS_ZERO(denom)) return false;
- vec3f _n;
- _n[0]=p1[3]*p2[0] - p2[3]*p1[0];
- _n[1]=p1[3]*p2[1] - p2[3]*p1[1];
- _n[2]=p1[3]*p2[2] - p2[3]*p1[2];
- VEC_CROSS(p,_n,d);
- p[0]/=denom;
- p[1]/=denom;
- p[2]/=denom;
- return true;
- }
- //***************** SEGMENT and LINE FUNCTIONS **********************************///
- /*! Finds the closest point(cp) to (v) on a segment (e1,e2)
- */
- template<typename CLASS_POINT>
- SIMD_FORCE_INLINE void CLOSEST_POINT_ON_SEGMENT(
- CLASS_POINT & cp, const CLASS_POINT & v,
- const CLASS_POINT &e1,const CLASS_POINT &e2)
- {
- vec3f _n;
- VEC_DIFF(_n,e2,e1);
- VEC_DIFF(cp,v,e1);
- GREAL _scalar = VEC_DOT(cp, _n);
- _scalar/= VEC_DOT(_n, _n);
- if(_scalar <0.0f)
- {
- VEC_COPY(cp,e1);
- }
- else if(_scalar >1.0f)
- {
- VEC_COPY(cp,e2);
- }
- else
- {
- VEC_SCALE(cp,_scalar,_n);
- VEC_SUM(cp,cp,e1);
- }
- }
- /*! \brief Finds the line params where these lines intersect.
- \param dir1 Direction of line 1
- \param point1 Point of line 1
- \param dir2 Direction of line 2
- \param point2 Point of line 2
- \param t1 Result Parameter for line 1
- \param t2 Result Parameter for line 2
- \param dointersect 0 if the lines won't intersect, else 1
- */
- template<typename T,typename CLASS_POINT>
- SIMD_FORCE_INLINE bool LINE_INTERSECTION_PARAMS(
- const CLASS_POINT & dir1,
- CLASS_POINT & point1,
- const CLASS_POINT & dir2,
- CLASS_POINT & point2,
- T& t1,T& t2)
- {
- GREAL det;
- GREAL e1e1 = VEC_DOT(dir1,dir1);
- GREAL e1e2 = VEC_DOT(dir1,dir2);
- GREAL e2e2 = VEC_DOT(dir2,dir2);
- vec3f p1p2;
- VEC_DIFF(p1p2,point1,point2);
- GREAL p1p2e1 = VEC_DOT(p1p2,dir1);
- GREAL p1p2e2 = VEC_DOT(p1p2,dir2);
- det = e1e2*e1e2 - e1e1*e2e2;
- if(GIM_IS_ZERO(det)) return false;
- t1 = (e1e2*p1p2e2 - e2e2*p1p2e1)/det;
- t2 = (e1e1*p1p2e2 - e1e2*p1p2e1)/det;
- return true;
- }
- //! Find closest points on segments
- template<typename CLASS_POINT>
- SIMD_FORCE_INLINE void SEGMENT_COLLISION(
- const CLASS_POINT & vA1,
- const CLASS_POINT & vA2,
- const CLASS_POINT & vB1,
- const CLASS_POINT & vB2,
- CLASS_POINT & vPointA,
- CLASS_POINT & vPointB)
- {
- CLASS_POINT _AD,_BD,n;
- vec4f _M;//plane
- VEC_DIFF(_AD,vA2,vA1);
- VEC_DIFF(_BD,vB2,vB1);
- VEC_CROSS(n,_AD,_BD);
- GREAL _tp = VEC_DOT(n,n);
- if(_tp<G_EPSILON)//ARE PARALELE
- {
- //project B over A
- bool invert_b_order = false;
- _M[0] = VEC_DOT(vB1,_AD);
- _M[1] = VEC_DOT(vB2,_AD);
- if(_M[0]>_M[1])
- {
- invert_b_order = true;
- GIM_SWAP_NUMBERS(_M[0],_M[1]);
- }
- _M[2] = VEC_DOT(vA1,_AD);
- _M[3] = VEC_DOT(vA2,_AD);
- //mid points
- n[0] = (_M[0]+_M[1])*0.5f;
- n[1] = (_M[2]+_M[3])*0.5f;
- if(n[0]<n[1])
- {
- if(_M[1]<_M[2])
- {
- vPointB = invert_b_order?vB1:vB2;
- vPointA = vA1;
- }
- else if(_M[1]<_M[3])
- {
- vPointB = invert_b_order?vB1:vB2;
- CLOSEST_POINT_ON_SEGMENT(vPointA,vPointB,vA1,vA2);
- }
- else
- {
- vPointA = vA2;
- CLOSEST_POINT_ON_SEGMENT(vPointB,vPointA,vB1,vB2);
- }
- }
- else
- {
- if(_M[3]<_M[0])
- {
- vPointB = invert_b_order?vB2:vB1;
- vPointA = vA2;
- }
- else if(_M[3]<_M[1])
- {
- vPointA = vA2;
- CLOSEST_POINT_ON_SEGMENT(vPointB,vPointA,vB1,vB2);
- }
- else
- {
- vPointB = invert_b_order?vB1:vB2;
- CLOSEST_POINT_ON_SEGMENT(vPointA,vPointB,vA1,vA2);
- }
- }
- return;
- }
- VEC_CROSS(_M,n,_BD);
- _M[3] = VEC_DOT(_M,vB1);
- LINE_PLANE_COLLISION(_M,_AD,vA1,vPointA,_tp,btScalar(0), btScalar(1));
- /*Closest point on segment*/
- VEC_DIFF(vPointB,vPointA,vB1);
- _tp = VEC_DOT(vPointB, _BD);
- _tp/= VEC_DOT(_BD, _BD);
- _tp = GIM_CLAMP(_tp,0.0f,1.0f);
- VEC_SCALE(vPointB,_tp,_BD);
- VEC_SUM(vPointB,vPointB,vB1);
- }
- //! Line box intersection in one dimension
- /*!
- *\param pos Position of the ray
- *\param dir Projection of the Direction of the ray
- *\param bmin Minimum bound of the box
- *\param bmax Maximum bound of the box
- *\param tfirst the minimum projection. Assign to 0 at first.
- *\param tlast the maximum projection. Assign to INFINITY at first.
- *\return true if there is an intersection.
- */
- template<typename T>
- SIMD_FORCE_INLINE bool BOX_AXIS_INTERSECT(T pos, T dir,T bmin, T bmax, T & tfirst, T & tlast)
- {
- if(GIM_IS_ZERO(dir))
- {
- return !(pos < bmin || pos > bmax);
- }
- GREAL a0 = (bmin - pos) / dir;
- GREAL a1 = (bmax - pos) / dir;
- if(a0 > a1) GIM_SWAP_NUMBERS(a0, a1);
- tfirst = GIM_MAX(a0, tfirst);
- tlast = GIM_MIN(a1, tlast);
- if (tlast < tfirst) return false;
- return true;
- }
- //! Sorts 3 componets
- template<typename T>
- SIMD_FORCE_INLINE void SORT_3_INDICES(
- const T * values,
- GUINT * order_indices)
- {
- //get minimum
- order_indices[0] = values[0] < values[1] ? (values[0] < values[2] ? 0 : 2) : (values[1] < values[2] ? 1 : 2);
- //get second and third
- GUINT i0 = (order_indices[0] + 1)%3;
- GUINT i1 = (i0 + 1)%3;
- if(values[i0] < values[i1])
- {
- order_indices[1] = i0;
- order_indices[2] = i1;
- }
- else
- {
- order_indices[1] = i1;
- order_indices[2] = i0;
- }
- }
- #endif // GIM_VECTOR_H_INCLUDED
|