ہم نے تین ہائی لائٹر جیومیٹری انجنز کو اسٹیمپس سے کیوں بدلا
حقیقی Apple Pencil ڈیٹا نے مصنوعی ٹیسٹ سے چھپی خامیاں دکھائیں، اور Lulucat Notes کو تین آؤٹ لائن انجنز سے MaLiang اسٹیمپ ماڈل تک پہنچایا۔
Lulucat Notes کا آغاز ایک روایتی ہائی لائٹر رینڈرر سے ہوا: وہ نمونہ شدہ راستے کے گرد ایک جیومیٹرک آؤٹ لائن (بیرونی خاکہ) بناتا، پھر اسے ایک بار نیم شفاف رنگ سے بھر دیتا تھا۔ ایک ہی بار بھرنے سے وہ گہری پٹیاں نہیں بنتیں جو نیم شفاف حصوں کے اوورلیپ ہونے پر ظاہر ہوتی ہیں۔ اس طرح ہر جوڑ، خود تقاطع، کیپ اور مختصر اسٹروک بھی اسی جیومیٹری کے مسئلے کا حصہ بن جاتے ہیں۔
حسبِ ضرورت جیومیٹری کی تین نسلوں نے ہر بار خامیوں کی ایک قسم دور کی اور دوسری سامنے لائی۔ اب جو رینڈرر ہم جاری کرتے ہیں، وہ MaLiang پر مبنی نرم گول اسٹیمپس استعمال کرتا ہے۔ MaLiang، Harley-xk کا MIT لائسنس یافتہ اوپن سورس ڈرائنگ فریم ورک ہے۔ آؤٹ لائن کی ناکامیوں کے ایک پورے زمرے کو ختم کرنے کے بدلے ہم نے زیادہ گہرے خود تقاطع اور دباؤ کے ساتھ پتلے ہوتے سروں کو قبول کیا۔

