Open In App

Voronoi Diagram

Last Updated : 16 Feb, 2024
Improve
Improve
Like Article
Like
Save
Share
Report

A Voronoi diagram known as a Voronoi tessellation or Voronoi partition is a geometric structure that divides a given space into the regions based on the distance to a set of the points called “seeds” or “sites“. In this diagram, each region represents the area that is closest to a specific seed compared to any other seed in set. Voronoi diagrams have applications in the various fields such as computer graphics, geographical information and more.

Algorithm for Constructing Voronoi Diagram:

One commonly used algorithm for constructing Voronoi diagrams is the “Fortune’s Algorithm” which operates in O(n log n) time where n is the number of input seeds.

  • Initialization: Begin by sorting the seed points along a line or plane using the appropriate sorting algorithm such as Quicksort or Merge Sort.
  • Event Queue: To Create a priority queue to manage events. Events can be either site events or circle events (circles formed by three consecutive seed points). Initially the event queue contains site events for the each seed point.
  • Sweep Line: The Introduce a vertical sweep line that moves from the left to right across the diagram. As the sweep line encounters events and it processes them updating the Voronoi diagram.
  • Beach Line: The Maintain a beach line which is a set of the parabolic arcs that represent the boundaries between Voronoi regions.
  • Event Processing: As the sweep line encounters a site event a new arc is inserted into the beach line. As the sweep line encounters a circle event the corresponding arc is removed from beach line.
  • Beach Line Adjustment: The beach line is adjusted based on the events. When a new arc is added due to a site event and it splits an existing arc.
  • Cell Creation: As the sweep line progresses Voronoi cells are constructed based on beach line’s configuration.
  • Output: The Voronoi diagram is the constructed as the sweep line completes its traversal.

Visual Explanation:

Consider a set of seed points in a 2D plane. The blue lines represent the Voronoi edges and each shaded region represents a Voronoi cell corresponding to the seed point.

Screenshot-2023-08-31-210714

the sweep line moves from the left to right and beach line adjusts new Voronoi edges are formed and Voronoi cells are created. The algorithm processes site events and circle events to determine the Voronoi structure.

Voronoi Diagram Using Sweep Line Algorithm:

The Sweep Line algorithm constructs the Voronoi Diagram by the sweeping a vertical line across the plane. As the sweep line encounters events like Voronoi vertices and cell intersections and it updates the Voronoi regions.

Below is the implementation of voronoi diagram using sweep line:

C++




#include <algorithm>
#include <cmath>
#include <iostream>
#include <set>
#include <vector>
 
using namespace std;
struct Point {
    double x, y;
};
 
// Define a region structure to
// represent Voronoi cells
struct Region {
    Point site;
    vector<Point> vertices;
};
// Event structure to handle events in the
// sweep line algorithm
struct GFG {
    Point point;
    int index;
    bool isSite;
    bool operator<(const GFG& other) const
    {
        if (point.x == other.point.x) {
            return (isSite && !other.isSite);
        }
        return point.x < other.point.x;
    }
};
// Function to construct Voronoi Diagram using
// Sweep Line algorithm
vector<Region> voronoiSweepLine(vector<Point>& points)
{
    int n = points.size();
    vector<Region> regions(n);
    // Sort points by their x-coordinates
    sort(points.begin(), points.end(),
        [](const Point& a, const Point& b) {
            return a.x < b.x;
        });
    set<GFG> eventQueue;
    // Initialize the event queue with the input points
    for (int i = 0; i < n; ++i) {
        eventQueue.insert({ points[i], i, true });
    }
    while (!eventQueue.empty()) {
        GFG currentEvent = *eventQueue.begin();
        eventQueue.erase(eventQueue.begin());
 
        if (currentEvent.isSite) {
        }
        else {
            // Handle circle event
            // Update Voronoi regions as the
            // sweep line encounters circle events
        }
    }
    return regions;
}
int main()
{
    // Sample input points
    vector<Point> points
        = { { 2, 5 }, { 4, 5 }, { 7, 2 }, { 5, 7 } };
    // Construct Voronoi Diagram
    vector<Region> voronoiRegions
        = voronoiSweepLine(points);
    // Display Voronoi regions
    for (int i = 0; i < voronoiRegions.size(); ++i) {
        cout << "Voronoi Region #" << i + 1 << ": Site ("
            << voronoiRegions[i].site.x << ", "
            << voronoiRegions[i].site.y << ")" << endl;
        for (const Point& vertex :
            voronoiRegions[i].vertices) {
            cout << "Vertex (" << vertex.x << ", "
                << vertex.y << ")" << endl;
        }
        cout << endl;
    }
    return 0;
}


