Thứ Hai, 26 tháng 10, 2015

XÂM NHẬP KHO CƠ SỞ DỮ LIỆU CỦA AUTOCAD

Hình như mọi thông tin về tất cả các đối tượng trên bản vẽ của bạn đều được Acad “ghi chép cẩn thận” và lưu trữ ở đâu đó, khi cần là có ngay? Thực tế đúng như vậy. Vấn đề đặt ra là, làm thế nào để chương trình lisp của bạn “moi” được các thông tin ấy để phục vụ cho nhiều mục đích khác nhau của chương trình?

Tiêu đề hơi “giật gân” nhưng không có gì ghê gớm. Còn thú vị hay không là tùy mỗi người…

ĐẶT VẤN ĐỀ

Bạn hãy vẽ một đường tròn, sau đó dùng lệnh dimradius: một dimension được tạo ra với ký hiệu R ở trước con số bán kính (rất bình thường, không có gì đặc biệt cả). Nhưng có khi nào bạn tự hỏi, Acad dựa vào cái gì để lấy trị số bán kính, cũng như biết đó là đường tròn để tự động thêm chữ R? Không chỉ có vậy, bạn hãy select vào một đối tượng bất kỳ và gõ lệnh mo (properties), một bảng “lý lịch trích ngang” hiện ra, cho phép bạn xác định hoàn toàn “nhân thân” của đối tượng đó.

Hình như mọi thông tin về tất cả các đối tượng trên bản vẽ của bạn đều được Acad “ghi chép cẩn thận” và lưu trữ ở đâu đó, khi cần là có ngay? Thực tế đúng như vậy. Vấn đề đặt ra là, làm thế nào để chương trình lisp của bạn “moi” được các thông tin ấy để phục vụ cho nhiều mục đích khác nhau của chương trình?

Cám ơn Autodesk đã cung cấp khá nhiều các “đồ chơi” cho việc này. Nào, xin mời các bạn, hãy cùng “xâm nhập” vào kho cơ sở dữ liệu của hoc vẽ cad để tìm hiểu, cũng như tham gia quản lý và điều khiển các đối tượng cùng với khóa học cad!

HÀNH TRANG

Trước hết, bạn phải có một chút “vốn liếng” cần thiết về lisp, cụ thể là phải hiểu được các khái niệm sau:

- List data type: kiểu dữ liệu danh sách, một kiểu dữ liệu có thể nói là cơ bản nhất của ngôn ngữ Lisp (không nắm được list nghĩa là chưa hiểu gì về lisp!), gồm các phần tử được đặt trong 2 dấu đóng mở ngoặc đơn và được ngăn cách với nhau bằng ít nhất 1 dấu cách (space) hoặc dấu tab. Ví dụ: (“a” “b” 2 3 “c”) là 1 danh sách có 5 phần tử, 3 phần tử kiểu string và 2 phần tử kiểu integer.

- Các hàm thao tác với list: list, car, cadr, caddr, nth, cdr…

Ví dụ:

Kiến tạo list: (setq L (list 1 2 3 4)) return (1 2 3 4)

Nếu các phần tử không phải là biến (variables), có thể dùng: (setq L ‘(1 2 3 4)), kết quả như trên.

(car L), tương đương với (nth 0 L) return 1 – trả về phần tử đầu tiên của list L

(cadr L) , tương đương với (nth 1 L) return 2 – trả về phần tử thứ 2 của L

(caddr L) , tương đương với (nth 2 L) return 3 – trả về phần tử thứ 3 của L

Một điểm trong hoc cad  được xem như một list có 3 thành phần là số thực (real)

(cdr L) return (2 3 4) – trả về 1 list sau khi loại ra phần tử đầu tiên của L

- Dotted pair: danh sách cặp với dấu chấm, là một kiểu list đặc biệt gồm 2 thành phần, được ngăn cách bởi 1 dấu chấm (chú ý: có ít nhất 1 dấu cách giữa dấu chấm với các thành phần). Ví dụ: (2 . “a”)

- Hàm kiến tạo dotted pair: cons

Ví dụ: (cons 2 5) return (2 . 5)

- Association list: danh sách liên hợp, là một list mà mỗi phần tử là một dotted pair. Ví dụ: ((2 . “a”) (1 . 3) (“x” . “y”))