228% زوم پر اصل ڈیوائس اسکرین شاٹ۔ کئی اسٹروکس کے دونوں سروں پر چھوٹے ہکس دکھائی دیتے ہیں۔
حقیقی لکھائی نے ایسے ہکس پیدا کیے جو مصنوعی مناظر میں نہیں آئے
ہمارے مصنوعی مناظر میں سیدھی لکیریں، قوسیں، مختصر ٹیپس، واپس پلٹنے والی لکیریں، دباؤ میں تبدیلیاں اور تیز موڑ شامل تھے، اور سب صاف رینڈر ہوئے۔ حقیقی چینی لکھائی نے بہت سے اسٹروکس کے آغاز اور اختتام پر تقریباً 1–3 پوائنٹس لمبے ہکس پیدا کیے۔
لہٰذا ہم نے ایپ میں save button شامل کیا اور 29 مکمل اسٹروکس ریکارڈ کیے۔ ہر نمونے کے ساتھ اس کا مقام، نصف قطر، دباؤ، سمت زاویہ، ارتفاع، ٹائم اسٹیمپ اور UIKit estimation flags محفوظ رہے۔ ایک آف لائن پروگرام نے اس JSON کو decode کیا اور وہی Stroke.swift، StrokeRenderer.swift اور HighlighterStrokeBuilder.swift فائلیں compile کیں جو ایپ استعمال کرتی ہے۔ اس کا نتیجہ ڈیوائس اسکرین شاٹ کے ہر اسٹروک سے، ہکس سمیت، بالکل مطابقت رکھتا تھا۔
چونکہ آف لائن رینڈرر نے صرف ریکارڈ شدہ ان پٹ سے خرابی دوبارہ پیدا کر دی تھی، اس لیے سبب ڈسپلے کے برتاؤ کے بجائے نمونوں اور جیومیٹری میں تھا۔ اب ہم رینڈرر میں داخل ہونے والے عین نمونے پڑھ سکتے تھے۔
ہمارے پہلے قیاس نے سطح کو چھوتے اور سطح سے اٹھتے وقت Pencil کی تخمینہ شدہ سمت کو ذمہ دار ٹھہرایا۔ ڈیٹا نے اسے رد کر دیا۔ تمام 29 اسٹروکس میں پہلے اور آخری آٹھ نمونوں کے دوران سمت زاویہ میں زیادہ سے زیادہ 0.09 ریڈیئن اور ارتفاع میں زیادہ سے زیادہ 0.02 ریڈیئن کی تبدیلی آئی، اور اس iPad پر ہر estimation flag false تھا۔ Pencil کی سمت مستحکم رہی، جبکہ دباؤ اور سمت تیزی سے بدلے۔
دباؤ کی ایک نچلی حد ڈیٹا کے صاف خلا سے نکلی
ریکارڈ کیے گئے ہر اسٹروک کے آخری نمونے میں دباؤ 0.000 تھا۔ لکھائی کے نمونوں کا دباؤ 0.01 یا اس سے زیادہ تھا، جبکہ قلم کے سطح سے اٹھنے کے بعد ریکارڈ کیے گئے نمونوں کا دباؤ 0.002 یا اس سے کم تھا۔ یہ ہوا میں موجود نمونے اکثر 2–7 پوائنٹس تک جاری رہے اور 0.8–9.0 پوائنٹس کا فاصلہ طے کیا، جبکہ ان کی سمت لکھی ہوئی لکیر سے تقریباً 90 ڈگری تک مڑ سکتی تھی۔
اسٹروک 2 اس طریقۂ کار کو دکھاتا ہے۔ اس کا جسم 143 سے 180 ڈگری کے درمیان ختم ہوا۔ کم دباؤ والی دم پھر −90 سے −67 ڈگری تک مڑی اور مزید 8.5 پوائنٹس آگے گئی۔ آؤٹ لائن رینڈرر نے آخری ہوا میں موجود نقطے کو حتمی نقطہ سمجھا، اس لیے اس نے جیومیٹری کا ایک تنگ ٹکڑا اس نقطے کی سمت کھینچ دیا۔
ناپے گئے دباؤ میں لکھائی اور ہوا میں حرکت کے درمیان تقریباً ایک پورے درجۂ مقدار کا فرق ہے، اس لیے ہم نے cutoff اسی خلا کے اندر رکھا:
private static let pressureFloor: CGFloat = 0.005
دونوں سروں پر موجود صرف کم دباؤ والے نمونے ہٹائے جاتے ہیں۔ اسٹروک کے درمیان کم دباؤ والا نمونہ اس کا حصہ رہتا ہے۔ یہ قاعدہ ناپے گئے واقعے کی حد کی پیروی کرتا ہے اور لکھی ہوئی راہ کو غیر ترمیم شدہ چھوڑتا ہے۔

تراشنے سے پہلے رینڈرر کیپ کو ہوا میں موجود نمونوں کے ساتھ باندھ دیتا ہے۔ سبز نقطے خام نمونے ہیں؛ سرخ لکیر تیار کردہ آؤٹ لائن ہے۔

