Posted in

How to draw a Delaunay triangulation on a Canvas?

Hey there! As a Canvas supplier, I’ve seen a lot of cool projects using our canvases. One of the most fascinating ones is drawing a Delaunay triangulation on a canvas. In this blog post, I’m gonna share with you how to do just that. Canvas

First off, let’s talk about what a Delaunay triangulation is. It’s a way of dividing a set of points in a plane into a set of non – overlapping triangles. The really cool thing about Delaunay triangulations is that for each triangle, the circumcircle of that triangle doesn’t contain any other points from the set. This property makes it super useful in a bunch of fields, like computer graphics, geographic information systems, and mesh generation.

So, how do we draw a Delaunay triangulation on a canvas? Well, we’ll break it down into a few steps.

Step 1: Set up the Canvas

First, we need to create a canvas element in our HTML file. It’s pretty easy. Just add this code to your HTML:

<canvas id="myCanvas"></canvas>

Then, in our JavaScript file, we’ll grab this canvas and get its 2D context. This context is what we’ll use to draw on the canvas.

const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');

We can also set the width and height of the canvas to fit our needs. For example:

canvas.width = window.innerWidth;
canvas.height = window.innerHeight;

Step 2: Generate Random Points

We need a set of points to create our Delaunay triangulation. A simple way to do this is to generate random points within the boundaries of the canvas.

const numPoints = 50;
const points = [];

for (let i = 0; i < numPoints; i++) {
    const x = Math.random() * canvas.width;
    const y = Math.random() * canvas.height;
    points.push({ x, y });
}

Step 3: Implement the Delaunay Triangulation Algorithm

There are a few different algorithms to calculate the Delaunay triangulation. One of the most common ones is the Bowyer – Watson algorithm.

The basic idea of the Bowyer – Watson algorithm is to start with a super – triangle that contains all the points. Then, we insert each point one by one into the triangulation. When we insert a point, we find all the triangles whose circumcircles contain the new point. We remove these triangles, which creates a cavity. Then, we connect the new point to the vertices of the cavity to form new triangles.

Here’s a simplified JavaScript implementation of the Bowyer – Watson algorithm:

function circumcircle(p1, p2, p3) {
    const A = p2.x - p1.x;
    const B = p2.y - p1.y;
    const C = p3.x - p1.x;
    const D = p3.y - p1.y;
    const E = A * (p1.x + p2.x) + B * (p1.y + p2.y);
    const F = C * (p1.x + p3.x) + D * (p1.y + p3.y);
    const G = 2 * (A * (p3.y - p2.y) - B * (p3.x - p2.x));
    const centerX = (D * E - B * F) / G;
    const centerY = (A * F - C * E) / G;
    const radius = Math.sqrt((p1.x - centerX) ** 2 + (p1.y - centerY) ** 2);
    return { centerX, centerY, radius };
}

function isPointInCircumcircle(p, c) {
    return Math.sqrt((p.x - c.centerX) ** 2 + (p.y - c.centerY) ** 2) <= c.radius;
}

function delaunayTriangulation(points) {
    const superTriangle = {
        p1: { x: -1000, y: -1000 },
        p2: { x: 3000, y: -1000 },
        p3: { x: 1000, y: 3000 }
    };
    let triangles = [superTriangle];

    for (let point of points) {
        const badTriangles = [];
        for (let triangle of triangles) {
            const c = circumcircle(triangle.p1, triangle.p2, triangle.p3);
            if (isPointInCircumcircle(point, c)) {
                badTriangles.push(triangle);
            }
        }

        const polygon = [];
        for (let triangle of badTriangles) {
            for (let edge of [
                [triangle.p1, triangle.p2],
                [triangle.p2, triangle.p3],
                [triangle.p3, triangle.p1]
            ]) {
                let isShared = false;
                for (let otherTriangle of badTriangles) {
                    if (otherTriangle!== triangle) {
                        if (
                            (otherTriangle.p1 === edge[0] && otherTriangle.p2 === edge[1]) ||
                            (otherTriangle.p2 === edge[0] && otherTriangle.p3 === edge[1]) ||
                            (otherTriangle.p3 === edge[0] && otherTriangle.p1 === edge[1])
                        ) {
                            isShared = true;
                            break;
                        }
                    }
                }
                if (!isShared) {
                    polygon.push(edge);
                }
            }
        }

        for (let badTriangle of badTriangles) {
            const index = triangles.indexOf(badTriangle);
            triangles.splice(index, 1);
        }

        for (let edge of polygon) {
            const newTriangle = {
                p1: edge[0],
                p2: edge[1],
                p3: point
            };
            triangles.push(newTriangle);
        }
    }

    const finalTriangles = [];
    for (let triangle of triangles) {
        if (
            triangle.p1!== superTriangle.p1 &&
            triangle.p1!== superTriangle.p2 &&
            triangle.p1!== superTriangle.p3 &&
            triangle.p2!== superTriangle.p1 &&
            triangle.p2!== superTriangle.p2 &&
            triangle.p2!== superTriangle.p3 &&
            triangle.p3!== superTriangle.p1 &&
            triangle.p3!== superTriangle.p2 &&
            triangle.p3!== superTriangle.p3
        ) {
            finalTriangles.push(triangle);
        }
    }

    return finalTriangles;
}

const triangles = delaunayTriangulation(points);

Step 4: Draw the Triangles on the Canvas

Now that we have our Delaunay triangulation, we can draw the triangles on the canvas.

ctx.strokeStyle = 'black';
ctx.lineWidth = 1;

for (let triangle of triangles) {
    ctx.beginPath();
    ctx.moveTo(triangle.p1.x, triangle.p1.y);
    ctx.lineTo(triangle.p2.x, triangle.p2.y);
    ctx.lineTo(triangle.p3.x, triangle.p3.y);
    ctx.closePath();
    ctx.stroke();
}

And that’s it! We’ve successfully drawn a Delaunay triangulation on a canvas.

If you’re looking to create more complex and interactive Delaunay triangulation projects, our high – quality canvases are the perfect choice. Our canvases offer great resolution and smooth drawing capabilities, which are essential for detailed graphics like Delaunay triangulations. Whether you’re a professional developer, a hobbyist, or an artist, our canvases can meet your needs.

Embroidery Lace If you’re interested in purchasing our canvases for your next project, don’t hesitate to reach out. We’re always happy to have a chat about your requirements and help you choose the right canvas for your specific use case. Contact us to start the procurement process and let’s create some amazing things together!

References

  • Computational Geometry: Algorithms and Applications by Mark de Berg, Otfried Cheong, Marc van Kreveld, and Mark Overmars.
  • "The Bowyer – Watson Algorithm" on Wikipedia.

Shandong Shengrun Textile Co., Ltd.
With over 15 years of experience, Shandong Shengrun Textile Co., Ltd. is one of the most professional canvas manufacturers and suppliers in China. Please rest assured to buy or wholesale durable canvas in stock here from our factory.
Address: 9th Floor, Hui Ji Business Tower, Ren Cheng District, Ji Ning, Shan Dong, China
E-mail: liang@shengrungroup.com
WebSite: https://www.shengruntextile.com/