Java




import java.util.*;
 
// Class to represent a point in 2D space
class Point implements Comparable<Point> {
    double x, y;
 
    public Point(double x, double y) {
        this.x = x;
        this.y = y;
    }
 
    // Implement compareTo method for sorting points
    @Override
    public int compareTo(Point other) {
        return Double.compare(this.x, other.x);
    }
}
 
// Class to represent a Voronoi region
class Region {
    Point site;
    List<Point> vertices;
 
    public Region(Point site, List<Point> vertices) {
        this.site = site;
        this.vertices = vertices;
    }
}
 
// Class to represent an Event during the sweep line algorithm
class Event implements Comparable<Event> {
    Point point;
    int index;
    boolean isSite;
 
    public Event(Point point, int index, boolean isSite) {
        this.point = point;
        this.index = index;
        this.isSite = isSite;
    }
 
    // Custom comparison for event sorting
    @Override
    public int compareTo(Event other) {
        if (this.point.x == other.point.x) {
            return this.isSite ? -1 : 1;
        }
        return Double.compare(this.point.x, other.point.x);
    }
}
 
public class VoronoiSweepLine {
    public static List<Region> voronoiSweepLine(List<Point> points) {
        int n = points.size();
        List<Region> regions = new ArrayList<>();
 
        // Sort points by their x-coordinates
        Collections.sort(points);
 
        TreeSet<Event> eventQueue = new TreeSet<>();
        for (int i = 0; i < n; i++) {
            eventQueue.add(new Event(points.get(i), i, true));
        }
 
        while (!eventQueue.isEmpty()) {
            Event currentEvent = eventQueue.pollFirst();
 
            if (currentEvent.isSite) {
                // Handle site event
                // Implement site event logic here
            } else {
                // Handle circle event
                // Implement circle event logic here
            }
 
            // Add an empty region to the result for demonstration
            regions.add(new Region(new Point(0, 0), new ArrayList<>()));
        }
 
        return regions;
    }
 
    public static void main(String[] args) {
        // Sample input points
        List<Point> points = Arrays.asList(
                new Point(2, 5),
                new Point(4, 5),
                new Point(7, 2),
                new Point(5, 7)
        );
 
        // Construct Voronoi Diagram
        List<Region> voronoiRegions = voronoiSweepLine(points);
 
        // Display Voronoi regions
        for (int i = 0; i < voronoiRegions.size(); i++) {
            Region region = voronoiRegions.get(i);
            System.out.println("Voronoi Region #" + (i + 1) +
                               ": Site (" + region.site.x + ", " + region.site.y + ")");
            for (Point vertex : region.vertices) {
                System.out.println("Vertex (" + vertex.x + ", " + vertex.y + ")");
            }
            System.out.println();
        }
    }
}


Python3




# Python Implementation
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
 
class Region:
    def __init__(self, site, vertices):
        self.site = site
        self.vertices = vertices
 
class Event:
    def __init__(self, point, index, is_site):
        self.point = point
        self.index = index
        self.is_site = is_site
 
    # Custom comparison for event sorting
    def compare_to(self, other):
        if self.point.x == other.point.x:
            return -1 if self.is_site else 1
        return self.point.x - other.point.x
 
def voronoi_sweep_line(points):
    n = len(points)
    regions = [Region(Point(0, 0), []) for _ in range(n)]
 
    # Sort points by their x-coordinates
    points.sort(key=lambda p: (p.x, p.y))
 
    event_queue = set()
 
    # Initialize the event queue with the input points
    for i, point in enumerate(points):
        event_queue.add(Event(point, i, True))
 
    while event_queue:
        # Extract the minimum event from the event queue
        current_event = min(event_queue, key=lambda e: (e.point.x, not e.is_site))
         
        event_queue.remove(current_event)
 
        if current_event.is_site:
            # Handle site event
            pass
        else:
            # Handle circle event
            # Update Voronoi regions as the sweep line encounters circle events
            pass
 
    return regions
 
 
# Sample input points
points = [
    Point(2, 5),
    Point(4, 5),
    Point(7, 2),
    Point(5, 7)
]
 
# Construct Voronoi Diagram
voronoi_regions = voronoi_sweep_line(points)
 
