Создать случайную точку внутри круга (равномерно)

212

Мне нужно создать равномерно случайную точку в радиусе круга R .

Я понимаю это, просто выбирая равномерно случайный угол в интервале [0 ... 2π) и равномерно случайный радиус в интервале (0 ... R ), я получу больше точек к центру, поскольку для двух данных радиусы, точки в меньшем радиусе будут ближе друг к другу, чем для точек в большем радиусе.

Я нашел запись в блоге по этому поводу здесь , но я не понимаю его рассуждения. Я полагаю, это правильно, но мне бы очень хотелось понять, откуда он получает (2 / R 2 ) × r и как он получает окончательное решение.


Обновление: 7 лет после публикации этого вопроса я все еще не получил удовлетворительного ответа на фактический вопрос относительно математики позади алгоритма квадратного корня. Так что я потратил день на написание ответа сам. Ссылка на мой ответ .

aioobe
источник
18
Действительно ли недостаток выборки отклонения имеет большое значение? Ожидаемое количество попыток составляет 4 / π ≈ 1.27, а вероятность того, что вам нужно больше, чем k попыток, составляет (1-π / 4) ^ k. Для k = 20 это ≈ .00000000000004, а для k = 50 это порядка 10 ^ {- 34}. Вы можете принять эти шансы в любой день; у тебя все будет хорошо.
ShreevatsaR
3
На самом деле, отбор отбраковки обеспечивает гарантию прекращения. Вероятность того, что ваш алгоритм никогда не завершится, бесконечно мала (точнее, равна нулю).
Джаред Нильсен
2
По моему мнению, важность недостатка выборки отбраковки пропорциональна простоте использования метода отбора проб, который позволяет избежать отклонения. В этом случае недостаток важен, потому что выборка без отклонения проста.
spex
4
@spex На практике метод отбраковки быстрее, потому что он устраняет необходимость оценки трансцендентных функций.
pjs
2
(продолжение) отклонение: 0,52 с Все дали идентичные средние и стандартные отклонения (до 3 сиг. рис.). Как и ожидалось, выборка отклонения не удалась в 27% случаев (4 / pi-1), поэтому требовалось на 27% больше случайных чисел, чем btilly, но на 15% меньше, чем sigfpe. Это подтверждает комментарии, сделанные pjs и другими, о том, что выборка отклонения является, вероятно, лучшим подходом, если случайные сигналы не очень дороги для генерации.
Питер Дэвидсон

Ответы:

189

Давайте подойдем к этому, как Архимед.

Как мы можем сгенерировать точку равномерно в треугольнике ABC, где | AB | = | BC |? Давайте сделаем это проще, расширив параллелограмм ABCD. В ABCD легко генерировать точки равномерно. Мы равномерно выбираем случайную точку X на AB и Y на BC и выбираем Z таким, что XBYZ является параллелограммом. Чтобы получить равномерно выбранную точку в исходном треугольнике, мы просто складываем любые точки, которые появляются в АЦП, обратно в АВС вдоль АС.

Теперь рассмотрим круг. В пределе мы можем рассматривать его как бесконечно много равнобедренных треугольников ABC с B в начале координат и A и C на окружности, исчезающе близко друг к другу. Мы можем выбрать один из этих треугольников, просто выбрав угол тета. Итак, теперь нам нужно сгенерировать расстояние от центра, выбрав точку в полоске ABC. Снова продлим до ABCD, где D теперь в два раза больше радиуса от центра круга.

Выбрать случайную точку в ABCD легко, используя описанный выше метод. Выберите случайную точку на AB. Равномерно выбрать случайную точку на BC. То есть. Выберите пару случайных чисел x и y равномерно на [0, R], давая расстояния от центра. Наш треугольник является тонкой полоской, поэтому AB и BC по существу параллельны. Таким образом, точка Z - это просто расстояние x + y от начала координат. Если x + y> R, мы сбрасываем обратно.

Вот полный алгоритм для R = 1. Я надеюсь, вы согласны, что это довольно просто. Он использует триггер, но вы можете дать гарантию того, сколько времени это займет и сколько random()вызовов ему нужно, в отличие от выборки отклонения.

t = 2*pi*random()
u = random()+random()
r = if u>1 then 2-u else u
[r*cos(t), r*sin(t)]

Вот это в Mathematica.

f[] := Block[{u, t, r},
  u = Random[] + Random[];
  t = Random[] 2 Pi;
  r = If[u > 1, 2 - u, u];
  {r Cos[t], r Sin[t]}
]

