ChartWindow: Make gebunden type fixed more user friendly

This commit is contained in:
2024-01-21 12:48:40 +01:00
parent 182b367811
commit 89d20f4c42
5 changed files with 112 additions and 76 deletions

View File

@ -210,21 +210,21 @@ namespace Elwig.Helpers.Billing {
var x = graph.DataX; var x = graph.DataX;
var y = graph.DataY; var y = graph.DataY;
if (y.Distinct().Count() == 1) { if (y.Distinct().Count() == 1) {
return JsonValue.Create(graph.DataY[0]); return JsonValue.Create((decimal)graph.DataY[0]);
} }
var data = new JsonObject(); var data = new JsonObject();
if (y[0] != y[1]) { if (y[0] != y[1]) {
data.Add(new KeyValuePair<string, JsonNode?>(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++) { 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)) { if (Math.Round(y[i] - y[i - 1], 10) != Math.Round(y[i + 1] - y[i], 10)) {
data.Add(new KeyValuePair<string, JsonNode?>(x[i] + mode, Math.Round(y[i], graph.Precision))); data[$"{x[i]}{mode}"] = Math.Round(y[i], graph.Precision);
} }
} }
if (y[^1] != y[^2]) { if (y[^1] != y[^2]) {
data.Add(new KeyValuePair<string, JsonNode?>(x[^1] + mode, Math.Round(y[^1], graph.Precision))); data[$"{x[^1]}{mode}"] = Math.Round(y[^1], graph.Precision);
} }
return data; return data;
} }
@ -247,16 +247,6 @@ namespace Elwig.Helpers.Billing {
} }
public JsonObject FromGraphEntries(IEnumerable<GraphEntry> graphEntries) { public JsonObject FromGraphEntries(IEnumerable<GraphEntry> 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 { var data = new JsonObject {
["mode"] = "elwig", ["mode"] = "elwig",
["version"] = 1, ["version"] = 1,
@ -270,6 +260,16 @@ namespace Elwig.Helpers.Billing {
if (ConsiderAutoBusinessShares) if (ConsiderAutoBusinessShares)
data["consider_auto_business_shares"] = true; 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["payment"] = payment;
data["curves"] = curves; data["curves"] = curves;

View File

@ -69,7 +69,7 @@ namespace Elwig.Helpers.Billing {
return dict3 return dict3
.Select(e => new GraphEntry(e.Key, season.Precision, curves[e.Key], e.Value .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)) .Select(s => new ContractSelection(vars[s[..2]], s.Length > 2 ? attrs[s[2..]] : null))
.ToList(), 50, 73, 140)) .ToList()))
.ToList(); .ToList();
} }

View File

