Metlivi ब्लॉग

किसी पथ पर एक निश्चित आकार को खिसकाकर चौड़े किनारे वाला पेन स्ट्रोक कैसे बनाएँ

चौड़े किनारे वाला पेन स्ट्रोक बनाने के लिए, एक पतली आयताकार निब परिभाषित करें, उसका कोण स्थिर रखें और उसे किसी पथ पर खिसकाएँ। स्ट्रोक उस आयत द्वारा घेरा गया हर स्थान मिलाकर बनता है। निब का आकार बदले बिना भी उसकी मोटाई चलने की दिशा के अनुसार बदलती है।

यह मार्गदर्शिका दिखाती है कि वेक्टर ड्रॉइंग या किसी कैरेक्टर के सजावटी निशान के लिए यह ज्यामिति कैसे बनाई जाए। आप निब परिभाषित करेंगे, उसे पॉलीलाइन पर लगातार खिसकाएँगे और एक संपूर्ण Python प्रोग्राम से SVG बनाएँगे। इस निर्माण में ब्रश को अलग-अलग छापों से अनुकरण करने पर दिखने वाले अंतराल नहीं आते।

29 अक्टूबर 2026पढ़ने में 8 मिनटलेखक: Metlivi Editorial Team
खंड 1

किसी निश्चित आकार को खिसकाने का क्या अर्थ है?

ड्रॉइंग को दो इनपुट में बाँटें: एक पथ, जो बताता है कि निब का संदर्भ-बिंदु कहाँ चलता है, और एक आकृति, जो बताती है कि निब एक स्थान पर कितना क्षेत्र ढकता है। आकृति के संदर्भ-बिंदु को मूल बिंदु पर रखें। पथ के हर स्थान पर, उस स्थान को आकृति के हर बिंदु में जोड़ें।

गणितीय रूप से, परिणामी समुच्चय S = {p + n | p belongs to P, n belongs to N} है, जहाँ P पथ है और N निब है। यह मिंकोव्स्की योग है, जिसकी बिंदुवार परिभाषा CGAL 2D Minkowski Sums उपयोगकर्ता पुस्तिका में दी गई है।

इस निर्माण में “निश्चित” का अर्थ है कि आकृति और उसका अभिविन्यास, दोनों ड्रॉइंग निर्देशांकों में स्थिर रहते हैं। निब पथ का अनुसरण करते हुए घूमे बिना खिसकती है। संदर्भ-बिंदु को आयत के केंद्र में रखने से पथ चलती हुई निब के केंद्र को दर्शाता है।

खंड 2

निब का कोण और चलने की दिशा मोटाई कैसे तय करते हैं?

तीन मान चुनें: आयत का लंबा आयाम w, उसका छोटा आयाम h और उसके लंबे किनारे का कोण α। छोटा धनात्मक h निब को दिखाई देने वाली न्यूनतम मोटाई देता है। इसके विपरीत, आदर्श रेखाखंड-आकार की निब की मोटाई शून्य होती है और यदि उसे ठीक अपनी दिशा में चलाया जाए, तो वह शून्य-क्षेत्रफल का निशान छोड़ सकती है।

दिशा कोण θ वाले सीधे पथ-खंड के लिए, यात्रा की दिशा के लंबवत मापी गई आयताकार निब की चौड़ाई यह है:

width across the stroke = w × |sin(θ − α)| + h × |cos(θ − α)|

यह सूत्र आयत के दो परस्पर लंबवत आयामों को पथ के अभिलंब पर प्रक्षेपित करने से मिलता है। यह सीधे खंड के लिए, या चिकने वक्र पर स्थानीय आकृति के प्रक्षेपण के लिए लागू होता है; वक्राकार स्ट्रोक के अतिव्यापी हिस्से उसकी पूरी बाहरी आकृति को और चौड़ा बना सकते हैं।

उदाहरण के लिए, 24 यूनिट × 3 यूनिट की निब लें। लंबे किनारे के समानांतर चलाने पर 3 यूनिट चौड़ी पट्टी बनती है। लंबवत चलाने पर 24 यूनिट चौड़ी पट्टी बनती है। 45° के अंतर पर चौड़ाई लगभग (24 + 3) / √2, यानी 19.09 यूनिट होती है। ये गणना किए गए आयाम हैं, ब्रश से मिले माप नहीं।

जटिल वक्र बनाने से पहले इन तीन दिशाओं को अंशांकन परीक्षण के रूप में इस्तेमाल करें। इससे आप कई अतिव्यापी मोड़ों का अर्थ निकाले बिना जाँच सकते हैं कि कोण और आयाम अपेक्षा के अनुसार काम कर रहे हैं।

