对于多边形的操作,网上有很多成熟的插件,可以轻松的进行多边形相关计算,但我貌似没有找到C#可以用的(可能查找方式不对),出于自身的兴趣,简单的写了一下,算法也不够成熟,还有很多缺陷,姑且先记录一下,待完善之后再做补充。
1、多边形实体:
public class PolygonData
{
/// <summary>
/// 创建一个多边形实体
/// </summary>
/// <param name="points">二维点数组</param>
public PolygonData(XPoint[] points)
{
Vertexs = points;
}
/// <summary>
/// 多边形顶点数组
/// </summary>
public XPoint[] Vertexs { get; set; }
/// <summary>
/// 多边形轮廓线集合
/// </summary>
/// <returns></returns>
public IEnumerable<XLine> BorderLines()
{
List<XLine> borders = new List<XLine>();
for (int i = 0; i < Vertexs.Length; i++)
{
var j = i + 1;
if (j >= Vertexs.Length)
{
j = 0;
}
XLine line = new XLine(Vertexs[i], Vertexs[j]);
borders.Add(line);
}
return borders;
}
/// <summary>
/// 获取顺时针定点
/// </summary>
/// <returns></returns>
public XPoint[] GetClockwiseVertexs()
{
double d = 0;
for (int i = 0; i < Vertexs.Length - 1; i++)
{
d += -0.5 * (Vertexs[i + 1].Y + Vertexs[i].Y) * (Vertexs[i + 1].X - Vertexs[i].X);
}
if (d > 0)
{
return GeometryUtility.ReverseArray(Vertexs);
}
return Vertexs;
}
/// <summary>
/// 多边形轮廓线集合
/// </summary>
/// <returns></returns>
public IEnumerable<XLine> ClockwiseBorderLines()
{
var clockwiseVertexs = GetClockwiseVertexs();
List<XLine> borders = new List<XLine>();
for (int i = 0; i < clockwiseVertexs.Length; i++)
{
var j = i + 1;
if (j >= clockwiseVertexs.Length)
{
j = 0;
}
XLine line = new XLine(clockwiseVertexs[i], clockwiseVertexs[j]);
borders.Add(line);
}
return borders;
}
/// <summary>
/// 是否包含二维点
/// </summary>
/// <param name="point"></param>
/// <returns></returns>
public bool ContainPoint(XPoint point)
{
//点在任意一条边线上直接当做包含
var borders = BorderLines();
int digits = 4;
double tolance = 0.0001;
foreach (var line in borders)
{
var lineStart = line.StartPt;
var lineEnd = line.EndPt;
var minX = Math.Min(lineStart.X, lineEnd.X);
var maxX = Math.Max(lineStart.X, lineEnd.X);
var minY = Math.Min(lineStart.Y, lineEnd.Y);
var maxY = Math.Max(lineStart.Y, lineEnd.Y);
if (Math.Round(point.X - lineStart.X, digits) * Math.Round(lineEnd.Y - lineStart.Y, digits) == Math.Round(lineEnd.X - lineStart.X, digits) * Math.Round(point.Y - lineStart.Y, digits)
&& point.X >= minX - tolance && point.X <= maxX + tolance && point.Y >= minY - tolance && point.Y <= maxY + tolance)
{
return true;
}
}
bool result = false;
int j = Vertexs.Count() - 1;
for (int i = 0; i < Vertexs.Count(); i++)
{
if (Vertexs[i].Y < point.Y && Vertexs[j].Y >= point.Y || Vertexs[j].Y < point.Y && Vertexs[i].Y >= point.Y)
{
if (Vertexs[i].X + (point.Y - Vertexs[i].Y) / (Vertexs[j].Y - Vertexs[i].Y) * (Vertexs[j].X - Vertexs[i].X) < point.X)
{
result = !result;
}
}
j = i;
}
return result;
}
}
//这个是多边形计算的时候用到的一个临时中转
public class LineGroup
{
public double Length { get; set; }
public XRange LineRange { get; set; }
public List<XLine> Lines { get; set; }
}
2、多边形与点、线段、圆弧等对象的一些简单操作(不完善,仅供参考):
public class GeometryUtility
{
/// <summary>
/// 求两个多边形的交集顶点
/// </summary>
/// <param name="first"></param>
/// <param name="second"></param>
/// <returns></returns>
public static XPoint[] IntersectionsVertexs(PolygonData first, PolygonData second)
{
var firstBorders = first.ClockwiseBorderLines();
var secondBorders = second.ClockwiseBorderLines();
List<XPoint> newFirstVertexs = new List<XPoint>();
foreach (var fsBd in firstBorders)
{
newFirstVertexs.Add(fsBd.StartPt);
List<XPoint> intersectPts = new List<XPoint>();
foreach (var scBd in secondBorders)
{
var intersectPoint = IntersectWith(fsBd, scBd);
if (intersectPoint != null)
{
intersectPts.Add(intersectPoint);
}
}
if (intersectPts.Count > 1)
{
var tol = fsBd.Length() * 0.001;
if (Math.Abs(fsBd.StartPt.X - fsBd.EndPt.X) < tol)
{
if (fsBd.StartPt.Y < fsBd.EndPt.Y)
{
intersectPts = intersectPts.OrderBy(t => t.Y).ToList();
}
else
{
intersectPts = intersectPts.OrderByDescending(t => t.Y).ToList();
}
}
else
{
if (fsBd.StartPt.X < fsBd.EndPt.X)
{
intersectPts = intersectPts.OrderBy(t => t.X).ToList();
}
else
{
intersectPts = intersectPts.OrderByDescending(t => t.X).ToList();
}
}
}
newFirstVertexs.AddRange(intersectPts);
newFirstVertexs.Add(fsBd.EndPt);
}
newFirstVertexs = FilterRepeatPoints(newFirstVertexs.ToArray()).ToList();
newFirstVertexs.Add(newFirstVertexs.First());
List<XPoint> newPolygonVertexs = new List<XPoint>();
int lastIndex = -1;
for (int i = 0; i < newFirstVertexs.Count; i++)
{
var fisPt = newFirstVertexs[i];
if (second.ContainPoint(fisPt))
{
newPolygonVertexs.Add(fisPt);
lastIndex = i;
}
else if (lastIndex >= 0 && lastIndex + 1 == i)
{
var lastPt = newFirstVertexs[lastIndex];
bool haveNext = false;
for (int j = i + 1; j < newFirstVertexs.Count; j++)
{
var nextPt = newFirstVertexs[j];
if (second.ContainPoint(nextPt))
{
haveNext = true;
var betweenPts = GetBetweenVertexs(second, lastPt, nextPt);
newPolygonVertexs.AddRange(betweenPts);
i = j - 1;
break;
}
}
if (!haveNext)
{
var nextPt = newPolygonVertexs.First();
if (second.ContainPoint(nextPt))
{
var betweenPts = GetBetweenVertexs(second, lastPt, nextPt);
newPolygonVertexs.AddRange(betweenPts);
}
break;
}
}
}
return FilterRepeatPoints(newPolygonVertexs.ToArray());
}
/// <summary>
/// 判断两条线段是否平行
/// </summary>
/// <param name="lineA">线段A</param>
/// <param name="lineB">线段B</param>
/// <returns>true:平行,反之</returns>
public static bool IsParallel(XLine lineA, XLine lineB)
{
bool flagA = lineA.StartPt.X == lineA.EndPt.X;
bool flagB = lineB.StartPt.X == lineB.EndPt.X;
if (flagA && flagB)
{
//两条垂直线
return true;
}
else if (flagB || flagB)
{
//一条垂直一条不垂直
return false;
}
else
{
//利用斜率进行判断
var slopeA = (lineA.EndPt.Y - lineA.StartPt.Y) / (lineA.EndPt.X - lineA.StartPt.X);
var slopeB = (lineB.EndPt.Y - lineB.StartPt.Y) / (lineB.EndPt.X - lineB.StartPt.X);
return slopeA == slopeB;
}
}
/// <summary>
/// 获取两条线段的交点
/// </summary>
/// <param name="lineM">线段M</param>
/// <param name="lineN">线段N</param>
/// <returns>相交则返回交点坐标,否则返回null</returns>
public static XPoint IntersectWith(XL