Đến nội dung


Hình ảnh
- - - - -

Tính tổng có điều kiện để thống kê thép cường độ cao


  • Please log in to reply
10 replies to this topic

#1 Tue_NV

Tue_NV

    KS Võ Quang Tuệ

  • Moderator
  • PipPipPipPipPipPipPip
  • 4296 Bài viết
Điểm đánh giá: 3804 (đỉnh cao)

Đã gửi 15 December 2008 - 07:18 AM

Lời đầu tiên xin cho phép mình gửi lời cảm ơn tới diễn đàn CADVIET, gửi lời cảm ơn tới tất cả mọi người. Ở đay mình cảm thấy rất vui vì đã học hỏi rất nhiều điều bổ ích.

Mình có 1 vấn đề trong việc thống kê và tổng hợp cốt thép cường độ cao.
Đường kính của cốt thép cường độ cao vừa có đường kính lẻ, vừa có đường kính là số thập phân. Nó không giống như cốt thép thường.
Đây là file đính kèm :
Bảng chuyển đổi thép cường độ cao
Việc thống kê cốt thép cường độ cao thì mình đã tính toán được rồi.
Nhưng đến giai đoạn tổng hợp cốt thép cường độ cao thì mới gặp vấn đề. Mình phải ngồi tính tổng (SUM) trọng lượng của từng loại đường kính thép (như trên đã nói vừa là đường kính lẻ, vừa đường kính số thập phân) nên rất mất nhiều thời gian.

Xin các anh em trên diễn đàn CADVIET có thể viét nên một đoạn Code để tính tổng có điều kiện như thế này được không? Nó từa tựa như hàm Sumif trong Excel

Mình có 2 cột số :
Cột thứ nhất là cột ghi giá trị đường kính.
Cột thứ hai chính là trọng lượng của cốt thép cường độ cao.
Khi mình chạy Code thì chương trình yêu cầu :
Kết quả đầu vào :
- Nhập cột số thứ nhất (là cột đường kính ).
- Nhập cột số thứ hai (là cột trọng lượng thép cường độ cao).
- Nhập đường kính thép cần tính tổng (chính là một đường kính fi nằm trong cột thứ nhất).
Kết quả đầu ra : Cho ra giá trị tính tổng trọng lượng của giá trị đường kính fi trong cột thứ nhất.

Mong mọi người bỏ ít thời gian để quan tâm đến vấn đề này. Vì xu hướng ngày nay sử dụng thép cường độ cao càng nhiều. Nếu ai đó trên diễn đàn viết được chương trình thống kê cốt thép cường độ cao (Với mọi giá trị đường kính) thì cực kì tốt.

Xin cảm ơn mọi người. Chúc mọi người sức khỏe.
  • 0

#2 ssg

ssg

    biết lệnh adcenter

  • Vip
  • PipPipPipPipPipPipPip
  • 1228 Bài viết
Điểm đánh giá: 1087 (rất tốt)

Đã gửi 15 December 2008 - 07:47 AM

Xin các anh em trên diễn đàn CADVIET có thể viét nên một đoạn Code để tính tổng có điều kiện như thế này được không? Nó từa tựa như hàm Sumif trong Excel

Mình có 2 cột số :
Cột thứ nhất là cột ghi giá trị đường kính.
Cột thứ hai chính là trọng lượng của cốt thép cường độ cao.
Khi mình chạy Code thì chương trình yêu cầu :
Kết quả đầu vào :
- Nhập cột số thứ nhất (là cột đường kính ).
- Nhập cột số thứ hai (là cột trọng lượng thép cường độ cao).
- Nhập đường kính thép cần tính tổng (chính là một đường kính fi nằm trong cột thứ nhất).
Kết quả đầu ra : Cho ra giá trị tính tổng trọng lượng của giá trị đường kính fi trong cột thứ nhất.

Chưa hiểu ý!
1. Cột thứ nhất và cột thứ hai trong diễn giải của bạn là cột nào trong file excel bạn đã post?
2. Bạn muốn thực hiện trong excel hay dùng lisp trong AutoCAD? Nếu là lisp, các "cột số" như bạn mô tả là loại đối tượng gì?
  • 0

#3 Tue_NV

Tue_NV

    KS Võ Quang Tuệ

  • Moderator
  • PipPipPipPipPipPipPip
  • 4296 Bài viết
Điểm đánh giá: 3804 (đỉnh cao)

