Tag: casio

ติดปีกเครื่องคิดเลขเทพ Casio fx 9860G II SD ด้วยโปรแกรมภาษาซีบน AddIn ตอนที่ 9 โปรแกรมคำนวณหาจุดตัด (Intersection)

งานในด้านสำรวจเป็นงานที่ต้องเกี่ยวข้องกับ Geometry บน plane เป็นส่วนใหญ่ ในบางครั้งอาจจะมีโจทย์ที่ต้องคำนวณหา จุดตัดระหว่างเส้นตรงสองเส้น หรือเส้นตรงกับวงกลม หรือวงกลมกับวงกลม โดยที่เส้นตรงอาจจะทราบค่าพิกัดหัวและท้าย หรือทราบค่าพิกัดเพียงหนึ่งจุดและค่าอะซิมัท ส่วนวงกลมนั้นจะต้องทราบค่าพิกัดจุดศูนย์กลางและรัศมี สูตรการคำนวณไม่ได้ยาก สมัยนี้โจทย์พวกนี้เราใช้โปรแกรมด้าน CAD เขียนแบบช่วยเสียเป็นส่วนใหญ่ อย่างที่ผมเคยบอกออกไปครับ ถ้าช่างสำรวจเรามีโอกาสได้ใช้สมองคิดด้าน geometry บ้างและสามารถใช้เครื่องคิดเลขเป็นตัวช่วย ก็จะสามารถพัฒนาทักษะด้านนี้พอสมควร

โปรแกรมคำนวณหาจุดตัด (Intersection)

โปรแกรมเขียนไว้นานแล้ว แต่มีโอกาสมาปรับแก้ใหม่ให้สามารถคำนวณจุดสัมผัส เช่นเส้นตรงกับวงกลมโดยสามารถตั้ง Tolerance ได้ ผมตั้งไว้ที่ 1 มม. ขอขยายความว่าเราสามารถหาจุดตัดเส้นตรงกับวงกลมได้เป๊ะๆ สองจุด แต่ในกรณีที่เป็นจุดสัมผัส (Tangent) นั้นยากโอกาสน้อยมากที่จะคำนวณหาจุดสัมผัสจากโจทย์ที่กำหนดเส้นตรงที่ผ่านจุดและมีทิศทางตามอะซิมัท มาสัมผัสกับวงกลมที่กำหนดจุดศูนย์กลางและรัศมี  ผมจึงตั้ง tolerance ไว้ 1 มม. ถ้าเส้นตรงมาเฉียดจุดสัมผัสนี้ไม่ว่าจะด้านนอกหรือด้านในวงกลมถ้าระยะห่างเส้นตรงห่างจากจุดสัมผัสจริงน้อยกว่า 1 มม. ก็ให้ถือว่าเส้นตรงเส้นนี้สัมผัสกับวงกลม สำหรับไอคอนโปรแกรมเมื่อติดตั้งแล้ว ดังรูปด้านล่าง

ดาวน์โหลดและติตตั้งบนเครื่องคิดเลข

ไปที่หน้าดาวน์โหลด (Download) มองหาโปรแกรมบนเครื่องคิดเลข Casio fx-9860G II SD  ชื่อโปรแกรม Intersection จากนั้นทำการดาวน์โหลดมาจะได้ไฟล์ชื่อ “INSCTEX.G1A” แล้วทำการ copy ไฟล์ตัวนี้ไปยังเครื่องคิดเลขด้วยโปรแกรม Casio FA-124  หรือ copy ผ่านทางตัว SD Card ที่มากับเครื่องคิดเลข

เริ่มต้นใช้งานโปรแกรมหาจุดตัด (Intersection)

กดคีย์ “Main Menu” ของเครื่องคิดเลขใช้คีย์ลูกศรไล่ไปหาไอคอนโปรแกรม Intersection ดังรูป แล้วกดคีย์ “EXE”

เมนูหลักของโปรแกรม

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

F1 – Set สำหรับเลือกการคำนวณว่าจะเป็นเส้นตรงตัดกับเส้นตรง เส้นตรงกับวงกลม หรือวงกลมกับวงกลม

F2 – IN (Input) จะเป็นการป้อนค่าพิกัดหรืออะซิมัท ตามตัวเลือกที่เลือกไว้ในเมนูแรก (F1 – Set)

F3 – Calc คำนวณหาจุดตัด ซึ่งในเมนูย่อยสามารถแสดงรูปเส้นตรง (Plot) วงกลมพร้อมจุดตัดได้

F5 – Info แสดงเครดิตไลบรารี ที่โปรแกรมนำมาใช้งาน

F6-Exit ออกจากโปรแกรม

ตัวอย่างที่ 1 คำนวณหาจุดตัดระหว่างเส้นตรงกับเส้นตรง (Line and Line Intersection)

เป็นการคำนวณหาจุดตัดเมื่อกำหนดเส้นตรงสองเส้นที่มีค่าพิกัดหัวและท้าย ดังรูปด้านล่างเป็นแปลงที่ดิน DEFG ต้องการหาค่าพิกัดจุด “X” ซึ่งเป็นพิกัดศุนย์กลางพื้นที่ที่เกิดจากเส้นตรงจากมุมของแปลงที่ดินลากเป็นเส้นทแยงมุมตัดกัน

เลือกรายการคำนวณ

ที่เมนูหลักของเครื่องคิดเลขกดคีย์ F1-Set จะเห็นตัวเลือกรูปแบบการคำนวณจุดตัด (Intersection Type) เมื่อกดคีย์ “EXE” จะเห็นรายการให้เลือก 4 อย่าง ให้เลือก “Line X Line” ดังรูป กดคีย์ “EXE” จากนั้นกดคีย์ F6-OK เพื่อออก

ป้อนค่าพิกัด

กลับมาที่เมนูหลักของโปรแกรม กดคีย์ F2-IN ป้อนค่าพิกัดของเส้นตรงสองเส้น ตามโจทย์ข้างต้น กดคีย์ F6 – OK เพื่อออก

คำนวณหาจุดตัด

กลับมาที่เมนูหลักของโปรแกรม จากนั้นกดคีย์ F3 – Calc เพื่อคำนวณหาจุดตัด “X” โปรแกรมจะทวนค่าพิกัดของเส้นตรงเส้นที่ป้อนไว้ก่อนจะแสดงค่าพิกัดจุดตัด ถ้าจุดนี้อยู่บนเส้นตรงทั้ง 2 เส้น กดคีย์ F2 – PgDn เพื่อเลื่อนไปหน้าต่อไป

หน้าสุดท้ายจะเห็นค่าพิกัดจุดตัด “X” N = 1652.560, E = 1739.142

แสดงรูปตัด (Plot)

กดคีย์ F5-Plot เพื่อแสดงเส้นตรงสองเส้นและจุดตัด จอภาพเป็น dot pixel หยาบๆก็ได้ขนาดนี้พอให้เกิดจินตนาการว่าเส้นตรง 2 เส้นวางตัวในลักษณะใดและตัดกันที่ตรงไหน กดคีย์ F6-Done เพื่อออก

ตัวอย่างที่ 2 คำนวณหาจุดตัดระหว่างเส้นตรงกับเส้นตรง (Azimuth and Azimuth Intersection)

การกำหนดเส้นตรงโดยกำหนดจุดและอะซิมัทให้ ในกรณีนี้เส้นตรงจะยาวไม่สิ้นสุด ดังนั้นถ้าเส้นตรงที่กำหนดไม่ขนานกัน ก็มั่นใจได้เลยว่าหาจุดตัดได้แน่ (ต่างจากตัวอย่างแรกที่หาจุดตัดบนเส้นตรงทั้งสองเท่านั้น)

กำหนดเส้นตรงที่เป็น Alignment ของงานถนน เส้นที่ 1 เป็น  ผ่านจุด N: 2641990.928 , E = 231848.514  Azimuth: 35°28′ 1.7433″ เส้นที่ 2 ผ่านจุด N: 2641812.446 E: 231753.041 Azimuth: 9°12′ 20.4212″ คำนวณหาจุดตัด PI (Point of Intersection)

เลือกรายการคำนวณ

ที่เมนูหลักของโปรแกรม กดคีย์ F1-Set เลือกรายการคำนวณ “Azi X Azi” กดคีย์ F6-OK เพื่อออก

ป้อนค่าพิกัด

กลับมาที่เมนูหลักโปรแกรม กดคีย์ F2-IN เพื่อป้อนค่าพิกัด ไม่ลืมว่าป้อนอะซิมัทคั่นด้วยเครื่องหมายลบ  เมื่อเสร็จแล้วกดคีย์ F6-OK เพื่อออก

คำนวณหาจุดตัดและแสดงรูป

ที่เมนูหลักของโปรแกรม กดคีย์ F3-Calc เพื่อคำนวณหาจุดตัด โปรแกรมจะทวนค่าพิกัดที่ป้อนเข้าไปก่อน กดคีย์ F2-PgDn เพื่อเลื่อนไปหน้าแสดงผลถัดไป

