2022-11-03 13:54:49 +00:00
|
|
|
package geo
|
|
|
|
|
|
|
|
|
|
import "fmt"
|
|
|
|
|
|
|
|
|
|
type Box struct {
|
|
|
|
|
TopLeft *Point
|
|
|
|
|
Width float64
|
|
|
|
|
Height float64
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func NewBox(tl *Point, width, height float64) *Box {
|
|
|
|
|
return &Box{
|
|
|
|
|
TopLeft: tl,
|
|
|
|
|
Width: width,
|
|
|
|
|
Height: height,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (b *Box) Copy() *Box {
|
|
|
|
|
if b == nil {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
return NewBox(b.TopLeft.Copy(), b.Width, b.Height)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (b *Box) Center() *Point {
|
|
|
|
|
return NewPoint(b.TopLeft.X+b.Width/2, b.TopLeft.Y+b.Height/2)
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-14 21:11:51 +00:00
|
|
|
// Intersects returns true if the segment comes within buffer of the box
|
|
|
|
|
func (b *Box) Intersects(s Segment, buffer float64) bool {
|
|
|
|
|
tl := NewPoint(b.TopLeft.X-buffer, b.TopLeft.Y-buffer)
|
|
|
|
|
tr := NewPoint(tl.X+b.Width+buffer*2, tl.Y)
|
|
|
|
|
br := NewPoint(tr.X, tr.Y+b.Height+buffer*2)
|
|
|
|
|
bl := NewPoint(tl.X, br.Y)
|
|
|
|
|
|
|
|
|
|
if p := IntersectionPoint(s.Start, s.End, tl, tr); p != nil {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
if p := IntersectionPoint(s.Start, s.End, tr, br); p != nil {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
if p := IntersectionPoint(s.Start, s.End, br, bl); p != nil {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
if p := IntersectionPoint(s.Start, s.End, bl, tl); p != nil {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-03 13:54:49 +00:00
|
|
|
func (b *Box) Intersections(s Segment) []*Point {
|
|
|
|
|
pts := []*Point{}
|
|
|
|
|
|
|
|
|
|
tl := b.TopLeft
|
|
|
|
|
tr := NewPoint(tl.X+b.Width, tl.Y)
|
|
|
|
|
br := NewPoint(tr.X, tr.Y+b.Height)
|
|
|
|
|
bl := NewPoint(tl.X, br.Y)
|
|
|
|
|
|
|
|
|
|
if p := IntersectionPoint(s.Start, s.End, tl, tr); p != nil {
|
|
|
|
|
pts = append(pts, p)
|
|
|
|
|
}
|
|
|
|
|
if p := IntersectionPoint(s.Start, s.End, tr, br); p != nil {
|
|
|
|
|
pts = append(pts, p)
|
|
|
|
|
}
|
|
|
|
|
if p := IntersectionPoint(s.Start, s.End, br, bl); p != nil {
|
|
|
|
|
pts = append(pts, p)
|
|
|
|
|
}
|
|
|
|
|
if p := IntersectionPoint(s.Start, s.End, bl, tl); p != nil {
|
|
|
|
|
pts = append(pts, p)
|
|
|
|
|
}
|
|
|
|
|
return pts
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (b *Box) ToString() string {
|
|
|
|
|
if b == nil {
|
|
|
|
|
return ""
|
|
|
|
|
}
|
|
|
|
|
return fmt.Sprintf("{TopLeft: %s, Width: %.0f, Height: %.0f}", b.TopLeft.ToString(), b.Width, b.Height)
|
|
|
|
|
}
|
2023-07-14 20:24:00 +00:00
|
|
|
|
|
|
|
|
func (b *Box) Contains(p *Point) bool {
|
|
|
|
|
return !(p.X < b.TopLeft.X || b.TopLeft.X+b.Width < p.X ||
|
|
|
|
|
p.Y < b.TopLeft.Y || b.TopLeft.Y+b.Height < p.Y)
|
|
|
|
|
}
|
2023-07-19 02:24:32 +00:00
|
|
|
|
|
|
|
|
func (b1 Box) Overlaps(b2 Box) bool {
|
|
|
|
|
// https://silentmatt.com/rectangle-intersection/
|
|
|
|
|
return (b1.TopLeft.X < (b2.TopLeft.X + b2.Width)) && ((b1.TopLeft.X + b1.Width) > b2.TopLeft.X) &&
|
|
|
|
|
(b1.TopLeft.Y < (b2.TopLeft.Y + b2.Height)) && ((b1.TopLeft.Y + b1.Height) > b2.TopLeft.Y)
|
|
|
|
|
}
|