खंड 3

स्टैम्पिंग के अंतराल छोड़े बिना लगातार स्वीप कैसे करें?

एक सीधी रेखा पर चलती उत्तल निब के लिए, दोनों सिरों पर निब की एक-एक प्रतिलिपि लें और उनके संयुक्त शीर्षों का उत्तल आवरण निकालें। यह आवरण उस रेखा-खंड पर खिसकाने के दौरान निब द्वारा घेरा गया सटीक क्षेत्र है।

इसका कारण सीधा है: बीच की हर स्थिति, सिरों पर निब की स्थितियों के बीच रैखिक प्रक्षेप है। निब उत्तल होने के कारण, उसका आवरण ठीक उन्हीं मध्यवर्ती स्थितियों को समेटता है। किसी अलग ब्रश सुविधा के बजाय, यह खंड-निर्माण सीधे मिंकोव्स्की योग की परिभाषा से निकलता है।

आयत के लिए हर खंड केवल आठ संभावित बिंदु देता है: शुरुआत में चार कोने और अंत में चार। उनके आवरण की गणना करें, पथ के हर क्रमागत बिंदु-युग्म के लिए इसे दोहराएँ और बने हुए बहुभुजों को मिलाएँ। आसन्न स्वीप अपने साझा अंतिम बिंदु पर निब की पूरी स्थिति साझा करते हैं, इसलिए ज्यामिति में निरंतर कवरेज रहता है।

पूरे पथ के चारों ओर एक ही उत्तल आवरण न निकालें। ऐसा करने से मोड़ों के आर-पार क्षेत्र भर जाएगा और इच्छित अंदरूनी कटाव मिट जाएँगे। आवरण हर अलग खंड के लिए होना चाहिए; पूरा स्ट्रोक इन खंडों का संघ है।

अवतल निब के लिए अलग तरीका चाहिए। उसका आवरण निकालने से अंदरूनी कटाव भर जाएँगे। उसे उत्तल हिस्सों में बाँटें, हर हिस्से को स्वीप करें और परिणामी आकृतियाँ मिलाएँ। CGAL, अवतल बहुभुजों के मिंकोव्स्की योग के लिए इसी से जुड़ी विभाजन और संघ वाली विधि बताता है।

खंड 4

Python में स्वीप कैसे लागू करें?

निम्नलिखित संपूर्ण प्रोग्राम के लिए Python 3 और उसकी मानक लाइब्रेरी चाहिए। यह पाँच बिंदुओं वाला नमूना पथ परिभाषित करता है, आयताकार निब बनाता है और चार भरे हुए स्वीप बहुभुजों वाला SVG दस्तावेज़ प्रिंट करता है। इसे broad_edge.py नाम से सहेजें, फिर ड्रॉइंग बनाने के लिए python broad_edge.py > stroke.svg चलाएँ।

यहाँ निर्देशांक SVG की परंपरा के अनुसार हैं: x दाईं ओर बढ़ता है और y नीचे की ओर। इसलिए इस प्रोग्राम में धनात्मक कोण स्क्रीन पर निब को दक्षिणावर्त झुकाता है। अन्य ड्रॉइंग इंटरफ़ेस में कोणों की परंपरा अलग हो सकती है।

from math import cos, sin, radians


def hull(points):
    pts = sorted(set(points))
    if len(pts) <= 1:
        return pts

    def cross(o, a, b):
        return ((a[0] - o[0]) * (b[1] - o[1])
                - (a[1] - o[1]) * (b[0] - o[0]))

    def half(sequence):
        out = []
        for p in sequence:
            while len(out) >= 2 and cross(out[-2], out[-1], p) <= 0:
                out.pop()
            out.append(p)
        return out

    return half(pts)[:-1] + half(reversed(pts))[:-1]


def sweep(path, width=24, thickness=3, angle=30):
    if not path or width <= 0 or thickness <= 0:
        raise ValueError(
            'Provide a nonempty path and positive nib dimensions'
        )

    a = radians(angle)
    u = (cos(a), sin(a))
    v = (-sin(a), cos(a))
    nib = [
        (s * width * u[0] / 2 + t * thickness * v[0] / 2,
         s * width * u[1] / 2 + t * thickness * v[1] / 2)
        for s, t in [(-1, -1), (1, -1), (1, 1), (-1, 1)]
    ]
    pairs = list(zip(path, path[1:])) or [(path[0], path[0])]
    return [
        hull([(p[0] + q[0], p[1] + q[1])
              for p in (start, end) for q in nib])
        for start, end in pairs
    ]


