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

ngokiet

Thành viên
  • Số lượng nội dung

    404
  • Đã tham gia

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

  • Ngày trúng

    43

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


  1. À mình mới thử. Thấy đúng. string hay int đều được.

     

    @vanlam6408 Hình như bác ít test bằng Console trong vlide.

    Bác vào vlide nhấn F6. Cửa sổ dòng lệnh hiện ra thì bác có thể test thoải mái mà.

    Ví dụ như đánh 

    (vla-put-color (vlax-ename->vla-object(car(entsel))) "2")

    Thì nó sẽ cho chọn object và set color là 2.

    Hay nhấn (getvar "CECOLOR") là nó trả lới giá trị của cecolor.

    Vì vậy bạn có thể test nhanh lệnh nào sai để sửa lại cho đúng. Lệnh gộp cũng có thể tách ra test thử.

    Hy vọng bác có thể nhanh viết lisp được riêng cho mình.

    Mình không thích vla nhiều mà thích lisp thường hơn. Nó nhanh hơn dùng vla vì khi sài vla nó sửa từng lần 1 trong bản vẽ. Còn entmod thì nó sửa 1 lần nên nhanh hơn. Nhất là khi vẽ mấy bãng table. Vla thích hợp khi đọc dữ liệu từ các app khác nhiều hơn.


  2. 4 phút trước, NTHAHT đã nói:

    Bác @ngokiet, nói đúng rồi, mình không để ý cái color...

    Làm cho bạn cái VL...

    (mapcar '(lambda (x)
                 (mapcar '(lambda (p v) (vlax-put x p v))
                         '(layer Color Linetype LineWeight)
                         (list (getvar "clayer")
                               (cond ((eq (setq cc (getvar "CECOLOR")) "BYLAYER") 256)
                                     ((eq cc "BYBLOCK") 0)
                                     (cc))
                               (getvar "CELTYPE")
                               (getvar "CELWEIGHT"))))
              (mapcar 'vlax-ename->vla-object
                      (vl-remove-if 'listp (mapcar 'cadr (ssnamex (ssget))))))

    (getvar "CECOLOR") của mình nó cho ra kết quả string nên cái (cc) sau đổi thành (atoi cc)

     

     

     @vanlam6408 

    Cái cc chỉ cho vla-put-color thôi.

    Bác sửa đoạn (vla-put-Color x (getvar "CECOLOR")) thành (vla-put-Color x cc) các thứ khác giữ nguyên.

     

    Còn lỗi  "error: bad DXF group: (-1 . #<VLA-OBJECT IAcadLWPolyline 2342be54>)" là do bác dùng list là object chứ không phải là ename.

    Còn không có acet thì lisp trên của mình sửa lại vậy.

    (setq ll (list (cons 8 (getvar 'clayer)) (cons 6 (getvar 'celtype)) (cons 62 (if (eq (setq ll (getvar "cecolor")) "BYLAYER") 256 (if (eq ll "BYBLOCK" ) 0 (atoi ll)))) (cons 370 (getvar 'celweight)))) (mapcar '(lambda(x) (entmod (cons (cons -1 x) ll))) (vl-remove-if 'listp (mapcar 'cadr (ssnamex (ssget)))))

     

    • Like 1

  3. 51 phút trước, NTHAHT đã nói:

    Trong đoạn màu đỏ viết đúng, nhưng bạn cần cho mọi người xem lý lịch của đồng chí này: entlst1

    Mình nghĩ nó sai ở đây (vla-put-Color x (getvar "CECOLOR")) vì khi Cecolor = Bylayer hay byblock sẽ bị lỗi.

    Vì vậy cần làm thêm biên cc (thêm dòng này trước lệnh mapcar)

    (setq cc (if (eq (setq cc (getvar "cecolor")) "BYLAYER") 256 (if (eq cc "BYBLOCK" ) 0 (atoi cc))))

    và sửa thành (vla-put-Color x cc)

     

    Còn làm thử theo entmod

    (setq ll (list (cons 8 (getvar 'clayer))
    		 (cons 6 (getvar 'celtype))
    		 (cons 62 (if (eq (setq ll (getvar "cecolor")) "BYLAYER") 256 (if (eq ll "BYBLOCK" ) 0 (atoi ll))))
    		 (cons 370 (getvar 'celweight))))
      (mapcar '(lambda(x) (entmod (cons (cons -1 x) ll))) (acet-ss-to-list (ssget '((0 . "CIRCLE")))))

     

     

     

     

     

     


  4. Bạn nên nghiên cứu các lệnh và biến 1 chút mới xử lý được. Xem khi biến CECOLOR , CELTYPE , CELWEIGHT khi ByLayer, ByBlock là có giá trị như thế nào?

    So sánh với các hàm vla thì giá trị tương ứng là bao nhiêu vì có thể khác nhau. Mình ko trên máy nên ko test được. Mấy hàm vla mình ít sài nên ko nhớ rõ lắm.

    không chừng bác dùng hàm vẽ lại circle đó rồi xoá cái cũ đi cũng dễ hơn. :-)


  5. 18 phút trước, TRUNGNGAMY đã nói:

    Mình tính hỏi các bạn cái này nhưng không biết để đâu cho tiện, đành để ở đây, nếu không đúng xin thứ lỗi.

    Mình có câu lệnh lisp như sau:

    (command "_.insert" "M_XY_KV" p 1 "" 0 "1")

    Đây là lệnh chèn block "M_XY_KV" có thuộc tính "1" tại vị trí p.

    Nếu thực hiện từ cad2013 về trước thấy vẫn bình thường,

    nhưng khi làm trên cad2017 nó lại hiện lên khung đối thoại để nhập.

    Vậy làm sao cho nó nhận trị "sohieu" như cad 2013 được mà không cần hiện hộp thoại.

    Nhờ các bạn chỉ giúp. Cám ơn các bạn

    M_XY_KV.dwg

    Bác thử (setvar 'attdia 0)  xem

    • Like 1

  6. Vào lúc 7/8/2020 tại 08:12, Ma Vương đã nói:

     

    Mình cũng bị như bạn, kiếm trong CUI không thấy phím tắt F1 của help để mà tắt.
    Chờ các bạn cao thủ

    Nó có có đâu mà thấy. Bạn có thễ lạo lệnh m2p như hướng dẫn để gán cho F1 hay Tìm lệnh cancel để gán cho F1 để chuyển F1 thành Cancel như ESC. Nếu ko có gán thì nó là help.


  7. Nếu bạn sài cad đời cao thì bạn gán biến dimlayer là dim thì dim nó sẽ tạo ở layer dim.

    còn bạn muốn viết lisp thì phải kết thúc lệnh command thì mới setvar clayer lại được.

    ví dụ:

    (defun c:dl(/ ll)
      (setq ll (getvar 'clayer))
      (setvar 'clayer "dim")
      (command "_dimlinear")
      (while (/= (getvar 'cmdactive) 0) (command pause))
      (setvar 'clayer ll))

     

    • Vote tăng 1

  8. Bác xem lại nết vẽ ấy. Do in laser nên nét nó chính xác quá nên không thấy. Layer Hatch của bạn là nét 0.05mm nên 1 chấm rất nhỏ. Hatch bên cạnh có chấm nhưng cũng ko thấy.

    Nếu hatch chấm thì nét vẽ phải hoi lớn 1 chút.

    Còn file pdf hiển thĩ trên màn hình thì nó luôn lấy nét tối thiểu mà nó hiển thị nên bạn thấy là đương nhiên.

    Còn bảng propertive thì do định dạng units của bạn thì nó hiển thị thôi. Giá trị đúng của nó vẫn là 0.2 hay 0.6 nó làm tròn để hiển thị thôi.


  9. 1 giờ} trướ}c, thiep đã nói:

    Sai như thế nào bạn?

    Bác viết có test lại chưa vậy? Mình nhìn đoạn lisp là biết bất kỳ 3 diễm nào thuộc các mp vuông góc với 3 trục nó đều cho kết quả là collinear.

    Lisp bác cũng gần như tính pháp vector. Nhưng bác cho ràng 2 giá trị = 0 là thẳng hàng là sai. Vì nếu giá trị còn lại #0 là bằng 2x diện tích tam giác có 3 đỉnh pt đó #0 nên nó không thẳng hàng dc.

     Dùng cách của leeMac

    ;; Collinear-p  -  Lee Mac
    ;; Returns T if p1,p2,p3 are collinear
    
    (defun LM:Collinear-p ( p1 p2 p3 )
        (
            (lambda ( a b c )
                (or
                    (equal (+ a b) c 1e-8)
                    (equal (+ b c) a 1e-8)
                    (equal (+ c a) b 1e-8)
                )
            )
            (distance p1 p2) (distance p2 p3) (distance p1 p3)
        )
    )

    Theo cách pháp vector mình viết lại  (Cách này mình chưa kiểm tra điểm 2d (caddr a/b/c) = nil)

    (defun iscollinear(a b c)
        (setq b (mapcar '- b a)
    	  c (mapcar '- c a))
        (and (equal (* (cadr b) (caddr c)) (* (caddr b)(cadr c)) 1e-6)
    	 (equal (* (caddr b) (car c)) (* (car b)(caddr c)) 1e-6)
    	 (equal (* (car b) (cadr c)) (* (cadr b)(car c)) 1e-6)))

    Còn 1 cách nữa là chứng minh 2 vector AB AC cùng phương. Thì 3 điểm ABC thẳng hàng. Nhưng viết khá rắc rối một chút.


  10. Mình đâu nói lisp bác sai gì đâu. Do post này đang nói về 3d. Nên cái lisp nó hơi sai chủ đề 1 chút.
    - còn cái lisp bác mới viết thì sai rồi đấy.

    Tích vô hướng dùng để tính diện tích tam giác bất kỳ qua 3 điểm. Khi S =0 là 3 điểm mới thẳng hàng.
    Lisp bác hơi rối. Mình góp ý 1 chút là : (equal (- a b) 0 fz) <=> (equal a b fz) dễ nhìn và hiệu quả hơn.

     


  11. Vào lúc 14/7/2020 tại 00:14, thiep đã nói:

    ;; Collinearity check (Lee Mac)

    (defun isCollinear ( p1 p2 p3 fz ) (equal (rem (angle p1 p2) pi) (rem (angle p2 p3) pi) fz) )

    Thông thường, để xét 3 điểm có thẳng hàng không, Thiệp dùng đoạn mã này:

    (setq v  (mapcar '- P1 P2)
            w    (mapcar '- P3 P2)  

    )

    (if (equal (- (* (car v) (cadr w)) (* (cadr v) (car w)) 0 1e-6)

    (princ "3 point p1 p2 p3 is collinear)

    (princ "3 point p1 p2 p3 isn't collinear))

    Collinear của leemac ở trên hình như cũ lắm rồi dễ lỗi khi góc là 0 và gần bằng pi.Mà cái này thường xảy ra vì cơ bản máy tính có sai số tuy rất nhỏ vì (rem x pi)= x nếu x<pi dù rất nhỏ. (Cái này mình bị rồi)

    Còn lisp bác @thiep đưa ra tuy giải quyết được vấn đề này nhưng cả 2 líp đều chỉ ứng dụng cho 2d là hình chiếu bằng mà thôi.

    Trong 3D thì 3 điểm ABC thẳng hàng thì ngoài cách tính tích có hướng 2 vector AB,ÁC bằng (0,0,0)  thì leemac dùng cách tính cạnh tâm giác có thể dùng cho cả 2d và 3d là có 1 cạnh bằng tổng 2 cạnh còn lại.

    Viết líp thì chắc dễ nên mình ko viết. Lấy của leemac vậy

    http://www.lee-mac.com/mathematicalfunctions.html#geometric


  12. (defun c:test ( / point et)
      (setq point (getpoint "\nPick diem trong vung kin"))
      (while point
        (if (setq et (bpoly point))
          (progn
            (entmake
                (append
                   '((000 . "LWPOLYLINE") (100 . "AcDbEntity") (100 . "AcDbPolyline") (090 . 4) (070 . 1))
                    (mapcar '(lambda ( p ) (cons 10 p)) (LM:boundingbox (vlax-ename->vla-object et)))))
    	(entdel et)))
        (setq point (getpoint "\n Chon diem tiep theo: ")))
      (princ))
    (vl-load-com) 
    ;; Bounding Box  -  Lee Mac
    ; Returns the point list describing the rectangular frame bounding the supplied object.
    ; obj - [vla] VLA-Object
    
    (defun LM:boundingbox ( obj / a b lst )
        (if
            (and
                (vlax-method-applicable-p obj 'getboundingbox)
                (not (vl-catch-all-error-p (vl-catch-all-apply 'vla-getboundingbox (list obj 'a 'b))))
                (setq lst (mapcar 'vlax-safearray->list (list a b)))
            )
            (mapcar '(lambda ( a ) (mapcar '(lambda ( b ) ((eval b) lst)) a))
               '(
                    (caar   cadar)
                    (caadr  cadar)
                    (caadr cadadr)
                    (caar  cadadr)
                )
            )
        )
    )
    (princ)

    Mình nghĩ nên làm thế này dễ hơn là sài Entlast và command vì lisp có lệnh bpoly.

    Còn lệnh command boundary thì đôi khi nó có nhiều hơn 1 vùng kín phía trong nên có thể tạo ra nhiều hơn 1 pl. Và lệnh bpoly nó trả về được pl nó tạo ra luôn. Đồng thời thông báo nếu ko kín luôn.

     

    • Like 2
    • Vote tăng 1

  13. Bác nhầm khi dùng từ rồi. Vector, phương và hướng.

    1 mặt phẳng có thể xác định băng 1 điểm và phương pháp tuyến.

    Nhưng 1 phương có 2 hướng ngược chiều nhau. Mà Cad khi muốn tính toán trong 3D thì nó cần có hướng extrusion direction để xác định chính xác các vật thể có chiều cao. Còn điểm thì nó lấy mặc định là tọa độ gốc. Và extrusion direction của Cad Là 1 vector có độ lớn là 1. Tuy nhiên AutoCAD có thể đã tụ tính lại. Nó chỉ cần phương và hướng thôi. Cad khác thì mình ko biết nên nhắc chủ thớt kt lại.
    Do yêu cầu là vẽ pl trên 1 mặt phẳng bất kỳ thì nó chỉ ảnh hưởng phương. Nhưng nếu pl có thíckness thì có hướng mới chính xác.

    Các lisp trên khi vẽ pl thì đều thực hiện đúng. Tuy nhiên ent tạo ra đôi khi ngược hướng z nhau. Ví dụ như vẽ qua 3 điểm ABC và ACB thì 2 pline nó có dxf 210 nó ngược nhau.

    cái này nó sẽ ảnh hưởng các líp khác vì ít lisp đọc lại cái dxf 210 này. Mà lúc đó giá trị dxf 10,38 nó khác nhau.


  14. @thiep Mình lần đầu tiên mình nghe nói 1 mặt phảng chỉ có duy nhất 1 vector pháp tuyến. Mình mới kt lại google thì đại đa số nói là 1 mở có vô số vector pháp tuyên và vector bác đua chỉ là 1 trong đó mà thôi.

    Còn 1 mặt phẳng có thể có nhiều phương trình nhưng 1 phương trình thì chỉ có 1 mặt phẳng. Đôi khi A là B nhưng B không là A.

    Còn mình viết tự định quy tắc ko giống ai. là trong lập trình riêng của mình thôi. Còn trả lời trên này mình vẫn rất quy củ đấy. Cho nên bác ko nên trích 1 phần câu ra để soi mói như vậy.


  15. @gia_bach Tích có hướng 2 vecto là vậy, Nhưng mặt phẳng thì khác. Nếu đảo 2 vecto ab với nhau thì  tích có hướng nó ngược lại. Nhưng nó cũng là 1 mặt phẳng chung.

    Trong cad thì khi 2 polyline có chung mp nhưng ngược assoc thì có thể join lại với nhau. Và nó tính lại tọa độ của 1 trong 2 đường đó.

    Với lại khi tạo polyline theo 3 diểm như bạn thì có thể bị lỗi nếu dùng để vẽ 3d vì z direction có thể không theo ý muốn. 

    Mình thấy viết lisp liên quan 3d khá khó vì có nhiều trường hợp xảy ra hơn 2D. Ví dụ như lisp bác xét 3 diểm thẵng hàng bắng lệnh angle thì lệnh angle chỉ tính được góc chiếu bằng thôi. Cho nên cần cẩn thận khi viết lisp 3d.

    • Like 1

  16. 1 giờ trước, thiep đã nói:

    Mọi mặt phẳng trong không gian có phương trình tổng quát có dạng :  Ax + By + Cz +D = 0  Khi đó vectơ  '(A  B  C) là vectơ pháp tuyến của mặt phẳng.

    Vì vậy với 1 mặt phẳng, theo quy ước chỉ có 1 vecto pháp tuyến mà thôi.

    Điều này hình như có liên quan đến quy tắc bàn tay phải, nghĩa là: nếu ta bẹt 3 ngón tay của bàn tay phải sao cho vuông góc nhau như 3 trục hệ toạ độ vuông góc: ngón tay trỏ là hướng dương trục Ox, ngón tay giữa là trục Oy thì ngón tay cái là vecto pháp tuyến của trục Oz.

    Vậy có điều kiện ABCD như thế nào không? Ví dụ như 0x+0y+1z -5=0 với 0x+0y-1z+5=0 là 1 mặt phẳng. Nhưng khi lấy ABC là 0 0 1 và 0 0 -1 là 2 vecto đối nhau.

    vì vây khi tính tích có hướng thì làm sao xác định nó là pháp vecto hay là Vectơ đối?

    Lập trình mình quên quy tắc toán nhiều nên đôi khi tự định quy tắc ko giống ai.


  17. Mình nghĩ AutoCAD có tính toán lại. Vì 1 mặt phẳng có 2 pháp vector ngược nhau. Nên khi entmake nó phải tính lại hướng. Ví dụ như ‘(0 0 1) và ‘(0 0 -1) thì nó tính như nhau. Nên tính đúng assoc 210 phải kiểm tra thêm. Nên cho Cad tính luôn. Mình ko biết Cad khác có vậy ko. Nếu có xem có lỗi gì khi pháp vector ngược nhau.


  18. 4 phút trước, gia_bach đã nói:

    @ngokiet

    - A210 phải tính vecto đon vị, đã kiểm tra.

    - ok tr/hợp thẳng hàng đưa về (0 0 1) là chưa chính xác.

    (defun c:test(/ en lp a210 a70 p1 p2 p3)
      (defun nor(a b c)
        (setq b (mapcar '- b a)
    	  c (mapcar '- c a))
        (list (- (* (cadr b) (caddr c)) (* (caddr b)(cadr c)))
    	  (- (* (caddr b) (car c)) (* (car b)(caddr c)))
    	  (- (* (car b) (cadr c)) (* (cadr b)(car c)))))
    	  
      (setq en (car(entsel "select 3d polyline"))
    	lp (acet-geom-vertex-list en))
      (mapcar 'set '(p1 p2 p3) lp)
      (setq a210 (nor p1 p2 p3)) ;(cal "nor(p1,p2,p3)"))
      (if (eq (car lp) (last lp))
        (setq a70 1
    	  lp (reverse (cdr (reverse lp))))
        (setq a70 0))
      (setq lp (mapcar '(lambda(x) (trans x 0 a210)) lp))
    	
      (entmakex (append
    	      (list '(0 . "LWPOLYLINE") '(100 . "AcDbEntity") '(100 . "AcDbPolyline")
    		    (cons 38 (caddar lp)) (cons 90 (length lp)) (cons 70 a70))
    	      (mapcar '(lambda(x) (list 10 (car x) (cadr x))) lp)
    	      (list (cons 210 a210))))
      (princ))

    Mình thử thấy vẫn ok mà . 


  19. 29 phút trước, gia_bach đã nói:

    Xin cám ơn tất cả mọi người đã đọc và đóng góp ý kiến cho chủ đề này, nói chung là các code-Lisp đều chạy tốt trên AutoCAD.

    Tuy nhiên do cá nhân tôi, từ khi viết tool cho nhiều nền tảng khác AutoCAD (vd: ZwCAD, BricsCad, IntelliCAD...) tôi thường có thói quen chỉ sử dụng các hàm thuần AutoLISP, hạn chế sử dụng các hàm built-in của AutoCAD như Express-tool (acet-*) hay VisualLISP (vla-*) khi có thể. Dĩ nhiên nếu không có cách khác thì phải sử dụng các hàm built-in thôi.

    Nếu chỉ dùng AutoCAD thì việc sử dụng các hàm này sẽ tiết kiệm rất nhiều thời gian và công sức, đạt hiệu suất cao vì đã được tối ưu cho AutoCAD. Và mục đích chính là làm cho AutoCAD phục vụ mình nhanh hơn, diệu kỳ hơn ... đã đạt được.

    Nhưng trong trường hợp phài sử dụng các phần mềm CAD khác (vì lý do bản quyền, chi phí đầu tư ...)  thì sẽ gặp khá nhiều khó khăn khi chuyển đổi, tính tương thích không cao (các CAD khác không hỗ trợ hoặc hỗ trợ rất kém các hàm này). Nếu muốn viết lại hàm thì không có công thức/thuật toán để chuyển đổi.

    Trên cơ sở các lisp của mọi người, xin cập nhật và hiệu chỉnh để có thể chạy với các CAD khác.

     

    
    ;; CrossProduct (Gile)
    ; Returns the cross product (vector) of two vectors
    ;
    ; Arguments: two vectors
    (defun CrossProduct (v1 v2)
     (list    (- (* (cadr v1) (caddr v2)) (* (caddr v1) (cadr v2)))
       (- (* (caddr v1) (car v2)) (* (car v1) (caddr v2)))
       (- (* (car v1) (cadr v2)) (* (cadr v1) (car v2)))
     )
    )
    
    ;; Normalize (Gile)
    ; Returns the single unit vector of a vector
    ;
    ; Argument : a vector
    (defun Normalize (v)
     ((lambda (l)
        (if (/= 0 l)
          (mapcar (function (lambda (x) (/ x l))) v)
        )
      )
       (distance '(0 0 0) v)
     )
    )
    
    ;; Norm_3Points (Gile)
    ; Returns the single unit normal vector of a plane definedby 3 points
    ;
    ; Arguments: three points
    (defun norm_3pts (p0 p1 p2)
     (Normalize (CrossProduct (mapcar '- p1 p0) (mapcar '- p2 p0)))
    )
    
    ;; Collinearity check (Lee Mac)
    (defun isCollinear ( p1 p2 p3 fz )
     (equal (rem (angle p1 p2) pi) (rem (angle p2 p3) pi) fz)
    )
    
    (defun c:test(/ lp p1 p2 p3 a210)
      (if
        (and
           (setq p1 (getpoint "\nChon diem 1"))
           (setq p2 (getpoint p1 "\nChon diem 2"))
           (setq p3 (getpoint p2 "\nChon diem 3"))       )
        (progn
          (setq p1 (trans p1 1 0)
    	    p2 (trans p2 1 0)
    	    p3 (trans p3 1 0))
          (if (isCollinear p1 p2 p3 1e-6)
    	(setq a210 '(0 0 1))
    	(setq a210 (norm_3pts p1 p2 p3)))
          (setq lp (list p1 p2 p3))
          (setq lp (mapcar '(lambda(x) (trans x 0 a210)) lp))
          (entmakex (append
    		  (list '(0 . "LWPOLYLINE") '(100 . "AcDbEntity") '(100 . "AcDbPolyline")
    			(cons 38 (caddar lp))(cons 90 (length lp)) )
    		  (mapcar '(lambda(x) (list 10 (car x) (cadr x))) lp)
    		  (list (cons 210 a210))))      )    )
      (princ))    

     

    - Cái a210 không cần tính về Normalize mà chỉ cần tính CrossProduct thôi là được rồi. Tính về CrossProduct thì khi entmake nó cũng tính lại hay sao đó. 

    - Còn kiểm tra 3 điểm thẳng hàng thì đơn giản hơn là CrossProduct là <> '(0 0 0) . (not (vl-every 'zerop a210)) 

       Trong trường hợp này bạn phải tính 1 vecto bất kỳ nào đó vuông góc với phương đó làm a210 chứ ko lấy '(0 0 1) vì nếu z khác nhau.

    (còn kiểm tra p1 p2 p3 không trùng nhau nữa)

     

     

    • Like 1
×