Prečo sme tri geometrické jadrá zvýrazňovača nahradili odtlačkami
Dáta z Apple Pencil odhalili chyby, ktoré syntetické testy prehliadli, a priviedli Lulucat Notes od troch obrysových jadier k modelu MaLiang.
Lulucat Notes začal s konvenčným vykresľovačom zvýrazňovača: okolo vzorkovanej trajektórie vytvoriť geometrický obrys a potom tento obrys raz vyplniť priesvitnou farbou. Jediné vyplnenie zabraňuje tmavším pásom, ktoré vznikajú tam, kde sa prekrývajú priesvitné segmenty. Zároveň vkladá každé spojenie, samopriesek, zakončenie aj krátky ťah do toho istého geometrického problému.
Tri generácie vlastnej geometrie vždy odstránili jednu triedu chýb a odhalili inú. Vykresľovač, ktorý teraz dodávame, používa mäkké kruhové odtlačky založené na MaLiang, open-source kresliacom frameworku s licenciou MIT od Harley-xk. Výmenou za odstránenie celej kategórie chýb obrysu sme prijali tmavšie samoprieseky a konce zužujúce sa podľa tlaku.

Pôvodná snímka obrazovky zo zariadenia pri priblížení 228 %. Na oboch koncoch viacerých ťahov sa objavujú malé háčiky.
Skutočné písanie vytvorilo háčiky, ktoré syntetické scény nevytvorili
Naše syntetické scény pokrývali rovné čiary, oblúky, krátke ťuknutia, spätné ťahy, zmeny tlaku a ostré zákruty a všetky sa vykreslili čisto. Skutočné písanie čínskych znakov však na začiatku a na konci mnohých ťahov stále vytváralo háčiky dlhé približne 1–3 body.
Preto sme do aplikácie pridali tlačidlo uloženia a zaznamenali 29 úplných ťahov. Každá vzorka si zachovala svoju polohu, polomer, tlak, azimut, výšku, časovú pečiatku a príznaky odhadu UIKit. Offline program dekódoval tento JSON a skompiloval tie isté súbory Stroke.swift, StrokeRenderer.swift a HighlighterStrokeBuilder.swift, ktoré používa aplikácia. Jeho výstup sa zhodoval so snímkou zariadenia ťah po ťahu vrátane háčikov.
Keďže offline vykresľovač zopakoval chybu iba zo zaznamenaného vstupu, príčina spočívala vo vzorkách a geometrii, nie v správaní displeja. Teraz sme mohli čítať presné vzorky, ktoré vstúpili do vykresľovača.
Naša prvá hypotéza obvinila odhadovanú orientáciu pera pri dotyku a zdvihnutí. Dáta ju vyvrátili. Vo všetkých 29 ťahoch sa azimut v rámci prvých a posledných ôsmich vzoriek zmenil najviac o 0.09 radiánu a výška najviac o 0.02 radiánu, pričom každý príznak odhadu bol na tomto iPade false. Orientácia zostala stabilná, zatiaľ čo tlak a smer sa menili prudko.
Tlakový prah vyplynul z čistej medzery v dátach
Posledná vzorka každého zaznamenaného ťahu mala tlak 0.000. Vzorky pri písaní mali tlak 0.01 alebo vyšší, zatiaľ čo vzorky zaznamenané po oddialení pera od povrchu mali tlak 0.002 alebo nižší. Tieto vzorky vo vzduchu často pokračovali ďalšie 2–7 bodov a prešli 0.8–9.0 bodu, pričom ich smer sa mohol od napísaného ťahu odchýliť približne o 90 stupňov.
Ťah 2 ukazuje tento mechanizmus. Jeho telo končilo medzi 143 a 180 stupňami. Chvost s nízkym tlakom sa potom otočil na −90 až −67 stupňov a prešiel ďalších 8.5 bodu. Vykresľovač obrysu považoval poslednú vzorku vo vzduchu za rozhodujúci koncový bod, takže k tejto vzorke natiahol úzky kus geometrie.
Namerané tlaky nechávajú medzi písaním a pohybom vo vzduchu takmer celý rád veľkosti, preto sme rez umiestnili do tejto medzery:
private static let pressureFloor: CGFloat = 0.005
Odstraňujú sa iba vzorky s nízkym tlakom na oboch koncoch. Vzorka s nízkym tlakom uprostred ťahu zostáva jeho súčasťou. Toto pravidlo kopíruje nameranú hranicu udalosti a ponecháva napísanú trajektóriu nezmenenú.

Pred orezaním vykresľovač ukotvuje zakončenie na vzorkách vo vzduchu. Zelené bodky sú surové vzorky; červená čiara je vygenerovaný obrys.