path = [(40, 45), (85, 125), (140, 150), (195, 110), (245, 45)]
polygons = sweep(path)
all_points = [p for polygon in polygons for p in polygon]
x0, y0 = (min(p[i] for p in all_points) - 5 for i in (0, 1))
x1, y1 = (max(p[i] for p in all_points) + 5 for i in (0, 1))

svg = [
    '<svg xmlns="http://www.w3.org/2000/svg" '
    f'viewBox="{x0} {y0} {x1 - x0} {y1 - y0}">',
    '<g fill="#23364d" stroke="none">'
]
for polygon in polygons:
    coordinates = ' '.join(f'{x:.6f},{y:.6f}' for x, y in polygon)
    svg.append(f'<polygon points="{coordinates}"/>')
svg.extend(['</g>', '</svg>'])
print('\n'.join(svg))

यदि पथ में केवल एक बिंदु हो, तो प्रोग्राम निब की एक आकृति बनाता है। लगातार दोहराए गए बिंदुओं से भी आकृति बनती है; दिशा की गणना की आवश्यकता नहीं होती। खाली पथ और शून्य से कम या बराबर निब आयाम पर त्रुटि आती है। निर्देशांकों के लिए सीमित संख्यात्मक युग्म दें; यह संक्षिप्त उदाहरण आयात किए गए पथ-डेटा की जाँच नहीं करता।

नमूना निर्देशांकों के साथ चलाने पर प्रोग्राम ने छह शीर्षों वाले चार स्वीप बहुभुज बनाए और उत्पन्न SVG XML के रूप में सफलतापूर्वक पार्स हुआ। एकल-बिंदु और दोहराए गए-बिंदु वाले मामलों की भी जाँच की गई। ये जाँचें निर्माण और दस्तावेज़ की संरचना को परखती हैं; दृश्य रेंडरिंग परीक्षण नहीं हैं।

खंड 5

वक्रों, कोनों और सिरों को कैसे सँभालें?

फ़्लोटिंग-पॉइंट गणना और निर्देशांक को गोल करने की सीमाओं के अधीन, यह उदाहरण अपनी पॉलीलाइन के लिए सटीक है। बेज़ियर वक्र इस्तेमाल करने के लिए, पहले उसे सीधे खंडों से लगभग दर्शाएँ, फिर वही स्वीप लागू करें। वक्र के पैरामीटर में सभी नमूने समान रूप से बाँटने के बजाय, जहाँ वक्र तेज़ी से मुड़ता है वहाँ अधिक खंड जोड़ें।

आउटपुट के इच्छित आकार के अनुसार सन्निकटन की सहनशीलता चुनें। उदाहरण के लिए, चौथाई पिक्सेल का विचलन स्क्रीन पर दिखाने के लिए शुरुआती लक्ष्य हो सकता है; फिर सबसे बड़े नियोजित आकार पर जाँच करें। यह एक उदाहरणात्मक इंजीनियरिंग विकल्प है, सार्वभौमिक गुणवत्ता-सीमा नहीं। ध्यान दें कि पहले से सीधे खंड पर उपखंड जोड़ने से उसका स्वीप क्षेत्र नहीं बदलता।

अलग-अलग पेन-डाउन पथों को अलग रखें। दो असंबद्ध स्ट्रोक के बिंदु एक ही कॉल में देने से उनके बीच अनचाहा जोड़ने वाला स्वीप बनेगा। हर स्ट्रोक अलग बनाएँ और उसके बहुभुजों को आउटपुट में शामिल करें।

अंतिम बिंदु पर निब अपनी पूरी आकृति बनाए रखती है। कोने पर दोनों आस-पास के स्वीप एक-दूसरे पर चढ़ते हैं। इस मॉडल में अतिरिक्त माइटर या गोल सिरा नहीं है। SVG की सामान्य स्ट्रोक प्रॉपर्टीज़ अपने कैप और जॉइन बनाती हैं, इसलिए उन्हें जोड़ने से इस निश्चित-निब स्वीप के बाहर की ज्यामिति भी शामिल हो जाएगी। SVG 2 में स्ट्रोक कैप और जॉइन की परिभाषाएँ देखें।

खंड 6

बहुभुजों को कब मिलाना चाहिए?

प्रोग्राम एक-दूसरे पर चढ़े हुए भरे बहुभुज निर्यात करता है। ठोस रंग का पूर्वावलोकन दिखाने के लिए ये स्वीप कवरेज दर्शाते हैं और किसी बहुभुज-संघ लाइब्रेरी की आवश्यकता नहीं होती। हालांकि, ये अलग-अलग संपादन योग्य ऑब्जेक्ट रहते हैं; प्रोग्राम एक संयुक्त सीमा की गणना नहीं करता।

