Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add useful functions to Geometry primitives #14

Merged
merged 6 commits into from
Jul 21, 2013
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 105 additions & 0 deletions Splat/PointExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
using System;
using System.Drawing;

namespace Splat
{
public static class PointMathExtensions
{
/// <summary>
/// Floor the specified point (i.e. round it to integer values)
/// </summary>
public static PointF Floor(this Point This)
{
#if UIKIT
// NB: I have no idea but Archimedes does this, soooooooo....

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You mixed up the conditional here. On OS X, Y = 0 is at the bottom of the screen/view (by default), so ceiling the Y coordinate will round the view upward.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed!

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
}

/// <summary>
/// Determines whether two points are within 'epsilon' of each other
/// </summary>
public static bool WithinEpsilonOf(this PointF This, PointF other, float epsilon)
{
return This.DistanceTo(other) < epsilon;
}

/// <summary>
/// Calculates the Dot product of two points
/// </summary>
public static float DotProduct(this PointF This, PointF other)
{
return (This.X * other.X + This.Y * other.Y);
}

/// <summary>
/// Scales a PointF by a scalar factor
/// </summary>
public static PointF ScaledBy(this PointF This, float factor)
{
return new PointF(This.X * factor, This.Y * factor);
}

/// <summary>
/// Calculates the magnitude of a point from (0,0)
/// </summary>
public static float Length(this PointF This)
{
return PointF.Empty.DistanceTo(This);
}

/// <summary>
/// Normalize the specified PointF (i.e. makes its magnitude = 1.0f)
/// </summary>
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);
}

/// <summary>
/// Calculates the angle in degrees of a PointF
/// </summary>
public static float AngleInDegrees(this PointF This)
{
return (float)(Math.Atan2(This.Y, This.X) * 180.0f / Math.PI);
}

/// <summary>
/// Projects a PointF along a specified direction
/// </summary>
public static PointF ProjectAlong(this PointF This, PointF direction)
{
var normalDirection = direction.Normalize();
var dist = This.DotProduct(normalDirection);

return normalDirection.ScaledBy(dist);
}

/// <summary>
/// Projects a PointF along a specified angle
/// </summary>
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);
}

/// <summary>
/// Calculates the distance between two points
/// </summary>
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);
}
}
}

82 changes: 82 additions & 0 deletions Splat/RectangleExtensions.cs
Original file line number Diff line number Diff line change
@@ -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
{
/// <summary>
/// Determine the center of a Rectangle
/// </summary>
public static PointF Center(this RectangleF This)
{
return new PointF(This.X + This.Width / 2.0f, This.Y + This.Height / 2.0f);
}

/// <summary>
/// Divide the specified Rectangle into two component rectangles
/// </summary>
/// <param name="amount">Amount to move away from the given edge</param>
/// <param name="fromEdge">The edge to create the slice from.</param>
public static Tuple<RectangleF, RectangleF> 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");
}
}

/// <summary>
/// Divide the specified Rectangle into two component rectangles, adding
/// a padding between them.
/// </summary>
/// <param name="amount">Amount to move away from the given edge</param>
/// <param name="padding">The amount of padding that is in neither rectangle.</param>
/// <param name="fromEdge">The edge to create the slice from.</param>
public static Tuple<RectangleF, RectangleF> 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);
}

/// <summary>
/// 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.
/// </summary>
public static RectangleF InvertWithin(this RectangleF This, RectangleF containingRect)
{
return new RectangleF(This.X, containingRect.Height - This.Bottom, This.Width, This.Height);
}
}
}
26 changes: 26 additions & 0 deletions Splat/SizeExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using System;
using System.Drawing;

namespace Splat
{
public static class SizeMathExtensions
{
/// <summary>
/// Determines whether two sizes are within epsilon of each other
/// </summary>
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;
}

/// <summary>
/// Scales a size by a scalar value
/// </summary>
public static SizeF ScaledBy(this SizeF This, float factor)
{
return new SizeF(This.Width * factor, This.Height * factor);
}
}
}
3 changes: 3 additions & 0 deletions Splat/Splat-Portable.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
<ItemGroup>
<Compile Include="AssemblyFinder.cs" />
<Compile Include="Bitmaps.cs" />
<Compile Include="PointExtensions.cs" />
<Compile Include="Points\RectangleF.cs" />
<Compile Include="Points\Rectangle.cs" />
<Compile Include="Points\Size.cs" />
Expand All @@ -51,7 +52,9 @@
<Compile Include="ModeDetector.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="RectangleExtensions.cs" />
<Compile Include="ReflectionStubs.cs" />
<Compile Include="SizeExtensions.cs" />
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Expand Down
3 changes: 3 additions & 0 deletions Splat/Splat-monoandroid.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@
<Compile Include="Android\Point.cs" />
<Compile Include="Android\Rect.cs" />
<Compile Include="AssemblyFinder.cs" />
<Compile Include="PointExtensions.cs" />
<Compile Include="RectangleExtensions.cs" />
<Compile Include="SizeExtensions.cs" />
</ItemGroup>
<ItemGroup>
<None Include="Resources\AboutResources.txt" />
Expand Down
3 changes: 3 additions & 0 deletions Splat/Splat-monomac.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@
<Compile Include="AssemblyFinder.cs" />
<Compile Include="Bitmaps.cs" />
<Compile Include="ModeDetector.cs" />
<Compile Include="PointExtensions.cs" />
<Compile Include="RectangleExtensions.cs" />
<Compile Include="SizeExtensions.cs" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Expand Down
3 changes: 3 additions & 0 deletions Splat/Splat-monotouch.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -54,5 +54,8 @@
<Compile Include="Colors\KnownColor.cs" />
<Compile Include="Colors\KnownColors.cs" />
<Compile Include="AssemblyFinder.cs" />
<Compile Include="RectangleExtensions.cs" />
<Compile Include="PointExtensions.cs" />
<Compile Include="SizeExtensions.cs" />
</ItemGroup>
</Project>