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