രണ്ട് ഇറേസറുകൾ, മായിക്കൽ സ്ട്രോക്കിന്റേതാകുന്നത് എന്തുകൊണ്ട്
സ്വന്തം ഘടകമായ ഇറേസർ സ്വാഭാവിക രൂപകൽപ്പനയാണ്. പക്ഷേ ഒബ്ജക്റ്റ് നീക്കുമ്പോൾ അത് തകരുന്നു; അതിനാൽ Lulucat Notes-ൽ മഷി നീക്കുന്ന സ്ട്രോക്കിന്റേതാണ് മായിക്കൽ.
ഒരു നോട്ട്ബുക്കിൽ മായിക്കുമ്പോൾ ആളുകൾ ഉദ്ദേശിക്കുന്നത് രണ്ട് വ്യത്യസ്ത കാര്യങ്ങളാണ്. ചിലപ്പോൾ ഒരു അടയാളം തെറ്റായിരിക്കും, അതിനാൽ ആ അടയാളം മുഴുവനും പോകണം: ഒരു guide line, വരയിട്ട് കടന്നുപോയ വാക്ക്, വിശ്രമിച്ചിരിക്കുന്ന കൈപ്പത്തിയിൽ നിന്ന് ശേഷിച്ച stray stroke. ചിലപ്പോൾ അടയാളത്തിന്റെ ഒരു ഭാഗം മാത്രമാണ് തെറ്റിയത്: ഒരു അക്ഷരത്തിന്റെ പകുതി, ഒരു diagram-ന്റെ ഒരു branch, വാക്യത്തിന് അപ്പുറം നീണ്ടുപോയ highlighter sweep-ന്റെ tail. Lulucat Notes ഇപ്പോൾ ഇവ രണ്ടും രണ്ട് വേറിട്ട tools ആയി നൽകുന്നു.
കൂടുതൽ കഠിനമായ ഡിസൈൻ ചോദ്യം പിക്സലുകൾ എങ്ങനെ നീക്കം ചെയ്യാം എന്നതല്ല. മായിക്കൽ എവിടെയാണ് നിലനിൽക്കുന്നത് എന്നതാണ്.
സ്ട്രോക്ക് ഇറേസറാണ് ആദ്യം വന്നത്
ആദ്യത്തെ ഇറേസർ മുഴുവൻ strokes നീക്കം ചെയ്തു. ഓരോ touch-ലും എല്ലാ strokes-ഉം പരിശോധിക്കുന്നു: bounding boxes മിക്കവാറും എല്ലാം തള്ളിക്കളയുന്നു, ശേഷിക്കുന്നവയ്ക്ക് eraser radius-ന്റെയും ആ segment-ലുടനീളം interpolate ചെയ്ത stroke radius-ന്റെയും തുകയെതിരെ point-to-segment squared-distance test നടത്തുന്നു. Pressure അനുസരിച്ച് width മാറുന്നതിനാൽ, ഒരൊറ്റ nominal width ഉപയോഗിച്ചാൽ ഉപയോക്താവ് തൊടാത്ത നേർത്ത strokes നീക്കം ചെയ്യുകയും തൊട്ട കട്ടിയുള്ള strokes ഒഴിവാക്കുകയും ചെയ്യും.
ഒരു gesture ഒരൊറ്റ undo entry ആയി ലയിക്കുന്നു. ആ entry നീക്കം ചെയ്ത ഓരോ stroke-ഉം അതിന്റെ original index-നൊപ്പം സൂക്ഷിക്കുന്നു. Undo അവയെ reverse order-ൽ വീണ്ടും ചേർക്കുന്നു, അതിനാൽ stacking order കൃത്യമായി പഴയപടിയാകും.
ഈ ഇറേസർ വേഗതയേറിയതും പ്രവചിക്കാവുന്നതുമാണ്, പക്ഷേ ഒരു വാക്കിന്റെ പകുതി നീക്കം ചെയ്യാൻ കഴിയില്ല.
MaLiang ഇറേസറിനെ ഒരു ബ്രഷാക്കുന്നു
ഞങ്ങൾ ഇതിനകം highlighter stamp model കടമെടുത്തിട്ടുള്ള MIT-licensed drawing framework ആയ MaLiang, partial erasing-ന് 24 lines-ൽ ഉത്തരം നൽകുന്നു. അതിലെ Eraser ഒരു Brush subclass ആണ്; blend options എന്ന ഒരൊറ്റ കാര്യത്തെ override ചെയ്ത് add ചെയ്യുന്നതിന് പകരം subtract ചെയ്യുന്നു. Eraser stroke മറ്റെല്ലാ strokes-ഉമുള്ള അതേ list-ലെ ഒരു element ആണ്. Undo ആ element നീക്കം ചെയ്യുന്നു. നിലവിലുള്ള ഒരു stroke-ഉം മാറ്റപ്പെടുന്നില്ല, കാരണം erasure replay സമയത്ത് list order-ൽ മാത്രമാണ് സംഭവിക്കുന്നത്.
ഞങ്ങൾ ആ model ship ചെയ്തു, രണ്ട് device sessions അതിനെ തകർത്തു.
ഒബ്ജക്റ്റ് നീക്കുന്നത് ഇല്ലാത്ത ഉടമയെ വെളിപ്പെടുത്തുന്നു
ആദ്യ റിപ്പോർട്ട് ഇതായിരുന്നു: lasso ഉപയോഗിച്ച് strokes തിരഞ്ഞെടുക്കുകയും വലിച്ചുനീക്കുകയും ചെയ്താൽ, വിടവ് പിന്നിൽ അവിടെത്തന്നെ നിൽക്കുന്നു.

