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

[Yêu cầu] Lisp phân nhỏ tập hợp chọn bằng cách chia ô

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

Mình xin bổ sung tên từng chủ đề để các bạn tiện tham khảo

 

Chủ đề 1: Phân nhỏ tập hợp chọn bằng cách chia ô

 

Chào các bạn.

Mình có một việc cần các bạn giúp đỡ. Số là công việc của mình có liên quan đến xử lý các đối tượng. Mình muốn rằng sau khi chọn lần đầu tiên bằng (ssget "c"). Lisp sẽ kiểm tra, nếu số đối tượng lớn hơn một số N nào đó (VD 500) thì sẽ tự động phân nhỏ của sổ ban đầu thành một số của sổ nhỏ hơn sao cho trong mỗi cửa số con, hàm (ssget "c") sẽ chọn đc nhỏ hơn N đối tượng. Tuy nhiên, việc phân nhỏ của sổ cũng không đc nhiều quá.

Mình lấy VD (N=500). Ban đầu chọn đc 900 đối tượng, Chia đôi ra, cửa sổ 1 chọn đc 200, cửa sổ 2 đc 700, lại chia đôi cửa sổ 2 ra , v.v... Cho đến lúc các cửa sổ đều chọn đc < N (=500) đối tượng. Kq cuối cùng trả về list gốm các cặp tọa độ của các cửa sổ chọn (VD : ((p1 p2) (p3 p4) ...)

Tuy nhiên, các bạn đừng chia nhỏ cửa sổ ngay từ đầu, vì nhiều quá sẽ làm chậm quá trình xử lý sau đó của mình. Mình nghĩ, số cửa sổ mỗi lần chia sẽ bẳng làm tròn lên của kết quả (số đối tượng / N). Ví dụ : 900/500=1.8 (số cửa sổ cần chia bằng 2).

Các bạn có thể thắc mắc tại sao mình kg làm, mình cũng đang làm, nhưng mình lọng cọng việc chia của sổ sao cho nhanh và cái vòng lặp cũng hơi trừu tượng.

Cám ơn các 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

Đọc đề toán của bạn thấy khó hiểu quá. Tôi tóm tắt lại, bạn xem có đúng ý không nhé:

- Gọi p1 và p2 là 2 điểm đối diện để xác định các đối tượng được chọn bởi hàm (ssget "c" p1 p2).

- Tìm số khung cửa sổ con m nằm trong khung p1p2 (đồng thời trả về list các cặp điểm đối diện) sao cho:

+) m là nhỏ nhất.

+) mỗi khung con đều chứa ít hơn N đối tượng cho trước.

Nếu đúng vậy thì trong trường hợp tổng quát rất có thể nó vô nghiệm hoặc có nhiều nghiệm.

  • 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

Đọc đề toán của bạn thấy khó hiểu quá. Tôi tóm tắt lại, bạn xem có đúng ý không nhé:

- Gọi p1 và p2 là 2 điểm đối diện để xác định các đối tượng được chọn bởi hàm (ssget "c" p1 p2).

- Tìm số khung cửa sổ con m nằm trong khung p1p2 (đồng thời trả về list các cặp điểm đối diện) sao cho:

+) m là nhỏ nhất.

+) mỗi khung con đều chứa ít hơn N đối tượng cho trước.

Nếu đúng vậy thì trong trường hợp tổng quát rất có thể nó vô nghiệm hoặc có nhiều nghiệm.

Không bắt buộc m là nhỏ nhất nhưng càng ít càng tốt, có thể ràng buộc lần chọn đầu tiên phải có dối tượngt mới chạy. Để mình diễn giải rõ hơn một tý.

Giả sử N=500. Lần chọn đầu tiên cho 1900 dt. bạn sẽ chia thành 4 cửa số rồi kiểm tra. Giả sử cửa sổ 1 chọn đc 100 dt xem như đạt, của sổ 2 có 500 cũng đạt, cửa số 3 có 600 và cửa số 4 có 700. Bạn phải xét tiếp cửa số 3 và 4 và cứ tiếp tục như vậy cho đến khi tất cả đều chọn đc nhỏ hơn 500 dt..

Tuy nhiên, cách chia cửa sổ nhỏ hơn như thế nào là tùy các bạn, miễn sao ít và nhanh

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

Em rất thích cách tư duy của bác để giải quyết vấn đề.

Bác thử cái này xem, em đưa vào thêm điều kiện lọc cho dễ thao tác, nếu bác không có nhu cầu thì bỏ nó đi (xóa toàn bộ biến filter trong code)

Code này sẽ chia đôi dần mỗi lần chọn, nếu cửa sổ chọn tìm thấy số đối tượng nhỏ hơn n thì thôi nó không chia nữa.

(defun select-c (p1 p2 n filter / ss)
(if (or (not (setq ss (ssget "w" p1 p2 filter))) (< (sslength ss) n))
(list (list p1 p2))
(append (select-c p1 (list (* 0.5 (+ (car p2) (car p1))) (cadr p2)) n filter)
(select-c p2 (list (* 0.5 (+ (car p2) (car p1))) (cadr p1)) n filter))))

- vì em dùng đệ quy nên nếu bác cần đổi tên hàm thì fải đổi cả trong hàm.

- n là số đối tượng tối đa cho 1 vùng chọn.

- "w" là em cố tình, bác đừng đổi về "c" nhé, việc này có thể sẽ dẫn đến sảy ra trường hợp hàm bị lặp vô tận.

- Test: (mapcar '(lambda (x) (command "rectang" (car x) (cadr x))) (select-c (getpoint) (getpoint) 7 '((0 . "INSERT"))))

 

