in src/core/MathUtils.js [110:237]
static getDelaunayTriangulation(vertices) {
if (!vertices || vertices.length < 3) {
throw new Error(
`Cannot get delaunay triangulation for points ${vertices}. Input must contain at least three points.`
);
}
let minX = Number.POSITIVE_INFINITY;
let minY = Number.POSITIVE_INFINITY;
let maxX = Number.NEGATIVE_INFINITY;
let maxY = Number.NEGATIVE_INFINITY;
vertices.forEach(v => {
minX = v[0] < minX ? v[0] : minX;
minY = v[1] < minY ? v[1] : minY;
maxX = v[0] > maxX ? v[0] : maxX;
maxY = v[1] > maxY ? v[1] : maxY;
});
const dX = maxX - minX;
const dY = maxY - minY;
const midX = (minX + maxX) / 2;
const midY = (minY + maxY) / 2;
const dMax = dX > dY ? dX : dY;
const superIndices = [
vertices.length,
vertices.length + 1,
vertices.length + 2,
];
const vertsWithSuper = [
...vertices,
[midX - 20 * dMax, midY - dMax],
[midX, midY + 20 * dMax],
[midX + 20 * dMax, midY - dMax],
];
const superSortedIndices = MathUtils.sortPointsCCW(
superIndices,
vertsWithSuper
);
const superTriangle = {
indices: superSortedIndices,
edges: [
[superSortedIndices[0], superSortedIndices[1]],
[superSortedIndices[1], superSortedIndices[2]],
[superSortedIndices[2], superSortedIndices[0]],
],
};
const triangles = [superTriangle];
vertsWithSuper.forEach((newVert, newIndex) => {
const invalidTriangles = [];
triangles.forEach(triangle => {
if (
MathUtils.isPointInCircumCircle(
vertsWithSuper[triangle.indices[0]],
vertsWithSuper[triangle.indices[1]],
vertsWithSuper[triangle.indices[2]],
newVert
)
) {
invalidTriangles.push(triangle);
}
});
const boundingPoly = [];
invalidTriangles.forEach(triangle => {
triangle.edges.forEach(edge => {
let count = 0;
invalidTriangles.forEach(otherTriangle => {
if (triangle !== otherTriangle) {
otherTriangle.edges.forEach(otherEdge => {
if (
(edge[0] === otherEdge[0] && edge[1] === otherEdge[1]) ||
(edge[1] === otherEdge[0] && edge[0] === otherEdge[1])
) {
count += 1;
}
});
}
});
if (count === 0) boundingPoly.push(edge);
});
});
invalidTriangles.forEach(triangle => {
triangles.splice(triangles.indexOf(triangle), 1);
});
boundingPoly.forEach(edge => {
const sortedIndices = MathUtils.sortPointsCCW(
[edge[0], edge[1], newIndex],
vertsWithSuper
);
triangles.push({
indices: sortedIndices,
edges: [
[sortedIndices[0], sortedIndices[1]],
[sortedIndices[1], sortedIndices[2]],
[sortedIndices[2], sortedIndices[0]],
],
});
});
});
const trianglesToRemove = [];
triangles.forEach(triangle => {
triangle.indices.forEach(index => {
if (superIndices.includes(index)) {
trianglesToRemove.push(triangle);
}
});
});
trianglesToRemove.forEach(triangle => {
const index = triangles.indexOf(triangle);
if (index !== -1) {
triangles.splice(index, 1);
}
});
return triangles.map(triangle => triangle.indices);
}