Lecture Link
https://www.youtube.com/watch?v=Pn19deUBsM8&t=13s
The Post-Office Problem
https://link.springer.com/chapter/10.1007%2F3-540-10291-4_1
http://blog.ivank.net/voronoi-diagram-in-javascript.html
http://paperjs.org/examples/voronoi/
https://shaneosullivan.wordpress.com/2011/03/22/sweep-line-voronoi-algorithm-in-javascript/
https://jacquesheunis.com/post/fortunes-algorithm/
http://blog.ivank.net/fortunes-algorithm-and-implementation.html
https://github.com/pvigier/FortuneAlgorithm
https://pvigier.github.io/2018/11/18/fortune-algorithm-details.html
TakeAwayFromPvigier’s blog
https://pvigier.github.io/2018/11/18/fortune-algorithm-details.html
pseudo-code from Pvigier’s Blog
1 | add a site event in the event queue for each site |
- site event
- circle event
Diagram’s Data Structure
Double connected edge list(DCEL).
1 | class VoronoiDiagram{ |
The Site
class represents an input point. Each site has an index, which is useful to query them, coordinates and a pointer to their cell(face
):
1 | struct Site{ |
The vertices of the cells are represented by the Vertex
class, they just have a cooridinates field:
1 | struct Vertex{ |
Here is the implementation of half-edges
:
1 | struct HalfEdge{ |
An edge in a Voronoi diagram is shared by two adjacent cells. In the DCEL data structure, we splite these edfes in two half-edges, one for each cell, and they are linked by the twin
pointer.
Moreover, a hald-edge has an origin vertex and a desrination vertex.
The incidenetFace
field points to the face to which the half-edge belongs to.
Finally, in DCEL, cells are implemented as a circular doubly linked list of half-edges where adjacent half-edges are linked together. Thus the prev
and next
fields points to the previous and next half-edges in the cell.
Finally, the Face
class represents a cell and it just contains a pointer to its site and another to one of its half-edges. It does not matter which half-edge it is because a cell is a closed polygon. Thus we can access to all of its hald-edges by traversing the circular linked list.
1 | struct Face{ |
Event Queue
The standard way to implement the event queue is to use a priority queue.
During the processing of site and circle events we may need to remove circle events from the queue because they are not valid anymore.
But most of the standard implementations of priority queues do not allow to remove an element which is not the top one. In particular that is the case for std::priority_queue
.
There are two ways to tackle this problem.
- The first and simplest one is to add a
valid
flag totrue
initially. Then instead of removing the circle event from the queue, we just set its flag tofalse
. Finially, when we process the events in the main loop, if thevalid
flag of an event equals tofalse
, we simply discard it and process the next one. - The second method which I adopted is not to use
std::priority_queue
. Instead, I implemented my own priority queue which supports removal of any element it contains. The implementation of such a queue is pretty straightforward. I choose this method because I find it makes the code for the algorithm clearer.
Beachline
If not implemented correctly there is no guarantee that the algorithm will run in O(log(n)). The key to reach this time complecity is to use a self-balancing tree.
In my implementation the beachline is still a tree, but all nodes represent an arc.
1 | struct Arc{ |
In Fortune’s algorithm we have no key, we only know that we want to insert an arc before or after another in the beachline. To do that, I create methods insertBefore
and insertAfter
:
1 | void Beachline::insertBefore(Arc* x, Arc* y){ |
Priority Queues
https://www.youtube.com/watch?v=wptevk0bshY
What is a Priority Queue
A priority queue is an Abstract Data Type(ADT) that operates similar to a normal queue excpet that each element has a certain priority. The priority of the elements in priority queue determin the order in which elements are removed from the PQ.
NOTE: Priority queues only supports comparable data.
What is a Heap?
A heap is a tree based DS that satifies the heap invariant(also called heap property):
If A is a parent node of B then A is ordered with repect to B for all nodes A, B in the heap.
- Max Heap
- Min Heap
Heaps must be trees.
When and where is a PQ used?
- Used in certain implementaitons of Dijkstra’s shortest Path algorithm.
- Anytime you need the dynamically fetch the
next best
ornext worst
element - Used in Huffman coding (which is often used for lossless data compression).
- Best First Search(BFS) algorithms such as A* use PQs to continuously grab the next most promising node
- Used by minimum Spanning Tree(MST) algorithms
Complexity PQ with binary heap
- Binary Heap construction: O(n)
- Polling: O(log(n))
- Peeking: O(1)
- Adding: O(log(n))
Self balance Tree (AVL Tree)
https://www.youtube.com/watch?v=vRwi_UcZGjU
- Balance
- Rotation
- Implementation
Rebalancing threshold
pseudo-code from Jacquesheunis’ blog
https://jacquesheunis.com/post/fortunes-algorithm/
1 | Fill the event queue with site events for each input site. |
Voronoi Diagram - Computataional Geometry
Fortune’s Sweep
1 | VoronoiDiagram(P are in R2) |
Handling Events
- HandleSiteEvent(point p)
- Search in
T
for the arca
vertically abovep
. Ifa
has pointer to circle event inQ
, delete this event. - Split
a
intoa0
anda2
. Leta1
be the new arc ofp
- Add Vor-edges
<q, p>
and<p, q>
to DECL - Check
<., a0, a1>
and<a1, a2, .>
for circle events.
- Search in
- HandleCircleEvent(arc
a
)- T.delete(a); update breakpts
- Delete all circle events involving
a
fromQ
- Add Vor-vtx
a_left
anda_right