Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 21 additions & 5 deletions App.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
using Stack_Solver.Data;
using Stack_Solver.Data.Repositories;
using Stack_Solver.Infrastructure;
using Stack_Solver.Models;
using Stack_Solver.Services;
using Stack_Solver.ViewModels.Pages;
using Stack_Solver.ViewModels.Windows;
Expand All @@ -28,7 +31,11 @@ public partial class App
// https://docs.microsoft.com/dotnet/core/extensions/logging
private static readonly IHost _host = Host
.CreateDefaultBuilder()
.ConfigureAppConfiguration(c => { c.SetBasePath(Path.GetDirectoryName(AppContext.BaseDirectory)); })
.ConfigureAppConfiguration(c =>
{
c.SetBasePath(Path.GetDirectoryName(AppContext.BaseDirectory)!);
c.AddJsonFile("defaults.json", optional: true, reloadOnChange: true);
})
.ConfigureServices((context, services) =>
{
services.AddNavigationViewPageProvider();
Expand All @@ -55,22 +62,31 @@ public partial class App
services.AddSingleton<SKULibraryPage>();
services.AddSingleton<SKULibraryViewModel>();
services.AddSingleton<PalletBuilderPage>();
services.AddSingleton<PalletBuilderViewModel>();
services.AddSingleton<PalletBuilderViewModel>(sp => new PalletBuilderViewModel(
sp.GetRequiredService<ISkuRepository>(),
sp.GetRequiredService<IEventAggregator>(),
sp.GetRequiredService<ILayerVisualizationService>(),
sp.GetRequiredService<IOptions<GenerationOptions>>(),
sp.GetRequiredService<IOptions<PalletDefaultsOptions>>()));
services.AddSingleton<TruckLoadingPage>();
services.AddSingleton<TruckLoadingViewModel>();
services.AddSingleton<JobManagerPage>();
services.AddSingleton<JobManagerViewModel>();

services.AddSingleton<IEventAggregator, EventAggregator>();
services.AddSingleton<ILayerVisualizationService, LayerVisualizationService>();

services.AddDbContextFactory<ApplicationDbContext>(options =>
{
options.UseSqlite($"Data Source={AppPaths.DatabaseFile}");
});

// Repositories
services.AddSingleton<ISkuRepository, SkuRepository>();

// Initializer
services.AddSingleton<DatabaseInitializer>();

// Bind options from host configuration
services.Configure<GenerationOptions>(context.Configuration.GetSection("LayerGeneration"));
services.Configure<PalletDefaultsOptions>(context.Configuration.GetSection("PalletDefaults"));
}).Build();

/// <summary>
Expand Down
48 changes: 48 additions & 0 deletions Infrastructure/EventAggregator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
namespace Stack_Solver.Infrastructure
{
public interface IEventAggregator
{
void Publish<TMessage>(TMessage message);
void Subscribe<TMessage>(Action<TMessage> handler);
void Unsubscribe<TMessage>(Action<TMessage> handler);
}

public class EventAggregator : IEventAggregator
{
private readonly Dictionary<Type, List<Delegate>> _handlers = [];

public void Publish<TMessage>(TMessage message)
{
var t = typeof(TMessage);
if (_handlers.TryGetValue(t, out var list))
{
foreach (var h in list.ToArray())
{
try { ((Action<TMessage>)h).Invoke(message); }
catch { }
}
}
}

public void Subscribe<TMessage>(Action<TMessage> handler)
{
var t = typeof(TMessage);
if (!_handlers.TryGetValue(t, out var list))
{
list = [];
_handlers[t] = list;
}
if (!list.Contains(handler)) list.Add(handler);
}

public void Unsubscribe<TMessage>(Action<TMessage> handler)
{
var t = typeof(TMessage);
if (_handlers.TryGetValue(t, out var list))
{
list.Remove(handler);
if (list.Count == 0) _handlers.Remove(t);
}
}
}
}
10 changes: 8 additions & 2 deletions Models/GenerationOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
{
public class GenerationOptions
{
public int MaxSolverTime { get; set; } = 60;
public int MaxCandidates { get; set; } = 2000;
public int MaxSolverTime { get; set; }
public int MaxCandidates { get; set; }

public GenerationOptions() { }

Expand All @@ -12,5 +12,11 @@ public GenerationOptions(int maxSolverTime, int maxCandidates)
MaxSolverTime = maxSolverTime;
MaxCandidates = maxCandidates;
}

public static GenerationOptions From(GenerationOptions? source)
{
if (source == null) return new GenerationOptions();
return new GenerationOptions(source.MaxSolverTime, source.MaxCandidates);
}
}
}
13 changes: 13 additions & 0 deletions Models/PalletDefaultsOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace Stack_Solver.Models
{
public class PalletDefaultsOptions
{
public string? DefaultCatalog { get; set; }
public string? DefaultPalletName { get; set; }
public int PalletLength { get; set; } = 120;
public int PalletWidth { get; set; } = 80;
public double PalletHeight { get; set; } = 14.4;
public int MaxStackHeight { get; set; } = 180;
public int MaxStackWeight { get; set; } = 950;
}
}
56 changes: 56 additions & 0 deletions Services/LayerVisualizationService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
using Stack_Solver.Helpers.Rendering;
using Stack_Solver.Models.Layering;
using Stack_Solver.Models.Supports;
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Media3D;

namespace Stack_Solver.Services
{
public interface ILayerVisualizationService
{
void HighlightItem(Model3DGroup scene, PositionedItem? item, double palletHeight);
void Build2DRectangles(Layer layer, SupportSurface pallet, int gridStep, ObservableCollection<Rect> target);
}

public class LayerVisualizationService : ILayerVisualizationService
{
private Model3DGroup? _selectionHighlight;

public void HighlightItem(Model3DGroup scene, PositionedItem? item, double palletHeight)
{
if (_selectionHighlight != null)
{
scene.Children.Remove(_selectionHighlight);
_selectionHighlight = null;
}
if (item == null) return;
var sku = item.SkuType;
double boxLength = item.Rotated ? sku.Width : sku.Length;
double boxWidth = item.Rotated ? sku.Length : sku.Width;
double boxHeight = sku.Height;
double inflate = 0.6;
var origin = new Point3D(item.X - inflate / 2.0, palletHeight + 0.01, item.Y - inflate / 2.0);
var fillBrush = new SolidColorBrush(Color.FromArgb(40, 255, 255, 0));
var edgeColor = Colors.Yellow;
_selectionHighlight = GeometryCreator.CreateBoxWithEdges(origin, boxLength + inflate, boxHeight + inflate, boxWidth + inflate, fillBrush, edgeColor, 0.6);
scene.Children.Add(_selectionHighlight);
}

public void Build2DRectangles(Layer layer, SupportSurface pallet, int gridStep, ObservableCollection<Rect> target)
{
LayerGeometryBuilder.Build(layer, pallet, gridStep);
target.Clear();
if (layer.Geometry?.ItemRectangles != null)
{
double canvasHeight = pallet.Width;
foreach (var r in layer.Geometry.ItemRectangles)
{
var display = new Rect(r.X, canvasHeight - (r.Y + r.Height), r.Width, r.Height);
target.Add(display);
}
}
}
}
}
6 changes: 6 additions & 0 deletions Stack-Solver.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@
<Page Remove="Tests\**" />
</ItemGroup>

<ItemGroup>
<Content Include="defaults.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>

<ItemGroup>
<PackageReference Include="Google.OrTools" Version="9.14.6206" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="10.0.0" />
Expand Down
Loading
Loading