Chuyển đến nội dung
Diễn đàn CADViet
Nguyen Hoanh

Học AutoLisp

Các bài được khuyến nghị

- Tôi xin thử nghiệm một chuỗi bài viết về đào tạo AutoLisp thông qua các dự án thực tế.

Xin mọi người đóng góp ý kiến.

  • Vote tăng 20
  • Vote giảm 1

Chia sẻ bài đăng này


Liên kết tới bài đăng
Chia sẻ trên các trang web khác

Phần 1: bắt đầu

 

Đầu tiên, chúng ta hãy bắt đầu bằng chương trình viết chữ.

 

Hãy tạo một file mới và save nó với tên hoclisp.lsp.

(princ "\nChao cadviet")

(princ)

Đây là đoạn mã đơn giản nhất của AutoLisp nhằm viết ra một dòng 'Chao cadviet' trên màn hình nhập dữ liệu của autocad. để sử dụng, appload file hoclisp.lsp này. ta sẽ thấy trên màn hình xuất hiện chữ Chao cadviet.

 

Đi sâu vào phân tích lệnh, ta thấy: mỗi hàm của cad được bắt đầu bằng dấu '(' ngay sau đó là tên hàm, tiếp đến là thông số của hàm (có thể có, có thể không có) và kết thúc bằng dấu ')' Trong trường hợp này princ là tên hàm, "\nChao cadviet" là tham số của hàm princ.

 

Trong hai câu lệnh gọi hàm vừa rồi, câu thứ nhất là để viết chữ ra màn hình text, câu lệnh thứ 2 dùng để ẩn kết thúc mà không hiển thị thêm gì cả. Nếu thiếu câu lệnh thứ 2, bạn sẽ nhìn thấy 'Chao cadviet"\nChao cadviet"' trên màn hình, trong đó "\nChao cadviet" là kết quả của hàm (princ "\nChao cadviet").

  • Like 2
  • Vote tăng 32
  • Vote giảm 1

Chia sẻ bài đăng này


Liên kết tới bài đăng
Chia sẻ trên các trang web khác

Phần 2:

 

Trong phần 1, chúng ta đã xây dựng được 1 chương trình lisp có thể nói là thô sơ nhất thế giới. Và nó có 1 nhược điểm: mỗi lần load thì viết ra lệnh. Muốn viết lại phải appload thêm 1 lần nữa.

 

Để điều khiển được thời điểm viết, và viết được nhiều lần, chúng ta phải định nghĩa một hàm AutoCAD, để mỗi khi gọi hàm này, chương trình sẽ viết ra màn hình text mà không cần phải appload lại file lisp.

 

Trên file hoclisp.lsp, chúng ta thêm mã lệnh để trở thành như sau:

(defun c:chao()

(princ "\nChao cadviet")

(princ)

)

 

Như vậy chúng ta đã định nghĩa được một lệnh của AutoCAD mang tên chao, mỗi lần gọi lệnh chao tại dòng nhắc Command, chương trình sẽ viết ra trên màn hình text dòng chữ: Chao cadviet.

 

Trong 2 dòng vừa thêm, hàm defun là hàm định nghĩa lệnh AutoCAD. Có cấu trúc:

(defun tenham() noidungham) trong đó:

- tenham là tên hàm cần định nghĩa, nếu muốn định nghĩa một lệnh trong AutoCAD thì thêm 'C:' vào trước tên hàm.

- noidungham là tập các lệnh mà hàm vừa định nghĩa sẽ thực thi.

  • Like 2
  • Vote tăng 15

Chia sẻ bài đăng này


Liên kết tới bài đăng
Chia sẻ trên các trang web khác

Phần 3:

 

Trong phần 2, chúng ta đã tạo được một chương trình lisp có giao tiếp với AutoCAD thông qua tên lệnh.

Tại phần 3 này, chúng ta sẽ viết một chương trình thực sự, có ích hẳn hoi.

 

