namespace IStation.Curve
{
///
/// 贝塞尔曲线类(二次)
///
public class Bezier2
{
///
///
///
public Bezier2() { }
///
///
///
public Bezier2(List points)
{
if (points == null || points.Count < 3)
{
throw new Exception("参数错误,无法解出二次贝塞尔曲线!");
}
this.Point0 = points[0];
this.Point1 = points[1];
this.Point2 = points[2];
}
///
/// 开始点
///
public CurvePoint Point0 { get; set; }
///
/// 开始点的控制点
///
public CurvePoint Point1 { get; set; }
///
/// 结束点
///
public CurvePoint Point2 { get; set; }
///
/// 获取 X 用于插值
///
public double GetX(double uu)
{
return Point0.X * Math.Pow(1 - uu, 2) +
Point1.X * uu * (1 - uu) * 2 +
Point2.X * Math.Pow(uu, 2);
}
///
/// 获取 Y 用于插值
///
public double GetY(double uu)
{
return Point0.Y * Math.Pow(1 - uu, 2) +
Point1.Y * uu * (1 - uu) * 2 +
Point2.Y * Math.Pow(uu, 2);
}
///
/// 通过 X 获取交点Y值
///
public bool GetSectPointYByX(double x, out double sect_y)
{
sect_y = 0;
//贝塞尔曲线与性能曲线有交点
if ((x <= this.Point0.X && x >= this.Point2.X) || (x >= this.Point0.X && x <= this.Point2.X))
{
#region 贝塞尔曲线集合循环
//第一次循环
for (int i = 0; i < 10; i++)
{
var start0_uu = i * 0.1;
var end0_uu = start0_uu + 0.1;
var start0_p_x = this.GetX(start0_uu);
//var start0_p_y = this.GetY(start0_uu);
var end0_p_x = this.GetX(end0_uu);
//var end0_p_y = this.GetY(end0_uu);
if ((x <= start0_p_x && x >= end0_p_x) || (x >= start0_p_x && x <= end0_p_x))
{
//第二次循环
for (int j = 0; j < 10; j++)
{
var start1_uu = start0_uu + j * 0.01;
var end1_uu = start1_uu + 0.01;
var start1_p_x = this.GetX(start1_uu);
//var start1_p_y = this.GetY(start1_uu);
var end1_p_x = this.GetX(end1_uu);
//var end1_p_y = this.GetY(end1_uu);
if ((x <= start1_p_x && x >= end1_p_x) || (x >= start1_p_x && x <= end1_p_x))
{
//第三次循环
for (int k = 0; k < 10; k++)
{
var start2_uu = start1_uu + k * 0.001;
var end2_uu = start2_uu + 0.001;
var start2_p_x = this.GetX(start2_uu);
//var start2_p_y = this.GetY(start2_uu);
var end2_p_x = this.GetX(end2_uu);
//var end2_p_y = this.GetY(end2_uu);
if ((x <= start2_p_x && x >= end2_p_x) || (x >= start2_p_x && x <= end2_p_x))
{
var set_x = (start2_p_x + end2_p_x) / 2;
sect_y = this.GetX((start2_uu + end2_uu) / 2);
return true;
}
}
break;
}
}
break;
}
}
#endregion
}
return false;
}
///
/// 最近的点
///
public CurvePoint GetClosePoint(CurvePoint ref_pt)
{
double boundary_min_x = Math.Min(Point0.X, Point2.X);
double boundary_max_x = Math.Max(Point0.X, Point2.X);
double boundary_min_y = Math.Min(Point0.Y, Point2.Y);
double boundary_max_y = Math.Max(Point0.Y, Point2.Y);
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;//由于流量扬程数量差别特别大, 所以假设他们在一个100*100的方格内,求距离
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);
}
}
}