This commit is contained in:
Scott Williams 2017-01-14 11:41:12 +00:00
Родитель 10cf98fab8
Коммит 9e047e83aa
9 изменённых файлов: 0 добавлений и 1181 удалений

Просмотреть файл

@ -1,18 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Text;
using System.Threading.Tasks;
namespace Shaper2D
{
public interface ILineSegment
{
/// <summary>
/// Simplifies the specified quality.
/// </summary>
/// <returns></returns>
IEnumerable<Vector2> Simplify();
}
}

Просмотреть файл

@ -1,41 +0,0 @@
using Shaper2D.Primitives;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Numerics;
using System.Text;
using System.Threading.Tasks;
namespace Shaper2D
{
public class LinearLineSegment : ILineSegment
{
public IReadOnlyList<Vector2> ControlPoints { get; }
internal LinearLineSegment(IEnumerable<Vector2> points)
{
//Guard.NotNull(points, nameof(points));
//Guard.MustBeGreaterThanOrEqualTo(points.Count(), 2, nameof(points));
ControlPoints = new ReadOnlyCollection<Vector2>(points.ToList());
}
public LinearLineSegment(params PointF[] points)
: this(points?.Select(x => x.ToVector2()))
{
}
public LinearLineSegment(IEnumerable<PointF> points)
: this(points?.Select(x => x.ToVector2()))
{
}
public IEnumerable<Vector2> Simplify()
{
return ControlPoints;
}
}
}

Просмотреть файл

@ -1,210 +0,0 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
namespace Shaper2D.Primitives
{
/// <summary>
/// Represents an ordered pair of floating point x- and y-coordinates that defines a point in
/// a two-dimensional plane.
/// </summary>
/// <remarks>
/// This struct is fully mutable. This is done (against the guidelines) for the sake of performance,
/// as it avoids the need to create new values for modification operations.
/// </remarks>
public struct PointF : IEquatable<PointF>
{
/// <summary>
/// Represents a <see cref="PointF"/> that has X and Y values set to zero.
/// </summary>
public static readonly PointF Empty = default(PointF);
/// <summary>
/// The backing vector for SIMD support.
/// </summary>
private Vector2 backingVector;
/// <summary>
/// Initializes a new instance of the <see cref="Point"/> struct.
/// </summary>
/// <param name="x">The horizontal position of the point.</param>
/// <param name="y">The vertical position of the point.</param>
public PointF(float x, float y)
: this()
{
this.backingVector = new Vector2(x, y);
}
/// <summary>
/// Initializes a new instance of the <see cref="Point"/> struct.
/// </summary>
/// <param name="vector">
/// The vector representing the width and height.
/// </param>
public PointF(Vector2 vector)
{
this.backingVector = vector;
}
/// <summary>
/// Gets or sets the x-coordinate of this <see cref="Point"/>.
/// </summary>
public float X => backingVector.X;
/// <summary>
/// Gets or sets the y-coordinate of this <see cref="Point"/>.
/// </summary>
public float Y => backingVector.Y;
/// <summary>
/// Gets a value indicating whether this <see cref="Point"/> is empty.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
public bool IsEmpty => this.Equals(Empty);
/// <summary>
/// Computes the sum of adding two points.
/// </summary>
/// <param name="left">The point on the left hand of the operand.</param>
/// <param name="right">The point on the right hand of the operand.</param>
/// <returns>
/// The <see cref="Point"/>
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static PointF operator +(PointF left, PointF right)
{
return new PointF(left.backingVector + right.backingVector);
}
/// <summary>
/// Computes the difference left by subtracting one point from another.
/// </summary>
/// <param name="left">The point on the left hand of the operand.</param>
/// <param name="right">The point on the right hand of the operand.</param>
/// <returns>
/// The <see cref="Point"/>
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static PointF operator -(PointF left, PointF right)
{
return new PointF(left.backingVector - right.backingVector);
}
/// <summary>
/// Compares two <see cref="Point"/> objects for equality.
/// </summary>
/// <param name="left">
/// The <see cref="Point"/> on the left side of the operand.
/// </param>
/// <param name="right">
/// The <see cref="Point"/> on the right side of the operand.
/// </param>
/// <returns>
/// True if the current left is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(PointF left, PointF right)
{
return left.backingVector == right.backingVector;
}
/// <summary>
/// Compares two <see cref="Point"/> objects for inequality.
/// </summary>
/// <param name="left">
/// The <see cref="Point"/> on the left side of the operand.
/// </param>
/// <param name="right">
/// The <see cref="Point"/> on the right side of the operand.
/// </param>
/// <returns>
/// True if the current left is unequal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(PointF left, PointF right)
{
return left.backingVector != right.backingVector;
}
/// <summary>
/// Gets a <see cref="Vector2"/> representation for this <see cref="Point"/>.
/// </summary>
/// <returns>A <see cref="Vector2"/> representation for this object.</returns>
public Vector2 ToVector2()
{
return new Vector2(this.backingVector.X, this.backingVector.Y);
}
/// <summary>
/// Translates this <see cref="Point"/> by the specified amount.
/// </summary>
/// <param name="dx">The amount to offset the x-coordinate.</param>
/// <param name="dy">The amount to offset the y-coordinate.</param>
public void Offset(int dx, int dy)
{
this.backingVector.X += dx;
this.backingVector.Y += dy;
}
/// <summary>
/// Translates this <see cref="Point"/> by the specified amount.
/// </summary>
/// <param name="p">The <see cref="Point"/> used offset this <see cref="Point"/>.</param>
public void Offset(PointF p)
{
this.backingVector += p.backingVector;
}
/// <inheritdoc/>
public override int GetHashCode()
{
return this.GetHashCode(this);
}
/// <inheritdoc/>
public override string ToString()
{
if (this.IsEmpty)
{
return "Point [ Empty ]";
}
return $"Point [ X={this.X}, Y={this.Y} ]";
}
/// <inheritdoc/>
public override bool Equals(object obj)
{
if (obj is PointF)
{
return this.Equals((PointF)obj);
}
return false;
}
/// <inheritdoc/>
public bool Equals(PointF other)
{
return this.backingVector == other.backingVector;
}
/// <summary>
/// Returns the hash code for this instance.
/// </summary>
/// <param name="point">
/// The instance of <see cref="Point"/> to return the hash code for.
/// </param>
/// <returns>
/// A 32-bit signed integer that is the hash code for this instance.
/// </returns>
private int GetHashCode(PointF point)
{
return point.backingVector.GetHashCode();
}
}
}

