using System.Collections.Generic;
using OpenNest.Math;
namespace OpenNest.Geometry
{
public abstract class Entity : IBoundable
{
protected Box boundingBox;
protected Entity()
{
Layer = OpenNest.Geometry.Layer.Default;
boundingBox = new Box();
}
///
/// Smallest box that contains the entity.
///
public Box BoundingBox
{
get { return boundingBox; }
}
///
/// Entity layer type.
///
public Layer Layer { get; set; }
///
/// X-Coordinate of the left-most point.
///
public virtual double Left
{
get { return boundingBox.Left; }
}
///
/// X-Coordinate of the right-most point.
///
public virtual double Right
{
get { return boundingBox.Right; }
}
///
/// Y-Coordinate of the highest point.
///
public virtual double Top
{
get { return boundingBox.Top; }
}
///
/// Y-Coordinate of the lowest point.
///
public virtual double Bottom
{
get { return boundingBox.Bottom; }
}
///
/// Length of the entity.
///
public abstract double Length { get; }
///
/// Reverses the entity.
///
public abstract void Reverse();
///
/// Moves the entity location to the given coordinates.
///
///
///
public abstract void MoveTo(double x, double y);
///
/// Moves the entity location to the given point.
///
///
public abstract void MoveTo(Vector pt);
///
/// Offsets the entity location by the given distances.
///
///
///
public abstract void Offset(double x, double y);
///
/// Offsets the entity location by the given distances.
///
///
public abstract void Offset(Vector voffset);
///
/// Scales the entity from the zero point.
///
///
public abstract void Scale(double factor);
///
/// Scales the entity from the origin.
///
///
///
public abstract void Scale(double factor, Vector origin);
///
/// Rotates the entity from the zero point.
///
///
public abstract void Rotate(double angle);
///
/// Rotates the entity from the origin.
///
///
///
public abstract void Rotate(double angle, Vector origin);
///
/// Updates the bounding box.
///
public abstract void UpdateBounds();
///
/// Gets a new entity offset the given distance from this entity.
///
///
///
///
public abstract Entity OffsetEntity(double distance, OffsetSide side);
///
/// Gets a new entity offset the given distance from this entity. Offset side determined by point.
///
///
///
///
public abstract Entity OffsetEntity(double distance, Vector pt);
///
/// Gets the closest point on the entity to the given point.
///
///
///
public abstract Vector ClosestPointTo(Vector pt);
///
/// Returns true if the given arc is intersecting this.
///
///
///
public abstract bool Intersects(Arc arc);
///
/// Returns true if the given arc is intersecting this.
///
///
/// List to store the points of intersection.
///
public abstract bool Intersects(Arc arc, out List pts);
///
/// Returns true if the given circle is intersecting this.
///
///
///
public abstract bool Intersects(Circle circle);
///
/// Returns true if the given circle is intersecting this.
///
///
///
///
public abstract bool Intersects(Circle circle, out List pts);
///
/// Returns true if the given line is intersecting this.
///
///
///
public abstract bool Intersects(Line line);
///
/// Returns true if the given line is intersecting this.
///
///
///
///
public abstract bool Intersects(Line line, out List pts);
///
/// Returns true if the given polygon is intersecting this.
///
///
///
public abstract bool Intersects(Polygon polygon);
///
/// Returns true if the given polygon is intersecting this.
///
///
///
///
public abstract bool Intersects(Polygon polygon, out List pts);
///
/// Returns true if the given shape is intersecting this.
///
///
///
public abstract bool Intersects(Shape shape);
///
/// Returns true if the given shape is intersecting this.
///
///
///
///
public abstract bool Intersects(Shape shape, out List pts);
///
/// Type of entity.
///
public abstract EntityType Type { get; }
}
public static class EntityExtensions
{
public static double FindBestRotation(this List 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;
}
}
}