namespace IStation.Curve
|
{
|
|
/// <summary>
|
/// 贝塞尔曲线类(二次)
|
/// </summary>
|
public class Bezier2
|
{
|
/// <summary>
|
///
|
/// </summary>
|
public Bezier2() { }
|
|
/// <summary>
|
///
|
/// </summary>
|
public Bezier2(List<CurvePoint> points)
|
{
|
if (points == null || points.Count < 3)
|
{
|
throw new Exception("参数错误,无法解出二次贝塞尔曲线!");
|
}
|
|
this.Point0 = points[0];
|
this.Point1 = points[1];
|
this.Point2 = points[2];
|
}
|
|
|
/// <summary>
|
/// 开始点
|
/// </summary>
|
public CurvePoint Point0 { get; set; }
|
|
/// <summary>
|
/// 开始点的控制点
|
/// </summary>
|
public CurvePoint Point1 { get; set; }
|
|
/// <summary>
|
/// 结束点
|
/// </summary>
|
public CurvePoint Point2 { get; set; }
|
|
/// <summary>
|
/// 获取 X 用于插值
|
/// </summary>
|
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);
|
}
|
|
/// <summary>
|
/// 获取 Y 用于插值
|
/// </summary>
|
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);
|
}
|
|
/// <summary>
|
/// 通过 X 获取交点Y值
|
/// </summary>
|
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;
|
}
|
|
/// <summary>
|
/// 最近的点
|
/// </summary>
|
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;
|
}
|
|
/// <summary>
|
/// 求与曲线的交点 (可能有多个,但只取第一个点)
|
/// </summary>
|
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;
|
}
|
|
/// <summary>
|
/// 变成一条一条直线端
|
/// </summary>
|
/// <param name="pointNumber">贝赛尔曲线中间插入的点数量</param>
|
public List<CurvePoint> GetApexPoints(int pointNumber)
|
{
|
var points_sect_list = new List<CurvePoint>();
|
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;
|
}
|
|
/// <summary>
|
/// 获取距离
|
/// </summary>
|
public double Distance(CurvePoint point)
|
{
|
var point1 = GetClosePoint(point);
|
return point.Distance(point1);
|
}
|
}
|
}
|