Мне нужен алгоритм, который может дать мне позиции вокруг сферы для N точек (менее 20, вероятно), который расплывчат их. Нет необходимости в «совершенстве», но мне это просто нужно, чтобы ни одно из них не было сгруппировано вместе.
- В этом вопросе был хороший код, но я не смог найти способ сделать эту униформу, так как она казалась на 100% случайной.
- В этом сообщении в блоге было рекомендовано два способа ввода количества точек на сфере, но алгоритм Саффа и Куйлаарса находится именно в псевдокоде, который я мог расшифровать, а найденный мной пример кода содержал «узел [k]», который я не мог смотри объяснил и разрушил эту возможность. Второй пример блога - спираль золотого сечения, которая дала мне странные, сгруппированные результаты, без четкого способа определения постоянного радиуса.
- Этот алгоритм из этого вопроса кажется, что он может работать, но я не могу объединить то, что на этой странице, в псевдокод или что-то еще.
Несколько других вопросов, с которыми я столкнулся, говорили о рандомизированном равномерном распределении, что добавляет уровень сложности, который меня не беспокоит. Прошу прощения, что это такой глупый вопрос, но я хотел показать, что действительно внимательно посмотрел и все же не смог.
Итак, я ищу простой псевдокод для равномерного распределения N точек вокруг единичной сферы, который либо возвращается в сферических, либо в декартовых координатах. Еще лучше, если он может даже распределяться с небольшим количеством случайностей (подумайте о планетах вокруг звезды, прилично разбросанных, но с местом для свободы действий).
Ответы:
В этом примере код
node[k]
- это только k-й узел. Вы создаете массив из N точек иnode[k]
является k-м (от 0 до N-1). Если это все, что вас смущает, надеюсь, вы сможете использовать это сейчас.(другими словами,
k
это массив размера N, который определяется до начала фрагмента кода и который содержит список точек).В качестве альтернативы , опираясь на другой ответ здесь (и используя Python):
Если вы построите это график, вы увидите, что расстояние по вертикали больше около полюсов, так что каждая точка расположена примерно на одной и той же общей площади пространства (около полюсов меньше места «по горизонтали», поэтому он дает больше «по вертикали» ).
Это не то же самое, что все точки имеют примерно одинаковое расстояние до своих соседей (это то, о чем, я думаю, говорят ваши ссылки), но этого может быть достаточно для того, что вы хотите, и улучшается простое создание единой сетки широты и долготы. ,
источник
Для этого отлично подходит алгоритм сферы Фибоначчи. Это быстро и дает результаты, которые легко обмануть человеческий глаз. Вы можете увидеть пример, выполненный с обработкой, которая покажет результат с течением времени по мере добавления точек. Вот еще один отличный интерактивный пример, сделанный @gman. А вот простая реализация на Python.
1000 образцов дает вам это:
источник
Метод золотой спирали
Вы сказали, что не можете заставить работать метод золотой спирали, и это позор, потому что он действительно хорош. Я хотел бы дать вам полное представление об этом, чтобы, возможно, вы могли понять, как уберечь это от «скучивания».
Итак, вот быстрый и неслучайный способ создать приблизительно правильную решетку; как обсуждалось выше, ни одна решетка не будет идеальной, но этого может быть достаточно. Его сравнивают с другими методами, например, на BendWavy.org, но у него просто красивый и красивый вид, а также гарантия равного интервала в пределах.
Праймер: спирали подсолнечника на агрегатном диске
Чтобы понять этот алгоритм, я сначала предлагаю вам взглянуть на алгоритм 2D спирали подсолнечника. Это основано на том факте, что наиболее иррациональным числом является золотое сечение,
(1 + sqrt(5))/2
и если кто-то излучает точки по принципу «встаньте в центре, поверните золотое сечение целых витков, а затем испустите еще одну точку в этом направлении», то естественно построить спираль, которая по мере того, как вы набираете все большее и большее количество точек, тем не менее отказывается иметь четко определенные «полосы», по которым выстраиваются точки. (Примечание 1.)Алгоритм равномерного размещения на диске:
и он дает результаты, которые выглядят (n = 100 и n = 1000):
Радиальное расположение точек
Ключевая странность - это формула
r = sqrt(indices / num_pts)
; как я пришел к этому? (Заметка 2.)Что ж, я использую здесь квадратный корень, потому что я хочу, чтобы они имели равномерный интервал вокруг диска. Это то же самое, что сказать, что в пределе большого N я хочу, чтобы небольшая область R ∈ ( r , r + d r ), Θ ∈ ( θ , θ + d θ ) содержала количество точек, пропорциональное ее площади, что есть r d r d θ . Теперь, если мы сделаем вид, что мы говорим здесь о случайной величине, это имеет прямую интерпретацию как утверждение, что совместная плотность вероятности для ( R , Θ ) равна crдля некоторой постоянной c . Нормализация на единичном круге тогда вынудила бы c = 1 / π.
Теперь позвольте мне представить трюк. Он исходит из теории вероятностей, где он известен как выборка обратного CDF : предположим, вы хотите сгенерировать случайную величину с плотностью вероятности f ( z ), и у вас есть случайная величина U ~ Uniform (0, 1), точно так же, как получается из
random()
на большинстве языков программирования. Как ты делаешь это?Теперь уловка со спиралью золотого сечения распределяет точки по хорошо равномерному шаблону для θ, так что давайте интегрировать это; для единичного круга остается F ( r ) = r 2 . Таким образом, обратная функция F -1 ( u ) = u 1/2 , и поэтому мы будем генерировать случайные точки на диске в полярных координатах с
r = sqrt(random()); theta = 2 * pi * random()
.Теперь вместо случайной выборки этой обратной функции мы ее выбираем равномерно , и хорошая вещь в равномерной выборке заключается в том, что наши результаты о том, как точки распределены в пределах большого N, будут вести себя так, как если бы мы выбрали ее случайным образом. Эта комбинация и есть уловка. Вместо того,
random()
чтобы использовать(arange(0, num_pts, dtype=float) + 0.5)/num_pts
, так что, скажем, если мы хотим выбрать 10 точек, они естьr = 0.05, 0.15, 0.25, ... 0.95
. Мы единообразно выбираем r, чтобы получить равные интервалы площадей, и используем приращение подсолнечника, чтобы избежать ужасных «полос» точек на выходе.Теперь делаем подсолнух на сфере
Изменения, которые нам нужно внести, чтобы расставить точки на сфере, просто включают в себя отключение полярных координат для сферических координат. Радиальная координата, конечно, сюда не входит, потому что мы находимся на единичной сфере. Для большей согласованности здесь, хотя я был физиком по образованию, я буду использовать координаты математиков, где 0 ≤ φ ≤ π - это широта, идущая от полюса, а 0 ≤ θ ≤ 2π - долгота. Таким образом, отличие от приведенного выше в том, что мы в основном заменяем переменную r на φ .
Наш элемент площади, который был r d r d θ , теперь становится не намного более сложным sin ( φ ) d φ d θ . Таким образом, наша плотность стыков для равномерного расстояния равна sin ( φ ) / 4π. Интегрируя θ , находим f ( φ ) = sin ( φ ) / 2, поэтому F ( φ ) = (1 - cos ( φ )) / 2. Обращая это, мы видим, что однородная случайная величина будет выглядеть как acos (1 - 2 u ), но мы делаем выборку равномерно, а не случайным образом, поэтому вместо этого мы используем φ k = acos (1 - 2 ( k+ 0,5) / N ). А остальная часть алгоритма просто проецирует это на координаты x, y и z:
Снова для n = 100 и n = 1000 результаты выглядят так:
Дальнейшие исследования
Я хотел отдать должное блогу Мартина Робертса. Обратите внимание, что выше я создал смещение своих индексов, добавив 0,5 к каждому индексу. Это было просто визуально привлекательно для меня, но оказалось, что выбор смещения имеет большое значение и не является постоянным в течение интервала и может означать повышение точности упаковки на 8% при правильном выборе. Также должен быть способ заставить его последовательность R 2 покрывать сферу, и было бы интересно посмотреть, дает ли это также хорошее равномерное покрытие, возможно, как есть, но, возможно, нужно, чтобы быть, например, взято только из половины единичный квадрат разрезают по диагонали или около того и растягиваются, чтобы получить круг.
Ноты
Эти «полосы» образованы рациональными приближениями к числу, а наилучшие рациональные приближения к числу получаются из его выражения непрерывной дроби,
z + 1/(n_1 + 1/(n_2 + 1/(n_3 + ...)))
гдеz
- целое число иn_1, n_2, n_3, ...
представляет собой конечную или бесконечную последовательность положительных целых чисел:Поскольку дробная часть
1/(...)
всегда находится между нулем и единицей, большое целое число в непрерывной дроби позволяет получить особенно хорошее рациональное приближение: «один, разделенный на что-то от 100 до 101» лучше, чем «один, разделенный на что-то между 1 и 2». Поэтому наиболее иррациональным числом является то, которое1 + 1/(1 + 1/(1 + ...))
не имеет особенно хороших рациональных приближений; можно решить φ = 1 + 1 / φ , умножив на φ, чтобы получить формулу золотого сечения.Для людей, которые не так хорошо знакомы с NumPy - все функции «векторизованы», так что
sqrt(array)
это то же самое, что и другие языкиmap(sqrt, array)
. Итак, это приложение для каждого компонентаsqrt
. То же самое справедливо и для деления на скаляр или сложения со скалярами - они применяются ко всем компонентам параллельно.Доказательство становится простым, если вы знаете, что это результат. Если вы спросите, какова вероятность того, что z < Z < z + d z , это то же самое, что спросить, какова вероятность того, что z < F -1 ( U ) < z + d z , примените F ко всем трем выражениям, отметив, что это монотонно возрастающая функция, следовательно, F ( z ) < U < F ( z + d z ), разверните правую часть, чтобы найти F ( z ) + f( z ) d z , и поскольку U равномерно, эта вероятность равна f ( z ) d z, как и было обещано.
источник
Это известно как точки упаковки на сфере, и не существует (известного) общего идеального решения. Однако есть множество несовершенных решений. Три самых популярных:
n
их) внутри куба, окружающего сферу, а затем отклоняете точки вне сферы. Считайте оставшиеся точки векторами и нормализуйте их. Это ваши «образцы» - выбирайтеn
их каким-либо методом (случайным, жадным и т. Д.).Намного больше информации об этой проблеме можно найти здесь
источник
То, что вы ищете, называется сферическим покрытием . Задача о сферическом покрытии очень сложна, и решения неизвестны, за исключением небольшого числа точек. Одно известно наверняка: для данных n точек на сфере всегда существуют две точки на расстоянии
d = (4-csc^2(\pi n/6(n-2)))^(1/2)
или ближе.Если вам нужен вероятностный метод для создания точек, равномерно распределенных на сфере, это просто: генерировать точки в пространстве равномерно по распределению Гаусса (он встроен в Java, нетрудно найти код для других языков). Итак, в трехмерном пространстве вам нужно что-то вроде
Затем спроецируйте точку на сферу, нормализуя ее расстояние от начала координат.
Распределение Гаусса в n измерениях сферически симметрично, поэтому проекция на сферу однородна.
Конечно, нет гарантии, что расстояние между любыми двумя точками в коллекции равномерно сгенерированных точек будет ограничено ниже, поэтому вы можете использовать отклонение, чтобы обеспечить выполнение любых таких условий, которые могут у вас возникнуть: вероятно, лучше всего сгенерировать всю коллекцию, а затем при необходимости отклонить всю коллекцию. (Или используйте «раннее отклонение», чтобы отклонить всю коллекцию, которую вы создали до сих пор; просто не оставляйте одни баллы и не отбрасывайте другие.) Вы можете использовать
d
приведенную выше формулу за вычетом некоторого запаса хода, чтобы определить минимальное расстояние между баллов, ниже которых вы отклоните набор баллов. Вам нужно будет вычислить n выбрать 2 расстояния, и вероятность отказа будет зависеть от слабины; Трудно сказать, как это сделать, поэтому запустите моделирование, чтобы получить представление о соответствующей статистике.источник
Этот ответ основан на той же «теории», которая хорошо изложена в этом ответе.
Я добавляю этот ответ в следующем виде:
- Ни один из других вариантов не подходит для «единообразия», требующего «точного определения» (или не совсем очевидного). (Отмечая, что поведение планеты, похожее на распределение, особенно желательно в исходном запросе, вы просто отклоняете из конечного списка k равномерно созданных точек случайным образом (случайным образом относительно числа индексов в k элементах назад).)
- Ближайшие другой impl вынудил вас выбрать `` N '' по `` угловой оси '', а не просто `` одно значение N '' по обоим значениям угловой оси (что при малых счетах N очень сложно определить, что может иметь или не иметь значения ( например хочешь 5 баллов - развлекайся))
- Кроме того, очень сложно понять, как отличить другие варианты без каких-либо изображений, поэтому вот как выглядит этот вариант (ниже) и готовая к запуску реализация, которая идет с ним.
с N на 20:
а затем N на 80:
вот готовый к запуску код python3, где эмуляция является тем же источником: " http://web.archive.org/web/20120421191837/http://www.cgafaq.info/wiki/Evenly_distributed_points_on_sphere ", найденный другими , (График, который я включил, который срабатывает при запуске как 'main', взят из: http://www.scipy.org/Cookbook/Matplotlib/mplot3D )
протестировано при небольшом количестве (N в 2, 5, 7, 13 и т. д.) и, похоже, работает «хорошо»
источник
Пытаться:
Вышеупомянутая функция должна выполняться в цикле с общим количеством циклов N и текущей итерацией цикла.
Он основан на узоре семян подсолнечника, за исключением того, что семена подсолнечника изогнуты в виде полукупола, а затем снова в сферу.
Вот изображение, за исключением того, что я поместил камеру на полпути внутрь сферы, чтобы она выглядела 2d, а не 3d, потому что камера находится на одинаковом расстоянии от всех точек. http://3.bp.blogspot.com/-9lbPHLccQHA/USXf88_bvVI/AAAAAAAAADY/j7qhQsSZsA8/s640/sphere.jpg
источник
Healpix решает тесно связанную проблему (пикселирование сферы пикселями равной площади):
http://healpix.sourceforge.net/
Это, вероятно, излишне, но, возможно, посмотрев на него, вы поймете, что некоторые из других его хороших свойств вам интересны. Это больше, чем просто функция, выводящая облако точек.
Я приземлился здесь, пытаясь найти его снова; название "healpix" не совсем похоже на сферы ...
источник
с небольшим количеством точек вы можете запустить симуляцию:
источник
Возьмите два самых больших ваших фактора
N
, еслиN==20
тогда два самых больших фактора{5,4}
, или, в более общем плане{a,b}
. РассчитатьСтавьте первую точку в точку
{90-dlat/2,(dlong/2)-180}
, вторую в точку ,{90-dlat/2,(3*dlong/2)-180}
третью точку в точке{90-dlat/2,(5*dlong/2)-180}
, пока вы не совершите кругосветное путешествие один раз, и к этому моменту вы должны примерно{75,150}
добраться до точки{90-3*dlat/2,(dlong/2)-180}
.Очевидно, я работаю над этим в градусах на поверхности сферической Земли, используя обычные условные обозначения для перевода +/- в С / Ю или В / З. И, очевидно, это дает вам совершенно неслучайное распределение, но оно равномерное и точки не сгруппированы вместе.
Чтобы добавить некоторую степень случайности, вы можете сгенерировать 2 нормально распределенных (со средним значением 0 и стандартным отклонением {dlat / 3, dlong / 3}, если необходимо) и добавить их к равномерно распределенным точкам.
источник
edit: Это не отвечает на вопрос, который OP намеревался задать, оставляя его здесь на тот случай, если люди сочтут это каким-то образом полезным.
Мы используем правило умножения вероятностей в сочетании с бесконечно малыми. В результате получается 2 строки кода для достижения желаемого результата:
(определено в следующей системе координат :)
Ваш язык обычно имеет единый примитив случайных чисел. Например, в python вы можете использовать
random.random()
для возврата числа в диапазоне[0,1)
. Вы можете умножить это число на k, чтобы получить случайное число в диапазоне[0,k)
. Таким образом, в Pythonuniform([0,2pi))
будет означатьrandom.random()*2*math.pi
.доказательство
Теперь мы не можем назначить θ равномерно, иначе мы получим слипание на полюсах. Мы хотим назначить вероятности, пропорциональные площади поверхности сферического клина (θ на этой диаграмме на самом деле φ):
Угловое смещение dφ на экваторе приведет к смещению dφ * r. Каким будет это смещение при произвольном азимуте θ? Ну, радиус от оси z равен
r*sin(θ)
, поэтому длина дуги этой «широты», пересекающей клин, равнаdφ * r*sin(θ)
. Таким образом, мы рассчитываем кумулятивное распределение площади для выборки из нее, интегрируя площадь среза от южного полюса до северного полюса.(где прочее =
dφ*r
)Теперь мы попытаемся получить из него инверсию CDF: http://en.wikipedia.org/wiki/Inverse_transform_sampling
Сначала мы нормализуем, разделив наш почти CDF на максимальное значение. Это имеет побочный эффект отмены dφ и r.
Таким образом:
источник
ИЛИ ... чтобы разместить 20 точек, вычислите центры граней икосаэдра. По 12 точкам найдите вершины икосаэдра. Для 30 точек середина ребер икосаэдра. вы можете сделать то же самое с тетраэдром, кубом, додекаэдром и октаэдром: один набор точек находится на вершинах, другой - в центре грани, а третий - в центре ребер. Однако их нельзя смешивать.
источник
источник
@robert king Это действительно хорошее решение, но в нем есть несколько неряшливых ошибок. Я знаю, что это мне очень помогло, так что не говоря уже о небрежности. :) Вот и исправленная версия ....
источник
Это работает, и это очень просто. Сколько хотите очков:
источник