Voronoi diyagramını uygulamak için kolay algoritmalar nelerdir?
Özellikle sözde formda herhangi bir algoritma bulamadım. Lütfen Voronoi diyagram algoritması, öğretici vb.'nin bazı bağlantılarını paylaşın.
Voronoi diyagramını uygulamak için kolay algoritmalar nelerdir?
Özellikle sözde formda herhangi bir algoritma bulamadım. Lütfen Voronoi diyagram algoritması, öğretici vb.'nin bazı bağlantılarını paylaşın.
Yanıtlar:
Bir nokta kümesinin Delaunay üçgenlemesini hesaplamak için kolay bir algoritma, kenarları çevirmektir . Bir Delaunay üçgenlemesi, bir Voronoi diyagramının ikili grafiği olduğundan, diyagramı üçgenlemeden doğrusal zamanda oluşturabilirsiniz.
Ne yazık ki, saygısız yaklaşımın en kötü durumdaki çalışma süresi O (n ^ 2) 'dir. Fortune'un satır taraması gibi, O (n log n) süresini alan daha iyi algoritmalar mevcuttur. Yine de bunu uygulamak biraz zor. Tembel iseniz (benim gibi), Delaunay üçgenlemesinin mevcut bir uygulamasını aramanızı, onu kullanmanızı ve ardından ikili grafiği hesaplamayı öneririm.
Genel olarak, konuyla ilgili iyi bir kitap de Berg ve ark. Tarafından yazılan Hesaplamalı Geometri'dir .
En kolay? Kaba kuvvet yaklaşımı budur: Çıktınızdaki her piksel için, tüm noktalarda yineleyin, mesafeyi hesaplayın, en yakın olanı kullanın. Olabildiğince yavaş ama çok basit. Performans önemli değilse, işi yapar. Ben de ilginç bir iyileştirme üzerinde çalışıyorum, ancak yine de başka birinin aynı (oldukça açık) fikre sahip olup olmadığını araştırıyorum.
Bowyer-Watson algoritmasının anlaşılması oldukça kolaydır. İşte bir uygulama: http://paulbourke.net/papers/triangulate/ . Bu, bir dizi nokta için bir delaunay üçgenlemesidir, ancak bunu delaunay'ın çiftini, yani bir voronoi diyagramını elde etmek için kullanabilirsiniz. BTW. minimum kapsayan ağaç, delaunay üçgenlemesinin bir alt kümesidir.
Bir voronoi diyagramı oluşturmak için en etkili algoritma , Fortune algoritmasıdır . O (n log n) ile çalışır.
İşte C'deki referans uygulamasına bir bağlantı .
Şahsen , genişletmeyi daha kolay bulduğum için Bill Simons ve Carson Farmer'ın python uygulamasını gerçekten seviyorum .
Wikipedia sayfasında ( http://en.wikipedia.org/wiki/Voronoi_diagram ), Voronoi diyagramlarını uygulamak için algoritmalara bağlantılar içeren bir Algoritmalar bölümü vardır.
Stephan Fortune / Shane O'Sullivan'dan C ve C ++ 'da 2-b grafikler için ücretsiz bir voronoi uygulaması var:
VoronoiDiagramGenerator.cpp
VoronoiDiagramGenerator.h
Bunu birçok yerde bulacaksınız. Yani http://www.skynet.ie/~sos/masters/ adresinde
İşte quat-tree kullanan ve artımlı yapıya izin veren bir javascript uygulaması.
Asıl soru Voronoi'nin nasıl uygulanacağını sorarken, bu konuda bilgi ararken aşağıdakileri söyleyen bir gönderi bulsaydım, bana çok zaman kazandırırdı:
Voronoi diyagramlarını uygulamak için internette pek çok "neredeyse doğru" C ++ kodu var. Çoğu, tohum noktaları çok yoğunlaştığında nadiren başarısızlıkları tetikler. İnternette bulduğunuz herhangi bir kodu, üzerinde çok fazla zaman harcamadan, bitmiş projenizde kullanmayı beklediğiniz puan sayısı ile kapsamlı bir şekilde test etmenizi tavsiye ederim.
Çevrimiçi bulduğum uygulamaların en iyisi, şuradan bağlanan MapManager programının bir parçasıydı: http://www.skynet.ie/~sos/mapviewer/voronoi.php Çoğunlukla işe yarıyor, ancak işlem yaparken aralıklı diyagram bozulması alıyorum 10 ^ 6 puan sipariş edin. Yolsuzluğun nasıl içeri sızdığını tam olarak çözemedim.
Dün gece bunu buldum: http://www.boost.org/doc/libs/1_53_0_beta1/libs/polygon/doc/voronoi_main.htm "The Boost.Polygon Voronoi kütüphanesi". Çok umut verici görünüyor. Bu, doğruluğunu ve mükemmel performansa sahip olduğunu kanıtlamak için karşılaştırma testleri ile birlikte gelir. Kütüphane, uygun bir arayüze ve belgelere sahiptir. Bu kütüphaneyi daha önce bulamadığıma şaşırdım, dolayısıyla burada yazıyorum. (Bu yazıyı araştırmamın başlarında okudum.)
Bu mümkün olan en hızlısı - basit bir voronoi ama harika görünüyor. Boşlukları bir ızgaraya böler, rastgele yerleştirilmiş her ızgara hücresine bir nokta yerleştirir ve bitişik hücrelerle nasıl ilişkili olduğunu bulmak için 3x3 hücreleri kontrol ederek ızgara boyunca hareket eder.
Gradyan olmadan daha hızlıdır.
En kolay 3d voronoi'nin ne olacağını sorabilirsiniz. Bilmek büyüleyici olurdu. Muhtemelen 3x3x3 hücre ve kontrol gradyanı.
http://www.iquilezles.org/www/articles/smoothvoronoi/smoothvoronoi.htm
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 );
}
ve burada chebychev mesafesi ile aynıdır. Buradan random2f 2d float gürültüsü kullanabilirsiniz:
https://www.shadertoy.com/view/Msl3DM
edit: Bunu C benzeri koda dönüştürdüm
Bu bir süre önceydi, bunu yapanların yararına, bunun harika olduğuna inanıyorum:
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 );
}
ivec2
? veya vec2
? Bu okunamaz.
Aslında https://rosettacode.org/wiki/Voronoi_diagram adresinde 25 farklı dil için uygulamalar mevcuttur.
Örneğin Java için:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Ellipse2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Random;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
public class Voronoi extends JFrame {
static double p = 3;
static BufferedImage I;
static int px[], py[], color[], cells = 100, size = 1000;
public Voronoi() {
super("Voronoi Diagram");
setBounds(0, 0, size, size);
setDefaultCloseOperation(EXIT_ON_CLOSE);
int n = 0;
Random rand = new Random();
I = new BufferedImage(size, size, BufferedImage.TYPE_INT_RGB);
px = new int[cells];
py = new int[cells];
color = new int[cells];
for (int i = 0; i < cells; i++) {
px[i] = rand.nextInt(size);
py[i] = rand.nextInt(size);
color[i] = rand.nextInt(16777215);
}
for (int x = 0; x < size; x++) {
for (int y = 0; y < size; y++) {
n = 0;
for (byte i = 0; i < cells; i++) {
if (distance(px[i], x, py[i], y) < distance(px[n], x, py[n], y)) {
n = i;
}
}
I.setRGB(x, y, color[n]);
}
}
Graphics2D g = I.createGraphics();
g.setColor(Color.BLACK);
for (int i = 0; i < cells; i++) {
g.fill(new Ellipse2D .Double(px[i] - 2.5, py[i] - 2.5, 5, 5));
}
try {
ImageIO.write(I, "png", new File("voronoi.png"));
} catch (IOException e) {
}
}
public void paint(Graphics g) {
g.drawImage(I, 0, 0, this);
}
static double distance(int x1, int x2, int y1, int y2) {
double d;
d = Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)); // Euclidian
// d = Math.abs(x1 - x2) + Math.abs(y1 - y2); // Manhattan
// d = Math.pow(Math.pow(Math.abs(x1 - x2), p) + Math.pow(Math.abs(y1 - y2), p), (1 / p)); // Minkovski
return d;
}
public static void main(String[] args) {
new Voronoi().setVisible(true);
}
}
En basit algoritma, bir voronoi diyagramının tanımından gelir: "N noktalı bir düzlemin dışbükey çokgenlere bölünmesi, öyle ki her çokgen tam olarak bir üretme noktası içerir ve belirli bir çokgendeki her nokta, üretim noktasına diğerlerinden daha yakın olur. . "wolfram'dan tanım.
Buradaki önemli kısım, her noktanın üretim noktasına diğerlerinden daha yakın olmasıdır, buradan itibaren algoritma çok basittir:
Bir renk diyagramı istiyorsanız, her bir oluşturma noktasıyla ilişkilendirilmiş bir renge sahip olun ve her pikseli en yakın üreten nokta ilişkili renkle renklendirin. Ve bununla ilgili, verimli değil ama uygulaması çok kolay.
Richard Franks tarafından sözde kod ile sunulan kaba kuvvet çözümünü , soruya verdiği yanıtta kontrol edin. Nokta kümesi ve Delaunay üçgenlemesine göre bir Voronoi diyagramını nasıl elde ederim?
Bu mükemmel C # kitaplığını, Fortune algoritması / Tarama hattı algoritmasına dayalı olarak Google kodunda buldum
https://code.google.com/p/fortune-voronoi/
Sadece bir Liste oluşturmanız yeterlidir. Float olarak iki sayı (koordinatlar) geçirilerek bir Vektör oluşturulabilir. Ardından listeyi Fortune.ComputeVoronoiGraph () 'a iletin
Algoritma kavramını şu Wikipedia sayfalarından biraz daha anlayabilirsiniz:
http://en.wikipedia.org/wiki/Fortune%27s_algorithm
http://en.wikipedia.org/wiki/Sweep_line_algorithm
Yine de anlayamadığım bir şey, Kısmen Sonsuz kenarlar için bir çizginin nasıl oluşturulacağıydı (koordinat geometrisi hakkında fazla bir şey bilmiyorum :-)). Birisi biliyorsa, lütfen bunu da bana bildirin.
Bir görüntüye çizmeye çalışıyorsanız, kuyruk tabanlı bir sel doldurma algoritması kullanabilirsiniz.
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;
}
Sıra kullanmak, bölgelerin paralel olarak yayılmasını sağlayarak toplam piksel ziyaret sayısını en aza indirir. Yığın kullanırsanız, ilk nokta tüm görüntüyü doldurur, ardından ikincisi, ona birinci noktadan daha yakın olan pikselleri doldurur. Bu devam edecek ve ziyaret sayılarını büyük ölçüde artıracak. Bir FIFO kuyruğu kullanmak, pikselleri itildikleri sırayla işler. Sonuçta elde edilen görüntüler, yığın veya sıra kullansanız da kabaca aynı olacaktır, ancak kuyruk için büyük-O, yığın algoritmasının büyük-O'suna göre doğrusalya (görüntü piksel sayısına göre) çok daha yakındır. Genel fikir, bölgelerin aynı oranda yayılacağı ve çarpışmaların genellikle bölge sınırlarına karşılık gelen noktalarda gerçekleşeceği yönündedir.