Đó là chương trình tính diện tích của một đối tượng. Trên file hoclisp.lsp, hãy sửa tên hàm chao thành tdt và thêm các mã lệnh như sau:

(defun c:tdt( / sel ent dientich)

(princ "\nChao cadviet")

 

(setq sel (entsel "\nHay chon doi tuong: "))

(setq ent (car sel))

(command ".area" "o" ent)

(setq dientich (getvar "area"))

(princ "\nDien tich doi tuong vua roi la: ")

(princ dientich)

(princ "\nm2")

 

(princ)

)

 

Bạn thử appload file hoclisp.lsp mới và gọi lệnh tdt thử xem, chương trình sẽ yêu cầu bạn nhập vào 1 đối tượng. Và nó sẽ kết xuất diện tích đối tượng vừa rồi ra màn hình:

Command: tdt

Chao cadviet

Hay chon doi tuong: .area

Specify first corner point or [Object/Add/Subtract]: o

Select objects:

Area = 46546736.0000, Perimeter = 28320.0000

 

Command:

Dien tich doi tuong vua roi la: 4.65467e+007m2

Điều gì làm nên sự khác biệt này vậy: chúng ta hãy lần theo từng lệnh nhé.

- Lệnh (entsel "\nHay chon doi tuong: ") là lệnh trả về đối tượng được pick, kết quả trả về là một tập hợp gồm 2 thành phần: thứ nhất là đối tượng được pick, thứ 2 là tọa độ pick.