यदि आगे की आउटलाइन एडिटिंग के लिए साफ बाहरी आकृति चाहिए, तो सभी खंड-बहुभुजों का बूलियन यूनियन निकालें। परिणाम में मौजूद छिद्रों को बनाए रखें। लूप बनाता हुआ पथ किसी रंगे बिना हिस्से को घेर सकता है, और हर बंद कंटूर को भरने से स्ट्रोक बदल जाएगा।

पारदर्शिता को भी सोच-समझकर सँभालें। एक-दूसरे पर चढ़े बहुभुजों पर अलग-अलग आंशिक fill-opacity लगाने से अतिव्यापन वाले हिस्से गहरे हो सकते हैं। एकसमान पारदर्शिता के लिए, बाहरी समूह पर अपारदर्शिता लागू करें या भरण की अपारदर्शिता लगाने से पहले ज्यामिति को मिला दें। SVG अपनी पेंटिंग विनिर्देश में ऑब्जेक्ट के भरण की अपारदर्शिता और समूह की अपारदर्शिता को अलग-अलग परिभाषित करता है।

इच्छित परिणाम अगला उपयुक्त कदम
ठोस रंग का पूर्वावलोकन भरे हुए स्वीप बहुभुज बनाए रखें
एकसमान पारदर्शी पूर्वावलोकन उनके बाहरी समूह पर अपारदर्शिता लागू करें
एक संपादन योग्य बाहरी आकृति स्वीप बहुभुजों का बूलियन यूनियन निकालें
कस्टम अवतल निब स्वीप करने से पहले निब को भागों में बाँटें
चिकना वक्राकार स्ट्रोक वक्र का सन्निकटन बनाएँ, फिर उसके खंडों को स्वीप करें
खंड 7

अनपेक्षित स्ट्रोक का कारण कैसे पता करें?

अंशांकन दिशाओं से शुरू करें, फिर पथ और आउटपुट के निर्माण की जाँच करें। एक बार में एक ही इनपुट बदलें, ताकि दिखाई देने वाले अंतर का कारण स्पष्ट रहे।

  • मोटाई लगभग समान रहती है: जाँचें कि निब पथ के साथ घूम तो नहीं रही। ड्रॉइंग निर्देशांकों में उसका कोण स्थिर रहना चाहिए।
  • निशानों के बीच खाली जगह दिखती है: अलग-अलग स्टैम्प के बजाय खंड-आवरण वाला निर्माण इस्तेमाल करें।
  • मोड़ के अंदर चौड़ा पच्चर भर जाता है: जाँचें कि कहीं आपने कई पथ-खंडों का एक साथ आवरण तो नहीं निकाल दिया।
  • सिरे गोल दिखते हैं: देखें कि कहीं सामान्य स्ट्रोक या अलग निब-आकृति तो नहीं जोड़ी गई।
  • मूल चिकना वक्र कोणीय दिखता है: मोड़ों के आसपास पॉलीलाइन सन्निकटन को और बारीक करें।
  • अनचाहे जोड़ दिखाई देते हैं: असंबद्ध पथों के लिए अलग-अलग स्वीप कॉल करें।

यदि आप परिणाम की तुलना Inkscape के Calligraphy टूल से कर रहे हैं, तो उसके दस्तावेज़ में कुछ उपयोगी पैरामीटर जाँचें दी गई हैं: Fixation 100 कोण को स्थिर रखता है, Thinning 0 वेग के आधार पर मोटाई में होने वाले बदलाव को हटाता है, और दबाव तथा झुकाव नियंत्रण मोटाई और कोण बदल सकते हैं। निश्चित-निब के व्यवहार की जाँच करते समय इन बदलते इनपुट को बंद करें। ये सेटिंग्स टूल के नियंत्रणों का वर्णन करती हैं; इनसे यह साबित नहीं होता कि उसका आउटपुट इस आयताकार निर्माण जैसा ही है। Inkscape Calligraphy टूलबार का दस्तावेज़ देखें।

विश्वसनीय चौड़े किनारे वाले स्ट्रोक की शुरुआत एक सरल अंशांकन पथ और स्पष्ट रूप से परिभाषित आकृति से होती है। समानांतर, लंबवत और विकर्ण परीक्षण सही व्यवहार करने लगें, तो चुने हुए पथ पर वही खंड-स्वीप इस्तेमाल करें, आउटपुट आकार के अनुसार वक्र वाले हिस्सों को और बारीक करें और जब अगले संपादन चरण में एक ही बाहरी आकृति चाहिए हो, तो बहुभुजों को मिला दें।

खंड 8

स्रोत

संबंधित लेख

इस विषय को आगे पढ़ें