namespace IStation.Curve
{
public static class CurveExpress_Extensions
{
#region CurveFunction
///
/// 获取曲线方程
///
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();
}
///
/// 获取
///
///
///
///
///
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 Extend
///
/// 获取拟合点
///
public static List 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);
}
///
/// 获取拟合点
///
public static List 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值
///
/// 获得Y值的坐标位置,多个点里取最后一个点(是线形插值,不是曲线上的点)
///
///
///
///
///
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;
}
///
/// 获得Y值的坐标位置,可能有多个点(是线形插值,不是曲线上的点):会计算延长部分:而且要求points点按照从小到大排序
///
///
///
///
///
public static List 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 ptList = new List();
//判断是否在前面的延长部分
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;
}
///
/// 获得Y值的坐标位置,可能有多个点(是线形插值,不是曲线上的点):会计算延长部分:而且要求points点按照从小到大排序
///
///
///
///
///
///
public static List 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 ptList = new List();
//判断是否在前面的延长部分
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值
///
/// 获取Y值最大值的点
///
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();
}
}
///
/// 获取Y值最大值的点
///
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();
}
///
/// 获取最大最小Y
///
///
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
///
/// 根据相似点设置相似曲线,相似点(选择点)的x:流量y:杨程
///
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 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 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 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
}
}