PS: em cũng lưu ý cho bác luôn là với cách đặt vấn đề như trên, sẽ sảy ra trường hợp các đối tượng nằm trên biên chung của 2 vùng chọn kề nhau sẽ xuất hiện trong cả 2 tập hợp chọn của 2 vùng. bác cần xử lý các đối tượng này sau đó nếu nó có ảnh hưởng đến kết quả chạy chương trình của bác

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

http://www.cadviet.c...7170_ttline.rar

Em rất thích cách tư duy của bác để giải quyết vấn đề.

Bác thử cái này xem, em đưa vào thêm điều kiện lọc cho dễ thao tác, nếu bác không có nhu cầu thì bỏ nó đi (xóa toàn bộ biến filter trong code)

Code này sẽ chia đôi dần mỗi lần chọn, nếu cửa sổ chọn tìm thấy số đối tượng nhỏ hơn n thì thôi nó không chia nữa.

(defun select-c (p1 p2 n filter / ss)
(if (or (not (setq ss (ssget "w" p1 p2 filter))) (< (sslength ss) n))
(list (list p1 p2))
(append (select-c p1 (list (* 0.5 (+ (car p2) (car p1))) (cadr p2)) n filter)
(select-c p2 (list (* 0.5 (+ (car p2) (car p1))) (cadr p1)) n filter))))

- vì em dùng đệ quy nên nếu bác cần đổi tên hàm thì fải đổi cả trong hàm.

- n là số đối tượng tối đa cho 1 vùng chọn.

- "w" là em cố tình, bác đừng đổi về "c" nhé, việc này có thể sẽ dẫn đến sảy ra trường hợp hàm bị lặp vô tận.

- Test: (mapcar '(lambda (x) (command "rectang" (car x) (cadr x))) (select-c (getpoint) (getpoint) 7 '((0 . "INSERT"))))

 

PS: em cũng lưu ý cho bác luôn là với cách đặt vấn đề như trên, sẽ sảy ra trường hợp các đối tượng nằm trên biên chung của 2 vùng chọn kề nhau sẽ xuất hiện trong cả 2 tập hợp chọn của 2 vùng. bác cần xử lý các đối tượng này sau đó nếu nó có ảnh hưởng đến kết quả chạy chương trình của bác

Cám ơn bạn, bạn viết rất nhanh. Tuy nhiên mình chỉ ứng dụng thử chứ chưa hiểu đc. Mình đã test qua code của bạn trong TH của bản vẽ mà mình sẽ gởi kèm sau đây và mình cũng viết thêm code để kiểm tra xem có đúng kg.

Để nhanh và dễ cho các bạn khi viết code và kiểm tra, mình đưa ra đk :

- Hai điểm đầu là extmax và extmin

- đk lọc là "line"

- số lượng chọn trong một cửa sổ tối đa 500

- Chấp nhận TH một đối tượng có thể có trên nhiều của sổ chọn

- Không được bỏ sót đối tượng nào so với tập hợp chọn ban đầu

- Bản vẽ mẫu do mình gởi.

 

Như vậy code của bạn cho kết quả 118 cửa sổ và 72 cửa sổ chọn lớn hơn 500 đối tượng. Bạn xem lại giúp. Bạn nào có cách làm ít hơn và nhanh hơn thì ra tay cho sôi động nhé.