# Display Voronoi regions
for i, region in enumerate(voronoi_regions):
    print(f"Voronoi Region #{i + 1}: Site ({region.site.x}, {region.site.y})")
    for vertex in region.vertices:
        print(f"Vertex ({vertex.x}, {vertex.y})")
    print()
# This code is contributed by Sakshi


C#




using System;
using System.Collections.Generic;
 
// Define a structure for a point in 2D space
public struct Point
{
    public double x, y;
}
 
// Define a structure for a Voronoi region
public struct Region
{
    public Point site; // The site that this region is based on
    public List<Point> vertices; // The vertices of this region
}
 
public class Program
{
    // Function to generate Voronoi regions for a given set of points
    public static List<Region> VoronoiSweepLine(List<Point> points)
    {
        int n = points.Count;
        List<Region> regions = new List<Region>(new Region[n]);
 
        // For each point, create a region with the site at (0, 0)
        for (int i = 0; i < n; ++i)
        {
            Region region = new Region { site = new Point { x = 0, y = 0 }, vertices = new List<Point>() };
            regions[i] = region;
        }
 
        return regions;
    }
 
    public static void Main()
    {
        // Define a list of points
        List<Point> points = new List<Point> { new Point { x = 2, y = 5 }, new Point { x = 4, y = 5 }, new Point { x = 7, y = 2 }, new Point { x = 5, y = 7 } };
         
        // Generate Voronoi regions for the points
        List<Region> voronoiRegions = VoronoiSweepLine(points);
 
        // Print out the Voronoi regions
        for (int i = 0; i < voronoiRegions.Count; ++i)
        {
            Console.WriteLine("Voronoi Region #" + (i + 1) + ": Site (" + voronoiRegions[i].site.x + ", " + voronoiRegions[i].site.y + ")");
            foreach (Point vertex in voronoiRegions[i].vertices)
            {
                Console.WriteLine("Vertex (" + vertex.x + ", " + vertex.y + ")");
            }
            Console.WriteLine();
        }
    }
}


Javascript




// Define a Point structure
class Point {
    constructor(x, y) {
        this.x = x;
        this.y = y;
    }
}
 
// Define a Region structure to
// represent Voronoi cells
class Region {
    constructor(site, vertices) {
        this.site = site;
        this.vertices = vertices;
    }
}
 
// Event structure to handle events
// in the sweep line algorithm
class Event {
    constructor(point, index, isSite) {
        this.point = point;
        this.index = index;
        this.isSite = isSite;
    }
 
    // Custom comparison for event sorting
    compareTo(other) {
        if (this.point.x === other.point.x) {
            return this.isSite ? -1 : 1;
        }
        return this.point.x - other.point.x;
    }
}
 
// Function to construct Voronoi
// Diagram using Sweep Line algorithm
function voronoiSweepLine(points) {
    const n = points.length;
    const regions = new Array(n).fill(null).map(() => new Region(new Point(0, 0), []));
 
    // Sort points by their x-coordinates
    points.sort((a, b) => a.x - b.x);
 
    const eventQueue = new Set();
 
    // Initialize the event queue
    // with the input points
    for (let i = 0; i < n; ++i) {
        eventQueue.add(new Event(points[i], i, true));
    }
 
    while (eventQueue.size > 0) {
        const currentEvent = [...eventQueue][0];
        eventQueue.delete(currentEvent);
 
        if (currentEvent.isSite) {
            // Handle site event
        }
        else {
            // Handle circle event
            // Update Voronoi regions as the
            // sweep line encounters circle events
        }
    }
 
    return regions;
}
 
// Sample input points
const points = [
    new Point(2, 5),
    new Point(4, 5),
    new Point(7, 2),
    new Point(5, 7)
];
 
// Construct Voronoi Diagram
const voronoiRegions = voronoiSweepLine(points);
 
// Display Voronoi regions
for (let i = 0; i < voronoiRegions.length; ++i) {
    console.log(`Voronoi Region #${i + 1}: Site (${voronoiRegions[i].site.x}, ${voronoiRegions[i].site.y})`);
    for (const vertex of voronoiRegions[i].vertices) {
        console.log(`Vertex (${vertex.x}, ${vertex.y})`);
    }
    console.log();
}


Output

Voronoi Region #1: Site (0, 0)

Voronoi Region #2: Site (0, 0)

Voronoi Region #3: Site (0, 0)

Voronoi Region #4: Site (0, 0)




Time Complexity: O(N log N)
Space Complexity: O(N)



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads