...

Source file src/github.com/golang/geo/s1/angle_test.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  	"testing"
    20  )
    21  
    22  // float64Eq reports whether the two values are within the default epsilon.
    23  func float64Eq(x, y float64) bool {
    24  	return float64Near(x, y, epsilon)
    25  }
    26  
    27  // float64Near reports whether the two values are within the specified epsilon.
    28  func float64Near(x, y, eps float64) bool {
    29  	return math.Abs(x-y) <= eps
    30  }
    31  
    32  func TestEmptyValue(t *testing.T) {
    33  	var a Angle
    34  	if rad := a.Radians(); rad != 0 {
    35  		t.Errorf("Empty value of Angle was %v, want 0", rad)
    36  	}
    37  }
    38  
    39  func TestPiRadiansExactly180Degrees(t *testing.T) {
    40  	if rad := (math.Pi * Radian).Radians(); rad != math.Pi {
    41  		t.Errorf("(π * Radian).Radians() was %v, want π", rad)
    42  	}
    43  	if deg := (math.Pi * Radian).Degrees(); deg != 180 {
    44  		t.Errorf("(π * Radian).Degrees() was %v, want 180", deg)
    45  	}
    46  	if rad := (180 * Degree).Radians(); rad != math.Pi {
    47  		t.Errorf("(180 * Degree).Radians() was %v, want π", rad)
    48  	}
    49  	if deg := (180 * Degree).Degrees(); deg != 180 {
    50  		t.Errorf("(180 * Degree).Degrees() was %v, want 180", deg)
    51  	}
    52  
    53  	if deg := (math.Pi / 2 * Radian).Degrees(); deg != 90 {
    54  		t.Errorf("(π/2 * Radian).Degrees() was %v, want 90", deg)
    55  	}
    56  
    57  	// Check negative angles.
    58  	if deg := (-math.Pi / 2 * Radian).Degrees(); deg != -90 {
    59  		t.Errorf("(-π/2 * Radian).Degrees() was %v, want -90", deg)
    60  	}
    61  	if rad := (-45 * Degree).Radians(); rad != -math.Pi/4 {
    62  		t.Errorf("(-45 * Degree).Radians() was %v, want -π/4", rad)
    63  	}
    64  }
    65  
    66  func TestE5E6E7Representation(t *testing.T) {
    67  	// NOTE(dsymonds): This first test gives a variance in the 16th decimal place. I should track that down.
    68  	exp, act := (-45 * Degree).Radians(), (-4500000 * E5).Radians()
    69  	if math.Abs(exp-act) > 1e-15 {
    70  		t.Errorf("(-4500000 * E5).Radians() was %v, want %v", act, exp)
    71  	}
    72  	if exp, act := (-60 * Degree).Radians(), (-60000000 * E6).Radians(); exp != act {
    73  		t.Errorf("(-60000000 * E6).Radians() was %v, want %v", act, exp)
    74  	}
    75  	if exp, act := (75 * Degree).Radians(), (750000000 * E7).Radians(); exp != act {
    76  		t.Errorf("(-750000000 * E7).Radians() was %v, want %v", act, exp)
    77  	}
    78  
    79  	if exp, act := int32(-17256123), (-172.56123 * Degree).E5(); exp != act {
    80  		t.Errorf("(-172.56123°).E5() was %v, want %v", act, exp)
    81  	}
    82  	if exp, act := int32(12345678), (12.345678 * Degree).E6(); exp != act {
    83  		t.Errorf("(12.345678°).E6() was %v, want %v", act, exp)
    84  	}
    85  	if exp, act := int32(-123456789), (-12.3456789 * Degree).E7(); exp != act {
    86  		t.Errorf("(-12.3456789°).E7() was %v, want %v", act, exp)
    87  	}
    88  
    89  	roundingTests := []struct {
    90  		have Angle
    91  		want int32
    92  	}{
    93  		{0.500000001, 1},
    94  		{-0.500000001, -1},
    95  		{0.499999999, 0},
    96  		{-0.499999999, 0},
    97  	}
    98  	for _, test := range roundingTests {
    99  		if act := (test.have * 1e-5 * Degree).E5(); test.want != act {
   100  			t.Errorf("(%v°).E5() was %v, want %v", test.have, act, test.want)
   101  		}
   102  		if act := (test.have * 1e-6 * Degree).E6(); test.want != act {
   103  			t.Errorf("(%v°).E6() was %v, want %v", test.have, act, test.want)
   104  		}
   105  		if act := (test.have * 1e-7 * Degree).E7(); test.want != act {
   106  			t.Errorf("(%v°).E7() was %v, want %v", test.have, act, test.want)
   107  		}
   108  	}
   109  }
   110  
   111  func TestNormalizeCorrectlyCanonicalizesAngles(t *testing.T) {
   112  	tests := []struct {
   113  		in, want float64 // both in degrees
   114  	}{
   115  		{360, 0},
   116  		{-90, -90},
   117  		{-180, 180},
   118  		{180, 180},
   119  		{540, 180},
   120  		{-270, 90},
   121  	}
   122  	for _, test := range tests {
   123  		deg := (Angle(test.in) * Degree).Normalized().Degrees()
   124  		if deg != test.want {
   125  			t.Errorf("Normalized %.0f° = %v, want %v", test.in, deg, test.want)
   126  		}
   127  	}
   128  }
   129  
   130  func TestAngleString(t *testing.T) {
   131  	if s, exp := (180 * Degree).String(), "180.0000000"; s != exp {
   132  		t.Errorf("(180°).String() = %q, want %q", s, exp)
   133  	}
   134  }
   135  
   136  func TestDegreesVsRadians(t *testing.T) {
   137  	// This test tests the exactness of specific values between degrees and radians.
   138  	for k := -8; k <= 8; k++ {
   139  		if got, want := Angle(45*k)*Degree, Angle((float64(k)*math.Pi)/4)*Radian; got != want {
   140  			t.Errorf("45°*%d != (%d*π)/4 radians (%f vs %f)", k, k, got, want)
   141  		}
   142  
   143  		if got, want := (Angle(45*k) * Degree).Degrees(), float64(45*k); got != want {
   144  			t.Errorf("Angle(45°*%d).Degrees() != 45*%d, (%f vs %f)", k, k, got, want)
   145  		}
   146  	}
   147  
   148  	for k := uint64(0); k < 30; k++ {
   149  		m := 1 << k
   150  		n := float64(m)
   151  		for _, test := range []struct{ deg, rad float64 }{
   152  			{180, 1},
   153  			{60, 3},
   154  			{36, 5},
   155  			{20, 9},
   156  			{4, 45},
   157  		} {
   158  			if got, want := Angle(test.deg/n)*Degree, Angle(math.Pi/(test.rad*n))*Radian; got != want {
   159  				t.Errorf("%v°/%d != π/%v*%d rad (%f vs %f)", test.deg, m, test.rad, m, got, want)
   160  			}
   161  		}
   162  	}
   163  
   164  	// We also spot check a non-identity.
   165  	if got := (60 * Degree).Degrees(); float64Eq(got, 60) {
   166  		t.Errorf("Angle(60).Degrees() == 60, but should not (%f vs %f)", got, 60.0)
   167  	}
   168  }
   169  
   170  // TODO(roberts): Differences from C++
   171  //   Benchmarking code.
   172  

View as plain text