;code cua ban Thai
(defun select-c (p1 p2 n filter)
(if (or (not (setq ss (ssget "w" p1 p2 filter))) (< (sslength ss) n))
(list (list p1 p2))
(append (select-c p1 (list (* 0.5 (+ (car p2) (car p1))) (cadr p2)) n filter)
(select-c p2 (list (* 0.5 (+ (car p2) (car p1))) (cadr p1)) n filter))))
;Lenh de kiem tra  
(defun c:tse( / lis p1 p2 dt i n)
 (setq p1 (getvar "extmax") p2 (getvar "extmin"))
 (setq lis (select-c p1 p2 500 '((0 . "LINE"))))
 (setq i 0 n 0)
 (while (< i (length lis))
(setq dt (nth i lis) p1 (car dt) p2 (cadr dt))
(setq ss (ssget "c" p1 p2 '((0 . "line"))))
(if (and ss (> (sslength ss) 500)) (setq n (1+ n)))
(print (sslength ss))
(setq i (1+ i))
 )
 (if (> n 0) (alert (strcat "Co " (itoa n) " truong hop chon > 500 doi tuong")))
 (print (strcat "So cua so la : " (itoa (length lis))))
)

  • 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

uhm. Có 1 điều có lẽ bác chưa nghĩ tới. đó là con số đối tượng tối đa N cho 1 cửa sổ chọn buộc phải mang tính gần đúng (cả lớn hơn và nhỏ hơn N) bởi vẫn tồn tại trường hợp ta không thể có phép chia hình nào để chọn được số đối tượng nhỏ hơn N. Em ví dụ với yêu cầu của bác, khi bản vẽ có 501 đường thẳng trùng nhau chẳng hạn, chương trình sẽ chia cửa sổ chọn mãi mãi mà không bao giờ thu được kết quả.

 

Bởi vậy ta phải thống nhất với nhau lại là: chỉ cần chọn được số đối tượng gần 500 nhất (có thể lớn hơn hoặc nhỏ hơn 1 chút) cho 1 cửa sổ chọn.

 

Em thay kiểu chọn "c" thành "w" là vì điều này. tất nhiên nó cũng không thể giải quyết được trường hợp 501 đường thẳng trùng nhau nêu trên, nhưng nó đã loại bỏ gần hết các trường hợp không thể chia được sảy ra so với "c" (trường hợp trên là duy nhất nó không chia được). đồng thời cũng giảm thêm tương đối nhiều số lượng cửa sổ so với "c".

 

Một thắc mắc nữa của em: bác dùng phép chia hình này để phục vụ công việc tiếp theo của bác để tăng tốc độ. vậy với phép chia hình này bác có cần quan tâm đến tốc độ không hay miễn là chia được số cửa sổ chọn ít nhất có thể, bằng mọi cách mà không cần xét đến tốc độ chia hì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

2 đối tượng trùng BoundingBox là đã không có nghiệm cho method select "w" rồi bac ơi. Hoặc là các đường thẳng = // nằm ngang mà cứ chia đôi cửa sổ theo phương x thì cũng chết ^^ Bài toán đã có sai số (delta) rồi thì e nghĩ cứ sắp xếp tất cả tập chọn ss ban đầu từ trái sang phải theo tâm BB, lấy n đối tượng bên trái để tính ra SS Boundingbox (p1,p2), sau đó chọn ngược lại bằng phương thức "c" (p1,p2). (chia theo x)

- Nếu số lượng chọn được nằm trong khoảng sai số cho phép thì loại bỏ tất cả các đối tượng này ra khỏi tập ss ban đầu, tiếp tục đệ quy, dừng lại khi số ss còn lại nhỏ hơn n

- Nếu số lượng chọn > khoảng sai số cho phép thì lấy n đối tượng từ trên xuống dưới và lại lặp lại bước kiểm tra (chia theo y)

- Nếu đã xoay 2 lần mà chưa tìm ra cửa sổ hợp lý thì cái ss của bước đó rơi vào vô nghiệm => máu thì đổi ngược lại bước đầu tiên chia theo y trước rồi chia theo x sau. Nếu lại xuất hiện tập ss vô nghiệm thì ..... > :)

 

=> Kết quả có thể giống cái hình cắt tấm tôn hén ^^

  • 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

Ketxu cũng nghĩ gần giống hướng giải quyết bài toán này như mình đang nghĩ rồi đấy! đó là dựa vào BB của từng đối tượng, gộp dần lại để tìm cửa sổ chọn chứ không phân chia cửa sổ chọn từ BB của cả tập hợp ban đầu như cách trên nữa. tuy nhiên việc tính toán BB của từng đối tượng rồi gộp dần sẽ gây chậm, thậm chí rất chậm vì số lượng đối tượng quá lớn. Ưu điểm của phương pháp này là sẽ cho ta được số lượng và vị trí cửa sổ chọn hợp lý nhất.

Bởi vậy mình mới hỏi bác Trung Nga Mỹ có cần fải xét đến tốc độ của việc fân chia này hay không?

 

Với cách làm trước, mình cũng có thêm ý tưởng là thay đổi trục chia cứ sau 1 lần chia: Ngang - Dọc - Ngang - Dọc .... sẽ khắc phục được 1 số nhược điểm của việc chỉ chia theo 1 trục X hoặc Y. tuy nhiên viết đệ quy kiểu này hơi bị tốn noron thần kinh, chắc phải lúc nào tinh thần minh mẫn hơn chút mới viết được :lol:

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

Ketxu cũng nghĩ gần giống hướng giải quyết bài toán này như mình đang nghĩ rồi đấy! đó là dựa vào BB của từng đối tượng, gộp dần lại để tìm cửa sổ chọn chứ không phân chia cửa sổ chọn từ BB của cả tập hợp ban đầu như cách trên nữa. tuy nhiên việc tính toán BB của từng đối tượng rồi gộp dần sẽ gây chậm, thậm chí rất chậm vì số lượng đối tượng quá lớn. Ưu điểm của phương pháp này là sẽ cho ta được số lượng và vị trí cửa sổ chọn hợp lý nhất.

Bởi vậy mình mới hỏi bác Trung Nga Mỹ có cần fải xét đến tốc độ của việc fân chia này hay không?

 

Với cách làm trước, mình cũng có thêm ý tưởng là thay đổi trục chia cứ sau 1 lần chia: Ngang - Dọc - Ngang - Dọc .... sẽ khắc phục được 1 số nhược điểm của việc chỉ chia theo 1 trục X hoặc Y. tuy nhiên viết đệ quy kiểu này hơi bị tốn noron thần kinh, chắc phải lúc nào tinh thần minh mẫn hơn chút mới viết được :lol:

Cám ơn các bạn đã quan tâm.

Con số 500 đúng là tương đối, nhưng các chọn (ssget "w") làm cho một số đối tượng kg bao giờ đc chọn.

Thực ra công việc của mình kg xảy ra TH có các ĐT trùng nhau theo phuong ngang và phương đứng nên mình kg đặt đk này ra, thậm chí nếu có thì mình cũng loại trừ nó trước.

Khi có đối tượng xuyên qua nhiều của số thì hàm chọn (ssget "c" ) phải nhận đc chứ kg đc loại trừ nó ở lần chọn trước.

Tốc độ là rất quan trọng, vì việc xử lý một lúc nhiều đối tượng thì công việc của mình sẽ chạy chậm nên mình mới nghĩ cách cải tiến nó. Tốc độ là ưu tiên cao hơn. Số cửa sổ nhiều hơn tý cũng đc. Nhưng mình nghĩ việc chia nhiều của sổ sẽ làm tốc độ chậm hơn.

Mình dự định thực hiện chia nhỏ cửa sổ theo kiểu phân tờ (A0-A1...) hoặc như kiều lưới hình chữa nhật nhỏ dần theo cả hai chiều nhưng chưa nghĩ ra giải thuật.

Nếu khi gặp TH kg chia đc, CT có lẽ phải tìm cách thoát. Giả sử sau hai lần chọn liên tiếp từ của sổ ban đầu mà có số lượng kg đổ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

Chỗ này bác hiểu sai này. "Con số 500 đúng là tương đối, nhưng các chọn (ssget "w") làm cho một số đối tượng kg bao giờ đc chọn"

(ssget "w") chỉ dùng ở bước phân chia cửa sổ chọn. mục đích là để giảm số cửa sổ so với (ssget "c").

Dù chọn bằng "W" hay "C" thì số cửa sổ thu được vẫn phủ kín miền extmax - extmin

sau khi có được số cửa sổ chọn rồi, bước kế tiếp áp dụng vào chương trình của bác thì bác vẫn chọn bằng (ssget "c") bình thường. => đảm bảo không mất bất kỳ đối tượng nào. chỉ có điều số lượng đối tượng chọn được có thể lớn hơn 1 chút so với con số tối đa yêu cầu.

 

mình cũng có thêm ý tưởng là thay đổi trục chia cứ sau 1 lần chia: Ngang - Dọc - Ngang - Dọc ....

Đây chính là kiểu chia nhỏ cửa sổ theo kiểu phân tờ (A0-A1...) đấy ạ. để mai em thử xem có viết được khô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ỗ này bác hiểu sai này. "Con số 500 đúng là tương đối, nhưng các chọn (ssget "w") làm cho một số đối tượng kg bao giờ đc chọn"

(ssget "w") chỉ dùng ở bước phân chia cửa sổ chọn. mục đích là để giảm số cửa sổ so với (ssget "c").

Dù chọn bằng "W" hay "C" thì số cửa sổ thu được vẫn phủ kín miền extmax - extmin

sau khi có được số cửa sổ chọn rồi, bước kế tiếp áp dụng vào chương trình của bác thì bác vẫn chọn bằng (ssget "c") bình thường. => đảm bảo không mất bất kỳ đối tượng nào. chỉ có điều số lượng đối tượng chọn được có thể lớn hơn 1 chút so với con số tối đa yêu cầu.

 

 

Đây chính là kiểu chia nhỏ cửa sổ theo kiểu phân tờ (A0-A1...) đấy ạ. để mai em thử xem có viết được không :)

Cám ơn. Mình đã hiểu ý của bạn rồi. Đúng là suy nghĩ của bạn rất nhanh và hợp lý mà đến nay mình mới hiểu hết. Có thể những gì bạn đưa ra đã là một đáp án nếu như kg có ý tưởng nào hay hơn.

Tuy nhiên, mình muốn thực hiện ý đồ theo kiểu chia nhỏ như phân tờ vì nó sẽ phản ảnh tốt hơn cho công việc của mình. Thường trong công việc của mình các line xuất hiện kế nhau và mật độ không đều (đại khái như file mình đưa lên). Sẽ có rất nhiều hữu ích cho mình nếu có thể kiểm soát đc mật độ xuất hiện của các line. Lúc đầu mình dự định thực hiện bằng cách chia ô vuông có tọa độ chẵn, sau đó kiểm tra nếu chỗ nào mật độ dày quá sẽ tiếp tục chia cho đến lúc tất cà các ô vuông kg bằng nhau sẽ có số đối tượng tương đối như chỉ định. Nhưng mình sợ suy nghĩ của mình mang tính cục bộ và áp đặt nên đưa ra một đề mở đế các bạn tự do vận dụng sáng tạo của mình. Nếu đáp án nào mình thấy hợp lý nhất sẽ viết lại cho phù hợp với công việc.

- Thực ra, mình muốn áp đặt các bạn viết giúp một giải thuật như vậy (mình nghĩ cũng là cách hay nhưng thấy rất khó viết) :

Căn cứ cửa sổ chọn (là một hình chữa nhật) ban đầu, hãy chia thành n HCN đồng dạng sao cho mỗi lần chọn bằng (ssget "c") số đối tượng tối đa bằng N (giả sử = 500). TH nào kg chia đc thì giữ nguyên.

Bạn nào có hứng thú thì thử giúp mình 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

Bác thử code mới này xem, code này sử dụng phương pháp chia khổ giấy. Em có cải tiến thêm 1 chút để loại trừ các miền chọn không tồn tại bất kỳ đối tượng nào.

Vì cách chia mới này đảm bảo khắc phục được một số điểm yếu của "c" so với "w" nên em quyết định giữ lại "c" chứ không thay bằng "w". Điều này sẽ đảm bảo cho tất cả các cửa sổ chọn chắc chắn sẽ có số đối tượng nhỏ hơn N cho phép

Tất nhiên bác có thể vẫn để "w" để giảm số cửa sổ chọn xuống nữa. nhưng kết quả em thử trên bản vẽ của bác là không đáng kể (145 của "c" so với 131 của "w")

 

Bản vẽ của bác có tổng số 42200 đối tượng. như vậy trong điều kiện lý tưởng thì số cửa sổ chọn có thể tạo được với N =500 là 42200/500 = 85 cửa sổ. Con số 145 lớn hơn 1.75 lần so với điều kiện lý tưởng em nghĩ là chấp nhận được.

(defun select-c (p1 p2 n filter)
(if (setq ss (ssget "c" p1 p2 filter))
(if (< (sslength ss) (abs (setq n (* -1 n))))
(list (list p1 p2))
(if (< n 0)
(append (select-c p1 (list (* 0.5 (+ (car p2) (car p1))) (cadr p2)) n filter)
(select-c p2 (list (* 0.5 (+ (car p2) (car p1))) (cadr p1)) n filter))
(append (select-c p1 (list (car p2) (* 0.5 (+ (cadr p2) (cadr p1)))) n filter)
(select-c p2 (list (car p1) (* 0.5 (+ (cadr p2) (cadr p1)))) n filter))))))

 

Test:

(command "zoom" "e")

(mapcar '(lambda (x) (command "rectang" (car x) (cadr x))) (select-c (getvar "extmin") (getvar "extmax") 500 '((0 . "LINE"))))

 

Bác chú ý 1 điều quan trọng khi dùng hàm ssget với lựa chọn "c" hoặc "w": đó là việc bản vẽ được zoom to hay nhỏ ảnh hưởng rất lớn đến kết quả chọn đối tượng của hàm ssget.

- Bản vẽ được zoom lớn, độ chính xác của hàm ssget tăng lên nhưng nếu đối tượng vượt khỏi biên hiển thị của màn hình quá xa hàm ssget sẽ không chọn được đối tương đó.

- ngược lại, nếu tập hợp đối tượng bị zoom nhỏ. mật độ đối tượng trên 1 đơn vị diện tích màn hình quá lớn sẽ khiến hàm ssget chạy chậm, độ chính xác giảm và chọn được số đối tượng vược mức thực tế rất nhiều.

Để khắc phục, bác cần zoom extend tập hợp đối tượng muốn chọn trước khi chạy.

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 thử code mới này xem, code này sử dụng phương pháp chia khổ giấy. Em có cải tiến thêm 1 chút để loại trừ các miền chọn không tồn tại bất kỳ đối tượng nào.

Vì cách chia mới này đảm bảo khắc phục được một số điểm yếu của "c" so với "w" nên em quyết định giữ lại "c" chứ không thay bằng "w". Điều này sẽ đảm bảo cho tất cả các cửa sổ chọn chắc chắn sẽ có số đối tượng nhỏ hơn N cho phép

Tất nhiên bác có thể vẫn để "w" để giảm số cửa sổ chọn xuống nữa. nhưng kết quả em thử trên bản vẽ của bác là không đáng kể (145 của "c" so với 131 của "w")

 

Bản vẽ của bác có tổng số 42200 đối tượng. như vậy trong điều kiện lý tưởng thì số cửa sổ chọn có thể tạo được với N =500 là 42200/500 = 85 cửa sổ. Con số 145 lớn hơn 1.75 lần so với điều kiện lý tưởng em nghĩ là chấp nhận được.

(defun select-c (p1 p2 n filter)
(if (setq ss (ssget "c" p1 p2 filter))
(if (< (sslength ss) (abs (setq n (* -1 n))))
(list (list p1 p2))
(if (< n 0)
(append (select-c p1 (list (* 0.5 (+ (car p2) (car p1))) (cadr p2)) n filter)
(select-c p2 (list (* 0.5 (+ (car p2) (car p1))) (cadr p1)) n filter))
(append (select-c p1 (list (car p2) (* 0.5 (+ (cadr p2) (cadr p1)))) n filter)
(select-c p2 (list (car p1) (* 0.5 (+ (cadr p2) (cadr p1)))) n filter))))))

 

Test:

(command "zoom" "e")

(mapcar '(lambda (x) (command "rectang" (car x) (cadr x))) (select-c (getvar "extmin") (getvar "extmax") 500 '((0 . "LINE"))))

 

