Working on 1827966: "Angles are recalculated to 360 mod". Experimenting with angles...
[synfig.git] / ETL / trunk / ETL / _angle.h
1 #include <stdio.h>
2 /* ========================================================================
3 ** Extended Template and Library
4 ** Angle Abstraction Class Implementation
5 ** $Id$
6 **
7 ** Copyright (c) 2002 Robert B. Quattlebaum Jr.
8 ** Copyright (c) 2007 Chris Moore
9 **
10 ** This package is free software; you can redistribute it and/or
11 ** modify it under the terms of the GNU General Public License as
12 ** published by the Free Software Foundation; either version 2 of
13 ** the License, or (at your option) any later version.
14 **
15 ** This package is distributed in the hope that it will be useful,
16 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18 ** General Public License for more details.
19 **
20 ** === N O T E S ===========================================================
21 **
22 ** This is an internal header file, included by other ETL headers.
23 ** You should not attempt to use it directly.
24 **
25 ** ========================================================================= */
26
27 /* === S T A R T =========================================================== */
28
29 #ifndef __ETL_ANGLE_H
30 #define __ETL_ANGLE_H
31
32 /* === H E A D E R S ======================================================= */
33
34 #include <cmath>
35 #include <functional>
36
37 /* === M A C R O S ========================================================= */
38
39 #ifndef PI
40 # define PI (3.1415926535897932384626433832795029L)
41 # define HALF_PI (PI/2)
42 #endif
43
44 #define ANGLE_EPSILON (1.0e-6)
45
46 /* === T Y P E D E F S ===================================================== */
47
48 /* === C L A S S E S & S T R U C T S ======================================= */
49
50 _ETL_BEGIN_NAMESPACE
51
52 // ========================================================================
53 /*!     \class  angle   _angle.h        ETL/angle
54 **      \brief  Abstraction of the concept of an angle
55 **  \see angle::deg, angle::rad, angle::rot, angle::sin, angle::cos, angle::tan, fastangle
56 **      \writeme
57 */
58 class angle
59 {
60 public:
61         typedef float value_type;
62
63 protected:
64         typedef value_type unit;
65
66         unit v; //! Stored in radians; positive values indicate counter-clockwise.
67
68 public:
69
70         /*
71         ** Arithmetic Operators
72         */
73
74         const angle     &
75         operator+=(const angle &rhs)
76         { v+=rhs.v; return *this; }
77
78         const angle     &
79         operator-=(const angle &rhs)
80         { v-=rhs.v; return *this; }
81
82         const angle     &
83         operator*=(const unit &rhs)
84         { v*=rhs; return *this; }
85
86         const angle     &
87         operator/=(const unit &rhs)
88         { v/=rhs; return *this; }
89
90         //! Angle Addition Operator
91         angle
92         operator+(const angle &rhs)const
93         { return angle(*this)+=rhs; }
94
95         //! Angle Subtraction Operator
96         /*! \sa angle dist(const angle &) */
97         angle
98         operator-(const angle &rhs)const
99         { return angle(*this)-=rhs; }
100
101         //! Angle Scalar Multiplication Operator
102         /*! This operator will multiply the given
103                 angle by the given scalar value. */
104         angle
105         operator*(const unit &rhs)const
106         { return angle(*this)*=rhs; }
107
108         angle
109         operator/(const unit &rhs)const
110         { return angle(*this)/=rhs; }
111
112         //! Angle Negation
113         angle
114         operator-()const
115         {
116                 angle ret;
117                 ret.v=-v;
118                 return ret;
119         }
120
121         //! 180 degree rotation operator
122         /*! Returns the angle directly opposite of
123                 the given angle, and will yield a result
124                 between 0 and 2PI */
125         angle
126         operator~()const
127         {
128                 angle ret;
129                 ret.v = v+PI;
130                 return ret.mod();
131         }
132
133 #ifdef ETL_WRAP_ANGLES
134         /*! Returns true if the shortest
135                 angle from the left-hand to the
136                 right-hand side is counter-clockwise */
137         bool
138         operator<(const angle &rhs)const
139         { return dist(rhs).v<(value_type)0.0; }
140
141         /*! Returns true if the shortest
142                 angle from the left-hand to the
143                 right-hand side is clockwise */
144         bool
145         operator>(const angle &rhs)const
146         { return dist(rhs).v>(value_type)0.0; }
147
148         /*! Returns true if the shortest
149                 angle from the left-hand to the
150                 right-hand side is counter-clockwise,
151                 or if the angles are refer to the same
152                 point on the unit circle. */
153         bool
154         operator<=(const angle &rhs)const
155         { return dist(rhs).v<=(value_type)0.0; }
156
157         /*! Returns true if the shortest
158                 angle from the left-hand to the
159                 right-hand side is clockwise,
160                 or if the angles are refer to the same
161                 point on the unit circle. */
162         bool
163         operator>=(const angle &rhs)const
164         { return dist(rhs).v>=(value_type)0.0; }
165
166         /*! Returns true if the angles
167                 are refer to the same point
168                 on the unit circle. */
169         bool
170         operator==(const angle &rhs)const
171         { return std::abs(dist(rhs).v)<ANGLE_EPSILON; }
172
173         /*! Returns false if the angles
174                 are refer to the same point
175                 on the unit circle. */
176         bool
177         operator!=(const angle &rhs)const
178         { return std::abs(dist(rhs).v)>ANGLE_EPSILON; }
179 #else // ETL_WRAP_ANGLES
180         /*! Returns true if the left-hand
181                 side is less than the
182                 right-hand side */
183         bool
184         operator<(const angle &rhs)const
185         { return v < rhs.v; }
186
187         /*! Returns true if the left-hand
188                 side is greater than the
189                 right-hand side */
190         bool
191         operator>(const angle &rhs)const
192         { return v > rhs.v; }
193
194         /*! Returns true if the left-hand
195                 side is less or equal to the
196                 right-hand side */
197         bool
198         operator<=(const angle &rhs)const
199         { return v <= rhs.v; }
200
201         /*! Returns true if the left-hand
202                 side is greater than or equal
203                 to the right-hand side */
204         bool
205         operator>=(const angle &rhs)const
206         { return v >= rhs.v; }
207
208         /*! Returns true if the angles
209                 are the same, or close */
210         bool
211         operator==(const angle &rhs)const
212         { return std::abs(v - rhs.v)<ANGLE_EPSILON; }
213
214         /*! Returns false if the angles
215                 are different */
216         bool
217         operator!=(const angle &rhs)const
218                 { return std::abs(v - rhs.v)>ANGLE_EPSILON; }
219 #endif // ETL_WRAP_ANGLES
220
221         //! Absolute Angle Function
222         /*! This function will return the
223                 absolute value of the angle. */
224         angle
225         abs()const
226         {
227                 angle ret;
228                 ret.v=std::abs(v);
229                 return ret;
230         }
231
232         //! Angle Difference Function
233         /*! This function will return the
234                 shortest physical distance between
235                 two angles, from -PI/2 to PI/2
236                 \sa angle operator-(const angle &) */
237         angle
238         dist(const angle &rhs)const
239         {
240                 angle ret;
241                 ret.v=v-rhs.v;
242                 ret.v-=rot_floor(ret.v+PI);
243                 return ret;
244         }
245
246         //! Rotation Modulus
247         /*! This function will return the
248                 value of the angle between 0 and 2PI */
249         angle
250         mod()const
251         {
252                 angle ret(*this);
253                 ret.v-=rot_floor(ret.v);
254                 return ret;
255         }
256
257         //! Zero Rotation (0 degrees)
258         static angle
259         zero()
260         {
261                 angle ret;
262                 ret.v=0;
263                 return ret;
264         }
265
266         //! One Complete Rotation (360 degrees)
267         static angle
268         one()
269         {
270                 angle ret;
271                 ret.v=PI*2;
272                 return ret;
273         }
274
275         //! One Half Rotation (180 degrees)
276         static angle
277         half()
278         {
279                 angle ret;
280                 ret.v=PI;
281                 return ret;
282         }
283
284         bool operator!()const { return std::abs(mod().v) < ANGLE_EPSILON; }
285
286 private:
287
288         static value_type rot_floor(value_type x)
289         { return static_cast<value_type>(std::floor(x/(PI*2))*PI*2); }
290
291 public:
292         /*
293         ** Conversion Classes
294         */
295
296         class rad;
297         class deg;
298         class rot;
299
300         /*
301         ** Trigonometric Classes
302         */
303
304         class sin;
305         class cos;
306         class tan;
307
308         /*
309         ** Friend classes
310         */
311
312         friend class rad;
313         friend class deg;
314         friend class rot;
315         friend class sin;
316         friend class cos;
317         friend class tan;
318
319         /*
320         ** Deprecated
321         */
322
323 #ifndef ETL_NO_DEPRECATED
324         typedef rad             radians;
325         typedef deg             degrees;
326         typedef rot             rotations;
327 #endif
328 }; // END of class angle
329
330 // ========================================================================
331 /*!     \class  angle::rad      _angle.h        ETL/angle
332 **      \brief  Angle representation in radians
333 **      \see angle
334 **      \writeme
335 */
336 class angle::rad : public angle
337 {
338 public:
339         explicit rad(const value_type &x) { v=x; }
340         rad(const angle &a):angle(a) { }
341         rad     mod()const { return angle::mod(); }
342         rad dist(const angle &rhs)const { return angle::dist(rhs); }
343         value_type get()const { return v; }
344 #ifndef ETL_NO_DEPRECATED
345         // operator value_type()const ETL_DEPRECATED_FUNCTION;
346 #endif
347 }; // END of class angle::radians
348 // inline angle::rad::operator angle::value_type()const { return get(); }
349
350 // ========================================================================
351 /*!     \class  angle::deg      _angle.h        ETL/angle
352 **      \brief  Angle representation in degrees
353 **      \see angle
354 **      \writeme
355 */
356 class angle::deg : public angle
357 {
358 public:
359         explicit deg(const value_type &x) { v=x*((PI*2)/360); }
360         deg(const angle &a):angle(a) { }
361         deg     mod()const { return angle::mod(); }
362         deg dist(const angle &rhs)const { return angle::dist(rhs); }
363         value_type get()const { return v*360/(PI*2); }
364 #ifndef ETL_NO_DEPRECATED
365         // operator value_type()const ETL_DEPRECATED_FUNCTION;
366 #endif
367 }; // END of class angle::degrees
368 // inline angle::deg::operator angle::value_type()const { return get(); }
369
370 // ========================================================================
371 /*!     \class  angle::rot      _angle.h        ETL/angle
372 **      \brief  Angle representation in rotations
373 **      \see angle
374 **      \writeme
375 */
376 class angle::rot : public angle
377 {
378 public:
379         explicit rot(const value_type &x) { v=x*(PI*2); }
380         rot(const angle &a):angle(a) { }
381         rot mod()const { return angle::mod(); }
382         rot dist(const angle &rhs)const { return angle::dist(rhs); }
383         value_type get()const { return v/(PI*2); }
384 #ifndef ETL_NO_DEPRECATED
385         // operator value_type()const ETL_DEPRECATED_FUNCTION;
386 #endif
387 }; // END of class angle::rotations
388 // inline angle::rot::operator angle::value_type()const { return get(); }
389
390 // ========================================================================
391 /*!     \class  angle::sin      _angle.h        ETL/angle
392 **      \brief  Angle representation as a sine function
393 **      \see angle
394 **      \writeme
395 */
396 class angle::sin : public angle
397 {
398 public:
399         explicit sin(const value_type &x) { v=static_cast<value_type>(std::asin(x)); }
400         sin(const angle &a):angle(a) { }
401         sin     mod()const { return angle::mod(); }
402         sin dist(const angle &rhs)const { return angle::dist(rhs); }
403         value_type get()const { return static_cast<value_type>(std::sin(v)); }
404 #ifndef ETL_NO_DEPRECATED
405         // operator value_type()const ETL_DEPRECATED_FUNCTION;
406 #endif
407 }; // END of class angle::sin
408 // inline angle::sin::operator angle::value_type()const { return get(); }
409
410 // ========================================================================
411 /*!     \class  angle::cos      _angle.h        ETL/angle
412 **      \brief  Angle representation as a cosine function
413 **      \see angle
414 **      \writeme
415 */
416 class angle::cos : public angle
417 {
418 public:
419         explicit cos(const value_type &x)       { v=(value_type)(std::acos(x)); }
420         cos(const angle &a):angle(a) { }
421         cos     mod()const { return angle::mod(); }
422         cos dist(const angle &rhs)const { return angle::dist(rhs); }
423         value_type get()const { return (value_type)std::cos(v); }
424 #ifndef ETL_NO_DEPRECATED
425         // operator value_type()const ETL_DEPRECATED_FUNCTION;
426 #endif
427 }; // END of class angle::cos
428 // inline angle::cos::operator angle::value_type()const { return get(); }
429
430 // ========================================================================
431 /*!     \class  angle::tan      _angle.h        ETL/angle
432 **      \brief  Angle representation as a tangent function
433 **      \see angle
434 **      \writeme
435 */
436 class angle::tan : public angle
437 {
438 public:
439         explicit tan(const value_type &x)       { v=(value_type)(std::atan(x)); }
440         tan(const value_type &y,const value_type &x) { v=(value_type)(std::atan2(y,x)); }
441         tan(const angle &a):angle(a) { }
442         tan     mod()const { return angle::mod(); }
443         tan dist(const angle &rhs)const { return angle::dist(rhs); }
444         value_type get()const { return (value_type)std::tan(v); }
445 #ifndef ETL_NO_DEPRECATED
446         // operator value_type()const ETL_DEPRECATED_FUNCTION;
447 #endif
448 }; // END of class angle::tan
449 // inline angle::tan::operator angle::value_type()const { return get(); }
450
451 _ETL_END_NAMESPACE
452
453 //#include <iostream>
454
455 template <typename T>
456 struct affine_combo<etl::angle, T>
457 {
458         typedef T time_type;
459
460         //affine_combo() { std::cerr<<"affine_combo<etl::angle,float>: I was created!"<<std::endl; }
461         //~affine_combo() { std::cerr<<"affine_combo<etl::angle,float>: I was DELETED!"<<std::endl; }
462
463         etl::angle operator()(const etl::angle &a,const etl::angle &b,const time_type &t)const
464         {
465                 return b.dist(a)*(float)t+a;
466         }
467
468         etl::angle reverse(const etl::angle &x, const etl::angle &b, const time_type &t)const
469         {
470                 return x.dist(b*(float)t)*(float)(time_type(1)/(time_type(1)-t));
471         }
472 };
473
474 template <>
475 struct distance_func<etl::angle> : public std::binary_function<etl::angle, etl::angle, etl::angle>
476 {
477         etl::angle operator()(const etl::angle &a,const etl::angle &b)const
478         {
479                 etl::angle delta=b.dist(a);
480                 //if(delta<etl::angle::zero())
481                 //      return delta+etl::angle::one();
482                 return delta;
483         }
484
485         etl::angle cook(const etl::angle &x)const { return x; }
486         etl::angle uncook(const etl::angle &x)const { return x; }
487 };
488
489 /* === E N D =============================================================== */
490
491 #endif