Просмотреть файл

@ -1,284 +0,0 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Numerics;
using System.Text;
using System.Threading.Tasks;
namespace Shaper2D.Primitives
{
public struct RectangleF : IEquatable<RectangleF>
{
/// <summary>
/// Represents a <see cref="RectangleF"/> that has X, Y, Width, and Height values set to zero.
/// </summary>
public static readonly RectangleF Empty = default(RectangleF);
/// <summary>
/// The backing vector for SIMD support.
/// </summary>
private Vector4 backingVector;
/// <summary>
/// Initializes a new instance of the <see cref="RectangleF"/> struct.
/// </summary>
/// <param name="x">The horizontal position of the rectangle.</param>
/// <param name="y">The vertical position of the rectangle.</param>
/// <param name="width">The width of the rectangle.</param>
/// <param name="height">The height of the rectangle.</param>
public RectangleF(float x, float y, float width, float height)
{
this.backingVector = new Vector4(x, y, width, height);
}
/// <summary>
/// Initializes a new instance of the <see cref="RectangleF"/> struct.
/// </summary>
/// <param name="vector">The vector.</param>
public RectangleF(Vector4 vector)
{
this.backingVector = vector;
}
/// <summary>
/// Gets or sets the x-coordinate of this <see cref="RectangleF"/>.
/// </summary>
public float X
{
get
{
return this.backingVector.X;
}
set
{
this.backingVector.X = value;
}
}
/// <summary>
/// Gets or sets the y-coordinate of this <see cref="RectangleF"/>.
/// </summary>
public float Y
{
get
{
return this.backingVector.Y;
}
set
{
this.backingVector.Y = value;
}
}
/// <summary>
/// Gets or sets the width of this <see cref="RectangleF"/>.
/// </summary>
public float Width
{
get
{
return this.backingVector.Z;
}
set
{
this.backingVector.Z = value;
}
}
/// <summary>
/// Gets or sets the height of this <see cref="RectangleF"/>.
/// </summary>
public float Height
{
get
{
return this.backingVector.W;
}
set
{
this.backingVector.W = value;
}
}
/// <summary>
/// Gets a value indicating whether this <see cref="RectangleF"/> is empty.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
public bool IsEmpty => this.Equals(Empty);
/// <summary>
/// Gets the y-coordinate of the top edge of this <see cref="Rectangle"/>.
/// </summary>
public float Top => this.Y;
/// <summary>
/// Gets the x-coordinate of the right edge of this <see cref="Rectangle"/>.
/// </summary>
public float Right => this.X + this.Width;
/// <summary>
/// Gets the y-coordinate of the bottom edge of this <see cref="Rectangle"/>.
/// </summary>
public float Bottom => this.Y + this.Height;
/// <summary>
/// Gets the x-coordinate of the left edge of this <see cref="Rectangle"/>.
/// </summary>
public float Left => this.X;
/// <summary>
/// Computes the sum of adding two rectangles.
/// </summary>
/// <param name="left">The rectangle on the left hand of the operand.</param>
/// <param name="right">The rectangle on the right hand of the operand.</param>
/// <returns>
/// The <see cref="Rectangle"/>
/// </returns>
public static RectangleF operator +(RectangleF left, RectangleF right)
{
return new RectangleF(left.backingVector + right.backingVector);
}
/// <summary>
/// Computes the difference left by subtracting one rectangle from another.
/// </summary>
/// <param name="left">The rectangle on the left hand of the operand.</param>
/// <param name="right">The rectangle on the right hand of the operand.</param>
/// <returns>
/// The <see cref="Rectangle"/>
/// </returns>
public static RectangleF operator -(RectangleF left, RectangleF right)
{
return new RectangleF(left.backingVector - right.backingVector);
}
/// <summary>
/// Compares two <see cref="Rectangle"/> objects for equality.
/// </summary>
/// <param name="left">
/// The <see cref="Rectangle"/> on the left side of the operand.
/// </param>
/// <param name="right">
/// The <see cref="Rectangle"/> on the right side of the operand.
/// </param>
/// <returns>
/// True if the current left is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
public static bool operator ==(RectangleF left, RectangleF right)
{
return left.Equals(right);
}
/// <summary>
/// Compares two <see cref="Rectangle"/> objects for inequality.
/// </summary>
/// <param name="left">
/// The <see cref="Rectangle"/> on the left side of the operand.
/// </param>
/// <param name="right">
/// The <see cref="Rectangle"/> on the right side of the operand.
/// </param>
/// <returns>
/// True if the current left is unequal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
public static bool operator !=(RectangleF left, RectangleF right)
{
return !left.Equals(right);
}
/// <summary>
/// Returns the center point of the given <see cref="Rectangle"/>
/// </summary>
/// <param name="rectangle">The rectangle</param>
/// <returns><see cref="Point"/></returns>
public static Point Center(Rectangle rectangle)
{
return new Point(rectangle.Left + (rectangle.Width / 2), rectangle.Top + (rectangle.Height / 2));
}
/// <summary>
/// Determines if the specfied point is contained within the rectangular region defined by
/// this <see cref="Rectangle"/>.
/// </summary>
/// <param name="x">The x-coordinate of the given point.</param>
/// <param name="y">The y-coordinate of the given point.</param>
/// <returns>The <see cref="bool"/></returns>
public bool Contains(int x, int y)
{
// TODO: SIMD?
return this.X <= x
&& x < this.Right
&& this.Y <= y
&& y < this.Bottom;
}
/// <summary>
/// Determines if the specfied <see cref="Rectangle"/> intersects the rectangular region defined by
/// this <see cref="Rectangle"/>.
/// </summary>
/// <param name="rect">The other Rectange </param>
/// <returns>The <see cref="bool"/></returns>
public bool Intersects(Rectangle rect)
{
return rect.Left <= this.Right && rect.Right >= this.Left
&&
rect.Top <= this.Bottom && rect.Bottom >= this.Top;
}
/// <inheritdoc/>
public override int GetHashCode()
{
return this.GetHashCode(this);
}
/// <inheritdoc/>
public override string ToString()
{
if (this.IsEmpty)
{
return "Rectangle [ Empty ]";
}
return
$"Rectangle [ X={this.X}, Y={this.Y}, Width={this.Width}, Height={this.Height} ]";
}
/// <inheritdoc/>
public override bool Equals(object obj)
{
if (obj is Rectangle)
{
return this.Equals((Rectangle)obj);
}
return false;
}
/// <inheritdoc/>
public bool Equals(Rectangle other)
{
return this.backingVector.Equals(other.backingVector);
}
/// <summary>
/// Returns the hash code for this instance.
/// </summary>
/// <param name="rectangle">
/// The instance of <see cref="Rectangle"/> to return the hash code for.
/// </param>
/// <returns>
/// A 32-bit signed integer that is the hash code for this instance.
/// </returns>
private int GetHashCode(Rectangle rectangle)
{
return rectangle.backingVector.GetHashCode();
}
}
}

