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