Bác chú ý 1 điều quan trọng khi dùng hàm ssget với lựa chọn "c" hoặc "w": đó là việc bản vẽ được zoom to hay nhỏ ảnh hưởng rất lớn đến kết quả chọn đối tượng của hàm ssget.

- Bản vẽ được zoom lớn, độ chính xác của hàm ssget tăng lên nhưng nếu đối tượng vượt khỏi biên hiển thị của màn hình quá xa hàm ssget sẽ không chọn được đối tương đó.

- ngược lại, nếu tập hợp đối tượng bị zoom nhỏ. mật độ đối tượng trên 1 đơn vị diện tích màn hình quá lớn sẽ khiến hàm ssget chạy chậm, độ chính xác giảm và chọn được số đối tượng vược mức thực tế rất nhiều.

Để khắc phục, bác cần zoom extend tập hợp đối tượng muốn chọn trước khi chạy.

Mình đã chạy thử code của bạn. Kq như hình mình đưa lên để bạn xem. Có 461 đối tượng bị sót lại (mình tô màu đỏ) và một (kg biết còn nữa kg) cửa sổ chọn là một đường thắng (2 điểm trùng nhau). Bạn xem lại giúp mình nhé, code bạn viết ngắn quá mình cũng chịu, chưa thể hiểu đc. Cám ơn bạn.

