drawing-geometry

วิธีอ่านเส้นในแบบก่อสร้างให้เป็นรูปทรงที่ใช้ถอดปริมาณได้ใน ESTIMETR — แยกผิวผนัง หน้าเสา และสัญลักษณ์ออกจากกันก่อนคำนวณเสมอ ใช้ skill นี้ทุกครั้งที่แตะการไล่ขอบห้อง การดูดจุด การหาพื้นที่จากแบบ หรือกา

SKILL.md

GitHub

อ่านเส้นในแบบให้เป็นรูปทรงที่เชื่อถือได้

กฎเดียวที่ต้องจำ

ในแบบก่อสร้างไม่มี "พิกเซลดำ" มีแต่ของสามชนิดที่หน้าตาเหมือนกันแต่ความหมายคนละเรื่อง โค้ดที่มองมันเป็นสิ่งเดียวกันจะได้พื้นที่ผิดเสมอ และผิดแบบเงียบ ๆ ที่ตรวจไม่เจอจากตัวเลข

ชนิด หน้าตาในแบบ ต้องทำอย่างไร
ผิวผนัง เส้นตรงยาวหลายเมตร มีคู่ขนานห่างกันเท่าความหนาผนัง ระหว่างคู่มักมีลายขีด กั้น — ขอบของห้องต้องแนบเส้นนี้พอดี
หน้าเสา สั้นกว่าผนังมาก แต่เป็นโครงสร้าง มักฝังอยู่ในแนวผนังหรือยื่นเข้ามาในห้อง กั้น — ขอบต้องเดินอ้อมเข้าไปกอด ไม่ตัดมุมข้าม
สัญลักษณ์ กรอบป้ายชนิดพื้นและฝ้า ตัวอักษรชื่อห้อง สามเหลี่ยมบอกระดับ วงโค้งบานสวิงประตู รูปสุขภัณฑ์ เส้นบอกระยะ มองข้าม — ต้องไม่กั้นและต้องไม่กินพื้นที่

เมื่อเจ้าของงานขีดเส้นไกด์ให้ อ่านมันเป็นข้อกำหนดของรูปทรงทั้งรูป

นี่คือบทเรียนที่แพงที่สุดของ 2026-09-04 เจ้าของงานส่งภาพที่ขีดเส้นน้ำเงินทับผลลัพธ์ มาให้แปดรอบ แต่ละรอบเขาชี้จุดที่ยังผิด แล้วเราก็ไล่แก้จุดนั้น ทำให้เสียเวลาแปดรอบ ทั้งที่มันคือความผิดพลาด สองอย่าง ที่โผล่ออกมาเป็นอาการหลายจุด

อาการที่เขาชี้ทีละครั้ง ความผิดพลาดจริง
สัญลักษณ์กินพื้นที่ · ประตูทำให้สีทะลุ · กรอบป้ายดันขอบ · วงสวิงทำให้ขอบอ้อม แยกชนิดของเส้นไม่ออก แก้ครั้งเดียวด้วยการคัดเส้นก่อนไล่สี
ขอบไม่แนบผนัง · มุมเสาเพี้ยน · เส้นลากเฉียง · ไฮไลท์กินเสา ขอบอยู่ผิดที่และผิดชนิด แก้ครั้งเดียวด้วยการไล่ขอบแบบเหลี่ยมล้วนแล้วดันไปชิดผิวในของเส้น

วิธีที่ถูก เอาเส้นไกด์มาถามว่า รูปทรงนี้ถูกนิยามด้วยกฎอะไร แล้วหากฎที่อธิบายทุกด้าน พร้อมกัน · สำหรับผังพื้น กฎคือ "สี่เหลี่ยมมุมฉาก ขอบชิดผิวในของเส้นผนัง หักเป็นขั้นอ้อมเสา" ซึ่งอธิบายทุกอาการข้างบนได้หมดในประโยคเดียว

อย่าไล่แก้ทีละจุดที่เขาชี้ เพราะแต่ละจุดคืออาการ ไม่ใช่โรค และการแก้ทีละอาการ มักสร้างอาการใหม่ เช่น กติกาเสาที่เพิ่มเข้าไปกลายเป็นเสาปลอมทุกบานประตูในรอบถัดมา