അതേ മായിച്ച strokes വലത്തേക്ക് നീക്കിയത്. മുകളിൽ: eraser സ്വന്തമായൊരു element ആണ്. താഴെ: erasure strokes-ന്റേതാണ്.
Selection അത് കൂടുതൽ മോശമാക്കി. തിരഞ്ഞെടുത്ത strokes bitmap-ൽ നിന്ന് overlay-യിലേക്ക് ഉയർത്തി, eraser element ഇല്ലാതെ നേരിട്ട് വരയ്ക്കുന്നു. അതിനാൽ മായിച്ച stroke തിരഞ്ഞെടുക്കുന്ന നിമിഷം തന്നെ അത് വീണ്ടും മുഴുവനായി കാണപ്പെട്ടു.
രണ്ടാമത്തെ റിപ്പോർട്ട്: eraser highlighter-ന് മുകളിലൂടെ ഒഴുകി. Highlighter ink സാധാരണ ink-ന് അടിയിലായിരിക്കേണ്ടതിനാൽ, ഞങ്ങളുടെ renderer രണ്ട് passes-ലാണ് replay ചെയ്യുന്നത്: ആദ്യം highlighters, പിന്നെ pens. ഒരു eraser element-ന് രണ്ട് passes-ലും പങ്കെടുക്കണം; അല്ലെങ്കിൽ രണ്ട് തരത്തിലുള്ള ink-ഉം മായിക്കാൻ അതിന് കഴിയില്ല. Pen pass-ൽ പങ്കെടുക്കുന്നത് എല്ലാ highlighter-ുകളും വരച്ചശേഷം പ്രവർത്തിക്കുക എന്നാണ്. അതിനാൽ സമയക്രമത്തിൽ പിന്നീട് വരച്ച highlighter strokes-നെയും eraser മുറിച്ചുകളഞ്ഞു.
രണ്ട് പരാജയങ്ങൾക്കും ഒരേ ഉറവിടമാണ്. MaLiang-ന് lasso-യോ move-ഓ brushes-ക്കിടയിലെ layer order-ഓ ഇല്ല, അതിനാൽ owner ഇല്ലാത്ത ഒരു element അവിടെ മതിയാകും. ഞങ്ങളുടെ canvas-ന് ഇവ മൂന്നുമുണ്ട്; owner ഇല്ലാത്ത ഒരു erasure-ന് “മഷി നീങ്ങുമ്പോൾ എന്ത് സംഭവിക്കും” എന്നതിനും “ഇത് ഏത് layer-ലാണ് പ്രവർത്തിക്കുന്നത്” എന്നതിനും നിർവചിച്ച ഉത്തരമില്ല.
സ്ട്രോക്കിന്റെ ഉടമസ്ഥതയിലുള്ള മായിക്കൽ
ഓരോ Stroke-ഉം ഇപ്പോൾ സ്വന്തം erase paths വഹിക്കുന്നു. ഇറേസർ ഏത് strokes-നെയാണ് തൊടുന്നതെന്ന് പരിശോധിച്ച്, ഓരോന്നിലേക്കും canvas coordinates-ൽ ഒരു path ചേർക്കുന്നു. ഒരു stroke 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 destination-നെ നിലനിർത്തുകയും source alpha-യുടെ അനുപാതത്തിൽ അതിൽ നിന്ന് നീക്കം ചെയ്യുകയും ചെയ്യുന്നു:
ഒരു transparency layer-ന്റെ ഉള്ളിൽ destination ആ ഒറ്റ stroke മാത്രമാണ്. അതിനാൽ ഈ operation paper-ലേക്കോ അടിയിലുള്ള strokes-ലേക്കോ പിന്നീട് വരയ്ക്കുന്ന strokes-ലേക്കോ എത്തില്ല. Erasures ഇല്ലാത്ത strokes-ന് layer-ന്റെ ചെലവില്ല, അവയിൽ ഏതാണ്ട് എല്ലാം അത്തരം strokes ആണ്: അവ പഴയ path തന്നെയാണ് ഉപയോഗിക്കുന്നത്.
Ownership രണ്ട് പരാജയങ്ങൾക്കും നേരിട്ട് ഉത്തരം നൽകുന്നു. Translation sample points-നൊപ്പം erase paths-ഉം നീക്കുന്നു, അതിനാൽ നീക്കിയ stroke സ്വന്തം വിടവുകളെയും കൂട്ടിക്കൊണ്ടുപോകുന്നു. Selection overlay അതേ stroke object വരയ്ക്കുന്നതിനാൽ, തിരഞ്ഞെടുത്ത stroke അതേ വിടവുകളോടെ കാണപ്പെടുന്നു. ഒരു erasure സ്വന്തം stroke-ൽ മാത്രമേ പ്രയോഗിക്കൂ, അതിനാൽ layer order ഇനി പ്രസക്തമല്ല.
Undo gesture-ലാണ് പ്രവർത്തിക്കുന്നത്: ഒരു entry ആ gesture സൃഷ്ടിച്ച ഓരോ (stroke, path) pair-ഉം പട്ടികപ്പെടുത്തുന്നു; undo ആ paths നീക്കം ചെയ്യുകയും redo അവ വീണ്ടും append ചെയ്യുകയും ചെയ്യുന്നു. ഒരു erasure-ന്റെ അടിയിലുള്ള ink ഒരിക്കലും edit ചെയ്യപ്പെടുന്നില്ല, അതിനാൽ ഒന്നും പുനർനിർമ്മിക്കേണ്ടതില്ല.
ലൈവ് ഫീഡ്ബാക്ക് tile bitmap വഴിയാണ് പോകുന്നത്
വരച്ചുകൊണ്ടിരിക്കുന്ന stroke സാധാരണ composited page-ന് മുകളിലുള്ള ഒരു overlay ആയി render ചെയ്യപ്പെടുന്നു. അവിടെ erasure പ്രവർത്തിക്കില്ല, കാരണം ആ overlay paper-ന്റെയും ink-ന്റെയും മുകളിലാണ് ഇരിക്കുന്നത്; destination-out paper-ലും ഒരു തുളയുണ്ടാക്കും.
അതിനാൽ ഇറേസർ ഉടൻ തന്നെ strokes-ലേക്ക് എഴുതുന്നു, ഓരോ പുതിയ samples batch-ഉം ബാധിച്ച rectangle-ന്റെ local replay trigger ചെയ്യുന്നു. Tile pipeline ഇതിനകം ഒരു rectangle clear ചെയ്യുകയും അതിനെ intersect ചെയ്യുന്ന strokes replay ചെയ്യുകയും ചെയ്യുന്നു; ഇറേസർ അതേ path വീണ്ടും ഉപയോഗിക്കുകയും രണ്ടാമതൊരു drawing semantic ചേർക്കാതിരിക്കുകയും ചെയ്യുന്നു.
രണ്ട് ഇറേസറുകൾ, ഒപ്പം ഒപ്പം
ടൂൾബാറിൽ ഒളിഞ്ഞിരിക്കുന്ന mode ഉള്ള ഒരൊറ്റ button-ന് പകരം രണ്ട് eraser buttons ഉണ്ട്. Partial eraser ഒരു stroke-ന്റെ ഭാഗം നീക്കം ചെയ്യുന്നു. Stroke eraser തൊടുമ്പോൾ മുഴുവൻ stroke-ഉം നീക്കം ചെയ്യുന്നു. അവയുടെ radii വേറിട്ട constants ആണ്, രണ്ടും ഇപ്പോൾ 4 points വീതം.
ഒരു മുഴുവൻ stroke നീക്കം ചെയ്യുമ്പോൾ അതിന്റെ erase paths-ഉം കൂടെ പോകുന്നു, കാരണം അവ ആ stroke-ന്റെ ഭാഗമാണ്; undo രണ്ടിനെയും ഒരുമിച്ച് തിരികെ കൊണ്ടുവരുന്നു. മറ്റെല്ലാ കാര്യങ്ങളെയും പോലെ erase paths-ഉം saved file-ന്റെ ഭാഗമാണ്, ഒരു പോയിന്റിന്റെ പത്തിലൊന്നായി quantize ചെയ്തവ: radius-ഉം coordinates-ഉം.
ഒരു പരിമിതി ഇപ്പോഴും ഉണ്ട്. ഒന്നും ബാക്കിയില്ലാത്തവിധം മായിച്ച stroke data ആയി ഇപ്പോഴും നിലനിൽക്കും. അത് ഒന്നും render ചെയ്യില്ല, പക്ഷേ lasso-യ്ക്ക് അതിനെ ഇപ്പോഴും select ചെയ്യാം, stroke eraser-ന് അത് ഇപ്പോഴും delete ചെയ്യാം, കൂടാതെ document-ൽ അത് സ്ഥലം കൈവശം വയ്ക്കുകയും ചെയ്യും. പൂർണ്ണമായി മായിച്ച strokes ശേഖരിക്കാൻ ഞങ്ങൾ ഇതുവരെ എഴുതാത്ത ഒരു coverage test വേണം, അതിനാൽ ഇപ്പോൾ അവ തുടരുന്നു.
മറ്റൊരു project-ൽ നിന്നുള്ള ഒരു model നിങ്ങളുടേതിൽ പ്രവർത്തിക്കാതാകുമ്പോൾ, വ്യത്യാസം സാധാരണയായി നിങ്ങൾ copy ചെയ്ത code-ലല്ല. ആ project-ന് ഇല്ലാത്ത features-ലാണ്.