ListPlot[Table[f[], {10000}], AspectRatio -> Automatic]

введите описание изображения здесь

SIGFPE
источник
6
@Karelzarath Мне нравится нелогичное представление о бесконечно тонком треугольнике, который все еще шире на одном конце, чем на другом :-) Он получает правильный ответ.
Sigfpe
2
@ Hammar Не уверен, что это хорошо обобщает на п измерения. Но в 3d вы можете использовать другой результат Архимеда! Используйте теорему «шляпной коробки», чтобы сгенерировать точку на цилиндре (легко!), А затем отобразить ее обратно на сферу. Это дает направление. Теперь используйте random()+random()+random()более сложное сворачивание (то есть, 6-кратный сгиб бесконечно тонкого параллелепипеда к тераэдру). Не уверен, что это хороший метод.
Sigfpe
2
Я думал, 1 минута, чтобы выяснить разницу между random () + random () и 2 * random () ... Я так глуп: /
JiminP
3
@ Tharwen Обратите внимание, что в круге больше точек с радиусом 0,9-1,0, чем с радиусом 0,0-0,1. random () + random () генерирует радиусы с большей вероятностью около 1,0, но лежат в диапазоне 0,0-2,0. Когда они сложены, они, скорее всего, будут около 1.0 и всегда в диапазоне 0.0-1.0. Более того, именно такая пропорция необходима в первом предложении этого комментария. Простое деление пополам дает больше чисел около 0,5, и это было бы неправильно.
Sigfpe
2
@ Tharwen Попробуйте использовать обе схемы для генерации случайных чисел и посмотрите, что вы получите. 2 * random () дает числа, равномерно распределенные в диапазоне от 0 до 2. random () + random () дает вам числа в диапазоне от 0 до 2, но (как правило) будет больше чисел около 1,0, чем около 0,0 или 2,0. Это похоже на то, как бросание двух кубиков и суммирование дают больше 7, чем любое другое число.
Sigfpe
134

Как создать случайную точку внутри круга радиуса R :

r = R * sqrt(random())
theta = random() * 2 * PI

(Предполагается, что random() дает значение между 0 и 1 равномерно)

Если вы хотите преобразовать это в декартовы координаты, вы можете сделать

x = centerX + r * cos(theta)
y = centerY + r * sin(theta)


Зачем sqrt(random()) ?

Давайте посмотрим на математику, которая приводит к sqrt(random()). Предположим для простоты, что мы работаем с единичным кругом, т.е. R = 1.

Среднее расстояние между точками должно быть одинаковым независимо от того, как далеко от центра мы смотрим. Это означает, например, что, глядя на периметр окружности с окружностью 2, мы должны найти вдвое больше точек, чем количество точек на периметре окружности с окружностью 1.


                

Поскольку окружность круга (2π r ) растет линейно с ростом r , отсюда следует, что число случайных точек должно расти линейно с ростом r . Другими словами, искомая функция плотности вероятности (PDF) растет линейно. Так как PDF должен иметь площадь, равную 1, а максимальный радиус равен 1, мы имеем


                

Итак, мы знаем, как должна выглядеть желаемая плотность наших случайных значений. Теперь: как мы можем генерировать такое случайное значение, когда все, что у нас есть, это равномерное случайное значение между 0 и 1?

Мы используем трюк под названием выборка обратного преобразования

  1. Из PDF создайте накопительную функцию распределения (CDF)
  2. Отразите это вдоль y = x
  3. Примените полученную функцию к равномерному значению от 0 до 1.

Звучит сложно? Позвольте мне вставить цитату с небольшой боковой дорожкой, которая передает интуицию:

Предположим, мы хотим сгенерировать случайную точку со следующим распределением:

                

То есть

  • 1/5 баллов равномерно между 1 и 2, и
  • 4/5 баллов равномерно между 2 и 3.

CDF - это, как следует из названия, кумулятивная версия PDF. Интуитивно понятно: в то время как PDF ( x ) описывает количество случайных значений в точке x , CDF ( x ) описывает количество случайных значений меньше значения x .

В этом случае CDF будет выглядеть так:

                

Чтобы увидеть, как это полезно, представьте, что мы стреляем пулями слева направо на равномерно распределенных высотах. Когда пули попадают в линию, они падают на землю:

                

Посмотрите, как плотность пуль на земле соответствует нашему желаемому распределению! Мы почти там!

Проблема в том, что для этой функции ось y является выходной, а ось x является входной . Мы можем только «стрелять пулями прямо с земли»! Нам нужна обратная функция!

