五、範例練習:單元七:圖元資料的取得與活用技巧(二)
範例一:請撰寫一個CHGRAD.LSP,用來修改圓半徑,此程式的執行過程要求如下:
指令: CHGRAD
選取已知圓:碰選畫面上已存在的圓 自動顯示該舊圓半徑值於指令區 新半徑:要求輸入一半徑值 new_rr程式內容解答: (defun c:chgrad()
(setvar "cmdecho" 0 ;指令執行過程不回應
;;;;以下為 INPUT 圖元選取
(setq en (entsel "選取已知圓:")) ;要求碰選一個圓
;;;;以下為圖元資料&半徑資料取得
(setq en_data (entget (car en))) ;取得元體資料串列
(setq old_rad_list (assoc 40 en_data));取得半徑子串列
(setq old_rr (cdr rad_list)) ;取得舊有半徑
(princ “\n舊半徑=”)(princ old_rr) ;顯示該舊圓半徑值於指令區
;;;;以下為新半徑輸入&圖元資料新舊半徑更替
(setq cenpt (cdr (assoc 10 en_data))) ;一口氣取得圓之圓心
(setq new_rr (getdist cenpt "New Radius:"))
;要求輸入一半徑值 (setq new_rad_list (cons 40 new_rr)) ;產生新半徑子串列 (setq en_data (subst new_rad_list old_rad_list en_data)) ;新舊交替 (entmod en_data) ;依新圖元資料自動更新圓半徑(prin1)
)(prompt "*************** << C:CHGRAD >> *****************")
(prin1)
程式執行:(請先在畫面上任意的畫一些圓) 指令: (load"chgrad")
回應: *************** << C:CHGRAD >> *****************
指令: CHGRAD
選取已知圓: (碰選畫面上已有的圓)
新半徑:20 ( 輸入一半徑值)
範例二:
請撰寫一個MCIR.LSP,當碰選畫面上的LINE時,會在該線的中點(Midpoint)產生一個圓,此程式的執行過程要求如下:
- 指令: MCIR
- Select a LINE:碰選畫面上已有的線
- Circle Radius:要求輸入一半徑值MR (可給整數、實數或拉一段距離)
- 自動的在該線的中點畫出一個半徑值為MR的圓
該如何設計MCIR.LSP呢???解題關鍵:先取得線的二端點座標pt1(px1 py1) & pt2(px2 py2),那二點的中點座標 mpt(mx my)就用數學幾何公式求得mx = (px1 + px2)/2
my = (py1 + py2)/2
程式內容解答: (defun c:mcir()(setvar "cmdecho" 0) ;指令執行過程不回應 (setq en (entsel "Select a LINE:")) ;要求碰選一條線 (setq en_data (entget (car en))) ;取得元體資料串列 ;******************** 求得 pt1 & px1、py1 *********************(setq pts (assoc 10 en_data)) ;取得群碼10的子串列
(setq pt1 (cdr pts)) ;取得起點pt1座標
(setq px1 (car pt1)) ;取得pt1座標的x值(setq py1 (cadr pt1)) ;取得pt1座標的y值
;******************** 求得 pt2 & px2、py2 ***********************
(setq pte (assoc 11 en_data)) ;取得群碼11的子串列
(setq pt2 (cdr pte)) ;取得終點pt2座標
(setq px2 (car pt2)) ;取得pt2座標的x值
(setq py2 (cadr pt2)) ;取得pt2座標的y值
;***************** 求得 mx & my 並結合成 mpt ****************(setq mx (/ (+ px1 px2) 2)) ;求得mx值
(setq my (/ (+ py1 py2) 2)) ;求得my值
(setq mpt (list mx my)) ;結合mx & my成mpt點
;******************** Input <mr> & Finish ************************
(setq mr (getdist mpt "Circle Radius:"));要求輸入半徑值
(command "circle" mpt mr) ;完成中點畫圓
(prin1)
)
(prompt "*************** << C:MCIR >> *****************")
(prin1)
程式執行:(請先在畫面上任意的畫一些線)
指令: (load"mcir")
回應: *************** << C:MCIR >> *****************
指令: MCIR
Select a LINE: (碰選畫面上已有的線)
Circle Radius:20 (輸入半徑20)
注意:
(prin1)
則程式在載入後,將只回應 c:mcir 建議讀者們養成加入最後兩行的習慣,以免未來程式越來越大,載入程式後,根本無從知道該如何執行此LISP程式,因為程式內可能有好幾個C:XX 的指令函數,也可能有很多副程式!!! 範例三:請撰寫一個 CPOLY5.LSP,碰選CIRCLE後,自動產生一個圓內接正五邊形,此程式的執行過程要求如下:
- 指令: cpoly5
- Select CIRCLE:碰選畫面上已有的圓
- 自動產生一個內接正五邊形,OK!
該如何設計CPOLY5.LSP呢??? 解題關鍵:
指令:POLYGON
邊數 <4>: 5
邊緣(E)/<多邊形的中心點>: (選一點為正多邊形中心)
內接或外切於圓 (內接(I)/外切(C)) <I>:I
圓的半徑: (給一個半徑值)
程式內容解答:(defun c:cpoly5()
(setvar "cmdecho" 0) ;指令執行過程不回應
(setq en (entsel "Select CIRCLE:")) ;要求碰選一個圓
(setq en_data (entget (car en))) ;取得元體資料串列
(setq cenpt (cdr (assoc 10 en_data))) ;求得圓心 cenpt
(setq rr (cdr (assoc 40 en_data))) ;求得半徑 rr
(command "polygon" 5 cenpt "i" rr) ;完成圓內接正五邊形
(prin1)
)
(prompt "*************** << C:CPOLY5 >> *****************")
(prin1)
程式執行:(請先在畫面上任意的畫一些圓) 指令:(load"cpoly5")回應 *************** << C:CPOLY5 >> *****************
指令: CPOLY5
Select CIRCLE: (碰選畫面上已有的圓)
OK! 完成一個內接正五邊形範例四:請撰寫一個 CIRSCA.LSP,其內有二個可執行函數:
此程式的執行過程要求如下:
- CIRA碰選CIRCLE後,原CIRCLE大小自動縮為原來的1/2
- CIRB碰選CIRCLE後,原CIRCLE大小自動放大為原來的2倍
指令:cira
Select CIRCLE to <Scale 0.5>: (碰選畫面上已有的圓)
自動產生CIRCLE 大小自動縮為原來的1/2
指令:cirb
Select CIRCLE to <Scale 2>: (碰選畫面上已有的圓)
自動產生CIRCLE 大小自動放大為原來的2倍
該如何設計CIRSCA.LSP呢???
解題關鍵:
(defun c:cira()
) (defun c:cirb()(setvar "cmdecho" 0)
(setq cir (entsel "Select CIRCLE to <Scale 0.5>:"))
(setq cir_data (entget (car cir))) ;取得元體資料串列
(setq old_rad_list (assoc 40 cir_data)) ;取得原半徑子串列
(setq old_r r(cdr rad_list)) ;求得半徑old_r
(setq new_rr (* old_rr 0.5)) ;求得新半徑new_r
(setq new_rad_list (cons 40 new_rr)) ;產生新半徑子串列
(setq cir_data (subst new_rad_list old_rad_list cir_data))
(entmod cir_data)
(prin1)
(setvar "cmdecho" 0)
(setq cir_data (entget (car cir))) ;取得元體資料串列 (setq old_rad_list (assoc 40 cir_data)) ;取得原半徑子串列(setq cir (entsel "Select CIRCLE to <Scale 2>:"))
(setq old_r r(cdr rad_list)) ;求得半徑old_r
(setq new_rr (* old_rr 2)) ;求得新半徑new_r
(setq new_rad_list (cons 40 new_r)) ;產生新半徑子串列
(setq cir_data (subst new_rad_list old_rad_list cir_data))
(entmod cir_data) ;畫面上元體更新
(prin1)
)
(prompt "*****<< C:CIRA >> ***** << C:CIRB >>********")
(prin1)
程式執行:(請先在畫面上任意的畫一些圓) 指令:(load"cirsca")回應 *****<< C:CIRA >> ***** << C:CIRB >>********
指令: cira
Select CIRCLE to <Scale 0.5>: (碰選畫面上已有的圓)
OK! 完成一個縮小為 1/2 倍的圓
指令
:cirbSelect CIRCLE to <Scale 2>:
碰選畫面上已有的圓OK!
完成一個放大為 2 倍的圓六、測驗練習&解答,舉一反三:
題目:
- 改寫範例二的MCIR.LSP,讓程式更精簡有力??? (原程式有21行)
- 特殊解法(配合函數 OSNAP & MID 物件鎖點功能)
- 而且希望問半徑時,能以類似標準circle指令的半徑拖動模式出現?
解答: 改寫範例二的MCIR.LSP,讓程式更精簡有力???新程式剩下 15 行,省了 6 行
(defun c:mcir1()(setvar "cmdecho" 0)
(setq en (entsel "Select a LINE:"))
(setq en_data (entget (car en)))
(setq pt1 (cdr (assoc 10 en_data))) ;直接取得第一點
(setq pt2 (cdr (assoc 11 en_data))) ;直接取得第二點
(setq mx (/ (+ (car pt1) (car pt2)) 2)) ;求得中點X座標
(setq my (/ (+ (cadr pt1) (cadr pt2)) 2));求得中點Y座標
(setq mpt (list mx my))
(setq mr (getdist mpt "Circle Radius:"));要求輸入半徑值
(command "circle" mpt mr) ;完成中點畫圓
(prin1)
)
(prompt "*************** << C:MCIR1 >> *****************")
(prin1)
- 特殊解法(配合函數 OSNAP & MID 物件鎖點功能)新程式剩下 11 行,省了 10 行
(defun c:mcir2()(setvar "cmdecho" 0)(setq en (entsel "Select a LINE:"))
(setq pts(cadr en)) ;選取時點選座標(setq mpt (osnap pts “mid”))
;直接取得中點(setq mr (getdist mpt "Circle Radius:"))
;要求輸入半徑值(command "circle" mpt mr)
;完成中點畫圓(prin1)
)
(prompt "*************** << C:MCIR2 >> *****************")(prin1)
(defun c:mcir3()
(setvar "cmdecho" 0)
(setq en (entsel "Select a LINE:"))
(setq pts (cadr en))
(setq mpt (osnap pts "mid"))
(command "circle" mpt pause) ;<<== 注意 pause 的用法
(prin1)
)
(prompt "*************** << C:MCIR3 >> *****************")(prin1)
七、本章結語:圖元資料的取得&修改更新是AutoLISP程式設計師必備的能力,不管是新手或熟手,而熟手甚至於要具備將【常用群碼對應】記在腦海本事,如此一來,才能讓您的AutoLISP程式設計速度再往前推進,除了【附錄C】可隨時翻查外,萬一沒帶書在身邊,也千萬別束手無策,別忘了在指令區常常輸入以下表示式:(entget (car (entsel)))休息一下,明天再來征服下一章吧!!! 以取得圖元聯合資料串列,來幫您快速的對照記憶各個圖元相關群碼,因為下一章的【判斷式&迴圈】是無數AutoLISP新手想不碰,又不能不碰,聞之喪膽,甚至終結新手AutoLISP程式設計生命的重要關卡,無論如何,必須請您在最清楚的頭腦&最佳的體力狀態下闖關,才不會搞的頭昏腦脹,遍體麟傷!!!