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 }