Просмотреть файл

@ -1,175 +0,0 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
namespace Shaper2D.Primitives
{
/// <summary>
/// Stores an ordered pair of integers, which specify a height and width.
/// </summary>
/// <remarks>
/// This struct is fully mutable. This is done (against the guidelines) for the sake of performance,
/// as it avoids the need to create new values for modification operations.
/// </remarks>
public struct SizeF : IEquatable<SizeF>
{
/// <summary>
/// Represents a <see cref="SizeF"/> that has Width and Height values set to zero.
/// </summary>
public static readonly SizeF Empty = default(SizeF);
/// <summary>
/// The backing vector for SIMD support.
/// </summary>
private Vector2 backingVector;
/// <summary>
/// Initializes a new instance of the <see cref="Size"/> struct.
/// </summary>
/// <param name="width">The width of the size.</param>
/// <param name="height">The height of the size.</param>
public SizeF(float width, float height)
{
backingVector = new Vector2(width, height);
}
public SizeF(Vector2 vector)
{
backingVector = vector;
}
/// <summary>
/// Gets or sets the width of this <see cref="SizeF"/>.
/// </summary>
public float Width => backingVector.X;
/// <summary>
/// Gets or sets the height of this <see cref="SizeF"/>.
/// </summary>
public float Height => backingVector.Y;
/// <summary>
/// Gets a value indicating whether this <see cref="SizeF"/> is empty.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
public bool IsEmpty => this.Equals(Empty);
/// <summary>
/// Computes the sum of adding two sizes.
/// </summary>
/// <param name="left">The size on the left hand of the operand.</param>
/// <param name="right">The size on the right hand of the operand.</param>
/// <returns>
/// The <see cref="Size"/>
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static SizeF operator +(SizeF left, SizeF right)
{
return new SizeF(left.backingVector + right.backingVector);
}
/// <summary>
/// Computes the difference left by subtracting one size from another.
/// </summary>
/// <param name="left">The size on the left hand of the operand.</param>
/// <param name="right">The size on the right hand of the operand.</param>
/// <returns>
/// The <see cref="SizeF"/>
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static SizeF operator -(SizeF left, SizeF right)
{
return new SizeF(left.backingVector - right.backingVector);
}
/// <summary>
/// Compares two <see cref="Size"/> objects for equality.
/// </summary>
/// <param name="left">
/// The <see cref="Size"/> on the left side of the operand.
/// </param>
/// <param name="right">
/// The <see cref="Size"/> on the right side of the operand.
/// </param>
/// <returns>
/// True if the current left is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(SizeF left, SizeF right)
{
return left.backingVector == right.backingVector;
}
/// <summary>
/// Compares two <see cref="Size"/> objects for inequality.
/// </summary>
/// <param name="left">
/// The <see cref="Size"/> on the left side of the operand.
/// </param>
/// <param name="right">
/// The <see cref="Size"/> on the right side of the operand.
/// </param>
/// <returns>
/// True if the current left is unequal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(SizeF left, SizeF right)
{
return left.backingVector != right.backingVector;
}
/// <inheritdoc/>
public override int GetHashCode()
{
return this.GetHashCode(this);
}
/// <inheritdoc/>
public override string ToString()
{
if (this.IsEmpty)
{
return "Size [ Empty ]";
}
return $"Size [ Width={this.Width}, Height={this.Height} ]";
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override bool Equals(object obj)
{
if (obj is SizeF)
{
return this.Equals((SizeF)obj);
}
return false;
}
/// <inheritdoc/>
public bool Equals(SizeF other)
{
return this.backingVector == other.backingVector;
}
/// <summary>
/// Returns the hash code for this instance.
/// </summary>
/// <param name="size">
/// The instance of <see cref="Size"/> to return the hash code for.
/// </param>
/// <returns>
/// A 32-bit signed integer that is the hash code for this instance.
/// </returns>
private int GetHashCode(SizeF size)
{
return size.backingVector.GetHashCode();
}
}
}

Просмотреть файл

@ -1,30 +0,0 @@
using System.Resources;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Shaper2D")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Shaper2D")]
[assembly: AssemblyCopyright("Copyright © 2016")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: NeutralResourcesLanguage("en")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

Просмотреть файл

@ -1,57 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{8EC582C9-750F-48BC-B48E-B3F89A5BA7B7}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Shaper2D</RootNamespace>
<AssemblyName>Shaper2D</AssemblyName>
<DefaultLanguage>en-US</DefaultLanguage>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<TargetFrameworkProfile>
</TargetFrameworkProfile>
<TargetFrameworkVersion>v5.0</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<!-- A reference to the entire .NET Framework is automatically included -->
<None Include="project.json" />
</ItemGroup>
<ItemGroup>
<Compile Include="Primitives\Size.cs" />
<Compile Include="Primitives\Point.cs" />
<Compile Include="Primitives\Rectangle.cs" />
<Compile Include="SimplePolygon.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<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.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

Просмотреть файл

@ -1,354 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Numerics;
using Shaper2D.Primitives;
using System.Collections.ObjectModel;
namespace Shaper2D
{
internal class SimplePolygon
{
private Lazy<RectangleF> bounds;
private IReadOnlyList<ILineSegment> segments;
public bool IsHole { get; set; } = false;
public SimplePolygon(ILineSegment segments)
: this(new[] { segments })
{
}
public SimplePolygon(IEnumerable<Vector2> points)
: this(new LinearLineSegment(points))
{
}
public SimplePolygon(IEnumerable<ILineSegment> segments)
{
this.segments = new ReadOnlyCollection<ILineSegment>(segments.ToList());
bounds = new Lazy<RectangleF>(CalculateBounds);
}
public int Corners
{
get
{
CalculatePoints();
return polyCorners;
}
}
public Vector2 this[int index]
{
get
{
CalculatePoints();
var boundexIndex = Math.Abs(index) % polyCorners;
if (index < 0)
{
// back counting
index = polyCorners - boundexIndex;
}
else
{
index = boundexIndex;
}
return new Vector2(polyX[index], polyY[index]);
}
}
public RectangleF Bounds => bounds.Value;
float[] constant;
float[] multiple;
bool calcualted = false;
object locker = new object();
float[] polyY;
float[] polyX;
int polyCorners;
bool calcualtedPoints = false;
object lockerPoints = new object();
private void CalculatePoints()
{
if (calcualtedPoints) return;
lock (lockerPoints)
{
if (calcualtedPoints) return;
var points = Simplify(segments).ToArray();
polyX = points.Select(x => (float)x.X).ToArray();
polyY = points.Select(x => (float)x.Y).ToArray();
polyCorners = points.Length;
calcualtedPoints = true;
}
}
private void CalculateConstants()
{
if (calcualted) return;
lock (locker)
{
if (calcualted) return;
// ensure points are availible
CalculatePoints();
constant = new float[polyCorners];
multiple = new float[polyCorners];
int i, j = polyCorners - 1;
for (i = 0; i < polyCorners; i++)
{
if (polyY[j] == polyY[i])
{
constant[i] = polyX[i];
multiple[i] = 0;
}
else
{
constant[i] = polyX[i] - (polyY[i] * polyX[j]) / (polyY[j] - polyY[i]) + (polyY[i] * polyX[i]) / (polyY[j] - polyY[i]);
multiple[i] = (polyX[j] - polyX[i]) / (polyY[j] - polyY[i]);
}
j = i;
}
calcualted = true;
}
}
bool PointInPolygon(float x, float y)
{
if (!Bounds.Contains((int)x, (int)y))
{
return false;
}
// things we cound do to make this more efficient
// pre calculate simple regions that are inside the polygo and see if its contained in one of those
CalculateConstants();
var j = polyCorners - 1;
bool oddNodes = false;
for (var i = 0; i < polyCorners; i++)
{
if ((polyY[i] < y && polyY[j] >= y
|| polyY[j] < y && polyY[i] >= y))
{
oddNodes ^= (y * multiple[i] + constant[i] < x);
}
j = i;
}
return oddNodes;
}
private float DistanceSquared(float x1, float y1, float x2, float y2, float xp, float yp)
{
var px = x2 - x1;
var py = y2 - y1;
float something = px * px + py * py;
var u = ((xp - x1) * px + (yp - y1) * py) / something;
if (u > 1)
{
u = 1;
}
else if (u < 0)
{
u = 0;
}
var x = x1 + u * px;
var y = y1 + u * py;
var dx = x - xp;
var dy = y - yp;
return dx * dx + dy * dy;
}
private float CalculateDistance(Vector2 vector)
{
return CalculateDistance(vector.X, vector.Y);
}
private float CalculateDistance(float x, float y)
{
float distance = float.MaxValue;
for (var i = 0; i < polyCorners; i++)
{
var next = i + 1;
if (next == polyCorners)
{
next = 0;
}
var lastDistance = DistanceSquared(polyX[i], polyY[i], polyX[next], polyY[next], x, y);
if (lastDistance < distance)
{
distance = lastDistance;
}
}
return (float)Math.Sqrt(distance);
}
public float Distance(Vector2 vector)
{
return Distance(vector.X, vector.Y);
}
public float Distance(float x, float y)
{
// we will do a nieve point in polygon test here for now
// TODO optermise here and actually return a distance
if (PointInPolygon(x, y))
{
if (IsHole)
{
return CalculateDistance(x, y);
}
//we are on line or inside
return 0;
}
if (IsHole)
{
return 0;
}
return CalculateDistance(x, y);
}
private RectangleF CalculateBounds()
{
// ensure points are availible
CalculatePoints();
var minX = polyX.Min();
var maxX = polyX.Max();
var minY = polyY.Min();
var maxY = polyY.Max();
return new RectangleF(minX, minY, maxX - minX, maxY - minY);
}
private IEnumerable<Vector2> Simplify(IEnumerable<ILineSegment> segments)
{
//used to deduplicate
HashSet<Vector2> pointHash = new HashSet<Vector2>();
foreach (var segment in segments)
{
var points = segment.Simplify();
foreach (var p in points)
{
if (!pointHash.Contains(p))
{
pointHash.Add(p);
yield return p;
}
}
}
}
Vector2? LineIntersectionPoint(Vector2 ps1, Vector2 pe1, Vector2 ps2, Vector2 pe2)
{
// Get A,B,C of first line - points : ps1 to pe1
float A1 = pe1.Y - ps1.Y;
float B1 = ps1.X - pe1.X;
float C1 = A1 * ps1.X + B1 * ps1.Y;
// Get A,B,C of second line - points : ps2 to pe2
float A2 = pe2.Y - ps2.Y;
float B2 = ps2.X - pe2.X;
float C2 = A2 * ps2.X + B2 * ps2.Y;
// Get delta and check if the lines are parallel
float delta = A1 * B2 - A2 * B1;
if (delta == 0)
{
return null;
}
// now return the Vector2 intersection point
return new Vector2(
(B2 * C1 - B1 * C2) / delta,
(A1 * C2 - A2 * C1) / delta
);
}
private RectangleF GetBounds(Vector2 start, Vector2 end)
{
var minX = Math.Min(start.X, end.X);
var maxX = Math.Min(start.X, end.X);
var minY = Math.Min(start.Y, end.Y);
var maxY = Math.Min(start.Y, end.Y);
return new RectangleF((int)minX, (int)minY, (int)maxX - (int)minX, (int)maxY - (int)minY);
}
//public Vector2? GetIntersectionPoint(SimplePolygon polygon)
//{
// for (var i = 0; i < this.Corners; i++)
// {
// var prevPoint = this[i - 1];
// var currentPoint = this[i];
// RectangleF src = GetBounds(prevPoint, currentPoint);
// for (var j = 0; j < polygon.Corners; j++)
// {
// var prevPointOther = polygon[j - 1];
// var currentPointOther = polygon[j];
// RectangleF target = GetBounds(prevPointOther, currentPointOther);
// //first do they have overlapping bounding boxes
// if (src.Intersects(target))
// {
// //there boxes intersect lets find where there lines touch
// LineIntersectionPoint()
// }
// }
// }
// // does this poly intersect with another
//}
public SimplePolygon Clone()
{
List<Vector2> points = new List<Vector2>();
for (var i = 0; i < this.polyCorners; i++)
{
points.Add(this[i]);
}
return new SimplePolygon(points) { IsHole = this.IsHole };
}
}
}

Просмотреть файл

@ -1,12 +0,0 @@
{
"supports": {},
"dependencies": {
"Microsoft.NETCore.Portable.Compatibility": "1.0.1",
"NETStandard.Library": "1.6.0",
"System.Numerics.Vectors": "4.3.0",
"System.Runtime.Numerics": "4.0.1"
},
"frameworks": {
"netstandard1.1": {}
}
}