Open In App

Java Program to Apply Delaunay Triangulation Algorithm

Last Updated : 19 Mar, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

Computational geometry to triangulate a set of points in a plane or in higher dimensions is not an easy task but we can perform this using Delaunay Triangulation Algorithm. Let us apply Delaunay Triangulation Algorithm in this article.

What is Delaunay Triangulation Algorithm?

Delaunay triangulation is a fundamental concept in computational geometry that has a wide range of applications, including computer graphics, finite element analysis, surface reconstruction, and mesh generation. The algorithm is named after Boris Delaunay, a Russian mathematician who first introduced the concept in 1934.

The Delaunay triangulation algorithm starts by taking a set of points in a plane and connecting them with a series of triangles. The triangulation is generated in a way that ensures that no point is inside the circumcircle of any triangle. This property is known as the Delaunay criterion, and it is a necessary and sufficient condition for a triangulation to be a Delaunay triangulation.

One of the key benefits of the Delaunay triangulation algorithm is that it ensures that the minimum angle of all triangles is maximized. This property is essential for applications that require accurate interpolation and geometric computation. A Delaunay triangulation has the property that the ratio of the circumradius to the shortest edge is minimized, making the triangles as close to equilateral as possible.

There are several algorithms for computing Delaunay triangulations, including divide and conquer, incremental, and sweep line algorithms. The choice of algorithm depends on the specific application and the size and complexity of the input point set.

Overall, Delaunay triangulation is a powerful algorithm that plays a critical role in many areas of computational geometry and has numerous practical applications in various fields.

The approach of the Algorithm

The algorithm works by connecting points with edges to form a mesh, which is then refined by iteratively flipping edges that violate the Delaunay condition. The Delaunay condition ensures that the circumcircles of all triangles in the mesh are empty of other points. The algorithm terminates when no more edge flips can be performed.

The resulting triangulation is unique and has some desirable properties, such as being a planar graph and having a low aspect ratio. The Delaunay triangulation has many applications in computational geometry, including mesh generation, finite element analysis, and computer graphics. It can be computed efficiently in O(n log n) time using algorithms such as divide and conquer or incremental construction.

Uses of Delaunay Triangulation algorithm 

Delaunay triangulation algorithm is mainly used in computational geometry to triangulate a set of points in a plane or in higher dimensions. The triangulation is such that it satisfies the Delaunay condition, which guarantees that the minimum angle of all triangles is maximized and that no point is inside the circumcircle of any triangle.

Delaunay triangulation has many applications in various fields, few of them are mentioned below:

  • Computer graphics: Delaunay triangulation is used to generate high-quality meshes for rendering 3D graphics and animations.
  • Geographic information systems (GIS): Delaunay triangulation is used to generate terrain models and contour maps from elevation data.
  • Finite element analysis (FEA): Delaunay triangulation is used to discretize a domain for numerical simulation in FEA.
  • Image processing: Delaunay triangulation is used for image registration and alignment.
  • Mesh generation: Delaunay triangulation is used to generate meshes for computational fluid dynamics (CFD) and other engineering simulations.

Below is the example Java code which illustrates the Delaunay Triangulation algorithm:

Java




// Java program to illustrate Delaunay Triangulation
// algorithm
import java.util.*;
 
//  Driver Class
public class DelaunayTriangulation {
 
    private static final double EPSILON = 1e-12;
 
    // structure to store the edge of the triangulation
    static class Edge {
        int a, b;
 
        Edge(int a, int b)
        {
            this.a = a;
            this.b = b;
        }
    }
 
    // structure to store the point in 2D space
    static class Point {
        double x, y;
 
        Point(double x, double y)
        {
            this.x = x;
            this.y = y;
        }
    }
 
    // function to calculate the cross product of two
    // vectors
    private static double crossProduct(Point A, Point B)
    {
        return A.x * B.y - A.y * B.x;
    }
 
    // function to check if the point P is inside the circle
    // defined by points A, B, and C
    private static boolean insideCircle(Point A, Point B,
                                        Point C, Point P)
    {
        double ax = A.x - P.x;
        double ay = A.y - P.y;
        double bx = B.x - P.x;
        double by = B.y - P.y;
        double cx = C.x - P.x;
        double cy = C.y - P.y;
 
        double a2 = ax * ax + ay * ay;
        double b2 = bx * bx + by * by;
        double c2 = cx * cx + cy * cy;
 
        return (ax * (by - cy) + bx * (cy - ay)
                + cx * (ay - by))
            >= EPSILON;
    }
 
