C++ Builder
| Главная | Уроки | Статьи | FAQ | Форум | Downloads | Литература | Ссылки | RXLib | Диски |

 
Алгоритм нахождения случайной точки
** westpine
  Отправлено: 31.07.2004, 01:12


Не зарегистрирован







Всем доброго времени суток... вопрос такой. Нужен эффективный алгоритм нахождения случайной точки на поверхности сферы. Именно на поверхности а не внутри. Всем заранее спасиба
timson
Отправлено: 31.07.2004, 09:37


Станционный диспетчер

Группа: Участник
Сообщений: 82



QUOTE
Нужен эффективный алгоритм нахождения случайной точки на поверхности сферы

вопрос не вполне ясен, постав коректнее..

надо чтоли просто найти точку на поверхности сферы случайным образом?? да??

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

- по каким плоскостям случайно (xy, xz, yz) — тогда в уравнении случайные параметры x, y, z;
- по какой плоскости первой, или тоже случайно — далее все выражается через уравнение сферы;
- и т.д. (даже какой алгоритм генератора случайных чисел использовать)..

надо бы уточнить...
Георгий
Отправлено: 31.07.2004, 11:42


Почетный железнодорожник

Группа: Модератор
Сообщений: 874



сфера это нечто x^2 + y^2 + z^2 = R^2 ?

тогда точку на её поверхности можно определить по углам 2х направляющих:
a [0,2PI)
b [0,2PI)
в этом случае равновероятны будут все точки сферы

в сечении плоскостью || оси z будет такое уравнение
х^2 + y^2 = R^2

пусть 'a' это случайное число равномерно распреденное в диапазоне [0, 2PI)
тогда (x,y) будут такими
x` = R*sin( a );
y` = R*cos( a );

теперь проводим прямую, проходящей через точки (0,0) && (x`,y`)

вычисляем координату проекции будущей случайной точки на эту прямую
пусть 'b' это случайное число равномерно распреденное в диапазоне [0, 2PI)
тогда координата этой бедной случайной точки на найденной прямой будет иметь координату
d = R * cos( b );

находим (x,y) на плоскости || оси z
x = d * cos( a );
y = d * sin( a );

и теперь из уравнения сферы получаем и заветный z:
z = sqrt( R^2 — d^2 );

итого:
x,y — случайны и зависят от угла 'a'
z  — случаен и зависит от угла 'b'
несмотря на неестественный вид уравнений (какие то они угловатые) ни одна из точек поверхности сферы не обделена вниманием — все они будут выбраны с одинаковой вероятностью

а вот и код, реализующий этот алгоритм
CODE
const int shift = 10000;

const double R = 666.666;

const double a = double(random( 2*M_PI * shift )) / double( shift );
const double b = double(random( 2*M_PI * shift )) / double( shift );

const double d = R * cos( b );
const double x = d * cos( a );
const double y = d * sin( a );

const double z = sqrt( R*R — d*d );


PS. правда вспоминается Кнут и то, что произведение 2х псевдослучайных величин не совсем случайная величина, поэтому с осторожностью пользуйтесь этим кодом.
exp
Отправлено: 31.07.2004, 23:11


Мастер участка

Группа: Участник
Сообщений: 304



Упрощение, хотя и небольшое.
Формулы преобразования координат из сферических в декартовы помните?
CODE

x= R*cos(gamma)*cos(A)
y= R*cos(gamma)*sin(A)
z= R*sin(gamma)

Если теперь Подкорректировать Георгия, то будет так
CODE

const int shift = 10000;

const double R = 666.666;

const double A = 2*M_PI * double(random(shift )) / double( shift );
const double gamma = 2*M_PI * double(random(shift )) / double( shift );

const double x = R * cos(gamma ) * cos( A );
const double y = R * cos(gamma ) * sin( A );
const double z = R * sin(gamma );

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


Paint — и пусть весь мир подождет....

Отредактировано exp — 01/08/2004, 00:14

Присоединить изображение

Присоединить изображение

Георгий
Отправлено: 01.08.2004, 10:18


Почетный железнодорожник

Группа: Модератор
Сообщений: 874



