Um algoritmo fácil para calcular a triangulação Delaunay de um conjunto de pontos é inverter as arestas . Como uma triangulação de Delaunay é o gráfico dual de um diagrama de Voronoi, você pode construir o diagrama a partir da triangulação em tempo linear.
Infelizmente, o pior caso de tempo de execução da abordagem de inversão é O (n ^ 2). Existem algoritmos melhores, como a varredura de linha da Fortune, que levam um tempo O (n log n). No entanto, isso é um tanto complicado de implementar. Se você é preguiçoso (como eu), sugiro que você procure uma implementação existente de uma triangulação de Delaunay, use-a e calcule o gráfico dual.
Mais fácil? Essa é a abordagem da força bruta: para cada pixel em sua saída, itere por todos os pontos, calcule a distância e use o mais próximo. Lento como pode ser, mas muito simples. Se o desempenho não for importante, ele faz o trabalho. Tenho trabalhado em um refinamento interessante, mas ainda estou procurando para ver se mais alguém teve a mesma ideia (bastante óbvia).
O algoritmo Bowyer-Watson é bastante fácil de entender. Aqui está uma implementação: http://paulbourke.net/papers/triangulate/ . É uma triangulação delaunay para um conjunto de pontos, mas você pode usá-la para obter o dual de delaunay, ou seja, um diagrama de voronoi. BTW. a árvore de abrangência mínima é um subconjunto da triangulação delaunay.
Amplamente referenciado, não documentado e quase todas as reimplementações que vi com base neste código estão erradas (em diferentes linguagens, muitas pessoas precisam do Voronoi, poucos podem entendê-lo bem o suficiente para portar corretamente). As únicas portas funcionais que vi são da comunidade científica / acadêmica e têm assinaturas de funções extremamente complicadas - ou extremamente otimizadas (de modo que não podem ser usadas para a maioria dos propósitos), tornando-as inutilizáveis por programadores normais.
Adam
VoronoiDiagramGenerator.cpp tem funcionalidade limitada. Ele produzirá um conjunto não ordenado de arestas. Extrair polígonos reais disso não é trivial. No lado positivo, ele apresenta um clipe contra um retângulo delimitador, de forma que nenhum ponto infinito seja gerado.
Bram
8
Aqui está uma implementação de javascript que usa quat-tree e permite a construção incremental.
Embora a pergunta original seja sobre como implementar o Voronoi, se eu tivesse encontrado um post que dizia o seguinte quando estava procurando informações sobre esse assunto, teria me economizado muito tempo:
Existem muitos códigos C ++ "quase corretos" na Internet para a implementação de diagramas de Voronoi. A maioria raramente dispara falhas quando os pontos de semente ficam muito densos. Eu recomendaria testar qualquer código que você encontrar online extensivamente com o número de pontos que você espera usar em seu projeto concluído, antes de perder muito tempo com ele.
A melhor das implementações que encontrei online foi parte do programa MapManager linkado aqui:
http://www.skynet.ie/~sos/mapviewer/voronoi.php
Funciona principalmente, mas estou recebendo corrupção intermitente de diagrama ao lidar com peça 10 ^ 6 pontos. Não consegui descobrir exatamente como a corrupção está se infiltrando.
Ontem à noite eu encontrei este:
http://www.boost.org/doc/libs/1_53_0_beta1/libs/polygon/doc/voronoi_main.htm
"A biblioteca Boost.Polygon Voronoi". Parece muito promissor. Isso vem com testes de benchmark para provar sua precisão e excelente desempenho. A biblioteca possui interface e documentação adequadas. Estou surpreso por não ter encontrado essa biblioteca antes, por isso escrevi sobre ela aqui. (Eu li esta postagem no início da minha pesquisa.)
O algoritmo mais simples vem da definição de um diagrama de voronoi: "O particionamento de um plano com n pontos em polígonos convexos de modo que cada polígono contenha exatamente um ponto gerador e cada ponto em um determinado polígono esteja mais próximo de seu ponto gerador do que de qualquer outro . "definição de volfrâmio.
A parte importante aqui é que cada ponto está mais próximo do ponto de geração do que qualquer outro, a partir daqui o algoritmo é muito simples:
Tenha uma série de pontos geradores.
Percorra cada pixel em sua tela.
Para cada pixel, procure o ponto gerador mais próximo a ele.
Dependendo de qual diagrama você deseja obter a cor do pixel. Se você quiser um diagrama separado por uma borda, verifique o segundo ao ponto mais próximo e, a seguir, verifique a diferença e a cor com a cor da borda se for menor que algum valor.
Se você quiser um diagrama de cores, tenha uma cor associada a cada ponto gerador e colora cada pixel com a cor associada ao ponto gerador mais próximo. E é isso, não é eficiente, mas muito fácil de implementar.
Este é o mais rápido possível - é um voronoi simples, mas parece ótimo. Ele divide os espaços em uma grade, coloca um ponto em cada célula da grade colocada aleatoriamente e se move ao longo da grade verificando as células 3x3 para descobrir como ela se relaciona com as células adjacentes.
É mais rápido sem o gradiente.
Você pode perguntar qual seria o voronoi 3D mais fácil. Seria fascinante saber. Provavelmente 3x3x3 células e gradiente de verificação.
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 );
}
e aqui é o mesmo com distância chebychev. você pode usar um ruído de flutuação 2d random2f aqui:
Isso foi há um tempo atrás, para o benefício de quem o quê, eu acho que isso é legal:
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 );
}
Você só precisa criar uma lista. Um vetor pode ser criado passando em dois números (coordenadas) como flutuante. Em seguida, passe a lista para Fortune.ComputeVoronoiGraph ()
Você pode entender o conceito do algoritmo um pouco mais nestas páginas da Wikipedia:
Embora uma coisa que eu não fui capaz de entender é como criar uma linha para arestas parcialmente infinitas (não sei muito sobre geometria de coordenadas :-)). Se alguém souber, por favor, me informe também.
Embora esses links possam responder à pergunta, é melhor incluir as partes essenciais da resposta aqui e fornecer o link para referência. As respostas somente com link podem se tornar inválidas se a página vinculada mudar.
Kmeixner
0
Se você está tentando desenhá-lo em uma imagem, pode usar um algoritmo de preenchimento com base em fila.
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;
}
O uso de uma fila garantirá que as regiões se espalhem em paralelo, minimizando o número total de visitas de pixels. Se você usar uma pilha, o primeiro ponto preencherá a imagem inteira e o segundo preencherá todos os pixels mais próximos a ela do que o primeiro ponto. Isso vai continuar, aumentando muito o número de visitas. O uso de uma fila FIFO processa os pixels na ordem em que são enviados. As imagens resultantes serão aproximadamente as mesmas se você usar pilha ou fila, mas o big-O para a fila está muito mais próximo do linear (em relação ao número de pixels da imagem) do que o big-O do algoritmo de pilha. A ideia geral é que as regiões se espalharão na mesma taxa e as colisões geralmente acontecerão exatamente em pontos que correspondem aos limites da região.
Respostas:
Um algoritmo fácil para calcular a triangulação Delaunay de um conjunto de pontos é inverter as arestas . Como uma triangulação de Delaunay é o gráfico dual de um diagrama de Voronoi, você pode construir o diagrama a partir da triangulação em tempo linear.
Infelizmente, o pior caso de tempo de execução da abordagem de inversão é O (n ^ 2). Existem algoritmos melhores, como a varredura de linha da Fortune, que levam um tempo O (n log n). No entanto, isso é um tanto complicado de implementar. Se você é preguiçoso (como eu), sugiro que você procure uma implementação existente de uma triangulação de Delaunay, use-a e calcule o gráfico dual.
Em geral, um bom livro sobre o assunto é Geometria Computacional de de Berg et al.
fonte
Mais fácil? Essa é a abordagem da força bruta: para cada pixel em sua saída, itere por todos os pontos, calcule a distância e use o mais próximo. Lento como pode ser, mas muito simples. Se o desempenho não for importante, ele faz o trabalho. Tenho trabalhado em um refinamento interessante, mas ainda estou procurando para ver se mais alguém teve a mesma ideia (bastante óbvia).
fonte
O algoritmo Bowyer-Watson é bastante fácil de entender. Aqui está uma implementação: http://paulbourke.net/papers/triangulate/ . É uma triangulação delaunay para um conjunto de pontos, mas você pode usá-la para obter o dual de delaunay, ou seja, um diagrama de voronoi. BTW. a árvore de abrangência mínima é um subconjunto da triangulação delaunay.
fonte
O algoritmo mais eficiente para construir um diagrama de voronoi é o algoritmo de Fortune . Ele é executado em O (n log n).
Aqui está um link para a sua implementação de referência em C .
Pessoalmente, gosto muito da implementação do python por Bill Simons e Carson Farmer, pois achei mais fácil estender.
fonte
A página da Wikipedia ( http://en.wikipedia.org/wiki/Voronoi_diagram ) tem uma seção Algoritmos com links para algoritmos para implementação de diagramas de Voronoi.
fonte
Há uma implementação voronoi disponível gratuitamente para gráficos 2-d em C e em C ++ de Stephan Fortune / Shane O'Sullivan:
Você o encontrará em muitos lugares. Ou seja, em http://www.skynet.ie/~sos/masters/
fonte
Aqui está uma implementação de javascript que usa quat-tree e permite a construção incremental.
http://code.google.com/p/javascript-voronoi/
fonte
Embora a pergunta original seja sobre como implementar o Voronoi, se eu tivesse encontrado um post que dizia o seguinte quando estava procurando informações sobre esse assunto, teria me economizado muito tempo:
Existem muitos códigos C ++ "quase corretos" na Internet para a implementação de diagramas de Voronoi. A maioria raramente dispara falhas quando os pontos de semente ficam muito densos. Eu recomendaria testar qualquer código que você encontrar online extensivamente com o número de pontos que você espera usar em seu projeto concluído, antes de perder muito tempo com ele.
A melhor das implementações que encontrei online foi parte do programa MapManager linkado aqui: http://www.skynet.ie/~sos/mapviewer/voronoi.php Funciona principalmente, mas estou recebendo corrupção intermitente de diagrama ao lidar com peça 10 ^ 6 pontos. Não consegui descobrir exatamente como a corrupção está se infiltrando.
Ontem à noite eu encontrei este: http://www.boost.org/doc/libs/1_53_0_beta1/libs/polygon/doc/voronoi_main.htm "A biblioteca Boost.Polygon Voronoi". Parece muito promissor. Isso vem com testes de benchmark para provar sua precisão e excelente desempenho. A biblioteca possui interface e documentação adequadas. Estou surpreso por não ter encontrado essa biblioteca antes, por isso escrevi sobre ela aqui. (Eu li esta postagem no início da minha pesquisa.)
fonte
Na verdade, existem implementações para 25 idiomas diferentes disponíveis em https://rosettacode.org/wiki/Voronoi_diagram
Por exemplo, para Java:
fonte
O algoritmo mais simples vem da definição de um diagrama de voronoi: "O particionamento de um plano com n pontos em polígonos convexos de modo que cada polígono contenha exatamente um ponto gerador e cada ponto em um determinado polígono esteja mais próximo de seu ponto gerador do que de qualquer outro . "definição de volfrâmio.
A parte importante aqui é que cada ponto está mais próximo do ponto de geração do que qualquer outro, a partir daqui o algoritmo é muito simples:
Se você quiser um diagrama de cores, tenha uma cor associada a cada ponto gerador e colora cada pixel com a cor associada ao ponto gerador mais próximo. E é isso, não é eficiente, mas muito fácil de implementar.
fonte
Este é o mais rápido possível - é um voronoi simples, mas parece ótimo. Ele divide os espaços em uma grade, coloca um ponto em cada célula da grade colocada aleatoriamente e se move ao longo da grade verificando as células 3x3 para descobrir como ela se relaciona com as células adjacentes.
É mais rápido sem o gradiente.
Você pode perguntar qual seria o voronoi 3D mais fácil. Seria fascinante saber. Provavelmente 3x3x3 células e gradiente de verificação.
http://www.iquilezles.org/www/articles/smoothvoronoi/smoothvoronoi.htm
e aqui é o mesmo com distância chebychev. você pode usar um ruído de flutuação 2d random2f aqui:
https://www.shadertoy.com/view/Msl3DM
editar: eu converti isso para código C like
Isso foi há um tempo atrás, para o benefício de quem o quê, eu acho que isso é legal:
fonte
ivec2
? ouvec2
? Isso é ilegível.Verifique a solução de força bruta apresentada com o pseudocódigo por Richard Franks em sua resposta à pergunta Como faço para derivar um diagrama de Voronoi dado seu conjunto de pontos e sua triangulação de Delaunay?
fonte
Encontrei esta excelente biblioteca C # no código do Google com base no algoritmo / algoritmo de linha de varredura da Fortune
https://code.google.com/p/fortune-voronoi/
Você só precisa criar uma lista. Um vetor pode ser criado passando em dois números (coordenadas) como flutuante. Em seguida, passe a lista para Fortune.ComputeVoronoiGraph ()
Você pode entender o conceito do algoritmo um pouco mais nestas páginas da Wikipedia:
http://en.wikipedia.org/wiki/Fortune%27s_algorithm
http://en.wikipedia.org/wiki/Sweep_line_algorithm
Embora uma coisa que eu não fui capaz de entender é como criar uma linha para arestas parcialmente infinitas (não sei muito sobre geometria de coordenadas :-)). Se alguém souber, por favor, me informe também.
fonte
Se você está tentando desenhá-lo em uma imagem, pode usar um algoritmo de preenchimento com base em fila.
O uso de uma fila garantirá que as regiões se espalhem em paralelo, minimizando o número total de visitas de pixels. Se você usar uma pilha, o primeiro ponto preencherá a imagem inteira e o segundo preencherá todos os pixels mais próximos a ela do que o primeiro ponto. Isso vai continuar, aumentando muito o número de visitas. O uso de uma fila FIFO processa os pixels na ordem em que são enviados. As imagens resultantes serão aproximadamente as mesmas se você usar pilha ou fila, mas o big-O para a fila está muito mais próximo do linear (em relação ao número de pixels da imagem) do que o big-O do algoritmo de pilha. A ideia geral é que as regiões se espalharão na mesma taxa e as colisões geralmente acontecerão exatamente em pontos que correspondem aos limites da região.
fonte