    // main function to perform Delaunay triangulation
    public static List<Edge> triangulate(Point[] points)
    {
        int n = points.length;
        List<Edge> edges = new ArrayList<>();
 
        // sorting the points by x-coordinate
        Point[] sorted = new Point[n];
        for (int i = 0; i < n; i++) {
            sorted[i] = points[i];
        }
        sorted = sortByX(sorted, 0, n - 1);
 
        // creating the lower hull
        for (int i = 0; i < n; i++) {
            while (edges.size() >= 2) {
                int j = edges.size() - 2;
                int k = edges.size() - 1;
                Point A = sorted[edges.get(j).a];
                Point B = sorted[edges.get(j).b];
                Point C = sorted[edges.get(k).b];
 
                if (crossProduct(
                        new Point(B.x - A.x, B.y - A.y),
                        new Point(C.x - B.x, C.y - B.y))
                    > 0) {
                    break;
                }
 
                edges.remove(edges.size() - 1);
            }
            edges.add(new Edge(edges.size(), i));
        }
        int lower = edges.size();
        // creating the upper hull
        for (int i = n - 2, t = lower + 1; i >= 0; i--) {
            while (edges.size() >= t) {
                int j = edges.size() - 2;
                int k = edges.size() - 1;
                Point A = sorted[edges.get(j).a];
                Point B = sorted[edges.get(j).b];
                Point C = sorted[edges.get(k).b];
 
                if (crossProduct(
                        new Point(B.x - A.x, B.y - A.y),
                        new Point(C.x - B.x, C.y - B.y))
                    > 0) {
                    break;
                }
 
                edges.remove(edges.size() - 1);
            }
            edges.add(new Edge(i, edges.size()));
        }
 
        // removing the duplicate edges from the hull
        edges.remove(edges.size() - 1);
 
        // creating the triangulation
        List<Edge> result = new ArrayList<>();
        for (int i = 0; i < edges.size(); i++) {
            int a = edges.get(i).a;
            int b = edges.get(i).b;
            Point A = sorted[a];
            Point B = sorted[b];
            boolean flag = true;
 
            for (int j = 0; j < n; j++) {
                if (j == a || j == b) {
                    continue;
                }
                Point P = sorted[j];
                if (insideCircle(A, B, P,
                                 sorted[a + b >> 1])) {
                    flag = false;
                    break;
                }
            }
            if (flag) {
                result.add(new Edge(a, b));
            }
        }
 
        return result;
    }
 
    // function to sort the points by x-coordinate
    private static Point[] sortByX(Point[] points,
                                   int start, int end)
    {
        if (start >= end) {
            return points;
        }
        int pivot = partition(points, start, end);
        sortByX(points, start, pivot - 1);
        sortByX(points, pivot + 1, end);
        return points;
    }
 
    // function to partition the points for quick sort
    private static int partition(Point[] points, int start,
                                 int end)
    {
        Point pivot = points[end];
        int i = start - 1;
        for (int j = start; j <= end - 1; j++) {
            if (points[j].x <= pivot.x) {
                i++;
                Point temp = points[i];
                points[i] = points[j];
                points[j] = temp;
            }
        }
        Point temp = points[i + 1];
        points[i + 1] = points[end];
        points[end] = temp;
        return i + 1;
    }
 
    // Main function
    public static void main(String[] args)
    {
        // Using Scanner for input
        Scanner sc = new Scanner(System.in);
        System.out.println("Enter the no. of coordinates:");
 
        int x, y, n = 0;
        n = sc.nextInt();
 
        // array created
        Point[] points = new Point[n];
 
        // Input coordinates
        for (int i = 0; i < n; i++) {
            System.out.println("Enter Coordinate No."
                               + " " + (i + 1));
            x = sc.nextInt();
            y = sc.nextInt();
            points[i] = new Point(x, y);
        }
 
        // List declared
        List<Edge> edges = triangulate(points);
        System.out.println("Triangulated Edges:");
 
        for (Edge edge : edges) {
            System.out.println(edge.a + " - " + edge.b);
        }
    }
}


Input:

Input of Coordinates

Output:

The output of Triangulated Edges

Explanation of the Program

The class defines two data structures – Point and Edge. A point is a structure that holds a pair of coordinates (x,y), and Edge holds two indices of the points forming the edge of the triangulation.

The main function of the class is triangulated, which takes an array of Point objects as input and returns a list of Edge objects representing the triangulation.

The implementation first sorts the array of points by x-coordinate. It then constructs the lower and upper hulls of the points using an iterative process, similar to the Graham scan algorithm for computing the convex hull of a set of points. After constructing the hulls, it removes duplicate edges from the hull, and finally, it creates the triangulation by checking for every edge if it should be included in the triangulation. An edge should be included if no other point is inside the circumcircle of the triangle formed by that edge and any other edge connected to the same endpoints. Two auxiliary functions, named as crossProduct to calculate the cross product of two vectors, and insideCircle to check if a point is inside the circumcircle of a triangle were implemented in this class.



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads