Lulucat

เหตุใดเราจึงเปลี่ยนเอนจินเรขาคณิตไฮไลต์สามชุดมาใช้แสตมป์

Gaoge ZhangGaoge Zhang

ข้อมูล Apple Pencil จริงเผยข้อบกพร่องที่การทดสอบสังเคราะห์มองไม่เห็น จึงนำ Lulucat Notes จากเอนจินเส้นขอบสามชุดมาใช้โมเดลแสตมป์ของ MaLiang

อัปเดตเมื่อ

Lulucat Notes เริ่มต้นด้วยตัวเรนเดอร์ไฮไลต์แบบทั่วไป: สร้างเส้นขอบเรขาคณิตรอบเส้นทางที่สุ่มตัวอย่าง แล้วเติมสีโปร่งแสงลงในเส้นขอบนั้นครั้งเดียว การเติมเพียงครั้งเดียวช่วยหลีกเลี่ยงแถบสีเข้มที่เกิดขึ้นเมื่อส่วนของเส้นโปร่งแสงซ้อนทับกัน และยังทำให้รอยต่อ การตัดกันของเส้นกับตัวเอง ปลายเส้น และเส้นสั้นทุกชนิดกลายเป็นปัญหาเรขาคณิตเดียวกัน

เอนจินเรขาคณิตแบบพัฒนาขึ้นเองสามรุ่นต่างแก้ข้อบกพร่องไปคนละประเภท แต่ก็เผยให้เห็นข้อบกพร่องอีกประเภทหนึ่ง ตัวเรนเดอร์ที่เราใช้งานอยู่ตอนนี้ใช้แสตมป์วงกลมนุ่มตาม MaLiang. MaLiang เป็นเฟรมเวิร์กวาดภาพโอเพนซอร์สที่ใช้ใบอนุญาต MIT โดย Harley-xk. การเลือกนี้แลกกับการกำจัดความล้มเหลวของเส้นขอบไปทั้งหมวดหนึ่ง แต่เรายอมรับการตัดกันของเส้นกับตัวเองที่เข้มขึ้นและปลายเส้นที่เรียวตามแรงกด

ลายมือไฮไลต์สีน้ำเงินที่บันทึกบน iPad โดยมีตะขอเส้นบางปรากฏที่จุดเริ่มและจุดจบของหลายเส้น

ภาพหน้าจอจากอุปกรณ์ต้นฉบับที่ซูม 228% มีตะขอเล็ก ๆ ปรากฏที่ปลายทั้งสองด้านของหลายเส้น

ลายมือจริงสร้างตะขอที่ฉากสังเคราะห์ไม่สร้าง

ฉากสังเคราะห์ของเราครอบคลุมเส้นตรง ส่วนโค้ง การแตะสั้น ๆ การลากย้อนกลับ การเปลี่ยนแรงกด และการหักเลี้ยวอย่างแหลมคม และทั้งหมดเรนเดอร์ออกมาได้สะอาด ลายมือจีนจริงยังคงสร้างตะขอที่ยาวประมาณ 1–3 จุดในช่วงเริ่มต้นและช่วงท้ายของหลายเส้น

ดังนั้นเราจึงเพิ่มปุ่มบันทึกลงในแอปและบันทึกเส้นที่เขียนจบสมบูรณ์ 29 เส้น ทุกตัวอย่างเก็บตำแหน่ง รัศมี แรงกด อะซิมัท ระดับความสูง การประทับเวลา และแฟล็กการประมาณค่าของ UIKit ไว้ทั้งหมด โปรแกรมออฟไลน์ถอดรหัส JSON นั้นและคอมไพล์ไฟล์ Stroke.swift, StrokeRenderer.swift และ HighlighterStrokeBuilder.swift ชุดเดียวกับที่แอปใช้ ผลลัพธ์ตรงกับภาพหน้าจอจากอุปกรณ์ทีละเส้น รวมถึงตะขอด้วย

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

สมมติฐานแรกของเราโทษการวางแนวของ Pencil ที่ผ่านการประมาณค่าในขณะวางและยกปากกา ข้อมูลไม่สนับสนุนสมมติฐานนั้น ในเส้นทั้ง 29 เส้น อะซิมัทเปลี่ยนแปลงไม่เกิน 0.09 เรเดียน และระดับความสูงไม่เกิน 0.02 เรเดียนภายในตัวอย่างแปดตัวแรกและแปดตัวสุดท้าย อีกทั้งแฟล็กการประมาณค่าทุกตัวเป็น false บน iPad เครื่องนั้น การวางแนวยังคงคงที่ ขณะที่แรงกดและทิศทางเปลี่ยนอย่างฉับพลัน

ค่าพื้นแรงกดมาจากช่องว่างสะอาดในข้อมูล

ตัวอย่างสุดท้ายของทุกเส้นที่บันทึกไว้มีแรงกด 0.000 ตัวอย่างขณะเขียนอยู่ที่ 0.01 ขึ้นไป ส่วนตัวอย่างที่บันทึกหลังจาก Pencil พ้นผิวไปแล้วอยู่ที่ 0.002 หรือต่ำกว่า ตัวอย่างขณะลอยเหล่านี้มักดำเนินต่ออีก 2–7 จุดและเคลื่อนที่ 0.8–9.0 จุด โดยทิศทางอาจหันออกจากเส้นที่เขียนไปประมาณ 90 องศา

เส้นที่ 2 แสดงกลไกนี้ ร่างกายของเส้นจบลงระหว่าง 143 ถึง 180 องศา จากนั้นหางแรงกดต่ำก็หันไปที่ −90 ถึง −67 องศาและเคลื่อนต่ออีก 8.5 จุด ตัวเรนเดอร์เส้นขอบถือว่าจุดสุดท้ายขณะลอยเป็นจุดปลายที่เชื่อถือได้ จึงยืดเรขาคณิตส่วนแคบ ๆ ไปหาจุดนั้น

ค่าแรงกดที่วัดได้ทิ้งช่องว่างเกือบหนึ่งลำดับขนาดระหว่างการเขียนกับการเคลื่อนที่ขณะลอย เราจึงวางจุดตัดไว้ภายในช่องว่างนั้น:

private static let pressureFloor: CGFloat = 0.005

เราตัดออกเฉพาะตัวอย่างแรงกดต่ำที่ปลายทั้งสองด้าน ตัวอย่างแรงกดต่ำที่อยู่กลางเส้นยังคงเป็นส่วนหนึ่งของเส้น กฎนี้ยึดตามขอบเขตของเหตุการณ์ที่วัดได้ และไม่แก้ไขเส้นทางที่เขียนไว้

ภาพระยะใกล้ที่ใส่ข้อมูลกำกับก่อนตัดแต่ง: ตัวอย่างอินพุตสีเขียวหันออกจากเส้น ขณะที่เส้นขอบสีแดงสร้างตะขอแคบ ๆ

ก่อนตัดแต่ง ตัวเรนเดอร์ยึดปลายเส้นไว้กับตัวอย่างขณะลอย จุดสีเขียวคือตัวอย่างดิบ เส้นสีแดงคือเส้นขอบที่สร้างขึ้น

ภาพระยะใกล้ที่ใส่ข้อมูลกำกับหลังตัดแต่ง: พื้นที่เติมสีน้ำเงินจบลงที่ตัวอย่างขณะเขียนล่าสุด และจุดสีเขียวแรงกดต่ำยังคงอยู่นอกพื้นที่นั้น

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

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

เอนจินเรขาคณิตสามรุ่นเพียงย้ายข้อบกพร่องไปมา

รุ่นที่หนึ่ง: เส้นขอบหนึ่งเส้น การเติมหนึ่งครั้ง

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

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

รุ่นที่สอง: ซ่อมเส้นขอบใกล้ปลายเส้น

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

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

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

รุ่นที่สาม: ยูเนียนพื้นที่ครอบคลุมพร้อมปลายตัดเป็นสี่เหลี่ยม

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

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

เส้นไฮไลต์สีน้ำเงินโค้งก่อนแก้การคลิปปลายเส้น โดยลำตัวด้านบนถูกตัดตามเส้นทแยงมุม จุดสีเขียวแสดงเส้นทางที่สุ่มตัวอย่างไว้ทั้งหมด

ข้อจำกัดปลายเส้นระดับโกลบอลตัดผ่านลำตัวของเส้นโค้ง

เส้นไฮไลต์สีน้ำเงินโค้งเส้นเดิมหลังเพิ่มเกตความยาวส่วนโค้งเฉพาะที่ โดยแขนทั้งสองข้างรอบเส้นทางที่สุ่มตัวอย่างสีเขียวกลับมาแล้ว

การจำกัดการคลิปปลายเส้นไว้เฉพาะพริมิทีฟที่อยู่ภายในครึ่งหนึ่งของความกว้างเส้นจากปลายเส้นช่วยคืนเส้นนี้กลับมาได้

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

MaLiang กำจัดขอบเขตแข็ง

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

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

เรานำโมเดลมาใช้ ไม่ได้นำโค้ดมาใช้ HighlighterStrokeBuilder ปัจจุบันทำงานสี่อย่าง:

  1. ลบเฉพาะตัวอย่างที่ปลายทั้งสองด้านซึ่งมีแรงกดต่ำกว่า 0.005
  2. ทำตำแหน่งให้เรียบด้วยเซกเมนต์ Bézier กำลังสองที่ใช้จุดกึ่งกลาง
  3. วางแสตมป์วงกลมหนึ่งอันต่อความยาวส่วนโค้งแต่ละจุด
  4. กำหนดเส้นผ่านศูนย์กลางของแสตมป์จากแรงกดที่ทำให้เป็นมาตรฐานแล้ว และประกอบแสตมป์ด้วยอัลฟาแบบ source-over

ตัวสร้างลดขนาดจาก 686 บรรทัดเหลือ 190 บรรทัด อะซิมัท ระดับความสูง การสร้างเส้นขอบ มาสก์ยูเนียน หน้าต่างทิศทางของปลายเส้น การขยายปลายเส้น และการคลิปปลายเส้น ล้วนออกจากเส้นทางไฮไลต์ เรายังคงบันทึกการวางแนวของ Pencil เพราะโมเดลอินพุตรองรับข้อมูลนี้ แต่ตัวไฮไลต์เองไม่อ่านฟิลด์เหล่านั้นอีกต่อไป

สูตรแรงกดของ MaLiang ต้องปรับเทียบกับอุปกรณ์

MaLiang กำหนดขนาดแสตมป์ด้วยสูตรที่เทียบเท่ากับ

ซึ่งสมมติว่า force ใช้ช่วงที่มีประโยชน์จาก 0 ถึง 1 ข้อมูลจากอุปกรณ์ของเราไม่เป็นเช่นนั้น จากตัวอย่าง Apple Pencil ประมาณ 3,400 ตัวอย่าง ค่ามัธยฐานของแรงกดคือ 0.047 และค่าสูงสุดคือ 0.178 การป้อนค่าเหล่านี้เข้าสูตรโดยตรงทำให้การเขียนปกติบางกว่าขนาดแปรงตามที่ระบุไว้มาก

ดังนั้นเราจึงทำให้เป็นมาตรฐานรอบค่ามัธยฐานที่สังเกตได้ จากนั้นใช้เลขชี้กำลังและจำกัดผลลัพธ์:

ตอนนี้แรงกดขณะเขียนที่ค่ามัธยฐานจะแมปไปยังเส้นผ่านศูนย์กลางที่กำหนดไว้ 12 จุด การแตะเบามากยังคงมองเห็นได้ที่ 35% ของขนาดที่กำหนดไว้ ส่วนแรงกดมากจะหยุดขยายที่ 120%

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

อัลฟาต่อแสตมป์มาจากจำนวนการซ้อนทับที่ทราบแน่ชัด

MaLiang ชดเชยแสตมป์โปร่งแสงที่ซ้อนทับกันด้วยนิพจน์เชิงประจักษ์ alpha ÷ overlapping × 2.5 แปรงของเรามีเส้นผ่านศูนย์กลางที่กำหนดไว้คงที่ 12 จุดและช่วงก้าวของแสตมป์ 1 จุด ดังนั้นเส้นกึ่งกลางจึงได้รับประมาณ 12 ชั้น ในกรณีของเรา จำนวนชั้นที่ซ้อนทับทราบแน่ชัด และเราสามารถแก้ค่าชดเชยได้แทนที่จะประมาณ

สำหรับความทึบของเส้นเป้าหมาย และ ชั้น source-over ที่เท่ากัน ความทึบของแสตมป์ จะให้ผลเป็น

ดังนั้นแสตมป์หนึ่งอันต้องใช้

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

แผ่นรอยไฮไลต์สีน้ำเงินหลากหลายแบบที่เรนเดอร์ด้วยโมเดลแสตมป์นุ่มสุดท้าย รวมทั้งวง วงตะขอ รอยสั้น และการตัดกันของเส้นกับตัวเอง

ตัวเรนเดอร์สุดท้ายเล่นเส้นทางจากอุปกรณ์ที่บันทึกไว้ซ้ำ ตะขอ รอยตัดแนวทแยง และช่องว่างสีขาวหายไป

ต้นทุนสองอย่างที่เรายอมรับ

การตัดกันของเส้นกับตัวเองจะเข้มขึ้น การประกอบแบบ source-over นับทุกแสตมป์ รวมถึงแสตมป์ที่วางไว้จากรอบก่อนหน้าบนพื้นที่เดียวกัน และเอนจินยูเนียนพื้นที่ครอบคลุมเคยหลีกเลี่ยงปัญหานี้ เรายอมรับการซ้อนทับที่เข้มขึ้นเพราะคาดเดาได้และรักษารูปทรงเส้นไว้

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

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

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