C#平面几何简单操作(多边形)

对于多边形的操作,网上有很多成熟的插件,可以轻松的进行多边形相关计算,但我貌似没有找到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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值