Вот почему мы отражаем все это; х становится у, а у становится х :

                

Мы называем это CDF -1 . Чтобы получить значения в соответствии с желаемым распределением, мы используем CDF -1 (random ()).

… Итак, вернемся к генерации случайных значений радиуса, где наш PDF равен 2 х .

Шаг 1: Создайте CDF: так

как мы работаем с реалами, CDF выражается как интеграл PDF.

CDF ( x ) = ∫ 2 x = x 2

Шаг 2: Зеркально отразите CDF вдоль y = x :

Математически это сводится к обмену x и y и решению для y :

CDF :      y = x 2
Обмен:    x = y 2
Решить:    y = √ x
CDF -1 :   y = √ x

Шаг 3: применить полученную функцию к равномерному значению от 0 до 1

CDF -1 (random ()) = √random ()

Что мы и собираемся извлечь :-)

aioobe
источник
Этот алгоритм может быть использован для эффективной генерации точек на кольце.
Иван Ковтун
На ринге? Как с фиксированным радиусом? Не уверен, что я понимаю ваш вопрос, но если у вас фиксированный радиус, вам просто нужно рандомизировать угол.
aioobe
2
Я попытался использовать более простое слово «кольцо» вместо кольца - область, ограниченную двумя концентрическими окружностями. В этом случае алгоритм отклонения становится неэффективным, и алгоритм первого топа трудно обобщать. И угловой корпус с одним радиусом также покрыт вашим алгоритмом. Мы всегда генерируем радиус как sqrt (случайный (min_radius ^ 2, max_radius ^ 2)), даже когда min_radius == max_radius.
Иван Ковтун
1
О, классно! Чтобы быть ясным, когда вы говорите random(min_radius², max_radius²), вы имеете в виду что-то эквивалентное random() * (max_radius² - min_radius²) + min_radius², где random()возвращает равномерное значение между 0 и 1?
aioobe
да, это именно то, что я имею в виду: radius = sqrt (random () * (max_radius² - min_radius²) + min_radius²).
Иван Ковтун
27

Вот быстрое и простое решение.

Выберите два случайных числа в диапазоне (0, 1), а именно aи b. Если b < aпоменять их. Ваша точка зрения(b*R*cos(2*pi*a/b), b*R*sin(2*pi*a/b)) .

Вы можете думать об этом решении следующим образом. Если вы возьмете круг, обрежете его, а затем выпрямите, вы получите прямоугольный треугольник. Уменьшите этот треугольник, и вы получите треугольник от (0, 0)до (1, 0)до (1, 1)и обратно до (0, 0). Все эти преобразования изменяют плотность равномерно. То, что вы сделали, равномерно выбрали случайную точку в треугольнике и полностью изменили процесс, чтобы получить точку в круге.

btilly
источник
По какой-то причине это дает мне гораздо более равномерное распределение, чем принятый ответ, хотя мне нужно было разделить координату на радиус, в противном случае она находится внутри окружности R ^ 2
Грег Заал
3
Спасибо, это ваш код на Java, возможно, кто-то найдет его полезным: float random1 = MathUtils.random (); float random2 = MathUtils.random (); float randomXPoint = random2 * radius MathUtils.cos (MathUtils.PI2 * random1 / random2); float randomYPoint = random2 * radius MathUtils.sin (MathUtils.PI2 * random1 / random2);
Тони Сералва
очень хорошо! Мне нравится идея большей вероятности для централизации точек, поэтому, если мы не поменяемся местами, когда b < aмы сможем достичь этого! например, в javascript jsfiddle.net/b0sb5ogL/1
Гильерме
Я думаю, что ваше решение плохо. Это не дает единообразных результатов. Проверьте этот скриншот prntscr.com/fizxgc
bolec_kolec
4
Можете ли вы объяснить немного больше, как вырезать круг и выправить его?
kec
21

Обратите внимание на плотность точек пропорционально обратному квадрату радиуса, поэтому вместо того, чтобы выбирать rиз [0, r_max], выберите из [0, r_max^2], а затем вычислите ваши координаты как:

x = sqrt(r) * cos(angle)
y = sqrt(r) * sin(angle)

Это даст вам равномерное распределение точек на диске.

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

ЛИБОР
источник
12

Подумайте об этом таким образом. Если у вас есть прямоугольник, где одна ось является радиусом, а другая - углом, и вы берете точки внутри этого прямоугольника, которые близки к радиусу 0. Все они будут располагаться очень близко к началу координат (то есть близко друг к другу на окружности.) Однако, точки около радиуса R, все они будут падать около края круга (то есть далеко друг от друга).

