-
Số lượng nội dung
905 -
Đã tham gia
-
Lần ghé thăm cuối
-
Ngày trúng
29
Bài đăng được đăng bởi Thaistreetz
-
-
2. Xây dựng hàm lấy đối tượng mới sinh từ thời điểm đánh dấu :
Bằng cách lấy ename ở "chổ đâu đó" và xây dựng hàm lấy đối tượng mới sinh.
Cái này thì tương đối đơn giản, chúng ta đã có nhiều lisp từng sử dụng thuật toán này. đây là kết quả em làm được
(defun C:SX (/ last-en lst)
(if (vl-member-if '(lambda (x) (= (vlr-data x) "Acdb Reactor: Select The new Objects")) (cdar (vlr-reactors :vlr-acdb-reactor)))
(if *Last-Objects*
(progn (setq last-en *Last-Objects*) (while (setq last-en (entnext last-en)) (setq lst (cons last-en lst))) (sssetfirst nil (list->ss lst)))
(prompt (TCVN3-Unicode "** Khong co doi tuong moi nao duoc chon (progn
(setq *Last-Objects* nil)
(prompt (TCVN3-Unicode " << bat che do theo doi doi tuong entlast>>"))
(vlr-acdb-reactor "Acdb Reactor: Select The new Objects" '((:vlr-objectAppended . Callback-objectAppended)))))
(princ))
Phần bôi đậm là ý tưởng xây dựng cho ý 1 sau đây
Ý tưởng trên hoàn toàn có thể làm được.
1. Xây dựng 1 hàm đánh dấu : Là 1 hàm lấy Ename cuối cùng -> Lưu trữ Ename này vào 1 "chổ đâu đó". Nếu "chỗ đâu đó" đã tồn tại ename thì thay ename cũ bằng ename cuối cùng đó.
Việc đánh dấu này khi đặt vấn đề thì nghĩ là đơn giản. nhưng thực ra nó không hề dễ 1 chút nào.
Tốt nhất là dùng 1 reactor để làm việc này nếu muốn tự động hóa hoàn toàn, mục đích là để có thể "select the new objecs" bất cứ lúc nào chúng ta muốn trong khi vẽ. Đã có 2 ý tưởng:
1 Của mình: Dùng 1 reactor để theo dõi các sự kiện: sự kiện bắt đầu dùng 1 lệnh autocad :VLR-CommandWillStart và sự kiện bắt đầu 1 lệnh lisp :VLR-LispWillStart. khi sảy ra 1 trong 2 sự kiện này thì gọi hàm callback và gán đối tượng cuối cùng cho 1 biến. Hàm callback cho 2 sự kiện này được đại khái như sau:
(defun callback (reactor pramlist) (setq *Object-last* (entlast)) .....);end
Các vấn đề mình chưa giải quyết được khi sử dụng cách trên:
- không biết nó có tác dụng với các lệnh được viết bằng các ngôn ngữ khác hay không hay chỉ có tác dụng với lệnh cad và lệnh lisp, khả năng 99% là không (như Detailing đã nêu)
- Nếu chỉ dùng với lệnh của cad thôi thì coi như xong. ý tưởng đã được thực hiện. nhưng đa số chúng ta ai cũng dùng lisp. Nếu 1 lệnh lisp có bao gồm 1 hoặc nhiều lệnh của cad thì toi rồi.
Cụ thể: Khi lệnh lisp được gọi thì sự kiên VLR-LispWillStart. sảy ra. hàm callback được gọi, biến *object-last* được gán giá trị. tuy nhiên nếu trong quá trình chạy lisp, 1 lệnh của cad được gọi thông quahàm (command "tenlenh") thì sự kiện :VLR-CommandWillStart lại sảy ra và hàm callback lại tiếp tục được gọi *object-last* được gán giá trị mới. cứ như vậy bao nhiêu lần thực hiện hàm command thì sẽ có bấy lần hàm callback được gọi, kết quả là biến *object-last* chỉ là đồ bỏ đi.
- Nếu trường hợp lệnh cad và lệnh lisp không được hoàn thành. người dùng thoát giữa chừng thì *object-last* cũng không dùng được nữa
Túm lại là cách này không dùng được
2. Ý tưởng của bác Detailing: theo dõi sự kiện dữ liệu bản vẽ (database) bị thay đổi bằng vlr-acdb-reactor. Cụ thể là sự kiện dữ liệu bản vẽ được ghi thêm đối tượng :vlr-objectAppended mà mình sử dụng ở trên. hàm callback được gọi khi dữ liệu bản vẽ xuất hiện đối tượng mới. nó cũng được viết đại khái giống hàm callback bên trên.
- Cách này càng không được. mình lấy ví dụ thế này cho dễ hiểu: Giả sử mình sử dụng lệnh copy để copy 2 đối tượng. như vậy có 2 lần sự kiện :vlr-objectAppended kết quả là 2 lần hàm callback được gọi và *object-last* sẽ được gán là đối tượng cuối cùng được tạo ra sau lệnh copy, huề cả làng rồi. (entnext *object-last*) = nil
Vậy nên mời các bác tiếp tục đóng góp ý kiến :(
@ bác gia_bach: bác hiểu sai ý em giống như bác DVH bên trên. thành thât xin lỗi các bác vì diễn đạt chưa rõ nghĩa.
-
2 reactor lispWillStart và CommadWillStart theo dõi việc start command của CAD và lisp vậy .Net và ARX thì sao?
vlr-acdb-reactor là reactor theo dõi sự thay đổi của database của bản vẽ (tương tự biến DBmod) -> khi có đối tượng nào tạo ra thì lưu vào list, khi nào xem list xong thì xóa các item của nó đi, bắt đầu lưu lại list mới.
Good luck!
Các trường hợp bạn nêu chính là những vấn đề thuộc về số 20% còn lại mà mình chưa giải quyết được nên đành chuyển hướng khác là ... lập topic này :D
-
Về nguyên tắc cơ bản thì trình tự làm như Bác Duy đã nêu.
Hqua em cũng viết thử dựa trên nguyên tắc này. sử dụng reactor theo dõi 2 sự kiện: lispWillStart và CommadWillStart của Vlr-editor-reactor. Tuy nhiên chỉ hoàn thành được 80% yêu cầu vì còn 1 vài điểm chưa giải quyết được. Tối về em post để các bác xem rồi ý kiến gỡ rối giúp em.
@Detailing Mình chưa thử nghiên cứu các sự kiện của vlr-acdb-reactor. Để mình thư xem có lôi ra được gì từ nó không.
-
Không. Bác Hà hiểu sai rồi.
Lisp trên lấy ra tập hợp đối tượng sau 1 lệnh cụ thể. (là lệnh HA)
Mình cần lisp lấy ra tập hợp đối tượng tạo ra bởi lệnh bất kỳ trước đó. nghĩa là...:
trong quá trình vẽ chúng ta thường xuyên phải select đối tượng. Cad đã cung cấp nhiều kiểu Select: P-Previuos; L-last; ...
Giờ mình muốn viết thêm 1 lệnh để select được tập hợp đối tượng cuối cùng được tạo ra.
-
Rất nhiều lần mình có nhu cầu cần chọn được tập hợp đối tượng gần nhất được sinh ra bởi 1 lệnh nào đó (có thể là lệnh của cad hoặc lệnh của lisp) nên định viết 1 lisp chức năng như vây. nôm na thì nó cũng tương tự (ssget "L") nhưng ra cả đám chứ không chỉ 1 thằng ku cuối cùng.
Tuy nhiên hiện tại mình đang bí về cách thức giải quyết vấn đề đành phải lập topic xin các bác cao kiến để viết nó. Các bác cùng thảo luận nhé.
Edit: Đã xong. Các bạn có thể down lisp ở bài số #21 (trang 2)
-
1
-
-
Bạn dùng lisp trong bài số #8. Gõ lệnh xong rồi muốn chia màn hình tại đâu thì pick điểm tại đó, khỏi phải quan tâm đến tỷ lệ nữa.
Còn nếu bạn thực sự muốn hiểu bản chất của việc tính toán tỷ lệ chia màn hình thì thế này:
- Màn hình cad được viewport đặt vào đó 1 hệ trục tọa độ tương đối. Gốc (0,0) tại góc trái bên dưới, góc phải bên trên sẽ có tọa độ (1,1)
- Tọa độ của 1 viewport được xác đinh bởi 2 điểm: góc trái bên dưới và góc phải bên trên của viewport đó theo hệ tọa độ trên.
- Lệnh trên tạo ra 2 viewport kề nhau chia màn hình theo phương đứng có tọa độ lần lượt là [(0 , 0) ; (x , 1)] và [(1-x , 0) ; (1 , 1)]
Các tọa độ này được quy định vào 2 mã dxf 10 và 11 của đối tượng viewport. Nếu bạn có chút kiến thức về autolisp có thể tự sửa code trên để chia màn hình theo ý thích: 2 hoặc 3 hoặc nhiều viewport cùng lúc chẳng hạn. hay có thể chia theo phương đứng hoặc phương ngang tùy nhu cầu.
Ngoài ra bằng cách này bạn có thể tạo được cả những viewport đặc biệt, có tọa độ đè lên nhau để tăng thêm diện tích cho mỗi viewport mà bằng lệnh cad thông thường thì không bao giờ có thể tạo được
-
1
-
-
hà hà. ketxu giải quyết vấn đề đơn giản mà hiệu quả. Cứ thấy thế nào vừa mắt là chơi, đỡ fải lăn tăn tỷ lệ.
Đã nâng thì nâng cho tới z luôn nhé. bỏ thằng "ThaistreetzView" kia đi khi không dùng nó nữa. như thế sẽ mềm dẻo hơn cho nhu cầu sử dụng
(defun C:VV (/ get-coordinate-screen TS:zoom PT1 PT2 tl) (defun get-coordinate-screen (coner / Y1 X1) (cond ((= (strcase coner) "TL") (polar(polar(getvar "viewctr")(* 0.5 pi) (setq Y1 (* 0.5 (getvar "viewsize")))) pi (/(* Y1 (car(setq X1 (getvar "screensize"))))(cadr X1)))) ((= (strcase coner) "TR") (polar(polar(getvar "viewctr")(* 0.5 pi) (setq Y1 (* 0.5 (getvar "viewsize")))) 0 (/(* Y1 (car(setq X1 (getvar "screensize"))))(cadr X1)))) ((= (strcase coner) "BL") (polar(polar(getvar "viewctr")(* -0.5 pi)(setq Y1 (* 0.5 (getvar "viewsize")))) pi (/(* Y1 (car(setq X1 (getvar "screensize"))))(cadr X1)))) ((= (strcase coner) "BR") (polar(polar(getvar "viewctr")(* -0.5 pi)(setq Y1 (* 0.5 (getvar "viewsize")))) 0 (/(* Y1 (car(setq X1 (getvar "screensize"))))(cadr X1)))))) (vl-load-com)(defun TS:zoom (pt1 pt2) (vlax-invoke (vlax-get-acad-object) 'zoomwindow pt1 pt2)) (command "propertiesclose") (setq PT1 (get-coordinate-screen "TL") PT2 (get-coordinate-screen "BR") x (abs (- (car pt1)(car pt2)))) (if (= (length (vports)) 1) (progn (setq tl (/ (- (car (getpoint "\nPart :")) (car pt1)) x)) (if (not(tblsearch "vport" "ThaistreetzView")) (progn (entmakex (append '((0 . "VPORT")(100 . "AcDbSymbolTableRecord")(100 . "AcDbViewportTableRecord")(2 . "ThaistreetzView") (70 . 0) (10 0.0 0.0) (13 0.0 0.0 0.0)(14 0.5 0.5 0.0)(15 0.5 0.5 0.0) (16 0.0 0.0 1.0)(17 0.0 0.0 0.0) (41 . 0.974843) (42 . 50.0) (43 . 0.0) (44 . 0.0) (50 . 0.0) (51 . 0.0) (71 . 0) (72 . 1000) (73 . 1) (74 . 3) (75 . 0) (76 . 0) (77 . 0) (78 . 0) (281 . 0) (65 . 1) (110 0.0 0.0 0.0) (111 1.0 0.0 0.0) (112 0.0 1.0 0.0) (79 . 0) (146 . 0.0) (60 . 2) (61 . 5) (292 . 1) (282 . 1) (141 . 0.0) (142 . 0.0) (63 . 250) (421 . 3355443))(list (cons 11 (list tl 1.0))))) (entmakex (append '((0 . "VPORT") (100 . "AcDbSymbolTableRecord") (100 . "AcDbViewportTableRecord") (2 . "ThaistreetzView") (70 . 0) (11 1.0 1.0 0.0) (13 0.0 0.0) (14 0.5 0.5) (15 0.5 0.5) (16 0.0 0.0 1.0) (17 0.0 0.0 0.0) (41 . 0.973617) (42 . 50.0) (43 . 0.0) (44 . 0.0) (50 . 0.0) (51 . 0.0) (71 . 0) (72 . 1000) (73 . 1) (74 . 3) (75 . 0) (76 . 0) (77 . 0) (78 . 0) (65 . 1) (110 0.0 0.0 0.0) (111 1.0 0.0 0.0) (112 0.0 1.0 0.0) (79 . 0) (146 . 0.0) (60 . 2) (61 . 5) (292 . 1) (282 . 1) (141 . 0.0) (142 . 0.0) (63 . 250) (421 . 3355443))(list (cons 10 (list tl 0.0 0.0))))))) (vl-cmdf "vports" "r" "ThaistreetzView") (ts:zoom pt1 pt2) (setvar "cvport" 3) (ts:zoom pt1 pt2)) (progn (vl-cmdf "vports" "si") (vl-cmdf "vports" "d" "ThaistreetzView"))) (princ))
-
4
-
-
Bên phải 3/5 bên trái 2/5 thì thay giá trị 0.6 bằng 0.4. Có 2 vị trí cần phải thay, bạn mới chỉ thay 1 vị trí. Xem lại hướng dẫn, sau khi sửa bạn lưu file lisp lại và load lại nó.
Đừng chạy lệnh VV vội. Trước tiên bạn gõ lệnh Vports -> chuyển sang tab Named Viewports -> xóa thằng "ThaistreetzView" đi. sau đó chạy lại lệnh VV rồi xem kết quả thế nào
PS: Lisp trên mình post ẩu. vẫn chạy được nhưng kết quả chưa được chuẩn. bạn sửa lại dòng này
(defun TS:zoom (pt1 pt2) (vlax-invoke *acad-object* 'zoomwindow pt1 pt2))
thành
(vl-load-com)(defun TS:zoom (pt1 pt2) (vlax-invoke (vlax-get-acad-object) 'zoomwindow pt1 pt2))
Hoặc có thể down lại, mình đã sửa trực tiếp vào bài viết bên trên.
-
Thông thường acad có một số mặc định chia màn hình thành các tỉ lệ 1/2 hoặc 1/3.
Mình thường chia màn hình máy thành 2 viewport với 2 tỷ lệ 4/9 và 5/9
Màn 4/9 là màn phụ để view vùng tham khảo.
Màn 5/9 là màn chính để thao tác vẽ.
Nhưng chuỗi thao tác chia màn hình của mình tốn nhiều công đoạn và máy tính chậm sẽ mất nhiều thời gian.
Tỷ lệ 4/9 và 5/9 để phân chia màn hình chính và phụ không hợp lý lắm. Tại vì bạn phải thao tác bằng lệnh của cad nên chỉ tạo được tỷ lệ này là điều dễ hiểu.
Mình đề xuất tỷ lệ 2/5 và 3/5 để tăng kích thước màn hình chính thêm 1 chút nữa.
;;; Copyright 2011 Thaistreetz from cadviet.com (defun C:VV (/ get-coordinate-screen TS:zoom PT1 PT2) (defun get-coordinate-screen (coner / Y1 X1) (cond ((= (strcase coner) "TL") (polar(polar(getvar "viewctr")(* 0.5 pi) (setq Y1 (* 0.5 (getvar"viewsize")))) pi (/(* Y1 (car(setq X1 (getvar"screensize"))))(cadr X1)))) ((= (strcase coner) "TR") (polar(polar(getvar "viewctr")(* 0.5 pi) (setq Y1 (* 0.5 (getvar"viewsize")))) 0 (/(* Y1 (car(setq X1 (getvar"screensize"))))(cadr X1)))) ((= (strcase coner) "BL") (polar(polar(getvar "viewctr")(* -0.5 pi)(setq Y1 (* 0.5 (getvar"viewsize")))) pi (/(* Y1 (car(setq X1 (getvar"screensize"))))(cadr X1)))) ((= (strcase coner) "BR") (polar(polar(getvar "viewctr")(* -0.5 pi)(setq Y1 (* 0.5 (getvar"viewsize")))) 0 (/(* Y1 (car(setq X1 (getvar"screensize"))))(cadr X1)))))) (defun TS:zoom (pt1 pt2) (vlax-invoke (vlax-get-acad-object) 'zoomwindow pt1 pt2)) (command "propertiesclose") (if (= (length (vports)) 1) (progn (if (not(tblsearch "vport" "ThaistreetzView")) (progn (entmakex '((0 . "VPORT")(100 . "AcDbSymbolTableRecord")(100 . "AcDbViewportTableRecord")(2 . "ThaistreetzView") (70 . 0) (10 0.0 0.0) (11 0.6 1.0) (13 0.0 0.0 0.0)(14 0.5 0.5 0.0)(15 0.5 0.5 0.0) (16 0.0 0.0 1.0)(17 0.0 0.0 0.0) (41 . 0.974843) (42 . 50.0) (43 . 0.0) (44 . 0.0) (50 . 0.0) (51 . 0.0) (71 . 0) (72 . 1000) (73 . 1) (74 . 3) (75 . 0) (76 . 0) (77 . 0) (78 . 0) (281 . 0) (65 . 1) (110 0.0 0.0 0.0) (111 1.0 0.0 0.0) (112 0.0 1.0 0.0) (79 . 0) (146 . 0.0) (60 . 2) (61 . 5) (292 . 1) (282 . 1) (141 . 0.0) (142 . 0.0) (63 . 250) (421 . 3355443))) (entmakex '((0 . "VPORT") (100 . "AcDbSymbolTableRecord") (100 . "AcDbViewportTableRecord") (2 . "ThaistreetzView") (70 . 0) (10 0.6 0.0 0.0)(11 1.0 1.0 0.0) (13 0.0 0.0) (14 0.5 0.5) (15 0.5 0.5) (16 0.0 0.0 1.0) (17 0.0 0.0 0.0) (41 . 0.973617) (42 . 50.0) (43 . 0.0) (44 . 0.0) (50 . 0.0) (51 . 0.0) (71 . 0) (72 . 1000) (73 . 1) (74 . 3) (75 . 0) (76 . 0) (77 . 0) (78 . 0) (65 . 1) (110 0.0 0.0 0.0) (111 1.0 0.0 0.0) (112 0.0 1.0 0.0) (79 . 0) (146 . 0.0) (60 . 2) (61 . 5) (292 . 1) (282 . 1) (141 . 0.0) (142 . 0.0) (63 . 250) (421 . 3355443))))) (setq PT1 (get-coordinate-screen "TL") PT2 (get-coordinate-screen "BR")) (vl-cmdf "vports" "r" "ThaistreetzView") (ts:zoom pt1 pt2) (setvar "cvport" 3) (ts:zoom pt1 pt2)) (vl-cmdf "vports" "si")) (princ))
Cả 2 lệnh bật và tắt chế độ chia màn hình được dùng chung 1 lệnh là VV
Nếu không ưng với tỷ lệ của mình thì bạn sửa 2 dòng này:
(10 0.0 0.0) (11 0.6 1.0) -> (10 0.0 0.0) (11 0.5555 1.0) (hoặc 0.44445 = 4/9) <= đây là kích thước màn hình bên trái
(10 0.6 0.0 0.0)(11 1.0 1.0 0.0) -> (10 0.5555 0.0 0.0)(11 1.0 1.0 0.0) (hoặc 0.44445) <= đây là kích thước màn hình bên phải
Với quy tắc trên, bạn có thể chia theo bất kỳ tỷ lệ nào mà bạn muốn
-
6
-
-
vì đối tượng của bạn chứa cùng lúc nhiều tỷ lệ. dùng lệnh Objectscale để xóa bớt các tỷ lệ không sử dụng
-
1
-
-
Tôi thì không muốn "khoe", tôi chỉ muốn share có phí các chương trình của tôi, nhưng tình hình trước mắt có nhiều lý do nên chưa share được,
Cái lanh tô của bạn mới chỉ có 2 nhánh, mới có giằng đứng. Riêng chương trình của tôi vẽ lanh tô, giằng đứng, giằng ngang, bổ trụ, các loại dầm mặt cắt 2, 3, 4, 6,8 nhánh, các dầm có cốt phụ ở giữa hay không? Quét toàn bộ bản vẽ là nó thống kê ra "tất tần tật" cho mình luôn.
Nhưng tôi chẳng muốn "khoe". Khoe làm chi, khoe cái mà làm chi, tìm cách share thì hay hơn ứ....
- Đã có một số topic được một vài lập trình viên lập ra để kêu gọi mọi người đóng góp ý tưởng. Ý tưởng từ những clip khoe hàng như thế này chứ ở đâu.
- Là người rành về mấy thứ ngôn ngữ lập trình cad thì bác cần người ta share cả chương trình làm gì nhỉ? Bác ấy khoe như thế cũng là share rồi đó bác à. Quan trọng là ý tưởng, có ý tưởng thực hiện thì sẽ viết được. Chẳng phải với lập trình viên thì thứ hơn người khác chính là ý tưởng sao? thiết nghĩ, những topic "khoe hàng" như thế này nên được đội ngũ quản lý diễn đàn khuyến khích mới phải. Bác có thể nhận xét, đánh giá cái hay cái dở trong ý tưởng của người ta. Nhưng với vai trò là mod, tiếng nói của bác có trọng lượng, bác không thể nói "hoặc anh share, hoặc đừng có khoe ở đây" như thế được.
Clip trên có thể không có ích với người này, không có ích với bác nhưng sẽ có ích với người khác.
-
3
-
-
Có cách nào để biết bản vẽ đã bị thay đổi so với lúc mở bản vẽ hoặc sau khi thực hiện lệnh save không các bác nhỉ.
Giống như khi ta mở bản vẽ hoặc sau khi save, chỉ cần Pan 1 nhát thôi rồi đóng bản vẽ là cad nó hỏi luôn: có lưu bản vẽ hay không ấy, nghĩa là lúc đó bản vẽ đã bị thay đổi thông tin
-
Tôi có 5 dòng lisp sau đây. Hỏi: tại sao dòng 2 và 3 không lỗi mà dòng 4 và 5 bị lỗi.
(setq lay1 "A" lay2 "B") (setq ss1 (ssget (list (cons -4 "<AND") (cons 0 "TEXT") (cons -4 "<OR") (cons 8 lay1) (cons 8 lay2) (cons -4 "OR>") (cons -4 "AND>")))) ;OK (setq ss2 (ssget '((-4 . "<AND") (0 . "TEXT") (-4 . "<OR") (8 . "A") (8 . "B") (-4 . "OR>") (-4 . "AND>")))) ;OK (setq ss3 (ssget '((cons -4 "<AND") (cons 0 "TEXT") (cons -4 "<OR") (cons 8 lay1) (cons 8 lay2) (cons -4 "OR>") (cons -4 "AND>")))) ;NO (setq ss4 (ssget '((-4 . "<AND") (0 . "TEXT") (-4 . "<OR") (8 . lay1) (8 . lay2) (-4 . "OR>") (-4 . "AND>")))) ;NO
chưa hiểu ss2 và ss4?
Ketxu đã nói rất rõ ràng rồi còn gì nhỉ.
- ss4: '((-4 . "<AND") (0 . "TEXT") (-4 . "<OR") (8 . LAY1) (8 . LAY2) (-4 . "OR>") (-4 . "AND>")) => trả về ((-4 . "<AND") (0 . "TEXT") (-4 . "<OR") (8 . LAY1) (8 . LAY2) (-4 . "OR>") (-4 . "AND>"))
List trên không dùng được cho hàm Ssget vì LAY1 và LAY 2 lúc này không phải kiểu chuỗi (string)
- ss3: Cũng tương tự vậy '((cons -4 "<AND") (cons 0 "TEXT") (cons -4 "<OR") (cons 8 lay1) (cons 8 lay2) (cons -4 "OR>") (cons -4 "AND>")))) => trả về ((cons -4 "<AND") (cons 0 "TEXT") (cons -4 "<OR") (cons 8 lay1) (cons 8 lay2) (cons -4 "OR>") (cons -4 "AND>")))) . không có kiểu (cons ...gì gì đó) trong điều kiện lọc filter.
Vậy phải hiểu thế nào:
- Hàm (quote....) - hay còn được viết thay thế bằng '(....)): trả về kết quả đúng như những gì bạn nhập vào nó. các biến và các hàm không được định giá trị trong hàm quote.
đễ dàng nhận thấy nếu bạn thử (setq a 1) -> (quote a) -> trả về a
- Hàm list: khác với hàm quote. tất cả các biến và các biểu thức thực hiện thông qua các hàm trung gian được định giá trị và nó sẽ trả về giá trị của các biến và hàm trung gian.
(setq a 1) -> (list a) -> trả về (1)
- ss2 có thể viết thế này:
(setq ss2 (ssget '((0 . "TEXT") (8 . "A,B"))))
ek! ketxu trả lời nhanh quá nên trả lời này thừa mất rồi
-
2
-
-
Cả 2 đều sai kiểu của đối số:
- vl-catch-all-apply 'vla-delete (list sst)) tại sao có hay không thì cũng không khác nhau: Vì (list sst) không phải kiểu đối số của hàm vla-delete. hàm này không thực hiện được và trả về lỗi. nhưng vì có hàm vl-catch-all-apply nên nó bỏ qua lỗi và chạy tiếp. Nếu không có hàm này, viết dưới dạng (vla-delete (list sst)) chương trình lập tức dừng lại
- (acet-ss-entdel sst) lỗi thông báo rất rõ ràng: bad argument type: lselsetp #<VLA-OBJECT IAcadSelectionSet 2412f104>
Đối số là của nó là tập chọn SelectionSet chứ không phải vla-object SelectionSet.
- Vậy thì tại sao dán cái này (acet-ss-entdel sst) vào command vẫn OK. Vì sst trong hàm con của bạn là VLA-OBJECT AcadSelectionSet nhưng trong chương trình chính bạn đã gắn nó là SelectionSet: (setq sst (ssget)). ngay sau khi hàm con kết thúc thì nó trả giá trị cũ về cho biến sst. tức là khi bạn dán (acet-ss-entdel sst) vào command thì sst đã trở về dạng selection set.
- Tiếp. Nếu đã sử dụng vla-get-activeselectionset thì không cần viết như thế này (setq sst (ssget)). Chỉ cần thế này là đủ (ssget). Hàm vla-get-activeselectionset acdoc sẽ lấy tập hợp chọn lần cuối cùng
Ở trên tôi có nói về việc sử dụng vl-catch-all-apply. Việc sử dụng các hàm vl-catch-* không thể tùy tiện lúc nào cũng sử dụng được. Nó là con dao 2 lưỡi đối với lập trình viên. Trừ khi bạn thành thạo và hiểu rõ về nó cũng như về chương trình của bạn thì hãy dùng, khi đó nó đảm bảo cho chương trình của bạn chạy 1 cách suôn sẻ. Nhưng ngược lại, nếu bạn viết không tốt, bạn rất dễ bị rơi vào trường hợp như trên, không biết chương trình của mình bị lỗi ở đâu, và có khi nó có lỗi đấy, chương trình của bạn vẫn chạy bình thường nhưng bạn không nhận biết được lỗi đã sảy ra, dẫn đến kết quả chạy ra bị sai. nếu chương trình lớn thì việc tìm ra lỗi ở chỗ nào có khi còn vất vả hơn việc viết ra chương trình đó.
-
@ketxu: hồi trước mình nhớ có 1 topic nói về Xrecord trong box autolisp này. Nhưng giờ tìm hoài không thấy. không biết có phải do các mod đã xóa nó đi hay không?
-
Cần phải hiểu:
- Lệnh move hay các hàm move đối tượng chỉ thay đổi các thông tin về tọa độ của đối tượng. nó không fải là việc xóa đối tượng gốc rồi tạo đối tượng mới tại vị trí khác.
- Lệnh copy mà ta thường dùng là kết quả của 2 lệnh hoặc 2 hàm: copy và move. Lệnh copy chỉ tạo ra bản sao (đối tượng hoàn toàn mới nhưng có thông tin giống hệt đối tượng gốc) và tất nhiên nó cũng có cùng tọa độ với bản gốc. lệnh hoặc hàm move sau đó dùng để thay đổi tọa độ của đối tượng được tạo ra.
Nếu (vl-catch-all-apply 'vla-delete.... đã xóa hết đối tượng rồi thì (acet-ss-entdel sst) đưa vào làm gì nữa nhỉ?
thêm nữa. ta thường dùng vl-catch-all-apply kết hợp với vl-catch-all-error để vượt qua lỗi nếu có khả năng sảy ra. trường hợp này dùng nó đâu có ý nghĩa gì đâu
-
1
-
-
Đã tìm ra nguyên nhân:
- Các đối tượng anotative được gắn dữ liệu mở rộng Xdata để phân biệt với các đối tượng bình thường. Chuỗi xác định 1 đối tương anotative là "AcadAnnotative".
- Giống như mọi đối tượng có chứa xdata khác. thông tin về kiểu của nó cần phải được khai báo vào cơ sở dữ liệu của bản vẽ. việc khai báo này được thực hiện thông qua hàm (regapp application) với đối số application là chuỗi xác định kiểu xdata.
ví dụ với các đối tượng của chương trình thiết kế đường Nova tạo ra, nó đăng ký kiểu là "TDNW". Bạn có thể tự tạo cho mình 1 kiểu xdata khi viết phần mềm để phân biệt với các đối tượng của chương trình khác bằng cách này (regapp "TenChuongTrinhCuaBan")
- Ở trường hợp trên thì chỉ cần cho hàm (regapp "AcadAnnotative") tự động thực thi khi mở bản vẽ là được. nếu "AcadAnnotative" đã được khai báo rồi nó trả về nil.
-
1
-
-
- AutoCAD theo dõi và lưu trữ rất chi tiết các hoạt động của người dùng, phần lớn là lưu vào các biến hệ thống. Đơn giản như việc cuộn bánh xe trên chuột để zoom thì nó làm cho biến VIEWSIZE và VIEWCTR thay đổi.
- Nhiều tùy chọn của lệnh cũng làm thay đổi biến hệ thống, ví dụ việc bật chế độ kéo giãn các cạnh trong lệnh Extend, làm cho biến EDGEMODE thay đổi.
- Có một số biến như CDATE, DATE, TDINDWG, TDUSRTIMER (chỉ thời gian) thường xuyên thay đổi dù bạn không làm gì cả.
Mình không biết (vlr-reactors :VLR-SysVar-Reactor) có thể theo dõi được những biến gì, nhưng chắc chắn một số biến đã không được theo dõi bạn ạ!
Tất nhiên bạn không thể thay đổi các biến hệ thống Chỉ cho phép đọc (Read-Only)
Vlr-SysVar-Reactor chỉ theo dõi các biến hệ thống mà người dùng có thể được phép tùy biến. dễ dàng nhận ra điều này mà bạn, đây là nguyên tắc bắt buộc để đảm bảo cad hoạt đông trơn tru và không bị treo do lỗi cố ý của người dùng.
Lưu ý các bạn. Lisp mình post bên trên có thể thông báo sự thay đổi của biến hệ thống tại bất kỳ thời điểm nào biến hệ thống bị thay đổi. Nó có thể thông báo sự thay đổi ngay cả khi lệnh của bạn đang trong quá trình thực hiện. Điều này rất quan trọng để dùng cho mục đích tham khảo.
Với cách làm của bác Hà thì ta chỉ biết được sự thay đổi giữa 2 thời điểm: trước và sau khi thực hiện xong 1 lệnh. còn lệnh đó đã tác động đến những biến nào thì chịu
-
1
-
-
Đôi khi ta cần biết những biến hệ thống nào đã bị thay đổi trong và sau khi thực hiện 1 lệnh nào đó trong quá trình vẽ. Việc lấy ra danh sách giá trị của tất cả biến hệ thống trước và sau khi thực hiện lệnh rồi so sánh thực sự vất vả mà kết quả không được đây đủ chi tiết nếu bạn lấy không đủ danh sách biến.
Lisp này có tác dụng theo dõi và thống kê cho bạn biết những biến hệ thống nào của cad đã bị thay đổi khi thực hiện 1 lệnh cad, 1 lệnh lisp hay bất kỳ lệnh nào gây ra sự thay đổi biến hệ thống, đồng thời ghi ra luôn giá trị trước và sau khi thay đổi là bao nhiêu để bạn nắm được sự thay đổi đó.
;;;Copyright 2012 Thaistreetz from Cadviet.com (defun C:RSV nil (if (vlr-reactors :VLR-SysVar-Reactor) (and (vlr-remove-all :VLR-SysVar-Reactor) (prompt "<< Da Tat che do theo doi bien he thong >>")) (and (vlr-sysvar-reactor "Sysvar Reactor: Sysvar Change" '((:vlr-sysvarwillchange . callback-sysvarchang) (:vlr-sysvarchanged . callback-sysvarchang))) (prompt "<< Da Bat che do theo doi bien he thong >>"))) (princ)) (defun callback-sysvarchang (reactor sysvar) (if (= (vlr-current-reaction-name) :vlr-sysvarwillchange) (setq *sysvar* (getvar (car sysvar))) (if (not (equal *sysvar* (getvar (car sysvar)))) (progn (princ (strcat "\n" (car sysvar) " : <" )) (princ *sysvar*) (princ ">") (princ " ----> <" ) (princ (getvar (car sysvar))) (princ ">")))))
Lưu ý: Hiện tại lisp này không nhận biết được sự thay đổi biến hệ thống qua việc thay đổi các lựa chọn trong hộp thoại Option của cad nhé. Mình dùng cad 2010 nó không nhận. các bản Cad khác thì mình chưa thử. Còn với command hay các lệnh lisp hoặc lệnh tạo bằng các ngôn ngữ khác nó nhận biết bình thường.
Bạn có thể bật hoặc tắt chế độ theo dõi bằng 1 lệnh duy nhất là RSV (reactor Sysvar)
Có thể cũng bạn quan tâm: Lisp so sánh sự khác nhau giữa các biến hệ thống của 2 bản vẽ
-
9
-
-
mình tạo 1 annotative style bằng hàm entmake như sau:
(defun makestyle:20-arial-t nil
(entmakex '((0 . "STYLE")(100 . "AcDbSymbolTableRecord")(100 . "AcDbTextStyleTableRecord")
(2 . "2.0Arial")(70 . 0)(40 . 0.002)(41 . 1.0)(50 . 0.0)(71 . 0)(42 . 0.002)(3 . "VNARIAL.ttf")(4 . "")
(-3 ("ACAD" (1000 . ".VnArial") (1071 . 34)) ("AcadAnnotative" (1000 . "AnnotativeData")(1002 . "{")(1070 . 1)(1070 . 1)(1002 . "}"))))))
Tuy nhiên nó chỉ chạy trơn chu trên bản vẽ được khởi tạo bằng các bản cad có hỗ trợ chức năng này. (2008 trở lên)
Với các bản vẽ được khởi tạo bằng cad đời thấp, đem mở bằng cad đời cao và chạy hàm trên thì nó không chịu nhả ra kết quả. Mình bắt buộc fải tạo ra 1 đối tượng nào đó có gắn annotative (bằng command) thì từ đó hàm trên mới chạy được.
=> KL: Các bản cad đời cao đã không tự động tải 1 thông tin gì đó liên quan đến annotative object khi mở các bản cad không fải do nó tạo ra. Thông tin đó chỉ được tải vào bản vẽ khi lần đầu tiên có 1 đối tượng annotative được tạo.
Có bác nào vấp phải vấn đề này chưa? Thông tin bị thiếu liên quan đến annotative là gì? làm thế nào để nó tự động tải khi mờ các bản vẽ của cad đời thấp.
Ps: mình kiểm tra các arx đã được tải vào bản vẽ, trước và sau khi chạy được hàm trên là như nhau nên có thể loại trừ nguyên nhân này.
-
1
-
-
được rùi ah.
Ctrl V lun không thấy j bác nhỉ? hjjj
e vẫn phải dùng tới F2 bôi đen rùi Ctrl C, rùi ed mtext rùi mới Ctrl V.
bạn thử copy cái này (vl-load-com) rồi paste vào command. xong rồi chạy lại lệnh. nếu Ctrl+V mà ra được thì đưa nó vào lisp luôn.
Làm như trên thì bạn thừa bước edit mtext. mặc định khi nhấn Ctrl+V trong cad thì nó sẽ tạo luôn đối tượng Mtext chứa nội dung trong Clipboard cho bạn.
-
e cám ơn bác. cho e hỏi, làm thế nào để rút bớt số chữ số thập phân sau dấu phẩy của thông số bán kính R khi dùng lisp này từ 4 về 2 con số thui ah?
thay
(rtos (setq R (cdr (assoc 40 ent))))
bằng
(rtos (setq R (cdr (assoc 40 ent))) 2 2)
-
Mình viết tạm cho bạn thế này thôi. ngại viết code lập bảng lắm.
Khi dùng, Chọn xong đường tròn sẽ thấy báo kết quả ở dòng command. nhấn tiếp Ctrl+V là được (không cần fải copy từ command nhá). Cũng không khác việc lập bảng là mấy..
(defun c:ytc (/ SetClipBoardText ytc-g i a r en ent) (defun SetClipBoardText (text / htmlfile result ) ; By XShrimp (if (= 'STR (type text)) (progn (setq htmlfile (vlax-create-object "htmlfile") result (vlax-invoke(vlax-get(vlax-get htmlfile'ParentWindow)'ClipBoardData)'SetData "Text" text )) (vlax-release-object htmlfile) text))) (defun ytc-g (goc / gd gp gs ) (setq Gd (fix Goc) Gp (fix (* (- Goc Gd) 60)) Gs (* (- (* (- Goc Gd) 60) Gp) 60)) (strcat (if (< Gd 10) (strcat "0" (rtos Gd 2 0)) (rtos Gd 2 0)) "d" (if (< Gp 10) (strcat "0" (rtos Gp 2 0)) (rtos Gp 2 0)) "'" (if (< Gs 9.5) (strcat "0" (rtos Gs 2 0)) (rtos Gs 2 0)) "''")) (and (setq i (getint "nhap ten duong cong (nhap so):")) (setq i (itoa i)) (not (while (not (and (setq en (car (entsel "\n chon duong can lay yeu to cong:\n"))) (wcmatch (cdr (assoc 0 (setq ent (entget en)))) "ARC"))))) (setq a (* (vlax-get-property (vlax-ename->vla-object en) 'TotalAngle) 0.5)) (SetClipBoardText (princ (strcat "A" i " = " (ytc-g (+ (/ (* (- pi a a) 180.) pi) 0.00002)) "\nR" i " = " (rtos (setq R (cdr (assoc 40 ent)))) "m" "\nT" i " = " (rtos (/ (* R (sin a)) (cos a)) 2 2) "m" "\nP" i " = " (rtos (- (/ R (cos a)) R) 2 2) "m" "\nK" i " = " (rtos (vlax-curve-getDistAtParam en (vlax-curve-getEndParam en)) 2 2) "m")))) (princ))
-
1
-
-
1 obj_reactor có owner chứa danh sách objname của các đối tượng mà nó liên kết. Vậy có cách nào thêm hoặc bớt objname vào danh sách này không?
Hàm vlr-owner-remove: (vlr-owner-remove obj_reactor notifier-object) không làm được điều này hoặc có thể mình đã hiểu sai cách thức sử dụng nó. Cụ thể:
- Mình gắn cho đối tượng 1 rector theo dỗi sự kiện đối tượng bị xóa.
- Rector này gọi tới hàm callback thực hiện hàm: (setq obj_reactor (vlr-owner-remove obj_reactor notifier-object)) (ở đây hàm callback gắn objname của đối tượng bị xóa cho đối số notifier-object)
- Sau khi thực hiện xong việc xóa đối tượng, nghĩa là hàm callback trên đã được thực hiện, kiểm tra lại owner của obj_reactor vẫn thấy tồn tại objname của đối tượng đã xóa trên.
Bác Gia_Bach hay bác nào nắm vững về rector trợ giúp mình với.
Mục đích của mình là tạo hàm callback gắn với sự kiện đối tượng bị xóa. nếu đối tượng bị xóa chứa 1 rector nào đó thì hàm tự động loại bỏ rector của nó trước khi xóa, nhưng không loại bỏ liên kết của các đối tượng khác cùng nhóm liên kết với nó.
[Hỏi] Lisp chọn tập hợp đối tượng gần nhất được sinh ra bởi 1 lênh.
trong AutoLisp
Đã đăng · Trả lời báo cáo
Nếu như chỉ cần kết quả như bạn đã làm thì vấn đề lại khá đơn giản, mình làm được bằng lisp, nhưng nó không phải là cái mà mình muốn. Có lẽ mình cần phải nói rõ hơn về ý định viết lệnh này của mình để các bác không bị lạc hướng đi nữa nhé:
- trong quá trình vẽ mình có nhu cầu chọn được tập hợp đối tượng cuối cùng được sinh ra bởi 1 lệnh trước đó.
- tập hợp đối tượng cuối cùng được sinh ra phải được hiểu là tập hợp được sinh ra bởi 1 lệnh duy nhất (cái của bạn là của rất nhiều lệnh tính từ thời điểm tập hợp đối tượng chọn của bạn ở trạng thái rỗng. thực tế, chúng ta không có nhu đó trong khi vẽ).
- 1 lệnh trước đó: Phải được hiểu là lệnh cuối cùng có phát sinh đối tượng mới chứ không nhất thiết phải là lệnh cuối cùng.
ví dụ đơn giản để minh họa:
1. bạn bạn dùng lệnh line để vẽ 1 line: bản vẽ có 1 line
2. bạn dùng lệnh copy để copy line đó thành 2 line: bản vẽ có 3 line (2 đối tượng đươc tạo mới)
3. bạn lại dùng lệnh copy 1 lần nữa để copy 2 line mới đó thành 4 line mới: bản vẽ có 7 line (4 đối tượng được tạo mới)
4. tiếp theo bạn dùng rất nhiều lênh khác, nhưng không có phát sinh đối tượng mới.
5. lúc này bạn có nhu cầu sử dụng 4 đối tượng line ở bước 3. chỉ việc gõ lệnh lệnh trên là chọn được: Tập hợp cuối cùng là 4 đối tượng được tạo bởi lệnh copy ở bước 3.
Yêu cầu bắt buộc của lệnh mình muốn viết: bất kể lúc nào người dùng cần, chỉ cần gõ lệnh là chọn được tập hợp đối tượng mới tạo mà không cần phải thủ công xác định điểm mốc.