จะได้ค่าพิกัดจุดตัดที่เป็นจุด PI (Point of Intersection N: 2641870.013, E: 231762.371 กดคีย์ F5-Plot จะเห็นรูปร่างเส้นตรงสองเส้น พร้อมจุดตัด “I1” บนหน้าจอภาพกดคีย์ F6-Done สองครั้งเพื่ออก

ตัวอย่างที่ 3 คำนวณหาจุดตัดระหว่างเส้นตรงกับวงกลม (Azimuth and Circle Intersection)

อย่างที่ผมเกริ่นไปข้างต้นว่าเส้นตรงถ้าตัดผ่าเข้าไปในวงกลมจะได้จุดตัดสองเส้น แต่กรณีพิเศษที่เส้นตรงไปสัมผัสกับวงกลมกรณีนี้จะได้จุดตัดคือจุดสัมผัสมาจุดเดียว มาลองดูตัวอย่างแบบนี้ กำหนดให้เส้นตรงผ่านจุด N: 2642178.562, E: 231597.085 Azimuth: 161°8′ 58.2981″ กำหนดวงกลมมีจุดศูนย์กลาง N: 2641772.451, E: 231999.821  รัศมี 249.921 เมตร

เลือกรายการคำนวณ

ที่เมนูหลักของโปรแกรม กดคีย์ F1-Set เลือกรายการคำนวณ “Azi X Cir” กดคีย์ F6-OK เพื่อออก

ป้อนค่าพิกัดและรัศมีวงกลม

ที่เมนูหลักของโปรแกรม กดคีย์ F2-IN เพื่อป้อนค่าพิกัดของเส้นตรงและป้อนค่าอะซิมัท ป้อนค่าพิกัดศูนย์กลางวงกลมพร้อมทั้งรัศมี เสร็จแล้วกดคีย์ F6-OK เพื่อออก

คำนวณจุดตัดและแสดงรูป

ที่เมนูหลักของโปรแกรมกดคีย์ F3-Calc เพื่อคำนวณจะได้ผลลัพธ์แสดงผลมาดังรูปด้านล่าง

สังเกตว่าตรงจุดตัดโปรแกรมจะแสดงว่าได้จุดสัมผัส Tangent มา 1 จุดคือ N: 2641691.702, E: 231763.305 กดคีย์ F5-Plot เพื่อแสดงรูปเส้นตรงและวงกลม ก็พอกล้อมแกล้มการวาดรูปร่างวงกลม ไม่มีไลบรารีของเครื่องคิดเลขต้องอาศัยวาดจุดลงไปตามเส้นรอบวงแทน  จุดสัมผัสแสดงด้วยตัวอักษร “I1” จุดศูนย์กลางวงกลมแสดงด้วยตัวอักษร “C1”

ตัวอย่างที่ 4 คำนวณหาจุดตัดระหว่างวงกลมกับวงกลม (Circle and Circle Intersection)

มาถึงตัวอย่างสุดท้าย ผมจะขอรวบรัดแสดงเฉพาะรูปหน้าจอ กำหนดโจทย์ วงกลมวงแรกมีค่าพิกัดศูนย์กลาง N: 2641210.885, E: 232480.916 รัศมี 525 เมตร วงกลมวงที่ 2 N: 2641256.635 E: 233130.568 รัศมี 250 เมตร คำนวณหาจุดตัดระหว่างวงกลมสองวงนี้

จัดเก็บข้อมูลและเรียกมาใช้ภายหลัง

เพื่อให้ผู้ใช้งานได้สะดวก การจับเก็บตัวแปรเช่นค่าพิกัดที่เคยป้อนไปแล้ว เมื่อเปิดโปรแกรมมาอีกรอบค่านั้นจะยังอยู่ ผมจึงอาศัยวิธีการจัดเก็บไฟล์ลงบน SDCard ที่เสียบไว้ที่เครื่องคิดเลขของเรา เมื่อออกจากโปรแกรม และจออ่านไฟล์มาอีกทีเมื่อเปิดโปรแกรม

ก่อนจะใช้งานได้ต้องมีการเตรียมโฟลเดอร์บน SDCard ดังต่อไปนี้  คือดึง SDCard จากเครื่องคิดเลขมาเสียบบนคอมพิวเตอร์ แล้วทำการสร้างโฟลเดอร์ชื่อ “svdata” ดังรูป แต่ถ้ามีการสร้างมาแล้วก็ไม่จำเป็นต้องทำอะไร

จากนั้นนำ SDCard มาเสียบบนเครื่องคิดเลขอีกครั้ง เมื่อนำไปใช้งานได้สักพักถ้าเอามาเปิดอีกครั้งจะเห็นไฟล์หลายๆไฟล์ มีนามสกุลเป็น “CFG”  หมายถึง config ตัวอย่างถ้าใช้โปรแกรมคำนวณหาจุดตัดนี้ไฟล์ที่จัดเก็บข้อมุลคือ “INTSCT.CFG

ก็ยังมีหลายซีรี่ย์สำหรับโปรแกรมเครื่องคิดเลขในชุดนี้ ก็ติดตามกันได้ต่อไปครับ

Update: โปรแกรมแปลงค่าพิกัดภูมิศาสตร์ Geographic Calculator (GeoCalc) บนเครื่องคิดเลข Casio fx-9860G II SD

Geographic Calculator

สืบเนื่องจากตอนก่อนหน้านี้ผมได้นำเสนอโปรแกรมแปลงพิกัด Geographic Calculator แบบไม่ได้ใช้ไลบรารีช่วยเรื่อง User Interface โปรแกรมมีลักษณะง่ายๆ เปิดมาเจอเมนูเลือกลักษณะที่จะคำนวณ จากนั้นโปรแกรมจะถามค่าพิกัดที่ต้องการแปลงแล้วคำนวณให้ ข้อดีคือใช้ง่าย ข้อเสียถ้าป้อนข้อมูลผิดพลาด จะย้อนกลับไม่ได้ ต้องเดินหน้าผิดไปจนจบ แล้วค่อยย้อนกลับมาอีกที

เปลี่ยนรูปแบบการติดต่อกับผู้ใช้ด้วยไลบรารี MyLib

ไลบรารี MyLib เป็นไลบรารีภาษาซีเล็กๆที่ผู้พัฒนาใช้นาม hayzel ได้เขียนไว้เพื่อใช้บนเครื่องคิดเลข Casio fx-9860G II SD ผมนำมาใช้และชอบ ทำให้มีแรงใจที่จะเขียนโปรแกรมบนเครื่องคิดเลขรุ่นเทพรุ่นนี้ได้มาหลายโปรแกรม และก็เหมือนเดิมครับว่าโปรแกรมที่ผมเขียนนั้นใช้งานได้ฟรี (Freely Usability) เพื่อใช้ในแวดวงงานสำรวจทำแผนที่ตลอดจนงานสำรวจเพื่อการก่อสร้างก็ตาม

ก็ขอตั้งชื่อโปรแกรมเล็กๆสำหรับแปลงพิกัดบนพื้นหลักฐาน WGS84 นี้ว่า “GeoCalc Extra” ก่อนอื่นสูตรที่ใช้ในการคำนวณผมใช้ไลบรารีชื่อ mgrs สามารถคำนวณแปลงพิกัดในระบบพิกัด UTM, geographic, UPS และ MGRS ได้ ขนาดไม่ใหญ่มากนัก สามารถคอมไพล์และบิวท์มาใส่เครื่องคิดเลขรุ่นนี้ได้ ทั้ง MyLib และ mgrs เป็นโปรแกรมเปิดโค้ด ฟรีทั้งคู่

ดาวน์โหลดโปรแกรม (Download)

ไปที่หน้าดาวน์โหลด (Download) มองหาโปรแกรมบนเครื่องคิดเลข Casio fx-9860G II SD  ชื่อโปรแกรม GeoCalc Extra จากนั้นทำการดาวน์โหลดมาจะได้ไฟล์ชื่อ “GEOCALC.G1A” แล้วทำการ copy ไฟล์ตัวนี้ไปยังเครื่องคิดเลขด้วยโปรแกรม Casio FA-124  หรือ copy ผ่านทางตัว SD Card ที่มากับเครื่องคิดเลข

เริ่มใช้โปรแกรม

ที่ “Main Menu” ของเครื่องคิดเลขเลื่อนไปหาไอคอนของโปรแกรมดังรูปด้านล่าง เมื่อกดคีย์ “EXE” แล้วจะเข้าเมนูของโปรแกรม ดังนี้

F1 – Set เลือกรายการคำนวณแปลงพิกัดระหว่าง UTM, Geographic หรือ MGRS

F2 – Src (Source) ป้อนค่าพิกัดที่ต้องการแปลงพิกัด

F3 – Calc คำนวณแปลงพิกัดพร้อมแสดงผลลัพธ์

F5 – Info แสดงเครดิตไลบรารีที่โปรแกรมใช้งาน

F6 – Exit ออกจากโปรแกรม

เลือกรายการคำนวณ (Menu)

ที่เมนูหลักกดคีย์ F1 – Set เพื่อเข้าไปเลือกรายการคำนวณ จะเห็น ระบบพิกัดเริ่มต้น (Source)   และระบบพิกัดปลายทาง (Target) ส่วนด้านล่าง MGRS Precision จะเป็นความละเอียดของระบบพิกัด MGRS (Military Grid Reference System) เลือกได้ 6 ระดับคือ 0, 2, 4, 6, 8, 10

ตัวอย่างที่ 1 แปลงค่าพิกัดจากค่าพิกัดภูมิศาสตร์ไปยังค่าพิกัดยูทีเอ็ม (Geographic to UTM)

ตั้งค่าระบบพิกัดเริ่มต้นและปลายทาง

ตั้งค่าระบบพิกัดต้นทางและปลายทางดังรูป จากนั้นกดคีย์ F6 – OK เพื่อออก

ป้อนค่าพิกัด

กลับมาที่เมนูหลักของโปรแกรมอีกครั้ง กดคีย์ F2 – Src เพื่อป้อนค่าพิกัดภูมิศาสตร์

ป้อนค่าพิกัดละติจูด Latitude 39°57’9.34803″N โดยการป้อน 39-57-9.34803N ค่าลองจิจูด 75°9’54.75490″W ป้อนค่า 75-9-54.75490W เสร็จแล้วกดคีย์ F6 – OK เพื่อออกไปคำนวณ

คำนวณแปลงพิกัด

กลับมาที่เมนูหลักของโปรแกรม กดคีย์ F3 – Calc เพื่อคำนวณจะได้ผลลัพธ์ดังรูปด้านล่าง โปรแกรม

จะแสดงค่าพิกัดเริ่มต้นให้และค่าพิกัดปลายทางคือยูทีเอ็มให้ พร้อมทั้งบอกโซนของยูทีเอ็มให้ กดคีย์ F6 – Done เพื่อออก

ตัวอย่างที่ 2 แปลงค่าพิกัดจากค่าพิกัดยูทีเอ็มไปยังค่าพิกัด MGRS (UTM to MGRS)

กำหนดค่าพิกัดยูทีเอ็ม (UTM) ดังนี้ N: 2642783.110, E: 232030.949 UTM Zone No: 46N กลับมาที่เมนูหลักของโปรแกรม กดคีย์ F1 – Set เพื่อเปลี่ยนรายการคำนวณ ตั้งค่าตามรูปด้านล่าง 

เสร็จแล้วกดคีย์ F6 – OK เพื่อออก

กลับมาเมนูหลักของโปรแกรมกดีย์ F2 – Src เพื่อออกป้อนค่าพิกัดยูทีเอ็มดังนี้ จากนั้นกดคีย์ F6 – OK เพื่อออก

กลับมาที่เมนูหลักของโปรแกรม กดคีย์ F3 – Calc เพื่อคำนวณ จะได้ผลลัพธ์ดังรูปด้านล่าง

ตัวอย่างที่ 3 แปลงค่าพิกัดจากค่าพิกัด MGRS ไปยังค่าพิกัดภูมิศาสตร์ (MGRS to Geographic)

กำหนดค่าพิกัด MGRS: 46QCK0907425049 ส่วนขั้นตอนจะขอรวบรัดแสดงด้วยรูปภาพ

จัดเก็บข้อมูลและเรียกมาใช้ภายหลัง

เพื่อให้ผู้ใช้งานได้สะดวก การจับเก็บตัวแปรเช่นค่าพิกัดที่เคยป้อนไปแล้ว เมื่อเปิดโปรแกรมมาอีกรอบค่านั้นจะยังอยู่ ผมจึงอาศัยวิธีการจัดเก็บไฟล์ลงบน SDCard ที่เสียบไว้ที่เครื่องคิดเลขของเรา เมื่อออกจากโปรแกรม และจออ่านไฟล์มาอีกทีเมื่อเปิดโปรแกรม

ก่อนจะใช้งานได้ต้องมีการเตรียมโฟลเดอร์บน SDCard ดังต่อไปนี้  คือดึง SDCard จากเครื่องคิดเลขมาเสียบบนคอมพิวเตอร์ แล้วทำการสร้างโฟลเดอร์ชื่อ “svdata” ดังรูป แต่ถ้ามีการสร้างมาแล้วก็ไม่จำเป็นต้องทำอะไร

จากนั้นนำ SDCard มาเสียบบนเครื่องคิดเลขอีกครั้ง เมื่อนำไปใช้งานได้สักพักถ้าเอามาเปิดอีกครั้งจะเห็นไฟล์หลายๆไฟล์ มีนามสกุลเป็น “CFG”  หมายถึง config ตัวอย่างถ้าใช้โปรแกรมคำนวณโค้งแปลงพิกัดภูมิศาสตร์นี้ไฟล์ที่จัดเก็บข้อมุลคือ “GEOCALC.CFG

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

ติดปีกเครื่องคิดเลขเทพ Casio fx 9860G II SD ด้วยโปรแกรมภาษาซีบน AddIn ตอนที่ 7 โปรแกรมคำนวณโค้งราบ (Horizontal Curve)

ติดปีกเครื่องคิดเลขเทพ Casio fx 9860G II SD ด้วยโปรแกรมภาษาซีบน AddIn ตอนที่ 7 โปรแกรมคำนวณโค้งราบ (Horizontal Curve)

โปรแกรมคำนวณโค้งราบ HCurve สำหรับเครื่องคิดเลข Casio fx-9860 G

ช่วงนี้อยู่ในชุดซีรี่ย์โปรแกรมเครื่องคิดเลข Casio fx-9860G ที่ใช้ไลบรารี MyLib ต่อไปขอนำเสนอโปรแกรมคำนวณโค้งราบ (Simple Horizontal Curve) ตัวโปรแกรมพัฒนาด้วยภาษาซี  ใช้เป็นโปรแกรม AddIn ดังรูปด้านล่าง

โปรแกรม HCurve คำนวณโค้งราบ (Simple Horizontal Curve)

องค์ประกอบของโค้งราบ (Elements of Horizontal Curve)

องค์ประกอบของโค้งราบ (Elements of Curve)

คำนิยาม (Abbrivations)

R – Radius คือรัศมีของโค้งราบ รัศมีจะตั้งฉากกับเส้นสัมผัสวงกลมเสมอ

PC –  Point of Curvature คือจุดเริ่มต้นโค้ง บางครั้งเรียกว่า BC (beginning of curve) หรือ TC (tangent to curve)

PI – Point of Intersection คือจุดตัดของ tangent 2 เส้น

PT – Point of Tangency คือจุดสิ้นสุดโค้ง บางครั้งเรียกว่า EC (end of curve) หรือ CT (curve to tangent)

POC – Point of Curve คือจุดบนโค้งในตำแหน่งใดก็ตาม

L – Length of Curve คือความยาวโค้งวัดตามโค้งจากจุด PC ไปจุด PT

T – Tangent Distance หรือ Tangent Length คือเส้นตรงที่สัมผัสโค้งวัดจากจุด PC ไปจุด PI หรือวัดจาก จุด PI ไปจุด PT

คุณสมบัติของโปรแกรม

โค้งราบ (Simple Horizontal Curve) ในงานสำรวจใช้ในงานสำรวจเพื่อการก่อสร้าง (Construction Survey) โดยที่ให้ตำแหน่ง (Setting out) งานก่อสร้างถนน ทางรถไฟ ผู้ใข้ป้อนข้อมูลองค์ประกอบของโค้งราบที่โปรแกรมต้องการจนครบ โปรแกรมสามารถคำนวณองค์ประกอบโค้งที่เหลือและสามารถคำนวณค่าพิกัดบนเส้น Center line หรือกระทั่งสามารถ offset ไปด้านซ้ายหรือด้านขวาก็ได้เช่นเดียวกัน สามารถคำนวณค่าพิกัดแบบทุกช่วงระยะ (interval) ให้ค่าพิกัดออกมาเป็นบัญชีรายการได้ โปรแกรมนี้ออกแบบและพัฒนามาเพื่อช่วยช่างสำรวจให้สามารถนำโปรแกรมไปตรวจสอบข้อมูลโค้งราบได้ด้วยตัวเอง

ในปัจจุบันการวางโค้งในสนาม ไม่ได้ถูกจำกัดเช่นสมัยแต่ก่อนเนื่องจากเครื่องมือเช่นอุปกรณ์กล้องสำรวจ Total Station ทันสมัยสามารถให้ตำแหน่งจากค่าพิกัดได้เลย ไม่เหมือนสมัยแต่ก่อนที่มีแต่กล้อง Theodolite และเทปวัดระยะ ที่การวางโค้งต้องอาศัยการตั้งกล้องที่จุด PC หรือ PI หรือแม้กระทั่ง PT แล้วทำการเปิดมุมและดึงเทปไปตามคอร์ด ปัจจุบันไม่ต้องทำอย่างนั้นแล้ว สามารถตั้งกล้องที่ไหนก็ได้ที่สะดวก

ก็เนื่องจากความทันสมัยของกล้อง Total Station นี้เอง ในอนาคตไม่ไกลการโอนข้อมูลจากกล้องไปที่ออฟฟิศหรือจากออฟฟิศไปที่กล้องจะเป็นเรื่องธรรมดามากผ่านทางออนไลน์ ซึ่งเรื่องนี้ข้อดีก็มีมากมาย แต่ข้อเสียที่เกิดขึ้นคือช่างสำรวจจะมีเวลาใช้สมองคิดเรื่อง geometry น้อยลงเพราะโปรแกรมบนกล้องทำให้หมด ทำให้ขาดการฝึกฝนทักษะในด้านนี้ ซึ่งผมคิดว่าอาจจะทำให้คุณภาพของบุคลากรด้านสำรวจของเราด้อยลงในอนาคต ดังนั้นการใช้เครื่องคิดเลขมาช่วยอาจจะช่วยฝึกฝนทักษะได้บ้างในจุดนี้

ดาวน์โหลดโปรแกรม (Download)

ไปที่หน้าดาวน์โหลด มองหาโปรแกรมคำนวณโค้งราบ HCurve  จะได้ไฟล์ชื่อ “HCURVEEX.G1A” เมื่อดาวน์โหลดมาแล้วโอนเข้าเครื่องคิดเลขผ่านทางโปรแกรม FA-124 หรือ SD Card

ใช้งานฟรี (Freely Usable)

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

เริ่มต้นใช้งาน

ที่เครื่องคิดเลขกดคีย์ “Menu” เพื่อเข้าสู่หน้า AddIn หรือ  Main Menu ของเครื่องคิดเลข เลื่อนลูกศรลงไปด้านล่างๆจะเห็นไอคอนของโปรแกรมดังรูปด้านล่าง กดคีย์ “EXE” เพื่อเข้าสู่โปรแกรม

จะเห็นหน้าเมนูหลักของโปรแกรมดังนี้

ก็เหมือนโปรแกรมคำนวณโค้งดิ่ง (VCurve) ที่ผ่านมาคือมีเมนูย่อยเรียงจากซ้ายไปขวา สัมพันธ์กับการกดคีย์ F1-F6 เรียงกันไป

เมนูหลัก (Main Menu)

F1 (Know) – Known สำหรับป้อนจุดที่ทราบค่า station และค่าพิกัด

F2 (Angl) – Angle สำหรับป้อนที่เกี่ยวกับมุมเช่น back tangent azimuth และมุมเบี่ยงเบน (Deflection Angle) ตลอดจนถึงทิศทางของโค้ง (Curve Direction)

F3 (Elem) – Elements สำหรับป้อนองค์ประกอบของโค้งเช่นรัศมีหรือความยาวโค้าง

F4 (Info) – Information สำหรับคำนวณหาข้อมูลพื้นฐานของโค้งทั้งหมด

F5 (Calc) – Calculate สำหรับคำนวณหาค่าพิกัดโค้งได้หลายรูปแบบเช่นกำหนดสถานี ระยะ offset ตลอดจนคำนวณจากช่วงระยะทาง (interval) ที่กำหนดให้

F6 (Exit) – Exit ออกจากโปรแกรม

ตัวอย่างการคำนวณโค้งราบ (Example)

มาดูวิธีการใช้งานจากตัวอย่างจะเข้าใจง่ายที่สุด

เลือกและป้อนสถานีที่ทราบและค่าพิกัด (Known Station and Know Coordinates)

ที่เมนูหลักกดคีย์ F1 (Know) แก้ไขค่าตามโจทย์ตัวอย่างที่ 1 ดังนี้

ในที่นี้สถานีและค่าพิกัดกำหนดที่จุด PI ทั้งคู่ เมื่อป้อนค่าเสร็จแล้วกดคีย์ F6 (OK) เพื่อออก

เลือกป้อนมุมอะซิมัทและมุมเบี่ยงเบน(Known Tangent and Deflection Angle)

ที่เมนูหลักกดคีย์ F2 (Angl) เพื่อเลือกอะซิมัทของเส้นสัมผัสที่ทราบค่าและมุมเบี่ยงเบน ตลอดจนป้อนทิศทางของโค้งราบว่าเลี้ยวซ้ายหรือเลี้ยวขวา จากตัวอย่างเลือกและป้อนค่าดังนี้

เสร็จแล้วกดคีย์ F6 (OK) เพื่อจัดเก็บค่าและออก

ป้อนองค์ประกอบโค้งราบ (Elements of Curve)

ที่เมนูหลักกดคีย์ F3 (Elem)  เลือกว่าจะป้อนค่ารัศมีโค้ง (Radius) หรือว่าความยาวโค้ง (Length of Curve) ในที่นี้เลือกรัศมีโค้งและป้อนค่า 201.950 เมตร

คำนวณหาข้อมูลพื้นฐานโค้งราบ (Curve Information)

ที่เมนูหลักกดคีย์ F4 (Info)

แสดงองค์ประกอบของโค้งและข้อมูลพื้นฐาน ค่าพิกัดของจุด PC, PI และ PT ตลอดจนจุดศูนย์กลางของโค้ง เนื่องจากจอภาพมีขนาดเล็กดังนั้นใช้การกดคีย์ F1 (PgUp) หรือ F2 (PaDn) เพื่อเลื่อนดูหน้าก่อนหน้านี้หรือหน้าถัดไป กดคีย์ F6 (Done) เพื่อออก

การคำนวณโค้งราบ (Horizontal Curve Calculation)

ที่เมนูหลักกดคีย์ F5 (Calc)จะเห็นเมนูย่อยอีกเมนูคือเมนูสำหรับคำนวณโค้งราบ

จะมีเมนูดังนี้

F1 (Sta) – Station คำนวณหาค่าพิกัดเมื่อกำหนดสถานี

F2 (INT) – Interval คำนวณหาค่าพิกัดสถานีเมื่อกำหนดช่วงระยะทาง (Interval) ให้

F4 (Info) – Information คำนวณข้อมูลพื้นฐานโค้งราบ โดยที่ผลลัพธ์เหมือนกับเมนู Info บนเมนูหลัก

F5 (Plot) – Plot Curve วาดรูปร่างโค้งราบ

F6 (Done) ออกจากเมนูคำนวณโค้งราบ

คำนวณหาค่าพิกัดเมื่อกำหนดสถานี (Calculate Coordinates of Station)

ที่เมนูคำนวณโค้งราบกดคีย์ F1 (Sta) จะมีไดอะล็อกให้ป้อนสถานี ตัวอย่างนี้ต้องการทราบค่าพิกัดของสถานี 17+200 โดยที่ offset ไปด้านซ้าย 8 เมตร ป้อนข้อมูลดังรูป ถ้าไม่ต้องการคำนวณหรือเก็บข้อมูลที่ป้อนก็กดคีย์ F5 (Canc) เพื่อ Cancel ออกไป หรือต้องการเก็บค่าแต่ไม่คำนวณก็กดคีย์ F6 (OK) ออกไป ถ้าต้องการคำนวณก็กดคีย์ F1 (Calc) จะได้ผลลัพธ์ดังรูปถัดไป กดคีย์ “EXE” เพื่อออก

คำนวณหาค่าพิกัดสถานีแบบกำหนดช่วงระยะทาง (Interval Calculation)

ที่เมนูคำนวณโค้งกดคีย์ F2 (INT) ในที่นี้ต้องการคำนวณทุกๆระยะ 25 เมตร โดยคำนวณในแนว Center Line (ไม่มีการ offset ไปซ้ายหรือขวา) กดคีย์ F1 (Calc) เพื่อคำนวณ

จะได้ผลลัพธ์ เริ่มตั้งแต่ PC (17+151.314), Sta 17+175, Sta 17+200, Sta 17+225, Sta 17+250, Sta 7+275, Sta 17+300 และสุดท้ายที่ PT (17+313.794) กด F1 (PgUp) เพื่อเลื่อนไปหน้าก่อนหน้านี้ และกด F2 (PgDn) เพื่อไปดูหน้าถัดไป กด F6 (Done)

 

วาดรูปโค้งราบ (Plot Curve)

จากเมนูคำนวณโค้งราบ กดคีย์ F5 (Plot) จะมีเมนูย่อยลงไปอีกสำหรับย่อ F1 (Z-) ขยาย F2 (Z+) ดึงรูปไปด้านซ้าย F3 (Lt) ดึงรูปไปด้านขวา F4 (Rt) กดคีย์ F5 (>) เพื่อไปเมนูย่อยอีกเมนูด้านขวา เมนูด้านขวาจะมีดึงรูปลง F1 (Dn) หรือดึงรูปขึ้น F2 (Up) กดคีย์ F6 (Exit) เพื่อออกจากเมนู

ก็อย่างว่าเครื่องคิดเลขรุ่นนี้เป็นจุดภาพ (pixel) บนจอภาพ ไม่ใช่จอภาพแบบโทรศัพท์มือถือในปัจจุบันที่มีความละเอียดสูง ข้อเสียคือแสดงภาพความละเอียดสูงไม่ได้ แต่ข้อดีไม่เปลืองแบตเตอรี สังเกตว่าแค่ถ่าน AAA สามก้อนใช้กันจนลืมครับ ดังนั้นก็ดูรูปโค้งพอให้เกิดจินตนาการว่าโค้งวางตัวในลักษณะไหน เวลาไปอยู่หน้างานจะได้วางภาพในใจได้

จัดเก็บข้อมูลและเรียกมาใช้ภายหลัง

เพื่อให้ผู้ใช้งานได้สะดวก การจับเก็บตัวแปรเช่นค่าพิกัดที่เคยป้อนไปแล้ว เมื่อเปิดโปรแกรมมาอีกรอบค่านั้นจะยังอยู่ ผมจึงอาศัยวิธีการจัดเก็บไฟล์ลงบน SDCard ที่เสียบไว้ที่เครื่องคิดเลขของเรา เมื่อออกจากโปรแกรม และจออ่านไฟล์มาอีกทีเมื่อเปิดโปรแกรม

ก่อนจะใช้งานได้ต้องมีการเตรียมโฟลเดอร์บน SDCard ดังต่อไปนี้  คือดึง SDCard จากเครื่องคิดเลขมาเสียบบนคอมพิวเตอร์ แล้วทำการสร้างโฟลเดอร์ชื่อ “svdata” ดังรูป แต่ถ้ามีการสร้างมาแล้วก็ไม่จำเป็นต้องทำอะไร

จากนั้นนำ SDCard มาเสียบบนเครื่องคิดเลขอีกครั้ง เมื่อนำไปใช้งานได้สักพักถ้าเอามาเปิดอีกครั้งจะเห็นไฟล์หลายๆไฟล์ มีนามสกุลเป็น “CFG”  หมายถึง config ตัวอย่างถ้าใช้โปรแกรมคำนวณโค้งราบนี้ไฟล์ที่จัดเก็บข้อมุลคือ “HCVEX.CFG

ติดปีกเครื่องคิดเลขเทพ Casio fx 9860G II SD ด้วยโปรแกรมภาษาซีบน AddIn ตอนที่ 6 โปรแกรมคำนวณโค้งดิ่ง (Vertical Curve)

ติดปีกเครื่องคิดเลขเทพ Casio fx 9860G II SD ด้วยโปรแกรมภาษาซีบน AddIn ตอนที่ 6 โปรแกรมคำนวณโค้งดิ่ง (Vertical Curve)

ประเภทลักษณะของโค้ง (Type of Curve)

โค้งในงานถนน งานรถไฟมีสองแบบคือโค้งราบ (Horizontal Curve) และโค้งดิ่ง (Vertical Curve) โค้งราบเป็นตัวกำหนดรูปรางและทิศทางของถนนในแนวราบ ส่วนโค้งดิ่งเป็นโค้งที่รองรับลักษณะภูมิประเทศขึ้นๆลงๆ การออกแบบโค้งสำหรับงานวิศวกรรมงานถนนนั้นเพื่อให้มีความปลอดภัยต่อยวดยานผู้ขับขี่ตลอดทั้งผู้โดยสาร

ประเภทโค้งดิ่ง (Type of Vertical Curve)

โค้งดิ่งจะแบ่งเป็นเส้นโค้งพาราโบลา (Parabola Vertical Curve) ลักษณะนี้จะเป็นโค้งที่นิยมกันมากที่สุดในโลกนี้แทบจะว่า 99% ก็ได้เพราะเวลารถยนต์หรือรถไฟเข้าโค้งนี้จะมีความนุ่มนวลมากที่สุด และเส้นโค้งประเภทต่อไปคือเส้นโค้งวงกลม (Circular Vertical Curve) ตามที่ได้ยินมาคือโค้งวงกลมนี้จะมีความสบายและความนุ่มนวลน้อยกว่าเส้นโค้งพาราโบลา จึงมีความนิยมน้อยกว่า ผมค้นหาในเว็บโดยใช้เสิร์ชเอนจิ้นปรากฎว่าเจอแค่เว็บเดียวที่เป็นเอกสาร PDF อธิบายสูตร คิดดูแล้วกันครับว่ามันใช้กันน้อยขนาดไหน ถึงแม้จะใช้กันน้อยมากแต่ผมก็มีโอกาสได้ใช้โค้งดิ่งแบบวงกลมนี้ในโครงการรถไฟฟ้าที่บังคลาเทศ แต่แปลกแต่จริงสำหรับรถไฟความเร็วสูงกลับนิยมใช้โค้งดิ่งแบบวงกลมมากกว่าพาราโบลา ซึ่งใช้รัศมีที่ใหญ่มากประมาณ10 กม.ขึ้นไป

ลักษณะของโค้งดิ่งจะมี 2 ลักษณะคือ โค้งหงาย (Sag Curve) และโค้งคว่ำ (Crest Curve)

โค้งทางดิ่ง (vertical Curve) แบบโค้งคว่ำ (Crest Curve) เครดิตภาพ wikibooks.org

ออกแบบโปรแกรมใหม่ (New Design)

ถ้าลองใช้โปรแกรมเครื่องคิดเลข Casio fx-9860G ที่ผมปล่อยฟรีมาก่อนหน้านี้ ระบบการติดต่อผู้ใช้จะเป็นลักษณะจากบนลงล่างคือเปิดโปรแกรมมาแล้ว โปรแกรมจะถามค่าตัวแปร เมื่อผู้ใช้ป่อนค่าลงไปจนครบ ต่อไปจะเป็นการนำค่าตัวแปรเหล่านี้มาคำนวณและแสดงผลให้ทราบ วิธีการดีตรงที่ตรงไปตรงมา ผู้ใช้จะถูกบังคับให้ป้อนค่าตามที่โปรแกรมต้องการจนครบ แต่ข้อเสียเมื่อต้องการคำนวณอีกครั้งในกรณีป้อนค่าผิดต้องการป้อนใหม่ จะต้องเรียกโปรแกรมมาอีกครั้งตั้งแต่ต้น ทำให้เสียเวลามากเกินไป จนในที่สุดก็ต้องหาตัวช่วยมาช่วยและก็ได้พบกับไลบรารี MyLib

ไลบรารี MyLib

ผมมีโอกาสได้เห็นโปรแกรมเครื่องคิดเลข HP 50g จากเว็บไซต์ที่ทางฝั่งผู้พัฒนาจากแคนาดาชื่อ Simple Geospatial Solution โปรแกรมนี้ไม่ฟรีต้องเสียเงินซื้อ ผมลองดูรูปแบบแล้วน่าสนใจ เลยกลายเป็นแรงบันดาลใจ หน้าตาประมาณรูปด้านล่าง

โปรแกรมสำรวจบนเครื่องคิดเลข HP 50g

หันมามองฝั่งเครื่องคิดเลข Casio fx-9860G ผมได้เจอคนเขียนไลบรารีเล็กๆชื่อ MyLib จากผู้ใช้นามว่า  hayzel ปล่อยซอร์สโค้ดภาษาซีออกมาด้วย ไลบรารีนี้สามารถนำมาเขียนเมนูเพื่อติดต่อกับผู้ใช้งาน และสามารถสร้างไดอะล็อกเพิ่อป้อนข้อมูลได้ และมีโค้ดสำหรับช่วยในการวาดรูปอีกนิดหน่อย ผมดูโค้ดแล้ว ถ้าให้ผมเขียนเองคงทำไม่ได้แน่ แต่ถ้าจะแกะเอามาใฃ้ก็เป็นงานถนัดไม่เหลือบ่ากว่าแรง ก็ต้องยกเครดิตและขอขอบคุณผู้เขียนไลบรารีนี้ ไม่มีไลบรารีนี้ก็ไม่มีโปรแกรมนี้

รูปแบบการติดต่อผู้ใช้ (User Interface)

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

ไลบราาี MyLib บนเครื่องคิดเลข Casio fx-9860G

ใช้งานได้ฟรี (Free to use)

ก็ยังเหมือนเดิมคือให้ใช้งานได้ฟรีไม่มีค่าใช้จ่ายและเพื่อช่วยเหลือวงการสำรวจบ้านเราเล็กๆน้อยๆตามกำลังที่ผมมีอยู่ โปรแกรมขนาดนี้ประมาณ 800-1000 บรรทัดดูมากสำหรับเครื่องคิดเลข แต่ถ้าเทียบกับโปรแกรมบนเครื่องคอมพิวเตอร์ถือว่าเล็กจิ๊บๆมาก

คำนิยาม (Abbreviations)

สำหรับโค้งดิ่งจะมีคำนิยามคำย่อ ที่บางตำราอาจจะเรียกแตกต่างกัน

BVC – Begin of Vertical Curve – จุดเริ่มโค้ง(บางทีเรียก PVC – Point of Vertical Curve)
PVI – Point of Vertical Intersection – จุดตัดแนวดิ่ง
EVC – End of Vertical Curve  – จุดสุดโค้ง(บางทีเรียกว่า PVT – Point of Vertical Tangent)
L – Length of Curve – ความยาวโค้ง
R – Radius – รัศมีโค้ง ใช้ในโค้งดิ่งแบบวงกลม(Circular Vertical Curve) เท่านั้น
g1 – Grades of Tangents (%) – ความชันด้านสัมผัสที่ผ่านจุด BVC/PVC
g2 – Grades of Tangents (%) – ความชันด้านสัมผัสที่ผานจุด EVC/PVT

ดาวน์โหลดโปรแกรม (Download)

ไปที่หน้าดาวน์โหลด มองหาโปรแกรม VCurve สำหรับเครื่องคิดเลข Casio fx-9860G แล้วทำการดาวน์โหลดจะได้ไฟล์ VCURVEEx.G1A ทำการติดตั้งลงเครื่องคิดเลขด้วยโปรแกรม FA-124 หรือ copy ผ่าน SD Card ก็ได้

วิธีการใช้งานโปรแกรม (How to Use)

ที่เครื่องคิดเลขกดคีย์ “Menu” จะเห็นโปรแกรม AddIn ขึ้นมาใช้คีย์ลูกศรกดไปจนพบกับไอคอนโปรแกรมดังรูป กดคีย์ “EXE” เพื่อรันโปรแกรม

เมนูหลัก (Main Menu)

จะเห็นเมนูโปรแกรมเรียงรายจากซ้ายมาขวาอยู่ที่ด้านลางของจอภาพ แต่ละเมนูจะสัมพันธ์กับคีย์ F1 ,F2, F3, F4, F5 และ F6 

เมนูหลัก (main menu)

Type – Curve Type – เลือกประเภทโค้งดิ่ง (F1)

Know – Known Station – เลือก Station ที่กำหนดค่าระดับ (F2)

Elem – Elements of Curve – ป้อนค่าส่วนประกอบของโค้ง (F3)

Info – Curve Information – แสดงข้อมูลโค้ง (F4)

Calc – Calculate – คำนวณโค้งเพื่อหาสถานี ค่าระดับ (F5)

Exit – Exit Program – ออกจากโปรแกรม (F6)

ตัวอย่างที่ 1 โค้งดิ่งแบบพาราโบลา (Example 1 – Parabola Curve)

ลักษณะโค้งดิ่ง (Vertical curve diagram)

ลักษณะเป็นโค้งหงาย (Sag Curve) ความยาวโค้ง 200 เมตร ต้องเตือนใจกันลืมนิดหนึ่งความยาวโค้งดิ่งที่ระบุมานั้นเป็นความยาวในแนวราบ  (ไม่ใช่ระยะทางวัดไปตามความยาวโค้ง)

เลือกประเภทโค้งดิ่ง

จากเมนูหลักเลือกกดคีย์ F1 (Type) จะเป็นการเลือกประเภทของโค้ง จะเห็น Dropdown List

เมนูหลัก (main menu)
ประเภทโค้งดิ่ง (Curve type)

กดคีย์ “EXE” เพื่อเลือก จะเห็นมีสองทางเลือกคือลักษณะเป็นโค้งดิ่งแบบวงกลม (Circular) กับโค้งดิ่งแบบพาราโบลา สามารถใช้คีย์ลูกศรเลื่อนขึ้นลงเพื่อเลือกได้ ในที่นี้เราเลือก “Parabola” ด้วยการกดคีย์ “EXE” เมื่อเสร็จแล้วกดคีย์ F6 (OK) เพื่อยืนยัน ถ้าต้องยกเลิกก็กดคีย์ F5(Canc)

เลือกสถานีที่ทราบค่าระดับ (Known Station)

กลับมาเมนูหลักกดคีย์ F2 (Know) จะเห็นจอภาพเครื่องคิดเลขดังรูปด้านล่าง

กำหนดสถานีที่ทราบค่า (Known station)

ตรง “Known” สามารถเลือกได้ว่าต้องการกำหนดค่าระดับที่สถานีไหน จะมีให้เลือก 3 อย่างคือ BVC/PVI/EVC เลื่อนคีย์ลูกศรขึ้นลงแล้วกดคีย์ “EXE” ตามตัวอย่างนี้เลือก “PVI

 

จากนั้นเลื่อนค่าลงไปที่ Station กดคีย์ “EXE” โปรแกรมจะแสดงไดอะล็อกให้ป้อนค่าสถานีลงไปตามตัวอย่างนี้ป้อน Station : 1000 ดังรูปด้านล่าง

และเลื่อนลูกศรไปป้อนค่า Elevation = 50 เมตรเข้าไป เสร็จแล้วกดคีย์ F6 (OK) เพื่อยืนยัน

ป้อนข้อมูลองค์ประกอบของโค้งดิ่ง (Elements of Vertical Curve)

ที่เมนูหลักกดคีย์ F3 (Elem) 

องค์ประกอบของโค้งจะประกอบไปด้วยความยาวโค้ง (L – Length of Curve), ความชันของเส้นสัมผัสด้านเข้าโค้ง (g1 – Entry Grade) และความชันของเส้นสัมผัสด้านออกโค้ง (g2 – Exit Grade) ป้อนข้อมูลตามรูปด้านบนโดยที่ L = 200 m, g1 = -2 % และ g2 = 3%

คำนวณโค้งหาข้อมูลพื้นฐาน (Curve Information)

ที่เมนูหลักกดคีย์ F4 (Info) โปรแกรมจะคำนวณข้อมูลพื้นฐานของโค้งมาให้  และแสดง station/elevation ของจุดต่ำสุดและสูงสุดของโค้งมาให้ด้วย

คำนวณโค้งหาระยะทางและค่าระดับ

ที่เมนูหลักกดคีย์ F5 (Calc) จะเห็นเมนูคำนวณโค้งดิ่ง

Elev? – Elevation? – คำนวณหาค่าระดับเมื่อทราบระยะทางหรือสถานี

Sta? – Station? – คำนวณหาระยะทางหรือสถานีเมื่อทราบค่าระดับ

INT – Interval – คำนวณหาระยะทางหรือสถานีและค่าระดับเมื่อกำหนดช่วงระยะทางให้

Info – Curve Information – คำนวณหาข้อมูลพื้นฐานโค้งดิ่ง

Plot – Plot Curve – วาดรูปโค้งดิ่ง

Done  – ออกจากเมนูคำนวณโค้ง

คำนวณหาค่าระดับ (Calculate Elevation)

ในกรณีทราบระยะทางหรือสถานีต้องการหาค่าระดับเช่นในภาคสนามต้องการ stake out สามารถคำนวณได้ ที่เมนูคำนวณโค้งดิ่ง กดคีย์ F1 (Elev?) ป้อนค่า 920 (0+920) ลงไป การป้อนสถานี้ให้ป้อนเป็นหน่วยเมตรไปก่อน รุ่นหน้าจะสามารถป้อนในลักษณะ 0+920 ได้ เมื่อป้อนเสร็จแล้วกดคีย์ F6 (OK) เพื่อยืนยัน

กดคีย์ F1 (Calc) เพื่อทำการคำนวณ จะได้ค่าระดับ 51.650 เมตร ดังรูปด้านล่าง

คำนวณหาสถานี (Calculate Station)

ในกรณีทราบค่าระดับต้องการคำนวณหาระยะทางหรือสถานี ที่เมนูคำนวณโค้งกดคีย์ F2 (Sta?) 

ป้อนค่า 51.5 เมตร กดคีย์ F1 (Calc) จะได้คำตอบเป็นสถานี 2 สถานีเพราะว่าเป็นโค้งหงายที่ค่าระดับเดียวกันคือ 51.5 เมตรถ้าลากเส้นตรงจะตัดผ่าน 2 สถานีคือสถานี 931.010 (0+931.010) และสถานี 1028.990 (1+028.990)

กำหนดช่วงห่างระยะทางคำนวณหาสถานีและค่าระดับ (Interval Calculation)

เมื่อกำหนดช่วงห่างระยะทาง (Interval) ต้องการหาระยะทาง(สถานี)และค่าระดับ ที่เมนูคำนวณโค้งดิ่งกดคีย์ F3 (INT) ตัวอย่างต้องการทราบระยะทางและค่าระดับทุกๆ 10 เมตร ป้อน 10.0 ดังรูป

กดคีย์ F1 (Calc) เพื่อทำการคำนวณจะได้ผลลัพธ์ออกมา ผลลัพธ์อาจจะมีหลายหน้าถ้าช่วงห่างระยะทางมีค่าน้อยๆ

กดคีย์ F2 (PgDn – Page Down) เพื่อดูหน้าถัดไป

ต้องการดูหน้าก่อนหน้านี้ก็กดคีย์ F1 (PgUp – Page Up) หรือกด F6 (Done) เพื่อออก

แสดงรูปรางของโค้งดิ่ง (Plot Curve)

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

ที่เมนูโค้งดิ่งกดคีย์ F5 (Plot) จะเห็นรูปร่างของโค้งดิ่งแสดงให้เห็นพอหอมปากหอมคอ (หมายเหตุ สเกลแนวราบแนวดิ่งอาจจะไม่เท่ากัน)


กดคีย์ F6 (Done) เพื่อออก

ตัวอย่างที่ 2 โค้งดิ่งแบบวงกลม (Example 2 – Circular Vertical Curve)

ก็จะขอไปแบบรวบรัดรูปเยอะๆ ภาพเครื่องคิดเลขอาจจะดูแปลกตานิดเพราะผมจับภาพจากเครื่องมือเขียนโปรแกรมบนเครื่องคอมพิวเตอร์

เลือกลักษณะของโค้งดิ่ง

เมนูหลัก กดคีย์ F1 (Type)
เลือกลักษณะโค้งดิ่ง กดคีย์ “EXE”
เลือกโค้งดิ่งแบบวงกลม (Circular)

กด F6 (OK) ออกไปหน้าเมนูหลัก

เลือกสถานีที่ทราบค่าระดับ (Known Station)

เมนูหลัก กดคีย์ F2 (Know)
ป้อนค่าสถานีและค่าระดับที่ทราบค่า

กดคีย์ F6 (OK) เพื่อออกกลับมาเมนูหลัก

ป้อนข้อมูลองค์ประกอบของโค้งดิ่ง (Elements of Vertical Curve)

เมนูหลัก กดคีย์ F3 (Elem)
ที่ Known: เลือก “Radius” ป้อนค่ารัศมีโค้งและค่าความชัน

กดคีย์ F6 (OK) เพื่อออกเข้าเมนูหลัก

คำนวณโค้งหาข้อมูลพื้นฐาน (Curve Information)

เมนูหลัก กดคีย์ F4 (Info)
องค์ประกอบของโค้งดิ่ง

กดคีย์ F6 (Done) เพื่อออกเข้าเมนูหลัก

เมนูหลัก กดคีย์ F5 (Calc)

กำหนดช่วงห่างระยะทางคำนวณหาสถานีและค่าระดับ (Interval Calculation)

เข้ามาเมนูคำนวณโค้งดิ่ง

กำหนดช่วงห่างระยะทางคำนวณหาสถานีและค่าระดับ (Interval Calculation)

ป้อนค่า  interval 5.0 เมตร เพื่อต้องการหาค่าสถานีและค่าระดับทุกๆ 5 เมตร

ป้อนค่า Interval กดคีย์ F1 (Calc)

กดคีย์ F1 (PgUp) เพื่อเลื่อนขึ้นไปหนึ่งหน้าหรือกดคีย์ F2 (PgDn) เพื่อเลื่อนไปหน้าถัดไป หรือกดคีย์ F6 (Done)  ออกมาเมนูคำนวณโค้งดิ่ง

 

แสดงรูปรางของโค้งดิ่ง (Plot Curve)

เมนูคำนวณโค้งดิ่ง

กดคีย์ F5 (Plot) เพื่อแสดงรูปร่างของโค้งดิ่ง

รูปร่างโค้งดิ่งแบบวงกลม

อยากจะเรียนให้ทราบว่าโปรแกรมที่ปล่อยให้ดาวน์โหลดมาก่อนหน้านี้ ผมจะรื้อมาเขียนใหม่ โดยใช้ไลบรารี MyLib ตัวนี้ เพราะว่าทำให้โปรแกรมใช้งานได้ง่ายขึ้นในแง่ที่สามารถแก้ไขค่าตัวแปรของโค้งและสามารถคำนวณใหม่ได้ตามที่ต้องการ ติดตามกันต่อไปครับ ตอนหน้าจะเป็นโปรแกรม Horizontal Curve ครับ

จัดเก็บข้อมูลและเรียกมาใช้ภายหลัง

ก่อนหน้านี้ผมพยายามจะใช้ตัวแปร A-Z เพื่อจัดเก็บค่าพิกัดหรือข้อมูลที่เราป้อนตอนใช้งาน เมื่อเปิดมาใช้งานใหม่สามารถเรียกกลับมาใช้ต่อได้ แต่ก็ยุ่งยากเพราะสามารถจัดเก็บได้น้อย จากตัวแปรบนเครื่องคิดเลข A-Z ได้แค่ 24 ตัวเท่านั้น ผมจึงอาศัยวิธีการจัดเก็บไฟล์ลงบน SDCard ที่เสียบไว้ที่เครื่องคิดเลขของเรา เมื่อออกจากโปรแกรม และอ่านอีกทีเมื่อเปิดโปรแกรม

ก่อนจะใช้งานได้ต้องมีการเตรียมโฟลเดอร์บน SDCard ดังต่อไปนี้  คือดึง SDCard จากเครื่องคิดเลขมาเสียบบนคอมพิวเตอร์ แล้วทำการสร้างโฟลเดอร์ชื่อ “svdata” ดังรูป

จากนั้นนำ SDCard มาเสียบบนเครื่องคิดเลขอีกครั้ง เมื่อนำไปใช้งานได้สักพักถ้าเอามาเปิดอีกครั้งจะเห็นไฟล์หลายๆไฟล์ มีนามสกุลเป็น “CFG”  หมายถึง config ตัวอย่างถ้าใช้โปรแกรมคำนวณโค้งดิ่งนี้ไฟล์ที่จัดเก็บข้อมุลคือ “VCVEX.CFG

ติดปีกเครื่องคิดเลขเทพ Casio fx 9860G II SD ด้วยโปรแกรมภาษาซีบน AddIn ตอนที่ 5 โปรแกรมคำนวณ Resection ด้วยอัลกอริทึ่มสมัยใหม่

ติดปีกเครื่องคิดเลขเทพ Casio fx 9860G II SD ด้วยโปรแกรมภาษาซีบน AddIn ตอนที่ 5 โปรแกรมคำนวณ Resection ด้วยอัลกอริทึ่มสมัยใหม่

การเล็งสกัดย้อน (Resection) และความเป็นมา

ในที่สุดก็มาถึงตอนที่ 5 ตอนที่ผมใช้เวลามากที่สุดในการ implement อัลกอริทึ่มที่ใช้คำนวณปัญหา Resection จาก 3 จุดที่กำหนด (Three Points Resection Problem) เป็นที่ทราบกันดีว่าการคำนวณ Resection นั้นนักคณิตศาสตร์ได้คิดค้นกันมาหลายร้อยปีแล้ว มีอัลกอริทึ่มรวมๆกันไม่น้อยกว่า 500 อัลกอริทึ่ม แต่บางอัลกอริทึ่มนั้นอายุเก่าแก่มากใช้การคำนวณหาด้วยการวาดลงบนกระดาษ ถ้าจะคัดออกมาจริงๆที่ใช้กันในปัจจุบันมีประมาณ 18 อัลกอริทึ่มหลักๆ และสามารถนำมา implement เป็นโปรแกรมในคอมพิวเตอร์ได้ ก่อนจะไปต่อกันลึกๆมาดูกันว่า Resection คืออะไร

การเล็งสกัดย้อน(Resection) คือการวัดพิกัดจุดตั้งกล้องจากสถานีที่ทราบค่าพิกัด 3 สถานี ตามตัวอย่างได้แก A, B และ C และวัดมุมราบคือมุม α และ β ตามลำดับ

ผมคนรุ่นเก่ายังทันเครื่องมือวัดมุม Sextant ผมทัน Sextant นี้ในช่วงทำงานใหม่ๆ โดยที่ลงเรือไปในทะเลกับพี่ๆช่างสำรวจของกรมเจ้าท่า ตอนนั้นเพิ่งเรียนจบมาใหม่ ยุคนั้น GPS/GNSS ยังไม่เป็นที่รู้จัก การวัดตำแหน่งของเรือสำรวจใช้เครื่องมือ Sextant ที่อาศัยหลักการของ Resection มาประยุกต์ใช้ บนเรือสำรวจจะมีเจ้าหน้าที่ 2 คน คนแรกจะส่องสถานี A และ B เพื่อวัดมุม α และคนที่สองจะส่องสถานี B และ C เพื่อวัดมุม β สองคนนี้ตามหลักการแล้วต้องขี่คอกันแต่จริงๆคงไม่มีใครทำเพียงแต่นั่งใกล้ๆกัน การใช้ Sextant วัดตำแหน่งเรือต้องอาศัยความชำนาญอย่างสูง เพราะเรือไม่อยู่นิ่งกับที่เพราะคลื่มลม จะปะทะให้เคลื่อนไหวตลอดเวลา

เมื่อการวัดมุมเสร็จสิ้นลงทั้งสองคนจะจดค่ามุม ∝ และ ∅ พร้อมๆกัน การใช้ Sextant ควบคู่ไปกับกับใช้เครื่องมือวัดความลึกของท้องน้ำจำพวก Echo sounder งาน post processing ในออฟฟิศได้แต่การนำค่ามุม α และ β มาคำนวณหาค่าพิกัดแตละจุด จากนั้นก็จัดทำแผนที่แสดงความลึกของแม่น้ำหรือทะเลในบริเวณที่ทำการสำรวจ ถึงแม้กระนั้นเครื่องมือ Sextant จะให้ค่าความละเอียดด้านมุมไม่ดีนัก แต่ค่าพิกัดที่ได้สมัยนั้นก็เพียงพอสำหรับงานในทะเลหรือแม่น้ำ

หัวข้อต่อๆไปจะกล่าวถึงที่ไปที่มาของสูตรที่ผมใช้สำหรับเครื่องคิดเลข fx-9860G ถ้าผู้อ่านไม่สนใจก็ข้ามไปที่การใช้โปรแกรมเครื่องคิดเลขด้านท้ายๆเลยครับ

หลักการคำนวณ Resection

อัลกอริทึ่มที่ผมกล่าวไปนั้นตั้งแต่ยุคอดีตกาลนั้นมากกว่า 500 อัลกอริทึ่ม แต่ส่วนใหญ่แล้วอาศัยหลักการคล้ายๆกันคือใช้หลักวงกลมสามวงตัดกันที่จุด P วงแรกจะลากผ่านจุด A-P-B วงที่สองลากผ่านจุด B-C-P วงที่สามลากผ่าน C-P-A ดังรูปด้านล่าง

ภาวะเอกฐาน (Singularity) ที่อัลกอริทึ่มล้มเหลว

ผมขอยืมคำแปล Singularity ที่แปลว่าภาวะเอกฐานจากเรื่องหลุมดำในทฤษฎีฟิสิกส์ควอนตัมหน่อย เพราะมันได้ใจความคือภาวะที่ทฤษฎีทางคณิตศาสตร์ล้มเหลว คือเหมือนกับพลัดตกลงไปในหลุมดำประมาณนั้น

การคำนวณ Resection ที่ใช้วงกลมสามวงมาตัดกันดังรูปด้านบน แต่จะเกิดอะไรขึ้น ถ้าจุดทั้ง 4 จุดนี้อยู่บนวงกลมวงเดียวกัน ก็หมายความว่าวงกลมสามวงนั้นจะซ้อนทับกันทั้งสามวง จนไม่สามารถหาจุดตัดกันได้ ดังนั้น Resection ไม่มีสูตรหรืออัลกอริทึ่มไหนในบรรณพิภพนี้ที่สามารถคำนวณได้บนภาวะเอกฐาน

ภาวะเอกฐานเสมือน (Pseudo Singularity)

ภาวะเอกฐานเสมือนเป็นสภาวะที่จุด P มาอยู่บนเส้นตรงระหว่าง A-B หรือ B-C หรือ A-C ด้านล่างจะเป็นกรณีจุด P อยู่บนเส้นตรงระหว่างจุด B และ C จะทำให้มุม β มีค่ากับ π เรเดียน (หรือเท่ากับ 180 องศา) หรือถ้าขยับจุด P ให้เลยออกจากจุด B แตยังอยู่ในแนวเส้นตรง ในกรณีนี้จะได้ มุม β = 0

ภาวะเอกฐานเสมือนนี้สูตรหลายๆสูตรไม่สามารถหาค่าได้เช่นสูตร Tienstra Method

อัลกอริทึ่มสมัยใหม่ (Modern Algorithm)

เท่าที่ผมทราบในปัจจุบันตัวที่ทำให้เกิดสูตรคณิตศาสตร์ใหม่ๆมาจากวงการ Robot ที่ต้องการให้ค่าพิกัดของหุ่นยนต์ในการเคลื่อนไหวได้แม่นยำ เนื่องจากหุ่นยนต์ทำงานอยู่ในอาคาร จึงทำให้ระบบให้ค่าพิกัด GNSS ไม่สามารถนำมาใช้งานได้ หุ่นยนต์ในที่นี้ไม่ได้หมายถึงหุ่นยนต์ที่ติดตั้งแบบอยู่กับที่ในโรงงานนะครับ แต่เป็นหุ่นยนต์ที่สามารถเคลื่อนไหวได้อิสระ ตัวอย่างง่ายๆได้แก่การแข่งขันหุ่นยนต์ของนักศึกษาในอินดอร์ อดึตกาลสูตรเหล้านี้มาจากนักคณิตศาสคร์ แต่สำหรับสูตรสมัยใหม่เนื่องจากความต้องการใช้งานในวงการหุ่นยนต์ ทำให้คนที่คิดค้นสูตรสมัยใหม่กลายเป็นวิศวกรไฟฟ้าหรือวิศวกรเครื่องกล เท่าที่ผมศึกษางานวิจัยในเบื้องต้นผมสนใจงานของ

    1. A New Three Object Triangulation Algorithm for Mobile Robot Positioning โดย Vincent Pierlot and Marc Van Droogenbroeck ทั้งสองท่านจบวิศวกรไฟฟ้า งานวิจัยนี้มีโค้ดภาษา C ด้วย แต่เนื่องจากลิขสิทธิ์ที่ระบุให้ใช้ในวงการศึกษาหรือใช้งานส่วนตัวเท่านั้น ผมจึงไม่สามารถนำโค้ดมาใช้งานได้เพราะยังกำกวม ความจริงงานทั้ง 2 ท่านได้รวบรวมอัลกอริทึ่มรวมทั้งของตัวเองด้วยทั้งหมด 18 อัลกอริทึ่มและ implement มาเป็นโค้ด พร้อมทั้งวัด benchmark ว่าใค้ดใครเร็วที่สุด ก็ตามคาดหมายโค้ดที่ทั้งสองท่านคิดค้นมานั้นเข้าวิน แต่สำหรับผมแล้วความต่างมันหนึ่งในพันส่วนของวินาทีอาจจะจำเป็นสำหรับงานให้ตำแหน่งหุ่นยนต์ที่ต้องมีการคำนวณตำแหน่งแบบ real time แต่สำหรับงานสำรวจในภาคสนามความจำเป็นกลับต่างออกไป
    2. New Method That Solves the Three-Point Resection Problem Using Straight Lines Intersection โดย Josep M. Font-Llagunes and Joaquim A. Batlle ผมชอบความคิดของสองท่านนี้ดูจากโพรไฟล์แล้วจบวิศวกรเครื่องกล แต่เนื่องจากเอกสารเข้าใจยากไปนิด ผมกลับใช้เวลาแกะอัลกอริทึมโดยใช้เวลาพอสมควรกว่าจะออกมาเป็นโค้ดได้ โปรแกรมสามารถคำนวณในสภาวะเอกฐานเสมือนได้

หลักการคำนวณโดยย่อ

ผมไม่มีเวลาที่จะศึกษาสูตรในเบื้องลึกให้กระจ่างมากนั้นแต่เน้น implement มาเป็นโค้ดภาษา C ดังนั้นความเข้าใจจึงอยู่ในระดับผิวเผิน ต่อไปผมจะบอกเล่าสิ่งที่ผมเข้าใจแบบจำกัดจำเขี่ย เราจะมาเริ่มต้น สมมติว่าตอนนี้ถ้าทราบค่าพิกัด P แล้วเราสามารถหาค่าอะซิมัทจากสถานี A, B และ C ไปยังจุด P ได้ง่ายๆ ตามรูปด้านล่าง

ค่าอะซิมัทของสถานีที่ทราบค่าพิกัด

1.คำนวณหาค่าอะซิมัทโดยประมาณ (Θ)

แต่ในชีวิตจริงค่าพิกัด P เป็นสิ่งที่เรายังไม่ทราบดังนั้นสูตรคำนวณนี้จะมีการหาค่าโดยประมาณก่อน Θ = θ – โดย  คือค่าเบี่ยงเบนไปจากค่าจริงจากที่เราประมาณ ถ้าทุกๆเส้นเบี่ยงเบนไป  เราสามารถลากเส้นไปตัดกันเป็นรู)สามเหลี่ยมเล็กๆ แต่ถ้า  ที่ประมาณการณ์ไว้มีขนาดเบี่ยงเบนไปมาก ก็จะได้ขนาดสามเหลี่ยมนี้ใหญ่ขึ้น สามเหลี่ยมนี้ทางผู้คิดค้นเรียกว่า error triangle จุดตัดแทนที่ด้วย PAB, PBC และ PAC

