using OpenNest.Math; using System.Collections.Generic; using System.Drawing; namespace OpenNest.Geometry { public abstract class Entity : IBoundable { protected Box boundingBox; protected Entity() { Layer = OpenNest.Geometry.Layer.Default; boundingBox = new Box(); } /// /// Entity color (resolved from DXF ByLayer/ByBlock to actual color). /// public Color Color { get; set; } /// /// Entity linetype name (e.g. "Continuous", "Center", "Dashed"). /// public string LineTypeName { get; set; } /// /// Whether this entity is visible (used for color/linetype filtering). /// public bool IsVisible { get; set; } = true; /// /// 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 BoundingRectangleResult FindBestRotation(this List entities, double startAngle = 0, double endAngle = Angle.TwoPI) { var points = new List(); foreach (var entity in entities) { switch (entity.Type) { case EntityType.Line: var line = (Line)entity; points.Add(line.StartPoint); points.Add(line.EndPoint); break; case EntityType.Arc: var arc = (Arc)entity; points.Add(arc.StartPoint()); points.Add(arc.EndPoint()); points.Add(arc.Center.Offset(arc.Radius, 0)); points.Add(arc.Center.Offset(-arc.Radius, 0)); points.Add(arc.Center.Offset(0, arc.Radius)); points.Add(arc.Center.Offset(0, -arc.Radius)); break; case EntityType.Circle: var circle = (Circle)entity; points.Add(circle.Center.Offset(circle.Radius, 0)); points.Add(circle.Center.Offset(-circle.Radius, 0)); points.Add(circle.Center.Offset(0, circle.Radius)); points.Add(circle.Center.Offset(0, -circle.Radius)); break; case EntityType.Polygon: var polygon = (Polygon)entity; points.AddRange(polygon.Vertices); break; case EntityType.Shape: var shape = (Shape)entity; var subResult = shape.Entities.FindBestRotation(startAngle, endAngle); return subResult; } } if (points.Count == 0) return new BoundingRectangleResult(startAngle, 0, 0); var hull = ConvexHull.Compute(points); bool constrained = !startAngle.IsEqualTo(0) || !endAngle.IsEqualTo(Angle.TwoPI); return constrained ? RotatingCalipers.MinimumBoundingRectangle(hull, startAngle, endAngle) : RotatingCalipers.MinimumBoundingRectangle(hull); } } }