From: Nigel Tao Date: Tue, 17 Feb 2015 00:15:06 +0000 (+1100) Subject: image: fix Rectangle.Overlaps and Rectangle.Union for empty rectangles. X-Git-Tag: go1.5beta1~1973 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=5c8f9e38eb96d274f82a93c936a8ec8015f90845;p=gostls13.git image: fix Rectangle.Overlaps and Rectangle.Union for empty rectangles. Fixes #9895. Change-Id: I37d78ced9ff8196e32d299504908a1c41ad4592d Reviewed-on: https://go-review.googlesource.com/4990 Reviewed-by: Rob Pike --- diff --git a/src/image/geom.go b/src/image/geom.go index 6ebaf67da8..7c56010653 100644 --- a/src/image/geom.go +++ b/src/image/geom.go @@ -164,6 +164,12 @@ func (r Rectangle) Intersect(s Rectangle) Rectangle { // Union returns the smallest rectangle that contains both r and s. func (r Rectangle) Union(s Rectangle) Rectangle { + if r.Empty() { + return s + } + if s.Empty() { + return r + } if r.Min.X > s.Min.X { r.Min.X = s.Min.X } @@ -192,7 +198,8 @@ func (r Rectangle) Eq(s Rectangle) bool { // Overlaps reports whether r and s have a non-empty intersection. func (r Rectangle) Overlaps(s Rectangle) bool { - return r.Min.X < s.Max.X && s.Min.X < r.Max.X && + return !r.Empty() && !s.Empty() && + r.Min.X < s.Max.X && s.Min.X < r.Max.X && r.Min.Y < s.Max.Y && s.Min.Y < r.Max.Y } diff --git a/src/image/geom_test.go b/src/image/geom_test.go new file mode 100644 index 0000000000..5bbd8a9492 --- /dev/null +++ b/src/image/geom_test.go @@ -0,0 +1,103 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package image + +import ( + "fmt" + "testing" +) + +func TestRectangle(t *testing.T) { + // in checks that every point in f is in g. + in := func(f, g Rectangle) error { + if !f.In(g) { + return fmt.Errorf("f=%s, f.In(%s): got false, want true", f, g) + } + for y := f.Min.Y; y < f.Max.Y; y++ { + for x := f.Min.X; x < f.Max.X; x++ { + p := Point{x, y} + if !p.In(g) { + return fmt.Errorf("p=%s, p.In(%s): got false, want true", p, g) + } + } + } + return nil + } + + rects := []Rectangle{ + Rect(0, 0, 10, 10), + Rect(1, 2, 3, 4), + Rect(4, 6, 10, 10), + Rect(2, 3, 12, 5), + Rect(-1, -2, 0, 0), + Rect(-1, -2, 4, 6), + Rect(-10, -20, 30, 40), + Rect(8, 8, 8, 8), + Rect(88, 88, 88, 88), + Rect(6, 5, 4, 3), + } + + // The intersection should be the largest rectangle a such that every point + // in a is both in r and in s. + for _, r := range rects { + for _, s := range rects { + a := r.Intersect(s) + if err := in(a, r); err != nil { + t.Errorf("Intersect: r=%s, s=%s, a=%s, a not in r: %v", r, s, a, err) + } + if err := in(a, s); err != nil { + t.Errorf("Intersect: r=%s, s=%s, a=%s, a not in s: %v", r, s, a, err) + } + if a.Empty() == r.Overlaps(s) { + t.Errorf("Intersect: r=%s, s=%s, a=%s: empty=%t same as overlaps=%t", + r, s, a, a.Empty(), r.Overlaps(s)) + } + largerThanA := [4]Rectangle{a, a, a, a} + largerThanA[0].Min.X-- + largerThanA[1].Min.Y-- + largerThanA[2].Max.X++ + largerThanA[3].Max.Y++ + for i, b := range largerThanA { + if b.Empty() { + // b isn't actually larger than a. + continue + } + if in(b, r) == nil && in(b, s) == nil { + t.Errorf("Intersect: r=%s, s=%s, a=%s, b=%s, i=%d: intersection could be larger", + r, s, a, b, i) + } + } + } + } + + // The union should be the smallest rectangle a such that every point in r + // is in a and every point in s is in a. + for _, r := range rects { + for _, s := range rects { + a := r.Union(s) + if err := in(r, a); err != nil { + t.Errorf("Union: r=%s, s=%s, a=%s, r not in a: %v", r, s, a, err) + } + if err := in(s, a); err != nil { + t.Errorf("Union: r=%s, s=%s, a=%s, s not in a: %v", r, s, a, err) + } + if a.Empty() { + // You can't get any smaller than a. + continue + } + smallerThanA := [4]Rectangle{a, a, a, a} + smallerThanA[0].Min.X++ + smallerThanA[1].Min.Y++ + smallerThanA[2].Max.X-- + smallerThanA[3].Max.Y-- + for i, b := range smallerThanA { + if in(r, b) == nil && in(s, b) == nil { + t.Errorf("Union: r=%s, s=%s, a=%s, b=%s, i=%d: union could be smaller", + r, s, a, b, i) + } + } + } + } +}