2.คำนวณหาค่าพิกัดของ Error Triangle

ค่าพิกัดของจุดตัด P นี้สามารถคำนวณได้จากสูตร

โดยที่ mA = cot(Θ), mB = cot(Θ – α) และ mC = cot(Θ – α -β) ไม่ลืมว่า Θ คือค่าอะซิมัทโดยประมาณ

3.คำนวณหาค่าพิกัดของ Centers Triangle

ถ้าจากจุด P ลากเส้นตรงไปหาสถานีที่ทราบค่าพิกัดแล้วแบ่งครึ่งลากเส้นตั้งจาก เราจะได้สามเหลี่ยมอีกชุดหนึ่งเรียกว่า centers triangle  และเป็นสามเหลี่ยมคล้ายสามเหลี่ยม error triangle ดังนั้นความสัมพันธ์ด้านมุมและระยะระหว่างสามเหลี่ยมสองรูปนี้สามารถคำนวณได้ ดังนั้นค่าพิกัดของ centers triangle สามารถคำนวณหาค่าพิกัดจุดตัด CAB, CBC และ CAC ได้จากสูตรดังต่อไปนี้

4.คำนวณมุมเบี่ยงเบน

ค่าเบี่ยงเบนเมื่อคำนวณมาได้แล้วสามารถนำไปบวกหรือลบกับค่าอะซิมัทประมาณการในครั้งแรกจะได้ค่าอะซิมัทที่ถูกต้อง

