2025, Oct 21 00:31
Turtle में begin_fill/end_fill के साथ आर्क आकृतियों को सही तरह से भरना
Python Turtle में आर्क टुकड़ों से बनी आकृति क्यों नहीं भरती और इसे कैसे ठीक करें: सतत आउटलाइन, begin_fill/end_fill का सही उपयोग, और turtle.circle से आर्क्स.
आर्क्स से बनी अनियमित Turtle आकृतियों को भरना उम्मीद से ज़्यादा पेचीदा हो सकता है. अगर बाहरी रेखा पूरी तरह निरंतर नहीं है या भराई गलत जगहों पर शुरू/रोक दी जाती है, तो ठोस रंग की जगह धारियों जैसे निशान या खाली हिस्से दिखते हैं. नीचे समझाया गया है कि ऐसा क्यों होता है और Turtle के मानक fill वर्कफ़्लो से इसे कैसे ठीक किया जा सकता है.
समस्या का सेटअप
बाहरी रेखा जैविक-सी बॉर्डर देने के लिए छोटे-छोटे आर्क टुकड़ों से बनाई गई है. ड्रॉइंग रूटीन अंडाकार के साथ बिंदु गणना करता है और उसी के अनुसार पेन को चलाता है. लक्ष्य पूरी बंद आकृति को भरना था, लेकिन इन आर्क्स के आसपास begin_fill और end_fill लगाने पर ठोस भराई के बजाय अजीब पैटर्न बन गया.
मुद्दा दिखाने वाला कोड
नीचे दिया गया फ़ंक्शन कोणों को चरणों में बदलते हुए गणना किए गए निर्देशांकों पर टर्टल को रखकर एक आर्क बनाता है. यह सीधे math और turtle का उपयोग करता है. यह लॉजिक उसी सेटअप का प्रतिनिधि है जो अप्रत्याशित fill परिणाम का कारण बनता है.
import turtle
import math
def draw_arc(ax, by, deg_start=None, deg_end=None, pen_obj=None):
    if pen_obj is None:
        pen_obj = turtle.Turtle()
    ox = pen_obj.pos()[0]
    oy = pen_obj.pos()[1]
    try:
        adj_start = math.radians(deg_start) * 0.875 * (180 / math.pi)
        adj_end = math.radians(deg_end) * 0.875 * (180 / math.pi)
    except:
        adj_start = 0
        adj_end = 315
    for k in range(int(adj_start), int(adj_end) + 1):
        if k == int(adj_start):
            pen_obj.up()
        else:
            pen_obj.down()
        pen_obj.setposition(ox + ax * math.cos(k / 50), oy + by * math.sin(k / 50))
भराई टूट क्यों जाती है
सबसे आम वजह मार्ग में दरार/गैप होना है. Turtle में भराई के लिए एक बंद, सतत बहुभुज पथ चाहिए. अगर पेन गलत समय पर ऊपर उठ जाए या आख़िरी बिंदु पहले बिंदु से ठीक-ठीक न मिले, तो फ़िलर अंदरूनी भाग तय नहीं कर पाता और नतीजा अनचाहे पैटर्न होता है.
कोण इकाइयों की असंगति भी समस्या बनती है. डिग्री और रेडियन मिलाने से बिंदु थोड़े-थोड़े खिसक जाते हैं, जिससे रेखा में सूक्ष्म गैप बन सकते हैं. यहां step चर को एक जगह डिग्री जैसा और दूसरी जगह रेडियन जैसा माना गया है—दिखाई में रेखा बंद लगे, तब भी भराई टूट सकती है.
अंत में, हर छोटे हिस्से के आसपास begin_fill और end_fill बुलाना उल्टा असर करता है. भराई एक बार पूरी बाहरी रेखा खींचने से पहले शुरू होनी चाहिए और बंद आकृति पूरी होने के बाद एक बार में खत्म होनी चाहिए.
समाधान: एक ही fill ऑपरेशन, सतत आउटलाइन और सुसंगत आर्क्स
मजबूत भराई का सबसे आसान तरीका है आकृति को एक ही सतत पथ में खींचना, शुरू करने से ठीक पहले सिर्फ एक बार begin_fill और बंद आकृति पूरी होने पर एक बार end_fill कॉल करना. आर्क बनाने के लिए turtle.circle का सहारा लेने से सततता सरल रहती है और कोण इकाइयों की गड़बड़ी से भी बचाव होता है.
import turtle as tr
def ripple(radius=20, sweep=45):
    tr.circle(radius, sweep)
    tr.circle(-radius, sweep)
