namespace IStation.Curve
|
{
|
/// <summary>
|
/// 贝塞尔线
|
/// </summary>
|
public class BezierCurveHelper
|
{
|
/// <summary>
|
/// 获取开放的贝塞尔曲线列表
|
/// </summary>
|
public static List<Bezier3> CreateOpenCurves(List<CurvePoint> points)
|
{
|
//http://wenku.baidu.com/link?url=9TGvGfedfkbskSWwfeO_iJJHvIzL0E_mE3wwVlWs1kEvvT9dHDQFdArhcdh8yuCK3pUbw2soJKs5qiQKlzhA885Tgtbu-Cdr1T37ANki_mS
|
if (points == null || points.Count() < 4)
|
return default;
|
|
int iPointCout = points.Count();
|
double a = 0.25;
|
double b = 0.25;
|
List<Bezier3> controlPoint = new List<Bezier3>();
|
//生成4控制点,产生贝塞尔曲线
|
for (int i = 0; i < iPointCout - 1; i++)
|
{
|
Bezier3 bezier = new Bezier3();
|
|
bezier.Point0 = points[i];
|
if (i == 0)
|
{
|
double x1 = points[i].X + a * (points[i + 1].X - points[i].X);
|
double y1 = points[i].Y + a * (points[i + 1].Y - points[i].Y);
|
bezier.Point1 = new CurvePoint(x1, y1);
|
}
|
else
|
{
|
double x1 = points[i].X + a * (points[i + 1].X - points[i - 1].X);
|
double y1 = points[i].Y + a * (points[i + 1].Y - points[i - 1].Y);
|
bezier.Point1 = new CurvePoint(x1, y1);
|
}
|
|
if (i == iPointCout - 2)
|
{
|
double x2 = points[i + 1].X - b * (points[i + 1].X - points[i].X);
|
double y2 = points[i + 1].Y - b * (points[i + 1].Y - points[i].Y);
|
bezier.Point2 = new CurvePoint(x2, y2);
|
}
|
else
|
{
|
double x2 = points[i + 1].X - b * (points[i + 2].X - points[i].X);
|
double y2 = points[i + 1].Y - b * (points[i + 2].Y - points[i].Y);
|
bezier.Point2 = new CurvePoint(x2, y2);
|
}
|
|
bezier.Point3 = points[i + 1];
|
controlPoint.Add(bezier);
|
}
|
return controlPoint;
|
}
|
|
/// <summary>
|
/// 获取封闭的贝塞尔曲线列表
|
/// </summary>
|
public static List<Bezier3> CreateCloseCurves(List<CurvePoint> points)
|
{
|
//http://blog.csdn.net/microchenhong/article/details/6316332
|
int originCount = points.Count();
|
//控制点收缩系数 ,经调试0.6较好
|
float scale = 0.6f;
|
var midpoints = new List<CurvePoint>();
|
//生成中点
|
for (int i = 0; i < originCount; i++)
|
{
|
int nexti = (i + 1) % originCount;
|
double x = (points[i].X + points[nexti].X) / 2.0;
|
double y = (points[i].Y + points[nexti].Y) / 2.0;
|
midpoints.Add(new CurvePoint(x, y));
|
}
|
|
//平移中点
|
var extrapoints = new List<CurvePoint>();//[2 * originCount];
|
for (int i = 0; i < originCount * 2; i++)
|
{
|
extrapoints.Add(new CurvePoint(0, 0));
|
}
|
for (int i = 0; i < originCount; i++)
|
{
|
int nexti = (i + 1) % originCount;
|
int backi = (i + originCount - 1) % originCount;
|
var midinmid = new CurvePoint();
|
midinmid.X = (midpoints[i].X + midpoints[backi].X) / 2.0;
|
midinmid.Y = (midpoints[i].Y + midpoints[backi].Y) / 2.0;
|
double offsetx = points[i].X - midinmid.X;
|
double offsety = points[i].Y - midinmid.Y;
|
int extraindex = 2 * i;
|
extrapoints[extraindex].X = midpoints[backi].X + offsetx;
|
extrapoints[extraindex].Y = midpoints[backi].Y + offsety;
|
//朝 originPoint[i]方向收缩
|
double addx = (extrapoints[extraindex].X - points[i].X) * scale;
|
double addy = (extrapoints[extraindex].Y - points[i].Y) * scale;
|
extrapoints[extraindex].X = points[i].X + addx;
|
extrapoints[extraindex].Y = points[i].Y + addy;
|
|
int extranexti = (extraindex + 1) % (2 * originCount);
|
extrapoints[extranexti].X = midpoints[i].X + offsetx;
|
extrapoints[extranexti].Y = midpoints[i].Y + offsety;
|
//朝 originPoint[i]方向收缩
|
addx = (extrapoints[extranexti].X - points[i].X) * scale;
|
addy = (extrapoints[extranexti].Y - points[i].Y) * scale;
|
extrapoints[extranexti].X = points[i].X + addx;
|
extrapoints[extranexti].Y = points[i].Y + addy;
|
}
|
|
List<Bezier3> controlPoint = new List<Bezier3>();
|
//生成4控制点,产生贝塞尔曲线
|
for (int i = 0; i < originCount - 1; i++)
|
{
|
Bezier3 bezier = new Bezier3();
|
|
bezier.Point0 = points[i];
|
int extraindex = 2 * i;
|
bezier.Point1 = extrapoints[extraindex + 1];
|
int extranexti = (extraindex + 2) % (2 * originCount);
|
bezier.Point2 = extrapoints[extranexti];
|
int nexti = (i + 1) % originCount;
|
bezier.Point3 = points[nexti];
|
controlPoint.Add(bezier);
|
}
|
return controlPoint;
|
}
|
|
/// <summary>
|
/// 通过 X 获取交点
|
/// </summary>
|
public static List<CurvePoint> GetSectPointsByX(List<Bezier3> allBeziers, double x)
|
{
|
if (allBeziers == null || allBeziers.Count() < 1)
|
return null;
|
|
var points_sect_list = new List<CurvePoint>();
|
foreach (var bezeir in allBeziers)
|
{
|
//贝塞尔曲线与性能曲线有交点
|
if ((x <= bezeir.Point0.X && x >= bezeir.Point3.X) || (x >= bezeir.Point0.X && x <= bezeir.Point3.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 = bezeir.GetX(start0_uu);
|
//var start0_p_y = bezeir.GetY(start0_uu);
|
var end0_p_x = bezeir.GetX(end0_uu);
|
//var end0_p_y = bezeir.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 = bezeir.GetX(start1_uu);
|
//var start1_p_y = bezeir.GetY(start1_uu);
|
var end1_p_x = bezeir.GetX(end1_uu);
|
//var end1_p_y = bezeir.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 = bezeir.GetX(start2_uu);
|
//var start2_p_y = bezeir.GetY(start2_uu);
|
var end2_p_x = bezeir.GetX(end2_uu);
|
//var end2_p_y = bezeir.GetY(end2_uu);
|
if ((x <= start2_p_x && x >= end2_p_x) || (x >= start2_p_x && x <= end2_p_x))
|
{
|
var set_x = bezeir.GetX((start2_uu + end2_uu) / 2);
|
var set_y = bezeir.GetY((start2_uu + end2_uu) / 2);
|
var set_pt = new CurvePoint(set_x, set_y);
|
|
points_sect_list.Add(set_pt);
|
break;
|
}
|
}
|
break;
|
}
|
}
|
break;
|
}
|
|
}
|
#endregion
|
}
|
}
|
|
return points_sect_list;
|
}
|
|
/// <summary>
|
/// 通过 Y 获取交点
|
/// </summary>
|
public static List<CurvePoint> GetSectPointsByY(List<Bezier3> allBeziers, double y)
|
{
|
if (allBeziers == null || allBeziers.Count() == 0)
|
return null;
|
var points_sect_list = new List<CurvePoint>();
|
foreach (var bezeir in allBeziers)
|
{
|
//贝塞尔曲线与性能曲线有交点
|
if ((y <= bezeir.Point0.Y && y >= bezeir.Point3.X) || (y >= bezeir.Point0.Y && y <= bezeir.Point3.Y))
|
{
|
#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 = bezeir.GetX(start0_uu);
|
var start0_p_y = bezeir.GetY(start0_uu);
|
//var end0_p_x = bezeir.GetX(end0_uu);
|
var end0_p_y = bezeir.GetY(end0_uu);
|
if ((y <= start0_p_y && y >= end0_p_y) || (y >= start0_p_y && y <= end0_p_y))
|
{
|
//第二次循环
|
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 = bezeir.GetX(start1_uu);
|
var start1_p_y = bezeir.GetY(start1_uu);
|
// var end1_p_x = bezeir.GetX(end1_uu);
|
var end1_p_y = bezeir.GetY(end1_uu);
|
if ((y <= start1_p_y && y >= end1_p_y) || (y >= start1_p_y && y <= end1_p_y))
|
{
|
//第三次循环
|
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 = bezeir.GetX(start2_uu);
|
var start2_p_y = bezeir.GetY(start2_uu);
|
// var end2_p_x = bezeir.GetX(end2_uu);
|
var end2_p_y = bezeir.GetY(end2_uu);
|
if ((y <= start2_p_y && y >= end2_p_y) || (y >= start2_p_y && y <= end2_p_y))
|
{
|
var set_x = bezeir.GetX((start2_uu + end2_uu) / 2);
|
var set_y = bezeir.GetY((start2_uu + end2_uu) / 2);
|
var set_pt = new CurvePoint(set_x, set_y);
|
|
points_sect_list.Add(set_pt);
|
break;
|
}
|
}
|
break;
|
}
|
}
|
break;
|
}
|
|
}
|
#endregion
|
}
|
}
|
|
return points_sect_list;
|
}
|
|
/// <summary>
|
/// 通过 曲线表达式 获取交点
|
/// </summary>
|
public static List<CurvePoint> GetCrossPoints(List<Bezier3> allBeziers, CurveExpress curve)
|
{
|
if (allBeziers == null || allBeziers.Count() == 0)
|
return null;
|
var points_sect_list = new List<CurvePoint>();
|
foreach (var bezeir in allBeziers)
|
{
|
var pt = bezeir.GetCrossPoint(curve);
|
if (pt != null)
|
points_sect_list.Add(pt);
|
}
|
|
return points_sect_list;
|
}
|
|
/// <summary>
|
/// 通过 曲线表达式 获取交点
|
/// </summary>
|
public static List<CurvePoint> GetCrossPoints(List<CurvePoint> originPoint, CurveExpress curve)
|
{
|
if (originPoint == null)
|
return null;
|
if (originPoint.Count() <= 2)
|
return null;
|
if (originPoint.Count() == 3)
|
{
|
var b2 = new Bezier2(originPoint);
|
var pt = b2.GetCrossPoint(curve);
|
if (pt == null)
|
return null;
|
return new List<CurvePoint>() { pt };
|
}
|
|
var allBeziers = CreateOpenCurves(originPoint);
|
|
var points_sect_list = new List<CurvePoint>();
|
foreach (var bezeir in allBeziers)
|
{
|
var pt = bezeir.GetCrossPoint(curve);
|
if (pt != null)
|
points_sect_list.Add(pt);
|
}
|
|
return points_sect_list;
|
}
|
|
/// <summary>
|
/// 获取距离
|
/// </summary>
|
public static double Distance(List<CurvePoint> curvePoints, CurvePoint point)
|
{
|
if (curvePoints == null || curvePoints.Count() == 0)
|
return 0;
|
if (curvePoints.Count() == 1)
|
{
|
var point1 = curvePoints.First();
|
return Math.Sqrt((point1.X - point.X) * (point1.X - point.X) + (point1.Y - point.Y) * (point1.Y - point.Y));
|
}
|
if (curvePoints.Count() == 2)
|
{
|
var point1 = curvePoints.First();
|
var point2 = curvePoints.Last();
|
|
return CurveLineHelper.Distance(point1, point2, point);
|
}
|
if (curvePoints.Count() == 3)
|
{
|
var b2 = new Bezier2(curvePoints);
|
return b2.Distance(point);
|
}
|
|
var allBeziers = CreateOpenCurves(curvePoints);
|
|
double min_dis = double.MaxValue;
|
foreach (var bezeir in allBeziers)
|
{
|
var dis = bezeir.Distance(point);
|
min_dis = Math.Min(min_dis, dis);
|
}
|
|
return min_dis;
|
}
|
|
/// <summary>
|
/// 获取距离(把曲线压缩到100*100的盒子里面 Boundary 求距离)
|
/// </summary>
|
public static double Distance(CurveBoundary boundary, List<CurvePoint> curve_real, CurvePoint point_real)
|
{
|
if (curve_real == null || curve_real.Count() == 0)
|
return 0;
|
if (boundary == null)
|
return Distance(curve_real, point_real);
|
double ratio_x = 0;
|
if (boundary.MaxX == boundary.MinX)
|
{
|
ratio_x = 100 / (boundary.MaxX);
|
}
|
else
|
{
|
ratio_x = 100 / (boundary.MaxX - boundary.MinX);
|
}
|
|
|
double ratio_y = 0;
|
if (boundary.MaxY == boundary.MinY)
|
{
|
ratio_y = 100 / (boundary.MaxY);
|
}
|
else
|
{
|
ratio_y = 100 / (boundary.MaxY - boundary.MinY);
|
}
|
|
var point_chart = new CurvePoint() { X = (point_real.X - boundary.MinX) * ratio_x, Y = (point_real.Y - boundary.MinY) * ratio_y };
|
var curvePoints = new List<CurvePoint>();
|
foreach (var pt in curve_real)
|
{
|
var point1 = new CurvePoint() { X = (pt.X - boundary.MinX) * ratio_x, Y = (pt.Y - boundary.MinY) * ratio_y };
|
curvePoints.Add(point1);
|
}
|
if (curvePoints.Count() == 1)
|
{
|
var point1 = curvePoints.First();
|
return Math.Sqrt((point1.X - point_chart.X) * (point1.X - point_chart.X) + (point1.Y - point_chart.Y) * (point1.Y - point_chart.Y));
|
}
|
if (curvePoints.Count() == 2)
|
{
|
var point1 = curvePoints.First();
|
var point2 = curvePoints.Last();
|
|
return CurveLineHelper.Distance(point1, point2, point_chart);
|
}
|
if (curvePoints.Count() == 3)
|
{
|
var b2 = new Bezier2(curvePoints);
|
return b2.Distance(point_chart);
|
}
|
|
var allBeziers = CreateOpenCurves(curvePoints);
|
|
double min_dis = double.MaxValue;
|
foreach (var bezeir in allBeziers)
|
{
|
var dis = bezeir.Distance(point_chart);
|
min_dis = Math.Min(min_dis, dis);
|
}
|
|
return min_dis;
|
}
|
|
/// <summary>
|
/// 变成直线端
|
/// </summary>
|
/// <param name="allBeziers">贝塞尔曲线</param>
|
/// <param name="pointNumber">贝赛尔曲线中间插入的点数量</param>
|
/// <returns></returns>
|
public static List<CurvePoint> GetApexPoints(List<Bezier3> allBeziers, int pointNumber)
|
{
|
var points_sect_list = new List<CurvePoint>();
|
foreach (var bezeir in allBeziers)
|
{
|
for (int i = 0; i <= pointNumber; i++)
|
{
|
var uu = i * 1.0 / pointNumber;
|
var p_x = bezeir.GetX(uu);
|
var p_y = bezeir.GetY(uu);
|
points_sect_list.Add(new CurvePoint(p_x, p_y));
|
}
|
}
|
|
return points_sect_list;
|
}
|
|
/// <summary>
|
/// 变成直线端(只针对开口的曲线)
|
/// </summary>
|
/// <param name="originPoint">贝塞尔曲线</param>
|
/// <param name="pointNumber">贝赛尔曲线中间插入的点数量</param>
|
/// <returns></returns>
|
public static List<CurvePoint> GetApexPoints(List<CurvePoint> originPoint, int pointNumber)
|
{
|
if (originPoint == null)
|
return null;
|
if (originPoint.Count() <= 2)
|
return null;
|
if (originPoint.Count() == 3)
|
{
|
var b2 = new Bezier2(originPoint);
|
return b2.GetApexPoints(pointNumber);
|
}
|
|
var allBeziers = CreateOpenCurves(originPoint);
|
var points_sect_list = new List<CurvePoint>();
|
foreach (var bezeir in allBeziers)
|
{
|
for (int i = 0; i <= pointNumber; i++)
|
{
|
var uu = i * 1.0 / pointNumber;
|
var p_x = bezeir.GetX(uu);
|
var p_y = bezeir.GetY(uu);
|
points_sect_list.Add(new CurvePoint(p_x, p_y));
|
}
|
}
|
|
return points_sect_list;
|
}
|
|
//三次贝塞尔曲线
|
private double bezier3funcX(double uu, List<CurvePoint> controlP)
|
{
|
double part0 = controlP[0].X * uu * uu * uu;
|
double part1 = 3 * controlP[1].X * uu * uu * (1 - uu);
|
double part2 = 3 * controlP[2].X * uu * (1 - uu) * (1 - uu);
|
double part3 = controlP[3].X * (1 - uu) * (1 - uu) * (1 - uu);
|
return part0 + part1 + part2 + part3;
|
}
|
private double bezier3funcY(double uu, List<CurvePoint> controlP)
|
{
|
double part0 = controlP[0].Y * uu * uu * uu;
|
double part1 = 3 * controlP[1].Y * uu * uu * (1 - uu);
|
double part2 = 3 * controlP[2].Y * uu * (1 - uu) * (1 - uu);
|
double part3 = controlP[3].Y * (1 - uu) * (1 - uu) * (1 - uu);
|
return part0 + part1 + part2 + part3;
|
}
|
|
|
|
}
|
}
|