From 89d20f4c42f6c2a7a3e565aa2cf5cd8564ff47c7 Mon Sep 17 00:00:00 2001 From: Lorenz Stechauner Date: Sun, 21 Jan 2024 12:48:40 +0100 Subject: [PATCH] ChartWindow: Make gebunden type fixed more user friendly --- Elwig/Helpers/Billing/BillingData.cs | 28 ++++----- Elwig/Helpers/Billing/EditBillingData.cs | 2 +- Elwig/Helpers/Billing/Graph.cs | 12 ++++ Elwig/Helpers/Billing/GraphEntry.cs | 80 +++++++++++++----------- Elwig/Windows/ChartWindow.xaml.cs | 66 +++++++++++-------- 5 files changed, 112 insertions(+), 76 deletions(-) diff --git a/Elwig/Helpers/Billing/BillingData.cs b/Elwig/Helpers/Billing/BillingData.cs index 858089d..9aba083 100644 --- a/Elwig/Helpers/Billing/BillingData.cs +++ b/Elwig/Helpers/Billing/BillingData.cs @@ -210,21 +210,21 @@ namespace Elwig.Helpers.Billing { var x = graph.DataX; var y = graph.DataY; if (y.Distinct().Count() == 1) { - return JsonValue.Create(graph.DataY[0]); + return JsonValue.Create((decimal)graph.DataY[0]); } var data = new JsonObject(); if (y[0] != y[1]) { - data.Add(new KeyValuePair(x[0] + mode, Math.Round(y[0], graph.Precision))); + data[$"{x[0]}{mode}"] = Math.Round(y[0], graph.Precision); } for (int i = 1; i < x.Length - 1; i++) { if (Math.Round(y[i] - y[i - 1], 10) != Math.Round(y[i + 1] - y[i], 10)) { - data.Add(new KeyValuePair(x[i] + mode, Math.Round(y[i], graph.Precision))); + data[$"{x[i]}{mode}"] = Math.Round(y[i], graph.Precision); } } if (y[^1] != y[^2]) { - data.Add(new KeyValuePair(x[^1] + mode, Math.Round(y[^1], graph.Precision))); + data[$"{x[^1]}{mode}"] = Math.Round(y[^1], graph.Precision); } return data; } @@ -247,16 +247,6 @@ namespace Elwig.Helpers.Billing { } public JsonObject FromGraphEntries(IEnumerable graphEntries) { - var payment = new JsonObject(); - var curves = new JsonArray(); - - foreach (var entry in graphEntries) { - curves.Add(GraphEntryToJson(entry)); - foreach (var contract in entry.Contracts) { - payment[$"{contract.Variety?.SortId}/{contract.Attribute?.AttrId}"] = $"curve:{entry.Id}"; - } - } - var data = new JsonObject { ["mode"] = "elwig", ["version"] = 1, @@ -270,6 +260,16 @@ namespace Elwig.Helpers.Billing { if (ConsiderAutoBusinessShares) data["consider_auto_business_shares"] = true; + var payment = new JsonObject(); + var curves = new JsonArray(); + + foreach (var entry in graphEntries) { + curves.Add(GraphEntryToJson(entry)); + foreach (var contract in entry.Contracts) { + payment[$"{contract.Variety?.SortId}/{contract.Attribute?.AttrId}"] = $"curve:{entry.Id}"; + } + } + data["payment"] = payment; data["curves"] = curves; diff --git a/Elwig/Helpers/Billing/EditBillingData.cs b/Elwig/Helpers/Billing/EditBillingData.cs index cf026cb..996266b 100644 --- a/Elwig/Helpers/Billing/EditBillingData.cs +++ b/Elwig/Helpers/Billing/EditBillingData.cs @@ -69,7 +69,7 @@ namespace Elwig.Helpers.Billing { return dict3 .Select(e => new GraphEntry(e.Key, season.Precision, curves[e.Key], e.Value .Select(s => new ContractSelection(vars[s[..2]], s.Length > 2 ? attrs[s[2..]] : null)) - .ToList(), 50, 73, 140)) + .ToList())) .ToList(); } diff --git a/Elwig/Helpers/Billing/Graph.cs b/Elwig/Helpers/Billing/Graph.cs index d86c989..fc2647b 100644 --- a/Elwig/Helpers/Billing/Graph.cs +++ b/Elwig/Helpers/Billing/Graph.cs @@ -28,6 +28,14 @@ namespace Elwig.Helpers.Billing { DataY = DataX.Select(i => (double)BillingData.GetCurveValueAt(data, i)).ToArray(); } + public Graph(double[] values, int precision, int minX, int maxX) { + Precision = precision; + MinX = minX; + MaxX = maxX; + DataX = Enumerable.Range(MinX, MaxX - MinX + 1).Select(i => (double)i).ToArray(); + DataY = values; + } + private Graph(double[] dataX, double[] dataY, int precision, int minX, int maxX) { Precision = precision; MinX = minX; @@ -52,6 +60,10 @@ namespace Elwig.Helpers.Billing { return DataY[index]; } + public double GetPriceAtOe(double oe) { + return DataY[Array.IndexOf(DataX, oe)]; + } + private void FlattenGraph(int begin, int end, double value) { for (int i = begin; i <= end; i++) { DataY[i] = value; diff --git a/Elwig/Helpers/Billing/GraphEntry.cs b/Elwig/Helpers/Billing/GraphEntry.cs index 255f78f..1ecc40f 100644 --- a/Elwig/Helpers/Billing/GraphEntry.cs +++ b/Elwig/Helpers/Billing/GraphEntry.cs @@ -1,77 +1,87 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; namespace Elwig.Helpers.Billing { public class GraphEntry { + public const int MinX = 50; + public const int MinXGeb = 73; + public const int MaxX = 140; + public int Id { get; set; } - private readonly int Precision; public BillingData.CurveMode Mode { get; set; } public bool Abgewertet { get; set; } + public Graph DataGraph { get; set; } public Graph? GebundenGraph { get; set; } - public decimal? GebundenFlatBonus { get; set; } - public List Contracts { get; set; } - public string ContractsStringSimple => Contracts.Any() ? string.Join(", ", Contracts.Select(c => c.Listing)) : "-"; - public string ContractsString => Contracts.Any() ? string.Join("\n", Contracts.Select(c => c.FullName)) : "-"; - private int MinX { get; set; } - private int MinXGebunden { get; set; } - private int MaxX { get; set; } + public double? GebundenFlatBonus { + get { + try { + return GebundenGraph?.DataX.Zip(GebundenGraph.DataY) + .Select(e => Math.Round(e.Second - DataGraph.GetPriceAtOe(e.First), Precision)) + .Distinct() + .Single(); + } catch { + return null; + } + } + set { + if (value is not double v) return; + var values = Enumerable.Range(MinXGeb, MaxX - MinXGeb + 1) + .Select(i => Math.Round(DataGraph.GetPriceAtOe(i) + v, Precision)) + .ToArray(); + GebundenGraph = new Graph(values, Precision, MinXGeb, MaxX); + } + } - public GraphEntry(int id, int precision, BillingData.CurveMode mode, int minX, int minXGebunden, int maxX) { + public List Contracts { get; set; } + public string ContractsStringSimple => Contracts.Count != 0 ? string.Join(", ", Contracts.Select(c => c.Listing)) : "-"; + public string ContractsString => Contracts.Count != 0 ? string.Join("\n", Contracts.Select(c => c.FullName)) : "-"; + + private readonly int Precision; + + public GraphEntry(int id, int precision, BillingData.CurveMode mode) { Id = id; Precision = precision; Mode = mode; - Abgewertet = false; - MinX = minX; - MinXGebunden = minXGebunden; - MaxX = maxX; - DataGraph = new Graph(precision, minX, maxX); + DataGraph = new Graph(precision, MinX, MaxX); ; Contracts = []; } - public GraphEntry(int id, int precision, BillingData.CurveMode mode, Dictionary data, Dictionary? gebunden, - int minX, int minXGebunden, int maxX) : this(id, precision, mode, minX, minXGebunden, maxX) { - DataGraph = new Graph(data, precision, minX, maxX); - if (gebunden != null) GebundenGraph = new Graph(gebunden, precision, minXGebunden, maxX); + public GraphEntry(int id, int precision, BillingData.CurveMode mode, Dictionary data, Dictionary? gebunden) : + this(id, precision, mode) { + DataGraph = new Graph(data, precision, MinX, MaxX); + if (gebunden != null) GebundenGraph = new Graph(gebunden, precision, MinXGeb, MaxX); } - public GraphEntry(int id, int precision, BillingData.Curve curve, List contracts, int minX, int minXGebunden, int maxX) : - this(id, precision, curve.Mode, minX, minXGebunden, maxX) { - DataGraph = new Graph(curve.Normal, precision, minX, maxX); + public GraphEntry(int id, int precision, BillingData.Curve curve, List contracts) : + this(id, precision, curve.Mode) { + DataGraph = new Graph(curve.Normal, precision, MinX, MaxX); if (curve.Gebunden != null) - GebundenGraph = new Graph(curve.Gebunden, precision, minXGebunden, maxX); + GebundenGraph = new Graph(curve.Gebunden, precision, MinXGeb, MaxX); Contracts = contracts; } - private GraphEntry(int id, int precision, BillingData.CurveMode mode, Graph dataGraph, Graph? gebundenGraph, - decimal? gebundenFlatPrice, List contracts, int minX, int minXGebunden, int maxX) { + private GraphEntry(int id, int precision, BillingData.CurveMode mode, Graph dataGraph, Graph? gebundenGraph, List contracts) { Id = id; Precision = precision; Mode = mode; - MinX = minX; - MinXGebunden = minXGebunden; - MaxX = maxX; DataGraph = dataGraph; GebundenGraph = gebundenGraph; - GebundenFlatBonus = gebundenFlatPrice; Contracts = contracts; } public void AddGebundenGraph() { - GebundenGraph ??= new Graph(Precision, MinXGebunden, MaxX); + GebundenGraph ??= new Graph(Precision, MinXGeb, MaxX); } public void RemoveGebundenGraph() { GebundenGraph = null; } - public void SetGebundenFlatBonus(decimal? value) { - GebundenFlatBonus = value; - } - public GraphEntry Copy(int id) { - return new GraphEntry(id, Precision, Mode, (Graph)DataGraph.Clone(), (Graph?)GebundenGraph?.Clone(), GebundenFlatBonus, [], MinX, MinXGebunden, MaxX); + return new GraphEntry(id, Precision, Mode, (Graph)DataGraph.Clone(), (Graph?)GebundenGraph?.Clone(), []); } } } diff --git a/Elwig/Windows/ChartWindow.xaml.cs b/Elwig/Windows/ChartWindow.xaml.cs index cf51a55..5bde18b 100644 --- a/Elwig/Windows/ChartWindow.xaml.cs +++ b/Elwig/Windows/ChartWindow.xaml.cs @@ -43,10 +43,6 @@ namespace Elwig.Windows { private bool HoverActive = false; private bool FillingInputs = false; - private const int MinOechsle = 50; - private const int MinOechsleGebunden = 73; - private const int MaxOechsle = 140; - private List GraphEntries = []; private GraphEntry? SelectedGraphEntry; @@ -125,12 +121,15 @@ namespace Elwig.Windows { private void FillInputs() { FillingInputs = true; - if (SelectedGraphEntry?.GebundenFlatBonus != null) { + if (SelectedGraphEntry?.GebundenFlatBonus is double bonus) { GebundenTypeFixed.IsChecked = true; + GebundenFlatBonus.Text = $"{bonus}"; } else if (SelectedGraphEntry?.GebundenGraph != null) { GebundenTypeGraph.IsChecked = true; + GebundenFlatBonus.Text = ""; } else { GebundenTypeNone.IsChecked = true; + GebundenFlatBonus.Text = ""; } ControlUtils.SelectCheckComboBoxItems(ContractInput, SelectedGraphEntry?.Contracts ?? [], i => (i as ContractSelection)?.Listing); @@ -165,7 +164,7 @@ namespace Elwig.Windows { OechslePricePlot.Configuration.DoubleClickBenchmark = false; //OechslePricePlot.Plot.XAxis.ManualTickSpacing(1); OechslePricePlot.Plot.YAxis.ManualTickSpacing(0.1); - OechslePricePlot.Plot.SetAxisLimits(Math.Min(MinOechsle, MinOechsleGebunden) - 1, MaxOechsle + 1, -0.1, 2); + OechslePricePlot.Plot.SetAxisLimits(Math.Min(GraphEntry.MinX, GraphEntry.MinXGeb) - 1, GraphEntry.MaxX + 1, -0.1, 2); OechslePricePlot.Plot.Layout(padding: 0); OechslePricePlot.Plot.XAxis2.Layout(padding: 0); @@ -247,17 +246,17 @@ namespace Elwig.Windows { } private void LockZoom() { - OechslePricePlot.Plot.XAxis.SetBoundary(MinOechsle - 1, MaxOechsle + 1); + OechslePricePlot.Plot.XAxis.SetBoundary(GraphEntry.MinX - 1, GraphEntry.MaxX + 1); OechslePricePlot.Plot.YAxis.SetBoundary(-0.1, 2); - OechslePricePlot.Plot.XAxis.SetZoomOutLimit(MaxOechsle - MinOechsle + 2); + OechslePricePlot.Plot.XAxis.SetZoomOutLimit(GraphEntry.MaxX - GraphEntry.MinX + 2); OechslePricePlot.Plot.YAxis.SetZoomOutLimit(2.1); - OechslePricePlot.Plot.SetAxisLimits(MinOechsle - 1, MaxOechsle + 1, -0.1, 2); + OechslePricePlot.Plot.SetAxisLimits(GraphEntry.MinX - 1, GraphEntry.MaxX + 1, -0.1, 2); } private void UnlockZoom() { OechslePricePlot.Plot.XAxis.SetBoundary(); OechslePricePlot.Plot.YAxis.SetBoundary(); - OechslePricePlot.Plot.XAxis.SetZoomOutLimit((MaxOechsle - MinOechsle) * 1.5); + OechslePricePlot.Plot.XAxis.SetZoomOutLimit((GraphEntry.MaxX - GraphEntry.MinX) * 1.5); OechslePricePlot.Plot.YAxis.SetZoomOutLimit(3.5); } @@ -342,12 +341,11 @@ namespace Elwig.Windows { private void PriceInput_TextChanged(object sender, TextChangedEventArgs evt) { if (PrimaryMarkedPoint != -1 && ActiveGraph != null) { - bool success = double.TryParse(PriceInput.Text, out double price); - - if (success) { + if (double.TryParse(PriceInput.Text, out double price)) { ActiveGraph.SetPriceAt(PrimaryMarkedPoint, price); PrimaryMarkedPointPlot.Y = price; OechslePricePlot.Refresh(); + CheckGebundenTypeFixed(); } } } @@ -358,6 +356,7 @@ namespace Elwig.Windows { } ActiveGraph.FlattenGraphLeft(PrimaryMarkedPoint); OechslePricePlot.Render(); + CheckGebundenTypeFixed(); } private void RightFlatButton_Click(object sender, RoutedEventArgs evt) { @@ -366,6 +365,7 @@ namespace Elwig.Windows { } ActiveGraph.FlattenGraphRight(PrimaryMarkedPoint); OechslePricePlot.Render(); + CheckGebundenTypeFixed(); } private void InterpolateButton_Click(object sender, RoutedEventArgs evt) { @@ -374,6 +374,7 @@ namespace Elwig.Windows { } ActiveGraph.InterpolateGraph(PrimaryMarkedPoint, SecondaryMarkedPoint); OechslePricePlot.Render(); + CheckGebundenTypeFixed(); } private void LinearIncreaseButton_Click(object sender, RoutedEventArgs e) { @@ -386,6 +387,7 @@ namespace Elwig.Windows { } ActiveGraph.LinearIncreaseGraphToEnd(PrimaryMarkedPoint, priceIncrease.Value); OechslePricePlot.Render(); + CheckGebundenTypeFixed(); } private void OechslePricePlot_MouseDown(object sender, MouseEventArgs e) { @@ -500,7 +502,7 @@ namespace Elwig.Windows { } private void AddButton_Click(object sender, RoutedEventArgs e) { - GraphEntry newGraphEntry = new(GetMaxGraphId() + 1, Season.Precision, BillingData.CurveMode.Oe, MinOechsle, MinOechsleGebunden, MaxOechsle); + GraphEntry newGraphEntry = new(GetMaxGraphId() + 1, Season.Precision, BillingData.CurveMode.Oe); GraphEntries.Add(newGraphEntry); GraphList.Items.Refresh(); GraphList.SelectedItem = newGraphEntry; @@ -600,9 +602,12 @@ namespace Elwig.Windows { } private void GebundenFlatBonus_TextChanged(object sender, TextChangedEventArgs e) { - var r = Validator.CheckDecimal(GebundenFlatBonus.TextBox, true, 2, 8); - if (r.IsValid) { - SelectedGraphEntry?.SetGebundenFlatBonus(decimal.Parse(GebundenFlatBonus.Text)); + if (FillingInputs) return; + var r = Validator.CheckDecimal(GebundenFlatBonus.TextBox, true, 2, Season.Precision); + if (r.IsValid && SelectedGraphEntry != null) { + SelectedGraphEntry.GebundenFlatBonus = double.Parse(GebundenFlatBonus.Text); + ResetPlot(); + InitPlot(); } } @@ -635,23 +640,32 @@ namespace Elwig.Windows { if (SelectedGraphEntry == null) { DisableUnitTextBox(GebundenFlatBonus); return; - } else if (GebundenTypeNone.IsChecked == true) { - SelectedGraphEntry.SetGebundenFlatBonus(null); + } + if (GebundenTypeNone.IsChecked == true) { SelectedGraphEntry.RemoveGebundenGraph(); DisableUnitTextBox(GebundenFlatBonus); - RefreshInputs(); } else if (GebundenTypeFixed.IsChecked == true) { - SelectedGraphEntry.SetGebundenFlatBonus(0); - SelectedGraphEntry.RemoveGebundenGraph(); + SelectedGraphEntry.GebundenFlatBonus = double.TryParse(GebundenFlatBonus.Text, out var val) ? val : 0.1; + SelectedGraphEntry.AddGebundenGraph(); EnableUnitTextBox(GebundenFlatBonus); - RefreshInputs(); } else if (GebundenTypeGraph.IsChecked == true) { - GebundenFlatBonus.Text = ""; - SelectedGraphEntry.SetGebundenFlatBonus(null); SelectedGraphEntry.AddGebundenGraph(); DisableUnitTextBox(GebundenFlatBonus); - RefreshInputs(); } + RefreshInputs(); + } + + private void CheckGebundenTypeFixed() { + FillingInputs = true; + if (SelectedGraphEntry?.GebundenFlatBonus is double bonus) { + GebundenTypeFixed.IsChecked = true; + GebundenFlatBonus.Text = $"{bonus}"; + EnableUnitTextBox(GebundenFlatBonus); + } else { + GebundenTypeGraph.IsChecked = true; + DisableUnitTextBox(GebundenFlatBonus); + } + FillingInputs = false; } } }