namespace Yw.Curve
|
{
|
/// <summary>
|
/// 曲线直线
|
/// </summary>
|
public class CurveLine : ICloneable
|
{
|
/// <summary>
|
///
|
/// </summary>
|
public CurveLine() { }
|
|
/// <summary>
|
///
|
/// </summary>
|
public CurveLine(double x1, double y1, double x2, double y2)
|
{
|
this.Point0 = new CurvePoint(x1, y1);
|
this.Point1 = new CurvePoint(x2, y2);
|
}
|
|
/// <summary>
|
///
|
/// </summary>
|
public CurveLine(CurvePoint pt1, CurvePoint pt2)
|
{
|
this.Point0 = pt1;
|
this.Point1 = pt2;
|
}
|
|
/// <summary>
|
///
|
/// </summary>
|
public CurveLine(List<CurvePoint> pts)
|
{
|
if (pts == null || pts.Count < 2)
|
{
|
throw new Exception("参数错误,无法解析出直线!");
|
}
|
this.Point0 = pts[0];
|
this.Point1 = pts[1];
|
}
|
|
/// <summary>
|
///
|
/// </summary>
|
public CurveLine(CurveLine rhs)
|
{
|
this.Point0 = new CurvePoint(rhs.Point0);
|
this.Point1 = new CurvePoint(rhs.Point1);
|
}
|
|
/// <summary>
|
/// 第一个点
|
/// </summary>
|
public CurvePoint Point0 { get; set; }
|
|
/// <summary>
|
/// 第二个点
|
/// </summary>
|
public CurvePoint Point1 { get; set; }
|
|
/// <summary>
|
/// 获取插值Y
|
/// </summary>
|
public double GetInsertY(double x)
|
{
|
if (Math.Abs(this.Point1.X - this.Point0.X) < 0.000001)
|
{
|
return 0;
|
}
|
if (Math.Abs(this.Point1.Y - this.Point0.Y) < 0.000001)
|
{
|
return 0;
|
}
|
return this.Point0.Y + (this.Point1.Y - this.Point0.Y) / (this.Point1.X - this.Point0.X) * (x - this.Point0.X);
|
}
|
|
/// <summary>
|
/// 是否一个点向x轴的射线穿透线段,有交点且在线的左边
|
/// </summary>
|
public bool IsIntersectLeft(CurvePoint pt)
|
{
|
double maxY = this.Point0.Y > this.Point1.Y ? this.Point0.Y : this.Point1.Y;
|
double minY = this.Point0.Y > this.Point1.Y ? this.Point1.Y : this.Point0.Y;
|
|
if (Math.Abs(this.Point1.Y - this.Point0.Y) < 0.000001)
|
{
|
if (Math.Abs(pt.Y - this.Point0.Y) < 0.000001)
|
return true;
|
return false;
|
}
|
|
|
bool IsInLine = false;
|
if (pt.Y < maxY && pt.Y >= minY)
|
{
|
if (pt.X <= (this.Point0.X + (this.Point1.X - this.Point0.X) * (pt.Y - this.Point0.Y) / (this.Point1.Y - this.Point0.Y)))
|
{
|
IsInLine = true;
|
}
|
}
|
return IsInLine;
|
}
|
|
/// <summary>
|
/// 获取内部点
|
/// </summary>
|
public CurvePoint GetInnerPoint(double ratio)
|
{
|
var x = this.Point0.X + ratio * (this.Point1.X - this.Point0.X);
|
var y = this.Point0.Y + ratio * (this.Point1.Y - this.Point0.Y);
|
return new CurvePoint(x, y);
|
}
|
|
/// <summary>
|
/// 获取内部X坐标
|
/// </summary>
|
public double GetInnerX(double ratio)
|
{
|
var x = this.Point0.X + ratio * (this.Point1.X - this.Point0.X);
|
return x;
|
}
|
|
/// <summary>
|
/// 获取内部Y坐标
|
/// </summary>
|
public double GetInnerY(double ratio)
|
{
|
var y = this.Point0.Y + ratio * (this.Point1.Y - this.Point0.Y);
|
return y;
|
}
|
|
/// <summary>
|
/// 返回直线的k和b y=kx+b
|
/// </summary>
|
public bool GetKandB(out double k, out double b, double ignore = 0.000001)
|
{
|
k = b = 0;
|
|
if (Math.Abs(this.Point0.X - this.Point1.X) < ignore)
|
{//竖直
|
k = 100000000;
|
b = this.Point0.X;
|
return false;
|
}
|
if (Math.Abs(this.Point0.Y - this.Point1.Y) < ignore)
|
{//平行
|
k = 0;
|
b = this.Point0.X;
|
return true;
|
}
|
|
|
k = (this.Point0.Y - this.Point1.Y) / (this.Point0.X - this.Point1.X);// Math.Atan((pt1.Y - pt2.Y) / (pt1.X - pt2.X)) * 180 / Math.PI;
|
b = this.Point0.Y - k * this.Point0.X;
|
return true;
|
}
|
|
/// <summary>
|
/// 通过 X 获取 Y
|
/// </summary>
|
public double GetYByX(double x)
|
{
|
if (!GetKandB(out double k, out double b))
|
{
|
return this.Point0.Y;
|
}
|
return k * x + b;
|
}
|
|
/// <summary>
|
/// 通过 Y 获取 X
|
/// </summary>
|
public double GetXByY(double y)
|
{
|
if (!GetKandB(out double k, out double b))
|
{
|
return this.Point0.X;
|
}
|
return (y - b) / k;
|
}
|
|
/// <summary>
|
/// 获取中间点
|
/// </summary>
|
public CurvePoint GetMiddlePoint()
|
{
|
return new CurvePoint((this.Point0.X + this.Point1.X) * 0.5, (this.Point0.Y + this.Point1.Y) * 0.5);
|
}
|
|
/// <summary>
|
/// 通过 X 判断是否为内部点
|
/// </summary>
|
public bool IsInnerByX(double x)
|
{
|
if (x >= this.Point0.X && x <= this.Point1.X)
|
return true;
|
if (x >= this.Point1.X && x <= this.Point0.X)
|
return true;
|
return false;
|
}
|
|
/// <summary>
|
/// 通过 Y 判断是否为内部点
|
/// </summary>
|
public bool IsInnerByY(double y)
|
{
|
if (y >= this.Point0.Y && y <= this.Point1.Y)
|
return true;
|
if (y >= this.Point1.Y && y <= this.Point0.Y)
|
return true;
|
return false;
|
}
|
|
/// <summary>
|
/// 三个点在同一条直线上,输入(X1,Y1),(X2,Y2)以及沿(X2,Y2)侧延长Length,得到的点(X3,Y3)
|
/// </summary>
|
public CurvePoint GetExtendPoint(double length)
|
{
|
double betweenLength = this.Point0.Distance(this.Point1);
|
if (betweenLength < 0.01)
|
return this.Point0;
|
|
var extPt = new CurvePoint();
|
extPt.X = (this.Point1.X - this.Point0.X) * length / betweenLength + this.Point1.X;
|
extPt.Y = (this.Point1.Y - this.Point0.Y) * length / betweenLength + this.Point1.Y;
|
|
return extPt;
|
}
|
|
/// <summary>
|
/// 求直线外一点到该直线的投影点
|
/// </summary>
|
public CurvePoint GetProjectivePoint(CurvePoint pOut)
|
{
|
if (!GetKandB(out double k, out double b))
|
return default;
|
return GetProjectivePoint(this.Point0, k, pOut);
|
}
|
|
/// <summary>
|
/// 点到线的距离, 注意不一定是垂直距离,点只在(line_start和line_end之间
|
/// </summary>
|
public double Distance(CurvePoint pt)
|
{
|
var project_pt = GetProjectivePoint(pt);
|
if (IsInnerByX(pt.X))
|
return project_pt.Distance(pt);
|
var dis1 = this.Point0.Distance(pt);
|
var dis2 = this.Point1.Distance(pt);
|
if (dis1 < dis2)
|
return dis1;
|
else
|
return dis2;
|
}
|
|
/// <summary>
|
/// 求直线外一点到该直线的投影点
|
/// </summary>
|
/// <param name="pl">线上任一点</param>
|
/// <param name="k">直线斜率</param>
|
/// <param name="pout">线外指定点</param>
|
public static CurvePoint GetProjectivePoint(CurvePoint pl, double k, CurvePoint pout)
|
{
|
CurvePoint pProject = new CurvePoint();
|
if (k == 0) //垂线斜率不存在情况
|
{
|
pProject.X = pout.X;
|
pProject.Y = pout.Y;
|
}
|
else
|
{
|
pProject.X = (float)((k * pl.X + pout.X / k + pout.Y - pl.Y) / (1 / k + k));
|
pProject.Y = (float)(-1 / k * (pProject.X - pout.X) + pout.Y);
|
}
|
return pProject;
|
}
|
|
|
/// <summary>
|
///
|
/// </summary>
|
public CurveLine Clone()
|
{
|
return new CurveLine(this);
|
}
|
|
/// <summary>
|
///
|
/// </summary>
|
object ICloneable.Clone()
|
{
|
return this.Clone();
|
}
|
|
}
|
}
|