明经CAD社区

 找回密码
 注册

QQ登录

只需一步,快速开始

搜索
查看: 4189|回复: 8

多段线自交判断

[复制链接]
发表于 2011-10-16 16:41:52 | 显示全部楼层 |阅读模式
本帖最后由 sen.sam 于 2011-10-16 16:47 编辑

在写一个小程序需要先判断多段线是否自交,找了一下论坛,很少相关的资料。按照某网友的提示凑了一个,但是只对闭合的完全自交的多段线(图1)有效,像图2有一个顶点落在边上的情况就不行了,另外对于虽然自交但不闭合(始点和终点重合),的情况也不支持。不知道各位有没更好的办法去判断这种情况?
  1. (defun c:test(/ ptlist1 ent1 ent2 ent0 ps entlist listlen1 listlen2)
  2. (setq ent1 (car (entsel "选择实体:")));
  3. (command "_.copy" ent1 "" '(0 0) "")
  4. (setq ent2 (entlast))
  5. (setq ps (obj_int ent1 ent2))
  6. (setq ent0  (entget ent1))
  7. (mapcar '(lambda(X)(if (= 10 (car x))(setq ptlist1 (cons (cdr x) ptlist1))))

  8. ent0)
  9. (setq entlist(reverse ptlist1))
  10. (setq listlen1 (length ptlist1))
  11. (setq listlen2 (length ps))
  12. (if (/= listlen2 listlen1 )
  13.        (alert "相交")
  14.       (alert "不相交")
  15.      )  
  16. (command "erase" ent2 "")
  17. (princ)
  18.   )


  19. ;功能:返回两个对象的所有交点
  20. ;参数: ent1、ent2 均为ename对象
  21. (defun obj_int (ent1 ent2 / ax_ent_1 ax_ent_2 intpoints points i)
  22.    (setq ax_ent_1 (vlax-ename->vla-object ent1)
  23.          ax_ent_2 (vlax-ename->vla-object ent2)
  24.    )
  25.    (setq intpoints (vla-intersectwith ax_ent_1 ax_ent_2 acextendnone))
  26.    (setq intpoints (vlax-variant-value intpoints))
  27.    (setq i 0)
  28.    (if (> (vlax-safearray-get-u-bound intpoints 1) 0)
  29.      (repeat (/ (+ 1
  30.                (- (vlax-safearray-get-u-bound intpoints 1)
  31.                   (vlax-safearray-get-l-bound intpoints 1)
  32.                )
  33.             )
  34.             3
  35.          )
  36.        (setq points (append points (list (list
  37.          (vlax-safearray-get-element intpoints i)
  38.          (vlax-safearray-get-element intpoints (+ i 1))
  39.          (vlax-safearray-get-element intpoints (+ i 2))
  40.        )))
  41.        )
  42.        (setq i (+ 3 i))
  43.      )
  44.    )
  45.    points
  46. )



本帖子中包含更多资源

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

x
发表于 2011-10-16 23:31:18 | 显示全部楼层
好难  先留个脚印 下次来看
发表于 2011-10-17 14:28:43 | 显示全部楼层
楼主的思路是比较(obj_int en en)得到的交点数目与en的顶点数目是否一致,但是由于en对应的多段线图元型式的不同,(obj_int en en)的结果并不稳定。
经测试:
1. 当en不闭合,(obj_int en en) 得到的结果不包含en的起终点,所以对于不闭合的多义线,只要自交点不是两个,都会判断为自交,自交点若是两个则反而判断不自交,有趣。
2. 当en闭合,不论是图面闭合(仅终点重合)还是标志闭合(图元闭合标志为1)或者二者兼而有之,(obj_int en en) 的结果都包含en的起终点。

因为求交点利用了vla-intersectwith(用(vla-invoke ... 'intersectwith ... ...)也一样),我想可能还是要研究一下函数返回值吧。

btw:
  1. (mapcar '(lambda(X)(if (= 10 (car x))(setq ptlist1 (cons (cdr x) ptlist1)))) ent0)
  2. (setq entlist(reverse ptlist1))
  3. (setq listlen1 (length ptlist1))
是不是太麻烦了?
  1. (setq listlen1 (cdr (assoc 90 ent0)))
不是更简洁一些么?

评分

参与人数 1明经币 +1 金钱 +10 收起 理由
sen.sam + 1 + 10 说得对!之前打算逐点比较的所以没改掉,谢.

查看全部评分

 楼主| 发表于 2011-10-17 22:27:13 | 显示全部楼层
有个想法,把多段线打散,逐条比较是否有交点。或者在多段线每两个顶点画一条直线,有凸度的地方计算出圆心半径画圆弧,再逐条判断每条线或者圆弧是否有交点。只是这样算起来太费劲了。不知道有没更好的方法?
 楼主| 发表于 2011-10-18 23:05:15 | 显示全部楼层
自己顶一下!
发表于 2011-10-19 01:41:49 | 显示全部楼层
多段线还是用几何方法计算比较稳妥,效率也最高
发表于 2011-10-23 13:22:49 | 显示全部楼层
无意中在Express Tools的extrim.lsp中发现带有函数能够判断多段线自交-- acet-geom-self-intersect 函数。
不过这个函数的源代码及参数含义没有找到。
发表于 2012-10-10 11:32:50 | 显示全部楼层
本帖最后由 miraclelll 于 2012-10-10 11:34 编辑

楼主, 我采用如下方法,可以解决这个问题, 且测试下来, 效率也是可以的~

解决方法:  对于多边形自交的定义是: 不相邻的线段有交点, 即为自交. 故此, 我采用对多边形的组成线段之间求交点的方式来判断.

编程思路:  
1 将多边形en 的节点组成一个表 ptlist, 首尾点重合(按先后顺序), 如: (pt1,pt2,pt3,...... ptn)
2 每两相邻点设定为 此多边形的 组成线段.
3 对ptlist中的点进行循环,从 第一个点pt1开始, 至pt(n-1) 为止
  取出其中的一点pt(i) 做为 线段L 的起点 pt1, pt(i+1)为终点pt2
   再取 pt(i+2) 为 对比判断线段M 的起点 pt3, pt(i+3) 为终点pt4
   然后 求L与M的交点, 如果有交点,则可判定 此多边形为自交
4 其中, 线段M 需要循环取, 但是注意不要和线段L 相邻

程序代码如下:
  1. (defun selfint (en /
  2.                        ptlist x n i j pt1 pt2 pt3 pt4 rtn pt_inter
  3.                        )
  4.   (setq rtn nil pt_inter nil)
  5.   ;;; 点坐标串ptlist;
  6.   (setq ptlist (mapcar 'cdr
  7.                        (vl-remove-if-not
  8.                          '(lambda (x) (= 10 (car x)))
  9.                          (entget en))
  10.                        )
  11.              )
  12.   ;;  首尾坐标不重合的,需要增加;;;
  13.   (if (not (equal
  14.         (nth 0 ptlist)
  15.         (nth (1- (length ptlist)) ptlist)
  16.         ))
  17.     (setq ptlist (append ptlist (list (nth 0 ptlist))))
  18.     )
  19.   (setq n (length ptlist))
  20.   (setq i 0
  21.         j (+ i 2)
  22.         )
  23.   ;;; 开始判断;
  24.   (while (and (<= i (- n 4)) (= rtn nil))
  25.     ;;; 线段L 的起始点;;
  26.     (setq pt1 (nth i ptlist)
  27.           pt2 (nth (1+ i) ptlist)
  28.           )
  29.     ;;; 下面是循环取 线段M的起始点;
  30.     (while (and (<= j (- n 2)) (= rtn nil))
  31.       (setq pt3 (nth j ptlist)
  32.             pt4 (nth (1+ j) ptlist)
  33.             )
  34.       (if (not (and (= i 0) (= j (- n 2)))) ;; 对于第一个线段L,与最后一个线段属于相邻,故需要排除;
  35.         (if (setq pt_inter (inters pt1 pt2 pt3 pt4));;; 判断L与M 是否相交;
  36.           (setq rtn T)
  37.           )
  38.         )
  39.       (setq j (1+ j))
  40.       )
  41.     (setq i (1+ i)
  42.           j (+ i 2)
  43.           )
  44.     )
  45.   (list rtn pt_inter)
  46.   )

点评

这个方法可能只能判断完全由直线段组成的多段线,对于有圆弧的多段线可能会出现错误的结果。  发表于 2012-11-30 14:54
发表于 2013-5-18 14:31:03 | 显示全部楼层
如果多线段的任一子线段与多线段的交点数大于2那么它一定是自相交

点评

这个思路不错,效率应该比上楼快!  发表于 2013-11-19 12:47
您需要登录后才可以回帖 登录 | 注册

本版积分规则

小黑屋|手机版|CAD论坛|CAD教程|CAD下载|联系我们|关于明经|明经通道 ( 粤ICP备05003914号 )  
©2000-2023 明经通道 版权所有 本站代码,在未取得本站及作者授权的情况下,不得用于商业用途

GMT+8, 2025-5-30 02:22 , Processed in 0.167434 second(s), 28 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

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