37170_se1.jpg

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ế độ bắt điểm bác ạ. thực tế nó vẫn chạy ra kết quả đúng nhưng khi vẽ các khung kết quả này ra em vẽ bằng command nên bị ảnh hưởng bởi chế độ bắt điểm. bác tắt nó đi trước khi chạy là được. Cái khung là đường thẳng và 1 vài khung khác trên hình nếu bác để ý kĩ đã bị sai lệch bởi chế độ bắt điểm của cad.

Kết quả khi bỏ bắt điểm đây ạ

22980_chiahinhthaistreetz.jpg

 

Về chuyện code ngắn khó hiểu thì đúng là chẳng còn cách nào khác cho nó tường minh hơn bác ạ. bài toán này không thể dùng các phép lặp thông thường để chia :(

  • 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ình đã chạy thử code của bạn. Kq như hình mình đưa lên để bạn xem. Có 461 đối tượng bị sót lại (mình tô màu đỏ) và một (kg biết còn nữa kg) cửa sổ chọn là một đường thắng (2 điểm trùng nhau). Bạn xem lại giúp mình nhé, code bạn viết ngắn quá mình cũng chịu, chưa thể hiểu đc. Cám ơn bạn.

Hề hề hề,

Các bác cho mình nói leo một chút nhé. Đây là cái mình đã làm thử. cách chia có vẻ khác của bác ThaiStreets còn kết quả có vẻ chấp nhận được Các bác test thử và cho thêm ý kiến. Về cơ bản sẽ có chút sai sót ở các đối tượng nằm trên biên vì cú mỗi lần tìm được ô có số lượng đối tượng nhỏ hơn số đã định thì mình lại xóa hết chúng đi. Vì thế ở lần chọn kế tiếp thì sẽ có những chú trên biên không được thống kê, Bởi thế tổng số các chú có thể sẽ nhỉnh hơn số giới hạn chút chút các bác ạ.

Mình cũng đã thử nghĩ tìm giải pháp cho nó chuẩn nhưng chưa ra. Rất mong các bác góp ý thêm về giải thuật của mình.

(defun c:separate (/ oldos pmin pmax h c n0 plst n pairl xlst ylst xmin ymin polst po nilst ni plst)
(vl-load-com)
(setq oldos (getvar "osmode"))
(setvar "osmode" 0)
(command "undo" "be")
(setq pmin (getpoint "\n Chon diem goc duoi ben trai vung chon")
         pmax (getpoint pmin "\n Chon diem goc tren ben phai vung chon")
         h 1
         c 1
)
(setq n0 (getint "\n Nhap so luong toi da cua mot o chon: "))
(if (not n0) (setq n0 500))
(setq plst (list))
(setq n (sslength (setq ss (ssget "c" pmin pmax))))
(while (> n n0)
  	(if (> h c)
  		(setq c (* 2 c))
  		(setq h (* 2 h))
  	)
  	(setq
        		pairl (list)
        		xlst (list (setq xmin (car pmin)))
        		ylst (list (setq ymin (cadr pmin)))
  	)
  	(while (< xmin (car pmax))
               (setq xmin (+ xmin (/ (- (car pmax) (car pmin)) c))
                		xlst (append xlst (list xmin))  )
  	)
  	(while (< ymin (cadr pmax))
               (setq ymin (+ ymin (/ (- (cadr pmax) (cadr pmin)) h))
                         ylst (append ylst (list ymin))  )
  	)
  	(setq xlst (append xlst (list (car pmax)))
        		ylst (append ylst (list (cadr pmax)))
        		polst (list)
  	)
  	(foreach x xlst
             (foreach y ylst
              		(setq po (list x y 0.0)
                               polst (append polst (list po))  )
             )
  	)
  	(foreach po polst
             (if (and (<= (+ (car po) (/ (- (car pmax) (car pmin)) c)) (car pmax))
                  		(<= (+ (cadr po) (/ (- (cadr pmax) (cadr pmin)) h)) (cadr pmax))  )
                 (setq pairl (append pairl (list (list po (list (+ (car po) (/ (- (car pmax) (car pmin)) c))
                                                                              		(+ (cadr po) (/ (- (cadr pmax) (cadr pmin)) h)) 0.0))))  )
             )
  	)
  	(setq nilst (list))
  	(foreach pair pairl
      		(if (ssget "c" (car pair) (cadr pair))
                   (progn
                  		(setq ni (sslength (ssget "c" (car pair) (cadr pair)))
                            		nilst (append nilst (list ni))   )
                         (if (< ni n0)
                             (progn
                            		(command "erase" (ssget "c" (car pair) (cadr pair)) "")
                            		(setq plst (append plst (list pair)))
                             )
                         )          
                   )
      		)

  	)
  	(setq nilst (vl-sort nilst '<)
               n (last nilst)   )
)
(command "undo" "e")
(command "undo" 1)
(command "undo" "be")
(foreach p plst
(command "rectang" (car p) (cadr p))
)
(command "undo" "e")
(setvar "osmode" oldos)
(princ)
)

 

 

Chúc các bác luôn mạnh khỏe và vui.

  • Vote tăng 3

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 Bình thử đổi trục chia của lần chia đầu tiên xem (bác đang để phương đứng, còn em để phương ngang). ra kết quả gần như trùng khít với kết quả khi chạy code của em luôn ^^. Chênh lệch 1 vài cửa sổ ở những vị trí có số đối tượng lớn hơn 500 như bác nêu.

22980_bacbinhadfa.jpg

Màu vàng của bác, màu xám của em. (Cái này là em đổi trục chia lần đầu tiên trong code của em cho giống bác)

 

Em nghĩ là cách chia của bác và của em bản chất thì như nhau. chỉ có cách triển khai code khác nhau thôi. Cách của bác mềm dẻo hơn, dễ can thiệp tỷ lệ chia hơn. của em thì chết cứng với tỷ lệ 1/2 cho mỗi lần chia, đổi tỷ lệ fát là nó lặp đến... treo máy thì thôi :(

 

Để tăng tốc độ của quá trình thực hiện chia hình thì bác nên sử dụng hàm entdel để xóa và khôi phục đối tượng, hoặc đơn giản hơn là ẩn nó đi bác ạ.

 

cảm ơn bác về cái này (command "undo" 1) giờ em mới biết :D

  • 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 Bình thử đổi trục chia của lần chia đầu tiên xem (bác đang để phương đứng, còn em để phương ngang). ra kết quả gần như trùng khít với kết quả khi chạy code của em luôn ^^. Chênh lệch 1 vài cửa sổ ở những vị trí có số đối tượng lớn hơn 500 như bác nêu.

22980_bacbinhadfa.jpg

Màu vàng của bác, màu xám của em. (Cái này là em đổi trục chia lần đầu tiên trong code của em cho giống bác)

 

Em nghĩ là cách chia của bác và của em bản chất thì như nhau. chỉ có cách triển khai code khác nhau thôi. Cách của bác mềm dẻo hơn, dễ can thiệp tỷ lệ chia hơn. của em thì chết cứng với tỷ lệ 1/2 cho mỗi lần chia, đổi tỷ lệ fát là nó lặp đến... treo máy thì thôi :(

 

Để tăng tốc độ của quá trình thực hiện chia hình thì bác nên sử dụng hàm entdel để xóa và khôi phục đối tượng, hoặc đơn giản hơn là ẩn nó đi bác ạ.

 

cảm ơn bác về cái này (command "undo" 1) giờ em mới biết :D

Mình cảm thấy ngỡ ngàng và rất mừng với kq của các bác. Chẳng biết nói sao, các bác viết quá hay và quá độc.

Hay ở chỗ các bác đã giải quyết nhanh bài toán kg dễ. Độc ở chỗ code quá ngắn gọn và mình chưa hiểu đc..

Nếu để nghiên cứu cho hiểu thì mình sẽ bắt đầu từ code của bác Bình, tuy nhiên mình thích kiểu viết của bác Thái, nó mang tính trừu tượng rất cao. Cách viết này chỉ đôi lúc mình viết đc khi tập trung cao độ. Nếu phân tích sâu hơn thì cách viết của bác Thái phù hợp với những giải thuật mang tính đột phá vế tốc độ.

Kg dám đòi hỏi gì hơn nữa, mình sẽ cố hiểu và viết phần còn để khỏi phụ lòng các bác.

Một lần nữa cám ơn các bác rất nhiều. Hẹn gặp lại các bác ở những đề tài khó khác.

 

Không biết các bác đã gặp TH này chưa.

 

Chủ đề 2 :

Hãy đặt một HCN có kích thước biết trước vào trong một hình có đủ thứ bên trong đc giới hạn bởi đường bao sao cho HCN kg đè lên cái gì cả. Nếu kg tìm đc vị trí đủ trống thì trả về nil.

 

Đây là file : http://www.cadviet.com/upfiles/3/37170_h1.dwgD9a632a6y

Đây là hình ảnh ví dụ minh hoạ. Đường bao màu đỏ, HCN màu trắng.37170_h1.jpg

Mời các bạn tham gia, mình cám ơn rất nhiều

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ới đọc cái yêu cầu là em thấy nó luôn xảy ra 2 trường hợp là vô nghiệm và vô số nghiệm vậy thì có thể giải quyết được không đây?

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 đề toán khó, nhưng giả thiết bạn đưa ra chưa rõ lắm. Vì thế nó có thể có nghiệm, vô nghiệm, hoặc vô số nghiệm.

Hỏi thêm chủ topic mấy câu cho rõ:

1). Cái đường bao là đối tượng kiểu gì? Nếu là pline thì có chứa arc không?

2). Khái niệm đè là theo kiểu "c" hay "w"?

3). Hình chữ nhật có thể nằm xiên không?

4). Trong trường hợp nhiều nghiệm thì xử hắn kiểu gì? Hay chỉ cần lôi cổ 1 thằng đem 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

