ถอดปริมาณงานจากโมเดล SketchUp ด้วยสคริปต์ Ruby
ปั้นโมเดลเสร็จแล้วยังต้องมานั่งกดวัดทีละชิ้นเพื่อกรอกใบถอดปริมาณ ทั้งที่ตัวเลขทุกตัวอยู่ในไฟล์อยู่แล้ว ปัญหาไม่ได้อยู่ที่โปรแกรม มันอยู่ที่ตอนปั้นเราไม่ได้ตั้งชื่อกลุ่มให้สคริปต์อ่านได้
พอดีผมรับงานปรับปรุงอาคารพักหลังเล็กหลังหนึ่ง ปั้นโมเดลแก้แบบให้เจ้าของงานดูจนจบ พอถึงตอนต้องส่งใบถอดปริมาณ ผมเปิดโมเดลแล้วเริ่มกดวัดทีละชิ้น วัดไปได้สักยี่สิบชิ้นก็รู้ตัวว่าทำผิดวิธี เพราะตัวเลขทุกตัวที่ใบถอดปริมาณต้องการมันอยู่ในไฟล์ครบอยู่แล้ว ทั้งขนาดกล่องครอบ พื้นที่หน้า และชื่อวัสดุ ผมเลยหยุดวัดแล้วมานั่งเขียนสคริปต์ให้มันไล่อ่านออกมาแทน จบงานนั้นเหลือคำสั่งเดียวรันแล้วได้ตารางครบทุกหมวด
เรื่องธรรมเนียมการเขียนแบบว่าชิ้นไหนต้องซ้อนบนชิ้นไหน ผมแยกเขียนไว้แล้วใน ธรรมเนียมเขียนแบบโครงเหล็กไทย ตอนนี้ว่าด้วยเรื่องเดียวคือการดึงตัวเลขออกจากโมเดลที่ปั้นเสร็จแล้ว
ตั้งชื่อกลุ่มตอนปั้น ไม่ใช่ตอนจะถอดแบบ
สคริปต์ถอดปริมาณจะเขียนง่ายหรือยากขึ้นกับข้อเดียวคือ ตอนปั้นเราตั้งชื่อกลุ่มไว้แบบไหน ถ้ากลุ่มชื่อ Group#12 Group#13 ไปทั้งไฟล์ ก็ไม่มีทางเขียนสคริปต์ให้แยกได้ว่าอันไหนคือผนัง อันไหนคือบานเกล็ด สุดท้ายต้องกลับไปนั่งคลิกทีละตัวอยู่ดี
ธรรมเนียมที่ผมใช้คือ ชื่อกลุ่ม = หมวด-ชนิด-เลขลำดับ โดยให้ตัวขึ้นต้นเป็นหมวดที่จะเอาไปเข้าใบถอดปริมาณตรงๆ เพราะสคริปต์จะเลือกด้วย start_with? เป็นหลัก ไม่ใช่ regex ยาวๆ
สคริปต์อ่านได้
- Bath-ผนังก่อกลาง · Bath-ผนังเบาพลาสวูด-1
- บานเกล็ด-ผนังหน้า โดยข้างในมีลูกกลุ่มชื่อ เสา-1
- มุ้งลวด-หน้าต่างห้องขวา
- ตัวขึ้นต้นซ้ำได้ ตัวต่อท้ายบอกตำแหน่ง
ต้องกลับไปคลิกเอง
- Group#12 · Group#13 · Copy of Group#12
- ตั้งชื่อเป็นเลขงานอย่างเดียว ไม่บอกชนิด
- ผนังก่อกับผนังเบาใช้ชื่อขึ้นต้นเดียวกัน แยกไม่ออก
- ลูกกลุ่มไม่มีชื่อ ทำให้นับใบเกล็ดกับเสาแยกไม่ได้
ผมยอมเสียเวลาพิมพ์ชื่อกลุ่มตอนปั้นเพิ่มสามสิบวินาทีต่อชิ้น เพื่อประหยัดการนั่งวัดตอนท้ายเป็นชั่วโมง ที่สำคัญกว่านั้นคือพอแก้แบบรอบสอง รอบสาม สคริปต์ตัวเดิมรันซ้ำได้เลย ไม่ต้องวัดใหม่ทั้งชุด
หน่วยภายในเป็นนิ้วเสมอ จำตัวคูณสี่ตัวนี้ให้ขึ้นใจ
SketchUp เก็บทุกอย่างเป็นนิ้วภายใน ไม่ว่าหน้าจอจะตั้งหน่วยเป็นมิลลิเมตรอยู่ก็ตาม ค่าที่ดึงจาก bounds และ Face#area ออกมาเป็นนิ้วกับตารางนิ้วทั้งหมด ผมเลยตั้ง lambda สำหรับแปลงหน่วยไว้บนหัวไฟล์ทุกครั้ง แล้วห้ามคูณเลขดิบที่อื่นอีก
# encoding: UTF-8
m = Sketchup.active_model
e = m.entities
q = 25.4
mm = ->(v) { (v.to_f * q).round } # นิ้ว -> มิลลิเมตร
m2 = ->(a) { (a * 0.00064516).round(2) } # ตารางนิ้ว -> ตารางเมตร
lm = ->(v) { (v.to_f * 0.0254).round(2) } # นิ้ว -> เมตร
m3 = ->(v) { (v * 1.6387e-5).round(3) } # ลูกบาศก์นิ้ว -> ลูกบาศก์เมตร
ค่า 0.00064516 คือ 0.0254 ยกกำลังสองพอดี ผมเขียนเป็นเลขเต็มไว้เลยไม่ให้ใครไปแก้เป็น 0.000645 แล้วพื้นที่รวมเพี้ยนไปหลักทศนิยม พอเจอพื้นที่หลักร้อยตารางเมตรมันเห็นผลจริง
หมวดแรก ผนัง แยกผนังก่อกับผนังเบาให้ขาดจากกัน
งานนี้มีผนังสองชนิดในชุดเดียวกัน ผนังก่อหนา 150 มิลลิเมตรเต็มความสูง กับผนังเบาโครงอลูมิเนียมกรุพลาสวูดสองด้าน หนา 70 มิลลิเมตร ลอยพ้นพื้น 150 มิลลิเมตรเพื่อใช้รางระบายน้ำเดิม สองชนิดนี้คิดราคาคนละแบบ ผนังก่อคิดเป็นตารางเมตรผิวฉาบสองด้านบวกปริมาตร ส่วนผนังเบาต้องแยกเป็นสองบรรทัดคือ พื้นที่แผ่นพลาสวูด กับ ความยาวโครงอลูมิเนียมเป็นเมตร
# ผนังก่อ: อ่านจากกล่องครอบของกลุ่มตรงๆ
e.grep(Sketchup::Group).select { |g| g.name.to_s.start_with?("Bath-ผนัง") }.each do |g|
b = g.bounds
w, d, h = b.width.to_f, b.height.to_f, b.depth.to_f
face = [w, d].max * h # ด้านกว้างคูณความสูง
puts "PART|#{g.name}|#{mm.(w)}x#{mm.(d)}x#{mm.(h)}|face=#{m2.(face)}|vol=#{m3.(w * d * h)}"
end
ผนังเบาต้องเดินเข้าไปในลูกกลุ่ม เพราะแผ่นพลาสวูดกับเส้นโครงอลูมิเนียมอยู่รวมในกลุ่มเดียวกัน วิธีแยกคือดูจากชื่อลูกกลุ่ม ถ้าขึ้นต้นว่าพลาสวูดคือแผ่น ให้คิดพื้นที่ ที่เหลือคือเส้นโครง ให้คิดความยาว
%w[1 2].each do |k|
g = e.grep(Sketchup::Group).find { |x| x.name.to_s == "Bath-ผนังเบาพลาสวูด-#{k}" }
next unless g
al = 0.0
pw = 0.0
g.entities.grep(Sketchup::Group).each do |s|
dims = [s.bounds.width.to_f, s.bounds.height.to_f, s.bounds.depth.to_f].sort
if s.name.to_s.start_with?("พลาสวูด")
pw += dims[1] * dims[2] # สองมิติที่ใหญ่ที่สุด = หน้าแผ่น
else
al += dims[2] # มิติที่ยาวที่สุด = ความยาวเส้นโครง
end
end
puts "LIGHTWALL|#{k}|plaswood=#{m2.(pw)}|alu_len=#{lm.(al)}"
end
ผลของสองชุดนี้ในงานจริงคือผนังกั้นรวม 10.44 ตารางเมตร แยกเป็นผนังก่อ 3.60 กับผนังเบาสองแผ่นแผ่นละ 3.42 ส่วนของที่ต้องสั่งซื้อคือพลาสวูด 13.68 ตารางเมตร และโครงอลูมิเนียม 21.90 เมตร ตัวเลขชุดนี้กรอกใบสั่งของได้เลยโดยไม่ต้องกดวัดสักครั้ง
กับดักที่หนึ่ง กล่องครอบของกลุ่มที่เอียง
ข้อนี้คือข้อที่ทำให้ผมเสียเวลามากที่สุด bounds.width ของ SketchUp ไม่ได้แปลว่าความกว้างของชิ้นงาน มันคือขนาดกล่องครอบตามแกนโลก แกน x เท่านั้น ถ้าชิ้นงานวางเอียง หรือถูก rotate มาก่อน สิ่งที่ width height depth คืนมาคือมิติของกล่องที่ครอบมันอยู่ ไม่ใช่หน้าตัดจริงของชิ้นงาน
เส้นโครงอลูมิเนียม 50 คูณ 25 ที่วางตามแกน x จะได้ width เป็นความยาวเส้น แต่ถ้าตัวเดียวกันวางตามแกน y ค่า width จะกลายเป็น 50 ทันที ถ้าเขียนสคริปต์บวก width ไปทั้งกอง จะได้ความยาวรวมที่ผิดแบบไม่มีทางสังเกตเห็น เพราะเลขมันยังดูสมเหตุสมผลอยู่ วิธีเดียวที่ปลอดภัยคือ เอาสามมิติมา sort ก่อนเสมอ แล้วอ่านเป็นตำแหน่ง ตัวที่ 0 คือความหนา ตัวที่ 1 คือความกว้าง ตัวที่ 2 คือความยาว
# ผิด: ได้ค่าถูกเฉพาะตอนชิ้นงานวางตามแกน x
al += s.bounds.width.to_f
# ถูก: เรียงสามมิติก่อน แล้วอ่านตามตำแหน่ง
dims = [s.bounds.width.to_f, s.bounds.height.to_f, s.bounds.depth.to_f].sort
thick, wide, long = dims[0], dims[1], dims[2]
al += long
ข้อจำกัดที่ต้องรู้คือ วิธี sort ใช้ได้กับชิ้นที่เป็นแท่งหรือแผ่นตรงๆ เท่านั้น ถ้าชิ้นงานเอียงเป็นมุมจริงในโมเดล เช่นใบเกล็ดที่เอียงสะบัดน้ำ กล่องครอบมันจะใหญ่กว่าชิ้นงานจริงทั้งสามด้าน กรณีแบบนั้นห้ามใช้ bounds เด็ดขาด ต้องไปดึงจากพื้นที่หน้าแทน ซึ่งจะเจอกับดักข้อสอง
กับดักที่สอง พื้นที่หน้าถูกนับสองครั้งเสมอ
Face#area คืนพื้นที่ของหน้าจริงเป็นตารางนิ้ว แม่นกว่ากล่องครอบมาก แต่มีเงื่อนไขที่คนพลาดกันทุกคนรอบแรก คือแผ่นเหล็กหนา 1 มิลลิเมตรหนึ่งแผ่น มีหน้าสองหน้า หน้าบนกับหน้าล่าง พอ sum(&:area) ไปทั้งกลุ่ม พื้นที่แผ่นจะออกมาเป็นสองเท่าของความจริงทันที ยังไม่นับหน้าขอบอีกสี่ด้านที่บางมากจนเลขไม่ขยับ
e.grep(Sketchup::Group).select { |g| g.name.to_s.start_with?("บานเกล็ด") }.each do |g|
blades = g.entities.grep(Sketchup::Group).reject { |s| s.name.to_s.start_with?("เสา") }
posts = g.entities.grep(Sketchup::Group).select { |s| s.name.to_s.start_with?("เสา") }
len = blades.sum { |s| b = s.bounds; [b.width.to_f, b.height.to_f].max }
sheet = blades.sum { |s| s.entities.grep(Sketchup::Face).sum(&:area) } / 2.0 # หาร 2
pl = posts.sum { |s| s.bounds.depth.to_f }
bb = g.bounds
elev = [bb.width.to_f, bb.height.to_f].max * bb.depth.to_f # พื้นที่หน้าบานตามรูปด้าน
puts "LOUVER|#{g.name}|n=#{blades.size}|len=#{lm.(len)}|sheet=#{m2.(sheet)}|" \
"elev=#{m2.(elev)}|posts=#{posts.size}/#{lm.(pl)}"
end
สังเกตว่าผมแยกออกมาสองค่าที่ไม่เท่ากันโดยตั้งใจ ค่า sheet คือพื้นที่แผ่นเมทัลชีทคลี่ ใช้สั่งของ ส่วนค่า elev คือพื้นที่หน้าบานตามรูปด้าน ใช้คิดค่าแรงติดตั้งและใช้เทียบกับแบบ สองค่านี้ต่างกันเยอะเพราะใบเกล็ดเอียงและซ้อนกัน งานจริงชุดนี้ได้แผ่นคลี่ 23.41 ตารางเมตร แต่หน้าบานแค่ 15.59 ตารางเมตร ถ้าเอาค่าเดียวไปใช้ทั้งสองที่ ไม่ฝั่งของก็ฝั่งค่าแรงที่จะเพี้ยน
แยกพื้นที่ตะแกรงด้วยชื่อวัสดุบวกทิศของหน้า
ตะแกรงเหล็กฉีกในงานนี้เป็นของเดิมที่ไม่รื้อ ต้องถอดปริมาณไว้เพื่อบอกในแบบว่าส่วนไหนคงเดิม ปัญหาคือมันไม่ได้ถูกจัดเป็นกลุ่มแยกตามผนัง มันเป็นหน้าที่ทาวัสดุตะแกรงกระจายอยู่ทั่วโมเดล ผมเลยเปลี่ยนวิธีเลือก จากเลือกด้วยชื่อกลุ่ม มาเป็นเลือกด้วย ชื่อวัสดุ แล้วจัดหมวดด้วย ทิศของเส้นตั้งฉาก บวกกับพิกัดระนาบ
mesh = Hash.new(0.0)
e.grep(Sketchup::Face).each do |f|
nm = f.material ? f.material.name : nil
next unless nm && nm.include?("Fencing")
b = f.bounds
key = if f.normal.y.abs > 0.9 && (b.min.y.to_f * q).round.abs < 3100 then "หน้าทางเดิน"
elsif f.normal.x.abs > 0.9 && (b.min.x.to_f * q) < 11000 then "ข้างซ้าย"
elsif f.normal.x.abs > 0.9 && (b.min.x.to_f * q) > 19000 then "ข้างขวา"
else "ระเบียงและอื่นๆ"
end
mesh[key] += f.area
end
mesh.each { |k, v| puts "MESH|#{k}|#{m2.(v)}" }
การเช็ค normal.y.abs > 0.9 แทนที่จะเช็ค > 0.99 มีเหตุผล เพราะหน้าที่ตั้งฉากกับแกนพอดีเป๊ะจะได้ 1.0 แต่หน้าที่ถูกสร้างจากการ push pull ต่อจากขอบที่เอียงนิดหน่อยอาจได้ 0.97 แล้วหลุดเงื่อนไขไปโดยที่เราไม่รู้ตัว ผมใช้ 0.9 เป็นเกณฑ์สำหรับ "จัดหมวด" แต่ใช้ 0.99 เป็นเกณฑ์สำหรับ "คิดพื้นที่ทาสี" ที่ต้องแม่น เพราะสองงานนี้ต้องการความเข้มงวดคนละระดับ ผลรวมของหมวดตะแกรงงานนี้ออกมา 50.48 ตารางเมตร แยกเป็นผนังหน้าทางเดิน 26.40 ผนังข้างซ้าย 4.80 ผนังข้างขวา 7.64 และระเบียงอีก 11.64
หักช่องเปิดด้วยการจับคู่พิกัดหน้า ไม่ใช่ลบทีหลัง
งานนี้มีการเจาะประตูห้องน้ำเพิ่มสี่ช่อง ขนาด 800 คูณ 2000 มิลลิเมตร วิธีที่คนทำกันคือคิดพื้นที่ผนังเต็มแล้วเอา 1.60 ตารางเมตรไปลบทีหลังสี่ครั้ง ซึ่งใช้ได้ถ้าจำนวนช่องถูก แต่ถ้าแบบถูกแก้แล้วช่องหายไปหนึ่งช่อง หรือเผลอเจาะไว้สองที่ในโมเดลแต่จำได้ที่เดียว ตัวเลขจะผิดเงียบๆ ผมเลยให้สคริปต์นับช่องจากโมเดลจริงแทน โดยจับที่หน้าวงกบซึ่งมีพิกัดตรงกับตำแหน่งที่เจาะ
dn = 0
[[14376, 14526], [15726, 15876]].each do |xa, xb|
e.grep(Sketchup::Face).select { |f|
b = f.bounds
f.normal.y.abs > 0.99 &&
(b.max.x.to_f * q - xb).abs < 3 && # ขอบขวาของช่อง คลาด 3 มม.
(b.min.x.to_f * q - xa).abs < 3 && # ขอบซ้ายของช่อง
b.min.z.to_f.abs < 0.01 && # เริ่มที่ระดับพื้น
(b.max.z.to_f * q - 2000).abs < 2 && # สูง 2000 พอดี
(b.max.y.to_f - b.min.y.to_f) * q > 700 # กว้างเกิน 700 = ไม่ใช่เศษหน้าเล็กๆ
}.each { dn += 1 }
end
puts "BATHDOOR|jamb_faces=#{dn}"
ค่าเผื่อคลาด 3 มิลลิเมตรตรงนั้นสำคัญ ถ้าเขียนเป็นเท่ากับเป๊ะ จะไม่เจอสักหน้า เพราะเลขที่ผ่านการแปลงจากนิ้วกลับมามันมีเศษทศนิยมติดเสมอ แต่ถ้าเผื่อกว้างเกินไปเป็น 30 มิลลิเมตร ก็จะไปคว้าหน้าอื่นที่อยู่ใกล้กันมาด้วย ผมใช้ 3 สำหรับพิกัด และ 2 สำหรับความสูง เพราะความสูงมีโอกาสชนกับระดับอื่นน้อยกว่า พอสคริปต์นับมาได้ตรงกับที่เจาะจริง ผมค่อยเอาไปคูณ 1.60 เป็นพื้นที่ช่อง กับคูณ 0.24 เป็นปริมาตรผนังที่ทุบออก
- คิดพื้นที่ผนังเต็มจากหน้าจริงในโมเดล ไม่ใช่จากขนาดห้องบนกระดาษ
- ให้สคริปต์ นับช่องเปิดจากหน้าวงกบ แล้วพิมพ์จำนวนออกมาให้เห็น
- เทียบจำนวนที่นับได้กับจำนวนในแบบด้วยตาหนึ่งรอบ ถ้าไม่ตรง แปลว่าโมเดลกับแบบไม่ตรงกัน หยุดแก้ก่อน
- ค่อยเอาจำนวนที่ยืนยันแล้วไปคูณพื้นที่ต่อช่องและปริมาตรผนังที่ทุบ
- แยกบรรทัด ผิวเปลือยรอบช่อง ออกมาต่างหาก เพราะเป็นงานฉาบเก็บขอบคนละราคา
พื้นที่ทาสี ต้องล็อกทั้งระนาบและช่วงพิกัด
หมวดที่พลาดง่ายที่สุดคือพื้นที่ทาสีภายในห้อง เพราะถ้าเลือกแค่ "หน้าที่ตั้งฉากกับแกน x" จะได้ผนังของห้องข้างเคียงติดมาด้วยทั้งกอง ผมเลยล็อกสามชั้น ชั้นแรกคือทิศของหน้า ชั้นที่สองคือระนาบที่หน้านั้นอยู่ ต้องตรงกับผิวผนังของห้องนี้ ชั้นที่สามคือช่วงพิกัดของอีกสองแกนต้องอยู่ในกรอบห้อง
[["ห้องซ้าย", 10876, 14376], ["ห้องขวา", 15876, 19376]].each do |nm, x1, x2|
a = 0.0
e.grep(Sketchup::Face).each do |f|
b = f.bounds
next if b.max.z.to_f * q > 3001 # ไม่เอาส่วนเหนือฝ้า
next unless b.min.y.to_f * q > 5580 && b.max.y.to_f * q < 11085 # อยู่ในช่วงลึกของห้อง
if f.normal.x.abs > 0.99 &&
((b.min.x.to_f * q - x1).abs < 2 || (b.min.x.to_f * q - x2).abs < 2)
a += f.area
elsif f.normal.y.abs > 0.99 &&
((b.min.y.to_f * q - 5582).abs < 2 || (b.min.y.to_f * q - 11082).abs < 2) &&
b.min.x.to_f * q > x1 - 2 && b.max.x.to_f * q < x2 + 2
a += f.area
end
end
puts "PAINT-IN|#{nm}|#{m2.(a)}"
end
ข้อดีของการคิดจากหน้าจริงคือ ช่องประตู หน้าต่าง และช่องลม ถูกหักออกให้เองอัตโนมัติ เพราะเนื้อที่ตรงนั้นไม่มีหน้าอยู่แล้ว ไม่ต้องมานั่งลบทีหลังทีละช่อง ห้องพักสองห้องในงานนี้ได้ห้องละ 38.44 ตารางเมตรเท่ากันพอดี ซึ่งเป็นตัวเลขที่ยืนยันได้ในตัวมันเองว่าถูก เพราะสองห้องนี้ทำเป็นภาพสะท้อนกัน ถ้าได้ไม่เท่ากันเมื่อไหร่ แปลว่ามีช่องเปิดสักช่องที่โมเดลไว้ไม่ครบ
ผมชอบหาคู่ที่ต้องเท่ากันโดยธรรมชาติไว้เสมอ เช่นสองห้องที่ทำ mirror กัน หรือผนังสองด้านที่ยาวเท่ากัน แล้วให้สคริปต์พิมพ์ทั้งคู่ออกมาข้างกัน ถ้าเลขสองตัวนี้ตรงกัน ผมเชื่อผลลัพธ์ที่เหลือได้เกือบหมด ถ้าไม่ตรง แปลว่าโมเดลมีจุดที่ผิด และผมยังไม่ต้องเสียเวลาไล่ตรวจตัวเลขอื่นเลย
ปิดท้ายด้วยรายงานที่ส่งได้จริง
ผมให้สคริปต์คืนค่าออกมาเป็นบรรทัดคั่นด้วยขีดตั้ง ขึ้นต้นด้วยชื่อหมวดตัวใหญ่ เช่น PART| LIGHTWALL| LOUVER| MESH| SCREEN| PAINT-IN| เหตุผลคือรูปแบบนี้อ่านด้วยตาก็ได้ และเอาไปแยกด้วย split เข้าตาราง HTML ก็ได้ทันที ไม่ต้องเขียน parser
out = []
# ... เก็บทุกหมวดใส่ out ระหว่างทาง ...
out << "SCREEN-TOTAL|net=#{m2.(tn)}|alu=#{lm.(ta)}"
out.join("\n")
จากนั้นผมเอาไปวางในไฟล์ HTML หน้าเดียวที่ตั้ง @page { size: A4 portrait; margin: 12mm; } แล้วสั่งพิมพ์เป็น PDF ส่งเจ้าของงาน ตารางแต่ละหมวดคือตารางเดียวในไฟล์ พร้อมหมายเหตุท้ายรายงานที่ผมเขียนไว้ตายตัวสี่บรรทัด คือ ตัวเลขทั้งหมดคิดจากพื้นผิวจริงในโมเดลและหักช่องเปิดแล้ว ผิวในห้องน้ำแยกไปเป็นงานปูกระเบื้องไม่รวมในพื้นที่ทาสี ส่วนที่ยังไม่ได้ใส่ในโมเดลมีอะไรบ้าง และหน่วยทั้งหมดเป็นมิลลิเมตรเว้นแต่ระบุ
สคริปต์ถอดปริมาณจะซื่อสัตย์กับโมเดลเท่านั้น ของที่ยังไม่ได้ปั้นก็จะไม่โผล่ในรายงาน และคนอ่านรายงานจะไม่มีทางรู้ว่ามันหายไป งานนี้ผมยังไม่ได้ใส่มุ้งลวดที่ช่องระบายอากาศด้านหลัง ผมเลยเขียนบรรทัดนั้นไว้ท้ายรายงานตรงๆ ว่ายังไม่รวม ดีกว่าปล่อยให้เจ้าของงานไปเจอเองตอนของมาไม่ครบ
ส่วนตัวผมคิดว่างานถอดปริมาณเป็นงานที่คุ้มกับการเขียนสคริปต์มากที่สุดในบรรดางานเขียนแบบทั้งหมด เพราะแบบมันถูกแก้เสมอ และทุกครั้งที่แก้ ใบถอดปริมาณต้องทำใหม่ทั้งใบ ถ้าวัดด้วยมือก็คือเริ่มนับหนึ่งใหม่ทุกรอบ แต่ถ้ามีสคริปต์ก็แค่รันซ้ำ เงื่อนไขเดียวคือต้องยอมตั้งชื่อกลุ่มให้ดีตั้งแต่วันแรก ใครจะปรับชุดชื่อกับเกณฑ์ค่าเผื่อคลาดให้เข้ากับงานตัวเองก็ตามสะดวกครับ ตรงไหนผมอธิบายตกหล่นหรือพิมพ์ผิด เดี๋ยวกลับมาแก้เพิ่มให้ภายหลังครับ
เคยเจองานแบบนี้ไหม? ติดตรงไหน?
มาแลกวิธีกันต่อในบอร์ด LinuxThai



ความคิดเห็น 0
ยังไม่มีความคิดเห็น — เป็นคนแรกเลย