From aa7ef59ecd79828d3b5e2c35fdcac758fceb00b4 Mon Sep 17 00:00:00 2001 From: Ben Cragg Date: Wed, 3 Apr 2019 11:47:36 +0100 Subject: [PATCH] wip line tests --- geometry.go | 46 +++++++++++++++-------------------------- geometry_test.go | 54 +++++++++++++++++++++++++++--------------------- 2 files changed, 47 insertions(+), 53 deletions(-) diff --git a/geometry.go b/geometry.go index d6f9709..9872b74 100644 --- a/geometry.go +++ b/geometry.go @@ -211,25 +211,34 @@ func (l Line) Closest(v Vec) Vec { // Account for horizontal lines if m == 0 { - fmt.Println("h", l) x := v.X y := l.A.Y - fmt.Println(x, y) return V(x, y) } // Account for vertical lines if math.IsInf(math.Abs(m), 1) { - fmt.Println("v", l) x := l.A.X y := v.Y - fmt.Println(x, y) return V(x, y) } - // Check if the point is within the lines' bounding box, if not, one of the endpoints will be the closest point - if !l.Bounds().Contains(v) { - fmt.Println("out") + perpendicularM := -1 / m + perpendicularB := v.Y - (perpendicularM * v.X) + + // Coordinates of intersect (of infinite lines) + 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 toStart := v.To(l.A) toEnd := v.To(l.B) @@ -240,15 +249,6 @@ func (l Line) Closest(v Vec) Vec { return l.B } - perpendicularM := -1 / m - perpendicularB := v.Y - (perpendicularM * v.X) - fmt.Println(m, b, perpendicularM, perpendicularB) - - // Coordinates of intersect (of infinite lines) - x := (perpendicularB - b) / (m - perpendicularM) - y := m*x + b - fmt.Println(x, y) - return V(x, y) } @@ -273,11 +273,9 @@ func (l Line) Formula() (m, b float64) { // Intersect will return the point of intersection for the two line segments. If the line segments do not intersect, // this function will return the zero-vector and `false`. func (l Line) Intersect(k Line) (Vec, bool) { - fmt.Println(l, k) // Check if the lines are parallel lDir := l.A.To(l.B) kDir := k.A.To(k.B) - fmt.Println(lDir, kDir) if lDir.X == kDir.X && lDir.Y == kDir.Y { return ZV, false } @@ -287,7 +285,6 @@ func (l Line) Intersect(k Line) (Vec, bool) { // segments lm, lb := l.Formula() km, kb := k.Formula() - fmt.Println(lm, lb, km, kb) // Account for vertical lines if math.IsInf(math.Abs(lm), 1) && math.IsInf(math.Abs(km), 1) { @@ -326,8 +323,6 @@ func (l Line) Intersect(k Line) (Vec, bool) { // Coordinates of intersect x := (kb - lb) / (lm - km) y := lm*x + lb - fmt.Println(x, y) - fmt.Println(l.Contains(V(x, y)), k.Contains(V(x, y))) if l.Contains(V(x, y)) && k.Contains(V(x, y)) { // The intersect point is on both line segments, they intersect. @@ -356,22 +351,18 @@ func (l Line) IntersectCircle(c Circle) Vec { func (l Line) IntersectRect(r Rect) Vec { // Check if either end of the line segment are within the rectangle if r.Contains(l.A) || r.Contains(l.B) { - fmt.Println("yes1") // Use the `Rect.Intersect` to get minimal return value rIntersect := l.Bounds().Intersect(r) if rIntersect.H() > rIntersect.W() { - fmt.Println("yes2") // Go vertical return V(0, rIntersect.H()) } return V(rIntersect.W(), 0) } - fmt.Println("No") // Check if any of the rectangles' edges intersect with this line. for _, edge := range r.Edges() { if _, ok := l.Intersect(edge); ok { - fmt.Println(edge) // Get the closest points on the line to each corner, where: // - the point is contained by the rectangle // - the point is not the corner itself @@ -380,15 +371,12 @@ func (l Line) IntersectRect(r Rect) Vec { closestCorner := corners[0] for _, c := range corners { cc := l.Closest(c) - if closest != ZV || (closest.Len() > cc.Len() && r.Contains(cc)) { + if closest == ZV || (closest.Len() > cc.Len() && r.Contains(cc)) { closest = cc closestCorner = c } } - fmt.Println(closest) - fmt.Println(closestCorner) - return closest.To(closestCorner) } } diff --git a/geometry_test.go b/geometry_test.go index dfcbf32..86f3a45 100644 --- a/geometry_test.go +++ b/geometry_test.go @@ -865,6 +865,12 @@ func TestLine_Closest(t *testing.T) { args: args{v: pixel.V(5, 6)}, want: pixel.V(5, 5), }, + { + name: "Point far from line", + fields: fields{A: pixel.V(0, 0), B: pixel.V(10, 10)}, + args: args{v: pixel.V(80, -70)}, + want: pixel.V(5, 5), + }, { name: "Point on inline with line", fields: fields{A: pixel.V(0, 0), B: pixel.V(10, 10)}, @@ -1108,30 +1114,30 @@ func TestLine_IntersectRect(t *testing.T) { args: args{r: pixel.R(-1, 1, 5, 5)}, want: pixel.V(-1, 0), }, - // { - // name: "Line through rect horizontally", - // fields: fields{A: pixel.V(-5, 0), B: pixel.V(5, 0)}, - // args: args{r: pixel.R(-2, -5, 2, 1)}, - // want: pixel.V(0, 1), - // }, - // { - // name: "Line through rect diagonally bottom and left edges", - // fields: fields{A: pixel.V(0, 0), B: pixel.V(10, 10)}, - // args: args{r: pixel.R(0, 2, 3, 3)}, - // want: pixel.V(1, -1), - // }, - // { - // name: "Line through rect diagonally top and right edges", - // fields: fields{A: pixel.V(10, 0), B: pixel.V(0, 10)}, - // args: args{r: pixel.R(5, 0, 8, 3)}, - // want: pixel.V(-1, -1), - // }, - // { - // name: "Line with not rect intersect", - // fields: fields{A: pixel.V(0, 0), B: pixel.V(10, 10)}, - // args: args{r: pixel.R(20, 20, 21, 21)}, - // want: pixel.ZV, - // }, + { + name: "Line through rect horizontally", + fields: fields{A: pixel.V(0, 1), B: pixel.V(10, 1)}, + args: args{r: pixel.R(1, 0, 5, 5)}, + want: pixel.V(0, -1), + }, + { + name: "Line through rect diagonally bottom and left edges", + fields: fields{A: pixel.V(0, 0), B: pixel.V(10, 10)}, + args: args{r: pixel.R(0, 2, 3, 3)}, + want: pixel.V(-1, 1), + }, + { + name: "Line through rect diagonally top and right edges", + fields: fields{A: pixel.V(10, 0), B: pixel.V(0, 10)}, + args: args{r: pixel.R(5, 0, 8, 3)}, + want: pixel.V(-2.5, -2.5), + }, + { + name: "Line with not rect intersect", + fields: fields{A: pixel.V(0, 0), B: pixel.V(10, 10)}, + args: args{r: pixel.R(20, 20, 21, 21)}, + want: pixel.ZV, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) {