namespace IStation.Curve { /// /// 曲线拟合辅助类 /// public class FitHelper { /// /// /// public FitHelper(CurveExpress express) { switch (express.FitType) { case eFitType.ThroughPoint: _fitPoint = new TwinRelateCurve0(express); break; case eFitType.LinearCurve: _fitPoint = new TwinRelateCurve1(express); break; case eFitType.ConicCurveB0: _fitPoint = new TwinRelateCurve2B0(express); break; case eFitType.ConicCurve: _fitPoint = new TwinRelateCurve2M(express); break; case eFitType.CubicCurve: _fitPoint = new TwinRelateCurve3M(express); break; case eFitType.FourM: _fitPoint = new TwinRelateCurve4M(express); break; default: break; } } /// /// /// public FitHelper(List points, eFitType fitType = eFitType.CubicCurve) { switch (fitType) { case eFitType.ThroughPoint: _fitPoint = new TwinRelateCurve0(points); break; case eFitType.LinearCurve: _fitPoint = new TwinRelateCurve1(points); break; case eFitType.ConicCurveB0: _fitPoint = new TwinRelateCurve2B0(points); break; case eFitType.ConicCurve: _fitPoint = new TwinRelateCurve2M(points); break; case eFitType.CubicCurve: _fitPoint = new TwinRelateCurve3M(points); break; case eFitType.FourM: _fitPoint = new TwinRelateCurve4M(points); break; default: break; } } //拟合接口对象 private IFitPoint _fitPoint = null; /// /// 获取曲线拟合点Y值 /// public double GetFitPointY(double x) { if (_fitPoint == null) return default; return _fitPoint.GetFitPointY(x); } /// /// 获取拟合点列表 /// public List GetFitPoints(int pointNumber) { if (_fitPoint == null) return default; return _fitPoint.GetFitPoints(pointNumber); } /// /// 通过X区间获取拟合点列表 /// public List GetFitPointsByXRange(double minX, double maxX, int pointNumber) { if (_fitPoint == null) return default; return _fitPoint.GetFitPointsByXRange(minX, maxX, pointNumber); } /// /// 获取拟合点Y /// public static double GetFitPointY(CurveExpress express, double x) { if (express == null) return default; var helper = new FitHelper(express); return helper.GetFitPointY(x); } /// /// 获取拟合点 /// public static List GetFitPoints(List points, eFitType fitType = eFitType.CubicCurve, int pointNumber = 12) { if (points == null || !points.Any()) return default; var express = BuildCurveExpress(points, fitType); var helper = new FitHelper(express); return helper.GetFitPoints(pointNumber); } /// /// 获取拟合点 /// public static List GetFitPoints(CurveExpress express, int pointNumber) { if (express == null) return default; var helper = new FitHelper(express); return helper.GetFitPoints(pointNumber); } /// /// 获取拟合点 /// public static List GetFitPointsByXRange(CurveExpress express, double minX, double maxX, int pointNumber) { if (express == null) return default; var helper = new FitHelper(express); return helper.GetFitPointsByXRange(minX, maxX, pointNumber); } /// /// 获取拟合次方 /// public static int GetFitPow(eFitType fitType) { switch (fitType) { case eFitType.CubicCurve: return 3; case eFitType.ConicCurve: return 2; case eFitType.ConicCurveB0: return 2; case eFitType.LinearCurve: return 1; case eFitType.ThroughPoint: return 0; case eFitType.FourM: return 4; default: return 3; } } /// /// 获取拟合类型 /// public static eFitType GetFitType(int fitPow) { switch (fitPow) { case 3: return eFitType.CubicCurve; case 2: return eFitType.ConicCurve; case 1: return eFitType.LinearCurve; case 0: return eFitType.ThroughPoint; case 4: return eFitType.FourM; default: return eFitType.CubicCurve; } } /// /// 创建曲线表达式 /// public static CurveExpress BuildCurveExpress(List points, eFitType fitType = eFitType.CubicCurve) { if (points == null || !points.Any()) { return default; } switch (fitType) { case eFitType.ThroughPoint: return TwinRelateCurve0.BuildCurveExpress(points); case eFitType.LinearCurve: return TwinRelateCurve1.BuildCurveExpress(points); case eFitType.ConicCurveB0: return TwinRelateCurve2B0.BuildCurveExpress(points); case eFitType.ConicCurve: return TwinRelateCurve2M.BuildCurveExpress(points); case eFitType.CubicCurve: return TwinRelateCurve3M.BuildCurveExpress(points); case eFitType.FourM: return TwinRelateCurve4M.BuildCurveExpress(points); default: return default; } } #region 获得X值 /// /// 获取线性插值X(可能有多个点) /// public static List GetInterPointX(List pts, double y) { if (pts == null || pts.Count < 2) { return default; } var list = new List(); for (int i = 0; i < pts.Count - 1; i++) { if ((y >= pts[i].Y && y <= pts[i + 1].Y) || (y <= pts[i].Y && y >= pts[i + 1].Y)) {//直线插值 double x; if (Math.Abs(pts[i].Y - pts[i + 1].Y) < 0.01) x = (pts[i].X + pts[i + 1].X) * 0.5; else x = pts[i].X + (pts[i + 1].X - pts[i].X) * (y - pts[i].Y) / (pts[i + 1].Y - pts[i].Y); list.Add(new CurvePoint(x, y)); } } return list; } /// /// 获取线性插值X(可能有多个点)(允许延长) /// public static List GetInterPointXByExtend(List pts, double y) { if (pts == null || pts.Count < 2) { return default; } //在范围内 var minY = pts.Min(x => x.Y); var maxY = pts.Max(x => x.Y); if (y >= minY && y <= maxY) { return GetInterPointX(pts, y); } var list = new List(); //判断是否在前面的延长部分 double x_start = CurveLineHelper.GetXbyY(pts[0].X, pts[0].Y, pts[1].X, pts[1].Y, y); if (x_start <= pts[0].X) { if (x_start > 0 && x_start > pts[0].X * 0.9)//放一点余量 { list.Add(new CurvePoint(x_start, y)); } } //判断是否在后面的延长部分:U型曲线 是前后都有 double x_end = CurveLineHelper.GetXbyY(pts[pts.Count - 2].X, pts[pts.Count - 2].Y, pts[pts.Count - 1].X, pts[pts.Count - 1].Y, y); if (x_end >= pts[pts.Count - 1].X && x_end < pts[pts.Count - 1].X * 1.1)//放一点余量 { list.Add(new CurvePoint(x_end, y)); } return list; } /// /// 获取线性插值X(可能有多个点) /// public static List GetInterPointX(CurveExpress express, double y, int pointNumber = 20, double extendRatio = 1.0) { if (express == null) { return default; } var pts = express.GetFitPointsByXRange(express.Min, express.Max * extendRatio, pointNumber); return GetInterPointX(pts, y); } /// /// 获取线性插值X(可能有多个点)(允许延长) /// public static List GetInterPointXByExtend(CurveExpress express, double y, int pointNumber = 20, double extendRatio = 1.2) { if (express == null) { return default; } var pts = express.GetFitPointsByXRange(express.Min, express.Max * extendRatio, pointNumber); return GetInterPointXByExtend(pts, y); } #endregion 获得X值 } }