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