1 /* Copyright (c) 2013 Scott Lembcke and Howling Moon Software
2  *
3  * Permission is hereby granted, free of charge, to any person obtaining a copy
4  * of this software and associated documentation files (the "Software"), to deal
5  * in the Software without restriction, including without limitation the rights
6  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7  * copies of the Software, and to permit persons to whom the Software is
8  * furnished to do so, subject to the following conditions:
9  *
10  * The above copyright notice and this permission notice shall be included in
11  * all copies or substantial portions of the Software.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19  * SOFTWARE.
20  */
21 
22 #ifndef CHIPMUNK_VECT_H
23 #define CHIPMUNK_VECT_H
24 
25 #include "chipmunk_types.h"
26 
27 /// @defgroup cpVect cpVect
28 /// Chipmunk's 2D vector type along with a handy 2D vector math lib.
29 /// @{
30 
31 /// Constant for the zero vector.
32 static const cpVect cpvzero = {0.0f,0.0f};
33 
34 /// Convenience constructor for cpVect structs.
cpv(const cpFloat x,const cpFloat y)35 static inline cpVect cpv(const cpFloat x, const cpFloat y)
36 {
37 	cpVect v = {x, y};
38 	return v;
39 }
40 
41 /// Check if two vectors are equal. (Be careful when comparing floating point numbers!)
cpveql(const cpVect v1,const cpVect v2)42 static inline cpBool cpveql(const cpVect v1, const cpVect v2)
43 {
44 	return (v1.x == v2.x && v1.y == v2.y);
45 }
46 
47 /// Add two vectors
cpvadd(const cpVect v1,const cpVect v2)48 static inline cpVect cpvadd(const cpVect v1, const cpVect v2)
49 {
50 	return cpv(v1.x + v2.x, v1.y + v2.y);
51 }
52 
53 /// Subtract two vectors.
cpvsub(const cpVect v1,const cpVect v2)54 static inline cpVect cpvsub(const cpVect v1, const cpVect v2)
55 {
56 	return cpv(v1.x - v2.x, v1.y - v2.y);
57 }
58 
59 /// Negate a vector.
cpvneg(const cpVect v)60 static inline cpVect cpvneg(const cpVect v)
61 {
62 	return cpv(-v.x, -v.y);
63 }
64 
65 /// Scalar multiplication.
cpvmult(const cpVect v,const cpFloat s)66 static inline cpVect cpvmult(const cpVect v, const cpFloat s)
67 {
68 	return cpv(v.x*s, v.y*s);
69 }
70 
71 /// Vector dot product.
cpvdot(const cpVect v1,const cpVect v2)72 static inline cpFloat cpvdot(const cpVect v1, const cpVect v2)
73 {
74 	return v1.x*v2.x + v1.y*v2.y;
75 }
76 
77 /// 2D vector cross product analog.
78 /// The cross product of 2D vectors results in a 3D vector with only a z component.
79 /// This function returns the magnitude of the z value.
cpvcross(const cpVect v1,const cpVect v2)80 static inline cpFloat cpvcross(const cpVect v1, const cpVect v2)
81 {
82 	return v1.x*v2.y - v1.y*v2.x;
83 }
84 
85 /// Returns a perpendicular vector. (90 degree rotation)
cpvperp(const cpVect v)86 static inline cpVect cpvperp(const cpVect v)
87 {
88 	return cpv(-v.y, v.x);
89 }
90 
91 /// Returns a perpendicular vector. (-90 degree rotation)
cpvrperp(const cpVect v)92 static inline cpVect cpvrperp(const cpVect v)
93 {
94 	return cpv(v.y, -v.x);
95 }
96 
97 /// Returns the vector projection of v1 onto v2.
cpvproject(const cpVect v1,const cpVect v2)98 static inline cpVect cpvproject(const cpVect v1, const cpVect v2)
99 {
100 	return cpvmult(v2, cpvdot(v1, v2)/cpvdot(v2, v2));
101 }
102 
103 /// Returns the unit length vector for the given angle (in radians).
cpvforangle(const cpFloat a)104 static inline cpVect cpvforangle(const cpFloat a)
105 {
106 	return cpv(cpfcos(a), cpfsin(a));
107 }
108 
109 /// Returns the angular direction v is pointing in (in radians).
cpvtoangle(const cpVect v)110 static inline cpFloat cpvtoangle(const cpVect v)
111 {
112 	return cpfatan2(v.y, v.x);
113 }
114 
115 /// Uses complex number multiplication to rotate v1 by v2. Scaling will occur if v1 is not a unit vector.
cpvrotate(const cpVect v1,const cpVect v2)116 static inline cpVect cpvrotate(const cpVect v1, const cpVect v2)
117 {
118 	return cpv(v1.x*v2.x - v1.y*v2.y, v1.x*v2.y + v1.y*v2.x);
119 }
120 
121 /// Inverse of cpvrotate().
cpvunrotate(const cpVect v1,const cpVect v2)122 static inline cpVect cpvunrotate(const cpVect v1, const cpVect v2)
123 {
124 	return cpv(v1.x*v2.x + v1.y*v2.y, v1.y*v2.x - v1.x*v2.y);
125 }
126 
127 /// Returns the squared length of v. Faster than cpvlength() when you only need to compare lengths.
cpvlengthsq(const cpVect v)128 static inline cpFloat cpvlengthsq(const cpVect v)
129 {
130 	return cpvdot(v, v);
131 }
132 
133 /// Returns the length of v.
cpvlength(const cpVect v)134 static inline cpFloat cpvlength(const cpVect v)
135 {
136 	return cpfsqrt(cpvdot(v, v));
137 }
138 
139 /// Linearly interpolate between v1 and v2.
cpvlerp(const cpVect v1,const cpVect v2,const cpFloat t)140 static inline cpVect cpvlerp(const cpVect v1, const cpVect v2, const cpFloat t)
141 {
142 	return cpvadd(cpvmult(v1, 1.0f - t), cpvmult(v2, t));
143 }
144 
145 /// Returns a normalized copy of v.
cpvnormalize(const cpVect v)146 static inline cpVect cpvnormalize(const cpVect v)
147 {
148 	// Neat trick I saw somewhere to avoid div/0.
149 	return cpvmult(v, 1.0f/(cpvlength(v) + CPFLOAT_MIN));
150 }
151 
152 /// Spherical linearly interpolate between v1 and v2.
153 static inline cpVect
cpvslerp(const cpVect v1,const cpVect v2,const cpFloat t)154 cpvslerp(const cpVect v1, const cpVect v2, const cpFloat t)
155 {
156 	cpFloat dot = cpvdot(cpvnormalize(v1), cpvnormalize(v2));
157 	cpFloat omega = cpfacos(cpfclamp(dot, -1.0f, 1.0f));
158 
159 	if(omega < 1e-3){
160 		// If the angle between two vectors is very small, lerp instead to avoid precision issues.
161 		return cpvlerp(v1, v2, t);
162 	} else {
163 		cpFloat denom = 1.0f/cpfsin(omega);
164 		return cpvadd(cpvmult(v1, cpfsin((1.0f - t)*omega)*denom), cpvmult(v2, cpfsin(t*omega)*denom));
165 	}
166 }
167 
168 /// Spherical linearly interpolate between v1 towards v2 by no more than angle a radians
169 static inline cpVect
cpvslerpconst(const cpVect v1,const cpVect v2,const cpFloat a)170 cpvslerpconst(const cpVect v1, const cpVect v2, const cpFloat a)
171 {
172 	cpFloat dot = cpvdot(cpvnormalize(v1), cpvnormalize(v2));
173 	cpFloat omega = cpfacos(cpfclamp(dot, -1.0f, 1.0f));
174 
175 	return cpvslerp(v1, v2, cpfmin(a, omega)/omega);
176 }
177 
178 /// Clamp v to length len.
cpvclamp(const cpVect v,const cpFloat len)179 static inline cpVect cpvclamp(const cpVect v, const cpFloat len)
180 {
181 	return (cpvdot(v,v) > len*len) ? cpvmult(cpvnormalize(v), len) : v;
182 }
183 
184 /// Linearly interpolate between v1 towards v2 by distance d.
cpvlerpconst(cpVect v1,cpVect v2,cpFloat d)185 static inline cpVect cpvlerpconst(cpVect v1, cpVect v2, cpFloat d)
186 {
187 	return cpvadd(v1, cpvclamp(cpvsub(v2, v1), d));
188 }
189 
190 /// Returns the distance between v1 and v2.
cpvdist(const cpVect v1,const cpVect v2)191 static inline cpFloat cpvdist(const cpVect v1, const cpVect v2)
192 {
193 	return cpvlength(cpvsub(v1, v2));
194 }
195 
196 /// Returns the squared distance between v1 and v2. Faster than cpvdist() when you only need to compare distances.
cpvdistsq(const cpVect v1,const cpVect v2)197 static inline cpFloat cpvdistsq(const cpVect v1, const cpVect v2)
198 {
199 	return cpvlengthsq(cpvsub(v1, v2));
200 }
201 
202 /// Returns true if the distance between v1 and v2 is less than dist.
cpvnear(const cpVect v1,const cpVect v2,const cpFloat dist)203 static inline cpBool cpvnear(const cpVect v1, const cpVect v2, const cpFloat dist)
204 {
205 	return cpvdistsq(v1, v2) < dist*dist;
206 }
207 
208 /// @}
209 
210 /// @defgroup cpMat2x2 cpMat2x2
211 /// 2x2 matrix type used for tensors and such.
212 /// @{
213 
214 // NUKE
215 static inline cpMat2x2
cpMat2x2New(cpFloat a,cpFloat b,cpFloat c,cpFloat d)216 cpMat2x2New(cpFloat a, cpFloat b, cpFloat c, cpFloat d)
217 {
218 	cpMat2x2 m = {a, b, c, d};
219 	return m;
220 }
221 
222 static inline cpVect
cpMat2x2Transform(cpMat2x2 m,cpVect v)223 cpMat2x2Transform(cpMat2x2 m, cpVect v)
224 {
225 	return cpv(v.x*m.a + v.y*m.b, v.x*m.c + v.y*m.d);
226 }
227 
228 ///@}
229 
230 #endif
231