5.2 Voronoi-Algorithmus (Fortune)
Überblick (Folie 14)
- Der klassische Algorithmus ist Divide-and-Conquer (Shamos & Hoey 1975) mit , aber schwer zu implementieren (das Zusammenfügen zweier Diagramme ist fummelig).
- Einfacher: der Sweep-Line-Algorithmus von Steven Fortune (1987), ebenfalls .
Grundidee: Eine waagrechte Sweep-Line läuft von oben nach unten und vervollständigt das Diagramm oberhalb.
Das Problem: Anders als beim Segmentschnitt ist das Diagramm direkt über noch nicht fertig. Ein Punkt knapp unter kann eine Zelle beeinflussen, die schon über beginnt. Fertig ist nur der Bereich oberhalb einer stückweise quadratischen Kurve , der Strandlinie (beach line).
Die Strandlinie (Folien 15–17)
Definition: Die Strandlinie besteht aus allen Punkten, die denselben Abstand zur Sweep-Line und zum nächsten Punkt oberhalb von haben.
Warum ist darüber alles fertig? Ein Punkt oberhalb der Strandlinie ist näher an einem Site über als an . Jeder Site unter ist aber weiter von entfernt als . Also kann kein späterer Site noch „wegschnappen“, die Zuordnung von ist endgültig.
Die Parabel
Die Punkte -Wert , Höhe mit gleichem Abstand zu und zu :
Quadrieren und nach auflösen:
Da , ist der Nenner positiv: Die Parabeln sind nach oben offen. Ihr Brennpunkt ist , ihre Leitlinie ist . Je weiter nach unten wandert, desto breiter werden sie.
Die Strandlinie ist das untere Minimum aller dieser Parabeln (in der Demo: „einzelne Parabeln“ einschalten). Sie besteht aus Parabelbögen (arcs).
Was die Strandlinie verrät (Folie 17)
- Die Übergangspunkte (Knicke) zwischen zwei benachbarten Bögen von und sind gleich weit von , und entfernt. Sie liegen also auf der Mittelsenkrechten von und wandern beim Sweep entlang der Voronoi-Kanten nach unten. So entdeckt man die Kanten.
- Ein neuer Bogen entsteht, wenn einen neuen Punkt erreicht: Punktereignis (site event). Der neue Bogen ist anfangs ein senkrechter Strich (Parabel mit Brennweite 0) und spaltet den Bogen darüber.
- Eine Parabel kann mehrere Bögen zur Strandlinie beitragen (sie wird beim Punktereignis in zwei Teile gespalten).
Lemma 4: Bögen entstehen nur durch Punktereignisse (Folien 18–20)
Ein Bogen kann nur durch ein Punktereignis auf der Strandlinie erscheinen.
Beweis (Widerspruch). Angenommen, eine schon vorhandene Parabel bricht von oben durch die Strandlinie. Das kann auf zwei Arten passieren:
- Im Inneren eines Bogens : Dann gäbe es eine Position , an der sich und in genau einem Punkt berühren, also mit gleicher Tangente: Zusammen mit folgt , Widerspruch dazu, dass sie sich nur in einem Punkt berühren.
- Genau am Übergang zweier Bögen : Dann gäbe es einen Kreis durch , der berührt. Schiebt man weiter nach unten und hält einen Kreis durch tangential an , gerät oder in sein Inneres. Also ist dort nie der niedrigste Bogen und kann keinen neuen Bogen bilden. □
Folge (Folie 21): Die Strandlinie hat höchstens Bögen. Jedes Punktereignis fügt einen Bogen hinzu und spaltet einen vorhandenen in zwei, erhöht die Zahl also um höchstens 2. Mit dem ersten Punkt (1 Bogen) ergibt das .
Kreisereignisse (Folien 22–25)
Wann verschwindet ein Bogen? Wenn er zwischen seinen beiden Nachbarn auf einen Punkt zusammenschrumpft. Dann treffen sich zwei Übergangspunkte, also zwei Voronoi-Kanten: ein Voronoi-Knoten entsteht.
Ein Bogen kann nur bei einem Kreisereignis verschwinden: Ein leerer Kreis durch die Sites dreier (bis dahin) benachbarter Bögen berührt von oben. Kein Punkt von liegt im Inneren von .
Beweis. Die einzige Alternative wäre, dass die Nachbarbögen und zur selben Parabel gehören. Dann müssten sie sich wieder vereinen, das hieße aber, dass ein Bogen dieser Parabel neu erscheint, was Lemma 4 verbietet. kann nur verschwinden, wenn der Kreis leer ist (sonst hätte der Punkt im Inneren schon vorher einen Bogen dazwischen erzeugt). □
Wo liegt der Voronoi-Knoten? Im Mittelpunkt von , nicht am Berührpunkt mit . Das Ereignis wird ausgelöst, wenn den tiefsten Punkt von erreicht (). Genau dann ist der Mittelpunkt von und gleich weit entfernt.
Alle Voronoi-Knoten werden durch Kreisereignisse erkannt.
Beweis. Zu zeigen ist: Die drei Sites eines Voronoi-Knotens haben kurz vor dem Kreisereignis drei benachbarte Bögen erzeugt. Hebt man um ein kleines an, gibt es zwei leere Kreise, die berühren und durch bzw. gehen. Ihre Mittelpunkte sind Übergangspunkte der Strandlinie. Also waren und benachbart und haben das Kreisereignis erzeugt. □
In der Demo: Mit „⏩ nächstes Ereignis“ springt von Ereignis zu Ereignis. Gestrichelte orange Kreise sind anstehende Kreisereignisse, rote Punkte gefundene Voronoi-Knoten.
Datenstrukturen (Folien 26–28)
| Struktur | Inhalt |
|---|---|
| Prioritätswarteschlange | Punkt- und Kreisereignisse, Priorität = -Koordinate (größtes zuerst). Anfangs alle Punktereignisse |
| Balancierter Suchbaum | die Strandlinie: findet zu jedem Ereignis den betroffenen Bogen in |
| Doppelt verkettete Kantenliste (DCEL) | das entstehende Voronoi-Diagramm. Gegen Halbgeraden in ein großes Rechteck (Bounding Box) eingebettet |
Die Warteschlange (Folie 27)
- Punktereignisse sind von Anfang an bekannt.
- Kreisereignisse werden unterwegs berechnet: Für jedes Tripel benachbarter Bögen wird ein Kreisereignis erzeugt, wenn die beiden Übergangspunkte aufeinander zulaufen (die Kanten konvergieren). Laufen sie auseinander, schrumpft der mittlere Bogen nie.
- Ein Punktereignis kann ein vorher erkanntes Kreisereignis ungültig machen (false alarm): Der neue Punkt liegt dann im Kreis, der Kreis ist nicht mehr leer. Dieses Ereignis muss wieder aus entfernt werden.
Der Suchbaum (Folie 28)
- Blätter = Bögen der Strandlinie von links nach rechts. Jedes Blatt speichert
- einen Zeiger auf den erzeugenden Site,
- einen Zeiger auf das Kreisereignis, das den Bogen entfernen wird (falls es eins gibt),
- Zeiger auf die Nachbarbögen.
- Innere Knoten = Übergänge zwischen Bögen, gespeichert als Paar . Sie speichern
- Zeiger auf die beiden erzeugenden Sites,
- einen Zeiger auf die zugehörige Voronoi-Kante in .
Die -Position eines Übergangs hängt von ab. Man speichert sie nicht, sondern berechnet sie beim Suchen aus , und (Schnitt zweier Parabeln). Wie beim Bentley–Ottmann-Status bleibt die Reihenfolge zwischen Ereignissen gleich.
Algorithmus 1 (Folie 29)
Algorithmus 1: Voronoi-Diagramm(P)
1: Initialisiere Q mit allen Punktereignissen;
2: Initialisiere leeren Suchbaum T und leere Kantenliste D;
3: while (Q ≠ ∅) {
4: Nimm das Ereignis mit größtem y aus Q;
5: if (Punktereignis) HandleSiteEvent(p_i);
7: else HandleCircleEvent(γ); // γ = Blatt des verschwindenden Bogens
9: }
10: Die übrigen inneren Knoten von T sind die Halbgeraden:
Bounding Box um alle Voronoi-Knoten und P berechnen
und die Halbgeraden dort in D anhängen;
HandleSiteEvent() (Folie 30)
1: if (T leer) { p_i in T einfügen; return; }
3: Suche in T das Blatt γ_j des Bogens β_j senkrecht über p_i;
4: if (γ_j zeigt auf ein Kreisereignis) entferne es aus Q; // false alarm
5: a) Ersetze γ_j durch einen Teilbaum mit drei Blättern:
Mitte = neuer Site p_i, außen je p_j;
b) Speichere ⟨p_j, p_i⟩ und ⟨p_i, p_j⟩ in zwei neuen inneren Knoten;
c) Rebalanciere T;
6: Neue Kante zwischen V(p_i) und V(p_j) in D anlegen;
7: if (β_i und seine zwei rechten Nachbarn erzeugen ein Kreisereignis)
in Q einfügen und mit den Blättern verlinken;
8: if (β_i und seine zwei linken Nachbarn erzeugen ein Kreisereignis)
in Q einfügen und mit den Blättern verlinken;
(Genauer: Bei Zeile 7/8 bildet das Tripel aus dem rechten Teilstück von und seinen zwei rechten Nachbarn das neue Tripel, denn selbst kann nicht verschwinden, er hat ja auf beiden Seiten dieselbe Parabel als Nachbarn.)
HandleCircleEvent() (Folie 31)
1: a) Entferne alle Kreisereignisse aus Q, an denen β_j beteiligt ist
(über die Vorgänger-/Nachfolger-Zeiger in T);
b) Entferne das Blatt γ des verschwindenden Bogens β_j aus T;
c) Aktualisiere die inneren Knoten (Übergänge);
d) Rebalanciere T;
2: Neuen Voronoi-Knoten (Kreismittelpunkt) und neue Kante
zwischen V(p_i) und V(p_k) in D eintragen
(p_i, p_k = Sites der Nachbarbögen);
3: if (die neuen Tripel aufeinanderfolgender Bögen um die Lücke
erzeugen Kreisereignisse) {
4: in Q einfügen und Zeiger in T setzen;
5: }
Satz 7: Laufzeit (Folie 32)
Algorithmus 1 läuft in Zeit und braucht Speicher.
Beweis.
- Jede Operation auf und (Suchen, Einfügen, Löschen) kostet , die Initialisierung .
- Jedes Ereignis braucht nur konstant viele solcher Operationen, also pro Ereignis.
- Es gibt Punktereignisse und höchstens Kreisereignisse (so viele Voronoi-Knoten gibt es höchstens, Satz 2). Falsche Alarme kosten nichts extra, denn jedes eingefügte Kreisereignis wird höchstens einmal gelöscht und pro Ereignis werden konstant viele eingefügt.
- ⇒ Gesamtlaufzeit .
- Die Strandlinie hat höchstens Bögen, also brauchen und linearen Speicher, nach Satz 2 ebenfalls. □
Sonderfälle (Folie 33)
- Zwei Punkte mit gleichem : Reihenfolge beliebig. Sind es die ersten beiden Punkte, gibt es über dem zweiten noch keinen Bogen (die erste Parabel ist ein senkrechter Strich) → Sonderbehandlung.
- Zwei Kreisereignisse fallen zusammen: Dann liegen vier Punkte auf einem Kreis. Vereinfachung: nicht gesondert behandeln, sondern eine Kante der Länge 0 erzeugen und im Nachgang entfernen.
- Punktereignis genau unter einem Übergangspunkt: Einer der Nachbarbögen wird gespalten, sodass ein Bogen der Länge 0 entsteht. Dieser erzeugt sofort ein Kreisereignis, das ihn beim Abarbeiten wieder entfernt.
Komplexität (Folie 34)
- Die Punkte mit unbeschränkter Zelle sind genau die Ecken der konvexen Hülle .
- Man findet sie in : Einen hinreichend großen Kreis um im Uhrzeigersinn ablaufen und seine Schnitte mit den Voronoi-Kanten bestimmen. Die Zellen, durch die man dabei läuft, sind die unbeschränkten, und zwar in Hüllreihenfolge.
- ⇒ Aus dem Voronoi-Diagramm bekommt man die konvexe Hülle in .
- Die Hülle braucht aber (2.3 untere Schranke).
- ⇒ Jeder Algorithmus für Voronoi-Diagramme braucht . Fortune ist worst-case-optimal.