First commit.
This commit is contained in:
538
Source/OpenNest.Core/Geometry/Arc.cs
Normal file
538
Source/OpenNest.Core/Geometry/Arc.cs
Normal file
@@ -0,0 +1,538 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace OpenNest.Geometry
|
||||
{
|
||||
public class Arc : Entity
|
||||
{
|
||||
private double radius;
|
||||
private double startAngle;
|
||||
private double endAngle;
|
||||
private Vector center;
|
||||
private bool reversed;
|
||||
|
||||
public Arc()
|
||||
{
|
||||
}
|
||||
|
||||
public Arc(double x, double y, double r, double a1, double a2, bool reversed = false)
|
||||
: this(new Vector(x, y), r, a1, a2, reversed)
|
||||
{
|
||||
}
|
||||
|
||||
public Arc(Vector center, double radius, double startAngle, double endAngle, bool reversed = false)
|
||||
{
|
||||
this.center = center;
|
||||
this.radius = radius;
|
||||
this.startAngle = startAngle;
|
||||
this.endAngle = endAngle;
|
||||
this.reversed = reversed;
|
||||
UpdateBounds();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Center point.
|
||||
/// </summary>
|
||||
public Vector Center
|
||||
{
|
||||
get { return center; }
|
||||
set
|
||||
{
|
||||
var offset = value - center;
|
||||
boundingBox.Offset(offset);
|
||||
center = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Arc radius.
|
||||
/// </summary>
|
||||
public double Radius
|
||||
{
|
||||
get { return radius; }
|
||||
set
|
||||
{
|
||||
radius = value;
|
||||
UpdateBounds();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Arc radius * 2. Value NOT stored.
|
||||
/// </summary>
|
||||
public double Diameter
|
||||
{
|
||||
get { return Radius * 2.0; }
|
||||
set { Radius = value / 2.0; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start angle in radians.
|
||||
/// </summary>
|
||||
public double StartAngle
|
||||
{
|
||||
get { return startAngle; }
|
||||
set
|
||||
{
|
||||
startAngle = Angle.NormalizeRad(value);
|
||||
UpdateBounds();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// End angle in radians.
|
||||
/// </summary>
|
||||
public double EndAngle
|
||||
{
|
||||
get { return endAngle; }
|
||||
set
|
||||
{
|
||||
endAngle = Angle.NormalizeRad(value);
|
||||
UpdateBounds();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Angle in radians between start and end angles.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public double SweepAngle()
|
||||
{
|
||||
var startAngle = StartAngle;
|
||||
var endAngle = EndAngle;
|
||||
|
||||
if (IsReversed)
|
||||
Generic.Swap(ref startAngle, ref endAngle);
|
||||
|
||||
if (startAngle > endAngle)
|
||||
startAngle -= Angle.TwoPI;
|
||||
|
||||
return endAngle - startAngle;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets if the arc direction is reversed (clockwise).
|
||||
/// </summary>
|
||||
public bool IsReversed
|
||||
{
|
||||
get { return reversed; }
|
||||
set
|
||||
{
|
||||
if (reversed != value)
|
||||
Reverse();
|
||||
}
|
||||
}
|
||||
|
||||
public RotationType Rotation
|
||||
{
|
||||
get { return IsReversed ? RotationType.CW : RotationType.CCW; }
|
||||
set
|
||||
{
|
||||
IsReversed = (value == RotationType.CW);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start point of the arc.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public Vector StartPoint()
|
||||
{
|
||||
return new Vector(
|
||||
Center.X + Radius * Math.Cos(StartAngle),
|
||||
Center.Y + Radius * Math.Sin(StartAngle));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// End point of the arc.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public Vector EndPoint()
|
||||
{
|
||||
return new Vector(
|
||||
Center.X + Radius * Math.Cos(EndAngle),
|
||||
Center.Y + Radius * Math.Sin(EndAngle));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the given arc has the same center point and radius as this.
|
||||
/// </summary>
|
||||
/// <param name="arc"></param>
|
||||
/// <returns></returns>
|
||||
public bool IsCoradialTo(Arc arc)
|
||||
{
|
||||
return center == arc.Center && Radius.IsEqualTo(arc.Radius);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the given arc has the same radius as this.
|
||||
/// </summary>
|
||||
/// <param name="arc"></param>
|
||||
/// <returns></returns>
|
||||
public bool IsConcentricTo(Arc arc)
|
||||
{
|
||||
return center == arc.center;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the given circle has the same radius as this.
|
||||
/// </summary>
|
||||
/// <param name="circle"></param>
|
||||
/// <returns></returns>
|
||||
public bool IsConcentricTo(Circle circle)
|
||||
{
|
||||
return center == circle.Center;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts the arc to a group of points.
|
||||
/// </summary>
|
||||
/// <param name="segments">Number of parts to divide the arc into.</param>
|
||||
/// <returns></returns>
|
||||
public List<Vector> ToPoints(int segments = 1000)
|
||||
{
|
||||
var points = new List<Vector>();
|
||||
var stepAngle = reversed
|
||||
? -SweepAngle() / segments
|
||||
: SweepAngle() / segments;
|
||||
|
||||
for (int i = 0; i <= segments; ++i)
|
||||
{
|
||||
var angle = stepAngle * i + StartAngle;
|
||||
|
||||
points.Add(new Vector(
|
||||
Math.Cos(angle) * Radius + Center.X,
|
||||
Math.Sin(angle) * Radius + Center.Y));
|
||||
}
|
||||
|
||||
return points;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Linear distance of the arc.
|
||||
/// </summary>
|
||||
public override double Length
|
||||
{
|
||||
get { return Diameter * Math.PI * SweepAngle() / Angle.TwoPI; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reverses the rotation direction.
|
||||
/// </summary>
|
||||
public override void Reverse()
|
||||
{
|
||||
reversed = !reversed;
|
||||
Generic.Swap(ref startAngle, ref endAngle);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Moves the center point to the given coordinates.
|
||||
/// </summary>
|
||||
/// <param name="x">The x-coordinate</param>
|
||||
/// <param name="y">The y-coordinate</param>
|
||||
public override void MoveTo(double x, double y)
|
||||
{
|
||||
Center = new Vector(x, y);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Moves the center point to the given point.
|
||||
/// </summary>
|
||||
/// <param name="pt">The new center point location.</param>
|
||||
public override void MoveTo(Vector pt)
|
||||
{
|
||||
Center = pt;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Offsets the center point by the given distances.
|
||||
/// </summary>
|
||||
/// <param name="x">The x-axis offset distance.</param>
|
||||
/// <param name="y">The y-axis offset distance.</param>
|
||||
public override void Offset(double x, double y)
|
||||
{
|
||||
Center = new Vector(Center.X + x, Center.Y + y);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Offsets the center point by the given distances.
|
||||
/// </summary>
|
||||
/// <param name="voffset"></param>
|
||||
public override void Offset(Vector voffset)
|
||||
{
|
||||
Center += voffset;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Scales the arc from the zero point.
|
||||
/// </summary>
|
||||
/// <param name="factor"></param>
|
||||
public override void Scale(double factor)
|
||||
{
|
||||
center *= factor;
|
||||
radius *= factor;
|
||||
UpdateBounds();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Scales the arc from the origin.
|
||||
/// </summary>
|
||||
/// <param name="factor"></param>
|
||||
/// <param name="origin"></param>
|
||||
public override void Scale(double factor, Vector origin)
|
||||
{
|
||||
center = center.Scale(factor, origin);
|
||||
radius *= factor;
|
||||
UpdateBounds();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rotates the arc from the zero point.
|
||||
/// </summary>
|
||||
/// <param name="angle"></param>
|
||||
public override void Rotate(double angle)
|
||||
{
|
||||
startAngle += angle;
|
||||
endAngle += angle;
|
||||
center = center.Rotate(angle);
|
||||
UpdateBounds();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rotates the arc from the origin.
|
||||
/// </summary>
|
||||
/// <param name="angle"></param>
|
||||
/// <param name="origin"></param>
|
||||
public override void Rotate(double angle, Vector origin)
|
||||
{
|
||||
startAngle += angle;
|
||||
endAngle += angle;
|
||||
center = center.Rotate(angle, origin);
|
||||
UpdateBounds();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the bounding box.
|
||||
/// </summary>
|
||||
public override void UpdateBounds()
|
||||
{
|
||||
var startpt = StartPoint();
|
||||
var endpt = EndPoint();
|
||||
|
||||
double minX;
|
||||
double minY;
|
||||
double maxX;
|
||||
double maxY;
|
||||
|
||||
if (startpt.X < endpt.X)
|
||||
{
|
||||
minX = startpt.X;
|
||||
maxX = endpt.X;
|
||||
}
|
||||
else
|
||||
{
|
||||
minX = endpt.X;
|
||||
maxX = startpt.X;
|
||||
}
|
||||
|
||||
if (startpt.Y < endpt.Y)
|
||||
{
|
||||
minY = startpt.Y;
|
||||
maxY = endpt.Y;
|
||||
}
|
||||
else
|
||||
{
|
||||
minY = endpt.Y;
|
||||
maxY = startpt.Y;
|
||||
}
|
||||
|
||||
var angle1 = StartAngle;
|
||||
var angle2 = EndAngle;
|
||||
|
||||
// switch the angle to counter clockwise.
|
||||
if (IsReversed)
|
||||
Generic.Swap(ref angle1, ref angle2);
|
||||
|
||||
if (Angle.IsBetweenRad(Angle.HalfPI, angle1, angle2))
|
||||
maxY = Center.Y + Radius;
|
||||
|
||||
if (Angle.IsBetweenRad(Math.PI, angle1, angle2))
|
||||
minX = Center.X - Radius;
|
||||
|
||||
const double oneHalfPI = Math.PI * 1.5;
|
||||
|
||||
if (Angle.IsBetweenRad(oneHalfPI, angle1, angle2))
|
||||
minY = Center.Y - Radius;
|
||||
|
||||
if (Angle.IsBetweenRad(Angle.TwoPI, angle1, angle2))
|
||||
maxX = Center.X + Radius;
|
||||
|
||||
boundingBox.X = minX;
|
||||
boundingBox.Y = minY;
|
||||
boundingBox.Width = maxX - minX;
|
||||
boundingBox.Height = maxY - minY;
|
||||
}
|
||||
|
||||
public override Entity OffsetEntity(double distance, OffsetSide side)
|
||||
{
|
||||
if (side == OffsetSide.Left && reversed)
|
||||
{
|
||||
return new Arc(center, radius + distance, startAngle, endAngle, reversed);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (distance >= radius)
|
||||
return null;
|
||||
|
||||
return new Arc(center, radius - distance, startAngle, endAngle, reversed);
|
||||
}
|
||||
}
|
||||
|
||||
public override Entity OffsetEntity(double distance, Vector pt)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the closest point on the arc to the given point.
|
||||
/// </summary>
|
||||
/// <param name="pt"></param>
|
||||
/// <returns></returns>
|
||||
public override Vector ClosestPointTo(Vector pt)
|
||||
{
|
||||
var angle = Center.AngleTo(pt);
|
||||
|
||||
if (Angle.IsBetweenRad(angle, StartAngle, EndAngle, IsReversed))
|
||||
{
|
||||
return new Vector(
|
||||
Math.Cos(angle) * Radius + Center.X,
|
||||
Math.Sin(angle) * Radius + Center.Y);
|
||||
}
|
||||
else
|
||||
{
|
||||
var sp = StartPoint();
|
||||
var ep = EndPoint();
|
||||
|
||||
return pt.DistanceTo(sp) <= pt.DistanceTo(ep) ? sp : ep;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the given arc is intersecting this.
|
||||
/// </summary>
|
||||
/// <param name="arc"></param>
|
||||
/// <returns></returns>
|
||||
public override bool Intersects(Arc arc)
|
||||
{
|
||||
List<Vector> pts;
|
||||
return Helper.Intersects(this, arc, out pts);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the given arc is intersecting this.
|
||||
/// </summary>
|
||||
/// <param name="arc"></param>
|
||||
/// <param name="pts">Points of intersection.</param>
|
||||
/// <returns></returns>
|
||||
public override bool Intersects(Arc arc, out List<Vector> pts)
|
||||
{
|
||||
return Helper.Intersects(this, arc, out pts); ;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the given circle is intersecting this.
|
||||
/// </summary>
|
||||
/// <param name="circle"></param>
|
||||
/// <returns></returns>
|
||||
public override bool Intersects(Circle circle)
|
||||
{
|
||||
List<Vector> pts;
|
||||
return Helper.Intersects(this, circle, out pts);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the given circle is intersecting this.
|
||||
/// </summary>
|
||||
/// <param name="circle"></param>
|
||||
/// <param name="pts">Points of intersection.</param>
|
||||
/// <returns></returns>
|
||||
public override bool Intersects(Circle circle, out List<Vector> pts)
|
||||
{
|
||||
return Helper.Intersects(this, circle, out pts);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the given line is intersecting this.
|
||||
/// </summary>
|
||||
/// <param name="line"></param>
|
||||
/// <returns></returns>
|
||||
public override bool Intersects(Line line)
|
||||
{
|
||||
List<Vector> pts;
|
||||
return Helper.Intersects(this, line, out pts);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the given line is intersecting this.
|
||||
/// </summary>
|
||||
/// <param name="line"></param>
|
||||
/// <param name="pts">Points of intersection.</param>
|
||||
/// <returns></returns>
|
||||
public override bool Intersects(Line line, out List<Vector> pts)
|
||||
{
|
||||
return Helper.Intersects(this, line, out pts);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the given polygon is intersecting this.
|
||||
/// </summary>
|
||||
/// <param name="polygon"></param>
|
||||
/// <returns></returns>
|
||||
public override bool Intersects(Polygon polygon)
|
||||
{
|
||||
List<Vector> pts;
|
||||
return Helper.Intersects(this, polygon, out pts);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the given polygon is intersecting this.
|
||||
/// </summary>
|
||||
/// <param name="polygon"></param>
|
||||
/// <param name="pts">Points of intersection.</param>
|
||||
/// <returns></returns>
|
||||
public override bool Intersects(Polygon polygon, out List<Vector> pts)
|
||||
{
|
||||
return Helper.Intersects(this, polygon, out pts);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the given shape is intersecting this.
|
||||
/// </summary>
|
||||
/// <param name="shape"></param>
|
||||
/// <returns></returns>
|
||||
public override bool Intersects(Shape shape)
|
||||
{
|
||||
List<Vector> pts;
|
||||
return Helper.Intersects(this, shape, out pts);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the given shape is intersecting this.
|
||||
/// </summary>
|
||||
/// <param name="shape"></param>
|
||||
/// <param name="pts">Points of intersection.</param>
|
||||
/// <returns></returns>
|
||||
public override bool Intersects(Shape shape, out List<Vector> pts)
|
||||
{
|
||||
return Helper.Intersects(this, shape, out pts);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Type of entity.
|
||||
/// </summary>
|
||||
public override EntityType Type
|
||||
{
|
||||
get { return EntityType.Arc; }
|
||||
}
|
||||
}
|
||||
}
|
||||
415
Source/OpenNest.Core/Geometry/Circle.cs
Normal file
415
Source/OpenNest.Core/Geometry/Circle.cs
Normal file
@@ -0,0 +1,415 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace OpenNest.Geometry
|
||||
{
|
||||
public class Circle : Entity
|
||||
{
|
||||
private Vector center;
|
||||
private double radius;
|
||||
|
||||
public Circle()
|
||||
{
|
||||
}
|
||||
|
||||
public Circle(double x, double y, double radius)
|
||||
: this(new Vector(x, y), radius)
|
||||
{
|
||||
}
|
||||
|
||||
public Circle(Vector center, double radius)
|
||||
{
|
||||
this.center = center;
|
||||
this.radius = radius;
|
||||
this.Rotation = RotationType.CCW;
|
||||
UpdateBounds();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a circle from two points.
|
||||
/// </summary>
|
||||
/// <param name="pt1"></param>
|
||||
/// <param name="pt2"></param>
|
||||
/// <returns></returns>
|
||||
public static Circle CreateFrom2Points(Vector pt1, Vector pt2)
|
||||
{
|
||||
var line = new Line(pt1, pt2);
|
||||
return new Circle(line.MidPoint, line.Length * 0.5);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Center point of the circle.
|
||||
/// </summary>
|
||||
public Vector Center
|
||||
{
|
||||
get { return center; }
|
||||
set
|
||||
{
|
||||
var offset = value - center;
|
||||
boundingBox.Offset(offset);
|
||||
center = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Radius of the circle.
|
||||
/// </summary>
|
||||
public double Radius
|
||||
{
|
||||
get { return radius; }
|
||||
set
|
||||
{
|
||||
radius = value;
|
||||
UpdateBounds();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Radius * 2. Value NOT stored.
|
||||
/// </summary>
|
||||
public double Diameter
|
||||
{
|
||||
get { return Radius * 2.0; }
|
||||
set { Radius = value / 2.0; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rotation direction.
|
||||
/// </summary>
|
||||
public RotationType Rotation { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Area of the circle.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public double Area()
|
||||
{
|
||||
return Math.PI * Radius * Radius;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Linear distance around the circle.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public double Circumference()
|
||||
{
|
||||
return Math.PI * Diameter;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the given circle has the same radius as this.
|
||||
/// </summary>
|
||||
/// <param name="circle"></param>
|
||||
/// <returns></returns>
|
||||
public bool IsConcentricTo(Circle circle)
|
||||
{
|
||||
return center == circle.center;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the given circle has the same radius as this.
|
||||
/// </summary>
|
||||
/// <param name="arc"></param>
|
||||
/// <returns></returns>
|
||||
public bool IsConcentricTo(Arc arc)
|
||||
{
|
||||
return center == arc.Center;
|
||||
}
|
||||
|
||||
public bool ContainsPoint(Vector pt)
|
||||
{
|
||||
return Center.DistanceTo(pt) <= Radius;
|
||||
}
|
||||
|
||||
public List<Vector> ToPoints(int segments = 1000)
|
||||
{
|
||||
var points = new List<Vector>();
|
||||
var stepAngle = Angle.TwoPI / segments;
|
||||
|
||||
for (int i = 0; i <= segments; ++i)
|
||||
{
|
||||
var angle = stepAngle * i;
|
||||
|
||||
points.Add(new Vector(
|
||||
Math.Cos(angle) * Radius + Center.X,
|
||||
Math.Sin(angle) * Radius + Center.Y));
|
||||
}
|
||||
|
||||
return points;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Linear distance around the circle.
|
||||
/// </summary>
|
||||
public override double Length
|
||||
{
|
||||
get { return Circumference(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reverses the rotation direction.
|
||||
/// </summary>
|
||||
public override void Reverse()
|
||||
{
|
||||
if (Rotation == RotationType.CCW)
|
||||
Rotation = RotationType.CW;
|
||||
else
|
||||
Rotation = RotationType.CCW;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Moves the center point to the given coordinates.
|
||||
/// </summary>
|
||||
/// <param name="x"></param>
|
||||
/// <param name="y"></param>
|
||||
public override void MoveTo(double x, double y)
|
||||
{
|
||||
Center = new Vector(x, y);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Moves the center point to the given point.
|
||||
/// </summary>
|
||||
/// <param name="pt"></param>
|
||||
public override void MoveTo(Vector pt)
|
||||
{
|
||||
Center = pt;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Offsets the center point by the given distances.
|
||||
/// </summary>
|
||||
/// <param name="x"></param>
|
||||
/// <param name="y"></param>
|
||||
public override void Offset(double x, double y)
|
||||
{
|
||||
Center = new Vector(Center.X + x, Center.Y + y);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Offsets the center point by the given distances.
|
||||
/// </summary>
|
||||
/// <param name="voffset"></param>
|
||||
public override void Offset(Vector voffset)
|
||||
{
|
||||
Center += voffset;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Scales the circle from the zero point.
|
||||
/// </summary>
|
||||
/// <param name="factor"></param>
|
||||
public override void Scale(double factor)
|
||||
{
|
||||
center *= factor;
|
||||
radius *= factor;
|
||||
UpdateBounds();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Scales the circle from the origin.
|
||||
/// </summary>
|
||||
/// <param name="factor"></param>
|
||||
/// <param name="origin"></param>
|
||||
public override void Scale(double factor, Vector origin)
|
||||
{
|
||||
center = center.Scale(factor, origin);
|
||||
radius *= factor;
|
||||
UpdateBounds();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rotates the circle from the zero point.
|
||||
/// </summary>
|
||||
/// <param name="angle"></param>
|
||||
public override void Rotate(double angle)
|
||||
{
|
||||
Center = Center.Rotate(angle);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// /// Rotates the circle from the origin.
|
||||
/// </summary>
|
||||
/// <param name="angle"></param>
|
||||
/// <param name="origin"></param>
|
||||
public override void Rotate(double angle, Vector origin)
|
||||
{
|
||||
Center = Center.Rotate(angle, origin);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the bounding box.
|
||||
/// </summary>
|
||||
public override void UpdateBounds()
|
||||
{
|
||||
boundingBox.X = Center.X - Radius;
|
||||
boundingBox.Y = Center.Y - Radius;
|
||||
boundingBox.Width = Diameter;
|
||||
boundingBox.Height = Diameter;
|
||||
}
|
||||
|
||||
public override Entity OffsetEntity(double distance, OffsetSide side)
|
||||
{
|
||||
if (side == OffsetSide.Left && Rotation == RotationType.CCW)
|
||||
{
|
||||
return Radius <= distance ? null : new Circle(center, Radius - distance)
|
||||
{
|
||||
Layer = Layer,
|
||||
Rotation = Rotation
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
return new Circle(center, Radius + distance) { Layer = Layer };
|
||||
}
|
||||
}
|
||||
|
||||
public override Entity OffsetEntity(double distance, Vector pt)
|
||||
{
|
||||
if (ContainsPoint(pt))
|
||||
{
|
||||
return Radius <= distance ? null : new Circle(center, Radius - distance)
|
||||
{
|
||||
Layer = Layer,
|
||||
Rotation = Rotation
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
return new Circle(center, Radius + distance) { Layer = Layer };
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the closest point on the circle to the specified point.
|
||||
/// </summary>
|
||||
/// <param name="pt"></param>
|
||||
/// <returns></returns>
|
||||
public override Vector ClosestPointTo(Vector pt)
|
||||
{
|
||||
var angle = Center.AngleTo(pt);
|
||||
|
||||
return new Vector(
|
||||
Math.Cos(angle) * Radius + Center.X,
|
||||
Math.Sin(angle) * Radius + Center.Y);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the given arc is intersecting this.
|
||||
/// </summary>
|
||||
/// <param name="arc"></param>
|
||||
/// <returns></returns>
|
||||
public override bool Intersects(Arc arc)
|
||||
{
|
||||
List<Vector> pts;
|
||||
return Helper.Intersects(arc, this, out pts);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the given arc is intersecting this.
|
||||
/// </summary>
|
||||
/// <param name="arc"></param>
|
||||
/// <param name="pts">Points of intersection.</param>
|
||||
/// <returns></returns>
|
||||
public override bool Intersects(Arc arc, out List<Vector> pts)
|
||||
{
|
||||
return Helper.Intersects(arc, this, out pts);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the given circle is intersecting this.
|
||||
/// </summary>
|
||||
/// <param name="circle"></param>
|
||||
/// <returns></returns>
|
||||
public override bool Intersects(Circle circle)
|
||||
{
|
||||
var dist = Center.DistanceTo(circle.Center);
|
||||
return (dist < (Radius + circle.Radius) && dist > Math.Abs(Radius - circle.Radius));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the given circle is intersecting this.
|
||||
/// </summary>
|
||||
/// <param name="circle"></param>
|
||||
/// <param name="pts">Points of intersection.</param>
|
||||
/// <returns></returns>
|
||||
public override bool Intersects(Circle circle, out List<Vector> pts)
|
||||
{
|
||||
return Helper.Intersects(this, circle, out pts);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the given line is intersecting this.
|
||||
/// </summary>
|
||||
/// <param name="line"></param>
|
||||
/// <returns></returns>
|
||||
public override bool Intersects(Line line)
|
||||
{
|
||||
List<Vector> pts;
|
||||
return Helper.Intersects(this, line, out pts);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the given line is intersecting this.
|
||||
/// </summary>
|
||||
/// <param name="line"></param>
|
||||
/// <param name="pts">Points of intersection.</param>
|
||||
/// <returns></returns>
|
||||
public override bool Intersects(Line line, out List<Vector> pts)
|
||||
{
|
||||
return Helper.Intersects(this, line, out pts);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the given polygon is intersecting this.
|
||||
/// </summary>
|
||||
/// <param name="polygon"></param>
|
||||
/// <returns></returns>
|
||||
public override bool Intersects(Polygon polygon)
|
||||
{
|
||||
List<Vector> pts;
|
||||
return Helper.Intersects(this, polygon, out pts);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the given polygon is intersecting this.
|
||||
/// </summary>
|
||||
/// <param name="polygon"></param>
|
||||
/// <param name="pts">Points of intersection.</param>
|
||||
/// <returns></returns>
|
||||
public override bool Intersects(Polygon polygon, out List<Vector> pts)
|
||||
{
|
||||
return Helper.Intersects(this, polygon, out pts);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the given shape is intersecting this.
|
||||
/// </summary>
|
||||
/// <param name="shape"></param>
|
||||
/// <returns></returns>
|
||||
public override bool Intersects(Shape shape)
|
||||
{
|
||||
List<Vector> pts;
|
||||
return Helper.Intersects(this, shape, out pts);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the given shape is intersecting this.
|
||||
/// </summary>
|
||||
/// <param name="shape"></param>
|
||||
/// <param name="pts">Points of intersection.</param>
|
||||
/// <returns></returns>
|
||||
public override bool Intersects(Shape shape, out List<Vector> pts)
|
||||
{
|
||||
return Helper.Intersects(this, shape, out pts);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Type of entity.
|
||||
/// </summary>
|
||||
public override EntityType Type
|
||||
{
|
||||
get { return EntityType.Circle; }
|
||||
}
|
||||
}
|
||||
}
|
||||
42
Source/OpenNest.Core/Geometry/DefinedShape.cs
Normal file
42
Source/OpenNest.Core/Geometry/DefinedShape.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace OpenNest.Geometry
|
||||
{
|
||||
public class DefinedShape
|
||||
{
|
||||
public DefinedShape(Shape shape)
|
||||
{
|
||||
Update(shape.Entities);
|
||||
}
|
||||
|
||||
public DefinedShape(List<Entity> entities)
|
||||
{
|
||||
Update(entities);
|
||||
}
|
||||
|
||||
private void Update(List<Entity> entities)
|
||||
{
|
||||
var shapes = Helper.GetShapes(entities);
|
||||
|
||||
Perimeter = shapes[0];
|
||||
Cutouts = new List<Shape>();
|
||||
|
||||
for (int i = 1; i < shapes.Count; i++)
|
||||
{
|
||||
if (shapes[i].Left < Perimeter.Left)
|
||||
{
|
||||
Cutouts.Add(Perimeter);
|
||||
Perimeter = shapes[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
Cutouts.Add(shapes[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Shape Perimeter { get; set; }
|
||||
|
||||
public List<Shape> Cutouts { get; set; }
|
||||
}
|
||||
}
|
||||
268
Source/OpenNest.Core/Geometry/Entity.cs
Normal file
268
Source/OpenNest.Core/Geometry/Entity.cs
Normal file
@@ -0,0 +1,268 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace OpenNest.Geometry
|
||||
{
|
||||
public abstract class Entity : IBoundable
|
||||
{
|
||||
protected Box boundingBox;
|
||||
|
||||
protected Entity()
|
||||
{
|
||||
Layer = OpenNest.Geometry.Layer.Default;
|
||||
boundingBox = new Box();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Smallest box that contains the entity.
|
||||
/// </summary>
|
||||
public Box BoundingBox
|
||||
{
|
||||
get { return boundingBox; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Entity layer type.
|
||||
/// </summary>
|
||||
public Layer Layer { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// X-Coordinate of the left-most point.
|
||||
/// </summary>
|
||||
public virtual double Left
|
||||
{
|
||||
get { return boundingBox.Left; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// X-Coordinate of the right-most point.
|
||||
/// </summary>
|
||||
public virtual double Right
|
||||
{
|
||||
get { return boundingBox.Right; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Y-Coordinate of the highest point.
|
||||
/// </summary>
|
||||
public virtual double Top
|
||||
{
|
||||
get { return boundingBox.Top; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Y-Coordinate of the lowest point.
|
||||
/// </summary>
|
||||
public virtual double Bottom
|
||||
{
|
||||
get { return boundingBox.Bottom; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Length of the entity.
|
||||
/// </summary>
|
||||
public abstract double Length { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Reverses the entity.
|
||||
/// </summary>
|
||||
public abstract void Reverse();
|
||||
|
||||
/// <summary>
|
||||
/// Moves the entity location to the given coordinates.
|
||||
/// </summary>
|
||||
/// <param name="x"></param>
|
||||
/// <param name="y"></param>
|
||||
public abstract void MoveTo(double x, double y);
|
||||
|
||||
/// <summary>
|
||||
/// Moves the entity location to the given point.
|
||||
/// </summary>
|
||||
/// <param name="pt"></param>
|
||||
public abstract void MoveTo(Vector pt);
|
||||
|
||||
/// <summary>
|
||||
/// Offsets the entity location by the given distances.
|
||||
/// </summary>
|
||||
/// <param name="x"></param>
|
||||
/// <param name="y"></param>
|
||||
public abstract void Offset(double x, double y);
|
||||
|
||||
/// <summary>
|
||||
/// Offsets the entity location by the given distances.
|
||||
/// </summary>
|
||||
/// <param name="voffset"></param>
|
||||
public abstract void Offset(Vector voffset);
|
||||
|
||||
/// <summary>
|
||||
/// Scales the entity from the zero point.
|
||||
/// </summary>
|
||||
/// <param name="factor"></param>
|
||||
public abstract void Scale(double factor);
|
||||
|
||||
/// <summary>
|
||||
/// Scales the entity from the origin.
|
||||
/// </summary>
|
||||
/// <param name="factor"></param>
|
||||
/// <param name="origin"></param>
|
||||
public abstract void Scale(double factor, Vector origin);
|
||||
|
||||
/// <summary>
|
||||
/// Rotates the entity from the zero point.
|
||||
/// </summary>
|
||||
/// <param name="angle"></param>
|
||||
public abstract void Rotate(double angle);
|
||||
|
||||
/// <summary>
|
||||
/// Rotates the entity from the origin.
|
||||
/// </summary>
|
||||
/// <param name="angle"></param>
|
||||
/// <param name="origin"></param>
|
||||
public abstract void Rotate(double angle, Vector origin);
|
||||
|
||||
/// <summary>
|
||||
/// Updates the bounding box.
|
||||
/// </summary>
|
||||
public abstract void UpdateBounds();
|
||||
|
||||
/// <summary>
|
||||
/// Gets a new entity offset the given distance from this entity.
|
||||
/// </summary>
|
||||
/// <param name="distance"></param>
|
||||
/// <param name="side"></param>
|
||||
/// <returns></returns>
|
||||
public abstract Entity OffsetEntity(double distance, OffsetSide side);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a new entity offset the given distance from this entity. Offset side determined by point.
|
||||
/// </summary>
|
||||
/// <param name="distance"></param>
|
||||
/// <param name="pt"></param>
|
||||
/// <returns></returns>
|
||||
public abstract Entity OffsetEntity(double distance, Vector pt);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the closest point on the entity to the given point.
|
||||
/// </summary>
|
||||
/// <param name="pt"></param>
|
||||
/// <returns></returns>
|
||||
public abstract Vector ClosestPointTo(Vector pt);
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the given arc is intersecting this.
|
||||
/// </summary>
|
||||
/// <param name="arc"></param>
|
||||
/// <returns></returns>
|
||||
public abstract bool Intersects(Arc arc);
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the given arc is intersecting this.
|
||||
/// </summary>
|
||||
/// <param name="arc"></param>
|
||||
/// <param name="pts">List to store the points of intersection.</param>
|
||||
/// <returns></returns>
|
||||
public abstract bool Intersects(Arc arc, out List<Vector> pts);
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the given circle is intersecting this.
|
||||
/// </summary>
|
||||
/// <param name="circle"></param>
|
||||
/// <returns></returns>
|
||||
public abstract bool Intersects(Circle circle);
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the given circle is intersecting this.
|
||||
/// </summary>
|
||||
/// <param name="circle"></param>
|
||||
/// <param name="pts"></param>
|
||||
/// <returns></returns>
|
||||
public abstract bool Intersects(Circle circle, out List<Vector> pts);
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the given line is intersecting this.
|
||||
/// </summary>
|
||||
/// <param name="line"></param>
|
||||
/// <returns></returns>
|
||||
public abstract bool Intersects(Line line);
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the given line is intersecting this.
|
||||
/// </summary>
|
||||
/// <param name="line"></param>
|
||||
/// <param name="pts"></param>
|
||||
/// <returns></returns>
|
||||
public abstract bool Intersects(Line line, out List<Vector> pts);
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the given polygon is intersecting this.
|
||||
/// </summary>
|
||||
/// <param name="polygon"></param>
|
||||
/// <returns></returns>
|
||||
public abstract bool Intersects(Polygon polygon);
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the given polygon is intersecting this.
|
||||
/// </summary>
|
||||
/// <param name="polygon"></param>
|
||||
/// <param name="pts"></param>
|
||||
/// <returns></returns>
|
||||
public abstract bool Intersects(Polygon polygon, out List<Vector> pts);
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the given shape is intersecting this.
|
||||
/// </summary>
|
||||
/// <param name="shape"></param>
|
||||
/// <returns></returns>
|
||||
public abstract bool Intersects(Shape shape);
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the given shape is intersecting this.
|
||||
/// </summary>
|
||||
/// <param name="shape"></param>
|
||||
/// <param name="pts"></param>
|
||||
/// <returns></returns>
|
||||
public abstract bool Intersects(Shape shape, out List<Vector> pts);
|
||||
|
||||
/// <summary>
|
||||
/// Type of entity.
|
||||
/// </summary>
|
||||
public abstract EntityType Type { get; }
|
||||
}
|
||||
|
||||
public static class EntityExtensions
|
||||
{
|
||||
public static double FindBestRotation(this List<Entity> entities, double stepAngle, double startAngle = 0, double endAngle = Angle.TwoPI)
|
||||
{
|
||||
startAngle = Angle.NormalizeRad(startAngle);
|
||||
|
||||
if (!endAngle.IsEqualTo(Angle.TwoPI))
|
||||
endAngle = Angle.NormalizeRad(endAngle);
|
||||
|
||||
if (stepAngle.IsEqualTo(0.0))
|
||||
return startAngle;
|
||||
|
||||
entities.ForEach(e => e.Rotate(startAngle));
|
||||
|
||||
var bestAngle = startAngle;
|
||||
var bestArea = entities.GetBoundingBox().Area();
|
||||
|
||||
var steps = startAngle < endAngle
|
||||
? (endAngle - startAngle) / stepAngle
|
||||
: (endAngle + Angle.TwoPI) - startAngle / stepAngle;
|
||||
|
||||
for (int i = 1; i <= steps; ++i)
|
||||
{
|
||||
entities.ForEach(e => e.Rotate(stepAngle));
|
||||
|
||||
var area = entities.GetBoundingBox().Area();
|
||||
|
||||
if (area < bestArea)
|
||||
{
|
||||
bestArea = area;
|
||||
bestAngle = startAngle + stepAngle * i;
|
||||
}
|
||||
}
|
||||
|
||||
return bestAngle;
|
||||
}
|
||||
}
|
||||
}
|
||||
12
Source/OpenNest.Core/Geometry/EntityType.cs
Normal file
12
Source/OpenNest.Core/Geometry/EntityType.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
|
||||
namespace OpenNest.Geometry
|
||||
{
|
||||
public enum EntityType
|
||||
{
|
||||
Arc,
|
||||
Circle,
|
||||
Line,
|
||||
Shape,
|
||||
Polygon
|
||||
}
|
||||
}
|
||||
29
Source/OpenNest.Core/Geometry/Layer.cs
Normal file
29
Source/OpenNest.Core/Geometry/Layer.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
using System.Drawing;
|
||||
|
||||
namespace OpenNest.Geometry
|
||||
{
|
||||
public class Layer
|
||||
{
|
||||
public static readonly Layer Default = new Layer("0")
|
||||
{
|
||||
Color = Color.White,
|
||||
IsVisible = true
|
||||
};
|
||||
|
||||
public Layer(string name)
|
||||
{
|
||||
Name = name;
|
||||
}
|
||||
|
||||
public string Name { get; set; }
|
||||
|
||||
public bool IsVisible { get; set; }
|
||||
|
||||
public Color Color { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Name;
|
||||
}
|
||||
}
|
||||
}
|
||||
552
Source/OpenNest.Core/Geometry/Line.cs
Normal file
552
Source/OpenNest.Core/Geometry/Line.cs
Normal file
@@ -0,0 +1,552 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace OpenNest.Geometry
|
||||
{
|
||||
public class Line : Entity
|
||||
{
|
||||
private Vector pt1;
|
||||
private Vector pt2;
|
||||
|
||||
public Line()
|
||||
{
|
||||
}
|
||||
|
||||
public Line(double x1, double y1, double x2, double y2)
|
||||
: this(new Vector(x1, y1), new Vector(x2, y2))
|
||||
{
|
||||
}
|
||||
|
||||
public Line(Vector startPoint, Vector endPoint)
|
||||
{
|
||||
pt1 = startPoint;
|
||||
pt2 = endPoint;
|
||||
UpdateBounds();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start point of the line.
|
||||
/// </summary>
|
||||
public Vector StartPoint
|
||||
{
|
||||
get { return pt1; }
|
||||
set
|
||||
{
|
||||
pt1 = value;
|
||||
UpdateBounds();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Mid-point of the line.
|
||||
/// </summary>
|
||||
public Vector MidPoint
|
||||
{
|
||||
get
|
||||
{
|
||||
var x = (pt1.X + pt2.X) * 0.5;
|
||||
var y = (pt1.Y + pt2.Y) * 0.5;
|
||||
return new Vector(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// End point of the line.
|
||||
/// </summary>
|
||||
public Vector EndPoint
|
||||
{
|
||||
get { return pt2; }
|
||||
set
|
||||
{
|
||||
pt2 = value;
|
||||
UpdateBounds();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the point on the line that is perpendicular from the given point.
|
||||
/// </summary>
|
||||
/// <param name="pt"></param>
|
||||
/// <returns></returns>
|
||||
public Vector PointPerpendicularFrom(Vector pt)
|
||||
{
|
||||
var diff1 = pt - StartPoint;
|
||||
var diff2 = EndPoint - StartPoint;
|
||||
var dotProduct = diff1.X * diff2.X + diff1.Y * diff2.Y;
|
||||
var lengthSquared = diff2.X * diff2.X + diff2.Y * diff2.Y;
|
||||
var param = dotProduct / lengthSquared;
|
||||
|
||||
if (param < 0)
|
||||
return StartPoint;
|
||||
else if (param > 1)
|
||||
return EndPoint;
|
||||
else
|
||||
{
|
||||
return new Vector(
|
||||
StartPoint.X + param * diff2.X,
|
||||
StartPoint.Y + param * diff2.Y);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the given line is parallel to this.
|
||||
/// </summary>
|
||||
/// <param name="line"></param>
|
||||
/// <returns></returns>
|
||||
public bool IsParallelTo(Line line)
|
||||
{
|
||||
bool line1Vertical = IsVertical();
|
||||
bool line2Vertical = line.IsVertical();
|
||||
|
||||
if (line1Vertical)
|
||||
return line2Vertical;
|
||||
else if (line2Vertical)
|
||||
return false;
|
||||
|
||||
return Slope().IsEqualTo(line.Slope());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the given line is perpendicular to this.
|
||||
/// </summary>
|
||||
/// <param name="line"></param>
|
||||
/// <returns></returns>
|
||||
public bool IsPerpendicularTo(Line line)
|
||||
{
|
||||
bool line1Vertical = IsVertical();
|
||||
bool line2Vertical = line.IsVertical();
|
||||
|
||||
if (line1Vertical)
|
||||
return line.IsHorizontal();
|
||||
else if (line.IsVertical())
|
||||
return IsHorizontal();
|
||||
|
||||
return Slope().IsEqualTo(-1 / line.Slope());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the given line is intersecting this.
|
||||
/// </summary>
|
||||
/// <param name="line"></param>
|
||||
/// <param name="pt">Point of intersection.</param>
|
||||
/// <returns></returns>
|
||||
public bool Intersects(Line line, out Vector pt)
|
||||
{
|
||||
var a1 = EndPoint.Y - StartPoint.Y;
|
||||
var b1 = StartPoint.X - EndPoint.X;
|
||||
var c1 = a1 * StartPoint.X + b1 * StartPoint.Y;
|
||||
|
||||
var a2 = line.EndPoint.Y - line.StartPoint.Y;
|
||||
var b2 = line.StartPoint.X - line.EndPoint.X;
|
||||
var c2 = a2 * line.StartPoint.X + b2 * line.StartPoint.Y;
|
||||
|
||||
var d = a1 * b2 - a2 * b1;
|
||||
|
||||
if (d.IsEqualTo(0.0))
|
||||
{
|
||||
pt = new Vector();
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
var x = (b2 * c1 - b1 * c2) / d;
|
||||
var y = (a1 * c2 - a2 * c1) / d;
|
||||
|
||||
pt = new Vector(x, y);
|
||||
return boundingBox.Contains(pt) && line.boundingBox.Contains(pt);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if this is vertical.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public bool IsVertical()
|
||||
{
|
||||
return pt1.X.IsEqualTo(pt2.X);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if this is horizontal.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public bool IsHorizontal()
|
||||
{
|
||||
return pt1.Y.IsEqualTo(pt2.Y);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the given line is collinear to this.
|
||||
/// </summary>
|
||||
/// <param name="line"></param>
|
||||
/// <returns></returns>
|
||||
public bool IsCollinearTo(Line line)
|
||||
{
|
||||
if (IsVertical())
|
||||
{
|
||||
if (!line.IsVertical())
|
||||
return false;
|
||||
|
||||
return StartPoint.X.IsEqualTo(line.StartPoint.X);
|
||||
}
|
||||
else if (line.IsVertical())
|
||||
return false;
|
||||
|
||||
if (!YIntercept().IsEqualTo(line.YIntercept()))
|
||||
return false;
|
||||
|
||||
if (!Slope().IsEqualTo(line.Slope()))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Angle of the line from start point to end point.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public double Angle()
|
||||
{
|
||||
return StartPoint.AngleTo(EndPoint);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the angle between the two lines in radians.
|
||||
/// </summary>
|
||||
/// <param name="line"></param>
|
||||
/// <returns></returns>
|
||||
public double AngleBetween(Line line)
|
||||
{
|
||||
var m1 = Slope();
|
||||
var m2 = line.Slope();
|
||||
return Math.Atan(Math.Abs((m2 - m1) / (1 + m2 * m1)));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Slope of the line.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public double Slope()
|
||||
{
|
||||
if (IsVertical())
|
||||
throw new DivideByZeroException();
|
||||
|
||||
return (EndPoint.Y - StartPoint.Y) / (EndPoint.X - StartPoint.X);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the y-axis intersection coordinate.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public double YIntercept()
|
||||
{
|
||||
return StartPoint.Y - Slope() * StartPoint.X;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Length of the line from start point to end point.
|
||||
/// </summary>
|
||||
public override double Length
|
||||
{
|
||||
get
|
||||
{
|
||||
var x = EndPoint.X - StartPoint.X;
|
||||
var y = EndPoint.Y - StartPoint.Y;
|
||||
return Math.Sqrt(x * x + y * y);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reversed the line.
|
||||
/// </summary>
|
||||
public override void Reverse()
|
||||
{
|
||||
Generic.Swap<Vector>(ref pt1, ref pt2);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Moves the start point to the given coordinates.
|
||||
/// </summary>
|
||||
/// <param name="x"></param>
|
||||
/// <param name="y"></param>
|
||||
public override void MoveTo(double x, double y)
|
||||
{
|
||||
var xoffset = pt1.X - x;
|
||||
var yoffset = pt1.Y - y;
|
||||
|
||||
pt2.X += xoffset;
|
||||
pt2.Y += yoffset;
|
||||
pt1.X = x;
|
||||
pt1.Y = y;
|
||||
boundingBox.Offset(xoffset, yoffset);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Moves the start point to the given point.
|
||||
/// </summary>
|
||||
/// <param name="pt"></param>
|
||||
public override void MoveTo(Vector pt)
|
||||
{
|
||||
var offset = pt1 - pt;
|
||||
|
||||
pt2 += offset;
|
||||
pt1 = pt;
|
||||
boundingBox.Offset(offset);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Offsets the line location by the given distances.
|
||||
/// </summary>
|
||||
/// <param name="x"></param>
|
||||
/// <param name="y"></param>
|
||||
public override void Offset(double x, double y)
|
||||
{
|
||||
pt2.X += x;
|
||||
pt2.Y += y;
|
||||
pt1.X += x;
|
||||
pt1.Y += y;
|
||||
boundingBox.Offset(x, y);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Offsets the line location by the given distances.
|
||||
/// </summary>
|
||||
/// <param name="voffset"></param>
|
||||
public override void Offset(Vector voffset)
|
||||
{
|
||||
pt1 += voffset;
|
||||
pt2 += voffset;
|
||||
boundingBox.Offset(voffset);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Scales the line from the zero point.
|
||||
/// </summary>
|
||||
/// <param name="factor"></param>
|
||||
public override void Scale(double factor)
|
||||
{
|
||||
pt1 *= factor;
|
||||
pt2 *= factor;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Scales the line from the origin.
|
||||
/// </summary>
|
||||
/// <param name="factor"></param>
|
||||
/// <param name="origin"></param>
|
||||
public override void Scale(double factor, Vector origin)
|
||||
{
|
||||
pt1 = (pt1 - origin) * factor + origin;
|
||||
pt2 = (pt2 - origin) * factor + origin;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rotates the line from the zero point.
|
||||
/// </summary>
|
||||
/// <param name="angle"></param>
|
||||
public override void Rotate(double angle)
|
||||
{
|
||||
StartPoint = StartPoint.Rotate(angle);
|
||||
EndPoint = EndPoint.Rotate(angle);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rotates the line from the origin.
|
||||
/// </summary>
|
||||
/// <param name="angle"></param>
|
||||
/// <param name="origin"></param>
|
||||
public override void Rotate(double angle, Vector origin)
|
||||
{
|
||||
StartPoint = StartPoint.Rotate(angle, origin);
|
||||
EndPoint = EndPoint.Rotate(angle, origin);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the bounding box.
|
||||
/// </summary>
|
||||
public override sealed void UpdateBounds()
|
||||
{
|
||||
if (StartPoint.X < EndPoint.X)
|
||||
{
|
||||
boundingBox.X = StartPoint.X;
|
||||
boundingBox.Width = EndPoint.X - StartPoint.X;
|
||||
}
|
||||
else
|
||||
{
|
||||
boundingBox.X = EndPoint.X;
|
||||
boundingBox.Width = StartPoint.X - EndPoint.X;
|
||||
}
|
||||
|
||||
if (StartPoint.Y < EndPoint.Y)
|
||||
{
|
||||
boundingBox.Y = StartPoint.Y;
|
||||
boundingBox.Height = EndPoint.Y - StartPoint.Y;
|
||||
}
|
||||
else
|
||||
{
|
||||
boundingBox.Y = EndPoint.Y;
|
||||
boundingBox.Height = StartPoint.Y - EndPoint.Y;
|
||||
}
|
||||
}
|
||||
|
||||
public override Entity OffsetEntity(double distance, OffsetSide side)
|
||||
{
|
||||
var angle = OpenNest.Angle.NormalizeRad(Angle() + OpenNest.Angle.HalfPI);
|
||||
|
||||
var x = Math.Cos(angle) * distance;
|
||||
var y = Math.Sin(angle) * distance;
|
||||
|
||||
var pt = new Vector(x, y);
|
||||
|
||||
return side == OffsetSide.Left
|
||||
? new Line(StartPoint + pt, EndPoint + pt)
|
||||
: new Line(EndPoint + pt, StartPoint + pt);
|
||||
}
|
||||
|
||||
public override Entity OffsetEntity(double distance, Vector pt)
|
||||
{
|
||||
var a = pt - StartPoint;
|
||||
var b = EndPoint - StartPoint;
|
||||
var c = a.DotProduct(b);
|
||||
var side = c < 0 ? OffsetSide.Left : OffsetSide.Right;
|
||||
|
||||
return OffsetEntity(distance, side);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the closest point on the line to the given point.
|
||||
/// </summary>
|
||||
/// <param name="pt"></param>
|
||||
/// <returns></returns>
|
||||
public override Vector ClosestPointTo(Vector pt)
|
||||
{
|
||||
var perpendicularPt = PointPerpendicularFrom(pt);
|
||||
|
||||
if (BoundingBox.Contains(perpendicularPt))
|
||||
return perpendicularPt;
|
||||
else
|
||||
return pt.DistanceTo(StartPoint) <= pt.DistanceTo(EndPoint) ? StartPoint : EndPoint;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the given arc is intersecting this.
|
||||
/// </summary>
|
||||
/// <param name="arc"></param>
|
||||
/// <returns></returns>
|
||||
public override bool Intersects(Arc arc)
|
||||
{
|
||||
List<Vector> pts;
|
||||
return Helper.Intersects(arc, this, out pts);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the given arc is intersecting this.
|
||||
/// </summary>
|
||||
/// <param name="arc"></param>
|
||||
/// <param name="pts"></param>
|
||||
/// <returns></returns>
|
||||
public override bool Intersects(Arc arc, out List<Vector> pts)
|
||||
{
|
||||
return Helper.Intersects(arc, this, out pts);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the given circle is intersecting this.
|
||||
/// </summary>
|
||||
/// <param name="circle"></param>
|
||||
/// <returns></returns>
|
||||
public override bool Intersects(Circle circle)
|
||||
{
|
||||
List<Vector> pts;
|
||||
return Helper.Intersects(circle, this, out pts);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the given circle is intersecting this.
|
||||
/// </summary>
|
||||
/// <param name="circle"></param>
|
||||
/// <param name="pts"></param>
|
||||
/// <returns></returns>
|
||||
public override bool Intersects(Circle circle, out List<Vector> pts)
|
||||
{
|
||||
return Helper.Intersects(circle, this, out pts);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the given line is intersecting this.
|
||||
/// </summary>
|
||||
/// <param name="line"></param>
|
||||
/// <returns></returns>
|
||||
public override bool Intersects(Line line)
|
||||
{
|
||||
Vector pt;
|
||||
return Intersects(line, out pt);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the given line is intersecting this.
|
||||
/// </summary>
|
||||
/// <param name="line"></param>
|
||||
/// <param name="pts"></param>
|
||||
/// <returns></returns>
|
||||
public override bool Intersects(Line line, out List<Vector> pts)
|
||||
{
|
||||
Vector pt;
|
||||
var success = Helper.Intersects(this, line, out pt);
|
||||
pts = new List<Vector>(new[] { pt });
|
||||
return success;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the given polygon is intersecting this.
|
||||
/// </summary>
|
||||
/// <param name="polygon"></param>
|
||||
/// <returns></returns>
|
||||
public override bool Intersects(Polygon polygon)
|
||||
{
|
||||
List<Vector> pts;
|
||||
return Helper.Intersects(this, polygon, out pts);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the given polygon is intersecting this.
|
||||
/// </summary>
|
||||
/// <param name="polygon"></param>
|
||||
/// <param name="pts"></param>
|
||||
/// <returns></returns>
|
||||
public override bool Intersects(Polygon polygon, out List<Vector> pts)
|
||||
{
|
||||
return Helper.Intersects(this, polygon, out pts);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the given shape is intersecting this.
|
||||
/// </summary>
|
||||
/// <param name="shape"></param>
|
||||
/// <returns></returns>
|
||||
public override bool Intersects(Shape shape)
|
||||
{
|
||||
List<Vector> pts;
|
||||
return Helper.Intersects(this, shape, out pts);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the given shape is intersecting this.
|
||||
/// </summary>
|
||||
/// <param name="shape"></param>
|
||||
/// <param name="pts"></param>
|
||||
/// <returns></returns>
|
||||
public override bool Intersects(Shape shape, out List<Vector> pts)
|
||||
{
|
||||
return Helper.Intersects(this, shape, out pts);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Type of entity.
|
||||
/// </summary>
|
||||
public override EntityType Type
|
||||
{
|
||||
get { return EntityType.Line; }
|
||||
}
|
||||
}
|
||||
}
|
||||
500
Source/OpenNest.Core/Geometry/Polygon.cs
Normal file
500
Source/OpenNest.Core/Geometry/Polygon.cs
Normal file
@@ -0,0 +1,500 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace OpenNest.Geometry
|
||||
{
|
||||
public class Polygon : Entity
|
||||
{
|
||||
public List<Vector> Vertices;
|
||||
|
||||
public Polygon()
|
||||
{
|
||||
Vertices = new List<Vector>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Closes the polygon if it's not already.
|
||||
/// </summary>
|
||||
public void Close()
|
||||
{
|
||||
if (Vertices.Count < 3)
|
||||
return;
|
||||
|
||||
var first = Vertices.First();
|
||||
var last = Vertices.Last();
|
||||
|
||||
if (first != last)
|
||||
Vertices.Add(first);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the polygon is closed.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public bool IsClosed()
|
||||
{
|
||||
if (Vertices.Count < 3)
|
||||
return false;
|
||||
|
||||
return (Vertices.First() == Vertices.Last());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the polygon is self intersecting.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public bool IsComplex()
|
||||
{
|
||||
var lines = ToLines();
|
||||
|
||||
for (int i = 0; i < lines.Count; ++i)
|
||||
{
|
||||
var line1 = lines[i];
|
||||
|
||||
for (int j = i; j < lines.Count; ++j)
|
||||
{
|
||||
var line2 = lines[j];
|
||||
|
||||
if (line1.Intersects(line2))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Area of the polygon.
|
||||
/// </summary>
|
||||
/// <returns>Returns the area or 0 if the polygon is NOT closed.</returns>
|
||||
public double Area()
|
||||
{
|
||||
if (Vertices.Count < 3)
|
||||
return 0.0;
|
||||
|
||||
return Math.Abs(CalculateArea());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Distance around the polygon.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public double Perimeter()
|
||||
{
|
||||
if (Vertices.Count < 3)
|
||||
return 0.0;
|
||||
|
||||
double sum = 0.0;
|
||||
|
||||
var last = Vertices[0];
|
||||
|
||||
for (int i = 1; i < Vertices.Count; ++i)
|
||||
{
|
||||
var current = Vertices[i];
|
||||
sum += last.DistanceTo(current);
|
||||
last = current;
|
||||
}
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the rotation direction of the polygon.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public RotationType RotationDirection()
|
||||
{
|
||||
if (Vertices.Count < 3)
|
||||
throw new Exception("Not enough points to determine direction. Must have at least 3 points.");
|
||||
|
||||
return CalculateArea() > 0 ? RotationType.CCW : RotationType.CW;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts the polygon to a group of lines.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public List<Line> ToLines()
|
||||
{
|
||||
var list = new List<Line>();
|
||||
|
||||
if (Vertices.Count < 2)
|
||||
return list;
|
||||
|
||||
var last = Vertices[0];
|
||||
|
||||
for (int i = 1; i < Vertices.Count; ++i)
|
||||
{
|
||||
var current = Vertices[i];
|
||||
list.Add(new Line(last, current));
|
||||
last = current;
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the area of the polygon.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// Returns the area of the polygon.
|
||||
/// * Positive number = counter-clockwise rotation
|
||||
/// * Negative number = clockwise rotation
|
||||
/// </returns>
|
||||
private double CalculateArea()
|
||||
{
|
||||
double xsum = 0;
|
||||
double ysum = 0;
|
||||
|
||||
for (int i = 0; i < Vertices.Count - 1; ++i)
|
||||
{
|
||||
var current = Vertices[i];
|
||||
var next = Vertices[i + 1];
|
||||
|
||||
xsum += current.X * next.Y;
|
||||
ysum += current.Y * next.X;
|
||||
}
|
||||
|
||||
return (xsum - ysum) * 0.5;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Distance around the polygon.
|
||||
/// </summary>
|
||||
public override double Length
|
||||
{
|
||||
get { return Perimeter(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reverses the rotation direction of the polygon.
|
||||
/// </summary>
|
||||
public override void Reverse()
|
||||
{
|
||||
Vertices.Reverse();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Moves the start point to the given coordinates.
|
||||
/// </summary>
|
||||
/// <param name="x"></param>
|
||||
/// <param name="y"></param>
|
||||
public override void MoveTo(double x, double y)
|
||||
{
|
||||
if (Vertices.Count == 0)
|
||||
return;
|
||||
|
||||
var first = Vertices[0];
|
||||
var offset = new Vector(x - first.X, y - first.Y);
|
||||
|
||||
Vertices.ForEach(vertex => vertex += offset);
|
||||
boundingBox.Offset(offset);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Moves the start point to the given point.
|
||||
/// </summary>
|
||||
/// <param name="pt"></param>
|
||||
public override void MoveTo(Vector pt)
|
||||
{
|
||||
if (Vertices.Count == 0)
|
||||
return;
|
||||
|
||||
var first = Vertices[0];
|
||||
var offset = pt - first;
|
||||
|
||||
Vertices.ForEach(vertex => vertex += offset);
|
||||
boundingBox.Offset(offset);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Offsets the location by the given distances.
|
||||
/// </summary>
|
||||
/// <param name="x"></param>
|
||||
/// <param name="y"></param>
|
||||
public override void Offset(double x, double y)
|
||||
{
|
||||
for (int i = 0; i < Vertices.Count; i++)
|
||||
Vertices[i] = Vertices[i].Offset(x, y);
|
||||
|
||||
boundingBox.Offset(x, y);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Offsets the location by the given distances.
|
||||
/// </summary>
|
||||
/// <param name="voffset"></param>
|
||||
public override void Offset(Vector voffset)
|
||||
{
|
||||
for (int i = 0; i < Vertices.Count; i++)
|
||||
Vertices[i] = Vertices[i].Offset(voffset);
|
||||
|
||||
boundingBox.Offset(voffset);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Scales the polygon from the zero point.
|
||||
/// </summary>
|
||||
/// <param name="factor"></param>
|
||||
public override void Scale(double factor)
|
||||
{
|
||||
for (int i = 0; i < Vertices.Count; i++)
|
||||
Vertices[i] *= factor;
|
||||
|
||||
UpdateBounds();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Scales the polygon from the zero point.
|
||||
/// </summary>
|
||||
/// <param name="factor"></param>
|
||||
/// <param name="origin"></param>
|
||||
public override void Scale(double factor, Vector origin)
|
||||
{
|
||||
for (int i = 0; i < Vertices.Count; i++)
|
||||
Vertices[i] = (Vertices[i] - origin) * factor + origin;
|
||||
|
||||
UpdateBounds();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rotates the polygon from the zero point.
|
||||
/// </summary>
|
||||
/// <param name="angle"></param>
|
||||
public override void Rotate(double angle)
|
||||
{
|
||||
for (int i = 0; i < Vertices.Count; i++)
|
||||
Vertices[i] = Vertices[i].Rotate(angle);
|
||||
|
||||
UpdateBounds();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rotates the polygon from the origin.
|
||||
/// </summary>
|
||||
/// <param name="angle"></param>
|
||||
/// <param name="origin"></param>
|
||||
public override void Rotate(double angle, Vector origin)
|
||||
{
|
||||
for (int i = 0; i < Vertices.Count; i++)
|
||||
Vertices[i] = Vertices[i].Rotate(angle, origin);
|
||||
|
||||
UpdateBounds();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the bounding box.
|
||||
/// </summary>
|
||||
public override void UpdateBounds()
|
||||
{
|
||||
if (Vertices.Count == 0)
|
||||
return;
|
||||
|
||||
var first = Vertices[0];
|
||||
var minX = first.X;
|
||||
var maxX = first.X;
|
||||
var minY = first.Y;
|
||||
var maxY = first.Y;
|
||||
|
||||
for (int i = 1; i < Vertices.Count; ++i)
|
||||
{
|
||||
var vertex = Vertices[i];
|
||||
|
||||
if (vertex.X < minX) minX = vertex.X;
|
||||
else if (vertex.X > maxX) maxX = vertex.X;
|
||||
|
||||
if (vertex.Y < minY) minY = vertex.Y;
|
||||
else if (vertex.Y > maxY) maxY = vertex.Y;
|
||||
}
|
||||
|
||||
boundingBox.X = minX;
|
||||
boundingBox.Y = minY;
|
||||
boundingBox.Width = maxX - minX;
|
||||
boundingBox.Height = maxY - minY;
|
||||
}
|
||||
|
||||
public override Entity OffsetEntity(double distance, OffsetSide side)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override Entity OffsetEntity(double distance, Vector pt)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the closest point on the polygon to the given point.
|
||||
/// </summary>
|
||||
/// <param name="pt"></param>
|
||||
/// <returns></returns>
|
||||
public override Vector ClosestPointTo(Vector pt)
|
||||
{
|
||||
var lines = ToLines();
|
||||
|
||||
if (lines.Count == 0)
|
||||
return Vector.Invalid;
|
||||
|
||||
Vector closestPt = lines[0].ClosestPointTo(pt);
|
||||
double distance = closestPt.DistanceTo(pt);
|
||||
|
||||
for (int i = 1; i < lines.Count; i++)
|
||||
{
|
||||
var line = lines[i];
|
||||
var closestPt2 = line.ClosestPointTo(pt);
|
||||
var distance2 = closestPt2.DistanceTo(pt);
|
||||
|
||||
if (distance2 < distance)
|
||||
{
|
||||
closestPt = closestPt2;
|
||||
distance = distance2;
|
||||
}
|
||||
}
|
||||
|
||||
return closestPt;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the given arc is intersecting this.
|
||||
/// </summary>
|
||||
/// <param name="arc"></param>
|
||||
/// <returns></returns>
|
||||
public override bool Intersects(Arc arc)
|
||||
{
|
||||
List<Vector> pts;
|
||||
return Helper.Intersects(arc, this, out pts);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the given arc is intersecting this.
|
||||
/// </summary>
|
||||
/// <param name="arc"></param>
|
||||
/// <param name="pts"></param>
|
||||
/// <returns></returns>
|
||||
public override bool Intersects(Arc arc, out List<Vector> pts)
|
||||
{
|
||||
return Helper.Intersects(arc, this, out pts);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the given circle is intersecting this.
|
||||
/// </summary>
|
||||
/// <param name="circle"></param>
|
||||
/// <returns></returns>
|
||||
public override bool Intersects(Circle circle)
|
||||
{
|
||||
List<Vector> pts;
|
||||
return Helper.Intersects(circle, this, out pts);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the given circle is intersecting this.
|
||||
/// </summary>
|
||||
/// <param name="circle"></param>
|
||||
/// <param name="pts"></param>
|
||||
/// <returns></returns>
|
||||
public override bool Intersects(Circle circle, out List<Vector> pts)
|
||||
{
|
||||
return Helper.Intersects(circle, this, out pts);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the given line is intersecting this.
|
||||
/// </summary>
|
||||
/// <param name="line"></param>
|
||||
/// <returns></returns>
|
||||
public override bool Intersects(Line line)
|
||||
{
|
||||
List<Vector> pts;
|
||||
return Helper.Intersects(line, this, out pts);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the given line is intersecting this.
|
||||
/// </summary>
|
||||
/// <param name="line"></param>
|
||||
/// <param name="pts"></param>
|
||||
/// <returns></returns>
|
||||
public override bool Intersects(Line line, out List<Vector> pts)
|
||||
{
|
||||
return Helper.Intersects(line, this, out pts);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the given polygon is intersecting this.
|
||||
/// </summary>
|
||||
/// <param name="polygon"></param>
|
||||
/// <returns></returns>
|
||||
public override bool Intersects(Polygon polygon)
|
||||
{
|
||||
List<Vector> pts;
|
||||
return Helper.Intersects(this, polygon, out pts);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the given polygon is intersecting this.
|
||||
/// </summary>
|
||||
/// <param name="polygon"></param>
|
||||
/// <param name="pts"></param>
|
||||
/// <returns></returns>
|
||||
public override bool Intersects(Polygon polygon, out List<Vector> pts)
|
||||
{
|
||||
return Helper.Intersects(this, polygon, out pts);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the given shape is intersecting this.
|
||||
/// </summary>
|
||||
/// <param name="shape"></param>
|
||||
/// <returns></returns>
|
||||
public override bool Intersects(Shape shape)
|
||||
{
|
||||
List<Vector> pts;
|
||||
return Helper.Intersects(shape, this, out pts);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the given shape is intersecting this.
|
||||
/// </summary>
|
||||
/// <param name="shape"></param>
|
||||
/// <param name="pts"></param>
|
||||
/// <returns></returns>
|
||||
public override bool Intersects(Shape shape, out List<Vector> pts)
|
||||
{
|
||||
return Helper.Intersects(shape, this, out pts);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Type of entity.
|
||||
/// </summary>
|
||||
public override EntityType Type
|
||||
{
|
||||
get { return EntityType.Polygon; }
|
||||
}
|
||||
|
||||
internal void Cleanup()
|
||||
{
|
||||
for (int i = Vertices.Count - 1; i > 0; i--)
|
||||
{
|
||||
var vertex = Vertices[i];
|
||||
var nextVertex = Vertices[i - 1];
|
||||
|
||||
if (vertex == nextVertex)
|
||||
Vertices.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
|
||||
public double FindBestRotation(double stepAngle)
|
||||
{
|
||||
var entities = new List<Entity>(ToLines());
|
||||
return entities.FindBestRotation(stepAngle);
|
||||
}
|
||||
|
||||
public double FindBestRotation(double stepAngle, double startAngle, double endAngle)
|
||||
{
|
||||
var entities = new List<Entity>(ToLines());
|
||||
return entities.FindBestRotation(stepAngle, startAngle, endAngle);
|
||||
}
|
||||
}
|
||||
}
|
||||
569
Source/OpenNest.Core/Geometry/Shape.cs
Normal file
569
Source/OpenNest.Core/Geometry/Shape.cs
Normal file
@@ -0,0 +1,569 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
|
||||
namespace OpenNest.Geometry
|
||||
{
|
||||
public class Shape : Entity
|
||||
{
|
||||
/// <summary>
|
||||
/// Entities that make up the shape.
|
||||
/// </summary>
|
||||
public List<Entity> Entities;
|
||||
|
||||
public Shape()
|
||||
{
|
||||
Entities = new List<Entity>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the shape is closed.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public bool IsClosed()
|
||||
{
|
||||
if (Entities.Count == 0)
|
||||
return false;
|
||||
|
||||
var first = Entities[0];
|
||||
Vector firstStartPoint;
|
||||
Vector firstEndPoint;
|
||||
|
||||
switch (first.Type)
|
||||
{
|
||||
case EntityType.Arc:
|
||||
var arc = (Arc)first;
|
||||
firstStartPoint = arc.StartPoint();
|
||||
firstEndPoint = arc.EndPoint();
|
||||
break;
|
||||
|
||||
case EntityType.Circle:
|
||||
return Entities.Count == 1;
|
||||
|
||||
case EntityType.Line:
|
||||
var line = (Line)first;
|
||||
firstStartPoint = line.StartPoint;
|
||||
firstEndPoint = line.EndPoint;
|
||||
break;
|
||||
|
||||
default:
|
||||
Debug.Fail("Unhandled geometry type");
|
||||
return false;
|
||||
}
|
||||
|
||||
var endpt = firstEndPoint;
|
||||
|
||||
Entity geo = null;
|
||||
|
||||
for (int i = 1; i < Entities.Count; ++i)
|
||||
{
|
||||
geo = Entities[i];
|
||||
|
||||
switch (geo.Type)
|
||||
{
|
||||
case EntityType.Arc:
|
||||
var arc = (Arc)geo;
|
||||
|
||||
if (arc.StartPoint() != endpt)
|
||||
return false;
|
||||
|
||||
endpt = arc.EndPoint();
|
||||
break;
|
||||
|
||||
case EntityType.Circle:
|
||||
return Entities.Count == 1;
|
||||
|
||||
case EntityType.Line:
|
||||
var line = (Line)geo;
|
||||
|
||||
if (line.StartPoint != endpt)
|
||||
return false;
|
||||
|
||||
endpt = line.EndPoint;
|
||||
break;
|
||||
|
||||
default:
|
||||
Debug.Fail("Unhandled geometry type");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (geo == null)
|
||||
return false;
|
||||
|
||||
var last = geo;
|
||||
Vector lastEndPoint;
|
||||
|
||||
switch (last.Type)
|
||||
{
|
||||
case EntityType.Arc:
|
||||
var arc = (Arc)last;
|
||||
lastEndPoint = arc.EndPoint();
|
||||
break;
|
||||
|
||||
case EntityType.Line:
|
||||
var line = (Line)last;
|
||||
lastEndPoint = line.EndPoint;
|
||||
break;
|
||||
|
||||
default:
|
||||
Debug.Fail("Unhandled geometry type");
|
||||
return false;
|
||||
}
|
||||
|
||||
return lastEndPoint == firstStartPoint;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the area.
|
||||
/// </summary>
|
||||
/// <returns>Returns the area or 0 if the shape is NOT closed.</returns>
|
||||
public double Area()
|
||||
{
|
||||
// Check if the shape is closed so we can get the area.
|
||||
if (!IsClosed())
|
||||
return 0;
|
||||
|
||||
// If the shape is closed and only one entity in the geometry
|
||||
// then that entity would have to be a circle.
|
||||
if (Entities.Count == 1)
|
||||
{
|
||||
var circle = Entities[0] as Circle;
|
||||
return circle == null ? 0 : circle.Area();
|
||||
}
|
||||
|
||||
return ToPolygon().Area();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Joins all overlapping lines and arcs.
|
||||
/// </summary>
|
||||
public void Optimize()
|
||||
{
|
||||
var lines = new List<Line>();
|
||||
var arcs = new List<Arc>();
|
||||
|
||||
foreach (var geo in Entities)
|
||||
{
|
||||
switch (geo.Type)
|
||||
{
|
||||
case EntityType.Arc:
|
||||
arcs.Add((Arc)geo);
|
||||
break;
|
||||
|
||||
case EntityType.Line:
|
||||
lines.Add((Line)geo);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Helper.Optimize(lines);
|
||||
Helper.Optimize(arcs);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the closest point on the shape to the given point.
|
||||
/// </summary>
|
||||
/// <param name="pt"></param>
|
||||
/// <param name="entity">Entity that contains the point.</param>
|
||||
/// <returns></returns>
|
||||
public Vector ClosestPointTo(Vector pt, out Entity entity)
|
||||
{
|
||||
if (Entities.Count == 0)
|
||||
{
|
||||
entity = null;
|
||||
return Vector.Invalid;
|
||||
}
|
||||
|
||||
var first = Entities[0];
|
||||
|
||||
Vector closestPt = first.ClosestPointTo(pt);
|
||||
double distance = closestPt.DistanceTo(pt);
|
||||
|
||||
entity = first;
|
||||
|
||||
for (int i = 1; i < Entities.Count; i++)
|
||||
{
|
||||
var entity2 = Entities[i];
|
||||
var closestPt2 = entity2.ClosestPointTo(pt);
|
||||
var distance2 = closestPt2.DistanceTo(pt);
|
||||
|
||||
if (distance2 < distance)
|
||||
{
|
||||
closestPt = closestPt2;
|
||||
distance = distance2;
|
||||
entity = entity2;
|
||||
}
|
||||
}
|
||||
|
||||
return closestPt;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts the shape to a polygon.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public Polygon ToPolygon(int arcSegments = 1000)
|
||||
{
|
||||
var polygon = new Polygon();
|
||||
|
||||
foreach (var entity in Entities)
|
||||
{
|
||||
switch (entity.Type)
|
||||
{
|
||||
case EntityType.Arc:
|
||||
var arc = (Arc)entity;
|
||||
polygon.Vertices.AddRange(arc.ToPoints(arcSegments));
|
||||
break;
|
||||
|
||||
case EntityType.Line:
|
||||
var line = (Line)entity;
|
||||
polygon.Vertices.AddRange(new[]
|
||||
{
|
||||
line.StartPoint,
|
||||
line.EndPoint
|
||||
});
|
||||
break;
|
||||
|
||||
case EntityType.Circle:
|
||||
var circle = (Circle)entity;
|
||||
polygon.Vertices.AddRange(circle.ToPoints(arcSegments));
|
||||
break;
|
||||
|
||||
default:
|
||||
Debug.Fail("Unhandled geometry type");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
polygon.Close();
|
||||
polygon.Cleanup();
|
||||
|
||||
return polygon;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reverses the rotation direction of the shape.
|
||||
/// </summary>
|
||||
public override void Reverse()
|
||||
{
|
||||
Entities.ForEach(e => e.Reverse());
|
||||
Entities.Reverse();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Linear distance of the shape.
|
||||
/// </summary>
|
||||
public override double Length
|
||||
{
|
||||
get { return Entities.Sum(geo => geo.Length); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Moves the start point to the given coordinates.
|
||||
/// </summary>
|
||||
/// <param name="x"></param>
|
||||
/// <param name="y"></param>
|
||||
public override void MoveTo(double x, double y)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Moves the start point to the given point.
|
||||
/// </summary>
|
||||
/// <param name="pt"></param>
|
||||
public override void MoveTo(Vector pt)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Offsets the shape location by the given distances.
|
||||
/// </summary>
|
||||
/// <param name="x"></param>
|
||||
/// <param name="y"></param>
|
||||
public override void Offset(double x, double y)
|
||||
{
|
||||
Entities.ForEach(e => e.Offset(x, y));
|
||||
boundingBox.Offset(x, y);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Offsets the shape location by the given distances.
|
||||
/// </summary>
|
||||
/// <param name="voffset"></param>
|
||||
public override void Offset(Vector voffset)
|
||||
{
|
||||
Entities.ForEach(e => e.Offset(voffset));
|
||||
boundingBox.Offset(voffset);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Scales the shape from the zero point.
|
||||
/// </summary>
|
||||
/// <param name="factor"></param>
|
||||
public override void Scale(double factor)
|
||||
{
|
||||
Entities.ForEach(e => e.Scale(factor));
|
||||
UpdateBounds();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Scales the shape from the origin.
|
||||
/// </summary>
|
||||
/// <param name="factor"></param>
|
||||
/// <param name="origin"></param>
|
||||
public override void Scale(double factor, Vector origin)
|
||||
{
|
||||
Entities.ForEach(e => e.Scale(factor, origin));
|
||||
UpdateBounds();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rotates the shape from the zero point.
|
||||
/// </summary>
|
||||
/// <param name="angle"></param>
|
||||
public override void Rotate(double angle)
|
||||
{
|
||||
Entities.ForEach(e => e.Rotate(angle));
|
||||
UpdateBounds();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rotates the shape from the origin.
|
||||
/// </summary>
|
||||
/// <param name="angle"></param>
|
||||
/// <param name="origin"></param>
|
||||
public override void Rotate(double angle, Vector origin)
|
||||
{
|
||||
Entities.ForEach(e => e.Rotate(angle, origin));
|
||||
UpdateBounds();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the bounding box.
|
||||
/// </summary>
|
||||
public override void UpdateBounds()
|
||||
{
|
||||
boundingBox = Entities.Select(geo => geo.BoundingBox)
|
||||
.ToList()
|
||||
.GetBoundingBox();
|
||||
}
|
||||
|
||||
public override Entity OffsetEntity(double distance, OffsetSide side)
|
||||
{
|
||||
var offsetShape = new Shape();
|
||||
var definedShape = new DefinedShape(this);
|
||||
|
||||
Entity lastEntity = null;
|
||||
Entity lastOffsetEntity = null;
|
||||
|
||||
foreach (var entity in definedShape.Perimeter.Entities)
|
||||
{
|
||||
var offsetEntity = entity.OffsetEntity(distance, side);
|
||||
|
||||
if (offsetEntity == null)
|
||||
continue;
|
||||
|
||||
switch (entity.Type)
|
||||
{
|
||||
case EntityType.Line:
|
||||
{
|
||||
var line = (Line)entity;
|
||||
var offsetLine = (Line)offsetEntity;
|
||||
|
||||
if (lastOffsetEntity != null && lastOffsetEntity.Type == EntityType.Line)
|
||||
{
|
||||
var lastLine = lastEntity as Line;
|
||||
var lastOffsetLine = lastOffsetEntity as Line;
|
||||
|
||||
if (lastLine == null || lastOffsetLine == null)
|
||||
continue;
|
||||
|
||||
Vector intersection;
|
||||
|
||||
if (Helper.Intersects(offsetLine, lastOffsetLine, out intersection))
|
||||
{
|
||||
offsetLine.StartPoint = intersection;
|
||||
lastOffsetLine.EndPoint = intersection;
|
||||
}
|
||||
else
|
||||
{
|
||||
var arc = new Arc(
|
||||
line.StartPoint,
|
||||
distance,
|
||||
line.StartPoint.AngleTo(lastOffsetLine.EndPoint),
|
||||
line.StartPoint.AngleTo(offsetLine.StartPoint),
|
||||
side == OffsetSide.Left
|
||||
);
|
||||
|
||||
offsetShape.Entities.Add(arc);
|
||||
}
|
||||
}
|
||||
|
||||
offsetShape.Entities.Add(offsetLine);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
offsetShape.Entities.Add(offsetEntity);
|
||||
break;
|
||||
}
|
||||
|
||||
lastOffsetEntity = offsetEntity;
|
||||
lastEntity = entity;
|
||||
}
|
||||
|
||||
foreach (var cutout in definedShape.Cutouts)
|
||||
offsetShape.Entities.AddRange(((Shape)cutout.OffsetEntity(distance, side)).Entities);
|
||||
|
||||
return offsetShape;
|
||||
}
|
||||
|
||||
public override Entity OffsetEntity(double distance, Vector pt)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the closest point on the shape to the given point.
|
||||
/// </summary>
|
||||
/// <param name="pt"></param>
|
||||
/// <returns></returns>
|
||||
public override Vector ClosestPointTo(Vector pt)
|
||||
{
|
||||
Entity entity;
|
||||
return ClosestPointTo(pt, out entity);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the given arc is intersecting this.
|
||||
/// </summary>
|
||||
/// <param name="arc"></param>
|
||||
/// <returns></returns>
|
||||
public override bool Intersects(Arc arc)
|
||||
{
|
||||
List<Vector> pts;
|
||||
return Helper.Intersects(arc, this, out pts);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the given arc is intersecting this.
|
||||
/// </summary>
|
||||
/// <param name="arc"></param>
|
||||
/// <param name="pts"></param>
|
||||
/// <returns></returns>
|
||||
public override bool Intersects(Arc arc, out List<Vector> pts)
|
||||
{
|
||||
return Helper.Intersects(arc, this, out pts);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the given circle is intersecting this.
|
||||
/// </summary>
|
||||
/// <param name="circle"></param>
|
||||
/// <returns></returns>
|
||||
public override bool Intersects(Circle circle)
|
||||
{
|
||||
List<Vector> pts;
|
||||
return Helper.Intersects(circle, this, out pts);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the given circle is intersecting this.
|
||||
/// </summary>
|
||||
/// <param name="circle"></param>
|
||||
/// <param name="pts"></param>
|
||||
/// <returns></returns>
|
||||
public override bool Intersects(Circle circle, out List<Vector> pts)
|
||||
{
|
||||
return Helper.Intersects(circle, this, out pts);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the given line is intersecting this.
|
||||
/// </summary>
|
||||
/// <param name="line"></param>
|
||||
/// <returns></returns>
|
||||
public override bool Intersects(Line line)
|
||||
{
|
||||
List<Vector> pts;
|
||||
return Helper.Intersects(line, this, out pts);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the given line is intersecting this.
|
||||
/// </summary>
|
||||
/// <param name="line"></param>
|
||||
/// <param name="pts"></param>
|
||||
/// <returns></returns>
|
||||
public override bool Intersects(Line line, out List<Vector> pts)
|
||||
{
|
||||
return Helper.Intersects(line, this, out pts);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the given polygon is intersecting this.
|
||||
/// </summary>
|
||||
/// <param name="polygon"></param>
|
||||
/// <returns></returns>
|
||||
public override bool Intersects(Polygon polygon)
|
||||
{
|
||||
List<Vector> pts;
|
||||
return Helper.Intersects(this, polygon, out pts);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the given polygon is intersecting this.
|
||||
/// </summary>
|
||||
/// <param name="polygon"></param>
|
||||
/// <param name="pts"></param>
|
||||
/// <returns></returns>
|
||||
public override bool Intersects(Polygon polygon, out List<Vector> pts)
|
||||
{
|
||||
return Helper.Intersects(this, polygon, out pts);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the given shape is intersecting this.
|
||||
/// </summary>
|
||||
/// <param name="shape"></param>
|
||||
/// <returns></returns>
|
||||
public override bool Intersects(Shape shape)
|
||||
{
|
||||
List<Vector> pts;
|
||||
return Helper.Intersects(this, shape, out pts);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the given shape is intersecting this.
|
||||
/// </summary>
|
||||
/// <param name="shape"></param>
|
||||
/// <param name="pts"></param>
|
||||
/// <returns></returns>
|
||||
public override bool Intersects(Shape shape, out List<Vector> pts)
|
||||
{
|
||||
return Helper.Intersects(this, shape, out pts);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Type of entity.
|
||||
/// </summary>
|
||||
public override EntityType Type
|
||||
{
|
||||
get { return EntityType.Shape; }
|
||||
}
|
||||
|
||||
public double FindBestRotation(double stepAngle)
|
||||
{
|
||||
return Entities.FindBestRotation(stepAngle);
|
||||
}
|
||||
|
||||
public double FindBestRotation(double stepAngle, double startAngle, double endAngle)
|
||||
{
|
||||
return Entities.FindBestRotation(stepAngle, startAngle, endAngle);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user