இரண்டு அழிப்பான்கள், அழிப்பு ஏன் ஸ்ட்ரோக்குக்கே சொந்தமானது
அழிப்பு ஸ்ட்ரோக்கைத் தனி உறுப்பாக வைத்திருப்பது வெளிப்படையான வடிவமைப்பு. பொருளை நகர்த்துவது அதை உடைக்கிறது; Lulucat Notes-ல் அழிப்பு, அது மையை அழிக்கும் ஸ்ட்ரோக்குக்கே சொந்தமானது.
நோட்டுப் புத்தகத்தில் எதையாவது அழிக்கும் போது, மக்கள் இரண்டு வேறுபட்ட விஷயங்களைக் குறிக்கிறார்கள். சில நேரங்களில் ஒரு குறி தவறாக இருக்கும்; அப்போது முழுக் குறியும் அகல வேண்டும்: வழிகாட்டுக் கோடு, கோடிட்டு நீக்கிய சொல், அல்லது ஓய்வாக இருந்த உள்ளங்கையால் ஏற்பட்ட தேவையற்ற ஸ்ட்ரோக். சில நேரங்களில் குறியின் ஒரு பகுதி மட்டுமே தவறாக இருக்கும்: ஒரு எழுத்தின் பாதி, ஒரு வரைபடத்தின் கிளை, அல்லது வாக்கியத்தைத் தாண்டிச் சென்ற ஹைலைட்டர் sweep-ன் வால். Lulucat Notes இப்போது இரண்டையும் தனித்தனி கருவிகளாக வழங்குகிறது.
கடினமான வடிவமைப்புக் கேள்வி, அழிப்பு எங்கே இருக்க வேண்டும் என்பதே.
முதலில் வந்தது ஸ்ட்ரோக் அழிப்பான்
முதல் அழிப்பான் முழு ஸ்ட்ரோக்குகளையும் நீக்கியது. ஒரு தொடுதல் ஒவ்வொரு ஸ்ட்ரோக்கையும் சோதிக்கிறது: bounding box-கள் கிட்டத்தட்ட அனைத்தையும் நிராகரிக்கின்றன; மீதமுள்ளவற்றுக்கு, அழிப்பானின் radius-க்கும் அந்த segment முழுவதும் இடைக்கணிக்கப்பட்ட stroke radius-க்கும் உள்ள கூட்டுத்தொகையுடன் ஒப்பிட்டு, point-to-segment squared distance test செய்யப்படுகிறது. அழுத்தத்துக்கு ஏற்ப அகலம் மாறுவதால், ஒரே nominal width-ஐ பயன்படுத்தினால் பயனர் தொடாத மெல்லிய strokes அழிந்துவிடும்; தொடப்பட்ட தடிமனான strokes தவறிவிடும்.
ஒரே gesture ஒரு undo entry-ஆக இணைகிறது; அந்த entry நீக்கப்பட்ட ஒவ்வொரு stroke-ஐயும் அதன் original index-உடன் சேமிக்கிறது. Undo அவற்றை reverse order-ல் மீண்டும் சேர்க்கிறது, எனவே stacking order இருந்தபடியே திரும்புகிறது.
இந்த அழிப்பான் வேகமானது, கணிக்கக்கூடியது, மேலும் ஒரு சொல்லின் பாதியை அழிக்க முடியாதது.
MaLiang அழிப்பானை ஒரு brush ஆக்குகிறது
நாம் ஏற்கெனவே highlighter stamp model-ஐ கடன் பெற்றிருக்கும் MIT உரிமம் பெற்ற drawing framework-ஆன MaLiang, partial erasing-க்கு 24 வரிகளில் பதில் அளிக்கிறது. அதன் Eraser, Brush-ன் subclass; அது blend options எனும் ஒரே விஷயத்தை override செய்து, add-க்குப் பதிலாக subtract செய்கிறது. ஒரு eraser stroke, மற்ற எல்லா strokes-உம் இருக்கும் அதே list-ல் உள்ள ஒரு element. Undo அந்த element-ஐ நீக்குகிறது. ஏற்கெனவே உள்ள எந்த stroke-மும் மாற்றப்படுவதில்லை, ஏனெனில் அழிப்பு list order-ல் replay செய்யும்போதுதான் நிகழ்கிறது.
அந்த model-ஐ வெளியிட்டோம்; இரண்டு device sessions அதை உடைத்தன.
பொருளை நகர்த்துவது விடுபட்ட owner-ஐ வெளிப்படுத்துகிறது
முதல் அறிக்கை: lasso மூலம் strokes-ஐத் தேர்ந்தெடுத்து, drag செய்தால், துளை பின்னால் தங்குகிறது.

