using RichCreator.Utility.Structs;
|
using System;
|
using System.Collections;
|
using System.Collections.Generic;
|
using System.Linq;
|
using System.Text;
|
using System.Threading.Tasks;
|
|
namespace RichCreator.Utility.Utilitys
|
{
|
|
/// <summary>
|
/// 几何体之间的关系类型
|
/// </summary>
|
public enum Intersection
|
{
|
None,//没关系
|
Tangent,//切线,正切
|
Intersection,//相交,交叉
|
Containment//包含
|
}
|
|
/// <summary>
|
/// 与几何相关的辅助类
|
/// </summary>
|
public static class GeometryHelper
|
{
|
/// <summary>
|
/// 获取点到点的距离
|
/// </summary>
|
/// <param name="a"></param>
|
/// <param name="b"></param>
|
/// <returns></returns>
|
public static double GetPointDistance(ZTPoint a, ZTPoint b)
|
{
|
return Math.Sqrt((a.X - b.X) * (a.X - b.X) + (a.Y - b.Y) * (a.Y - b.Y));
|
}
|
|
/// <summary>
|
/// 获取点到直线的距离
|
/// </summary>
|
/// <param name="line"></param>
|
/// <param name="point"></param>
|
/// <returns></returns>
|
public static double GetNearestDistance(ZTLinePoint line, ZTPoint point)
|
{
|
double a, b, c;
|
a = GetPointDistance(line.P2, point);
|
if (a <= 0.00001)
|
{
|
return 0.0f;
|
}
|
|
b = GetPointDistance(line.P1, point);
|
if (b <= 0.00001)
|
{
|
return 0.0f;
|
}
|
|
c = GetPointDistance(line.P1, line.P2);
|
if (c <= 0.00001)
|
{
|
//如果PA和PB坐标相同,则退出函数,并返回距离
|
return a;
|
}
|
|
if (a * a >= b * b + c * c)
|
{
|
return b; //如果是钝角返回b
|
}
|
|
if (b * b >= a * a + c * c)
|
{
|
return a; //如果是钝角返回a
|
}
|
|
double l = (a + b + c) / 2; //周长的一半
|
double s = Math.Sqrt(Math.Abs(l * (l - a) * (l - b) * (l - c))); //海伦公式求面积,也可以用矢量求
|
return 2 * s / c;
|
}
|
|
|
|
/// <summary>
|
/// 判断线段与多边形的关系
|
/// </summary>
|
/// <param name="line"></param>
|
/// <param name="polygon"></param>
|
/// <returns></returns>
|
public static Intersection IntersectionOf(ZTLinePoint line, ZTPolygon polygon)
|
{
|
if (polygon.Length == 0)
|
{
|
return Intersection.None;
|
}
|
if (polygon.Length == 1)
|
{
|
return IntersectionOf(polygon[0], line);
|
}
|
bool tangent = false;
|
for (int index = 0; index < polygon.Length; index++)
|
{
|
int index2 = (index + 1) % polygon.Length;
|
Intersection intersection = IntersectionOf(line, new ZTLinePoint(polygon[index], polygon[index2]));
|
if (intersection == Intersection.Intersection)
|
{
|
return intersection;
|
}
|
if (intersection == Intersection.Tangent)
|
{
|
tangent = true;
|
}
|
}
|
return tangent ? Intersection.Tangent : IntersectionOf(line.P1, polygon);
|
}
|
|
|
/// <summary>
|
/// 判断点与多边形的关系
|
/// </summary>
|
/// <param name="point"></param>
|
/// <param name="polygon"></param>
|
/// <returns></returns>
|
public static Intersection IntersectionOf(ZTPoint point, ZTPolygon polygon)
|
{
|
switch (polygon.Length)
|
{
|
case 0:
|
return Intersection.None;
|
case 1:
|
if (polygon[0].X == point.X && polygon[0].Y == point.Y)
|
{
|
return Intersection.Tangent;
|
}
|
else
|
{
|
return Intersection.None;
|
}
|
case 2:
|
return IntersectionOf(point, new ZTLinePoint(polygon[0], polygon[1]));
|
}
|
|
int counter = 0;
|
int i;
|
ZTPoint p1;
|
int n = polygon.Length;
|
p1 = polygon[0];
|
if (point == p1)
|
{
|
return Intersection.Tangent;
|
}
|
|
for (i = 1; i <= n; i++)
|
{
|
ZTPoint p2 = polygon[i % n];
|
if (point == p2)
|
{
|
return Intersection.Tangent;
|
}
|
if (point.Y > Math.Min(p1.Y, p2.Y))
|
{
|
if (point.Y <= Math.Max(p1.Y, p2.Y))
|
{
|
if (point.X <= Math.Max(p1.X, p2.X))
|
{
|
if (p1.Y != p2.Y)
|
{
|
double xinters = (point.Y - p1.Y) * (p2.X - p1.X) / (p2.Y - p1.Y) + p1.X;
|
if (p1.X == p2.X || point.X <= xinters)
|
counter++;
|
}
|
}
|
}
|
}
|
p1 = p2;
|
}
|
|
return (counter % 2 == 1) ? Intersection.Containment : Intersection.None;
|
}
|
|
/// <summary>
|
/// 判断点与直线的关系
|
/// </summary>
|
/// <param name="point"></param>
|
/// <param name="line"></param>
|
/// <returns></returns>
|
public static Intersection IntersectionOf(ZTPoint point, ZTLinePoint line)
|
{
|
float bottomY = Math.Min(line.Y1, line.Y2);
|
float topY = Math.Max(line.Y1, line.Y2);
|
bool heightIsRight = point.Y >= bottomY &&
|
point.Y <= topY;
|
//Vertical line, slope is divideByZero error!
|
if (line.X1 == line.X2)
|
{
|
if (point.X == line.X1 && heightIsRight)
|
{
|
return Intersection.Tangent;
|
}
|
else
|
{
|
return Intersection.None;
|
}
|
}
|
float slope = (line.X2 - line.X1) / (line.Y2 - line.Y1);
|
bool onLine = (line.Y1 - point.Y) == (slope * (line.X1 - point.X));
|
if (onLine && heightIsRight)
|
{
|
return Intersection.Tangent;
|
}
|
else
|
{
|
return Intersection.None;
|
}
|
}
|
|
/// <summary>
|
/// 判断直线与直线的关系
|
/// </summary>
|
/// <param name="line1"></param>
|
/// <param name="line2"></param>
|
/// <returns></returns>
|
public static Intersection IntersectionOf(ZTLinePoint line1, ZTLinePoint line2)
|
{
|
// Fail if either line segment is zero-length.
|
if (line1.X1 == line1.X2 && line1.Y1 == line1.Y2 || line2.X1 == line2.X2 && line2.Y1 == line2.Y2)
|
return Intersection.None;
|
|
if (line1.X1 == line2.X1 && line1.Y1 == line2.Y1 || line1.X2 == line2.X1 && line1.Y2 == line2.Y1)
|
return Intersection.Intersection;
|
if (line1.X1 == line2.X2 && line1.Y1 == line2.Y2 || line1.X2 == line2.X2 && line1.Y2 == line2.Y2)
|
return Intersection.Intersection;
|
|
// (1) Translate the system so that point A is on the origin.
|
line1.X2 -= line1.X1; line1.Y2 -= line1.Y1;
|
line2.X1 -= line1.X1; line2.Y1 -= line1.Y1;
|
line2.X2 -= line1.X1; line2.Y2 -= line1.Y1;
|
|
// Discover the length of segment A-B.
|
double distAB = Math.Sqrt(line1.X2 * line1.X2 + line1.Y2 * line1.Y2);
|
|
// (2) Rotate the system so that point B is on the positive X axis.
|
double theCos = line1.X2 / distAB;
|
double theSin = line1.Y2 / distAB;
|
double newX = line2.X1 * theCos + line2.Y1 * theSin;
|
line2.Y1 = (Int32)(line2.Y1 * theCos - line2.X1 * theSin); line2.X1 = (Int32)newX;
|
newX = line2.X2 * theCos + line2.Y2 * theSin;
|
line2.Y2 = (Int32)(line2.Y2 * theCos - line2.X2 * theSin); line2.X2 = (Int32)newX;
|
|
// Fail if segment C-D doesn't cross line A-B.
|
if (line2.Y1 < 0 && line2.Y2 < 0 || line2.Y1 >= 0 && line2.Y2 >= 0)
|
return Intersection.None;
|
|
// (3) Discover the position of the intersection point along line A-B.
|
double posAB = line2.X2 + (line2.X1 - line2.X2) * line2.Y2 / (line2.Y2 - line2.Y1);
|
|
// Fail if segment C-D crosses line A-B outside of segment A-B.
|
if (posAB < 0 || posAB > distAB)
|
return Intersection.None;
|
|
// (4) Apply the discovered position to line A-B in the original coordinate system.
|
return Intersection.Intersection;
|
}
|
}
|
|
|
}
|