0.005 سے کم نمونے تراشنے کے بعد کیپ آخری تحریری نقطے پر ختم ہوتی ہے۔ دباؤ کی یہ نچلی حد موجودہ اسٹیمپ رینڈرر میں بھی برقرار ہے۔
اس حد نے ہوا میں بننے والے لمبے ہکس ختم کر دیے۔ قلم کے سطح کو چھوتے وقت ہونے والی مختصر کھنچاؤ والی حرکات اور قلم اٹھانے کی وہ قوسیں جن کا دباؤ 0.005 سے زیادہ رہا، اس سے محفوظ رہیں، کیونکہ وہ لکھی ہوئی حرکت ہیں۔ آؤٹ لائن ماڈل کے اندر ان حرکات کو سنبھالنے نے جیومیٹری کے اگلے ادوار کی طرف لے گیا۔
تین جیومیٹری انجنز نے خامیوں کو ادھر ادھر منتقل کیا
نسل اول: ایک آؤٹ لائن، ایک بھرائی
پہلے دباؤ سے حساس انجن نے ایک مانوس پائپ لائن کی پیروی کی۔ اس نے مرکزی لکیر کو ہموار کیا، بائیں اور دائیں آف سیٹس کا حساب لگایا، انہیں ایک کثیر الاضلاع شکل میں جوڑا، اور اس شکل کو ایک بار بھرا۔ نوک ایک بیضوی شکل تھی جسے Apple Pencil کے سمت زاویے اور ارتفاع سے کنٹرول کیا جاتا تھا، اس لیے لکھنے کی سمت کے ساتھ اس کا مقطع بدلتا تھا۔ مختصر ٹیپس کے لیے الگ شکل تھی، اور چپٹی کیپس میں صفر-وائنڈنگ خالی جیبوں سے بچنے کے لیے چھوٹی غیر متوازنیوں کا استعمال کیا جاتا تھا۔
ایک بار کی بھرائی نے اسٹروک کے اندر اوپیسٹی کے جمع ہونے کا مسئلہ حل کیا، اور اس کے لیے ہر موڑ پر ایک درست کثیر الاضلاع شکل درکار تھی۔ قلم کے سطح چھونے کے وقت کی کھنچاؤ والی حرکات نے کیپ اور جسم کے درمیان پچر بنائے۔ واپس پلٹنے والی لکیریں سفید ہلال نما خالی جیبیں پیدا کر سکتی تھیں۔ تیز موڑ اندرونی آؤٹ لائن کو خود سے ٹکرا سکتے تھے اور ایک بے بھرا ہوا شگاف چھوڑ سکتے تھے۔
نسل دوم: سروں کے قریب آؤٹ لائن کی مرمت
دوسرے انجن نے آؤٹ لائن برقرار رکھی اور مقامی مرمتیں شامل کیں: واپس پلٹنے والی لکیر کی تراش خراش، ابتدائی تخمینہ شدہ خصوصیات کے لیے damping، endpoint کو سیدھا کرنا، عارضی سمت کی تراش خراش، اور کیپ میں ایک چھوٹا سا اضافہ۔ ہر patch نے دوبارہ پیدا کی گئی ایک خرابی کو حل کیا۔ مجموعی طور پر endpoint کا برتاؤ کئی thresholds اور windows پر منحصر ہو گیا۔
پھر حقیقی لکھائی نے ان windows سے باہر کے حالات پیدا کیے۔ 24 پوائنٹس کی مستقل سیدھا کرنے والی window نے مختصر اسٹروکس کے ارادی ہکس مٹا دیے۔ adaptive window نے ان ہکس کو محفوظ رکھا، مگر قلم اٹھانے کی قوسیں پھر بھی نمایاں کونوں میں بدل سکتی تھیں۔ سمت سے باخبر trimming نے زیادہ عارضی حرکت ہٹا دی، لیکن ایک ریکارڈ شدہ اسٹروک کے واقعی خم دار آغاز کے تقریباً 2.5 پوائنٹس ضائع ہو گئے۔
ہر patch نے اپنے ہدف والے معاملے کو درست کیا۔ پھر بھی اس کے نیچے موجود ماڈل کو ایک ایسی سخت آؤٹ لائن درکار تھی جو شور زدہ، خم دار ان پٹ کے تحت درست رہے۔
نسل سوم: clipped square caps کے ساتھ کوریج یونین
تیسرے انجن نے ایک واحد contour بنانا چھوڑ دیا۔ اس نے ہر segment کے لیے ایک trapezoid اور ہر اندرونی sample پر ایک disc کو خاکستری mask میں بنایا، پھر ان کی coverage union لی، اور اس کے بعد ہائی لائٹر کا رنگ ایک بار لگایا۔ واپس پلٹنے والی لکیروں کے ہلال، خود تقاطع کی سیاہی اور صفر-وائنڈنگ سوراخ غائب ہو گئے، کیونکہ رینڈرر اب polygon winding پر منحصر نہیں تھا۔
یونین نے سروں کو گول کر دیا، اس لیے ہم نے دو endpoint half-planes کے خلاف coverage کو clip کر کے square caps واپس لائے۔ اس clip نے مستقل دباؤ والی سیدھی لکیروں کا مسئلہ حل کیا، مگر اس سے زیادہ سنگین خرابی پیدا ہوئی: خم دار اسٹروک کا جسم جائز طور پر کسی endpoint half-plane کو پار کر سکتا ہے، اور cap clip پھر اسٹروک کے بیچ کا حصہ بھی ہٹا دیتا ہے۔ براہِ راست ان پٹ کے دوران endpoint کی سمت بدلتی رہتی تھی، اس لیے clipped علاقہ حرکت کرتا اور اسٹروک ٹمٹماتا تھا۔