สามารถคำนวณสมการ (9) จากระยะทางแต่ละด้านของ error triangle และ centers triangle เช่นตัวอย่าง |δθ| = arcsin(ระยะทางระหว่างจุด PAB– PBC / ระยะทางจุด CAB– CBC )

หรือในสมการ (10) สามารถใช้พื้นที่ของสามเหลี่ยมสองรูปนี้ได้

5.คำนวณหาเครื่องหมายมุมเบี่ยงเบน

ก่อนหน้านี้ที่แสดงค่าที่คำนวณได้ในสมการ (9) และ (10) จะเห็นว่าติดเครื่องหมาย absolute ไว้คือยังไม่ได้คิดเครื่องหมาย ส่วนเครื่องหมายมุมเบี่ยงเบนหาได้ดังนี้

ทางผู้พัฒนาแสดงทิศทางของ error triangle เมื่อเทียบ center triangle ตามเครื่องหมายของ error triangle ดังนี้

อาจจะดูยากไปนิดเป็นการคูณไขว้กัน ดูตัวอย่างเพื่อความง่าย

sign = (xPAC-xPBC)*(yCAC-yCBC) – (xCAC-xCBC)*(yPAC-yPBC)

ค่าของ  sign จะออกมาเป็นบวกหรือเป็นลบ แล้วจะเอาเครื่องหมายนี้ไปใส่ให้สมการในข้อต่อไป

6.คำนวณหาอะซิมัทที่ถูกต้อง

สมการ θ=Θ +sign(dθ)

7.คำนวณหาพิกัดของจุดตัด Resection

ถ้าจุดตัดไม่ตกหลุมดำ ก็สามารถคำนวณหาจุดตัดได้จาก 1 ใน 3 สมการ ของสมการ (1), (2) หรือ (3) เช่นตัวอย่าง

mA = cot(θ)
mB = cot(θ – α)
xP = (mA x xA – mB x xB – yA + yB) / (mA – mB)
yP = mA x (xP – xA) + yA

การคำนวณเมื่อจุดตัดตกภาวะเอกฐานเสมือน

จะมี 3 กรณีคือ

1) ค่า α = 180 หรือ α = 0

2)ค่า β = 180 หรือ β = 0

3)ค่ามุม α+β = 180 หรือ α+β = 0

จากการคำนวณในข้อ 3 จะสังเกตในสูตร (5) จะมีตัวคูณด้วย cot(α) อยู่ ในกรณีนี้จุดตัด P อยู่บนเส้นตรงระหว่างจุด A และ B ดังนั้นมุม α = 180 องศาจะทำให้ cot(α) ไม่สามารถคำนวณได้เพราะค่าเป็นอนันต์ (infinity)  ในเคสนี้เราจะไม่คำนวณหาจุด CAB เพราะหาไม่ได้นั่นเอง แต่จุด CBC และ CAC ก็ยังหาได้ปกติ ดังนั้นในกระบวนการสุดท้ายค่าพิกัดของจุด P สามารถคำนวณได้จากการใช้สมการอีก 2 สมการคือสมการ (2) และ (3)

ไม่ใช้สมการ (1) เพราะมีค่า (mA – mB)  = 0 ทำให้ห่าค่า xP ไม่ได้

ข้อสังเกต สามารถลากวงกลมได้แค่ 2 วงเท่านั้นคือวงกลม A-P-C และ B-P-C ส่วนอีกวงลากไ่ม่ได้เพราะว่า A-P-B เป็นเส้นตรง

ดาวน์โหลด (Download) โปรแกรมสำหรับเครื่องคิดเลข fx-9860G

ไปที่หน้าดาวน์โหลดมองหาโปรแกรม Resection เมื่อดาวน์โหลดมาแล้วจะได้ไฟล์ “RESCTION.G1A” ใช้โปรแกรม FA-124 ทำการโอนโปรแกรมเข้าเครื่องคิดเลข (ดูโพสต์เก่าได้วิธีการนี้) จะเห็นไอคอนปรากฎที่หน้า AddIn ดังรูป

กรณีที่ 1 ตัวอย่างงานรังวัดในงานสำรวจทั่วไป (Survey Engineering Example)

กำหนดค่าพิกัดของสถานี A, B และ C ดังนี้

วัดค่ามุม ∝ และ ∅ จากกล้อง total station ได้ดังนี้ ∝= 40°35’22.11“ และค่ามุม ∅ = 9°18’31.84“ ที่ไอคอนโปรแกรมกดคีย์ “EXE” เข้าไปป้อนค่าพิกัดสถานีทั้งสามดังนี้

จากนั้นป้อนมุมภายใน

โปรแกรมจะคำนวณหาค่าพิกัดของจุดตัด โดยที่แจ้งสถานะมาก่อนว่าคำนวณได้ Resection Solved…

กรณีที่ 2 ตัวอย่างงานที่จุดตัดตกอยู่ในภาวะเอกฐานเสมือน (Pseudo Singularity)

นี่เป็นกรณีพิเศษจริงๆ เพราะว่าหลายๆสูตรคำนวณด้วยวิธีนี้ไม่ได้เช่นสูตร Tienstra กำหนดค่าพิกัดสถานี  A (2639303.349mN, 231605.043mE) ค่าพิกัดสถานี B (2639271.845mN, 231419.755mE) และสถานี C (2639180.389mN, 231561.178mE) มุมที่รังวัดมา α = 180° มุม β = 105°3’14.94“

ข้อสังเกตุถ้ามุม α เท่ากับ 180 แสดงว่าจุดตัดตกอยู่บนเส้นตรงระหว่างสถานี A และ B แต่เขยิบเข้าไปใกล้ B มากกว่าเพราะว่ามุม β เป็นมุมป้าน มาดูการคำนวณจากเครื่องคิดเลข เมื่อเรียกโปรแกรมมาแล้วป้อนค่าพิกัดสถานีตามลำดับ A, B และ C แล้ว

จากนั้นป้อนมุม α และ β

ผลลัพธ์ที่ได้

กรณีที่ 3 ตัวอย่างจุดตัดตกหลุมดำในภาวะเอกฐาน (Singularity)

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

กำหนดค่าพิกัดสถานี A (2369180.389mN, 231561.178mE) สถานีพิกัดสถานี B (2639303.349mN, 231605.093mE) และสถานี C (2639478.455mN, 231509.233mE) วัดมุม α = 29°32’23.9“และ β = 18°48’43.9“

เมื่อเข้าไปในโปรแกรมป้อนค่าพิกัด A, B และ C ตามลำดับ

จากนั้นป้อนมุม α และ β ตามลำดับ

สุดท้ายโปรแกรมไม่สามารถคำนวณหาพิกัดจุดตัดได้และแสดงว่า Resection unsolved…

เครดิต (Credit)

ก็ยกเครดิตสำหรับอัลกอริทึ่มหรือสูตรคำนวณนี้ให้กับสองท่านคือ Josep M. Font-Llagunes and Joaquim A. Batlle.

ซอร์สโค้ดสูตรคำนวณ (Sourcecode)

ผมยกมาเฉพาะสูตรคำนวณตั้งชื่อฟังก์ชั่น straightLineIntersection สำหรับคนที่สนใจเรื่องโปรแกรมมิ่งก็ศึกษาโค้ดภาษาซีกันได้ครับ ไม่มีอะไรยุ่งยาก

/* Algorithm based on Josep M. Font-Llagunes and Joaquim A. Batlle.
  - Input angles are radians. 
  - Internal angles is clock-wise direction.
  - A, B and C must be located from right to left respectively.*/
bool straightLineIntersection(double *xP, double *yP,
				double alpha_AB, double alpha_BC,
				double xA, double yA, double xB, double yB, double xC, double yC)
{
  double mA, mB, mC; //slope of lines.
  double cot_12, cot_23, cot_31;
  double pAB, pAC, pBC; //Euclidean distance between station.
  double estB; //Estimated angle A-B-C.
  double xPAB, yPAB, xPBC, yPBC, xPAC, yPAC; //error triangle.
  double xCAB, yCAB, xCBC, yCBC, xCAC, yCAC; //center of triangle.
  double deltatheta;
  double theta; //first estimated and actual azimuth from P to A at the end.
  double AP, AC;
  double sign;
  double dPAC_PBC, dCAC_CBC;
  double dPAB_PBC, dCAB_CBC;
  double dPAB_PAC, dCAB_CAC;

  pAB = sqrt((xA-xB)*(xA-xB) + (yA-yB)*(yA-yB));
  pAC = sqrt((xA-xC)*(xA-xC) + (yA-yC)*(yA-yC));
  pBC = sqrt((xB-xC)*(xB-xC) + (yB-yC)*(yB-yC));

  estB = acos((pAB*pAB + pBC*pBC - pAC*pAC) / (2*pAB*pBC));
  //Check if found absolutely singularity then stop and return.
  if (((estB + alpha_AB + alpha_BC - PI) >= -0.0001) and 
      ((estB + alpha_AB + alpha_BC - PI) <= 0.0001))
    return false;

  /*first guess (theta), try to avoid for cot(angle) 
    when angle == PI or zero).*/ 
  theta = alpha_AB + alpha_BC/2.0;    
  mA = cot(theta);
  mB = cot(theta - alpha_AB);
  mC = cot(theta - alpha_AB - alpha_BC);
	
  //calc coordinates of error triangle.
  xPAB = (mA*xA - mB*xB - yA + yB) / (mA - mB);
  yPAB = mA*(xPAB - xA) + yA;  
  xPBC = (mB*xB - mC*xC - yB + yC) / (mB - mC);
  yPBC = mB*(xPBC - xB) + yB;
  xPAC = (mA*xA - mC*xC - yA + yC) / (mA - mC);
  yPAC = mA*(xPAC - xA) + yA;
	
  dPAC_PBC = sqrt((xPAC-xPBC)*(xPAC-xPBC) + (yPAC-yPBC)*(yPAC-yPBC));
  dPAB_PBC = sqrt((xPAB-xPBC)*(xPAB-xPBC) + (yPAB-yPBC)*(yPAB-yPBC));
  dPAB_PAC = sqrt((xPAB-xPAC)*(xPAB-xPAC) + (yPAB-yPAC)*(yPAB-yPAC));
  
  AP = ((xPAB - xPBC) * (yPBC - yPAC) - (xPBC - xPAC) * (yPAB - yPBC))/* / 2*/ ;
  AP = (AP < 0.0) ? -AP : AP;

  /* The next 3 Cases are psudosingularities.
    
    1st case: P is aligned with A & B.Therefore cannot calc PAB & CAB.*/
  if (alpha_AB == PI || alpha_AB == 0.0){ /* P is aligned on A & B.*/
    /* cot(alpha_AB) is infinity */
    cot_23 = cot(alpha_BC);
    cot_31 = cot(alpha_AB+alpha_BC);
   
    //calc coordinates of center triangle.
    xCBC = 0.5 * (xB + xC + (yB - yC) * cot_23);
    yCBC = 0.5 * (yB + yC + (xC - xB) * cot_23);
    xCAC = 0.5 * (xA + xC + (yA - yC) * cot_31);
    yCAC = 0.5 * (yA + yC + (xC - xA) * cot_31);

    //distance CAC to CBC (center triangle).
    dCAC_CBC = sqrt((xCAC-xCBC)*(xCAC-xCBC)+(yCAC-yCBC)*(yCAC-yCBC));

    deltatheta = asin(0.5*(dPAC_PBC/dCAC_CBC));
	deltatheta = (deltatheta < 0.0) ? -deltatheta : deltatheta; 
    sign = (xPAC-xPBC)*(yCAC-yCBC) - (xCAC-xCBC)*(yPAC-yPBC);
	if (sign < 0.0 ) deltatheta = -deltatheta ;   
    theta += deltatheta;

    mB = cot(theta - alpha_AB);
    mC = cot(theta - alpha_AB - alpha_BC);
  
    *xP = (mB * xB - mC * xC - yB + yC) / (mB - mC);
    *yP = mB * ((*xP) - xB) + yB; 
    return true;
  }else if ((alpha_BC == PI) || (alpha_BC == 0)){ 
    /* 2nd case: P is aligned on B & C.
                 cot(alpha_BC) is infinity */
    cot_12 = cot(alpha_AB);
    cot_31 = cot(alpha_AB+alpha_BC);
   
    //calc coordinates of center triangle.
    xCAB = 0.5 * (xA + xB + (yA - yB) * cot_12);
    yCAB = 0.5 * (yA + yB + (xB - xA) * cot_12);
    xCAC = 0.5 * (xA + xC + (yA - yC) * cot_31);
    yCAC = 0.5 * (yA + yC + (xC - xA) * cot_31);

    //distance CAB ot CAC (center triangle)
    dCAB_CAC = sqrt((xCAB-xCAC)*(xCAB-xCAC)+(yCAB-yCAC)*(yCAB-yCAC));

    deltatheta = asin(0.5*(dPAB_PAC/dCAB_CAC));
	deltatheta = (deltatheta < 0.0) ? -deltatheta : deltatheta; 
    sign = (xPAB-xPAC)*(yCAB-yCAC) - (xCAB-xCAC)*(yPAB-yPAC);
	if (sign < 0.0 ) deltatheta = -deltatheta ;   
    theta += deltatheta;

    mA = cot(theta);
    mB = cot(theta - alpha_AB);
  
    *xP = (mA * xA - mB * xB - yA + yB) / (mA - mB);
    *yP = mA * ((*xP) - xA) + yA; 
    return true;
  }else if (((alpha_AB + alpha_BC) == PI) || ((alpha_AB + alpha_BC) == 0)){
    /* 3rd case: P is aligned on A & C. 
       cot(alpha_AB+alpha_BC) is infinity.*/
    cot_12 = cot(alpha_AB);
    cot_23 = cot(alpha_BC);
   
    //calc coordinates of center triangle.
    xCAB = 0.5 * (xA + xB + (yA - yB) * cot_12);
    yCAB = 0.5 * (yA + yB + (xB - xA) * cot_12);
    xCBC = 0.5 * (xB + xC + (yB - yC) * cot_23);
    yCBC = 0.5 * (yB + yC + (xC - xB) * cot_23);

    //distance CAB ot CBC (center triangle)
    dCAB_CBC = sqrt((xCAB-xCBC)*(xCAB-xCBC)+(yCAB-yCBC)*(yCAB-yCBC));

    deltatheta = asin(0.5*(dPAB_PBC/dCAB_CBC));
	deltatheta = (deltatheta < 0.0) ? -deltatheta : deltatheta; 
	sign = (xPBC - xPAB) * (yCBC - yCAB) - (xCBC - xCAB) * (yPBC - yPAB);
	if (sign < 0.0 ) deltatheta = -deltatheta;   
    theta += deltatheta;

    mA = cot(theta);
    mB = cot(theta - alpha_AB);
  
	*xP = (mA * xA - mB * xB - yA + yB) / (mA - mB);
	*yP = mA * ((*xP) - xA) + yA;   
    return true;
  }else {
    /* Normal case can be calculated by other methods as well.*/
    cot_12 = cot(alpha_AB);
    cot_23 = cot(alpha_BC);
    cot_31 = cot(alpha_AB+alpha_BC);
   
    //calc coordinates of center triangle.
    xCAB = 0.5 * (xA + xB + (yA - yB) * cot_12);
    yCAB = 0.5 * (yA + yB + (xB - xA) * cot_12);
    xCBC = 0.5 * (xB + xC + (yB - yC) * cot_23);
    yCBC = 0.5 * (yB + yC + (xC - xB) * cot_23);
    xCAC = 0.5 * (xA + xC + (yA - yC) * cot_31);
    yCAC = 0.5 * (yA + yC + (xC - xA) * cot_31);

	AC = ((xCAB - xCBC) * (yCBC - yCAC) - (xCBC - xCAC) * (yCAB - yCBC))/* / 2*/ ;
	AC = (AC < 0.0) ? -AC : AC;

    deltatheta = asin(0.5*sqrt(AP/AC));
	deltatheta = (deltatheta < 0.0) ? -deltatheta : deltatheta; 
	sign = (xPBC - xPAB) * (yCBC - yCAB) - (xCBC - xCAB) * (yPBC - yPAB);
	if (sign < 0.0 ) deltatheta = -deltatheta ;   
    theta += deltatheta;

    mA = cot(theta);
    mB = cot(theta - alpha_AB);
  
	*xP = (mA * xA - mB * xB - yA + yB) / (mA - mB);
	*yP = mA * ((*xP) - xA) + yA;  
    return true;
  }
}
ติดปีกเครื่องคิดเลขเทพ Casio fx 9860G II SD ด้วยโปรแกรมภาษาซีบน AddIn ตอนที่ 4 โปรแกรมพื้นฐานงานสำรวจชุดที่ 1 (COGO SSE 1)

ติดปีกเครื่องคิดเลขเทพ Casio fx 9860G II SD ด้วยโปรแกรมภาษาซีบน AddIn ตอนที่ 4 โปรแกรมพื้นฐานงานสำรวจชุดที่ 1 (COGO SSE 1)

COGO (Coordinate Geometry)

ผมพยายามจะแปลคำนี้เป็นภาษาไทยอยู่นานทีเดียว แต่สุดท้ายขอทับศัพท์ดีกว่า จริงๆแล้วงานสำรวจคืองานที่เกี่ยวกับทรงเรขาคณิต (Geometry) อยู่แล้ว และต้องสามารถระบุค่าพิกัด (Coordinate) ทุกๆจุดได้บนเรขาคณิตนั้นๆ ความเกี่ยวข้องระหว่างรูปทรงเรขาคณติกับค่าพิกัดจะเกี่ยวข้องกันด้วยมุมและระยะทางเป็นส่วนใหญ่

Selected Serie 1 (SSE 1)

คำนี้เอามันครับ ผมนึกถึงโปรแกรมตระกูลไมโครสเตชัน (Microstation) ที่มักจะใช้คำนี้บอกรุนของโปรแกรม ดังนั้นคำว่า  Selected Serie 1 คำแปลก็ประมาณว่าเลือกสรรแล้วชุดที่ 1

โปรแกรมพื้นฐานงานสำรวจชุดที่ 1 (COGO SSE 1)

ก่อนหน้านี้ผมเขียนโปรแกรมภาษาซีสำหรับเครื่องคิดเลข Casio fx-9860G II SD มาหลายตอนแต่เป็นโปรแกรมระดับ advance มาในตอนนี้จะกลับมาที่พื้นฐานงานสำรวจที่ต้องเกี่ยวข้องกับค่าพิกัด มุมและระยะทาง

ดาวน์โหลดและติดตั้ง

ไปที่หน้าดาวน์โหลด (Download) มองหาโปรแกรม COGO SSE1 แล้วดาวน์โหลดจะได้ไฟล์ COGOSSE1.G1A  แล้ว copy ไฟล์ไปที่เครื่องคิดเลขตามวิธีขั้นตอนที่ผมได้บอกไว้ก่อนหน้านี้

ส่วนประกอบของโปรแกรม

สำหรับโปรแกรมพื้นฐานงานสำรวจในชุดนี้จะจัดโปรแกรมย่อยเล็กๆ ไว้ 4 โปรแกรม

  1. Bearing-Dist (2 pt) เมื่อกำหนดจุดค่าพิกัด 2 จุด สำหรับคำนวณหามุมอะซิมัทและระยะทาง
  2. Bearing-Dist(3 pt) เมื่อกำหนดจุดค่าพิกัด 3 จุด สำหรับคำนวณหาง่ามมุมราบ อะซิมัทและระยะทาง ในงานสำรวจก็ได้แก่การตั้งเป้าหลัง  (backsight)  จุดตั้งกล้อง (station) และเป้าหน้า (target)
  3. Coordinate 2D เมื่อกำหนดจุดค่าพิกัด 2 จุด กำหนดมุมราบและระยะราบ คำนวณหาค่าพิกัดจุดที่ 3 คำนวณหาพิกัดจุดที่ 3 การคำนวณคำนวณในระนาบสองมิติอย่างเดียว ไม่มีค่าระดับมาเกี่ยวข้อง
  4. Coordinate 3D เมื่อกำหนดจุดค่าพิกัด 2 จุด กำหนดมุมราบและมุมดิ่ง ระยะทางแบบ slope distance ต้องการคำนวณหาค่าพิกัดและค่าระดับจุดที่ 3

วิธีการใช้งานโปรแกรม

กดคีย์ “MENU” ที่เครื่องคิดเลขจะเห็นหน้าตาประมาณนี้ เลื่อนลูกศรไปที่ไอคอนของโปรแกรมดังรูป กดคีย์ “EXE”

Bearing-Dist (2 pt)

ที่เมนูกดคีย์ “1” เป็นการคำนวณหาค่ามุมอะซิมัทและระยะทางเมื่อกำหนดจุดค่าพิกัดให้สองจุด ลองทดสอบจากตัวอย่างดังรูป การประยุกต์ใช้งานส่วนใหญ่เป็นตอนที่ช่างสำรวจตั้งกล้องที่หมุดและส่องไปเป้าหลังหรือเป้าหน้าแล้ววัดระยะทางเพื่อตรวจสอบจากค่าพิกัด

ผลลัพธ์ก็ออกมาดังนี้

Bearing-Dist (3 pt)

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

จะได้ผลลัพธ์มาดังนี้ ครั้งแรกจะแสดงมุมอะซิมัทและระยะทางไปเป้าหลังก่อน

ถัดไปจะเป็นมุมราบ มุมอะซิมัทและระยะทางไปเป้าหน้า

Coordinate 2D

ที่เมนูกดคีย์เลข “3” เป็นการคำนวณหาค่าพิกัดเป้าหน้าเมื่อกำหนดค่าพิกัดจุดตั้งกล้องและเป้าหลัง กำหนดมุมราบและระยะทาง การคำนวณจะไม่มีค่าระดับมาเกี่ยวข้อง จึงเรียกว่า 2D หรือสองมิติ สำหรับโปรแกรมนี้ผมได้นำค่าสเกลแฟคเตอร์เข้ามาช่วยประยุกต์ใช้ด้วย ในกรณีที่ไม่ต้องใช้ก็ป้อนค่าสเกลแฟคเตอร์นี้ เป็น 1.0

สเกลแฟคเตอร์ตัวนี้แล้วจริงๆคือ Combine Scale Factor (CSF) ที่ได้จาก Elevation Scale Factor (ESF) x Grid Scale Factor (GSF) การประยุกต์ใช้สเกลแฟคเตอร์ส่วนใหญ่นำมาใช้โครงการที่ระบบพิกัดฉากกริดยูทีเอ็มในงานใหญ่ๆยาวๆ เช่นโครงการก่อสร้างถนน รถไฟ เพราะว่าแบบ drawing เราอยู่บนระนาบพิกัดฉาก ให้คิดเสียว่าแบบอยู่บนกระดาษขนาดใหญ่มาตราส่วน 1:1 แล้วเราวัดระยะทางบนผิวโลกที่มีความโค้ง ดังนั้นการวัดระยะทางจะต้องมีการทอนจากบนผิวโค้งเพื่อให้ลงมาเข้ากับระนาบพิกัดฉากของกระดาษ