Đã gửi 15 December 2008 - 08:11 AM

Chưa hiểu ý!
1. Cột thứ nhất và cột thứ hai trong diễn giải của bạn là cột nào trong file excel bạn đã post?
2. Bạn muốn thực hiện trong excel hay dùng lisp trong AutoCAD? Nếu là lisp, các "cột số" như bạn mô tả là loại đối tượng gì?

Cảm ơn bác SSG đã hồi âm.
Ý của em là dùng Lisp trong AutoCAD.
Cột số của em ở đây là đối tượng Text
Em sẽ gửi một file CAD để minh họa :
Thống kê và tổng hợp cốt thép cường độ caoKết quả đầu vào :
- Nhập cột số thứ nhất (là cột đường kính ).
- Nhập cột số thứ hai (là cột trọng lượng thép cường độ cao).
- Nhập đường kính thép cần tính tổng (chính là một đường kính fi nằm trong cột thứ nhất).
Kết quả đầu ra : Cho ra giá trị tính tổng trọng lượng của giá trị đường kính fi trong cột thứ nhất (nằm trong bảng tổng hợp cốt thép)

Cảm ơn bác SSG nhiều lắm.
  • 0

#4 ssg

ssg

    biết lệnh adcenter

  • Vip
  • PipPipPipPipPipPipPip
  • 1228 Bài viết
Điểm đánh giá: 1087 (rất tốt)

Đã gửi 15 December 2008 - 08:26 AM

Hiểu rồi. Bạn dùng hàm sumif như sau:

(defun sumif (L1 L2 v1 / i x Sum)
(setq i 0 Sum 0)
(foreach x L1
(if (= x v1) (setq Sum (+ Sum (nth i L2))))
(setq i (1+ i))
)
Sum
)


Diễn giải:
L1, L2 là list chứa các số thực (real)
v1 là 1 giá trị (phần tử) nào đó trong L1
sumif return kết quả sum các phần tử trong L2, tương ứng với v1
Ví dụ:
(setq L1 (list 1 2 3 1))
(setq L2 (list 10 20 30 10))
(sumif L1 L2 1) -> return 10 + 10 = 20

Trình tự thực hiện:
1. Dùng ssget chọn cột text1, convert sang list các số thực -> L1
2. Tương tự với cột text2 -> L2
3. Tính sumif theo L1, L2 và giá trị V1 (đường kính cần quan tâm) do user nhập, chuyển sang text và ghi kết quả

Hy vọng bạn tự làm được. Vướng chỗ nào ssg sẽ hỗ trợ thêm.
  • 0

#5 ssg

ssg

    biết lệnh adcenter

  • Vip
  • PipPipPipPipPipPipPip
  • 1228 Bài viết
Điểm đánh giá: 1087 (rất tốt)

Đã gửi 15 December 2008 - 09:41 AM

Để bảo đảm tính thứ tự các thành phần trong cột 1 và 2, bổ sung vào trình tự thực hiện như sau:
1.
a- Dùng ssget chọn cột text1
b- Convert sang list oí text. Sắp xếp theo thứ tự tung độ giảm dần (dùng vl-sort)
c- Convert sang list các số thực

2. Tương tự 1

3. Không đổi

Ngoài ra, bạn có thể làm hàng loạt cho các giá trị trong cột 1 (không cần user nhập đường kính) bằng cách dùng hàm SumSpec như sau:

(defun SumSpec(L1 L2 / i Res v1 v2 old) ;;;Sum Special
(setq i 0)
(foreach v1 L1
(setq v2 (nth i L2))
(if (setq old (assoc v1 Res))
(setq Res (subst (cons v1 (+ v2 (cdr old))) old Res))
(setq Res (append Res (list (cons v1 v2))))
)
(setq i (1+ i))
)
Res
)


Kết quả trả về là một association list (danh sách kết hợp). Mỗi phần tử là một dotted pair (danh sách cặp có dấu chấm).
- Thành phần đầu của dotted pair là phần tử (đại diện, nếu có hơn 1 phần tử giống nhau) trong L1.
- Thành phần 2 là tổng tương ứng trong L2

Ví dụ:
(setq L1 (list 1 2 3 1 1))
(setq L2 (list 10 20 30 10 10))
(sumspec l1 l2) -> return ((1 . 30) (2 . 20) (3 . 30))
Đây là kết quả tổng hợp. Chẳng hạn, (1 . 30) có nghĩa là loại có giá trị là 1 trong L1 sẽ có tổng số là 30 tương ứng trong L2...

