Bir daire içindeki rastgele noktaları (piksel) hesapla (resim)


19

Belirli bir konumda ve belirli bir çapta daireler içeren bir görüntüm var. Yapmam gereken, daire içindeki rastgele noktaları hesaplayabilmek ve daha sonra belirtilen noktaların ilişkili olduğu pikselleri manipüle edebilmektir. Zaten aşağıdaki kodu var:

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 );
}

Ve bu, dairenin çevresindeki tüm noktaları bulmak için iyi çalışıyor, ancak dairenin herhangi bir yerinden tüm noktalara ihtiyacım var. Bu mantıklı değilse bana bildirin ve açıklığa kavuşturmak için elimden geleni yapacağım.


Güncellemeyi kontrol edin.
David Gouveia

3
Yanlışlıkla ağırlıklı bir dağılım yaratmanın yaygın bir hata olduğu iyi bir soru.
Tim Holt

Yanıtlar:


35

Basit bir çözüm istiyorsanız, yarıçapı da rastgele seçin:

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);
}

Ancak bu, puanlarınızın dairenin merkezine doğru daha yoğun olmasına neden olur:

resim açıklamasını buraya girin

Düzgün bir dağılım elde etmek için algoritmada aşağıdaki değişikliği yapın:

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

Bu da aşağıdaki sonucu verecektir:

resim açıklamasını buraya girin

Daha fazla bilgi için aşağıdaki bağlantıyı kontrol edin: MathWorld - Disk Noktası Toplama .

Ve son olarak algoritmanın her iki versiyonunu karşılaştıran basit bir JsFiddle gösterisi .


1
Mükemmel cevap. Eklemek için sadece bir şey: rasgele sayı üretecini tohumlamayı unutma :)
kevintodisco

Oop yendi sen onunla bir araya geldi - benim yayınladığımda bu yazı görmedim. Volfram sitesi bu tür şeyler için harika bir kaynaktır.
Tim Holt

1
@TimHolt her zaman olur :)
David Gouveia

Daire merkezinin 0,0 olduğu varsayılıyor mu?
jjxtra

@PsychoDad Dairenin merkezi (_originX, _originY) olacaktır
David Gouveia

5

Sadece rastgele r ve teta KULLANMAYIN! Bu merkezde daha fazla nokta ile ağırlıklı bir dağılım oluşturur. Bu sayfa iyi gösteriyor ...

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

İşte ağırlıklı olmayan bir dağıtım oluşturan yöntem ...

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

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

Hata! Seçilen cevabın kopyası: P
Tim Holt

Ben rasgele r ve teta ağırlıklı bir dağıtım oluşturur gibi kullanmak değil demek çünkü karışık olduğunu sonra iddia bir ağırlıklı olmayan dağıtım oluşturduğunu göstermek kodu r [0,1] aralığında üretir. Rastgele sayıyı köklendirmeyi düşündünüz mü?
PeteUK

Evet yarıçapın kare kökünü yapmak (0-1 olduğu sürece), ortadaki noktaların beklenmedik konsantrasyonunu azaltır. Yayınladığım Wolfram bağlantısına bakın, bunu gösteren ve matematikle benden daha iyi açıklayan.
Tim Holt

Benim hatam. X ve y hesaplarken sqrt (r) yaptığınızı görüyorum.
PeteUK

4

Orada yarı yoldasınız. Rasgele bir açı oluşturmaya ek olarak, tekdüze bir dağılım elde etmek için ağırlıklı olarak yarıçaptan daha küçük veya yarıçapa eşit rastgele bir mesafe oluşturun:

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);
}

Şimdi birlikte düşünüyoruz kutupsal .

Ayrıca bir kare kökü önlemek için mesafeyi de ağırlıklandırabilirsiniz:

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

Tamam, bu yüzden birkaç saniye içinde aynı cevabı verdik. Şimdi ne olacak? :)
David Gouveia

@DavidGouveia İkimiz de doğru olduğu için ikimiz de oy alıyoruz. Herkes kazanır! : D
Jon Purdy

Her iki cevap da çok takdir edildi (ve bağlantı da!). Adam kendimi olsa -1 görmüyorum için aptalım, bana :(
ikinize

Bu rastgele noktalar oluşturur, ancak disk üzerinde eşit olarak dağılmazlar, değil mi? Aksine merkeze doğru ağırlıklandırılırlar. Sadece bir şey eksik olmadığımı kontrol ediyorum.
PeteUK

1
@PeteUK: Haklısın, mesafe tartılmalı. Güncellememe izin ver.
Jon Purdy

3

Performans bir sorunsa, alternatif bir çözüm, dairenizin genişliğine / yüksekliğine sahip bir kutuda rastgele bir konum oluşturmak ve daha sonra dairenin bölgesinde olmayan noktaları atmaktır.

Bu yöntemin avantajı, platformunuza bağlı olarak büyük bir hız tasarrufu olabilecek cos / sin / sqrt işlevleri gerçekleştirmemenizdir.

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)
}

Bunu deneyeceğim ve işleri hızlandırıp hızlandırmayacağım. Bir performans sorunum olduğundan emin değilim, ama yine de deneyeceğim, teşekkürler!
DMills

0

Listelenen yorumlardan birine yaklaştım ve çörek şekilli nokta oluşturma sistemi oluşturma işlevini genişlettim.

            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);
            }

Daha önce bahsedildiği gibi benzer bir yaklaşımdır, ancak farklı sonuçlar sağlamıştır. Dairenin iç kısmı boş bırakılacaktır.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.