using System;
|
using System.Collections.Generic;
|
using System.Linq;
|
using System.Text;
|
|
namespace Hydro.Model
|
{
|
public partial class Line2d
|
{
|
/// <summary>
|
/// 是否垂直
|
/// </summary>
|
/// <param name="k"></param>
|
/// <returns></returns>
|
public static bool IsVerticalK(double k)
|
{
|
if (k >= 100000000 - 1)
|
return true;
|
else
|
return false;
|
}
|
private const double vertical_k = 100000000;//垂直时K的值
|
|
//直线插值
|
public static double GetLineInsert(double X1, double X2, double Y1, double Y2, double X)
|
{
|
if (Math.Abs(X2 - X1) < 0.000001)
|
{
|
//MessageBox.Show("输入值X2与X1不能相同!", "信息提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
return 0;
|
}
|
if (Math.Abs(Y2 - Y1) < 0.000001)
|
{
|
//MessageBox.Show("输入值Y2与Y1不能相同!", "信息提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
return 0;
|
}
|
|
double Y = Y1 + (Y2 - Y1) / (X2 - X1) * (X - X1);
|
return Y;
|
}
|
|
//是否一个点向x轴的射线穿透线段,有交点且在线的左边
|
public static bool IsIntersectLeft(Point2d basePoint, Point2d pt1, Point2d pt2)
|
{
|
return IsIntersectLeft(basePoint.X, basePoint.Y, pt1.X, pt1.Y, pt2.X, pt2.Y);
|
}
|
|
public static bool IsIntersectLeft(double x, double y, double x1, double y1, double x2, double y2)
|
{
|
double maxY = y1 > y2 ? y1 : y2;
|
double minY = y1 > y2 ? y2 : y1;
|
|
if (Math.Abs(y2 - y1) < 0.000001)
|
{
|
if (Math.Abs(y - y1) < 0.000001)
|
return true;
|
else
|
return false;
|
}
|
|
|
bool IsInLine = false;
|
if (y < maxY && y >= minY)
|
{
|
if (x <= (x1 + (x2 - x1) * (y - y1) / (y2 - y1)))
|
{
|
IsInLine = true;
|
}
|
}
|
return IsInLine;
|
}
|
|
//X1和X2之间连一条线, 在比率ratio处点的坐标
|
public static double GetRatioPoint(double X1, double X2, double ratio)
|
{
|
double X3 = 0.0;
|
X3 = X1 + ratio * (X2 - X1);
|
return X3;
|
}
|
|
//X1,Y1和X2 Y2之间连一条线,在X处点的Y坐标
|
public static double GetYbyX(double X1, double Y1, double X2, double Y2, double X)
|
{
|
if (Math.Abs(X1 - X2) < 0.000001)
|
return Y1;
|
|
if (Math.Abs(Y1 - Y2) < 0.000001)
|
return Y1;
|
|
double k = 0, b = 0;
|
if (!GetKandB(X1, Y1, X2, Y2, ref k, ref b))
|
return Y1;
|
|
double Y = 0;
|
Y = k * X + b;
|
|
return Y;
|
}
|
|
//X1,Y1和X2 Y2之间连一条线,在Y处点的X坐标
|
public static double GetXbyY(double X1, double Y1, double X2, double Y2, double Y)
|
{
|
if (Math.Abs(X1 - X2) < 0.000001)
|
return X1;
|
|
if (Math.Abs(Y1 - Y2) < 0.000001)
|
return X1;
|
|
double k = 0, b = 0;
|
if (!GetKandB(X1, Y1, X2, Y2, ref k, ref b))
|
return X1;
|
|
double X = (Y - b) / k;
|
|
return X;
|
}
|
|
//输入(X1,Y1),(X1,Y1)生成直线,返回直线的k和b y=kx+b
|
public static bool GetKandB(double X1, double Y1, double X2, double Y2, ref double k, ref double b)
|
{
|
if (Math.Abs(X1 - X2) < 0.000001)
|
{
|
k = vertical_k;
|
b = Y2;
|
return false;
|
}
|
else
|
{
|
k = (Y1 - Y2) / (X1 - X2);
|
b = Y1 - (Y1 - Y2) * X1 / (X1 - X2);
|
return true;
|
}
|
}
|
|
|
|
//输入(X1,Y1),(X1,Y1)生成直线,返回直线的k和b y=kx+b
|
public static bool GetKandB(Hydro.Model.Point2d pt1, Hydro.Model.Point2d pt2, ref double k, ref double b)
|
{
|
if (pt1 == null || pt2 == null)
|
return false;
|
double X1 = pt1.X;
|
double Y1 = pt1.Y;
|
double X2 = pt2.X;
|
double Y2 = pt2.Y;
|
if (Math.Abs(X1 - X2) < 0.000001)
|
{
|
k = vertical_k;
|
b = Y2;
|
return false;
|
}
|
else
|
{
|
k = (Y1 - Y2) / (X1 - X2);
|
b = Y1 - (Y1 - Y2) * X1 / (X1 - X2);
|
return true;
|
}
|
}
|
|
//通过2点,得到通过这2点的直线的k,b 线的形式是 y=k*x+b,竖直返回false
|
public static bool GetKandB(Point2d pt1, Point2d pt2, out double k, out double b,double ingoreDis = 0.000001)
|
{
|
k = 0;
|
b = 0;
|
if (Math.Abs(pt1.X - pt2.X) < ingoreDis)
|
{//竖直
|
k = vertical_k;
|
b = pt1.X;
|
return false;
|
}
|
if (Math.Abs(pt1.Y - pt2.Y) < ingoreDis)
|
{//平行
|
k = 0;
|
b = pt1.X;
|
return true;
|
}
|
|
k = (pt1.Y - pt2.Y) / (pt1.X - pt2.X);// Math.Atan((pt1.Y - pt2.Y) / (pt1.X - pt2.X)) * 180 / Math.PI;
|
|
b = pt1.Y - k * pt1.X;
|
|
return true;
|
}
|
|
//取中间点
|
public static Point2d GetMiddlePoint(Point2d pt1, Point2d pt2)
|
{
|
return new Point2d((pt1.X + pt2.X) * 0.5, (pt1.Y + pt2.Y) * 0.5);
|
}
|
|
//取内部点
|
public static Point2d GetInnerPoint(Point2d startPt, Point2d endPt, double ratio)
|
{
|
if (startPt == null || endPt == null)
|
return null;
|
return new Point2d(startPt.X + (endPt.X - startPt.X) * ratio, startPt.Y + (endPt.Y - startPt.Y) * ratio);
|
}
|
|
|
//是否是内部点
|
public static bool IsInnerPoint(Point2d startPt, Point2d endPt, Point2d pt)
|
{
|
if (startPt == null || endPt == null)
|
return false ;
|
if (pt.X < startPt.X && pt.X > endPt.X)
|
return true;
|
if (pt.X > startPt.X && pt.X < endPt.X)
|
return true;
|
return false;
|
}
|
|
//是否是内部点
|
public static bool IsInnerPointByX(Point2d startPt, Point2d endPt, Point2d pt)
|
{
|
if (startPt == null || endPt == null)
|
return false ;
|
if (pt.X < startPt.X && pt.X > endPt.X)
|
return true;
|
if (pt.X > startPt.X && pt.X < endPt.X)
|
return true;
|
return false;
|
}
|
//
|
public static bool IsInnerPointByY(Point2d startPt, Point2d endPt, Point2d pt)
|
{
|
if (startPt == null || endPt == null)
|
return false ;
|
if (pt.Y < startPt.X && pt.Y > endPt.Y)
|
return true;
|
if (pt.Y > startPt.X && pt.Y < endPt.Y)
|
return true;
|
return false;
|
}
|
/// <summary>
|
/// 计算交点(没有 就返回null)
|
/// </summary>
|
/// <param name="startPt"></param>
|
/// <param name="endPt"></param>
|
/// <returns></returns>
|
public static Point2d GetCrossPoint(Point2d startPt1, Point2d endPt1, Point2d startPt2, Point2d endPt2)
|
{
|
if (startPt1 == null || endPt1 == null)
|
return null;
|
if (startPt2 == null || endPt2 == null)
|
return null;
|
|
double k1, b1;
|
GetKandB(startPt1, endPt1, out k1, out b1);
|
|
double k2, b2;
|
GetKandB(startPt2, endPt2, out k2, out b2);
|
|
if (Math.Abs(k1 - k2) < 0.000001)
|
return null;
|
|
if (k1 == vertical_k)
|
{//垂直
|
return new Point2d(startPt1.X, startPt1.X * k2 + b2);
|
}
|
if (k2 == vertical_k)
|
{//垂直
|
return new Point2d(startPt2.X, startPt2.X * k1 + b1 );
|
}
|
|
double sect_x = (b2-b1)/(k1-k2);
|
return new Point2d(sect_x, sect_x * k1 + b1);
|
}
|
/// <summary>
|
/// 是否平行
|
/// </summary>
|
/// <param name="startPt1"></param>
|
/// <param name="endPt1"></param>
|
/// <param name="startPt2"></param>
|
/// <param name="endPt2"></param>
|
/// <returns></returns>
|
public static bool IsParallel(Point2d startPt1, Point2d endPt1, Point2d startPt2, Point2d endPt2)
|
{
|
if (startPt1 == null || endPt1 == null)
|
return false;
|
if (startPt2 == null || endPt2 == null)
|
return false;
|
|
double k1, b1;
|
GetKandB(startPt1, endPt1, out k1, out b1);
|
|
double k2, b2;
|
GetKandB(startPt2, endPt2, out k2, out b2);
|
|
if (Math.Abs(k1 - k2) < 0.000001)
|
return true;
|
else
|
return false;
|
}
|
|
//三个点在同一条直线上,输入(X1,Y1),(X2,Y2)以及沿(X2,Y2)侧延长Length,得到的点(X3,Y3)
|
public static Point2d GetExtendPoint(Point2d startPt, Point2d endPt, double exLength)
|
{
|
return GetExtendPointByLength(startPt, endPt, exLength);
|
}
|
|
//三个点在同一条直线上,输入(X1,Y1),(X2,Y2)以及沿(X2,Y2)侧延长Length,得到的点(X3,Y3)
|
public static Point2d GetExtendPointByLength(Point2d startPt, Point2d endPt, double exLength)
|
{
|
if (startPt == null || endPt == null)
|
return null;
|
double betweenLength = Point.GetDistance(startPt, endPt);
|
if (betweenLength < 0.01)
|
return startPt;
|
double ex_ratio = (betweenLength + exLength) / betweenLength;
|
Point2d extPt = new Point2d();
|
extPt.X = (endPt.X - startPt.X) * ex_ratio + startPt.X;
|
extPt.Y = (endPt.Y - startPt.Y) * ex_ratio + startPt.Y;
|
|
return extPt;
|
}
|
|
//三个点在同一条直线上,输入(X1,Y1),(X2,Y2)以及沿(X2,Y2)侧延长Length,得到的点(X3,Y3)
|
public static Point2d GetExtendPointByX(Point2d startPt, Point2d endPt, double exPointX)
|
{
|
if (startPt == null || endPt == null)
|
return null;
|
double X1 = startPt.X;
|
double Y1 = startPt.Y;
|
double X2 = endPt.X;
|
double Y2 = endPt.Y;
|
|
if (Math.Abs(X1 - X2) < 0.000001)
|
{//竖直
|
|
return null;
|
}
|
else if (Math.Abs(Y1 - Y2) < 0.000001)
|
{//竖直
|
|
return new Point2d(exPointX, Y1);
|
}
|
else
|
{
|
//线的形式是 y = k * x + b,
|
double k = (Y1 - Y2) / (X1 - X2);
|
double b = Y1 - (Y1 - Y2) * X1 / (X1 - X2);
|
|
double Y = k * exPointX + b;
|
return new Point2d(exPointX, Y);
|
}
|
}
|
/// <summary>
|
/// 求直线外一点到该直线的投影点
|
/// </summary>
|
/// <param name="pLine">线上任一点</param>
|
/// <param name="k">直线斜率</param>
|
/// <param name="pOut">线外指定点</param>
|
/// <param name="pProject">投影点</param>
|
public static Point2d GetProjectivePoint(Point2d pLine, double k, Point2d pOut)
|
{
|
if (pLine == null || pOut == null)
|
return null ;
|
Point2d pProject = new Point2d();
|
if (k == 0) //垂线斜率不存在情况
|
{
|
pProject.X = pOut.X;
|
pProject.Y = pLine.Y;
|
}
|
else
|
{
|
pProject.X = (float)((k * pLine.X + pOut.X / k + pOut.Y - pLine.Y) / (1 / k + k));
|
pProject.Y = (float)(-1 / k * (pProject.X - pOut.X) + pOut.Y);
|
}
|
return pProject;
|
}
|
|
/// <summary>
|
///
|
/// </summary>
|
/// <param name="pLine1"></param>
|
/// <param name="pLine2"></param>
|
/// <param name="pOut"></param>
|
/// <returns></returns>
|
public static Point2d GetProjectivePoint(Point2d pLine1, Point2d pLine2, Point2d pOut)
|
{
|
if (pLine1 == null || pLine2 == null || pOut == null)
|
return null;
|
double k,b;
|
GetKandB(pLine1, pLine2, out k, out b);
|
if (k >= vertical_k)
|
{//垂直
|
return new Point2d(pLine1.X, pOut.Y);
|
}
|
return GetProjectivePoint(pLine1, k, pOut);
|
}
|
|
/// <summary>
|
/// 点到线的距离, 注意不一定是垂直距离,点只在(line_start和line_end之间
|
/// </summary>
|
/// <param name="line_start"></param>
|
/// <param name="line_end"></param>
|
/// <param name="point"></param>
|
/// <returns></returns>
|
public static double DistancePointToLine(Point2d line_start, Point2d line_end, Point2d point) // a和b是线段的两个端点, c是检测点
|
{
|
if (line_start == null || line_end == null || point == null)
|
return 0;
|
var project_pt = GetProjectivePoint(line_start, line_end, point);
|
if (project_pt.X == line_start.X)
|
{//垂直
|
if (IsInnerPointByY(line_start, line_end, project_pt))
|
return project_pt.Distance(point);
|
}
|
else
|
{
|
if (IsInnerPointByX(line_start, line_end, project_pt))
|
return project_pt.Distance(point);
|
}
|
|
var dis1 = line_start.Distance(point);
|
var dis2 = line_end.Distance(point);
|
if (dis1 < dis2)
|
return dis1;
|
else
|
return dis2;
|
}
|
/// <summary>
|
/// 点到线的距离, 注意不一定是垂直距离,点只在(line_start和line_end之间
|
/// </summary>
|
/// <param name="line_start"></param>
|
/// <param name="line_end"></param>
|
/// <param name="point"></param>
|
/// <returns></returns>
|
public static double DistancePointToLine(List<Point2d> multi_line_start,bool isCloseCurve , Point2d point) // a和b是线段的两个端点, c是检测点
|
{
|
if (multi_line_start == null || multi_line_start.Count() < 2)
|
return -1;
|
double min_dis = DistancePointToLine(multi_line_start[0], multi_line_start[1], point);
|
|
for (int index = 1; index < multi_line_start.Count-1; index++)
|
{
|
var min_dis_current = DistancePointToLine(multi_line_start[index], multi_line_start[index+1], point);
|
if (min_dis_current < min_dis)
|
{
|
min_dis = min_dis_current;
|
}
|
}
|
if (isCloseCurve)
|
{
|
var min_dis_current = DistancePointToLine(multi_line_start[0], multi_line_start[multi_line_start.Count - 1], point);
|
if (min_dis_current < min_dis)
|
{
|
min_dis = min_dis_current;
|
}
|
}
|
|
|
return min_dis;
|
}
|
|
}
|
}
|