Cái này hơi phức tạp hơn một chút. Nhưng khi đã hiểu bạn sẽ thấy nó cũng bình thường. Điều quan trọng là hiệu quả sử dụng cao hơn nhiều. Bạn chỉ cần user quét chọn lần lượt 2 cột text, chương trình sẽ cho ra luôn bảng tổng hợp thống kê tất cả các loại đường kính có trong cột 1, kèm theo giá trị sum cho từng loại mà không cần buộc user phải nhập lần lượt từng đường kính.

Bài viết đã được chỉnh sửa nội dung bởi ssg: 15 December 2008 - 10:25 AM

  • 0

#6 ssg

ssg

    biết lệnh adcenter

  • Vip
  • PipPipPipPipPipPipPip
  • 1228 Bài viết
Điểm đánh giá: 1087 (rất tốt)

Đã gửi 15 December 2008 - 10:05 AM

Thống nhất quan điểm: ssg hỗ trợ, bạn tự xây dựng chương trình. OK?

Về convert từ ss sang list, mình tưởng rằng bạn đã biết vì có rất nhiều chương trình lisp post trên diễn đàn đã dùng kiểu như vậy. Đây là code của anh Hoành đưa lên lần đầu trên diễn đàn, rất nhiều mem chúng ta đã dùng nó như là tài sản chung của CADVIET:

;;;------------------------------------------------
(defun ss2ent(ss / sodt index ent lstent)
(setq
sodt (if ss (sslength ss) 0)
index 0
)
(repeat sodt
(setq
ent (ssname ss index)
index (1+ index)
lstent (cons ent lstent)
)
)
(reverse lstent)
)
;;;------------------------------------------------


Diễn giải:
1. List Data Type là kiểu dữ liệu cơ bản của ngôn ngữ Lisp. Người ta đã cung cấp sẵn rất nhiều hàm thao tác với list. Mọi trường hợp, cảm thấy xử lý cái gì đó khó khăn, hãy nghĩ ngay đến việc chuyển chung về dạng List, bạn sẽ có lời giải rất đơn giản.
2. Kết quả gọi hàm ssget là một Selection Set (tập hợp thực thể). Thao tác trực tiếp với ss có rất nhiều hạn chế vì có rất ít hàm có sẵn của AutoLisp thao tác trực tiếp với chúng. Hàm ss2ent sẽ chuyển toàn bộ các entity trong ss sang kiểu list -> bạn tha hồ chọn các hàm có sẵn của Lisp để xử lý.

Ssg đề nghị, tạm thời bạn hãy hoàn chỉnh chương trình theo phương án 1 (làm lần lượt từng cái, user nhập đường kính). Khi đã OK, thử làm theo phương án "hàng loạt" như ssg vừa post. Cứ yên tâm, ssg sẽ hỗ trợ bạn tối đa.
Chúc thành công.
  • 0

#7 Tue_NV

Tue_NV

    KS Võ Quang Tuệ

  • Moderator
  • PipPipPipPipPipPipPip
  • 4296 Bài viết
Điểm đánh giá: 3804 (đỉnh cao)

Đã gửi 15 December 2008 - 10:05 AM

Để bảo đảm tính thứ tự các thành phần trong cột 1 và 2, bổ sung vào trình tự thực hiện như sau:
1.
a- Dùng ssget chọn cột text1
b- Sắp xếp theo thứ tự tung độ giảm dần (dùng vl-sort)
c- Convert sang list các số thực

Ở bước b (dùng vl-sort) và bước c : Convert sang list các số thực : Quả thật em chưa biết.
Mong bác SSG hướng dẫn thêm

Ví dụ:
(setq L1 (list 1 2 3 1 1))
(setq L2 (list 10 20 30 10 10))
(sumspec l1 l2) -> return ((1 . 30) (2 . 20) (3 . 30))
Đây là kết quả tổng hợp. Chẳng hạn, (1 . 30) có nghĩa là loại có giá trị là 1 trong L1 sẽ có tổng số là 30 tương ứng trong L2...

Ví dụ này thì em hiểu bác ạ. Tức là kết quả sẽ là : giá trị 1 trong L1 sẽ có 3 giá trị tương ứng ở L2 : tức là 3 giá trị 10,10,10
Lấy 3 giá trị 10 cộng với nhau : 10+10+10=30.