สิ่งที่ผิดมาแล้วจริง อย่าเดินซ้ำ

หนึ่ง — ไล่สีบนพิกเซลดิบ แล้วสีทะลุออกทั้งชั้น

2026-09-01 คลิกห้องที่มีช่องประตู ได้ 266 ตร.ม. จากห้องที่จริง ๆ ราว 20 ตร.ม. 2026-09-04 เกิดซ้ำ ได้ 265.13 ตร.ม. จากห้องราว 7 ตร.ม. · เพดานสัดส่วนพื้นที่จับไม่ได้ เพราะหน้ากระดาษ A3 ใหญ่พอที่ 265 ตร.ม. ยังไม่ถึงหนึ่งในสี่ของหน้า → ช่องเปิดต้องถูกเชื่อมก่อนไล่สี ไม่ใช่ไล่ไปก่อนแล้วค่อยตรวจว่ารั่วไหม

สอง — เอาการขยาย-หดรูปทรงมาแก้ปัญหาของเส้น

2026-09-04 ใช้ morphological closing รัศมี 0.40 เมตรกับก้อนพื้นที่ที่ไล่ได้ กลบสามเหลี่ยมบอกระดับได้จริง แต่ (ก) เอากรอบป้ายที่กว้างเกือบ 2 เมตรไม่อยู่ (ข) เอาวงสวิงประตูรัศมีเกือบ 1 เมตรไม่อยู่ (ค) มนมุมจริงของห้องด้วยรัศมีเดียวกัน ทำให้ขอบลอยห่างผนัง เจ้าของงานจับได้ทันทีจากรูป ทั้งที่ตัวเลขพื้นที่ดูสมเหตุสมผล → การเพิ่มรัศมีไม่ใช่คำตอบ รัศมีที่ใหญ่พอจะกลบป้ายได้ จะกินเสาหายและมนมุมจนไม่ใช่ห้อง → ปัญหาของเส้นต้องแก้ที่เส้น คือคัดว่าเส้นไหนกั้น ก่อนจะเริ่มไล่สี

สาม — ตัวเลขถูกไม่ได้แปลว่ารูปถูก

พื้นที่ที่ได้อาจใกล้เคียงของจริงทั้งที่รูปทรงผิดคนละเรื่อง เพราะส่วนที่ขาดกับส่วนที่เกิน หักกลบกันพอดีโดยบังเอิญ · ต้องดูรูปทับบนแบบทุกครั้ง ไม่ใช่ดูแค่ตัวเลข 2026-09-04 เคยรายงานว่าแก้แล้วโดยถ่ายภาพหน้าจอเก็บไว้แต่ไม่ได้เปิดดู ตัวเลขดีขึ้นจริง แต่รูปยังผิด · ถ่ายแล้วต้องเปิดดูก่อนพูด

สี่ — ลดจุดของขอบด้วย Douglas-Peucker

วิธีนั้นยอมแทนบันไดพิกเซลด้วยเส้นเฉียงถ้าคลาดไม่เกินค่าที่ตั้งไว้ ซึ่งกินมุมเสาไปเป็น สามเหลี่ยมโดยที่ตัวเลขพื้นที่ยังดูสมเหตุสมผล · องค์อาคารเป็นเหลี่ยม ขอบจึงต้องเป็น แนวนอนกับแนวตั้งล้วน โดยโครงสร้างของอัลกอริทึม ไม่ใช่โดยค่าที่ตั้งไว้ → ไล่ขอบตามรอยต่อระหว่างพิกเซล (traceRectilinearOutline) แล้วยุบเฉพาะขั้นที่สั้นกว่า OUTLINE_MIN_STEP_METRES ซึ่งเป็นความหยาบของภาพ ไม่ใช่รูปทรง

ห้า — เอาคำว่า "กึ่งกลาง" ไปใช้กับเส้นผนัง

