mirror of
https://github.com/ajisaacs/OpenNest.git
synced 2026-10-27 05:01:05 -04:00
An applied cutting program for a display-perimeter blank held only its cutouts, so the part shrank to them: a 30 x 20 door reported an 11.5 x 20 extent, overlap and the plate view lost the blank, and running automatic cut-offs afterwards added lines straight through it. A complete emission now ends with a display tail: a marker comment, a rapid to the outline and the outline on the display perimeter layer. The part keeps the blank's bounds and material, so later cut-offs still have nothing to cut and the door plans again as before. Nothing executes the tail: executed reads stop at the marker, so search, replay and the pre-post review see only the cuts, and cut time, the rapid display and the cut simulation leave it out. DisplayPerimeterTail.ForPosting gives posts the program without it and refuses an unplanned display perimeter.
121 lines
4.3 KiB
C#
121 lines
4.3 KiB
C#
using System;
|
|
using System.Linq;
|
|
using OpenNest.CNC;
|
|
using OpenNest.Converters;
|
|
using OpenNest.Geometry;
|
|
|
|
namespace OpenNest
|
|
{
|
|
public static class Timing
|
|
{
|
|
public static TimingInfo GetTimingInfo(Program pgm)
|
|
{
|
|
// A display perimeter's tail is never cut, so it takes no time.
|
|
pgm = DisplayPerimeterTail.WithoutTail(pgm);
|
|
var entities = ConvertProgram.ToGeometry(pgm);
|
|
var shapes = ShapeBuilder.GetShapes(
|
|
entities.Where(entity => entity.Layer != SpecialLayers.Rapid)
|
|
);
|
|
var info = new TimingInfo { PierceCount = shapes.Count };
|
|
|
|
var last = entities[0];
|
|
ProcessEntity(info, last, null);
|
|
|
|
for (int i = 1; i < entities.Count; i++)
|
|
{
|
|
var entity = entities[i];
|
|
ProcessEntity(info, entity, last);
|
|
last = entity;
|
|
}
|
|
|
|
return info;
|
|
}
|
|
|
|
public static TimingInfo GetTimingInfo(Plate plate)
|
|
{
|
|
var info = new TimingInfo();
|
|
var pos = new Vector(0, 0);
|
|
|
|
foreach (var part in plate.Parts)
|
|
{
|
|
var endpt = DisplayPerimeterTail.WithoutTail(part.Program).EndPoint() + part.Location;
|
|
info += GetTimingInfo(part.Program);
|
|
info.TravelDistance += pos.DistanceTo(endpt);
|
|
pos = endpt;
|
|
}
|
|
|
|
// D9: once per physical sheet, before the quantity multiply below scales it with
|
|
// everything else cut on that sheet.
|
|
info.ClampRemovalMinutes = plate.ClampRemovalMinutes;
|
|
|
|
info *= plate.Quantity;
|
|
|
|
return info;
|
|
}
|
|
|
|
public static TimingInfo GetTimingInfo(Nest nest)
|
|
{
|
|
var info = new TimingInfo();
|
|
return nest.Plates.Aggregate(info, (current, plate) => current + GetTimingInfo(plate));
|
|
}
|
|
|
|
private static void ProcessEntity(TimingInfo info, Entity entity, Entity lastEntity)
|
|
{
|
|
if (entity.Layer == SpecialLayers.Cut)
|
|
{
|
|
info.CutDistance += entity.Length;
|
|
|
|
if (
|
|
entity.Type == EntityType.Line
|
|
&& lastEntity != null
|
|
&& lastEntity.Type == EntityType.Line
|
|
&& lastEntity.Layer == SpecialLayers.Cut
|
|
)
|
|
info.IntersectionCount++;
|
|
}
|
|
else if (entity.Layer == SpecialLayers.Rapid)
|
|
info.TravelDistance += entity.Length;
|
|
}
|
|
|
|
/// <summary>
|
|
/// A plate's cut time over its quantity: its <see cref="CutSimulation"/> timeline (hole and
|
|
/// outside feeds, skipped etch, and acceleration when <see cref="CutParameters.Motion"/> is
|
|
/// set) plus clamp removal.
|
|
/// </summary>
|
|
public static TimeSpan CalculateTime(Plate plate, CutParameters cutParams)
|
|
{
|
|
var sheet = CutSimulation.Build(plate, cutParams).TotalTime
|
|
+ TimeSpan.FromMinutes(plate.ClampRemovalMinutes);
|
|
return sheet * plate.Quantity;
|
|
}
|
|
|
|
public static TimeSpan CalculateTime(Nest nest, CutParameters cutParams) =>
|
|
nest.Plates.Aggregate(TimeSpan.Zero, (total, plate) => total + CalculateTime(plate, cutParams));
|
|
|
|
public static TimeSpan CalculateTime(TimingInfo info, CutParameters cutParams)
|
|
{
|
|
var time = new TimeSpan();
|
|
|
|
switch (cutParams.Units)
|
|
{
|
|
case Units.Inches:
|
|
time += TimeSpan.FromMinutes(info.CutDistance / cutParams.Feedrate);
|
|
time += TimeSpan.FromMinutes(info.TravelDistance / cutParams.RapidTravelRate);
|
|
break;
|
|
|
|
case Units.Millimeters:
|
|
time += TimeSpan.FromSeconds(info.CutDistance / cutParams.Feedrate);
|
|
time += TimeSpan.FromSeconds(info.TravelDistance / cutParams.RapidTravelRate);
|
|
break;
|
|
}
|
|
|
|
time += TimeSpan.FromTicks(info.PierceCount * cutParams.PierceTime.Ticks);
|
|
|
|
// D9: a flat per-removed-clamp time, already in minutes regardless of cutParams.Units.
|
|
time += TimeSpan.FromMinutes(info.ClampRemovalMinutes);
|
|
|
|
return time;
|
|
}
|
|
}
|
|
}
|