5). "Không đè lên cái gì cả". "Cái gì" ở đây theo em hiểu là vị trí các vật thể thuộc địa hình (nhà cửa, cây cối...) chứ không kể đến các đối tượng ghi chú trên bản vẽ như dim, text, leader... thế mới đúng mục đích sử dụng.

6). "Cái gì" thực tế phải quy định gồm cả phần bên trong của miền kín chứ không chỉ là đối tượng đường. bác không thể đặt vật thể của bác vào trong lòng nhà của người ta được phải không ạ

Bài này khó quá :D

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

7). Hình như gom góp lại thì ý chủ topic là thế này thì phải: chủ topic mới tậu được 1 miếng đất, trên đó đã xây biệt thự, hồ bơi, gara và đủ thứ khác nữa. Bây giờ muốn làm thêm cái sân tennis mà không biết liệu có chỗ nào đặt được hay không? :lol:

Ái dà! Cái này chắc thuê khảo sát đi đo dễ hơn viết lisp quá! :lol:

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

7). Hình như gom góp lại thì ý chủ topic là thế này thì phải: chủ topic mới tậu được 1 miếng đất, trên đó đã xây biệt thự, hồ bơi, gara và đủ thứ khác nữa. Bây giờ muốn làm thêm cái sân tennis mà không biết liệu có chỗ nào đặt được hay không? :lol:

