C#平面几何简单操作(根据线段计算表格)

算法并非完美,欢迎大佬指正!

代码如下:

public class CellExtract
{
    /// <summary>
    /// 根据表格线计算单元格
    /// </summary>
    /// <param name="horiLines">水平表格线</param>
    /// <param name="vertLines">垂直表格线</param>
    /// <returns></returns>
    public static XExtents[] CalExtents2dByLines(XLine[] horiLines, XLine[] vertLines)
    {
        if (horiLines.Length == 0 || vertLines.Length == 0)
        {
            return new XExtents[0];
        }
        XPoint[,] insectPoints = CalCellPoint(horiLines, vertLines);
        double tol = horiLines[0].Length() * 0.002;//控制精度,以便提升性能
        XExtents[] xEntentsArry = CalExtents2dByPoints(insectPoints);//垂直和水平直线构成的单元格
        List<XExtents> fitlerExt = new List<XExtents>();
        foreach (XExtents xExtents in xEntentsArry)
        {
            try
            {
                //判断单元格四条边的中点是否在表格线的间隔范围内
                XPoint left = new XPoint(xExtents.MinPoint.X, (xExtents.MinPoint.Y + xExtents.MaxPoint.Y) * 0.5);
                XPoint right = new XPoint(xExtents.MaxPoint.X, (xExtents.MinPoint.Y + xExtents.MaxPoint.Y) * 0.5);
                XPoint top = new XPoint((xExtents.MinPoint.X + xExtents.MaxPoint.X) * 0.5, xExtents.MaxPoint.Y);
                XPoint bottom = new XPoint((xExtents.MinPoint.X + xExtents.MaxPoint.X) * 0.5, xExtents.MinPoint.Y);

                XLine[] leftline = vertLines.Where(t => Math.Abs(t.StartPt.X - left.X) < tol || Math.Abs(t.EndPt.X - left.X) < tol).ToArray();
                bool leftflag = leftline.Length > 0 && leftline.Any(t => t.In(left));

                XLine[] rightline = vertLines.Where(t => Math.Abs(t.StartPt.X - right.X) < tol || Math.Abs(t.EndPt.X - right.X) < tol).ToArray();
                bool rightflag = rightline.Length > 0 && rightline.Any(t => t.In(right));

                XLine[] topline = horiLines.Where(t => Math.Abs(t.StartPt.Y - top.Y) < tol || Math.Abs(t.EndPt.Y - top.Y) < tol).ToArray();
                bool topflag = topline.Length > 0 && topline.Any(t => t.In(top));

                XLine[] bottomline = horiLines.Where(t => Math.Abs(t.StartPt.Y - bottom.Y) < tol || Math.Abs(t.EndPt.Y - bottom.Y) < tol).ToArray();
                bool bottomflag = bottomline.Length > 0 && bottomline.Any(t => t.In(bottom));

                if (leftflag && rightflag && topflag && bottomflag)
                {
                    fitlerExt.Add(xExtents);
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }
        }
        return fitlerExt.ToArray();
    }

    /// <summary>
    /// 计算横线段和竖线段的所有交点
    /// </summary>
    /// <param name="horlines">网格中所有横线</param>
    /// <param name="verlines">网格中所有竖线</param>
    /// <returns></returns>/
    public static XPoint[,] CalCellPoint(XLine[] horlines, XLine[] verlines)
    {
        XPoint[,] points = new XPoint[horlines.Length + 2, verlines.Length + 2];
        int iiii = -1;
        int jjjj = -1;
        try
        {
            for (int i = 0; i < horlines.Length; i++)
            {
                for (int j = 0; j < verlines.Length; j++)
                {
                    XPoint sectPnt = XLine.IntersectWith(horlines[i], verlines[j], 0.01);
                    points[i + 1, j + 1] = sectPnt;
                    iiii = i;
                    jjjj = j;
                }
            }
            //用线的起点终点补齐交点集周围一圈点
            for (int i = 0; i < horlines.Length; i++)
            {
                points[i + 1, 0] = horlines[i].StartPt.X < horlines[i].EndPt.X ? horlines[i].StartPt : horlines[i].EndPt;
                points[i + 1, verlines.Length + 1] = horlines[i].StartPt.X > horlines[i].EndPt.X ? horlines[i].StartPt : horlines[i].EndPt;
            }
            for (int j = 0; j < verlines.Length; j++)
            {
                points[0, j + 1] = verlines[j].StartPt;
                points[horlines.Length + 1, j + 1] = verlines[j].EndPt;
            }
            points[0, 0] = new XPoint(double.NaN, double.NaN);
            points[horlines.Length + 1, 0] = new XPoint(double.NaN, double.NaN);
            points[horlines.Length + 1, verlines.Length + 1] = new XPoint(double.NaN, double.NaN);
            points[0, verlines.Length + 1] = new XPoint(double.NaN, double.NaN);
        }
        catch (Exception e)
        {
            string text = iiii + "-" + jjjj;//调试代码,用于定位求交出错的线
            Console.WriteLine($"【{text}】{e.Message}");
        }
        return points;
    }

    /// <summary>
    /// 根据二维点列,计算单元格
    /// </summary>
    /// <param name="points">二维点列</param>
    /// <returns></returns>
    private static XExtents[] CalExtents2dByPoints(XPoint[,] points)
    {
        List<XExtents> xExtentsList = new List<XExtents>();
        int rowCount = points.GetLength(0);
        int colCount = points.GetLength(1);

        for (int i = 0; i < rowCount; i++)
        {
            for (int j = 0; j < colCount; j++)
            {
                if (XPoint.IsNaN(points[i, j])) continue;

                XPoint[] p = new XPoint[4];//P1左上,P2右上,P3右下,P4左下

                p[0] = points[i, j];//找到第一个点P1
                //第一步,向右找
                int k;
                for (k = j + 1; k < colCount; k++)
                {
                    if (!XPoint.IsNaN(points[i, k]))
                    {
                        p[1] = points[i, k];//找到第二个点P2
                        //第二步,P1,P2同时向下找
                        for (int s = i + 1; s < rowCount; s++)
                        {
                            if ((!XPoint.IsNaN(points[s, j])) && (!XPoint.IsNaN(points[s, k])))
                            {
                                p[2] = points[s, k];//找到第三个点P3
                                p[3] = points[s, j];//找到第四个点P4

                                if (XPoint.JugeRect(p[0], p[1], p[2], p[3]) || XPoint.JugeRect(p[0], p[2], p[1], p[3]))//判断4个点是否构成正常的矩形
                                {
                                    double minX = Min(new List<double>() { p[0].X, p[1].X, p[2].X, p[3].X });
                                    double maxX = Max(new List<double>() { p[0].X, p[1].X, p[2].X, p[3].X });
                                    double minY = Min(new List<double>() { p[0].Y, p[1].Y, p[2].Y, p[3].Y });
                                    double maxY = Max(new List<double>() { p[0].Y, p[1].Y, p[2].Y, p[3].Y });
                                    XPoint minPt = new XPoint(minX, minY);
                                    XPoint maxPt = new XPoint(maxX, maxY);
                                    XExtents xExtents = new XExtents(minPt, maxPt);
                                    xExtentsList.Add(xExtents);
                                }
                            }
                        }
                    }
                }
            }
        }
        for (int i = 0; i < rowCount; i++)
        {
            for (int j = 0; j < colCount; j++)
            {
                if (XPoint.IsNaN(points[i, j])) continue;

                XPoint[] p = new XPoint[4];//P1左上,P2右上,P3右下,P4左下
                p[0] = points[i, j];//找到第一个点P1
                //第一步,向下找
                int s = j + 1;
                for (int k = i + 1; k < rowCount; k++)
                {
                    if (!XPoint.IsNaN(points[k, j]))
                    {
                        p[1] = points[k, j];//找到第二个点P2
                        //第二步,P1,P2同时向右找
                        for (s = j + 1; s < colCount; s++)
                        {
                            if ((!XPoint.IsNaN(points[i, s])) && (!XPoint.IsNaN(points[k, s])))
                            {
                                p[2] = points[k, s];//找到第三个点P3
                                p[3] = points[i, s];//找到第四个点P4

                                if (XPoint.JugeRect(p[0], p[3], p[2], p[1]) || XPoint.JugeRect(p[0], p[2], p[1], p[3]))//判断4个点是否构成正常的矩形
                                {
                                    double minX = Min(new List<double>() { p[0].X, p[1].X, p[2].X, p[3].X });
                                    double maxX = Max(new List<double>() { p[0].X, p[1].X, p[2].X, p[3].X });
                                    double minY = Min(new List<double>() { p[0].Y, p[1].Y, p[2].Y, p[3].Y });
                                    double maxY = Max(new List<double>() { p[0].Y, p[1].Y, p[2].Y, p[3].Y });
                                    XPoint minPt = new XPoint(minX, minY);
                                    XPoint maxPt = new XPoint(maxX, maxY);
                                    XExtents xExtents = new XExtents(minPt, maxPt);
                                    xExtentsList.Add(xExtents);
                                }
                            }
                        }
                    }
                }
            }
        }
        return xExtentsList.ToArray();
    }

    /// <summary>
    /// 获取集合中的最小值
    /// </summary>
    /// <param name="list"></param>
    /// <returns></returns>
    public static double Min(IList<double> list)
    {
        if (list.Count == 0)
        {
            return 0;
        }
        double temp = double.MaxValue;
        for (int i = 0; i < list.Count; i++)
        {
            if (temp > list[i]) temp = list[i];
        }
        return temp;
    }

    /// <summary>
    /// 获取集合中的最大值
    /// </summary>
    /// <param name="list"></param>
    /// <returns></returns>
    public static double Max(IList<double> list)
    {
        if (list.Count == 0)
        {
            return 0;
        }
        double temp = double.MinValue;
        for (int i = 0; i < list.Count; i++)
        {
            if (temp < list[i]) temp = list[i];
        }
        return temp;
    }
}

代码中,对于点、线、面的相关操作,详见:C#平面几何简单操作(点、线、面)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值