Kaksi pyyhekumia – ja miksi pyyhintä kuuluu vedolle
Pyyhekumin veto omana elementtinään on ilmeinen ratkaisu. Objektien siirtäminen rikkoo sen, joten Lulucat Notesissa pyyhintä kuuluu vedolle, jonka musteen se poistaa.
Muistikirjassa pyyhkiminen tarkoittaa kahta eri asiaa. Joskus merkki on väärä ja koko merkin pitäisi kadota: apuviiva, yliviivattu sana tai lepäävästä kämmenestä tullut ylimääräinen veto. Joskus vain osa merkistä on väärä: puolet merkistä, yksi kaavion haara tai lauseen ohi jatkuneen korostuskynänvedon häntä. Lulucat Notesissa on nyt molemmat erillisinä työkaluina.
Vaikeampi suunnittelukysymys on, missä pyyhintä sijaitsee.
Vetojen pyyhekumi tuli ensin
Ensimmäinen pyyhekumi poisti kokonaisia vetoja. Jokainen kosketus testaa kaikki vedot: rajaavat laatikot hylkäävät lähes kaikki, ja jäljelle jääville tehdään pisteen ja janan välisen etäisyyden neliötesti pyyhekumin säteen sekä janan varrelle interpoloidun vedon säteen summaa vasten. Leveys vaihtelee paineen mukaan, joten yksi nimellinen leveys poistaisi ohuita vetoja, joihin käyttäjä ei osunut, ja jättäisi paksut, joihin osuttiin, poistamatta.
Yksi ele yhdistyy yhdeksi kumoamismerkinnäksi, joka tallentaa jokaisen poistetun vedon yhdessä sen alkuperäisen indeksin kanssa. Kumoaminen lisää ne takaisin käänteisessä järjestyksessä, joten pinoamisjärjestys palautuu täsmälleen ennalleen.
Tämä pyyhekumi on nopea, ennakoitava eikä pysty poistamaan puolta sanasta.
MaLiang tekee pyyhekumista siveltimen
MaLiang, MIT-lisensoitu piirtojärjestelmä, josta lainasimme jo korostuskynän leimamallin, ratkaisee osittaisen pyyhkimisen kahdellakymmenelläneljällä rivillä. Sen Eraser on Brush-aliluokka, joka ylikirjoittaa yhden asian, sekoitusasetukset, vähentääkseen lisäämisen sijaan. Pyyhekumin veto on elementti samassa luettelossa kaikkien muiden vetojen kanssa. Kumoaminen poistaa tämän elementin. Yhtäkään olemassa olevaa vetoa ei muokata, koska pyyhintä tapahtuu vain toiston aikana luettelon järjestyksessä.
Toimitimme tämän mallin, ja kaksi laiteistuntoa rikkoi sen.
Objektien siirtäminen paljastaa puuttuvan omistajan
Ensimmäinen ilmoitus: valitse vedot lassolla, vedä niitä, ja aukko jää taakse.

