using System.Collections.Generic; using System.Linq; using OpenNest.Geometry; namespace OpenNest.Diagnostics; /// An owned diagnostic result. An empty Pairs list is clear only if IsComplete is true. public sealed class PlateOverlapReport { internal PlateOverlapReport(List pairs, List issues) { Pairs = pairs.AsReadOnly(); Issues = issues.AsReadOnly(); } public IReadOnlyList Pairs { get; } public IReadOnlyList Issues { get; } public bool IsComplete => Issues.Count == 0; public double ChordTolerance => PlateOverlapAnalyzer.ChordTolerance; } /// Shared material for two input positions, ordered by zero-based input index. public sealed class PlateOverlapPair { private readonly Box bounds; internal PlateOverlapPair(int partAId, int partBId, string partAName, string partBName, List regions) { PartAId = partAId; PartBId = partBId; PartAName = partAName; PartBName = partBName; Regions = regions.AsReadOnly(); Area = regions.Sum(region => region.Area); var points = regions.SelectMany(region => region.Vertices).ToArray(); var left = points.Min(point => point.X); var bottom = points.Min(point => point.Y); bounds = new Box(left, bottom, points.Max(point => point.X) - left, points.Max(point => point.Y) - bottom); } public int PartAId { get; } public int PartBId { get; } public string PartAName { get; } public string PartBName { get; } /// Convex fragments, not connected islands; no mutable kernel polygons are exposed. public IReadOnlyList Regions { get; } public double Area { get; } /// A fresh world-coordinate bounds copy. public Box Bounds => new(bounds.X, bounds.Y, bounds.Length, bounds.Width); } /// A positive-area, hole-subtracted convex polygon in world coordinates. public sealed class PlateOverlapRegion { internal PlateOverlapRegion(IEnumerable vertices, double area) { Vertices = System.Array.AsReadOnly(vertices.ToArray()); Area = area; } /// Read-only vertices with an exactly repeated closing vertex. public IReadOnlyList Vertices { get; } public double Area { get; } } /// An input or pair that could not be checked. IDs are zero-based input positions. public sealed record PlateOverlapIssue(int PartAId, int? PartBId, string Message); /// /// Owned clean geometry and poses. Capture while inputs are stable, then analyze on a worker. /// No live Part, Drawing, Program, or subprogram is retained. /// public sealed class PlateOverlapSnapshot { internal PlateOverlapSnapshot(List parts, List issues) { Parts = parts.AsReadOnly(); Issues = issues.AsReadOnly(); } internal IReadOnlyList Parts { get; } internal IReadOnlyList Issues { get; } } internal sealed record CapturedOverlapPart(int Id, string Name, List Entities, double Rotation, Vector Location);