diff --git a/Splat/PointExtensions.cs b/Splat/PointExtensions.cs
new file mode 100644
index 000000000..c2449949b
--- /dev/null
+++ b/Splat/PointExtensions.cs
@@ -0,0 +1,105 @@
+using System;
+using System.Drawing;
+
+namespace Splat
+{
+ public static class PointMathExtensions
+ {
+ ///
+ /// Floor the specified point (i.e. round it to integer values)
+ ///
+ public static PointF Floor(this Point This)
+ {
+#if UIKIT
+ // NB: I have no idea but Archimedes does this, soooooooo....
+ return new PointF((float)Math.Floor((double)This.X), (float)Math.Ceiling((double)This.Y));
+#else
+ return new PointF((float)Math.Floor((double)This.X), (float)Math.Floor((double)This.Y));
+#endif
+ }
+
+ ///
+ /// Determines whether two points are within 'epsilon' of each other
+ ///
+ public static bool WithinEpsilonOf(this PointF This, PointF other, float epsilon)
+ {
+ return This.DistanceTo(other) < epsilon;
+ }
+
+ ///
+ /// Calculates the Dot product of two points
+ ///
+ public static float DotProduct(this PointF This, PointF other)
+ {
+ return (This.X * other.X + This.Y * other.Y);
+ }
+
+ ///
+ /// Scales a PointF by a scalar factor
+ ///
+ public static PointF ScaledBy(this PointF This, float factor)
+ {
+ return new PointF(This.X * factor, This.Y * factor);
+ }
+
+ ///
+ /// Calculates the magnitude of a point from (0,0)
+ ///
+ public static float Length(this PointF This)
+ {
+ return PointF.Empty.DistanceTo(This);
+ }
+
+ ///
+ /// Normalize the specified PointF (i.e. makes its magnitude = 1.0f)
+ ///
+ public static PointF Normalize(this PointF This)
+ {
+ var length = This.Length();
+ if (length == 0.0f) return This;
+
+ return new PointF(This.X / length, This.Y / length);
+ }
+
+ ///
+ /// Calculates the angle in degrees of a PointF
+ ///
+ public static float AngleInDegrees(this PointF This)
+ {
+ return (float)(Math.Atan2(This.Y, This.X) * 180.0f / Math.PI);
+ }
+
+ ///
+ /// Projects a PointF along a specified direction
+ ///
+ public static PointF ProjectAlong(this PointF This, PointF direction)
+ {
+ var normalDirection = direction.Normalize();
+ var dist = This.DotProduct(normalDirection);
+
+ return normalDirection.ScaledBy(dist);
+ }
+
+ ///
+ /// Projects a PointF along a specified angle
+ ///
+ public static PointF ProjectAlongAngle(this PointF This, float angleInDegrees)
+ {
+ var rads = angleInDegrees * Math.PI / 180.0f;
+ var direction = new PointF((float)Math.Cos(rads), (float)Math.Sin(rads));
+
+ return This.ProjectAlong(direction);
+ }
+
+ ///
+ /// Calculates the distance between two points
+ ///
+ public static float DistanceTo(this PointF This, PointF other)
+ {
+ var deltaX = other.X - This.X;
+ var deltaY = other.Y - This.Y;
+ return (float)Math.Sqrt(deltaX * deltaX + deltaY * deltaY);
+ }
+ }
+}
+
diff --git a/Splat/RectangleExtensions.cs b/Splat/RectangleExtensions.cs
new file mode 100644
index 000000000..723a3c84f
--- /dev/null
+++ b/Splat/RectangleExtensions.cs
@@ -0,0 +1,82 @@
+using System;
+using System.Drawing;
+
+namespace Splat
+{
+ public enum RectEdge {
+ Left, Top, // Left / Top
+ Right, Bottom, // Right / Bottom
+ }
+
+ public static class RectangleMathExtensions
+ {
+ ///
+ /// Determine the center of a Rectangle
+ ///
+ public static PointF Center(this RectangleF This)
+ {
+ return new PointF(This.X + This.Width / 2.0f, This.Y + This.Height / 2.0f);
+ }
+
+ ///
+ /// Divide the specified Rectangle into two component rectangles
+ ///
+ /// Amount to move away from the given edge
+ /// The edge to create the slice from.
+ public static Tuple Divide(this RectangleF This, float amount, RectEdge fromEdge)
+ {
+ var delta = default(float);
+
+ switch (fromEdge) {
+ case RectEdge.Left:
+ delta = Math.Max(This.Width, amount);
+ return Tuple.Create(
+ new RectangleF(This.Left, This.Top, delta, This.Height),
+ new RectangleF(This.Left + delta, This.Top, This.Width - delta, This.Height));
+ case RectEdge.Top:
+ delta = Math.Max(This.Height, amount);
+ return Tuple.Create(
+ new RectangleF(This.Left, This.Top, This.Width, amount),
+ new RectangleF(This.Left, This.Top + delta, This.Width, This.Height - delta));
+ case RectEdge.Right:
+ delta = Math.Max(This.Width, amount);
+ return Tuple.Create(
+ new RectangleF(This.Right - delta, This.Top, delta, This.Height),
+ new RectangleF(This.Left, This.Top, This.Width - delta, This.Height));
+ case RectEdge.Bottom:
+ delta = Math.Max(This.Height, amount);
+ return Tuple.Create(
+ new RectangleF(This.Left, This.Bottom - delta, This.Width, delta),
+ new RectangleF(This.Left, This.Top, This.Width, This.Height - delta));
+ default:
+ throw new ArgumentException("edge");
+ }
+ }
+
+ ///
+ /// Divide the specified Rectangle into two component rectangles, adding
+ /// a padding between them.
+ ///
+ /// Amount to move away from the given edge
+ /// The amount of padding that is in neither rectangle.
+ /// The edge to create the slice from.
+ public static Tuple DivideWithPadding(this RectangleF This, float sliceAmount, float padding, RectEdge fromEdge)
+ {
+ var slice = This.Divide(sliceAmount, fromEdge);
+ var pad = This.Divide(padding, fromEdge);
+ return Tuple.Create(slice.Item1, pad.Item2);
+ }
+
+ ///
+ /// Vertically inverts the coordinates of the rectangle within containingRect
+ ///
+ /// This can effectively be used to change the coordinate system of a rectangle.
+ /// For example, if `rect` is defined for a coordinate system starting at the
+ /// top-left, the result will be a rectangle relative to the bottom-left.
+ ///
+ public static RectangleF InvertWithin(this RectangleF This, RectangleF containingRect)
+ {
+ return new RectangleF(This.X, containingRect.Height - This.Bottom, This.Width, This.Height);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Splat/SizeExtensions.cs b/Splat/SizeExtensions.cs
new file mode 100644
index 000000000..6b9ef8e45
--- /dev/null
+++ b/Splat/SizeExtensions.cs
@@ -0,0 +1,26 @@
+using System;
+using System.Drawing;
+
+namespace Splat
+{
+ public static class SizeMathExtensions
+ {
+ ///
+ /// Determines whether two sizes are within epsilon of each other
+ ///
+ public static bool WithinEpsilonOf(this SizeF This, SizeF other, float epsilon)
+ {
+ var deltaW = other.Width - This.Width;
+ var deltaH = other.Height - This.Height;
+ return Math.Sqrt(deltaW * deltaW + deltaH * deltaH) < epsilon;
+ }
+
+ ///
+ /// Scales a size by a scalar value
+ ///
+ public static SizeF ScaledBy(this SizeF This, float factor)
+ {
+ return new SizeF(This.Width * factor, This.Height * factor);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Splat/Splat-Portable.csproj b/Splat/Splat-Portable.csproj
index 934f5edf1..561ce97ac 100644
--- a/Splat/Splat-Portable.csproj
+++ b/Splat/Splat-Portable.csproj
@@ -39,6 +39,7 @@
+
@@ -51,7 +52,9 @@
Code
+
+