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 }