Это может дать вам некоторое представление о том, почему вы получаете такое поведение.

Коэффициент, полученный по этой ссылке, говорит вам, сколько соответствующей области в прямоугольнике нужно отрегулировать, чтобы она не зависела от радиуса после его сопоставления с окружностью.

Редактировать: Итак, он пишет в ссылке, которой вы делитесь: «Это достаточно легко сделать, рассчитав обратное кумулятивному распределению, и мы получим для r:».

Основным условием здесь является то, что вы можете создать переменную с желаемым распределением из униформы, отобразив униформу с помощью обратной функции кумулятивной функции распределения желаемой функции плотности вероятности. Зачем? Просто пока принимайте это как должное, но это факт.

Вот мое интуитивное объяснение математики. Функция плотности f (r) по отношению к r должна быть пропорциональна самой r. Понимание этого факта является частью любой основной книги исчисления. Смотрите разделы об элементах полярной зоны. Некоторые другие постеры упоминали об этом.

Поэтому мы назовем это f (r) = C * r;

Это оказывается большая часть работы. Теперь, поскольку f (r) должна быть плотностью вероятности, вы можете легко увидеть, что, интегрируя f (r) по интервалу (0, R), вы получите, что C = 2 / R ^ 2 (это упражнение для читателя .)

Таким образом, f (r) = 2 * r / R ^ 2

Хорошо, вот как вы получите формулу в ссылке.

Затем последняя часть идет от равномерной случайной величины u в (0,1), которую необходимо отобразить с помощью обратной функции кумулятивной функции распределения от этой требуемой плотности f (r). Чтобы понять, почему это так, вам нужно найти расширенный вероятностный текст, такой как, вероятно, папулис (или получить его самостоятельно).

Интегрируя f (r), вы получите F (r) = r ^ 2 / R ^ 2

Чтобы найти обратную функцию этого, вы устанавливаете u = r ^ 2 / R ^ 2, а затем решаете для r, что дает вам r = R * sqrt (u)

Это также имеет смысл интуитивно, u = 0 должно отображаться на r = 0. Кроме того, u = 1 должно отображаться на r = R. Кроме того, оно идет по функции квадратного корня, которая имеет смысл и соответствует ссылке.

Крис А.
источник
10

Причина, по которой наивное решение не работает, заключается в том, что оно дает более высокую плотность вероятности точкам, расположенным ближе к центру круга. Другими словами, у круга, который имеет радиус r / 2, есть вероятность r / 2 получить выбранную точку, но у него есть область (количество точек) pi * r ^ 2/4.

Поэтому мы хотим, чтобы плотность вероятности радиуса имела следующее свойство:

Вероятность выбора радиуса, меньшего или равного данному r, должна быть пропорциональна площади круга с радиусом r. (потому что мы хотим иметь равномерное распределение по точкам, а большие области означают больше точек)

Другими словами, мы хотим, чтобы вероятность выбора радиуса между [0, r] была равна его доле от общей площади круга. Общая площадь круга равна pi * R ^ 2, а площадь круга с радиусом r равна pi * r ^ 2. Таким образом, мы хотели бы, чтобы вероятность выбора радиуса между [0, r] была (pi * r ^ 2) / (pi * R ^ 2) = r ^ 2 / R ^ 2.

Теперь приходит математика:

Вероятность выбора радиуса между [0, r] является интегралом p (r) dr от 0 до r (это просто потому, что мы добавляем все вероятности меньших радиусов). Таким образом, мы хотим, чтобы интеграл (p (r) dr) = r ^ 2 / R ^ 2. Мы можем ясно видеть, что R ^ 2 является константой, поэтому все, что нам нужно сделать, это выяснить, какой p (r) при интеграции даст нам что-то вроде r ^ 2. Ответ явно г * постоянный. интеграл (r * постоянная dr) = r ^ 2/2 * постоянная. Это должно быть равно r ^ 2 / R ^ 2, поэтому константа = 2 / R ^ 2. Таким образом, у вас есть распределение вероятности p (r) = r * 2 / R ^ 2

Примечание. Другой, более интуитивно понятный способ осмыслить проблему - представить, что вы пытаетесь присвоить каждому кругу радиус вероятности плотности ra, равный пропорции числа точек на его окружности. Таким образом, окружность с радиусом r будет иметь 2 * pi * r "точки" на своей окружности. Общее количество баллов: pi * R ^ 2. Таким образом, вы должны дать окружности ra вероятность, равную (2 * pi * r) / (pi * R ^ 2) = 2 * r / R ^ 2. Это намного проще для понимания и более интуитивно понятно, но не совсем математически обоснованно.

