AutoLISP入門教學.JPG (45140 bytes)


單元七:圖元資料的取得與活用技巧(二)

五、範例練習:

範例一:撰寫一個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         ( 輸入一半徑值)

lisp7-1.GIF (2232 bytes)

範例二: 請撰寫一個MCIR.LSP,當碰選畫面上的LINE,會在該線的中點(Midpoint)產生一個圓,此程式的執行過程要求如下:

  • 指令: MCIR
  • Select a LINE:碰選畫面上已有的線
  • Circle Radius:要求輸入一半徑值MR (可給整數、實數或拉一段距離)
  • 自動的在該線的中點畫出一個半徑值為MR的圓lisp7-2.GIF (2250 bytes)

該如何設計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 & px1py1 *********************

(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 & px2py2 ***********************

(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 & mympt

;******************** 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)

lisp7-3.GIF (2151 bytes)

注意:

  1. 變數值查詢:您若想進一步查詢執行後變數值,沒問題!!!請搭配à 驚嘆號『!+『變數名』輸入在『指令:』後如!en!en_data!pts!pt1!px1!py1!pte!pt2!px2!py2 !mx!my!mpt!mr
  2. 以上程式中所用到的變數,讀者皆可自行命名,以方便、好記、不會混淆為原則
  3. 若不加上最後兩行

    (prompt "*************** << C:MCIR >> *****************")

    (prin1)

    則程式在載入後,將只回應 c:mcir

  4. 建議讀者們養成加入最後兩行的習慣,以免未來程式越來越大,載入程式後,根本無從知道該如何執行此LISP程式,因為程式內可能有好幾個C:XX 的指令函數,也可能有很多副程式!!!

範例三:請撰寫一個 CPOLY5.LSP,碰選CIRCLE,自動產生一個圓內接正五邊形,此程式的執行過程要求如下:

  • 指令: cpoly5
  • Select CIRCLE:碰選畫面上已有的圓
  • 自動產生一個內接正五邊形,OK!

lisp7-4.GIF (2774 bytes)

該如何設計CPOLY5.LSP???

解題關鍵:

  • 先取得圓的圓心點座標cenpt & 半徑rr
  • 模擬polygon完成內接正五邊形的過程:

指令: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! 完成一個內接正五邊形

lisp7-4.GIF (2774 bytes)

 

範例四:請撰寫一個 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

lisp7-5.GIF (3751 bytes)

該如何設計CIRSCA.LSP???

解題關鍵:

  • entget函數取得圓的元體資料串列cir_data
  • assoc函數取得群碼40的半徑『子串列』rad_list,並以cdr取得半徑值old_r,再依此值作放大2倍或縮小一半新的半徑子串列可以用cons函數結合群碼40 & 新半徑值
  • subst函數將資料串列中的新、舊子串列替換
  • entmod 函數依更新的資料串列更新螢幕上圓

程式內容解答:

(defun c:cira()

(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)

)

(defun c:cirb()

(setvar "cmdecho" 0)

(setq cir (entsel "Select CIRCLE to <Scale 2>:"))

(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 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 倍的圓

lisp7-6.GIF (2195 bytes)

指令:cirb

Select CIRCLE to <Scale 2>:碰選畫面上已有的圓

OK! 完成一個放大為 2 倍的圓

lisp7-7.GIF (2258 bytes)

 

六、測驗練習&解答,舉一反三:

題目:

 

解答: 改寫範例二的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程式設計生命的重要關卡,無論如何,必須請您在最清楚的頭腦&最佳的體力狀態下闖關,才不會搞的頭昏腦脹,遍體麟傷!!!