2026-09-04 เซสชันหนึ่งอ่านเส้นไกด์แล้วสรุปเองว่า "ผิวจริงอยู่ที่กึ่งกลางเส้นผนัง" แล้วเขียนลง โค้ด ลงไม้ต่อ และลง skill นี้ ราวกับเป็นคำสั่งของเจ้าของงาน ทั้งที่เขาไม่เคยพูด เขาทักเองว่า "กึ่งกลางเส้นยังไง ผมเคยบอกที่ไหน" · เซสชันถัดมาก็หลงเชื่อคำอธิบายในโค้ดต่ออีกทอด

ในคำพูดของเจ้าของงาน "กึ่งกลาง" เป็นของเสาเท่านั้น คือจุดตัดของเส้นกริดแนวแกน x กับ y ที่วิ่งผ่านกึ่งกลางเสา ซึ่งเป็นคนละเลขกับพื้นที่ห้อง (grid-bay.ts ป้ายไทย "กึ่งกลางเสาถึงกึ่งกลางเสา") ห้ามเอาคำนี้ไปใช้กับเส้นผนังเด็ดขาด

กติกาจริงของขอบห้อง เขาเคาะเมื่อ 2026-09-04 ว่า "เส้นผนังเอาตามที่ผมลากเลย หนาหรือบาง ก็เอาชิดด้านในห้อง" ซึ่งตรงกับที่บันทึกไว้ตั้งแต่ 2026-09-03 ใน docs/plans/2026-09-03-room-area-explained-and-materials.md ว่าไล่ขอบตามเส้นผิวผนังด้านใน และตรงกับที่จอแอปเขียนอยู่แล้วว่า "วัดถึงผิวผนังด้านใน ไม่ใช่กึ่งกลางเสา" → snapToLinePixels เอื้อมออกไปหาผิวในของหมึกแล้วหยุดตรงนั้น ไม่เข้าไปในเนื้อผนัง

บทเรียนที่ใหญ่กว่าเรื่องขอบ คำตัดสินของเจ้าของงานอยู่ใน docs/plans/ กับ ADR เท่านั้น คำอธิบายในโค้ดกับไม้ต่อเป็นการตีความของเซสชันก่อน เชื่อไม่ได้จนกว่าจะเปิดเอกสารต้นทางเทียบ ก่อนอ้างว่า "เจ้าของงานสั่งไว้ว่า..." ให้ไปหาบรรทัดจริงมาก่อนเสมอ

หก — เชื่อว่าหมึกตัวแรกที่การไล่สีชนคือผนัง

2026-09-04 ผนังบนของห้องพักพยาบาลมีหมึกหนาสองพิกเซลเกาะอยู่ใต้เส้นผิวผนัง ตั้งแต่กรอบ หน้าต่างถึงปลายสามเหลี่ยมบอกระดับ กินไปแปดในสิบของด้าน ขอบจึงไปหยุดใต้หมึกก้อนนั้น ต่ำกว่าเส้นน้ำเงินของเจ้าของงานสองพิกเซล · เขาเลือกจากภาพขยาย 14 เท่าว่าขอบต้องอยู่ใต้ เส้นผิวบางที่วิ่งตลอดแนว ไม่ใช่ใต้หมึกที่โผล่แค่บางช่วง → snapOutlineToLines ถามทั้งด้านพร้อมกันว่าแถวหมึกแถวไหนมีจุดสุ่มเห็นอย่างน้อยเก้าในสิบ แล้วยกทั้งด้านไปชิดแถวนั้น · แถวที่เห็นแค่บางช่วงคือสัญลักษณ์

เจ็ด — ยุบขั้นบันไดทีละขั้น แล้วบันไดที่ต่อกันไม่เคยหาย

