using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace IStation.Model { /// /// 样条曲线(三次拟合):使用MathNet /// public class TwinRelateCurve3M : IFitCurvePoint { /// /// /// /// public TwinRelateCurve3M(CurveExpress express) { _express = express; } /// /// /// /// /// public TwinRelateCurve3M(List points) { if (points == null || points.Count < 4) { throw new Exception("出现数值计算问题 ,无法解出三次样条曲线!"); } _express = BuildCurveExpress(points); } private CurveExpress? _express = null; /// /// 创建曲线表达式 /// public static CurveExpress BuildCurveExpress(List points) { if (points == null || points.Count() < 3) return null; Model.CurveExpress express = new CurveExpress(); express.DefinePoints = points ; var X = (from x in points select x.X).ToArray(); var Y = (from x in points select x.Y).ToArray(); var min = X.Min(); var max = X.Max(); var res = IStation.Numerics.Fit.Polynomial(X, Y, 3); //曲线类型 express.FitPow = 3; express.FitType = eCurveFitType.CubicCurve; express.DefinePoints = points.Select(x => new CurvePoint(x)).ToList(); //范围 express.Min = X.Min(); //最小值 express.Max = X.Max();//最大值 //0次方 express.Index0 = res[0]; //1次方 express.Index1 = res[1]; //2次方 express.Index2 = res[2]; //3次方 express.Index3 = res[3]; return express; } /// /// 获取拟合点Y /// public double GetFitPointY(double x) { if (_express == null) return default; var dx = x;// - _express.Min; //不用减掉最小值, 和alglib有点不一样 return _express.Index3 * dx * dx * dx + _express.Index2 * dx * dx + _express.Index1 * dx + _express.Index0; } /// /// 获取拟合点列表 /// /// /// public List? GetFitPoints(int pointNumber) { if (_express == null) return null; if (pointNumber < 1) pointNumber = 12; if (pointNumber > 10000) pointNumber = 10000; double space = (_express.Max - _express.Min) / (pointNumber - 1); if (space < 0.0001) return null; List< IStation.Model.CurvePoint> points = new List(); for (int i = 0; i < pointNumber; i++) { double x = space * i + _express.Min; double y = GetFitPointY(x); points.Add(new IStation.Model.CurvePoint(x, y)); } return points; } /// /// 通过区间获取拟合点列表 /// /// /// /// /// public List? GetFitPointsByRange(double x_min, double x_max, int pointNumber) { if (pointNumber < 1) pointNumber = 12; if (pointNumber > 10000) pointNumber = 10000; if(x_min >= x_max) {//交换大小 var x_m = x_max; x_max = x_min; x_min = x_m; } double space = (x_max - x_min) / (pointNumber - 1); if (space < 0.0001) return default; if (_express == null) return null; if (pointNumber < 1) pointNumber = 12; if (pointNumber > 10000) pointNumber = 10000; if (space < 0.0001) return null; List points = new List(); for (int i = 0; i < pointNumber; i++) { double x = space * i + x_min; double y = GetFitPointY(x); points.Add(new IStation.Model.CurvePoint(x, y)); } return points; } /// /// 获取拟合点Y /// public static double GetFitPointY(CurveExpress express, double x) { if (express == null) return default; if (express.IsNull) return default; return new TwinRelateCurve3M(express).GetFitPointY(x); } /// /// 获取拟合点Y /// public static double GetFitPointY(List points, double x) { if (points == null || points.Count < 4) return default; return new TwinRelateCurve3M(points).GetFitPointY(x); } /// /// 获取拟合点 /// public static List? GetFitPoints(CurveExpress express, int pointNumber) { if (express == null) return default; return GetFitPointsByRange(express, express.Min, express.Max, pointNumber); } /// /// 通过区间获取拟合点列表 /// public static List? GetFitPointsByRange(CurveExpress express, double x_min, double x_max, int pointNumber) { if (express == null) return default; return new TwinRelateCurve3M(express).GetFitPointsByRange(x_min, x_max, pointNumber); } } }