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; } } }