马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
本帖最后由 newer 于 2018-7-19 13:12 编辑
参照这篇博客写的https://blog.csdn.net/keng_s/article/details/52231046 |
先给出结论
以点为端点,朝两侧发射射线(两根射线平行),如果任意一侧的交点个数为偶数个,那么这个点就不在几何体的内部,反之在几何体的内部。
以上图为例,红色的点为需要判断的点,射线组合p,n,q都是合法的检测线(图上的p,n,q代表的是同时两侧的射线,同时我们称图中字母所在的一侧为正,例:p正射线) 采用p,n,q甚至任意两根平行射线,这个条件都是满足的。(上图中p,n,q和边缘的交点个数都为1,所以在几何体内部)
还有几种特殊情况需要处理如下图
如上图,共有五种情况,五种情况的特点如下
1. 五种情况都有一个共同点,射线穿过了线段的端点。 2.与射线平行的线段不参与讨论。
3. (4)(5),可视为同一种情况,都处于射线的同一侧,同时经过一个平行于射线的线段。 4. (4)(5)忽略平行线,可视为与(2)一样的情况,有两根线段处于射线的同一侧。 5. 同上理,(3) 可视为(1)一样的情况,有两根线段,且两根线段分别处理射线的一侧。
结论: (1)如果射线穿过了端点,则寻找这个端点的上下各一根,且不与射线平行的线段。 (2)如果这两根线段的同时处于射线一端,那么数量+2,反之两根线段分别处于线段的一侧,那么数量+1。(如何判断一个线段在另外一个线段的那一侧)
注意事项: (1)选用的射线,最好使用Y轴或者X轴方向的射线,原因在于选用这根射线的时候,计算量非常少,假设线段由A,B点构成,测试点P,选用Y轴方向的射线判断,判断相交只需要判断P.x在没在A.x和B.x之间。如果在之间一定相交,然后利用P.x在A.x,B.x之间的百分比,可以求出交点的y值,最后,如果交点的y值大于P.y 则在一侧,小于P.y在另外一侧。
PS:
在特殊情况中我们得到了,如果这两根线段的同时处于射线一端,那么数量+2,反之两根线段分别处于线段的一侧,那么数量+1。 那是因为如果在同一侧,代表路径前进的方向已经掉头了,所以我们穿过了两个路径,如果分别在一侧,代表路径的方向还是没有回头,所以我们只是穿越了一个路径。 - bool CGePointUtil::IsInside(const AcGePoint3d &pt, AcDbPolyline* pPoly)
- {
- bool isinside = false;
- CPolylineUtil::clearDbPts(pPoly); //去除相邻重复点
- AcGePoint3dArray points,inPts;
- AcGePoint3d pt3d;
- AcDbExtents ext;
- int num = pPoly->numVerts();
- for (int i = 0; i < num; i++)
- {
- pPoly->getPointAt(i, pt3d);
- points.append(pt3d);
- }
- ErrorStatus es= pPoly->getGeomExtents(ext);
- double xDis = ext.maxPoint().x - ext.minPoint().x;
- AcGeVector3d vec(xDis, 0, 0);
- AcDbLine* pLine = new AcDbLine(pt, pt + vec);
- if (pLine->intersectWith(pPoly,AcDb::kExtendArg,AcGePlane::kXYPlane,inPts)==Acad ::eOk)
- {
- int len = inPts.length();
- if (len==0)
- {
- pLine->close();
- return isinside;
- }
- AcGePoint3d ptFront, ptBack;
- for (int j=0;j<inPts.length();j++)
- {
- pt3d = inPts.at(j);
- if (points.contains(pt3d))
- {
- int index = points.find(pt3d);
- ptFront = points.at(index - 1);
- ptBack = points.at(index + 1);
- AcGeVector3d vecFront(pt3d-ptFront);
- AcGeVector3d vecBack(ptBack-pt3d);
- while (vecFront.isParallelTo(vec))
- {
- AcGePoint3d ptTemp(ptFront);
- ptFront = points.at(points.find(ptTemp) - 1);
- vecFront=(AcGeVector3d(ptTemp - ptFront));
- }
- while (vecBack.isParallelTo(vec))
- {
- AcGePoint3d pttemp(ptBack);
- ptBack = points.at(points.find(pttemp) + 1);
- vecBack = (AcGeVector3d(ptBack - pttemp));
- }
- if (vec.crossProduct(vecFront).isCodirectionalTo(vec.crossProduct(vecBack)))
- {
- len += 2;
- }
- else
- {
- len += 1;
- }
- }
- }
- if (len%2!=0)
- {
- isinside = true;
- }
- }
- pLine->close();
- return isinside;
- }
|