2009-07-29 11 views
39

मैं तेजी से सर्कल ड्राइंग के लिए Bresenham's circle algorithm का उपयोग कर रहा हूं। हालांकि, मैं भी (उपयोगकर्ता के अनुरोध पर) एक भरे सर्कल को आकर्षित करना चाहता हूं।भरे सर्कल ड्राइंग के लिए तेजी से एल्गोरिदम?

क्या ऐसा करने का एक तेज़ और कारगर तरीका है? ब्रेसनहेम की एक ही पंक्ति के साथ कुछ?

भाषा मैं उपयोग कर रहा हूँ सी

उत्तर

76

the Wikipedia page on Bresenham's (also 'Midpoint') circle algorithm पढ़ा है, यह जाहिर होता है कि ऐसा करने के लिए सबसे आसान काम इस तरह के

setPixel(x0 + x, y0 + y); 
setPixel(x0 - x, y0 + y); 

और इसी तरह, हर बार के बजाय आप के बजाय

lineFrom(x0 - x, y0 + y, x0 + x, y0 + y); 

है कि, उसके कार्यों को संशोधित करने के होगा यही है, अंक की प्रत्येक जोड़ी (उसी y के साथ) कि ब्रेसनहेम आपके पास साजिश है, इसके बजाय आप लाइन से कनेक्ट हैं।

+1

बहुत स्पष्ट। – dmckee

+0

क्या वास्तव में काम करता है? मैंने कोशिश की .. यह पूरी तरह से सर्कल भर नहीं है। क्या मैं कुछ भूल रहा हूँ ? किसी भी मामले में, नीचे कुछ सही उत्तर हैं। – AJed

+1

