at artful, screen stabilizes
[feisty_meow.git] / graphiq / library / geometric / angle.h
1 #ifndef ANGLE_CLASS
2 #define ANGLE_CLASS
3
4 /*****************************************************************************\
5 *                                                                             *
6 *  Name   : angle                                                             *
7 *  Author : Chris Koeritz                                                     *
8 *                                                                             *
9 *******************************************************************************
10 * Copyright (c) 1992-$now By Author.  This program is free software; you can  *
11 * redistribute it and/or modify it under the terms of the GNU General Public  *
12 * License as published by the Free Software Foundation; either version 2 of   *
13 * the License or (at your option) any later version.  This is online at:      *
14 *     http://www.fsf.org/copyleft/gpl.html                                    *
15 * Please send any updates to: fred@gruntose.com                               *
16 \*****************************************************************************/
17
18 #include <basis/byte_array.h>
19 #include <basis/common_outcomes.h>
20 #include <basis/contracts.h>
21 #include <structures/object_packers.h>
22
23 #include <math.h>
24
25 namespace geometric {
26
27 //! Represents a geometric angle.
28
29 //! angles can be measured in degrees or radians in this class.
30 enum angular_units { DEGREES, RADIANS };
31
32 template <class contents>
33 class angle : public basis::packable
34 {
35 public:
36   DEFINE_CLASS_NAME("angle");
37
38   angle(contents inital_rotation = 0, angular_units unit = RADIANS);
39     //!< constructs a new angle with "initial_rotation" in the "unit".
40
41   void set(contents a, angular_units unit);
42     //!< sets the angle to a new rotation "a" in the "unit".
43   contents get(angular_units unit) const;
44     //!< retrieves the current angular measure.
45
46   angle operator - (void) const;
47     //!< returns the negation of this angle.
48
49   angle operator + (const angle &to_add) const;
50   angle operator - (const angle &to_subtract) const;
51   angle operator * (contents to_multiply) const;
52   angle operator / (contents to_divide) const;
53   angle &operator += (const angle &to_add);
54   angle &operator -= (const angle &to_subtract);
55   angle &operator *= (contents to_multiply);
56   angle &operator /= (contents to_divide);
57
58   contents sine() const;
59     //!< returns the sin function of this angle.
60   contents cosine() const;
61     //!< returns the cos function of this angle.
62   contents tangent() const;
63     //!< returns the tan function of this angle.
64
65   static angle arctangent(contents opposite, contents adjacent,
66           basis::outcome &retval);
67     //!< returns the atan of the angle.
68     /*!< the outcome will be set to OKAY if the function operated successfully.
69     otherwise it will be set to BAD_INPUT. */
70   static angle arccosine(contents adjacent, contents hypotenuse,
71           basis::outcome &retval);
72     //!< returns the acos of the angle.
73   static angle arcsine(contents opposite, contents hypotenuse,
74           basis::outcome &retval);
75     //!< returns the asin of the angle.
76
77   virtual int packed_size() const;
78   virtual void pack(basis::byte_array &packed_form) const;
79     //!< packs the angle for shipping in bytes.
80   virtual bool unpack(basis::byte_array &packed_form);
81     //!< unpacks the angle from the "packed_form".
82
83 private:
84   contents _theta;  //!< the held angular measure.
85
86   contents to_internal(contents initial, angular_units unit) const;
87     //!< converts the angle into the units we use inside the class.
88   contents from_internal(contents initial, angular_units unit) const;
89     //!< converts the angle from our internal measure into "unit" measure.
90 };
91
92 //////////////
93
94 //! double_angle provides a non-templated class for forward declarations.
95
96 class double_angle : public angle<double>
97 {
98 public:
99   double_angle(double init = 0, angular_units unit = RADIANS)
100       : angle<double>(init, unit) {}
101   double_angle(const angle<double> &to_copy) : angle<double>(to_copy) {}
102 };
103
104 //////////////
105
106 // implementation of larger methods below.
107
108 template <class contents>
109 angle<contents>::angle(contents a, angular_units unit) { set(a, unit); }
110
111 template <class contents>
112 angle<contents> angle<contents>::operator - (void) const
113 { angle<contents> to_return(*this); to_return *= -1; return to_return; }
114
115 template <class contents>
116 angle<contents> angle<contents>::operator + (const angle<contents> &a) const
117 { angle<contents> to_return(*this); to_return += a; return to_return; }
118
119 template <class contents>
120 angle<contents> angle<contents>::operator - (const angle<contents> &a) const
121 { angle<contents> to_return(*this); to_return -= a; return to_return; }
122
123 template <class contents>
124 angle<contents> angle<contents>::operator * (contents to_multiply) const
125 {
126   angle<contents> to_return(*this);
127   to_return *= to_multiply;
128   return to_return;
129 }
130
131 template <class contents>
132 angle<contents> angle<contents>::operator / (contents to_divide) const
133 { angle<contents> to_return(*this); to_return /= to_divide; return to_return; }
134
135 template <class contents>
136 angle<contents> &angle<contents>::operator += (const angle<contents> &a)
137 { _theta += a._theta; return *this; }
138
139 template <class contents>
140 angle<contents> &angle<contents>::operator -= (const angle<contents> &a)
141 { _theta -= a._theta; return *this; }
142
143 template <class contents>
144 angle<contents> &angle<contents>::operator *= (contents f)
145 { _theta *= f; return *this; }
146
147 template <class contents>
148 angle<contents> &angle<contents>::operator /= (contents f)
149 { _theta /= f; return *this; }
150
151 template <class contents>
152 contents angle<contents>::sine() const { return sin(_theta); }
153
154 template <class contents>
155 contents angle<contents>::cosine() const { return cos(_theta); }
156
157 template <class contents>
158 contents angle<contents>::tangent() const { return tan(_theta); }
159
160 template <class contents>
161 int angle<contents>::packed_size() const
162 {
163   basis::byte_array temp;
164 //hmmm: inefficient!
165   pack(temp);
166   return temp.length();
167 }
168
169 template <class contents>
170 void angle<contents>::pack(basis::byte_array &packed_form) const
171 { structures::attach(packed_form, _theta); }
172
173 template <class contents>
174 bool angle<contents>::unpack(basis::byte_array &packed_form)
175 { return structures::detach(packed_form, _theta); }
176
177 template <class contents>
178 contents angle<contents>::to_internal(contents a, angular_units unit) const
179 {
180   switch(unit) {
181     case RADIANS: return a;
182     case DEGREES: return a * PI_APPROX / 180.0;
183     default: return 0;
184   }
185 }
186
187 template <class contents>
188 contents angle<contents>::from_internal(contents a, angular_units unit) const
189 {
190   switch(unit) {
191     case RADIANS: return a;
192     case DEGREES: return a * 180.0 / PI_APPROX;
193     default: return 0;
194   }
195 }
196
197 template <class contents>
198 void angle<contents>::set(contents a, angular_units unit)
199 { _theta = to_internal(a, unit); }
200
201 template <class contents>
202 contents angle<contents>::get(angular_units unit) const
203 { return from_internal(_theta, unit); }
204
205 template <class contents>
206 angle<contents> angle<contents>::arccosine(contents adjacent,
207     contents hypotenuse, basis::outcome &retval)
208 {
209   contents d = adjacent / hypotenuse;
210   retval = basis::common::BAD_INPUT;
211   bounds_return(d, -1.0, 1.0, angle<contents>());
212   retval = basis::common::OKAY;
213   return angle<contents>(acos(d), RADIANS);
214 }
215
216 template <class contents>
217 angle<contents> angle<contents>::arcsine(contents opposite, contents hypotenuse,
218     basis::outcome &retval)
219 {
220   contents d = opposite / hypotenuse;
221   retval = basis::common::BAD_INPUT;
222   bounds_return(d, -1.0, 1.0, angle<contents>());
223   retval = basis::common::OKAY;
224   return angle<contents>(asin(d), RADIANS);
225 }
226
227 template <class contents>
228 angle<contents> angle<contents>::arctangent(contents opposite, contents adjacent,
229     basis::outcome &retval)
230 {
231   retval = basis::common::BAD_INPUT;
232   if ( (adjacent == 0.0) && (opposite == 0.0) ) return angle<contents>();
233   retval = basis::common::OKAY;
234   return angle<contents>(atan2(opposite, adjacent), RADIANS);
235 }
236
237 } // namespace.
238
239 #endif
240