- Lệnh (setq sel (entsel "\nHay chon doi tuong: ")) là lệnh gán kết quả vừa pick vào biến sel. Bạn nhớ là lệnh (setq a :lol: là gán giá trị a bằng giá trị b. Trong trường hợp này a là sel, b là kết quả của hàm entsel.

- Lệnh (car sel) là lệnh lấy giá trị đầu tiên của biến sel (biến sel có dạng tập hợp) tức là đối tượng được chọn.

- lệnh (setq ent (car sel)) là lệnh gán giá trị biến ent bằng ename của đối tượng được chọn. ename của một đối tượng là giá trị chỉ ra đối tượng trong một bản vẽ cad.

Như vậy, 2 dòng lệnh

(setq sel (entsel "\nHay chon doi tuong: "))

(setq ent (car sel))

có ý nghĩa là gán giá trị biến ent cho đối tượng vừa được chọn bằng phương pháp pick.

 

Tiếp đến, lệnh (command ".area" "o" ent) tương đương với gõ tại dòng lệnh command: .area rồi gõ tiếp o và pick đối tượng. Bạn nhớ là lệnh (command a b c d e f...) tương đương với việc gõ các giá trị a, b, c, d, e, f ... vào dòng lệnh của cad. Như vậy, lệnh trên tương đương với việc tính diện tích của đối tượng vừa được chọn.

 

- Lệnh (setq dientich (getvar "area")): gán giá trị biến dientich bằng giá trị của biến hệ thống AREA (biến hệ thống AREA chứa diện tích vừa được tính bằng lệnh AREA trước đó của cad).

 

-cụm lệnh:

(princ "\nDien tich doi tuong vua roi la: ")

(princ dientich)

(princ "m2")

chắc chắn bạn biết đó là lệnh viết dòng chữ 'Dien tich doi tuong vua roi la: ' diện tích đối tượng vừa rồi 'm2'.

Trên màn hình bạn còn nhìn thấy các dòng chữ khác ngoài dòng chữ trên đó là do các lệnh area của CAD sinh ra. Trong bài học sau chúng ta sẽ biết cách loại bỏ chữ này.

  • Like 1
  • Vote tăng 30

Chia sẻ bài đăng này


Liên kết tới bài đăng
Chia sẻ trên các trang web khác

Anh Hoành ơi viết tiếp phần cơ bản đi để anh em có cái móng thì mới tự học được. Chương trình nào cũng thế, phải cần 1 người chỉ đường thì mới nhanh được

  • Vote tăng 11

Chia sẻ bài đăng này


Liên kết tới bài đăng
Chia sẻ trên các trang web khác

Patpat lại khích tướng rồi. Xin giới thiệu phần tiếp theo để mọi người khỏi phải chờ, hy vọng là nó có ích.

 

Phần 4:

* Các phần trước, chúng ta đã thực hành được với lệnh lisp tính diện tích của một đối tượng. Phần này, chúng ta sẽ đi vào cải tiến để lệnh tính diện tích sẽ áp dụng cho một tập đối tượng được chọn của chúng ta.

 

* Trong AutoLisp tập đối tượng được lưu trong biến kiểu tập chọn. Với lệnh (ssget), có thể tạo ra một tập chọn chứa các đối tượng chúng ta chọn. Với lệnh (ssname ss index) chúng ta sẽ lấy được entname đối tượng thứ index trong tập đối tượng ss. lệnh (sslength ss) trả về số đối tượng trong tập chọn.

 

* Tính diện tích của một tập đối tượng, ta sẽ tính diện tích của từng đối tượng trong tập này và cộng lại với nhau. Để làm được như vậy, chúng ta sẽ làm một hàm lặp như sau:

(repeat sodoituong

(setq

ent_ht (ssname ssdt index)

index (+ index 1)

dientich (tinhdientich_one ent_ht)

tongdientich (+ tongdientich dientich)

)

Vòng lặp này sẽ quét qua tất cả các đối tượng và cộng dồn diện tích của đối tượng hiện tại vào diện tích tổng. Trong đoạn mã trên, biến sodoituong chứa số đối tượng có trong tập chọn. index là biến chứa chỉ số của đối tượng hiện tại (index có giá trị từ 0 đến sodoituong-1). ent_ht là tên của đối tượng hiện tại. tinhdientich_one là hàm tính diện tích của một đối tượng được chỉ định, hàm này có được bằng cách gom 2 dòng lệnh của phần trước lại với nhau là: (command ".area" "o" ent)(setq dientich (getvar "area")). Tongdientich chính là diện tích của tất cả các đối tượng, giá trị này có được nhờ cộng dồn tất cả các giá trị của biến dientich lại với nhau.

 

* Chương trình tính diện tích sẽ tiếp tục được cải tiến như sau:

--------------------Gốc (xin nhắc lại phần trước):

(defun c:tdt( / sel ent dientich)

(princ "\nChao cadviet")

(setq sel (entsel "\nHay chon doi tuong: "))

(setq ent (car sel))

(command ".area" "o" ent)

(setq dientich (getvar "area"))

(princ "\nDien tich tap doi tuong vua roi la: ")

(princ dientich)

(princ "\nm2")

(princ)

)

 

--------------------Cải tiến (màu xám là đoạn code bỏ đi, màu xanh là đoạn code thêm mới):

(defun c:tdt( / sel ent dientich)

(princ "\nChao cadviet")

;(setq sel (entsel "\nHay chon doi tuong: "))

(setq ssdt (ssget))

;(setq ent (car sel))

(defun tinhdientich_one(ent)

(command ".area" "o" ent)

(setq dientich (getvar "area"))

)

; khởi tạo các biến

(setq

sodoituong (sslength ssdt)

index 0

tongdientich 0.0

)

 

; vòng lặp quét qua các đối tượng

(repeat sodoituong

(setq

ent_ht (ssname ssdt index)

index (1+ index)

dientich (tinhdientich_one ent_ht)

tongdientich (+ tongdientich dientich)

)

)

(princ "\nDien tich tap doi tuong vua roi la: ")

;(princ dientich)

;in tổng diện tích

(princ tongdientich)

(princ "\nm2")

(princ)

)

 

* Như vậy, chúng ta đã tạo được một đoạn code tính diện tích của một tập đối tượng. Tuy nhiên, đoạn code này hơi rườm rà, do có một lệnh định nghĩa hàm defun tinhdientich_one nằm ngay giữa đoạn code. Bây giờ, chúng ta sẽ làm sạch lại đoạn code trên bằng cách sắp xếp lại mà không thay đổi bất cứ ý nghĩa của một mã nào:

(defun c:tdt( / sel ent dientich)

 

;định nghĩa hàm tính diện tích 1 đối tượng

(defun tinhdientich_one(ent)

(command ".area" "o" ent)

(setq dientich (getvar "area"))

)

 

; viết lời chào và chọn đối tượng

(princ "\nChao cadviet")

(setq ssdt (ssget))

 

; khởi tạo các biến

(setq

sodoituong (sslength ssdt)

index 0

tongdientich 0.0

)

 

; quét qua tất cả các đối tượng trong tập chọn, tính diện tích và cộng dồn diện tích

(repeat sodoituong

(setq

ent_ht (ssname ssdt index)

index (1+ index)

dientich (tinhdientich_one ent_ht)

tongdientich (+ tongdientich dientich)

)

)

 

; xuất kết quả ra màn hình

(princ "\nDien tich tap doi tuong vua roi la: ")

(princ tongdientich)

(princ "\nm2")

(princ)

)

 

--------------------------------------------------------------------------------------------

Phần tiếp theo sẽ trình bày phần tinh chỉnh code để:

- kết xuất kết quả ra đối tượng text

- lọc các đối tượng được chọn

- ẩn các đoạn text trung gian.

 

Cảm ơn các bạn vẫn đang theo dõi.

  • Vote tăng 21

Chia sẻ bài đăng này


Liên kết tới bài đăng
Chia sẻ trên các trang web khác

Quá hay!!! :lol: Come on! kiểu này dễ hiểu hơn đọc ebook rồi. anh Hoành move topic này vào phần tutorial hợp lý hơn

Chia sẻ bài đăng này


Liên kết tới bài đăng
Chia sẻ trên các trang web khác

Để đơn giản về ý tưởng viết tut. Hoành có thể viết bải giải thích các lisp đã post trên diễn đàn. Như vậy anh dễ theo dõi mà lại mang thống nhất của diễn đàn. ý kiến của em có hợp lý không

  • Vote tăng 1

Chia sẻ bài đăng này


Liên kết tới bài đăng
Chia sẻ trên các trang web khác

Mổ xẻ lệnh ẩn đối tượng.

Lệnh ẩn đối tượng này là dựa trên nguyên tắc điều khiển mã dxf 60 của đối tượng. Mã này kiểm soát sự ẩn, hiện của đối tượng. Nếu đối tượng có mã dxf 60 bằng 1 có nghĩa là ẩn, 0 có nghĩa là hiện.

 

Để gán mã dxf 60 bằng 1 cho đối tượng (làm ẩn đối tượng), ta cần tìm xem trong mã của đối tượng đã có mã dxf 60 hay chưa? nếu có thì thay nó bằng giá trị 1, nếu chưa có thì thêm vào nó một mã dxf 60 bằng 1.

 

Trước tiên, chúng ta định nghĩa hàm (Dxf id obj) xem ở phần dưới. Hàm này trả về giá trị của mã id của đối tượng obj, nếu đối tượng obj không có mã id thì kết quả trả về là nil (rỗng).

 

Sau đó, dùng câu lệnh rẽ nhánh: nếu đối tượng có mã dxf 60 thì thay bằng giá trị mới, nếu không có thì thêm một giá trị dxf 60=1 mới vào. Câu lệnh đó như sau:

(if (dxf 60 Elem) ; kiểm tra xem có mã 60 không?

;nếu có? thay:

(entmod (subst (cons 60 1) (cons 60 (dxf 60 elem)) (entget Elem)))

 

;nếu không? thêm:

(entmod (append (entget Elem) (list '(60 . 1))))

)

Trong cụm lệnh trên, Elem là ent name của đối tượng cần ẩn. Hàm entmod có tác dụng modify các thuộc tính một đối tượng theo tập hợp các thuộc tính đã cho (bao gồm thuộc tính tên của đối tượng cần sửa) . Hàm entget trả về tập hợp các thuộc tính của một đối tượng. hàm subst là hàm thay giá một giá trị trong tập hợp bằng một giá trị khác. hàm append là hàm trộn hai tập hợp. Dòng lệnh (entmod (subst (cons 60 1) (cons 60 (dxf 60 elem)) (entget Elem))) để thay mã dxf 60 của đối tượng từ giá trị "(dxf 60 elem)" về giá trị 1.

 

Như vậy, chúng ta có thể viết được một hàm đơn giản để ẩn một đối tượng:

(defun c:ivone()

(defun Dxf (Id Obj) ;định nghĩa hàm dxf

(cdr (assoc Id (entget Obj)))

);end Dxf

(setq elem (car (entsel "\nDoi tuong can an: "))) ;chọn đối tượng

(if (dxf 60 Elem) ; kiểm tra xem có mã 60 không?

;nếu có? thay:

(entmod (subst (cons 60 1) (cons 60 (dxf 60 elem)) (entget Elem)))

;nếu không? thêm:

(entmod (append (entget Elem) (list '(60 . 1))))

)

)

 

Và hàm ẩn nhiều đối tượng sẽ như sau (xin xem thêm ở phần tutor tính diện tích để biết cách biến cách làm 1 đối tượng thành nhiều đối tượng):

(defun c:InVis (/ SSet Count Elem)

(defun Dxf (Id Obj)

(cdr (assoc Id (entget Obj)))

);end Dxf

(prompt "\nSelect object(s) to hide: ")

(cond

((setq SSet (ssget))

(repeat (setq Count (sslength SSet))

(setq Count (1- COunt)

Elem (ssname SSet Count))

(if (/= 4 (logand 4 (Dxf 70 (tblobjname "layer" (Dxf 8 Elem)))))

(if (Dxf 60 Elem)

(entmod (subst '(60 . 1) (assoc 60 (entget Elem)) (entget Elem)))

(entmod (append (entget Elem) (list '(60 . 1))))

)

(prompt "\nEntity on a locked layer. Cannot hide this entity. ")

);end if

);end repeat

)

);end cond

(princ)

);end c:InVis

  • Vote tăng 10

Chia sẻ bài đăng này


Liên kết tới bài đăng
Chia sẻ trên các trang web khác

Làm sao để khi mình bấm chuột phải thì thoát hoàn toàn khỏi vòng lặp repeat của chương trình viết bằng Lisp. Bác nào chỉ hộ mình nha.

Chia sẻ bài đăng này


Liên kết tới bài đăng
Chia sẻ trên các trang web khác
Làm sao để khi mình bấm chuột phải thì thoát hoàn toàn khỏi vòng lặp repeat của chương trình viết bằng Lisp. Bác nào chỉ hộ mình nha.

Chỉ có thoát khỏi cả chương trình lisp (bằng lệnh exit hoặc quit) chứ không thể chỉ thoát khỏi lặp repeat.

Hơn nữa, để thoát khỏi một vòng lặp bằng cách bấm chuột phải còn phụ thuộc vào đoạn mã của bạn, có thể được và cũng có thể không được.

  • Vote tăng 1

Chia sẻ bài đăng này


Liên kết tới bài đăng
Chia sẻ trên các trang web khác
Chỉ có thoát khỏi cả chương trình lisp (bằng lệnh exit hoặc quit) chứ không thể chỉ thoát khỏi lặp repeat.

Hơn nữa, để thoát khỏi một vòng lặp bằng cách bấm chuột phải còn phụ thuộc vào đoạn mã của bạn, có thể được và cũng có thể không được.

Bác có thể cho một ví dụ cụ thể trường hợp nào có thể thoát khỏi vòng lặp hoặc cả chương trình không? Cám ơn trước nha.

  • Vote tăng 1

Chia sẻ bài đăng này


Liên kết tới bài đăng
Chia sẻ trên các trang web khác
Bác có thể cho một ví dụ cụ thể trường hợp nào có thể thoát khỏi vòng lặp hoặc cả chương trình không? Cám ơn trước nha.

 

bạn dùng vòng lặp while, lệnh test dưới đây sẽ yêu cầu người sử dụng nhập một chuỗi và thông báo chuỗi đó. Lặp đi lặp lại cho đến khi người dùng nhấn enter, hoặc nhập vào chuỗi có giá trị là thoat:

 

(defun c:test()

(setq lanthu 0)

(while (and

(setq s (getstring "\nVao chuoi: "))

(/= s "")

(/= s "thoat")

)

(alert s)

)

(princ)

)

  • Vote tăng 2

Chia sẻ bài đăng này


Liên kết tới bài đăng
Chia sẻ trên các trang web khác
Thông tin gì bạn?

Line có rất nhiều thông tin!

 

Tôi muốn viết một đoạn lệnh để chèn symbol vào giữa 2 điểm. Để định hướng cho symbol tôi sẽ vẽ 1 line tạo bởi 2 điểm đó. Sau khi chèn symbol vào rồi thì xoá line định hướng đó. Bác có rảnh thì hương dẫn dùm nha. Cám ơn đã trả lời.

Chia sẻ bài đăng này


Liên kết tới bài đăng
Chia sẻ trên các trang web khác
Tôi muốn viết một đoạn lệnh để chèn symbol vào giữa 2 điểm. Để định hướng cho symbol tôi sẽ vẽ 1 line tạo bởi 2 điểm đó. Sau khi chèn symbol vào rồi thì xoá line định hướng đó. Bác có rảnh thì hương dẫn dùm nha. Cám ơn đã trả lời.

 

Sau đây là 1 đoạn lisp tạo một điểm point ở giữa một đối tượng line:

(defun c:test()

(setq ent (car (entsel "\nPick vao 1 line: "))

tt (entget ent)

p1 (cdr (assoc 10 tt))

p2 (cdr (assoc 11 tt))

pg (polar p1 (angle p1 p2) (/ (distance p1 p2) 2.0))

)

(entmake (list (cons 0 "POINT") (cons 10 pg)))

(princ)

)

  • Vote tăng 4

Chia sẻ bài đăng này


Liên kết tới bài đăng
Chia sẻ trên các trang web khác

Nhờ bác Hoành mổ xẻ lệnh: TRACDIA của bác SSG giúp được không. Đang cần học 1 số cái trong lễnh này nhưng chưa hiểu lắm nhất là các hàm diều khiển dialoag.

Chia sẻ bài đăng này


Liên kết tới bài đăng
Chia sẻ trên các trang web khác
Nhờ bác Hoành mổ xẻ lệnh: TRACDIA của bác SSG giúp được không. Đang cần học 1 số cái trong lễnh này nhưng chưa hiểu lắm nhất là các hàm diều khiển dialoag.

là lệnh nào bạn?

Chia sẻ bài đăng này


Liên kết tới bài đăng
Chia sẻ trên các trang web khác

Tạo một tài khoản hoặc đăng nhập để nhận xét

Bạn cần phải là một thành viên để lại một bình luận

Tạo tài khoản

Đăng ký một tài khoản mới trong cộng đồng của chúng tôi. Điều đó dễ mà.

Đăng ký tài khoản mới

Đăng nhập

Bạn có sẵn sàng để tạo một tài khoản ? Đăng nhập tại đây.

Đăng nhập ngay

×