@AJed यह जानने के लिए कि क्या आप कुछ खो रहे हैं, हमें आपके कोड को [अपने स्वयं के एक नए प्रश्न] में देखना होगा (http://stackoverflow.com/questions/ask) – AakashM

20

है यहाँ एक सी # किसी न किसी गाइड (कि सी के लिए सही विचार प्राप्त करने के लिए मुश्किल नहीं होना चाहिए) है - इस का उपयोग करते हुए Bresenham दोहराया को खत्म करने के बिना "कच्चे" रूप है वर्गाकार जड़ें।

Bitmap bmp = new Bitmap(200, 200); 

int r = 50; // radius 
int ox = 100, oy = 100; // origin 

for (int x = -r; x < r ; x++) 
{ 
    int height = (int)Math.Sqrt(r * r - x * x); 

    for (int y = -height; y < height; y++) 
     bmp.SetPixel(x + ox, y + oy, Color.Red); 
} 

bmp.Save(@"c:\users\dearwicker\Desktop\circle.bmp"); 
+1

या वाई पर लूप और क्षैतिज रेखाएं खींचें। कभी-कभी एक या दूसरे को चुनने का एक कारण होता है, लेकिन ज्यादातर मामलों में इससे कोई फर्क नहीं पड़ता। एंडपॉइंट्स को जल्दी से ढूंढने के लिए आप उसी ब्रेसेनहम तर्क का उपयोग करते हैं। – dmckee

+3

उन सभी गणित। वर्ग का विशेष रूप से तेज़ नहीं होगा ... – AakashM

+1

नहीं, लेकिन आप इससे बचने के लिए ब्रेसेनहम का उपयोग कर सकते हैं। बुनियादी विचार सर्कल द्वारा कवर किए गए प्रत्येक एक्स समन्वय पर ऊपरी और निचले बिंदुओं के बीच "बिंदुओं में शामिल होना" है। –

1

मैं सिर्फ अंक की एक सूची उत्पन्न करता हूं और फिर प्रतिपादन के लिए बहुभुज ड्रा फ़ंक्शन का उपयोग करता हूं।

+1

यदि उसने खुले संस्करण के लिए ब्रेसनहेम लागू किया है, तो वह एक एपीआई का उपयोग करके कम परत पर काम कर रहा है ... या तो सीखने के उद्देश्यों के लिए या * एपीआई * लागू करने के लिए। – dmckee

46

बस ब्रूट फोर्स का उपयोग करें। यह विधि कुछ बहुत सारे पिक्सल पर फिर से चलती है, लेकिन यह केवल पूर्णांक गुणा और जोड़ों का उपयोग करती है। आप पूरी तरह से ब्रेसनहेम की जटिलता और वर्ग के संभावित बाधा से बचते हैं।

for(int y=-radius; y<=radius; y++) 
    for(int x=-radius; x<=radius; x++) 
     if(x*x+y*y <= radius*radius) 
      setpixel(origin.x+x, origin.y+y); 
+1

मुझे यह जवाब पसंद है क्योंकि यह समस्या को बहुत सीधी तरीके से हल करता है। इसके साथ एकमात्र समस्या यह है कि यह मिडपॉइंट सर्कल एल्गोरिदम की तुलना में एक अलग सर्कल उत्पन्न करता है। ये मंडल मध्यबिंदु के बराबर की तुलना में "पतली" हैं, जो अधिक सही आकार के रूप में दिखाई देती हैं। इसे ठीक करने का कोई तरीका? – Dwight

+4

यह भयानक लगता है, लेकिन मैंने पाया कि ज्यादातर मामलों में मैं इस एल्गोरिदम से सटीक उसी सर्कल को मध्य बिंदु के रूप में प्राप्त कर सकता हूं यदि मैं थोड़ा चेक संशोधित करता हूं। उन बार यह बिल्कुल मेल नहीं खाता है, यह बहुत करीब है। चेक में संशोधन है: x * x + y * y <= रेंज * रेंज + रेंज * 0.8 एफ – Dwight

+0

ग्रेट उत्तर, बिना संशोधन के सीधे काम किया – Chris

2

आप एक तेजी से एल्गोरिथ्म चाहते हैं, उच्च एन है एन पक्षों के साथ बहुभुज बना पर विचार करें, और अधिक सटीक वृत्त होगा।

+2

यह काम करता है, लेकिन तेज़ नहीं है। – finnw

+0

शायद इसे किसी प्रकार के हार्डवेयर त्वरण की आवश्यकता होगी सबसे तेज़ – Spikolynn

3

यहाँ कैसे मैं इसे कर रहा हूँ है:
मैं दो बिट्स परिशुद्धता के साथ नियत बिन्दु मान का उपयोग कर रहा
पिछले एक जवाब में mentionned के रूप में, मैं (हम आधा अंक और आधा अंक के वर्ग मूल्यों का प्रबंधन करने के लिए) मी वर्ग वर्ग की बजाय वर्ग मूल्यों का भी उपयोग कर रहा हूँ।
सबसे पहले, मैं सर्कल के 1/8 वें भाग में अपने सर्कल की सीमा सीमा का पता लगा रहा हूं। मैं सर्कल के 4 "सीमाओं" को आकर्षित करने के लिए इन बिंदुओं के सममित का उपयोग कर रहा हूं। फिर मैं सर्कल के अंदर वर्ग खींच रहा हूँ।

algorith मध्य वृत्त विपरीत यह भी व्यास के साथ काम करेंगे (और वास्तविक संख्या के साथ व्यास भी, कुछ छोटे परिवर्तन के साथ)।

मुझे माफ़ कर दो अगर मेरी स्पष्टीकरण स्पष्ट नहीं थे, मैं फ्रेंच हूँ,)

void DrawFilledCircle(int circleDiameter, int circlePosX, int circlePosY) 
{ 
    const int FULL = (1 << 2); 
    const int HALF = (FULL >> 1); 

    int size = (circleDiameter << 2);// fixed point value for size 
    int ray = (size >> 1); 
    int dY2; 
    int ray2 = ray * ray; 
    int posmin,posmax; 
    int Y,X; 
    int x = ((circleDiameter&1)==1) ? ray : ray - HALF; 
    int y = HALF; 
    circlePosX -= (circleDiameter>>1); 
    circlePosY -= (circleDiameter>>1); 

    for (;; y+=FULL) 
    { 
     dY2 = (ray - y) * (ray - y); 

     for (;; x-=FULL) 
     { 
      if (dY2 + (ray - x) * (ray - x) <= ray2) continue; 

      if (x < y) 
      { 
       Y = (y >> 2); 
       posmin = Y; 
       posmax = circleDiameter - Y; 

       // Draw inside square and leave 
       while (Y < posmax) 
       { 
        for (X = posmin; X < posmax; X++) 
         setPixel(circlePosX+X, circlePosY+Y); 
        Y++; 
       } 
       // Just for a better understanding, the while loop does the same thing as: 
       // DrawSquare(circlePosX+Y, circlePosY+Y, circleDiameter - 2*Y); 
       return; 
      } 

      // Draw the 4 borders 
      X = (x >> 2) + 1; 
      Y = y >> 2; 
      posmax = circleDiameter - X; 
      int mirrorY = circleDiameter - Y - 1; 

      while (X < posmax) 
      { 
       setPixel(circlePosX+X, circlePosY+Y); 
       setPixel(circlePosX+X, circlePosY+mirrorY); 
       setPixel(circlePosX+Y, circlePosY+X); 
       setPixel(circlePosX+mirrorY, circlePosY+X); 
       X++; 
      } 
      // Just for a better understanding, the while loop does the same thing as: 
      // int lineSize = circleDiameter - X*2; 
      // Upper border: 
      // DrawHorizontalLine(circlePosX+X, circlePosY+Y, lineSize); 
      // Lower border: 
      // DrawHorizontalLine(circlePosX+X, circlePosY+mirrorY, lineSize); 
      // Left border: 
      // DrawVerticalLine(circlePosX+Y, circlePosY+X, lineSize); 
      // Right border: 
      // DrawVerticalLine(circlePosX+mirrorY, circlePosY+X, lineSize); 

      break; 
     } 
    } 
} 

