diff --git a/X10D.Tests/src/Drawing/EllipseFTests.cs b/X10D.Tests/src/Drawing/EllipseFTests.cs
new file mode 100644
index 0000000..78a7514
--- /dev/null
+++ b/X10D.Tests/src/Drawing/EllipseFTests.cs
@@ -0,0 +1,128 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using X10D.Drawing;
+
+namespace X10D.Tests.Drawing;
+
+[TestClass]
+public class EllipseFTests
+{
+ [TestMethod]
+ public void Area_ShouldBePiRadiusRadius_GivenUnitEllipse()
+ {
+ var unitEllipse = EllipseF.Unit;
+ Assert.AreEqual(MathF.PI, unitEllipse.Area, 1e-6f);
+ }
+
+ [TestMethod]
+ public void ApproximateCircumference_ShouldBe2PiRadius_GivenUnitEllipse()
+ {
+ var unitEllipse = EllipseF.Unit;
+ Assert.AreEqual(2 * MathF.PI, unitEllipse.ApproximateCircumference, 1e-6f);
+ }
+
+ [TestMethod]
+ public void Equals_ShouldBeTrue_GivenTwoUnitEllipses()
+ {
+ var unitEllipse1 = EllipseF.Unit;
+ var unitEllipse2 = EllipseF.Unit;
+ Assert.AreEqual(unitEllipse1, unitEllipse2);
+ Assert.IsTrue(unitEllipse1 == unitEllipse2);
+ Assert.IsFalse(unitEllipse1 != unitEllipse2);
+ }
+
+ [TestMethod]
+ public void Equals_ShouldBeFalse_GivenDifferentEllipses()
+ {
+ Assert.AreNotEqual(EllipseF.Unit, EllipseF.Empty);
+ Assert.IsFalse(EllipseF.Unit == EllipseF.Empty);
+ Assert.IsTrue(EllipseF.Unit != EllipseF.Empty);
+ }
+
+ [TestMethod]
+ public void GetHashCode_ShouldBeCorrect_GivenEmptyEllipse()
+ {
+ // this test is pretty pointless, it exists only for code coverage purposes
+ int hashCode = EllipseF.Empty.GetHashCode();
+ Assert.AreEqual(hashCode, EllipseF.Empty.GetHashCode());
+ }
+
+ [TestMethod]
+ public void GetHashCode_ShouldBeCorrect_GivenUnitEllipse()
+ {
+ // this test is pretty pointless, it exists only for code coverage purposes
+ int hashCode = EllipseF.Unit.GetHashCode();
+ Assert.AreEqual(hashCode, EllipseF.Unit.GetHashCode());
+ }
+
+ [TestMethod]
+ public void HorizontalRadius_ShouldBe0_GivenEmptyEllipse()
+ {
+ Assert.AreEqual(0, EllipseF.Empty.HorizontalRadius);
+ }
+
+ [TestMethod]
+ public void HorizontalRadius_ShouldBe1_GivenUnitEllipse()
+ {
+ Assert.AreEqual(1, EllipseF.Unit.HorizontalRadius);
+ }
+
+ [TestMethod]
+ public void op_Explicit_ShouldReturnEquivalentEllipse_GivenEllipse()
+ {
+ EllipseF unitEllipse = EllipseF.Unit;
+ Ellipse converted = (Ellipse)unitEllipse;
+
+ Assert.AreEqual(unitEllipse, converted);
+ Assert.AreEqual(unitEllipse.HorizontalRadius, converted.HorizontalRadius);
+ Assert.AreEqual(unitEllipse.VerticalRadius, converted.VerticalRadius);
+ Assert.AreEqual(unitEllipse.Center, converted.Center);
+ }
+
+ [TestMethod]
+ public void op_Implicit_ShouldReturnEquivalentEllipse_GivenCircle()
+ {
+ Circle unitCircle = Circle.Unit;
+ EllipseF converted = unitCircle;
+
+ Assert.AreEqual(unitCircle, converted);
+ Assert.AreEqual(unitCircle.Radius, converted.HorizontalRadius);
+ Assert.AreEqual(unitCircle.Radius, converted.VerticalRadius);
+ Assert.AreEqual(unitCircle.Center, converted.Center);
+ }
+
+ [TestMethod]
+ public void op_Implicit_ShouldReturnEquivalentEllipse_GivenCircleF()
+ {
+ CircleF unitCircle = CircleF.Unit;
+ EllipseF converted = unitCircle;
+
+ Assert.AreEqual(unitCircle, converted);
+ Assert.AreEqual(unitCircle.Radius, converted.HorizontalRadius);
+ Assert.AreEqual(unitCircle.Radius, converted.VerticalRadius);
+ Assert.AreEqual(unitCircle.Center, converted.Center);
+ }
+
+ [TestMethod]
+ public void op_Implicit_ShouldReturnEquivalentEllipse_GivenEllipse()
+ {
+ Ellipse unitEllipse = Ellipse.Unit;
+ EllipseF converted = unitEllipse;
+
+ Assert.AreEqual(unitEllipse, converted);
+ Assert.AreEqual(unitEllipse.HorizontalRadius, converted.HorizontalRadius);
+ Assert.AreEqual(unitEllipse.VerticalRadius, converted.VerticalRadius);
+ Assert.AreEqual(unitEllipse.Center, converted.Center);
+ }
+
+ [TestMethod]
+ public void VerticalRadius_ShouldBe0_GivenEmptyEllipse()
+ {
+ Assert.AreEqual(0, EllipseF.Empty.VerticalRadius);
+ }
+
+ [TestMethod]
+ public void VerticalRadius_ShouldBe1_GivenUnitEllipse()
+ {
+ Assert.AreEqual(1, EllipseF.Unit.VerticalRadius);
+ }
+}
diff --git a/X10D.Tests/src/Drawing/EllipseTests.cs b/X10D.Tests/src/Drawing/EllipseTests.cs
new file mode 100644
index 0000000..0c62cdc
--- /dev/null
+++ b/X10D.Tests/src/Drawing/EllipseTests.cs
@@ -0,0 +1,92 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using X10D.Drawing;
+
+namespace X10D.Tests.Drawing;
+
+[TestClass]
+public class EllipseTests
+{
+ [TestMethod]
+ public void Area_ShouldBePiRadiusRadius_GivenUnitEllipse()
+ {
+ var unitEllipse = Ellipse.Unit;
+ Assert.AreEqual(MathF.PI, unitEllipse.Area, 1e-6f);
+ }
+
+ [TestMethod]
+ public void ApproximateCircumference_ShouldBe2PiRadius_GivenUnitEllipse()
+ {
+ var unitEllipse = Ellipse.Unit;
+ Assert.AreEqual(2 * MathF.PI, unitEllipse.ApproximateCircumference, 1e-6f);
+ }
+
+ [TestMethod]
+ public void Equals_ShouldBeTrue_GivenTwoUnitEllipses()
+ {
+ var unitEllipse1 = Ellipse.Unit;
+ var unitEllipse2 = Ellipse.Unit;
+ Assert.AreEqual(unitEllipse1, unitEllipse2);
+ Assert.IsTrue(unitEllipse1 == unitEllipse2);
+ Assert.IsFalse(unitEllipse1 != unitEllipse2);
+ }
+
+ [TestMethod]
+ public void Equals_ShouldBeFalse_GivenDifferentEllipses()
+ {
+ Assert.AreNotEqual(Ellipse.Unit, Ellipse.Empty);
+ Assert.IsFalse(Ellipse.Unit == Ellipse.Empty);
+ Assert.IsTrue(Ellipse.Unit != Ellipse.Empty);
+ }
+
+ [TestMethod]
+ public void GetHashCode_ShouldBeCorrect_GivenEmptyEllipse()
+ {
+ // this test is pretty pointless, it exists only for code coverage purposes
+ int hashCode = Ellipse.Empty.GetHashCode();
+ Assert.AreEqual(hashCode, Ellipse.Empty.GetHashCode());
+ }
+
+ [TestMethod]
+ public void GetHashCode_ShouldBeCorrect_GivenUnitEllipse()
+ {
+ // this test is pretty pointless, it exists only for code coverage purposes
+ int hashCode = Ellipse.Unit.GetHashCode();
+ Assert.AreEqual(hashCode, Ellipse.Unit.GetHashCode());
+ }
+
+ [TestMethod]
+ public void HorizontalRadius_ShouldBe0_GivenEmptyEllipse()
+ {
+ Assert.AreEqual(0, Ellipse.Empty.HorizontalRadius);
+ }
+
+ [TestMethod]
+ public void HorizontalRadius_ShouldBe1_GivenUnitEllipse()
+ {
+ Assert.AreEqual(1, Ellipse.Unit.HorizontalRadius);
+ }
+
+ [TestMethod]
+ public void op_Implicit_ShouldReturnEquivalentEllipse_GivenCircle()
+ {
+ Circle unitCircle = Circle.Unit;
+ Ellipse converted = unitCircle;
+
+ Assert.AreEqual(unitCircle, converted);
+ Assert.AreEqual(unitCircle.Radius, converted.HorizontalRadius);
+ Assert.AreEqual(unitCircle.Radius, converted.VerticalRadius);
+ Assert.AreEqual(unitCircle.Center, converted.Center);
+ }
+
+ [TestMethod]
+ public void VerticalRadius_ShouldBe0_GivenEmptyEllipse()
+ {
+ Assert.AreEqual(0, Ellipse.Empty.VerticalRadius);
+ }
+
+ [TestMethod]
+ public void VerticalRadius_ShouldBe1_GivenUnitEllipse()
+ {
+ Assert.AreEqual(1, Ellipse.Unit.VerticalRadius);
+ }
+}
diff --git a/X10D/src/Drawing/Ellipse.cs b/X10D/src/Drawing/Ellipse.cs
new file mode 100644
index 0000000..950265a
--- /dev/null
+++ b/X10D/src/Drawing/Ellipse.cs
@@ -0,0 +1,138 @@
+using System.Drawing;
+
+namespace X10D.Drawing;
+
+///
+/// Represents an ellipse that is composed of a 32-bit signed integer center point and radius.
+///
+public readonly struct Ellipse : IEquatable
+{
+ ///
+ /// The empty ellipse. That is, an ellipse whose center point is (0, 0) and whose two radii are 0.
+ ///
+ public static readonly Ellipse Empty = new();
+
+ ///
+ /// The unit ellipse. That is, an ellipse whose center point is (0, 0) and whose two radii are 1.
+ ///
+ public static readonly Ellipse Unit = new(Point.Empty, 1, 1);
+
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// The center point of the ellipse.
+ /// The horizontal radius of the ellipse.
+ /// The vertical radius of the ellipse.
+ public Ellipse(Point center, int horizontalRadius, int verticalRadius)
+ {
+ Center = center;
+ HorizontalRadius = horizontalRadius;
+ VerticalRadius = verticalRadius;
+ }
+
+ public static implicit operator Ellipse(Circle circle)
+ {
+ return new Ellipse(circle.Center, circle.Radius, circle.Radius);
+ }
+
+ ///
+ /// Gets the area of the ellipse.
+ ///
+ /// The area of the ellipse, calculated as πab.
+ public float Area
+ {
+ get => MathF.PI * HorizontalRadius * VerticalRadius;
+ }
+
+ ///
+ /// Gets the center point of the ellipse.
+ ///
+ /// The center point.
+ public Point Center { get; }
+
+ ///
+ /// Gets the approximate circumference of the ellipse.
+ ///
+ ///
+ /// The approximate circumference of the ellipse, calculated as
+ /// π(a+b)(3([(a-b)²]/(a+b)²(sqrt(-3(((a-b)²)/(a+b)²)+4+10))+1).
+ ///
+ public float ApproximateCircumference
+ {
+ get
+ {
+ float aMinusB = HorizontalRadius - VerticalRadius;
+ float aPlusB = HorizontalRadius + VerticalRadius;
+
+ float aMinusB2 = aMinusB * aMinusB;
+ float aPlusB2 = aPlusB * aPlusB;
+
+ return MathF.PI * (aPlusB * (3 * (aMinusB2 / (aPlusB2 * MathF.Sqrt(-3 * (aMinusB2 / aPlusB2) + 4 + 10))) + 1));
+ }
+ }
+
+ ///
+ /// Gets the horizontal radius of the ellipse.
+ ///
+ /// The horizontal radius.
+ public int HorizontalRadius { get; }
+
+ ///
+ /// Gets the vertical radius of the ellipse.
+ ///
+ /// The vertical radius.
+ public int VerticalRadius { get; }
+
+ ///
+ /// Returns a value indicating whether two instances of are equal.
+ ///
+ /// The first instance.
+ /// The second instance.
+ ///
+ /// if and are considered equal; otherwise,
+ /// .
+ ///
+ public static bool operator ==(Ellipse left, Ellipse right)
+ {
+ return left.Equals(right);
+ }
+
+ ///
+ /// Returns a value indicating whether two instances of are not equal.
+ ///
+ /// The first instance.
+ /// The second instance.
+ ///
+ /// if and are considered not equal; otherwise,
+ /// .
+ ///
+ public static bool operator !=(Ellipse left, Ellipse right)
+ {
+ return !left.Equals(right);
+ }
+
+ ///
+ public override bool Equals(object? obj)
+ {
+ return obj is Ellipse ellipse && Equals(ellipse);
+ }
+
+ ///
+ /// Returns a value indicating whether this instance and another instance are equal.
+ ///
+ /// The instance with which to compare.
+ ///
+ /// if this instance and are considered equal; otherwise,
+ /// .
+ ///
+ public bool Equals(Ellipse other)
+ {
+ return HorizontalRadius.Equals(other.HorizontalRadius) && VerticalRadius.Equals(other.VerticalRadius);
+ }
+
+ ///
+ public override int GetHashCode()
+ {
+ return HashCode.Combine(HorizontalRadius, VerticalRadius);
+ }
+}
diff --git a/X10D/src/Drawing/EllipseF.cs b/X10D/src/Drawing/EllipseF.cs
new file mode 100644
index 0000000..c07cd2d
--- /dev/null
+++ b/X10D/src/Drawing/EllipseF.cs
@@ -0,0 +1,174 @@
+using System.Drawing;
+
+namespace X10D.Drawing;
+
+///
+/// Represents an ellipse that is composed of a single-precision floating-point center point and radius.
+///
+public readonly struct EllipseF : IEquatable
+{
+ ///
+ /// The empty ellipse. That is, an ellipse whose center point is (0, 0) and whose two radii are 0.
+ ///
+ public static readonly EllipseF Empty = new();
+
+ ///
+ /// The unit ellipse. That is, an ellipse whose center point is (0, 0) and whose two radii are 1.
+ ///
+ public static readonly EllipseF Unit = new(PointF.Empty, 1.0f, 1.0f);
+
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// The center point of the ellipse.
+ /// The horizontal radius of the ellipse.
+ /// The vertical radius of the ellipse.
+ public EllipseF(PointF center, float horizontalRadius, float verticalRadius)
+ {
+ Center = center;
+ HorizontalRadius = horizontalRadius;
+ VerticalRadius = verticalRadius;
+ }
+
+ ///
+ /// Gets the area of the ellipse.
+ ///
+ /// The area of the ellipse, calculated as πab.
+ public float Area
+ {
+ get => MathF.PI * HorizontalRadius * VerticalRadius;
+ }
+
+ ///
+ /// Gets the center point of the ellipse.
+ ///
+ /// The center point.
+ public PointF Center { get; }
+
+ ///
+ /// Gets the approximate circumference of the ellipse.
+ ///
+ ///
+ /// The approximate circumference of the ellipse, calculated as
+ /// π(a+b)(3([(a-b)²]/(a+b)²(sqrt(-3(((a-b)²)/(a+b)²)+4+10))+1).
+ ///
+ public float ApproximateCircumference
+ {
+ get
+ {
+ float aMinusB = HorizontalRadius - VerticalRadius;
+ float aPlusB = HorizontalRadius + VerticalRadius;
+
+ float aMinusB2 = aMinusB * aMinusB;
+ float aPlusB2 = aPlusB * aPlusB;
+
+ return MathF.PI * (aPlusB * (3 * (aMinusB2 / (aPlusB2 * MathF.Sqrt(-3 * (aMinusB2 / aPlusB2) + 4 + 10))) + 1));
+ }
+ }
+
+ ///
+ /// Gets the horizontal radius of the ellipse.
+ ///
+ /// The horizontal radius.
+ public float HorizontalRadius { get; }
+
+ ///
+ /// Gets the vertical radius of the ellipse.
+ ///
+ /// The vertical radius.
+ public float VerticalRadius { get; }
+
+ ///
+ /// Returns a value indicating whether two instances of are equal.
+ ///
+ /// The first instance.
+ /// The second instance.
+ ///
+ /// if and are considered equal; otherwise,
+ /// .
+ ///
+ public static bool operator ==(EllipseF left, EllipseF right)
+ {
+ return left.Equals(right);
+ }
+
+ ///
+ /// Returns a value indicating whether two instances of are not equal.
+ ///
+ /// The first instance.
+ /// The second instance.
+ ///
+ /// if and are considered not equal; otherwise,
+ /// .
+ ///
+ public static bool operator !=(EllipseF left, EllipseF right)
+ {
+ return !left.Equals(right);
+ }
+
+ ///
+ /// Implicitly converts a to an .
+ ///
+ /// The circle to convert.
+ /// The converted ellipse.
+ public static implicit operator EllipseF(Circle circle)
+ {
+ return new EllipseF(circle.Center, circle.Radius, circle.Radius);
+ }
+
+ ///
+ /// Implicitly converts a to an .
+ ///
+ /// The circle to convert.
+ /// The converted ellipse.
+ public static implicit operator EllipseF(CircleF circle)
+ {
+ return new EllipseF(circle.Center, circle.Radius, circle.Radius);
+ }
+
+ ///
+ /// Implicitly converts an to an .
+ ///
+ /// The ellipse to convert.
+ /// The converted ellipse.
+ public static implicit operator EllipseF(Ellipse ellipse)
+ {
+ return new EllipseF(ellipse.Center, ellipse.HorizontalRadius, ellipse.VerticalRadius);
+ }
+
+ ///
+ /// Explicitly converts an to an .
+ ///
+ /// The ellipse to convert.
+ /// The converted ellipse.
+ public static explicit operator Ellipse(EllipseF ellipse)
+ {
+ PointF center = ellipse.Center;
+ return new Ellipse(new Point((int)center.X, (int)center.Y), (int)ellipse.HorizontalRadius, (int)ellipse.VerticalRadius);
+ }
+
+ ///
+ public override bool Equals(object? obj)
+ {
+ return obj is EllipseF ellipse && Equals(ellipse);
+ }
+
+ ///
+ /// Returns a value indicating whether this instance and another instance are equal.
+ ///
+ /// The instance with which to compare.
+ ///
+ /// if this instance and are considered equal; otherwise,
+ /// .
+ ///
+ public bool Equals(EllipseF other)
+ {
+ return HorizontalRadius.Equals(other.HorizontalRadius) && VerticalRadius.Equals(other.VerticalRadius);
+ }
+
+ ///
+ public override int GetHashCode()
+ {
+ return HashCode.Combine(HorizontalRadius, VerticalRadius);
+ }
+}