Алгоритм. Вычислить псевдослучайную точку внутри эллипса.

Для простой системы частиц, которую я создаю, мне нужно, учитывая эллипс с шириной и высотой, вычислить случайную точку X, Y, которая лежит в этом эллипсе.

Теперь я не лучший в математике, поэтому я хотел спросить здесь, может ли кто-нибудь указать мне в правильном направлении.

Возможно, правильный способ - выбрать случайный float в диапазоне ширины, взять его для X и из него рассчитать значение Y?

Ответы

Ответ 1

  • Создайте случайную точку внутри круга радиуса 1. Это можно сделать, взяв случайный угол phi в интервале [0, 2*pi) и случайное значение rho в интервале [0, 1) и вычислить

    x = sqrt(rho) * cos(phi)
    y = sqrt(rho) * sin(phi)
    

    Квадратный корень в формуле обеспечивает равномерное распределение внутри круга.

  • Масштаб x и y к размерам эллипса

    x = x * width/2.0
    y = y * height/2.0
    

Ответ 2

Используйте выборку отбраковки: выберите случайную точку в прямоугольнике вокруг эллипса. Проверьте, находится ли точка внутри эллипса, проверив знак (x-x0) ^ 2/a ^ 2 + (y-y0) ^ 2/b ^ 2-1. Повторяйте, если точка не внутри. (Это предполагает, что эллипс выровнен с координатными осями. Аналогичное решение работает в общем случае, но, конечно, сложнее).

Ответ 3

Вы можете использовать преобразование координат с квадратом в декарте:

x = cos(angle) * radius
y = sin(angle) * radius

что небольшое изменение

x = cos(angle) * width
y = sin(angle) * height

Вы не указали какой-либо язык, но здесь приведена быстрая демонстрация с помощью Обработки:

float ellipseWidth = 150,ellipseHeight = 100;
float angle,radius,x,y;
void setup(){
  size(400,400);
  smooth();
  noStroke();
  ellipseMode(CENTER);
  background(0);
  fill(255);
}

void draw(){
  //choose a random angle on the ellipse
  angle = random(TWO_PI);
  //convert from polar to cartesian, using both width and height as radii
  x = cos(angle) * ellipseWidth;
  y = sin(angle) * random(ellipseHeight);//random 'lengths' vertically
  //draw
  translate(200,200);//move to centre
  ellipse(x,y,5,5);  
}

Вы можете увидеть, как он запускает здесь

points in ellipse

НТН

Ответ 4

Я бы предложил очень простой метод:

  • Выберите случайный X
  • Рассчитайте верхнюю и нижнюю границы Y для этого конкретного X
  • Рандомизировать Y в пределах расчетных границ

Формула Bounds (любезность Википедии):

Upper and lower bounds

Ответ 5

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

Полярный радиус эллипса

Интуитивно говоря, мы должны чаще выбирать полярный угол θ, где радиус больше. Математически, наш PDF для случайной величины θ должен быть p (θ) dθ = dA/A, где dA - площадь одного сегмента под углом θ с шириной dθ. Используя уравнение для области полярного угла dA = 1/2 r 2 dθ, а площадь эллипса равна π a b, тогда PDF становится

Theta PDF

Для случайного отбора из этого PDF-документа одним прямым методом является метод Обратный CDF

где u пробегает от 0 до 1. Итак, чтобы выбрать случайный угол θ, вы просто генерируете равномерное случайное число u между 0 и 1 и подставляете его в это уравнение для обратного CDF.

Чтобы получить случайный радиус, можно использовать тот же метод, который работает для круга (см., например, Создать случайную точку внутри круга (равномерно)).

Вот пример кода Python, который реализует этот алгоритм:

import numpy
import matplotlib.pyplot as plt
import random

# Returns theta in [-pi/2, 3pi/2]
def generate_theta(a, b):
    u = random.random() / 4.0
    theta = numpy.arctan(b/a * numpy.tan(2*numpy.pi*u))

    v = random.random()
    if v < 0.25:
        return theta
    elif v < 0.5:
        return numpy.pi - theta
    elif v < 0.75:
        return numpy.pi + theta
    else:
        return -theta

def radius(a, b, theta):
    return a * b / numpy.sqrt((b*numpy.cos(theta))**2 + (a*numpy.sin(theta))**2)

def random_point(a, b):
    random_theta = generate_theta(a, b)
    max_radius = radius(a, b, random_theta)
    random_radius = max_radius * numpy.sqrt(random.random())

    return numpy.array([
        random_radius * numpy.cos(random_theta),
        random_radius * numpy.sin(random_theta)
    ])

a = 2
b = 1

points = numpy.array([random_point(a, b) for _ in range(2000)])

plt.scatter(points[:,0], points[:,1])
plt.show()

Случайно сгенерированные точки в эллипсе с осями 2 и 1