- Hàm truy cập association list: assoc

Ví dụ:

(setq aL (list (cons 2 3) (cons 1 "a"))) return ((2 . 3) (1 . "a"))

(assoc 1 aL) return (1 . "a") – trả về dotted pair trong aL, có phần tử đầu là 1

(cdr (assoc 1 aL)) return “a” – tách ra được phần tử thứ 2 trong dotted pair

Hành trang từng ấy là đủ nhưng nhớ mang thêm quyển sách lisp (lỡ bí cái gì thì lật ra xem!). Ngoài ra, xin lưu ý rằng, bạn có thể nhập trực tiếp các biểu thức lisp ví dụ nêu trong bài ngay tại dòng nhắc lệnh Command: của AutoCAD, nó sẽ thực thi ngay tức khắc. Nếu lười biếng, có thể copy, paste vào và… ung dung ngồi xem kết quả!

TIẾP CẬN

AutoLisp định nghĩa khái niệm “đối tượng” bằng thuật ngũ Entity (thực thể). Tại sao không phải là Object (dễ hiểu và phổ biến hơn) mà là entity? Vì khái niệm Object đã được dành cho VBA và ARX mất rồi! Cùng để chỉ một “vật”, nhưng VBA gọi là Object còn AutoLisp gọi là Entity. Không quan trọng, chẳng qua là quy ước, “nhập gia tùy tục” thôi.

Bắt đầu làm quen với entity, trong layer “0” bạn hãy vẽ một đường tròn, bán kính 50, tâm tại điểm 100, 120 (các số liệu trên chỉ là ví dụ để tiện theo dõi) và nhập biểu thức lisp sau:

Command: (setq e (entlast))

Ý nghĩa: gán thực thể cuối cùng trong kho cơ sở dữ liệu (last entity) cho biến e

Kết quả trả về có dạng: <Entity name: 400871a8> (dãy số sau dấu 2 chấm bạn nhận được chắc là sẽ khác ở đây, nhưng dạng thì đúng như vậy)

Đó là một dãy số hexa, được AutoCAD gán cho thực thể (đường tròn) bạn vừa tạo ra. Mỗi thực thể trong bản vẽ được mang 1 dãy số duy nhất, không trùng nhau, giống như số chứng minh nhân dân (CMND) vậy. AutoLisp định nghĩa dãy số đó là một kiểu dữ liệu – kiểu Entity name.

Đối với AutoLisp, Entity name đại diện cho thực thể (giống như căn cứ vào số CMND, cảnh sát sẽ biết chính xác bạn là ai). Nó là chìa khóa để bạn có thể “moi” được thông tin cũng như có thể điều khiển được thực thể. Hãy thử xem bạn có thể làm gì với biến e nhận được ở trên.

(command "move" e "" '(100 120) '(150 160)); thực thể di chuyển

(command “erase” e “”); thực thể biến mất

OK! Bạn có thể dùng biến e để điều khiển thực thể theo ý thích rồi đó. Dòng lệnh thứ 2 cho thấy một ý rất quan trọng trong việc quản lý và điều khiển entity: dù đã move đi chỗ khác, nhưng nó vẫn là nó. Khi cảnh sát đã cấp cho bạn một số CMND, dù bạn có chạy đằng trời, họ vẫn tóm được!

Nhưng nó biến mất rồi, lấy gì để khảo sát tiếp? Đơn giản nhất là undo 2 lần, dùng lisp để thực hiện cho… oai:

(command “undo” 2)

XÂM NHẬP

Hàm entget (ghép từ Entity Get) cho phép bạn “xâm nhập” thật sự vào kho cơ sở dữ liệu mà AutoCAD lưu trữ thông tin về thực thể.

(setq mydata (entget e)).

Bấm F2 để xem, kết quả có dạng:

((-1 . <Entity name: 400871a8>) (0 . "CIRCLE") (330 . <Entity name: 4008fcf8>)

(5 . "AD") (100 . "AcDbEntity") (67 . 0) (410 . "Model") (8 . "0") (100 .

"AcDbCircle") (10 100.0 120.0 0.0) (40 . 50.0) (210 0.0 0.0 1.0))