มาลองทดสอบข้อมูล ป้อนข้อมูลค่าพิกัดเป้าหลัง ค่าพิกัดจุดต้องกลองดังนี้

จากนั้นป้อนมุมราบ และระยะทาง (Ground Distance ใช้ตัวย่อ Gnd dist) ในกรณีกล้องโททัล สเตชัน ไม่ได้ตั้งค่าสเกลแฟคเตอร์ไว้ที่ตัวกล้อง ระยะทางที่วัดออกมาจะเป็นระยะทางบนพื้นโลก ส่วนค่าสเกลแฟคเตอร์ในตัวอย่างผมใช้ 1.000480

 

โปรแกรมจะคำนวณมุมอะซิมัทและระยะทางไปเป้าหลังให้ดูก่อนเพื่อตรวจสอบ และไม่ลืมว่าค่าพิกัดที่เราป้อนเข้าไปในเครื่องคิดเลขคือค่าพิกัดในระบบพิกัดฉาก ระยะทางที่คำนวณออกมาคือระยะทางบนพิกัดฉาก (Grid Distance ใช้ตัวย่อ Grd Dist) และถ้าวัดระยะทางจริงๆควรจะได้เท่ากับ Ground Distance

ทวนกันนิด ระยะทางบนพิกัดฉาก(กริด)= ระยะทางบนพื้นโลก x สเกลแฟคเตอร์ 

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

Coordinate 3D

ที่เมนูกดคีย์ “4” โปรแกรมคล้าย Coordinate 2D แต่จะมีมิติทางดิ่งเข้ามาเพิ่มดังนั้นที่จุดตั้งกล้องจะวัดความสูงของกล้อง (HI – Height of instrument) และที่เป้าหน้าก็จะต้องวัดความสูงมาด้วย (HT – Height of target) นอกจากนั้นจะมีมุมดิ่ง (Vertical angle) มาด้วย มาดูข้อมูลทดสอบกัน เริ่มจากป้อนค่าพิกัดเป้าหลัง ต่อมาป้อนค่าพิกัดจุดตั้งกล้อง ค่าระดับจุดตั้งกล้อง ความสูงกล้อง

ต่อไปป้อนมุมราบ(H.Ang) มุมดิ่ง(V.Ang) ระยะทาง (Slope distance) และความสูงเป้า(HT) และค่าสเกลแฟคเตอร์ (Scale Factor)

โปรแกรมจะคำนวณอะซิมัท ระยะทางจากจุดตั้งกล้องไปเป้าหลัง ข้อสังเกตผมใส่เครื่องหมายดาว (*) หน้าระยะทางบนพื้นโลก (Ground Distance)

กดคีย์ “EXE” จะได้ผลลัพธ์ อะซิมัท ระยะราบทั้งระยะบนพื้นโลกและระยะกริดจากจุดตั้งกล้องไปเป้าหน้า

สุดท้ายคือผลลัพธ์ที่ต้องการคือค่าพิกัดและค่าระดับของเป้าหน้า

สรุป

ก็พอหอมปากหอมคอสำหรับโปรแกรมพื้นฐานงานสำรวจชุดที่ 1 โดยมีสิ่งที่ช่างสำรวจจะต้องเข้าใจตั้งแต่เรื่องมุมอะซิมัทคือมุมอะไร สำคัญมากเพราะมุมนี้เป็นหัวใจขั้นพื้นฐานและจะสัมพันธ์กับระยะทางโดยที่แยกกันไม่ออกและสามารถนำไปคำนวณค่าพิกัดได้ สำหรับการคำนวณแบบนี้ โปรแกรมในกล้อง Total Station ปัจจุบันก็คำนวณให้อยู่แล้ว แล้วก็เก่งขึ้นเรื่อยๆ แต่ในทางกลับกัน สำหรับช่างสำรวจเอง คงไม่มีใครได้จับกล้องพวกนี้ได้ตลอดเวลา จำเป็นจะต้องมีเครื่องคิดเลขคู่ใจไว้ติดตัวตลอด สามารถหยิบมาใช้งานได้สะดวกและถ้ามีโปรแกรมที่จำเป็นสำหรับการทำงานติดอยู่ด้วย ชีวิตการทำงานก็พลอยลื่นไหล ติดตามตอนต่อไปครับ

ติดปีกเครื่องคิดเลขเทพ Casio fx 9860G II SD ด้วยโปรแกรมภาษาซีบน AddIn ตอนที่ 3 โปรแกรมคำนวณหาระยะทางจากค่าพิกัดภูมิศาสตร์ (Geodetic Dist Calc)

ติดปีกเครื่องคิดเลขเทพ Casio fx 9860G II SD ด้วยโปรแกรมภาษาซีบน AddIn ตอนที่ 3 โปรแกรมคำนวณหาระยะทางจากค่าพิกัดภูมิศาสตร์ (Geodetic Dist Calc)

มาถึงตอนที่ 3 ขอนำเสนอโปรแกรมคำนวณหาระยะทางที่สั้นที่สุดบนทรงรีด้วยสูตรการคำนวณของ Vincenty  และระยะทางที่สั้นที่สุดบนทรงกลมด้วยสูตรของ Haversine โดยที่กำหนดค่าพิกัดภูมิศาสตร์ (แลตติจูด/ลองจิจูด) มาให้ 2 จุด

Geodesic Distance

ระยะทางที่สั้นที่สุดบนทรงรี (Ellipsoid) จะเรียกว่า Geodesic distance ผมใช้ไลบรารี GeographicLib ที่พัฒนาโดย Charles F. F. Karney ไลบรารีตัวนี้ใช้ c standard library เฉพาะ math อย่างเดียว ดังนั้นมั่นใจได้เลยว่าสามารถเอามาคอมไพล์บนเครื่องคิดเลข Casio fx-9860G II SD ได้อย่างแน่นอน ไฟล์ header และซอร์สภาษาซีสามารถไปดาวน์โหลดได้ตามลิ๊งค์นี้ ให้ดาวน์โหลดเฉพาะไฟล์ geodesic.h และ geodesic.c ก็พอ ในไลบรารีเองจะแบ่งการคำนวณออกเป็น 2 แบบ คือ

  • Inverse กำหนดค่าพิกัดภูมิศาสตร์ 2 จุด คำนวณหาระยะทางและอะซิมัทของจุดเริ่มและจุดสิ้นสุด
  • Direct กำหนดค่าพิกัดภูมิศาสตร์ 1 จุดและอะซิมัทจุดเริ่มต้นและระยะทาง สามารถคำนวณหาค่าพิกัดภูมิศาสตร์จุดสิ้นสุดหรือจุดปลายได้
Image from http://proj4.org

ไลบรารี GeographicLib นอกจากจะคำนวณ Inverse & Direct แล้วยังสามารถคำนวณหาพื้นที่ของรูปปิด polygon ได้ แต่ผมไม่ได้นำมาคำนวณในที่นี้

Great Circle Distance

ส่วนการคำนวณหาระยะทางบนทรางกลม ที่ใช้สูตร Haversine ผมเขียนเองเพราะเป็นสูตรสั้นๆ แบ่งการคำนวณแบบ Inverse และ Direct ได้ หมายเหตุความถูกต้องของระยะทางยังสู้ Geodesic distance ไม่ได้

Image from https://en.wikipedia.org

ดาวน์โหลด (Download) โปรแกรมเครื่องคิดเลข

ไปที่หน้าดาวน์โหลด ตามลิ๊งค์นี้  มองหาโปรแกรม Geodetic Dist Calc จะได้ไฟล์ GEODIST.G1A แล้วติดตั้งลงเครื่องคิดเลข Casio fx-9860G II SD ผ่านทาง SD card หรือผ่าน FA-124

ทดสอบการใช้งาน

ในโหมด “MAIN MENU” ใช้ปุ่มคีย์บอร์ดลูกศรลงมาที่ไอคอน ดังรูป จากนั้นกดคีย์ “EXE” ประมวลผล

จะเห็นเมนูขึ้นมาดังรูป

Vincenty Inverse

เมื่อกำหนดค่าพิกัดสองจุด ต้องการคำนวณหาระยะทางบนทรงรี ที่เมนูกดคีย์ “1” ที่เครื่องคิดเลข เพืื่อคำนวณระยะทางแบบ Geodesic dist ป้อนค่าพิกัดดังรูป

กดคีย์ “EXE” เพื่อดูผลลัพธ์ จะได้ระยะทางสองหน่วยคือเมตรและกิโลเมตร  Azi 1 คือค่าอะซิมัทจุดเริ่มต้น Azi 2 อะซิมัทที่จุดปลายทาง

Vincenty Direct

กำหนดค่าพิกัดเริ่มต้น กำหนดระยะทางและอะซิมัท คำนวณหาค่าพิกัดปลายทางและอะซิมัทปลายทาง ที่เมนูกดคีย์ “2” ป้อนข้อมูลทดสอบดังนี้

ได้ผลลัพธ์ดังนี้

Haversine Inverse

กำหนดค่าพิกัดให้สองจุด คำนวณหาระยะทางและอะซิมัท ที่เมนูกดคีย์เลข “3” ป้อนข้อมูลทดสอบดังนี้

กดคีย์ “EXE” ได้ผลลัพธ์ดังนี้

จะเห็นว่าค่าพิกัดสองจุดเป็นจุดเดียวกันกับตัวอย่าง Vincenty Inverse แต่ระยะทางที่คำนวณด้วยสูตร Vincentry ได้เท่ากับ 9271.574 กม. แต่ที่คำนวณด้วย Haversine ได้ระยะทาง 9273.574 กม. ต่างกันเล็กน้อยมากประมาณ 0.02  %

Haversine Direct

กำหนดค่าพิกัดให้หนึ่งจุด อะซิมัทแบะระยะทาง คำนวณค่าพิกัดจุดปลายทาง ที่เมนูกดคีย์ “4” ป้อนข้อมูลทดสอบดังนี้ 

กดคีย์ “EXE” ได้ผลลัพธ์ดังนี้

สรุป

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

 

แนะนำโปรแกรมมิ่งภาษาซีบนเครื่องคิดเลข Casio fx-9860G II SD ด้วยเครื่องมือพัฒนา SDK ของ Casio

แนะนำโปรแกรมมิ่งภาษาซีบนเครื่องคิดเลข Casio fx-9860G II SD ด้วยเครื่องมือพัฒนา SDK ของ Casio

เคยเกริ่นมาก่อนว่าต้องการเขียนบทความนี้ขึ้นมาเพื่อวงการศึกษาบ้านเราที่สนใจเรื่องโปรแกรมมิ่งบนเครื่องคิดเลขสามารถจะพัฒนาโปรแกรมภาษาซีบน Casio fx-9860G II SD หรือรุ่นที่ใกล้เคียงนี้ได้ โดยที่มีไม่มีข้อจำกัดด้านภาษาโปรแกรมมิ่ง เหมือนกับภาษา casio basic อาจจะส่งผลให้ในอนาคต มีโปรแกรมที่พัฒนาโดยบุคคลากรท่านอื่นๆ เข้ามาสู่วงการนี้มากขึ้น และได้ตัวโปรแกรมงานสำรวจที่มีความหลากหลายและความสามารถมากขึ้นทั้งนี้เพื่อขยายขีดความสามารถโปรแกรมบนเครื่องคิดเลขให้สามารถคิดงานที่ยาก ซับซ้อนได้ บางครั้งเกือบจะเทียบเท่าโปรแกรมที่ใช้งานบนคอมพิวเตอร์

เครื่องมือพัฒนา Software Development Kit (SDK)

เครื่องมือตัวนี้เดิมทีสามารถดาวน์โหลดที่เว็บไซต์ตามลิ๊งค์นี้ได้ http://edu.casio.com/support/en/agreement.html#2 ขั้นตอนแรกยอมรับเงื่อนไขแล้วเลื่อนหน้าไปด้านล่างๆจะเห็นเครื่องคิดเลขรุ่น fx-9860 เมื่อคลิกลิ๊งค์ SDK เข้าไปจะเห็นว่าลิ๊งค์เครื่องมือพัฒนาโปรแกรมขาด แต่คู่มือยังสามารถดาวน์โหลดมาอ่านศึกษาได้ ผมอาศัยลงใต้ดินที่มีคนปล่อยให้ดาวน์โหลด (ถ้าใครอยากได้เครื่องมือตัวนี้ก็ขอมาหลังไมค์กันได้ครับ) และดาวน์โหลดโปรแกรม FA-124 มาด้วยอยู่ในหมวด Support Software/PC Link software

ติดตั้งเครื่องมือพัฒนาโปรแกรม

เปิดไฟล์ zip ของเครื่องมือพัฒนาจะเห็นไฟล์ข้างในดังนี้

จากนั้นทำการติดตั้งเครื่องมือลงคอมพิวเตอร์  ข้อสำคัญคือพาทของโฟลเดอร์หรือไดเรคทอรีที่ติดตั้งจะต้องไม่มีช่องว่าง ดังนั้นให้ติดตั้งไปที่รากของไดรว์ C: ตัวอย่างผมใช้ชื่อว่า fx-9860-sdk 

ถ้าพาทของโฟลเดอร์ที่ติดตั้งมีช่องว่างการ compile & build จะไม่ผ่านเลย เมื่อติดตั้งแล้วจะมีไอคอนที่หน้า desktop

เริ่มต้นใช้งาน

เมื่อเปิดโปรแกรมจากไอคอนที่ desktop จะเห็นหน้าตาเครื่องมือพัฒนาโปรแกรม ดังรูป อาจจะดูทื่อๆเพราะเครื่องมือตัวนี้ออกมานานแล้วตั้งแต่วินโดส์รุ่นก่อนหน้านี้ ที่เมนู “Project” คลิกเลือก “New” ผมสร้างโฟลเดอร์ชื่อ “FX9860GIISD” ไว้ที่ไดรว์ D: และตั้งชื่อโฟลเดอร์สำหรับทดสอบการเขียนโปรแกรมนี้ว่า “Test” และตั้งชื่อโปรแกรมว่า “Hello”

จะเห็นหน้าตาเครื่องมือพัฒนาประมาณรูปด้านล่าง และตัวอีมูเลเตอร์ “Display” และ “Keyboard” ของ fx-9860G

Project แรกเริ่ม

เมื่อเราสร้าง Project ใหม่จะเห็นโครงร่างที่เครื่องมือเขียนมาให้ดังนี้

/*****************************************************************/
/*                                                               */
/*   CASIO fx-9860G SDK Library                                  */
/*                                                               */
/*   File name : Hello.c                                 */
/*                                                               */
/*   Copyright (c) 2006 CASIO COMPUTER CO., LTD.                 */
/*                                                               */
/*****************************************************************/
#include "fxlib.h"

//****************************************************************************
//  AddIn_main (Sample program main function)
//
//  param   :   isAppli   : 1 = This application is launched by MAIN MENU.
//                        : 0 = This application is launched by a strip in eACT application.
//
//              OptionNum : Strip number (0~3)
//                         (This parameter is only used when isAppli parameter is 0.)
//
//  retval  :   1 = No error / 0 = Error
//
//****************************************************************************
int AddIn_main(int isAppli, unsigned short OptionNum)
{
    unsigned int key;

    Bdisp_AllClr_DDVRAM();

    locate(1,4);
    Print((unsigned char*)"This application is");
    locate(1,5);
    Print((unsigned char*)" sample Add-In.");

    while(1){
        GetKey(&key);
    }

    return 1;
}

//****************************************************************************
//**************                                              ****************
//**************                 Notice!                      ****************
//**************                                              ****************
//**************  Please do not change the following source.  ****************
//**************                                              ****************
//****************************************************************************

#pragma section _BR_Size
unsigned long BR_Size;
#pragma section

#pragma section _TOP

//****************************************************************************
//  InitializeSystem
//
//  param   :   isAppli   : 1 = Application / 0 = eActivity
//              OptionNum : Option Number (only eActivity)
//
//  retval  :   1 = No error / 0 = Error
//
//****************************************************************************
int InitializeSystem(int isAppli, unsigned short OptionNum)
{
    return INIT_ADDIN_APPLICATION(isAppli, OptionNum);
}
#pragma section

จากโค้ดด้านบนจะเห็นว่าไม่เห็นจุดเริ่มต้นเข้าโปรแกรม (entry point) ฟังก์ชัน main() เช่นภาษาซีทั่วๆไป แต่จะมี AddIn_main() มาแทนให้รู้ว่าเป็นจุดเริ่มต้นของโปรแกรม AddIn สำหรับเครื่องคิดเลขนี้

มาดูโค้ดกันสักนิด ที่ #inlucde “fxlib.h” จะเป็น header ของ Casio สำหรับการแสดงผลเช่นฟังก์ชัน Print เพื่อแสดงบนจอภาพเครื่องคิดเลข Bdisp_AllClr_DDVRAM(); จะเป็นฟังก์ชันเคลียร์หน้าจอภาพให้ว่างเปล่า  locate(1,4); เลื่อนเคอเซอร์มาที่คอลัมน์ 1 และบรรทัดที่ 4 จากนั้นพิมพ์ด้วยฟังก์ชัน Print((unsigned char*)”This application is”); สุดท้ายปิดด้วย loop ไม่รู้จบ while (1) แล้วรอผู้ใช้กดคีย์ GetKey(&key); ตอนรันโปรแกรมถ้าผู้ใช้กดคีย์ “MENU” บนเครื่องคิดเลขก็จะเข้าสู่โหมด “MAIN MENU” แต่โปรแกรมก็ยังรันค้างอยู่ในสถานะเดิม

Compile & Build

มาลองคอมไพล์และบิวด์ดู ที่เมนู “Project” คลิก “Rebuild all” ถ้าไม่มีอะไรผิดพลาดที่กรอบ “Builds” จะแสดงผลดังนี้

Executing Hitachi SH C/C++ Compiler/Assembler phase

set SHC_INC=C:\fx-9860G-SDK\OS\SH\include
set PATH=C:\fx-9860G-SDK\OS\SH\bin
set SHC_LIB=C:\fx-9860G-SDK\OS\SH\bin
set SHC_TMP=D:\FX9860GIISD\Test\Debug
"C:\fx-9860G-SDK\OS\SH\bin\shc.exe" -subcommand=C:\Users\priabroy\AppData\Local\Temp\hmk9A12.tmp

Executing Hitachi OptLinker04 phase

"C:\fx-9860G-SDK\OS\SH\bin\Optlnk.exe" -subcommand=C:\Users\priabroy\AppData\Local\Temp\hmk9D5F.tmp

Optimizing Linkage Editor Completed

HMAKE MAKE UTILITY Ver. 1.1
Copyright (C) Hitachi Micro Systems Europe Ltd. 1998
Copyright (C) Hitachi Ltd. 1998 


	Make proccess completed

"D:\FX9860GIISD\Test\HELLO.G1A" was created.

Build has completed.

ถ้าสำเร็จจะเห็น HELLO.G1A ถูกสร้างขึ้นมา จากนั้นที่เมนู “Run” คลิกที่เมนูย่อย “Run” อีมูเลเตอร์จะเริ่มทำงาน

ที่ “Keyboard” กดปุ่มเลื่อนลูกศรลงที่ไอคอน “Debug” กดคีย์ “EXE” จะเห็นหน้าตาโปรแกรมดังนี้

ดาวน์โหลดซอร์สโค้ด (Source code) โปรแกรมแปลงพิกัดภูมิศาสตร์ (Geographic Calc)

เพื่อการลดระยะเวลาการเรียนรู้สำหรับคนที่เพิ่งจะมาศึกษาการใช้งานเครื่องมือ SDK ผมจะขอแสดงโครงการที่ผมทำไว้แล้ว ไปที่หน้าดาวน์โหลด (Download) มองหาซอร์สโค้ด (Source code) โปรแกรมสำหรับเครื่องคิดเลข Casio fx-9860G II SD จะได้ไฟล์ zip ชื่อ “UTM-Geo.zip” ทำการแตกไฟล์ zip จะเห็นไฟล์ดังนี้

ที่ผมวงสีแดงไว้คือโค้ดที่ได้จาก ไลบรารีที่ผมดาวน์โหลดมาใช้จาก githubพัฒนาโดย Howard Butler ส่วนที่ผมวงสีฟ้าไว้คือโค๊ดของผมเอง แตกไฟล์ zip ไปไว้ที่โฟลเดอร์สำหรับผมเองอยู่ที่ไดรว์ D:\FX9860GIISD

เปิดโครงการโปรแกรมแปลงพิกัดภูมิศาสตร์

ใช้เมนู “Project” > “Open…” เปิดไฟล์ชื่อ “UTMGeo.g1w”  ที่ช่อง panel  ด้านซ้ายสุดของเครื่องมือพัฒนาจะเห็นเป็นชื่อไฟล์ที่ผมได้ add มาไว้ จะสังเกตเห็นชื่อไฟล์บางตัวมี นามสกุล extension *.h, *.c ที่เป็นปกติของไฟล header และซอร์สโค้ดของภาษาซีและ *.hpp, *.cpp ของภาษาซีพลัสพลัส ซึ่งไฟล์ extension ที่เราตั้งชื่อไว้ถ้ามีโค้ดภาษาซีพลัสพลัส จะต้องใช้ extension เป็น hpp และ cpp

แก้ไขโครงการ

ใช้เมนู “Project” > “Edit…” เพื่อแก้ไขชื่อโครงการ หรือเพิ่มลดไฟล์ header และ source file

แก้ไขไอคอนสำหรับปรากฎที่หน้า “MAIN MENU” ของเครื่องคิดเลข ไอคอนขนาดกว้าง 39 pixel และสูงขนาด 19 pixel ฟอร์แม็ตเป็น bitmap แบบขาวดำ 1 bit ผมออกแบบในโปรแกรม Paint.net จัดเก็บเป็นไฟล์ bitmap (bmp) แต่ไม่สามารถจัดเก็บเป็นไฟล์ขาวดำแบบ 1 bit ได้ต้องไปเปิดต่อใน Gimp แล้วเลือกเมนู Image>Mode>Indexed ตรง Color map เลือก Use black and white (1 bit) palette จากนั้น save จึงจะได้ไฟล์รูปที่มีฟอร์แม็ต bitmap แบบ 1 bit ได้ ทั้งสองโปรแกรมนี้ฟรี

ตรง Edit icon เวลาจะคลิกต้องระวังเพราะถ้าเราออกแบบไอคอนมาแล้ว จะโดนทับด้วยรูปไอคอนดีฟอลท์ทันที ผมไม่ใช้เลยเพราะพลาดหลายทีแล้ว

การจัดการโค้ด C++

ถ้ามีโค้ดซีพลัสพลัสมาผสมด้วย ที่ด้านบนสุดไฟล์จะต้องกำหนดดังนี้

#ifdef __cplusplus
  extern "C" {
#endif

ด้านล่างสุดปิดท้ายด้วย

  #ifdef __cplusplus
}
  #endif

โค้ดจัดการการป้อนข้อมูล

การป้อนข้อมูลของงานสำรวจในเครื่องคิดเลขส่วนใหญ่จะเป็นเลขทศนิยมเช่นระยะทางหรือค่าพิกัด แต่ถ้าเป็นมุมทีแยกองศา ลิปดาและฟิลิปดา ปกติในเครื่องคิดเลขเช่น  fx-4500, fx-5800P จะมีคีย์ให้กดสะดวก แต่เครื่อง  fx-9860G II SD กลับเอาไปไว้ลึกมากต้องกดหลายครั้งจากคีย์ “OPTN” แต่ที่ผมช็อคคือใน SDK กลับไม่มีฟังก์ชันให้เรียกใช้งานได้เลย จะต้องเขียนฟังก์ชันขึ้นมาเองทั้งหมด ผมอาศัยไปอ่านตามฟอรั่มที่มีคนแฮ็คไว้ พบว่าสามารถเรียกใช้ฟังก์ชัน EditExpress ที่ทาง Casio ไม่ได้เปิดเผยเอกสารไว้ (สังเกตว่าใช้เป็น function pointer อ่านรายละเอียดการใช้งานได้ที่ลิ๊งค์นี้)