QUOTE
Кстати, таким образом мы избегаем перемножения псевдослучайных величин. (У Кнута там ничего не написанно про перемножение тригонометрических функций этих величин, надеюсь?)
всё равно плохо. Что сами величины, что функции от них. некоторые разряды, в худшем случае, могут вообще не изменяться или изменеяться, но по некоторому закону.
дискретность значение целочисленного генератора ПСП удалось замаскировать масштабным коэффициентом shift — если угол требуется с точностью до градуса, то 10 000 хватает, а вот от перемножения уйти, при подобном методе решения, похоже не удастся.
Нужна идея! smile.gif

Кстати — спасибо за избавление от угловатости и хороший рисунок.

PS. приступаем к элипсоиду?
exp
Отправлено: 02.08.2004, 00:50


Мастер участка

Группа: Участник
Сообщений: 304



Давайте и с эллипсоидом разберемся.
Только поздно уже. Денек посмотрю. Вечером напишу.
exp
Отправлено: 03.08.2004, 01:11


Мастер участка

Группа: Участник
Сообщений: 304



Тааак. Чем эллипс оличается от сферы? Тем, что у него радиус изменяется.
Значит формулы для пересчета координат примут вид:
CODE

x= R(A,gamma) * cos(gamma)*cos(A)
y= R(A,gamma) * cos(gamma)*sin(A)
z= R(A,gamma) * sin(gamma)


!!!! Существенное замечание !!!!
Угол gamma условимся брать в плоскости zOy, т. к. для разных точек эллипса, лежащих в сечении этого эллипса плоскостью, параллельной xOy, этот угол будет разным.

Здесь R — уже не постоянная величина а функция двух углов A и gamma.
Найдя вид этой функции, сможем решить задачу.

Итак, после 1.5 часов гемора и проверок была получена эта формула.
Где a,b,c — полуоси эллипсоида.
Тперь надо добавить в код еще строчку для вычисления R по этой ф-ле. и усе.

Maple 4ever!!!!

Отредактировано exp — 03/08/2004, 02:16

Присоединить изображение

Присоединить изображение

Георгий
Отправлено: 03.08.2004, 07:08


Почетный железнодорожник

Группа: Модератор
Сообщений: 874



спешу тебя обрадовать — точка перестала быть равномерно распределённой по поверхности smile.gif
вероятность выше на полюсах
exp
Отправлено: 06.08.2004, 11:56


Мастер участка

Группа: Участник
Сообщений: 304



Тоже спешу обрадовать. Я нашел ошибку в формуле. Поэтому пришлось поменять систему координат. Теперь она вот такая. Я поменял угол gamma. Теперь это угол между осью Oz и радиус-вектором.

Отредактировано exp — 06/08/2004, 13:06

Присоединить изображение

Присоединить изображение

exp
Отправлено: 06.08.2004, 12:05


Мастер участка

Группа: Участник
Сообщений: 304



Формула для длины радиус вектора такая:

Присоединить изображение

Присоединить изображение

exp
Отправлено: 06.08.2004, 12:07


Мастер участка

Группа: Участник
Сообщений: 304



Формулы преобразования тоже изменятся:
CODE

x= R(A,gamma) * sin(gamma)*cos(A)
y= R(A,gamma) * sin(gamma)*sin(A)
z= R(A,gamma) * cos(gamma)

Теперь все. Георгий, по идее точки теперь должны быть равномерно распределены.
Георгий
Отправлено: 06.08.2004, 19:17


Почетный железнодорожник

Группа: Модератор
Сообщений: 874



меня вот что смущает:

user posted image

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

ЗЫ. эти рассуждения основаны только на эмпирических выводах — если ошибаюсь, то буду рад если поправите.
exp
Отправлено: 28.08.2004, 23:47


Мастер участка

Группа: Участник
Сообщений: 304



Здравствуйте. После перерыва я снова в строю.
Георгий, картинки нет. Не могли бы вы еще раз ее прикрепить. А то мысль не вполне ясна.

ЗЫ: что-то наш заказчик не объявляется...

Отредактировано exp — 29/08/2004, 00:52
Георгий
Отправлено: 29.08.2004, 01:55