Po orezaní vzoriek pod 0.005 sa zakončenie končí pri poslednom napísanom bode. Tento tlakový prah zostáva v aktuálnom vykresľovači s odtlačkami.
Tento prah odstránil dlhé háčiky vo vzduchu. Krátke ťahania pri dotyku a oblúky pri zdvihnutí, ktorých tlak zostal nad 0.005, prežili, pretože ide o napísaný pohyb. Spracovanie týchto pohybov v modeli obrysu viedlo k ďalším kolám geometrie.
Tri geometrické jadrá presúvali chyby z miesta na miesto
Prvá generácia: jeden obrys, jedna výplň
Prvé tlakovo citlivé jadro sledovalo známy postup. Vyhladilo stredovú krivku, vypočítalo ľavé a pravé odsadenia, spojilo ich do jedného polygónu a tento polygón raz vyplnilo. Hrot bol elipsou riadenou azimutom a výškou Apple Pencil, takže jeho prierez sa menil podľa smeru písania. Krátke ťuknutia mali samostatný tvar a ploché zakončenia používali malé asymetrie, aby sa vyhli dutinám s nulovým vinutím.
Jedna výplň vyriešila hromadenie opacít vo vnútri ťahu, ale vyžadovala platný polygón pri každej zákrute. Ťahania pri dotyku vytvárali kliny medzi zakončením a telom. Spätné ťahy mohli vytvoriť biele kosákovité dutiny. Ostré zákruty mohli spôsobiť samopriesek vnútorného obrysu a zanechať nevyplnený zárez.
Druhá generácia: oprava obrysu pri jeho koncoch
Druhé jadro si zachovalo obrys a pridalo lokálne opravy: orezanie spätných ťahov, tlmenie skorých odhadovaných vlastností, vyrovnávanie koncových bodov, orezanie prechodného smeru a malé predĺženie zakončenia. Každá oprava riešila reprodukovanú chybu. Spoločne spôsobili, že správanie koncov záviselo od viacerých prahov a okien.
Skutočné písanie potom prinieslo prípady mimo týchto okien. Pevné 24-bodové okno vyrovnávania vymazalo zámerné háčiky v krátkych ťahoch. Adaptívne okno tieto háčiky zachovalo, no oblúky pri zdvihnutí sa stále mohli zmeniť na viditeľné rohy. Orezanie zohľadňujúce smer odstránilo viac prechodného pohybu, za cenu zahodenia približne 2.5 bodu skutočne zakriveného začiatku v jednom zaznamenanom ťahu.
Každá oprava vyriešila prípad, na ktorý bola zameraná. Model pod nimi však stále vyžadoval tvrdý obrys, ktorý zostane platný pri zašumenom a zakrivenom vstupe.
Tretia generácia: zjednotenie pokrytia s orezanými štvorcovými zakončeniami
Tretie jadro prestalo vytvárať jeden obrys. Pre každý segment nakreslilo lichobežník a pri každej vnútornej vzorke disk do odtieňovej masky, zjednotilo ich pokrytie a potom raz použilo farbu zvýrazňovača. Kosákovité dutiny pri spätných ťahoch, stmavnutie pri samopriesekoch a otvory s nulovým vinutím zmizli, pretože vykresľovač už nezávisel od vinutia polygónu.
Zjednotenie zaoblilo konce a štvorcové zakončenia sme obnovili orezaním pokrytia podľa dvoch polrovín koncových bodov. Toto orezanie opravilo rovné čiary s konštantným tlakom, ale prinieslo vážnejšiu chybu: telo zakriveného ťahu môže legitímne prejsť cez polrovinu koncového bodu a orezanie zakončenia potom odstránilo časť stredu ťahu. Počas živého vstupu sa smer koncového bodu stále menil, takže orezávaná plocha sa posúvala a ťah blikal.

Globálne obmedzenie zakončenia pretína telo zakriveného ťahu.