user502248
источник
9

Пусть ρ (радиус) и φ (азимут) - две случайные величины, соответствующие полярным координатам произвольной точки внутри окружности. Если точки распределены равномерно, то какова функция распределения ρ и φ?

Для любого r: 0 <r <R вероятность радиусной координаты ρ меньше r равна

P [ρ <r] = P [точка находится в окружности радиуса r] = S1 / S0 = (r / R) 2

Где S1 и S0 - площади круга радиуса r и R соответственно. Таким образом, CDF может быть дан как:

          0          if r<=0
  CDF =   (r/R)**2   if 0 < r <= R
          1          if r > R

И PDF:

PDF = d/dr(CDF) = 2 * (r/R**2) (0 < r <= R).

Обратите внимание, что для R = 1 случайная величина sqrt (X), где X равномерно на [0, 1), имеет этот точный CDF (потому что P [sqrt (X) <y] = P [x <y ** 2] = y * * 2 для 0 <y <= 1).

Распределение φ очевидно равномерно от 0 до 2 * π. Теперь вы можете создавать случайные полярные координаты и преобразовывать их в декартовы, используя тригонометрические уравнения:

x = ρ * cos(φ)
y = ρ * sin(φ)

Не могу удержаться, чтобы опубликовать код Python для R = 1.

from matplotlib import pyplot as plt
import numpy as np

rho = np.sqrt(np.random.uniform(0, 1, 5000))
phi = np.random.uniform(0, 2*np.pi, 5000)

x = rho * np.cos(phi)
y = rho * np.sin(phi)

plt.scatter(x, y, s = 4)

Ты получишь

введите описание изображения здесь

англичанин, иммигрировавшие в Австралии
источник
7

Это действительно зависит от того, что вы подразумеваете под «равномерно случайным». Это тонкий момент, и вы можете узнать больше об этом на странице вики здесь: http://en.wikipedia.org/wiki/Bertrand_paradox_%28probability%29 , где та же проблема, давая различные интерпретации для «равномерно случайных» дает разные ответы!

В зависимости от того, как вы выбираете точки, распределение может варьироваться, даже если они в некоторых смысле .

Кажется, что запись в блоге пытается сделать ее равномерно случайной в следующем смысле: если вы возьмете под круг окружности с тем же центром, то вероятность того, что точка попадет в эту область, пропорциональна площади область. Я полагаю, что это попытка следовать принятой в настоящее время стандартной интерпретации «равномерно случайных» для 2D-областей с определенными на них областями : вероятность падения точки в любом регионе (с четко определенной областью) пропорциональна площади этого региона.


источник
5
Или, скорее, вероятность того, что точка попадет в любую произвольную область, пропорциональна области области - при условии, что область имеет область .
ShreevatsaR
@Shree: Правильно, именно это я и имел в виду под моим утверждением в скобках. Я сделаю это яснее, спасибо. Кстати, о блоге не было никаких реальных доказательств того, что произвольные области дают пропорциональные вероятности, поэтому я решил сформулировать это так.
6

Вот мой код Python для генерации numслучайных точек из круга радиуса rad:

import matplotlib.pyplot as plt
import numpy as np
rad = 10
num = 1000

t = np.random.uniform(0.0, 2.0*np.pi, num)
r = rad * np.sqrt(np.random.uniform(0.0, 1.0, num))
x = r * np.cos(t)
y = r * np.sin(t)

plt.plot(x, y, "ro", ms=1)
plt.axis([-15, 15, -15, 15])
plt.show()
krishnab
источник
1
Почему не просто r = np.sqrt(np.random.uniform(0.0, rad**2, num))?
4

Я думаю, что в этом случае использование полярных координат является способом усложнения проблемы, было бы намного проще, если вы выберете случайные точки в квадрат со сторонами длины 2R, а затем выберите точки так (x,y), чтобы x^2+y^2<=R^2.

Асканио
источник
Я имею в виду x ^ 2 + y ^ 2 <= R ^ 2
Sigfpe
1
Это отбраковка выборки. Это нормально, но означает, что время расчета несколько меняется, что может быть проблемой.
Стив Беннетт
Все квадраты 4-х сторонние.
xaxxon
Этот алгоритм более эффективен, чем все, что связано с квадратными корнями или вычислениями sin / cos. Отклоняет менее 21,5% точек квадрата.
Иван Ковтун
3

