gonum.org/v1/gonum@v0.14.0/spatial/r2/vector_test.go (about)

     1  // Copyright ©2020 The Gonum Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package r2
     6  
     7  import (
     8  	"math"
     9  	"testing"
    10  
    11  	"golang.org/x/exp/rand"
    12  	"gonum.org/v1/gonum/floats/scalar"
    13  )
    14  
    15  func TestAdd(t *testing.T) {
    16  	for _, test := range []struct {
    17  		v1, v2 Vec
    18  		want   Vec
    19  	}{
    20  		{Vec{0, 0}, Vec{0, 0}, Vec{0, 0}},
    21  		{Vec{1, 0}, Vec{0, 0}, Vec{1, 0}},
    22  		{Vec{1, 2}, Vec{3, 4}, Vec{4, 6}},
    23  		{Vec{1, -3}, Vec{1, -6}, Vec{2, -9}},
    24  		{Vec{1, 2}, Vec{-1, -2}, Vec{}},
    25  	} {
    26  		got := Add(test.v1, test.v2)
    27  		if got != test.want {
    28  			t.Errorf(
    29  				"error: %v + %v: got=%v, want=%v",
    30  				test.v1, test.v2, got, test.want,
    31  			)
    32  		}
    33  	}
    34  }
    35  
    36  func TestSub(t *testing.T) {
    37  	for _, test := range []struct {
    38  		v1, v2 Vec
    39  		want   Vec
    40  	}{
    41  		{Vec{0, 0}, Vec{0, 0}, Vec{0, 0}},
    42  		{Vec{1, 0}, Vec{0, 0}, Vec{1, 0}},
    43  		{Vec{1, 2}, Vec{3, 4}, Vec{-2, -2}},
    44  		{Vec{1, -3}, Vec{1, -6}, Vec{0, 3}},
    45  		{Vec{1, 2}, Vec{1, 2}, Vec{}},
    46  	} {
    47  		got := Sub(test.v1, test.v2)
    48  		if got != test.want {
    49  			t.Errorf(
    50  				"error: %v - %v: got=%v, want=%v",
    51  				test.v1, test.v2, got, test.want,
    52  			)
    53  		}
    54  	}
    55  }
    56  
    57  func TestScale(t *testing.T) {
    58  	for _, test := range []struct {
    59  		a    float64
    60  		v    Vec
    61  		want Vec
    62  	}{
    63  		{3, Vec{0, 0}, Vec{0, 0}},
    64  		{1, Vec{1, 0}, Vec{1, 0}},
    65  		{0, Vec{1, 0}, Vec{0, 0}},
    66  		{3, Vec{1, 0}, Vec{3, 0}},
    67  		{-1, Vec{1, -3}, Vec{-1, 3}},
    68  		{2, Vec{1, -3}, Vec{2, -6}},
    69  		{10, Vec{1, 2}, Vec{10, 20}},
    70  	} {
    71  		got := Scale(test.a, test.v)
    72  		if got != test.want {
    73  			t.Errorf(
    74  				"error: %v * %v: got=%v, want=%v",
    75  				test.a, test.v, got, test.want)
    76  		}
    77  	}
    78  }
    79  
    80  func TestDot(t *testing.T) {
    81  	for _, test := range []struct {
    82  		u, v Vec
    83  		want float64
    84  	}{
    85  		{Vec{1, 2}, Vec{1, 2}, 5},
    86  		{Vec{1, 0}, Vec{1, 0}, 1},
    87  		{Vec{1, 0}, Vec{0, 1}, 0},
    88  		{Vec{1, 0}, Vec{0, 1}, 0},
    89  		{Vec{1, 1}, Vec{-1, -1}, -2},
    90  		{Vec{1, 2}, Vec{-0.3, 0.4}, 0.5},
    91  	} {
    92  		{
    93  			got := Dot(test.u, test.v)
    94  			if got != test.want {
    95  				t.Errorf(
    96  					"error: %v · %v: got=%v, want=%v",
    97  					test.u, test.v, got, test.want,
    98  				)
    99  			}
   100  		}
   101  		{
   102  			got := Dot(test.v, test.u)
   103  			if got != test.want {
   104  				t.Errorf(
   105  					"error: %v · %v: got=%v, want=%v",
   106  					test.v, test.u, got, test.want,
   107  				)
   108  			}
   109  		}
   110  	}
   111  }
   112  
   113  func TestCross(t *testing.T) {
   114  	for _, test := range []struct {
   115  		v1, v2 Vec
   116  		want   float64
   117  	}{
   118  		{Vec{1, 0}, Vec{1, 0}, 0},
   119  		{Vec{1, 0}, Vec{0, 1}, 1},
   120  		{Vec{0, 1}, Vec{1, 0}, -1},
   121  		{Vec{1, 2}, Vec{-4, 5}, 13},
   122  		{Vec{1, 2}, Vec{2, 3}, -1},
   123  	} {
   124  		got := Cross(test.v1, test.v2)
   125  		if got != test.want {
   126  			t.Errorf(
   127  				"error: %v × %v = %v, want %v",
   128  				test.v1, test.v2, got, test.want,
   129  			)
   130  		}
   131  	}
   132  }
   133  
   134  func TestNorm(t *testing.T) {
   135  	for _, test := range []struct {
   136  		v    Vec
   137  		want float64
   138  	}{
   139  		{Vec{0, 0}, 0},
   140  		{Vec{0, 1}, 1},
   141  		{Vec{1, 1}, math.Sqrt2},
   142  		{Vec{1, 2}, math.Sqrt(5)},
   143  		{Vec{3, -4}, 5},
   144  		{Vec{1, 1e-16}, 1},
   145  		{Vec{4.3145006366056343748277397783556100978621924913975e-196, 4.3145006366056343748277397783556100978621924913975e-196}, 6.101625315155041e-196},
   146  	} {
   147  		if got, want := Norm(test.v), test.want; got != want {
   148  			t.Errorf("|%v| = %v, want %v", test.v, got, want)
   149  		}
   150  	}
   151  }
   152  
   153  func TestNorm2(t *testing.T) {
   154  	for _, test := range []struct {
   155  		v    Vec
   156  		want float64
   157  	}{
   158  		{Vec{0, 0}, 0},
   159  		{Vec{0, 1}, 1},
   160  		{Vec{1, 1}, 2},
   161  		{Vec{1, 2}, 5},
   162  		{Vec{3, -4}, 25},
   163  		{Vec{1, 1e-16}, 1},
   164  		// This will underflow and return zero.
   165  		{Vec{4.3145006366056343748277397783556100978621924913975e-196, 4.3145006366056343748277397783556100978621924913975e-196}, 0},
   166  	} {
   167  		if got, want := Norm2(test.v), test.want; got != want {
   168  			t.Errorf("|%v|^2 = %v, want %v", test.v, got, want)
   169  		}
   170  	}
   171  }
   172  
   173  func TestUnit(t *testing.T) {
   174  	const tol = 1e-14
   175  	for _, test := range []struct {
   176  		v, want Vec
   177  	}{
   178  		{Vec{}, Vec{math.NaN(), math.NaN()}},
   179  		{Vec{1, 0}, Vec{1, 0}},
   180  		{Vec{0, 1}, Vec{0, 1}},
   181  		{Vec{-1, 0}, Vec{-1, 0}},
   182  		{Vec{3, 4}, Vec{0.6, 0.8}},
   183  		{Vec{3, -4}, Vec{0.6, -0.8}},
   184  		{Vec{1, 1}, Vec{1. / math.Sqrt(2), 1. / math.Sqrt(2)}},
   185  		{Vec{1, 1e-16}, Vec{1, 1e-16}},
   186  		{Vec{1, 1e16}, Vec{1e-16, 1}},
   187  		{Vec{1e4, math.MaxFloat32 - 1}, Vec{0, 1}},
   188  	} {
   189  		got := Unit(test.v)
   190  		if !vecApproxEqual(got, test.want, tol) {
   191  			t.Errorf(
   192  				"Unit(%v) = %v, want %v",
   193  				test.v, got, test.want,
   194  			)
   195  		}
   196  		if vecIsNaN(got) {
   197  			return
   198  		}
   199  		if n, want := Norm(got), 1.0; n != want {
   200  			t.Errorf("|%v| = %v, want 1", got, n)
   201  		}
   202  	}
   203  }
   204  
   205  func TestCos(t *testing.T) {
   206  	const tol = 1e-14
   207  	for _, test := range []struct {
   208  		v1, v2 Vec
   209  		want   float64
   210  	}{
   211  		{Vec{1, 1}, Vec{1, 1}, 1},
   212  		{Vec{1, 1}, Vec{-1, -1}, -1},
   213  		{Vec{1, 0}, Vec{1, 0}, 1},
   214  		{Vec{1, 0}, Vec{0, 1}, 0},
   215  		{Vec{1, 0}, Vec{-1, 0}, -1},
   216  	} {
   217  		got := Cos(test.v1, test.v2)
   218  		if !scalar.EqualWithinAbs(got, test.want, tol) {
   219  			t.Errorf("cos(%v, %v)= %v, want %v",
   220  				test.v1, test.v2, got, test.want,
   221  			)
   222  		}
   223  	}
   224  }
   225  
   226  func TestRotate(t *testing.T) {
   227  	const tol = 1e-14
   228  	for _, test := range []struct {
   229  		v, q  Vec
   230  		alpha float64
   231  		want  Vec
   232  	}{
   233  		{Vec{1, 0}, Vec{0, 0}, math.Pi / 2, Vec{0, 1}},
   234  		{Vec{1, 0}, Vec{0, 0}, 3 * math.Pi / 2, Vec{0, -1}},
   235  		{Vec{1, 0}, Vec{0, 1}, 0, Vec{1, 0}},
   236  		{Vec{1, 0}, Vec{0, 1}, 2 * math.Pi, Vec{1, 0}},
   237  		{Vec{1, 1}, Vec{0, 0}, math.Pi, Vec{-1, -1}},
   238  		{Vec{2, 2}, Vec{1, 1}, math.Pi / 2, Vec{0, 2}},
   239  		{Vec{2, 2}, Vec{1, 1}, math.Pi, Vec{0, 0}},
   240  		{Vec{2, 2}, Vec{2, 0}, math.Pi, Vec{2, -2}},
   241  	} {
   242  		got := Rotate(test.v, test.alpha, test.q)
   243  		if !vecApproxEqual(got, test.want, tol) {
   244  			t.Errorf(
   245  				"rotate(%v, %v, %v)= %v, want=%v",
   246  				test.v, test.alpha, test.q, got, test.want,
   247  			)
   248  		}
   249  	}
   250  }
   251  
   252  func vecIsNaN(v Vec) bool {
   253  	return math.IsNaN(v.X) && math.IsNaN(v.Y)
   254  }
   255  
   256  func vecIsNaNAny(v Vec) bool {
   257  	return math.IsNaN(v.X) || math.IsNaN(v.Y)
   258  }
   259  
   260  func vecApproxEqual(a, b Vec, tol float64) bool {
   261  	if tol == 0 {
   262  		return vecEqual(a, b)
   263  	}
   264  	if vecIsNaNAny(a) || vecIsNaNAny(b) {
   265  		return vecIsNaN(a) && vecIsNaN(b)
   266  	}
   267  	return scalar.EqualWithinAbs(a.X, b.X, tol) &&
   268  		scalar.EqualWithinAbs(a.Y, b.Y, tol)
   269  }
   270  
   271  func randomVec(rnd *rand.Rand) (v Vec) {
   272  	v.X = (rnd.Float64() - 0.5) * 20
   273  	v.Y = (rnd.Float64() - 0.5) * 20
   274  	return v
   275  }
   276  
   277  func vecEqual(a, b Vec) bool {
   278  	if vecIsNaNAny(a) || vecIsNaNAny(b) {
   279  		return vecIsNaN(a) && vecIsNaN(b)
   280  	}
   281  	return a == b
   282  }