void DrawSquare(int x, int y, int size) 
{ 
    for(int i=0 ; i<size ; i++) 
     DrawHorizontalLine(x, y+i, size); 
} 

void DrawHorizontalLine(int x, int y, int width) 
{ 
    for(int i=0 ; i<width ; i++) 
     SetPixel(x+i, y); 
} 

void DrawVerticalLine(int x, int y, int height) 
{ 
    for(int i=0 ; i<height ; i++) 
     SetPixel(x, y+i); 
} 

गैर पूर्णांक व्यास का उपयोग करने के लिए आपको नियत बिन्दु की शुद्धता को बढ़ाने या डबल मूल्यों का उपयोग कर सकते हैं। डीवाई 2 + (रे - एक्स) * (रे - एक्स) और रे 2 (डीएक्स² + डी² और आर²) के बीच अंतर के आधार पर एंटी-एलियास बनाने के लिए भी संभव होना चाहिए

8

आप इसका उपयोग कर सकते हैं:

void DrawFilledCircle(int x0, int y0, int radius) 
{ 
    int x = radius; 
    int y = 0; 
    int xChange = 1 - (radius << 1); 
    int yChange = 0; 
    int radiusError = 0; 

    while (x >= y) 
    { 
     for (int i = x0 - x; i <= x0 + x; i++) 
     { 
      SetPixel(i, y0 + y); 
      SetPixel(i, y0 - y); 
     } 
     for (int i = x0 - y; i <= x0 + y; i++) 
     { 
      SetPixel(i, y0 + x); 
      SetPixel(i, y0 - x); 
     } 

     y++; 
     radiusError += yChange; 
     yChange += 2; 
     if (((radiusError << 1) + xChange) > 0) 
     { 
      x--; 
      radiusError += xChange; 
      xChange += 2; 
     } 
    } 
} 
5

मुझे पाल्म 3 डी का जवाब पसंद है। क्रूर बल होने के लिए, यह एक अद्भुत तेज़ समाधान है। इसे धीमा करने के लिए कोई वर्ग रूट या त्रिकोणमितीय कार्य नहीं हैं। इसकी एक कमजोरी घोंसला लूप है।

इसे एक लूप में कनवर्ट करने से यह कार्य लगभग दोगुना तेज़ हो जाता है।

int r2 = r * r; 
int area = r2 << 2; 
int rr = r << 1; 

for (int i = 0; i < area; i++) 
{ 
    int tx = (i % rr) - r; 
    int ty = (i/rr) - r; 

    if (tx * tx + ty * ty <= r2) 
     SetPixel(x + tx, y + ty, c); 
} 

यह एकल लूप समाधान लाइन ड्राइंग समाधान की दक्षता को प्रतिद्वंद्वी बनाता है।

  int r2 = r * r; 
      for (int cy = -r; cy <= r; cy++) 
      { 
       int cx = (int)(Math.Sqrt(r2 - cy * cy) + 0.5); 
       int cyy = cy + y; 

       lineDDA(x - cx, cyy, x + cx, cyy, c); 
      } 
+0

मुझे आश्चर्य है कि आपका समाधान palm3d से तेज है। क्या आपने इसे माप लिया? क्या आपके पास संख्याएं हैं? –

संबंधित मुद्दे