...

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

Documentation: github.com/golang/geo/s1

     1  // Copyright 2015 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  func TestChordAngleBasics(t *testing.T) {
    23  	var zeroChord ChordAngle
    24  	tests := []struct {
    25  		a, b     ChordAngle
    26  		lessThan bool
    27  		equal    bool
    28  	}{
    29  		{NegativeChordAngle, NegativeChordAngle, false, true},
    30  		{NegativeChordAngle, zeroChord, true, false},
    31  		{NegativeChordAngle, StraightChordAngle, true, false},
    32  		{NegativeChordAngle, InfChordAngle(), true, false},
    33  
    34  		{zeroChord, zeroChord, false, true},
    35  		{zeroChord, StraightChordAngle, true, false},
    36  		{zeroChord, InfChordAngle(), true, false},
    37  
    38  		{StraightChordAngle, StraightChordAngle, false, true},
    39  		{StraightChordAngle, InfChordAngle(), true, false},
    40  
    41  		{InfChordAngle(), InfChordAngle(), false, true},
    42  		{InfChordAngle(), StraightChordAngle, false, false},
    43  	}
    44  
    45  	for _, test := range tests {
    46  		if got := test.a < test.b; got != test.lessThan {
    47  			t.Errorf("%v should be less than %v", test.a, test.b)
    48  		}
    49  		if got := test.a == test.b; got != test.equal {
    50  			t.Errorf("%v should be equal to %v", test.a, test.b)
    51  		}
    52  	}
    53  }
    54  
    55  func TestChordAngleAngleEquality(t *testing.T) {
    56  	var zeroAngle Angle
    57  	var zeroChord ChordAngle
    58  
    59  	if InfAngle() != InfChordAngle().Angle() {
    60  		t.Errorf("Infinite ChordAngle to Angle = %v, want %v", InfChordAngle().Angle(), InfAngle())
    61  	}
    62  
    63  	oneEighty := 180 * Degree
    64  	if oneEighty != StraightChordAngle.Angle() {
    65  		t.Errorf("Right ChordAngle to degrees = %v, want %v", StraightChordAngle.Angle(), oneEighty)
    66  	}
    67  
    68  	if zeroAngle != zeroChord.Angle() {
    69  		t.Errorf("Zero ChordAngle to Angle = %v, want %v", zeroChord.Angle(), zeroAngle)
    70  	}
    71  
    72  	d := RightChordAngle.Angle().Degrees()
    73  	if !float64Near(90, d, 1e-13) {
    74  		t.Errorf("Right ChordAngle to degrees = %v, want %v", d, 90)
    75  	}
    76  
    77  }
    78  
    79  func TestChordAngleIsFunctions(t *testing.T) {
    80  	var zeroChord ChordAngle
    81  	tests := []struct {
    82  		have       ChordAngle
    83  		isNegative bool
    84  		isZero     bool
    85  		isInf      bool
    86  		isSpecial  bool
    87  	}{
    88  		{zeroChord, false, true, false, false},
    89  		{NegativeChordAngle, true, false, false, true},
    90  		{StraightChordAngle, false, false, false, false},
    91  		{InfChordAngle(), false, false, true, true},
    92  	}
    93  
    94  	for _, test := range tests {
    95  		if got := test.have < 0; got != test.isNegative {
    96  			t.Errorf("%v.isNegative() = %t, want %t", test.have, got, test.isNegative)
    97  		}
    98  		if got := test.have == 0; got != test.isZero {
    99  			t.Errorf("%v.isZero() = %t, want %t", test.have, got, test.isZero)
   100  		}
   101  		if got := test.have.IsInfinity(); got != test.isInf {
   102  			t.Errorf("%v.IsInfinity() = %t, want %t", test.have, got, test.isInf)
   103  		}
   104  		if got := test.have.isSpecial(); got != test.isSpecial {
   105  			t.Errorf("%v.isSpecial() = %t, want %t", test.have, got, test.isSpecial)
   106  		}
   107  	}
   108  }
   109  
   110  func TestChordAngleSuccessor(t *testing.T) {
   111  	if got, want := NegativeChordAngle.Successor(), ChordAngle(0.0); got != want {
   112  		t.Errorf("NegativeChordAngle.Successor() = %v, want %v", got, want)
   113  	}
   114  	if got, want := StraightChordAngle.Successor(), InfChordAngle(); got != want {
   115  		t.Errorf("StraightChordAngle.Successor() = %v, want %v", got, want)
   116  	}
   117  	if got, want := InfChordAngle().Successor(), InfChordAngle(); got != want {
   118  		t.Errorf("InfChordAngle.Successor() = %v, want %v", got, want)
   119  	}
   120  	x := NegativeChordAngle
   121  	for i := 0; i < 10; i++ {
   122  		if x >= x.Successor() {
   123  			t.Errorf("%d. %0.24f >= %0.24f.Successor() = %0.24f, want <", i, x, x, x.Successor())
   124  		}
   125  		x = x.Successor()
   126  	}
   127  }
   128  
   129  func TestChordAnglePredecessor(t *testing.T) {
   130  	if got, want := InfChordAngle().Predecessor(), StraightChordAngle; got != want {
   131  		t.Errorf("InfChordAngle.Predecessor() = %v, want %v", got, want)
   132  	}
   133  	if got, want := (ChordAngle(0)).Predecessor(), NegativeChordAngle; got != want {
   134  		t.Errorf("Zero ChordAngle.Predecessor() = %v, want %v", got, want)
   135  	}
   136  	if got, want := NegativeChordAngle.Predecessor(), NegativeChordAngle; got != want {
   137  		t.Errorf("NegativeChordAngle.Predecessor() = %v, want %v", got, want)
   138  	}
   139  	x := InfChordAngle()
   140  	for i := 0; i < 10; i++ {
   141  		if x <= x.Predecessor() {
   142  			t.Errorf("%v <= %v.Predecessor() = %v, want <", x, x, x.Predecessor())
   143  		}
   144  		x = x.Predecessor()
   145  	}
   146  }
   147  
   148  func TestChordAngleFromAngle(t *testing.T) {
   149  	for _, angle := range []float64{0, 1, -1, math.Pi} {
   150  		if got := ChordAngleFromAngle(Angle(angle)).Angle().Radians(); got != angle {
   151  			t.Errorf("ChordAngleFromAngle(Angle(%v)) = %v, want %v", angle, got, angle)
   152  		}
   153  	}
   154  
   155  	if got := ChordAngleFromAngle(Angle(math.Pi)); got != StraightChordAngle {
   156  		t.Errorf("a ChordAngle from an Angle of π = %v, want %v", got, StraightChordAngle)
   157  	}
   158  
   159  	if InfAngle() != ChordAngleFromAngle(InfAngle()).Angle() {
   160  		t.Errorf("converting infinite Angle to ChordAngle should yield infinite Angle")
   161  	}
   162  }
   163  
   164  func TestChordAngleArithmetic(t *testing.T) {
   165  	var (
   166  		zero      ChordAngle
   167  		degree30  = ChordAngleFromAngle(30 * Degree)
   168  		degree60  = ChordAngleFromAngle(60 * Degree)
   169  		degree90  = ChordAngleFromAngle(90 * Degree)
   170  		degree120 = ChordAngleFromAngle(120 * Degree)
   171  		degree180 = StraightChordAngle
   172  	)
   173  
   174  	addTests := []struct {
   175  		a, b ChordAngle
   176  		want ChordAngle
   177  	}{
   178  		{zero, zero, zero},
   179  		{degree60, zero, degree60},
   180  		{zero, degree60, degree60},
   181  		{degree30, degree60, degree90},
   182  		{degree60, degree30, degree90},
   183  		{degree180, zero, degree180},
   184  		{degree60, degree30, degree90},
   185  		{degree90, degree90, degree180},
   186  		{degree120, degree90, degree180},
   187  		{degree120, degree120, degree180},
   188  		{degree30, degree180, degree180},
   189  		{degree180, degree180, degree180},
   190  	}
   191  
   192  	subTests := []struct {
   193  		a, b ChordAngle
   194  		want ChordAngle
   195  	}{
   196  		{zero, zero, zero},
   197  		{degree60, degree60, zero},
   198  		{degree180, degree180, zero},
   199  		{zero, degree60, zero},
   200  		{degree30, degree90, zero},
   201  		{degree90, degree30, degree60},
   202  		{degree90, degree60, degree30},
   203  		{degree180, zero, degree180},
   204  	}
   205  
   206  	for _, test := range addTests {
   207  		if got := float64(test.a.Add(test.b)); !float64Eq(got, float64(test.want)) {
   208  			t.Errorf("%v.Add(%v) = %0.24f, want %0.24f", test.a.Angle().Degrees(), test.b.Angle().Degrees(), got, test.want)
   209  		}
   210  	}
   211  	for _, test := range subTests {
   212  		if got := float64(test.a.Sub(test.b)); !float64Eq(got, float64(test.want)) {
   213  			t.Errorf("%v.Sub(%v) = %0.24f, want %0.24f", test.a.Angle().Degrees(), test.b.Angle().Degrees(), got, test.want)
   214  		}
   215  	}
   216  }
   217  
   218  func TestChordAngleTrigonometry(t *testing.T) {
   219  	// Because of the way the math works out, the 9/10th's case has slightly more
   220  	// difference than all the other computations, so this gets a more generous
   221  	// epsilon to deal with that.
   222  	const epsilon = 1e-14
   223  	const iters = 40
   224  	for iter := 0; iter <= iters; iter++ {
   225  		radians := math.Pi * float64(iter) / float64(iters)
   226  		angle := ChordAngleFromAngle(Angle(radians))
   227  		if !float64Near(math.Sin(radians), angle.Sin(), epsilon) {
   228  			t.Errorf("(%d/%d)*π. %v.Sin() = %v, want %v", iter, iters, angle, angle.Sin(), math.Sin(radians))
   229  		}
   230  		if !float64Near(math.Cos(radians), angle.Cos(), epsilon) {
   231  			t.Errorf("(%d/%d)*π. %v.Cos() = %v, want %v", iter, iters, angle, angle.Cos(), math.Cos(radians))
   232  		}
   233  		// Since tan(x) is unbounded near pi/4, we map the result back to an
   234  		// angle before comparing. The assertion is that the result is equal to
   235  		// the tangent of a nearby angle.
   236  		if !float64Near(math.Atan(math.Tan(radians)), math.Atan(angle.Tan()), epsilon) {
   237  			t.Errorf("(%d/%d)*π. %v.Tan() = %v, want %v", iter, iters, angle, angle.Tan(), math.Tan(radians))
   238  		}
   239  	}
   240  
   241  	// Unlike Angle, ChordAngle can represent 90 and 180 degrees exactly.
   242  	angle90 := ChordAngleFromSquaredLength(2)
   243  	angle180 := ChordAngleFromSquaredLength(4)
   244  	if !float64Eq(1, angle90.Sin()) {
   245  		t.Errorf("%v.Sin() = %v, want 1", angle90, angle90.Sin())
   246  	}
   247  	if !float64Eq(0, angle90.Cos()) {
   248  		t.Errorf("%v.Cos() = %v, want 0", angle90, angle90.Cos())
   249  	}
   250  	if !math.IsInf(angle90.Tan(), 0) {
   251  		t.Errorf("%v.Tan() should be infinite, but was not.", angle90)
   252  	}
   253  	if !float64Eq(0, angle180.Sin()) {
   254  		t.Errorf("%v.Sin() = %v, want 0", angle180, angle180.Sin())
   255  	}
   256  	if !float64Eq(-1, angle180.Cos()) {
   257  		t.Errorf("%v.Cos() = %v, want -1", angle180, angle180.Cos())
   258  	}
   259  	if !float64Eq(0, angle180.Tan()) {
   260  		t.Errorf("%v.Tan() = %v, want 0", angle180, angle180.Tan())
   261  	}
   262  }
   263  
   264  func TestChordAngleExpanded(t *testing.T) {
   265  	var zero ChordAngle
   266  
   267  	tests := []struct {
   268  		have ChordAngle
   269  		add  float64
   270  		want ChordAngle
   271  	}{
   272  		{NegativeChordAngle, 5, NegativeChordAngle.Expanded(5)},
   273  		{InfChordAngle(), -5, InfChordAngle()},
   274  		{StraightChordAngle, 5, ChordAngleFromSquaredLength(5)},
   275  		{zero, -5, zero},
   276  		{ChordAngleFromSquaredLength(1.25), 0.25, ChordAngleFromSquaredLength(1.5)},
   277  		{ChordAngleFromSquaredLength(0.75), 0.25, ChordAngleFromSquaredLength(1)},
   278  	}
   279  
   280  	for _, test := range tests {
   281  		if got := test.have.Expanded(test.add); got != test.want {
   282  			t.Errorf("%v.Expanded(%v) = %v, want %v", test.have, test.add, got, test.want)
   283  		}
   284  	}
   285  }
   286  

View as plain text