gonum.org/v1/gonum@v0.14.0/spatial/r2/box_test.go (about)

     1  // Copyright ©2022 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  	"testing"
     9  
    10  	"golang.org/x/exp/rand"
    11  )
    12  
    13  func TestBoxContains(t *testing.T) {
    14  	rnd := rand.New(rand.NewSource(1))
    15  	for i := 0; i < 200; i++ {
    16  		b := randomBox(rnd)
    17  		for j := 0; j < 10; j++ {
    18  			contained := b.random(rnd)
    19  			if !b.Contains(contained) {
    20  				t.Error("bounding box should contain Vec")
    21  			}
    22  		}
    23  		uncontained := [4]Vec{
    24  			Add(b.Max, Vec{1, 0}),
    25  			Add(b.Max, Vec{0, 1}),
    26  			Sub(b.Min, Vec{1, 0}),
    27  			Sub(b.Min, Vec{0, 1}),
    28  		}
    29  		for _, unc := range uncontained {
    30  			if b.Contains(unc) {
    31  				t.Error("box should not contain vec")
    32  			}
    33  		}
    34  	}
    35  }
    36  
    37  func TestBoxUnion(t *testing.T) {
    38  	rnd := rand.New(rand.NewSource(1))
    39  	for i := 0; i < 200; i++ {
    40  		b1 := randomBox(rnd)
    41  		b2 := randomBox(rnd)
    42  		u := b1.Union(b2)
    43  		for j := 0; j < 10; j++ {
    44  			contained := b1.random(rnd)
    45  			if !u.Contains(contained) {
    46  				t.Error("union should contain b1's Vec")
    47  			}
    48  			contained = b2.random(rnd)
    49  			if !u.Contains(contained) {
    50  				t.Error("union should contain b2's Vec")
    51  			}
    52  		}
    53  		uncontained := [4]Vec{
    54  			Add(maxElem(b1.Max, b2.Max), Vec{1, 0}),
    55  			Add(maxElem(b1.Max, b2.Max), Vec{0, 1}),
    56  			Sub(minElem(b1.Min, b2.Min), Vec{1, 0}),
    57  			Sub(minElem(b1.Min, b2.Min), Vec{0, 1}),
    58  		}
    59  		for _, unc := range uncontained {
    60  			if !b1.Contains(unc) && !b2.Contains(unc) && u.Contains(unc) {
    61  				t.Error("union should not contain Vec")
    62  			}
    63  		}
    64  	}
    65  }
    66  
    67  func TestBoxCenter(t *testing.T) {
    68  	const tol = 1e-11
    69  	rnd := rand.New(rand.NewSource(1))
    70  	for i := 0; i < 300; i++ {
    71  		b := randomBox(rnd)
    72  		center := b.Center()
    73  		size := b.Size()
    74  		newBox := centeredBox(center, size)
    75  		if b.Empty() {
    76  			t.Fatal("random box result must be well formed")
    77  		}
    78  		if !vecApproxEqual(b.Min, newBox.Min, tol) {
    79  			t.Errorf("min values of box not equal. got %g, expected %g", newBox.Min, b.Min)
    80  		}
    81  		if !vecApproxEqual(b.Max, newBox.Max, tol) {
    82  			t.Errorf("max values of box not equal. got %g, expected %g", newBox.Max, b.Max)
    83  		}
    84  	}
    85  }
    86  
    87  func TestBoxAdd(t *testing.T) {
    88  	const tol = 1e-14
    89  	rnd := rand.New(rand.NewSource(1))
    90  	for i := 0; i < 12; i++ {
    91  		b := randomBox(rnd)
    92  		v := randomVec(rnd)
    93  		got := b.Add(v)
    94  		want := Box{Min: Add(b.Min, v), Max: Add(b.Max, v)}
    95  		if !vecApproxEqual(got.Min, want.Min, tol) {
    96  			t.Error("box min incorrect result")
    97  		}
    98  		if !vecApproxEqual(got.Max, want.Max, tol) {
    99  			t.Error("box max incorrect result")
   100  		}
   101  	}
   102  }
   103  
   104  func TestBoxScale(t *testing.T) {
   105  	const tol = 1e-11
   106  	rnd := rand.New(rand.NewSource(1))
   107  	for i := 0; i < 300; i++ {
   108  		b := randomBox(rnd)
   109  		size := b.Size()
   110  
   111  		scaler := absElem(randomVec(rnd))
   112  		scaled := b.Scale(scaler)
   113  		gotScaler := divElem(scaled.Size(), size)
   114  		if !vecApproxEqual(scaler, gotScaler, tol) {
   115  			t.Errorf("got scaled %g, expected %g", gotScaler, scaler)
   116  		}
   117  		center := b.Center()
   118  		scaledCenter := scaled.Center()
   119  		if !vecApproxEqual(center, scaledCenter, tol) {
   120  			t.Error("scale modified center")
   121  		}
   122  	}
   123  }
   124  
   125  func TestBoxEmpty(t *testing.T) {
   126  	rnd := rand.New(rand.NewSource(1))
   127  	for i := 0; i < 300; i++ {
   128  		v := absElem(randomVec(rnd))
   129  		b := randomBox(rnd)
   130  		min := b.Min
   131  		max := b.Max
   132  		if !(Box{Min: min, Max: min}).Empty() {
   133  			t.Error("Box{min,min} should be empty")
   134  		}
   135  		if !(Box{Min: max, Max: max}).Empty() {
   136  			t.Error("Box{max,max} should be empty")
   137  		}
   138  		bmm := Box{Min: min, Max: Sub(min, v)}
   139  		if !bmm.Empty() {
   140  			t.Error("Box{min,min-v} should be empty")
   141  		} else if bmm.Canon().Empty() {
   142  			t.Error("Canonical box of Box{min,min-v} is not empty")
   143  		}
   144  		bMM := Box{Min: Add(max, v), Max: max}
   145  		if !bMM.Empty() {
   146  			t.Error("Box{max+v,max} should be empty")
   147  		} else if bmm.Canon().Empty() {
   148  			t.Error("Canonical box of Box{max+v,max} is not empty")
   149  		}
   150  	}
   151  }
   152  func TestBoxCanon(t *testing.T) {
   153  	rnd := rand.New(rand.NewSource(1))
   154  	for i := 0; i < 300; i++ {
   155  		b := randomBox(rnd)
   156  		badBox := Box{Min: b.Max, Max: b.Min}
   157  		canon := badBox.Canon()
   158  		if canon != b {
   159  			t.Error("swapped box canon should be equal to original box")
   160  		}
   161  	}
   162  }
   163  
   164  func TestBoxVertices(t *testing.T) {
   165  	rnd := rand.New(rand.NewSource(1))
   166  	for i := 0; i < 300; i++ {
   167  		b := randomBox(rnd)
   168  		gots := b.Vertices()
   169  		wants := goldenVertices(b)
   170  		if len(gots) != len(wants) {
   171  			t.Fatalf("bad length of vertices. expect 4, got %d", len(gots))
   172  		}
   173  		for j, want := range wants {
   174  			got := gots[j]
   175  			if !vecEqual(want, got) {
   176  				t.Errorf("%dth vertex not equal", j)
   177  			}
   178  		}
   179  	}
   180  }
   181  
   182  // randomBox returns a random valid bounding Box.
   183  func randomBox(rnd *rand.Rand) Box {
   184  	spatialScale := randomRange(0, 2000)
   185  	boxScale := randomRange(0.01, 1000)
   186  	return centeredBox(Scale(spatialScale, randomVec(rnd)), Scale(boxScale, absElem(randomVec(rnd))))
   187  }
   188  
   189  // Random returns a random point within the Box.
   190  // used to facilitate testing
   191  func (b Box) random(rnd *rand.Rand) Vec {
   192  	return Vec{
   193  		X: randomRange(b.Min.X, b.Max.X),
   194  		Y: randomRange(b.Min.Y, b.Max.Y),
   195  	}
   196  }
   197  
   198  // randomRange returns a random float64 [a,b)
   199  func randomRange(a, b float64) float64 {
   200  	return a + (b-a)*rand.Float64()
   201  }
   202  
   203  func goldenVertices(a Box) []Vec {
   204  	return []Vec{
   205  		0: a.Min,
   206  		1: {a.Max.X, a.Min.Y},
   207  		2: a.Max,
   208  		3: {a.Min.X, a.Max.Y},
   209  	}
   210  }