注:此时我已经完成了一个演示版本,但是为了文章的渐进性,我将把开发过程一步步的写出来,用来记录。
本实验代码用到的图形学关系和算法列举如下:
基本计算机图形学关系和算法
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
关注上海,封何时止?
上一个今天做出的复原图,证明我确实是在写代码。