Решение на Java и пример распространения (2000 баллов)

public void getRandomPointInCircle() {
    double t = 2 * Math.PI * Math.random();
    double r = Math.sqrt(Math.random());
    double x = r * Math.cos(t);
    double y = r * Math.sin(t);
    System.out.println(x);
    System.out.println(y);
}

Распределение 2000 баллов

на основе предыдущего решения https://stackoverflow.com/a/5838055/5224246 от @sigfpe

bolec_kolec
источник
2

Сначала мы генерируем cdf [x], который

Вероятность того, что точка меньше расстояния х от центра круга. Предположим, что круг имеет радиус R.

очевидно, если x равен нулю, то cdf [0] = 0

очевидно, что если x равен R, то cdf [R] = 1

очевидно, если x = r, то cdf [r] = (Pi r ^ 2) / (Pi R ^ 2)

Это связано с тем, что каждая «небольшая область» на круге имеет одинаковую вероятность выбора, поэтому вероятность пропорциональна рассматриваемой области. И площадь, заданная расстоянием х от центра круга, равна Pi r ^ 2

поэтому cdf [x] = x ^ 2 / R ^ 2, потому что Пи отменяют друг друга

у нас есть cdf [x] = x ^ 2 / R ^ 2, где x идет от 0 до R

Итак, мы решаем за х

R^2 cdf[x] = x^2

x = R Sqrt[ cdf[x] ]

Теперь мы можем заменить cdf случайным числом от 0 до 1

x = R Sqrt[ RandomReal[{0,1}] ]

в заключение

r = R Sqrt[  RandomReal[{0,1}] ];
theta = 360 deg * RandomReal[{0,1}];
{r,theta}

мы получаем полярные координаты {0.601168 R, 311.915 градуса}

Стивен Сью
источник
1

Существует линейная зависимость между радиусом и количеством точек, «близких» к этому радиусу, поэтому он должен использовать распределение радиуса, которое также делает число точек данных около радиуса rпропорциональным r.

рекурсивный
источник
1

Я однажды использовал этот метод: он может быть полностью неоптимизирован (то есть он использует массив точек, поэтому его нельзя использовать для больших кругов), но дает достаточно случайное распределение. Вы можете пропустить создание матрицы и рисовать напрямую, если хотите. Метод состоит в том, чтобы рандомизировать все точки в прямоугольнике, которые попадают в круг.

bool[,] getMatrix(System.Drawing.Rectangle r) {
    bool[,] matrix = new bool[r.Width, r.Height];
    return matrix;
}

void fillMatrix(ref bool[,] matrix, Vector center) {
    double radius = center.X;
    Random r = new Random();
    for (int y = 0; y < matrix.GetLength(0); y++) {
        for (int x = 0; x < matrix.GetLength(1); x++)
        {
            double distance = (center - new Vector(x, y)).Length;
            if (distance < radius) {
                matrix[x, y] = r.NextDouble() > 0.5;
            }
        }
    }

}

private void drawMatrix(Vector centerPoint, double radius, bool[,] matrix) {
    var g = this.CreateGraphics();

    Bitmap pixel = new Bitmap(1,1);
    pixel.SetPixel(0, 0, Color.Black);

    for (int y = 0; y < matrix.GetLength(0); y++)
    {
        for (int x = 0; x < matrix.GetLength(1); x++)
        {
            if (matrix[x, y]) {
                g.DrawImage(pixel, new PointF((float)(centerPoint.X - radius + x), (float)(centerPoint.Y - radius + y)));
            }
        }
    }

    g.Dispose();
}

private void button1_Click(object sender, EventArgs e)
{
    System.Drawing.Rectangle r = new System.Drawing.Rectangle(100,100,200,200);
    double radius = r.Width / 2;
    Vector center = new Vector(r.Left + radius, r.Top + radius);
    Vector normalizedCenter = new Vector(radius, radius);
    bool[,] matrix = getMatrix(r);
    fillMatrix(ref matrix, normalizedCenter);
    drawMatrix(center, radius, matrix);
}

введите описание изображения здесь

Марино Шимич
источник
3
Распределения не являются «достаточно случайными». Они либо являются или не являются случайными для данного определения случайного. Ваш ответ косвенный: вы не комментируете свой код и не объясняете, как вы его получили. За косвенными ответами трудно следовать, и им сложнее доверять.
Ричард
1

