ViewVC Help
View File | Revision Log | Show Annotations | Root Listing
root/cvsroot/UserCode/MitCommon/MathTools/interface/Angle.h
Revision: 1.2
Committed: Fri Mar 20 13:33:19 2009 UTC (16 years, 1 month ago) by loizides
Content type: text/plain
Branch: MAIN
CVS Tags: Mit_009c, Mit_009b, Mit_009a, Mit_009
Changes since 1.1: +276 -249 lines
Log Message:
Cleanup

File Contents

# User Rev Content
1 loizides 1.1 //--------------------------------------------------------------------------------------------------
2 loizides 1.2 // $Id: Angle.h,v 1.1 2008/09/17 04:01:50 loizides Exp $
3 loizides 1.1 //
4     // Angle classes, with automatic range checking. SignedAngle ranges from -PI to PI, UnsignedAngle
5     // from 0 to 2PI. The two types of angle convert implicitly into double.
6     //
7     // The Angle classes reimplement (inline) most arithmetic operators, instead of relying on the
8     // implicit conversion to double and converting the result back when it is assigned to an Angle
9     // variable. There are two reasons for this:
10     //
11     // 1) Temporary values are kept in range (example: std::cout << alpha+beta)
12     // 2) Optimization (the difference of two Angles is guaranteed to lie less
13     // than 2PI outside the allowed range, for example)
14     //
15     // The only exception is multiplication: the "2" in "2 * alpha" could be interpreted as a length. If
16     // you want the result of a multiplication to be bounded, assign it to a temporary Angle, or use *=.
17     //
18     // Due to operator ambiguity, some mixed-type arithmetics might fail:
19     // for example, (int + Angle) or (Angle / long)
20     // The most common operations are supported:
21     // double +- angle; angle +-/ double; angle / int
22     //
23     // Comparison between Angles is done via conversion to double. Make sure you do not compare a
24     // SignedAngle to an UnsignedAngle.
25     //
26     // Since the bounds and return types for the two classes are different, operators cannot be factored
27     // in a single superclass.
28     //
29     // In C++, implicit conversion operators are shallow - they are not nested. Therefore, if you want
30     // to convert a SignedAngle into an UnsignedAngle, you need an intermediate cast into double. For
31     // example:
32     //
33     // SignedAngle s; UnsignedAngle u = double(s);
34     //
35     // Adding a direct conversion between the two types of angle would result in several ambiguities.
36     //
37 loizides 1.2 // Author: C.Paus (stolen from CDF implementation of Paolo Gatti, University of Padova / INFN,
38     // therefore not all our coding conventions fulfilled)
39 loizides 1.1 //--------------------------------------------------------------------------------------------------
40    
41     #ifndef MITCOMMON_MATHTOOLS_ANGLE_H
42     #define MITCOMMON_MATHTOOLS_ANGLE_H
43    
44     #include <iostream>
45     #include <limits>
46     #include <math.h>
47    
48     namespace mithep
49     {
50     //--------------------------------------------------------------------------------------------------
51     //
52     // Signed angles, ranging from -PI to +PI
53     //
54     //--------------------------------------------------------------------------------------------------
55     class SignedAngle
56     {
57     public:
58     // Constructor
59     SignedAngle(double angle = 0.0);
60    
61     // No destructor; use standard copy constructor and assignment operator
62    
63     // Implicit conversion to double
64     operator double() const;
65    
66     // Self-modifying operations
67     SignedAngle& operator += (const SignedAngle& other);
68     SignedAngle& operator -= (const SignedAngle& other);
69     SignedAngle& operator *= (double other);
70     SignedAngle& operator /= (double other);
71    
72     // Other operations
73     friend SignedAngle operator + (double me, const SignedAngle& other);
74     SignedAngle operator + (const SignedAngle& other) const;
75     SignedAngle operator + (double other) const;
76     friend SignedAngle operator - (double me, const SignedAngle& other);
77     SignedAngle operator - (const SignedAngle& other) const;
78     SignedAngle operator - (double other) const;
79     SignedAngle operator / (double other) const;
80     SignedAngle operator / (int other) const;
81    
82     // I/O
83     friend std::ostream& operator << (std::ostream& out, const SignedAngle& me)
84     { out << me.fValue; return out; }
85    
86     friend std::istream& operator >> (std::istream& in, SignedAngle& me)
87     { in >> me.fValue; me.FixRangeSlow(); return in; }
88    
89     private:
90     // Enforce the correct range for the angle's value. The first version is faster, but assumes
91     // the current value is within 2PI of the correct range. The second version is slower but
92     // always works
93     void FixRangeFast();
94     void FixRangeSlow();
95    
96     double fValue;
97     };
98    
99    
100     //--------------------------------------------------------------------------------------------------
101     //
102     // Unsigned angles, ranging from 0 to 2PI
103     //
104     //--------------------------------------------------------------------------------------------------
105     class UnsignedAngle
106     {
107     public:
108     // Constructor
109     UnsignedAngle(double angle = 0.0);
110    
111     // No destructor; use standard copy constructor and assignment operator
112    
113     // Implicit conversion to double
114     operator double() const;
115    
116     // Self-modifying operations
117     UnsignedAngle& operator += (const UnsignedAngle& other);
118     UnsignedAngle& operator -= (const UnsignedAngle& other);
119     UnsignedAngle& operator *= (double other);
120     UnsignedAngle& operator /= (double other);
121    
122     // Other operations
123     friend UnsignedAngle operator + (double me, const UnsignedAngle& other);
124     UnsignedAngle operator + (const UnsignedAngle& other) const;
125     UnsignedAngle operator + (double other) const;
126     friend UnsignedAngle operator - (double me, const UnsignedAngle& other);
127     UnsignedAngle operator - (const UnsignedAngle& other) const;
128     UnsignedAngle operator - (double other) const;
129     UnsignedAngle operator / (double other) const;
130     UnsignedAngle operator / (int other) const;
131    
132     // I/O
133     friend std::ostream& operator << (std::ostream& out, const UnsignedAngle& me)
134     { out << me.fValue; return out; }
135     friend std::istream& operator >> (std::istream& in, UnsignedAngle& me)
136     { in >> me.fValue; me.FixRangeSlow(); return in; }
137    
138     private:
139     // Enforce the correct range for the angle's value. The first version is faster,
140     // but assumes the current value is within 2PI of the correct range.
141     // The second version is slower but always works.
142    
143     void FixRangeFast();
144     void FixRangeSlow();
145    
146     double fValue;
147     };
148    
149     // By default, "Angles" are unsigned (CDF convention: 0-2PI range).
150     typedef UnsignedAngle Angle;
151    
152 loizides 1.2 //--------------------------------------------------------------------------------------------------
153     inline
154     void mithep::SignedAngle::FixRangeFast()
155     {
156     if (fValue >= M_PI)
157 loizides 1.1 fValue -= 2 * M_PI;
158 loizides 1.2 else if (fValue < -M_PI)
159     fValue += 2 * M_PI;
160     }
161 loizides 1.1
162 loizides 1.2 //--------------------------------------------------------------------------------------------------
163     inline
164     void mithep::SignedAngle::FixRangeSlow()
165     {
166     if (fValue < -M_PI) {
167     if (fValue < double(std::numeric_limits<int>::min()) * 2 * M_PI)
168     std::cout << "@SUB=SignedAngle::FixRangeSlow"
169     << "Angle out of range: " << fValue << std::endl;
170     else {
171     int shift = int((M_PI - fValue) / (2 * M_PI));
172     fValue += shift * 2 * M_PI;
173     }
174 loizides 1.1 }
175 loizides 1.2 // The previous step might have brought -3PI to +PI, so no 'else' here.
176     if (fValue >= M_PI) {
177     if (fValue > double(std::numeric_limits<int>::max()) * 2 * M_PI) {
178     std::cout << "@SUB=SignedAngle::FixRangeSlow"
179     << "Angle out of range: " << fValue << std::endl;
180     }
181     else {
182     int shift = int((fValue + M_PI) / (2 * M_PI));
183     fValue -= shift * 2 * M_PI;
184     }
185 loizides 1.1 }
186     }
187    
188    
189 loizides 1.2 //--------------------------------------------------------------------------------------------------
190     inline
191     mithep::SignedAngle::SignedAngle(double angle)
192     : fValue(angle)
193     {
194     // Constructor
195 loizides 1.1
196 loizides 1.2 FixRangeSlow();
197     }
198 loizides 1.1
199 loizides 1.2 //--------------------------------------------------------------------------------------------------
200     inline
201     mithep::SignedAngle::operator double() const
202     {
203     // Implicit conversion to double
204     return fValue;
205     }
206 loizides 1.1
207     // Self-modifying operations
208 loizides 1.2 //--------------------------------------------------------------------------------------------------
209     inline
210     mithep::SignedAngle& mithep::SignedAngle::operator += (const mithep::SignedAngle& other)
211     {
212     fValue += other.fValue;
213     FixRangeFast(); // other.fValue is guaranteed to be in range
214     return *this;
215     }
216 loizides 1.1
217 loizides 1.2 //--------------------------------------------------------------------------------------------------
218 loizides 1.1 inline
219 loizides 1.2 mithep::SignedAngle& mithep::SignedAngle::operator -= (const mithep::SignedAngle& other)
220     {
221     fValue -= other.fValue;
222     FixRangeFast(); // other.fValue is guaranteed to be in range
223     return *this;
224     }
225 loizides 1.1
226 loizides 1.2 //--------------------------------------------------------------------------------------------------
227     inline
228     mithep::SignedAngle& mithep::SignedAngle::operator *= (double other)
229     {
230     fValue *= other;
231     FixRangeSlow();
232     return *this;
233     }
234 loizides 1.1
235 loizides 1.2 //--------------------------------------------------------------------------------------------------
236     inline
237     mithep::SignedAngle& mithep::SignedAngle::operator /= (double other)
238     {
239     fValue /= other;
240     FixRangeSlow();
241     return *this;
242     }
243 loizides 1.1
244     // Other operations
245 loizides 1.2 //--------------------------------------------------------------------------------------------------
246     inline
247     mithep::SignedAngle operator + (double me, const mithep::SignedAngle& other)
248     {
249     mithep::SignedAngle result(me);
250     result += other;
251     return result;
252     }
253 loizides 1.1
254 loizides 1.2 //--------------------------------------------------------------------------------------------------
255     inline
256     mithep::SignedAngle mithep::SignedAngle::operator + (const mithep::SignedAngle& other) const
257     {
258     mithep::SignedAngle result(*this);
259     result += other;
260     return result;
261     }
262 loizides 1.1
263 loizides 1.2 //--------------------------------------------------------------------------------------------------
264     inline
265     mithep::SignedAngle mithep::SignedAngle::operator + (double other) const
266     {
267     return mithep::SignedAngle(fValue + other);
268     }
269 loizides 1.1
270 loizides 1.2 //--------------------------------------------------------------------------------------------------
271     inline
272     mithep::SignedAngle operator - (double me, const mithep::SignedAngle& other)
273     {
274     mithep::SignedAngle result(me);
275     result -= other;
276     return result;
277     }
278 loizides 1.1
279 loizides 1.2 //--------------------------------------------------------------------------------------------------
280     inline
281     mithep::SignedAngle mithep::SignedAngle::operator - (const mithep::SignedAngle& other) const
282     {
283     mithep::SignedAngle result(*this);
284     result -= other;
285     return result;
286     }
287 loizides 1.1
288 loizides 1.2 //--------------------------------------------------------------------------------------------------
289     inline
290     mithep::SignedAngle mithep::SignedAngle::operator - (double other) const
291     {
292     return mithep::SignedAngle(fValue - other);
293     }
294 loizides 1.1
295 loizides 1.2 //--------------------------------------------------------------------------------------------------
296     inline
297     mithep::SignedAngle mithep::SignedAngle::operator / (double other) const
298     {
299     mithep::SignedAngle result(*this);
300     result /= other;
301     return result;
302     }
303 loizides 1.1
304 loizides 1.2 //--------------------------------------------------------------------------------------------------
305     inline
306     mithep::SignedAngle mithep::SignedAngle::operator / (int other) const
307     {
308     mithep::SignedAngle result(*this);
309     result /= other;
310     return result;
311     }
312 loizides 1.1
313 loizides 1.2 //--------------------------------------------------------------------------------------------------
314     inline
315     void mithep::UnsignedAngle::FixRangeFast()
316     {
317     if (fValue >= 2 * M_PI)
318     fValue -= 2 * M_PI;
319     else if (fValue < 0)
320     fValue += 2 * M_PI;
321     }
322 loizides 1.1
323 loizides 1.2 //--------------------------------------------------------------------------------------------------
324     inline
325     void mithep::UnsignedAngle::FixRangeSlow()
326     {
327     if (fValue < 0) {
328     if (fValue < double(std::numeric_limits<int>::min()) * 2 * M_PI)
329     std::cout << "@SUB=UnsignedAngle::FixRangeSlow"
330     << "Angle out of range: " << fValue << std::endl;
331     else {
332     int shift = 1 - int(fValue / (2 * M_PI));
333     fValue += shift * 2 * M_PI;
334     }
335 loizides 1.1 }
336     // The previous step might have brought -2PI to +2PI, so no 'else' here.
337 loizides 1.2 if (fValue >= 2 * M_PI) {
338     if (fValue > double(std::numeric_limits<int>::max()) * 2 * M_PI)
339     std::cout << "@SUB=UnsignedAngle::FixRangeSlow"
340     << "Angle out of range: " << fValue << std::endl;
341     else {
342     int shift = int(fValue / (2 * M_PI));
343     fValue -= shift * 2 * M_PI;
344     }
345 loizides 1.1 }
346     }
347    
348 loizides 1.2 //--------------------------------------------------------------------------------------------------
349     inline
350     mithep::UnsignedAngle::UnsignedAngle(double angle)
351     : fValue(angle)
352     {
353     // Constructor
354     FixRangeSlow();
355     }
356 loizides 1.1
357 loizides 1.2 //--------------------------------------------------------------------------------------------------
358     inline
359     mithep::UnsignedAngle::operator double() const
360     {
361     // Implicit conversion to double
362    
363     return fValue;
364     }
365 loizides 1.1
366     // Self-modifying operations
367 loizides 1.2 //--------------------------------------------------------------------------------------------------
368     inline
369     mithep::UnsignedAngle& mithep::UnsignedAngle::operator += (const mithep::UnsignedAngle& other)
370     {
371     fValue += other.fValue;
372     FixRangeFast(); // other.fValue is guaranteed to be in range
373     return *this;
374     }
375 loizides 1.1
376 loizides 1.2 //--------------------------------------------------------------------------------------------------
377     inline
378     mithep::UnsignedAngle& mithep::UnsignedAngle::operator -= (const mithep::UnsignedAngle& other)
379     {
380     fValue -= other.fValue;
381     FixRangeFast(); // other.fValue is guaranteed to be in range
382     return *this;
383     }
384 loizides 1.1
385 loizides 1.2 //--------------------------------------------------------------------------------------------------
386     inline
387     mithep::UnsignedAngle& mithep::UnsignedAngle::operator *= (double other)
388     {
389     fValue *= other;
390     FixRangeSlow();
391     return *this;
392     }
393 loizides 1.1
394 loizides 1.2 //--------------------------------------------------------------------------------------------------
395     inline
396     mithep::UnsignedAngle& mithep::UnsignedAngle::operator /= (double other)
397     {
398     fValue /= other;
399     FixRangeSlow();
400     return *this;
401     }
402 loizides 1.1
403     // Other operations
404 loizides 1.2 //--------------------------------------------------------------------------------------------------
405     inline
406     mithep::UnsignedAngle operator + (double me, const mithep::UnsignedAngle& other)
407     {
408     mithep::UnsignedAngle result(me);
409     result += other;
410     return result;
411     }
412 loizides 1.1
413 loizides 1.2 //--------------------------------------------------------------------------------------------------
414     inline
415     mithep::UnsignedAngle mithep::UnsignedAngle::operator + (const mithep::UnsignedAngle& other) const
416     {
417     mithep::UnsignedAngle result(*this);
418     result += other;
419     return result;
420     }
421 loizides 1.1
422 loizides 1.2 //--------------------------------------------------------------------------------------------------
423     inline
424     mithep::UnsignedAngle mithep::UnsignedAngle::operator + (double other) const
425     {
426     return mithep::UnsignedAngle(fValue + other);
427     }
428 loizides 1.1
429 loizides 1.2 //--------------------------------------------------------------------------------------------------
430     inline
431     mithep::UnsignedAngle operator - (double me, const mithep::UnsignedAngle& other)
432     {
433     mithep::UnsignedAngle result(me);
434     result -= other;
435     return result;
436     }
437 loizides 1.1
438 loizides 1.2 //--------------------------------------------------------------------------------------------------
439     inline
440     mithep::UnsignedAngle mithep::UnsignedAngle::operator - (const mithep::UnsignedAngle& other) const
441     {
442     mithep::UnsignedAngle result(*this);
443     result -= other;
444     return result;
445     }
446 loizides 1.1
447 loizides 1.2 //--------------------------------------------------------------------------------------------------
448     inline
449     mithep::UnsignedAngle mithep::UnsignedAngle::operator - (double other) const
450     {
451     return mithep::UnsignedAngle(fValue - other);
452     }
453 loizides 1.1
454 loizides 1.2 //--------------------------------------------------------------------------------------------------
455     inline
456     mithep::UnsignedAngle mithep::UnsignedAngle::operator / (double other) const
457     {
458     mithep::UnsignedAngle result(*this);
459     result /= other;
460     return result;
461     }
462 loizides 1.1
463 loizides 1.2 //--------------------------------------------------------------------------------------------------
464     inline
465     mithep::UnsignedAngle mithep::UnsignedAngle::operator / (int other) const
466     {
467     mithep::UnsignedAngle result(*this);
468     result /= other;
469     return result;
470     }
471 loizides 1.1 } //close namespace here because of friend declarations
472     #endif