Bóc khối lượng đường ống, tính chiều dài gờ chắn, đo tổng chiều dài mạch điện, cộng chiều dài đường bao thửa đất. Bốn việc ấy cùng một dạng: có sẵn vài trăm nét trên bản vẽ, cần một con số tổng.
AutoCAD không có lệnh nào làm việc đó. LIST đọc từng đối tượng một, MEASUREGEOM đo mỗi lần một nét. Cộng tay ba trăm con số thì sai, mà sai thì không ai biết. Lisp tính tổng chiều dài giải đúng chỗ trống này, và bài này in trọn mã nguồn để bạn đọc trước khi chạy trên máy mình. Muốn học trọn khâu bóc khối lượng từ bản vẽ thì xem khóa AutoCAD Xây Dựng.
Lisp đo chiều dài trong CAD: vì sao phải có tệp riêng
Ba cách sẵn có của AutoCAD, và chỗ hụt của từng cách:
| Cách | Làm được gì | Hụt ở đâu |
|---|---|---|
LIST | In mọi thuộc tính của đối tượng đã chọn | Chọn 300 nét thì in 300 khối chữ, không cộng |
MEASUREGEOM | Đo chiều dài một đường | Mỗi lần một nét |
| Bảng Properties | Hiện ô chiều dài | Chọn nhiều nét cùng loại thì ô ấy trống |
Chỗ hụt chung: không có phép cộng. Bảng Properties là ví dụ rõ nhất — chọn một đường thì thấy ô Length, chọn mười đường thì ô ấy biến mất, vì phần mềm không biết bạn muốn tổng hay muốn từng cái. Bảng Properties có trong bài bảng Properties trong CAD.
Vậy nên việc cộng phải làm bằng một tệp lisp. Và tệp ấy chỉ đáng tin khi nó in ra bảng phân loại chứ không chỉ một con số trần, vì một con số trần thì không có cách nào kiểm.
Người đi tìm gõ vào ô tìm kiếm mỗi người một kiểu: lisp tổng chiều dài, lisp đo tổng chiều dài trong cad, hay lisp cad tính tổng chiều dài. Nhưng việc cần làm thì chỉ có một. Chọn một đống nét rồi lấy ra một con số tin được.
Về mặt kỹ thuật, mọi tệp làm việc này đều dựa vào cùng một hàm của AutoLISP. Tài liệu Autodesk mô tả hàm vlax-curve-getDistAtParam là "Returns the length of the curve's segment from the curve's beginning to the specified parameter". Hỏi nó tại tham số cuối của đường là ra trọn chiều dài. Cái hay là hàm này dùng chung cho mọi loại đường cong, nên không phải viết riêng cho đoạn thẳng, cung tròn, đa tuyến hay spline.
Tải lisp tính tổng chiều dài trong CAD của Viện
| Lệnh | Việc nó làm |
|---|---|
TCD | chọn đối tượng, in tổng chiều dài kèm bảng phân loại ra dòng lệnh |
TCDT | như trên, rồi ghi con số ấy thành một dòng chữ trên bản vẽ |
TCDL | cộng riêng từng lớp và in thành bảng |
Cả ba đều in cột số lượng bên cạnh cột chiều dài. Cột ấy có lý do tồn tại, và phần dưới sẽ chỉ rõ.
;;; ==================================================================
;;; DCD-IIC.LSP - cong tong chieu dai cac doi tuong da chon
;;; Vien Tin hoc Xay dung (IIC) - Truong Dai hoc Xay dung Ha Noi
;;; https://iic.huce.edu.vn - Tel: 0989 427 809
;;; ------------------------------------------------------------------
;;; Ba lenh:
;;; TCD chon doi tuong, in tong chieu dai ra dong lenh
;;; TCDT nhu tren, roi ghi con so ay thanh mot dong chu tren ban ve
;;; TCDL cong rieng tung LOP (layer) va in thanh bang
;;;
;;; Vi sao can tep nay: lenh LIST doc tung doi tuong mot, lenh MEASUREGEOM
;;; chi do mot doi tuong moi lan. Muon biet tong chieu dai 300 doan ong
;;; hay 80 doan duong bao thi phai cong tay, va cong tay thi sai.
;;;
;;; Cach lam: dung vlax-curve-getDistAtParam tren tham so cuoi cua
;;; duong. Ham nay dung cho MOI loai duong cong nen khong phai viet
;;; rieng cho line, cung tron, da tuyen, elip hay spline.
;;;
;;; BON DIEU CAN BIET TRUOC KHI CHAY - cac tep tren mang khong noi:
;;; 1. HAI NET NAM CHONG LEN NHAU duoc cong HAI lan. May khong biet
;;; chung trung nhau. Chay lenh OVERKILL don net trung truoc khi
;;; cong, neu khong con so se lon hon thuc te.
;;; 2. DUONG TRON va ELIP duoc tinh bang CHU VI. Neu ban chi muon
;;; chieu dai cac doan thang thi dung loc bo chung o bang phan
;;; loai ma lenh in ra.
;;; 3. DOI TUONG NAM TRONG BLOCK KHONG duoc tinh. Chi dem nhung gi
;;; nam truc tiep tren ban ve. Muon tinh thi pha block ra truoc,
;;; hoac dem rieng roi nhan so ban chen.
;;; 4. DA TUYEN CO BE RONG van duoc tinh theo DUONG TIM, khong phai
;;; theo mep. Dung cho ong nuoc, sai cho tuong ve bang da tuyen.
;;; Sau khi chay, lenh IN ra bang phan loai theo tung loai doi tuong,
;;; de doi chieu chu khong phai tin mot con so tron.
;;;
;;; Don vi: con so in ra dung DON VI BAN VE. Ban ve don vi mm thi ket
;;; qua la mm. Lenh in ra ca con so chia cho 1000 de doc nhanh ra met.
;;;
;;; Ten lenh da do truoc khi dat: tep bi danh acad.pgp cua ban 2027
;;; khong co TCD, TCDT lan TCDL.
;;;
;;; Nap tep: go APPLOAD, chon tep nay, bam Load.
;;; Tep luu bang ma UTF-8. Sua bang Notepad thi nho luu lai dung UTF-8.
;;; ==================================================================
(vl-load-com)
;;; ------------------------------------------------------------------
;;; Chieu dai cua MOT doi tuong. Tra ve nil neu doi tuong khong phai
;;; duong cong (chu, hatch, block...).
;;; ------------------------------------------------------------------
(defun iic-dai (e / p)
(if (and e (not (vl-catch-all-error-p
(setq p (vl-catch-all-apply
'vlax-curve-getEndParam (list e))))))
(if p
(vl-catch-all-apply 'vlax-curve-getDistAtParam (list e p))
)
)
)
;;; ------------------------------------------------------------------
;;; Gom mot tap chon thanh danh sach (loai . (so_luong . tong_dai))
;;; ------------------------------------------------------------------
(defun iic-gom (ss / i e loai d bang o bo)
(setq bang nil bo 0 i 0)
(while (< i (sslength ss))
(setq e (ssname ss i)
loai (cdr (assoc 0 (entget e)))
d (iic-dai e))
(if (and d (numberp d))
(progn
(setq o (assoc loai bang))
(if o
(setq bang (subst (cons loai (cons (1+ (cadr o)) (+ (cddr o) d)))
o bang))
(setq bang (cons (cons loai (cons 1 d)) bang))
)
)
(setq bo (1+ bo))
)
(setq i (1+ i))
)
(cons bang bo)
)
;;; ------------------------------------------------------------------
;;; In bang phan loai + tong. Tra ve tong chieu dai.
;;; ------------------------------------------------------------------
(defun iic-in (bang bo / tong)
(setq tong 0.0)
(princ "\n")
(princ "\n Loai doi tuong So luong Chieu dai")
(princ "\n ---------------------------------------------")
(foreach o (reverse bang)
(setq tong (+ tong (cddr o)))
(princ (strcat "\n " (iic-dem (car o) 20)
(iic-phai (itoa (cadr o)) 8)
(iic-phai (rtos (cddr o) 2 2) 15)))
)
(princ "\n ---------------------------------------------")
(princ (strcat "\n TONG" (iic-phai (rtos tong 2 2) 39)))
(princ (strcat "\n Chia 1000" (iic-phai (rtos (/ tong 1000.0) 2 3) 34)))
(if (> bo 0)
(princ (strcat "\n Bo qua " (itoa bo)
" doi tuong khong phai duong (chu, hatch, block...)"))
)
(princ "\n")
tong
)
;;; canh trai trong o rong n
(defun iic-dem (s n)
(while (< (strlen s) n) (setq s (strcat s " ")))
s
)
;;; canh phai trong o rong n
(defun iic-phai (s n)
(while (< (strlen s) n) (setq s (strcat " " s)))
s
)
;;; ------------------------------------------------------------------
;;; TCD - cong tong chieu dai, in ra dong lenh
;;; ------------------------------------------------------------------
(defun c:TCD (/ ss r)
(princ "\nChon cac doi tuong can cong chieu dai: ")
(setq ss (ssget))
(if ss
(progn
(setq r (iic-gom ss))
(iic-in (car r) (cdr r))
)
(princ "\nKhong chon duoc gi.")
)
(princ)
)
;;; ------------------------------------------------------------------
;;; TCDT - cong roi ghi ket qua thanh mot dong chu tren ban ve
;;; ------------------------------------------------------------------
(defun c:TCDT (/ ss r tong p cao chu)
(princ "\nChon cac doi tuong can cong chieu dai: ")
(setq ss (ssget))
(if ss
(progn
(setq r (iic-gom ss)
tong (iic-in (car r) (cdr r)))
(setq p (getpoint "\nChi cho dat dong chu: "))
(if p
(progn
(setq cao (getvar "TEXTSIZE"))
(if (or (null cao) (<= cao 0)) (setq cao 2.5))
(setq chu (strcat "Tong chieu dai = " (rtos tong 2 2)))
(entmake (list (cons 0 "TEXT")
(cons 10 p)
(cons 40 cao)
(cons 1 chu)))
(princ (strcat "\nDa ghi: " chu))
)
)
)
(princ "\nKhong chon duoc gi.")
)
(princ)
)
;;; ------------------------------------------------------------------
;;; TCDL - cong rieng tung lop
;;; ------------------------------------------------------------------
(defun c:TCDL (/ ss i e lop d bang o tong bo)
(princ "\nChon cac doi tuong can cong theo lop: ")
(setq ss (ssget))
(if ss
(progn
(setq bang nil bo 0 i 0)
(while (< i (sslength ss))
(setq e (ssname ss i)
lop (cdr (assoc 8 (entget e)))
d (iic-dai e))
(if (and d (numberp d))
(progn
(setq o (assoc lop bang))
(if o
(setq bang (subst (cons lop (cons (1+ (cadr o)) (+ (cddr o) d)))
o bang))
(setq bang (cons (cons lop (cons 1 d)) bang))
)
)
(setq bo (1+ bo))
)
(setq i (1+ i))
)
(setq tong 0.0)
(princ "\n")
(princ "\n Lop So luong Chieu dai")
(princ "\n ---------------------------------------------")
(foreach o (reverse bang)
(setq tong (+ tong (cddr o)))
(princ (strcat "\n " (iic-dem (car o) 20)
(iic-phai (itoa (cadr o)) 8)
(iic-phai (rtos (cddr o) 2 2) 15)))
)
(princ "\n ---------------------------------------------")
(princ (strcat "\n TONG" (iic-phai (rtos tong 2 2) 39)))
(if (> bo 0)
(princ (strcat "\n Bo qua " (itoa bo) " doi tuong khong phai duong"))
)
(princ "\n")
)
(princ "\nKhong chon duoc gi.")
)
(princ)
)
(princ "\nDCD-IIC da nap. Lenh: TCD (in ra dong lenh), TCDT (ghi thanh chu), TCDL (tach theo lop).")
(princ)
Hướng dẫn dùng, từng bước một
| Bước | Làm gì |
|---|---|
| 1 | Gõ APPLOAD, chọn tệp DCD-IIC.lsp, bấm Load |
| 2 | Gõ TCD |
| 3 | Chọn các đối tượng cần cộng, rồi Enter |
| 4 | Đọc bảng in ra ở dòng lệnh |
Nếu dòng lệnh chỉ hiện một hai dòng thì bấm F2 để mở cửa sổ lịch sử, bảng sẽ hiện đủ. Cách nạp tệp lisp và các lỗi hay gặp khi nạp có trong bài lệnh appload trong CAD.
Có một điều nhiều người không biết: hàm lisp chỉ sống trong bản vẽ đang mở. Mở bản vẽ khác là phải nạp lại. Muốn nạp một lần cho mãi thì đưa tệp vào mục Startup Suite của chính hộp thoại APPLOAD.
Con số máy in ra khớp đúng phép tính tay
Một tệp lisp chỉ đáng tin khi có ai đó đối chiếu nó với phép tính tay. Dưới đây là phép đối chiếu ấy.
Vẽ bốn hình có chiều dài biết trước rồi cộng bằng lệnh TCD:
| Hình | Chiều dài đúng |
|---|---|
| Đoạn thẳng | 1.000 |
| Cung tròn một phần tư, bán kính 500 | π × 500 / 2 = 785,3982 |
| Đường tròn bán kính 300 | 2π × 300 = 1.884,9556 |
| Đa tuyến kín 1200 × 800 | 4.000 |
| Cộng tay | 7.670,3538 |
Chạy lệnh, máy in ra:
Loai doi tuong So luong Chieu dai
---------------------------------------------
LWPOLYLINE 1 4000.00
CIRCLE 1 1884.96
ARC 1 785.40
LINE 1 1000.00
---------------------------------------------
TONG 7670.35
Chia 1000 7.670
Khớp tới hai chữ số thập phân, chênh lệch 0,00%. Từng dòng trong bảng cũng khớp: cung tròn 785,40 so với 785,3982 tính tay, đường tròn 1.884,96 so với 1.884,9556.
Dòng Chia 1000 là tiện dụng thuần tuý: bản vẽ xây dựng hầu hết đặt đơn vị mi-li-mét, nên chia nghìn là ra mét, khỏi nhẩm.
Ba cái bẫy khiến con số sai mà không ai biết
Đây là phần các tệp lisp đang lưu hành không nói, và là lý do bài này dài hơn một trang tải về.
Bẫy thứ nhất: hai nét chồng khít lên nhau được cộng hai lần. Vẽ hai đoạn thẳng dài 1.000 nằm đúng chồng lên nhau, mắt chỉ thấy một nét. Chạy lệnh, máy in:
LINE 2 2000.00
Số lượng 2, tổng 2.000. Máy không biết hai nét ấy trùng nhau, và trên một mặt bằng thật thì chuyện nét chồng nét xảy ra liên tục — do copy nhầm, do xref chồng lên bản gốc, do vẽ lại mà quên xoá nét cũ.
Đây chính là lý do bảng phải có cột số lượng: nhìn thấy một nét trên màn hình mà bảng ghi 2 là biết có nét chồng. Trước khi cộng nên chạy lệnh OVERKILL dọn nét trùng — cách dùng có trong bài xoá nét trùng trong CAD.
Bẫy thứ hai: đối tượng nằm trong block không được tính. Đặt một đoạn dài 1.000 vào trong một block, chèn block ấy lên bản vẽ, rồi thêm một đoạn 1.000 nữa... thật ra chỉ thêm một đoạn dài 500 nằm ngoài. Chọn cả hai rồi chạy lệnh:
LINE 1 500.00
---------------------------------------------
TONG 500.00
Chia 1000 0.500
Bo qua 1 doi tuong khong phai duong (chu, hatch, block...)
Chỉ 500. Đoạn 1.000 trong block biến mất khỏi phép cộng, và may là máy có báo dòng Bo qua 1 doi tuong. Nhiều tệp trên mạng không báo gì cả, nên người dùng cứ tưởng đã cộng hết.
Cách xử lý: phá block ra rồi cộng, hoặc cộng riêng một bản block rồi nhân với số lần chèn. Đếm số lần chèn có trong bài đếm block trong CAD.
Bẫy thứ ba: chữ và mảng hatch nằm trong vùng chọn. Chúng không có chiều dài nên bị bỏ qua — điều này đúng, nhưng phải có báo. Trong phép thử, một dòng chữ và một mảng hatch lọt vào vùng chọn cho ra dòng Bo qua 2 doi tuong. Con số tổng không bị làm bẩn.
Lisp tính tổng chiều dài trong CAD khi bản vẽ nhiều lớp
Hồ sơ thật không bao giờ chỉ có một loại nét. Ống cấp một lớp, ống thoát một lớp, gờ chắn một lớp. Cộng gộp hết thì con số vô nghĩa.
Lệnh TCDL cộng riêng từng lớp. Phép thử: hai đoạn trên lớp IIC-ONG dài 1.000 và 1.500, một đoạn trên lớp IIC-TUONG dài 2.000.
Lop So luong Chieu dai
---------------------------------------------
IIC-TUONG 1 2000.00
IIC-ONG 2 2500.00
---------------------------------------------
TONG 4500.00
Đúng như tính tay: 1.000 cộng 1.500 bằng 2.500 cho lớp ống, 2.000 cho lớp tường.
Cách làm việc gọn nhất với hồ sơ thật: chọn cả bản vẽ bằng một khung bao rồi chạy TCDL một lần, là ra ngay bảng khối lượng theo lớp. Quản lý lớp có trong bài layer trong CAD.
Đa tuyến có bề rộng: đo theo tim hay theo mép
Câu hỏi này quyết định con số đúng hay sai trong bóc khối lượng, mà không tài liệu nào trả lời.
Vẽ một đa tuyến một đoạn, đường tim dài 1.000, đặt bề rộng nét 200. Chạy lệnh:
LWPOLYLINE 1 1000.00
Đúng 1.000, tức đo theo đường tim, không cộng thêm gì cho bề rộng. Hiểu đúng thì dùng đúng: vẽ ống nước bằng đa tuyến có bề rộng thì con số này là chiều dài ống, chuẩn. Nhưng vẽ tường bằng đa tuyến có bề rộng thì con số này là chiều dài tim tường, không phải chu vi mặt tường.
Đa tuyến và cách đặt bề rộng nét có trong bài đa tuyến trong CAD.
Mấy điều hay nghe nhưng không đúng
| Người ta hay nói | Thực tế đo được |
|---|---|
| AutoCAD có sẵn lệnh cộng chiều dài | Không có; LIST in từng cái, MEASUREGEOM đo từng cái |
| Chọn nhiều nét là bảng Properties hiện tổng | Ô Length biến mất khi chọn nhiều đối tượng |
| Lisp cộng ra con số nào thì tin con số ấy | Hai nét chồng khít bị cộng hai lần thành 2.000 |
| Chọn cả bản vẽ là cộng được hết | Nét nằm trong block không được tính |
| Đa tuyến có bề rộng thì đo cả bề rộng | Đo theo tim: tim 1.000 ra đúng 1.000 |
Câu hỏi thường gặp
Tệp này cộng được những loại nét nào?
Đoạn thẳng, cung tròn, đường tròn, elip, đa tuyến và spline. Đường tròn và elip được tính bằng chu vi.
Vì sao con số lớn hơn tôi nghĩ?
Nhiều khả năng bản vẽ có nét chồng nét. Nhìn cột số lượng: thấy một nét trên màn hình mà bảng ghi hai là có nét trùng. Chạy OVERKILL rồi cộng lại.
Nét trong block có được cộng không?
Không. Máy sẽ báo dòng Bo qua ... doi tuong. Phải phá block, hoặc cộng một bản rồi nhân số lần chèn.
Kết quả ra đơn vị gì?
Đúng đơn vị bản vẽ. Bản vẽ đặt mi-li-mét thì kết quả là mi-li-mét, và dòng Chia 1000 cho luôn con số mét.
Muốn ghi kết quả lên bản vẽ thì làm sao?
Dùng lệnh TCDT: cộng xong nó hỏi chỗ đặt rồi ghi thành một dòng chữ ngay tại đó.
Cộng riêng từng lớp được không?
Được, dùng lệnh TCDL. Nó in bảng theo từng lớp kèm số lượng đối tượng của mỗi lớp.