feat: add BestFitFilter and TileEvaluator for pair filtering and tiling
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
46
OpenNest.Engine/BestFit/BestFitFilter.cs
Normal file
46
OpenNest.Engine/BestFit/BestFitFilter.cs
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace OpenNest.Engine.BestFit
|
||||||
|
{
|
||||||
|
public class BestFitFilter
|
||||||
|
{
|
||||||
|
public double MaxPlateWidth { get; set; }
|
||||||
|
public double MaxPlateHeight { get; set; }
|
||||||
|
public double MaxAspectRatio { get; set; } = 5.0;
|
||||||
|
public double MinUtilization { get; set; } = 0.3;
|
||||||
|
|
||||||
|
public void Apply(List<BestFitResult> results)
|
||||||
|
{
|
||||||
|
foreach (var result in results)
|
||||||
|
{
|
||||||
|
if (!result.Keep)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (result.ShortestSide > System.Math.Min(MaxPlateWidth, MaxPlateHeight))
|
||||||
|
{
|
||||||
|
result.Keep = false;
|
||||||
|
result.Reason = "Exceeds plate dimensions";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var aspect = result.LongestSide / result.ShortestSide;
|
||||||
|
|
||||||
|
if (aspect > MaxAspectRatio)
|
||||||
|
{
|
||||||
|
result.Keep = false;
|
||||||
|
result.Reason = string.Format("Aspect ratio {0:F1} exceeds max {1}", aspect, MaxAspectRatio);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.Utilization < MinUtilization)
|
||||||
|
{
|
||||||
|
result.Keep = false;
|
||||||
|
result.Reason = string.Format("Utilization {0:P0} below minimum", result.Utilization);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
result.Reason = "Valid";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
62
OpenNest.Engine/BestFit/Tiling/TileEvaluator.cs
Normal file
62
OpenNest.Engine/BestFit/Tiling/TileEvaluator.cs
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using OpenNest.Geometry;
|
||||||
|
using OpenNest.Math;
|
||||||
|
|
||||||
|
namespace OpenNest.Engine.BestFit.Tiling
|
||||||
|
{
|
||||||
|
public class TileEvaluator
|
||||||
|
{
|
||||||
|
public TileResult Evaluate(BestFitResult bestFit, Plate plate)
|
||||||
|
{
|
||||||
|
var plateWidth = plate.Size.Width - plate.EdgeSpacing.Left - plate.EdgeSpacing.Right;
|
||||||
|
var plateHeight = plate.Size.Height - plate.EdgeSpacing.Top - plate.EdgeSpacing.Bottom;
|
||||||
|
|
||||||
|
var result1 = TryTile(bestFit, plateWidth, plateHeight, false);
|
||||||
|
var result2 = TryTile(bestFit, plateWidth, plateHeight, true);
|
||||||
|
return result1.PartsNested >= result2.PartsNested ? result1 : result2;
|
||||||
|
}
|
||||||
|
|
||||||
|
private TileResult TryTile(BestFitResult bestFit, double plateWidth, double plateHeight, bool rotatePair)
|
||||||
|
{
|
||||||
|
var pairWidth = rotatePair ? bestFit.BoundingHeight : bestFit.BoundingWidth;
|
||||||
|
var pairHeight = rotatePair ? bestFit.BoundingWidth : bestFit.BoundingHeight;
|
||||||
|
var spacing = bestFit.Candidate.Spacing;
|
||||||
|
|
||||||
|
var cols = (int)System.Math.Floor((plateWidth + spacing) / (pairWidth + spacing));
|
||||||
|
var rows = (int)System.Math.Floor((plateHeight + spacing) / (pairHeight + spacing));
|
||||||
|
var pairsNested = cols * rows;
|
||||||
|
var partsNested = pairsNested * 2;
|
||||||
|
|
||||||
|
var usedArea = partsNested * (bestFit.TrueArea / 2);
|
||||||
|
var plateArea = plateWidth * plateHeight;
|
||||||
|
|
||||||
|
var placements = new List<PairPlacement>();
|
||||||
|
|
||||||
|
for (var row = 0; row < rows; row++)
|
||||||
|
{
|
||||||
|
for (var col = 0; col < cols; col++)
|
||||||
|
{
|
||||||
|
placements.Add(new PairPlacement
|
||||||
|
{
|
||||||
|
Position = new Vector(
|
||||||
|
col * (pairWidth + spacing),
|
||||||
|
row * (pairHeight + spacing)),
|
||||||
|
PairRotation = rotatePair ? Angle.HalfPI : 0
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new TileResult
|
||||||
|
{
|
||||||
|
BestFit = bestFit,
|
||||||
|
PairsNested = pairsNested,
|
||||||
|
PartsNested = partsNested,
|
||||||
|
Rows = rows,
|
||||||
|
Columns = cols,
|
||||||
|
Utilization = plateArea > 0 ? usedArea / plateArea : 0,
|
||||||
|
Placements = placements,
|
||||||
|
PairRotated = rotatePair
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
23
OpenNest.Engine/BestFit/Tiling/TileResult.cs
Normal file
23
OpenNest.Engine/BestFit/Tiling/TileResult.cs
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using OpenNest.Geometry;
|
||||||
|
|
||||||
|
namespace OpenNest.Engine.BestFit.Tiling
|
||||||
|
{
|
||||||
|
public class TileResult
|
||||||
|
{
|
||||||
|
public BestFitResult BestFit { get; set; }
|
||||||
|
public int PairsNested { get; set; }
|
||||||
|
public int PartsNested { get; set; }
|
||||||
|
public int Rows { get; set; }
|
||||||
|
public int Columns { get; set; }
|
||||||
|
public double Utilization { get; set; }
|
||||||
|
public List<PairPlacement> Placements { get; set; }
|
||||||
|
public bool PairRotated { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class PairPlacement
|
||||||
|
{
|
||||||
|
public Vector Position { get; set; }
|
||||||
|
public double PairRotation { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -41,7 +41,10 @@
|
|||||||
<Compile Include="BestFit\BestFitResult.cs" />
|
<Compile Include="BestFit\BestFitResult.cs" />
|
||||||
<Compile Include="BestFit\IBestFitStrategy.cs" />
|
<Compile Include="BestFit\IBestFitStrategy.cs" />
|
||||||
<Compile Include="BestFit\PairEvaluator.cs" />
|
<Compile Include="BestFit\PairEvaluator.cs" />
|
||||||
|
<Compile Include="BestFit\BestFitFilter.cs" />
|
||||||
<Compile Include="BestFit\RotationSlideStrategy.cs" />
|
<Compile Include="BestFit\RotationSlideStrategy.cs" />
|
||||||
|
<Compile Include="BestFit\Tiling\TileResult.cs" />
|
||||||
|
<Compile Include="BestFit\Tiling\TileEvaluator.cs" />
|
||||||
<Compile Include="CirclePacking\Bin.cs" />
|
<Compile Include="CirclePacking\Bin.cs" />
|
||||||
<Compile Include="CirclePacking\FillEndEven.cs" />
|
<Compile Include="CirclePacking\FillEndEven.cs" />
|
||||||
<Compile Include="CirclePacking\FillEndOdd.cs" />
|
<Compile Include="CirclePacking\FillEndOdd.cs" />
|
||||||
|
|||||||
Reference in New Issue
Block a user