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