using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using static System.Windows.Forms.VisualStyles.VisualStyleElement; using System.Windows.Forms.DataVisualization.Charting; using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Windows.Forms; using MathNet.Numerics.LinearAlgebra.Double; // 引入 Math.NET Numerics 库进行多项式拟合 using MathNet.Numerics; using System.IO; using System.Xml.Serialization; using System.Xml.Linq; using CloudWaterNetwork.建模; using static System.Windows.Forms.LinkLabel; using Series = System.Windows.Forms.DataVisualization.Charting.Series; using System.Drawing.Imaging; using static System.Windows.Forms.VisualStyles.VisualStyleElement.Status; using System.Reflection; namespace CloudWaterNetwork.建模 { public static class PointsExtansion { public static int FindNearest(this DataPointCollection dataPoints, double x) { var dataPoints_sort = dataPoints.ToList(); dataPoints_sort.Sort((a, b) => { return a.XValue > b.XValue ? 1 : -1; }); for (int i = 0; i < dataPoints_sort.Count; i++) { if (dataPoints_sort[i].XValue > x) { if (i == 0) return i; var left = x - dataPoints_sort[i - 1].XValue; var right = dataPoints_sort[i].XValue - x; if (right < left) return i; else return i - 1; } } return dataPoints_sort.Count - 1; } } public enum FactoryType { 水厂, 泵站 } public enum PumpType { 调速泵, 定速泵 } public class Dataset { public Dataset(string name) { Name = name; } public Dataset() { } public string Name { get; set; } public List Data { get; set; } = new List(); public int degree { get { return 2; } } public List ForumParams = null; public DenseVector coefficients = null; // 存储多项式系数 public double ErrNum { get { return -1; } } private int stepNum { get { return 50; } } private double step { get { return (range_X.Max - range_X.Min) / stepNum; } } /// /// 不需要读取 /// public string Legend { get { switch (Name) { case "流量扬程曲线": return "Legend1"; case "流量功率曲线": return "Legend1"; case "流量效率曲线": return "Legend1"; } return "Legend1"; } } public AxisType axisType { get { switch(Name) { case "流量扬程曲线": return AxisType.Primary; default: return AxisType.Secondary; } } } public void CurveFit() { if (!HasData) { IsFitted= false; return; } coefficients = Fit.Polynomial(Data.Select(p => (double)p.X).ToArray(), Data.Select(p => (double)p.Y).ToArray(), degree); if (range_X == null) { range_X = new Range(9999999, -9999999); Data.ForEach(p=> { if (range_X.Min > p.X) range_X.Min = p.X; if (range_X.Max= x1) ? x2 : x1; return x; } else { return ErrNum; } } public string getForum { get { // 生成多项式的字符串表示形式 string polyStr = "y="; for (int i = coefficients.Count - 1; i >= 0; i--) { if (coefficients[i] == 0) continue; if (i == coefficients.Count - 1) { polyStr += coefficients[i].ToString() + "x^" + i; } else if (i == 1) { if (coefficients[i] > 0) { if (polyStr != "") polyStr += " + "; polyStr += coefficients[i].ToString() + "x"; } else { polyStr += " - " + (-coefficients[i]).ToString() + "x"; } } else if (i == 0) { if (coefficients[i] > 0) { if (polyStr != "") polyStr += " + "; polyStr += coefficients[i].ToString(); } else { polyStr += " - " + (-coefficients[i]).ToString(); } } else { if (coefficients[i] > 0) { if (polyStr != "") polyStr += " + "; polyStr += coefficients[i].ToString() + "x^" + i; } else { polyStr += " - " + (-coefficients[i]).ToString() + "x^" + i; } } } if (polyStr == "") polyStr = "0"; return polyStr; } } public double YMax { get { if (!IsFitted) return ErrNum; double a = coefficients[degree]; double b = coefficients[degree - 1]; double c = coefficients[0]; double delta = b * b - 4 * a * c; double minExtremePoint = -b / (2 * a); // 计算导函数的零点 double maxValue = 0; if (a<0) maxValue =- delta / (4 * a) + c; else maxValue = a * minExtremePoint * minExtremePoint + b * minExtremePoint + c; // 计算最小值 return maxValue; } } public double YdataMax { get { double max = -99999; foreach(var p in Data) { if (max < p.Y) max = p.Y; } return max; } } public bool is_Yvalue_validate(double y) { if (!IsFitted) return false; double a = coefficients[degree]; if (a < 0) return y <= YMax; else return y >= YMax; } /// /// X显示的范围 /// public Range range_X; /// /// Y显示的范围 /// public Range range_Y; public bool HasData { get { return Data.Count >= 3; } } public bool IsFitted = false; public List FittedCurve { get { List doubles = new List(); for (double x = range_X.Min; x <= range_X.Max; x += step) { double y = Evaluate(x); //chart.Series[1].Points.AddXY(x, y); doubles.Add(new PointF ((float) x,(float) y )); } return doubles; } } public List FittedCurvebyRange(Range range) { List doubles = new List(); if (range==null) { range = new Range(); range.Min = range_X.Min; range.Max = range_X.Max; } var step = (range.Max - range.Min) / stepNum; for (double x = range.Min; x <= range.Max; x += step) { double y = Evaluate(x); //chart.Series[1].Points.AddXY(x, y); doubles.Add(new PointF((float)x, (float)y)); } return doubles; } } public class Range { public Range() { } public Range(double Min,double Max) { this.Min = Min; this.Max = Max; } public double Max; public double Min; public double Len { get { return Max - Min; } } public static Range Union(Range a,Range b) { return new Range(a.Min < b.Min ? a.Min : b.Min, a.Max > b.Max ? a.Max : b.Max); } public bool isValid { get { return Min < Max; } } } public class Pump { public Pump() { Datasets = new Dictionary() { {"流量扬程曲线",new Dataset("流量扬程曲线") }, {"流量功率曲线",new Dataset("流量功率曲线") }, {"流量效率曲线",new Dataset("流量效率曲线") } //,new Dataset("流量功率曲线"),new Dataset("流量效率曲线") }; } public string Name { get; set; } public PumpType Type { get; set; } public Dictionary Datasets { get; set; } public string factoryName = ""; public double 额定转速 { get; set; } = 1500; public double 额定流量 { get; set; } = 0; public double 额定扬程 { get; set; } = 0; public double 额定功率 { get; set; } = 75; public Dataset 流量扬程曲线 { get { return Datasets["流量扬程曲线"]; } } public Dataset 流量功率曲线 { get { return Datasets["流量功率曲线"]; } } public Dataset 流量效率曲线 { get { return Datasets["流量效率曲线"]; } } public void CurveFit() { foreach (var data in Datasets) { data.Value.Data.Sort((a, b) => a.X > b.X ? 1 : -1); if (data.Value.HasData) data.Value.CurveFit(); } string basetype = "流量扬程曲线"; string type = ""; type = "流量效率曲线"; var type1 = "流量功率曲线"; if (Datasets[type].IsFitted) { List points = new List(); List points1 = new List(); foreach (var yc in Datasets[basetype].Data) { float x= yc.X; float y_扬程 = yc.Y; float y_效率= (float)Datasets[type].Evaluate(x); points.Add(new PointF(x, y_效率)); points1.Add(new PointF(x,x* y_扬程 / y_效率 /3.6f )); } Datasets[type].Data = points; Datasets[type1].Data = points1; Datasets[type1].CurveFit(); } //type = "流量功率曲线"; //if (Datasets[type].IsFitted) //{ // List points = new List(); // foreach (var x in Datasets[basetype].Data.Select(p => p.X)) // { // points.Add(new PointF(x, (float)Datasets[type].Evaluate(x))); // } // Datasets[type].Data = points; //} } public void ShowInGrid(DataGridView dataGridView) { dataGridView.Rows.Clear(); for (int i = 0; i < 流量扬程曲线.Data.Count; i++) { PointF p = 流量扬程曲线.Data[i]; double y1 = 0, y2 = 0; if (流量功率曲线.IsFitted) y1 = 流量功率曲线.Data[i].Y; if (流量效率曲线.IsFitted) y2 = 流量效率曲线.Data[i].Y; dataGridView.Rows.Add(Math.Round(p.X,1), Math.Round(p.Y,2), Math.Round(y1,2), Math.Round(y2, 2)); } } public void AddCurve(Chart chart, string type = "流量扬程曲线",bool onlyOne=false,Range Force_range_X=null) { Series series; List Points; List FittedCurve; string baseType = "流量扬程曲线"; string baseType2 = "流量效率曲线"; if (onlyOne) { if (Datasets[type].IsFitted) { FittedCurve = Datasets[type].FittedCurvebyRange(Force_range_X); series = AddSeries("ChartArea1", SeriesChartType.Spline, Datasets[type].Legend, Datasets[type].axisType, $"{factoryName}_{Name}_{type}", FittedCurve, true); chart.Series.Add(series); } } else { Points = Datasets[type].Data; series = AddSeries("ChartArea1", SeriesChartType.Point, Datasets[type].Legend, Datasets[type].axisType, $"{type}点", Points, false); chart.Series.Add(series); var series0 = series; foreach (var data in Datasets) { var type0 = data.Key; if (!Datasets[type0].IsFitted) continue; FittedCurve = Datasets[type0].FittedCurve; series = AddSeries("ChartArea1", SeriesChartType.Spline, Datasets[type0].Legend, Datasets[type0].axisType, $"{factoryName}_{Name}_{type0}", FittedCurve, true); chart.Series.Add(series); } if (chart.Series.Count==1&& series0.Points.Count == 0) { series0.Points.Add(-2, -2); series0.Points.Add(-1, -1); series0.IsVisibleInLegend = true; series0.YAxisType = AxisType.Primary; chart.ChartAreas[0].AxisX.Minimum = 0; chart.ChartAreas[0].AxisX.Maximum = 3000; chart.ChartAreas[0].AxisY.Minimum = 0; chart.ChartAreas[0].AxisY.Maximum = 50; chart.ChartAreas[0].AxisY2.Minimum = 0; chart.ChartAreas[0].AxisY2.Maximum = 100; return; } } Range range_X = null; if (Force_range_X != null && Force_range_X.isValid) { range_X = Force_range_X; } else if (Datasets[type].range_X!=null && Datasets[type].range_X.isValid) { range_X=Datasets[type].range_X; } else if (Datasets[baseType].range_X != null && Datasets[baseType].range_X.isValid) { range_X= Datasets[baseType].range_X; } else { range_X = new Range(double.NaN, double.NaN); } chart.ChartAreas[0].AxisX.Minimum = range_X.Min; chart.ChartAreas[0].AxisX.Maximum = range_X.Max; if (Datasets[baseType].range_Y != null && Datasets[baseType].range_Y.isValid) { // 设置 X 轴的最大最小值 chart.ChartAreas[0].AxisY.Minimum = Datasets[baseType].range_Y.Min; chart.ChartAreas[0].AxisY.Maximum = Datasets[baseType].range_Y.Max; } else { chart.ChartAreas[0].AxisY.Minimum = double.NaN; chart.ChartAreas[0].AxisY.Maximum = double.NaN; } if (type!=baseType && Datasets[type].range_Y != null) { // 设置 X 轴的最大最小值 chart.ChartAreas[0].AxisY2.Minimum = Datasets[type].range_Y.Min; chart.ChartAreas[0].AxisY2.Maximum = Datasets[type].range_Y.Max; } else if (Datasets[baseType2].range_Y != null) { // 设置 X 轴的最大最小值 chart.ChartAreas[0].AxisY2.Minimum = Datasets[baseType2].range_Y.Min; chart.ChartAreas[0].AxisY2.Maximum = Datasets[baseType2].range_Y.Max; } else { chart.ChartAreas[0].AxisY2.Minimum = 0; chart.ChartAreas[0].AxisY2.Maximum = 100; } } private Series AddSeries(string Area, SeriesChartType type, String Legend, AxisType axisType, String Name, List Points, bool showLegend = true) { Series series = new Series(); series.ChartArea = Area; series.ChartType = type; series.Legend = Legend; series.Name = Name; series.IsVisibleInLegend = showLegend; series.YAxisType = axisType; if (Points != null) Points.ForEach(p => series.Points.AddXY(p.X, p.Y)); return series; } } public class Factory { public string Name { get; set; } public FactoryType Type { get; set; } public List Pumps { get; set; } public void CurveFit() { foreach(var p in Pumps) { p.CurveFit(); } } } public class FactoryList { public List Factories { get; set; } public FactoryList() { Factories = new List(); } public void AddFactory(string name, FactoryType type) { Factories.Add(new Factory { Name = name, Type = type, Pumps = new List() }); } public Pump AddPump(Factory factory, string name, PumpType type) { Pump pump = new Pump { Name = name, Type = type, factoryName = factory.Name }; factory.Pumps.Add(pump); return pump; } public void RemoveFactory(Factory factory) { Factories.Remove(factory); } private readonly string _filePath = "data.txt"; private readonly string _bakPath = "bak\\"; //public FactoryListFileManager(string filePath) //{ // _filePath = filePath; //} public void Save() { if (File.Exists(_filePath)) { FileInfo fi=new FileInfo(_filePath); if (!Directory.Exists(_bakPath)) Directory.CreateDirectory(_bakPath); string bakName = Path.Combine(_bakPath, $"data.txt_bak_{fi.LastWriteTime.ToString("yyyy_MM_dd_HH_mm_ss")}"); File.Copy(_filePath, bakName, true); } var sb = new StringBuilder(); foreach (var factory in Factories) { // 写入工厂信息 sb.AppendLine($"Factory,{factory.Type},{factory.Name}"); foreach (var pump in factory.Pumps) { // 写入水泵信息 sb.AppendLine($"Pump,{pump.Type},{pump.Name},{pump.额定转速},{pump.额定流量},{pump.额定扬程},{pump.额定功率}"); foreach (var dataset in pump.Datasets) { // 写入数据集信息 sb.AppendLine($"Dataset,{dataset.Value.Name}"); if (dataset.Value.range_X!=null) sb.AppendLine($"Dataset_Range_X,{dataset.Value.range_X.Min},{dataset.Value.range_X.Max}"); if (dataset.Value.range_Y != null) sb.AppendLine($"Dataset_Range_Y,{dataset.Value.range_Y.Min},{dataset.Value.range_Y.Max}"); if (dataset.Value.Data != null) foreach (var point in dataset.Value.Data) { // 写入数据点信息 sb.AppendLine($"{point.X},{point.Y}"); } } } } // 将数据写入文件 File.WriteAllText(_filePath, sb.ToString()); } public void Load() { //var factoryList = new FactoryList(); Factories.Clear(); if (!File.Exists(_filePath)) { return; } var currentFactory = default(Factory); var currentPump = default(Pump); var currentDataset = default(Dataset); foreach (var line in File.ReadAllLines(_filePath)) { var fields = line.Split(','); switch (fields[0]) { case "Factory": // 读取工厂信息 var factoryType = (FactoryType)Enum.Parse(typeof(FactoryType), fields[1]); var factoryName = fields[2]; currentFactory = new Factory { Name = factoryName, Type = factoryType, Pumps = new List() }; this.Factories.Add(currentFactory); currentPump = null; currentDataset = null; break; case "Pump": // 读取水泵信息 var pumpType = (PumpType)Enum.Parse(typeof(PumpType), fields[1]); var pumpName = fields[2]; currentPump = new Pump { Name = pumpName, Type = pumpType, factoryName = currentFactory.Name, 额定转速 = double.Parse(fields[3]), 额定流量 = double.Parse(fields[4]), 额定扬程 = double.Parse(fields[5]), 额定功率 = fields.Length >= 7 ? double.Parse(fields[6]) : 75 }; currentFactory.Pumps.Add(currentPump); currentDataset = null; break; case "Dataset": // 读取数据集信息 var datasetName = fields[1]; currentDataset = new Dataset { Name = datasetName, Data = new List() }; currentPump.Datasets[currentDataset.Name] = currentDataset; break; case "Dataset_Range_X": { double d1 = 0; double d2 = 0; if (double.TryParse(fields[1], out d1) && double.TryParse(fields[2], out d2)) { currentDataset.range_X = new Range(d1, d2); } break; } case "Dataset_Range_Y": { double d1 = 0; double d2 = 0; if (double.TryParse(fields[1], out d1) && double.TryParse(fields[2], out d2)) { currentDataset.range_Y = new Range(d1, d2); } break; } default: // 读取数据点信息 var x = float.Parse(fields[0]); var y = float.Parse(fields[1]); currentDataset.Data.Add(new PointF(x, y)); break; } } CurveFit(); //return factoryList; } public void CurveFit() { foreach (var f in Factories) { f.CurveFit(); } } } }