added rect-circle intersection functions

This commit is contained in:
Ben Cragg 2019-01-29 11:20:21 +00:00
parent 620c551f70
commit 4c6d061455
2 changed files with 102 additions and 0 deletions

View File

@ -318,6 +318,16 @@ func (r Rect) Intersect(s Rect) Rect {
return t
}
// IntersectsCircle returns whether the Circle and the Rect intersect.
//
// This function will return true if:
// - The Rect contains the Circle, partially or fully
// - The Circle contains the Rect, partially of fully
// - An edge of the Rect is a tangent to the Circle
func (r Rect) IntersectsCircle(c Circle) bool {
return c.IntersectsRect(r)
}
// Circle is a 2D circle. It is defined by two properties:
// - Radius float64
// - Center vector
@ -470,6 +480,28 @@ func (c Circle) Intersect(d Circle) Circle {
}
}
// IntersectsRect returns whether the Circle and the Rect intersect.
//
// This function will return true if:
// - The Rect contains the Circle, partially or fully
// - The Circle contains the Rect, partially of fully
// - An edge of the Rect is a tangent to the Circle
func (c Circle) IntersectsRect(r Rect) bool {
// Checks if the c.Center is not in the diagonal quadrants of the rectangle
var grownR Rect
if (r.Min.X <= c.Center.X && c.Center.X <= r.Max.X) || (r.Min.Y <= c.Center.Y && c.Center.Y <= r.Max.Y) {
// 'grow' the Rect by c.Radius in each diagonal
grownR = Rect{
Min: r.Min.Sub(V(c.Radius, c.Radius)),
Max: r.Max.Add(V(c.Radius, c.Radius)),
}
return grownR.Contains(c.Center)
}
// The center is in the diagonal quadrants
return c.Center.To(r.Min).Len() <= c.Radius || c.Center.To(r.Max).Len() <= c.Radius
}
// Matrix is a 2x3 affine matrix that can be used for all kinds of spatial transforms, such
// as movement, scaling and rotations.
//

View File

@ -576,3 +576,73 @@ func TestCircle_Intersect(t *testing.T) {
})
}
}
func TestRect_IntersectsCircle(t *testing.T) {
type fields struct {
Min pixel.Vec
Max pixel.Vec
}
type args struct {
c pixel.Circle
}
tests := []struct {
name string
fields fields
args args
want bool
}{
{
name: "Rect.IntersectsCircle(): no overlap",
fields: fields{Min: pixel.V(0, 0), Max: pixel.V(10, 10)},
args: args{c: pixel.C(1, pixel.V(50, 50))},
want: false,
},
{
name: "Rect.IntersectsCircle(): circle contains rect",
fields: fields{Min: pixel.V(0, 0), Max: pixel.V(10, 10)},
args: args{c: pixel.C(10, pixel.V(5, 5))},
want: true,
},
{
name: "Rect.IntersectsCircle(): rect contains circle",
fields: fields{Min: pixel.V(0, 0), Max: pixel.V(10, 10)},
args: args{c: pixel.C(1, pixel.V(5, 5))},
want: true,
},
{
name: "Rect.IntersectsCircle(): circle overlaps one corner",
fields: fields{Min: pixel.V(0, 0), Max: pixel.V(10, 10)},
args: args{c: pixel.C(1, pixel.V(0, 0))},
want: true,
},
{
name: "Rect.IntersectsCircle(): circle overlaps two corner",
fields: fields{Min: pixel.V(0, 0), Max: pixel.V(10, 10)},
args: args{c: pixel.C(11, pixel.V(0, 5))},
want: true,
},
{
name: "Rect.IntersectsCircle(): circle overlaps one edge",
fields: fields{Min: pixel.V(0, 0), Max: pixel.V(10, 10)},
args: args{c: pixel.C(1, pixel.V(0, 5))},
want: true,
},
{
name: "Rect.IntersectsCircle(): edge is tangent",
fields: fields{Min: pixel.V(0, 0), Max: pixel.V(10, 10)},
args: args{c: pixel.C(1, pixel.V(-1, 5))},
want: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
r := pixel.Rect{
Min: tt.fields.Min,
Max: tt.fields.Max,
}
if got := r.IntersectsCircle(tt.args.c); got != tt.want {
t.Errorf("Rect.IntersectsCircle() = %v, want %v", got, tt.want)
}
})
}
}