github.com/jingcheng-WU/gonum@v0.9.1-0.20210323123734-f1a2a11a8f7b/spatial/r3/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 r3
     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, 0}, Vec{0, 0, 0}, Vec{0, 0, 0}},
    20  		{Vec{1, 0, 0}, Vec{0, 0, 0}, Vec{1, 0, 0}},
    21  		{Vec{1, 2, 3}, Vec{4, 5, 7}, Vec{5, 7, 10}},
    22  		{Vec{1, -3, 5}, Vec{1, -6, -6}, Vec{2, -9, -1}},
    23  		{Vec{1, 2, 3}, Vec{-1, -2, -3}, 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, 0}, Vec{0, 0, 0}, Vec{0, 0, 0}},
    41  		{Vec{1, 0, 0}, Vec{0, 0, 0}, Vec{1, 0, 0}},
    42  		{Vec{1, 2, 3}, Vec{4, 5, 7}, Vec{-3, -3, -4}},
    43  		{Vec{1, -3, 5}, Vec{1, -6, -6}, Vec{0, 3, 11}},
    44  		{Vec{1, 2, 3}, Vec{1, 2, 3}, 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, 0}, Vec{0, 0, 0}},
    63  		{1, Vec{1, 0, 0}, Vec{1, 0, 0}},
    64  		{0, Vec{1, 0, 0}, Vec{0, 0, 0}},
    65  		{3, Vec{1, 0, 0}, Vec{3, 0, 0}},
    66  		{-1, Vec{1, -3, 5}, Vec{-1, 3, -5}},
    67  		{2, Vec{1, -3, 5}, Vec{2, -6, 10}},
    68  		{10, Vec{1, 2, 3}, Vec{10, 20, 30}},
    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, 3}, Vec{1, 2, 3}, 14},
    85  		{Vec{1, 0, 0}, Vec{1, 0, 0}, 1},
    86  		{Vec{1, 0, 0}, Vec{0, 1, 0}, 0},
    87  		{Vec{1, 0, 0}, Vec{0, 1, 1}, 0},
    88  		{Vec{1, 1, 1}, Vec{-1, -1, -1}, -3},
    89  		{Vec{1, 2, 2}, Vec{-0.3, 0.4, -1.2}, -1.9},
    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, want Vec
   115  	}{
   116  		{Vec{1, 0, 0}, Vec{1, 0, 0}, Vec{0, 0, 0}},
   117  		{Vec{1, 0, 0}, Vec{0, 1, 0}, Vec{0, 0, 1}},
   118  		{Vec{0, 1, 0}, Vec{1, 0, 0}, Vec{0, 0, -1}},
   119  		{Vec{1, 2, 3}, Vec{-4, 5, -6}, Vec{-27, -6, 13}},
   120  		{Vec{1, 2, 3}, Vec{1, 2, 3}, Vec{}},
   121  		{Vec{1, 2, 3}, Vec{2, 3, 4}, Vec{-1, 2, -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}, 0},
   139  		{Vec{0, 1, 0}, 1},
   140  		{Vec{3, -4, 12}, 13},
   141  		{Vec{1, 1e-16, 1e-32}, 1},
   142  		{Vec{-0, 4.3145006366056343748277397783556100978621924913975e-196, 4.3145006366056343748277397783556100978621924913975e-196}, 6.101625315155041e-196},
   143  	} {
   144  		if got, want := Norm(test.v), test.want; got != want {
   145  			t.Errorf("|%v| = %v, want %v", test.v, got, want)
   146  		}
   147  	}
   148  }
   149  
   150  func TestNorm2(t *testing.T) {
   151  	for _, test := range []struct {
   152  		v    Vec
   153  		want float64
   154  	}{
   155  		{Vec{0, 0, 0}, 0},
   156  		{Vec{0, 1, 0}, 1},
   157  		{Vec{1, 1, 1}, 3},
   158  		{Vec{1, 2, 3}, 14},
   159  		{Vec{3, -4, 12}, 169},
   160  		{Vec{1, 1e-16, 1e-32}, 1},
   161  		// This will underflow and return zero.
   162  		{Vec{-0, 4.3145006366056343748277397783556100978621924913975e-196, 4.3145006366056343748277397783556100978621924913975e-196}, 0},
   163  	} {
   164  		if got, want := Norm2(test.v), test.want; got != want {
   165  			t.Errorf("|%v|^2 = %v, want %v", test.v, got, want)
   166  		}
   167  	}
   168  }
   169  
   170  func TestUnit(t *testing.T) {
   171  	for _, test := range []struct {
   172  		v, want Vec
   173  	}{
   174  		{Vec{}, Vec{math.NaN(), math.NaN(), math.NaN()}},
   175  		{Vec{1, 0, 0}, Vec{1, 0, 0}},
   176  		{Vec{0, 1, 0}, Vec{0, 1, 0}},
   177  		{Vec{0, 0, 1}, Vec{0, 0, 1}},
   178  		{Vec{1, 1, 1}, Vec{1. / math.Sqrt(3), 1. / math.Sqrt(3), 1. / math.Sqrt(3)}},
   179  		{Vec{1, 1e-16, 1e-32}, Vec{1, 1e-16, 1e-32}},
   180  	} {
   181  		got := Unit(test.v)
   182  		if !vecEqual(got, test.want) {
   183  			t.Errorf(
   184  				"Normalize(%v) = %v, want %v",
   185  				test.v, got, test.want,
   186  			)
   187  		}
   188  		if test.v == (Vec{}) {
   189  			return
   190  		}
   191  		if n, want := Norm(got), 1.0; n != want {
   192  			t.Errorf("|%v| = %v, want 1", got, n)
   193  		}
   194  	}
   195  }
   196  
   197  func TestCos(t *testing.T) {
   198  	for _, test := range []struct {
   199  		v1, v2 Vec
   200  		want   float64
   201  	}{
   202  		{Vec{1, 1, 1}, Vec{1, 1, 1}, 1},
   203  		{Vec{1, 1, 1}, Vec{-1, -1, -1}, -1},
   204  		{Vec{1, 1, 1}, Vec{1, -1, 1}, 1.0 / 3},
   205  		{Vec{1, 0, 0}, Vec{1, 0, 0}, 1},
   206  		{Vec{1, 0, 0}, Vec{0, 1, 0}, 0},
   207  		{Vec{1, 0, 0}, Vec{0, 1, 1}, 0},
   208  		{Vec{1, 0, 0}, Vec{-1, 0, 0}, -1},
   209  	} {
   210  		tol := 1e-14
   211  		got := Cos(test.v1, test.v2)
   212  		if !scalar.EqualWithinAbs(got, test.want, tol) {
   213  			t.Errorf("cos(%v, %v)= %v, want %v",
   214  				test.v1, test.v2, got, test.want,
   215  			)
   216  		}
   217  	}
   218  }
   219  
   220  func TestRotate(t *testing.T) {
   221  	const tol = 1e-14
   222  	for _, test := range []struct {
   223  		v, axis Vec
   224  		alpha   float64
   225  		want    Vec
   226  	}{
   227  		{Vec{1, 0, 0}, Vec{1, 0, 0}, math.Pi / 2, Vec{1, 0, 0}},
   228  		{Vec{1, 0, 0}, Vec{1, 0, 0}, 0, Vec{1, 0, 0}},
   229  		{Vec{1, 0, 0}, Vec{1, 0, 0}, 2 * math.Pi, Vec{1, 0, 0}},
   230  		{Vec{1, 0, 0}, Vec{0, 0, 0}, math.Pi / 2, Vec{math.NaN(), math.NaN(), math.NaN()}},
   231  		{Vec{1, 0, 0}, Vec{0, 1, 0}, math.Pi / 2, Vec{0, 0, -1}},
   232  		{Vec{1, 0, 0}, Vec{0, 1, 0}, math.Pi, Vec{-1, 0, 0}},
   233  		{Vec{2, 0, 0}, Vec{0, 1, 0}, math.Pi, Vec{-2, 0, 0}},
   234  		{Vec{1, 2, 3}, Vec{1, 1, 1}, 2. / 3. * math.Pi, Vec{3, 1, 2}},
   235  	} {
   236  		got := Rotate(test.v, test.alpha, test.axis)
   237  		if !vecApproxEqual(got, test.want, tol) {
   238  			t.Errorf(
   239  				"rotate(%v, %v, %v)= %v, want=%v",
   240  				test.v, test.alpha, test.axis, got, test.want,
   241  			)
   242  		}
   243  	}
   244  }
   245  
   246  func vecIsNaN(v Vec) bool {
   247  	return math.IsNaN(v.X) && math.IsNaN(v.Y) && math.IsNaN(v.Z)
   248  }
   249  
   250  func vecIsNaNAny(v Vec) bool {
   251  	return math.IsNaN(v.X) || math.IsNaN(v.Y) || math.IsNaN(v.Z)
   252  }
   253  
   254  func vecEqual(a, b Vec) bool {
   255  	if vecIsNaNAny(a) || vecIsNaNAny(b) {
   256  		return vecIsNaN(a) && vecIsNaN(b)
   257  	}
   258  	return a == b
   259  }
   260  
   261  func vecApproxEqual(a, b Vec, tol float64) bool {
   262  	if vecIsNaNAny(a) || vecIsNaNAny(b) {
   263  		return vecIsNaN(a) && vecIsNaN(b)
   264  	}
   265  	return scalar.EqualWithinAbs(a.X, b.X, tol) &&
   266  		scalar.EqualWithinAbs(a.Y, b.Y, tol) &&
   267  		scalar.EqualWithinAbs(a.Z, b.Z, tol)
   268  }