Почетный железнодорожник

Группа: Модератор
Сообщений: 874



да он уже давно в ауте biggrin.gif емуто всего то надо было, а тут такое развернулось smile.gif

а вот так видно?

user posted image

Отредактировано Георгий — 29/08/2004, 03:01
Георгий
Отправлено: 29.08.2004, 02:01


Почетный железнодорожник

Группа: Модератор
Сообщений: 874



а так?

Присоединить изображение

Присоединить изображение

klen
Отправлено: 29.08.2004, 10:21


Машинист паровоза

Группа: Участник
Сообщений: 239



Здорово мужики,ж попробую решить проблему с псевдослучайными числами, и вставлю свой пяточек.
1. Встроеный конгруентный генератор — на свалку истории.
2. Будем пользоватся генератром Фиббоначи, выдающим действительные числа double на интервале [0,1), он характеризуется лагами 97 и 33, дает период последовательной корреляции 10^19 шагов (встроенный иеет 4.9*10^9, почувствуте разницу)


CODE

double fibonachi_rand_values[97];
UINT fibonachi_rand_value_cur_pointer = 0;

// инициализация генератора Фибоначчи
void __fastcall initfrnd ()
{
srand( GetTickCount() );
// генерация начальных значений массива
for ( int element = 0; element < 97; element ++ )
{
fibonachi_rand_values[element] = (double)rand()/ RAND_MAX;
}
}

double __fastcall frnd()
{

fibonachi_rand_value_cur_pointer = (fibonachi_rand_value_cur_pointer + 1 )% 97;

fibonachi_rand_values[ fibonachi_rand_value_cur_pointer ] =
fibonachi_rand_values[ (fibonachi_rand_value_cur_pointer — 97) % 97 ] -
fibonachi_rand_values[ (fibonachi_rand_value_cur_pointer — 33) % 97 ];
if ( fibonachi_rand_values[ fibonachi_rand_value_cur_pointer ] < 0 )
fibonachi_rand_values[ fibonachi_rand_value_cur_pointer ] = 1 + fibonachi_rand_values[ fibonachi_rand_value_cur_pointer ];

return fibonachi_rand_values[ fibonachi_rand_value_cur_pointer ];
}


единственное ограничение это GetTickCount() которая работает толко под Win, но для получения случайного начального значения для запуска генератора можно воспользоватся счетчиком тактов процессора:


CODE

DWORD HightCount; // использовать для инициализации
DWORD LowCount ; .. или это число, или их комбинацию
__asm
{
rdtsc
mov HightCount , edx
mov LowCount , eax
}


ЗЫ. Пора на AMD64 пересаживатся, а то с 32 разраядым double' ом слишком часто сингулярные матрицы "всплывают" smile.gif

Отредактировано klen — 29/08/2004, 11:27
exp
Отправлено: 29.08.2004, 13:57


Мастер участка

Группа: Участник
Сообщений: 304



Да. Верно, Георгий, из двух дуг равной длины вероятность попадания в дугу с большей кривизной меньше, т. к. меньше угол, на который она опирается.
Вы, вероятно, хотите сделать, чтоб на единицу длины дуги эллипса приходилось одинаковое число точек? Тогда нужно не равномерное распределение для угла, а некоторое другое. Какое, пока не знаю.
Георгий
Отправлено: 29.08.2004, 20:16


Почетный железнодорожник

Группа: Модератор
Сообщений: 874



может стоит попробовать случайное число из интервала [0,1) масштабировать по длине окружности (эллипса) ? а потом перевести в угол, а угол в координаты?

правда в 3х мерном случае, кажется, опять какие то неравномерности получатся..
exp
Отправлено: 30.08.2004, 23:39


Мастер участка

Группа: Участник
Сообщений: 304



QUOTE

может стоит попробовать случайное число из интервала [0,1) масштабировать по длине окружности (эллипса) ? а потом перевести в угол, а угол в координаты?


С окружностью проблем нет при таком подходе, но с элипсом...
ОЧЧЧЕНЬ большие проблемы с первым переводом.

Вернуться в Вопросы программирования в C++Builder