]> Cypherpunks repositories - gostls13.git/commitdiff
exp/draw: clip destination rectangle to the image bounds.
authorNigel Tao <nigeltao@golang.org>
Thu, 9 Sep 2010 09:12:54 +0000 (19:12 +1000)
committerNigel Tao <nigeltao@golang.org>
Thu, 9 Sep 2010 09:12:54 +0000 (19:12 +1000)
image: introduce Intersect and Union rectangle methods.

R=r, rog, nigeltao
CC=golang-dev
https://golang.org/cl/2115043

src/pkg/exp/draw/draw.go
src/pkg/image/geom.go

index b6b9eff4f8b62edd12636b1fb359a008b9f38760..00bd829467bfaf8c45892c3960b2300d9432cfca 100644 (file)
@@ -60,9 +60,10 @@ func DrawMask(dst Image, r image.Rectangle, src image.Image, sp image.Point, mas
        if r.Dy() > dy {
                r.Max.Y = r.Min.Y + dy
        }
-
-       // TODO(nigeltao): Clip r to dst's bounding box, and handle the case when sp or mp has negative X or Y.
-       // TODO(nigeltao): Ensure that r is well formed, i.e. r.Max.X >= r.Min.X and likewise for Y.
+       r = r.Intersect(dst.Bounds())
+       if r.Empty() {
+               return
+       }
 
        // Fast paths for special cases. If none of them apply, then we fall back to a general but slow implementation.
        if dst0, ok := dst.(*image.RGBA); ok {
index ad0f987cb824f7ada7abeab884c6386258d4acac..06c13fec16aaf985bfc4375abcf06cac31d080fa 100644 (file)
@@ -37,6 +37,9 @@ func Pt(X, Y int) Point {
 }
 
 // A Rectangle contains the points with Min.X <= X < Max.X, Min.Y <= Y < Max.Y.
+// It is well-formed if Min.X <= Max.X and likewise for Y. Points are always
+// well-formed. A rectangle's methods always return well-formed outputs for
+// well-formed inputs.
 type Rectangle struct {
        Min, Max Point
 }
@@ -72,12 +75,63 @@ func (r Rectangle) Sub(p Point) Rectangle {
        }
 }
 
-// Inset returns the rectangle r inset by n, which may be negative.
+// Inset returns the rectangle r inset by n, which may be negative. If either
+// of r's dimensions is less than 2*n then an empty rectangle near the center
+// of r will be returned.
 func (r Rectangle) Inset(n int) Rectangle {
-       return Rectangle{
-               Point{r.Min.X + n, r.Min.Y + n},
-               Point{r.Max.X - n, r.Max.Y - n},
+       if r.Dx() < 2*n {
+               r.Min.X = (r.Min.X + r.Max.X) / 2
+               r.Max.X = r.Min.X
+       } else {
+               r.Min.X += n
+               r.Max.X -= n
+       }
+       if r.Dy() < 2*n {
+               r.Min.Y = (r.Min.Y + r.Max.Y) / 2
+               r.Max.Y = r.Min.Y
+       } else {
+               r.Min.Y += n
+               r.Max.Y -= n
+       }
+       return r
+}
+
+// Intersect returns the largest rectangle contained by both r and s. If the
+// two rectangles do not overlap then the zero rectangle will be returned.
+func (r Rectangle) Intersect(s Rectangle) Rectangle {
+       if r.Min.X < s.Min.X {
+               r.Min.X = s.Min.X
+       }
+       if r.Min.Y < s.Min.Y {
+               r.Min.Y = s.Min.Y
+       }
+       if r.Max.X > s.Max.X {
+               r.Max.X = s.Max.X
+       }
+       if r.Max.Y > s.Max.Y {
+               r.Max.Y = s.Max.Y
        }
+       if r.Min.X > r.Max.X || r.Min.Y > r.Max.Y {
+               return ZR
+       }
+       return r
+}
+
+// Union returns the smallest rectangle that contains both r and s.
+func (r Rectangle) Union(s Rectangle) Rectangle {
+       if r.Min.X > s.Min.X {
+               r.Min.X = s.Min.X
+       }
+       if r.Min.Y > s.Min.Y {
+               r.Min.Y = s.Min.Y
+       }
+       if r.Max.X < s.Max.X {
+               r.Max.X = s.Max.X
+       }
+       if r.Max.Y < s.Max.Y {
+               r.Max.Y = s.Max.Y
+       }
+       return r
 }
 
 // Empty returns whether the rectangle contains no points.
@@ -103,9 +157,8 @@ func (r Rectangle) Contains(p Point) bool {
                p.Y >= r.Min.Y && p.Y < r.Max.Y
 }
 
-// Canon returns the canonical version of r. The returned rectangle has
-// minimum and maximum coordinates swapped if necessary so that Min.X <= Max.X
-// and Min.Y <= Max.Y.
+// Canon returns the canonical version of r. The returned rectangle has minimum
+// and maximum coordinates swapped if necessary so that it is well-formed.
 func (r Rectangle) Canon() Rectangle {
        if r.Max.X < r.Min.X {
                r.Min.X, r.Max.X = r.Max.X, r.Min.X