Обчисліть випадкові точки (пікселі) у колі (зображення)


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
Відмінна відповідь. Ще одне, що потрібно додати: не забудьте
посадити

На жаль, ти побив її, - не побачив цієї публікації, коли я розмістив свою. Сайт wolfram - це дивовижний ресурс для подібних речей.
Тім Холт

1
@TimHolt трапляється весь час :)
David Gouveia

Це, якщо центр кола знаходиться на рівні 0,0?
jjxtra

@PsychoDad Центром кола буде (_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)

На жаль, дублікат обраної відповіді: P
Тім Холт

Я збентежений, тому що ви кажете не використовувати випадкові r та тети, оскільки це створює зважений розподіл, тоді код, який ви показуєте, що стверджує, що створює неваговий розподіл, генерує r у межах [0,1]. Чи мали намір вивести корінь на випадкове число?
PeteUK

Так, виконання квадратного кореня радіуса (поки це 0-1) зменшує несподівану концентрацію точок посередині. Дивіться посилання Wolfram, яке я опублікував, яке ілюструє це та пояснює це з математикою краще, ніж я можу.
Тім Холт

Моє ліжко. Я бачу, що ви робите sqrt (r) під час обчислення х і у.
PeteUK

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 Ми обидва отримуємо нагороди за те, що обидва мають рацію. Усі перемагають! : D
Джон Перді

Обидві відповіді дуже вдячні (і посилання теж!). Чоловік, який я ідіот за те, що сам цього не бачив, -1 для мене :( Ще раз дякую обом!
DMills

Це призведе до генерування випадкових точок, але вони не будуть рівномірно розподілені по диску, правда? Швидше вони будуть зваженими до центру. Просто перевіряючи, що я чогось не пропускаю.
PeteUK

1
@ PeteUK: Ти маєш рацію, відстань слід зважувати. Дозвольте мені оновити.
Джон Перді

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

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 та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.