swapped radius and center order

This commit is contained in:
Ben Cragg 2019-01-30 08:37:27 +00:00
parent 4d30a8fe49
commit 5abf2d29a6
2 changed files with 59 additions and 59 deletions

View File

@ -329,20 +329,20 @@ func (r Rect) IntersectsCircle(c Circle) bool {
} }
// Circle is a 2D circle. It is defined by two properties: // Circle is a 2D circle. It is defined by two properties:
// - Radius float64
// - Center vector // - Center vector
// - Radius float64
type Circle struct { type Circle struct {
Radius float64
Center Vec Center Vec
Radius float64
} }
// C returns a new Circle with the given radius and center coordinates. // C returns a new Circle with the given radius and center coordinates.
// //
// Note that a negative radius is valid. // Note that a negative radius is valid.
func C(radius float64, center Vec) Circle { func C(center Vec, radius float64) Circle {
return Circle{ return Circle{
Radius: radius,
Center: center, Center: center,
Radius: radius,
} }
} }
@ -352,17 +352,17 @@ func C(radius float64, center Vec) Circle {
// c.String() // returns "Circle(10.12, Vec(0, 0))" // c.String() // returns "Circle(10.12, Vec(0, 0))"
// fmt.Println(c) // Circle(10.12, Vec(0, 0)) // fmt.Println(c) // Circle(10.12, Vec(0, 0))
func (c Circle) String() string { func (c Circle) String() string {
return fmt.Sprintf("Circle(%.2f, %s)", c.Radius, c.Center) return fmt.Sprintf("Circle(%s, %.2f)", c.Center, c.Radius)
} }
// Norm returns the Circle in normalized form - this sets the radius to its absolute value. // Norm returns the Circle in normalized form - this sets the radius to its absolute value.
// //
// c := pixel.C(-10, pixel.ZV) // c := pixel.C(-10, pixel.ZV)
// c.Norm() // returns pixel.Circle{10, pixel.Vec{0, 0}} // c.Norm() // returns pixel.Circle{pixel.Vec{0, 0}, 10}
func (c Circle) Norm() Circle { func (c Circle) Norm() Circle {
return Circle{ return Circle{
Radius: math.Abs(c.Radius),
Center: c.Center, Center: c.Center,
Radius: math.Abs(c.Radius),
} }
} }
@ -374,20 +374,20 @@ func (c Circle) Area() float64 {
// Moved returns the Circle moved by the given vector delta. // Moved returns the Circle moved by the given vector delta.
func (c Circle) Moved(delta Vec) Circle { func (c Circle) Moved(delta Vec) Circle {
return Circle{ return Circle{
Radius: c.Radius,
Center: c.Center.Add(delta), Center: c.Center.Add(delta),
Radius: c.Radius,
} }
} }
// Resized returns the Circle resized by the given delta. The Circles center is use as the anchor. // Resized returns the Circle resized by the given delta. The Circles center is use as the anchor.
// //
// c := pixel.C(10, pixel.ZV) // c := pixel.C(pixel.ZV, 10)
// c.Resized(-5) // returns pixel.Circle{5, pixel.Vec{0, 0}} // c.Resized(-5) // returns pixel.Circle{pixel.Vec{0, 0}, 5}
// c.Resized(25) // returns pixel.Circle{35, pixel.Vec{0, 0}} // c.Resized(25) // returns pixel.Circle{pixel.Vec{0, 0}, 35}
func (c Circle) Resized(radiusDelta float64) Circle { func (c Circle) Resized(radiusDelta float64) Circle {
return Circle{ return Circle{
Radius: c.Radius + radiusDelta,
Center: c.Center, Center: c.Center,
Radius: c.Radius + radiusDelta,
} }
} }
@ -434,8 +434,8 @@ func (c Circle) Union(d Circle) Circle {
center := Lerp(smallerC.Center, biggerC.Center, theta) center := Lerp(smallerC.Center, biggerC.Center, theta)
return Circle{ return Circle{
Radius: r,
Center: center, Center: center,
Radius: r,
} }
} }
@ -464,14 +464,14 @@ func (c Circle) Intersect(d Circle) Circle {
// No need to calculate radius if the circles do not overlap // No need to calculate radius if the circles do not overlap
if c.Center.To(d.Center).Len() >= c.Radius+d.Radius { if c.Center.To(d.Center).Len() >= c.Radius+d.Radius {
return C(0, center) return C(center, 0)
} }
radius := c.Center.To(d.Center).Len() - (c.Radius + d.Radius) radius := c.Center.To(d.Center).Len() - (c.Radius + d.Radius)
return Circle{ return Circle{
Radius: math.Abs(radius),
Center: center, Center: center,
Radius: math.Abs(radius),
} }
} }