Элементом площади в круге является dA = rdr * dphi. Этот дополнительный фактор r разрушил вашу идею случайного выбора ar и phi. Хотя phi распределено ровно, r - нет, но ровно в 1 / r (т. Е. У вас больше шансов попасть на границу, чем в «яблочко»).

Таким образом, для генерации точек, равномерно распределенных по окружности, выберите фи из плоского распределения, а r из распределения 1 / r.

В качестве альтернативы используйте метод Монте-Карло, предложенный Mehrdad.

РЕДАКТИРОВАТЬ

Чтобы выбрать случайную r-квартиру в 1 / r, вы можете выбрать случайный x из интервала [1 / R, бесконечность] и вычислить r = 1 / x. Затем r распределяется равномерно в 1 / r.

Для вычисления случайного фи выберите случайный х из интервала [0, 1] и вычислите фи = 2 * пи * х.

Бенджамин Банье
источник
Как именно я выбираю r из "распределения 1 / r" ?
aioobe
0

Я не знаю, открыт ли этот вопрос для нового решения с уже полученным ответом, но я сам столкнулся с точно таким же вопросом. Я попытался «найти решение» для себя, и я нашел его. Это может быть то же самое, что некоторые уже предложили здесь, но в любом случае здесь это:

для того чтобы два элемента поверхности круга были равны, предполагая равные dr, мы должны иметь dtheta1 / dtheta2 = r2 / r1. Запись выражения вероятности для этого элемента как P (r, theta) = P {r1 <r <r1 + dr, theta1 <theta <theta + dtheta1} = f (r, theta) * dr * dtheta1 и установка двух вероятности (для r1 и r2) равны, мы приходим к (при условии, что r и тета независимы) f (r1) / r1 = f (r2) / r2 = постоянная, что дает f (r) = c * r. А в остальном определение константы c следует из условия, что f (r) является PDF.

arsaKasra
источник
Интересный подход для начала с dtheta1 / dtheta2 = r2 / r1. Не могли бы вы рассказать, как вы пришли к этому уравнению?
aioobe
Как уже упоминалось (например, Honk), дифференциальный элемент поверхности круга задается как r dr dtheta, поэтому, если мы предположим, что r1 = r2, то мы будем иметь dr1 * dtheta1 = dr2 * dtheta2, а остальное следует ,
АрсаКасра
0

Решение для программиста:

  • Создайте битовую карту (матрицу логических значений). Он может быть настолько большим, насколько вы хотите.
  • Нарисуйте круг в этой битовой карте.
  • Создайте таблицу поиска точек круга.
  • Выберите случайный индекс в этой таблице поиска.
const int RADIUS = 64;
const int MATRIX_SIZE = RADIUS * 2;

bool matrix[MATRIX_SIZE][MATRIX_SIZE] = {0};

struct Point { int x; int y; };

Point lookupTable[MATRIX_SIZE * MATRIX_SIZE];

void init()
{
  int numberOfOnBits = 0;

  for (int x = 0 ; x < MATRIX_SIZE ; ++x)
  {
    for (int y = 0 ; y < MATRIX_SIZE ; ++y)
    {
      if (x * x + y * y < RADIUS * RADIUS) 
      {
        matrix[x][y] = true;

        loopUpTable[numberOfOnBits].x = x;
        loopUpTable[numberOfOnBits].y = y;

        ++numberOfOnBits;

      } // if
    } // for
  } // for
} // ()

Point choose()
{
  int randomIndex = randomInt(numberOfBits);

  return loopUpTable[randomIndex];
} // ()

Растровое изображение необходимо только для объяснения логики. Это код без растрового изображения:

const int RADIUS = 64;
const int MATRIX_SIZE = RADIUS * 2;

struct Point { int x; int y; };

Point lookupTable[MATRIX_SIZE * MATRIX_SIZE];

void init()
{
  int numberOfOnBits = 0;

  for (int x = 0 ; x < MATRIX_SIZE ; ++x)
  {
    for (int y = 0 ; y < MATRIX_SIZE ; ++y)
    {
      if (x * x + y * y < RADIUS * RADIUS) 
      {
        loopUpTable[numberOfOnBits].x = x;
        loopUpTable[numberOfOnBits].y = y;

        ++numberOfOnBits;
      } // if
    } // for
  } // for
} // ()

Point choose()
{
  int randomIndex = randomInt(numberOfBits);

  return loopUpTable[randomIndex];
} // ()
selalerer
источник
0

Я все еще не уверен насчет точного '(2 / R2) × r', но очевидно, что количество точек, которые необходимо распределить в данной единице 'dr', т.е. увеличение r будет пропорционально r2, а не r.

