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值
}
}