明经CAD社区

 找回密码
 注册

QQ登录

只需一步,快速开始

搜索
查看: 2949|回复: 6

[函数] 求大神指导,二维坐标排序问题

[复制链接]
发表于 2013-4-21 22:42:42 | 显示全部楼层 |阅读模式
本帖最后由 张和平 于 2013-4-21 23:00 编辑

我现在根据【自贡黄明儒】的函数自己稍作改编了一下,得到如下函数中二维坐标排序函数。现在问题来了,我用这个函数获得如下图形中指定点(A,B,C,D,E,F,G,H)的坐标,比如A点可以先获得这个多边形边界的各端点坐标表,然后先按Y从小到大排序后按X从小到大排序获得新点表,读取这个新点表的第一个元素便是A点坐标。
现在分两种情况描述:
1、我手动输入A~H点坐标,形成一个点表(即test1),然后排序,按上述方法能够准确获得各点坐标;
2、我用boundary命令获得边界pline并获得这个pline的各端点坐标形成点表,然后按上述方法,获得的有些点的坐标就不能正确获得了。
不知其中的原因为何。。。请大神们出手帮忙看看,,,

  1. (defun c:test1()
  2.   (vl-load-com)
  3.   (defun *error* (msg)
  4.     (princ "\n**error: ")
  5.     (princ msg)      ;_ 打印错误信息
  6.     (princ)         
  7.   )
  8.   (setq plist '((4 3)(0 3)(1 4)(3 4)(0 1)(4 1)(3 0)(1 0)))
  9.   (setq p1 (car (test:Sort_pList plist "D->U" "L->R")))
  10.   (setq p2 (car (test:Sort_pList plist "L->R" "D->U")))
  11.   (setq p3 (car (test:Sort_pList plist "L->R" "U->D")))
  12.   (setq p4 (car (test:Sort_pList plist "U->D" "L->R")))
  13.   (setq p5 (car (test:Sort_pList plist "U->D" "R->L")))
  14.   (setq p6 (car (test:Sort_pList plist "R->L" "U->D")))
  15.   (setq p7 (car (test:Sort_pList plist "R->L" "D->U")))
  16.   (setq p8 (car (test:Sort_pList plist "D->U" "R->L")))
  17.   (PRINC P1)
  18.   (PRINC P2)
  19.   (PRINC P3)
  20.   (PRINC P4)
  21.   (PRINC P5)
  22.   (PRINC P6)
  23.   (PRINC P7)
  24.   (PRINC P8)
  25.   (PRINC)
  26. )
  27. (defun c:test2()
  28.   (setq P1 (getpoint "\n指定区域内部任意一点:"))
  29.   (command ".Boundary" p1 "")
  30.   (setq holeboundary (entlast))
  31.   (setq holepointslst (Assoc_ItemList 10 (entget holeboundary '("*")))) ;获取边界PLINE的端点列表
  32.   (setq holepointnum (length holepointslst))
  33.   (PRINC holepointslst)
  34.   (setq P1 (car (test:Sort_pList holepointslst "D->U" "L->R"))) ;左下角点1
  35.   (setq P2 (car (test:Sort_pList holepointslst "L->R" "D->U"))) ;左下角点2
  36.   (setq P3 (car (test:Sort_pList holepointslst "L->R" "U->D"))) ;左上角点1
  37.   (setq P4 (car (test:Sort_pList holepointslst "U->D" "L->R"))) ;左上角点2
  38.   (setq P5 (car (test:Sort_pList holepointslst "U->D" "R->L"))) ;右上角点1
  39.   (setq P6 (car (test:Sort_pList holepointslst "R->L" "U->D"))) ;右上角点2
  40.   (setq P7 (car (test:Sort_pList holepointslst "R->L" "D->U"))) ;右下角点1
  41.   (setq P8 (car (test:Sort_pList holepointslst "D->U" "R->L"))) ;右下角点2
  42.   (princ "\n")
  43.   (PRINC P1)  
  44.   (PRINC P2)
  45.   (princ "\n")
  46.   (PRINC P3)
  47.   (PRINC P4)
  48.   (princ "\n")
  49.   (PRINC P5)
  50.   (PRINC P6)
  51.   (princ "\n")
  52.   (PRINC P7)
  53.   (PRINC P8)
  54.   (princ)
  55. )

  56. ;;二维坐标排序
  57. ;;"D->U"从下到上;"U->D"从上到下;"L->R"从左到右;"R->L"从右到左
  58. ;;排序有先后,若调用如:(test:Sort_pList plist "D->U" "L->R"),
  59. ;;则整体按y从小到大排序,遇x值相同时,按x从小到大排序
  60. (defun test:Sort_pList (PLIST Sort1 Sort2 / Symbol1 Symbol2 plistout)
  61.   (vl-load-com)
  62.   (cond
  63.     ((member Sort1 (list "L->R" "R->L")) ;若sort1为"L->R"或"R->L",则先x向排序后y向排序,反之亦然
  64.       (cond ((= Sort1 "L->R") (setq Symbol1 '<)) ;若sort1="L->R",则(eval Symbol1)=>
  65.             (T (setq Symbol1 '>))                    ;否则Symbol1=<
  66.       )
  67.       (cond ((= Sort2 "D->U") (setq Symbol2 '<)) ;若sort2="D->U",则(eval Symbol2)=>
  68.             (T (setq Symbol2 '>))                    ;否则Symbol2=<
  69.       )
  70.       (setq plistout
  71.       (vl-sort
  72.         PLIST
  73.        '(lambda (p1 p2)
  74.           (cond (((eval Symbol1) (car p1) (car p2)) T)
  75.                 ((and (= (car p1) (car p2))
  76.                       ((eval Symbol2) (cadr p1) (cadr p2))
  77.                  )
  78.                  T
  79.                 )
  80.           )
  81.         )
  82.       )
  83.       )
  84.     )
  85.     (T
  86.       (cond ((= Sort1 "D->U") (setq Symbol1 '<))
  87.             (T (setq Symbol1 '>))
  88.       )
  89.       (cond ((= Sort2 "L->R") (setq Symbol2 '<))
  90.             (T (setq Symbol2 '>))
  91.       )
  92.       (setq plistout
  93.       (vl-sort
  94.         PLIST
  95.        '(lambda (p1 p2)
  96.           (cond (((eval Symbol1) (cadr p1) (cadr p2)) T)
  97.                 ((and (= (cadr p1) (cadr p2))
  98.                       ((eval Symbol2) (car p1) (car p2))
  99.                  )
  100.                  T
  101.                 )
  102.           )
  103.         )
  104.       )
  105.       )
  106.     )
  107.   )
  108.   plistout
  109. )
=====自己的分析

请看TEST1的计算结果
  1. 命令: TEST1
  2. (1 0)(0 1)(0 3)(1 4)(3 4)(4 3)(4 1)(3 0) ;依次为A\B\C\D\E\F\G\H
复制代码
请看TEST2的结果显示:
  1. 指定区域内部任意一点:((4.0 3.0) (3.0 3.0) (3.0 4.0) (1.0 4.0) (1.0 3.0) (0.0
  2. 3.0) (0.0 1.0) (1.0 1.0) (1.0 2.71837e-016) (3.0 1.49376e-016) (3.0 1.0) (4.0
  3. 1.0))
  4. (3.0 1.49376e-016)(0.0 1.0) ;应该为A\B
  5. (0.0 3.0)(1.0 4.0) ;应该为C\D
复制代码
自动获取的点坐标中,和test1的计算结果对比,发现获取的A点坐标是错误的。A\H点的坐标实际上应当为A=(1.0 2.71837e-016),H=(3.0 1.49376e-016),但是YA>YH,按照上述描述的获取A点坐标的方法(先按Y从小到大排序再按X从小到大排序),获取的A点坐标确实为(3.0 1.49376e-016),因此,出现本文问题的原因便是CAD在处理数据上的容差问题,原本YA=YH=0,但是CAD分别赋予了2.71837e-016和1.49376e-016。
那么,避免这样问题的方法是什么呢?能不能设置一个容差呢?两者差小于这个容差时,便认为两者相等。







本帖子中包含更多资源

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

x

点评

借穿它人裤子,不是长久计。  发表于 2013-4-22 20:45
"觉得好,就打赏"
还没有人打赏,支持一下
发表于 2013-4-22 20:43:58 | 显示全部楼层
本帖最后由 zml84 于 2013-4-22 20:44 编辑

1、补充个函数
  1. (defun Assoc_ItemList (int ent / tmp lst)
  2.   (foreach tmp ent
  3.     (if        (= (car tmp) int)
  4.       (setq lst (cons (cdr tmp) lst))
  5.     )
  6.   )
  7.   (reverse lst)
  8. )

2、看你的返回结果,貌似是数字小数位上,有问题,
建议test:Sort_pList在vl-sort比较过程中不要用= ,而用equal,并置入允许误差,即可。



回复 支持 1 反对 0

使用道具 举报

 楼主| 发表于 2013-4-22 13:41:25 | 显示全部楼层
自己顶一下,,
发表于 2013-4-22 20:02:55 | 显示全部楼层
我帮你一起顶!
 楼主| 发表于 2013-4-23 09:28:04 | 显示全部楼层
zml84 发表于 2013-4-22 20:43
1、补充个函数

2、看你的返回结果,貌似是数字小数位上,有问题,

你的方法很简洁,我等下试试看
以下是我自己的解决办法:
思路很简单,就是在坐标形成list时把坐标进行一下格式转换,,
  1. ;把坐标值转换成一定小数位数的坐标 by PEACE 2013/04/22
  2. (defun PEACE:DK_coordchange(point fractlen / x y)
  3.   (setq x (atof (rtos (car point) 2 fractlen)))
  4.   (setq y (atof (rtos (cadr point) 2 fractlen)))
  5.   (setq point (list x y))
  6.   point
  7. )
  8. ;;;获取表(Alist)中索引码(Item)相同的所有元素,并组成一个表(lst)返回
  9. (defun Assoc_ItemList (Item Alist / a lst point)
  10.   (while (setq a (assoc Item Alist))
  11.     (setq  Alist (cdr (member a Alist)) ;cdr返回list(member a Alist)中除了第一个以外的所有元素的表
  12.            point (PEACE:DK_coordchange (cdr a) 10)
  13.              lst (cons point lst)
  14.     )
  15.   )
  16.   (reverse lst) ;前面获得的坐标表是倒序的,现在再转换为正序
  17. )

点评

杀猪杀屁股,各有各的杀法。  发表于 2013-4-25 19:38
 楼主| 发表于 2013-4-25 14:53:55 | 显示全部楼层
后来想想,干脆把坐标值改成两位小数保留得了,附上转化成两位小数的函数:
  1. ;;;把坐标值转换成一定小数位数的坐标 by PEACE 2013/04/22
  2. ;;;POINT=需要转换的点,FRACTLEN=小数位数,若小于0则自动赋予0,若为正实数,则自动转换成正整数
  3. (defun PEACE:DK_coordchange(point fractlen / x y)
  4.   (if (< fractlen 0)
  5.     (setq fractlen 0)
  6.   )
  7.   (setq fractlen (fix fractlen))
  8.   (setq x (/ (fix (* (car point) (expt 10 fractlen))) (expt 10 fractlen)))
  9.   (setq y (/ (fix (* (cadr point) (expt 10 fractlen))) (expt 10 fractlen)))
  10.   ;(setq x (atof (rtos (car point) 2 fractlen)))
  11.   ;(setq y (atof (rtos (cadr point) 2 fractlen)))
  12.   (setq point (list x y))
  13.   point
  14. )
  15. ;;;获取表(Alist)中索引码(Item)相同的所有元素,并组成一个表(lst)返回
  16. (defun Assoc_ItemList (Item Alist / a lst point)
  17.   (while (setq a (assoc Item Alist))
  18.     (setq  Alist (cdr (member a Alist)) ;cdr返回list(member a Alist)中除了第一个以外的所有元素的表
  19.            point (PEACE:DK_coordchange (cdr a) 2)
  20.              lst (cons point lst)
  21.     )
  22.   )
  23.   (reverse lst) ;前面获得的坐标表是倒序的,现在再转换为正序
  24. )
发表于 2016-5-8 09:49:08 | 显示全部楼层
可以考虑使用环形排序的方法
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

GMT+8, 2024-12-23 13:04 , Processed in 0.200550 second(s), 37 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

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