Obmedzenie orezania zakončenia na primitíva v rámci jednej polovičnej šírky od koncového bodu obnoví tento ťah.
Brána podľa dĺžky oblúka urobila orezanie zakončenia lokálnym a opravila každý zaznamenaný prípad. Extrémny syntetický háčik stále ukázal malý biely zárez tam, kde sa hrot s nízkym tlakom stretol s orezaným zakončením. Tretie jadro opäť vymenilo jednu geometrickú chybu za inú.
MaLiang odstraňuje tvrdú hranicu
MaLiang vytvára ťah z opakovaných textúrovaných odtlačkov, nie z jedného uzavretého obrysu. Jeho generátor trajektórie používa kvadratické Bézierove segmenty, ktoré prechádzajú stredmi susedných vzoriek, a jeho vykresľovač čiary umiestňuje odtlačky v pravidelnom kroku pozdĺž tejto trajektórie. Veľkosť, rotácia, farba aj opacita odtlačku sa môžu pozdĺž ťahu meniť.
Mäkký odtlačok nemá samostatné zakončenie, spoj ani pravidlo vinutia. Prudká zmena smeru zostáva sekvenciou prekrývajúcich sa značiek. Spätné ťahy nemôžu vytvoriť prázdnu polygonálnu dutinu a polrovina koncového bodu nemôže prerezať stred ťahu, pretože model neobsahuje orezanie konca.
Prevzali sme model, nie kód. Aktuálny HighlighterStrokeBuilder vykonáva štyri operácie:
- Odstrániť iba koncové vzorky, ktorých tlak je nižší než
0.005. - Vyhladiť polohy pomocou kvadratických Bézierových segmentov cez stredy.
- Umiestniť jeden kruhový odtlačok na každý bod dĺžky oblúka.
- Nastaviť priemer odtlačku z normalizovaného tlaku a kompozitovať odtlačky s alpha v režime source-over.
Jadro kleslo zo 686 riadkov na 190. Azimut, výška, konštrukcia obrysu, masky zjednotenia, okná smeru koncového bodu, predĺženie zakončenia aj orezanie zakončenia opustili trajektóriu zvýrazňovača. Orientáciu pera stále zaznamenávame, pretože ju vstupný model podporuje, no samotný zvýrazňovač už tieto polia nečíta.
Tlakový vzorec MaLiang potreboval kalibráciu zariadenia
MaLiang určuje veľkosť odtlačku vzorcom ekvivalentným k
ktorý predpokladá, že force využíva užitočnú časť rozsahu od 0 do 1. Naše dáta zo zariadenia to nepotvrdili. Z približne 3 400 vzoriek Apple Pencil bol medián tlaku 0.047 a maximum 0.178. Priame vloženie týchto hodnôt do vzorca spôsobilo, že bežné písanie bolo oveľa tenšie než menovitá veľkosť štetca.
Preto normalizujeme okolo pozorovaného mediánu, potom použijeme exponent a výsledok ohraničíme:
Medián tlaku pri písaní sa teraz mapuje na menovitý priemer 12 bodov. Veľmi ľahký dotyk zostáva viditeľný pri 35 % menovitej veľkosti, zatiaľ čo silný tlak prestane rásť pri 120 %.
Táto kalibrácia patrí vstupnému zariadeniu a správaniu štetca, nie MaLiang. Kopírovanie pôvodného vzorca bez zmerania vlastného rozdelenia tlaku by zachovalo architektúru a vytvorilo nesprávny štetec.
Opacita jednotlivých odtlačkov vyplynula zo známeho počtu prekrytí
MaLiang kompenzuje prekrývajúce sa priesvitné odtlačky empirickým výrazom alpha ÷ overlapping × 2.5. Náš štetec má pevný menovitý priemer 12 bodov a krok odtlačku 1 bod, takže jeho stredová línia dostáva približne 12 vrstiev. V našom prípade je počet prekrytí známy a kompenzáciu možno vypočítať namiesto odhadovania.
Pre cieľovú opacitu ťahu
takže jeden odtlačok potrebuje
Pri

Finálny vykresľovač prehráva zaznamenané trajektórie zo zariadenia. Háčiky, diagonálne rezy a biele dutiny chýbajú.
Dve nevýhody, ktoré sme prijali
Samoprieseky stmavnú. Kompozícia v režime source-over započítava každý odtlačok vrátane odtlačkov nanesených pri skoršom prechode cez tú istú plochu a jadro so zjednotením pokrytia sa tomu vyhýbalo. Tmavšie prekrytie sme prijali, pretože je predvídateľné a zachováva tvar ťahu.
Zakončenia sa s tlakom zužujú. Skutočné zdvihnutie pera znižuje tlak, čo zmenší priemer odtlačku, takže ťah sa zužuje namiesto toho, aby končil plným štvorcovým zakončením. Počas všetkých troch geometrických jadier sme toto štvorcové zakončenie považovali za požiadavku. Jeho vypustenie odstránilo orezanie a koncovú mechaniku, ktoré stáli za niekoľkými vyššie uvedenými chybami, preto sme prijali zúžený koniec.
Model, ktorý dodávame, preto robí menej než predchádzajúce modely. Zachováva nameranú udalosť písania, reaguje na tlak po kalibrácii zariadenia a vykresľuje zakrivené a samopretínajúce sa trajektórie bez potreby globálne platného obrysu. Sekáčovitý hrot, dokonale štvorcové zakončenie a presná lomená čiara medzi surovými vzorkami sú vlastnosti, ktorých sme sa za to vzdali.
Tlakový prah sa najľahšie prenáša do iných projektov. Hodnota 0.005 pochádzala z medzery medzi dvoma zhlukmi v reálnom vstupe: písanie na 0.01 a vyššie, sledovanie vo vzduchu na 0.002 a nižšie. Tie isté zaznamenané ťahy ukázali, kde zlyhala každá geometrická oprava. Tieto zlyhania viedli k modelu s odtlačkami a k dvom nevýhodám, ktoré prináša.