mirror of
https://github.com/ajisaacs/OpenNest.git
synced 2026-11-05 01:11:35 -05:00
The summary's parts table squeezed each thumbnail into a 62 pt column and had no room for the size and weight the shop asks for. Each drawing is now a card, four to a row: ID, a larger thumbnail, name, bounding-box size, weight each and for all nested copies, required/nested counts and plates. A shortage or extra is a badge beside the ID (SHORT in red) so it stays easy to spot without a column to scan. Weight is net area x nest thickness x material density, read as lb/in^3 like the machine material defaults; millimeter jobs report kilograms. A nest without thickness or density shows "-" and a note saying what is missing, never a zero weight. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
61 lines
2.6 KiB
C#
61 lines
2.6 KiB
C#
using System.Collections.Immutable;
|
|
|
|
namespace OpenNest.Reporting;
|
|
|
|
public sealed record ReportPoint(double X, double Y);
|
|
|
|
public sealed record ReportBounds(double Left, double Bottom, double Right, double Top)
|
|
{
|
|
public double Length => Right - Left;
|
|
public double Width => Top - Bottom;
|
|
}
|
|
|
|
/// <summary>Native line or arc; angles are radians and a null center denotes a line.</summary>
|
|
public sealed record ReportSegment(ReportPoint Start, ReportPoint End, ReportPoint? Center,
|
|
double Radius, double StartAngle, double SweepAngle);
|
|
|
|
public sealed record ReportContour(ImmutableArray<ReportSegment> Segments, bool Closed);
|
|
|
|
public sealed record ReportGeometry(ImmutableArray<ReportContour> Contours, ReportBounds Bounds)
|
|
{
|
|
public bool StrokeOnly => Contours.Any(contour => !contour.Closed);
|
|
}
|
|
|
|
public sealed record ReportDrawing(string Id, string Name, long Required, long Nested,
|
|
long Shortage, long Extra, ImmutableArray<int> Plates, ReportGeometry Geometry)
|
|
{
|
|
/// <summary>
|
|
/// Net weight of one part in <see cref="NestReportSnapshot.WeightUnits"/>; null when the nest
|
|
/// has no thickness or the material has no density.
|
|
/// </summary>
|
|
public double? Weight { get; init; }
|
|
}
|
|
|
|
public sealed record ReportPlacement(string ReportId, ReportGeometry Geometry);
|
|
|
|
public sealed record ReportPlate(int Number, ReportBounds Bounds, int Copies, double PartSpacing,
|
|
double Utilization, ImmutableArray<ReportPlacement> Parts, ImmutableArray<ReportGeometry> Cutoffs)
|
|
{
|
|
/// <summary>Estimated time to cut one copy of this plate; null when no estimate was requested.</summary>
|
|
public TimeSpan? CutTime { get; init; }
|
|
}
|
|
|
|
/// <summary>A detached value snapshot. No domain objects or mutable geometry are retained.</summary>
|
|
public sealed record NestReportSnapshot(string Name, string Customer, string Notes, string Material,
|
|
string Grade, double Thickness, string Units, DateTimeOffset GeneratedAt,
|
|
ImmutableArray<ReportDrawing> Drawings, ImmutableArray<ReportPlate> Plates)
|
|
{
|
|
public long TotalSheets => Plates.Aggregate(0L, (total, plate) => checked(total + plate.Copies));
|
|
|
|
/// <summary>"lb" for inch jobs, "kg" for millimeter jobs.</summary>
|
|
public string WeightUnits => Units == "mm" ? "kg" : "lb";
|
|
|
|
/// <summary>True when the report carries estimated cut times.</summary>
|
|
public bool HasCutTimes { get; init; }
|
|
|
|
/// <summary>Every plate's estimate times its copies; null when the report has no estimates.</summary>
|
|
public TimeSpan? TotalCutTime => !HasCutTimes
|
|
? null
|
|
: Plates.Aggregate(TimeSpan.Zero, (total, plate) => total + (plate.CutTime ?? TimeSpan.Zero) * plate.Copies);
|
|
}
|