Lulucat

Dvě gumy a proč mazání patří tahu

Gaoge ZhangGaoge Zhang

Guma jako samostatný prvek je očividný návrh. Přesun objektů ho rozbije, proto v Lulucat Notes mazání patří tahu, z něhož odstraňuje inkoust.

Aktualizováno

Když v zápisníku gumujete, můžete tím myslet dvě různé věci. Někdy je chybný celý tah a měl by zmizet: vodicí čára, přeškrtnuté slovo, zatoulaný tah od dlaně opřené o stránku. Jindy je chybná jen část tahu: polovina znaku, jedna větev diagramu, konec tahu zvýrazňovačem, který přejel za větu. Lulucat Notes nyní nabízí obojí jako dva samostatné nástroje.

Obtížnější otázkou návrhu je, kam mazání patří.

Nejprve přišla guma celých tahů

První guma mazala celé tahy. Dotyk otestuje každý tah: obdélníky ohraničení odmítnou téměř všechny a u přeživších se provede test druhé mocniny vzdálenosti bodu od úsečky proti součtu poloměru gumy a poloměru tahu interpolovaného podél daného segmentu. Šířka se mění s tlakem, takže jediná jmenovitá šířka by mazala tenké tahy, kterých se uživatel nedotkl, a míjela tlusté tahy, kterých se dotkl.

Jedno gesto se sloučí do jedné položky undo a položka uchovává každý odstraněný tah spolu s jeho původním indexem. Undo je vloží zpět v opačném pořadí, takže pořadí překrývání se vrátí přesně do původního stavu.

Tato guma je rychlá, předvídatelná a neumí odstranit polovinu slova.

MaLiang dělá z gumy štětec

MaLiang, framework pro kreslení s licencí MIT, od kterého jsme už převzali model razítek zvýrazňovače, řeší částečné mazání ve dvaceti čtyřech řádcích. Jeho Eraser je podtřída Brush, která přepisuje jedinou věc — volby pro prolnutí — aby místo přidávání odečítala. Mazací tah je prvek ve stejném seznamu jako každý jiný tah. Undo tento prvek odstraní. Žádný existující tah se nemění, protože k vymazání dochází až při přehrání v pořadí seznamu.

Tento model jsme nasadili a dvě relace na zařízení odhalily, že nefunguje.

Přesun objektů odhalí chybějícího vlastníka

První hlášení: vyberte tahy lasem, přetáhněte je a díra zůstane na místě.

Čtyři panely porovnávající dva modely gumy před a po přesunutí tahů. Když je guma vlastním prvkem, mezera zůstane na starém místě; když mazání patří tahu, mezera se přesune spolu s inkoustem.

Stejné tahy smazané gumou, přesunuté doprava. Nahoře: guma je samostatný prvek. Dole: mazání patří tahům.

Výběr to zhoršil. Vybrané tahy se z bitmapy zvednou do překryvné vrstvy, která je vykreslí přímo, bez prvku gumy, takže ve chvíli, kdy vyberete vymazaný tah, se znovu objeví celý.

Druhé hlášení: guma se vznášela nad zvýrazňovačem. Náš vykreslovač přehrává ve dvou průchodech, nejprve zvýrazňovače a potom pera, protože inkoust zvýrazňovače musí ležet pod inkoustem. Prvek gumy se musí účastnit obou průchodů, jinak nemůže mazat oba druhy. Účast v průchodu perem znamená spustit ho až po vykreslení každého zvýrazňovače, takže guma odřízla i tahy zvýrazňovače nakreslené později v čase.

Obě selhání mají stejný zdroj. MaLiang nemá laso, přesun ani pořadí vrstev mezi štětci, takže prvek bez vlastníka tam stačí. Naše plátno má všechny tři funkce a mazání bez vlastníka nemá jednoznačnou odpověď na otázku „co se stane, když se inkoust přesune“ ani „na které vrstvě tato operace probíhá“.

Mazání patří tahu

Každý Stroke nyní nese vlastní mazací cesty. Guma testuje, kterých tahů se dotkne, a ke každému připojí cestu v souřadnicích plátna. Vykreslení jednoho tahu nakreslí jeho inkoust a vlastní mazací cesty uvnitř vrstvy průhlednosti:

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()

Destination-out zachová cíl a odstraní ho v poměru k alfa kanálu zdroje:

Uvnitř vrstvy průhlednosti je cílem právě tento jeden tah, takže operace nemůže zasáhnout papír, tahy pod ním ani tahy vykreslené později. U tahů bez mazání vrstva nic nestojí, což se týká téměř všech: ty používají původní cestu.

Vlastnictví řeší obě selhání přímo. Přesun posune mazací cesty spolu se vzorkovacími body, takže přesunutý tah si nese své mezery. Překryvná vrstva výběru vykreslí stejný objekt tahu, takže vybraný tah ukazuje stejné mezery. Pořadí vrstev přestává být důležité, protože mazání nikdy nepůsobí na nic kromě vlastního tahu.

Undo pracuje s gestem: jedna položka obsahuje každý pár (stroke, path), který gesto vytvořilo, undo tyto cesty odstraní a redo je znovu připojí. Inkoust pod vymazáním se nikdy neupravuje, takže se nic nemusí rekonstruovat.

Živá odezva prochází dlaždicovou bitmapou

Právě kreslený tah se obvykle vykresluje jako překryvná vrstva nad složenou stránkou. Mazání tam nemůže fungovat, protože tato překryvná vrstva leží nad papírem i inkoustem a destination-out by prorazilo skrz papír.

Guma proto zapisuje do tahů okamžitě a každá dávka nových vzorků spustí lokální přehrání pouze zasaženého obdélníku. Dlaždicový řetězec už obdélník vyčistí a přehraje tahy, které ho protínají; guma tuto cestu znovu používá a nepřidává žádnou druhou sémantiku vykreslení.

Obě gumy vedle sebe

Panel nástrojů má dvě tlačítka gumy, ne jedno tlačítko se skrytým režimem. Částečná guma odstraňuje část tahu. Guma tahů při kontaktu odstraňuje celé tahy. Jejich poloměry jsou samostatné konstanty, obě jsou nyní 4 body.

Smazání celého tahu odstraní i jeho mazací cesty, protože jsou jeho součástí, a undo vrátí obojí společně. Mazací cesty jsou také součástí uloženého souboru, kvantizované jako vše ostatní: poloměr a souřadnice v desetinách bodu.

Jedno omezení zůstává. Tah vymazaný až do úplného zmizení stále existuje jako data. Vykreslí se jako nic, ale laso ho stále může vybrat, guma tahů ho stále může smazat a v dokumentu stále zabírá místo. Odstranění tahů vymazaných beze zbytku vyžaduje test pokrytí, který jsme zatím nenapsali, takže prozatím zůstávají.

Když model z jiného projektu přestane v tom vašem fungovat, rozdíl obvykle není v kódu, který jste zkopírovali. Je ve funkcích, které tamní projekt nemá.