عالمی کیپ کی پابندی خم دار اسٹروک کے جسم کو کاٹ دیتی ہے۔

کیپ clipping کو endpoint سے ایک نصف چوڑائی کے اندر موجود primitives تک محدود کرنے سے یہ اسٹروک بحال ہو جاتا ہے۔
قوس کی لمبائی کے gate نے کیپ clipping کو مقامی بنا دیا اور ہر ریکارڈ شدہ کیس کی مرمت کر دی۔ ایک انتہائی مصنوعی ہک نے پھر بھی ایک چھوٹا سفید شگاف دکھایا، جہاں کم دباؤ والی نوک clipped کیپ سے ملتی تھی۔ تیسرے انجن نے ایک بار پھر جیومیٹری کی ایک خرابی کو دوسری کے بدلے قبول کیا۔
MaLiang نے سخت حد ختم کر دی
MaLiang ایک بند آؤٹ لائن کے بجائے بار بار لگائے گئے texture stamps سے اسٹروک بناتا ہے۔ اس کا path generator ایسے quadratic Bézier segments استعمال کرتا ہے جو ملحقہ sample midpoints میں سے گزرتے ہیں، اور اس کا line renderer اس راستے پر باقاعدہ وقفے سے stamps لگاتا ہے۔ اسٹروک کے ساتھ stamp کا سائز، rotation، رنگ اور اوپیسٹی سب بدل سکتے ہیں۔
نرم stamp میں الگ کیپ، جوڑ یا winding rule نہیں ہوتا۔ سمت میں تیز تبدیلی اوورلیپ ہونے والے marks کی ایک ترتیب ہی رہتی ہے۔ واپس پلٹنے والی لکیریں خالی polygon pocket نہیں بنا سکتیں، اور endpoint half-plane اسٹروک کے بیچ کو نہیں کاٹ سکتا، کیونکہ ماڈل میں endpoint clip موجود ہی نہیں۔
ہم نے code کے بجائے ماڈل اختیار کیا۔ موجودہ HighlighterStrokeBuilder چار کام کرتا ہے:
- صرف ان endpoint samples کو ہٹانا جن کا دباؤ
0.005سے کم ہو۔ - midpoint quadratic Bézier segments سے مقامات کو ہموار کرنا۔
- قوس کی لمبائی کے ہر point پر ایک گول stamp لگانا۔
- normalized pressure سے stamp کا قطر مقرر کرنا اور stamps کو source-over alpha کے ساتھ composite کرنا۔
Builder 686 لائنوں سے کم ہو کر 190 لائنوں کا رہ گیا۔ سمت زاویہ، ارتفاع، آؤٹ لائن کی تعمیر، union masks، endpoint direction windows، cap extension اور cap clipping سب ہائی لائٹر path سے نکل گئے۔ ہم اب بھی Pencil orientation ریکارڈ کرتے ہیں، کیونکہ input model اسے support کرتا ہے، مگر ہائی لائٹر خود ان fields کو نہیں پڑھتا۔
MaLiang کے دباؤ کے فارمولے کو ڈیوائس calibration درکار تھی
MaLiang stamp کا سائز درج ذیل کے مساوی فارمولے سے مقرر کرتا ہے:
یہ فرض کرتا ہے کہ force صفر سے 1 تک کی range کا مفید حصہ استعمال کرتا ہے۔ ہمارے ڈیوائس ڈیٹا میں ایسا نہیں تھا۔ تقریباً 3,400 Apple Pencil samples میں median pressure 0.047 اور maximum 0.178 تھا۔ ان values کو براہِ راست فارمولے میں ڈالنے سے معمول کی لکھائی nominal brush size کے مقابلے میں کہیں زیادہ پتلی ہو گئی۔
لہٰذا ہم observed median کے گرد normalize کرتے ہیں، پھر exponent لگاتے اور نتیجے کو clamp کرتے ہیں:
اب لکھائی کا median pressure nominal 12-point diameter میں map ہوتا ہے۔ بہت ہلکا رابطہ nominal size کے 35% پر بھی نمایاں رہتا ہے، جبکہ زیادہ دباؤ 120% پر بڑھنا بند کر دیتا ہے۔
یہ calibration ان پٹ ڈیوائس اور brush behavior سے متعلق ہے، MaLiang سے نہیں۔ اپنے pressure distribution کو ناپے بغیر اصل فارمولے کی نقل کرنا architecture کو تو برقرار رکھتا، مگر brush غلط بنا دیتا۔
فی اسٹیمپ الفا معلوم overlap count سے نکلا
MaLiang اوورلیپ ہونے والے نیم شفاف stamps کی تلافی تجرباتی expression alpha ÷ overlapping × 2.5 سے کرتا ہے۔ ہمارے brush کا nominal diameter 12 پوائنٹس اور stamp step 1 پوائنٹ ہے، اس لیے اس کی centerline کو تقریباً 12 layers ملتی ہیں۔ ہمارے معاملے میں overlap count معلوم ہے، اس لیے compensation کا حساب کیا جا سکتا ہے، اندازہ نہیں لگانا پڑتا۔
ہدف stroke opacity
لہٰذا ایک stamp کو درکار ہے:

حتمی رینڈرر ریکارڈ کیے گئے ڈیوائس راستوں کو دوبارہ چلا رہا ہے۔ ہکس، ترچھے کٹ اور سفید pockets موجود نہیں ہیں۔
وہ دو قیمتیں جو ہم نے قبول کیں
خود تقاطع زیادہ گہرے ہو جاتے ہیں۔ source-over composition ہر stamp کو شمار کرتی ہے، ان stamps کو بھی جو اسی جگہ سے پہلے گزرنے پر بچھائے گئے تھے، جبکہ coverage-union انجن اس سے بچ گیا تھا۔ ہم نے گہرا overlap قبول کیا، کیونکہ یہ قابلِ پیش گوئی ہے اور اسٹروک کی شکل برقرار رکھتا ہے۔
سروں کی چوڑائی دباؤ کے ساتھ کم ہوتی ہے۔ قلم اٹھاتے وقت حقیقی lift-off دباؤ کم کرتا ہے، جس سے stamp کا قطر کم ہو جاتا ہے، لہٰذا اسٹروک پوری چوڑائی والی square cap کے بجائے بتدریج پتلے سرے پر ختم ہوتا ہے۔ ہم نے تینوں جیومیٹری انجنز کے دوران اس square cap کو ایک تقاضا سمجھا تھا۔ اسے چھوڑنے سے اوپر بیان کی گئی کئی خامیوں کے پیچھے موجود clipping اور endpoint machinery ختم ہو گئی، اس لیے ہم نے پتلا ہوتا سرا قبول کیا۔
اس لیے جو ماڈل ہم جاری کرتے ہیں وہ پچھلے ماڈلز سے کم کام کرتا ہے۔ یہ ناپی گئی لکھائی کے واقعے کو محفوظ رکھتا ہے، ڈیوائس calibration کے بعد دباؤ کا جواب دیتا ہے، اور عالمی طور پر درست آؤٹ لائن کا تقاضا کیے بغیر خم دار اور خود تقاطع والے راستوں کو رینڈر کرتا ہے۔ چھینی نما نوک، بالکل square cap اور خام نمونوں کے درمیان عین polyline وہ خصوصیات ہیں جن سے ہم نے اس کے بدلے دست بردار ہوئے۔
اس تجزیے سے حاصل ہونے والے نتائج میں دباؤ کی نچلی حد دوسرے منصوبوں میں سب سے براہِ راست منتقل کی جا سکتی ہے۔ 0.005 کی value حقیقی input کے دو clusters کے درمیان موجود خلا سے آئی: لکھائی 0.01 اور اس سے زیادہ، اور ہوا میں tracking 0.002 اور اس سے کم۔ انہی ریکارڈ شدہ اسٹروکس نے پھر دکھایا کہ جیومیٹری کی ہر مرمت کہاں ناکام ہوئی؛ ان ناکامیوں نے ماڈل بدلنے کا جواز فراہم کیا اور ان دو قیمتوں کا تعین کیا جنہیں ہم نے برقرار رکھا۔