มุมเสาล่างขวาของห้องเดียวกันเป็นบันไดหกขั้น ขั้นละหนึ่งถึงสามพิกเซล เพราะสามเหลี่ยม บอกระดับวางทับมุมเสาพอดี พอคัดสัญลักษณ์ออก มุมที่เหลือจึงแหว่ง · removeJogs ยุบไม่ได้ เพราะมันต้องการด้านข้างที่ยาวกว่าขั้น ซึ่งในบันไดต่อกันไม่มีขั้นไหนมี → collapseStaircases ยุบบันไดที่ทุกขั้นเล็กกว่าเสาต้นเล็กสุด (COLUMN_MIN_METRES) เป็น มุมฉากเดียว เลือกมุมที่พื้นที่เล็กลง เพราะเศษบันไดคือเสาที่แหว่ง ไม่ใช่พื้นห้อง · ต้องยุบหลังเกาะเส้นผนัง ยุบก่อนแล้วมุมใหม่จะพาดทับที่แหว่ง ขั้นเกาะเส้นจะดันมันเข้าเสาอีก

แปด — ถือว่าทุกเส้นกั้น แล้วค่อยคัดสัญลักษณ์ออกทีละชนิด

2026-09-04 ค่ำ ห้องน้ำหน้า 7 พื้นเป็นตารางกระเบื้อง 132 ช่อง โถ อ่าง สัญลักษณ์เต็มห้อง เส้นกระเบื้องยาวเป็นเมตรผ่านด่านผนัง ช่องกระเบื้อง 0.28 ม. ขนาดพอดีเกณฑ์เสา พื้นทั้งห้องถูกถมดำ คลิกแล้วได้ "จุดอยู่บนเส้น" · ไล่คัดทีละชนิด (กระเบื้อง แล้วสุขภัณฑ์ แล้วเส้นตัด …) ไม่มีวันครบ → กลับด้านคำถาม: อะไรคือผนัง — เส้นยาวที่มีเส้นคู่ขนานในระยะความหนาผนังและช่องระหว่าง เป็นลายผนังหรือสะอาด หรือแถบทึบที่ยาวในตัวเอง · อะไรคือเสา — ช่องปิดสนิทขนาดเท่าเสาที่ล้อม ครบสี่ด้านและรอบนอกสะอาด หรือก้อนทึบขนาดเท่าเสา · ที่เหลือมองข้ามหมด (structuralMask) เจ้าของงานพูดไว้เอง: "ให้ยึดเสา กับเส้นผนัง แนวประตู มันก็แค่กว้างคูณยาว" · กับดักย่อยเก้าข้อที่เจอตอนทดลองอยู่ในไม้ต่อ docs/handoff/2026-09-04-ip-235-walls-and-columns-only.md

ห้ามใช้แบบจำลองภาษาในขั้นนี้

เขียนไว้ที่หัว src/lib/region-fill.ts แล้วและยังจริงอยู่ — ห้องเดียวกันต้องได้พื้นที่เท่ากัน ทุกครั้งที่คลิก ซึ่งแบบจำลองรับประกันให้ไม่ได้ และมันขัดกับจุดขายข้อแรกที่แพลตฟอร์มประกาศไว้ว่า ถามซ้ำกี่ครั้งก็ได้คำตอบเดิม (src/lib/method-claims.ts) · ผลพลอยได้ของการไม่ใช้คือ ไม่มีค่าใช้จ่ายต่อคลิกและทำงานได้แม้ไม่มีเน็ต

ที่ใช้แบบจำลองได้คือขั้นที่คนกดรับทีละรายการ เช่น อ่านป้าย F1 C1 มาเสนอว่าห้องนี้ ใช้พื้นชนิดไหน ตาม ADR 0019 และ 0024 — ไม่ใช่ขั้นที่คลิกแล้วออกมาเป็นตัวเลขทันที

หน่วยและการแปลง

  • พิกัดทุกจุดที่เก็บลงฐานเป็น หน่วยหน้ากระดาษ (point) ไม่ใช่พิกเซลบนจอ — ค่าที่วัดได้ จึงไม่ขยับเมื่อผู้ใช้ซูม
  • ภาพที่ใช้ไล่ขอบคือชั้นวิเคราะห์ซึ่งความละเอียดคงที่ต่อหน้า ไม่ผูกกับระดับซูม ถ้าเผลอไปใช้ภาพที่เห็นบนจอ ห้องเดียวกันที่ซูมต่างกันจะได้รูปคนละรูป
  • ค่าคงที่ที่เป็นเมตรอยู่ใน region-fill.ts ส่วนตัวฟังก์ชันรับเป็นพิกเซล ผู้เรียกแปลงด้วย analysisScale / pageScale.metresPerPoint

