Commit 2deee293 authored by Nigel Tao's avatar Nigel Tao

exp/draw: clip destination rectangle to the image bounds.

image: introduce Intersect and Union rectangle methods.

R=r, rog, nigeltao
CC=golang-dev
https://golang.org/cl/2115043
parent 6c8b8527
...@@ -60,9 +60,10 @@ func DrawMask(dst Image, r image.Rectangle, src image.Image, sp image.Point, mas ...@@ -60,9 +60,10 @@ func DrawMask(dst Image, r image.Rectangle, src image.Image, sp image.Point, mas
if r.Dy() > dy { if r.Dy() > dy {
r.Max.Y = r.Min.Y + dy r.Max.Y = r.Min.Y + dy
} }
r = r.Intersect(dst.Bounds())
// TODO(nigeltao): Clip r to dst's bounding box, and handle the case when sp or mp has negative X or Y. if r.Empty() {
// TODO(nigeltao): Ensure that r is well formed, i.e. r.Max.X >= r.Min.X and likewise for Y. return
}
// Fast paths for special cases. If none of them apply, then we fall back to a general but slow implementation. // 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 { if dst0, ok := dst.(*image.RGBA); ok {
......
...@@ -37,6 +37,9 @@ func Pt(X, Y int) Point { ...@@ -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. // 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 { type Rectangle struct {
Min, Max Point Min, Max Point
} }
...@@ -72,12 +75,63 @@ func (r Rectangle) Sub(p Point) Rectangle { ...@@ -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 { func (r Rectangle) Inset(n int) Rectangle {
return Rectangle{ if r.Dx() < 2*n {
Point{r.Min.X + n, r.Min.Y + n}, r.Min.X = (r.Min.X + r.Max.X) / 2
Point{r.Max.X - n, r.Max.Y - n}, 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. // Empty returns whether the rectangle contains no points.
...@@ -103,9 +157,8 @@ func (r Rectangle) Contains(p Point) bool { ...@@ -103,9 +157,8 @@ func (r Rectangle) Contains(p Point) bool {
p.Y >= r.Min.Y && p.Y < r.Max.Y p.Y >= r.Min.Y && p.Y < r.Max.Y
} }
// Canon returns the canonical version of r. The returned rectangle has // Canon returns the canonical version of r. The returned rectangle has minimum
// minimum and maximum coordinates swapped if necessary so that Min.X <= Max.X // and maximum coordinates swapped if necessary so that it is well-formed.
// and Min.Y <= Max.Y.
func (r Rectangle) Canon() Rectangle { func (r Rectangle) Canon() Rectangle {
if r.Max.X < r.Min.X { if r.Max.X < r.Min.X {
r.Min.X, r.Max.X = r.Max.X, r.Min.X r.Min.X, r.Max.X = r.Max.X, r.Min.X
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment