จากโมเดลเป็นผังตัดเหล็ก 6 เมตร แล้วออกชีทตัดให้ช่าง
ใบสั่งตัดเหล็กที่ช่างเอาไปใช้ได้จริง ไม่ใช่แค่รายการความยาว มันต้องบอกด้วยว่าชิ้นไหนอยู่เส้นไหน ตัดเรียงยังไง และเหลือเศษเท่าไร ซึ่งทั้งหมดนั้นคำนวณจากโมเดลได้ตรงๆ
พอดีผมทำโครงเหล็กชิ้นเล็กชิ้นหนึ่งเป็นชั้นวางแปะข้างเตียง ปั้นในคอมพิวเตอร์จนจบแล้วก็ถึงตอนต้องบอกร้านว่าจะซื้อเหล็กกี่เส้น ตอนแรกผมนับความยาวรวมได้ 4.69 เมตรก็คิดว่าซื้อเส้นเดียวจบ แต่พอเอาไปให้ช่างดู ช่างถามกลับว่าแล้วชิ้นไหนตัดก่อนตัดหลัง เพราะถ้าเรียงผิดคือเหล็กเส้นเดียวไม่พอ ผมเลยกลับมาเขียนสคริปต์ให้มันจัดผังตัดออกมาให้เสร็จ แล้วออกเป็นชีทตัดที่พิมพ์ลง A4 ไปวางข้างเครื่องตัดได้เลย
เรื่องธรรมเนียมว่าชิ้นไหนซ้อนบนชิ้นไหน หน้าตัดไหนมีขายจริง ผมเขียนแยกไว้แล้วใน ธรรมเนียมเขียนแบบโครงเหล็กไทย ตอนนี้เอาไปต่ออีกช่วงหนึ่งคือ ตั้งแต่โมเดลเสร็จ ไปจนถึงกระดาษที่ช่างถือไว้ตอนตัด
อ่านหน้าตัดกับความยาวจากกล่องครอบ แต่ต้องเรียงก่อน
ชิ้นส่วนโครงเหล็กเกือบทั้งหมดเป็นแท่งตรง กล่องครอบของมันเลยบอกทุกอย่างที่ต้องรู้ ขอแค่อย่าไปเชื่อว่า width คือความกว้าง เพราะค่าพวกนั้นอิงแกนโลก ไม่ได้อิงตัวชิ้นงาน เสาที่วางตั้งกับคานที่วางนอนเป็นเหล็กหน้าตัดเดียวกันแท้ๆ แต่ค่าที่อ่านได้จะสลับกันหมด วิธีเดียวที่ปลอดภัยคือเอาสามมิติมาเรียงก่อนแล้วอ่านตามตำแหน่ง
# encoding: UTF-8
m = Sketchup.active_model
st = m.entities.grep(Sketchup::Group).find { |g| g.name =~ /ชั้นข้างเตียง/ }
mv = ->(v) { (v.to_f * 25.4).round(1) }
rows = [] # [ชื่อชิ้น, หน้าตัด, ความยาว, จำนวน]
st.entities.grep(Sketchup::Group).each do |g|
b = g.bounds
dx = mv.(b.max.x - b.min.x)
dy = mv.(b.max.y - b.min.y)
dz = mv.(b.max.z - b.min.z)
d = [dx, dy, dz].sort # d[0]=หนา d[1]=กว้าง d[2]=ยาว
case g.name
when /^เสาแนบข้าง/ then rows << ["เสาแนบข้าง", "กล่อง 1 นิ้ว", d[2], 1]
when /^เสาค้ำบนเพลท/ then rows << ["เสาค้ำบนเพลท", "กล่อง 1 นิ้ว", d[2], 1]
when /^คานขวางชั้น/ then rows << ["คานขวางชั้น", "กล่อง 1 นิ้ว", d[2], 1]
when /^เพลทคีบ/ then rows << ["เพลทคีบสันเตียง", "แบน 4 มม. x #{d[1].round}", d[2], 1]
end
end
สังเกตว่าเหล็กแบนผมดึงมาสองค่า คือ d[1] เป็นหน้ากว้างของแผ่น และ d[2] เป็นความยาว เพราะเหล็กแบนสั่งของด้วยหน้ากว้างคูณความหนา แล้วตัดตามความยาว มันคนละแบบกับเหล็กกล่องที่หน้าตัดตายตัวอยู่แล้ว ถ้าเอาไปรวมกองเดียวกันแล้วจัดผังตัดพร้อมกัน จะได้ผังที่ตัดจริงไม่ได้
รวมรายการซ้ำก่อน แล้วค่อยจัดผัง
ในโครงหนึ่งชุดมีชิ้นที่ยาวเท่ากันซ้ำกันเยอะมาก เสาสี่ต้นยาวเท่ากันหมด คานขวางสามเส้นยาวเท่ากันหมด ถ้าปล่อยเป็นรายการยาวสิบสองบรรทัด ช่างต้องมานั่งไล่ว่าอันไหนซ้ำ ผมเลยยุบด้วย Hash ที่ใช้คู่ ชื่อ หน้าตัด ความยาว เป็นกุญแจ แล้วนับจำนวนแทน
agg = Hash.new(0)
rows.each { |nm, sec, len, n| agg[[nm, sec, len]] += n }
box_rows = agg.select { |(nm, sec, _), _| sec =~ /กล่อง/ }
flat_rows = agg.reject { |(nm, sec, _), _| sec =~ /กล่อง/ }
tot_box = box_rows.sum { |(_, _, len), n| len * n }
การยุบรายการยังมีผลกับผังตัดด้วย เพราะขั้นตอนถัดไปจะคลี่กลับเป็นชิ้นเดี่ยวอีกที แต่คราวนี้เรารู้แล้วว่ามีกี่ชิ้นและยาวเท่าไร ไม่ต้องเดินเข้าโมเดลอีกรอบ
จัดผังตัดด้วย first-fit decreasing แล้วเผื่อร่องใบเลื่อย
ปัญหาการจัดชิ้นลงเส้นให้ใช้เส้นน้อยที่สุด เป็นปัญหาที่หาคำตอบดีที่สุดจริงๆ ยาก แต่ในงานหน้างานไม่ต้องดีที่สุด แค่ดีพอและอธิบายให้ช่างเข้าใจได้ วิธีที่ผมใช้คือ เรียงชิ้นจากยาวไปสั้น แล้วยัดลงเส้นแรกที่ยังพอ เรียกว่า first-fit decreasing เขียนได้ในสิบบรรทัด และให้ผลใกล้เคียงค่าดีที่สุดในงานขนาดเล็กเกือบทุกครั้ง
# ผังตัดจากเส้น 6000 มม. เผื่อร่องใบเลื่อย 3 มม. ต่อหนึ่งรอยตัด
pieces = []
box_rows.each { |(nm, _, len), n| n.times { pieces << [len, nm] } }
pieces.sort_by! { |l, _| -l } # ยาวก่อน
bars = []
pieces.each do |len, nm|
bar = bars.find { |b| b[:left] >= len + 3 } # เส้นแรกที่ยังพอ
bar ||= (bars << { :left => 6000.0, :items => [] }).last
bar[:left] -= (len + 3)
bar[:items] << "#{nm} #{len.round}"
end
bars.each_with_index do |b, i|
puts "เส้น #{i + 1}: " + b[:items].join(" + ") + " | เหลือ #{b[:left].round}"
end
ใบเลื่อยวงเดือนตัดเหล็กกินเนื้อประมาณ 2 ถึง 3 มิลลิเมตรต่อหนึ่งรอย ผมใส่ 3 ไว้ให้ปลอดภัย ถ้าชิ้นเล็กหลายสิบชิ้นแล้วไม่บวกส่วนนี้ ตอนตัดจริงจะพบว่าชิ้นสุดท้ายสั้นไปสองสามมิลลิเมตรทุกครั้ง งานเล็กอาจไม่รู้สึก แต่งานที่มีสามสิบรอยตัดต่อเส้นคือหายไปเกือบสิบเซนติเมตร ซึ่งพอทำให้ชิ้นสุดท้ายใช้ไม่ได้
ผมให้สคริปต์พิมพ์ เศษเหลือต่อเส้น ออกมาด้วยเสมอ ไม่ใช่แค่จำนวนเส้นที่ต้องซื้อ เพราะเศษเหลือคือข้อมูลที่ช่างใช้ตัดสินใจ ถ้าเหลือ 1,276 มิลลิเมตรแบบงานนี้ ช่างจะเก็บไว้ทำงานอื่นได้ แต่ถ้าเหลือเป็นเศษกระจายทีละ 200 มิลลิเมตรสามสี่ก้อน แปลว่าผังตัดไม่ดี ควรกลับไปขยับความยาวชิ้นในแบบให้ลงตัวกว่านี้ก่อน
มุมกรอบ ตัดปาก 45 สองหัว หรือใช้เส้นเดียวบากคอ
พอถึงกรอบชั้นที่เป็นผัง ตัวแอล มีหกด้าน คำถามคือจะทำยังไง วิธีมาตรฐานคือตัดหกท่อน แต่ละท่อนตัดปาก 45 องศาสองหัว แล้วเชื่อมชนกันที่มุม รวมเป็นสิบสองรอยตัดเอียงและหกรอยเชื่อมมุม ผมลองอีกวิธีคือ ใช้เหล็กเส้นเดียวยาวตลอด แล้วบากคอที่มุมแล้วหักเอา
หกท่อน ตัดปาก 45
- ตัดเอียง 45 องศา 12 รอย
- เชื่อมชนมุม 6 จุด ต้องประกบให้ได้ฉาก
- ความยาวรวมคิดจากขอบนอกของแต่ละด้าน
- มุมเบี้ยวได้ถ้าจับยึดไม่แน่นตอนเชื่อม
บากคอ 90 แล้วหักฉาก
- บาก 6 จุด บวกรอยต่อชนปลาย 1 จุด
- ประหยัดเหล็ก 100 มิลลิเมตร ต่อกรอบ
- มุมได้ฉากพอดีเพราะหักจากเส้นเดียว
- ความยาวต้องคิดจาก เส้นกึ่งกลางท่อ ไม่ใช่ขอบนอก
จุดที่คนคำนวณผิดกันบ่อยคือความยาวของเส้นเดียวนี้ ถ้าเอาความยาวขอบนอกหกด้านมาบวกกัน จะได้ยาวเกินความจริง เพราะการบากแล้วหักใช้ ผนังในของท่อเป็นบานพับ แนวที่ไม่ยืดไม่หดตอนหักคือเส้นกึ่งกลางท่อ ผมเลยคำนวณจากเส้นกึ่งกลางเสมอ ได้ออกมา 2,374 มิลลิเมตรสำหรับกรอบชุดนี้
# ผังตัว L: เดินตามจุดมุมของเส้นกึ่งกลางท่อ แล้ววัดระยะทีละช่วง
arm_x0 = -100.0; x_end = 900.0
y_out = -250.0; y_in = 0.0; y_wood = -50.0
cl = 4.0 # ครึ่งความหนาผนังท่อ
fo = [[arm_x0, y_out + cl], [x_end - cl, y_out + cl], [x_end - cl, y_in - cl],
[0, y_in - cl], [0, y_wood], [arm_x0, y_wood]]
fo.each_with_index do |p, i|
q = fo[(i + 1) % fo.size]
len = Math.sqrt((q[0] - p[0])**2 + (q[1] - p[1])**2).round(1)
puts "ช่วงที่ #{i + 1} ยาว #{len}"
end
รอยบากคอ 90 องศาคือการตัดเอียง 45 องศาสองครั้งให้ปลายมาบรรจบกันที่ผนังในพอดี ทะลุสามด้านของท่อ เหลือผนังในไว้เป็นบานพับ แล้วหักบนโต๊ะระนาบเดียวกัน จบด้วยการเชื่อมปิดรอยบาก ความกว้างของปากบากที่ผิวนอกเท่ากับสองเท่าของความสูงท่อพอดี ท่อหนึ่งนิ้วก็คือ 50.8 มิลลิเมตร
ตำแหน่งบากต้องเริ่มวัดจากกลางเส้นตรง ไม่ใช่จากมุม
เรื่องนี้ไม่ใช่คณิตศาสตร์ แต่เป็นเรื่องของการทำงานจริง ถ้าเริ่มวัดจากมุมใดมุมหนึ่ง รอยต่อชนปลายที่ปิดวงก็จะไปตกที่มุมพอดี ซึ่งเป็นจุดที่อ่อนที่สุดของกรอบและเชื่อมยากที่สุด ผมเลยเริ่มวัดจากกึ่งกลางของด้านที่ยาวที่สุด ให้รอยต่อชนปลายไปอยู่กลางเส้นตรงแทน
| ลำดับบาก | ระยะจากจุดเริ่ม | ช่วงถัดไป | ทิศที่หัก |
|---|---|---|---|
| 1 | 485.3 | 216.6 | หักเข้า มุมนอก |
| 2 | 701.9 | 870.6 | หักเข้า มุมนอก |
| 3 | 1,572.5 | 46.0 | หักเข้า มุมนอก |
| 4 | 1,618.5 | 100.0 | หักออก มุมเว้า บากด้านตรงข้าม |
| 5 | 1,718.5 | 170.6 | หักเข้า มุมนอก |
| 6 | 1,889.1 | 485.3 | หักเข้า แล้วชนปลายกับจุดเริ่ม |
บากจุดที่ 3 กับจุดที่ 4 ห่างกันแค่ 46 มิลลิเมตร และหักคนละทิศ ซึ่งเป็นระยะที่จับยึดยาก ผมเลยเขียนกำกับไว้ในชีทตรงๆ ว่า ถ้าช่างเห็นว่าสั้นไป ให้ตัดช่วง 46 นี้เป็นชิ้นแยกแล้วเชื่อมชนสองรอยแทนได้ การเขียนทางออกไว้ให้ ดีกว่าปล่อยให้ช่างตัดสินใจเองหน้างานแล้วเราไม่รู้ว่าของจริงออกมาเป็นแบบไหน
รูปตัดขวางที่ดึงพิกัดจากโมเดลจริง
ชีทตัดที่มีแต่ตัวเลขความยาว ช่างยังต้องเดาว่าชิ้นไหนอยู่ระดับไหน ผมเลยใส่รูปตัดขวางไว้หนึ่งรูปเสมอ โดยไม่วาดมือ แต่ให้สคริปต์เดินเข้าไปในโมเดล หาทุกชิ้นที่ถูกระนาบตัดผ่าน แล้วคืนพิกัดสี่เหลี่ยมของแต่ละชิ้นออกมา
# ดึงหน้าตัดจริงที่ระนาบ x = xc คืนสี่เหลี่ยม (y0,z0,y1,z1) ของทุกชิ้นที่โดนตัด
m = Sketchup.active_model
xc = 300.0
mv = ->(v) { (v.to_f * 25.4).round(1) }
rows = []
walk = lambda do |ents, prefix|
ents.grep(Sketchup::Group).each do |g|
kids = g.entities.grep(Sketchup::Group)
if kids.empty? # ชิ้นจริง ไม่ใช่กลุ่มห่อ
b = g.bounds
next unless mv.(b.min.x) <= xc && mv.(b.max.x) >= xc
rows << [prefix + g.name, mv.(b.min.y), mv.(b.min.z), mv.(b.max.y), mv.(b.max.z)]
else
walk.(g.entities, prefix) # ลงลึกต่อ
end
end
end
walk.(m.entities, "")
rows.sort_by! { |r| [r[2], r[1]] } # เรียงจากล่างขึ้นบน
ค่าที่ได้เอาไปวาดเป็น SVG ในชีทได้ตรงๆ เพราะมันเป็นสี่เหลี่ยมพร้อมพิกัดอยู่แล้ว ข้อดีคือรูปตัดจะตรงกับโมเดลเสมอ แก้โมเดลแล้วรันใหม่ รูปก็เปลี่ยนตาม ไม่มีวันหลุดจากกัน ระดับสำคัญที่ผมเขียนกำกับไว้ในรูปคือ ท้องกรอบ ผิวบนกรอบ สันขอบของเดิม และท้องเสาแต่ละชุด เพราะสี่ค่านี้คือสิ่งที่ช่างต้องขีดเส้นบนของจริงก่อนเชื่อม
เผื่อระยะร่นตามความหนาของผิวปิด ไม่ใช่ตามขนาดช่อง
ข้อนี้ผมเจอตอนทำงานไม้ที่เป็นโครงแล้วปิดผิวด้วยไม้อัด แต่หลักคิดใช้กับงานเหล็กที่ต้องกรุแผ่นได้เหมือนกัน สมมติฝาหนึ่งแผ่นประกอบด้วยไม้อัด 4 มิลลิเมตร บวกโครง 22 มิลลิเมตร บวกไม้อัดอีก 4 มิลลิเมตร รวมเป็น 30 มิลลิเมตรพอดี ถ้าโครงของฝาบนวิ่งไปหยุดที่ผิวนอกของฝาข้าง แปลว่ามันไปหยุดที่ ผิวไม้อัด ไม่ใช่เนื้อโครง ยิงตะปูเข้าไปก็ไม่มีอะไรจับ
# ฝาหนึ่งแผ่น = ไม้อัด 4 + โครง 22 + ไม้อัด 4 = 30 มม.
# ฝาข้างซ้ายวางที่ x = 4 ถึง 34 -> ผิวเนื้อโครงอยู่ที่ x = 26
# ฝาข้างขวาวางที่ x = 1150 ถึง 1180 -> ผิวเนื้อโครงอยู่ที่ x = 1154
#
# ความกว้างช่องระหว่างผิวไม้อัดด้านใน = 1120
# แต่โครงฝาบน/ล่าง/หลัง ต้องยาว 1128 เพื่อวิ่งเข้าไปชนเนื้อโครงฝาข้าง
frame_len_wrong = 1120 # หยุดที่ผิวไม้อัด ไม่มีเนื้อไม้ให้ยึด
frame_len_right = 1128 # ชนเนื้อโครงกับเนื้อโครง
หลักที่ผมใช้เตือนตัวเองสั้นๆ คือ โครงต้องชนเนื้อกับเนื้อ ผิวปิดค่อยมาทีหลัง ระยะที่ต้องเผื่อไม่ใช่ขนาดช่องบนแบบ แต่คือความหนาของผิวปิดที่แต่ละด้าน สองด้านก็บวกเข้าไปสองครั้ง เวลาถอดแบบเป็นรายการตัด ตัวเลขที่ต้องพิมพ์ลงชีทคือ 1128 ไม่ใช่ 1120 และตรงนี้คือจุดที่คนถอดแบบด้วยตาผิดกันเยอะที่สุด เพราะบนหน้าจอมันดูเหมือนกันหมด
ชีทตัด A4 ที่พิมพ์แล้วออกมาตรงจริง
ชีทตัดผมทำเป็น HTML หน้าเดียวแล้วสั่งพิมพ์ผ่านเบราว์เซอร์ เหตุผลคือแก้ง่ายกว่าไปวาดในโปรแกรมเขียนแบบ และฝัง SVG ที่ได้จากสคริปต์เข้าไปตรงๆ ได้ กุญแจอยู่ที่ CSS สำหรับสั่งพิมพ์สามข้อ คือกำหนดขนาดหน้าเป็น A4 ยกเลิกระยะขอบของเบราว์เซอร์แล้วมาตั้งเองในกล่อง และห้ามตัดกลางส่วนของเนื้อหา
@media print {
@page { size: A4; margin: 0; }
body { background: #fff; padding: 0; }
.sheet {
border: none; margin: 0;
width: auto; min-height: auto;
padding: 12mm; /* ตั้งขอบกระดาษเอง ให้คุมได้จริง */
page-break-after: always;
}
.sheet:last-child { page-break-after: auto; }
section { break-inside: avoid; } /* ห้ามตัดตารางกลางหน้า */
}
โครงของชีทที่ผมใช้ทุกงานมีเจ็ดส่วนเรียงตามลำดับที่ช่างทำงานจริง ไม่ใช่ตามลำดับที่คนเขียนแบบคิด
- สรุปงานเหล็ก ตัวใหญ่ทั้งสี่ตัว ความยาวรวม จำนวนท่อน จำนวนรอยบาก จำนวนชิ้นตัดฉาก
- ผังกรอบมองจากบน พร้อมเลขในวงกลมบอกตำแหน่งบาก และตัวเลขความยาวคลี่บนเส้น
- ตารางรายการตัด รหัส ชื่อชิ้น ความยาว จำนวน รวม วิธีขึ้นรูป
- ตารางตำแหน่งบาก ระยะจากจุดเริ่ม ช่วงถัดไป และทิศที่หัก
- รูปตัดขวาง ที่ระนาบซึ่งตัดผ่านชิ้นสำคัญ พร้อมระดับกำกับ
- ผังตัดบนเส้น 6 เมตร เรียงจากยาวไปสั้น ปิดท้ายด้วยเศษเหลือ
- ตารางเจาะและอุปกรณ์ยึด ขนาดรู จำนวน ระยะ และลำดับเชื่อมประกอบ
ถ้าใครเปิดกล่องพิมพ์แล้วปล่อยไว้ที่ ย่อให้พอดีหน้า สเกลจะเพี้ยนทั้งแผ่นโดยที่ตัวเลขบนกระดาษยังถูกอยู่ ช่างที่เอาไม้บรรทัดไปทาบวัดจะได้ระยะไม่ตรงกับตัวเลข แล้วเชื่อว่าตัวเลขผิด ผมเลยเขียนไว้ท้ายชีททุกใบว่า ทุกระยะเป็นมิลลิเมตร ให้ยึดตัวเลขเป็นหลัก ไม่ให้ยึดจากการวัดบนกระดาษ แล้วไม่ต้องใส่มาตราส่วนลงในชีทตัดเลย เพราะชีทตัดไม่ใช่แบบก่อสร้าง
ส่วนตัวผมคิดว่าการทำถึงขั้นชีทตัดคุ้มมาก เพราะมันย้ายจุดที่ต้องคิดจากหน้างานมาอยู่บนโต๊ะ ช่างไม่ต้องคำนวณอะไรเลยตอนยืนอยู่หน้าเครื่องตัด แค่ไล่ตามลำดับที่พิมพ์ไว้ และถ้าแบบเปลี่ยน ก็แค่รันสคริปต์ใหม่แล้วพิมพ์ใหม่ ไม่ต้องมานั่งไล่แก้ตัวเลขในตารางทีละช่อง ใครจะเอาโครงชีทกับค่าเผื่อร่องเลื่อยไปปรับตามเครื่องมือที่ตัวเองมีก็ตามสะดวกครับ ตรงไหนผมอธิบายตกหล่นหรือพิมพ์ผิด เดี๋ยวกลับมาแก้เพิ่มให้ภายหลังครับ
เคยเจองานแบบนี้ไหม? ติดตรงไหน?
มาแลกวิธีกันต่อในบอร์ด LinuxThai



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