diff --git a/geometry.go b/geometry.go index 4b45afb..f2c0017 100644 --- a/geometry.go +++ b/geometry.go @@ -314,38 +314,26 @@ func (l Line) Intersect(k Line) (Vec, bool) { return ZV, false } + var x, y float64 + if math.IsInf(math.Abs(lm), 1) || math.IsInf(math.Abs(km), 1) { // One line is vertical intersectM := lm intersectB := lb - verticalLine := k if math.IsInf(math.Abs(lm), 1) { intersectM = km intersectB = kb - verticalLine = l } - maxVerticalY := verticalLine.A.Y - minVerticalY := verticalLine.B.Y - if verticalLine.B.Y > maxVerticalY { - maxVerticalY = verticalLine.B.Y - minVerticalY = verticalLine.A.Y - } - - y := intersectM*l.A.X + intersectB - if y > maxVerticalY || y < minVerticalY { - // Point is not on the horizontal line - return ZV, false - } - - return V(l.A.X, y), true + y = intersectM*l.A.X + intersectB + x = l.A.X + } else { + // Coordinates of intersect + x = (kb - lb) / (lm - km) + y = lm*x + lb } - // Coordinates of intersect - x := (kb - lb) / (lm - km) - y := lm*x + lb - if l.Contains(V(x, y)) && k.Contains(V(x, y)) { // The intersect point is on both line segments, they intersect. return V(x, y), true @@ -619,6 +607,28 @@ func (r Rect) IntersectLine(l Line) Vec { return l.IntersectRect(r).Scaled(-1) } +// IntersectionPoints returns all the points where the Rect intersects with the line provided. This can be zero, one or +// two points, depending on the location of the shapes. +func (r Rect) IntersectionPoints(l Line) []Vec { + // Use map keys to ensure unique points + pointMap := make(map[Vec]struct{}) + + for _, edge := range r.Edges() { + if intersect, ok := edge.Intersect(l); ok { + fmt.Println(edge) + fmt.Println(l) + fmt.Println(intersect) + pointMap[intersect] = struct{}{} + } + } + + points := make([]Vec, 0, len(pointMap)) + for point := range pointMap { + points = append(points, point) + } + return points +} + // Vertices returns a slice of the four corners which make up the rectangle. func (r Rect) Vertices() [4]Vec { return [4]Vec{ @@ -858,6 +868,12 @@ func (c Circle) IntersectRect(r Rect) Vec { } } +// IntersectionPoints returns all the points where the Circle intersects with the line provided. This can be zero, one or +// two points, depending on the location of the shapes. +func (c Circle) IntersectionPoints(l Line) []Vec { + return []Vec{} +} + // Matrix is a 2x3 affine matrix that can be used for all kinds of spatial transforms, such // as movement, scaling and rotations. // diff --git a/geometry_test.go b/geometry_test.go index 488a5a3..4f8f8df 100644 --- a/geometry_test.go +++ b/geometry_test.go @@ -609,6 +609,35 @@ func TestCircle_Intersect(t *testing.T) { } } +func TestCircle_IntersectPoints(t *testing.T) { + type fields struct { + Center pixel.Vec + Radius float64 + } + type args struct { + l pixel.Line + } + tests := []struct { + name string + fields fields + args args + want []pixel.Vec + }{ + // TODO: Add test cases. + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c := pixel.Circle{ + Center: tt.fields.Center, + Radius: tt.fields.Radius, + } + if got := c.IntersectionPoints(tt.args.l); !reflect.DeepEqual(got, tt.want) { + t.Errorf("Circle.IntersectPoints() = %v, want %v", got, tt.want) + } + }) + } +} + func TestRect_IntersectCircle(t *testing.T) { // closeEnough will shift the decimal point by the accuracy required, truncates the results and compares them. // Effectively this compares two floats to a given decimal point. @@ -759,6 +788,52 @@ func TestRect_IntersectCircle(t *testing.T) { } } +func TestRect_IntersectionPoints(t *testing.T) { + type fields struct { + Min pixel.Vec + Max pixel.Vec + } + type args struct { + l pixel.Line + } + tests := []struct { + name string + fields fields + args args + want []pixel.Vec + }{ + { + name: "No intersection points", + fields: fields{Min: pixel.V(1, 1), Max: pixel.V(5, 5)}, + args: args{l: pixel.L(pixel.V(-5, 0), pixel.V(-2, 2))}, + want: []pixel.Vec{}, + }, + // { + // name: "One intersection point", + // fields: fields{Min: pixel.V(1, 1), Max: pixel.V(5, 5)}, + // args: args{l: pixel.L(pixel.V(2, 0), pixel.V(2, 2))}, + // want: []pixel.Vec{pixel.V(2, 1)}, + // }, + // { + // name: "Two intersection points", + // fields: fields{Min: pixel.V(1, 1), Max: pixel.V(5, 5)}, + // args: args{l: pixel.L(pixel.V(0, 2), pixel.V(6, 2))}, + // want: []pixel.Vec{pixel.V(1, 2), pixel.V(5, 2)}, + // }, + } + 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.IntersectionPoints(tt.args.l); !reflect.DeepEqual(got, tt.want) { + t.Errorf("Rect.IntersectPoints() = %v, want %v", got, tt.want) + } + }) + } +} + func TestLine_Bounds(t *testing.T) { type fields struct { A pixel.Vec @@ -1008,6 +1083,13 @@ func TestLine_Intersect(t *testing.T) { want: pixel.V(5, 5), want1: true, }, + { + name: "Lines intersect 2", + fields: fields{A: pixel.V(1, 1), B: pixel.V(1, 5)}, + args: args{k: pixel.L(pixel.V(-5, 0), pixel.V(-2, 2))}, + want: pixel.ZV, + want1: false, + }, { name: "Line intersect with vertical", fields: fields{A: pixel.V(5, 0), B: pixel.V(5, 10)},