Lulucat

Dve gumy a prečo mazanie patrí ťahu

Gaoge ZhangGaoge Zhang

Samostatný prvok pre ťah gumy je očividný návrh. Presun objektu ho rozbije, preto Lulucat Notes priraďuje mazanie k ťahu, z ktorého odstraňuje atrament.

Aktualizované

Keď v zápisníku používate gumu, môžete tým myslieť dve rôzne veci. Niekedy je chybný celý ťah a mal by zmiznúť: pomocná čiara, preškrtnuté slovo, náhodný ťah od odpočívajúcej dlane. Niekedy je chybná iba časť ťahu: polovica znaku, jedna vetva diagramu, chvost ťahu zvýrazňovačom, ktorý presiahol vetu. Lulucat Notes teraz ponúka oboje ako dva samostatné nástroje.

Ťažšia návrhová otázka znie, kam mazanie patrí.

Guma na celé ťahy prišla prvá

Prvá guma mazala celé ťahy. Dotyk testuje každý ťah: ohraničujúce rámčeky vyradia takmer všetky a pri zvyšných sa druhá mocnina vzdialenosti bodu od úsečky porovná s polomerom gumy plus polomerom ťahu interpolovaným pozdĺž tejto úsečky. Šírka sa mení podľa tlaku, takže jediná menovitá šírka by vymazala tenké ťahy, ktorých sa používateľ nedotkol, a minula hrubé, ktorých sa dotkol.

Jedno gesto vytvorí jednu položku operácie Späť a tá uchová každý odstránený ťah spolu s jeho pôvodným indexom. Operácia Späť ich vloží späť v opačnom poradí, takže poradie vrstiev sa obnoví presne tak, ako bolo.

Táto guma je rýchla, predvídateľná a nedokáže odstrániť polovicu slova.

MaLiang robí z gumy štetec

MaLiang, kresliaci framework s licenciou MIT, od ktorého sme už prevzali model odtlačkov zvýrazňovača, rieši čiastočné vymazanie v 24 riadkoch. Jeho Eraser je podtrieda Brush, ktorá prepisuje jednu vec — možnosti miešania — aby namiesto pridávania odčítavala. Ťah gumy je prvok v tom istom zozname ako každý iný ťah. Operácia Späť odstráni tento prvok. Žiadny existujúci ťah sa nemení, pretože mazanie prebehne až pri prehrávaní v poradí zoznamu.

Model sme nasadili a dve relácie na zariadeniach ho rozbili.

Presun objektu odhalí chýbajúceho vlastníka

Prvé hlásenie: vyberte ťahy lasom, potiahnite ich a vymazaná medzera zostane na pôvodnom mieste.

Štyri panely porovnávajúce dva modely gumy pred presunom ťahov a po ňom. Keď je guma samostatným prvkom, medzera zostáva na pôvodnom mieste; keď mazanie patrí ťahu, medzera putuje spolu s atramentom.

Rovnaké vymazané ťahy presunuté doprava. Hore: guma je samostatný prvok. Dole: mazanie patrí ťahom.

Výber to zhoršil. Vybrané ťahy sa z bitmapy vyzdvihnú do prekryvnej vrstvy, ktorá ich vykresľuje priamo bez prvku gumy, takže vo chvíli, keď ste vybrali vymazaný ťah, opäť vyzeral celý.

Druhé hlásenie: guma sa vznášala nad zvýrazňovačom. Náš vykresľovač prehráva v dvoch prechodoch, najprv zvýrazňovače a potom perá, pretože atrament zvýrazňovača musí byť pod atramentom pera. Prvok gumy sa musí zúčastniť oboch prechodov, inak nemôže gumovať oba druhy. Účasť v prechode pera znamená vykreslenie po každom zvýrazňovači, takže guma zároveň vymazala aj ťahy zvýrazňovača, ktoré boli nakreslené neskôr v čase.