проверьте таким образом ... количество точек под некоторым углом тета и между r (от 0,1r до 0,2r), т. е. доля r и количество точек между r (от 0,6r до 0,7r) будут равны, если вы используете стандартную генерацию, так как разница составляет всего 0,1р между двумя интервалами. но поскольку область, покрытая между точками (от 0,6 до 0,7r), будет намного больше, чем область, покрытая от 0,1 до 0,2r, равное количество точек будет редко разнесено в большей области, это, я полагаю, вы уже знаете, поэтому функция генерация случайных точек должна быть не линейной, а квадратичной (поскольку число точек, которые необходимо распределить в заданной единице 'dr', т.е. увеличение r будет пропорционально r2, а не r), поэтому в этом случае оно будет обратным к квадратичный, так как дельта у нас (0.

cheesefest
источник
Вы первый, кто ссылается на теорему Пифагора здесь. Я хотел бы, чтобы вы расширили это цифрой или двумя, поддерживая ваше объяснение. Мне трудно следить за тем, как оно сейчас стоит :-(
aioobe
@aioobe Я попытался перефразировать ответ, я могу добавить диаграммы, если вам нужно :)
cheesefest
Я понимаю, почему я не могу распространить это линейно. Что я не понимаю здесь, так это связь с Пифагором или с грехом / соз. Может быть, диаграммы могли бы помочь мне здесь.
aioobe
Пифагор - моя ошибка, пожалуйста, забудьте об этом, но надеюсь, что вы поняли квадратичную природу функции, точное (2 / R2) × r нуждается в доказательстве, и я не могу придумать никакого доказательства для этого
чизфест
0

Такая веселая проблема.
Обоснование вероятности снижения выбранной точки при увеличении расстояния от начала координат объясняется многократно выше. Мы учтем это, взяв корень U [0,1]. Вот общее решение для положительного r в Python 3.

import numpy
import math
import matplotlib.pyplot as plt

def sq_point_in_circle(r):
    """
    Generate a random point in an r radius circle 
    centered around the start of the axis
    """

    t = 2*math.pi*numpy.random.uniform()
    R = (numpy.random.uniform(0,1) ** 0.5) * r

    return(R*math.cos(t), R*math.sin(t))

R = 200 # Radius
N = 1000 # Samples

points = numpy.array([sq_point_in_circle(R) for i in range(N)])
plt.scatter(points[:, 0], points[:,1])

введите описание изображения здесь

AChervony
источник
0

Вы также можете использовать свою интуицию.

Площадь круга pi*r^2

Для r=1

Это даст нам площадь pi. Давайте предположим, что у нас есть какая-то функция, fкоторая будет равномерно искажатьN=10 точки внутри круга. Соотношение здесь10 / pi

Теперь мы удваиваем площадь и количество очков

Для r=2 иN=20

Это дает площадь 4piи соотношение сейчас 20/4piили 10/2pi. Отношение будет становиться все меньше и меньше, чем больше радиус, потому что его рост является квадратичным иN масштабируется линейно.

Чтобы это исправить, мы можем просто сказать,

x = r^2
sqrt(x) = r

Если бы вы создали вектор в полярных координатах, как это

length = random_0_1();
angle = random_0_2pi();

Больше точек приземлится вокруг центра.

length = sqrt(random_0_1());
angle = random_0_2pi();

length больше не распределяется равномерно, но вектор теперь будет распределяться равномерно.

Майк Кляйн
источник
-1

1) Выберите случайный X между -1 и 1.

var X:Number = Math.random() * 2 - 1;

2) Используя формулу круга, рассчитайте максимальное и минимальное значения Y, учитывая, что X и радиус 1:

var YMin:Number = -Math.sqrt(1 - X * X);
var YMax:Number = Math.sqrt(1 - X * X);

3) Выберите случайный Y между этими крайностями:

var Y:Number = Math.random() * (YMax - YMin) + YMin;

4) Включите ваше местоположение и значения радиуса в окончательное значение:

var finalX:Number = X * radius + pos.x;
var finalY:Number = Y * radois + pos.y;
xytor
источник
2
Не равномерно - вероятность для [-1, 0] намного выше, чем для [0, 0], учитывая, что p ([- 1, Y]) = p ([0, Y]), и существует только один выбор для [-1, Y] и много вариантов для [0, Y].
Амадан
Это решение благоприятствует точкам к левой и правой сторонам круга. Точки с x, близким к нулю, представлены недостаточно. Не равномерное распределение вообще.
Дауд ибн Карим