1 /////////////////////////////////////////
2 //
3 // OpenLieroX
4 //
5 // Auxiliary Software class library
6 //
7 // based on the work of JasonB
8 // enhanced by Dark Charlie and Albert Zeyer
9 //
10 // code under LGPL
11 //
12 /////////////////////////////////////////
13
14
15 // Mathematics Library
16 // Created 20/12/01
17 // Jason Boettcher
18
19
20 #include <cassert>
21 #include <stdlib.h>
22 #include <cmath>
23 #include <time.h>
24 #include <SDL_timer.h>
25
26 #include "MathLib.h"
27
28
29 const int HALF_RAND = (RAND_MAX / 2);
30
31
32 //////////////////////////////////////
33 // Generic maths
34 //////////////////////////////////////
35
36
37 ///////////////////
38 // Faster SQRT function
fastSQRT(float x)39 float fastSQRT(float x)
40 {
41
42 /*if(x <= 0) return 0;
43
44 float tmp = x / 2;
45 for(short i = 0; i<=10; i++) {
46 tmp = tmp + x / tmp;
47 tmp = tmp / 2;
48 }
49 return tmp;*/
50
51
52 return (float)sqrt(x);
53 }
54
55
56 ///////////////////
57 // Get a random number between -1 and 1
GetRandomNum()58 float GetRandomNum()
59 {
60 int rn = rand();
61 return ((float)(rn - HALF_RAND) / (float)HALF_RAND);
62 }
63
GetRandomPosNum()64 float GetRandomPosNum() {
65 int rn = rand();
66 return (float)rn / (float)RAND_MAX;
67 }
68
69 ///////////////////
70 // Get a random integer with a max value
GetRandomInt(int max)71 int GetRandomInt(int max)
72 {
73 assert(max >= 0);
74 float f = GetRandomPosNum()*(float)(max+1);
75 return CLAMP((int)f, 0, max);
76 }
77
78 //////////////////
79 // Round the number
Round(float x)80 int Round(float x)
81 {
82 return (int) ceil((double)x-0.5);
83 }
84
85
86 //#ifdef VEC2D
87
88 //////////////////////////////////////
89 // 2D Section
90 //////////////////////////////////////
91
92
93 ///////////////////
94 // Calculate the distance between 2 vectors
CalculateDistance(CVec p1,CVec p2)95 float CalculateDistance(CVec p1, CVec p2)
96 {
97 CVec dist = p2-p1;
98 return fastSQRT( (dist.x*dist.x) + (dist.y*dist.y) );
99 }
100
101
102 ///////////////////
103 // Normalize a vector
NormalizeVector(CVec * vec)104 float NormalizeVector(CVec *vec)
105 {
106 float length;
107
108 length = (float)fastSQRT( vec->x*vec->x + vec->y*vec->y );
109
110 if(length) {
111 vec->x /= length;
112 vec->y /= length;
113 }
114
115 return length;
116 }
117
118
119 ///////////////////
120 // Get a random normalized vector
GetRandomVec()121 CVec GetRandomVec()
122 {
123 return CVec(GetRandomNum(),GetRandomNum());
124 }
125
126
127 ///////////////////
128 // Get forward, and right vectors from a yaw angle
GetVecsFromAngle(float yaw,CVec * forward,CVec * right)129 void GetVecsFromAngle(float yaw,CVec *forward, CVec *right)
130 {
131 const float angle = yaw * (float)(PI / 180);
132 const float sy = sinf(angle);
133 const float cy = cosf(angle);
134 const float sp = 0; //sinf(0);
135 const float cp = 1; //cosf(0);
136 const float sr = sp;
137 const float cr = cp;
138
139 if(forward)
140 *forward = CVec(cp*cy,cp*sy);
141 if(right)
142 *right = CVec((-1*sr*sp*cy+-1*cr*-sy),(-1*sr*sp*sy+-1*cr*cy));
143 }
144
GetVecFromAngle(float yaw)145 CVec GetVecFromAngle(float yaw) {
146 CVec ret;
147 GetVecsFromAngle(yaw, &ret, NULL);
148 return ret;
149 }
150
151
152 //////////////////
153 // Get the angle (in radians) of two vectors
VectorAngle(CVec vec1,CVec vec2)154 float VectorAngle(CVec vec1, CVec vec2)
155 {
156 return (float)atan2(vec1.y-vec2.y,vec1.x-vec2.x);
157
158 /* //return (float)acos(vec1.x*vec2.x+vec1.y*vec2.y)/(VectorLength(vec1)*VectorLength(vec2));
159 float scalar = vec1.x*vec2.x + vec1.y*vec2.y;
160 float len1 = vec1.GetLength();
161 float len2 = vec2.GetLength();
162 float result = (float)acos(scalar/(len1*len2));
163 return result; */
164 }
165
166
167 ///////////////////
168 // Get the length of a vector
VectorLength(CVec vec)169 float VectorLength(CVec vec)
170 {
171 return (float)fastSQRT( vec.x*vec.x + vec.y*vec.y );
172 }
173
174 ////////////////////
175 // Create a parabola from three points
Parabola(CVec p1,CVec p2,CVec p3)176 Parabola::Parabola(CVec p1, CVec p2, CVec p3)
177 {
178 const float m = p1.x;
179 const float n = p1.y;
180 const float o = p2.x;
181 const float p = p2.y;
182 const float q = p3.x;
183 const float r = p3.y;
184
185 const float denom = (pow(m,2)-m*(o+q)+o*q)*(o-q);
186 if (denom == 0) {
187 a = b = c = 0;
188 return;
189 }
190
191 a = -(m*(p-r)+n*(q-o)+o*r-p*q)/denom;
192 b = (m*m*(p-r)+n*(o+q)*(q-o)+o*o*r-p*q*q)/denom;
193 c = (m*m*(o*r-p*q)+m*(p*q*q-o*o*r)+n*o*q*(o-q))/denom;
194 }
195
196 /////////////////////
197 // Create a parabola from two points and a tangent angle in point p1
Parabola(CVec p1,float angleP1,CVec p2)198 Parabola::Parabola(CVec p1, float angleP1, CVec p2)
199 {
200 const float p = p1.x;
201 const float r = p1.y;
202 const float s = p2.x;
203 const float t = p2.y;
204 const float cos_f = cosf(angleP1);
205 const float sin_f = sinf(angleP1);
206
207 const float denom = (p-s) * (p-s) * cos_f;
208 if (denom == 0) {
209 a = b = c = 0;
210 return;
211 }
212
213 a = -((r-t)*cos_f+(s-p)*sin_f)/denom;
214 b = (2*p*(r-t)*cos_f+(p+s)*(s-p)*sin_f)/denom;
215 c = ((p*p*t-2*p*r*s+r*s*s)*cos_f+p*s*(p-s)*sin_f)/denom;
216 }
217
218 /////////////////////
219 // Get length of a parabola segment between points p1 and p2, p1 and p2 must be part of the parabola
getLength(CVec p1,CVec p2)220 float Parabola::getLength(CVec p1, CVec p2)
221 {
222 if (isPointAtParabola(p1) && isPointAtParabola(p2))
223 return getLength(p1.x, p2.x);
224 else
225 return -1;
226 }
227
getLength(float pa,float pb)228 float Parabola::getLength(float pa, float pb)
229 {
230 // Check if we have a line
231 if (a == 0) {
232 CVec x1(pa, b * pa + c);
233 CVec x2(pb, b * pb + c);
234 return (x2 - x1).GetLength();
235 }
236
237 float upper_u = 2*a*pa + b;
238 float lower_u = 2*a*pb + b;
239
240 float up = (log(sqrt(upper_u*upper_u + 1) + upper_u) + upper_u*sqrt(upper_u*upper_u + 1))/(4*a);
241 float low = (log(sqrt(lower_u*lower_u + 1) + lower_u) + lower_u*sqrt(lower_u*lower_u + 1))/(4*a);
242
243 return fabs(up - low);
244 }
245