明经CAD社区

 找回密码
 注册

QQ登录

只需一步,快速开始

搜索
查看: 738|回复: 1

[源码] Autolisp凸包算法+最小外接矩形

[复制链接]
发表于 2023-5-17 22:56:46 | 显示全部楼层 |阅读模式
本帖最后由 danier 于 2023-5-21 21:35 编辑

最近研究了下凸包算法写了两个程序:

1、求点集的凸包(修复上版一个小bug);
2、求点集的最小外接矩形。
未经严格测试,供大家参考~
  1. ;;;点集凸包
  2. (defun c:tt1()
  3.   (L-entity-creatlwployline nil (l-point-convexpolygon (setq pt_lst (mapcar '(lambda(x)(cdr (assoc 10 (entget x)))) (L-sel->list (ssget '((0 . "POINT"))))))))
  4. )
  5. ;;;点集最小外接矩形
  6. (defun c:tt2()
  7.   (L-entity-creatlwployline nil (l-point-minrectangle (setq pt_lst (mapcar '(lambda(x)(cdr (assoc 10 (entget x)))) (L-sel->list (ssget '((0 . "POINT"))))))))
  8. )



  9. ;;;-----------------------------------------------------------;;
  10. ;;; 获取点集的凸包
  11. ;;;-----------------------------------------------------------;;
  12. ;;; L-point-convexpolygon
  13. ;;; 输入: pt_lst>>>点集
  14. ;;; 输出: 多边形点集
  15. ;;; 示例:
  16. ;;;-----------------------------------------------------------;;
  17. ;;;-----------------------------------------------------------;;
  18. (defun L-point-convexpolygon(pt_lst / pt0 i res)
  19.   (if (> (length pt_lst) 3)
  20.     (progn
  21.       (setq pt0 (car (setq pt_lst (vl-sort pt_lst '(lambda (p1 p2) (< (cadr p1) (cadr p2)) )))))
  22.       (setq pt_lst (vl-sort pt_lst '(lambda (p1 p2) (< (angle '(0 0 0) (L-point-subtract p1 pt0) ) (angle '(0 0 0) (L-point-subtract p2 pt0))))))
  23.       (setq i 0)
  24.       (setq res (append (list (cadr pt_lst)) (list (car pt_lst)) ))
  25.       (setq pt_lst (L-list-getnvalue pt_lst 2 (length pt_lst)))
  26.       (while (< i (length pt_lst))
  27.         (cond
  28.           ((> (L-point-positiononline (nth i pt_lst)  (nth 1 res) (nth 0 res)) 0)
  29.             (setq res (append (list (nth i pt_lst)) res))
  30.           )
  31.           ((< (L-point-positiononline (nth i pt_lst)  (nth 1 res) (nth 0 res)) 0)
  32.             (setq res (L-list-getnvalue res 1 (length pt_lst)))
  33.             (while  (and (< (L-point-positiononline (nth i pt_lst)  (nth 1 res) (nth 0 res)) 0) (> (length res) 1))
  34.                     (setq res (L-list-getnvalue res 1 (length pt_lst)))
  35.             )
  36.             (setq res (append (list (nth i pt_lst)) res))
  37.           )
  38.           ((= (L-point-positiononline (nth i pt_lst)  (nth 1 res) (nth 0 res)) 0)
  39.             (setq res (L-list-getnvalue res 1 (length pt_lst)))
  40.             (setq res (append (list (nth i pt_lst)) res))
  41.           )
  42.         )
  43.         (setq i (1+ i))
  44.       )
  45.       (reverse res)
  46.       ;;(setq res (append (list (nth (- (length pt_lst) 1) pt_lst)) res))
  47.     )
  48.     (setq res pt_lst)
  49.   )
  50. )

  51. ;;;-----------------------------------------------------------;;
  52. ;;; 获取点集最小外接矩形
  53. ;;;-----------------------------------------------------------;;
  54. ;;; L-point-minrectangle
  55. ;;; 输入: pt_lst>>>点集
  56. ;;; 输出: 矩形点集
  57. ;;; 示例:(L-point-minrectangle(setq pt_lst (mapcar '(lambda(x)(cdr (assoc 10 (entget x)))) (L-sel->list (ssget)))))
  58. (defun L-point-minrectangle(pt_lst / i res line m m_rev pt_tmp pt x_max x_min y_max y_min rect rect_area)
  59.   ;; 获取凸包点集,并转换为相对坐标系
  60.   (setq pt_lst (mapcar '(lambda(x) (trans x 0 1)) (L-point-convexpolygon pt_lst)))
  61.   (setq pt_lst (append pt_lst (list (car pt_lst))))
  62.   (setq i 0)
  63.   (setq res nil)
  64.   ;; 遍历凸包中的所有直线
  65.   (while (< i (- (length pt_lst) 1))
  66.     (PRINC i)
  67.     ;; 获取直线
  68.     (setq line (list (nth i pt_lst) (nth (setq i (1+ i)) pt_lst)))
  69.     ;; 获取当前直线相对当前用户坐标系的变换矩阵和逆变换矩阵
  70.     (setq m     (L-mat-line     (car line) (cadr line) nil))
  71.     (setq m_rev (L-mat-revline  (car line) (cadr line) nil))
  72.     ;; 所有点变换为相对line的相对坐标
  73.     (setq pt_tmp (mapcar '(lambda(pt) (mapcar '+ (L-mat-mxv (car m_rev) pt) (cadr m_rev))) pt_lst))
  74.     ;; 获取最小、最大x
  75.     (setq pt_tmp (vl-sort pt_tmp '(lambda(pt1 pt2) (< (car pt1) (car pt2)))))
  76.     (setq x_min (car (nth 0                     pt_tmp)))
  77.     (setq x_max (car (nth (- (length pt_tmp) 1) pt_tmp)))
  78.     ;; 获取最小、最大y
  79.     (setq pt_tmp (vl-sort pt_tmp '(lambda(pt1 pt2) (< (cadr pt1) (cadr pt2)))))
  80.     (setq y_min (cadr (nth 0                     pt_tmp)))
  81.     (setq y_max (cadr (nth (- (length pt_tmp) 1) pt_tmp)))
  82.     (setq rect (list (list x_min y_min 0) (list x_max y_min 0) (list x_max y_max 0) (list x_min y_max 0)))
  83.     (setq rect_area (* (- x_max x_min) (- y_max y_min)))
  84.     ;; 矩形坐标转换为世界坐标系
  85.     (setq rect (mapcar '(lambda(pt) (trans (mapcar '+ (L-mat-mxv (car m) pt) (cadr m)) 1 0)) rect))
  86.     (setq res (append res (list (list rect_area rect))))
  87.   )
  88.   (setq res (vl-sort res '(lambda(x1 x2) (< (car x1) (car x2)))))
  89.   (cadr (car res))
  90. )


  91. ;;;-----------------------------------------------------------;;
  92. ;;; 判断点在直线左侧、右侧、直线上
  93. ;;;-----------------------------------------------------------;;
  94. ;;; L-point-positiononline
  95. ;;; 输入: pt>>>需要判断的点
  96. ;;;       pt1>>>直线起点
  97. ;;;       pt2>>>直线终点
  98. ;;; 输出:等于0>在直线上,小于0>在直线右侧,大于0>在直线左侧
  99. ;;; 示例:
  100. ;;;-----------------------------------------------------------;;
  101. ;;;-----------------------------------------------------------;;
  102. (defun L-point-positiononline(pt pt1 pt2)
  103.   (- (*(-(car pt1) (car pt))(- (cadr pt2) (cadr pt))) (*(-(car pt2) (car pt))(- (cadr pt1) (cadr pt))))
  104. )

  105. ;;;-----------------------------------------------------------;;
  106. ;;; 两点加法
  107. ;;;-----------------------------------------------------------;;
  108. ;;; L-Point-Add、L-Point-subtract
  109. ;;; 输入:
  110. ;;; 输出:
  111. ;;; 示例:
  112. ;;;-----------------------------------------------------------;;
  113. ;;;-----------------------------------------------------------;;
  114. (defun L-point-subtract(PT1 PT2)
  115.   (list (-(car pt1) (car pt2)) (-(cadr pt1) (cadr pt2)) (-(caddr pt1) (caddr pt2)))
  116. )

  117. ;;;-----------------------------------------------------------;;
  118. ;;; 获取列表指定区间的值
  119. ;;;-----------------------------------------------------------;;                                   
  120. ;;; L-list-getnvalue                                       
  121. ;;; 输入:m>>>起点位置 列表第一位为0
  122. ;;;       n>>>结束位置
  123. ;;; 输出:                                    
  124. ;;; 示例:
  125. ;;;-----------------------------------------------------------;;
  126. (defun L-list-getnvalue (lst m n / res i)
  127.   (setq res nil)
  128.   (if (and (= (type m) 'INT) (= (type n) 'INT))
  129.     (progn
  130.       (setq i m)
  131.       (while (and (setq l (nth i lst)) (< i (+ n m)))
  132.         (setq res (append res (list l)))
  133.         (setq i (1+ i))
  134.       )
  135.     )
  136.   )
  137.   res
  138. )

  139. ;;;-----------------------------------------------------------;;
  140. ;;; 创建多段线                                 
  141. ;;; L-entity-creatline                                       
  142. ;;; 输入:                                          
  143. ;;; 输出:
  144. ;;; 示例:
  145. ;;;-----------------------------------------------------------;;
  146. (defun L-entity-creatlwployline (lay l_lst / i res)
  147.   (setq i 0)
  148.   (setq res nil)
  149.   (if (null lay)
  150.     (entmakex ((lambda(x)  (setq res (list (cons 0 "LWPOLYLINE") (cons 100 "AcDbEntity")(cons 100 "AcDbPolyline")(cons 90 (length x))(cons 70 1)))        (foreach lst x (setq res (append res (list (cons 10 lst))))) )  l_lst))
  151.     (entmakex ((lambda(x)  (setq res (list (cons 0 "LWPOLYLINE") (cons 100 "AcDbEntity")(cons 100 "AcDbPolyline")(cons 90 (length x))(cons 70 1) (cons 8 lay))) (foreach lst x (setq res (append res (list (cons 10 lst))))) )  l_lst))
  152.   )
  153. )

  154. ;;;-----------------------------------------------------------;;
  155. ;;; 列表、选择集互转
  156. ;;;-----------------------------------------------------------;;
  157. ;;; L-sel->list  L-list->sel                             
  158. ;;; 输入:
  159. ;;; 输出:
  160. ;;; 示例:
  161. ;;;-----------------------------------------------------------;;
  162. (defun L-sel->list(sel / res i)
  163.   (setq res nil)
  164.   (setq i 0)
  165.   (if (/= sel nil)  
  166.     (repeat (sslength sel)
  167.       (setq res (append res (list (ssname sel i))))
  168.       (setq i (1+ i))
  169.     )
  170.   )
  171.   res
  172. )
  173. (defun L-list->sel (lst / res)
  174.   (setq res (ssadd))
  175.   (foreach l lst (setq res (ssadd l res)))
  176. )

  177. ;;;-----------------------------------------------------------;;
  178. ;;; 向量的矩阵变换(向量乘矩阵)                 
  179. ;;;-----------------------------------------------------------;;                  
  180. ;;; L-mat-mxv               
  181. ;;; 输入:            
  182. ;;; 输出:                     
  183. ;;;-----------------------------------------------------------;;
  184. (defun L-mat-mxv (m v)
  185.     (mapcar (function (lambda (r) (apply '+ (mapcar '* r v)))) m)
  186. )

  187. ;;;-----------------------------------------------------------;;
  188. ;;; 矩阵相乘                  
  189. ;;;-----------------------------------------------------------;;                  
  190. ;;; L-mat-mxm               
  191. ;;; 输入:            
  192. ;;; 输出:                     
  193. ;;;-----------------------------------------------------------;;
  194. (defun L-mat-mxm (m q)
  195.     (mapcar (function (lambda (r) (L-mat-mxv (L-mat-trp q) r))) m)
  196. )

  197. ;;;-----------------------------------------------------------;;
  198. ;;; 矩阵转置            
  199. ;;;-----------------------------------------------------------;;                  
  200. ;;; L-mat-trp              
  201. ;;; 输入:            
  202. ;;; 输出:                     
  203. ;;;-----------------------------------------------------------;;
  204. (defun L-mat-trp (m)
  205.     (apply 'mapcar (cons 'list m))
  206. )

  207. ;;;-----------------------------------------------------------;;
  208. ;;; 功能:直线的变换矩阵(平面变换)                          
  209. ;;;-----------------------------------------------------------;;                  
  210. ;;; L-mat-line                  
  211. ;;; 输入:pt1>>>直线起点
  212. ;;;       pt2>>>直线终点
  213. ;;;        sc>>>列表(x y z),直线x、y、z方向的缩放比例,为空时默认为1                  
  214. ;;; 输出:
  215. ;;; 示例:(setq m (L-mat-line (getpoint) (getpoint) nil))    (mapcar '+ (L-mat-mxv (car m) (getpoint)) (cadr m))                  
  216. ;;;-----------------------------------------------------------;;
  217. (defun L-mat-line (pt1 pt2 sc / elst ang norm mat)
  218.   ;;(setq pt1 (trans pt1 0 1))
  219.   ;;(setq pt2 (trans pt2 0 1))
  220.   ;; 直线与当前用户坐标系的夹角
  221.   (setq ang   (angle pt1 pt2))
  222.   (if (or (null sc) (/= (type sc) 'LIST) (/= (length sc) 3)) (setq sc '(1 1 1)))
  223.   (list
  224.     ;; 旋转、缩放变换矩阵
  225.     (setq mat
  226.            (L-mat-mxm
  227.              ;; 单位矩阵
  228.              (list '(1.0 0.0 0.0) '(0.0 1.0 0.0) '(0.0 0.0 1.0))
  229.              (L-mat-mxm
  230.                ;; 旋转矩形
  231.                (list (list (cos ang) (- (sin ang)) 0.0)
  232.                      (list (sin ang) (cos ang) 0.0)
  233.                      '(0.0 0.0 1.0)
  234.                )
  235.                ;; 缩放矩阵
  236.                (list (list (car sc) 0.0 0.0)
  237.                      (list 0.0 (cadr sc) 0.0)
  238.                      (list 0.0 0.0 (caddr sc))
  239.                )
  240.              )
  241.            )
  242.     )
  243.     ;; 位移矩阵
  244.     pt1
  245.   )
  246. )
  247. ;;;-----------------------------------------------------------;;
  248. ;;; 功能:直线变换逆矩阵(平面变换)                          
  249. ;;;-----------------------------------------------------------;;                  
  250. ;;; L-mat-line                  
  251. ;;; 输入:pt1>>>直线起点
  252. ;;;       pt2>>>直线终点
  253. ;;;        sc>>>列表(x y z),直线x、y、z方向的缩放比例,为空时默认为1                  
  254. ;;; 输出:
  255. ;;; 示例:                        
  256. ;;;-----------------------------------------------------------;;
  257. (defun L-mat-revline (pt1 pt2 sc / elst ang norm mat)
  258.   ;;(setq pt1 (trans pt1 0 1))
  259.   ;;(setq pt2 (trans pt2 0 1))
  260.   ;; 直线与当前用户坐标系的夹角
  261.   (setq ang   (- (angle pt1 pt2)))
  262.   (if (or (null sc) (/= (type sc) 'LIST) (/= (length sc) 3)) (setq sc '(1 1 1)))
  263.   (list
  264.     ;; 旋转、缩放变换矩阵
  265.     (setq mat
  266.            (L-mat-mxm
  267.              ;; 缩放矩阵
  268.              (list (list (/ 1 (car sc)) 0.0             0.0)
  269.                    (list 0.0            (/ 1 (cadr sc)) 0.0)
  270.                    (list 0.0            0.0             (/ 1 (caddr sc)))
  271.              )
  272.              (L-mat-mxm
  273.                ;; 旋转矩形
  274.                (list (list (cos ang) (- (sin ang)) 0.0)
  275.                      (list (sin ang) (cos ang)     0.0)
  276.                      '(0.0 0.0 1.0)
  277.                )
  278.                ;; 单位矩阵
  279.                (list '(1.0 0.0 0.0) '(0.0 1.0 0.0) '(0.0 0.0 1.0))
  280.              )
  281.            )
  282.     )
  283.     ;; 位移矩阵
  284.     (mapcar '- (L-mat-mxv mat pt1))
  285.   )
  286. )


  287. (princ)

本帖子中包含更多资源

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

x

评分

参与人数 1明经币 +1 收起 理由
USER2128 + 1 赞一个!

查看全部评分

发表于 2023-5-18 23:06:00 | 显示全部楼层
(defun c:tt ()
  "点集的最小外接矩形"
  (if (setq ss (ssget '((0 . "POINT"))))(xyp-Rectang (xyp-9pt ss 1) (xyp-9pt ss 9)))
  (princ)
)
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

GMT+8, 2024-11-16 19:07 , Processed in 0.170197 second(s), 27 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

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