namespace IStation.Curve { /// /// 贝塞尔曲线类(三次) /// public class Bezier3 { /// /// /// public Bezier3() { } /// /// /// public Bezier3(List points) { if (points == null || points.Count < 4) { throw new Exception("参数错误,无法解出三次贝塞尔曲线!"); } this.Point0 = points[0]; this.Point1 = points[1]; this.Point2 = points[2]; this.Point3 = points[3]; } /// /// 开始点 /// public CurvePoint Point0 { get; set; } /// /// 开始点的控制点 /// public CurvePoint Point1 { get; set; } /// /// 结束点的控制点 /// public CurvePoint Point2 { get; set; } /// /// 结束点 /// public CurvePoint Point3 { get; set; } /// /// 获取 X 用于插值 /// public double GetX(double uu) { double u0 = Point3.X * uu * uu * uu; double u1 = 3 * Point2.X * uu * uu * (1 - uu); double u2 = 3 * Point1.X * uu * (1 - uu) * (1 - uu); double u3 = Point0.X * (1 - uu) * (1 - uu) * (1 - uu); return u0 + u1 + u2 + u3; } /// /// 获取 Y 用于插值 /// public double GetY(double uu) { double u0 = Point3.Y * uu * uu * uu; double u1 = 3 * Point2.Y * uu * uu * (1 - uu); double u2 = 3 * Point1.Y * uu * (1 - uu) * (1 - uu); double u3 = Point0.Y * (1 - uu) * (1 - uu) * (1 - uu); return u0 + u1 + u2 + u3; } /// /// 距离最近的点 /// public CurvePoint GetClosePoint(CurvePoint ref_pt) { double boundary_min_x = Math.Min(Point0.X, Point3.X); double boundary_max_x = Math.Max(Point0.X, Point3.X); double boundary_min_y = Math.Min(Point0.Y, Point3.Y); double boundary_max_y = Math.Max(Point0.Y, Point3.Y); //由于流量扬程数量差别特别大, 所以假设他们在一个100*100的方格内,求距离 double ratio_x = 0; if (boundary_max_x == boundary_min_x) { ratio_x = 100 / (boundary_max_x); } else { ratio_x = 100 / (boundary_max_x - boundary_min_x); } double ratio_y = 0; if (boundary_max_y == boundary_min_y) { ratio_y = 100 / (boundary_max_y); } else { ratio_y = 100 / (boundary_max_y - boundary_min_y); } double chart_ref_x = (ref_pt.X - boundary_min_x) * ratio_x; double chart_ref_y = (ref_pt.Y - boundary_min_y) * ratio_y; CurvePoint sect = null; double min_dist = double.MaxValue; for (double uu = 0; uu <= 1; uu = uu + 0.01) { double chart_x = (GetX(uu) - boundary_min_x) * ratio_x - chart_ref_x; double chart_y = (GetY(uu) - boundary_min_y) * ratio_y - chart_ref_y; double distance = chart_x * chart_x + chart_y * chart_y; if (distance < min_dist) { min_dist = distance; sect = new CurvePoint(GetX(uu), GetY(uu)); } } return sect; } /// /// 求与曲线的交点 (可能有多个,但只取第一个点) /// public CurvePoint GetCrossPoint(CurveExpress curve) { if (curve == null) return null; //第一次迭代 var index1 = GetCrossPointIndex_不迭代(curve, 0.2, 0, 5); if (index1 < 0) return null; //第二次迭代 var index2 = GetCrossPointIndex_不迭代(curve, 0.02, 0.2 * index1, 10); if (index2 < 0) return null; double uu = 0.2 * index1 + 0.02 * index2; double x_bers = GetX(uu); double y_bers = FitHelper.GetFitPointY(curve, x_bers); return new CurvePoint(x_bers, y_bers); } //计算在第几个点相交(可能有多个,但只取第一个点):思路, 不断逼近,一个正数一个负数就表示有交点 private int GetCrossPointIndex_不迭代(CurveExpress curve, double space, double start, int number) { double last_dis_y = 0; for (int i = 0; i <= number; i++) { double uu1 = start + space * i; double x_bers = GetX(uu1); double y_bers = GetY(uu1); double y_curve = FitHelper.GetFitPointY(curve, x_bers); double current_dis_y = y_bers - y_curve; if (uu1 == 0) { last_dis_y = current_dis_y; continue; } if ((current_dis_y > 0 && last_dis_y < 0) || (current_dis_y < 0 && last_dis_y > 0)) { return i - 1; } last_dis_y = current_dis_y; } return -1; } /// /// 变成一条一条直线段 /// /// 贝赛尔曲线中间插入的点数量 public List GetApexPoints(int pointNumber) { var points_sect_list = new List(); for (int i = 0; i <= pointNumber; i++) { var uu = i * 1.0 / pointNumber; var p_x = this.GetX(uu); var p_y = this.GetY(uu); points_sect_list.Add(new CurvePoint(p_x, p_y)); } return points_sect_list; } /// /// 获取距离 /// public double Distance(CurvePoint point) { var point1 = GetClosePoint(point); return point.Distance(point1); } /// /// 通过 Y 判断是否在其中 /// public bool IsInnerByY(double y) { if (y >= this.Point0.Y && y <= this.Point3.Y) return true; if (y >= this.Point3.Y && y <= this.Point0.Y) return true; return false; } } }