1 /*
2  * File:         vector.c
3  *
4  * Description:  funcs for doing vector math
5  *
6  * This source code is part of kludge3d, and is released under the
7  * GNU General Public License.
8  *
9  *
10  */
11 
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <math.h>
15 #include <string.h>
16 
17 #include "vector.h"
18 
19 #ifdef MEMWATCH
20 #include "memwatch.h"
21 #endif
22 
23 
24 /* clear v1
25  */
vector_zero(float * v1)26 void vector_zero( float *v1 ) {
27 
28     int i;
29 
30     if( v1 == NULL ) return;
31 
32     for( i = 0; i < 3; i++ ) {
33         v1[i] = 0.0;
34     }
35 
36 }
37 
38 /* copies contents of v2 to v1
39  * Note that it's ok for v1 to actually point to v2
40  * (it wouldn't make sense to do so, but...)
41  */
vector_copy(float * v1,float * v2)42 void vector_copy( float *v1, float *v2 ) {
43 
44     int i;
45 
46     if( v1 == NULL || v2 == NULL ) return;
47 
48     for( i = 0; i < 3; i++ ) {
49         v1[i] = v2[i];
50     }
51 
52 }
53 
54 /* adds v3 to v2, stores result in v1
55  * Note that it's ok for v1 to actually point to v2 or v3
56  */
vector_add(float * v1,float * v2,float * v3)57 void vector_add( float *v1, float *v2, float *v3 ) {
58 
59     int i;
60 
61     if( v1 == NULL || v2 == NULL || v3 == NULL ) return;
62 
63     for( i = 0; i < 3; i++ ) {
64         v1[i] = v2[i] + v3[i];
65     }
66 
67 }
68 
69 /* subtracts v3 from v2, stores result in v1
70  * Note that it's ok for v1 to actually point to v2 or v3
71  */
vector_sub(float * v1,float * v2,float * v3)72 void vector_sub( float *v1, float *v2, float *v3 ) {
73 
74     int i;
75 
76     if( v1 == NULL || v2 == NULL || v3 == NULL ) return;
77 
78     for( i = 0; i < 3; i++ ) {
79         v1[i] = v2[i] - v3[i];
80     }
81 
82 }
83 
84 
85 /* finds the length of v1 (ie |v1|) */
vector_length(float * v1)86 float vector_length( float *v1 ) {
87 
88     return sqrt ( ( v1[0] * v1[0] ) + ( v1[1] * v1[1] ) + ( v1[2] * v1[2] ) );
89 }
90 
91 
92 /* finds the length^2 of v1 (ie |v1|^2) */
vector_length_sqrd(float * v1)93 float vector_length_sqrd( float *v1 ) {
94 
95     return ( v1[0] * v1[0] ) + ( v1[1] * v1[1] ) + ( v1[2] * v1[2] );
96 }
97 
98 
99 /* makes length( v1 ) equal to 1.0, also returns length before normalization */
vector_normalize(float * v1)100 float vector_normalize( float *v1 ) {
101 
102     int i;
103     float mag1;
104 
105     if( v1 == NULL ) return -1.0;
106 
107     // Compute magnitude
108     mag1 = vector_length( v1 );
109 
110     // Normalize
111     for( i = 0; i < 3; i++ ) {
112         v1[i] = ( v1[i] / mag1 );
113     }
114 
115 	return mag1;
116 }
117 
118 
119 /* finds cross product of v2 and v3, stores result in v1
120  * Note that you should never use v2 or v3 as v1!
121  */
vector_cross_prod(float * v1,float * v2,float * v3)122 void vector_cross_prod( float *v1, float *v2, float *v3 ) {
123 
124     if( v1 == NULL || v2 == NULL || v3 == NULL ) return;
125 
126     // Compute Cross Product
127     v1[0] = ( v2[1] * v3[2] ) - ( v2[2] * v3[1] );
128     v1[1] = ( v2[2] * v3[0] ) - ( v2[0] * v3[2] );
129     v1[2] = ( v2[0] * v3[1] ) - ( v2[1] * v3[0] );
130 
131 }
132 
133 
134 /* returns dot product (a scalar) of v1 and v2 */
vector_dot_prod(float * v1,float * v2)135 float vector_dot_prod( float *v1, float *v2 ) {
136 
137     if( v1 == NULL || v2 == NULL ) return 0.0f;
138 
139     return
140     ( v1[0] * v2[0] ) +
141     ( v1[1] * v2[1] ) +
142     ( v1[2] * v2[2] );
143 
144 }
145 
146 
147 /* multiplies elements of v2 by s (a scalar) and stores results in v1
148  * Note that it's ok for v1 to actually point to v2
149  */
vector_mul(float * v1,float * v2,float s)150 void vector_mul( float *v1, float *v2, float s ) {
151 
152     if( v1 == NULL || v2 == NULL ) return;
153 
154     // multiply vector by scalar
155     v1[0] = v2[0] * s;
156     v1[1] = v2[1] * s;
157     v1[2] = v2[2] * s;
158 
159 }
160 
161 
162 /* multiplies elements of v2 by corresponding element in v3, and stores
163  * results in v1
164  * Note that it's ok for v1 to actually point to v2 or v3
165  */
vector_mul_piecewise(float * v1,float * v2,float * v3)166 void vector_mul_piecewise( float *v1, float *v2, float *v3 ) {
167 
168     if( v1 == NULL || v2 == NULL || v3 == NULL ) return;
169 
170     v1[0] = v2[0] * v3[0];
171     v1[1] = v2[1] * v3[1];
172     v1[2] = v2[2] * v3[2];
173 }
174 
175 
176 
177 /* treats v2 as the origin of a ray, v3 as its direction, and finds the
178  * point v1 at distance s from the ray's origin
179  * Note - it is NOT ok for v1 and v2 to point to the same vector!
180  */
vector_find_point(float * v1,float * v2,float * v3,float s)181 void vector_find_point( float *v1, float *v2, float *v3, float s ) {
182 
183     if( v1 == NULL || v2 == NULL || v3 == NULL ) return;
184 
185 	vector_mul( v1, v3, s );
186 	vector_add( v1, v1, v2 );
187 
188 }
189 
190 
vector_find_dist_pt2line(float * rayorig,float * raydir,float * pt)191 float vector_find_dist_pt2line( float *rayorig, float *raydir, float *pt ) {
192 
193 	float t0, result;
194 	float delta[3];
195 	float temp[3];
196 
197     if( rayorig == NULL || raydir == NULL || pt == NULL ) return 0.0;
198 
199 	vector_sub( delta, pt, rayorig );
200 	t0 = vector_dot_prod( raydir, delta ) / vector_dot_prod( raydir, raydir );
201 
202 	if( t0 > 0.0 ) {
203 		vector_find_point( temp, rayorig, raydir, t0 );
204 		vector_sub( temp, pt, temp );
205 		result = vector_length( temp );
206 	} else {
207 		result = vector_length( delta );
208 	}
209 
210 	return result;
211 }
212 
213 
214 /* v is assumed to be normalized
215    the z component for v is assumed to be 0
216    returns heading in radians
217 */
vector_find_heading(float * v)218 float vector_find_heading( float *v ) {
219 	float xAxis[] = { 1.0, 0.0, 0.0 };
220 	float deltaV2V1[3], invV[3], tempPt[3];
221 	int reflexAngle = 0;
222 	float cosTheta, result = 0.0;
223 
224 	if( v == NULL ) return 0.0;
225 
226 	/* This is a tricky bit of code, and it took me forever to work this out.
227 	   Dot product gets us the cosine of the angle between two unit vectors,
228 	   but its the SMALLEST angle between the two.  This is no good for
229 	   "reflex angles," ie angles greater then 180.  The following code
230 	   discriminates between reflex and non-reflex angles.  In short, if the
231 	   normal of v1 and deltaV2V1 points up, all is well.  If it points down,
232 	   that means that we have a reflex angle, and need to take appropriate
233 	   action.
234 	 */
235 	vector_sub( deltaV2V1, xAxis, v );
236 	vector_normalize( deltaV2V1 );
237 	/* flip v1 around */
238 	vector_mul( invV, v, -1.0 );
239 	vector_cross_prod( tempPt, invV, deltaV2V1 );
240 	if( tempPt[2] < 0.0 ) {
241 		reflexAngle = 1;
242 	}
243 
244 	cosTheta = vector_dot_prod( v, xAxis );
245 	result = acos( cosTheta );
246 	if( reflexAngle )
247 		result = (2*M_PI) - result;
248 
249 /*printf( "v: < %3.3f %3.3f %3.3f > costheta: %3.3f result: %3.3f reflang?: %i\n",
250 v[0],
251 v[1],
252 v[2],
253 cosTheta,
254 result,
255 reflexAngle );*/
256 
257 	return result;
258 }
259 
260 
vector_dist(float * v1,float * v2)261 float vector_dist( float *v1, float *v2 ) {
262 	float temp[3];
263 
264     if( v1 == NULL || v2 == NULL ) return 0.0f;
265 
266 	vector_sub( temp, v2, v1 );
267 	return vector_length( temp );
268 }
269 
270 
vector_dist_sqrd(float * v1,float * v2)271 float vector_dist_sqrd( float *v1, float *v2 ) {
272 	float temp[3];
273 
274     if( v1 == NULL || v2 == NULL ) return 0.0f;
275 
276 	vector_sub( temp, v2, v1 );
277 	return vector_length_sqrd( temp );
278 }
279 
280 
281 /* is angle between vectors < 90 degrees? args must be normalized. */
vector_coincident(float * v1,float * v2)282 int vector_coincident( float *v1, float *v2 ) {
283 
284     if( v1 == NULL || v2 == NULL ) return 0;
285 
286 	if( vector_dot_prod( v1, v2 ) > 0.0 ) {
287 		/* The dot prod of two unit vectors gets us the cosine of the
288 		   angle between them.  At this point, since the cosine is positive,
289 		   we know that the angle is from either 0-90 or 270-360.  Since
290 		   the dotprod trick will always measure the shortest angle between
291 		   the vectors, we know that the angles are in fact coincidental.
292 		   (now that I think about it, 270-360 works too :)
293 		*/
294 		return 1;
295 	}
296 	return 0;
297 }
298 
299 
vector_rotate_about_point(float * result,float * v,int axis,float * origin,float angle)300 void vector_rotate_about_point(
301 	float *result, float *v, int axis, float *origin, float angle )
302 {
303 	/* Note - don't use this func if you are rotating a whole bunch of
304 	objects by the same amount.  A func for doing so (for Verts, at least)
305 	already exists.  (cos and sin are expensive funcs, and need only be
306 	executed once per rotation, not once per object) */
307 
308 	float cosine = cos(angle);
309 	float sine = sin(angle);
310 
311 	if( result == NULL )
312 		return;
313 	if( v == NULL )
314 		return;
315 	if( origin == NULL )
316 		return;
317 
318 	vector_copy( result, v );
319 
320 	{
321 
322 	float temp0, temp1, temp2;
323 
324 	if( axis == 0 ) {
325 		temp1 = v[1] - origin[1];
326 		temp2 = v[2] - origin[2];
327 
328 		result[1] = temp1*cosine - temp2*sine + origin[1];
329 		result[2] = temp1*sine + temp2*cosine + origin[2];
330 	} else if( axis == 1 ) {
331 		temp0 = v[0] - origin[0];
332 		temp2 = v[2] - origin[2];
333 
334 		result[0] =   temp0*cosine + temp2*sine + origin[0];
335 		result[2] = - temp0*sine + temp2*cosine + origin[2];
336 	} else if( axis == 2 ) {
337 		temp0 = v[0] - origin[0];
338 		temp1 = v[1] - origin[1];
339 
340 		result[0] = temp0*cosine - temp1*sine + origin[0];
341 		result[1] = temp0*sine + temp1*cosine + origin[1];
342 	}
343 
344 	}
345 
346 }
347