#define SCA 0xD201D002
#define SCB 0x422B0009
#define SCE 0x80010070

const unsigned int sc08DB[] = {SCA, SCB, SCE, 0x08DB};
typedef int(*sc_EE)(int, short, int, char*, char*, short, char*, int );
#define EditExpression (*(sc_EE)sc08DB) 

วิธีใช้งานก็ประมาณนี้

#define MAXEDITBUFFER 21
//
void AddIn_main(int isAppli, unsigned short OptionNum){
int key;
char vBCD[24];
unsigned char sBCD[MAXEDITBUFFER];

   memset( vBCD, 0, sizeof(vBCD));
   memset( sBCD, 0, sizeof(sBCD));
   key = EditExpression(0, KEY_CTRL_RIGHT, 1, vBCD, (char*)sBCD, MAXEDITBUFFER - 1, "Input:", 0x04);
   
   locate(1, 4);
   PrintLine(sBCD, 21);
   
   GetKey(&key);
   return 1;
}

ข้อมูลที่ผู้ใช้ป้อนจะกลับมาที่ข้อมูลสตริง sBCD ผมพบว่าเรียกใช้ EditExpression มี  mode ให้ป้อนเลือกว่าจะป้อนข้อมูลเป็น double ไหม ซึ่งตอนป้อนข้อมูลจะรับแค่ตัวเลข แต่ในโหมดตามตัวอย่างด้านบน (พารามิเตอร์สุดท้าย 0x04) นั้นจะรับค่าทั่วๆไปทั้งตัวอักษรผสมกับตัวเลข แต่ผมสังเกตว่าเวลาเราป้อนข้อมูลแล้วกดคีย์ “EXE” จะมีการประมวลผล expression ด้วย ปัญหาที่ผมพบคือถ้าป้อนสตริงค่าพิกัดแบบ MGRS เช่น “18SVK8588822509” กลับ error ผมเลยต้องเขียนฟังก์ชันขึ้นมาเองคือ inputMGRSString() โดยเฉพาะ

การป้อนข้อมูลมุม