@ -28,6 +28,14 @@ namespace Elwig.Helpers.Billing {
DataY = DataX.Select(i => (double)BillingData.GetCurveValueAt(data, i)).ToArray(); 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) { private Graph(double[] dataX, double[] dataY, int precision, int minX, int maxX) {
Precision = precision; Precision = precision;
MinX = minX; MinX = minX;
@ -52,6 +60,10 @@ namespace Elwig.Helpers.Billing {
return DataY[index]; return DataY[index];
} }
public double GetPriceAtOe(double oe) {
return DataY[Array.IndexOf(DataX, oe)];
}
private void FlattenGraph(int begin, int end, double value) { private void FlattenGraph(int begin, int end, double value) {
for (int i = begin; i <= end; i++) { for (int i = begin; i <= end; i++) {
DataY[i] = value; DataY[i] = value;

View File

@ -1,77 +1,87 @@
using System.Collections.Generic; using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
namespace Elwig.Helpers.Billing { namespace Elwig.Helpers.Billing {
public class GraphEntry { public class GraphEntry {
public const int MinX = 50;
public const int MinXGeb = 73;
public const int MaxX = 140;
public int Id { get; set; } public int Id { get; set; }
private readonly int Precision;
public BillingData.CurveMode Mode { get; set; } public BillingData.CurveMode Mode { get; set; }
public bool Abgewertet { get; set; } public bool Abgewertet { get; set; }
public Graph DataGraph { get; set; } public Graph DataGraph { get; set; }
public Graph? GebundenGraph { get; set; } public Graph? GebundenGraph { get; set; }
public decimal? GebundenFlatBonus { get; set; } public double? GebundenFlatBonus {
public List<ContractSelection> Contracts { get; set; } get {
public string ContractsStringSimple => Contracts.Any() ? string.Join(", ", Contracts.Select(c => c.Listing)) : "-"; try {
public string ContractsString => Contracts.Any() ? string.Join("\n", Contracts.Select(c => c.FullName)) : "-"; return GebundenGraph?.DataX.Zip(GebundenGraph.DataY)
private int MinX { get; set; } .Select(e => Math.Round(e.Second - DataGraph.GetPriceAtOe(e.First), Precision))
private int MinXGebunden { get; set; } .Distinct()
private int MaxX { get; set; } .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<ContractSelection> 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; Id = id;
Precision = precision; Precision = precision;
Mode = mode; Mode = mode;
Abgewertet = false; DataGraph = new Graph(precision, MinX, MaxX); ;
MinX = minX;
MinXGebunden = minXGebunden;
MaxX = maxX;
DataGraph = new Graph(precision, minX, maxX);
Contracts = []; Contracts = [];
} }
public GraphEntry(int id, int precision, BillingData.CurveMode mode, Dictionary<double, decimal> data, Dictionary<double, decimal>? gebunden, public GraphEntry(int id, int precision, BillingData.CurveMode mode, Dictionary<double, decimal> data, Dictionary<double, decimal>? gebunden) :
int minX, int minXGebunden, int maxX) : this(id, precision, mode, minX, minXGebunden, maxX) { this(id, precision, mode) {
DataGraph = new Graph(data, precision, minX, maxX); DataGraph = new Graph(data, precision, MinX, MaxX);
if (gebunden != null) GebundenGraph = new Graph(gebunden, precision, minXGebunden, maxX); if (gebunden != null) GebundenGraph = new Graph(gebunden, precision, MinXGeb, MaxX);
} }
public GraphEntry(int id, int precision, BillingData.Curve curve, List<ContractSelection> contracts, int minX, int minXGebunden, int maxX) : public GraphEntry(int id, int precision, BillingData.Curve curve, List<ContractSelection> contracts) :
this(id, precision, curve.Mode, minX, minXGebunden, maxX) { this(id, precision, curve.Mode) {
DataGraph = new Graph(curve.Normal, precision, minX, maxX); DataGraph = new Graph(curve.Normal, precision, MinX, MaxX);
if (curve.Gebunden != null) if (curve.Gebunden != null)
GebundenGraph = new Graph(curve.Gebunden, precision, minXGebunden, maxX); GebundenGraph = new Graph(curve.Gebunden, precision, MinXGeb, MaxX);
Contracts = contracts; Contracts = contracts;
} }
private GraphEntry(int id, int precision, BillingData.CurveMode mode, Graph dataGraph, Graph? gebundenGraph, private GraphEntry(int id, int precision, BillingData.CurveMode mode, Graph dataGraph, Graph? gebundenGraph, List<ContractSelection> contracts) {
decimal? gebundenFlatPrice, List<ContractSelection> contracts, int minX, int minXGebunden, int maxX) {
Id = id; Id = id;
Precision = precision; Precision = precision;
Mode = mode; Mode = mode;
MinX = minX;
MinXGebunden = minXGebunden;
MaxX = maxX;
DataGraph = dataGraph; DataGraph = dataGraph;
GebundenGraph = gebundenGraph; GebundenGraph = gebundenGraph;
GebundenFlatBonus = gebundenFlatPrice;
Contracts = contracts; Contracts = contracts;
} }
public void AddGebundenGraph() { public void AddGebundenGraph() {
GebundenGraph ??= new Graph(Precision, MinXGebunden, MaxX); GebundenGraph ??= new Graph(Precision, MinXGeb, MaxX);
} }
public void RemoveGebundenGraph() { public void RemoveGebundenGraph() {
GebundenGraph = null; GebundenGraph = null;
} }
public void SetGebundenFlatBonus(decimal? value) {
GebundenFlatBonus = value;
}
public GraphEntry Copy(int id) { 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(), []);
} }
} }
} }

View File

@ -43,10 +43,6 @@ namespace Elwig.Windows {
private bool HoverActive = false; private bool HoverActive = false;
private bool FillingInputs = false; private bool FillingInputs = false;
private const int MinOechsle = 50;
private const int MinOechsleGebunden = 73;
private const int MaxOechsle = 140;
private List<GraphEntry> GraphEntries = []; private List<GraphEntry> GraphEntries = [];
private GraphEntry? SelectedGraphEntry; private GraphEntry? SelectedGraphEntry;
@ -125,12 +121,15 @@ namespace Elwig.Windows {
private void FillInputs() { private void FillInputs() {
FillingInputs = true; FillingInputs = true;
if (SelectedGraphEntry?.GebundenFlatBonus != null) { if (SelectedGraphEntry?.GebundenFlatBonus is double bonus) {
GebundenTypeFixed.IsChecked = true; GebundenTypeFixed.IsChecked = true;
GebundenFlatBonus.Text = $"{bonus}";
} else if (SelectedGraphEntry?.GebundenGraph != null) { } else if (SelectedGraphEntry?.GebundenGraph != null) {
GebundenTypeGraph.IsChecked = true; GebundenTypeGraph.IsChecked = true;
GebundenFlatBonus.Text = "";
} else { } else {
GebundenTypeNone.IsChecked = true; GebundenTypeNone.IsChecked = true;
GebundenFlatBonus.Text = "";
} }
ControlUtils.SelectCheckComboBoxItems(ContractInput, SelectedGraphEntry?.Contracts ?? [], i => (i as ContractSelection)?.Listing); ControlUtils.SelectCheckComboBoxItems(ContractInput, SelectedGraphEntry?.Contracts ?? [], i => (i as ContractSelection)?.Listing);
@ -165,7 +164,7 @@ namespace Elwig.Windows {
OechslePricePlot.Configuration.DoubleClickBenchmark = false; OechslePricePlot.Configuration.DoubleClickBenchmark = false;
//OechslePricePlot.Plot.XAxis.ManualTickSpacing(1); //OechslePricePlot.Plot.XAxis.ManualTickSpacing(1);
OechslePricePlot.Plot.YAxis.ManualTickSpacing(0.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.Layout(padding: 0);
OechslePricePlot.Plot.XAxis2.Layout(padding: 0); OechslePricePlot.Plot.XAxis2.Layout(padding: 0);
@ -247,17 +246,17 @@ namespace Elwig.Windows {
} }
private void LockZoom() { 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.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.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() { private void UnlockZoom() {
OechslePricePlot.Plot.XAxis.SetBoundary(); OechslePricePlot.Plot.XAxis.SetBoundary();
OechslePricePlot.Plot.YAxis.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); OechslePricePlot.Plot.YAxis.SetZoomOutLimit(3.5);
} }
@ -342,12 +341,11 @@ namespace Elwig.Windows {
private void PriceInput_TextChanged(object sender, TextChangedEventArgs evt) { private void PriceInput_TextChanged(object sender, TextChangedEventArgs evt) {
if (PrimaryMarkedPoint != -1 && ActiveGraph != null) { if (PrimaryMarkedPoint != -1 && ActiveGraph != null) {
bool success = double.TryParse(PriceInput.Text, out double price); if (double.TryParse(PriceInput.Text, out double price)) {
if (success) {
ActiveGraph.SetPriceAt(PrimaryMarkedPoint, price); ActiveGraph.SetPriceAt(PrimaryMarkedPoint, price);
PrimaryMarkedPointPlot.Y = price; PrimaryMarkedPointPlot.Y = price;
OechslePricePlot.Refresh(); OechslePricePlot.Refresh();
CheckGebundenTypeFixed();
} }
} }
} }
@ -358,6 +356,7 @@ namespace Elwig.Windows {
} }
ActiveGraph.FlattenGraphLeft(PrimaryMarkedPoint); ActiveGraph.FlattenGraphLeft(PrimaryMarkedPoint);
OechslePricePlot.Render(); OechslePricePlot.Render();
CheckGebundenTypeFixed();
} }
private void RightFlatButton_Click(object sender, RoutedEventArgs evt) { private void RightFlatButton_Click(object sender, RoutedEventArgs evt) {
@ -366,6 +365,7 @@ namespace Elwig.Windows {
} }
ActiveGraph.FlattenGraphRight(PrimaryMarkedPoint); ActiveGraph.FlattenGraphRight(PrimaryMarkedPoint);
OechslePricePlot.Render(); OechslePricePlot.Render();
CheckGebundenTypeFixed();
} }
private void InterpolateButton_Click(object sender, RoutedEventArgs evt) { private void InterpolateButton_Click(object sender, RoutedEventArgs evt) {
@ -374,6 +374,7 @@ namespace Elwig.Windows {
} }
ActiveGraph.InterpolateGraph(PrimaryMarkedPoint, SecondaryMarkedPoint); ActiveGraph.InterpolateGraph(PrimaryMarkedPoint, SecondaryMarkedPoint);
OechslePricePlot.Render(); OechslePricePlot.Render();
CheckGebundenTypeFixed();
} }
private void LinearIncreaseButton_Click(object sender, RoutedEventArgs e) { private void LinearIncreaseButton_Click(object sender, RoutedEventArgs e) {
@ -386,6 +387,7 @@ namespace Elwig.Windows {
} }
ActiveGraph.LinearIncreaseGraphToEnd(PrimaryMarkedPoint, priceIncrease.Value); ActiveGraph.LinearIncreaseGraphToEnd(PrimaryMarkedPoint, priceIncrease.Value);
OechslePricePlot.Render(); OechslePricePlot.Render();
CheckGebundenTypeFixed();
} }
private void OechslePricePlot_MouseDown(object sender, MouseEventArgs e) { private void OechslePricePlot_MouseDown(object sender, MouseEventArgs e) {
@ -500,7 +502,7 @@ namespace Elwig.Windows {
} }
private void AddButton_Click(object sender, RoutedEventArgs e) { 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); GraphEntries.Add(newGraphEntry);
GraphList.Items.Refresh(); GraphList.Items.Refresh();
GraphList.SelectedItem = newGraphEntry; GraphList.SelectedItem = newGraphEntry;
@ -600,9 +602,12 @@ namespace Elwig.Windows {
} }
private void GebundenFlatBonus_TextChanged(object sender, TextChangedEventArgs e) { private void GebundenFlatBonus_TextChanged(object sender, TextChangedEventArgs e) {
var r = Validator.CheckDecimal(GebundenFlatBonus.TextBox, true, 2, 8); if (FillingInputs) return;
if (r.IsValid) { var r = Validator.CheckDecimal(GebundenFlatBonus.TextBox, true, 2, Season.Precision);
SelectedGraphEntry?.SetGebundenFlatBonus(decimal.Parse(GebundenFlatBonus.Text)); if (r.IsValid && SelectedGraphEntry != null) {
SelectedGraphEntry.GebundenFlatBonus = double.Parse(GebundenFlatBonus.Text);
ResetPlot();
InitPlot();
} }
} }
@ -635,23 +640,32 @@ namespace Elwig.Windows {
if (SelectedGraphEntry == null) { if (SelectedGraphEntry == null) {
DisableUnitTextBox(GebundenFlatBonus); DisableUnitTextBox(GebundenFlatBonus);
return; return;
} else if (GebundenTypeNone.IsChecked == true) { }
SelectedGraphEntry.SetGebundenFlatBonus(null); if (GebundenTypeNone.IsChecked == true) {
SelectedGraphEntry.RemoveGebundenGraph(); SelectedGraphEntry.RemoveGebundenGraph();
DisableUnitTextBox(GebundenFlatBonus); DisableUnitTextBox(GebundenFlatBonus);
RefreshInputs();
} else if (GebundenTypeFixed.IsChecked == true) { } else if (GebundenTypeFixed.IsChecked == true) {
SelectedGraphEntry.SetGebundenFlatBonus(0); SelectedGraphEntry.GebundenFlatBonus = double.TryParse(GebundenFlatBonus.Text, out var val) ? val : 0.1;
SelectedGraphEntry.RemoveGebundenGraph(); SelectedGraphEntry.AddGebundenGraph();
EnableUnitTextBox(GebundenFlatBonus); EnableUnitTextBox(GebundenFlatBonus);
RefreshInputs();
} else if (GebundenTypeGraph.IsChecked == true) { } else if (GebundenTypeGraph.IsChecked == true) {
GebundenFlatBonus.Text = "";
SelectedGraphEntry.SetGebundenFlatBonus(null);
SelectedGraphEntry.AddGebundenGraph(); SelectedGraphEntry.AddGebundenGraph();
DisableUnitTextBox(GebundenFlatBonus); 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;
} }
} }
} }