एक वृत्त (छवि) के भीतर यादृच्छिक बिंदुओं (पिक्सेल) की गणना करें


19

मेरी एक छवि है जिसमें एक विशिष्ट स्थान और एक विशिष्ट व्यास में एक मंडलियां हैं। मुझे जो करने की ज़रूरत है वह सर्कल के भीतर यादृच्छिक बिंदुओं की गणना करने में सक्षम होने के लिए है, और फिर जोड़तोड़ करते हुए पिक्सल ने कहा कि अंक संबंधित हैं। मेरे पास निम्नलिखित कोड पहले से हैं:

private Point CalculatePoint()
{
    var angle = _random.NextDouble() * ( Math.PI * 2 );
    var x = _originX + ( _radius * Math.Cos( angle ) );
    var y = _originY + ( _radius * Math.Sin( angle ) );
    return new Point( ( int )x, ( int )y );
}

और वह सर्कल के परिधि में सभी बिंदुओं को खोजने के लिए ठीक काम करता है, लेकिन मुझे सर्कल में कहीं से भी सभी बिंदुओं की आवश्यकता है। अगर इससे कोई मतलब नहीं है तो मुझे बताएं और मैं स्पष्ट करने की पूरी कोशिश करूंगा।


अद्यतन की जाँच करें।
डेविड गाविया

3
इस अर्थ में अच्छा प्रश्न है कि अनजाने में भारित वितरण बनाना एक सामान्य त्रुटि है।
टिम होल्ट

जवाबों:


35

यदि आप एक सरल समाधान चाहते हैं तो बस त्रिज्या को भी यादृच्छिक करें:

private Point CalculatePoint()
{
    var angle = _random.NextDouble() * Math.PI * 2;
    var radius = _random.NextDouble() * _radius;
    var x = _originX + radius * Math.Cos(angle);
    var y = _originY + radius * Math.Sin(angle);
    return new Point((int)x,(int)y);
}

हालांकि आपके अंक सर्कल के केंद्र की ओर अधिक केंद्रित होते हैं:

यहाँ छवि विवरण दर्ज करें

एक समान वितरण प्राप्त करने के लिए एल्गोरिथ्म में निम्नलिखित परिवर्तन करें:

var radius = Math.Sqrt(_random.NextDouble()) * _radius;

जो निम्नलिखित परिणाम देगा:

यहाँ छवि विवरण दर्ज करें

अधिक जानकारी के लिए निम्न लिंक की जाँच करें: MathWorld - डिस्क पॉइंट पिकिंग

और अंत में यहाँ एल्गोरिदम के दोनों संस्करण की तुलना में एक सरल JsFiddle प्रदर्शन है।


1
बहुत बढ़िया जवाब। जोड़ने के लिए बस एक चीज: यादृच्छिक संख्या जनरेटर को बीज न भूलें :)
kevintodisco

ओह, आप इसे हरा दिया - जब मैंने मेरा पोस्ट किया तो यह पोस्ट नहीं देखी। वुल्फराम साइट इस तरह की चीज़ के लिए एक भयानक संसाधन है।
टिम होल्ट

1
@TimHolt हर समय होता है :)
डेविड

क्या यह मान लिया जाए कि वृत्त केंद्र 0,0 पर है?
jjxtra

@PychoDad चक्र का केंद्र होगा (_originX, _originY)
डेविड

5

बस यादृच्छिक आर और थीटा का उपयोग न करें! यह केंद्र में अधिक बिंदुओं के साथ भारित वितरण बनाता है। यह पृष्ठ इसे अच्छी तरह दिखाता है ...

http://mathworld.wolfram.com/DiskPointPicking.html

यहाँ विधि है कि एक गैर भारित वितरण बनाता है ...

var r = rand(0,1)
var theta = rand(0,360)

var x = sqrt(r) * cos(theta)
var y = sqrt(r) * sin(theta)

चयनित उत्तर के डुप्लिकेट ओह्स: पी
टिम होल्ट 20

मैं उलझन में हूं क्योंकि आप कहते हैं कि यादृच्छिक आर और थीटा का उपयोग न करें क्योंकि यह एक भारित वितरण बनाता है, फिर आपके द्वारा दिखाए गए कोड का दावा है कि आप एक गैर-भारित वितरण रेंज के भीतर r उत्पन्न करते हैं [0,1]। क्या आपने यादृच्छिक संख्या को वर्गाकार करने का इरादा किया है?
पेटेयूके