เนื่องจากเครื่องมือพัฒนา SDK ไม่สนับสนุนการป้อนมุมแบบใช้งานปกติ ผมเลยกำหนดว่ามุมองศา ลิปดาและฟิลิปดาให้คั่นด้วยเครื่องหมายลบ (-) เช่นแลตติจูด (Latitude) จะใช้ตัวอักษร “N” หรือ “S” มากำกับว่าอยู่ในซึกโลกเหนือหรือซีกโลกใต้ คั่นด้วยเส้นศูนย์สูตร ส่วนมุมลองจิจูด (Longitude) แบ่งเป็นซีกโลกตะวันออก (“E” ปิดท้าย) และซีกโลกตะวันตก (“W” ปิดท้าย

ตัวอย่าง แลตติจูด 45-5-32.525N ลองจิจูด 98-45-38.587W

โค้ดอ่านเขียนข้อมูลเข้าตัวแปร  Alpha

ส่วนใหญ่เวลาเราป้อนข้อมูลเข้าไปในการคำนวณงาน เราต้องการให้โปรแกรมจดจำค่านั้นไว้ ดังนั้นโปรแกรมต้องมีการจัดเก็บเอาไว้แล้วเรียกมาใช้ทีหลังเมื่อเรียกโปรแกรมมาใช้งานอีกที เพราะไม่ต้องป้อนบ่อย ถ้ายังใช้ค่าเดิมแค่กดคีย์ “EXE” ผ่านได้เลย และก็เหมือนเดิมครับ SDK ไม่ได้เปิดเผยฟังก์ชันนี้ไว้ทั้งที่สำคัญมาก ผมไปค้นหาตามฟอรั่มพบว่าการจัดเก็บข้อมูลเข้าตัวแปรตัวอักษร A-Z ใช้โครงสร้างข้อมูลเฉพาะ อ่านได้ตามลิ๊งค์นี้ การแปลงข้อมูลสามารถใช้ class TBCD (โค๊ดเดิมมีบั๊กผมแก้ไปนิดหน่อย)

#define SCA 0xD201D002
#define SCB 0x422B0009
#define SCE 0x80010070

const unsigned int sc04E0[] = {SCA, SCB, SCE, 0x04E0};
const unsigned int sc04DF[] = {SCA, SCB, SCE, 0x04DF};

typedef void(*sc_agd)(char, TBCDvalue*);
typedef void(*sc_asd)(char, TBCDvalue*);

#define Alpha_GetData (*(sc_agd)sc04DF)
#define Alpha_SetData (*(sc_asd)sc04E0)

void GetAlphaDoubleData(char alpha, double *dval);
void SetAlphaDoubleData(char alpha, double val);

typedef struct{
  unsigned char hnibble:4;
  unsigned char lnibble:4;
} TBCDbyte;

typedef struct{
  unsigned short exponent:12;
  unsigned short mantissa0:4;
  TBCDbyte mantissa[7];
  char flags;
  short info;
} TBCDvalue;

typedef struct{
  int exponent;
  int sign;
  int unknown; 
  char mantissa[15];
} TBCDInternal;

//Implement of class TBCD please see utilities.cpp
class TBCD{
  public:
        TBCDvalue*PValue();
        int Get( TBCDvalue&value );
        int Set( TBCDvalue&value );
        int Set( double&value );
        int Get( double&value );
        int SetError( int error );
        int GetError();
        void Swap();
  protected:
  private:
        TBCDvalue FValue[2];
};

void GetAlphaDoubleData(char alpha, double *dval){
  TBCD *bcd;
  TBCDvalue *bval;
  int i, ii;

  bval = (TBCDvalue *)malloc(sizeof(TBCDvalue));
  Alpha_GetData(alpha, bval);
  bcd = new TBCD;
  i = bcd->Set(*bval);
  ii = bcd->Get(*dval);
  delete bcd;
  free(bval);
}

void SetAlphaDoubleData(char alpha, double dval){
  TBCD *bcd;
  TBCDvalue bval;
  int i, ii;

  bcd = new TBCD;
  i = bcd->Set(dval);
  ii = bcd->Get(bval);
  Alpha_SetData(alpha, &bval);
  delete bcd;
}

วิธีการใช้งานก็ง่ายๆ

      SetAlphaDoubleData('B', 123.456); //เอาค่า 123.456 เข้าเก็บที่ตัวแปรอักษร "B"
      GetAlphaDoubleData('B', &x); //ดึงค่าที่เก็บในตัวอักษร "B" ออกมาเข้าตัวแปร x
      Locate(1, 4);
      sprintf((char*) str, (char*) "Value = %.3lf", x); 
      Print((unsigned char*)str); //Value = 123.456     

โค้ดสำหรับเมนูหลัก

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

โค้ดก็ง่ายๆดังนี้

      memset(s, '-', 21);
      Bdisp_AllClr_DDVRAM(); 
      locate(0, 1);
      Print((unsigned char *)"Geographic Calc");
      locate(0, 2);
      PrintLine((unsigned char*)s, 21);
      locate(0, 3);
      PrintLine("[1]:UTM to Geo", 21);
      locate(0, 4);
      PrintLine("[2]:Geo to UTM", 21);
      locate(1, 5);
      PrintLine("[3]:MGRS to Geo", 21);
      locate(0, 6);
      PrintLine("[4]:Geo to MGRS", 21);
      locate(1, 8);
      PrintLine("Select 1,2,3 or 4", 21);
      while (!((key1 >= 0x31) && (key1 <= 0x34)){ 
        GetKey(&key1);

จะมีลูป while ดักการกดคีย์อีก loop ถ้าพบว่ากดคีย์เลข “1” (character code = 0x31) ถึงเลข “4” (Character code = 0x34) เงื่อนไขจริงจะออกจาก loop เข้าเงื่อนไข if (มีหลายชั้นใช้ case แทนได้)

โค้ดงานคำนวณหลัก

ถ้าผู้ใช้กดคีย์ “1” จะเป็นการคำนวณค่าพิกัดจาก UTM ไปยัง Geographic

    if (key1 == 0x31) { //UTM to Geo
      Bdisp_AllClr_DDVRAM(); 
      locate(0, 1);
      Print((unsigned char *)"UTM to Geo");
      locate(0, 2);
      PrintLine((unsigned char*)s, 21);

      GetAlphaDoubleData('A', A);//ดึงค่าข้อมูลเดิมจากหน่วยความจำตัวอักษร "A" 
      sprintf((char*)sBCD, (char*) "%.3lf", *A); //เตรียมรูปแบบข้อมูลทศนิยมสามตำแหน่งไว้ใน sBCD
      //เรียกฟังก์ชันป้อนข้อมูล โดยส่ง sBCD ไปให้
      key2 = EditExpression(0, KEY_CTRL_RIGHT, 3, vBCD, (char*)sBCD, MAXEDITBUFFER - 1, "N? : ", 0x04);
      y = atof((char*)sBCD); //แปลงข้อมูลที่ป้อนมาเป็นตัวเลขทศนิยม
      SetAlphaDoubleData('A', y);//เก็บค่าที่ป้อนไว้ในหน่วยความจำตัวอักษร "A"

      GetAlphaDoubleData('B', B);
      sprintf((char*)sBCD, (char*) "%.3lf", *B); 
      key2 = EditExpression(0, KEY_CTRL_RIGHT, 4, vBCD, (char*)sBCD, MAXEDITBUFFER - 1, "E? : ", 0x04);
      x = atof((char*)sBCD);
      SetAlphaDoubleData('B', x);
     
      GetAlphaDoubleData('Z', Z);
      sprintf((char*)sBCD, (char*) "%.3lf", *Z); 
      key2 = EditExpression(0, KEY_CTRL_RIGHT, 5, vBCD, (char*)sBCD, MAXEDITBUFFER - 1, "UTM Zone No.? : ", 0x04);
      if (strchr((char*)sBCD, 0x87) != NULL) {
        removechar((char*)sBCD, 0x87);
        hemi = 'S';
      } else if(strchr((char*)sBCD, 0x2D) != NULL) {
        removechar((char*)sBCD, 0x2D);
        hemi = 'S';
      } else
        hemi = 'N';

      zn = atoi((char*)sBCD);
      SetAlphaDoubleData('Z', zn);
      //เรียกไลบรารีแปลงพิกัดที่ประกาศใน utm.c
      err = Convert_UTM_To_Geodetic(zn, hemi, x, y, &lat, &lng);
      if (!err){
	      Lat = lat * RAD2DEG; 
	      Lng = lng * RAD2DEG;
              //แยกทศนิยมจัดรูปแบบที่ที่องศา ลิปดาและฟิลิปดาคั่นด้วยเครื่องหมายลบ
	      slat = degreetodms(fabs(Lat), NUMDECIMAL, 0x2D);
	      if(Lat >= 0)
	        sprintf(str, "Lat= %s N", slat);
	      else
	        sprintf(str, "Lat= %s S", slat);
	      locate(1, 6);
	      Print((unsigned char*)str); 
	      locate(1, 7);
	      slong = degreetodms(fabs(Lng), NUMDECIMAL, 0x2D);
	      if (Lng >= 0)
	        sprintf(str, "Lon= %s E", slong);
	      else
	        sprintf(str, "Lon= %s W", slong);
	      Print((unsigned char*)str);      
	      free(slat);
	      free(slong);
       }

ลองดูโค้ดแปลงพิกัดจากค่าพิกัดฉากยูทีเอ็มไปค่าพิกัดภูมิศาสตร์ โดยใช้ไลบรารี

err = Convert_UTM_To_Geodetic(zn, hemi, x, y, &lat, &lng);

zn คือโซนยูทีเอ็ม hemi คือซีกโลก x และ y คือค่าพิกัดฉากยูทีเอ็ม ส่วนค่าที่คำนวณแล้วจะส่งกลับมาที่ตัวแปร lat, lng ส่วนการแปลงพิกัดอย่างอื่นก็ลองดูได้ตามโค้ด

คอมไพล์และบิวด์ (compile & build)

ทดสอบโดยเมนู “Project” > “Rebuild all” ถ้าเมนูนี้ไม่ขึ้นให้คลิก “Project” > “Reload” ก่อน จากทำการรันโปรแกรมโดย “Run” > “Run” จะเห็นอีมูเลเตอร์ “Display” เลื่อนกดคีย์ ไปที่ไอคอนโปรแกรม จากอีมูเลเตอร์ “Keyboard” แล้วกดคีย์ “EXE”

จะเห็นโปรแกรม “Geographic Cacl” ขึ้นเมนูมา

การใช้งานโปรแกรมนี้พร้อมตัวอย่างไปดูที่ลิ๊งค์นี้ได้

ซอร์สโค้ดหลัก

ท้ายสุดผมเอาซอร์สโค้ดของไฟล์ “main.cpp” มาลงให้ดูเต็มๆ จะเห็นว่าไม่มีอะไรสลับซับซ้อนมาก ง่ายๆครับ

#ifdef __cplusplus
  extern "C" {
#endif

#include "fxlib.h"
#include "string.h"
#include "stdlib.h"
#include "stdio.h"
#include "math.h"
#include "mgrs.h"
#include "tranmerc.h"
#include "utm.h"
#include "utilities.hpp"


#define MAXEDITBUFFER 21
#define NUMDECIMAL 5


void removechar(char* s, const char toremove)
{
  while(s=strchr(s, toremove))   
    memmove(s, s+1, 1+strlen(s+1));
}

int InputMGRSString(int x, int y, unsigned char*prompt, unsigned char*buffer, int bufferSize ){
   unsigned int key, edit_key, return_key = 0;
   int pos, len, len2;
   Cursor_SetFlashMode(1);   // set cursor visibility on
   pos = strlen((char*)buffer);// initially set the cursor to the end of the string

   locate(x, y);
   Print(prompt);
   len2 = strlen((char*)prompt);
   while (!return_key){
      locate(x + len2, y);
      PrintLine(buffer, 22-x);
      locate (x + pos + len2, y);
      GetKey( &key );
      edit_key = 0;
      if ((key >= 0x30 ) && (key <= 0x39)){ edit_key = key; } else if ((key >= 0x41) && (key <= 0x5A)){ edit_key = key; } else{ switch (key){ case KEY_CTRL_DEL : if ( pos > 0 ) pos--;
               len = strlen( (char*)buffer );   // get the current length of the string
               memmove( buffer+pos, buffer+pos+1, len-pos);   // shift the memory: XXYDYYY -> XXXYYY
               break;
            case KEY_CTRL_RIGHT :
               len = strlen( (char*)buffer );   // get the current length of the string
               if ( pos < len ) pos++; break; case KEY_CTRL_LEFT : if ( pos > 0 ) pos--;
               break;
            case KEY_CTRL_UP :
            case KEY_CTRL_DOWN :
               return_key = key;
               break;
            case KEY_CTRL_EXE :
            case KEY_CTRL_EXIT :
               return_key = key;
               break;
            default :
               break;
         };
      }
      if ( edit_key ){
         if ( pos < bufferSize-1 ){ buffer[ pos ] = edit_key; pos++; } } } Cursor_SetFlashMode( 0 ); // set cursor visibility off return ( return_key ); } int AddIn_main(int isAppli, unsigned short OptionNum) { unsigned char buffer[21]; char str[21], s[21]; int editresult; unsigned int key1, key2; double x, y, lat, lng, Lat, Lng; char *slat, *slong, *sangle; long zn; char hemi;//North hemi is 'N', South hemi is 'S' char vBCD[24]; unsigned char sBCD[MAXEDITBUFFER] = ""; int err; unsigned char mgrs[15]; long precision; double *A, *B, *C, *D, *E, *F, *H, *I, *Z; A = (double *)malloc(sizeof(double)); B = (double *)malloc(sizeof(double)); C = (double *)malloc(sizeof(double)); D = (double *)malloc(sizeof(double)); E = (double *)malloc(sizeof(double)); F = (double *)malloc(sizeof(double)); H = (double *)malloc(sizeof(double)); I = (double *)malloc(sizeof(double)); Z = (double *)malloc(sizeof(double)); memset(s, '-', 21); while(1){ Bdisp_AllClr_DDVRAM(); locate(0, 1); Print((unsigned char *)"Geographic Calc"); locate(0, 2); PrintLine((unsigned char*)s, 21); locate(0, 3); PrintLine("[1]:UTM to Geo", 21); locate(0, 4); PrintLine("[2]:Geo to UTM", 21); locate(1, 5); PrintLine("[3]:MGRS to Geo", 21); locate(0, 6); PrintLine("[4]:Geo to MGRS", 21); locate(1, 8); PrintLine("Select 1,2,3 or 4", 21); while (!(key1 >= 0x31) && (key1 <= 0x34)){ GetKey(&key1); } if (key1 == 0x31) { //UTM to Geo Bdisp_AllClr_DDVRAM(); locate(0, 1); Print((unsigned char *)"UTM to Geo"); locate(0, 2); PrintLine((unsigned char*)s, 21); GetAlphaDoubleData('A', A); sprintf((char*)sBCD, (char*) "%.3lf", *A); key2 = EditExpression(0, KEY_CTRL_RIGHT, 3, vBCD, (char*)sBCD, MAXEDITBUFFER - 1, "N? : ", 0x04); y = atof((char*)sBCD); SetAlphaDoubleData('A', y); GetAlphaDoubleData('B', B); sprintf((char*)sBCD, (char*) "%.3lf", *B); key2 = EditExpression(0, KEY_CTRL_RIGHT, 4, vBCD, (char*)sBCD, MAXEDITBUFFER - 1, "E? : ", 0x04); x = atof((char*)sBCD); SetAlphaDoubleData('B', x); GetAlphaDoubleData('Z', Z); sprintf((char*)sBCD, (char*) "%.3lf", *Z); key2 = EditExpression(0, KEY_CTRL_RIGHT, 5, vBCD, (char*)sBCD, MAXEDITBUFFER - 1, "UTM Zone No.? : ", 0x04); if (strchr((char*)sBCD, 0x87) != NULL) { removechar((char*)sBCD, 0x87); hemi = 'S'; } else if(strchr((char*)sBCD, 0x2D) != NULL) { removechar((char*)sBCD, 0x2D); hemi = 'S'; } else hemi = 'N'; zn = atoi((char*)sBCD); SetAlphaDoubleData('Z', zn); //Call function declared in utm.c err = Convert_UTM_To_Geodetic(zn, hemi, x, y, &lat, &lng); if (!err){ Lat = lat * RAD2DEG; Lng = lng * RAD2DEG; slat = degreetodms(fabs(Lat), NUMDECIMAL, 0x2D); if(Lat >= 0)
	        sprintf(str, "Lat= %s N", slat);
	      else
	        sprintf(str, "Lat= %s S", slat);
	      locate(1, 6);
	      Print((unsigned char*)str); 
	      locate(1, 7);
	      slong = degreetodms(fabs(Lng), NUMDECIMAL, 0x2D);
	      if (Lng >= 0)
	        sprintf(str, "Lon= %s E", slong);
	      else
	        sprintf(str, "Lon= %s W", slong);
	      Print((unsigned char*)str);      
	      free(slat);
	      free(slong);
       }
    } else if (key1 == 0x32) { //Geographic to UTM
      Bdisp_AllClr_DDVRAM(); 
      locate(0, 1);
      Print((unsigned char *)"Geo To UTM");
      locate(0, 2);
      PrintLine((unsigned char*)s, 21);

      GetAlphaDoubleData('H', H);
      sangle = degreetodms(*H, NUMDECIMAL, 0x99); 
      if(*H >= 0)
        sprintf(str, "%sN", sangle);
      else
        sprintf(str, "%sS", sangle);
      key2 = EditExpression(0, KEY_CTRL_RIGHT, 3, vBCD, (char*)str, MAXEDITBUFFER - 1, "Lat?: ", 0x04);
      lat = parsedms((char*)str);
      SetAlphaDoubleData('H', lat);
      free(sangle);

      GetAlphaDoubleData('I', I);
      sangle = degreetodms(*I, NUMDECIMAL, 0x99); 
      if(*I >= 0)
        sprintf(str, "%sE", sangle);
      else
        sprintf(str, "%sW", sangle);
      key2 = EditExpression(0, KEY_CTRL_RIGHT, 4, vBCD, (char*)str, MAXEDITBUFFER - 1, "Lon?: ", 0x04);
      lng = parsedms((char*)str);
      SetAlphaDoubleData('I', lng);
      free(sangle);

      Lat = lat * DEG2RAD;
      slat = degreetodms(fabs(Lat), NUMDECIMAL, 0x2D);
      Lng = lng * DEG2RAD;
      slong = degreetodms(fabs(Lng), NUMDECIMAL, 0x2D);
      //Call function declared in utm.c
      err = Convert_Geodetic_To_UTM(Lat, Lng, &zn, &hemi, &x, &y);
      if (!err) {
	      sprintf(str, "North= %11.3lf", y);
	      locate(1, 5);
	      Print((unsigned char*)str);      
	      sprintf(str, "East= %10.3lf", x);
	      locate(1, 6);
	      Print((unsigned char*)str);      
	      sprintf(str, "UTM Zone No= %d%c", zn, hemi);
	      locate(1, 7);
	      Print((unsigned char*)str); 
      }
      free(slat);
      free(slong);      
    } else if (key1 == 0x33) { //MGRS to Geo
      Bdisp_AllClr_DDVRAM(); 
      locate(0, 1);
      Print((unsigned char *)"MGRS to Geo");
      locate(0, 2);
      PrintLine((unsigned char*)s, 21);

      memset(mgrs, 0, 16);
      editresult = InputMGRSString( 1, 3, "MGRS?", buffer, sizeof(buffer) );
      if (editresult) {
        memcpy(mgrs, buffer, 15);
        //Call function that declared in mgrs.c
        err = Convert_MGRS_To_Geodetic((char*)mgrs, &lat, &lng);
        if (!err){
          Lat = lat * 180.0 / PI;
          slat = degreetodms(fabs(Lat), NUMDECIMAL, 0x2D);
          Lng = lng * 180.0 / PI;
          slong = degreetodms(fabs(Lng), NUMDECIMAL, 0x2D);
          if(Lat >= 0)
            sprintf(str, "Lat= %s N", slat);
          else
            sprintf(str, "Lat= %s S", slat);
          locate(1, 4);
          Print((unsigned char*)str);      
          if(Lng >= 0)
            sprintf(str, "Lon= %s E", slong);
          else
            sprintf(str, "Lon= %s W", slong);
          locate(1, 5);
          Print((unsigned char*)str);        
          free(slat);
          free(slong);
        } 
      }
    } else if (key1 == 0x34) { //Geographic to MGRS
      Bdisp_AllClr_DDVRAM(); 
      locate(0, 1);
      Print((unsigned char *)"MGRS to Geo");
      locate(0, 2);
      PrintLine((unsigned char *)s, 21);

      memset(sBCD, 0, MAXEDITBUFFER);
      key2 = EditExpression(0, KEY_CTRL_RIGHT, 3, vBCD, (char*)sBCD, MAXEDITBUFFER - 1, "Lat?:", 0x04);
      lat = parsedms((char*)sBCD);
      lat = lat * DEG2RAD;
      memset(sBCD, 0, MAXEDITBUFFER);
      key2 = EditExpression(0, KEY_CTRL_RIGHT, 4, vBCD, (char*)sBCD, MAXEDITBUFFER - 1, "Lon?:", 0x04);
      lng = parsedms((char*)sBCD);
      lng = lng * DEG2RAD;

      //Call function that declared in mgrs.c
      err = Convert_Geodetic_To_MGRS(lat, lng, 5, (char*)mgrs);
      if (!err){
        sprintf(str, "MGRS= %s", mgrs);
        locate(1, 5);
        Print((unsigned char*)str);        
      }     
    }
    GetKey(&key1);
  } //while (1)
  free(A);
  free(B);
  free(C);
  free(D);
  free(E);
  free(F);
  free(H);
  free(I);
  free(Z);
  return 1;
}

#pragma section _BR_Size
unsigned long BR_Size;
#pragma section

#pragma section _TOP

int InitializeSystem(int isAppli, unsigned short OptionNum)
{
    return INIT_ADDIN_APPLICATION(isAppli, OptionNum);
}

#pragma section

#ifdef __cplusplus
}
#endif

การนำโปรแกรมไปติดตั้งบนเครื่องคิดเลข

เมื่อคอมไพล์และบิวด์แล้วจะได้ไฟล์ G1a ก็สามารถนำไปใช้บนเครื่องคิดเลขได้ วิธีการเอาโปรแกรมไปใส่เครื่องคิดเลขสามารถทำได้หลายวิธี ดูโพสต์เก่าแสดงวิธีการได้ตามลิ๊งค์นี้

สรุป

การพัฒนาโปรแกรมสำหรับเครื่องคิดเลขไม่มีอะไรยากเย็นมากนัก มีความรู้ภาษาซีขั้นพื้นฐานแบบผมก็ทำได้ เพียงแต่ถ้าต้องการคำนวณอะไรซับซ้อนอาจจะต้องหาไลบรารีที่ท่านอื่นได้พัฒนาเขียนไว้ แต่เครื่องมือพัฒนานี้มีข้อจำกัดอยู่บ้างเช่นคอมไพเลอร์นี้สนับสนุน c standard library ได้ไม่ครบทุกอย่าง ตัวอย่างเช่นฟังก์ชั่น strtok() ที่ตัดสตริงออกตามตัวคั่นก็ไม่สนับสนุน ดังนั้นการเลือกไลบรารีที่คนอื่นได้ทำไว้ก็ต้องพิจารณาส่วนนี้ด้วย ส่วนการรับข้อมูลจากผู้ใช้ สำหรับผมแล้วที่มีอยู่ตอนนี้เกือบจะเพียงพอ เพราะงานสำรวจก็จะมีแค่ป้อนมุม ระยะทาง เป็นหลัก ติดตามกันต่อไปครับ

ติดปีกเครื่องคิดเลขเทพ Casio fx 9860G II SD ด้วยโปรแกรมภาษาซีบน AddIn ตอนที่ 2 โปรแกรมคำนวณค่าพิกัดจุดศูนย์กลางวงกลม (Circle Center Calc)

ติดปีกเครื่องคิดเลขเทพ Casio fx 9860G II SD ด้วยโปรแกรมภาษาซีบน AddIn ตอนที่ 2 โปรแกรมคำนวณค่าพิกัดจุดศูนย์กลางวงกลม (Circle Center Calc)

จุดศูนย์กลางวงกลมนั้นสำคัญไฉน

ในงานสำรวจสำหรับการก่อสร้างเช่นเข็มเจาะ ในขั้นตอนแรกช่างสำรวจจะวางตำแหน่งจุดศูนย์กลางของเสาเข็ม จากนั้นจะวัด offset อย่างน้อยสามด้านตั้งฉากแล้วตอกเหล็กเช่นเหล็กข้ออ้อยลงไปเป็นหมาย ขั้นตอนต่อไปจะปักปลอกเหล็ก (Casing) ในชั้นดินอ่อนเพื่อกันดินทลายตัวลง ในขั้นตอนนี้ช่วงการปักปลอกเหล็กจะมีการวัดระยะจากหมายที่ offset ไว้เพื่อให้ปลอกเหล็กอยู่ในตำแหน่งทั้งทางราบและทางดิ่ง เมื่อปลอกเหล็กลงไปสุดแล้ว เพื่อความมั่นใจว่าได้ตำแหน่งที่ถูกต้องแล้ว จะสำรวจเพื่อเก็บค่าพิกัดคือจุดศูนย์กลางของปลอกเหล็ก แต่คำถามคือจะวัดค่าพิกัดจุดศูนย์กลางของปลอกเหล็กวงกลมได้อย่างไร ในทางปฏิบัติบางครั้งจะใช้ตะแกรงเหล็กปิดปากปลอกเหล็ก แล้วช่างสำรวจจะใช้ตลับเมตรวัดระยะครึ่งหนึ่งของเส้นผ่าศูนย์กลางสองด้านตั้งฉากกันแล้วทำเครื่องหมายไว้บนกระดานไม้ จากนั้นจึงจะวัดค่าพิกัดโดยการตั้งเป้าปริซึม ถ้าใช้มินิปริซึม ตั้งต่ำจะให้ค่าที่ถูกต้องดียิ่งขึ้น แต่ปัญหาคือตอนใช้ตลับเมตรวัดกึ่งกลาง (เส้นที่ผ่านจุดศูนย์กลางคือเส้นที่ยาวที่สุด) เพื่อหาตำแหน่งศูนย์กลางนั้นใช้เวลาพอสมควรและมี error จากการคาดคะเน

วิธีต่อไปที่จะนำเสนอเพื่อทำให้การวัดค่าพิกัดทำได้เร็วขึ้น จะใช้สูตรทางคณิตศาสตร์มาช่วย โดยการวัดค่าพิกัดสามจุดโดยแบ่งให้ระยะห่างแต่ละจุดเท่าๆกัน จากนั้นช่างสำรวจจะใช้เครื่องคิดเลข คำนวณหาค่าพิกัดจุดศูนย์กลาง วิธีการนี้จะใช้เวลารวดเร็วกว่าวิธีแรกพอสมควร ในความเป็นจริงวิธีนี้อยู่บนสมมติฐานว่าปลอกเหล็กต้องไม่บุบเบี้ยว เมื่อได้ค่าพิกัดจุดศุนย์กลางมาแล้วจะนำมาเทียบกับค่าพิกัดที่ได้จากแบบ drawing ถ้าพบว่าค่าต่างกันมากเกินที่กำหนดไว้ จะต้องถอนปลอกเหล็กและทำการปักใหม่

คำนวณได้ทั้ง 2D และ 3D

โปรแกรมที่ผมเขียนนั้นคำนวณได้ทั้ง 2D (ไม่ต้องป้อนค่าระดับ) และ 3D (ป้อนค่าระดับไปด้วย) ส่วนสูตรนั้นถ้าคำนวณแบบ 3D นั้นค่อนข้างซับซ้อน ผมใช้วิธีทางลัดคือไปดูโค้ดที่มีคนเขียนไว้ในอินเทอร์เน็ต โค้ดเดิมเป็น Visual Basic ผมแปลงเป็นโค้ดภาษาซี ส่วนการคำนวณ 2D นั้นซับซ้อนน้อยกว่ามาก ถ้าสนใจสูตรก็สามารถดูจากโค้ดของผมได้

int calcCircleCenter3D(double Ya, double Xa, double Za, 
                       double Yb, double Xb, double Zb, 
                       double Yc, double Xc, double Zc, 
                       double *YCen, double *XCen, double *ZCen, double *Radius){
    double AB, BC, AC;
    double ABi, ABj, ABk, ACi, ACj, ACk, CDi, CDj, CDk, Ni, Nj, Nk;
    double cosBAC, sinBAC;
    double AD, CD, Xd, Yd, Zd;
    double X2e, Y2e, Z2e;

	//if the two points are on the same coordinates stop and return.
    if (((Xa == Xb) && (Ya == Yb)) || ((Xa == Xc) && (Ya == Yc)) 
     || ((Xb == Xc) && (Yb == Yc)))
      return 0;

    //Xa = 80.779; Ya = 90.198; Za = 23.567;
    //Xb = 78.334; Yb = 66.990; Zb = 25.567;
    //Xc = 45.345; Yc = 67.623; Zc = 34.123;
    // Answer Radius = 21.778
    // N Center = 80.840, E Center = 61.890, Z Center = 29.037

    //Lengths of AB, AC, AC
    AB = sqrt(pow(Xa - Xb, 2) + pow(Ya - Yb, 2) + pow(Za - Zb, 2));
    BC = sqrt(pow(Xb - Xc, 2) + pow(Yb - Yc, 2) + pow(Zb - Zc, 2));
    AC = sqrt(pow(Xa - Xc, 2) + pow(Ya - Yc, 2) + pow(Za - Zc, 2));
    //Direction cosines of AB(ABi,ABj,ABk)
    ABi = (Xb - Xa) / AB;
    ABj = (Yb - Ya) / AB;
    ABk = (Zb - Za) / AB;
    //Direction cosines of AC(ACi,ACj,ACk)
    ACi = (Xc - Xa) / AC;
    ACj = (Yc - Ya) / AC;
    ACk = (Zc - Za) / AC;
    //Cosine of angle BAC
    cosBAC = (pow(AB, 2) + pow(AC, 2) - pow(BC, 2)) / (2 * AB * AC);
    AD = cosBAC * AC;
    CD = sqrt(pow(AC, 2) - pow(AD, 2));
    //Position of point D, which is C projected normally onto AB
    Xd = Xa + (AD * ABi);
    Yd = Ya + (AD * ABj);
    Zd = Za + (AD * ABk);
    //Direction cosines of CD(Cdi,CDj,CDk)
    CDi = (Xc - Xd) / CD;
    CDj = (Yc - Yd) / CD;
    CDk = (Zc - Zd) / CD;
    //Direction cosines of normal to AB and CD
    //to be used for rotations of circle centre
    Ni = (ABk * CDj) - (ABj * CDk);
    Nj = (ABi * CDk) - (ABk * CDi);
    Nk = (ABj * CDi) - (ABi * CDj);
    //# Diameter of circumscribed circle of a triangle is equal to the
    //the length of any side divided by sine of the opposite angle.
    //This is done in a coordinate system where X is colinear with AB, Y is // to CD,
    //and Z is the normal (N) to X and Y, and the origin is point A
    //  R = D / 2
    sinBAC = sqrt(1 - pow(cosBAC, 2));
    *Radius = (BC / sinBAC) / 2;
    //Centre of circumscribed circle is point E
    X2e = AB / 2;
    Y2e = sqrt((*Radius) * (*Radius) - X2e * X2e);
    Z2e = 0;
    //Transform matrix
    //                   Rotations                 Translations
    //           ——————————————————————————————————————————————
    //              ABi  ,   ABj  ,  ABk                 Xa
    //              CDi  ,   CDj  ,  CDk                 Ya
    //               Ni  ,    Nj  ,   Nk                 Za
    //           ——————————————————————————————————————————————
    //Position of circle centre in absolute axis system
    *XCen = Xa + (X2e * ABi) + (Y2e * CDi) + (Z2e * Ni);
    *YCen = Ya + (X2e * ABj) + (Y2e * CDj) + (Z2e * Nj);
    *ZCen = Za + (X2e * ABk) + (Y2e * CDk) + (Z2e * Nk);
    return 1;
}

int calcCircleCenter2D(double N1, double E1, double N2, double E2, 
                       double N3, double E3,
                       double *Nc, double *Ec, double *Radius){
    double midN12, midE12, midN23, midE23;
    double k, l, p, q, r, s;
    
    //1 23.432m 78.234m
    //2 45.323m 98.765m
    //3 67.334m 66.999m
    //Answer R=22.907, N Center = 75.876, E Center = 46.217

    if (((N2 == N1) && (E2 == E1)) ||
       ((N2 == N3) && (E2 == E3)) ||
       ((N1 == N3) && (E1 == E3)))
      return 0;

    midN12 = (N1 + N2) / 2.0;
    midE12 = (E1 + E2) / 2.0;
    midN23 = (N2 + N3) / 2.0;
    midE23 = (E2 + E3) / 2.0;


    k = atan((E2-E1)/(N2-N1)) + PI / 2.0;
    l = atan((E2-E3)/(N2-N3)) + PI / 2.0;
    p = 1.0 / tan(k);
    q = 1.0 / tan(l);
    r = tan(k);
    s = tan(l);
    *Ec = ((midE23*q)-(midE12*p)+midN12-midN23)/(q-p);
    *Nc = ((midN23*s)-(midN12*r)+midE12-midE23)/(s-r);
    *Radius = sqrt((E1-*Ec)*(E1-*Ec) + (N1-*Nc)*(N1-*Nc));
    return 1;
}

ดาวน์โหลดโปรแกรม

ไปดาวน์โหลดโปรแกรมได้ที่หน้าดาวน์โหลด  หาโปรแกรมชื่อ Circle Center Calc จะได้ไฟล์มาชื่อ “ARCCENPT.g1a” วิธีการติดตั้งสามารถทำได้หลายวิธี วิธีแรกผมเขียนไว้แล้วที่ตอนที่ 1 ด้วยการ  copy โปรแกรมลง SD card แล้วถ่ายเข้าเครื่องคิดเลขอีกที วิธีที่ 2 ใช้โปรแกรม FA-124 ของ casio

การใช้งาน FA-124

โปรแกรม FA-124 สามารถไปดาวน์โหลดได้ที่ ลิ๊งค์ นี้ จากนั้นแตก zip แล้วทำการติดตั้งง่ายๆ เป็นโปรแกรมเล็กๆ  ผมเข้าใจว่าช่วงติดตั้งน่าจะมีการติดตั้งไดรเวอร์ของ casio ลงไปด้วย เพราะหลังจากนั้นผมเปิดโปรแกรม FA-124 แล้วเอาสาย USB  มาเสียบเชื่อมต่อเครื่องคิดเลขกับคอมพิวเตอร์จะมองเห็นได้ทันที  ที่เครื่องคิดเลขกดคีย์บอร์ดปุ่ม “F1” เพื่อจะเข้าโหมดการโอนข้อมูล (Data Transfer) คำเตือนการเสียบสาย USB นี้ไม่ควรจะนานเกิน 15 นาที เพราะจอภาพเครื่องคิดเลขจะเสื่อมสภาพได้ 

ส่วนหน้าตาโปรแกรม FA-124 ก็ประมาณนี้

จากนั้นมองที่หน้าต่างด้านขวามือคลิกที่ไอคอนที่วงด้วยหมายเลข “1” จากนั้นมาคลิกขวาที่วงด้วยหมายเลข “2” ที่คำว่า Default เลือกเมนู “Import

จะมีไดอะล๊อกบ็อกซ์ ให้เลือกโฟลเดอร์และไฟล์ ไปที่ไฟล์ “ARCCENPT.g1a” ที่เก็บไว้ในเครื่องคอมพิวเตอร์ ตรง Files of type ต้องเลือกเป็น “G1A File (*.g1a)

จะเห็นไฟล์ “ARCCENPT.g1a” เข้ามาใต้ลิสต์ของคำว่า “Default” ดังรูป ที่หน้าต่างด้านซ้ายให้คลิกที่ไอคอนรูปเครื่องคิดเลข ตามที่ผมวงไว้หมายเลข “1” โปรแกรมจะอ่านไฟล์จาก Storage memory ของเครื่องคิดเลข มาแสดงใต้คำว่า “User1” จากนั้นลากไฟล์ “ARCCENPT.g1a” มาวางที่คำว่า User1 (เผอิญเครื่องคิดเลขผมมีไฟล์นี้อยู่แล้ว) โปรแกรมจะถามว่าต้องการทับหรือไม่ตอบ “Yes” 

ก็เป็นอันว่าขั้นตอนเกือบจะเสร็จ ตอนนี้โปรแกรมนี้จะไปอยู่ใน Storage memory ของเครื่องคิดเลขเรียบร้อย ไม่ลืมว่าขนาดของเมมโมรีนี้ 1.5 MB โปรแกรมขนาดนี้สามารถวางได้ประมาณ 30-40 โปรแกรม ซึ่งเหลือเฟือมาก จากนั้นคลิกที่ไอคอนเพื่อทำการ disconnect และอย่าลืมดึงสาย USB ออก

ทดสอบการใช้โปรแกรมคำนวณจุดศูนย์กลางวงกลม (Circle Center Calc)

ที่เครื่องคิดเลขกดคีย์ “MENU”  จากนั้นเลื่อนลงมาที่โปรแกรมดังรูปด้านล่าง

จะเห็นเมนูของโปรแกรม ซึ่งมีให้เลือก 3 โปรแกรมย่อย ส่วนโปรแกรมที่ 3 นั้นเป็นของแถม

    1. 3 Points in 3D  (Circle Center in 3D) – คำนวณหาค่าพิกัดและค่าระดับจุดศูนย์กลางวงกลม โดยค่าที่ป้อน 3 จุดต้องประกอบด้วยค่าพิกัดและค่าระดับ (X, Y, Z)
    2. 3 Points in 2D (Circle Center in 2D) – คำนวณหาค่าพิกัดของจุดศูนย์กลางวงกลม โดยค่าที่ป้อน 3 จุด เฉพาะค่าพิกัดทางราบเท่านั้น
    3. 2 Angles & 1 Dist – คำนวณหาค่าพิกัดของจุดศูนย์กลางวงกลม โดยวัดมุมสองมุมที่ขอบของวงกลมและวัดระยะราบที่ขอบวงกลมตรงจุดแบ่งครึ่งระหว่างขอบวงกลม อธิบายไม่เห็นภาพค่อยดูรูปอีกทีภายหลัง

คำนวณหาจุดศูนย์กลางวงกลมแบบ 3D (Circle Center in 3D)

ที่เมนูกดเลข “1” ป้อนค่าพิกัด N, E  ตอนถามค่า Z คือป้อนค่าระดับ โดยที่จุดที่เก็บค่าพิกัดและระดับมามี 3 จุด จุดไม่ต้องเรียงตามลำดับเส้นรอบวงก็ได้

จากนั้นกด “EXE” เพื่อคำนวณหาค่าพิกัดและค่าระดับของจุดศูนย์กลาง ผลลัพธ์ดังรูปด้านล่าง

คำนวณหาจุดศูนย์กลางวงกลมแบบ 2D (Circle Center in 2D)

ที่เมนูกดเลข “2” ทดสอบป้อนตัวเลขดังนี้ ป้อนค่าพิกัดจุดที่ 1, 2 และ 3

กด “EXE”  จะได้ผลลัพธ์ดังนี้

คำนวณหาจุดศูนย์กลางวงกลมแบบวัดมุมและระยะทาง

ในบางครั้งการเก็บ As-built เช่นเสากลม เราไม่สามารถวัดค่าพิกัดของศูนย์กลางได้ จึงต้องใช้วัดทางอ้อมและใช้สูตรทางคณิตศาสตร์ช่วย จากรูปด้านล่างจะวัดมุมที่ขอบด้านซ้ายและขอบด้านขวาป้อนเข้าโปรแกรม จากนั้นโปรแกรมจะให้เปิดมุมมาที่ตรงกลาง (ถ้าการวัดมุมมีความแม่นยำ มุมที่ตรงกลางนี้จะผ่านจุดศูนย์กลางวงกลมพอดี) แล้วทำการวัดระยะทาง สุดท้ายโปรแกรมจะคำนวณค่าพิกัดจุดศูนย์กลางให้

ที่เมนูหลักกดคีย์เลข “3” ทดสอบโปรแกรมด้วยการป้อนข้อมูลดังนี้ โดยที่ BS = Back Station คือจุดเป้าหลัง ส่วน STA คือ Station  จุดตั้งกล้องนั่นเอง

จากนั้นโปรแกรมจะให้ set มุมของกล้องไปที่กึ่งกลางวงกลม จากนั้นวัดระยะทาง

และป้อนค่าระยะทาง สุดท้ายโปรแกรมจะคำนวณหาค่าพิกัดจุดศูนย์กลางวงกลมและรัศมีวงกลมมาด้วย

สรุป

โปรแกรมนี้เป็นโปรแกรมลำดับที่ 2 ผมหวังว่าคงเป็นประโยชน์ในแวดวงสำรวจบ้านเราบ้างไม่มากก็น้อย โปรแกรมต่างๆเหล่านี้ จะถูกปรับปรุงแก้ไขในอนาคต ท่านผู้อ่านอาจจะสังเกตเห็นว่า เวลาเรียกโปรแกรมมาอีกครั้ง จะไม่เรียกค่าเดิมที่เคยป้อนไว้ ทำให้ต้องป้อนใหม่ทุกครั้ง ในตอนนี้ผมไม่สามารถอ่านหรือเขียนค่าลงตัวแปรอักษร A-Z ได้ เพราะ casio ไม่ได้เขียนเอกสารไว้ (undocumented) แต่สักพักผมคิดว่าคงหาทางได้ เพราะมีคนทำ reverse engineering เครื่องคิดเลขรุ่นนี้พอสมควร แต่ละโปรแกรมที่ใช้สามารถเก็บค่าที่ป้อนเข้าตัวแปรตัวอักษร A-Z เวลาเรียกโปรแกรมมาใช้อีกครั้งถ้าค่าในตัวแปรไม่ได้ถูกทับไปก็สามารถกด “EXE” ผ่านไปได้เลย ติดตามกันตอนต่อไปครับ

 

 

ติดปีกเครื่องคิดเลขเทพ Casio fx 9860G II SD ด้วยโปรแกรมภาษาซีบน AddIn ตอนที่ 1 โปรแกรมแปลงพิกัดภูมิศาสตร์ (Geographic Calc)

ติดปีกเครื่องคิดเลขเทพ Casio fx 9860G II SD ด้วยโปรแกรมภาษาซีบน AddIn ตอนที่ 1 โปรแกรมแปลงพิกัดภูมิศาสตร์ (Geographic Calc)

รอคอยมานานแต่ไม่รู้ว่าสิ่งที่รอคอยมันคืออะไร

สำหรับคนที่เคยเขียนโปรแกรมลงเครื่องคิดเลขคาสิโอ ถ้าเคยเขียนโปรแกรมมิ่งบนระบบใหญ่ๆมาก่อนเช่นจาวา ซี หรือไพทอน จะรู้สึกว่าโดนมัดมือมัดเท้าทำอะไรไม่ถนัด ภาษาเบสิคของคาสิโอ (basic casio) ก็ดูจะหน่อมแน๊ม ตัวแปรก็จำกัดไม่กี่ตัว เมมโมรีสำหรับเก็บโปรแกรมก็น้อยนิดเดียว เขียนฟังก์ชั่นก็ไม่ถนัด ก็เลยได้แต่โปรแกรมอะไรที่ง่ายๆ ใช้ตัวแปรไม่มาก  แต่ไม่นานที่ผ่านมา เผอิญไปค้นหาในอินเทอร์เน็ต โดยที่หาโปรแกรมแบบ basic casio บนเครื่องคิดเลขระดับเทพในวงการสำรวจบ้านเราคือ fx-9860G II SD ที่ผมเคยร่ำๆจะซื้อหามาใช้หลายเที่ยวแต่ติดที่ความรู้สึกว่าแพงไปนิดเมื่อเทียบกับ fx-5800P ที่ใช้อยู่ โปรแกรมที่ค้นหาก็ไม่ได้มีอะไรมากแค่เอามาเปรียบเทียบอัลกอริทึ่มที่ผมมีอยู่ บังเอิญไปเจอว่าการเขียนโปรแกรม AddIn ต้องใช้ SDK (Software Development Kit) ที่ต้องใช้ภาษาซี ก็เลยสะดุดตา ลองค้นเข้าไปอีกหน่อย ก็พออนุมานได้ว่าสามารถเขียนโปรแกรมอะไรก็ได้แบบ AddIn ให้กับเครื่องคิดเลข ที่ไม่ติดจำกัดด้านโครงสร้างภาษาเพราะใช้ภาษาซี ที่คาสิโอเตรียมคอมไพเลอร์ ไลบรารีเครื่องมือพัฒนาโปรแกรมด้านภาษาซีมาพอประมาณ สุดท้ายผมก็เลยมานึกว่า ก่อนหน้านี้ผมคงต้องรอคอยอะไรบางอย่างมานานแต่ไม่รู้ว่าคืออะไร จนกระทั่งได้เจอสิ่งนี้ 🙂 มันใช่เลย ถึงแม้ตอนเจอดูเหมือนผมจะมาสายไปบ้างก็ตาม

อารมณ์มัน Back to school คือความสนุกสนานได้กลับมาอีกครั้ง ผมเคยพูดถึงว่าเครื่องรุ่นเทพสมัยแต่ก่อนคือ Casio fx-880P ที่เขียนภาษาเบสิค(แบบกำกับด้วยหมายเลขบรรทัด) เวลาพกเครื่องคิดเลขรุ่นนี้ ถ้าเอาเท่ห์ก็เอาเหน็บที่กระเป๋าหลังของกางเกงยีนส์ แต่บ่อยครั้งที่ลืมนั่งทับจนเครื่องพัง ที่สามารถเขึยนโปรแกรมได้พอประมาณ แต่ปัญหาคือเมมโมรีที่จัดเก็บโปรแกรมมาน้อย ถึงแม้สามารถซื้อแรมขนาด 32KB มาเพิ่มได้ก็ตาม เคยเขียนโปรแกรม Traverse เล่นๆลงไปเขมือบเมมโมรีไปเกินครึ่ง จนต้องลบโปรแกรมอื่นทิ้งไป ถึงจะใส่ได้ การจะโอนโปรแกรมไปหาเครื่องอื่นก็แสนยากเย็นกระไร เพราะต้องหาสายลิ๊งค์ สมัยก่อนไม่มีอีเบย์ ก็เลยใครอยากได้โปรแกรมอะไรก็ต้องพิมพ์เองสดๆลงไปในเครื่อง ประมวลผลดูผิดตรงไหนก็ตามไปแก้ สำหรับเครื่องคิดเลขในทศวรรษนี้ไม่ต้องทำแบบนั้นแล้วครับมีสายลิ๊งค์มาให้ หรือรุ่น fx-9860G II SD ก็มี SD card มาให้สามารถโอนโปรแกรมให้กันได้สะดวก

รู้จัก Casio fx-9860G II SD

เครื่องรุ่นนี้ออกเก็บเกี่ยวความสำเร็จตามหลัง fx-9750G โดยที่ผลิตออกมาสองรุ่น รุ่นแรกเคสสีเงินส่วนคีย์บอร์ดสีน้ำเงิน ใช้ CPU SH3 รุ่นที่สองเป็นรุ่นล่าสุดเคสสีน้ำเงินเข้มส่วนคีย์บอร์ดสีขาวใช้ CPU SH4a มีเมมโมรีใช้งาน 62 KB (ขนาดน่าสงสารมาก) มีพื้นที่จัดเก็บโปรแกรม (storage memory) เป็น 1.5 MB ที่ผมประเมินดูโปรแกรมขนาดกลางๆสำหรับเครื่องคิดเลขขนาด น่าจะประมาณ 50000 Bytes ถ้าพื้นที่จัดเก็บโปรแกรม 1.5 MB น่าจะใส่โปรแกรมได้ไม่ต่ำกว่า 30 โปรแกรมเลยทีเดียว โดยรวมการประมวลผลเร็วครับ ตามความเข้าใจผมตัว OS ของรุ่นนี้น่าจะกินเมมโมรีไม่มากนัก ที่ผมชอบอีกอย่างคือพื้นที่การแสดงผล ถ้าเอาแบบแสดงตัวอักษรอย่างเดียว ได้ทั้งหมด 8 แถว (row) และแถวละ 21 ตัวอักษร ถามว่าพอไหม ก็ตอบได้ว่าพอครับแบบเบียดเสียดไปหน่อย แต่ยังโอเคกว่ารุ่น fx-5800P ที่มีแค่ 2 บรรทัด แต่อย่างไรก็ตามยังมีโหมดกราฟฟิคมีความละเอียดกว้าง x สูง = 127 x 63 สำหรับวาดกราฟ ก็มาดูขนาดโปรแกรมแปลงพิกัดภูมิศาสตร์ของผม UTMGeo.g1a คือโปรแกรมที่คอมไพล์และบิวท์ (compile & build) มาแล้ว ขนาดประมาณตามรูป 78760 ไบต์ ส่วนโปรแกรมสองโปรแกรมด้านบน (ARCCENPT.g1a และ INTERSCT.g1a) ผมก็เขียนเหมือนกันแต่ขนาดเล็กกว่า

ตามล่าเครื่องมือพัฒนาโปรแกรม SDK (Software Development Kit)

เมื่อรู้ว่าใช้ภาษาซีเขียนได้ ผมก็ตามหาเครื่องมือเพื่อพัฒนาโปรแกรม แต่เนื่องจากรุ่นนี้ออกมาได้หลายปีร่วมๆสิบปีแล้ว (ออกมาปี 2009) เข้าไปในเว็บไซต์ของคาสิโอแต่กลับพบกับผิดหวัง ไม่มีลิ๊งค์ให้ดาวน์โหลด (Link ขาดไปนาน) ทั้งๆที่คู่มือต่างๆเช่นการใช้งาน SDK, ไลบรารี ต่างๆก็ยังมีให้ดาวน์โหลดปกติแต่เครื่องมือพัฒนาโปรแกรมตั้งแต่เขียนโปรแกรม คอมไพล์ บิวท์ กลับหายไป สุดท้ายต้องลงใต้ดินตามหา จนเจอยังมีคนปล่อยให้ดาวน์โหลดได้ แต่ต้องใช้ระยะเวลาความพยายามเป็นอาทิตย์เหมือนกัน ผมจะไม่แสดงลิ๊งค์นี้เพราะอาจติดขัดกับลิขสิทธิ์ของคาสิโอได้ (ถ้าใครอยากได้ก็ขอมาหลังไมค์ละกันครับ) เมื่อได้มาแล้วก็มาลงบนคอมพิวเตอร์โน๊ตบุ๊ค วินโดส์ 10 และจอของผมเป็น 4K ก็ไม่ได้มีปัญหาอะไร สามารถเปิดโปรแกรมมาได้ปกติ เครื่องมือพัฒนาโปรแกรมเรียกว่า integrated development environment (IDE) ตั้งแต่ปล่อยมาปี 2007 Casio ไม่เคยอัพเดทอีกเลย เครื่องมือนี้ใช้คอมไพเลอร์ของ Renesas SHC ซึ่งอิงภาษาซีของ ANSI C standard (C89)

เริ่มแรกใช้งานกับปัญหาที่ประสบ

แต่พอเริ่มคอมไพล์โปรแกรมทดสอบเล็กๆดูกลับมีปัญหาเล็กๆน้อยๆ เช่น ** L2011 (E) Invalid parameter specified in option “input” : “”C:\Program Files (x86)\CASIO\fx-9860G SDK\OS\FX\lib\setup.obj”” วิธีการแก้ไข ให้ถอนโปรแกรมไปติดตั้งใหม่ แต่ตอนติดตั้งให้ติดเลือกติดตั้งที่รากของไดรว์ C: (ไม่เลือกดีฟอลต์คือติดตั้งลง C:\Program fils(x86) เพราะโปรแกรมนี้รุ่นเก่าไม่ชอบ path ทีมีตัว space) ปัญหาเล็กๆน้อยๆ เหล่านี้พอหาได้ตามฟอรั่มที่เกี่ยวข้องกับเครื่องคิดเลขของคาสิโอครับ แต่แล้วเส้นทางนี้ไม่ได้โรยด้วยกลีบกุหลาบ ปัญหาที่นึกไม่ถึงคือ user interface ทางคาสิโอไม่ได้เตรียม document ไว้ให้เลย พวกสิ่งเหล่านี้ได้แก่การ input แม้กระทั่งการอ่านข้อมูลจากตัวแปรตัวอักษร A-Z ก็ไม่ได้ทำไว้ ข้อมูลเป็นตัวเลข เป็นสตริง ผมอาศัยไปอ่านตามฟอรั่มที่มีหลายคน hack ไว้ ตรงนี้เสียเวลาไปหลายสิบวันกว่าจะแกะและจูนได้

โปรแกรมแรกเป็นกรณีศึกษา -เขียนโปรแกรมแปลงพิกัดภูมิศาสตร์ (Geographic Calc)

จั่วหัวไปเหมือนโปรแกรมจะใหญ่โต แต่เปล่าเลยผมเคยเขียนโปรแกรมแปลงพิกัดระหว่าง UTM และค่าพิกัดภูมิศาสตร์ (Geographic) บน fx 5800P ก็ไม่ได้ยากเย็นอะไรมากเพราะการแปลงพิกัดเหลานี้มีสูตรที่แน่นอนถึงแม้สูตรจะยาวไปหน่อยก็ตาม แต่ก็ไม่ได้ยากเย็นอะไร ผมมีเรื่องการแปลงพิกัดค้างคาอยู่นิดหนึ่งคือในโปรแกรม Surveyor Pocket Tools ในส่วนการแปลงพิกัดจะสังเกตเห็นว่าไม่มีระบบพิกัด MGRS (Military Grid Reference System) ซึ่งสำหรับพลเรือนอย่างพวกเรา คงไม่มีโอกาสได้ใช้งานเท่าไหร่นัก ผมค้นดูไลบรารีที่สามารถแปลงพิกัดได้ตาม github ไปพบมาอันหนึ่งชื่อ mrgs พัฒนาโดย Howard Butler ซึ่งไลบรารีที่เขียนไว้ไม่ใหญ่มาก นอกจากแปลงพิกัด Transverse Mercator ได้ยังแปลง MGRS ได้ และโปรแกรมในรุ่นนี้ผมขอจำกัดแค่ดาตั้ม “WGS84

ส่วนผมเองต้องบอกก่อนว่าไม่ใช่แฟนพันธุ์แท้ภาษาซี พอจะเขียนได้แต่ไม่ได้เก่งกาจนัก ดังนั้นโปรแกรมที่เขียนขึ้นมาอาจจะมีส่วนใดส่วนหนึ่งที่เยิ่นเย้อไปบ้าง

ลอง Military Grid Reference System (MGRS) ดูสักตั้ง

ในส่วนระบบพิกัด MGRS ซึ่งผมเห็นว่ามันแปลกดีที่ระบบนี้เอาตัวอักษรและตัวเลขแบ่งเป็นกริดมาขมวดรวมกันก็กลายเป็นค่า coordinate ได้ ลองดูรูปแบบดังตัวอย่างด้านล่าง

    • 46Q …………………GZD only, precision level 6° × 8° (in most cases)
    • 46QFJ ……………….GZD and 100 km Grid Square ID, precision level 100 km
    • 46QFJ 1 6 ……………precision level 10 km
    • 46QFJ 12 67 ………….precision level 1 km
    • 46QFJ 123 678 ………..precision level 100 m
    • 46QFJ 1234 6789 ………precision level 10 m
    • 46QFJ 12345 67890 …….precision level 1 m

ในเบื้องต้นผมขอใช้ไลบรารีนี้เพื่อเป็นกรณีศึกษา เพื่อลองเขียนโปรแกรมแปลงพิกัด MGRS ดูบ้าง ซึ่งระบบพิกัดนี้เครื่องคิดเลข fx-5800P ทำไม่ได้แน่นอนครับเพราะเครื่องคิดเลขไม่มีระบบรับข้อมูลเป็นสตริง (ยาวสุดประมาณ 15 ตัวอักษร) นอกจากไม่มีระบบรับข้อมูลสตริงแล้ว ไม่มีไลบรารีตัดสตริงออกมาเป็นท่อนๆ

เส้นทางและระยะเวลาในการพัฒนา

เนื่องจากโปรแกรมแปลงพิกัดนี้เป็นโปรแกรมเล็กๆ ไลบรารีที่ผมไปเอามาใช้จาก github ก็ใช้ง่ายสะดวก แต่ติดปัญหาที่ผมบอกไปแล้วคือระบบติดต่อผู้ใช้รับข้อมูลตัวเลข ตัวอักษรทาง casio ไม่ได้เปิดเผยเอกสาร บางอย่างต้องเขียนเองเช่นการรับข้อมูลเป็นสายสตริงเช่นค่าพิกัด MGRS (ตัวอย่างเช่น “18SVK8588822509”) บางอย่างไปหาตามฟอรั่ม เลยใช้เวลาสำหรับโปรแกรมแรกนี้ประมาณหนึ่งอาทิตย์กว่าๆ ในตอนนี้โปรแกรมเล็กๆนี้ก็เสร็จพอใช้งานได้แล้ว คุณสมบัติของโปรแกรมนี้คือค่าพิกัด latitude/longitude ที่แปลงมาจาก MGRS หรือ UTM สามารถแสดงผลได้ในทศนิยมที่ห้า ซึ่งจะเทียบเท่ากับหน่วยมิลลิเมตร ที่เราชาวสำรวจที่ต้องใช้ ถ้าใครเคยใช้โปรแกรมแปลงพิกัด UTM <==> Geo ที่ผมเขียนด้วย fx-5800P จะสังเกตเห็นว่าคำนวณแล้วได้ทศนิยมแค่สองตำแหน่งเท่านั้น ข้อได้เปรียบของ fx-9860G II คือสถาปัตยกรรมของเครื่องรุ่นนี้สามารถใช้ตัวแปร double ได้ ซึ่งในงานสำรวจนั้นเพียงพออยู่แล้ว

มาดาวน์โหลดโปรแกรมไปทดสอบ

เมื่อผม compile และ build โปรแกรมในเครื่องมือพัฒนาโปรแกรมของคาสิโอ แล้วจะได้ไฟล์ที่นามสกุล G1A (ตัว A คงหมายความว่า AddIn) ถ้าสนใจก็ไปดาวน์โหลดได้ที่หน้าดาวน์โหลด เมื่อได้ไฟล์มาแล้วชื่อ “UTMGeo.G1A” จากนั้นให้ดึง SD card ที่เสียบอยู่ด้านบนเครื่องคิดเลข fx-9860G II SD แล้วนำมาเสียบที่เครื่องพีซีหรือโน๊ตบุ๊ค เมื่อเปิดด้วย windows explorer จากนั้นสร้างโฟลเดอร์ใหม่ อย่างของผมตั้งชื่อ “Survey Addin Programs” แล้วก็อปปี้ไฟล์ “UTMGeo.G1A” ไปไว้ที่โฟลเดอร์ดังกล่าวนี้

จากนั้นดึง SD card เอาไปเสียบที่เครื่องคิดเลขเหมือนเดิม จากนั้นกดปุ่ม “MENU” ที่คีย์บอร์ดของเครื่องคิดเลข จะเห็นไอคอนของโปรแกรม AddIn ขึ้นมาทั้งหมด ใช้คีย์บอร์ดลูกศรเลื่อนไปที่ “MEMORY” กด “EXE”

  • จะเห็นตัวหนังสือ Memory Manager พร้อมเมนูให้เลือก เลือกกดคีย์บอร์ด “F3” เพื่อเลือก F3:SD Card
  • จะเห็นโฟลเดอร์ ที่อยู่ในเครื่องคิดเลข จะเป็นชื่อสั้น 8.3 แบบระบบปฏิบัติการ DOS สมัยแต่ก่อน เลื่อนไปที่ [SURVEY~2] กด “EXE”
  • จะเห็นชื่อไฟล์ “UTMGeo.G1A” ที่เราก็อปปี้มาจากโน๊ตบุ๊คคอมพิวเตอร์นั่นเอง กด “F1” (SEL) และกดปุ่ม “F2” (COPY)
  • ที่นี้จะมีไดอะล็อกเล็กๆให้เลือกปลายทาง กดคีย์เลข 2 เลือกโฟลเดอร์ปลายทางเป็น “ROOT” กด “EXE” ถ้ามีไฟล์อยู่แล้วให้ยืนยันการเขียนทับ “Yes” ด้วยกดคีย์ “F1”
  • จากนั้นก็กดคีย์ “EXIT” หลายๆครั้ง สุดท้ายกดคีย์ “MENU” กดลูกศรเลื่อนลงไปด้านล่าง จะเห็นไอคอน “UTM Geo” จากนั้นกดปุ่ม “EXE”

ทดสอบการใช้งานโปรแกรมแปลงพิกัด Geographic Calc

เมื่อกด “EXE” เข้าไปแล้วจะเห็นบรรทัดบนสุดแสดงชื่อโปรแกรม “Geographic Calc” มีเมนูแบบง่ายๆ 4 เมนูให้เลือกคือ ต้องการเลือกตัวไหนก็กดตัวเลขตามเมนู

    1.  UTM to Geo – แปลงพิกัดจากระบบพิกัดฉากยูทีเอ็มไปยังค่าพิกัดภูมิศาสตร์ Latitude/Longitude
    2. Geo to UTM – แปลงพิกัดจากระบบพิกัดภูมิศาสตร์ไปยังระบบพิกัดฉากยูทีเอ็ม
    3. MGRS to Geo – แปลงพิกัดจากระบบพิกัด MGRS ไปยังระบบพิกัดภูมิศาสตร์
    4. Geo to MGRS – แปลงพิกัดจากระบบพิกัดภูมิศาสตร์ไปยังระบบพิกัด MGRS

แปลงพิกัดจากระบบพิกัดฉากยูทีเอ็มไปยังค่าพิกัดภูมิศาสตร์ (UTM to Geo)

ที่เมนูกดคีย์เลข “1” เข้าไปโปรแกรมจะถามค่าพิกัด North, East และตัวเลขของโซนยูทีเอ็ม ลองป้อนข้อมูลตามตัวอย่าง

จะได้ผลลัพธ์ดังต่อไปนี้ ครับตามที่กล่าวไปแล้วได้ทศนิยมค่าแลตติจูด ลองจิจูด ตำแหน่งที่ห้า

แปลงพิกัดจากพิกัดภูมิศาสตร์ไปยังระบบพิกัดฉากยูทีเอ็ม (Geo to UTM)

ที่เมนูกดเลข “2” โปรแกรมจะถามค่าพิกัดภูมิศาสตร์ สามารถป้อนทศนิยมได้มากกว่า 5 ตัว ป้อนค่ามุมตัวคั่นองศา ลิปดา ฟิลิปดาให้ใช้เครื่องหมายลบ (-) ค่าแลตติจูดลงท้ายให้ป้อนตัวอักษร ถ้าซึกโลกเหนือให้ป้อน “N” ตามหลัง ตามเป็นซีกโลกใต้ให้ป้อน “S” หรือค่าลองจิจูดซึกโลกตะวันตกให้ป้อนคำว่า “W” ลงท้าย ซีกโลกตะวันออกให้ป้อน “E” ลงท้าย ดูตัวอย่าง

เมื่อกด “EXE” จะได้ผลลัพธ์ดังนี้

แปลงค่าพิกัดจาก MGRS ไปยังค่าพิกัดภูมิศาสตร์ (MGRS to Geo)

ที่เมนูกดปุ่ม “3” เลือก โปรแกรมจะถามค่าพิกัด MGRS ป้อนไปดังรูปด้านล่าง

กด “EXE” จะได้ผลลัพธ์ค่าพิกัดภูมิศาสตร์

แปลงค่าพิกัดจากค่าพิกัดภูมิศาสตร์ ไปยัง MGRS  (Geo to MGRS)

ที่เมนูกดเลข “4” ลองป้อนค่าพิกัดแลตติจูด ลองจิจูดเข้าไปดังรูป

กด “EXE” จะได้ค่าผลลัพธ์ดังรูป

สรุป

ในขณะที่ลองเขียนโปรแกรมสำหรับเครื่องคิดเลข fx-9860G II นี้ ผมยังทำงานที่บังคลาเทศ ใช้เครื่องคิดเลขของน้องๆ แต่ด้วยความประทับใจเครื่องรุ่นนี้เลยสั่งซื้อเครื่องที่เมืองไทยส่งไปที่บ้านรอกลับไปค่อยไปลองเครื่องใหม่อีกที (สั่งจาก mr.finance ที่รับของแล้วค่อยโอนเงินอีกที บริการประทับใจครับ) ด้วยสนนราคาประมาณตอนนี้สี่พันบาทปลายๆ รวม SD card  มีความรู้สึกว่าคุ้มค่า ไม่ลังเลเหมือนก่อน ผมมีโครงการจะเขียนโปรแกรมเล็กๆด้วยภาษาซีอีกหลายโปรแกรมเพื่อแจกจ่ายเป็นโปรแกรมให้พี่ๆน้องๆในวงการสำรวจได้ใช้งานกันโดยไม่ได้คิดมูลค่า

ขอเพิ่มเติมอีกนิดครับ บทความที่นำเสนอมานี้ไม่ได้มีเจตนาส่งเสริมการขายเครื่องคิดเลขรุ่น fx-9860G II SD นี้ให้ขายดีขึ้นแต่อย่างใด สำหรับน้องๆนักศึกษาหรือช่างสำรวจที่จบมาทำงานใหม่ๆ เครื่องคิดเลข fx-5800P สามารถใช้งานได้ทั่วๆไปได้เพียงพอ โปรแกรมที่มีขายแและแจกจ่ายในวงการบ้านเราก็สามารถหามาใช้งานกันได้อย่างเหลือเฟือ และราคาเครื่องคิดเลข fx-5800P ก็พอจะซื้อหามาใช้งานได้ แต่สำหรับเครื่องคิดเลขรุ่น fx-9860G II SD นั้นราคามากกว่า fx-5800P ประมาณ 2-3 เท่า ถ้ามีเงินเหลือใช้ก็หาซื้อหามาใช้กันได้ สำหรับคนที่มีงานทำแล้วก็พอจะสามารถเก็บเงินซื้อได้

ผมเขียนบทความนี้เพื่อวงการศึกษาช่างสำรวจบ้านเราที่สนใจเรื่องโปรแกรมมิ่งสามารถจะพัฒนาโปรแกรมภาษาซีบนเครื่องคิดเลขรุ่นนี้ได้ โดยที่มีไม่มีข้อจำกัดด้านภาษาโปรแกรมมิ่งแต่อย่างใด เหมือนภาษา basic casio อาจจะส่งผลให้ในอนาคต มีโปรแกรมที่พัฒนาโดยบุคคลากรท่านอื่นๆ เข้ามาสู่วงการนี้มากขึ้น และได้ตัวโปรแกรมงานสำรวจก็มีความหลากหลายและความสามารถมากขึ้น ในบทความตอนหน้าไม่กี่ตอนจากนี้ไปจะมีบทความ แนะนำการใช้เครื่องมือพัฒนาโปรแกรม SDK (Software Development Kit) ของ casio และเทคนิคการใช้เครื่องมืออื่นๆที่ แฮกเกอร์เครื่องคิดเลขรุ่นนี้ได้ reverse-engineering เขียนเผยแพร่ไว้ หรือแม้กระทั่งใช้ฟังก์ชั่นที่ไม่ได้เปิดเผยจากทาง casio เองก็ตาม พบกันใหม่ครับ