Hơi rối mắt, nhưng đừng hoảng! Bình tĩnh nhận xét, bạn sẽ thấy đây là một association list, mỗi phần tử của nó là một dotted pair. Thành phần đầu của dotted pair gọi là mã DXF, đại diện cho một thuộc tính nào đó, được quy định thống nhất tùy theo loại thực thể. Thành phần thứ 2 của dotted pair là giá trị (value) của thuộc tính đó.

Tạm thời, bạn đừng bận tâm đến quá nhiều thứ, chỉ cần chú ý đến 4 thông tin quan trọng nhất: loại thực thể (tất nhiên là đường tròn), layer, tọa độ tâm và bán kính. Quan sát bạn sẽ thấy chúng nằm ở các dotted pair có mã DXF là 0, 8, 10 và 40. Bạn có thể dùng hàm assoc, kết hợp với cdr để lấy các thông tin này:

Loại: (setq mytype (cdr (assoc 0 mydata))) ;return “CIRCLE”

Layer: (setq mylayer (cdr (assoc 8 mydata))) ;return “0”

Tâm: (setq p (cdr (assoc 10 mydata))) ;return (100.0 120.0 0.0)

Bán kính: (setq R (cdr (assoc 40 mydata))) ;return (50.0)

Những thông tin kiểu như trên là nguồn “vật liệu” rất quý giá cho lập trình viên lisp. Bạn có thể bày ra đủ trò từ chúng. Một ví dụ đơn giản, bạn có thể lập một chương trình xác định ngay loại của đối tượng khi người dùng bấm vào nó (copy cả đoạn sau paste vào Command, vẽ một lô một lốc các loại đối tượng khác nhau rồi gõ ET để thử):

(defun C:ET() ;;;Entity Type

(alert (strcat “This is a “ (cdr (assoc 0 (entget (car (entsel “\nSelect object:”)))))))

)

Một thử nghiệm tiếp theo: bạn hãy làm thay đổi thực thể cho khác đi, xem lisp có nhận ra không. Tạo một layer mới có tên Layer1 có màu white, chuyển đường tròn của chúng ta sang Layer1, gán cho nó màu green, tiện thể bấm vào điểm grip ở quadrant của nó và kéo dãn ra 10 đơn vị (bán kính tăng thêm 10), gọi lại entget:

(setq mydata (entget e))

Kết quả:

((-1 . <Entity name: 400871a8>) (0 . "CIRCLE") (330 . <Entity name: 4008fcf8>)

(5 . "AD") (100 . "AcDbEntity") (67 . 0) (410 . "Model") (8 . "Layer1") (62 .

3) (100 . "AcDbCircle") (10 100.0 120.0 0.0) (40 . 60.0) (210 0.0 0.0 1.0))

Quan sát các thành phần ở DXF 8 và 40 bạn thấy gì? Các thay đổi bạn vừa thực hiện với layer và bán kính đường tròn đã được cập nhật. Ngoài ra, lần này xuất hiện thêm cặp (62 . 3): 62 là mã DXF của màu, 3 = green là giá trị màu của thực thể.

Bạn lưu ý rằng suốt từ đầu đến giờ, chúng ta chỉ thực hiện phép gán (setq e (entlast)) có 1 lần duy nhất. Điều đó có nghĩa là, bất chấp mọi biến đổi, e vẫn mang đúng số Entity Name như lúc đầu: 400871a8, và tất nhiên nó vẫn cứ là nó. Không những di chuyển lung tung, mà kể cả bạn có thay hình đổi dạng, có đeo mặt nạ hóa trang, cảnh sát vẫn tóm được bạn nhờ vào số CMND!

Không tin cứ thử là biết ngay: (command “erase” e “”)

THAY LỜI KẾT

Một vài ví dụ nhỏ, chưa thể nói hết ý được, chỉ xin nhấn mạnh: hãy tìm hiểu về Entity với hàm Entget, cũng như tập hợp của chúng là Selection Set với hàm Ssget, bạn sẽ lập được rất nhiều chương trình lisp hiệu quả. Mọi thắc mắc về Entity, đặc biệt là mã DXF, trước tiên mời bạn tham khảo ở: Developer Help – DXF Reference – Entities Section. Sau đó, có vấn đề gì thì post lên đây, chúng ta sẽ cùng trao đổi tiếp.

Cám ơn các bạn đã kiên nhẫn đọc đến những dòng này!

1 nhận xét: