Adding vertical/horizontal edge cases

This commit is contained in:
Ben Cragg 2019-04-03 12:12:27 +01:00
parent e5ff236d71
commit 98d5b9b417
1 changed files with 30 additions and 9 deletions

View File

@ -206,20 +206,48 @@ func (l Line) Center() Vec {
// Closest will return the point on the line which is closest to the `Vec` provided. // Closest will return the point on the line which is closest to the `Vec` provided.
func (l Line) Closest(v Vec) Vec { func (l Line) Closest(v Vec) Vec {
// Closest point will be on a line, perpendicular to this line // between is a helper function which determines whether 'x' is greater than min(a, b) and less than max(a, b)
between := func(a, b, x float64) bool {
min := math.Min(a, b)
max := math.Max(a, b)
return min < x && x < max
}
// Closest point will be on a line which perpendicular to this line.
// If and only if the infinite perpendicular line intersects the segment.
m, b := l.Formula() m, b := l.Formula()
// Account for horizontal lines // Account for horizontal lines
if m == 0 { if m == 0 {
x := v.X x := v.X
y := l.A.Y y := l.A.Y
return V(x, y)
// check if the X coordinate of v is on the line
if between(l.A.X, l.B.X, v.X) {
return V(x, y)
}
// Otherwise get the closest endpoint
if l.A.To(v).Len() < l.B.To(v).Len() {
return l.A
}
return l.B
} }
// Account for vertical lines // Account for vertical lines
if math.IsInf(math.Abs(m), 1) { if math.IsInf(math.Abs(m), 1) {
x := l.A.X x := l.A.X
y := v.Y y := v.Y
// check if the Y coordinate of v is on the line
if between(l.A.Y, l.B.Y, v.Y) {
return V(x, y)
}
// Otherwise get the closest endpoint
if l.A.To(v).Len() < l.B.To(v).Len() {
return l.A
}
return V(x, y) return V(x, y)
} }
@ -230,13 +258,6 @@ func (l Line) Closest(v Vec) Vec {
x := (perpendicularB - b) / (m - perpendicularM) x := (perpendicularB - b) / (m - perpendicularM)
y := m*x + b y := m*x + b
// between is a helper function which determines whether 'x' is greater than min(a, b) and less than max(a, b)
between := func(a, b, x float64) bool {
min := math.Min(a, b)
max := math.Max(a, b)
return min < x && x < max
}
// Check if the point lies between the x and y bounds of the segment // Check if the point lies between the x and y bounds of the segment
if !between(l.A.X, l.B.X, x) && !between(l.A.Y, l.B.Y, y) { if !between(l.A.X, l.B.X, x) && !between(l.A.Y, l.B.Y, y) {
// Not within bounding box // Not within bounding box