Lulucat

రెండు ఎరేజర్లు, ఎరేజింగ్ స్ట్రోక్‌కే ఎందుకు చెందుతుంది

Gaoge ZhangGaoge Zhang

ఎరేజర్ స్ట్రోక్‌ను ప్రత్యేక ఎలిమెంట్‌గా ఉంచడం సహజమైన డిజైన్. ఆబ్జెక్ట్‌ను కదపడం దాన్ని పాడు చేస్తుంది; Lulucat Notes‌లో ఎరేజింగ్, సిరాను తొలగించే స్ట్రోక్‌కే చెందుతుంది.

నవీకరించబడింది

నోట్‌బుక్‌లో ఏదైనా చెరిపేటప్పుడు, మనం రెండు వేర్వేరు విషయాలను ఉద్దేశిస్తాం. కొన్నిసార్లు ఒక గుర్తు తప్పుగా ఉంటుంది; అప్పుడు ఆ గుర్తంతా పోవాలి: గైడ్ లైన్, కొట్టివేసిన పదం, లేదా విశ్రాంతిగా ఉంచిన అరచేతి వల్ల పడిన అదనపు స్ట్రోక్. కొన్నిసార్లు గుర్తులోని కొంత భాగమే తప్పు: అక్షరంలో సగం, డయాగ్రామ్‌లోని ఒక శాఖ, లేదా వాక్యాన్ని దాటి వెళ్లిన హైలైటర్ స్వీప్ చివర. Lulucat Notes ఇప్పుడు రెండింటినీ రెండు వేర్వేరు టూల్స్‌గా అందిస్తుంది.

కష్టమైన డిజైన్ ప్రశ్న ఎరేజింగ్ ఎక్కడ ఉండాలి అనేదే.

స్ట్రోక్ ఎరేజర్ ముందుగా వచ్చింది

మొదటి ఎరేజర్ మొత్తం స్ట్రోక్‌లను తొలగించింది. ఒక్క టచ్ ప్రతి స్ట్రోక్‌ను పరీక్షిస్తుంది: bounding boxలు దాదాపు అన్నింటినీ ముందే తిరస్కరిస్తాయి; మిగిలిన వాటిపై ఎరేజర్ radiusకు, ఆ segment వెంబడి interpolate చేసిన stroke radiusకు కలిపిన విలువతో పోల్చి point-to-segment squared distance test జరుగుతుంది. వెడల్పు pressureతో మారుతుంది; కాబట్టి ఒకే nominal width వాడితే యూజర్ తాకని పలుచని స్ట్రోక్‌లు తొలగిపోతాయి, తాకిన మందమైనవి మాత్రం మిస్ అవుతాయి.

ఒక gesture ఒకే undo entryగా merge అవుతుంది; ఆ entry తొలగించిన ప్రతి stroke‌ను దాని అసలు indexతో పాటు నిల్వ చేస్తుంది. Undo వాటిని reverse orderలో మళ్లీ insert చేస్తుంది, కాబట్టి stacking order ఉన్నట్టుగానే తిరిగి వస్తుంది.

ఈ ఎరేజర్ వేగంగా, అంచనా వేయగలిగేలా ఉంటుంది, కానీ ఒక పదంలో సగం భాగాన్ని తొలగించలేడు.

MaLiang ఎరేజర్‌ను బ్రష్‌గా చేస్తుంది

మనం ఇప్పటికే highlighter stamp modelను తీసుకున్న MIT-licensed drawing framework అయిన MaLiang, partial erasingకు 24 linesలో సమాధానం ఇస్తుంది. దాని Eraser, Brush యొక్క subclass; add చేయడానికి బదులు subtract చేయడానికి blend options అనే ఒక్క విషయాన్నే override చేస్తుంది. ఒక eraser stroke, మిగతా అన్ని strokesలాగే అదే listలోని ఒక element. Undo ఆ elementను తొలగిస్తుంది. ఇప్పటికే ఉన్న ఏ stroke కూడా మార్చబడదు, ఎందుకంటే erasure list orderలో replay చేసినప్పుడే జరుగుతుంది.

మేము ఆ modelను ship చేశాం; రెండు device sessions దాన్ని పాడు చేశాయి.

ఆబ్జెక్ట్‌ను కదపడం ఎరేజింగ్‌కు యజమాని లేకపోవడాన్ని బయటపెడుతుంది

మొదటి రిపోర్ట్: lassoతో strokesను ఎంచుకుని drag చేస్తే, రంధ్రం వెనుకే మిగిలిపోతుంది.

స్ట్రోక్‌లను కదపడానికి ముందు, తర్వాత రెండు ఎరేజర్ మోడళ్లను పోల్చే నాలుగు ప్యానెల్‌లు. ఎరేజర్‌కు స్వంత ఎలిమెంట్‌గా ఉన్నప్పుడు ఖాళీ పాత స్థానంలోనే ఉంటుంది; ఎరేజింగ్ స్ట్రోక్‌కు చెందినప్పుడు ఖాళీ సిరాతో పాటు కదులుతుంది.

