// Copyright 2005 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS-IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // // Author: [email protected] (Eric Veach) // Needed on Windows to get |M_PI| from math.h. #ifdef _WIN32 #define _USE_MATH_DEFINES #endif #ifndef S2_S1ANGLE_H_ #define S2_S1ANGLE_H_ #include <math.h> #include <limits> #include <ostream> #include <type_traits> #include "s2/_fpcontractoff.h" #include "s2/util/math/mathutil.h" #include "s2/util/math/vector.h" class S2LatLng; // Avoid circular include of s2.h. // This must be a typedef rather than a type alias declaration because of SWIG. S2Point; // This class represents a one-dimensional angle (as opposed to a // two-dimensional solid angle). It has methods for converting angles to // or from radians, degrees, and the E5/E6/E7 representations (i.e. degrees // multiplied by 1e5/1e6/1e7 and rounded to the nearest integer). // // The internal representation is a double-precision value in radians, so // conversion to and from radians is exact. Conversions between E5, E6, E7, // and Degrees are not always exact; for example, Degrees(3.1) is different // from E6(3100000) or E7(310000000). However, the following properties are // guaranteed for any integer "n", provided that "n" is in the input range of // both functions: // // Degrees(n) == E6(1000000 * n) // Degrees(n) == E7(10000000 * n) // E6(n) == E7(10 * n) // // The corresponding properties are *not* true for E5, so if you use E5 then // don't test for exact equality when comparing to other formats such as // Degrees or E7. // // The following conversions between degrees and radians are exact: // // Degrees(180) == Radians(M_PI) // Degrees(45 * k) == Radians(k * M_PI / 4) for k == 0..8 // // These identities also hold when the arguments are scaled up or down by any // power of 2. Some similar identities are also true, for example, // Degrees(60) == Radians(M_PI / 3), but be aware that this type of identity // does not hold in general. For example, Degrees(3) != Radians(M_PI / 60). // // Similarly, the conversion to radians means that Angle::Degrees(x).degrees() // does not always equal "x". For example, // // S1Angle::Degrees(45 * k).degrees() == 45 * k for k == 0..8 // but S1Angle::Degrees(60).degrees() != 60. // // This means that when testing for equality, you should allow for numerical // errors (EXPECT_DOUBLE_EQ) or convert to discrete E5/E6/E7 values first. // // CAVEAT: All of the above properties depend on "double" being the usual // 64-bit IEEE 754 type (which is true on almost all modern platforms). // // This class is intended to be copied by value as desired. It uses // the default copy constructor and assignment operator. class S1Angle { … }; ////////////////// Implementation details follow //////////////////// inline constexpr S1Angle S1Angle::Infinity() { … } inline constexpr S1Angle S1Angle::Zero() { … } inline constexpr double S1Angle::radians() const { … } inline constexpr double S1Angle::degrees() const { … } // Note that the E5, E6, and E7 conversion involve two multiplications rather // than one. This is mainly for backwards compatibility (changing this would // break many tests), but it does have the nice side effect that conversions // between Degrees, E6, and E7 are exact when the arguments are integers. inline int32_t S1Angle::e5() const { … } inline int32_t S1Angle::e6() const { … } inline int32_t S1Angle::e7() const { … } inline S1Angle S1Angle::abs() const { … } inline bool operator==(S1Angle x, S1Angle y) { … } inline bool operator!=(S1Angle x, S1Angle y) { … } inline bool operator<(S1Angle x, S1Angle y) { … } inline bool operator>(S1Angle x, S1Angle y) { … } inline bool operator<=(S1Angle x, S1Angle y) { … } inline bool operator>=(S1Angle x, S1Angle y) { … } inline S1Angle operator-(S1Angle a) { … } inline S1Angle operator+(S1Angle a, S1Angle b) { … } inline S1Angle operator-(S1Angle a, S1Angle b) { … } inline S1Angle operator*(double m, S1Angle a) { … } inline S1Angle operator*(S1Angle a, double m) { … } inline S1Angle operator/(S1Angle a, double m) { … } inline double operator/(S1Angle a, S1Angle b) { … } inline S1Angle& S1Angle::operator+=(S1Angle a) { … } inline S1Angle& S1Angle::operator-=(S1Angle a) { … } inline S1Angle& S1Angle::operator*=(double m) { … } inline S1Angle& S1Angle::operator/=(double m) { … } inline double sin(S1Angle a) { … } inline double cos(S1Angle a) { … } inline double tan(S1Angle a) { … } inline constexpr S1Angle S1Angle::Radians(double radians) { … } inline constexpr S1Angle S1Angle::Degrees(double degrees) { … } inline constexpr S1Angle S1Angle::E5(int32_t e5) { … } inline constexpr S1Angle S1Angle::E6(int32_t e6) { … } inline constexpr S1Angle S1Angle::E7(int32_t e7) { … } inline constexpr S1Angle S1Angle::UnsignedE6(uint32_t e6) { … } inline constexpr S1Angle S1Angle::UnsignedE7(uint32_t e7) { … } // Writes the angle in degrees with 7 digits of precision after the // decimal point, e.g. "17.3745904". std::ostream& operator<<(std::ostream& os, S1Angle a); #endif // S2_S1ANGLE_H_