?? 步進法凸包.lsp
字號:
;;;************************************************************************
;;;一個求點集合的凸包的lisp程序--------------------------------------------
;;;------采用的算法為禮品包扎法--------------------------------------------
;;;方法為最右端的點開始處理,將該點作為凸包邊界的第一個點P1,從最初的垂直線
;;;方向繞P1順時針旋轉,直到碰到另一個P2這就是凸包邊界的第二個點P2,依此類推
;;;p2求得p3......直到又重新回到p1,已經考慮了各種退化情況和浮點運算,其算法
;;;時間不超過O(n.h),其中h是凸包的復雜度,時間還是很快的。大家不妨驗證。
;;;參考文獻<<計算幾何-算法及其應用>>(第二版),以及參考了其他網站的一些源代碼
;;;------------------------------------------------------------------------
;;;其中程序主段是核心算法,其他的附加程序為取得點集,畫凸包邊界線,測試大量
;;;點集函數處理所花費的時間。----------------------------------------------
;;;用法: 加載lisp運行test選取點,直線段,或多義線(全是直線段組成)即可。----
;;;************************************************************************
(defun C:test (/ olderr en errmsg oldmode oce sl ss t0 ptlist pp)
;;定義錯誤函數和預處理--------------------
(setvar "errno" 0)
(setq olderr *error*)
(defun *error* (msg)
(setq en (getvar "errno"))
(setq errmsg (strcat "errno=" (itoa en) "\nError:" msg))
(alert errmsg)
(setq *error* olderr)
)
(graphscr)
(setq oldmode (getvar "osmode"))
(setq oce (getvar "cmdecho"))
(setvar "cmdecho" 0)
(command ".ucs" "W")
;;也可以用其他方式取得點集----------------
;;取點,畫線,并對函數用時計算------------
(setq sl '((-4 . "<OR")
(0 . "POINT")
(0 . "LINE")
(0 . "POLYLINE")
(0 . "LWPOLYLINE")
(-4 . "OR>")
)
)
(setq ss (ssget sl))
(setq ptlist (getpt ss))
(setq t0 (getvar "TDUSRTIMER"))
(setq pp (hull ptlist))
(princ "\n用時")
(princ (* (- (getvar "TDUSRTIMER") t0) 86400))
(princ "秒")
(if (= nil pp)
(progn
(alert "點的有效數目太小,請重新輸入!")
(command ".ucs" "p")
(setvar "osmode" oldmode)
(setvar "cmdecho" oce)
(princ)
)
(progn
;;畫凸包邊界線------------------------
(setvar "osmode" 0)
(entmake
(append
'((0 . "lwpolyline")
(100 . "AcDbEntity")
(100 . "AcDbPolyline")
)
(list (cons 90 (length pp)))
(mapcar '(lambda (x) (cons 10 (list (car x) (cadr x)))) pp)
(list (cons 70 1))
(list (cons 62 1))
)
)
(command ".ucs" "P")
(setvar "osmode" oldmode)
(setvar "cmdecho" oce)
(princ)
)
)
)
;;;*****************************************
;;;*****************************************
;;;程序主段,可以單獨成為函數---------------
(defun hull (ptlist / pfirst p0 p1 p2 pp)
(cond
( (= (length ptlist) 0)
nil
)
( (or nil (= (length ptlist) 1) (= (length ptlist) 2))
(progn
(alert "你輸入的點為兩點或一點!")
ptlist
)
)
( t
(progn
;;計算--------------------------------
(setq pfirst (maxium ptlist))
(setq p1 pfirst
p0 (list (car pfirst) (+ 1.0 (cadr pfirst)))
)
(setq p2 (angmax ptlist p0 p1))
(setq pp (cons p2 (list p1)))
(while (not (equal pfirst p2 1e-8))
(setq pp (cons p2 pp))
(setq p0 p1
p1 p2
p2 (angmax ptlist p0 p1)
)
)pp
)
)
)
)
;;;程序主段結束-----------------------------
;;;*****************************************
;;;*****************************************
;;依據曉東網站的代碼改寫而成的取點函數------
(defun getpt (ss / i listpp a b c d)
(setq i 0
listpp nil
)
(if ss
(repeat (sslength ss)
(setq a (ssname ss i))
(setq b (entget a))
(setq ename (cdr (assoc 0 b)))
(cond
((or nil (= ename "POLYLINE") (= ename "LWPOLYLINE"))
(progn
(setq c (xdl-pl-vertexs a))
(setq listpp (append c listpp))
)
)
((= ename "LINE")
(progn
(setq c (cdr (assoc 10 b)))
(setq d (cdr (assoc 11 b)))
(setq listpp (cons c listpp))
(setq listpp (cons d listpp))
)
)
((= ename "POINT")
(progn
(setq c (cdr (assoc 10 b)))
(setq listpp (cons c listpp))
)
)
)
(setq i (1+ i))
)
)
listpp
)
;;定義順時針方向的夾角為正值,反之為負
(defun ang (p1 p0 p2 / x)
(setq x (- (angle p1 p2) (angle p1 p0)))
(cond
((equal p1 p2 1e-8) 0)
((<= (abs (- x 1e-8)) Pi) x)
(t (- x (* (/ x (abs x)) 2 Pi)))
)
)
;;求點集中順時針方向的夾角的最大值的點
(defun angmax (ptlist p0 p1 / ppp)
(setq ppp (mapcar '(lambda (x) (ang p1 p0 x)) ptlist))
(nth (vl-position (apply 'max ppp) ppp) ptlist)
)
;;排序函數----------------------------
(defun maxium (ptlist)
(car
(vl-sort ptlist
'(lambda (e1 e2)
(if (equal (car e1) (car e2) 1e-8)
(> (cadr e1) (cadr e2))
(> (car e1) (car e2))
)
)
)
)
)
;;取得多邊形頂點------------------感謝eachy!
(defun xdl-pl-vertexs (e / n lst)
(if (= e nil)
nil
(progn
(setq lst
(repeat (setq n (fix (1+ (vlax-curve-getendparam e))))
(setq lst
(cons (vlax-curve-getpointatparam e (setq n (1- n))) lst)
)
)
)
(if (= 0 (cdr (assoc 70 (entget e))))
lst
(cdr lst)
)
)
)
)
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -