xref: /haiku/src/servers/app/Angle.cpp (revision ba499cdc3336fb89429027418871bf263f1f5e14)
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 */
43 Angle::Angle(float angle)
44 	: fAngleValue(angle)
45 {
46 	_InitTrigTables();
47 }
48 
49 //! Constructor
50 Angle::Angle()
51 	: fAngleValue(0)
52 {
53 	_InitTrigTables();
54 }
55 
56 //! Empty destructor
57 Angle::~Angle()
58 {
59 }
60 
61 //! Constrains angle to 0 <= angle <= 360
62 void
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
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
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
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
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
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
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
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
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
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
255 Angle::SetValue(float angle)
256 {
257 	fAngleValue = angle;
258 	Normalize();
259 }
260 
261 
262 float
263 Angle::Value() const
264 {
265 	return fAngleValue;
266 }
267 
268 //! Initializes the global trig tables
269 void
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&
305 Angle::operator=(const Angle &from)
306 {
307 	fAngleValue = from.fAngleValue;
308 	return *this;
309 }
310 
311 
312 Angle&
313 Angle::operator=(const float &from)
314 {
315 	fAngleValue = from;
316 	return *this;
317 }
318 
319 
320 Angle&
321 Angle::operator=(const long &from)
322 {
323 	fAngleValue = (float)from;
324 	return *this;
325 }
326 
327 
328 Angle&
329 Angle::operator=(const int &from)
330 {
331 	fAngleValue = (float)from;
332 	return *this;
333 }
334 
335 
336 bool
337 Angle::operator==(const Angle &from)
338 {
339 	return (fAngleValue == from.fAngleValue);
340 }
341 
342 
343 bool
344 Angle::operator!=(const Angle &from)
345 {
346 	return (fAngleValue != from.fAngleValue);
347 }
348 
349 
350 bool
351 Angle::operator>(const Angle &from)
352 {
353 	return (fAngleValue > from.fAngleValue);
354 }
355 
356 
357 bool
358 Angle::operator<(const Angle &from)
359 {
360 	return (fAngleValue < from.fAngleValue);
361 }
362 
363 
364 bool
365 Angle::operator>=(const Angle &from)
366 {
367 	return (fAngleValue >= from.fAngleValue);
368 }
369 
370 
371 bool
372 Angle::operator<=(const Angle &from)
373 {
374 	return (fAngleValue <= from.fAngleValue);
375 }
376