namespace IStation.Curve
|
{
|
/// <summary>
|
/// 曲线拟合辅助类
|
/// </summary>
|
public class FitHelper
|
{
|
/// <summary>
|
///
|
/// </summary>
|
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;
|
}
|
}
|
|
/// <summary>
|
///
|
/// </summary>
|
public FitHelper(List<CurvePoint> 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;
|
|
/// <summary>
|
/// 获取曲线拟合点Y值
|
/// </summary>
|
public double GetFitPointY(double x)
|
{
|
if (_fitPoint == null)
|
return default;
|
return _fitPoint.GetFitPointY(x);
|
}
|
|
/// <summary>
|
/// 获取拟合点列表
|
/// </summary>
|
public List<CurvePoint> GetFitPoints(int pointNumber)
|
{
|
if (_fitPoint == null)
|
return default;
|
return _fitPoint.GetFitPoints(pointNumber);
|
}
|
|
/// <summary>
|
/// 通过X区间获取拟合点列表
|
/// </summary>
|
public List<CurvePoint> GetFitPointsByXRange(double minX, double maxX, int pointNumber)
|
{
|
if (_fitPoint == null)
|
return default;
|
return _fitPoint.GetFitPointsByXRange(minX, maxX, pointNumber);
|
}
|
|
/// <summary>
|
/// 获取拟合点Y
|
/// </summary>
|
public static double GetFitPointY(CurveExpress express, double x)
|
{
|
if (express == null)
|
return default;
|
var helper = new FitHelper(express);
|
return helper.GetFitPointY(x);
|
}
|
|
/// <summary>
|
/// 获取拟合点
|
/// </summary>
|
public static List<CurvePoint> GetFitPoints(List<CurvePoint> 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);
|
}
|
|
|
/// <summary>
|
/// 获取拟合点
|
/// </summary>
|
public static List<CurvePoint> GetFitPoints(CurveExpress express, int pointNumber)
|
{
|
if (express == null)
|
return default;
|
var helper = new FitHelper(express);
|
return helper.GetFitPoints(pointNumber);
|
}
|
|
/// <summary>
|
/// 获取拟合点
|
/// </summary>
|
public static List<CurvePoint> 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);
|
}
|
|
/// <summary>
|
/// 获取拟合次方
|
/// </summary>
|
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;
|
}
|
}
|
|
/// <summary>
|
/// 获取拟合类型
|
/// </summary>
|
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;
|
}
|
}
|
|
/// <summary>
|
/// 创建曲线表达式
|
/// </summary>
|
public static CurveExpress BuildCurveExpress(List<CurvePoint> 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值
|
|
/// <summary>
|
/// 获取线性插值X(可能有多个点)
|
/// </summary>
|
public static List<CurvePoint> GetInterPointX(List<CurvePoint> pts, double y)
|
{
|
if (pts == null || pts.Count < 2)
|
{
|
return default;
|
}
|
var list = new List<CurvePoint>();
|
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;
|
}
|
|
/// <summary>
|
/// 获取线性插值X(可能有多个点)(允许延长)
|
/// </summary>
|
public static List<CurvePoint> GetInterPointXByExtend(List<CurvePoint> 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<CurvePoint>();
|
|
//判断是否在前面的延长部分
|
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;
|
}
|
|
/// <summary>
|
/// 获取线性插值X(可能有多个点)
|
/// </summary>
|
public static List<CurvePoint> 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);
|
}
|
|
/// <summary>
|
/// 获取线性插值X(可能有多个点)(允许延长)
|
/// </summary>
|
public static List<CurvePoint> 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值
|
|
}
|
}
|