Nhưng em chưa biết cách xuất dữ liệu ra như thế nào bác ạ. Mong bác chỉ giúp.
  • 0

#8 ssg

ssg

    biết lệnh adcenter

  • Vip
  • PipPipPipPipPipPipPip
  • 1228 Bài viết
Điểm đánh giá: 1087 (rất tốt)

Đã gửi 15 December 2008 - 10:17 AM

Ở bước b (dùng vl-sort) và bước c : Convert sang list các số thực : Quả thật em chưa biết.

1. Hàm atof sẽ chuyển string sang real
2. Vl-sort... chà, nếu quả thật chưa biết thì hơi gay. Thôi được, tạm thời bạn hãy xem Help, đọc sách hoặc search trên diễn đàn. Mình sẽ quay lại sau. Giờ mình có việc rồi, điện thoại của sếp đang réo!
  • 0

#9 ssg

ssg

    biết lệnh adcenter

  • Vip
  • PipPipPipPipPipPipPip
  • 1228 Bài viết
Điểm đánh giá: 1087 (rất tốt)

Đã gửi 15 December 2008 - 03:00 PM

Bạn chạy thử lisp sau, lệnh VD:

;;;---------------------------------------------------
(defun ss2ent(ss / sodt index ent lstent) ;;;Convert ss to list of entities
(setq
sodt (if ss (sslength ss) 0)
index 0
)
(repeat sodt
(setq
ent (ssname ss index)
index (1+ index)
lstent (cons ent lstent)
)
)
(reverse lstent)
)
;;;---------------------------------------------------
(defun SumSpec(L1 L2 / i Res v1 v2 old) ;;;Sum Special
(setq i 0)
(foreach v1 L1
(setq v2 (nth i L2))
(if (setq old (assoc v1 Res))
(setq Res (subst (cons v1 (+ v2 (cdr old))) old Res))
(setq Res (append Res (list (cons v1 v2))))
)
(setq i (1+ i))
)
Res
)
;;;---------------------------------------------------
(defun Upper (e1 e2) ;;;Return T if e1 upper e2, otherwise return nil
(> (cadr (cdr (assoc 10 (entget e1)))) (cadr (cdr (assoc 10 (entget e2)))))
)
;;;---------------------------------------------------
(defun Ent2Real(Le / e Lr) ;;;Convert list of text entities to list of real
(foreach e Le (setq Lr (append Lr (list (atof (cdr (assoc 1 (entget e))))))))
)
;;;---------------------------------------------------
(defun C:VD( / ss1 ss2 L1 L2 Res Temp x)
(prompt "\nChon cac text o cot duong kinh...")
(setq ss1 (ssget '((0 . "TEXT"))))
(prompt "\nChon cac text o cot khoi luong...")
(setq ss2 (ssget '((0 . "TEXT"))))
(setq
L1 (ent2real (vl-sort (ss2ent ss1) 'Upper))
L2 (ent2real (vl-sort (ss2ent ss2) 'Upper))
Res (sumspec L1 L2)
Temp ""
)
(foreach x Res (setq Temp (strcat Temp "\nD = " (rtos (car x)) " -> " (rtos (cdr x)) " kg")))
(alert Temp)
)
;;;---------------------------------------------------
;;;That is a example only! Replace alert by other, according your purpose...
;;;Maybe you should add check conditions for input data if necessary...
;;;Success!
;;;---------------------------------------------------


Đề nghị:
1. Phân tích kỹ các code sử dụng trong các functions con và cách áp dụng chúng trong chương trình chính. Nếu thấy hơi khó hiểu, thử làm vài ví dụ đơn giản áp dụng các function con, bạn sẽ hiểu ra vấn đề.
2. Kết quả tổng hợp nằm trong biến Res. Hàm alert chỉ là ví dụ thể hiện kết quả. Bạn hãy tìm cách chuyển data trong Res theo mục đích và cách thức trình bày kết quả của bạn. Tham khảo cách tạo nên giá trị của biến Temp sau khi kết thúc vòng foreach sẽ rất hữu ích.
3. Bài này là một trong những "cột mốc" quan trọng trong quá trình "làm chủ AutoLisp". Vượt qua nó, bạn sẽ có một nền tảng kiến thức Lisp khá vững chắc để có thể tạo nên những ứng dụng hiệu quả. Hãy cố lên!
  • 0

#10 Tue_NV

Tue_NV

    KS Võ Quang Tuệ

  • Moderator
  • PipPipPipPipPipPipPip
  • 4296 Bài viết
Điểm đánh giá: 3804 (đỉnh cao)

Đã gửi 15 December 2008 - 03:45 PM

Bạn chạy thử lisp sau, lệnh VD:


;;;---------------------------------------------------
(defun ss2ent(ss / sodt index ent lstent) ;;;Convert ss to list of entities
(setq
sodt (if ss (sslength ss) 0)
index 0
)
(repeat sodt
(setq
ent (ssname ss index)
index (1+ index)
lstent (cons ent lstent)
)
)
(reverse lstent)
)
;;;---------------------------------------------------
(defun SumSpec(L1 L2 / i Res v1 v2 old) ;;;Sum Special
(setq i 0)
(foreach v1 L1
(setq v2 (nth i L2))
(if (setq old (assoc v1 Res))
(setq Res (subst (cons v1 (+ v2 (cdr old))) old Res))
(setq Res (append Res (list (cons v1 v2))))
)
(setq i (1+ i))
)
Res
)
;;;---------------------------------------------------
(defun Upper (e1 e2) ;;;Return T if e1 upper e2, otherwise return nil
(> (cadr (cdr (assoc 10 (entget e1)))) (cadr (cdr (assoc 10 (entget e2)))))
)
;;;---------------------------------------------------
(defun Ent2Real(Le / e Lr) ;;;Convert list of text entities to list of real
(foreach e Le (setq Lr (append Lr (list (atof (cdr (assoc 1 (entget e))))))))
)
;;;---------------------------------------------------
(defun C:VD( / ss1 ss2 L1 L2 Res Temp x)
(prompt "\nChon cac text o cot duong kinh...")
(setq ss1 (ssget '((0 . "TEXT"))))
(prompt "\nChon cac text o cot khoi luong...")
(setq ss2 (ssget '((0 . "TEXT"))))
(setq
L1 (ent2real (vl-sort (ss2ent ss1) 'Upper))
L2 (ent2real (vl-sort (ss2ent ss2) 'Upper))
Res (sumspec L1 L2)
Temp ""
)
(foreach x Res (setq Temp (strcat Temp "\nD = " (rtos (car x)) " -> " (rtos (cdr x)) " kg")))
(alert Temp)
)
;;;---------------------------------------------------
;;;That is a example only! Replace alert by other, according your purpose...
;;;Maybe you should add check conditions for input data if necessary...
;;;Success!
;;;---------------------------------------------------


Đề nghị:
1. Phân tích kỹ các code sử dụng trong các functions con và cách áp dụng chúng trong chương trình chính. Nếu thấy hơi khó hiểu, thử làm vài ví dụ đơn giản áp dụng các function con, bạn sẽ hiểu ra vấn đề.
2. Kết quả tổng hợp nằm trong biến Res. Hàm alert chỉ là ví dụ thể hiện kết quả. Bạn hãy tìm cách chuyển data trong Res theo mục đích và cách thức trình bày kết quả của bạn. Tham khảo cách tạo nên giá trị của biến Temp sau khi kết thúc vòng foreach sẽ rất hữu ích.
3. Bài này là một trong những "cột mốc" quan trọng trong quá trình "làm chủ AutoLisp". Vượt qua nó, bạn sẽ có một nền tảng kiến thức Lisp khá vững chắc để có thể tạo nên những ứng dụng hiệu quả. Hãy cố lên!

Rất chân thành cảm ơn bác SSG. Em sẽ cố gắng nghiên cứu bài học cột mốc quý giá này để tạo nên những ứng dụng hiệu quả nhờ AutoLisp.
  • 0

#11 shinnikel

shinnikel

    biết vẽ line

  • Members
  • PipPip
  • 22 Bài viết
Điểm đánh giá: 1 (bình thường)

Đã gửi 12 February 2009 - 01:18 PM

Các bạn cadviet có thể viết cho tôi 1 lisp chọn một bề mặt ngẫu nhiên(đối tượng kính) sau đó cho ra lựa chọn vật liệu là nhôm, thép, kính và tiếp đó là lựa chọn chiều dài hoặc dầy để cho ra 1 kết quả text là khối lượng của khối đó tính bằng (Kg) chân thành cảm ơn anh e tối rất cần lisp nay.
  • 0