diff --git a/geometry.go b/geometry.go
index 82ff17b119aa77ae23b0a901dbe5e58e608aa179..61b93cac62f14b141ed48c046666f086624f11e8 100644
--- a/geometry.go
+++ b/geometry.go
@@ -345,7 +345,7 @@ func (c Circle) String() string {
 	return fmt.Sprintf("Circle(%.2f, %s)", c.Radius, c.Center)
 }
 
-// Norm returns the Circle in normalized form - this is that the radius is set to an absolute version.
+// Norm returns the Circle in normalized form - this sets the radius to its absolute value.
 //
 // c := pixel.C(-10, pixel.ZV)
 // c.Norm() // returns pixel.Circle{10, pixel.Vec{0, 0}}
@@ -374,7 +374,7 @@ func (c Circle) Moved(delta Vec) Circle {
 	}
 }
 
-// Resized returns the Circle resized by the given delta.
+// Resized returns the Circle resized by the given delta.  The Circles center is use as the anchor.
 //
 // c := pixel.C(10, pixel.ZV)
 // c.Resized(-5) // returns pixel.Circle{5, pixel.Vec{0, 0}}
@@ -392,14 +392,26 @@ func (c Circle) Contains(u Vec) bool {
 	return c.Radius >= toCenter.Len()
 }
 
-// Union returns the minimal Circle which covers both `c` and `d`.
-func (c Circle) Union(d Circle) Circle {
-	biggerC := c
-	smallerC := d
+// MaxCircle will return the larger circle based on the radius.
+func MaxCircle(c, d Circle) Circle {
+	if c.Radius < d.Radius {
+		return d
+	}
+	return c
+}
+
+// MinCircle will return the smaller circle based on the radius.
+func MinCircle(c, d Circle) Circle {
 	if c.Radius < d.Radius {
-		biggerC = d
-		smallerC = c
+		return c
 	}
+	return d
+}
+
+// Union returns the minimal Circle which covers both `c` and `d`.
+func (c Circle) Union(d Circle) Circle {
+	biggerC := MaxCircle(c, d)
+	smallerC := MinCircle(c, d)
 
 	// Get distance between centers
 	dist := c.Center.To(d.Center).Len()
@@ -427,7 +439,28 @@ func (c Circle) Union(d Circle) Circle {
 // If `c` and `d` don't overlap, this function returns a zero-sized circle at the centerpoint between the two Circle's
 // centers.
 func (c Circle) Intersect(d Circle) Circle {
-	center := Lerp(c.Center, d.Center, 0.5)
+	// Check if one of the circles encompasses the other; if so, return that one
+	biggerC := MaxCircle(c, d)
+	smallerC := MinCircle(c, d)
+
+	if biggerC.Radius >= biggerC.Center.To(smallerC.Center).Len()+smallerC.Radius {
+		return biggerC
+	}
+
+	// Calculate the midpoint between the two radii
+	// Distance between centers
+	dist := c.Center.To(d.Center).Len()
+	// Difference between radii
+	diff := dist - (c.Radius + d.Radius)
+	// Distance from c.Center to the weighted midpoint
+	distToMidpoint := c.Radius + 0.5*diff
+	// Weighted midpoint
+	center := Lerp(c.Center, d.Center, distToMidpoint/dist)
+
+	// No need to calculate radius if the circles do not overlap
+	if c.Center.To(d.Center).Len() >= c.Radius+d.Radius {
+		return C(0, center)
+	}
 
 	radius := math.Min(0, c.Center.To(d.Center).Len()-(c.Radius+d.Radius))
 
diff --git a/geometry_test.go b/geometry_test.go
index 70106203fd991c99fa2b5023338db67b498ea2c9..4cab36f726312f5950f57508528c989a6dc6523a 100644
--- a/geometry_test.go
+++ b/geometry_test.go
@@ -545,6 +545,24 @@ func TestCircle_Intersect(t *testing.T) {
 			args:   args{d: pixel.C(1, pixel.V(3, 3))},
 			want:   pixel.C(0, pixel.V(1.5, 1.5)),
 		},
+		{
+			name:   "Circle.Intersect(): first circle encompassing second",
+			fields: fields{radius: 10, center: pixel.V(0, 0)},
+			args:   args{d: pixel.C(1, pixel.V(3, 3))},
+			want:   pixel.C(10, pixel.V(0, 0)),
+		},
+		{
+			name:   "Circle.Intersect(): second circle encompassing first",
+			fields: fields{radius: 1, center: pixel.V(-1, -4)},
+			args:   args{d: pixel.C(10, pixel.V(0, 0))},
+			want:   pixel.C(10, pixel.V(0, 0)),
+		},
+		{
+			name:   "Circle.Intersect(): matching circles",
+			fields: fields{radius: 1, center: pixel.V(0, 0)},
+			args:   args{d: pixel.C(1, pixel.V(0, 0))},
+			want:   pixel.C(1, pixel.V(0, 0)),
+		},
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
@@ -558,3 +576,79 @@ func TestCircle_Intersect(t *testing.T) {
 		})
 	}
 }
+
+func TestMaxCircle(t *testing.T) {
+	bigCircle := pixel.C(10, pixel.ZV)
+	smallCircle := pixel.C(1, pixel.ZV)
+
+	type args struct {
+		c pixel.Circle
+		d pixel.Circle
+	}
+	tests := []struct {
+		name string
+		args args
+		want pixel.Circle
+	}{
+		{
+			name: "MaxCircle(): first bigger",
+			args: args{c: bigCircle, d: smallCircle},
+			want: bigCircle,
+		},
+		{
+			name: "MaxCircle(): first smaller",
+			args: args{c: smallCircle, d: bigCircle},
+			want: bigCircle,
+		},
+		{
+			name: "MaxCircle(): both same size",
+			args: args{c: smallCircle, d: smallCircle},
+			want: smallCircle,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			if got := pixel.MaxCircle(tt.args.c, tt.args.d); !reflect.DeepEqual(got, tt.want) {
+				t.Errorf("MaxCircle() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
+
+func TestMinCircle(t *testing.T) {
+	bigCircle := pixel.C(10, pixel.ZV)
+	smallCircle := pixel.C(1, pixel.ZV)
+
+	type args struct {
+		c pixel.Circle
+		d pixel.Circle
+	}
+	tests := []struct {
+		name string
+		args args
+		want pixel.Circle
+	}{
+		{
+			name: "MinCircle(): first bigger",
+			args: args{c: bigCircle, d: smallCircle},
+			want: smallCircle,
+		},
+		{
+			name: "MinCircle(): first smaller",
+			args: args{c: smallCircle, d: bigCircle},
+			want: smallCircle,
+		},
+		{
+			name: "MinCircle(): both same size",
+			args: args{c: smallCircle, d: smallCircle},
+			want: smallCircle,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			if got := pixel.MinCircle(tt.args.c, tt.args.d); !reflect.DeepEqual(got, tt.want) {
+				t.Errorf("MinCircle() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}