हां त्रिज्या का वर्गमूल (जब तक यह 0-1 है) मध्य में बिंदुओं की अप्रत्याशित एकाग्रता को कम करता है। मेरे द्वारा पोस्ट किया गया वोल्फ्राम लिंक देखें, जो इसे दिखाता है और इसे गणित से बेहतर बताता है जितना मैं कर सकता हूं।
टिम होल्ट

मेरी गलती। मैं देखता हूं कि x और y की गणना करते समय आप sqrt (r) करते हैं।
पेटेयूके

4

तुम वहाँ आधी हो। एक यादृच्छिक कोण उत्पन्न करने के अलावा, बस एक यादृच्छिक दूरी उत्पन्न करें, जो त्रिज्या से कम या बराबर हो, ताकि आपको एक समान दूरी मिल सके:

private Point CalculatePoint()
{
    var angle = _random.NextDouble() * Math.PI * 2;
    var distance = Math.Sqrt(_random.NextDouble()) * _radius;
    var x = _originX + (distance * Math.Cos(angle));
    var y = _originY + (distance * Math.Sin(angle));
    return new Point((int)x, (int)y);
}

अब आप ध्रुवीय के साथ सोच रहे हैं ।

एक वर्गमूल से बचने के लिए आप दूरी भी नाप सकते हैं जैसे:

var distance = _random.NextDouble() + _random.NextDouble();
distance = (distance <= 1 ? distance : 2 - distance) * _radius;

ठीक है, इसलिए हमने अंतर के सेकंड के भीतर एक ही जवाब दिया। अब क्या? :)
डेविड गौविया

@DavidGouveia हम दोनों सही होने के लिए उठते हैं। हर कोई जीतता है! : डी
जॉन पूर्डी

दोनों जवाब बहुत सराहना की (और लिंक भी!)। यार मैं एक बेवकूफ हूँ कि खुद को नहीं देख पा रहा हूँ, -1 से मुझे :( फिर से तुम दोनों को धन्यवाद!
DMills

यह यादृच्छिक अंक उत्पन्न करेगा, लेकिन वे डिस्क पर समान रूप से वितरित नहीं होंगे, है ना? बल्कि उन्हें केंद्र की ओर भारित किया जाएगा। बस जाँच मैं कुछ याद नहीं कर रहा हूँ।
पेटेयूके

1
@ पेतुका: आप सही कह रहे हैं, दूरी का वजन होना चाहिए। मुझे अपडेट करने दो।
जॉन पूर्डी

3

यदि प्रदर्शन एक समस्या है, तो एक वैकल्पिक समाधान आपके सर्कल की चौड़ाई / ऊंचाई के साथ एक बॉक्स में एक यादृच्छिक स्थिति उत्पन्न करना है और फिर किसी भी बिंदु को फेंकना है जो सर्कल के क्षेत्र में नहीं हैं।

इस पद्धति का लाभ यह है कि आप कोई cos / sin / sqrt फ़ंक्शंस नहीं कर रहे हैं, जो आपके प्लेटफ़ॉर्म के आधार पर एक बड़ी गति बचत हो सकती है।

var x = _random.NextDouble();
var y = _random.NextDouble();
if (x*x + y*y < 1.0f)
{
    // we have a usable point inside a circle
    x = x * diameter - _radius + _OriginX;
    y = y * diameter - _radius + _OriginY;
    // use the point(x,y)
}

मैं कोशिश कर रहा हूँ कि बाहर देखें और देखें कि क्या यह चीजों को गति देता है। मुझे यकीन नहीं है कि मुझे एक प्रदर्शन समस्या है, लेकिन मैं इस तरह से कोशिश करूँगा, धन्यवाद!
DMills 1

0

मैंने सूचीबद्ध टिप्पणियों में से एक का दृष्टिकोण लिया है, और डोनट के आकार की बिंदु पीढ़ी प्रणाली बनाने के लिए कार्यक्षमता को बढ़ाया है।

            private Vector2 CalculatePosition()
            {
                double angle = _rnd.NextDouble() * Math.PI * 2;
                double radius = InnerCircleRadius + (Math.Sqrt(_rnd.NextDouble()) * (OuterCircleRadius - InnerCircleRadius));
                double x = (_context.ScreenLayout.Width * 0.5f) + (radius * Math.Cos(angle));
                double y = (_context.ScreenLayout.Height * 0.5f) + (radius * Math.Sin(angle));
                return new Vector2((int)x, (int)y);
            }

यह एक समान दृष्टिकोण है जैसा कि पहले उल्लेख किया गया है लेकिन विभिन्न परिणाम प्रदान किए गए हैं। वृत्त का आंतरिक भाग बिना किसी बिंदु के खाली छोड़ दिया जाएगा।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.