అదే ఎరేజ్ చేసిన స్ట్రోక్‌లను కుడివైపుకు కదిపినవి. పైన: ఎరేజర్‌కు స్వంత ఎలిమెంట్ ఉంది. కింద: ఎరేజింగ్ స్ట్రోక్‌లకు చెందుతుంది.

ఎంపిక ఈ సమస్యను మరింత చెడ్డదిగా చేసింది. ఎంచుకున్న స్ట్రోక్‌లు bitmap నుంచి overlayలోకి lift అవుతాయి; eraser element లేకుండా వాటినే నేరుగా draw చేస్తారు. అందువల్ల ఎరేజ్ చేసిన స్ట్రోక్‌ను ఎంచుకున్న క్షణం అది మళ్లీ పూర్తిగా కనిపించింది.

రెండవ రిపోర్ట్: ఎరేజర్ హైలైటర్ పైన తేలుతూ కనిపించింది. మా renderer రెండు passesలో replay చేస్తుంది: హైలైటర్‌లు ముందు, పెన్‌లు తర్వాత, ఎందుకంటే హైలైటర్ ink, ink కింద ఉండాలి. ఒక eraser element రెండు passesలోనూ పాల్గొనాలి; లేకపోతే అది రెండు రకాల inkనూ తొలగించలేడు. పెన్ passలో పాల్గొనడం అంటే ప్రతి హైలైటర్ గీసిన తర్వాత అది నడవాలి; దాంతో ఎరేజర్ సమయపరంగా తర్వాత గీసిన హైలైటర్ స్ట్రోక్‌లను కూడా కత్తిరించింది.

ఈ రెండు వైఫల్యాల మూలం ఒకటే. MaLiangలో lasso లేదు, move లేదు, brushes మధ్య layer order లేదు; అందుకే యజమాని లేని element అక్కడ సరిపోతుంది. మా canvasలో ఈ మూడూ ఉన్నాయి. యజమాని లేని erasureకు సిరా కదిలినప్పుడు ఏమవుతుంది, ఇది ఏ layerపై పనిచేస్తోంది అనే ప్రశ్నలకు నిర్వచిత సమాధానం లేదు.

ఎరేజింగ్ స్ట్రోక్‌కే చెందుతుంది

ఇప్పుడు ప్రతి Stroke తన సొంత erase pathsను కలిగి ఉంటుంది. ఎరేజర్ తాను తాకిన స్ట్రోక్‌లను పరీక్షించి, వాటిలో ప్రతి దానికీ canvas coordinatesలో ఒక pathను జత చేస్తుంది. ఒక స్ట్రోక్‌ను render చేసేటప్పుడు దాని సిరాను, దాని సొంత 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కు అనుపాతంగా దాన్ని తొలగిస్తుంది:

ట్రాన్స్‌పరెన్సీ లేయర్‌లో destination ఆ ఒక్క స్ట్రోక్‌నే. కాబట్టి ఈ ఆపరేషన్ కాగితాన్ని, కింద గీసిన స్ట్రోక్‌లను, తర్వాత గీసే స్ట్రోక్‌లను తాకదు. ఎరేజింగ్ లేని స్ట్రోక్‌లకు ఈ layer వల్ల ఎలాంటి అదనపు ఖర్చు ఉండదు, అలాంటివే దాదాపు అన్నీ: అవి మునుపటి pathనే ఉపయోగిస్తాయి.

యాజమాన్యం ఈ రెండు వైఫల్యాలకు నేరుగా సమాధానం ఇస్తుంది. Translation erase pathsను sample pointsతో పాటు కదిలిస్తుంది, కాబట్టి కదిలించిన stroke తన ఖాళీలను కూడా వెంట తీసుకెళ్తుంది. Selection overlay అదే stroke objectను గీస్తుంది, కాబట్టి ఎంచుకున్న strokeలోనూ అదే ఖాళీలు కనిపిస్తాయి. Layer order ఇక ముఖ్యం కాదు, ఎందుకంటే erasure తన సొంత stroke తప్ప మరేదానికీ వర్తించదు.

Undo gestureపైనే పనిచేస్తుంది: ఒక entry ఆ gesture సృష్టించిన ప్రతి (stroke, path) జంటను జాబితా చేస్తుంది; Undo ఆ pathsను తొలగిస్తుంది, Redo వాటిని మళ్లీ append చేస్తుంది. Erasure కింద ఉన్న ink ఎప్పుడూ edit చేయబడదు, కాబట్టి ఏదీ reconstruct చేయాల్సిన అవసరం ఉండదు.

లైవ్ ఫీడ్‌బ్యాక్ టైల్ బిట్‌మ్యాప్ ద్వారా సాగుతుంది

సాధారణంగా గీస్తున్న stroke composited page పైన overlayగా render అవుతుంది. అక్కడ erasure పనిచేయదు, ఎందుకంటే ఆ 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లో ఉంటుంది.