1 //------------------------------------------------------------------------------
2 // Copyright (c) 2001-2002, Haiku, Inc.
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining a
5 // copy of this software and associated documentation files (the "Software"),
6 // to deal in the Software without restriction, including without limitation
7 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 // and/or sell copies of the Software, and to permit persons to whom the
9 // Software is furnished to do so, subject to the following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included in
12 // all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 // DEALINGS IN THE SOFTWARE.
21 //
22 // File Name: Angle.cpp
23 // Author: DarkWyrm <bpmagic@columbus.rr.com>
24 // Description: Angle class for speeding up trig functions
25 //
26 //------------------------------------------------------------------------------
27 #include "Angle.h"
28 #include <math.h>
29
30 #ifndef ANGLE_PI
31 #define ANGLE_PI 3.14159265358979323846
32 #endif
33
34 static bool sTablesInitialized = false;
35 static float sSinTable[360];
36 static float sCosTable[360];
37 static float sTanTable[360];
38
39 /*!
40 \brief Constructor
41 \param angle Value in degrees
42 */
Angle(float angle)43 Angle::Angle(float angle)
44 : fAngleValue(angle)
45 {
46 _InitTrigTables();
47 }
48
49 //! Constructor
Angle()50 Angle::Angle()
51 : fAngleValue(0)
52 {
53 _InitTrigTables();
54 }
55
56 //! Empty destructor
~Angle()57 Angle::~Angle()
58 {
59 }
60
61 //! Constrains angle to 0 <= angle <= 360
62 void
Normalize()63 Angle::Normalize()
64 {
65 // if the value of the angle is >=360 or <0, make it so that it is
66 // within those bounds
67 fAngleValue = fmodf(fAngleValue, 360);
68 if (fAngleValue < 0)
69 fAngleValue += 360;
70 }
71
72 /*!
73 \brief Obtains the sine of the angle
74 \return The sine of the angle
75 */
76 float
Sine()77 Angle::Sine()
78 {
79 return sSinTable[(int)fAngleValue];
80 }
81
82 /*!
83 \brief Calculates an angle given a float value
84 \param value Number between 0 and 1 inclusive
85 \return The angle obtained or 0 if value passed was invalid
86 */
87 Angle
InvSine(float value)88 Angle::InvSine(float value)
89 {
90 // Returns the inverse sine of a value in the range 0 <= value <= 1 via
91 // reverse-lookup any value out of range causes the function to return 0
92
93 // Filter out bad values
94 value = fabs(value);
95
96 if (value > 1)
97 return Angle(0);
98
99 uint16 i = 90;
100 while (value < sSinTable[i])
101 i--;
102
103 // current sSinTable[i] is less than value. Pick the degree value which is closer
104 // to the passed value
105 if ((value - sSinTable[i]) > (sSinTable[i + 1] - value))
106 return Angle(i + 1);
107
108 return Angle(i); // value is closer to previous
109 }
110
111
112 /*!
113 \brief Obtains the cosine of the angle
114 \return The cosine of the angle
115 */
116 float
Cosine(void)117 Angle::Cosine(void)
118 {
119 return sCosTable[(int)fAngleValue];
120 }
121
122 /*!
123 \brief Calculates an angle given a float value
124 \param value Number between 0 and 1 inclusive
125 \return The angle obtained or 0 if value passed was invalid
126 */
127 Angle
InvCosine(float value)128 Angle::InvCosine(float value)
129 {
130 // Returns the inverse cosine of a value in the range 0 <= value <= 1 via
131 // reverse-lookup any value out of range causes the function to return 0
132
133 // Filter out bad values
134 value = fabs(value);
135
136 if (value > 1)
137 return 0;
138
139 uint16 i = 90;
140 while (value > sCosTable[i])
141 i--;
142
143 // current sCosTable[i] is less than value. Pick the degree value which is closer
144 // to the passed value
145 if ((value - sCosTable[i]) < (sCosTable[i + 1] - value))
146 return Angle(i + 1);
147
148 return Angle(i); // value is closer to previous
149 }
150
151 /*!
152 \brief Obtains the tangent of the angle
153 \return The tangent of the angle
154 */
155 float
Tangent(int * status)156 Angle::Tangent(int *status)
157 {
158 if (fAngleValue == 90 || fAngleValue == 270) {
159 if (status)
160 *status = 0;
161 return 0.0;
162 }
163
164 return sTanTable[(int)fAngleValue];
165 }
166
167 /*!
168 \brief Returns the inverse tangent of a value given
169 \param value Number between 0 and 1 inclusive
170 \return The angle found or 0 if value was invalid
171 */
172 Angle
InvTangent(float value)173 Angle::InvTangent(float value)
174 {
175 // Filter out bad values
176 value = fabs(value);
177
178 if (value > 1)
179 return Angle(0);
180
181 uint16 i = 90;
182 while (value > sTanTable[i])
183 i--;
184
185 if ((value - sTanTable[i]) < (sTanTable[i+1] - value))
186 return Angle(i+1);
187
188 return Angle(i); // value is closer to previous
189 }
190
191 /*!
192 \brief Returns a value based on what quadrant the angle is in
193 \return
194 - \c 1: 0 <= angle <90
195 - \c 2: 90 <= angle < 180
196 - \c 3: 180 <= angle < 270
197 - \c 4: 270 <= angle < 360
198 */
199 uint8
Quadrant()200 Angle::Quadrant()
201 {
202 // We can get away with not doing extra value checks because of the order in
203 // which the checks are done.
204 if (fAngleValue < 90)
205 return 1;
206
207 if (fAngleValue < 180)
208 return 2;
209
210 if (fAngleValue < 270)
211 return 3;
212
213 return 4;
214 }
215
216 /*!
217 \brief Obtains the angle constrained to between 0 and 180 inclusive
218 \return The constrained value
219 */
220 Angle
Constrain180()221 Angle::Constrain180()
222 {
223 // Constrains angle to 0 <= angle < 180
224 if (fAngleValue < 180)
225 return Angle(fAngleValue);
226
227 float value = fmodf(fAngleValue, 180);;
228 if (value < 0)
229 value += 180;
230 return Angle(value);
231 }
232
233 /*!
234 \brief Obtains the angle constrained to between 0 and 90 inclusive
235 \return The constrained value
236 */
237 Angle
Constrain90()238 Angle::Constrain90()
239 {
240 // Constrains angle to 0 <= angle < 90
241 if (fAngleValue < 90)
242 return Angle(fAngleValue);
243
244 float value = fmodf(fAngleValue, 90);;
245 if (value < 0)
246 value += 90;
247 return Angle(value);
248 }
249
250 /*!
251 \brief Sets the angle's value and normalizes the value
252 \param angle Value in degrees
253 */
254 void
SetValue(float angle)255 Angle::SetValue(float angle)
256 {
257 fAngleValue = angle;
258 Normalize();
259 }
260
261
262 float
Value() const263 Angle::Value() const
264 {
265 return fAngleValue;
266 }
267
268 //! Initializes the global trig tables
269 void
_InitTrigTables()270 Angle::_InitTrigTables()
271 {
272 if (sTablesInitialized)
273 return;
274 sTablesInitialized = true;
275
276 for(int32 i = 0; i < 90; i++) {
277 double currentRadian = (i * ANGLE_PI) / 180.0;
278
279 // Get these so that we can do some superfast assignments
280 double sinValue = sin(currentRadian);
281 double cosValue = cos(currentRadian);
282
283 // Do 4 assignments, taking advantage of sin/cos symmetry
284 sSinTable[i] = sinValue;
285 sSinTable[i + 90] = cosValue;
286 sSinTable[i + 180] = sinValue * -1;
287 sSinTable[i + 270] = cosValue * -1;
288
289 sCosTable[i] = cosValue;
290 sCosTable[i + 90] = sinValue * -1;
291 sCosTable[i + 180] = cosValue * -1;
292 sCosTable[i + 270] = sinValue;
293
294 double tanValue = sinValue / cosValue;
295
296 sTanTable[i] = tanValue;
297 sTanTable[i + 90] = tanValue;
298 sTanTable[i + 180] = tanValue;
299 sTanTable[i + 270] = tanValue;
300 }
301 }
302
303
304 Angle&
operator =(const Angle & from)305 Angle::operator=(const Angle &from)
306 {
307 fAngleValue = from.fAngleValue;
308 return *this;
309 }
310
311
312 Angle&
operator =(const float & from)313 Angle::operator=(const float &from)
314 {
315 fAngleValue = from;
316 return *this;
317 }
318
319
320 Angle&
operator =(const long & from)321 Angle::operator=(const long &from)
322 {
323 fAngleValue = (float)from;
324 return *this;
325 }
326
327
328 Angle&
operator =(const int & from)329 Angle::operator=(const int &from)
330 {
331 fAngleValue = (float)from;
332 return *this;
333 }
334
335
336 bool
operator ==(const Angle & from)337 Angle::operator==(const Angle &from)
338 {
339 return (fAngleValue == from.fAngleValue);
340 }
341
342
343 bool
operator !=(const Angle & from)344 Angle::operator!=(const Angle &from)
345 {
346 return (fAngleValue != from.fAngleValue);
347 }
348
349
350 bool
operator >(const Angle & from)351 Angle::operator>(const Angle &from)
352 {
353 return (fAngleValue > from.fAngleValue);
354 }
355
356
357 bool
operator <(const Angle & from)358 Angle::operator<(const Angle &from)
359 {
360 return (fAngleValue < from.fAngleValue);
361 }
362
363
364 bool
operator >=(const Angle & from)365 Angle::operator>=(const Angle &from)
366 {
367 return (fAngleValue >= from.fAngleValue);
368 }
369
370
371 bool
operator <=(const Angle & from)372 Angle::operator<=(const Angle &from)
373 {
374 return (fAngleValue <= from.fAngleValue);
375 }
376