using System.Collections.Generic; using System.Linq; using OpenNest.Converters; using OpenNest.Engine; using OpenNest.Geometry; using OpenNest.Math; namespace OpenNest.Engine.BestFit { public class BestFitResult { public PairCandidate Candidate { get; set; } public double RotatedArea { get; set; } public double BoundingWidth { get; set; } public double BoundingHeight { get; set; } public double OptimalRotation { get; set; } public bool Keep { get; set; } public string Reason { get; set; } public double TrueArea { get; set; } public List HullAngles { get; set; } public double Utilization { get { return RotatedArea > 0 ? TrueArea / RotatedArea : 0; } } public double LongestSide { get { return System.Math.Max(BoundingWidth, BoundingHeight); } } public double ShortestSide { get { return System.Math.Min(BoundingWidth, BoundingHeight); } } public List BuildParts(Drawing drawing) { var part1 = Part.CreateAtOrigin(drawing); var part2 = Part.CreateAtOrigin(drawing, Candidate.Part2Rotation); part2.Location = Candidate.Part2Offset; part2.UpdateBounds(); if (!OptimalRotation.IsEqualTo(0)) { var pairBounds = ( (IEnumerable)new IBoundable[] { part1, part2 } ).GetBoundingBox(); var center = pairBounds.Center; part1.Rotate(-OptimalRotation, center); part2.Rotate(-OptimalRotation, center); } var finalBounds = ( (IEnumerable)new IBoundable[] { part1, part2 } ).GetBoundingBox(); var offset = new Vector(-finalBounds.Left, -finalBounds.Bottom); part1.Offset(offset); part2.Offset(offset); return new List { part1, part2 }; } public List BuildCanonicalParts() { return NormalizeToCutOrigin(BuildParts(Candidate.Drawing)); } public List BuildSourceParts(Drawing drawing) { var parts = BuildCanonicalParts(); return NormalizeToCutOrigin(CanonicalFrame.RebindToOriginal(parts, drawing)); } public Box GetCutBounds(List parts) { return GetCutBoundingBox(parts); } private static List NormalizeToCutOrigin(List parts) { if (parts == null || parts.Count == 0) return parts; var bounds = GetCutBoundingBox(parts); var offset = new Vector(-bounds.Left, -bounds.Bottom); foreach (var part in parts) part.Offset(offset); return parts; } private static Box GetCutBoundingBox(List parts) { var entities = new List(); foreach (var part in parts) { var partEntities = ConvertProgram .ToGeometry(part.Program) .Where(e => e.Layer != SpecialLayers.Rapid) .ToList(); foreach (var entity in partEntities) { entity.Offset(part.Location); entities.Add(entity); } } return entities.GetBoundingBox(); } } public enum BestFitSortField { Area, LongestSide, ShortestSide, Type, OriginalSequence, Keep, WhyKeepDrop, } }