1 // -*- Mode: C++; tab-width: 2; -*-
2 // vi: set ts=2:
3 //
4 
5 #ifndef BALL_MATHS_ANGLE_H
6 #define BALL_MATHS_ANGLE_H
7 
8 #ifndef BALL_COMMON_EXCEPTION_H
9 # include <BALL/COMMON/exception.h>
10 #endif
11 
12 #ifndef BALL_COMMON_DEBUG_H
13 # include <BALL/COMMON/debug.h>
14 #endif
15 
16 #ifndef BALL_COMMON_CREATE_H
17 # include <BALL/COMMON/create.h>
18 #endif
19 
20 #ifndef BALL_MATHS_COMMON_H
21 #	include <BALL/MATHS/common.h>
22 #endif
23 
24 namespace BALL
25 {
26 	/** \defgroup Angle Representation of angles.
27 	 	  class  \link BALL::TAngle TAngle \endlink  and class  \link Angle Angle \endlink
28 	 		\ingroup Primitives
29 	 */
30 	//@{
31 	template <typename T>
32 	class TAngle;
33 
34 	template <typename T>
35 	BALL_INLINE
36 	TAngle<T> operator * (const T& val, const TAngle<T>& angle);
37 
38 	template <typename T>
39 	BALL_INLINE
40 	TAngle<T> operator + (const T& val, const TAngle<T>& angle);
41 
42 	template <typename T>
43 	BALL_INLINE
44 	TAngle<T> operator - (const T& val, const TAngle<T>& angle);
45 
46 	/**	Generic Angle Class.
47 			Use this class to describe angles. The TAngle class permits the conversion
48 			from degree to radians and is the return type of all functions used to calculate
49 			angles.
50 	*/
51 	template <typename T>
52 	class TAngle
53 	{
54 		public:
55 
56 		BALL_CREATE(TAngle<T>)
57 
58 		/**	@name	Enums
59 		*/
60 		//@{
61 
62 		/** form of the angle range:
63 				<tt>RANGE__UNLIMITED = 0</tt> no limitations
64 				<tt>RANGE__UNSIGNED  = 1</tt> 0 <= angle <= 360, 0 <= angle <= PI * 2
65 				<tt>RANGE__SIGNED    = 2</tt> -180 <= angle <= 180, -PI <= angle <= PI
66 		*/
67 		enum Range
68 		{
69 			// no limitations
70 			RANGE__UNLIMITED = 0,
71 			// 0 <= angle <= 360, 0 <= angle <= (Constants::PI * 2)
72 			RANGE__UNSIGNED  = 1,
73 			// -180 <= angle <= 180, -Constants::PI <= angle <= Constants::PI
74 			RANGE__SIGNED    = 2
75 		};
76 		//@}
77 		/**	@name	Constructors and Destructors
78 		*/
79 		//@{
80 
81 		/**	Default constructor.
82 				Creates a new angle object. Its value is set to 0.
83 		*/
84 		TAngle();
85 
86 		/**	Copy constructor.
87 				Create a copy of a TAngle object. Copies are always
88 				shallow.
89 				@param	angle the object to be copied
90 		*/
91 		TAngle(const TAngle& angle);
92 
93 		/**	Detailed constructor.
94 				Create a new angle object and set its value to
95 				<tt>new_value</tt>. <tt>radian</tt> determines whether <tt>new_value</tt>
96 				is in radians or in degrees.
97 				@param	new_value the value of the angle object
98 				@param	radian <b>true</b> if <tt>new_value</tt> is in radians, <tt>false</tt> otherwise
99 		*/
100 		explicit TAngle(const T& new_value, bool radian = true);
101 
102 		/**	Destructor.
103 		*/
~TAngle()104 		virtual ~TAngle()
105 		{
106 		}
107 
108 		/** Clear method
109 				The value is set to 0.
110 		*/
clear()111 		virtual void clear()
112 		{
113 			value = (T)0;
114 		}
115 		//@}
116 
117 		/**	@name	Assignment
118 		*/
119 		//@{
120 
121 		/**	Swap the contents of two angles.
122 		*/
123 		void swap(TAngle& angle);
124 
125 		/**	Assign a new value to the angle.
126 				<tt>radian</tt> determines whether <tt>new_value</tt>
127 				is in radians or in degrees.
128 				@param	new_value the value of the angle object
129 				@param	radian <b>true</b> if <tt>new_value</tt> is in radians, <tt>false</tt> otherwise
130 		*/
131 		void set(const T& new_value, bool radian = true);
132 
133 		/**	Assign an Angle object from another.
134 				@param	angle the angle object to be assigned from
135 		*/
136 		void set(const TAngle& angle);
137 
138 		/**	Assignment operator
139 		*/
140 		TAngle& operator = (const TAngle& angle);
141 
142 		/**	Assignment operator for floats.
143 				Assign a float value to the angle.
144 				The assigned value has to be in radians!
145 				@param	new_value the new value
146 		*/
147 		TAngle& operator = (const T& new_value);
148 
149 		/**	Assign the value to another angle.
150 				@param	angle the angle to assign the value to
151 		*/
152 		void get(TAngle& angle) const;
153 
154 		/**	Assign the value to a variable of type <tt>T</tt>.
155 				@param	val the variable to assign the value to
156 				@param	radian if set to <tt>true</tt> assigns the value in radians (default).
157 		*/
158 		void get(T& val, bool radian = true) const;
159 
160 		//@}
161 		/**	@name	Accessors
162 		*/
163 		//@{
164 
165 		/** Cast operator
166 				@return value in radians
167 		*/
168 		operator T () const;
169 
170 		/** Return the value of the angle
171 				@return value in radians
172 		*/
173 		T toRadian() const
174 	;
175 
176 		/** Calculate radians from degrees
177 				@param degree the value in degrees
178 				@return T the value in radians
179 		*/
180 		static T toRadian(const T& degree);
181 
182 		/** Return the value of the angle
183 				@return value in degrees
184 		*/
185 		T toDegree() const;
186 
187 		/** Calculate degrees from radians
188 				@param radian the value in radians
189 				@return T the value in degrees
190 		*/
191 		static T toDegree(const T& radian);
192 
193 		/**	Normalize the angle over a given range.
194 				<tt>RANGE__UNLIMITED = 0</tt> no limitations.
195 				<tt>RANGE__UNSIGNED  = 1</tt> \f$0 \le \mathtt{angle} \le 360, 0 \le angle \le 2 \pi\f$.
196 				<tt>RANGE__SIGNED    = 2</tt> \f$-180 \le \mathtt{angle} \le 180, -\pi \le \mathtt{angle} \le \pi\f$.
197 				@param range the range of the angle
198 		*/
199 		void normalize(Range range);
200 
201 		/**  Negate the angle
202 		*/
203 		void negate();
204 
205 		/**	Positive sign.
206 		*/
207 		TAngle operator + () const;
208 
209 		/**	Negative sign.
210 		*/
211 		TAngle operator - () const;
212 
213 		/**	Addition operator.
214 				@param angle the angle to add
215 				@return TAngle, {\em *this}
216 		*/
217 		TAngle& operator += (const TAngle& angle);
218 
219 		/**	Add a value to this angle.
220 				@param val the value to add
221 				@return TAngle, {\em *this}
222 		*/
223 		TAngle& operator += (const T& val);
224 
225 		/**	Addition operator.
226 				@param angle the angle to add
227 				@return TAngle, the new angle
228 		*/
229 		TAngle operator + (const TAngle& angle);
230 
231 		/**	Substraction operator.
232 				@param angle the angle to substract
233 				@return TAngle, {\em *this}
234 		*/
235 		TAngle& operator -= (const TAngle& angle);
236 
237 		/**	Substract a value from this angle.
238 				@param val the value to substract
239 				@return TAngle, {\em *this}
240 		*/
241 		TAngle& operator -= (const T& val);
242 
243 		/**	Subtraction an angle from this angle.
244 				@param angle the angle to substract
245 				@return TAngle, the new angle
246 		*/
247 		TAngle operator - (const TAngle& angle);
248 
249 		/**	Multiply an angle with this angle.
250 				@param angle the angle to multiply by
251 				@return TAngle, {\em *this}
252 		*/
253 		TAngle& operator *= (const TAngle& angle);
254 
255 		/**	Multiply a value with this angle.
256 				@param val the value to multiply by
257 				@return TAngle, {\em *this}
258 		*/
259 		TAngle& operator *= (const T& val);
260 
261 		/**	Division operator.
262 				@param angle the angle to divide by
263 				@return TAngle, {\em *this}
264 				@throw  Exception::DivisionByZero if angle is zero
265 		*/
266 		TAngle& operator /= (const TAngle& angle);
267 
268 		/**	Divide this angle by a value.
269 				@param val the angle to divide by
270 				@return TAngle, {\em *this}
271 				@throw  Exception::DivisionByZero if val is zero
272 		*/
273 		TAngle& operator /= (const T& val);
274 
275 		/**	Divide this angle by a value.
276 				@param val the angle to divide by
277 				@return TAngle, the new angle
278 				@throw  Exception::DivisionByZero if val is zero
279 		*/
280 		TAngle operator / (const TAngle& val);
281 
282 		//@}
283 		/**	@name	Predicates
284 		*/
285 		//@{
286 
287 		/**	Equality operator.
288 				This test uses Maths::isEqual instead of comparing the
289 				values directly.
290 				@param angle the angle to compare with
291 				@return bool, <b>true</b> if the two angles are equal
292 		*/
293 		bool operator == (const TAngle& angle) const;
294 
295 		/**	Inequality operator
296 				This test uses Maths::isNotEqual instead of comparing the
297 				values directly.
298 				@param angle the angle to compare with
299 				@return bool, <b>true</b> if the two angles are not equal
300 		*/
301 		bool operator != (const TAngle& angle) const;
302 
303 		/**	Is less operator.
304 				This test uses Maths::isLess instead of comparing the
305 				values directly.
306 				@param angle the angle to compare with
307 				@return bool, <b>true</b> if {\em *this} angle is smaller than <tt>value</tt>
308 		*/
309 		bool operator < (const TAngle& angle) const;
310 
311 		/**	Is less operator.
312 				This test uses Maths::isLess instead of comparing the
313 				values directly.
314 				@param val the value to compare with
315 				@return bool, <b>true</b> if {\em *this} angle is smaller than <tt>value</tt>
316 		*/
317 		bool operator < (const T& val) const;
318 
319 		/**	Is less or equal operator.
320 				This test uses Maths::isLessOrEqual instead of comparing the
321 				values directly.
322 				@param angle the angle to compare with
323 				@return bool, <b>true</b> if {\em *this} angle is smaller or equal than <tt>value</tt>
324 		*/
325 		bool operator <= (const TAngle& angle) const;
326 
327 		/**	Is greater or equal operator.
328 				This test uses Maths::isGreaterOrEqual instead of comparing the
329 				values directly.
330 				@param angle the angle to compare with
331 				@return bool, <b>true</b> if {\em *this} angle is greater or equal than <tt>value</tt>
332 		*/
333 		bool operator >= (const TAngle& angle) const;
334 
335 		/**	Is greater operator.
336 				This test uses Maths::isGreater instead of comparing the
337 				values directly.
338 				@param angle the angle to compare with
339 				@return bool, <b>true</b> if {\em *this} angle is greater than <tt>value</tt>
340 		*/
341 		bool operator > (const TAngle& angle) const;
342 
343 		/**	Test whether two angles are equivalent.
344 				Both angles are normalized and afterwards compared with Maths::isEqual
345 				instead of comparing the values directly.
346 				@param angle the angle to compare with
347 				@return bool, <b>true</b> if {\em *this} angle is equal to <tt>value</tt>
348 		*/
349 		bool isEquivalent(TAngle angle) const;
350 
351 		//@}
352 		/**	@name	Debugging and Diagnostics
353 		*/
354 		//@{
355 
356 		/**	Test whether instance is valid.
357 				Always returns true
358 				@return bool <b>true</b>
359 		*/
360 		bool isValid () const;
361 
362 		/** Internal state dump.
363 				Dump the current internal state of {\em *this} to
364 				the output ostream <b>  s </b> with dumping depth <b>  depth </b>.
365 				@param   s - output stream where to output the internal state of {\em *this}
366 				@param   depth - the dumping depth
367 		*/
368 		void dump(std::ostream& s = std::cout, Size depth = 0) const;
369 
370 		//@}
371 		/**	@name	Attributes
372 		*/
373 		//@{
374 
375 		/**	The value
376 		*/
377 		T value;
378 
379 		//@}
380 	};
381 	//@}
382 
383 	template <typename T>
TAngle()384 	TAngle<T>::TAngle()
385 		: value((T)0)
386 	{
387 	}
388 
389 	template <typename T>
TAngle(const TAngle & angle)390 	TAngle<T>::TAngle(const TAngle& angle)
391 		:	value((T)angle.value)
392 	{
393 	}
394 
395 	template <typename T>
TAngle(const T & new_value,bool radian)396 	TAngle<T>::TAngle(const T& new_value, bool radian)
397 		:	value((radian == true)
398 			 ? (T)new_value
399 			 : (T)BALL_ANGLE_DEGREE_TO_RADIAN((double)new_value))
400 	{
401 	}
402 
403 	template <typename T>
swap(TAngle & angle)404 	void TAngle<T>::swap(TAngle& angle)
405 	{
406 		T temp = value;
407 		value = angle.value;
408 		angle.value = temp;
409 	}
410 
411 	template <typename T>
set(const TAngle & angle)412 	void TAngle<T>::set(const TAngle& angle)
413 	{
414 		value = angle.value;
415 	}
416 
417 	template <typename T>
set(const T & new_value,bool radian)418 	void TAngle<T>::set(const T& new_value, bool radian)
419 	{
420 		value = (radian == true)
421 			 ? new_value
422 			 : BALL_ANGLE_DEGREE_TO_RADIAN(new_value);
423 	}
424 
425 	template <typename T>
426 	TAngle<T>& TAngle<T>::operator = (const TAngle& angle)
427 	{
428 		value = angle.value;
429 		return *this;
430 	}
431 
432 	template <typename T>
433 	TAngle<T>& TAngle<T>::operator = (const T& new_value)
434 	{
435 		value = new_value;
436 		return *this;
437 	}
438 
439 	template <typename T>
get(TAngle & angle)440 	void TAngle<T>::get(TAngle& angle) const
441 	{
442 		angle.value = value;
443 	}
444 
445 	template <typename T>
get(T & val,bool radian)446 	void TAngle<T>::get(T& val, bool radian) const
447 	{
448 		val = (radian == true)
449 					 ? value
450 					 : BALL_ANGLE_RADIAN_TO_DEGREE(value);
451 	}
452 
453 	template <typename T>
T()454 	TAngle<T>::operator T () const
455 	{
456 		return value;
457 	}
458 
459 	template <typename T>
toRadian()460 	T TAngle<T>::toRadian() const
461 	{
462 		return value;
463 	}
464 
465 	template <typename T>
toRadian(const T & degree)466 	T TAngle<T>::toRadian(const T& degree)
467 	{
468 		return BALL_ANGLE_DEGREE_TO_RADIAN(degree);
469 	}
470 
471 	template <typename T>
toDegree()472 	T TAngle<T>::toDegree() const
473 	{
474 		if (value == (T) 0.0) return (T) 0.0;
475 		return BALL_ANGLE_RADIAN_TO_DEGREE(value);
476 	}
477 
478 	template <typename T>
toDegree(const T & radian)479 	T TAngle<T>::toDegree(const T& radian)
480 	{
481 		if (radian == (T) 0.0) return (T) 0.0;
482 		return BALL_ANGLE_RADIAN_TO_DEGREE(radian);
483 	}
484 
485 	template <typename T>
normalize(Range range)486 	void TAngle<T>::normalize(Range range)
487 	{
488 		if (range == RANGE__UNLIMITED)
489 		{
490 			return;
491 		}
492 
493 		long mod_factor = (long)(value / (2 * Constants::PI));
494 		value -= mod_factor * (Constants::PI * 2);
495 
496 		while (Maths::isGreater(value, (Constants::PI * 2)))
497 		{
498 			value -= (Constants::PI * 2);
499 		}
500 		while (Maths::isLess(value, -(Constants::PI * 2)))
501 		{
502 			value += (Constants::PI * 2);
503 		}
504 		if (range == RANGE__SIGNED) // invariant: -180 to 180:
505 		{
506 			if (Maths::isGreater(value, Constants::PI))
507 			{
508 				value -= (Constants::PI * 2);
509 			}
510 		}
511 		else
512 		{ // invariant: 0 to 360:
513 			if (Maths::isLess(value, 0))
514 			{
515 				value += (Constants::PI * 2);
516 			}
517 		}
518 	}
519 
520 	template <typename T>
negate()521 	void TAngle<T>::negate()
522 	{
523 		value = -value;
524 	}
525 
526 	template <typename T>
527 	TAngle<T> TAngle<T>::operator + () const
528 	{
529 		return *this;
530 	}
531 
532 	template <typename T>
533 	TAngle<T> TAngle<T>::operator - () const
534 	{
535 		return TAngle(-value);
536 	}
537 
538 	template <typename T>
539 	TAngle<T>& TAngle<T>::operator += (const TAngle& angle)
540 	{
541 		value += angle.value;
542 		return *this;
543 	}
544 
545 	template <typename T>
546 	TAngle<T>& TAngle<T>::operator += (const T& val)
547 	{
548 		value += val;
549 		return *this;
550 	}
551 
552 	template <typename T>
553 	TAngle<T> TAngle<T>::operator + (const TAngle& angle)
554 	{
555 		return TAngle(value + angle.value);
556 	}
557 
558 	template <typename T>
559 	TAngle<T>& TAngle<T>::operator -= (const TAngle& angle)
560 	{
561 		value -= angle.value;
562 		return *this;
563 	}
564 
565 	template <typename T>
566 	TAngle<T>& TAngle<T>::operator -= (const T& val)
567 	{
568 		value -= val;
569 		return *this;
570 	}
571 
572 	template <typename T>
573 	TAngle<T> TAngle<T>::operator - (const TAngle& angle)
574 	{
575 		return TAngle(value - angle.value);
576 	}
577 
578 	template <typename T>
579 	TAngle<T>& TAngle<T>::operator *= (const TAngle& angle)
580 	{
581 		value *= angle.value;
582 		return *this;
583 	}
584 
585 	template <typename T>
586 	TAngle<T>& TAngle<T>::operator *= (const T& val)
587 	{
588 		value *= val;
589 		return *this;
590 	}
591 
592 	template <typename T>
593 	TAngle<T>& TAngle<T>::operator /= (const TAngle& angle)
594 	{
595 		if (angle.value == 0)
596 		{
597 			throw Exception::DivisionByZero(__FILE__, __LINE__);
598 		}
599 		value /= angle.value;
600 		return *this;
601 	}
602 
603 
604 	template <typename T>
605 	TAngle<T>& TAngle<T>::operator /= (const T& val)
606 	{
607 		if (val == 0)
608 		{
609 			throw Exception::DivisionByZero(__FILE__, __LINE__);
610 		}
611 
612 		value /= val;
613 		return *this;
614 	}
615 
616 
617 	template <typename T>
618 	TAngle<T> TAngle<T>::operator / (const TAngle<T>& val)
619 	{
620 		if (val.value == 0)
621 		{
622 			throw Exception::DivisionByZero(__FILE__, __LINE__);
623 		}
624 
625 		return TAngle(value / val.value);
626 	}
627 
628 	template <typename T>
629 	bool TAngle<T>::operator == (const TAngle& angle) const
630 	{
631 		return Maths::isEqual(value, angle.value);
632 	}
633 
634 	template <typename T>
635 	bool TAngle<T>::operator != (const TAngle& angle) const
636 	{
637 		return Maths::isNotEqual(value, angle.value);
638 	}
639 
640 	template <typename T>
641 	bool TAngle<T>::operator < (const TAngle& angle) const
642 	{
643 		return Maths::isLess(value, angle.value);
644 	}
645 
646 	template <typename T>
647 	bool TAngle<T>::operator < (const T& val) const
648 	{
649 		return Maths::isLess(value, val);
650 	}
651 
652 	template <typename T>
653 	bool TAngle<T>::operator <= (const TAngle& angle) const
654 	{
655 		return Maths::isLessOrEqual(value, angle.value);
656 	}
657 
658 	template <typename T>
659 	bool TAngle<T>::operator >= (const TAngle& angle) const
660 	{
661 		return Maths::isGreaterOrEqual(value, angle.value);
662 	}
663 
664 	template <typename T>
665 	bool TAngle<T>::operator > (const TAngle& angle) const
666 
667 	{
668 		return Maths::isGreater(value, angle.value);
669 	}
670 
671 	template <typename T>
isEquivalent(TAngle angle)672 	bool TAngle<T>::isEquivalent(TAngle angle) const
673 	{
674 		TAngle this_angle(*this);
675 
676 		this_angle.normalize(RANGE__UNSIGNED);
677 		angle.normalize(RANGE__UNSIGNED);
678 
679 		return (this_angle == angle);
680 	}
681 
682 	template <typename T>
isValid()683 	bool TAngle<T>::isValid() const
684 	{
685 		return true;
686 	}
687 
688 	template <typename T>
dump(std::ostream & s,Size depth)689 	void TAngle<T>::dump(std::ostream& s, Size depth) const
690 	{
691 		BALL_DUMP_STREAM_PREFIX(s);
692 
693 		BALL_DUMP_HEADER(s, this, this);
694 
695 		BALL_DUMP_DEPTH(s, depth);
696 		s << "  value: " << value << std::endl;
697 
698 		BALL_DUMP_STREAM_SUFFIX(s);
699 	}
700 
701 	/**	The Default Angle Type.
702 			If double precision is not needed, <tt>TAngle<float></tt> should
703 			be used. It is predefined as <tt>Angle</tt> for convenience.
704 	*/
705 	typedef TAngle<float> Angle;
706 
707 	/**	Multiplication operator.
708 			Multiplies a number with an angle.
709 	*/
710 	template <typename T>
711 	BALL_INLINE
712 	TAngle<T> operator * (const T& val, const TAngle<T>& angle)
713 	{
714 		return TAngle<T>(val * angle.value);
715 	}
716 
717 	/**	Plus operator.
718 			Adds a number with an angle (in rad!)
719 	*/
720 	template <typename T>
721 	BALL_INLINE
722 	TAngle<T> operator + (const T& val, const TAngle<T>& angle)
723 	{
724 		return TAngle<T>(val + angle.value);
725 	}
726 
727 	/**	Minus operator.
728 			Subtracts the value of an angle (in rad!) from a number.
729 	*/
730 	template <typename T>
731 	BALL_INLINE
732 	TAngle<T> operator - (const T& val, const TAngle<T>& angle)
733 	{
734 		return TAngle<T>(val - angle.value);
735 	}
736 
737 	/**	Input Operator.
738 			Reads the value (in radians) of an angle from an instream using T::operator >>
739 	*/
740 	template <typename T>
741 	std::istream& operator >> (std::istream& s, TAngle<T>& angle)
742 	{
743 		char c;
744 		s >> c >> angle.value >> c;
745 		return s;
746 	}
747 
748 	/**	Output Operator.
749 			Writes the value of the angle to an output stream.
750 			The stream operator <tt>operator <<</tt> has to be defined
751 			for the template parameter <tt>T</tt>.
752 	*/
753 	template <typename T>
754 	std::ostream& operator << (std::ostream& s, const TAngle<T>& angle)
755 	{
756 		s << '(' << angle.value << ')';
757 
758 		return s;
759 	}
760 
761 } // namespace BALL
762 
763 #endif // BALL_MATHS_ANGLE_H
764