找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

查看: 706|回复: 3

[每日一码] arx判断一点是否在多段线内

[复制链接]

已领礼包: 28个

财富等级: 恭喜发财

发表于 2018-7-19 11:08:56 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
本帖最后由 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。

那是因为如果在同一侧,代表路径前进的方向已经掉头了,所以我们穿过了两个路径,如果分别在一侧,代表路径的方向还是没有回头,所以我们只是穿越了一个路径。

  1. bool CGePointUtil::IsInside(const AcGePoint3d &pt, AcDbPolyline* pPoly)
  2. {
  3.         bool isinside = false;
  4.         CPolylineUtil::clearDbPts(pPoly);  //去除相邻重复点
  5.         AcGePoint3dArray points,inPts;
  6.         AcGePoint3d pt3d;
  7.         AcDbExtents ext;
  8.         int num = pPoly->numVerts();
  9.         for (int i = 0; i < num; i++)
  10.         {
  11.                 pPoly->getPointAt(i, pt3d);
  12.                 points.append(pt3d);
  13.         }
  14.         ErrorStatus es= pPoly->getGeomExtents(ext);
  15.         double xDis = ext.maxPoint().x - ext.minPoint().x;
  16.         AcGeVector3d vec(xDis, 0, 0);
  17.         AcDbLine* pLine = new AcDbLine(pt, pt + vec);
  18.         if (pLine->intersectWith(pPoly,AcDb::kExtendArg,AcGePlane::kXYPlane,inPts)==Acad ::eOk)
  19.         {
  20.                 int len = inPts.length();
  21.                 if (len==0)
  22.                 {
  23.                         pLine->close();
  24.                         return isinside;
  25.                 }
  26.                 AcGePoint3d ptFront, ptBack;
  27.                 for (int j=0;j<inPts.length();j++)
  28.                 {
  29.                         pt3d = inPts.at(j);
  30.                         if (points.contains(pt3d))
  31.                         {
  32.                                 int index = points.find(pt3d);
  33.                                 ptFront = points.at(index - 1);
  34.                                 ptBack = points.at(index + 1);
  35.                                 AcGeVector3d vecFront(pt3d-ptFront);
  36.                                 AcGeVector3d vecBack(ptBack-pt3d);
  37.                                 while (vecFront.isParallelTo(vec))
  38.                                 {
  39.                                         AcGePoint3d ptTemp(ptFront);
  40.                                         ptFront = points.at(points.find(ptTemp) - 1);
  41.                                         vecFront=(AcGeVector3d(ptTemp - ptFront));
  42.                                 }
  43.                                 while (vecBack.isParallelTo(vec))
  44.                                 {
  45.                                         AcGePoint3d pttemp(ptBack);
  46.                                         ptBack = points.at(points.find(pttemp) + 1);
  47.                                         vecBack = (AcGeVector3d(ptBack - pttemp));
  48.                                 }
  49.                                 if (vec.crossProduct(vecFront).isCodirectionalTo(vec.crossProduct(vecBack)))
  50.                                 {
  51.                                         len += 2;
  52.                                 }
  53.                                 else
  54.                                 {
  55.                                         len += 1;
  56.                                 }
  57.                         }
  58.                 }
  59.                 if (len%2!=0)
  60.                 {
  61.                         isinside = true;
  62.                 }
  63.         }
  64.         pLine->close();
  65.         return isinside;
  66. }

评分

参与人数 1D豆 +5 收起 理由
newer + 5 很给力!经验;技术要点;资料分享奖!

查看全部评分

论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!

已领礼包: 28个

财富等级: 恭喜发财

 楼主| 发表于 2018-7-27 12:17:35 来自手机 | 显示全部楼层
如果多段线是自相交且自相重复的,那么无效。
来自: 微社区

点评

算法当然有条件。 实际工作中,自交的多段线一般都要处理成非自交的。 如果非要求适合自交的,就去找合适的算法咯。  详情 回复 发表于 2018-7-27 13:55
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

已领礼包: 40个

财富等级: 招财进宝

发表于 2018-7-27 13:55:23 | 显示全部楼层
1121443108qaz 发表于 2018-7-27 12:17
如果多段线是自相交且自相重复的,那么无效。

算法当然有条件。
实际工作中,自交的多段线一般都要处理成非自交的。

如果非要求适合自交的,就去找合适的算法咯。
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

已领礼包: 28个

财富等级: 恭喜发财

 楼主| 发表于 2018-7-28 10:47:22 来自手机 | 显示全部楼层
newer 发表于 2018-7-27 13:55
算法当然有条件。
实际工作中,自交的多段线一般都要处理成非自交的。


是的,另外我写的这个对于有弧的来说也不对,应该用一阶导数求向量再比较。
来自: 微社区
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|申请友链|Archiver|手机版|小黑屋|辽公网安备|晓东CAD家园 ( 辽ICP备15016793号 )

GMT+8, 2024-11-14 22:06 , Processed in 0.418830 second(s), 38 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表