วิธีตรวจว่าทำถูก

  1. เทสต์ก่อน สร้างภาพจำลองเป็นตัวเลขล้วนใน region-fill.test.ts — ห้องปิด ห้องมีประตู ห้องมีสัญลักษณ์ชิดผนัง ห้องคู่ที่คั่นด้วยผนังบาง · ทุกกรณีต้องมีข้อที่พิสูจน์ว่า ผนังไม่ขยับ ไม่ใช่พิสูจน์แค่ว่าพื้นที่เพิ่มขึ้น
  2. แล้วกดจริงใน Edge บนแบบโรงพยาบาลกุสุมาลย์ C:\Users\moosu\Downloads\drawing.pdf 32 หน้า หน้า 7 เป็นผังพื้นที่ใช้ทดสอบมาตลอด
  3. เทียบกับกริด ห้องที่ล้อมด้วยแนวเสา พื้นที่ผิวในต้องน้อยกว่าพื้นที่กึ่งกลางเสาเล็กน้อย เช่น 7.03 เทียบกับ 7.50 · ถ้าผิวในมากกว่ากึ่งกลางเสา แปลว่ารั่วแน่นอน
  4. ให้เจ้าของงานดูรูป เขาจับรูปที่ผิดได้ทันทีทั้งที่ตัวเลขดูดี ตรวจตัวเลขอย่างเดียวไม่พอ

กับดักของเครื่องมือทดสอบ ไม่ใช่ของแอป

  • MCP คลิกต่ำกว่าเป้า 46 พิกเซล วัดไว้เมื่อ 2026-09-04 สั่งคลิกปุ่มที่ (199,127) ไปลงจริงที่ (199,172) ทำให้สรุปผิดว่าปุ่มทั้งแถบตาย ทั้งที่คีย์ลัดใช้ได้ปกติ → ก่อนสรุปว่าอะไรพัง ให้ดักจับพิกัดจริงด้วย pointerdown listener แล้วเทียบกับ getBoundingClientRect ของเป้า · ชดเชยด้วยการวางกล่องเล็งสูงกว่าเป้า 46 พิกเซล
  • ภาพหน้าจอกับพิกัดหน้าเว็บไม่เท่ากัน วัดได้ sx = 1.395·vx และ sy = 1.396·vy − 65 คาลิเบรตใหม่ทุกครั้งด้วยการวางจุดสีสองจุดที่พิกัดที่รู้ค่า แล้วอ่านจากภาพ
  • dispatch PointerEvent เองบนผืนวาดไม่ได้ state ของ React เพี้ยนหนึ่งจังหวะ ต้องใช้ปุ่มเล็ง #aim-box ที่ position:fixed; pointer-events:none แล้วให้ MCP คลิกที่ uid ของมัน

อย่าส่งออกอะไรจากไฟล์คอมโพเนนต์นอกจากคอมโพเนนต์

drawing-markup.tsx เคยส่งออกค่าที่ไม่ใช่ React ทำให้ Fast Refresh ยอมแพ้แล้วโหลดใหม่ ทั้งหน้าทุกครั้งที่แก้ไฟล์ · ถ้าต้องเปิดค่าให้เทสต์เรียก ให้ย้ายค่านั้นไปโมดูลของมันเอง

เอกสารที่ต้องอ่านคู่กัน

  • docs/plans/2026-09-03-room-area-explained-and-materials.md — คำตัดสินของเจ้าของงาน เรื่องพื้นที่ห้อง รวมข้อที่ว่าเลขที่ใช้ประมาณราคาจริงมาจากกึ่งกลางเสา ไม่ใช่จากการไล่ขอบ
  • docs/adr/0024-a-quantity-records-how-it-was-produced-not-whether-it-is-accurate.md
  • src/lib/method-claims.ts — จุดขายที่เราประกาศไว้ ห้ามทำอะไรที่ทำให้ข้อไหนไม่จริง