அழிக்கப்பட்ட அதே ஸ்ட்ரோக்குகள் வலப்புறம் நகர்த்தப்பட்டுள்ளன. மேலே: அழிப்பான் தனி element. கீழே: அழிப்பு ஸ்ட்ரோக்குகளுக்குச் சொந்தமானது.
தேர்வு நிலைமையை இன்னும் மோசமாக்கியது. தேர்ந்தெடுக்கப்பட்ட strokes bitmap-இலிருந்து overlay-க்குள் எடுத்துச் செல்லப்படுகின்றன; அங்கே eraser element இல்லாமல் அவை நேரடியாக வரையப்படுகின்றன. ஆகவே அழிக்கப்பட்ட ஒரு stroke-ஐத் தேர்ந்தெடுத்த உடனே அது மீண்டும் முழுமையாகத் தோன்றியது.
இரண்டாவது அறிக்கை: அழிப்பான் highlighter-க்கு மேலே மிதந்தது. எங்கள் renderer இரண்டு passes-ல் replay செய்கிறது: highlighters முதலில், pens இரண்டாவது; ஏனெனில் highlighter ink, ink-க்குக் கீழே இருக்க வேண்டும். ஒரு eraser element இரண்டு passes-லும் பங்கேற்க வேண்டும்; இல்லையெனில் அது இரண்டு வகை ink-ஐயும் அழிக்க முடியாது. அது pen pass-ல் பங்கேற்பது, அனைத்து highlighter-களும் வரையப்பட்ட பிறகு இயங்க வேண்டும் என்பதாகும்; அதனால் காலத்தில் பின்னர் வரையப்பட்ட highlighter strokes-களையும் அழிப்பான் வெட்டியது.
இரண்டு தோல்விகளுக்கும் ஒரே மூலமே உள்ளது. MaLiang-க்கு lasso, move, அல்லது brushes-க்கிடையிலான layer order எதுவும் இல்லை; எனவே owner இல்லாத element அங்கே போதுமானதாகிறது. எங்கள் canvas-ல் இம்மூன்றும் உள்ளன; owner இல்லாத erasure-க்கு ink நகரும்போது என்ன நடக்கும், இது எந்த layer-ல் செயல்படுகிறது என்ற கேள்விகளுக்கு வரையறுக்கப்பட்ட பதில் இல்லை.
ஸ்ட்ரோக்குக்குச் சொந்தமான அழிப்பு
இப்போது ஒவ்வொரு Stroke-மும் தன் சொந்த erase paths-ஐக் கொண்டுள்ளது. அழிப்பான் எந்த ஸ்ட்ரோக்குகளைத் தொடுகிறது என்பதைச் சோதித்து, ஒவ்வொன்றிலும் canvas coordinates-ல் ஒரு path-ஐ append செய்கிறது. ஒரு ஸ்ட்ரோக்கை render செய்யும்போது, அதன் ink-ஐயும் அதன் சொந்த erasures-ஐயும் ஒரே transparency layer-க்குள் வரைகிறது:
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, source alpha-வுக்கு ஏற்ப destination-ஐத் தக்கவைத்து அதிலிருந்து கழிக்கிறது:
ஒரு transparency layer-க்குள் destination என்பது அந்த ஒரு ஸ்ட்ரோக் மட்டுமே. எனவே இந்தச் செயல்பாடு paper-ஐயோ, கீழே உள்ள ஸ்ட்ரோக்குகளையோ, பின்னர் வரையப்படும் ஸ்ட்ரோக்குகளையோ எட்ட முடியாது. அழிப்புகள் இல்லாத ஸ்ட்ரோக்குகளுக்கு இந்த layer எந்தச் செலவையும் ஏற்படுத்தாது; கிட்டத்தட்ட எல்லா ஸ்ட்ரோக்குகளும் இப்படித்தான், எனவே அவற்றுக்கு அசல் path பயன்படுத்தப்படுகிறது.
Ownership இரண்டு தோல்விகளுக்கும் நேரடியாகப் பதிலளிக்கிறது. Translation sample points-ஐப் போலவே erase paths-ஐயும் நகர்த்துகிறது; எனவே நகர்த்தப்பட்ட stroke தன் இடைவெளிகளையும் சுமந்து செல்கிறது. Selection overlay அதே stroke object-ஐ வரைவதால், தேர்ந்தெடுக்கப்பட்ட stroke-க்கும் அதே இடைவெளிகள் தெரிகின்றன. Layer order இனி முக்கியமில்லை, ஏனெனில் ஒரு அழிப்பு அதன் சொந்த stroke-ஐத் தவிர வேறு எதற்கும் பொருந்தாது.
Undo gesture-ல் செயல்படுகிறது: ஒரு entry அந்த gesture உருவாக்கிய ஒவ்வொரு (stroke, path) pair-ஐயும் பட்டியலிடுகிறது; undo அந்த paths-ஐ நீக்குகிறது, redo அவற்றை மீண்டும் append செய்கிறது. அழிப்புக்குக் கீழே உள்ள ink ஒருபோதும் திருத்தப்படுவதில்லை; எனவே எதையும் மீண்டும் உருவாக்க வேண்டியதில்லை.
நேரடி feedback tile bitmap வழியாகச் செல்கிறது
வரையப்படும் stroke வழக்கமாக composited page-க்கு மேலே overlay-ஆக render செய்யப்படுகிறது. அங்கே அழிப்பு வேலை செய்ய முடியாது, ஏனெனில் அந்த overlay paper-ன் மீதும் ink-ன் மீதும் அமர்ந்திருக்கிறது; destination-out paper-ஐயும் துளைத்துவிடும்.
ஆகவே அழிப்பான் உடனடியாக strokes-க்குள் எழுதுகிறது; புதிய samples கொண்ட ஒவ்வொரு batch-ம் பாதிக்கப்பட்ட rectangle-ஐ மட்டும் local replay செய்யத் தூண்டுகிறது. Tile pipeline ஏற்கெனவே ஒரு rectangle-ஐ clear செய்து, அதனை intersect செய்யும் strokes-ஐ replay செய்கிறது; அழிப்பான் அதே பாதையை மீண்டும் பயன்படுத்துகிறது, இரண்டாவது drawing semantic எதையும் சேர்ப்பதில்லை.
இரண்டு அழிப்பான்கள், அருகருகே
Toolbar-ல் மறைக்கப்பட்ட mode கொண்ட ஒரே button-க்குப் பதிலாக இரண்டு eraser buttons உள்ளன. Partial eraser ஒரு stroke-ன் பகுதியை அகற்றுகிறது. Stroke eraser தொடும்போதே முழு strokes-ஐ நீக்குகிறது. அவற்றின் radii தனித்தனி constants; இரண்டும் தற்போது 4 points.
ஒரு முழு stroke-ஐ அழிப்பது அதன் erase paths-ஐயும் அதனுடன் எடுத்துச் செல்கிறது, ஏனெனில் அவை அந்த stroke-ன் ஒரு பகுதியாகும்; undo இரண்டையும் ஒன்றாகத் திரும்பக் கொண்டுவருகிறது. Erase paths சேமிக்கப்பட்ட file-ன் ஒரு பகுதியாகவும் உள்ளன; மற்ற அனைத்தையும் போலவே அவையும் quantize செய்யப்படுகின்றன: radius மற்றும் coordinates, ஒரு point-ன் பத்தில் ஒரு பகுதி அளவாக.
ஒரு வரம்பு இன்னும் உள்ளது. முற்றிலும் எதுவுமின்றி அழிக்கப்பட்ட ஒரு stroke data-ஆகத் தொடர்ந்து இருக்கும். அது எதுவுமாக render ஆகாது; இருந்தாலும் lasso அதைத் தேர்ந்தெடுக்கலாம், stroke eraser அதை நீக்கலாம், மேலும் அது document-ல் இடத்தையும் பிடித்துக்கொண்டிருக்கும். முழுமையாக அழிக்கப்பட்ட strokes-ஐ அகற்ற, நாம் இன்னும் எழுதாத coverage test தேவை; எனவே இப்போதைக்கு அவை அப்படியே இருக்கும்.
வேறொரு project-ல் இருந்து எடுத்த model உங்களுடைய project-ல் வேலை செய்யாமல் போனால், வேறுபாடு பொதுவாக நீங்கள் copy செய்த code-ல் இருப்பதில்லை. அந்த project-க்கு இல்லாத features-ல்தான் அது இருக்கும்.