namespace IStation.Curve
|
{
|
public static class CurveExpress_Extensions
|
{
|
|
#region CurveFunction
|
|
/// <summary>
|
/// 获取曲线方程
|
/// </summary>
|
public static string GetCurveFunction(this CurveExpress express, string xName = "Q")
|
{
|
|
StringBuilder sb = new StringBuilder();
|
sb.Append(Math.Abs(express.Index0).ToString("0.00"));
|
|
if (express.Index1 > 0)
|
sb.Append(" + ");
|
else
|
sb.Append(" - ");
|
sb.Append(Math.Abs(express.Index1).ToString("0.0000"));
|
sb.Append(" * ");
|
sb.Append(xName);
|
|
if (express.Index2 > 0)
|
sb.Append(" + ");
|
else
|
sb.Append(" - ");
|
sb.Append(Math.Abs(express.Index2).ToString("0.000000000"));
|
sb.Append(" * ");
|
sb.Append(xName);
|
sb.Append("^2 ");
|
|
|
if (express.Index3 > 0)
|
sb.Append(" + ");
|
else
|
sb.Append(" - ");
|
sb.Append(Math.Abs(express.Index3).ToString("0.000000000000"));
|
sb.Append(" * ");
|
sb.Append(xName);
|
sb.Append("^3 ");
|
|
return sb.ToString();
|
}
|
|
/// <summary>
|
/// 获取
|
/// </summary>
|
/// <param name="functionIndex"></param>
|
/// <param name="functionCoeff"></param>
|
/// <param name="signValue"></param>
|
/// <param name="IndexValue"></param>
|
private static void GetFuncScientificValue(int functionIndex, double functionCoeff, ref double signValue, ref int IndexValue)
|
{
|
string strList = "";
|
if (functionIndex == 0)
|
{
|
strList = functionCoeff.ToString("0.000e+000");
|
}
|
else if (functionIndex == 1)
|
{
|
strList = functionCoeff.ToString("0.000000e+000");
|
}
|
else if (functionIndex == 2)
|
{
|
strList = functionCoeff.ToString("#.#########e+000");
|
}
|
else if (functionIndex == 3)
|
{
|
strList = functionCoeff.ToString("#.############e+000");
|
}
|
string[] st1 = null;
|
st1 = strList.Split('e');
|
signValue = Convert.ToDouble(st1[0]);
|
IndexValue = Convert.ToInt32(st1[1]);
|
}
|
|
#endregion
|
|
#region List<CurvePoint> Extend
|
|
/// <summary>
|
/// 获取拟合点
|
/// </summary>
|
public static List<CurvePoint> GetFitPointsByExtend(this CurveExpress express, double ratioExtend, int pointNumber)
|
{
|
if (express == null)
|
return default;
|
var helper = new FitHelper(express);
|
return helper.GetFitPointsByXRange(express.Min, express.Max * ratioExtend, pointNumber);
|
}
|
|
/// <summary>
|
/// 获取拟合点
|
/// </summary>
|
public static List<CurvePoint> GetFitPointsByExtend(this CurveExpress express, double ratioExtendmin, double ratioExtendmax, int pointNumber)
|
{
|
if (express == null)
|
return default;
|
var helper = new FitHelper(express);
|
return helper.GetFitPointsByXRange(express.Min * ratioExtendmin, express.Max * ratioExtendmax, pointNumber);
|
}
|
|
#endregion
|
|
#region 获得X值
|
|
/// <summary>
|
/// 获得Y值的坐标位置,多个点里取最后一个点(是线形插值,不是曲线上的点)
|
/// </summary>
|
/// <param name="curve"></param>
|
/// <param name="y"></param>
|
/// <param name="interPointNum"></param>
|
/// <returns></returns>
|
public static double? GetInterPointLastX(this CurveExpress curve, double y, int interPointNum = 20)
|
{
|
if (curve == null)
|
return null;
|
var points = FitHelper.GetFitPoints(curve, interPointNum);
|
if (points == null)
|
return null;
|
|
//在范围内
|
double maxY = (from yyy in points select yyy.Y).Max();
|
double minY = (from yyy in points select yyy.Y).Min();
|
|
if (double.IsNaN(maxY) || double.IsNaN(minY))
|
return null;
|
if (y < minY || y > maxY)
|
return null;
|
|
var list = points.GetPointsByInterPointX(y);
|
if (list == null || list.Count < 1)
|
return null;
|
|
return list.Last().X;
|
}
|
|
|
/// <summary>
|
/// 获得Y值的坐标位置,可能有多个点(是线形插值,不是曲线上的点):会计算延长部分:而且要求points点按照从小到大排序
|
/// </summary>
|
/// <param name="curve"></param>
|
/// <param name="y"></param>
|
/// <param name="interPointNum"></param>
|
/// <returns></returns>
|
public static List<CurvePoint> GetInterPointExX(this CurveExpress curve, double y, int interPointNum)
|
{
|
if (curve == null)
|
return null;
|
var points = FitHelper.GetFitPoints(curve, interPointNum);
|
if (points == null)
|
return null;
|
|
//在范围内
|
double maxY = (from yyy in points select yyy.Y).Max();
|
double minY = (from yyy in points select yyy.Y).Min();
|
|
if (double.IsNaN(maxY) || double.IsNaN(minY))
|
return null;
|
if (y > minY && y < maxY)
|
{
|
return points.GetPointsByInterPointX(y);
|
}
|
|
List<CurvePoint> ptList = new List<CurvePoint>();
|
|
//判断是否在前面的延长部分
|
double x_start = CurveLineHelper.GetXbyY(points[0].X, points[0].Y, points[1].X, points[1].Y, y);
|
if (x_start <= points[0].X)
|
{
|
if (x_start > 0 && x_start > points[0].X * 0.9)//放一点余量
|
ptList.Add(new CurvePoint(x_start, y));
|
}
|
|
//判断是否在后面的延长部分:U型曲线 是前后都有
|
double x_end = CurveLineHelper.GetXbyY(points[points.Count - 2].X, points[points.Count - 2].Y, points[points.Count - 1].X, points[points.Count - 1].Y, y);
|
if (x_end >= points[points.Count - 1].X && x_end < points[points.Count - 1].X * 1.1)//放一点余量
|
{
|
ptList.Add(new CurvePoint(x_end, y));
|
}
|
|
if (ptList.Count == 0)
|
return null;
|
return ptList;
|
}
|
|
|
|
/// <summary>
|
/// 获得Y值的坐标位置,可能有多个点(是线形插值,不是曲线上的点):会计算延长部分:而且要求points点按照从小到大排序
|
/// </summary>
|
/// <param name="curve"></param>
|
/// <param name="y"></param>
|
/// <param name="interPointNum"></param>
|
/// <param name="extendRatio"></param>
|
/// <returns></returns>
|
public static List<CurvePoint> GetInterPointExX(this CurveExpress curve, double y, int interPointNum, double extendRatio)
|
{
|
if (curve == null)
|
return null;
|
var points = GetFitPointsByExtend(curve, extendRatio, interPointNum);
|
if (points == null)
|
return null;
|
|
//在范围内
|
double maxY = (from yyy in points select yyy.Y).Max();
|
double minY = (from yyy in points select yyy.Y).Min();
|
if (y > minY && y < maxY)
|
{
|
return points.GetPointsByInterPointX(y);
|
}
|
|
List<CurvePoint> ptList = new List<CurvePoint>();
|
//判断是否在前面的延长部分
|
double x_start = CurveLineHelper.GetXbyY(points[0].X, points[0].Y, points[1].X, points[1].Y, y);
|
if (x_start <= points[0].X)
|
{
|
if (x_start > 0 && x_start > points[0].X * 0.9)//放一点余量
|
ptList.Add(new CurvePoint(x_start, y));
|
}
|
|
//判断是否在后面的延长部分:U型曲线 是前后都有
|
double x_end = CurveLineHelper.GetXbyY(points[points.Count - 2].X, points[points.Count - 2].Y, points[points.Count - 1].X, points[points.Count - 1].Y, y);
|
if (x_end >= points[points.Count - 1].X && x_end < points[points.Count - 1].X * extendRatio)//放一点余量
|
{
|
ptList.Add(new CurvePoint(x_end, y));
|
}
|
|
if (ptList.Count == 0)
|
return null;
|
return ptList;
|
}
|
|
#endregion 获得X值
|
|
#region 获得Y值
|
|
/// <summary>
|
/// 获取Y值最大值的点
|
/// </summary>
|
public static CurvePoint GetMaxPoint(this CurveExpress express, int pointNumber = 200)
|
{
|
if (express == null)
|
return null;
|
if (express.FitType <= 0 && express.DefinePoints != null)
|
{
|
return express.DefinePoints.GetPointByMaxY();
|
}
|
else if (express.FitType == eFitType.ThroughPoint)
|
{
|
return express.DefinePoints.GetPointByMaxY();
|
}
|
else
|
{
|
var points = express.GetFitPoints(pointNumber);
|
return points.GetPointByMaxY();
|
}
|
}
|
|
/// <summary>
|
/// 获取Y值最大值的点
|
/// </summary>
|
public static CurvePoint GetMaxPointByRange(this CurveExpress express, double rangeMin, double rangeMax, int pointNumber = 200)
|
{
|
if (express == null)
|
return null;
|
var points = express.GetFitPointsByXRange(rangeMin, rangeMax, pointNumber);
|
return points.GetPointByMaxY();
|
}
|
|
|
/// <summary>
|
/// 获取最大最小Y
|
/// </summary>
|
/// <param name=""></param>
|
public static bool GetMinMaxPointY(this CurveExpress express, out double maxY, out double minY)
|
{
|
if (express == null)
|
{
|
maxY = minY = 0;
|
return false;
|
}
|
var fitPoints = express.GetFitPoints(50);
|
if (fitPoints == null)
|
{
|
maxY = minY = 0;
|
return false;
|
}
|
maxY = fitPoints.Max(x => x.Y);
|
minY = fitPoints.Min(x => x.Y);
|
return true;
|
}
|
|
#endregion 取Y的最大最小值
|
|
#region SimuValue
|
|
/// <summary>
|
/// 根据相似点设置相似曲线,相似点(选择点)的x:流量y:杨程
|
/// </summary>
|
public static double GetSimuValue(this CurveExpress express, CurvePoint simularPoint, double originValue, double extendRatio = 1)
|
{
|
if (express == null)
|
return -3;
|
if (simularPoint.X < 0.1 || simularPoint.Y < 0.1)
|
return -2;
|
if (simularPoint.X > express.Max * extendRatio * 1.5)
|
return -4;
|
|
CurvePoint sectPoint = GetSectPoint(express, simularPoint, extendRatio);
|
if (sectPoint == null || sectPoint.IsZeroPoint())
|
return -5;
|
|
//计算相似点的转速/直径
|
return PumpCalculateHelper.CalculateSimuByH(originValue, sectPoint.Y, simularPoint.Y);
|
}
|
|
//ratioIgnore:作用 当simularPoint超出曲线范围时,曲线扩大的倍数
|
public static CurvePoint GetSectPoint(this CurveExpress CurveExpress, CurvePoint simularPoint, double ratioIgnore)
|
{
|
return GetSectPointGeneral(CurveExpress, simularPoint, 2, ratioIgnore);
|
}
|
|
#endregion
|
|
#region 曲线与H=K*Q^i的交点
|
|
|
//通过点simularPoint和点(0,0)的直线,与曲线Curve的交点(没有,返回Point(0,0))
|
public static CurvePoint GetSectPointLine(List<CurvePoint> CurvePoints, CurvePoint simularPoint)
|
{
|
CurvePoint sectPoint = new CurvePoint(0, 0);
|
if (CurvePoints == null || CurvePoints.Count < 2)
|
return sectPoint;
|
|
//计算直线的K
|
if (simularPoint.X < 1)
|
return sectPoint;
|
double a = simularPoint.Y / simularPoint.X;
|
if (a < 0.0001)
|
return sectPoint;
|
|
//与2点连成直线的交点,判断交点是否在2点之间,即可是曲线的交点
|
double b, c;
|
double x;
|
for (int i = 0; i < CurvePoints.Count - 1; i++)
|
{
|
CurveLineHelper.GetKandB(CurvePoints[i], CurvePoints[i + 1], out b, out c);
|
|
/*解方程
|
* y=ax
|
* y=bx+c
|
*/
|
if (Math.Abs(a - b) < 0.001)
|
continue;
|
|
x = c / (a - b);
|
if (IStation.Curve.UtilsHelper.IsMiddle(CurvePoints[i].X, CurvePoints[i + 1].X, x))
|
{
|
sectPoint.X = x;
|
sectPoint.Y = a * x;
|
return sectPoint;
|
}
|
}
|
|
return sectPoint;
|
}
|
|
//通过点simularPoint和点(0,0)的抛物线,与曲线Curve的交点(没有,返回Point(0,0))
|
//曲线公式:H=K*Q^2
|
public static CurvePoint GetSectPointParabola(List<CurvePoint> CurvePoints, CurvePoint simularPoint)
|
{
|
return ParabolaCurveHelper.GetSectPoint(CurvePoints, simularPoint, 0);
|
}
|
|
public static CurvePoint GetSectPointParabola(CurveExpress CurveExpress, CurvePoint simularPoint)
|
{
|
CurvePoint sectPoint = new CurvePoint(0, 0);
|
if (CurveExpress == null)
|
return sectPoint;
|
|
return GetSectPointParabola(CurveExpress.GetFitPointsByExtend(1.2, 50), simularPoint);
|
}
|
|
public static CurvePoint GetSectPointLine(this CurveExpress CurveExpress, CurvePoint simularPoint)
|
{
|
CurvePoint sectPoint = new CurvePoint(0, 0);
|
if (CurveExpress == null)
|
return sectPoint;
|
|
//计算直线的K
|
if (simularPoint.X < 1)
|
return sectPoint;
|
double a = simularPoint.Y / simularPoint.X;
|
if (a < 0.0001)
|
return sectPoint;
|
|
//点越多越精确
|
return GetSectPointLine(CurveExpress.GetFitPoints(100), simularPoint);
|
}
|
|
//曲线H=K*Q^i 与曲线Curve的交点(没有,返回Point(0,0))
|
public static CurvePoint GetSectPointGeneral(List<CurvePoint> CurvePoints, CurvePoint simularPoint, double index)
|
{
|
CurvePoint sectPoint = new CurvePoint(0, 0);
|
if (CurvePoints == null || CurvePoints.Count < 2)
|
return sectPoint;
|
|
if (simularPoint.X < 0.1)
|
return sectPoint;
|
|
if (Math.Abs(index - 1) < 0.01)
|
return GetSectPointLine(CurvePoints, simularPoint);
|
if (Math.Abs(index - 2) < 0.01)
|
return GetSectPointParabola(CurvePoints, simularPoint);
|
|
//计算系数K
|
double fixK = simularPoint.Y / Math.Pow(simularPoint.X, index);
|
if (fixK < 0.000001)
|
return sectPoint;
|
|
//思路是从simularPoint开始逐个增加0.1,直到k值最接近fixK
|
double space = (CurvePoints.Last().X - simularPoint.X) / 1200;
|
double x = simularPoint.X;
|
double y, k;
|
do
|
{
|
x = x + space;
|
y = 0;
|
if (!CurvePoints.GetInterPointY(x, out y))
|
{
|
break;
|
}
|
|
k = y / Math.Pow(x, index);
|
} while (k > fixK);
|
|
sectPoint.X = x;
|
sectPoint.Y = y;
|
return sectPoint;
|
}
|
|
//曲线H=K*Q^i 与曲线Curve的交点(没有,返回Point(0,0))
|
public static CurvePoint GetSectPointGeneral(this CurveExpress express, CurvePoint simularPoint, double index)
|
{
|
CurvePoint sectPoint = new CurvePoint(0, 0);
|
if (express == null)
|
return sectPoint;
|
|
if (simularPoint.X < 1)
|
return sectPoint;
|
|
//检查是否在曲线的区域范围内
|
double maxQ = express.Max;
|
double maxH = express.GetFitPointY(maxQ);
|
double k1 = maxH / Math.Pow(maxQ, index);
|
double k2 = simularPoint.Y / Math.Pow(simularPoint.X, index);
|
if (k1 > k2)
|
{
|
return sectPoint;
|
}
|
|
if (Math.Abs(index - 1) < 0.01)
|
return GetSectPointLine(express, simularPoint);
|
if (Math.Abs(index - 2) < 0.01)
|
return GetSectPointParabola(express, simularPoint);
|
|
//计算系数K
|
double fixK = simularPoint.Y / Math.Pow(simularPoint.X, index);
|
if (fixK < 0.000001)
|
return sectPoint;
|
|
//思路是从simularPoint开始逐个增加0.1,直到k值最接近fixK
|
double space = (express.Max - simularPoint.X) / 1000;
|
double x = simularPoint.X;
|
double y, k;
|
do
|
{
|
x = x + space;
|
y = express.GetFitPointY(x);
|
k = y / Math.Pow(x, index);
|
} while (k > fixK);
|
|
sectPoint.X = x;
|
sectPoint.Y = y;
|
return sectPoint;
|
}
|
|
//ratioIgnore:作用 当simularPoint超出范围时,扩大的倍数
|
public static CurvePoint GetSectPointGeneral(this CurveExpress curveExpress, CurvePoint simularPoint, double index, double ratioIgnore)
|
{
|
CurvePoint sectPoint = new CurvePoint(0, 0);
|
if (curveExpress == null)
|
return sectPoint;
|
|
if (simularPoint.X < 1)
|
return sectPoint;
|
var CurveExpressEx = curveExpress.Clone();
|
//检查是否在曲线的区域范围内
|
double maxQ = CurveExpressEx.Max;
|
double maxH = CurveExpressEx.GetFitPointY(maxQ);
|
double k1 = maxH / Math.Pow(maxQ, index);
|
double k2 = simularPoint.Y / Math.Pow(simularPoint.X, index);
|
if (k1 > k2)
|
{
|
CurveExpressEx.Max = CurveExpressEx.Max * ratioIgnore;//放大1.2倍
|
}
|
|
if (Math.Abs(index - 1) < 0.01)
|
return GetSectPointLine(CurveExpressEx, simularPoint);
|
if (Math.Abs(index - 2) < 0.01)
|
return GetSectPointParabola(CurveExpressEx, simularPoint);
|
|
//计算系数K
|
double fixK = simularPoint.Y / Math.Pow(simularPoint.X, index);
|
if (fixK < 0.000001)
|
return sectPoint;
|
|
//思路是从simularPoint开始逐个增加0.1,直到k值最接近fixK
|
double space = (CurveExpressEx.Max - simularPoint.X) / 1000;
|
double x = simularPoint.X;
|
double y, k;
|
do
|
{
|
x = x + space;
|
y = CurveExpressEx.GetFitPointY(x);
|
k = y / Math.Pow(x, index);
|
} while (k > fixK);
|
|
sectPoint.X = x;
|
sectPoint.Y = y;
|
return sectPoint;
|
}
|
|
#endregion 曲线与H=K*Q^i的交点 protect类型,给子类调用,怎么覆盖GetSectPoint
|
}
|
}
|