Samat pyyhityt vedot siirrettyinä oikealle. Ylhäällä: pyyhekumi on oma elementtinsä. Alhaalla: pyyhintä kuuluu vedoille.
Valinta pahensi tilannetta. Valitut vedot nostetaan bittikuvasta peittokuvaan, joka piirtää ne suoraan ilman pyyhekumin elementtiä, joten heti kun valitsit pyyhityn vedon, se näytti jälleen ehjältä.
Toinen ilmoitus: pyyhekumi leijui korostuskynän päällä. Renderöijämme toistaa kahdessa vaiheessa, korostuskynät ensin ja kynät toisena, koska korostuskynän musteen on oltava muun musteen alla. Pyyhekumin elementin on osallistuttava molempiin vaiheisiin, muuten se ei voi pyyhkiä kumpaakaan tyyppiä. Kynävaiheeseen osallistuminen tarkoittaa, että se ajetaan kaikkien korostuskynien piirtämisen jälkeen, joten pyyhekumi leikkasi myös ajallisesti myöhemmin piirretyt korostuskynävedot.
Molemmat viat johtuvat samasta lähteestä. MaLiangissa ei ole lassoa, siirtämistä eikä siveltimien välistä kerrosjärjestystä, joten siellä riittää elementti, jolla ei ole omistajaa. Meidän kanvaasissamme on kaikki kolme, ja omistajaton pyyhintä ei anna määriteltyä vastausta kysymyksiin ”mitä tapahtuu, kun muste liikkuu” tai ”millä tasolla tämä toimii”.
Vedon omistama pyyhintä
Jokaisella Stroke-oliolla on nyt omat pyyhintäpolkunsa. Pyyhekumi testaa, mihin vetoihin se osuu, ja lisää kuhunkin polun kanvaskoordinaateissa. Yhden vedon renderöinti piirtää sen musteen ja omat pyyhintänsä läpinäkyvyyskerroksessa:
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 säilyttää kohteen ja poistaa sitä lähteen alfan suhteessa:
Läpinäkyvyyskerroksen sisällä kohde on tuo yksi veto, joten operaatio ei ulotu paperiin, alla oleviin vetoihin eikä myöhemmin piirrettyihin vetoihin. Kerros ei aiheuta kustannuksia vedoille, joissa ei ole pyyhintöjä: sellaisia on lähes kaikki, ja niille käytetään alkuperäistä polkua.
Omistajuus ratkaisee molemmat viat suoraan. Siirto liikuttaa pyyhintäpolut näytepisteiden mukana, joten siirretty veto kantaa aukkojansa mukanaan. Valinnan peittokuva piirtää saman Stroke-olion, joten valittu veto näyttää samat aukot. Kerrosjärjestyksellä ei enää ole väliä, koska pyyhintä kohdistuu aina vain omaan vetoon.
Kumoaminen toimii eleen tasolla: yksi merkintä luettelee jokaisen kyseisen eleen tuottaman (stroke, path)-parin, kumoaminen poistaa nämä polut ja uudelleen tekeminen lisää ne jälleen. Pyyhinnän alla olevaa mustetta ei koskaan muokata, joten mitään ei tarvitse rekonstruoida.
Reaaliaikainen palaute kulkee laattabittikartan kautta
Piirrettävä veto renderöidään tavallisesti yhdistetyn sivun päällä olevana peittokuvana. Pyyhintä ei voi toimia siellä, koska peittokuva on sekä paperin että musteen päällä, ja destination-out puhkaisisi paperin.
Siksi pyyhekumi kirjoittaa vetoihin heti, ja jokainen uusien näytteiden erä käynnistää vain vaikutusalueen suorakulmion paikallisen toiston. Laattaputki tyhjentää jo suorakulmion ja toistaa sen kanssa leikkaavat vedot; pyyhekumi käyttää samaa polkua eikä lisää toista piirron semantiikkaa.
Molemmat pyyhekumit rinnakkain
Työkalupalkissa on kaksi pyyhekumipainiketta yhden piilotetulla tilalla varustetun painikkeen sijaan. Osittainen pyyhekumi poistaa osan vedosta. Koko vedon pyyhekumi poistaa kokonaiset vedot kosketuksesta. Niiden säteet ovat erillisiä vakioita, ja molempien arvo on tällä hetkellä neljä pistettä.
Kokonaisen vedon poistaminen vie sen pyyhintäpolut mukanaan, koska ne ovat osa kyseistä vetoa, ja kumoaminen palauttaa molemmat yhdessä. Pyyhintäpolut ovat myös osa tallennettua tiedostoa, kvantisoituina kuten kaikki muukin: säde ja koordinaatit pisteen kymmenesosina.
Yksi rajoitus jää. Tyhjiin pyyhitty veto on edelleen datana olemassa. Se ei renderöidy miksikään, mutta lasso voi silti valita sen ja koko vedon pyyhekumi poistaa sen, ja se vie edelleen tilaa asiakirjassa. Täysin pyyhittyjen vetojen kerääminen vaatisi peittoastetestin, jota emme ole kirjoittaneet, joten ne jäävät toistaiseksi.
Kun toisen projektin malli lakkaa toimimasta omassasi, ero ei yleensä ole kopioimassasi koodissa. Se on ominaisuuksissa, joita siinä projektissa ei ole.