Chuyển đến nội dung
Diễn đàn CADViet
Jin Yong

Hỏi về Lisp (thuật toán, ý tưởng, coding,...)

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

Hình như bạn chưa hiểu bài viết của giabach thì phải.

Cái bạn muốn làm mình không hiểu cách tư duy của bạn.

Chỉ cần sửa dòng này là xong mà!

(command "rectangle" (list (- (car ul) 100) (+ (cadr ul) 50)) (list (+ (car lr) 100) (- (cadr lr) 50)))

 

 

Chào anh Duy.

Em đã sửa như dòng dưới mà không hiểu sao khoảng cách 50 100 thì đúng còn tổng khoảng cách 350 thì không đúng, nó lại ra 366.

(command "rectangle" (list (- (car ul) (+ 100 27)) (+ (cadr ul) (+ 50 33))) (list (+ (car lr) (+ 100 27)) (- (cadr lr) (+ 50 33))))

http://www.cadviet.com/upfiles/Drawing1_29.dwg

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ào anh Duy.

Em đã sửa như dòng dưới mà không hiểu sao khoảng cách 50 100 thì đúng còn tổng khoảng cách 350 thì không đúng, nó lại ra 366.

(command "rectangle" (list (- (car ul) (+ 100 27)) (+ (cadr ul) (+ 50 33))) (list (+ (car lr) (+ 100 27)) (- (cadr lr) (+ 50 33))))

http://www.cadviet.com/upfiles/Drawing1_29.dwg

Chào bạn Tuan_thietkedien,

Hôm nay mình mới đọc bài pót của bạn. Về cơ bản mình thấy ý kiến của bác Giabach là hoàn toàn đúng. Việc bạn chỉnh lại lisp như vậy thực ra mới chỉ là chỉnh lại kích thước của khung theo kích thước truy xuất của hàm textbox chứ chưa phải theo tọa độ điểm chèn text. Rất có thể do người viết font tiếng Anh và người viết font tiếng Nhật có quan điểm khác nhau khi chọn điểm chèn text nên nó xảy ra tình trạng như vậy.

Bạn lưu ý kỹ trên bản vẽ của bạn sẽ thấy các kích thước từ điểm giới hạn text được truy xuất bởi hàm textbox trong hai trường hợp này có khác nhau do việc chọn điểm chèn text của người viết font.

Do vậy nếu bạn muốn vẽ khung bao text đúng với kích thước mà bạn dự định thì bạn phải test đối với từng loại font mà bạn sử dụng chứ không thể chỉ 1 lisp mà giải quyết cho tất cả các font được.

Về lisp của bạn, theo mình thì không cần thiết phải sử dụng các biến u1 và 1r vì tất cả các tọa độ bạn cần sử dụng đều đã có sẵn từ biến 1l và ur rồi. Bạn chỉ cần lưu ý chọn đúng nó ở trong hàm vẽ khung Rectangle là được.

Còn về con số 366 nó là đương nhiên vì trước khi bạn chỉnh lisp nó đã là 300, sau khi chỉnh bạn thêm vào cả trên và dưới là 33 thì phải ra 366 chứ chạy vào đâu được. Nếu bạn muốn nó đúng 350 thì cái kích thước 50 của bạn sẽ chỉ còn 42 là do sự khác nhau về điểm chèn text của người viết font.

Mình cũng không biết cách nào để có thể làm đúng hết như ý bạn được vì chả biết cái ý của người viết font này ra sao cả. Bạn hãy tự chọn cho mình cái gì là thuận lợi nhất.

Chúc bạn vui và thành công.

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ào bạn Tuan_thietkedien,

Hôm nay mình mới đọc bài pót của bạn. Về cơ bản mình thấy ý kiến của bác Giabach là hoàn toàn đúng. Việc bạn chỉnh lại lisp như vậy thực ra mới chỉ là chỉnh lại kích thước của khung theo kích thước truy xuất của hàm textbox chứ chưa phải theo tọa độ điểm chèn text. Rất có thể do người viết font tiếng Anh và người viết font tiếng Nhật có quan điểm khác nhau khi chọn điểm chèn text nên nó xảy ra tình trạng như vậy.

Bạn lưu ý kỹ trên bản vẽ của bạn sẽ thấy các kích thước từ điểm giới hạn text được truy xuất bởi hàm textbox trong hai trường hợp này có khác nhau do việc chọn điểm chèn text của người viết font.

Do vậy nếu bạn muốn vẽ khung bao text đúng với kích thước mà bạn dự định thì bạn phải test đối với từng loại font mà bạn sử dụng chứ không thể chỉ 1 lisp mà giải quyết cho tất cả các font được.

Về lisp của bạn, theo mình thì không cần thiết phải sử dụng các biến u1 và 1r vì tất cả các tọa độ bạn cần sử dụng đều đã có sẵn từ biến 1l và ur rồi. Bạn chỉ cần lưu ý chọn đúng nó ở trong hàm vẽ khung Rectangle là được.

