xref: /haiku/src/servers/app/Angle.cpp (revision fef6144999c2fa611f59ee6ffe6dd7999501385c)
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 bool tables_initialized=false;
35 float sintable[360], costable[360], tantable[360];
36 
37 /*!
38 	\brief Constructor
39 	\param angle Value in degrees
40 */
41 Angle::Angle(float angle)
42 {
43 	fAngleValue=angle;
44 	if(tables_initialized==false)
45 	{
46 		InitTrigTables();
47 		tables_initialized=true;
48 	}
49 }
50 
51 //! Constructor
52 Angle::Angle()
53 {
54 	fAngleValue=0;
55 	if(tables_initialized==false)
56 	{
57 		InitTrigTables();
58 		tables_initialized=true;
59 	}
60 }
61 
62 //! Empty destructor
63 Angle::~Angle()
64 {
65 }
66 
67 //! Constrains angle to 0 <= angle <= 360
68 void Angle::Normalize(void)
69 {
70 	// if the value of the angle is >=360 or <0, make it so that it is
71 	// within those bounds
72 
73 	if(fAngleValue>359)
74 	{
75 		while(fAngleValue>359)
76 			fAngleValue-=360;
77 		return;
78 	}
79 	if(fAngleValue<0)
80 	{
81 		while(fAngleValue<0)
82 			fAngleValue+=360;
83 	}
84 }
85 
86 /*!
87 	\brief Obtains the sine of the angle
88 	\return The sine of the angle
89 */
90 float Angle::Sine(void)
91 {
92 	return sintable[(int)fAngleValue];
93 }
94 
95 /*!
96 	\brief Calculates an angle given a float value
97 	\param value Number between 0 and 1 inclusive
98 	\return The angle obtained or 0 if value passed was invalid
99 */
100 Angle Angle::InvSine(float value)
101 {
102 	// Returns the inverse sine of a value in the range 0 <= value <= 1 via
103 	//	reverse-lookup any value out of range causes the function to return 0
104 	uint16 i=90;
105 
106 	// Filter out bad values
107 	if(value<0)
108 		value*=-1;
109 
110 	if(value > 1)
111 		return Angle(0);
112 
113 	while(value < sintable[i])
114 		i--;
115 
116 	// current sintable[i] is less than value. Pick the degree value which is closer
117 	// to the passed value
118 	if( (value - sintable[i]) > (sintable[i+1] - value) )
119 		return Angle(i+1);
120 
121 	return Angle(i);		// value is closer to previous
122 }
123 
124 
125 /*!
126 	\brief Obtains the cosine of the angle
127 	\return The cosine of the angle
128 */
129 float Angle::Cosine(void)
130 {
131 	return costable[(int)fAngleValue];
132 }
133 
134 /*!
135 	\brief Calculates an angle given a float value
136 	\param value Number between 0 and 1 inclusive
137 	\return The angle obtained or 0 if value passed was invalid
138 */
139 Angle Angle::InvCosine(float value)
140 {
141 	// Returns the inverse cosine of a value in the range 0 <= value <= 1 via
142 	//	reverse-lookup any value out of range causes the function to return 0
143 	uint16 i=90;
144 
145 	// Filter out bad values
146 	if(value<0)
147 		value*=-1;
148 
149 	if(value > 1)
150 		return 0;
151 
152 	while(value > costable[i])
153 		i--;
154 
155 	// current costable[i] is less than value. Pick the degree value which is closer
156 	// to the passed value
157 	if( (value - costable[i]) < (costable[i+1] - value) )
158 		return Angle(i+1);
159 
160 	return Angle(i);		// value is closer to previous
161 }
162 
163 /*!
164 	\brief Obtains the tangent of the angle
165 	\return The tangent of the angle
166 */
167 float Angle::Tangent(int *status)
168 {
169 	if(fAngleValue==90 || fAngleValue==270)
170 	{
171 		if(status)
172 			*status=0;
173 		return 0.0;
174 	}
175 
176 	return tantable[(int)fAngleValue];
177 }
178 
179 /*!
180 	\brief Returns the inverse tangent of a value given
181 	\param value Number between 0 and 1 inclusive
182 	\return The angle found or 0 if value was invalid
183 */
184 Angle Angle::InvTangent(float value)
185 {
186 	uint16 i=90;
187 
188 	// Filter out bad values
189 	if(value<0)
190 		value*=-1;
191 
192 	if(value > 1)
193 		return Angle(0);
194 
195 	while(value > tantable[i])
196 		i--;
197 
198 	if( (value - tantable[i]) < (tantable[i+1] - value) )
199 		return Angle(i+1);
200 
201 	return Angle(i);		// value is closer to previous
202 }
203 
204 /*!
205 	\brief Returns a value based on what quadrant the angle is in
206 	\return
207 	- \c 1: 0 <= angle <90
208 	- \c 2: 90 <= angle < 180
209 	- \c 3: 180 <= angle < 270
210 	- \c 4: 270 <= angle < 360
211 */
212 uint8 Angle::Quadrant(void)
213 {
214 	// We can get away with not doing extra value checks because of the order in
215 	// which the checks are done.
216 	if(fAngleValue < 90)
217 		return 1;
218 
219 	if(fAngleValue < 180)
220 		return 2;
221 
222 	if(fAngleValue < 270)
223 		return 3;
224 
225 	return 4;
226 }
227 
228 /*!
229 	\brief Obtains the angle constrained to between 0 and 180 inclusive
230 	\return The constrained value
231 */
232 Angle Angle::Constrain180(void)
233 {
234 	// Constrains angle to 0 <= angle < 180
235 	float val=fAngleValue;
236 
237 	if(fAngleValue<180)
238 		return Angle(fAngleValue);
239 
240 	while(!(val<180))
241 		val-=90;
242 	return Angle(val);
243 }
244 
245 /*!
246 	\brief Obtains the angle constrained to between 0 and 90 inclusive
247 	\return The constrained value
248 */
249 Angle Angle::Constrain90(void)
250 {
251 	// Constrains angle to 0 <= angle < 90
252 	float val=fAngleValue;
253 
254 	if(fAngleValue<90)
255 		return Angle(fAngleValue);
256 
257 	while(!(val<90))
258 		val-=90;
259 	return Angle(val);
260 }
261 
262 /*!
263 	\brief Sets the angle's value and normalizes the value
264 	\param angle Value in degrees
265 */
266 void Angle::SetValue(float angle)
267 {
268 	fAngleValue=angle;
269 	Normalize();
270 }
271 
272 /*!
273 	\brief Returns the value of the angle
274 	\return The angle's value in degrees
275 */
276 float Angle::Value(void) const
277 {
278 	return fAngleValue;
279 }
280 
281 //! Initializes the global trig tables
282 void Angle::InitTrigTables(void)
283 {
284 	int8 i;
285 	double sval,cval,tval,current_radian;
286 
287 	for(i=0;i<90; i++)
288 	{
289 		current_radian=(i * ANGLE_PI)/180.0;
290 
291 		// Get these so that we can do some superfast assignments
292 		sval=(float)sin(current_radian);
293 		cval=(float)cos(current_radian);
294 
295 		// Do 4 assignments, taking advantage of sin/cos symmetry
296 		sintable[i]=sval;
297 		sintable[i+90]=cval;
298 		sintable[i+180]=sval * -1;
299 		sintable[i+270]=cval * -1;
300 
301 		costable[i]=cval;
302 		costable[i+90]=sval * -1;
303 		costable[i+180]=cval * -1;
304 		costable[i+270]=sval;
305 
306 		tval=sval/cval;
307 
308 		tantable[i]=tval;
309 		tantable[i+90]=tval;
310 		tantable[i+180]=tval;
311 		tantable[i+270]=tval;
312 	}
313 }
314 
315 /*!
316 	\brief Overloaded assignment operator
317 	\param from Angle to copy the value from
318 	\return The angle's new value
319 */
320 Angle & Angle::operator=(const Angle &from)
321 {
322 	fAngleValue=from.fAngleValue;
323 	return *this;
324 }
325 
326 /*!
327 	\brief Overloaded assignment operator
328 	\param from New value of the angle
329 	\return The angle's new value
330 */
331 Angle & Angle::operator=(const float &from)
332 {
333 	fAngleValue=from;
334 	return *this;
335 }
336 
337 /*!
338 	\brief Overloaded assignment operator
339 	\param from New value of the angle
340 	\return The angle's new value
341 */
342 Angle & Angle::operator=(const long &from)
343 {
344 	fAngleValue=(float)from;
345 	return *this;
346 }
347 
348 /*!
349 	\brief Overloaded assignment operator
350 	\param from New value of the angle
351 	\return The angle's new value
352 */
353 Angle & Angle::operator=(const int &from)
354 {
355 	fAngleValue=(float)from;
356 	return *this;
357 }
358 
359 /*!
360 	\brief Overloaded equivalence operator
361 	\param The angle to compare to
362 	\return True if equal, false if not
363 */
364 bool Angle::operator==(const Angle &from)
365 {
366 	return (fAngleValue==from.fAngleValue)?true:false;
367 }
368 
369 /*!
370 	\brief Overloaded inequality operator
371 	\param The angle to compare to
372 	\return True if not equal, false if not
373 */
374 bool Angle::operator!=(const Angle &from)
375 {
376 	return (fAngleValue!=from.fAngleValue)?true:false;
377 }
378 
379 /*!
380 	\brief Overloaded greater than operator
381 	\param The angle to compare to
382 	\return True if greater, false if not
383 */
384 bool Angle::operator>(const Angle &from)
385 {
386 	return (fAngleValue>from.fAngleValue)?true:false;
387 }
388 
389 /*!
390 	\brief Overloaded less than operator
391 	\param The angle to compare to
392 	\return True if less than, false if not
393 */
394 bool Angle::operator<(const Angle &from)
395 {
396 	return (fAngleValue<from.fAngleValue)?true:false;
397 }
398 
399 /*!
400 	\brief Overloaded greater than or equal to operator
401 	\param The angle to compare to
402 	\return True if greater than or equal to, false if not
403 */
404 bool Angle::operator>=(const Angle &from)
405 {
406 	return (fAngleValue>=from.fAngleValue)?true:false;
407 }
408 
409 /*!
410 	\brief Overloaded less than or equal to operator
411 	\param The angle to compare to
412 	\return True if less than or equal to, false if not
413 */
414 bool Angle::operator<=(const Angle &from)
415 {
416 	return (fAngleValue<=from.fAngleValue)?true:false;
417 }
418