ViewVC Help
View File | Revision Log | Show Annotations | Root Listing
root/cvsroot/UserCode/MitCommon/MathTools/interface/Angle.h
Revision: 1.1
Committed: Wed Sep 17 04:01:50 2008 UTC (16 years, 7 months ago) by loizides
Content type: text/plain
Branch: MAIN
CVS Tags: Mit_008pre2, Mit_008pre1, Mit_006b, Mit_006a, Mit_006, Mit_005, Mit_004
Log Message:
Moved MitVertex contents to MitCommon. MitVertex therefore is obsolute and should not be touched anymore.

File Contents

# User Rev Content
1 loizides 1.1 //--------------------------------------------------------------------------------------------------
2     // $Id: Angle.h,v 1.4 2008/09/14 15:28:19 loizides Exp $
3     //
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     // Author: C.Paus (stolen from CDF implementation of Paolo Gatti, University of Padova / INFN)
38     //--------------------------------------------------------------------------------------------------
39    
40     #ifndef MITCOMMON_MATHTOOLS_ANGLE_H
41     #define MITCOMMON_MATHTOOLS_ANGLE_H
42    
43     #include <iostream>
44     #include <limits>
45     #include <math.h>
46    
47     namespace mithep
48     {
49     //--------------------------------------------------------------------------------------------------
50     //
51     // Signed angles, ranging from -PI to +PI
52     //
53     //--------------------------------------------------------------------------------------------------
54     class SignedAngle
55     {
56     public:
57     // Constructor
58     SignedAngle(double angle = 0.0);
59    
60     // No destructor; use standard copy constructor and assignment operator
61    
62     // Implicit conversion to double
63     operator double() const;
64    
65     // Self-modifying operations
66     SignedAngle& operator += (const SignedAngle& other);
67     SignedAngle& operator -= (const SignedAngle& other);
68     SignedAngle& operator *= (double other);
69     SignedAngle& operator /= (double other);
70    
71     // Other operations
72     friend SignedAngle operator + (double me, const SignedAngle& other);
73     SignedAngle operator + (const SignedAngle& other) const;
74     SignedAngle operator + (double other) const;
75     friend SignedAngle operator - (double me, const SignedAngle& other);
76     SignedAngle operator - (const SignedAngle& other) const;
77     SignedAngle operator - (double other) const;
78     SignedAngle operator / (double other) const;
79     SignedAngle operator / (int other) const;
80    
81     // I/O
82     friend std::ostream& operator << (std::ostream& out, const SignedAngle& me)
83     { out << me.fValue; return out; }
84    
85     friend std::istream& operator >> (std::istream& in, SignedAngle& me)
86     { in >> me.fValue; me.FixRangeSlow(); return in; }
87    
88     private:
89     // Enforce the correct range for the angle's value. The first version is faster, but assumes
90     // the current value is within 2PI of the correct range. The second version is slower but
91     // always works
92     void FixRangeFast();
93     void FixRangeSlow();
94    
95     double fValue;
96     };
97    
98    
99     //--------------------------------------------------------------------------------------------------
100     //
101     // Unsigned angles, ranging from 0 to 2PI
102     //
103     //--------------------------------------------------------------------------------------------------
104     class UnsignedAngle
105     {
106     public:
107     // Constructor
108     UnsignedAngle(double angle = 0.0);
109    
110     // No destructor; use standard copy constructor and assignment operator
111    
112     // Implicit conversion to double
113     operator double() const;
114    
115     // Self-modifying operations
116     UnsignedAngle& operator += (const UnsignedAngle& other);
117     UnsignedAngle& operator -= (const UnsignedAngle& other);
118     UnsignedAngle& operator *= (double other);
119     UnsignedAngle& operator /= (double other);
120    
121     // Other operations
122     friend UnsignedAngle operator + (double me, const UnsignedAngle& other);
123     UnsignedAngle operator + (const UnsignedAngle& other) const;
124     UnsignedAngle operator + (double other) const;
125     friend UnsignedAngle operator - (double me, const UnsignedAngle& other);
126     UnsignedAngle operator - (const UnsignedAngle& other) const;
127     UnsignedAngle operator - (double other) const;
128     UnsignedAngle operator / (double other) const;
129     UnsignedAngle operator / (int other) const;
130    
131     // I/O
132     friend std::ostream& operator << (std::ostream& out, const UnsignedAngle& me)
133     { out << me.fValue; return out; }
134     friend std::istream& operator >> (std::istream& in, UnsignedAngle& me)
135     { in >> me.fValue; me.FixRangeSlow(); return in; }
136    
137     private:
138     // Enforce the correct range for the angle's value. The first version is faster,
139     // but assumes the current value is within 2PI of the correct range.
140     // The second version is slower but always works.
141    
142     void FixRangeFast();
143     void FixRangeSlow();
144    
145     double fValue;
146     };
147    
148     // By default, "Angles" are unsigned (CDF convention: 0-2PI range).
149     typedef UnsignedAngle Angle;
150    
151     inline
152     void mithep::SignedAngle::FixRangeFast()
153     {
154     if (fValue >= M_PI)
155     fValue -= 2 * M_PI;
156     else if (fValue < -M_PI)
157     fValue += 2 * M_PI;
158     }
159    
160     inline
161     void mithep::SignedAngle::FixRangeSlow()
162     {
163     if (fValue < -M_PI) {
164     if (fValue < double(std::numeric_limits<int>::min()) * 2 * M_PI)
165     std::cout << "@SUB=SignedAngle::FixRangeSlow"
166     << "Angle out of range: " << fValue << std::endl;
167     else {
168     int shift = int((M_PI - fValue) / (2 * M_PI));
169     fValue += shift * 2 * M_PI;
170     }
171     }
172     // The previous step might have brought -3PI to +PI, so no 'else' here.
173     if (fValue >= M_PI) {
174     if (fValue > double(std::numeric_limits<int>::max()) * 2 * M_PI) {
175     std::cout << "@SUB=SignedAngle::FixRangeSlow"
176     << "Angle out of range: " << fValue << std::endl;
177     }
178     else {
179     int shift = int((fValue + M_PI) / (2 * M_PI));
180     fValue -= shift * 2 * M_PI;
181     }
182     }
183     }
184    
185     // Constructor
186    
187     inline
188     mithep::SignedAngle::SignedAngle(double angle)
189     : fValue(angle)
190     {
191     FixRangeSlow();
192     }
193    
194     // Implicit conversion to double
195    
196     inline
197     mithep::SignedAngle::operator double() const
198     {
199     return fValue;
200     }
201    
202     // Self-modifying operations
203    
204     inline
205     mithep::SignedAngle& mithep::SignedAngle::operator += (const mithep::SignedAngle& other)
206     {
207     fValue += other.fValue;
208     FixRangeFast(); // other.fValue is guaranteed to be in range
209     return *this;
210     }
211    
212     inline
213     mithep::SignedAngle& mithep::SignedAngle::operator -= (const mithep::SignedAngle& other)
214     {
215     fValue -= other.fValue;
216     FixRangeFast(); // other.fValue is guaranteed to be in range
217     return *this;
218     }
219    
220     inline
221     mithep::SignedAngle& mithep::SignedAngle::operator *= (double other)
222     {
223     fValue *= other;
224     FixRangeSlow();
225     return *this;
226     }
227    
228     inline
229     mithep::SignedAngle& mithep::SignedAngle::operator /= (double other)
230     {
231     fValue /= other;
232     FixRangeSlow();
233     return *this;
234     }
235    
236     // Other operations
237    
238     inline
239     mithep::SignedAngle operator + (double me, const mithep::SignedAngle& other)
240     {
241     mithep::SignedAngle result(me);
242     result += other;
243     return result;
244     }
245    
246     inline
247     mithep::SignedAngle mithep::SignedAngle::operator + (const mithep::SignedAngle& other) const
248     {
249     mithep::SignedAngle result(*this);
250     result += other;
251     return result;
252     }
253    
254     inline
255     mithep::SignedAngle mithep::SignedAngle::operator + (double other) const
256     {
257     return mithep::SignedAngle(fValue + other);
258     }
259    
260     inline
261     mithep::SignedAngle operator - (double me, const mithep::SignedAngle& other)
262     {
263     mithep::SignedAngle result(me);
264     result -= other;
265     return result;
266     }
267    
268     inline
269     mithep::SignedAngle mithep::SignedAngle::operator - (const mithep::SignedAngle& other) const
270     {
271     mithep::SignedAngle result(*this);
272     result -= other;
273     return result;
274     }
275    
276     inline
277     mithep::SignedAngle mithep::SignedAngle::operator - (double other) const
278     {
279     return mithep::SignedAngle(fValue - other);
280     }
281    
282     inline
283     mithep::SignedAngle mithep::SignedAngle::operator / (double other) const
284     {
285     mithep::SignedAngle result(*this);
286     result /= other;
287     return result;
288     }
289    
290     inline
291     mithep::SignedAngle mithep::SignedAngle::operator / (int other) const
292     {
293     mithep::SignedAngle result(*this);
294     result /= other;
295     return result;
296     }
297    
298     inline
299     void mithep::UnsignedAngle::FixRangeFast()
300     {
301     if (fValue >= 2 * M_PI)
302     fValue -= 2 * M_PI;
303     else if (fValue < 0)
304     fValue += 2 * M_PI;
305     }
306    
307     inline
308     void mithep::UnsignedAngle::FixRangeSlow()
309     {
310     if (fValue < 0) {
311     if (fValue < double(std::numeric_limits<int>::min()) * 2 * M_PI)
312     std::cout << "@SUB=UnsignedAngle::FixRangeSlow"
313     << "Angle out of range: " << fValue << std::endl;
314     else {
315     int shift = 1 - int(fValue / (2 * M_PI));
316     fValue += shift * 2 * M_PI;
317     }
318     }
319     // The previous step might have brought -2PI to +2PI, so no 'else' here.
320     if (fValue >= 2 * M_PI) {
321     if (fValue > double(std::numeric_limits<int>::max()) * 2 * M_PI)
322     std::cout << "@SUB=UnsignedAngle::FixRangeSlow"
323     << "Angle out of range: " << fValue << std::endl;
324     else {
325     int shift = int(fValue / (2 * M_PI));
326     fValue -= shift * 2 * M_PI;
327     }
328     }
329     }
330    
331     // Constructor
332    
333     inline
334     mithep::UnsignedAngle::UnsignedAngle(double angle)
335     : fValue(angle)
336     {
337     FixRangeSlow();
338     }
339    
340     // Implicit conversion to double
341    
342     inline
343     mithep::UnsignedAngle::operator double() const
344     {
345     return fValue;
346     }
347    
348     // Self-modifying operations
349    
350     inline
351     mithep::UnsignedAngle& mithep::UnsignedAngle::operator += (const mithep::UnsignedAngle& other)
352     {
353     fValue += other.fValue;
354     FixRangeFast(); // other.fValue is guaranteed to be in range
355     return *this;
356     }
357    
358     inline
359     mithep::UnsignedAngle& mithep::UnsignedAngle::operator -= (const mithep::UnsignedAngle& other)
360     {
361     fValue -= other.fValue;
362     FixRangeFast(); // other.fValue is guaranteed to be in range
363     return *this;
364     }
365    
366     inline
367     mithep::UnsignedAngle& mithep::UnsignedAngle::operator *= (double other)
368     {
369     fValue *= other;
370     FixRangeSlow();
371     return *this;
372     }
373    
374     inline
375     mithep::UnsignedAngle& mithep::UnsignedAngle::operator /= (double other)
376     {
377     fValue /= other;
378     FixRangeSlow();
379     return *this;
380     }
381    
382     // Other operations
383    
384     inline
385     mithep::UnsignedAngle operator + (double me, const mithep::UnsignedAngle& other)
386     {
387     mithep::UnsignedAngle result(me);
388     result += other;
389     return result;
390     }
391    
392     inline
393     mithep::UnsignedAngle mithep::UnsignedAngle::operator + (const mithep::UnsignedAngle& other) const
394     {
395     mithep::UnsignedAngle result(*this);
396     result += other;
397     return result;
398     }
399    
400     inline
401     mithep::UnsignedAngle mithep::UnsignedAngle::operator + (double other) const
402     {
403     return mithep::UnsignedAngle(fValue + other);
404     }
405    
406     inline
407     mithep::UnsignedAngle operator - (double me, const mithep::UnsignedAngle& other)
408     {
409     mithep::UnsignedAngle result(me);
410     result -= other;
411     return result;
412     }
413    
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    
422     inline
423     mithep::UnsignedAngle mithep::UnsignedAngle::operator - (double other) const
424     {
425     return mithep::UnsignedAngle(fValue - other);
426     }
427    
428     inline
429     mithep::UnsignedAngle mithep::UnsignedAngle::operator / (double other) const
430     {
431     mithep::UnsignedAngle result(*this);
432     result /= other;
433     return result;
434     }
435    
436     inline
437     mithep::UnsignedAngle mithep::UnsignedAngle::operator / (int other) const
438     {
439     mithep::UnsignedAngle result(*this);
440     result /= other;
441     return result;
442     }
443    
444     } //close namespace here because of friend declarations
445     #endif