Còn về con số 366 nó là đương nhiên vì trước khi bạn chỉnh lisp nó đã là 300, sau khi chỉnh bạn thêm vào cả trên và dưới là 33 thì phải ra 366 chứ chạy vào đâu được. Nếu bạn muốn nó đúng 350 thì cái kích thước 50 của bạn sẽ chỉ còn 42 là do sự khác nhau về điểm chèn text của người viết font.

Mình cũng không biết cách nào để có thể làm đúng hết như ý bạn được vì chả biết cái ý của người viết font này ra sao cả. Bạn hãy tự chọn cho mình cái gì là thuận lợi nhất.

Chúc bạn vui và thành công.

 

Cám ơn thanhbinh đã góp ý nha. :cheers:

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ào mọi người.

 

Các bác cho em hỏi 2 vấn đề

 

1 - Cái lisp giãn dòng text với kích thước là 500 này chạy không như ý muốn, xin các bác góp ý dùm

 

http://www.cadviet.com/upfiles/Drawing1_31.dwg

 

http://www.cadviet.com/upfiles/new_2.lsp

 

2 - Khi muốn lấy điểm chèn block có thể sử dụng đoạn code sau hay không?

(setq dt (ensel))

(setq diemchen (cdr (assoc 10 dt)))

 

Cám ơn các bác nhiều lắm.

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
2 - Khi muốn lấy điểm chèn block có thể sử dụng đoạn code sau hay không?

(setq dt (ensel))

(setq diemchen (cdr (assoc 10 dt)))

 

Cám ơn các bác nhiều lắm.

Oài :cheers:

- Hàm entsel cho ra kết quả là (ename, điểm ta pick chuột). không tin bạn có thể đánh ngay dòng lệnh (entsel) ngay ngoài command thì bít. Đây là cái bạn hiểu sai về bản chất.

-Nó ra kết quả không hề có dạng(ename (10 x y z)) mà chỉ là (ename (x y z)). cho nên bạn dùng hàm (assoc 10 dt) là vô ích . Cái này bạn hiểu sai về cấu trúc dữ liệu được cho ra bởi hàm entsel.

=> sửa lại cho đúng là:

(setq dt (ensel))

