明经CAD社区

 找回密码
 注册

QQ登录

只需一步,快速开始

搜索
查看: 5598|回复: 10

[【高飞鸟】] 【飞鸟集】区域查找及foreach的妙用

[复制链接]
发表于 2006-11-22 20:16 | 显示全部楼层 |阅读模式



首先从正交区域查找开始:
在很多情况下数据库的查询都可以转化为正交区域查找,在此先提供一个lisp程序,用来查找二维的点集落在某区域(a<=x<=b,c<=y<=d)的点集。
加载程序运行te1 ,然后选择点集,指定要查找的区域,(左下角和右上角点),这样就可以看到有哪些点找到了。代码在附件上。为:serachrec.lsp
接着我编了另外一个程序,不仅满足正交区域查找,对于多边形区域同样有效。(多边形可以为直线段的,也可以自相交的,可以是样条曲线的,但不能包含圆弧段,否则不准确)
运行te2 ,然后选择多边形,即可找出在这个多边形内的点。

  1. ;;;*****************************************
  2. ;;;定义查找函数2,并获得每个点的坐标和原编号
  3. (defun search (ptlist pl / pp ex)
  4.   (setq pp nil)
  5.   (foreach n ptlist
  6.     (if (ptinpm n pl)
  7.       (setq pp (cons n pp))
  8.     )
  9.   )
  10.   pp
  11. )
  12. ;;;*****************************************
  13. (defun C:te2 (/ olderr en errmsg oldmode oce sl ss ss1 ename t0 ptlist pp)
  14.   ;;定义错误函数和预处理--------------------
  15.   (setvar "errno" 0)
  16.   (setq olderr *error*)
  17.   (defun *error* (msg)
  18.     (setq en (getvar "errno"))
  19.     (setq errmsg (strcat "errno=" (itoa en) "\nError:" msg))
  20.     (alert errmsg)
  21.     (setq *error* olderr)
  22.   )
  23.   (graphscr)
  24.   (setq oldmode (getvar "osmode"))
  25.   (setq oce (getvar "cmdecho"))
  26.   (setvar "cmdecho" 0)
  27.   (command ".ucs" "W")
  28.   ;;也可以用其他方式取得点集----------------
  29.   (setq sl '((0 . "POINT")))
  30.   (setq ss (ssget sl))
  31.   (setq t0 (getvar "TDUSRTIMER"))
  32.   (setq ptlist (getpt ss))
  33.   (princ "\n构造点集用时")
  34.   (princ (* (- (getvar "TDUSRTIMER") t0) 86400))
  35.   (princ "秒")
  36.   (command "_.change" ss "" "P" "C" "BYL" "")
  37.   (princ "\n请选择多边形:")
  38.   (setq ss1 (ssget ":S" '((-4 . "<OR")(0 . "POLYLINE")(0 . "LWPOLYLINE")(-4 . "OR>"))))
  39.   (setq ename (if (= ss1 nil) nil (ssname ss1 0)))
  40.   (if (= ename nil)
  41.     (progn
  42.       (alert "你没有选择多边形!")
  43.       (command ".ucs" "P")
  44.       (setvar "osmode" oldmode)
  45.       (setvar "cmdecho" oce)
  46.       (princ)
  47.     )
  48.     (progn
  49.       (setq pl (xdl-pl-vertexs ename))
  50.       ;;查找区域中的点并对用时进行估算------
  51.       (setq t0 (getvar "TDUSRTIMER"))
  52.       (setq pp (search ptlist pl))
  53.       (princ "\n查找点用时")
  54.       (princ (* (- (getvar "TDUSRTIMER") t0) 86400))
  55.       (princ "秒")
  56.       (if (= nil pp)
  57. (progn
  58.    (alert "在这个区域没有点集中的点!")
  59.    (command ".ucs" "p")
  60.    (setvar "osmode" oldmode)
  61.    (setvar "cmdecho" oce)
  62.    (princ)
  63. )
  64. (progn
  65.    ;;改变查找出来的点的颜色为红色----
  66.    (setvar "osmode" 0)
  67.    (setq t0 (getvar "TDUSRTIMER"))
  68.    (change-color ss pp 1)
  69.    (princ "\n点变色用时")
  70.    (princ (* (- (getvar "TDUSRTIMER") t0) 86400))
  71.    (princ "秒")
  72.    (command ".ucs" "P")
  73.    (setvar "osmode" oldmode)
  74.    (setvar "cmdecho" oce)
  75.    (princ)
  76. )
  77.       )
  78.     )
  79.   )
  80. )
  81. ;;依据晓东网站的代码改写而成的取点函数------
  82. (defun getpt (ss / i listpp a b c)
  83.   (setq i 0 listpp nil)
  84.   (if ss
  85.     (repeat (sslength ss)
  86.       (setq a (ssname ss i)
  87.      b (entget a)
  88.      c (cdr (assoc 10 b))
  89.      c (list (car c) (cadr c) i)
  90.       )
  91.       ;;i用来定义在选择集中的编号,不是Z坐标
  92.       (setq listpp (cons c listpp))
  93.       (setq i (1+ i))
  94.     )
  95.   )
  96.   (reverse listpp)
  97. )
  98. ;;定义改变查找到的点的颜色的函数------------
  99. (defun change-color (ss pp color / i)
  100.   (setq i 0)
  101.   (foreach n pp
  102.     (setq a (ssname ss (caddr n)))
  103.     (setq b (entget a))
  104.     (setq b (cons (cons 62 color) b))
  105.     (entmod b)
  106.   )
  107. )
  108. ;;取得多边形顶点------------------感谢eachy!
  109. (defun xdl-pl-vertexs (e / n lst)
  110.   (if (= e nil)
  111.     nil
  112.     (progn
  113.       (setq lst
  114. (repeat (setq n (fix (1+ (vlax-curve-getendparam e))))
  115.    (setq lst (cons (vlax-curve-getpointatparam e (setq n (1- n))) lst))
  116. )
  117.       )
  118.       (if (= 0 (cdr (assoc 70 (entget e))))
  119. lst
  120. (cdr lst)
  121.       )
  122.     )
  123.   )
  124. )
  125. ;;判断点是否在多边形内-------------感谢狂刀!
  126. (defun ptinpm (pt lst)
  127.   (equal
  128.     PI
  129.     (abs
  130.       (apply
  131. '+
  132. (mapcar '(lambda (x y) (rem (- (angle pt x) (angle pt y)) PI))
  133.   (cons (last lst) lst)
  134.   lst
  135. )
  136.       )
  137.     )
  138.     1e-6
  139.   )
  140. )
  141. (defun C:te1 (/ olderr en errmsg oldmode oce sl ss t0 ptlist pp corpt1 corpt2)
  142.   ;;定义错误函数和预处理--------------------
  143.   (setvar "errno" 0)
  144.   (setq olderr *error*)
  145.   (defun *error* (msg)
  146.     (setq en (getvar "errno"))
  147.     (setq errmsg (strcat "errno=" (itoa en) "\nError:" msg))
  148.     (alert errmsg)
  149.     (setq *error* olderr)
  150.   )
  151.   (graphscr)
  152.   (setq oldmode (getvar "osmode"))
  153.   (setq oce (getvar "cmdecho"))
  154.   (setvar "cmdecho" 0)
  155.   (command ".ucs" "W")
  156.   ;;也可以用其他方式取得点集----------------
  157.   (setq sl '((0 . "POINT")))
  158.   (setq ss (ssget sl))
  159.   (setq t0 (getvar "TDUSRTIMER"))
  160.   (setq ptlist (getpt1 ss))
  161.   (princ "\n用时")
  162.   (princ (* (- (getvar "TDUSRTIMER") t0) 86400))
  163.   (princ "秒")
  164.   (command "_.change" ss "" "P" "C" "BYL" "")
  165.   (setq corpt1 (getpoint "\n区域的左下角:"))
  166.   (setq corpt2 (getpoint "\n区域的右上角:"))
  167.   (setq a (car  corpt1) b (car  corpt2) c (cadr corpt1) d (cadr corpt2))
  168.   ;;查找区域中的点并对用时进行估算----------
  169.   (setq t0 (getvar "TDUSRTIMER"))
  170.   (setq pp (search1 ptlist a b c d))
  171.   (princ "\n查找点用时")
  172.   (princ (* (- (getvar "TDUSRTIMER") t0) 86400))
  173.   (princ "秒")
  174.   (if (= nil pp)
  175.     (progn
  176.       (alert "在这个区域没有点集中的点!")
  177.       (command ".ucs" "p")
  178.       (setvar "osmode" oldmode)
  179.       (setvar "cmdecho" oce)
  180.       (princ)
  181.     )
  182.     (progn
  183.       ;;画凸包边界线------------------------
  184.       (setvar "osmode" 0)
  185.       (command ".rectang" corpt1 corpt2)
  186.       (setq t0 (getvar "TDUSRTIMER"))
  187.       (change1-color pp 1)
  188.       (princ "\n点变色用时")
  189.       (princ (* (- (getvar "TDUSRTIMER") t0) 86400))
  190.       (princ "秒")
  191.       (command ".ucs" "P")
  192.       (setvar "osmode" oldmode)
  193.       (setvar "cmdecho" oce)
  194.       (princ)
  195.     )
  196.   )
  197. )
  198. ;;;*****************************************
  199. ;;;定义查找函数1,并获得每个点的坐标和原编号
  200. (defun search1 (ptlist a b c d / pp ex)
  201.   (if (< b a) (setq ex b b a a ex))
  202.   (if (< d c) (setq ex d d c c ex))
  203.   (setq pp nil)
  204.   (foreach n ptlist
  205.     (if (and (>= (car  n) a)
  206.       (<= (car  n) b)
  207.       (>= (cadr n) c)
  208.       (<= (cadr n) d)
  209. )
  210.       (setq pp (cons n pp))
  211.     )
  212.   )
  213.   pp
  214. )
  215. ;;;*****************************************
  216. ;;依据晓东网站的代码改写而成的取点函数------
  217. (defun getpt1 (ss / i listpp a b c)
  218.   (setq i 0 listpp nil )
  219.   (if ss
  220.     (repeat (sslength ss)
  221.       (setq a (ssname ss i))
  222.       (setq b (entget a))
  223.       (setq c (cdr (assoc 10 b)))
  224.       (setq c (list (car c) (cadr c) a))
  225.       (setq listpp (cons c listpp))
  226.       (setq i (1+ i))  
  227.     )
  228.   )
  229.   (reverse listpp)
  230. )
  231. ;;定义改变颜色函数--------------------------
  232. (defun change1-color (pp color / a b)
  233.   (foreach n pp
  234.     (setq a (caddr n))
  235.     (setq b (entget a))
  236.     (setq b (cons (cons 62 color) b))
  237.     (entmod b)
  238.   )
  239. )
现在我要讨论的是:显然对于正交区域查找 ,用CAD的选择集方法亦可实现,但CAD选择集有BUG,注意看了,下面的图中,黄色的点是用查找函数找出来的点,而用选择集的点除了包含黄色的点外,还选择了查找区域外的点(红色的点),而且在选择的时候用'zoom等命令,很可能会出错,因而不精确,甚至是错误的(我已编写了这方面的程序验证了)。
另外用选择集的方法显然对于一些是样条曲线的多边形不能完成,而且,也不能适应自交叉的问题。
这个程序没有涉及到算法,但还是很快的。对于正交查找,100万个点3、4秒钟可完成,跟用选择集的时间相差无几。为什么这么快,归根于用了foreach函数,而不是用循环函数。
抛砖引玉,希望大家提提意见。

本帖子中包含更多资源

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

x
"觉得好,就打赏"
还没有人打赏,支持一下

本帖被以下淘专辑推荐:

发表于 2006-11-25 11:45 | 显示全部楼层

楼主 用什么方法可以来判断点在是否不规则多边形里面的(比如有弧的 样条曲线.....)

讨论一下

发表于 2006-11-25 13:50 | 显示全部楼层

将所有对像都近似的拟合成多边形就好了。我就是这么做的。效果非常好。比用CAD的特性计算快一些。

发表于 2006-11-25 23:19 | 显示全部楼层

楼主 你的程序对于带弧的多边形效果不好   你的程序里面好象没有拟合把??

还有1个问题

;;判断点是否在多边形内-------------感谢狂刀!
(defun ptinpm (pt lst)
  (equal
    PI
    (abs
      (apply
 '+
 (mapcar '(lambda (x y) (rem (- (angle pt x) (angle pt y)) PI))
  (cons (last lst) lst)
  lst
 )
      )
    )
    1e-6
  )
)

这段代码你能帮我解释一下吗?(我对这个算法没理解),我个人是用另外一种方法来求点是否在多边形内部.  没有这个方法代码简单

 楼主| 发表于 2006-11-26 14:16 | 显示全部楼层

的确如此,如果多边形有弧段的话,我还没有想出好的解决办法。正在解决中。

关于上段代码,参考了晓东网站狂刀的,请关注他的帖子。

发表于 2006-11-26 20:42 | 显示全部楼层
楼主帮我个忙 你把狂刀的帖子的链接给我一下 我在晓东望站里面找了好久没找到 不清楚是在哪个版块 相信你比较清楚 谢过了!!
 楼主| 发表于 2006-11-27 20:17 | 显示全部楼层

http://www.xdcad.net/forum/showthread.php?s=&postid=2499761#post2499761

Archive_view.asp?boardID=3&ID=49681

这里面已经解决了点在曲线内的大部分问题了,但还有一小点没有解决

我正在研究中 。

发表于 2015-8-24 19:16 | 显示全部楼层
本帖最后由 llsheng_73 于 2015-8-24 19:18 编辑
highflybir 发表于 2006-11-27 20:17
http://www.xdcad.net/forum/showt ... 2499761#post2499761
Archive_view.asp?boardID=3 ...


不是问题的问题:点与封闭曲线关系可简化至点与三角形关系?
http://bbs.mjtd.com/forum.php?mo ... &fromuid=202795
请大神看下这个判断点与非自交封闭曲线关系的办法,自己只测试过带弧线的多线段,圆,椭圆,对于样条曲线没进行测试
发表于 2018-8-18 16:52 | 显示全部楼层
看看效果怎么样
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

GMT+8, 2024-4-25 08:25 , Processed in 4.995367 second(s), 28 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

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