// Angle classes, with automatic range checking. // SignedAngle ranges from -PI to PI, UnsignedAngle from 0 to 2PI. // The two types of angle convert implicitly into double. // // The Angle classes reimplement (inline) most arithmetic operators, // instead of relying on the implicit conversion to double and converting // the result back when it is assigned to an Angle variable. There are two // reasons for this: // 1) Temporary values are kept in range (example: cout << alpha+beta) // 2) Optimization (the difference of two Angles is guaranteed to lie less // than 2PI outside the allowed range, for example) // // The only exception is multiplication: the "2" in "2 * alpha" could be // interpreted as a length. If you want the result of a multiplication to be // bounded, assign it to a temporary Angle, or use *=. // // Due to operator ambiguity, some mixed-type arithmetics might fail: // for example, (int + Angle) or (Angle / long) // The most common operations are supported: // double +- angle; angle +-/ double; angle / int // // Comparison between Angles is done via conversion to double. Make sure // you do not compare a SignedAngle to an UnsignedAngle. // // Since the bounds and return types for the two classes are different, // operators cannot be factored in a single superclass. // // In C++, implicit conversion operators are shallow - they are not nested. // Therefore, if you want to convert a SignedAngle into an UnsignedAngle, // you need an intermediate cast into double. For example: // SignedAngle s; UnsignedAngle u = double(s); // Adding a direct conversion between the two types of angle would result // in several ambiguities. // // Author: Paolo Gatti, University of Padova / INFN #ifndef ANGLE_HH #define ANGLE_HH #include #include // Signed angles, ranging from -PI to PI class SignedAngle { public: // Constructor SignedAngle(double angle = 0.0); // No destructor; use standard copy constructor and assignment operator // Implicit conversion to double operator double() const; // Self-modifying operations SignedAngle& operator += (const SignedAngle& other); SignedAngle& operator -= (const SignedAngle& other); SignedAngle& operator *= (double other); SignedAngle& operator /= (double other); // Other operations friend SignedAngle operator + (double me, const SignedAngle& other); SignedAngle operator + (const SignedAngle& other) const; SignedAngle operator + (double other) const; friend SignedAngle operator - (double me, const SignedAngle& other); SignedAngle operator - (const SignedAngle& other) const; SignedAngle operator - (double other) const; SignedAngle operator / (double other) const; SignedAngle operator / (int other) const; // I/O friend std::ostream& operator << (std::ostream& out, const SignedAngle& me); friend std::istream& operator >> (std::istream& in, SignedAngle& me); private: // Enforce the correct range for the angle's value. The first version is // faster, but assumes the current value is within 2PI of the correct range. // The second version is slower but always works. void fixRangeFast(); void fixRangeSlow(); double _value; }; // Unsigned angles, ranging from 0 to 2PI class UnsignedAngle { public: // Constructor UnsignedAngle(double angle = 0.0); // No destructor; use standard copy constructor and assignment operator // Implicit conversion to double operator double() const; // Self-modifying operations UnsignedAngle& operator += (const UnsignedAngle& other); UnsignedAngle& operator -= (const UnsignedAngle& other); UnsignedAngle& operator *= (double other); UnsignedAngle& operator /= (double other); // Other operations friend UnsignedAngle operator + (double me, const UnsignedAngle& other); UnsignedAngle operator + (const UnsignedAngle& other) const; UnsignedAngle operator + (double other) const; friend UnsignedAngle operator - (double me, const UnsignedAngle& other); UnsignedAngle operator - (const UnsignedAngle& other) const; UnsignedAngle operator - (double other) const; UnsignedAngle operator / (double other) const; UnsignedAngle operator / (int other) const; // I/O friend std::ostream& operator << (std::ostream& out, const UnsignedAngle& me); friend std::istream& operator >> (std::istream& in, UnsignedAngle& me); private: // Enforce the correct range for the angle's value. The first version is // faster, but assumes the current value is within 2PI of the correct range. // The second version is slower but always works. void fixRangeFast(); void fixRangeSlow(); double _value; }; // By default, "Angles" are unsigned (CDF convention: 0-2PI range). typedef UnsignedAngle Angle; #include "Angle.icc" #endif /* ANGLE_HH */