用数学方法解决工程问题系列(三) 判断任意给定一点是否在多边形内

本文探讨了在高频率调用场景下,如何优化判断一个点是否位于矩形内部的算法。通过对比内角和法与叉积法,最终采用叉积法实现了性能的有效提升。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

项目里有这样一个需求,需要把一组矩形合并成一个多边形,这个多边形正好把所有矩形包在里面,而且是最小多边形。这里面尝试了好几种方案,不过每一种方案里都有这样一个步骤,判断给定的点在不在给定的矩形区域内。因为这是一个被频繁调用的方法,所以需要找出最优的实现。

  • 最先尝试的是使用内角和法,将这个在网上有详细说明和C++代码,改成C#代码如下:
            Line[] lineArray = new Line[vertexArray.Length];
            for (int index = 0; index < vertexArray.Length; index++)
            {
                if (vertexArray[index] == point)        //判断点与顶点重合
                {
                    return true;
                }

                lineArray[index] = new Line(point, vertexArray[index]);
            }

            Array.Sort(lineArray);

            for (int index = 0; index < lineArray.Length - 1; index++)
            {
                if (lineArray[index].IncludedAngleWith(lineArray[index + 1]) >= 180)
                {
                    return false;
                }
            }

            if (lineArray[lineArray.Length - 1].IncludedAngleWith(lineArray[0]) >= 180)
            {
                return false;
            }

            return true;
  • 使用DotTrace监测,发现因为调用次数非常多,总的消耗的时间太多,鉴于项目里只需要判断是否在矩形内,于是改用叉积法:
            PointF[] vertexArray = beanRect.apexPoints; // 矩形的四个顶点

            float cross1, cross2;

            float pointX = grid.CenterPoint.X + offsetX; // 点的X坐标
            float pointY = grid.CenterPoint.Y + offsetY; // 点的Y坐标

            // 判是否在v[0]v[1]和v[2]v[3]两边的同侧
            cross1 = (pointX - vertexArray[0].X) * (vertexArray[1].Y - vertexArray[0].Y) - (pointY - vertexArray[0].Y) * (vertexArray[1].X - vertexArray[0].X);
            cross2 = (pointX - vertexArray[3].X) * (vertexArray[2].Y - vertexArray[3].Y) - (pointY - vertexArray[3].Y) * (vertexArray[2].X - vertexArray[3].X);

            if ((cross1 * cross2) > 0 || (cross1 == 0 && cross2 > 0) || (cross2 == 0 && cross1 > 0))
                return false;

            // 判是否在v[0]v[3]和v[1]v[2]两边的同侧
            cross1 = (pointX - vertexArray[0].X) * (vertexArray[3].Y - vertexArray[0].Y) - (pointY - vertexArray[0].Y) * (vertexArray[3].X - vertexArray[0].X);
            cross2 = (pointX - vertexArray[1].X) * (vertexArray[2].Y - vertexArray[1].Y) - (pointY - vertexArray[1].Y) * (vertexArray[2].X - vertexArray[1].X);

            if ((cross1 * cross2 > 0) || (cross1 == 0 && cross2 > 0) || (cross2 == 0 && cross1 > 0))
                return false;

            return true;

再使用DotTrace监测,果然时间消耗瓶颈已经不在这里。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值