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

Thaistreetz

Nhà quảng cáo
  • Số lượng nội dung

    905
  • Đã tham gia

  • Lần ghé thăm cuối

  • Ngày trúng

    29

Bài đăng được đăng bởi Thaistreetz


  1. Tiếp tục là 1 hàm xử lý list khá tiện dụng của acet: ACET-LIST-GROUP-BY-ASSOC. hàm này sẽ nhóm các phần tử trong list có cùng "assoc" (phần tử đầu tiên giống nhau)

    (defun CV:list-group-by-assoc (lst / lst-i name)
    (setq name (caar lst))
    (mapcar '(lambda (x) (if (= name (car x)) (setq lst-i (append lst-i (cdr x)) lst (vl-remove x lst)))) lst)
    (if lst (append (list (cons name lst-i)) (cv:list-group-by-assoc lst)) (list (cons name lst-i))))

    Test:

    (setq lst '(("a" 1 2) ("a" 3 4) ("b" 1 2) ("a" 5 6) ("b" x y z) ("c" 1 2 3)))

    (CV:list-group-by-assoc lst) => (("a" 1 2 3 4 5 6) ("b" 1 2 X Y Z) ("c" 1 2 3))


  2. 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:


  3. 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?


  4. 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


  5. @ketxu:

    dân kiến trúc thì thường sử dụng khung tên block bởi vì họ thường để tất cả bản vẽ của mình chỉ trong 1 file dwg duy nhất (hoặc có thể 2 hoặc 3 chứ không nhiều) việc chỉnh sửa thông tin không mất quá nhiều công sức.

     

    Còn dân cầu đường bọn mình thì 1 công trình có rất nhiều hạng mục riêng biệt nên fải tách làm nhiều file dwg. khi đó khung tên block không fù hợp nữa bởi mỗi lần thay đổi thông tin thì fải mở tất cả bản vẽ ra để thay đổi. Giải pháp thường được dùng cho dân cầu đường là sử dụng 1 file xref khung tên chứa các thông tin chung (tên chủ đầu tư, tên công ty, tên công trình, tên ku sếp ...) kết hợp với 1 block chứa các thông tin riêng của từng bản vẽ (tên bản vẽ, số thứ tự, tỷ lệ, hạng mục, người thiết kế...) dùng phương pháp này khi cần thay đổi các thông tin chung thì việc duy nhất fải làm là thay đổi thông tin của file xref, toàn bộ bản vẽ liên kết với nó sẽ thay đổi theo.

     

    Mình có viết 1 chương trình in ấn dùng loại khung tên này. tuy nhiên nó chỉ phù hợp với khung tên và cách quản lý bản vẽ của cty mình nên rất tiếc là không đóng góp gì được.

    • Vote tăng 1

  6. Các bác có cái hàm con nào lấy tọa độ ucs (điểm chèn) của đối tượng không cho mình xin. dạo này mình mắc bệnh lười, ngại viết quá, hề!:

    nếu đối tượng thuộc đối tượng khối (block, xref, dim...) thì cũng quy nó về ucs luôn. Mục đích của mình là để tìm vị trí của đối tượng trong bản vẽ thôi :D


  7. đọc cái quy tắc của bác DVH sao mà trừu tượng rối rắm thế (!?)

    Mình toàn làm kiểu thế này cho nó đơn giản và tiện lắp ghép không sợ nhầm lẫn : (phần màu đỏ là fần cần bỏ)

    (car (cdr)) = (ca-dr) = (cadr)

    (cadr (cadr)) = (cad-adr) = (cadadr)

    (car (cadadr)) = (ca-adadr) = (caadadr)

    (cadr (cadr (car))) = cad-ad-ar = (cadadar)

     

    => Chốt hạ 1 câu ngắn gọn là: hãy bỏ 3 ký tự nối giữa 2 hàm "r(c" bạn sẽ có 1 hàm gộp của 2 hàm đó

     

    Vì mình viết code bằng vlide nên danh sách các hàm hỗ trợ đã được nhận biết. với quy tắc trên, nếu kết quả không thuộc danh sách các từ khóa được bảo vệ (các từ khóa được bảo vệ tự động chuyển sang màu xanh dương khi ta hoàn thành từ khóa) thì có nghĩa ta không có hàm đó.

    • Vote tăng 1

  8. Tue_NV đã hoàn thành xong Lisp chọn số nguyên Z (type Z) -> INT , số thực R (type R) -> Real.

    -Số thực R không bao gồm cả số nguyên theo đúng (type R) -> Real

    -Code có xét tới trường hợp mà User nhập khoảng trắng (space) trước Text (Không biết do vô tình hay hữu ý) :rolleyes:

    Các bạn thử xem nhé.....

    ;;;;1. Chon so thuc tap R
    (setq so (ssget '((0 . "*TEXT") (1 . "~*[~-0--9~~ ]*") (1 . "*`.*") )))
    
    ;;;;2. Chon so thuc R>= 0
    (setq so (ssget '((0 . "*TEXT") (1 . "~*[~`.0-9~~ ]*") (1 . "*`.*") )))
    
    ;;;;3. Chon so thuc R>0
    (setq so (ssget '((0 . "*TEXT") (1 . "~*[~`.0-9~~ ]*") (1 . "*`.*")  (1 . "~0*"))))
    
    ;;;;4. Chon so thuc R<= 0
    (setq so (ssget '((0 . "*TEXT") (1 . "~*[~-0--9~~ ]*")  (1 . "0.0*,*`-*.*")  )))
    
    ;;;;5. Chon so thuc R< 0
    (setq so (ssget '((0 . "*TEXT") (1 . "~*[~-0--9~~ ]*")  (1 . "*`-*.*")  )))
    
    ;;;;6. Chon so nguyen Z
    (setq so (ssget '((0 . "*TEXT") (1 . "~*[~-0-9~~ ]*"))))
    
    ;;;; 7. Chon so nguyen Z>=0
    (setq so (ssget '((0 . "*TEXT") (1 . "~*[~0-9~~ ]*"))))
    
    ;;;;8, Chon so nguyen Z>0
    (setq so (ssget '((0 . "*TEXT") (1 . "~*[~0-9~~ ]*") (1 . "~0*") )))
    
    ;;;;;9. Chon so nguyen Z<=0
    (setq so (ssget '((0 . "*TEXT") (1 . "~*[~-0-9~~ ]*") (1 . "*[-0]*"))))
    
    ;10. Chon so nguyen Z<0
    (setq so (ssget '((0 . "*TEXT") (1 . "~*[~-0-9~~ ]*") (1 . "*`-*"))))
    

    Em từng thấy cái này ở đâu rồi thì fải. ???! :huh:


  9. bạn duyệt từ đầu đến đít chuỗi bằng while. mỗi lần lấy 1 ký tự.

    - Nếu kí tự đó là "\" thì đọc tiếp ký tự kế tiếp.

    + Nếu ký tự kế tiếp là "U" thì chắc chắn đó là 1 ký tự unicode. nhảy 1 fát 7 bước để duyệt tiếp và biến đếm tăng 1 đơn vị

    + Nếu ký tự kế tiếp là "n" hoặc "P" hoặc "t" hoặc """ hoặc "\"thì nhảy 1 fát 2 bước để duyệt tiếp và biến đếm tăng 1 đơn vị

    + Nếu khác 2 trường hợp trên thì nó là 1 ký tự bình thường. biến đếm tăng 1

    Giá trị của biến đếm cuối cùng là chiều dài thực của chuỗi

    • Vote tăng 1

  10. Phần lớn nguyên nhân là do không cùng đơn vị bản vẽ. Đối tượng xref vào bị tự đông thiết lập Unit mặc định là unitless dù trước đó bạn đã thiết lập không fải chế độ này. Trường hợp như vậy bạn open xref trực tiếp từ bản vẽ để thiết lập lại cho cùng đơn vị với bản vẽ đích. sau đó detach xref đó đi rồi attach lại là được

    • Like 1

  11. Code lật ngược thế trận này đẹp quá:

    (setq *n (not *n))

    Đẹp nhưng tăng 1 biến toàn cục. => không nên

     

    để viết được lệnh này như bạn chủ topic yêu cầu mà không fải sử dụng 1 biến toàn cục thì cần kiểm tra màu của các layer. layer bị off nếu màu của nó = màu thực nhân với -1.

    từ nguyên tắc này có thể viết được 3 lệnh layon; layoff và layiso mà không cần express

    • Vote tăng 2

  12. Mình thấy yêu cầu của victor

    Vĩ đại! Vĩ đại! Ý tôi muốn nói là mong muốn của bạn quá lớn.

    Trích dẫn ngắn cho bạn dưới đây để thấy một đối tượng tổng quát thì có tới hàng trăm thuộc tính lận. Và bạn muốn thay đổi tất tần tật?

                   	LAYER
                   	COLOR
                   	LINETYPE
                   	LINEWEIGHT
                   	ALIGNMENT
                   	ARCLENGTH
                   	AREA
                   	ATTACHMENTPOINT
                   	CENTER
                   	CIRCUMFERENCE
                   	CLOSED
                   	CUSTOMSCALE
                   	DEGREE
                   	DIAMETER
                   	DISPLAYLOCKED
                   	ELEVATION
                   	HEIGHT
                   	LENGTH
                   	MEASUREMENT
                   	OBLIQUEANGLE
                   	RADIUS
                   	ROTATION
                   	SCALEFACTOR
                   	STYLENAME
                   	TEXTOVERRIDE
                   	TEXTSTRING
                   	TOTALANGLE
                   	WIDTH
    

    Bác hiểu máy móc ý của người ta. Yêu cầu của Victor quá rõ ràng còn gì. Chỉ là thay đổi 1 chút về cách thức chọn đối tượng của lệnh Matchpro thôi chứ có gì to tát vĩ đại đâu. mấy cái tính chất bác nêu quan tâm làm gì cho mệt. việc đó đã có lệnh matchpro làm.

     

    Câu trả lời cuối cùng thì quá đơn giản như bác thấy đấy thôi:

     

    ai nói bạn Matchrop không làm được? Đầu tiên bạn cứ qslect hay find gi đó tùy thích, xong thoat ra khoi lệnh đó. bây giờ gõ lệnh MATCHPROP , sau khi chọn dt mẫu xong, gõ P thì cad vẫn hiểu P là những thằng mà khi nãy bạn lọc ra.


  13. bạn để nguyên (không thay thế \\ bằng /) mà đưa thẳng vào clipboad thì nó vẫn ra đường dẫn chuẩn cho bạn cơ mà

    thử paste ra word hay notepad mà xem. lằng nhằng chi vậy bạn?

     

    Trong ngôn ngữ lisp. Một số ký tự đặc biệt không được thể hiện bằng cách thông thường vì các ký tự đó được dùng vào mục đích khác. hoặc không có phím nào thể hiện được ký tự đó

    Ví dụ: ký tự nháy kép " được dùng cho mục đích đánh dấu điểm đầu và cuối 1 chuỗi. Các ký tự tab, Xuống dòng, các tổ hợp nhận biết các bảng mã...

    Vì vậy lisp fải sử dụng 1 tổ hợp ký tự thay thế để thể hiện các ký tự trên bằng cách đặt trước các ký tứ đó 1 dấu \

    Cụ thể: \" = " ; \n = xuống dòng (chuỗi đơn line) ; \P = xuống dòng (chuỗi multi Line) ; \t = tab ...

    Khi đó do bị lấy fục vụ vào mục đích trên nên bản thân ký tự \ lại không thể dùng để thể hiện chính nó nữa. và nó vô tình cũng trở thành 1 ký tự đặc biệt với nhóm trên. vì vậy để thể hiện nó thì cũng theo nguyên tắc trên ta có \\ = \

    Vì thế khi lisp đọc 1 chuỗi C:\program file\autodesk thì nó thể hiện ra là C:\\program file\\autodesk . thực tế nó vẫn là C:\program file\autodesk


  14. Mình đã test qua while và repeat, kết quả là tương đương nhau :D, mấy trường hợp khác chắc để mở topic riêng dể test thêm.

    riêng phần so sánh giữa các ngôn ngữ thì đây là kết quả benchmark của Autodesk:

    Acad%20API%20benchmarks.png

    Ủng hộ Detailing 1 fiếu cho việc lập topic so sánh. Ngoài ra vì diễn đàn này đang có 1 đội ngũ con chiên của LISP khá hùng hậu nên có thể test bằng 2 fép thử: Autolisp và Visual lisp (Hiện có khá nhiều tranh cãi về vấn đề này, một số tài liệu mình đọc được khẳng định Visual lisp chậm hơn Autolisp và khuyên lập trình viên hãy sử dụng Autolisp nếu có thể. Nhưng một số tài liệu khác thì cho rằng điều ngược lại mới đúng, phép thử trên của bạn và kết quả của autodesk trên đây phần nào khẳng định lại điều đó)

    Ngoài ra phép thử với visual lisp cũng có thể dùng để đánh giá thực tế VBA khi chuyển về Visual lisp tốc độ thay đổi thế nào?

    • Vote tăng 1

  15. Bạn có thể nói rõ thao tác của lệnh Textmask không. mình thực hiền mà không được

    . ở đây mình phải br nó đi để nhìn cho rễ.

    (Nếu không Break thì mình có cách làm như thế này: Tạo block cái text đó có cả WIPEOUT sau đó dùng lệnh MEASURE là OK)

    Nhưng sếp lại kêu là Break đi bạn ah.

    Bảo sếp của bạn: ông bắt tôi break ra rồi nếu có phải chỉnh sửa sau này thì ông tính sao?

     

    - Nếu đó là đường đồng mức và chữ số ấy là nhãn của đường đồng mức, mà sếp bạn yêu cầu như vậy thì hắn bị hâm hoặc chả biết gì về cách thức làm việc với số liệu của bản vẽ. đừng có nhắm mắt nghe cái dốt của hắn. hãy làm theo cách ketxu bày cho bạn.

     

    - Nếu đó không phải là đường đồng mức mà chỉ là 1 đường mục đích ghi chú gì đó thì tốt hơn là bạn tạo 1 linetype.

    • Vote tăng 1

  16. Choáng quá! Lisp chậm hơn gần 10 lần, và tệ nhất bọn; .NET chậm hơn 2 lần

    Kết quả trên còn chưa phản ánh đúng tốc độ thực sự của arx do quá trình tính toán đươc thực hiện thông qua 1 hàm .NET, chưa kể đến việc phép thử dành cho arx còn thực hiện cuối cùng. Như vậy thực tế còn nhanh hơn nữa. Buồn cho em lisp :D


  17. Theo e thì dùng while nhanh hơn bác ạ. Mà bác chạy từ sslength chạy ngược về thì cons sẽ thành list chuẩn, sao lại rev mần chi ^^

    ACET thì ta biết rồi, dính vào thằng ARX ^^

    Đúng rồi, Ketxu rất tinh ý. Mình nhớ nhầm, ban đầu mình sử dụng 1+ thấy rườm rà hơn nên đổi về 1-

    Về mấy vòng lặp, mình chưa từng kiểm tra sự chênh lệch tốc độ giữa while, foreach và repeat. Mình suy nghĩ chủ quan rằng với những fép lặp có thể xác định trước số lần lặp thì repeat là nhanh nhất bởi while có thêm yêu cầu kiểm tra điều kiện lặp. có lẽ fải test lại mới được.


  18. Thiệt tình là như cái hàm đã nói thì bần tui cũng đi mót thôi. Sau đó lấy búa gõ ra từng miếng rồi ngâm... rượu. Có cái ngâm nó ngọt, có cái ngâm nó đắng lè.

    Nhưng chắc chắn 100% kết quả của hàm trên là đúng. Biết đâu thằng acet nó cũng viết kiểu đó bác ạ.

    Có thể trả lời chắc chắn cho bác Hà biết là Acet nó không viết hàm trên như thế. Có thể nó không dùng lisp để viết mà dùng ngôn ngữ khác cho tốc độ nhanh hơn. Mình đã tốn tương đối nhiều công sức để viết 1 hàm chuyển đổi selection set về list. Cách viết như trên chỉ là 1 trong số các cách mà mình từng viết. Khi viết mình ưu tiên tốc độ vì hầu hết chương trình của mình đều thường xuyên fải xử lý con số hàng nghìn đối tượng. (hình như bác cũng chuyên ngành cầu đường nên chắc sẽ hiểu vì sao lại nhiều như vậy)

     

    Kết luận: Cách trên là cách triển khai code ngắn gọn nhất, nhưng nó cũng là cách viết tệ nhất vì nó cực chậm. Chậm hơn acet có khi đến cả 1000 lần. Nguyên nhân gây chậm chính là ở hàm ssnamex. Các cách viết khác sử dụng hàm ssname cho tốc độ gần bằng acet. Tuy nhiên mình chưa viết được 1 hàm nào nhanh bằng hoặc hơn acet-ss-to-list cả. Đây là lựa chọn cuối cùng của mình để thay thế cho acet:

    (defun ss->list (ss / i lst) (if ss (repeat (setq i (sslength ss)) (setq lst (cons (ssname ss (setq i (1- i))) lst)))))

    Đúng ra fải reverse kết quả mới đúng thứ tự. tuy nhiên do ít khi có nhu cầu nên mình cũng bỏ hàm này luôn. khi nào cần list kết quả đúng thứ tự thì viết thế này (reverse (ss->list ss))

    • Vote tăng 3
×