明经CAD社区

 找回密码
 注册

QQ登录

只需一步,快速开始

搜索
查看: 1512|回复: 7

[源码] 点集凸包的autolisp实现(几何方法)

[复制链接]
发表于 2022-10-30 16:45:35 | 显示全部楼层 |阅读模式
本帖最后由 freedom_ice 于 2022-10-30 17:22 编辑

问题:给定一系列二维点集,求包围所有点的最小凸多边形。

思路:1.将二维点集按X升序排列,当X值相等时,按Y值升序;
          2.沿着排序后的左下点P0(第一点)和右上点P1(最末点),作分界线line0,将点集分为上部和下部,上部的边界线为上包,下部的边界线为下包;
          3.递归方法求上包。上包的下边线line0,找到上包点集中距离line0最远的点Pmax,得到两条分界线,点P0和Pmax组成line1,点Pmax和P1组成line2,同样方法求line1的上包和line2的上包,两者合并即为line0的上包,递归出口为点集中只有两个点时,即为要求的点,输出即可。
          4.同样方法求下包,上包结果与下包合并即为所求凸包。
          5.输出结果为一段一段的线段,所以会有重复的点,未经去重处理;
          6.供探讨学习,未经完全验证,可能会有不可知的问题。比如对处于凸包边缘上的点未经特殊处理。

  1. ( defun c:tt()
  2.   ( setq pts '( ( 5 4 ) ( 0 0 ) ( 1 1 ) ( 2 2 ) ( 2 3 ) ( 3 1 ) ( 3 0 ) ( 5 1 )) )
  3.   ( setq pts '( ( 3 0 ) ( 4 1 ) ( 5 4 ) ( 2 2 ) ( 1 2 ) ( 3 4 ) ( 4 2 ) ( 3 2 ) ( 4 3 ) ) )
  4.   ;( setq pts '( ( 1 1 ) ( 2 1 ) ( 3 2 ) ( 4 4 ) ) )
  5.   ;( setq pts '( ( 5 4 ) ( 2 2 ) ) )
  6.   ;( setq pts '( ( 1 1 ) ( 2 4 ) ( 3 4 ) ( 3 5 ) ( 4 4 ) ( 4.5 4.5 ) ( 4 5 ) ( 5 4 ) ( 6 4 ) ( 7 7 ) ) )
  7.   ;( setq a ( IncreaseXY a ) )
  8.   ;( setq line '(  ( 2 2 ) ( 0 0 ) ) )
  9.   ;( setq pt '( 1.5 1 ) )
  10.   ;( princ ( IsPtOnLine pt line ) )
  11.   ;( UpBoundingPts pts )
  12.   ;( princ ( UpBoundingPts pts ) )
  13.   ;( princ "\n" )
  14.   ;( princ ( DownBoundingPts pts ) )
  15.   ( princ ( BoundingPts pts ) )
  16.   ( princ )
  17. )

  18. ;;;*****************************************************************************
  19. ;;;*****************************************************************************
  20. ;;;函数名  : BoundingPts ***************************************************
  21. ;;;功  能  : 获取点集的凸包 ****************************************************
  22. ;;;参  数  : pts - 要判断的点集 ************************************************
  23. ;;;返回值  : 凸包点集 **********************************************************
  24. ( defun BoundingPts ( pts / downpts j len linepts uppts )
  25.   ( setq pts ( IncreaseXY pts ) )
  26.   ( setq len ( length pts ) )
  27.   ( if ( < len 4 )
  28.        pts
  29.        ( progn
  30.             ( setq linepts ( list ( car pts ) ( last pts ) ) )
  31.             ( setq uppts linepts )
  32.             ( setq downpts linepts )
  33.              ( setq j 1 )
  34.             ( repeat ( - len 2 )
  35.                      ( if ( = ( IsPtOnLine ( nth j pts ) linepts ) 1 )
  36.                            ( setq uppts ( cons ( nth j pts ) uppts ) )
  37.                      )
  38.                      ( if ( = ( IsPtOnLine ( nth j pts ) linepts ) -1 )
  39.                            ( setq downpts ( cons ( nth j pts ) downpts ) )
  40.                      )               
  41.                      ( setq j ( 1+ j ) )
  42.             )
  43.             ( append ( UpBoundingPts uppts ) ( DownBoundingPts downpts ) )
  44.        )
  45.   )
  46. )
  47. ;;;*****************************************************************************
  48. ;;;*****************************************************************************
  49. ;;;*****************************************************************************



  50. ;;;*****************************************************************************
  51. ;;;*****************************************************************************
  52. ;;;函数名  : DownBoundingPts ***************************************************
  53. ;;;功  能  : 获取点集的下包 ****************************************************
  54. ;;;参  数  : pts - 要判断的点集 ************************************************
  55. ;;;返回值  : 下包点集 **********************************************************
  56. ( defun DownBoundingPts( pts / dis i j leftdownpts leftlinepts len linepts rightdownpts rightlinepts targetpt )
  57.   ( setq pts ( IncreaseXY pts ) )
  58.   ( setq len ( length pts ) )
  59.   ( cond ( ( = len 2 ) ( append pts ) )
  60.          ( ( > len 2 ) ( progn
  61.                                ( setq linepts ( list ( car pts ) ( last pts ) ) )
  62.                                ( setq leftdownpts nil )
  63.                                ( setq rightdownpts nil )
  64.                                ( setq dis 0 )
  65.                                ( setq i 1 )
  66.                                ( repeat ( - len 2 )
  67.                                        ( if ( and ( > ( PtDisToLine ( nth i pts ) linepts ) dis )
  68.                                                   ( = ( IsPtOnLine ( nth i pts ) linepts ) -1 )
  69.                                             )
  70.                                              ( setq dis      ( PtDisToLine ( nth i pts ) linepts )
  71.                                                    targetpt ( nth i pts )
  72.                                             )
  73.                                        )
  74.                                        ( setq i ( 1+ i ) )
  75.                               )
  76.                               ( if ( /= targetpt nil )
  77.                                    (  progn
  78.                                       ( setq leftlinepts ( list ( car pts ) targetpt ) )
  79.                                       ( setq rightlinepts ( list targetpt ( last pts ) ) )
  80.                                       ( setq leftdownpts leftlinepts )
  81.                                       ( setq rightdownpts rightlinepts )
  82.                                       ( setq j 1 )
  83.                                       ( repeat ( - len 2 )
  84.                                                ( if ( = ( IsPtOnLine ( nth j pts ) leftlinepts ) -1 )
  85.                                                      ( setq leftdownpts ( cons ( nth j pts ) leftdownpts ) )
  86.                                                )
  87.                                                ( if ( = ( IsPtOnLine ( nth j pts ) rightlinepts ) -1 )
  88.                                                      ( setq rightdownpts ( cons ( nth j pts ) rightdownpts ) )
  89.                                                )               
  90.                                                ( setq j ( 1+ j ) )
  91.                                       )
  92.                                       ( append ( DownBoundingPts leftdownpts )
  93.                                                 ( DownBoundingPts rightdownpts )            
  94.                                       )                    
  95.                                    )
  96.                                    ( append ( DownBoundingPts linepts ) )   
  97.                               )
  98.             )           
  99.          )
  100.   )  
  101. )
  102. ;;;*****************************************************************************
  103. ;;;*****************************************************************************
  104. ;;;*****************************************************************************



  105. ;;;*****************************************************************************
  106. ;;;*****************************************************************************
  107. ;;;函数名  : UpBoundingPts *****************************************************
  108. ;;;功  能  : 获取点集的上包 ****************************************************
  109. ;;;参  数  : pts - 要判断的点集 ************************************************
  110. ;;;参  数  : linepts - 直线上的两点 ********************************************
  111. ;;;返回值  : 上包点集 **********************************************************
  112. ( defun UpBoundingPts( pts / a b c dis i j leftlinepts leftuppts len linepts output rightlinepts rightuppts target targetpt )
  113.   ( setq pts ( IncreaseXY pts ) )
  114.   ( setq len ( length pts ) )
  115.   ( cond ( ( = len 2 ) ( append pts ) )
  116.          ( ( > len 2 ) ( progn
  117.                                ( setq linepts ( list ( car pts ) ( last pts ) ) )
  118.                                ( setq leftuppts nil )
  119.                                ( setq rightuppts nil )
  120.                                ( setq dis 0 )
  121.                                ( setq i 1 )
  122.                                ( repeat ( - len 2 )
  123.                                        ( if ( and ( > ( PtDisToLine ( nth i pts ) linepts ) dis )
  124.                                                   ( = ( IsPtOnLine ( nth i pts ) linepts ) 1 )
  125.                                             )
  126.                                              ( setq dis      ( PtDisToLine ( nth i pts ) linepts )
  127.                                                    targetpt ( nth i pts )
  128.                                             )
  129.                                        )
  130.                                        ( setq i ( 1+ i ) )
  131.                               )
  132.                               ( if ( /= targetpt nil )
  133.                                    ( progn
  134.                                           ( setq leftlinepts ( list ( car pts ) targetpt ) )
  135.                                            ( setq rightlinepts ( list targetpt ( last pts ) ) )
  136.                                            ( setq leftuppts leftlinepts )
  137.                                            ( setq rightuppts rightlinepts )
  138.                                            ( setq j 1 )
  139.                                            ( repeat ( - len 2 )
  140.                                                    ( if ( = ( IsPtOnLine ( nth j pts ) leftlinepts ) 1 )
  141.                                                          ( setq leftuppts ( cons ( nth j pts ) leftuppts ) )
  142.                                                    )
  143.                                                    ( if ( = ( IsPtOnLine ( nth j pts ) rightlinepts ) 1 )
  144.                                                          ( setq rightuppts ( cons ( nth j pts ) rightuppts ) )
  145.                                                    )               
  146.                                                    ( setq j ( 1+ j ) )
  147.                                           )
  148.                                          ( append ( UpBoundingPts leftuppts )
  149.                                                    ( UpBoundingPts rightuppts )            
  150.                                          )                                
  151.                                    )
  152.                                    ( append ( UpBoundingPts linepts ) )
  153.                               )                        
  154.                         )           
  155.          )
  156.   )  
  157. )
  158. ;;;*****************************************************************************
  159. ;;;*****************************************************************************
  160. ;;;*****************************************************************************



  161. ;;;*****************************************************************************
  162. ;;;*****************************************************************************
  163. ;;;函数名  : PtDisToLine *******************************************************
  164. ;;;功  能  : 判断点到直线的距离 ************************************************
  165. ;;;参  数  : pt - 要判断的点 ***************************************************
  166. ;;;参  数  : linepts - 直线上的两点 ********************************************
  167. ;;;返回值  : 返回距离值 ********************************************************
  168. ( defun PtDisToLine( pt linepts / a b c output target )
  169.   ;;linepts = ( ( x1 y1 ) ( x2 y2 ) )
  170.   ;;x1 = ( caar linepts )
  171.   ;;y1 = ( cadar linepts )
  172.   ;;x2 = ( caadr linepts )
  173.   ;;y2 = ( cadadr linepts )
  174.   ( setq A ( - ( cadar linepts ) ( cadadr linepts ) ) )
  175.   ( setq B ( - ( caadr linepts ) ( caar linepts ) ) )
  176.   ( setq C ( - ( * ( caar linepts )  ( cadadr linepts ) ) ( * ( caadr linepts ) ( cadar linepts ) ) ) )
  177.   ( setq target ( + ( * A ( car pt ) )
  178.                     ( * B ( cadr pt ) )
  179.                     C  ) )
  180.   ( setq target ( abs target ) )
  181.   ;;点到直线的距离
  182.   ( setq output ( / target ( expt ( + ( expt A 2 ) ( expt B 2 ) ) 0.5 ) ) )
  183. )

  184. ;;;*****************************************************************************
  185. ;;;*****************************************************************************
  186. ;;;*****************************************************************************



  187. ;;;*****************************************************************************
  188. ;;;*****************************************************************************
  189. ;;;函数名  : IsPtOnLine ********************************************************
  190. ;;;功  能  : 判断点是否在直线上 ************************************************
  191. ;;;参  数  : pt - 要判断的点 ***************************************************
  192. ;;;参  数  : linepts - 直线上的两点 ********************************************
  193. ;;;返回值  : 点在直线上方 返回1 ************************************************
  194. ;;;返回值  : 点在直线上 返回0 **************************************************
  195. ;;;返回值  : 点在直线下方 返回-1 ***********************************************
  196. ( defun IsPtOnLine( pt linepts / a b c target )
  197.   ;;linepts = ( ( x1 y1 ) ( x2 y2 ) )
  198.   ;;x1 = ( caar linepts )
  199.   ;;y1 = ( cadar linepts )
  200.   ;;x2 = ( caadr linepts )
  201.   ;;y2 = ( cadadr linepts )
  202.   ( setq A ( - ( cadar linepts ) ( cadadr linepts ) ) )
  203.   ( setq B ( - ( caadr linepts ) ( caar linepts ) ) )
  204.   ( setq C ( - ( * ( caar linepts )  ( cadadr linepts ) ) ( * ( caadr linepts ) ( cadar linepts ) ) ) )
  205.   ( setq target ( + ( * A ( car pt ) )
  206.                     ( * B ( cadr pt ) )
  207.                     C  ) )
  208.   ( if ( > target 0 )
  209.         1
  210.        ( if ( = target 0 )
  211.             0
  212.             -1
  213.        )
  214.   )
  215. )

  216. ;;;*****************************************************************************
  217. ;;;*****************************************************************************
  218. ;;;*****************************************************************************



  219. ;;;*****************************************************************************
  220. ;;;*****************************************************************************
  221. ;;;函数名  : IncreaseXY ********************************************************
  222. ;;;功  能  : 点表按X升序排列,若X相等,则按Y坐标升序排列************************
  223. ;;;参  数  : SourceList - 源数据表**********************************************
  224. ;;;返回值  : 排序后的数据表*****************************************************
  225. ( defun IncreaseXY( SourceList )
  226.   ( setq SourceList ( vl-sort SourceList
  227.                               ( function ( lambda ( e1 e2 )
  228.                                            ( if ( < ( car e1 ) ( car e2 ) )
  229.                                                 ( < ( car e1 ) ( car e2 ) )
  230.                                                  ( if ( = ( car e1 ) ( car e2 ) )
  231.                                                      ( <= ( cadr e1 ) ( cadr e2 ) )
  232.                                                 )
  233.                                            )
  234.                                          )
  235.                               )
  236.                     )
  237.   )
  238. )
  239. ;;;*****************************************************************************
  240. ;;;*****************************************************************************
  241. ;;;*****************************************************************************

  242. ( princ )
复制代码



本帖子中包含更多资源

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

x

评分

参与人数 4明经币 +4 金钱 +10 收起 理由
USER2128 + 1 赞一个!
guosheyang + 1 赞一个!
kucha007 + 1 赞一个!
tigcat + 1 + 10 很给力!

查看全部评分

发表于 2022-11-3 19:31:28 | 显示全部楼层
  1. (defun tb (ptn / mode p0 p1 p2 tmp rr)
  2.   "点集逆时针凸包点"
  3.   (setq        ptn  (vl-sort ptn '(lambda (x y) (< (cadr x) (cadr y))))
  4.         p0   (car ptn)
  5.         ptn  (vl-sort (cdr ptn)
  6.                       '(lambda (x y) (< (angle p0 x) (angle p0 y)))
  7.              )
  8.         rr   (angle p0 (car ptn))
  9.         tmp  (list p0)
  10.         p1   p0
  11.         mode t
  12.   )
  13.   (while mode
  14.     (setq ptn (vl-remove-if '(lambda (x) (< (angle p1 x) rr)) ptn)
  15.           ptn (vl-sort ptn '(lambda (x y) (< (angle p1 x) (angle p1 y))))
  16.           p2  (car ptn)
  17.           rr  (angle p1 p2)
  18.           ptn (vl-remove p2 ptn)
  19.           ptn (if (not (member p0 ptn))
  20.                 (cons p0 ptn)
  21.                 ptn
  22.               )
  23.     )
  24.     (if        (not (equal p2 p0 1e-3))
  25.       (setq tmp        (cons p2 tmp)
  26.             p1        p2
  27.       )
  28.       (setq mode nil)
  29.     )
  30.   )
  31.   (reverse tmp)
  32. )

评分

参与人数 2明经币 +2 金钱 +20 收起 理由
xj6019 + 1 很给力!
freedom_ice + 1 + 20 优秀!

查看全部评分

回复 支持 1 反对 0

使用道具 举报

发表于 2022-10-30 19:10:58 | 显示全部楼层







发表于 2022-11-1 13:32:36 | 显示全部楼层
算法有些复杂,简单一些,找到最下面的一个点,然后依次找到所有点中到上一个点角度最靠右的那个点,就可以找到凸包了。
找最靠右的向量以上上个点到上一个点的向量作为标准方向。
 楼主| 发表于 2022-11-1 15:25:14 | 显示全部楼层
ytianxia 发表于 2022-11-1 13:32
算法有些复杂,简单一些,找到最下面的一个点,然后依次找到所有点中到上一个点角度最靠右的那个点,就可以 ...

这就是凸包的向量算法吧,思路确实更清晰简单。下一步准备实现这个办法。感谢。
发表于 2022-11-4 08:05:36 | 显示全部楼层

牛!院长的代码好精炼!
发表于 2022-11-4 08:29:08 | 显示全部楼层

院长威武!!!!
发表于 2022-11-4 08:30:21 | 显示全部楼层
感谢楼主分享   楼主威武!!!!
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

GMT+8, 2024-11-16 00:26 , Processed in 0.182362 second(s), 27 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

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