def shape_outline(repeat_count=2, radius=20, sweep=90):
    for _ in range(4):
        for _ in range(repeat_count):
            ripple(radius, sweep)
        tr.left(90)
tr.fillcolor("red")
tr.begin_fill()
shape_outline(repeat_count=3)
tr.end_fill()
tr.mainloop()
यह लहरदार, आयत-जैसा बहुभुज बनाता है, पथ को निरंतर रखता है और सफ़ाई से भर देता है. अहम बातें: आकृति बंद हो और begin_fill तथा end_fill पूरे आउटलाइन के लिए सिर्फ एक-एक बार बुलाए जाएं, हर आर्क पर नहीं.
गोल कोनों और रोटेशन के साथ वैरिएंट
अगर आपको गोल कोने और रोटेशन का नियंत्रण चाहिए, तब भी पूरी रेखा के लिए एक ही fill पास रखें. यह संस्करण वही लहरदार किनारे बनाता है, गोल कोने जोड़ता है और sweep को कमांड-लाइन आर्ग्यूमेंट के रूप में देने देता है.
import turtle as tr
import sys
def ripple(radius=20, sweep=45):
    tr.circle(radius, sweep)
    tr.circle(-radius, sweep)
def shape_outline(repeat_count=2, radius=20, sweep=90, rounded=True):
    for _ in range(4):
        for _ in range(repeat_count):
            ripple(radius, sweep)
        if rounded:
            tr.circle(radius, 90)
        else:
            tr.left(90)
if len(sys.argv) > 1:
    SWEEP = int(sys.argv[1])
else:
    SWEEP = 90
tr.fillcolor("red")
tr.begin_fill()
tr.right(SWEEP // 2)
shape_outline(repeat_count=3, sweep=SWEEP)
tr.left(SWEEP // 2)
tr.end_fill()
tr.mainloop()
Turtle ग्राफ़िक्स में यह क्यों मायने रखता है
भराई की गुणवत्ता पूरी तरह ज्योमेट्री पर निर्भर है. एक पिक्सेल की भी असततता भराई को बाहर रिसने दे सकती है या गणना ही फेल करा सकती है. बिना टूटे आउटलाइन रखना और fill API को एक ही बार चलाना व्यवहार को पूर्वानुमेय बनाता है. निर्देशांक बनाते हुए रेडियन और डिग्री मिलाने से बचें—ऐसी सूक्ष्म असंगतियाँ दिखती नहीं, पर बहुभुज भराई के लिए घातक होती हैं. आर्क्स के लिए turtle.circle अपनाने से इंजन-नैटिव, सतत पथ मिलता है जो खंडों के बीच भी जुड़ा रहता है.
मुख्य बातें
पूरी आकृति खींचने से पहले begin_fill एक बार और पथ पूरी तरह बंद होने के बाद end_fill एक बार ही कॉल करें. आउटलाइन में कोई गैप न रहे—यहां तक कि कोण इकाइयों की असंगति से बने सूक्ष्म अंतर भी नहीं. जहाँ संभव हो, सततता बनाए रखने के लिए Turtle के अपने arc primitives का उपयोग करें. इन सुधारों के साथ, दोहराए गए आर्क तत्वों से बनी जटिल आकृतियाँ भी बिना दिक्कत साफ़-सुथरी तरह से भर जाती हैं.
यह लेख StackOverflow के एक प्रश्न (लेखक: ونداد شاهدی) और furas के उत्तर पर आधारित है।