Đến nội dung


Hình ảnh
* - - - - 1 Bình chọn

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


  • Please log in to reply
102 replies to this topic

#1 TRUNGNGAMY

TRUNGNGAMY

    biết lệnh block

  • Members
  • PipPipPipPipPipPip
  • 401 Bài viết
Điểm đánh giá: 91 (tàm tạm)

Đã gửi 09 June 2012 - 07:34 PM

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
  • 0

#2 Doan Van Ha

Doan Van Ha

    biết lệnh adcenter

  • CADViet Team
  • PipPipPipPipPipPipPip
  • 5454 Bài viết
Điểm đánh giá: 2626 (tuyệt vời)

Đã gửi 09 June 2012 - 10:33 PM

Đọ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.
  • 1

* Chỉ nên yêu cầu Lisp khi bạn làm việc đó mất cả ngày nhưng họ chỉ viết 1 giờ. Đừng nêu yêu cầu Lisp khi bạn chỉ làm 1 giờ nhưng bắt họ phải mất cả ngày.

* Nhờ viết lisp cũng như đi khám bệnh. Chỉ gởi căn cước và than sắp chết thì không bác sỹ nào cứu sống được.


#3 TRUNGNGAMY

TRUNGNGAMY

    biết lệnh block

  • Members
  • PipPipPipPipPipPip
  • 401 Bài viết
Điểm đánh giá: 91 (tàm tạm)

Đã gửi 09 June 2012 - 10:49 PM

Đọ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
  • 0

#4 Thaistreetz

Thaistreetz

    biết lệnh adcenter

  • Advance Member
  • PipPipPipPipPipPipPip
  • 903 Bài viết
Điểm đánh giá: 505 (tốt)

Đã gửi 09 June 2012 - 11:12 PM

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
  • 0

Hình đã gửi
IN HIM, I TRUST. THE TRUST IN MY GOD


#5 TRUNGNGAMY

TRUNGNGAMY

    biết lệnh block

  • Members
  • PipPipPipPipPipPip
  • 401 Bài viết
Điểm đánh giá: 91 (tàm tạm)

Đã gửi 10 June 2012 - 01:33 AM

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))))
)

  • 1

#6 TRUNGNGAMY

TRUNGNGAMY

    biết lệnh block

  • Members
  • PipPipPipPipPipPip
  • 401 Bài viết
Điểm đánh giá: 91 (tàm tạm)

Đã gửi 10 June 2012 - 01:59 AM

http://www.cadviet.c...70_ttline_1.rar
  • 0

#7 Thaistreetz

Thaistreetz

    biết lệnh adcenter

  • Advance Member
  • PipPipPipPipPipPipPip
  • 903 Bài viết
Điểm đánh giá: 505 (tốt)

Đã gửi 10 June 2012 - 10:22 AM

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

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?
  • 0

Hình đã gửi
IN HIM, I TRUST. THE TRUST IN MY GOD


#8 ketxu

ketxu

    Copier - Paster - Editor

  • Moderator
  • PipPipPipPipPipPipPip
  • 5685 Bài viết
Điểm đánh giá: 2606 (tuyệt vời)

Đã gửi 10 June 2012 - 11:56 AM

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 ^^
  • 1

Thành viên nhóm CadMagic.
Mời bạn ghé thăm facebook nhóm - Page viết lisp theo yêu cầu  :
CAD MAGIC


#9 Thaistreetz

Thaistreetz

    biết lệnh adcenter

  • Advance Member
  • PipPipPipPipPipPipPip
  • 903 Bài viết
Điểm đánh giá: 505 (tốt)

Đã gửi 10 June 2012 - 01:17 PM

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:
  • 0

Hình đã gửi
IN HIM, I TRUST. THE TRUST IN MY GOD


#10 TRUNGNGAMY

TRUNGNGAMY

    biết lệnh block

  • Members
  • PipPipPipPipPipPip
  • 401 Bài viết
Điểm đánh giá: 91 (tàm tạm)

Đã gửi 10 June 2012 - 10:07 PM

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.
  • 0

#11 Thaistreetz

Thaistreetz

    biết lệnh adcenter

  • Advance Member
  • PipPipPipPipPipPipPip
  • 903 Bài viết