Ái dà! Cái này chắc thuê khảo sát đi đo dễ hơn viết lisp quá! :lol:

Cám ơn các bạn đã tham gia đông vui. Khi mình đưa ra một đề toán thì thường kg dễ, nếu dể mình đã làm 10 năm về trước rối. Tuy nhiên, đối với mình là khó nhưng đối với các bạn chưa hẳn vậy. Mình đã có những "thu hoạch kg ngờ" từ các bạn. Nói vui vậy thôi, mình tham gia chủ yếu để học hỏi và mở mang kiến thức, chủ yếu tạo ra đc sự hứng thú khi viết Lisp nói riêng.

Trở lại chủ đề trên, "cái gì" mình nói ở đấy là cái mà mình nhìn thấy trên màn hình (tránh những cái nhìn thấy trên màn hình), đường bao là một polyline nói chung.

Nói như bạn là rất chính xác, mình muốn làm đại khái như cái sân tennis vậy, nhưng cái việc này đo đạc cũng kg làm nhanh đc vì phải làm rất nhiều hình tương tự như vậy (bạn cần gì phải đo khi các vật thể đã có kích thước và tọa độ). Cái bạn cần phải làm là cầm một cái HCN đưa tới đưa lui rồi đặt vào chỗ trống có thể, nhưng mình cần làm việc đó tự động từ Lisp.

