Самый простой алгоритм диаграммы Вороного для реализации? [закрыто]
88
Каковы простые алгоритмы реализации диаграммы Вороного?
Я не мог найти ни одного алгоритма специально в псевдо форме. Пожалуйста, поделитесь некоторыми ссылками на алгоритм диаграммы Вороного, учебник и т. Д.
Простой алгоритм вычисления триангуляции Делоне набора точек - это переворот ребер . Поскольку триангуляция Делоне - это двойственный график диаграммы Вороного, вы можете построить диаграмму из триангуляции за линейное время.
К сожалению, время работы с переворачиванием в худшем случае - O (n ^ 2). Существуют лучшие алгоритмы, такие как строчная развертка Fortune, которые занимают время O (n log n). Однако реализовать это довольно сложно. Если вы ленивы (как и я), я бы посоветовал найти существующую реализацию триангуляции Делоне, использовать ее, а затем вычислить двойной граф.
Самый простой? Это метод грубой силы: для каждого пикселя в выходных данных перебирайте все точки, вычисляйте расстояние, используйте ближайший. Медленно, но очень просто. Если производительность не важна, она делает свою работу. Я сам работал над интересным усовершенствованием, но все еще ищу, есть ли у кого-нибудь такая же (довольно очевидная) идея.
Алгоритм Бойера-Ватсона довольно легко понять. Вот реализация: http://paulbourke.net/papers/triangulate/ . Это триангуляция Делоне для набора точек, но вы можете использовать ее для получения двойника Делоне, то есть диаграммы Вороного. Кстати. минимальное остовное дерево - это подмножество триангуляции Делоне.
Широко упоминаемые, недокументированные и почти все повторные реализации, которые я видел на основе этого кода, ошибочны (на разных языках многим нужен Вороной, немногие могут понять его достаточно хорошо, чтобы правильно портировать). Единственные работающие порты, которые я видел, принадлежат научному / академическому сообществу и имеют чрезвычайно сложные сигнатуры функций или сильно оптимизированы (так что их нельзя использовать для большинства целей), что делает их непригодными для использования обычными программистами.
Adam
VoronoiDiagramGenerator.cpp имеет ограниченную функциональность. Он выведет неупорядоченный набор ребер. Извлечь из этого фактические полигоны нетривиально. С другой стороны, у него есть клипса против ограничивающего прямоугольника, поэтому точки бесконечности не генерируются.
Брэм
8
Вот реализация javascript, которая использует дерево квадратов и допускает инкрементное построение.
В то время как исходный вопрос спрашивает о том, как реализовать Вороного, если бы я нашел сообщение, в котором говорилось следующее, когда я искал информацию по этой теме, это сэкономило бы мне много времени:
В Интернете есть много «почти правильного» кода C ++ для реализации диаграмм Вороного. Большинство из них редко приводят к сбоям, когда начальные точки становятся очень плотными. Я бы порекомендовал тщательно протестировать любой код, который вы найдете в Интернете, с тем количеством баллов, которое вы ожидаете использовать в своем готовом проекте, прежде чем тратить на это слишком много времени.
Лучшая из реализаций, которые я нашел в Интернете, была частью программы MapManager, ссылка на которую находится здесь:
http://www.skynet.ie/~sos/mapviewer/voronoi.php
В основном это работает, но я получаю периодические искажения диаграммы при работе с порядка 10 ^ 6 баллов. Я не мог точно понять, как расползается коррупция.
Вчера вечером я нашел это:
http://www.boost.org/doc/libs/1_53_0_beta1/libs/polygon/doc/voronoi_main.htm
"Библиотека Вороного Boost.Polygon". Выглядит очень многообещающе. Он поставляется с тестовыми тестами, подтверждающими его точность и отличную производительность. У библиотеки хороший интерфейс и документация. Я удивлен, что не нашел эту библиотеку раньше, поэтому я пишу об этом здесь. (Я прочитал этот пост в начале своего исследования.)
Самый простой алгоритм исходит из определения диаграммы Вороного: «Разбиение плоскости с n точками на выпуклые многоугольники так, что каждый многоугольник содержит ровно одну производящую точку, и каждая точка в данном многоугольнике ближе к своей производящей точке, чем к любой другой. ... "определение из вольфрама.
Важной частью здесь является то, что каждая точка находится ближе к генерирующей точке, чем любая другая, отсюда алгоритм очень прост:
Имейте массив генерирующих точек.
Просматривайте каждый пиксель на холсте.
Для каждого пикселя ищите ближайшую к нему генерирующую точку.
В зависимости от того, на какой диаграмме вы хотите получить цвет пикселя. Если вы хотите, чтобы диаграмма была разделена рамкой, проверьте наличие второй ближайшей точки, а затем проверьте их разницу и цвет с помощью цвета границы, если он меньше некоторого значения.
Если вам нужна цветовая диаграмма, укажите цвет, связанный с каждой точкой генерации, и раскрасьте каждый пиксель цветом, соответствующим ближайшей точке генерации. И это все, это неэффективно, но очень легко реализовать.
Это самый быстрый из возможных - это простой вороной, но выглядит он великолепно. Он делит пробелы на сетку, помещает точку в каждую ячейку сетки, размещенную случайным образом, и перемещается по сетке, проверяя ячейки 3x3, чтобы определить, как они соотносятся с соседними ячейками.
Это быстрее без градиента.
Вы спросите, какой будет самый простой 3д вороной. Было бы интересно узнать. Наверное 3x3x3 клетки и проверка градиента.
float voronoi( in vec2 x )
{
ivec2 p = floor( x );
vec2 f = fract( x );
float res = 8.0;
for( int j=-1; j<=1; j++ )
for( int i=-1; i<=1; i++ )
{
ivec2 b = ivec2( i, j );
vec2 r = vec2( b ) - f + random2f( p + b );
float d = dot( r, r );
res = min( res, d );
}
return sqrt( res );
}
и здесь то же самое с расстоянием Чебычева. вы можете использовать случайный 2f-шум с плавающей точкой отсюда:
Это было некоторое время назад, для тех, кто, я считаю, это круто:
function rndng ( n: float ): float
{//random number -1, 1
var e = ( n *321.9)%1;
return (e*e*111.0)%2-1;
}
function voronoi( vtx: Vector3 )
{
var px = Mathf.Floor( vtx.x );
var pz = Mathf.Floor( vtx.z );
var fx = Mathf.Abs(vtx.x%1);
var fz = Mathf.Abs(vtx.z%1);
var res = 8.0;
for( var j=-1; j<=1; j++ )
for( var i=-1; i<=1; i++ )
{
var rx = i - fx + nz2d(px+i ,pz + j ) ;
var rz = j - fz + nz2d(px+i ,pz + j ) ;
var d = Vector2.Dot(Vector2(rx,rz),Vector2(rx,rz));
res = Mathf.Min( res, d );
}
return Mathf.Sqrt( res );
}
Вам просто нужно создать список. Вектор можно создать, передав два числа (координаты) как float. Затем передайте список в Fortune.ComputeVoronoiGraph ()
Вы можете немного больше понять концепцию алгоритма на этих страницах википедии:
Хотя одной вещи я не мог понять, это как создать линию для частично бесконечных ребер (мало что знаю о координатной геометрии :-)). Если кто-то знает, дайте мне знать и об этом.
Хотя эти ссылки могут дать ответ на вопрос, лучше включить сюда основные части ответа и предоставить ссылку для справки. Ответы, содержащие только ссылки, могут стать недействительными, если ссылка на страницу изменится.
Kmeixner 03
0
Если вы пытаетесь нарисовать его на изображении, вы можете использовать алгоритм заполнения очереди на основе флуда.
Voronoi::draw(){
// define colors for each point in the diagram;
// make a structure to hold {pixelCoords,sourcePoint} queue objects
// initialize a struct of two closest points for each pixel on the map
// initialize an empty queue;
// for each point in diagram:
// for the push object, first set the pixelCoords to pixel coordinates of point;
// set the sourcePoint of the push object to the current point;
// push the queue object;
// while queue is not empty:
// dequeue a queue object;
// step through cardinal neighbors n,s,e,w:
// if the current dequeued source point is closer to the neighboring pixel than either of the two closest:
// set a boolean doSortAndPush to false;
// if only one close neighbor is set:
// add sourcePoint to closestNeighbors for pixel;
// set doSortAndPush to true;
// elif sourcePoint is closer to pixel than it's current close neighbor points:
// replace the furthest neighbor point with sourcePoint;
// set doSortAndPush to true;
// if flag doSortAndPush is true:
// re-sort closest neighbors;
// enqueue object made of neighbor pixel coordinates and sourcePoint;
// for each pixel location:
// if distance to closest point within a radius for point drawing:
// color pixel the point color;
// elif distances to the two closest neighbors are roughly equal:
// color the pixel to your border color;
// else
// color the pixel the color of the point's region;
}
Использование очереди гарантирует, что регионы распределяются параллельно, сводя к минимуму общее количество посещений пикселей. Если вы используете стек, первая точка заполнит все изображение, а вторая - все пиксели, расположенные ближе к ней, чем первая точка. Это будет продолжаться, значительно увеличивая количество посещений. При использовании очереди FIFO пиксели обрабатываются в том порядке, в котором они помещаются. Результирующие изображения будут примерно одинаковыми независимо от того, используете ли вы стек или очередь, но большой О для очереди гораздо ближе к линейному (по отношению к количеству пикселей изображения), чем большой О алгоритма стека. Общая идея состоит в том, что регионы будут распространяться с одинаковой скоростью, и столкновения, как правило, будут происходить точно в точках, которые соответствуют границам регионов.
Ответы:
Простой алгоритм вычисления триангуляции Делоне набора точек - это переворот ребер . Поскольку триангуляция Делоне - это двойственный график диаграммы Вороного, вы можете построить диаграмму из триангуляции за линейное время.
К сожалению, время работы с переворачиванием в худшем случае - O (n ^ 2). Существуют лучшие алгоритмы, такие как строчная развертка Fortune, которые занимают время O (n log n). Однако реализовать это довольно сложно. Если вы ленивы (как и я), я бы посоветовал найти существующую реализацию триангуляции Делоне, использовать ее, а затем вычислить двойной граф.
В общем, хорошая книга по этой теме - Computational Geometry by de Berg et al.
источник
Самый простой? Это метод грубой силы: для каждого пикселя в выходных данных перебирайте все точки, вычисляйте расстояние, используйте ближайший. Медленно, но очень просто. Если производительность не важна, она делает свою работу. Я сам работал над интересным усовершенствованием, но все еще ищу, есть ли у кого-нибудь такая же (довольно очевидная) идея.
источник
Алгоритм Бойера-Ватсона довольно легко понять. Вот реализация: http://paulbourke.net/papers/triangulate/ . Это триангуляция Делоне для набора точек, но вы можете использовать ее для получения двойника Делоне, то есть диаграммы Вороного. Кстати. минимальное остовное дерево - это подмножество триангуляции Делоне.
источник
Наиболее эффективным алгоритмом построения диаграммы Вороного является алгоритм Фортуны . Он выполняется за O (n log n).
Вот ссылка на его эталонной реализации в C .
Лично мне очень нравится реализация python Билла Саймонса и Карсона Фармера, так как я обнаружил, что ее легче расширять.
источник
На странице Википедии ( http://en.wikipedia.org/wiki/Voronoi_diagram ) есть раздел Алгоритмы со ссылками на алгоритмы для реализации диаграмм Вороного.
источник
Существует свободно доступная реализация voronoi для двумерных графиков на C и C ++ от Стефана Форчун / Шейна О'Салливана:
Вы найдете его во многих местах. Т.е. на http://www.skynet.ie/~sos/masters/
источник
Вот реализация javascript, которая использует дерево квадратов и допускает инкрементное построение.
http://code.google.com/p/javascript-voronoi/
источник
В то время как исходный вопрос спрашивает о том, как реализовать Вороного, если бы я нашел сообщение, в котором говорилось следующее, когда я искал информацию по этой теме, это сэкономило бы мне много времени:
В Интернете есть много «почти правильного» кода C ++ для реализации диаграмм Вороного. Большинство из них редко приводят к сбоям, когда начальные точки становятся очень плотными. Я бы порекомендовал тщательно протестировать любой код, который вы найдете в Интернете, с тем количеством баллов, которое вы ожидаете использовать в своем готовом проекте, прежде чем тратить на это слишком много времени.
Лучшая из реализаций, которые я нашел в Интернете, была частью программы MapManager, ссылка на которую находится здесь: http://www.skynet.ie/~sos/mapviewer/voronoi.php В основном это работает, но я получаю периодические искажения диаграммы при работе с порядка 10 ^ 6 баллов. Я не мог точно понять, как расползается коррупция.
Вчера вечером я нашел это: http://www.boost.org/doc/libs/1_53_0_beta1/libs/polygon/doc/voronoi_main.htm "Библиотека Вороного Boost.Polygon". Выглядит очень многообещающе. Он поставляется с тестовыми тестами, подтверждающими его точность и отличную производительность. У библиотеки хороший интерфейс и документация. Я удивлен, что не нашел эту библиотеку раньше, поэтому я пишу об этом здесь. (Я прочитал этот пост в начале своего исследования.)
источник
На самом деле есть реализации для 25 разных языков, доступные на https://rosettacode.org/wiki/Voronoi_diagram.
Например, для Java:
источник
Самый простой алгоритм исходит из определения диаграммы Вороного: «Разбиение плоскости с n точками на выпуклые многоугольники так, что каждый многоугольник содержит ровно одну производящую точку, и каждая точка в данном многоугольнике ближе к своей производящей точке, чем к любой другой. ... "определение из вольфрама.
Важной частью здесь является то, что каждая точка находится ближе к генерирующей точке, чем любая другая, отсюда алгоритм очень прост:
Если вам нужна цветовая диаграмма, укажите цвет, связанный с каждой точкой генерации, и раскрасьте каждый пиксель цветом, соответствующим ближайшей точке генерации. И это все, это неэффективно, но очень легко реализовать.
источник
Это самый быстрый из возможных - это простой вороной, но выглядит он великолепно. Он делит пробелы на сетку, помещает точку в каждую ячейку сетки, размещенную случайным образом, и перемещается по сетке, проверяя ячейки 3x3, чтобы определить, как они соотносятся с соседними ячейками.
Это быстрее без градиента.
Вы спросите, какой будет самый простой 3д вороной. Было бы интересно узнать. Наверное 3x3x3 клетки и проверка градиента.
http://www.iquilezles.org/www/articles/smoothvoronoi/smoothvoronoi.htm
и здесь то же самое с расстоянием Чебычева. вы можете использовать случайный 2f-шум с плавающей точкой отсюда:
https://www.shadertoy.com/view/Msl3DM
изменить: я преобразовал это в код типа C
Это было некоторое время назад, для тех, кто, я считаю, это круто:
источник
ivec2
? илиvec2
? Это нечитаемо.Проверьте решение методом перебора, представленное с помощью псевдокода Ричардом Фрэнксом в его ответе на вопрос « Как мне вывести диаграмму Вороного с учетом ее набора точек и ее триангуляции Делоне?»
источник
Нашел эту отличную библиотеку C # в коде Google, основанном на алгоритме Fortune / алгоритме Sweep line.
https://code.google.com/p/fortune-voronoi/
Вам просто нужно создать список. Вектор можно создать, передав два числа (координаты) как float. Затем передайте список в Fortune.ComputeVoronoiGraph ()
Вы можете немного больше понять концепцию алгоритма на этих страницах википедии:
http://en.wikipedia.org/wiki/Fortune%27s_algorithm
http://en.wikipedia.org/wiki/Sweep_line_algorithm
Хотя одной вещи я не мог понять, это как создать линию для частично бесконечных ребер (мало что знаю о координатной геометрии :-)). Если кто-то знает, дайте мне знать и об этом.
источник
Если вы пытаетесь нарисовать его на изображении, вы можете использовать алгоритм заполнения очереди на основе флуда.
Использование очереди гарантирует, что регионы распределяются параллельно, сводя к минимуму общее количество посещений пикселей. Если вы используете стек, первая точка заполнит все изображение, а вторая - все пиксели, расположенные ближе к ней, чем первая точка. Это будет продолжаться, значительно увеличивая количество посещений. При использовании очереди FIFO пиксели обрабатываются в том порядке, в котором они помещаются. Результирующие изображения будут примерно одинаковыми независимо от того, используете ли вы стек или очередь, но большой О для очереди гораздо ближе к линейному (по отношению к количеству пикселей изображения), чем большой О алгоритма стека. Общая идея состоит в том, что регионы будут распространяться с одинаковой скоростью, и столкновения, как правило, будут происходить точно в точках, которые соответствуют границам регионов.
источник