(setq diemchen (cdr (assoc 10 (entget (car dt))))

Giải thích:

(car dt)->lấy ename của đối tượng pick

(entget (car dt ))-> lấy cấu trúc dữ liệu của ename . Điểm chèn sẽ có dạng (10 x y z)

(cdr (assoc 10 (entget (car dt))))-> lấy ra tọa độ (x y z) từ (10 x y z)

Mịn chưa :cheers:

  • 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
Chào mọi người.

 

Các bác cho em hỏi 2 vấn đề

 

1 - Cái lisp giãn dòng text với kích thước là 500 này chạy không như ý muốn, xin các bác góp ý dùm

 

http://www.cadviet.com/upfiles/Drawing1_31.dwg

 

http://www.cadviet.com/upfiles/new_2.lsp

 

2 - Khi muốn lấy điểm chèn block có thể sử dụng đoạn code sau hay không?

(setq dt (ensel))

(setq diemchen (cdr (assoc 10 dt)))

 

Cám ơn các bác nhiều lắm.

Chào bạn Tuan_thietkedien,

Mình chạy thử lisp của bạn thì thấy nó xếp hàng nghiêm chỉnh lắm chứ không thấy như cái kết quả bạn post. Chỉ có điều các text không sắp xếp đúng theo thứ tự từ 1 đến 7 mà thôi.

Điều này có thể do bạn nhập text không đúng với thứ tự lựa chọn của hàm ssget. Text1 không phải là phần tử thứ nhất trong tập ss. Các text khác cũng vậy.

Việc kết quả của bạn bị lộn xộn có khả năng do bạn chưa tắt biến hệ thống osmode nên nó truy bắt điểm sai mà thôi. Tốt nhất bạn nên tắt tất cả các biến hệ thống này trong quá trình ứng dụng lisp bạn ạ.

Cái kết quả mình chạy ra đây:

http://www.cadviet.com/upfiles/Drawing2_11.dwg

 

Còn câu hỏi thứ hai của bạn thì hoàn toàn được nhưng mình chưa hiểu bạn sử dụng điểm chèn này vào việc gì??? Và do bạn dùng hàm entsel để chọn đối tượng nên bạn cần có thêm bước kiểm tra xem đối tượng có phải là block hay không thì sẽ tốt hơn và tránh được nhầm lẫn.

 

À lưu ý bạn là trong lisp của bạn, do bạn đặt (setq dm (list (car dc) (+ (cadr dc) (* i 500)))) nên các text sẽ được sắp xếp từ dưới lên trên, mình đã đổi hàm (+ (cadr dc) (* i 500)) thành (- (cadr dc) (* i 500)) thì nó sẽ xếp theo thứ tự từ trên xuống bắt đầu từ điểm chọn bạn ạ.

 

Rất mừng là bạn đã thành công bước đầu trong việc ứng dụng lisp vào chuyên môn.

Chúc bạn khỏe và tiến bộ nhiều.

  • 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
Oài :cheers:

- Hàm entsel cho ra kết quả là (ename, điểm ta pick chuột). không tin bạn có thể đánh ngay dòng lệnh (entsel) ngay ngoài command thì bít. Đây là cái bạn hiểu sai về bản chất.

-Nó ra kết quả không hề có dạng(ename (10 x y z)) mà chỉ là (ename (x y z)). cho nên bạn dùng hàm (assoc 10 dt) là vô ích . Cái này bạn hiểu sai về cấu trúc dữ liệu được cho ra bởi hàm entsel.

=> sửa lại cho đúng là:

(setq dt (ensel))

(setq diemchen (cdr (assoc 10 (entget (car dt))))

Giải thích:

(car dt)->lấy ename của đối tượng pick

(entget (car dt ))-> lấy cấu trúc dữ liệu của ename . Điểm chèn sẽ có dạng (10 x y z)

(cdr (assoc 10 (entget (car dt))))-> lấy ra tọa độ (x y z) từ (10 x y z)

Mịn chưa :cheers:

 

Hihi..Cúm ơn bác natca nhiều nhé, hèn chi nhiều lúc nhìn mấy đoạn code của các bác viết lúc dùng entsel, lúc dùng entget bây giờ mới hiểu rõ. :s_big:

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ào bạn Tuan_thietkedien,

Mình chạy thử lisp của bạn thì thấy nó xếp hàng nghiêm chỉnh lắm chứ không thấy như cái kết quả bạn post. Chỉ có điều các text không sắp xếp đúng theo thứ tự từ 1 đến 7 mà thôi.

Điều này có thể do bạn nhập text không đúng với thứ tự lựa chọn của hàm ssget. Text1 không phải là phần tử thứ nhất trong tập ss. Các text khác cũng vậy.

Việc kết quả của bạn bị lộn xộn có khả năng do bạn chưa tắt biến hệ thống osmode nên nó truy bắt điểm sai mà thôi. Tốt nhất bạn nên tắt tất cả các biến hệ thống này trong quá trình ứng dụng lisp bạn ạ.

Cái kết quả mình chạy ra đây:

http://www.cadviet.com/upfiles/Drawing2_11.dwg

 

Còn câu hỏi thứ hai của bạn thì hoàn toàn được nhưng mình chưa hiểu bạn sử dụng điểm chèn này vào việc gì??? Và do bạn dùng hàm entsel để chọn đối tượng nên bạn cần có thêm bước kiểm tra xem đối tượng có phải là block hay không thì sẽ tốt hơn và tránh được nhầm lẫn.

 

À lưu ý bạn là trong lisp của bạn, do bạn đặt (setq dm (list (car dc) (+ (cadr dc) (* i 500)))) nên các text sẽ được sắp xếp từ dưới lên trên, mình đã đổi hàm (+ (cadr dc) (* i 500)) thành (- (cadr dc) (* i 500)) thì nó sẽ xếp theo thứ tự từ trên xuống bắt đầu từ điểm chọn bạn ạ.

 

Rất mừng là bạn đã thành công bước đầu trong việc ứng dụng lisp vào chuyên môn.

Chúc bạn khỏe và tiến bộ nhiều.

 

 

Bác thanhbinh nói không sai tí nào, cao thủ cao thủ..hihi. Mà làm sao bác biết được nguyên nhân vậy kà??? :cheers:

Chúc bác luôn vui vẻ nhé.

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ào bạn Tuan_thietkedien,

Mình chạy thử lisp của bạn thì thấy nó xếp hàng nghiêm chỉnh lắm chứ không thấy như cái kết quả bạn post. Chỉ có điều các text không sắp xếp đúng theo thứ tự từ 1 đến 7 mà thôi.

Điều này có thể do bạn nhập text không đúng với thứ tự lựa chọn của hàm ssget. Text1 không phải là phần tử thứ nhất trong tập ss. Các text khác cũng vậy.

Việc kết quả của bạn bị lộn xộn có khả năng do bạn chưa tắt biến hệ thống osmode nên nó truy bắt điểm sai mà thôi. Tốt nhất bạn nên tắt tất cả các biến hệ thống này trong quá trình ứng dụng lisp bạn ạ.

Tắt osmode trước khi gọi command (chịu ảnh hưởng của osmode) là đúng rồi. Riêng ss nhận được từ ssget thì có vài vấn đề cần lưu ý:

 

1. Khi user pick chọn lần lượt "từng chú" một (theo dòng nhắc "Select Objects:") -> thứ tự các entity trong ss theo đúng thứ tự pick chọn.

 

2. Khi user chọn "một phát" bằng window -> thứ tự entity ngược với thứ tự hình thành hoặc edit entity (chú nào sinh ra sau hoặc được sửa đổi sau sẽ đứng trước)

 

3. Ta không thể buộc user phải pick "từng chú" như trường hợp 1. Thói quen hợp lý của user là nếu có thể thì chọn một phát bằng window như trường hợp 2. Nói chung, ta không thể biết được chú nào sinh ra trước, chú nào sinh ra sau, chú nào vừa bị edit... Tóm lại, việc xác định tính thứ tự của một tập đối tượng nhận được từ ssget là không lường trước được.

 

Biện pháp giải quyết triệt để là:

1. Chuyển ss thành list (bằng hàm ss2ent của anh Hoành)

2. Dùng vl-sort, kết hợp lambda để sắp xếp các phần tử trong list theo quy luật nào đó (quy luật do người lập trình tự định nghĩa bằng hàm khuyết danh lambda). Trong ví dụ này, có thể sort theo tiêu chí "tung độ điểm chèn text từ thấp đến cao".

3. Dùng foreach cho list. Trong vòng foreach, muốn tác vụ nào đó tuỳ ý, thứ tự thực hiện sẽ đúng như thứ tự của các phần tử trong list.

 

Các bạn có thể vào Help, hoặc search trên diễn đàn với từ khoá vl-sort và lambda để xem thêm nhiều ví dụ. Nếu có vướng mắc gì thì nêu lên, anh em sẽ hỗ trợ thêm.

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
3. Ta không thể buộc user phải pick "từng chú" như trường hợp 1. Thói quen hợp lý của user là nếu có thể thì chọn một phát bằng window như trường hợp 2. Nói chung, ta không thể biết được chú nào sinh ra trước, chú nào sinh ra sau, chú nào vừa bị edit... Tóm lại, việc xác định tính thứ tự của một tập đối tượng nhận được từ ssget là không lường trước được.

 

Đối tượng nào sinh ra trước hay sau có thể biết được đấy. Dựa vào giá trị Handle của đối tượng. Cái nào sinh ra sau sẽ có Handle lớn hơn. Việc edit không làm thay đổi Handle ngọai trừ việc dùng EXPLODE

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
Đối tượng nào sinh ra trước hay sau có thể biết được đấy. Dựa vào giá trị Handle của đối tượng. Cái nào sinh ra sau sẽ có Handle lớn hơn. Việc edit không làm thay đổi Handle ngọai trừ việc dùng EXPLODE

Cám ơn bạn đã "nhắc bài"! Trong lisp, dùng DXF 5 sẽ lấy được handle. Tuy nhiên, ssg đã xem lại, tính thứ tự của selection set trong một số trường hợp cũng không tuân theo quy luật mà ssg nêu trên (có vẻ như nó lấy "tuỳ hứng", hoặc là mình chưa hiểu hết quy luật). Mặt khác, thực hiện tác vụ theo tiêu chí sinh ra trước hay sinh ra sau, trong rất nhiều trường hợp không phải là ý muốn của user.

Tính thứ tự mà ssg đề cập trong dòng in đậm trên có ý nghĩa là tính thứ tự thực hiện tác vụ mà user muốn trong từng trường hợp cụ thể. Dù có phân tích kiểu gì đi nữa, chuyển ss sang list và dùng vl-sort là phương pháp hợp lý và hiệu quả.

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
Cám ơn bạn đã "nhắc bài"! Trong lisp, dùng DXF 5 sẽ lấy được handle. Tuy nhiên, ssg đã xem lại, tính thứ tự của selection set trong một số trường hợp cũng không tuân theo quy luật mà ssg nêu trên (có vẻ như nó lấy "tuỳ hứng", hoặc là mình chưa hiểu hết quy luật). Mặt khác, thực hiện tác vụ theo tiêu chí sinh ra trước hay sinh ra sau, trong rất nhiều trường hợp không phải là ý muốn của user.

Tính thứ tự mà ssg đề cập trong dòng in đậm trên có ý nghĩa là tính thứ tự thực hiện tác vụ mà user muốn trong từng trường hợp cụ thể. Dù có phân tích kiểu gì đi nữa, chuyển ss sang list và dùng vl-sort là phương pháp hợp lý và hiệu quả.

 

Nó tăng dần theo hệ số 16

 

0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F

 

VD: 8B -> 8C -> 8D -> 8E -> 8F -> 90 -> 91 -> 92...->9F ->A0...

  • 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
Nó tăng dần theo hệ số 16

 

0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F

 

VD: 8B -> 8C -> 8D -> 8E -> 8F -> 90 -> 91 -> 92...->9F ->A0...

Số hecxa thì ssg biết rồi. Vấn đề là hàm ssget nó không theo như vậy! Bạn cứ thử khắc biết...

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
Còn câu hỏi thứ hai của bạn thì hoàn toàn được nhưng mình chưa hiểu bạn sử dụng điểm chèn này vào việc gì???

 

Để trả lời bạn thanhbinh, mình up lisp bố trí đèn, do không giỏi về lisp nên viết hơi rắc rối, lủng củng, mong các bác xem rồi phân tích khuyết điểm, đơn giản được công đoạn nào thì đúng là tuyệt.

 

http://www.cadviet.com/upfiles/1_4.rar

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
Để trả lời bạn thanhbinh, mình up lisp bố trí đèn, do không giỏi về lisp nên viết hơi rắc rối, lủng củng, mong các bác xem rồi phân tích khuyết điểm, đơn giản được công đoạn nào thì đúng là tuyệt.

 

http://www.cadviet.com/upfiles/1_4.rar

Xin lỗi bạn Tuan_thietkedien,

Mình đã đọc lisp của bạn , thấy bạn xài nhiều biến hệ thống quá mà thú thực là mình chửa rành hết mấy thằng cu này. Để mình tìm hiểu thêm đã rồi mới góp ý được. Tuy nhiên bạn đã xài mà thấy ổn là Ok. việc cải tiến nó tính sau đi.

Có hai chỗ mình chưa hiểu lắm:

1/- Vì sao bạn lại phải vẽ rectangle rồi lại explore nó để có d1 và d2. Như vậy hơi phiền hà. Theo mình bạn đã có r1 và r2 thì chỉ cần dùng các lệnh đơn giản là (command "line" r1 '((car r1) (cadr r2)) "") và (command "line" r1 '((car r2) (cadr r1)) "") là bạn đã có hai cạnh như ý rồi. Từ đó bạn thoải mái chọn để có d1 và d2. Bạn thử xem nhé.

 

2/- Mình chưa hiểu cách chọn điểm p1 và p2 của bạn. Chọn tùy ý à? Hay là chọn theo một yêu cầu nào đó của bạn? Mối liên hệ giữa p1, p2 và các điểm r1, r2 , td ....??? Theo mình nghĩ thì nó phải có ràng buộc chi đó chứ không thể tùy tiện được và bạn nên có cái ràng buộc nó.

 

Khi viết một chương trình bạn nên phân biệt rõ các biến cho trước và các biến lệ thuộc khác. Ví dụ như trong lisp này, nếu p1 và p2 là tùy ý cho trước thì bạn nên nhập nó vào ngay sau khi nhập r1 và r2. Cũng như với các biến md, gq , bạn cũng nên cho trước vào một rọ với các biến hd và hn.

Như vậy sẽ dễ theo dõi và quản lý nó hơn.

 

Bạn nên cấu trúc chương trình thành từng nhiệm vụ độc lập sẽ dễ theo dõi hơn là viết theo cách liền tù tì thế này.

Ví dụ: Phần nhập dữ liệu - Phần xử lý dữ liệu số - Phần xử lý từng nhiệm vụ - Phần ghi và hiển thị kết quả .

Chúc bạn thành công.

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
Xin lỗi bạn Tuan_thietkedien,

Mình đã đọc lisp của bạn , thấy bạn xài nhiều biến hệ thống quá mà thú thực là mình chửa rành hết mấy thằng cu này. Để mình tìm hiểu thêm đã rồi mới góp ý được. Tuy nhiên bạn đã xài mà thấy ổn là Ok. việc cải tiến nó tính sau đi.

Có hai chỗ mình chưa hiểu lắm:

1/- Vì sao bạn lại phải vẽ rectangle rồi lại explore nó để chọn d1 và d2. Như vậy hơi phiền hà. Theo mình bạn đã có r1 và r2 thì chỉ cần dùng lệnh đơn giản là (setq d1 (command "line" r1 '((car r1) (cadr r2)))) và (setq d2 (command "line" r1 '((car r2) (cadr r1)))) là bạn đã có d1 và d2 như ý rồi. Bạn thử xem nhé.

2/- Mình chưa hiểu cách chọn điểm p1 và p2 của bạn. Chọn tùy ý à? Hay là chọn theo một yêu cầu nào đó của bạn? Mối liên hệ giữa p1, p2 và các điểm r1, r2 , td ....??? Theo mình nghĩ thì nó phải có ràng buộc chi đó chứ không thể tùy tiện được và bạn nên có cái ràng buộc nó.

 

Khi viết một chương trình bạn nên phân biệt rõ các biến cho trước và các biến lệ thuộc khác. Ví dụ như trong lisp này, nếu p1 và p2 là tùy ý cho trước thì bạn nên nhập nó vào ngay sau khi nhập r1 và r2. Cũng như với các biến md, gq , bạn cũng nên cho trước vào một rọ với các biến hd và hn.

Như vậy sẽ dễ theo dõi và quản lý nó hơn.

 

Bạn nên cấu trúc chương trình thành từng nhiệm vụ độc lập sẽ dễ theo dõi hơn là viết theo cách liền tù tì thế này.

Ví dụ: Phần nhập dữ liệu - Phần xử lý dữ liệu số - Phần xử lý từng nhiệm vụ - Phần ghi và hiển thị kết quả .

Chúc bạn thành công.

 

Câu 1 để mình xem lại nhé.

Cấu 2 : đầu tiên mình muốn insert cái đèn màu vàng trong vùng màu vàng trước, sau đó mới array. Do mình không rành lisp lắm nên chưa biết cách ràng buộc biến, nếu là người lạ chắc có lẽ không dùng được vì không hiểu rõ trình tự bắt điểm. Mình cũng đang cố học thêm tí nữa để làm theo như bạn gợi ý.

http://www.cadviet.com/upfiles/BAN_VE_1.dwg

Để mình phân cái lisp này lại rồi up lên sau nhé.

Cám ơn bạn thanhbinh nhiều lắm.

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
1/- Vì sao bạn lại phải vẽ rectangle rồi lại explore nó để có d1 và d2. Như vậy hơi phiền hà. Theo mình bạn đã có r1 và r2 thì chỉ cần dùng các lệnh đơn giản là (command "line" r1 '((car r1) (cadr r2)) "") và (command "line" r1 '((car r2) (cadr r1)) "") là bạn đã có hai cạnh như ý rồi. Từ đó bạn thoải mái chọn để có d1 và d2. Bạn thử xem nhé.

 

Mình up trước đoạn code chia đoạn thẳng theo ý bạn thanhbinh

 

(defun c:thu()

(setq r1 (getpoint))

(setq r2 (getcorner r1))

(setq r12 (list (car r1) (cadr r2)))

(setq r21 (list (car r2) (cadr r1)))

(command "line" r1 r12 "")

(setq d1 (entlast))

(command "line" r1 r21 "")

(setq d2 (entlast))

(command "divide" d1 5)

(command "divide" d2 10)

(command "erase" d1 d2 "")

)

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ình up trước đoạn code chia đoạn thẳng theo ý bạn thanhbinh

 

(defun c:thu()

(setq r1 (getpoint))

(setq r2 (getcorner r1))

(setq r12 (list (car r1) (cadr r2)))

(setq r21 (list (car r2) (cadr r1)))

(command "line" r1 r12 "")

(setq d1 (entlast))

(command "line" r1 r21 "")

(setq d2 (entlast))

(command "divide" d1 5)

(command "divide" d2 10)

(command "erase" d1 d2 "")

)

Chào bạn tuan_thietkedien,

Ở đoạn lisp này biến d1, d2 của bạn có khác đi so với lisp cũ. Ở đây biến d1 và d2 là các ename thôi, còn trong lisp cũ thì biến d1 và d2 là các list bao gồm cả ename và tọa độ điểm chọn. Dùng như trong lisp này sẽ tốt hơn lisp cũ vì bạn không cần có thao tác chọn đối tượng nữa.

Mình đã thử và vẫn chưa hiểu vì sao lệnh divide lại dùng được cả với hai loại biến này. Cứ xài đã bạn nhỉ.

Thực ra thì bạn không cần xác định thêm các điểm r12 và r21 làm gì. Tuy nhiên dùng vậy cũng không sao, chỉ dài thêm đoạn code một chút.

 

Xem trên hình bạn gửi thì mình đã đoán đúng về việc chọn điểm p1 và p2. Vậy thì đơn giản rồi vì thực chất biến kchang của bạn chính là độ dài length của thằng d1/ hn và kccot là độ dài length của thằng d2 /hd. Việc lấy độ dài của đoạn thẳng d1 và d2 chắc bạn đã biết rối. Bạn chú ý rằng biến kchang và kccot có thể là một số không nguyên nên để cho việc array được chính xác bạn không nên xài hàm (fix kchang) và (fix kccot) làm gì. Cứ để nguyên các biến này trong các tham số của lệnh array bạn ạ.

Để tránh phải lặp lại hàm (fix hn) và (fix hd) nhiều lần bạn có thể đặt ngay (setq hn (fix (getreal "\n: ......."))) và (setq hd (fix (getreal "\n: ......."))).

Khi đó điểm p1 của bạn sẽ là '((car r1) (+ (cadr r1) kchang)) và p2 sẽ là '((+ (car r1) kccot) (cadr r1)) .

Còn cách lấy điểm td và array vẫn như cũ bạn ạ.

 

Bạn thử lại nhé. Chúc thành công.

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ào bạn Tuanthietkedien.

Cho mình tham gia góp ý thêm một chút nhé :

Ở đoạn Lisp bố trí đèn thì có đoạn :

(setq hn (getreal "\nSo hang doc: "))

(setq hd (getreal "\nSo hang ngang: "))

 

Bạn thấy đó biến hn và biến hd chỉ nhận giá trị nguyên (integer) mà thôi. Bạn không nên sử dụng getreal trong trường hợp này mà sử dụng bằng hàm getint và qua đó thì không cần sử dụng hàm (fix hn) hay (fix hd) vì biến hn và hd đã là số nguyên thì bạn sử dụng hàm fix là thừa và rất rối mắt.

(fix hn) thay bằng hn

(fix hd) thay bằng hd

khi bạn đã sử dụng hàm getint để gán cho biến hn và hd.

Chúc thành công

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
Biện pháp giải quyết triệt để là:

1. Chuyển ss thành list (bằng hàm ss2ent của anh Hoành)

2. Dùng vl-sort, kết hợp lambda để sắp xếp các phần tử trong list theo quy luật nào đó (quy luật do người lập trình tự định nghĩa bằng hàm khuyết danh lambda). Trong ví dụ này, có thể sort theo tiêu chí "tung độ điểm chèn text từ thấp đến cao".

3. Dùng foreach cho list. Trong vòng foreach, muốn tác vụ nào đó tuỳ ý, thứ tự thực hiện sẽ đúng như thứ tự của các phần tử trong list.

 

Các bạn có thể vào Help, hoặc search trên diễn đàn với từ khoá vl-sort và lambda để xem thêm nhiều ví dụ. Nếu có vướng mắc gì thì nêu lên, anh em sẽ hỗ trợ thêm.

 

Chào bác SSG

Em đã tìm ra code của bác Nguyễn Hoành viết về cái này

 

(defun c:test ()
(setq ss (ssget '((0 . "TEXT")))
lst (ss2ent ss)
lst (vl-sort lst
'(lambda (e1 e2)
(<
(caddr (assoc 10 (entget e1)))
(caddr (assoc 10 (entget e2)))
)
)
)
)
(foreach e lst
(command ".erase" e "")
(getstring "\nNhan enter de tiep tuc!")
)
)

(defun ss2ent (ss / sodt index lstent)
(setq
sodt (if ss (sslength ss) 0)
index 0
)
(repeat sodt
(setq ent (ssname ss index)
index (1+ index)
lstent (cons ent lstent)
)
)
(reverse lstent)
)

 

Hiên tại em chưa hiểu rõ về ss2ent còn vl-sort sau khi search trong help đã hiểu đại khái rồi. Có vài điều chưa hiểu xin hỏi bác 1 tí

- Sao mình dùng ...(caddr (assoc 10 (entget e1)))..., nhưng trong help dùng (:cheers:

Cám ơn bác nhiều lắm.

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

Còn 1 vấn đề xin hỏi các bác 1 tí

 

(setq dt (car (entsel)))

(setq dt (entget dt))

(setq bk (cdr (assoc 40 dt)))

 

3 dòng trên có phải lấy giá trị bán kính của vòng tròn hay không?

Nếu đối tượng là block (hình tròn) có thể dùng nó để lấy giá trị bán kính block hay không? Nếu không phải vậy có cách nào lấy giá trị bán kính của block hay không?

 

Cám ơn các bác nhiều nhé.

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ào bác SSG

 

Hiên tại em chưa hiểu rõ về ss2ent còn vl-sort sau khi search trong help đã hiểu đại khái rồi. Có vài điều chưa hiểu xin hỏi bác 1 tí

- Sao mình dùng ...(caddr (assoc 10 (entget e1)))..., nhưng trong help dùng (:cheers:

Cám ơn bác nhiều lắm.

 

Chào bạn Tuan_thietkedien,

Ối cha mẹ ơi, bạn chạy nhanh quá, đuổi theo muốn hụt hơi luôn. Tà tà bạn ơi, phóng nhanh phanh gấp dễ nguy hiểm lắm. Nó làm bạn đôi khi quên cả các thao tác cơ bản của lisp đấy.

Về các câu hỏi của bạn, mình xin giải thích chút xíu như sau, đúng sai bạn tự kiểm nghiệm nha.

 

1/- Hàm (caddr (assoc 10 (entget e1))) là hàm lấy tọa độ z của điểm nhập text e1 bạn ạ. Như vậy có nghĩa bác Hoành phân loại text theo tọa độ z này của điểm nhập text.

Còn hàm trong help là (cadr e1) có nghĩa là lấy tọa độ y của điểm e1. Tức là nó phân loại điểm theo tọa độ y của điểm đó.

Do vậy việc bạn chọn cái gì là do yêu cầu phân loại của bạn chứ không phải bạn cứ bê nguyên xi lisp của bác Hoành về xài được đâu bạn ạ. Cái chính là bạn cần hiểu rõ các hàm trong lisp này một cách đầy đủ thì mới ứng dụng nó theo yêu cầu của mình được.

 

2/- (setq dc (getpoint)) ;chọn điểm

(setq dtext (cdr (assoc 10 e))) ; lấy vị trí bắt điểm của e

(setq dm (list (car dc) (+ (cadr dc) (* i 500)))) ; lập list tọa độ điểm move tới

(command "move" e "" dtext dm) ; move

Đoạn code này bạn thêm vào đâu trong cái lisp của bác Hoành nhỉ?

Nếu bạn thêm vào cuối cùng thì nó không chạy là đương nhiên vì các biến e của bạn đã bị xóa sạch còn đâu. Biến e của bạn chỉ tồn tại trước khi xài hàm Foreach và khi đó nếu bạn muốn dùng thì phải định nghĩa cho nó đã. Trong chương trình của bác Hoành biến e được định nghĩa là một phần tử của tập lst. Còn bạn???

Mặt khác Cái hàm (setq dtext (cdr (assoc 10 e))) của bạn là sai rất trầm trọng đấy. Hàm assoc đòi hỏi cái biến là một list các mã DXF có chứa các list tương tác của đối tượng e chứ đâu phải là bản thân caí đối tượng e này. Do vậy bạn phải viết là (setq dtext (cdr (assoc 10 (entget e)))) mới đúng.

Túm lại, bạn nên hiểu kỹ cái lisp của bác Hoành đã trước khi bạn định sử dụng hay bổ sung nó.

 

3/- (setq dt (car (entsel)))

(setq dt (entget dt))

(setq bk (cdr (assoc 40 dt)))

 

Cái đoạn lisp này không sai về cú pháp nhưng khi chọn đối tượng bạn phải chọn đối tượng là vòng tròn (circle) bạn muốn lấy bán kính.

Còn đối tượng block thì chả thấy ai nói đến khái niệm block hình tròn cả mà chỉ có block thôi bất kể nó là hình quỷ quái gì trong đó tập hợp rất nhiều các đối tượng cad bạn ạ. Trong mã DXF của block mà mình biết thì chả có cái mã nào mang số 40 cả, bạn tham khảo trang 119-121 trong tài liệu tự học Autolisp mình gửi bạn hoặc xem trong bảng mã trang 48 cũng sẽ thấy.

 

Nếu bạn muốn tìm bán kính của một đối tượng hình tròn có trong một block nào đó thì cách nhanh nhất là bạn explore nó ra rồi áp dụng đoạn lisp trên là OK ngay.

 

Chúc bạn thành công.

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ào bác SSG

Hiên tại em chưa hiểu rõ về ss2ent còn vl-sort sau khi search trong help đã hiểu đại khái rồi. Có vài điều chưa hiểu xin hỏi bác 1 tí

- Sao mình dùng ...(caddr (assoc 10 (entget e1)))..., nhưng trong help dùng (:cheers:

Cám ơn bác nhiều lắm.

Các vấn đề khác, bạn thanhbinh đã giải thích rồi. Chỗ nào chưa thông bạn nêu lại đúng chỗ đó. Riêng ss2ent thì ssg có vài ý này:

 

1. Có thể bạn chưa hiểu hết ý tứ của từng dòng code, nhưng chỉ cần bạn hiểu công dụng và cách dùng là có thể vận dụng được (từ từ sẽ hiểu sau). Cụ thể:

- Công dụng: convert một Selection Set (thường nhận được từ ssget) thành một List of Entity.

- Cú pháp: (ss2ent ss) -> return lstent

- Argument: ss, là Selection Set

- Return: lstent, là List of Entities

 

2. Lisp là gì? Đã có nhiều người hỏi và nhiều người trả lời. Với lập trình viên Lisp, chỉ đơn giản là:

 

LISP = LISt Processing

Diễn nôm: Lập trình Lisp là nghệ thuật xử lý danh sách

 

Điều đó có nghĩa rằng, List Data Type là kiểu dữ liệu cơ bản nhất, quan trọng nhất của ngôn ngữ Lisp -> AutoLisp cung cấp sẵn rất nhiều hàm thao tác với List. Khi cảm thấy xử lý một cái gì đó khó khăn, bạn hãy nghĩ ngay đến việc chuyển nó sang List (ss2ent là một ví dụ điển hình).

 

3. Nếu bạn cảm thấy khó nắm bắt "ý tứ" của anh Hoành, có thể tham khảo code của ssg:

;;;------------------------------------------------------------------------------
(defun ss2ent (ss / i Le e) ;;;Convert ss to list of ename
(setq i 0)
(repeat (sslength ss) 
   (setq
       e (ssname ss i)
       Le (append Le (list e))
       i (1+ i)
   )
)
Le
)
;;;------------------------------------------------------------------------------

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ờ sự giúp đỡ của anh SSG, bạn thanhbinh, bạn Tue_NV, đoạn code của anh Hoành đã viết sẵn, mình đã dùng để bổ sung thêm vài chỗ để hoàn chỉnh cái lisp giãn dòng text này. Tuy chưa hiểu sâu lắm nhưng như anh SSG nói, có thể vận dụng nó rùi từ từ hiểu sau, vì hiện tại kiến thức còn yếu quá.

 

(defun c:gt ( / os dc i ss dt dtt dm)
(setq
os (getvar "osmode")
dc (getpoint "\nChon diem chuan: ")
i 0
)
(setvar "osmode" 0)
(setq ss (ssget '((0 . "TEXT")))
lst (ss2ent ss)
lst (vl-sort lst
'(lambda (e1 e2)
(<
(caddr (assoc 10 (entget e1)))
(caddr (assoc 10 (entget e2)))
)
)
)
)
(foreach e lst
(setq
dt (entget e)
dtt (cdr (assoc 10 dt))
dm (list (car dc) (+ (cadr dc) (* i 500)))
)
(command ".justifytext" e "" "ml")
(command ".move" e "" dtt dm)
(setq i (1+ i))
)
(setvar "osmode" os)
(princ)
)

(defun ss2ent (ss / i Le e);;;Convert ss to list of ename
(setq i 0)
(repeat (sslength ss)
(setq
e (ssname ss i)
Le (append Le (list e))
i (1+ i)
)
)
Le
)

 

Nếu còn chỗ nào chưa hợp lý xin mọi người góp ý tiếp nhé.

Chúc mọi người luôn vui vẻ.

:cheers:

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ờ sự giúp đỡ của anh SSG, bạn thanhbinh, bạn Tue_NV, đoạn code của anh Hoành đã viết sẵn, mình đã dùng để bổ sung thêm vài chỗ để hoàn chỉnh cái lisp giãn dòng text này.

 

(defun c:gt ( / os dc i ss dt dtt dm)
..............
(vl-sort lst
.............
(command ".justifytext" e "" "ml")
......................
)

 

Nếu còn chỗ nào chưa hợp lý xin mọi người góp ý tiếp nhé.

 

Góp ý: bạn nên để dòng (command ".justifytext" e "" "ml") trước dòng (vl-sort lst.. để tránh trường hợp các text nằm ngang(cùng cao độ) nhưng justifytext khác nhau sẽ cho kết quả không được như ý.

 

Tốt hơn là gọi lệnh justifytext trước khi chạy lisp giãn dòng.

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

×