Nếu kg có nghiệm trả về nil. Nếu có nhiều nghiệm, trả về một vị trí là đủ (vị trí thoáng nhất càng tốt).

Mình có cảm giác, đề tài này liên quan đến bài toán chia ô vừa giải xong.

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

Lisp Check xem 1 Rectangle có thể đặt gọn vào trong 1 Curve kín hay không, với điều kiện là Rectangle không đè lên bất cứ đối tượng nào.

Chú ý: mức độ chính xác phụ thuộc số lần lặp. Để đạt chính xác càng cao thì lisp càng chạy chậm.

Bác nào có thể góp ý để lisp chạy nhanh hơn thì rất cám ơn (dù đã tìm cách khắc phục rồi).

;Doan Van Ha - CADViet.com - Ngay 13/6/2012
;Muc dich: Check xem 1 Rectangle co the nam gon trong 1 Curve kin hay khong, va Rectangle khong de len bat cu doi tuong nao trong Curve.
;Chu y: Lisp su dung tot khi Rectangle // OXY cua UCS_World. Neu Rectangle khong // thi Rotate tat ca ban ve, sau do dung lisp, roi Rotate tra lai.
(defun C:HA( / ent ent1 ent2 baoN baoT numx numy lxT lyT dx dy x y p1 p2 p3 p4 lst lst4 co)
(vl-load-com)
(while (not (setq ent1 (car (entsel "\nChon Curve bao ngoai: ")))))
(while (not (setq ent2 (car (entsel "\nChon Rectangle: ")))))
(setq baoN (LM:BoundingBox (vlax-ename->vla-object ent1))
      	baoT (LM:BoundingBox (vlax-ename->vla-object ent2))
      	lxT (distance (nth 0 baoT) (nth 1 baoT))
      	lyT (distance (nth 1 baoT) (nth 2 baoT))
      	numx 50
      	numy (* numx (fix (/ lxT lxT)))
      	dx (/ (distance (nth 0 baoN) (nth 1 baoN)) numx)
      	dy (/ (distance (nth 1 baoN) (nth 2 baoN)) numy)
      	x 0)
(princ "\nDang tinh toan. Vui long doi...\n")
(repeat numx
 (setq y 0)
 (repeat numy
  (setq p1 (polar (polar (nth 0 baoN) (/ pi 2) (- (* y dy) (* y (/ (- lyT dy) (1- numy))))) 0 (- (* x dx) (* x (/ (- lxT dx) (1- numx)))))
        	p2 (polar p1 0 lxT)
        	p3 (polar p2 (/ pi 2) lyT)
        	p4 (polar p3 (- pi) lxT)
        	lst4 (list p1 p2 p3 p4)
        	ent (LWPoly lst4 1)
        	lst (LM:ss->ent (HA:Inside2 ent1 100 "C")))
  (if (or (/= (sslength (ssget "CP" lst4)) 1) (not (member ent lst)))
(vla-Delete (vlax-ename->vla-object ent))
(setq co T))
  (setq y (1+ y)))
 (setq x (1+ x)))
(if co
 (alert "\nDa tim duoc vi tri dat Rectangle(s). \nNhau di thoi ban oi!")
 (alert "\nBuon qua di thoi. \nKhong co vi tri nao co the dat Rectangle(s)."))
(princ))
;-----
(defun LM:ss->ent (ss / i l) (if ss (repeat (setq i (sslength ss)) (setq l (cons (ssname ss (setq i (1- i))) l)))))
;----- Chän c¸c Objects bªn trong Curve, theo kiÓu "CP" hoÆc "WP".
(defun HA:Inside2 (ent num cw / i j lst)
(cond
 ((vlax-curve-isclosed ent)
  (setq i (/ (vlax-curve-getdistatparam ent (vlax-curve-getendparam ent)) num) j (- i))
  (repeat num
(setq lst (cons (vlax-curve-getpointatdist ent (setq j (+ j i))) lst)))))
(if (= (strcase cw) "C")
 (ssget "cp" lst)
 (ssget "wp" lst)))
;-----
(defun LM:BoundingBox (obj / ll ur)
 (if (vlax-method-applicable-p obj 'GetBoundingBox)
((lambda (boundingbox)
   	(mapcar
     	(function
       	(lambda (_functionlist)
         	(mapcar
           	(function
             	(lambda (_function) ((eval _function) boundingbox)))
           	_functionlist)))
    	'((caar cadar) (caadr cadar)
       	(caadr cadadr) (caar cadadr))))
 	(mapcar 'vlax-safearray->list
   	(progn
     	(vla-getBoundingBox obj 'll 'ur) (list ll ur))))))
;----- cls=1: ®ãng; cls=0: më. (by Thai)
(defun LWPoly (lst cls)
(entmakex (append (list (cons 0 "LWPOLYLINE") (cons 100 "AcDbEntity") (cons 100 "AcDbPolyline") (cons 90 (length lst)) (cons 70 cls)) (mapcar (function (lambda (p) (cons 10 p))) lst))))

P/S: 22h30 13/6/2012: đang update liên tục để tăng tốc độ nếu có thể.

  • 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ật thú vị ^^ Cách giải của bác Hạ là chia ngay BoundingBox thành ô nxn, sau đó đặt HCN vào từng mút để kiểm tra. Với cách làm này thì sẽ đi lần lượt từng ô và tất nhiên đối tượng bao không nhất thiết phải kín

- Cũng có thể dùng đường Line để quét

- Cũng có thể vẫn giữ ý tưởng của bác ĐVH nhưng list tọa độ trước và bỏ đi những thằng nằm trong đối tượng con bên trong

- Cũng có thể .....

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

×