using System.Collections.Generic; using System.Linq; using OpenNest.CNC; using OpenNest.Converters; using OpenNest.Geometry; namespace OpenNest { public interface IPart : IBoundable { Vector Location { get; set; } double Rotation { get; } void Rotate(double angle); void Rotate(double angle, Vector origin); void Offset(double x, double y); void Offset(Vector voffset); void Update(); } public class Part : IPart, IBoundable { private Vector location; public readonly Drawing BaseDrawing; public Part(Drawing baseDrawing) : this(baseDrawing, new Vector()) { } public Part(Drawing baseDrawing, Vector location) { BaseDrawing = baseDrawing; Program = baseDrawing.Program.Clone() as Program; this.location = location; UpdateBounds(); } /// /// Location of the part. /// public Vector Location { get { return location; } set { BoundingBox.Offset(value - location); location = value; } } public Program Program { get; private set; } /// /// Gets the rotation of the part in radians. /// public double Rotation { get { return Program.Rotation; } } /// /// Rotates the part. /// /// Angle of rotation in radians. public void Rotate(double angle) { Program.Rotate(angle); location = Location.Rotate(angle); UpdateBounds(); } /// /// Rotates the part around the specified origin. /// /// Angle of rotation in radians. /// The origin to rotate the part around. public void Rotate(double angle, Vector origin) { Program.Rotate(angle); location = Location.Rotate(angle, origin); UpdateBounds(); } /// /// Offsets the part. /// /// The x-axis offset distance. /// The y-axis offset distance. public void Offset(double x, double y) { location = new Vector(location.X + x, location.Y + y); BoundingBox.Offset(x, y); } /// /// Offsets the part. /// /// The vector containing the x-axis & y-axis offset distances. public void Offset(Vector voffset) { location += voffset; BoundingBox.Offset(voffset); } /// /// Creates a part normalized to the origin with optional rotation. /// public static Part CreateAtOrigin(Drawing drawing, double rotation = 0) { var part = new Part(drawing); if (!Math.Tolerance.IsEqualTo(rotation, 0)) part.Rotate(rotation); var bbox = part.Program.BoundingBox(); part.Offset(-bbox.Location.X, -bbox.Location.Y); part.UpdateBounds(); return part; } /// /// Updates the bounding box of the part. /// public void UpdateBounds() { BoundingBox = Program.BoundingBox(); BoundingBox.Offset(Location); } /// /// Updates the part from the drawing it was derived from. /// public void Update() { var rotation = Rotation; Program = BaseDrawing.Program.Clone() as Program; Program.Rotate(Program.Rotation - rotation); } /// /// The smallest box that contains the part. /// public Box BoundingBox { get; protected set; } public bool Intersects(Part part, out List pts) { pts = new List(); var entities1 = ConvertProgram.ToGeometry(Program) .Where(e => e.Layer != SpecialLayers.Rapid); var entities2 = ConvertProgram.ToGeometry(part.Program) .Where(e => e.Layer != SpecialLayers.Rapid); var shapes1 = Helper.GetShapes(entities1); var shapes2 = Helper.GetShapes(entities2); shapes1.ForEach(shape => shape.Offset(Location)); shapes2.ForEach(shape => shape.Offset(part.Location)); for (int i = 0; i < shapes1.Count; i++) { var shape1 = shapes1[i]; for (int j = 0; j < shapes2.Count; j++) { var shape2 = shapes2[j]; List pts2; if (shape1.Intersects(shape2, out pts2)) pts.AddRange(pts2); } } return pts.Count > 0; } public double Left { get { return BoundingBox.Left; } } public double Right { get { return BoundingBox.Right; } } public double Top { get { return BoundingBox.Top; } } public double Bottom { get { return BoundingBox.Bottom; } } /// /// Gets a deep copy of the part. /// /// public object Clone() { var part = new Part(BaseDrawing); part.Rotate(Rotation); part.Location = Location; return part; } /// /// Creates an offset copy of the part. Clones from the already-rotated /// program (skips re-rotation) and computes the bounding box arithmetically /// (skips Program.BoundingBox walk). /// public Part CloneAtOffset(Vector offset) { var clonedProgram = Program.Clone() as Program; var part = new Part(BaseDrawing, clonedProgram, location + offset, new Box(BoundingBox.X + offset.X, BoundingBox.Y + offset.Y, BoundingBox.Width, BoundingBox.Length)); return part; } private Part(Drawing baseDrawing, Program program, Vector location, Box boundingBox) { BaseDrawing = baseDrawing; Program = program; this.location = location; BoundingBox = boundingBox; } } }