View File

@ -191,7 +191,7 @@ func TestC(t *testing.T) {
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
if got := pixel.C(tt.args.radius, tt.args.center); !reflect.DeepEqual(got, tt.want) { if got := pixel.C(tt.args.center, tt.args.radius); !reflect.DeepEqual(got, tt.want) {
t.Errorf("C() = %v, want %v", got, tt.want) t.Errorf("C() = %v, want %v", got, tt.want)
} }
}) })
@ -211,27 +211,27 @@ func TestCircle_String(t *testing.T) {
{ {
name: "Circle.String(): positive radius", name: "Circle.String(): positive radius",
fields: fields{radius: 10, center: pixel.ZV}, fields: fields{radius: 10, center: pixel.ZV},
want: "Circle(10.00, Vec(0, 0))", want: "Circle(Vec(0, 0), 10.00)",
}, },
{ {
name: "Circle.String(): zero radius", name: "Circle.String(): zero radius",
fields: fields{radius: 0, center: pixel.ZV}, fields: fields{radius: 0, center: pixel.ZV},
want: "Circle(0.00, Vec(0, 0))", want: "Circle(Vec(0, 0), 0.00)",
}, },
{ {
name: "Circle.String(): negative radius", name: "Circle.String(): negative radius",
fields: fields{radius: -5, center: pixel.ZV}, fields: fields{radius: -5, center: pixel.ZV},
want: "Circle(-5.00, Vec(0, 0))", want: "Circle(Vec(0, 0), -5.00)",
}, },
{ {
name: "Circle.String(): irrational radius", name: "Circle.String(): irrational radius",
fields: fields{radius: math.Pi, center: pixel.ZV}, fields: fields{radius: math.Pi, center: pixel.ZV},
want: "Circle(3.14, Vec(0, 0))", want: "Circle(Vec(0, 0), 3.14)",
}, },
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
c := pixel.C(tt.fields.radius, tt.fields.center) c := pixel.C(tt.fields.center, tt.fields.radius)
if got := c.String(); got != tt.want { if got := c.String(); got != tt.want {
t.Errorf("Circle.String() = %v, want %v", got, tt.want) t.Errorf("Circle.String() = %v, want %v", got, tt.want)
} }
@ -252,22 +252,22 @@ func TestCircle_Norm(t *testing.T) {
{ {
name: "Circle.Norm(): positive radius", name: "Circle.Norm(): positive radius",
fields: fields{radius: 10, center: pixel.ZV}, fields: fields{radius: 10, center: pixel.ZV},
want: pixel.C(10, pixel.ZV), want: pixel.C(pixel.ZV, 10),
}, },
{ {
name: "Circle.Norm(): zero radius", name: "Circle.Norm(): zero radius",
fields: fields{radius: 0, center: pixel.ZV}, fields: fields{radius: 0, center: pixel.ZV},
want: pixel.C(0, pixel.ZV), want: pixel.C(pixel.ZV, 0),
}, },
{ {
name: "Circle.Norm(): negative radius", name: "Circle.Norm(): negative radius",
fields: fields{radius: -5, center: pixel.ZV}, fields: fields{radius: -5, center: pixel.ZV},
want: pixel.C(5, pixel.ZV), want: pixel.C(pixel.ZV, 5),
}, },
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
c := pixel.C(tt.fields.radius, tt.fields.center) c := pixel.C(tt.fields.center, tt.fields.radius)
if got := c.Norm(); !reflect.DeepEqual(got, tt.want) { if got := c.Norm(); !reflect.DeepEqual(got, tt.want) {
t.Errorf("Circle.Norm() = %v, want %v", got, tt.want) t.Errorf("Circle.Norm() = %v, want %v", got, tt.want)
} }
@ -303,7 +303,7 @@ func TestCircle_Area(t *testing.T) {
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
c := pixel.C(tt.fields.radius, tt.fields.center) c := pixel.C(tt.fields.center, tt.fields.radius)
if got := c.Area(); got != tt.want { if got := c.Area(); got != tt.want {
t.Errorf("Circle.Area() = %v, want %v", got, tt.want) t.Errorf("Circle.Area() = %v, want %v", got, tt.want)
} }
@ -329,24 +329,24 @@ func TestCircle_Moved(t *testing.T) {
name: "Circle.Moved(): positive movement", name: "Circle.Moved(): positive movement",
fields: fields{radius: 10, center: pixel.ZV}, fields: fields{radius: 10, center: pixel.ZV},
args: args{delta: pixel.V(10, 20)}, args: args{delta: pixel.V(10, 20)},
want: pixel.C(10, pixel.V(10, 20)), want: pixel.C(pixel.V(10, 20), 10),
}, },
{ {
name: "Circle.Moved(): zero movement", name: "Circle.Moved(): zero movement",
fields: fields{radius: 10, center: pixel.ZV}, fields: fields{radius: 10, center: pixel.ZV},
args: args{delta: pixel.ZV}, args: args{delta: pixel.ZV},
want: pixel.C(10, pixel.V(0, 0)), want: pixel.C(pixel.V(0, 0), 10),
}, },
{ {
name: "Circle.Moved(): negative movement", name: "Circle.Moved(): negative movement",
fields: fields{radius: 10, center: pixel.ZV}, fields: fields{radius: 10, center: pixel.ZV},
args: args{delta: pixel.V(-5, -10)}, args: args{delta: pixel.V(-5, -10)},
want: pixel.C(10, pixel.V(-5, -10)), want: pixel.C(pixel.V(-5, -10), 10),
}, },
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
c := pixel.C(tt.fields.radius, tt.fields.center) c := pixel.C(tt.fields.center, tt.fields.radius)
if got := c.Moved(tt.args.delta); !reflect.DeepEqual(got, tt.want) { if got := c.Moved(tt.args.delta); !reflect.DeepEqual(got, tt.want) {
t.Errorf("Circle.Moved() = %v, want %v", got, tt.want) t.Errorf("Circle.Moved() = %v, want %v", got, tt.want)
} }
@ -372,24 +372,24 @@ func TestCircle_Resized(t *testing.T) {
name: "Circle.Resized(): positive delta", name: "Circle.Resized(): positive delta",
fields: fields{radius: 10, center: pixel.ZV}, fields: fields{radius: 10, center: pixel.ZV},
args: args{radiusDelta: 5}, args: args{radiusDelta: 5},
want: pixel.C(15, pixel.V(0, 0)), want: pixel.C(pixel.V(0, 0), 15),
}, },
{ {
name: "Circle.Resized(): zero delta", name: "Circle.Resized(): zero delta",
fields: fields{radius: 10, center: pixel.ZV}, fields: fields{radius: 10, center: pixel.ZV},
args: args{radiusDelta: 0}, args: args{radiusDelta: 0},
want: pixel.C(10, pixel.V(0, 0)), want: pixel.C(pixel.V(0, 0), 10),
}, },
{ {
name: "Circle.Resized(): negative delta", name: "Circle.Resized(): negative delta",
fields: fields{radius: 10, center: pixel.ZV}, fields: fields{radius: 10, center: pixel.ZV},
args: args{radiusDelta: -5}, args: args{radiusDelta: -5},
want: pixel.C(5, pixel.V(0, 0)), want: pixel.C(pixel.V(0, 0), 5),
}, },
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
c := pixel.C(tt.fields.radius, tt.fields.center) c := pixel.C(tt.fields.center, tt.fields.radius)
if got := c.Resized(tt.args.radiusDelta); !reflect.DeepEqual(got, tt.want) { if got := c.Resized(tt.args.radiusDelta); !reflect.DeepEqual(got, tt.want) {
t.Errorf("Circle.Resized() = %v, want %v", got, tt.want) t.Errorf("Circle.Resized() = %v, want %v", got, tt.want)
} }
@ -438,7 +438,7 @@ func TestCircle_Contains(t *testing.T) {
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
c := pixel.C(tt.fields.radius, tt.fields.center) c := pixel.C(tt.fields.center, tt.fields.radius)
if got := c.Contains(tt.args.u); got != tt.want { if got := c.Contains(tt.args.u); got != tt.want {
t.Errorf("Circle.Contains() = %v, want %v", got, tt.want) t.Errorf("Circle.Contains() = %v, want %v", got, tt.want)
} }
@ -463,19 +463,19 @@ func TestCircle_Union(t *testing.T) {
{ {
name: "Circle.Union(): overlapping circles", name: "Circle.Union(): overlapping circles",
fields: fields{radius: 5, center: pixel.ZV}, fields: fields{radius: 5, center: pixel.ZV},
args: args{d: pixel.C(5, pixel.ZV)}, args: args{d: pixel.C(pixel.ZV, 5)},
want: pixel.C(5, pixel.ZV), want: pixel.C(pixel.ZV, 5),
}, },
{ {
name: "Circle.Union(): separate circles", name: "Circle.Union(): separate circles",
fields: fields{radius: 1, center: pixel.ZV}, fields: fields{radius: 1, center: pixel.ZV},
args: args{d: pixel.C(1, pixel.V(0, 2))}, args: args{d: pixel.C(pixel.V(0, 2), 1)},
want: pixel.C(2, pixel.V(0, 1)), want: pixel.C(pixel.V(0, 1), 2),
}, },
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
c := pixel.C(tt.fields.radius, tt.fields.center) c := pixel.C(tt.fields.center, tt.fields.radius)
if got := c.Union(tt.args.d); !reflect.DeepEqual(got, tt.want) { if got := c.Union(tt.args.d); !reflect.DeepEqual(got, tt.want) {
t.Errorf("Circle.Union() = %v, want %v", got, tt.want) t.Errorf("Circle.Union() = %v, want %v", got, tt.want)
} }
@ -500,39 +500,39 @@ func TestCircle_Intersect(t *testing.T) {
{ {
name: "Circle.Intersect(): intersecting circles", name: "Circle.Intersect(): intersecting circles",
fields: fields{radius: 1, center: pixel.ZV}, fields: fields{radius: 1, center: pixel.ZV},
args: args{d: pixel.C(1, pixel.V(1, 0))}, args: args{d: pixel.C(pixel.V(1, 0), 1)},
want: pixel.C(1, pixel.V(0.5, 0)), want: pixel.C(pixel.V(0.5, 0), 1),
}, },
{ {
name: "Circle.Intersect(): non-intersecting circles", name: "Circle.Intersect(): non-intersecting circles",
fields: fields{radius: 1, center: pixel.ZV}, fields: fields{radius: 1, center: pixel.ZV},
args: args{d: pixel.C(1, pixel.V(3, 3))}, args: args{d: pixel.C(pixel.V(3, 3), 1)},
want: pixel.C(0, pixel.V(1.5, 1.5)), want: pixel.C(pixel.V(1.5, 1.5), 0),
}, },
{ {
name: "Circle.Intersect(): first circle encompassing second", name: "Circle.Intersect(): first circle encompassing second",
fields: fields{radius: 10, center: pixel.ZV}, fields: fields{radius: 10, center: pixel.ZV},
args: args{d: pixel.C(1, pixel.V(3, 3))}, args: args{d: pixel.C(pixel.V(3, 3), 1)},
want: pixel.C(10, pixel.ZV), want: pixel.C(pixel.ZV, 10),
}, },
{ {
name: "Circle.Intersect(): second circle encompassing first", name: "Circle.Intersect(): second circle encompassing first",
fields: fields{radius: 1, center: pixel.V(-1, -4)}, fields: fields{radius: 1, center: pixel.V(-1, -4)},
args: args{d: pixel.C(10, pixel.ZV)}, args: args{d: pixel.C(pixel.ZV, 10)},
want: pixel.C(10, pixel.ZV), want: pixel.C(pixel.ZV, 10),
}, },
{ {
name: "Circle.Intersect(): matching circles", name: "Circle.Intersect(): matching circles",
fields: fields{radius: 1, center: pixel.ZV}, fields: fields{radius: 1, center: pixel.ZV},
args: args{d: pixel.C(1, pixel.ZV)}, args: args{d: pixel.C(pixel.ZV, 1)},
want: pixel.C(1, pixel.ZV), want: pixel.C(pixel.ZV, 1),
}, },
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
c := pixel.C( c := pixel.C(
tt.fields.radius,
tt.fields.center, tt.fields.center,
tt.fields.radius,
) )
if got := c.Intersect(tt.args.d); !reflect.DeepEqual(got, tt.want) { if got := c.Intersect(tt.args.d); !reflect.DeepEqual(got, tt.want) {
t.Errorf("Circle.Intersect() = %v, want %v", got, tt.want) t.Errorf("Circle.Intersect() = %v, want %v", got, tt.want)
@ -558,49 +558,49 @@ func TestRect_IntersectsCircle(t *testing.T) {
{ {
name: "Rect.IntersectsCircle(): no overlap", name: "Rect.IntersectsCircle(): no overlap",
fields: fields{Min: pixel.ZV, Max: pixel.V(10, 10)}, fields: fields{Min: pixel.ZV, Max: pixel.V(10, 10)},
args: args{c: pixel.C(1, pixel.V(50, 50))}, args: args{c: pixel.C(pixel.V(50, 50), 1)},
want: false, want: false,
}, },
{ {
name: "Rect.IntersectsCircle(): circle contains rect", name: "Rect.IntersectsCircle(): circle contains rect",
fields: fields{Min: pixel.ZV, Max: pixel.V(10, 10)}, fields: fields{Min: pixel.ZV, Max: pixel.V(10, 10)},
args: args{c: pixel.C(10, pixel.V(5, 5))}, args: args{c: pixel.C(pixel.V(5, 5), 10)},
want: true, want: true,
}, },
{ {
name: "Rect.IntersectsCircle(): rect contains circle", name: "Rect.IntersectsCircle(): rect contains circle",
fields: fields{Min: pixel.ZV, Max: pixel.V(10, 10)}, fields: fields{Min: pixel.ZV, Max: pixel.V(10, 10)},
args: args{c: pixel.C(1, pixel.V(5, 5))}, args: args{c: pixel.C(pixel.V(5, 5), 1)},
want: true, want: true,
}, },
{ {
name: "Rect.IntersectsCircle(): circle overlaps bottom-left corner", name: "Rect.IntersectsCircle(): circle overlaps bottom-left corner",
fields: fields{Min: pixel.ZV, Max: pixel.V(10, 10)}, fields: fields{Min: pixel.ZV, Max: pixel.V(10, 10)},
args: args{c: pixel.C(1, pixel.V(-.5, -.5))}, args: args{c: pixel.C(pixel.V(-.5, -.5), 1)},
want: true, want: true,
}, },
{ {
name: "Rect.IntersectsCircle(): circle overlaps top-left corner", name: "Rect.IntersectsCircle(): circle overlaps top-left corner",
fields: fields{Min: pixel.ZV, Max: pixel.V(10, 10)}, fields: fields{Min: pixel.ZV, Max: pixel.V(10, 10)},
args: args{c: pixel.C(1, pixel.V(-.5, 10.5))}, args: args{c: pixel.C(pixel.V(-.5, 10.5), 1)},
want: true, want: true,
}, },
{ {
name: "Rect.IntersectsCircle(): circle overlaps two corners", name: "Rect.IntersectsCircle(): circle overlaps two corners",
fields: fields{Min: pixel.ZV, Max: pixel.V(10, 10)}, fields: fields{Min: pixel.ZV, Max: pixel.V(10, 10)},
args: args{c: pixel.C(6, pixel.V(0, 5))}, args: args{c: pixel.C(pixel.V(0, 5), 6)},
want: true, want: true,
}, },
{ {
name: "Rect.IntersectsCircle(): circle overlaps one edge", name: "Rect.IntersectsCircle(): circle overlaps one edge",
fields: fields{Min: pixel.ZV, Max: pixel.V(10, 10)}, fields: fields{Min: pixel.ZV, Max: pixel.V(10, 10)},
args: args{c: pixel.C(1, pixel.V(0, 5))}, args: args{c: pixel.C(pixel.V(0, 5), 1)},
want: true, want: true,
}, },
{ {
name: "Rect.IntersectsCircle(): edge is tangent", name: "Rect.IntersectsCircle(): edge is tangent",
fields: fields{Min: pixel.ZV, Max: pixel.V(10, 10)}, fields: fields{Min: pixel.ZV, Max: pixel.V(10, 10)},
args: args{c: pixel.C(1, pixel.V(-1, 5))}, args: args{c: pixel.C(pixel.V(-1, 5), 1)},
want: true, want: true,
}, },
} }