Điểm đánh giá: 505 (tốt)

Đã gửi 10 June 2012 - 11:41 PM

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 :)
  • 0

Hình đã gửi
IN HIM, I TRUST. THE TRUST IN MY GOD


#12 TRUNGNGAMY

TRUNGNGAMY

    biết lệnh block

  • Members
  • PipPipPipPipPipPip
  • 401 Bài viết
Điểm đánh giá: 91 (tàm tạm)

Đã gửi 11 June 2012 - 01:00 AM

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é.
  • 0

#13 Thaistreetz

Thaistreetz

    biết lệnh adcenter

  • Advance Member
  • PipPipPipPipPipPipPip
  • 903 Bài viết
Điểm đánh giá: 505 (tốt)

Đã gửi 11 June 2012 - 09:46 PM

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.
  • 0

Hình đã gửi
IN HIM, I TRUST. THE TRUST IN MY GOD


#14 TRUNGNGAMY

TRUNGNGAMY

    biết lệnh block

  • Members
  • PipPipPipPipPipPip
  • 401 Bài viết
Điểm đánh giá: 91 (tàm tạm)

Đã gửi 12 June 2012 - 02:14 AM

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.
Hình đã gửi
  • 0

#15 Thaistreetz

Thaistreetz

    biết lệnh adcenter

  • Advance Member
  • PipPipPipPipPipPipPip
  • 903 Bài viết
Điểm đánh giá: 505 (tốt)

Đã gửi 12 June 2012 - 07:51 AM

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 ạ
Hình đã gửi

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 :(
  • 1

Hình đã gửi
IN HIM, I TRUST. THE TRUST IN MY GOD


#16 phamthanhbinh

phamthanhbinh

    biết lệnh adcenter

  • Moderator
  • PipPipPipPipPipPipPip
  • 6009 Bài viết
Điểm đánh giá: 3113 (tuyệt vời)

Đã gửi 12 June 2012 - 03:09 PM

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.
  • 3
Chúc các quý Anh trên diễn đàn luôn khỏe, đẻ thêm được nhiều thứ để mót.

#17 Thaistreetz

Thaistreetz

    biết lệnh adcenter

  • Advance Member
  • PipPipPipPipPipPipPip
  • 903 Bài viết
Điểm đánh giá: 505 (tốt)

Đã gửi 12 June 2012 - 05:28 PM

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.
Hình đã gửi
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
  • 1

Hình đã gửi
IN HIM, I TRUST. THE TRUST IN MY GOD


#18 TRUNGNGAMY

TRUNGNGAMY

    biết lệnh block

  • Members
  • PipPipPipPipPipPip
  • 401 Bài viết
Điểm đánh giá: 91 (tàm tạm)

Đã gửi 13 June 2012 - 01:35 AM

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.
Hình đã gửi
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.c...h1.dwgD9a632a6y
Đây là hình ảnh ví dụ minh hoạ. Đường bao màu đỏ, HCN màu trắng.Hình đã gửi
Mời các bạn tham gia, mình cám ơn rất nhiều
  • 0

#19 lp_hai

lp_hai

    biết lệnh measure

  • Members
  • PipPipPipPipPipPip
  • 456 Bài viết
Điểm đánh giá: 202 (khá)

Đã gửi 13 June 2012 - 09:13 AM

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?
  • 0
Hình đã gửi

#20 Doan Van Ha

Doan Van Ha

    biết lệnh adcenter

  • CADViet Team
  • PipPipPipPipPipPipPip
  • 5454 Bài viết
Điểm đánh giá: 2626 (tuyệt vời)

Đã gửi 13 June 2012 - 09:43 AM

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?
  • 0

* Chỉ nên yêu cầu Lisp khi bạn làm việc đó mất cả ngày nhưng họ chỉ viết 1 giờ. Đừng nêu yêu cầu Lisp khi bạn chỉ làm 1 giờ nhưng bắt họ phải mất cả ngày.

* Nhờ viết lisp cũng như đi khám bệnh. Chỉ gởi căn cước và than sắp chết thì không bác sỹ nào cứu sống được.