Skip to content

Commit 5a5bb90

Browse files
authored
Merge pull request #11 from VladM7/layer-gen-improvements
Layer gen improvements
2 parents eda9f0a + f1bef14 commit 5a5bb90

13 files changed

+635
-343
lines changed
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
using System.Windows.Controls;
2+
using System.Windows.Input;
3+
using System.Windows.Media;
4+
5+
namespace Stack_Solver.Helpers.Behaviors;
6+
7+
/// <summary>
8+
/// Attached behavior that forwards mouse wheel events to the nearest scrollable parent <see cref="ScrollViewer"/>.
9+
/// Use this when nested controls (DataGrid, NumberBox, etc.) consume wheel events and prevent parent scrolling.
10+
/// </summary>
11+
public static class ParentScrollBehavior
12+
{
13+
public static readonly DependencyProperty EnabledProperty =
14+
DependencyProperty.RegisterAttached(
15+
"Enabled",
16+
typeof(bool),
17+
typeof(ParentScrollBehavior),
18+
new PropertyMetadata(false, OnEnabledChanged));
19+
20+
public static bool GetEnabled(DependencyObject obj) => (bool)obj.GetValue(EnabledProperty);
21+
public static void SetEnabled(DependencyObject obj, bool value) => obj.SetValue(EnabledProperty, value);
22+
23+
private static void OnEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
24+
{
25+
if (d is not UIElement element)
26+
return;
27+
28+
if ((bool)e.NewValue)
29+
{
30+
element.AddHandler(UIElement.PreviewMouseWheelEvent, new MouseWheelEventHandler(OnPreviewMouseWheel), handledEventsToo: true);
31+
}
32+
else
33+
{
34+
element.RemoveHandler(UIElement.PreviewMouseWheelEvent, new MouseWheelEventHandler(OnPreviewMouseWheel));
35+
}
36+
}
37+
38+
private static void OnPreviewMouseWheel(object sender, MouseWheelEventArgs e)
39+
{
40+
if (FindScrollableParent(sender as DependencyObject) is { } scrollViewer)
41+
{
42+
scrollViewer.ScrollToVerticalOffset(scrollViewer.VerticalOffset - e.Delta);
43+
e.Handled = true;
44+
}
45+
}
46+
47+
private static ScrollViewer? FindScrollableParent(DependencyObject? element)
48+
{
49+
var parent = element is null ? null : VisualTreeHelper.GetParent(element);
50+
51+
while (parent is not null)
52+
{
53+
if (parent is ScrollViewer sv && CanScroll(sv))
54+
return sv;
55+
56+
parent = VisualTreeHelper.GetParent(parent);
57+
}
58+
59+
return null;
60+
}
61+
62+
private static bool CanScroll(ScrollViewer sv) =>
63+
sv.ScrollableHeight > 0 ||
64+
(sv.VerticalScrollBarVisibility != ScrollBarVisibility.Disabled &&
65+
sv.ComputedVerticalScrollBarVisibility == Visibility.Visible);
66+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
using Stack_Solver.Models.Layering;
2+
3+
namespace Stack_Solver.Helpers.Layering
4+
{
5+
public static class LayerCandidateHelper
6+
{
7+
private const double UtilizationTolerance = 1e-6;
8+
9+
public static List<Layer> SelectBestBySkuCounts(IEnumerable<Layer> layers)
10+
{
11+
if (layers == null)
12+
return [];
13+
14+
var bestByKey = new Dictionary<string, Layer>(StringComparer.Ordinal);
15+
16+
foreach (var layer in layers)
17+
{
18+
if (layer == null)
19+
continue;
20+
21+
var key = BuildSkuCountKey(layer);
22+
if (!bestByKey.TryGetValue(key, out var incumbent) || IsBetter(layer, incumbent))
23+
bestByKey[key] = layer;
24+
}
25+
26+
return [.. bestByKey.Values
27+
.OrderByDescending(l => l.Metadata.Utilization)
28+
.ThenByDescending(l => l.Items.Count)];
29+
}
30+
31+
public static bool IsBetter(Layer candidate, Layer incumbent, double tolerance = UtilizationTolerance)
32+
{
33+
if (incumbent == null)
34+
return true;
35+
if (candidate == null)
36+
return false;
37+
38+
double delta = candidate.Metadata.Utilization - incumbent.Metadata.Utilization;
39+
if (delta > tolerance)
40+
return true;
41+
42+
if (Math.Abs(delta) <= tolerance)
43+
return candidate.Items.Count > incumbent.Items.Count;
44+
45+
return false;
46+
}
47+
48+
public static string BuildSkuCountKey(Layer layer)
49+
{
50+
if (layer == null)
51+
return string.Empty;
52+
53+
return string.Join(",", layer.Items
54+
.GroupBy(i => i.SkuType.SkuId)
55+
.OrderBy(g => g.Key, StringComparer.Ordinal)
56+
.Select(g => $"{g.Key}:{g.Count()}"));
57+
}
58+
}
59+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
using Stack_Solver.Models;
2+
3+
namespace Stack_Solver.Helpers.Layering
4+
{
5+
public readonly record struct SkuVariant(string VariantId, SKU Sku, int SpanX, int SpanY, bool Rotated);
6+
7+
public static class SkuVariantFactory
8+
{
9+
public static List<SkuVariant> CreateAllOrientations(IEnumerable<SKU>? skus)
10+
{
11+
var variants = new List<SkuVariant>();
12+
if (skus == null)
13+
return variants;
14+
15+
foreach (var sku in skus)
16+
{
17+
if (sku == null)
18+
continue;
19+
20+
variants.Add(new SkuVariant($"{sku.SkuId}_n", sku, sku.Length, sku.Width, false));
21+
22+
if (sku.Rotatable && sku.Length != sku.Width)
23+
{
24+
variants.Add(new SkuVariant($"{sku.SkuId}_r", sku, sku.Width, sku.Length, true));
25+
}
26+
}
27+
28+
return variants;
29+
}
30+
}
31+
}

Models/GenerationOptions.cs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,23 @@
33
public class GenerationOptions
44
{
55
public int MaxSolverTime { get; set; }
6-
public int MaxCandidates { get; set; }
6+
public int MaxCPSATCandidates { get; set; }
7+
8+
public int BLFAttempts { get; set; }
79

810
public GenerationOptions() { }
911

10-
public GenerationOptions(int maxSolverTime, int maxCandidates)
12+
public GenerationOptions(int maxSolverTime, int maxCandidates, int blfAttempts)
1113
{
1214
MaxSolverTime = maxSolverTime;
13-
MaxCandidates = maxCandidates;
15+
MaxCPSATCandidates = maxCandidates;
16+
BLFAttempts = blfAttempts;
1417
}
1518

1619
public static GenerationOptions From(GenerationOptions? source)
1720
{
1821
if (source == null) return new GenerationOptions();
19-
return new GenerationOptions(source.MaxSolverTime, source.MaxCandidates);
22+
return new GenerationOptions(source.MaxSolverTime, source.MaxCPSATCandidates, source.BLFAttempts);
2023
}
2124
}
2225
}

0 commit comments

Comments
 (0)