From 98d5b9b417d585a2d0baf4a28c7b2dd3fe7b4b35 Mon Sep 17 00:00:00 2001 From: Ben Cragg Date: Wed, 3 Apr 2019 12:12:27 +0100 Subject: [PATCH] Adding vertical/horizontal edge cases --- geometry.go | 39 ++++++++++++++++++++++++++++++--------- 1 file changed, 30 insertions(+), 9 deletions(-) diff --git a/geometry.go b/geometry.go index 4f4c1e4..73f4854 100644 --- a/geometry.go +++ b/geometry.go @@ -206,20 +206,48 @@ func (l Line) Center() Vec { // Closest will return the point on the line which is closest to the `Vec` provided. 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() // Account for horizontal lines if m == 0 { x := v.X 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 if math.IsInf(math.Abs(m), 1) { x := l.A.X 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) } @@ -230,13 +258,6 @@ func (l Line) Closest(v Vec) Vec { x := (perpendicularB - b) / (m - perpendicularM) 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 if !between(l.A.X, l.B.X, x) && !between(l.A.Y, l.B.Y, y) { // Not within bounding box