...

Source file src/github.com/golang/geo/s1/angle.go

Documentation: github.com/golang/geo/s1

     1  // Copyright 2014 Google Inc. All rights reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package s1
    16  
    17  import (
    18  	"math"
    19  	"strconv"
    20  )
    21  
    22  // Angle represents a 1D angle. The internal representation is a double precision
    23  // value in radians, so conversion to and from radians is exact.
    24  // Conversions between E5, E6, E7, and Degrees are not always
    25  // exact. For example, Degrees(3.1) is different from E6(3100000) or E7(31000000).
    26  //
    27  // The following conversions between degrees and radians are exact:
    28  //
    29  //	    Degree*180 == Radian*math.Pi
    30  //	Degree*(180/n) == Radian*(math.Pi/n)     for n == 0..8
    31  //
    32  // These identities hold when the arguments are scaled up or down by any power
    33  // of 2. Some similar identities are also true, for example,
    34  //
    35  //	Degree*60 == Radian*(math.Pi/3)
    36  //
    37  // But be aware that this type of identity does not hold in general. For example,
    38  //
    39  //	Degree*3 != Radian*(math.Pi/60)
    40  //
    41  // Similarly, the conversion to radians means that (Angle(x)*Degree).Degrees()
    42  // does not always equal x. For example,
    43  //
    44  //	(Angle(45*n)*Degree).Degrees() == 45*n     for n == 0..8
    45  //
    46  // but
    47  //
    48  //	(60*Degree).Degrees() != 60
    49  //
    50  // When testing for equality, you should allow for numerical errors (ApproxEqual)
    51  // or convert to discrete E5/E6/E7 values first.
    52  type Angle float64
    53  
    54  // Angle units.
    55  const (
    56  	Radian Angle = 1
    57  	Degree       = (math.Pi / 180) * Radian
    58  
    59  	E5 = 1e-5 * Degree
    60  	E6 = 1e-6 * Degree
    61  	E7 = 1e-7 * Degree
    62  )
    63  
    64  // Radians returns the angle in radians.
    65  func (a Angle) Radians() float64 { return float64(a) }
    66  
    67  // Degrees returns the angle in degrees.
    68  func (a Angle) Degrees() float64 { return float64(a / Degree) }
    69  
    70  // round returns the value rounded to nearest as an int32.
    71  // This does not match C++ exactly for the case of x.5.
    72  func round(val float64) int32 {
    73  	if val < 0 {
    74  		return int32(val - 0.5)
    75  	}
    76  	return int32(val + 0.5)
    77  }
    78  
    79  // InfAngle returns an angle larger than any finite angle.
    80  func InfAngle() Angle {
    81  	return Angle(math.Inf(1))
    82  }
    83  
    84  // isInf reports whether this Angle is infinite.
    85  func (a Angle) isInf() bool {
    86  	return math.IsInf(float64(a), 0)
    87  }
    88  
    89  // E5 returns the angle in hundred thousandths of degrees.
    90  func (a Angle) E5() int32 { return round(a.Degrees() * 1e5) }
    91  
    92  // E6 returns the angle in millionths of degrees.
    93  func (a Angle) E6() int32 { return round(a.Degrees() * 1e6) }
    94  
    95  // E7 returns the angle in ten millionths of degrees.
    96  func (a Angle) E7() int32 { return round(a.Degrees() * 1e7) }
    97  
    98  // Abs returns the absolute value of the angle.
    99  func (a Angle) Abs() Angle { return Angle(math.Abs(float64(a))) }
   100  
   101  // Normalized returns an equivalent angle in (-π, π].
   102  func (a Angle) Normalized() Angle {
   103  	rad := math.Remainder(float64(a), 2*math.Pi)
   104  	if rad <= -math.Pi {
   105  		rad = math.Pi
   106  	}
   107  	return Angle(rad)
   108  }
   109  
   110  func (a Angle) String() string {
   111  	return strconv.FormatFloat(a.Degrees(), 'f', 7, 64) // like "%.7f"
   112  }
   113  
   114  // ApproxEqual reports whether the two angles are the same up to a small tolerance.
   115  func (a Angle) ApproxEqual(other Angle) bool {
   116  	return math.Abs(float64(a)-float64(other)) <= epsilon
   117  }
   118  
   119  // BUG(dsymonds): The major differences from the C++ version are:
   120  //   - no unsigned E5/E6/E7 methods
   121  

View as plain text