...

Source file src/github.com/golang/geo/r3/precisevector_test.go

Documentation: github.com/golang/geo/r3

     1  // Copyright 2016 Google Inc. All rights reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package r3
    16  
    17  import (
    18  	"math/big"
    19  	"testing"
    20  )
    21  
    22  // preciseEq compares two big.Floats and checks if the are the same.
    23  func preciseEq(a, b *big.Float) bool {
    24  	return a.SetPrec(prec).Cmp(b.SetPrec(prec)) == 0
    25  }
    26  
    27  func TestPreciseRoundtrip(t *testing.T) {
    28  	tests := []struct {
    29  		v Vector
    30  	}{
    31  		{Vector{0, 0, 0}},
    32  		{Vector{1, 2, 3}},
    33  		{Vector{3, -4, 12}},
    34  		{Vector{1, 1e-16, 1e-32}},
    35  	}
    36  
    37  	for _, test := range tests {
    38  		if got, want := PreciseVectorFromVector(test.v).Vector(), test.v.Normalize(); !got.ApproxEqual(want) {
    39  			t.Errorf("PreciseVectorFromVector(%v).Vector() = %v, want %v", test.v, got, want)
    40  		}
    41  	}
    42  }
    43  
    44  func TestPreciseIsUnit(t *testing.T) {
    45  	const epsilon = 1e-14
    46  	tests := []struct {
    47  		v    PreciseVector
    48  		want bool
    49  	}{
    50  		{
    51  			v:    NewPreciseVector(0, 0, 0),
    52  			want: false,
    53  		},
    54  		{
    55  			v:    NewPreciseVector(1, 0, 0),
    56  			want: true,
    57  		},
    58  		{
    59  			v:    NewPreciseVector(0, 1, 0),
    60  			want: true,
    61  		},
    62  		{
    63  			v:    NewPreciseVector(0, 0, 1),
    64  			want: true,
    65  		},
    66  		{
    67  			v:    NewPreciseVector(1+2*epsilon, 0, 0),
    68  			want: false,
    69  		},
    70  		{
    71  			v:    NewPreciseVector(0*(1+epsilon), 0, 0),
    72  			want: false,
    73  		},
    74  		{
    75  			v:    NewPreciseVector(1, 1, 1),
    76  			want: false,
    77  		},
    78  	}
    79  
    80  	for _, test := range tests {
    81  		if got := test.v.IsUnit(); got != test.want {
    82  			t.Errorf("%v.IsUnit() = %v, want %v", test.v, got, test.want)
    83  		}
    84  	}
    85  }
    86  
    87  func TestPreciseNorm2(t *testing.T) {
    88  	tests := []struct {
    89  		v    PreciseVector
    90  		want *big.Float
    91  	}{
    92  		{
    93  			v:    NewPreciseVector(0, 0, 0),
    94  			want: precise0,
    95  		},
    96  		{
    97  			v:    NewPreciseVector(0, 1, 0),
    98  			want: precise1,
    99  		},
   100  		{
   101  			v:    NewPreciseVector(1, 1, 1),
   102  			want: precStr("3"),
   103  		},
   104  		{
   105  			v:    NewPreciseVector(1, 2, 3),
   106  			want: precStr("14"),
   107  		},
   108  		{
   109  			v:    NewPreciseVector(3, -4, 12),
   110  			want: precStr("169"),
   111  		},
   112  	}
   113  
   114  	for _, test := range tests {
   115  		if got := test.v.Norm2(); !preciseEq(got, test.want) {
   116  			t.Errorf("%v.Norm2() = %v, want %v", test.v, test.v.Norm2(), test.want)
   117  		}
   118  	}
   119  }
   120  
   121  func TestPreciseAdd(t *testing.T) {
   122  	tests := []struct {
   123  		v1, v2, want PreciseVector
   124  	}{
   125  		{
   126  			v1:   NewPreciseVector(0, 0, 0),
   127  			v2:   NewPreciseVector(0, 0, 0),
   128  			want: NewPreciseVector(0, 0, 0),
   129  		},
   130  		{
   131  			v1:   NewPreciseVector(1, 0, 0),
   132  			v2:   NewPreciseVector(0, 0, 0),
   133  			want: NewPreciseVector(1, 0, 0),
   134  		},
   135  		{
   136  			v1:   NewPreciseVector(1, 2, 3),
   137  			v2:   NewPreciseVector(4, 5, 7),
   138  			want: NewPreciseVector(5, 7, 10),
   139  		},
   140  		{
   141  			v1:   NewPreciseVector(1, -3, 5),
   142  			v2:   NewPreciseVector(1, -6, -6),
   143  			want: NewPreciseVector(2, -9, -1),
   144  		},
   145  	}
   146  
   147  	for _, test := range tests {
   148  		if got := test.v1.Add(test.v2); !got.Equal(test.want) {
   149  			t.Errorf("%v + %v = %v, want %v", test.v1, test.v2, got, test.want)
   150  		}
   151  	}
   152  }
   153  
   154  func TestPreciseSub(t *testing.T) {
   155  	tests := []struct {
   156  		v1, v2, want PreciseVector
   157  	}{
   158  		{
   159  			v1:   NewPreciseVector(0, 0, 0),
   160  			v2:   NewPreciseVector(0, 0, 0),
   161  			want: NewPreciseVector(0, 0, 0),
   162  		},
   163  		{
   164  			v1:   NewPreciseVector(1, 0, 0),
   165  			v2:   NewPreciseVector(0, 0, 0),
   166  			want: NewPreciseVector(1, 0, 0),
   167  		},
   168  		{
   169  			v1:   NewPreciseVector(1, 2, 3),
   170  			v2:   NewPreciseVector(4, 5, 7),
   171  			want: NewPreciseVector(-3, -3, -4),
   172  		},
   173  		{
   174  			v1:   NewPreciseVector(1, -3, 5),
   175  			v2:   NewPreciseVector(1, -6, -6),
   176  			want: NewPreciseVector(0, 3, 11),
   177  		},
   178  	}
   179  
   180  	for _, test := range tests {
   181  		if got := test.v1.Sub(test.v2); !got.Equal(test.want) {
   182  			t.Errorf("%v - %v = %v, want %v", test.v1, test.v2, got, test.want)
   183  		}
   184  	}
   185  }
   186  
   187  func TestPreciseMul(t *testing.T) {
   188  	tests := []struct {
   189  		v    PreciseVector
   190  		f    *big.Float
   191  		want PreciseVector
   192  	}{
   193  		{
   194  			v:    NewPreciseVector(0, 0, 0),
   195  			f:    precFloat(3),
   196  			want: NewPreciseVector(0, 0, 0),
   197  		},
   198  		{
   199  			v:    NewPreciseVector(1, 0, 0),
   200  			f:    precFloat(1),
   201  			want: NewPreciseVector(1, 0, 0),
   202  		},
   203  		{
   204  			v:    NewPreciseVector(1, 0, 0),
   205  			f:    precFloat(0),
   206  			want: NewPreciseVector(0, 0, 0),
   207  		},
   208  		{
   209  			v:    NewPreciseVector(1, 0, 0),
   210  			f:    precFloat(3),
   211  			want: NewPreciseVector(3, 0, 0),
   212  		},
   213  		{
   214  			v:    NewPreciseVector(1, -3, 5),
   215  			f:    precFloat(-1),
   216  			want: NewPreciseVector(-1, 3, -5),
   217  		},
   218  		{
   219  			v:    NewPreciseVector(1, -3, 5),
   220  			f:    precFloat(2),
   221  			want: NewPreciseVector(2, -6, 10),
   222  		},
   223  	}
   224  
   225  	for _, test := range tests {
   226  		if got := test.v.Mul(test.f); !got.Equal(test.want) {
   227  			t.Errorf("%v.Mul(%v) = %v, want %v", test.v, test.f, got, test.want)
   228  		}
   229  	}
   230  }
   231  
   232  func TestPreciseMulByFloat64(t *testing.T) {
   233  	tests := []struct {
   234  		v    PreciseVector
   235  		f    float64
   236  		want PreciseVector
   237  	}{
   238  		{
   239  			v:    NewPreciseVector(0, 0, 0),
   240  			f:    3,
   241  			want: NewPreciseVector(0, 0, 0),
   242  		},
   243  		{
   244  			v:    NewPreciseVector(1, 0, 0),
   245  			f:    1,
   246  			want: NewPreciseVector(1, 0, 0),
   247  		},
   248  		{
   249  			v:    NewPreciseVector(1, 0, 0),
   250  			f:    0,
   251  			want: NewPreciseVector(0, 0, 0),
   252  		},
   253  		{
   254  			v:    NewPreciseVector(1, 0, 0),
   255  			f:    3,
   256  			want: NewPreciseVector(3, 0, 0),
   257  		},
   258  		{
   259  			v:    NewPreciseVector(1, -3, 5),
   260  			f:    -1,
   261  			want: NewPreciseVector(-1, 3, -5),
   262  		},
   263  		{
   264  			v:    NewPreciseVector(1, -3, 5),
   265  			f:    2,
   266  			want: NewPreciseVector(2, -6, 10),
   267  		},
   268  	}
   269  
   270  	for _, test := range tests {
   271  		if got := test.v.MulByFloat64(test.f); !got.Equal(test.want) {
   272  			t.Errorf("%v.MulByFloat64(%v) = %v, want %v", test.v, test.f, got, test.want)
   273  		}
   274  	}
   275  }
   276  
   277  func TestPreciseDot(t *testing.T) {
   278  	tests := []struct {
   279  		v1, v2 PreciseVector
   280  		want   *big.Float
   281  	}{
   282  		{
   283  			// Dot with self should be 1.
   284  			v1:   NewPreciseVector(1, 0, 0),
   285  			v2:   NewPreciseVector(1, 0, 0),
   286  			want: precise1,
   287  		},
   288  		{
   289  			// Dot with self should be 1.
   290  			v1:   NewPreciseVector(0, 1, 0),
   291  			v2:   NewPreciseVector(0, 1, 0),
   292  			want: precise1,
   293  		},
   294  		{
   295  			// Dot with self should be 1.
   296  			v1:   NewPreciseVector(0, 0, 1),
   297  			v2:   NewPreciseVector(0, 0, 1),
   298  			want: precise1,
   299  		},
   300  		{
   301  			// Perpendicular should be 0.
   302  			v1:   NewPreciseVector(1, 0, 0),
   303  			v2:   NewPreciseVector(0, 1, 0),
   304  			want: precise0,
   305  		},
   306  		{
   307  			// Perpendicular should be 0.
   308  			v1:   NewPreciseVector(1, 0, 0),
   309  			v2:   NewPreciseVector(0, 1, 1),
   310  			want: precise0,
   311  		},
   312  		{
   313  			v1:   NewPreciseVector(1, 1, 1),
   314  			v2:   NewPreciseVector(-1, -1, -1),
   315  			want: precStr("-3"),
   316  		},
   317  	}
   318  
   319  	for _, test := range tests {
   320  		if got := test.v1.Dot(test.v2); !preciseEq(got, test.want) {
   321  			t.Errorf("%v · %v = %v, want %v", test.v1, test.v2, got, test.want)
   322  		}
   323  		if got := test.v2.Dot(test.v1); !preciseEq(got, test.want) {
   324  			t.Errorf("%v · %v = %v, want %v", test.v2, test.v1, got, test.want)
   325  		}
   326  	}
   327  }
   328  
   329  func TestPreciseCross(t *testing.T) {
   330  	tests := []struct {
   331  		v1, v2, want PreciseVector
   332  	}{
   333  		{
   334  			// Cross with self should be 0.
   335  			v1:   NewPreciseVector(1, 0, 0),
   336  			v2:   NewPreciseVector(1, 0, 0),
   337  			want: NewPreciseVector(0, 0, 0),
   338  		},
   339  		{
   340  			// Cross with perpendicular should give the remaining axis.
   341  			v1:   NewPreciseVector(1, 0, 0),
   342  			v2:   NewPreciseVector(0, 1, 0),
   343  			want: NewPreciseVector(0, 0, 1),
   344  		},
   345  		{
   346  			// Cross with perpendicular should give the remaining axis.
   347  			v1:   NewPreciseVector(0, 1, 0),
   348  			v2:   NewPreciseVector(0, 0, 1),
   349  			want: NewPreciseVector(1, 0, 0),
   350  		},
   351  		{
   352  			// Cross with perpendicular should give the remaining axis.
   353  			v1:   NewPreciseVector(0, 0, 1),
   354  			v2:   NewPreciseVector(1, 0, 0),
   355  			want: NewPreciseVector(0, 1, 0),
   356  		},
   357  		{
   358  			v1:   NewPreciseVector(0, 1, 0),
   359  			v2:   NewPreciseVector(1, 0, 0),
   360  			want: NewPreciseVector(0, 0, -1),
   361  		},
   362  		{
   363  			v1:   NewPreciseVector(1, 2, 3),
   364  			v2:   NewPreciseVector(-4, 5, -6),
   365  			want: NewPreciseVector(-27, -6, 13),
   366  		},
   367  	}
   368  
   369  	for _, test := range tests {
   370  		if got := test.v1.Cross(test.v2); !got.Equal(test.want) {
   371  			t.Errorf("%v ⨯ %v = %v, want %v", test.v1, test.v2, got, test.want)
   372  		}
   373  	}
   374  }
   375  
   376  func TestPreciseIdentities(t *testing.T) {
   377  	tests := []struct {
   378  		v1, v2 PreciseVector
   379  	}{
   380  		{
   381  			v1: NewPreciseVector(0, 0, 0),
   382  			v2: NewPreciseVector(0, 0, 0),
   383  		},
   384  		{
   385  			v1: NewPreciseVector(0, 0, 0),
   386  			v2: NewPreciseVector(0, 1, 2),
   387  		},
   388  		{
   389  			v1: NewPreciseVector(1, 0, 0),
   390  			v2: NewPreciseVector(0, 1, 0),
   391  		},
   392  		{
   393  			v1: NewPreciseVector(1, 0, 0),
   394  			v2: NewPreciseVector(0, 1, 1),
   395  		},
   396  		{
   397  			v1: NewPreciseVector(1, 1, 1),
   398  			v2: NewPreciseVector(-1, -1, -1),
   399  		},
   400  		{
   401  			v1: NewPreciseVector(1, 2, 2),
   402  			v2: NewPreciseVector(-0.3, 0.4, -1.2),
   403  		},
   404  	}
   405  
   406  	for _, test := range tests {
   407  		c1 := test.v1.Cross(test.v2)
   408  		c2 := test.v2.Cross(test.v1)
   409  		d1 := test.v1.Dot(test.v2)
   410  		d2 := test.v2.Dot(test.v1)
   411  
   412  		// Dot commutes
   413  		if !preciseEq(d1, d2) {
   414  			t.Errorf("%v = %v · %v != %v · %v = %v", d1, test.v1, test.v2, test.v2, test.v1, d2)
   415  		}
   416  		// Cross anti-commutes
   417  		if !c1.Equal(c2.MulByFloat64(-1.0)) {
   418  			t.Errorf("%v = %v ⨯ %v != -(%v ⨯ %v) = -%v", c1, test.v1, test.v2, test.v2, test.v1, c2)
   419  		}
   420  		// Cross is orthogonal to original vectors
   421  		if got := test.v1.Dot(c1); !preciseEq(got, precise0) {
   422  			t.Errorf("%v · (%v ⨯ %v) = %v, want %v", test.v1, test.v1, test.v2, got, precise0)
   423  		}
   424  		if got := test.v2.Dot(c1); !preciseEq(got, precise0) {
   425  			t.Errorf("%v · (%v ⨯ %v) = %v, want %v", test.v2, test.v1, test.v2, got, precise0)
   426  		}
   427  	}
   428  }
   429  
   430  func TestPreciseLargestSmallestComponents(t *testing.T) {
   431  	tests := []struct {
   432  		v                 PreciseVector
   433  		largest, smallest Axis
   434  	}{
   435  		{
   436  			v:        NewPreciseVector(0, 0, 0),
   437  			largest:  ZAxis,
   438  			smallest: ZAxis,
   439  		},
   440  		{
   441  			v:        NewPreciseVector(1, 0, 0),
   442  			largest:  XAxis,
   443  			smallest: ZAxis,
   444  		},
   445  		{
   446  			v:        NewPreciseVector(1, -1, 0),
   447  			largest:  YAxis,
   448  			smallest: ZAxis,
   449  		},
   450  		{
   451  			v:        NewPreciseVector(-1, -1.1, -1.1),
   452  			largest:  ZAxis,
   453  			smallest: XAxis,
   454  		},
   455  		{
   456  			v:        NewPreciseVector(0.5, -0.4, -0.5),
   457  			largest:  ZAxis,
   458  			smallest: YAxis,
   459  		},
   460  		{
   461  			v:        NewPreciseVector(1e-15, 1e-14, 1e-13),
   462  			largest:  ZAxis,
   463  			smallest: XAxis,
   464  		},
   465  	}
   466  
   467  	for _, test := range tests {
   468  		if got := test.v.LargestComponent(); got != test.largest {
   469  			t.Errorf("%v.LargestComponent() = %v, want %v", test.v, got, test.largest)
   470  		}
   471  		if got := test.v.SmallestComponent(); got != test.smallest {
   472  			t.Errorf("%v.SmallestComponent() = %v, want %v", test.v, got, test.smallest)
   473  		}
   474  	}
   475  }
   476  
   477  func TestPreciseVectorIsZero(t *testing.T) {
   478  
   479  	x := NewPreciseVector(1e20, 0, 0)
   480  	y := NewPreciseVector(1, 0, 0)
   481  	xy := x.Add(y)
   482  
   483  	tests := []struct {
   484  		have PreciseVector
   485  		want bool
   486  	}{
   487  		{
   488  			have: NewPreciseVector(0, 0, 0),
   489  			want: true,
   490  		},
   491  		{
   492  			// Test with one element being negatively signed 0.
   493  			have: NewPreciseVector(0, -0, 0),
   494  			want: true,
   495  		},
   496  		{
   497  			// Test a non-zero value.
   498  			have: NewPreciseVector(0, 0, 1),
   499  			want: false,
   500  		},
   501  		{
   502  			// 1e20+1-1e20 should equal 1.  Testing the case where the
   503  			// numbers are outside the range a traditional double would
   504  			// be able to handle correctly.
   505  			have: x.Add(y).Add(x.Mul(precFloat(-1))),
   506  			want: false,
   507  		},
   508  		{
   509  			// (1e20+1) - (1e20+1) should be zero. Test the same case
   510  			// where a non-representable double minus itself is 0.
   511  			have: xy.Sub(xy),
   512  			want: true,
   513  		},
   514  	}
   515  
   516  	for _, test := range tests {
   517  		if got := test.have.IsZero(); got != test.want {
   518  			t.Errorf("%s.IsZero() = %v, want %v", test.have, got, test.want)
   519  		}
   520  	}
   521  }
   522  

View as plain text