2014年6月16日 星期一

Visual Lisp 的點資料

   既然是 AutoCAD,必然牽涉到點的輸出入,程式或使用者給你一個點資料,如何取出點的 x, y , z 三軸座標數值;程式計算出的數值,如何交回給 CAD 讓它畫出來。
    先來看怎們取出點資料,如果你在命令列輸入 (getpoint),再螢幕上點選一點,這時程式會回應一個像下面的資料 (串列)

    (982.466 568.978 0.0)

    直覺的,它一定是 x, y , z 值,那怎麼拿出來,先得講 LISP 如何操作串列,基本上先認識 (car) (cadr) (caddr) 三個兄弟函數,老大 car 取出串列第一個內容,所以一個點 pt 的內容為 (1 2 3),那麼 (car pt) 便傳回 1,同理 (cadr pt) 傳回 2,同理 (caddr pt) 傳回 3,此時再設定變數,便可以得到 x, y ,z 參數

   (setq x (car pt)
       y (cadr pt)
       z (caddr pt)
   )

    便可對 x, y, z 三個變數進行運算,但要說明的是在 LISP 語言內不只以上三個函數,例如 (cdr pt) 傳回 (2 3),很明顯的是傳回第二個到最後一個串列內容;(nth 2 pt) 傳回 3(nth) 函數則依據 index 2 傳回內容 3,當然串列的第一個 index 0


    當有了新的 x y z 值,要將其組合成一個點資料傳給函數,一樣是 LISP 語言內串列的操作函數 (list),沒啥技巧

(list x y z)

   就可以了,如果在 2D 環境繪圖,那麼 z 可以省略,不需再設定。

   下面一個例子,程式要求使用者輸入一點,然後程式劃出由輸入點開始長度 10030 度角的直線

(defun c:aline( / pt x y _osmode)
    (setq _osmode (getvar "OSMODE"))
    (setvar "OSMODE" 0)
 
    // 取得起始點
    (setq pt (getpoint "輸入起始點\n")
          x (car pt)
          y (cadr pt)
    )
    // 計算終點
    (setq x (+ x (* 100 (cos (/ pi 6))))
        y (+ y (* 100 (sin (/ pi 6))))
    )
    // 繪出
    (command "LINE" pt (list x y) "")

    (setvar "OSMODE" _osmode) 
)

當然,實際程式設計時會使用 (polar) 函數
    (command  "LINE" pt (polar pt (/ pi 6) 100) "")

2014年6月13日 星期五

繪圖前的預備動作

     LISP 繪圖前要有還要有預備動作?? 當然不是作作熱身操上上廁所種,記得 Visual LISP 可以使用 (command) 指令嗎 ? 雖然很方便,只要會操作 AutoCAD 就會使用這個指令,但是,CAD 繪圖好像不止只有繪圖動作,還有環境設定的問題,例如圖層,鎖點,標註比例,文字尺寸等等等...,當你使用 command 指令時,你已經承認目前 AutoCAD 的環境設定就你()想要的,例如

    (command "LINE" pt1 pt2 "")

    如果 CAD 現在圖層是 "0",線形式 "Continues",那麼這條線的預設值便已訂好,如果你要別的圖層,那要先更改圖層,例如先執行

    (setvar "CLAYER" "LINE")

   把預設的圖層改為 "LINE",下一個物件若不是在 "LINE" 圖層上,那麼請再換一次,畢竟 CAD 不是你肚子裡的蛔蟲。

   還有什麼問題,鎖點,若在繪圖時鎖點模式打開,那麼鎖點會取代程式輸入值,明明畫的點應該形成四邊形,螢幕上卻跑出四不像,所以繪圖前先把鎖點關閉 (當然不是按 F9)

    (setvar "OSMODE" 0)

   那麼程式完成時呢?抱歉,鎖點就被關閉了,如果還想恢回覆繪圖前狀態,先把鎖點的參數記下來,最後在設定一次

    (setvar _osmode (getvar "OSMODE"))
    (setvar "OSMODE" 0)

    ..... (繪圖指令)....

    (setvar "OSMODE" _osmode)

    還有問題,是關於對話盒的問題,例如開啟舊檔對話盒,圖塊屬性對話盒,若在 LISP 執行過程跳出,則程式會中斷,等待使用者輸入並關閉對話盒後才會繼續執行,若不想被打斷,那麼 "FILEDIA" "ATTDIA" 也記得要關。

    若對指令欄中一連串輸出厭煩 (或是不想讓使用者知道執行過程),先設定

    (setvar "CMDECHO" 0)

   上面這些拉拉雜雜的問題都是跟 (command) 指令有關,所以 Visual LISP 內還有一個 (entmake) 指令,以設定群碼內容方式繪圖,就沒有上面的問題 (但是並如容易掌控)

    最後有一個動作也是值得設定的,就是 UNDO 指令,在所有動作開始前設定

    (command "UNDO" "M")

   若程式執行結果不如預期,例如畫出的圖形與現有圖形重疊,而你的程式已經執行了幾百個動作,又無法放棄不存檔,那心中的無奈跟手指按 CTRL+Z 的痛苦可是無以覆加
   如果程式先設定 UNOD MARK 位置,那麼此時只要執行 UNDO/B,就可回到 LISP 執行前狀態,當然付出的代價是程式執行速度,不過,還是那句話,我輩能寫的出的程式,通常不會有這個問題滴。