Obe zlyhania majú rovnaký zdroj. MaLiang nemá laso, presun ani poradie vrstiev medzi štetcami, takže prvok bez vlastníka tam stačí. Naše plátno má všetky tri a mazanie bez vlastníka nemá definovanú odpoveď na otázku „čo sa stane, keď sa atrament presunie“ ani „na ktorej vrstve táto operácia prebieha“.

Mazanie vo vlastníctve ťahu

Každý Stroke teraz obsahuje vlastné cesty vymazania. Guma testuje, ktorých ťahov sa dotýka, a ku každému z nich pridá cestu v súradniciach plátna. Vykreslenie jedného ťahu vykreslí jeho atrament a vlastné vymazania vnútri vrstvy priehľadnosti:

context.beginTransparencyLayer(auxiliaryInfo: nil)
drawInk(stroke, in: context, clip: clip, colorOverride: colorOverride)
context.setBlendMode(.destinationOut)
for path in stroke.erasePaths { fillErasePath(path, in: context) }
context.endTransparencyLayer()

Režim destination-out zachováva cieľ a odstraňuje ho úmerne alfe zdroja:

Vnútri vrstvy priehľadnosti je cieľom práve tento jeden ťah, takže operácia nemôže zasiahnuť papier, ťahy pod ním ani ťahy vykreslené neskôr. Vrstva nepredstavuje náklad pri ťahoch bez vymazaní, ktorých je takmer všetko: tie použijú pôvodnú cestu.

Vlastníctvo odpovedá priamo na obe zlyhania. Posun presunie cesty vymazania spolu so vzorkami, takže presunutý ťah nesie svoje medzery so sebou. Prekryvná vrstva výberu vykresľuje ten istý objekt ťahu, takže vybraný ťah ukáže tie isté medzery. Poradie vrstiev prestáva byť dôležité, pretože mazanie sa nikdy neuplatní na nič okrem vlastného ťahu.

Operácia Späť pracuje s gestom: jedna položka uvádza každú dvojicu (stroke, path), ktorú gesto vytvorilo, operácia Späť tieto cesty odstráni a operácia Znova ich opäť pripojí. Atrament pod mazaním sa nikdy neupravuje, takže ho netreba rekonštruovať.

Živá odozva prechádza cez dlaždicovú bitmapu

Práve kreslený ťah sa bežne vykresľuje ako prekrytie nad zloženou stránkou. Mazanie tam nemôže fungovať, pretože toto prekrytie leží nad papierom aj atramentom a destination-out by prerazil až do papiera.

Preto guma zapisuje do ťahov okamžite a každá dávka nových vzoriek spustí lokálne prehratie iba príslušného obdĺžnika. Dlaždicové spracovanie už vyčistí obdĺžnik a prehrá ťahy, ktoré ho pretínajú; guma túto cestu znovu využíva a nepridáva druhú sémantiku vykresľovania.

Obe gumy vedľa seba

Panel nástrojov má dve tlačidlá gumy namiesto jedného tlačidla so skrytým režimom. Čiastočná guma odstráni časť ťahu. Guma na celé ťahy pri kontakte odstráni celé ťahy. Ich polomery sú samostatné konštanty, obe sú momentálne 4 body.

Vymazanie celého ťahu odoberie spolu s ním aj jeho cesty vymazania, keďže sú súčasťou tohto ťahu, a operácia Späť vráti oboje spolu. Cesty vymazania sú tiež súčasťou uloženého súboru a rovnako ako všetko ostatné sú kvantizované: polomer a súradnice na desatiny bodu.

Zostáva jedno obmedzenie. Ťah vymazaný až na nulu stále existuje ako dáta. Vykresľuje sa ako prázdny, no laso ho stále môže vybrať, guma na celé ťahy ho môže stále odstrániť a v dokumente stále zaberá miesto. Čistenie úplne vymazaných ťahov si vyžaduje test pokrytia, ktorý sme ešte nenapísali, takže zatiaľ zostávajú.

Keď model z iného projektu prestane fungovať vo vašom, rozdiel zvyčajne nie je v kóde, ktorý ste skopírovali. Je vo funkciách, ktoré tento projekt nemá.