七巧板复原算法——计算机图形学基本算法之一, 点在多边形内部的判断

注:此时我已经完成了一个演示版本,但是为了文章的渐进性,我将把开发过程一步步的写出来,用来记录。
本实验代码用到的图形学关系和算法列举如下:

基本计算机图形学关系和算法

1.点在多边形内部的
点在多边形内部的判断方法的原理非常简单:由该点发出的射线如果和多边形的交点数是奇数,则该点在多边形的内部,如果是偶数,则在外部。简单说明如图示:

在这里插入图片描述
对于一个凸多边形,这个结论是显然的,因为该点在多边内部的话,经过该点的射线只能和凸多边形有一个交点;而在外面的点,如果和多边形的一条边相交,子必然经过其 内部的一个点,这样根据上面的结论,则该射线在射出时,必然还会和另一边有一个交点,这样交点数就是两个。这样对于图多边形是成立的。
对于凹多边形,有两种情况,即A点和B点 的情况,这两种情况和凸多边形是一致的。下面讨论C点。C点在凸多边形内部,发出的射线如果从某一条边射出,则有一个交点, 再再进入内部再射出时,必然是两个交点(可利用凸多边形的结论),交点数是1+2*n, 是个奇数。D点则必然是偶数。
需要说明的是,为了计算的简便,会选择和X轴平行的直线进行计算,这样就会可能出现下图的情景。

在这里插入图片描述

A射线过一个顶点,B射线经过一条边和一个顶点,C射线和某一边二重合。为了遵循上面的判断方法,需要做出几个规定。
对于A,如果射线经过顶点,且不是顶点,则在外部,或者认为是有两个交点。其实这个从微观的角度讲,就是两个交点。对于射线B,和一条边相交,过一个顶点,规定这种顶点算一个交点。射线C其实和A是一样的,和某线段重合,不算有交点。经过这样处理,上面的判断方法就一致了。
判断点在多边形内部的代码如下:
注:代码参考了 https://www.cnblogs.com/soundcode/p/7727893.html

       public bool PointInsidePolygon(PointF pnt)
        {
            int j = 0, cnt = 0;
            //点在多边形某条边上的判断
            if (PntOnPlgSeg(pnt, this, out _, true))
            {

                return true;

            }
            else
            {
                for (int i = 0; i < m_OrgPointArr.Length; i++)
                {
                    

                    j = (i == m_OrgPointArr.Length - 1) ? 0 : j + 1;
                    if ((m_OrgPointArr[i].Y != m_OrgPointArr[j].Y) && (((pnt.Y >= m_OrgPointArr[i].Y) && (pnt.Y < m_OrgPointArr[j].Y)) || ((pnt.Y >= m_OrgPointArr[j].Y) && (pnt.Y < m_OrgPointArr[i].Y))) && (pnt.X < (m_OrgPointArr[j].X - m_OrgPointArr[i].X) * (pnt.Y - m_OrgPointArr[i].Y) / (m_OrgPointArr[j].Y - m_OrgPointArr[i].Y) + m_OrgPointArr[i].X)) cnt++;
                }
            }
            return (cnt % 2 > 0);
        }

上述代码在点在多边形的边上的判断有问题,因此笔者增加了点在边上的判断。函数代码如下:

      private bool PntOnPlgSeg(PointF pnt, TangramPolygon plg, out int outBoxIdx, bool bPositiveOrder)
        {
            bool bOnPlg = false;
            outBoxIdx = -1;

            int idx = 0;
            if (!bPositiveOrder)
            {
                idx = plg.Count() - 1;
            }

            for (int i = 0; i < plg.Count(); i++)
            {
                PointF pnt1, pnt2;
                pnt1 = plg.GetVertexPoint(idx);
                pnt2 = plg.GetNextVertexPoint(idx);
                if (!bPositiveOrder)
                {
                    pnt2 = plg.GetVertexPoint(idx);
                    pnt1 = plg.GetNextVertexPoint(idx);
                }
                if (PointOnSegment(pnt, pnt1, pnt2))
                {
                    bOnPlg = true;
                    outBoxIdx = idx;
                    break;
                }
                if (bPositiveOrder)
                {
                    idx = plg.GetVertex(idx).next_idx;
                }
                else
                {
                    idx = plg.GetVertex(idx).last_idx;
                }

            }
            return bOnPlg;
        }

说明:上述判断的原理应该是使用率线段相交判断的方法,即跨立实验法,本人并没有研究代码的原理和准确性。但是经过检验,大体是对的。
后面将陆续给出各个使用函数,待续。

maraSun 2022-04-20 BJFWDQ
关注上海,封何时止?

上一个今天做出的复原图,证明我确实是在写代码。
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值