...

Source file src/github.com/golang/geo/r2/rect_test.go

Documentation: github.com/golang/geo/r2

     1  // Copyright 2014 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  // Most of the Rect methods have trivial implementations in terms of the
    16  // Interval class, so most of the testing is done in that unit test.
    17  
    18  package r2
    19  
    20  import (
    21  	"math"
    22  	"reflect"
    23  	"testing"
    24  
    25  	"github.com/golang/geo/r1"
    26  )
    27  
    28  var (
    29  	sw = Point{0, 0.25}
    30  	se = Point{0.5, 0.25}
    31  	ne = Point{0.5, 0.75}
    32  	nw = Point{0, 0.75}
    33  
    34  	empty   = EmptyRect()
    35  	rect    = RectFromPoints(sw, ne)
    36  	rectMid = RectFromPoints(Point{0.25, 0.5}, Point{0.25, 0.5})
    37  	rectSW  = RectFromPoints(sw, sw)
    38  	rectNE  = RectFromPoints(ne, ne)
    39  )
    40  
    41  func float64Eq(x, y float64) bool { return math.Abs(x-y) < 1e-14 }
    42  
    43  func pointsApproxEqual(a, b Point) bool {
    44  	return float64Eq(a.X, b.X) && float64Eq(a.Y, b.Y)
    45  }
    46  
    47  func TestOrtho(t *testing.T) {
    48  	tests := []struct {
    49  		p    Point
    50  		want Point
    51  	}{
    52  		{Point{0, 0}, Point{0, 0}},
    53  		{Point{0, 1}, Point{-1, 0}},
    54  		{Point{1, 1}, Point{-1, 1}},
    55  		{Point{-4, 7}, Point{-7, -4}},
    56  		{Point{1, math.Sqrt(3)}, Point{-math.Sqrt(3), 1}},
    57  	}
    58  	for _, test := range tests {
    59  		if got := test.p.Ortho(); !pointsApproxEqual(got, test.want) {
    60  			t.Errorf("%v.Ortho() = %v, want %v", test.p, got, test.want)
    61  		}
    62  	}
    63  }
    64  
    65  func TestDot(t *testing.T) {
    66  	tests := []struct {
    67  		p    Point
    68  		op   Point
    69  		want float64
    70  	}{
    71  		{Point{0, 0}, Point{0, 0}, 0},
    72  		{Point{0, 1}, Point{0, 0}, 0},
    73  		{Point{1, 1}, Point{4, 3}, 7},
    74  		{Point{-4, 7}, Point{1, 5}, 31},
    75  	}
    76  	for _, test := range tests {
    77  		if got := test.p.Dot(test.op); !float64Eq(got, test.want) {
    78  			t.Errorf("%v.Dot(%v) = %v, want %v", test.p, test.op, got, test.want)
    79  		}
    80  	}
    81  }
    82  
    83  func TestCross(t *testing.T) {
    84  	tests := []struct {
    85  		p    Point
    86  		op   Point
    87  		want float64
    88  	}{
    89  		{Point{0, 0}, Point{0, 0}, 0},
    90  		{Point{0, 1}, Point{0, 0}, 0},
    91  		{Point{1, 1}, Point{-1, -1}, 0},
    92  		{Point{1, 1}, Point{4, 3}, -1},
    93  		{Point{1, 5}, Point{-2, 3}, 13},
    94  	}
    95  
    96  	for _, test := range tests {
    97  		if got := test.p.Cross(test.op); !float64Eq(got, test.want) {
    98  			t.Errorf("%v.Cross(%v) = %v, want %v", test.p, test.op, got, test.want)
    99  		}
   100  	}
   101  }
   102  
   103  func TestNorm(t *testing.T) {
   104  	tests := []struct {
   105  		p    Point
   106  		want float64
   107  	}{
   108  		{Point{0, 0}, 0},
   109  		{Point{0, 1}, 1},
   110  		{Point{-1, 0}, 1},
   111  		{Point{3, 4}, 5},
   112  		{Point{3, -4}, 5},
   113  		{Point{2, 2}, 2 * math.Sqrt(2)},
   114  		{Point{1, math.Sqrt(3)}, 2},
   115  		{Point{29, 29 * math.Sqrt(3)}, 29 * 2},
   116  		{Point{1, 1e15}, 1e15},
   117  		{Point{1e14, math.MaxFloat32 - 1}, math.MaxFloat32},
   118  	}
   119  
   120  	for _, test := range tests {
   121  		if !float64Eq(test.p.Norm(), test.want) {
   122  			t.Errorf("%v.Norm() = %v, want %v", test.p, test.p.Norm(), test.want)
   123  		}
   124  	}
   125  }
   126  
   127  func TestNormalize(t *testing.T) {
   128  	tests := []struct {
   129  		have Point
   130  		want Point
   131  	}{
   132  		{Point{}, Point{}},
   133  		{Point{0, 0}, Point{0, 0}},
   134  		{Point{0, 1}, Point{0, 1}},
   135  		{Point{-1, 0}, Point{-1, 0}},
   136  		{Point{3, 4}, Point{0.6, 0.8}},
   137  		{Point{3, -4}, Point{0.6, -0.8}},
   138  		{Point{2, 2}, Point{math.Sqrt(2) / 2, math.Sqrt(2) / 2}},
   139  		{Point{7, 7 * math.Sqrt(3)}, Point{0.5, math.Sqrt(3) / 2}},
   140  		{Point{1e21, 1e21 * math.Sqrt(3)}, Point{0.5, math.Sqrt(3) / 2}},
   141  		{Point{1, 1e16}, Point{0, 1}},
   142  		{Point{1e4, math.MaxFloat32 - 1}, Point{0, 1}},
   143  	}
   144  
   145  	for _, test := range tests {
   146  		if got := test.have.Normalize(); !pointsApproxEqual(got, test.want) {
   147  			t.Errorf("%v.Normalize() = %v, want %v", test.have, got, test.want)
   148  		}
   149  	}
   150  
   151  }
   152  
   153  func TestEmptyRect(t *testing.T) {
   154  	if !empty.IsValid() {
   155  		t.Errorf("empty Rect should be valid: %v", empty)
   156  	}
   157  	if !empty.IsEmpty() {
   158  		t.Errorf("empty Rect should be empty: %v", empty)
   159  	}
   160  }
   161  
   162  func TestFromVariousTypes(t *testing.T) {
   163  	d1 := RectFromPoints(Point{0.1, 0}, Point{0.25, 1})
   164  	tests := []struct {
   165  		r1, r2 Rect
   166  	}{
   167  		{
   168  			RectFromCenterSize(Point{0.3, 0.5}, Point{0.2, 0.4}),
   169  			RectFromPoints(Point{0.2, 0.3}, Point{0.4, 0.7}),
   170  		},
   171  		{
   172  			RectFromCenterSize(Point{1, 0.1}, Point{0, 2}),
   173  			RectFromPoints(Point{1, -0.9}, Point{1, 1.1}),
   174  		},
   175  		{
   176  			d1,
   177  			Rect{d1.X, d1.Y},
   178  		},
   179  		{
   180  			RectFromPoints(Point{0.15, 0.3}, Point{0.35, 0.9}),
   181  			RectFromPoints(Point{0.15, 0.9}, Point{0.35, 0.3}),
   182  		},
   183  		{
   184  			RectFromPoints(Point{0.12, 0}, Point{0.83, 0.5}),
   185  			RectFromPoints(Point{0.83, 0}, Point{0.12, 0.5}),
   186  		},
   187  	}
   188  
   189  	for _, test := range tests {
   190  		if got := test.r1.ApproxEqual(test.r2); !got {
   191  			t.Errorf("%v.ApproxEqual(%v); got %v want true", test.r1, test.r2, got)
   192  		}
   193  	}
   194  }
   195  
   196  func TestCenter(t *testing.T) {
   197  	tests := []struct {
   198  		rect Rect
   199  		want Point
   200  	}{
   201  		{empty, Point{0.5, 0.5}},
   202  		{rect, Point{0.25, 0.5}},
   203  	}
   204  	for _, test := range tests {
   205  		if got := test.rect.Center(); got != test.want {
   206  			t.Errorf("%v.Center(); got %v want %v", test.rect, got, test.want)
   207  		}
   208  	}
   209  }
   210  
   211  func TestVertices(t *testing.T) {
   212  	want := [4]Point{sw, se, ne, nw}
   213  	got := rect.Vertices()
   214  	if !reflect.DeepEqual(got, want) {
   215  		t.Errorf("%v.Vertices(); got %v want %v", rect, got, want)
   216  	}
   217  }
   218  
   219  func TestContainsPoint(t *testing.T) {
   220  	tests := []struct {
   221  		rect Rect
   222  		p    Point
   223  		want bool
   224  	}{
   225  		{rect, Point{0.2, 0.4}, true},
   226  		{rect, Point{0.2, 0.8}, false},
   227  		{rect, Point{-0.1, 0.4}, false},
   228  		{rect, Point{0.6, 0.1}, false},
   229  		{rect, Point{rect.X.Lo, rect.Y.Lo}, true},
   230  		{rect, Point{rect.X.Hi, rect.Y.Hi}, true},
   231  	}
   232  	for _, test := range tests {
   233  		if got := test.rect.ContainsPoint(test.p); got != test.want {
   234  			t.Errorf("%v.ContainsPoint(%v); got %v want %v", test.rect, test.p, got, test.want)
   235  		}
   236  	}
   237  }
   238  
   239  func TestInteriorContainsPoint(t *testing.T) {
   240  	tests := []struct {
   241  		rect Rect
   242  		p    Point
   243  		want bool
   244  	}{
   245  		// Check corners are not contained.
   246  		{rect, sw, false},
   247  		{rect, ne, false},
   248  		// Check a point on the border is not contained.
   249  		{rect, Point{0, 0.5}, false},
   250  		{rect, Point{0.25, 0.25}, false},
   251  		{rect, Point{0.5, 0.5}, false},
   252  		// Check points inside are contained.
   253  		{rect, Point{0.125, 0.6}, true},
   254  	}
   255  	for _, test := range tests {
   256  		if got := test.rect.InteriorContainsPoint(test.p); got != test.want {
   257  			t.Errorf("%v.InteriorContainsPoint(%v); got %v want %v",
   258  				test.rect, test.p, got, test.want)
   259  		}
   260  	}
   261  }
   262  
   263  func TestIntervalOps(t *testing.T) {
   264  	tests := []struct {
   265  		r1, r2                                           Rect
   266  		contains, intContains, intersects, intIntersects bool
   267  		wantUnion, wantIntersection                      Rect
   268  	}{
   269  		{
   270  			rect, rectMid,
   271  			true, true, true, true,
   272  			rect, rectMid,
   273  		},
   274  		{
   275  			rect, rectSW,
   276  			true, false, true, false,
   277  			rect, rectSW,
   278  		},
   279  		{
   280  			rect, rectNE,
   281  			true, false, true, false,
   282  			rect, rectNE,
   283  		},
   284  		{
   285  			rect,
   286  			RectFromPoints(Point{0.45, 0.1}, Point{0.75, 0.3}),
   287  			false, false, true, true,
   288  			RectFromPoints(Point{0, 0.1}, Point{0.75, 0.75}),
   289  			RectFromPoints(Point{0.45, 0.25}, Point{0.5, 0.3}),
   290  		},
   291  		{
   292  			rect,
   293  			RectFromPoints(Point{0.5, 0.1}, Point{0.7, 0.3}),
   294  			false, false, true, false,
   295  			RectFromPoints(Point{0, 0.1}, Point{0.7, 0.75}),
   296  			RectFromPoints(Point{0.5, 0.25}, Point{0.5, 0.3}),
   297  		},
   298  		{
   299  			rect,
   300  			RectFromPoints(Point{0.45, 0.1}, Point{0.7, 0.25}),
   301  			false, false, true, false,
   302  			RectFromPoints(Point{0, 0.1}, Point{0.7, 0.75}),
   303  			RectFromPoints(Point{0.45, 0.25}, Point{0.5, 0.25}),
   304  		},
   305  		{
   306  			RectFromPoints(Point{0.1, 0.2}, Point{0.1, 0.3}),
   307  			RectFromPoints(Point{0.15, 0.7}, Point{0.2, 0.8}),
   308  			false, false, false, false,
   309  			RectFromPoints(Point{0.1, 0.2}, Point{0.2, 0.8}),
   310  			EmptyRect(),
   311  		},
   312  		// Check that the intersection of two rectangles that overlap in x but not y
   313  		// is valid, and vice versa.
   314  		{
   315  			RectFromPoints(Point{0.1, 0.2}, Point{0.4, 0.5}),
   316  			RectFromPoints(Point{0, 0}, Point{0.2, 0.1}),
   317  			false, false, false, false,
   318  			RectFromPoints(Point{0, 0}, Point{0.4, 0.5}),
   319  			EmptyRect(),
   320  		},
   321  		{
   322  			RectFromPoints(Point{0, 0}, Point{0.1, 0.3}),
   323  			RectFromPoints(Point{0.2, 0.1}, Point{0.3, 0.4}),
   324  			false, false, false, false,
   325  			RectFromPoints(Point{0, 0}, Point{0.3, 0.4}),
   326  			EmptyRect(),
   327  		},
   328  	}
   329  	for _, test := range tests {
   330  		if got := test.r1.Contains(test.r2); got != test.contains {
   331  			t.Errorf("%v.Contains(%v); got %v want %v",
   332  				test.r1, test.r2, got, test.contains)
   333  		}
   334  
   335  		if got := test.r1.InteriorContains(test.r2); got != test.intContains {
   336  			t.Errorf("%v.InteriorContains(%v); got %v want %v",
   337  				test.r1, test.r2, got, test.contains)
   338  		}
   339  
   340  		if got := test.r1.Intersects(test.r2); got != test.intersects {
   341  			t.Errorf("%v.Intersects(%v); got %v want %v",
   342  				test.r1, test.r2, got, test.intersects)
   343  		}
   344  
   345  		if got := test.r1.InteriorIntersects(test.r2); got != test.intIntersects {
   346  			t.Errorf("%v.InteriorIntersects(%v); got %v want %v",
   347  				test.r1, test.r2, got, test.intIntersects)
   348  		}
   349  
   350  		tCon := test.r1.Contains(test.r2)
   351  		if got := test.r1.Union(test.r2).ApproxEqual(test.r1); got != tCon {
   352  			t.Errorf("%v.Union(%v) == %v.Contains(%v); got %v want %v",
   353  				test.r1, test.r2, test.r1, test.r2, got, tCon)
   354  		}
   355  
   356  		tInter := test.r1.Intersects(test.r2)
   357  		if got := !test.r1.Intersection(test.r2).IsEmpty(); got != tInter {
   358  			t.Errorf("%v.Intersection(%v).IsEmpty() == %v.Intersects(%v); got %v want %v",
   359  				test.r1, test.r2, test.r1, test.r2, got, tInter)
   360  		}
   361  
   362  		if got := test.r1.Union(test.r2); got != test.wantUnion {
   363  			t.Errorf("%v.Union(%v); got %v want %v",
   364  				test.r1, test.r2, got, test.wantUnion)
   365  		}
   366  
   367  		if got := test.r1.Intersection(test.r2); got != test.wantIntersection {
   368  			t.Errorf("%v.Intersection(%v); got %v want %v",
   369  				test.r1, test.r2, got, test.wantIntersection)
   370  		}
   371  
   372  		r := test.r1.AddRect(test.r2)
   373  
   374  		if r != test.wantUnion {
   375  			t.Errorf("%v.AddRect(%v); got %v want %v", test.r1, test.r2, r, test.wantUnion)
   376  		}
   377  	}
   378  }
   379  
   380  func TestAddPoint(t *testing.T) {
   381  	r1 := rect
   382  	r2 := EmptyRect()
   383  
   384  	r2 = r2.AddPoint(sw)
   385  	r2 = r2.AddPoint(se)
   386  	r2 = r2.AddPoint(nw)
   387  	r2 = r2.AddPoint(Point{0.1, 0.4})
   388  
   389  	if !r1.ApproxEqual(r2) {
   390  		t.Errorf("%v.AddPoint(%v); got false want true", r1, r2)
   391  	}
   392  }
   393  
   394  func TestClampPoint(t *testing.T) {
   395  	r := Rect{r1.Interval{Lo: 0, Hi: 0.5}, r1.Interval{Lo: 0.25, Hi: 0.75}}
   396  	tests := []struct {
   397  		p    Point
   398  		want Point
   399  	}{
   400  		{Point{-0.01, 0.24}, Point{0, 0.25}},
   401  		{Point{-5.0, 0.48}, Point{0, 0.48}},
   402  		{Point{-5.0, 2.48}, Point{0, 0.75}},
   403  		{Point{0.19, 2.48}, Point{0.19, 0.75}},
   404  
   405  		{Point{6.19, 2.48}, Point{0.5, 0.75}},
   406  		{Point{6.19, 0.53}, Point{0.5, 0.53}},
   407  		{Point{6.19, -2.53}, Point{0.5, 0.25}},
   408  		{Point{0.33, -2.53}, Point{0.33, 0.25}},
   409  		{Point{0.33, 0.37}, Point{0.33, 0.37}},
   410  	}
   411  	for _, test := range tests {
   412  		if got := r.ClampPoint(test.p); got != test.want {
   413  			t.Errorf("%v.ClampPoint(%v); got %v want %v", r, test.p, got, test.want)
   414  		}
   415  	}
   416  }
   417  
   418  func TestExpandedEmpty(t *testing.T) {
   419  	tests := []struct {
   420  		rect Rect
   421  		p    Point
   422  	}{
   423  		{
   424  			EmptyRect(),
   425  			Point{0.1, 0.3},
   426  		},
   427  		{
   428  			EmptyRect(),
   429  			Point{-0.1, -0.3},
   430  		},
   431  		{
   432  			RectFromPoints(Point{0.2, 0.4}, Point{0.3, 0.7}),
   433  			Point{-0.1, 0.3},
   434  		},
   435  		{
   436  			RectFromPoints(Point{0.2, 0.4}, Point{0.3, 0.7}),
   437  			Point{0.1, -0.2},
   438  		},
   439  	}
   440  	for _, test := range tests {
   441  		if got := test.rect.Expanded(test.p); !got.IsEmpty() {
   442  			t.Errorf("%v.Expanded(%v); got %v want true", test.rect, test.p, got.IsEmpty())
   443  		}
   444  	}
   445  }
   446  
   447  func TestExpandedEqual(t *testing.T) {
   448  	tests := []struct {
   449  		rect Rect
   450  		p    Point
   451  		want Rect
   452  	}{
   453  		{
   454  			RectFromPoints(Point{0.2, 0.4}, Point{0.3, 0.7}),
   455  			Point{0.1, 0.3},
   456  			RectFromPoints(Point{0.1, 0.1}, Point{0.4, 1.0}),
   457  		},
   458  		{
   459  			RectFromPoints(Point{0.2, 0.4}, Point{0.3, 0.7}),
   460  			Point{0.1, -0.1},
   461  			RectFromPoints(Point{0.1, 0.5}, Point{0.4, 0.6}),
   462  		},
   463  		{
   464  			RectFromPoints(Point{0.2, 0.4}, Point{0.3, 0.7}),
   465  			Point{0.1, 0.1},
   466  			RectFromPoints(Point{0.1, 0.3}, Point{0.4, 0.8}),
   467  		},
   468  	}
   469  	for _, test := range tests {
   470  		if got := test.rect.Expanded(test.p); !got.ApproxEqual(test.want) {
   471  			t.Errorf("%v.Expanded(%v); got %v want %v", test.rect, test.p, got, test.want)
   472  		}
   473  	}
   474  }
   475  

View as plain text