| 279 | } |
| 280 | |
| 281 | func TestVectorIdentities(t *testing.T) { |
| 282 | tests := []struct { |
| 283 | v1, v2 Vector |
| 284 | }{ |
| 285 | {Vector{0, 0, 0}, Vector{0, 0, 0}}, |
| 286 | {Vector{0, 0, 0}, Vector{0, 1, 2}}, |
| 287 | {Vector{1, 0, 0}, Vector{0, 1, 0}}, |
| 288 | {Vector{1, 0, 0}, Vector{0, 1, 1}}, |
| 289 | {Vector{1, 1, 1}, Vector{-1, -1, -1}}, |
| 290 | {Vector{1, 2, 2}, Vector{-0.3, 0.4, -1.2}}, |
| 291 | } |
| 292 | for _, test := range tests { |
| 293 | a1 := test.v1.Angle(test.v2).Radians() |
| 294 | a2 := test.v2.Angle(test.v1).Radians() |
| 295 | c1 := test.v1.Cross(test.v2) |
| 296 | c2 := test.v2.Cross(test.v1) |
| 297 | d1 := test.v1.Dot(test.v2) |
| 298 | d2 := test.v2.Dot(test.v1) |
| 299 | // Angle commutes |
| 300 | if !float64Eq(a1, a2) { |
| 301 | t.Errorf("%v = %v.Angle(%v) != %v.Angle(%v) = %v", a1, test.v1, test.v2, test.v2, test.v1, a2) |
| 302 | } |
| 303 | // Dot commutes |
| 304 | if !float64Eq(d1, d2) { |
| 305 | t.Errorf("%v = %v · %v != %v · %v = %v", d1, test.v1, test.v2, test.v2, test.v1, d2) |
| 306 | } |
| 307 | // Cross anti-commutes |
| 308 | if !c1.ApproxEqual(c2.Mul(-1.0)) { |
| 309 | t.Errorf("%v = %v ⨯ %v != -(%v ⨯ %v) = -%v", c1, test.v1, test.v2, test.v2, test.v1, c2) |
| 310 | } |
| 311 | // Cross is orthogonal to original vectors |
| 312 | if !float64Eq(test.v1.Dot(c1), 0.0) { |
| 313 | t.Errorf("%v · (%v ⨯ %v) = %v != 0", test.v1, test.v1, test.v2, test.v1.Dot(c1)) |
| 314 | } |
| 315 | if !float64Eq(test.v2.Dot(c1), 0.0) { |
| 316 | t.Errorf("%v · (%v ⨯ %v) = %v != 0", test.v2, test.v1, test.v2, test.v2.Dot(c1)) |
| 317 | } |
| 318 | } |
| 319 | } |
| 320 | |
| 321 | func TestVectorLargestSmallestComponents(t *testing.T) { |
| 322 | tests := []struct { |