UNPKG

voronator

Version:

Compute the Voronoi diagram of a set of two-dimensional points.

106 lines (99 loc) 3.56 kB
import Cell from "./cell.js"; import Delaunator from "delaunator"; import Voronoi from "./voronoi.js"; export default class Delaunay { constructor(points, halfedges, hull, triangles) { this.points = points; this.halfedges = halfedges; this.hull = hull; this.triangles = triangles; } voronoi([xmin, ymin, xmax, ymax] = [0, 0, 960, 500]) { const {points, halfedges, hull, triangles} = this; const cells = new Array(points.length / 2); const circumcenters = new Float64Array(triangles.length / 3 * 2); const voronoi = new Voronoi(cells, circumcenters, this, xmin, ymin, xmax, ymax); // Compute cell topology. for (let i = 0, n = cells.length; i < n; ++i) { cells[i] = new Cell(voronoi); } for (let i = 0, m = halfedges.length; i < m; ++i) { cells[triangles[i]]._connect(Math.floor(i / 3), Math.floor(halfedges[i] / 3)); } for (let i = 0, n = cells.length; i < n; ++i) { const cell = cells[i]; cell.triangles = cell.triangles.length === 1 ? cell.triangles[0] : null; } // Compute circumcenters. for (let i = 0, j = 0, n = triangles.length; i < n; i += 3, j += 2) { const t1 = triangles[i] * 2; const t2 = triangles[i + 1] * 2; const t3 = triangles[i + 2] * 2; const x1 = points[t1]; const y1 = points[t1 + 1]; const x2 = points[t2]; const y2 = points[t2 + 1]; const x3 = points[t3]; const y3 = points[t3 + 1]; const a2 = x1 - x2; const a3 = x1 - x3; const b2 = y1 - y2; const b3 = y1 - y3; const d1 = x1 * x1 + y1 * y1; const d2 = d1 - x2 * x2 - y2 * y2; const d3 = d1 - x3 * x3 - y3 * y3; const ab = (a3 * b2 - a2 * b3) * 2; circumcenters[j] = (b2 * d3 - b3 * d2) / ab; circumcenters[j + 1] = (a3 * d2 - a2 * d3) / ab; } // Compute exterior cell rays. { let node = hull; do { const {x: x1, y: y1, t: i, next: {x: x2, y: y2, t: j}} = node; const ci = Math.floor(i / 3) * 2; const cx = circumcenters[ci]; const cy = circumcenters[ci + 1]; const dx = (x1 + x2) / 2 - cx; const dy = (y1 + y2) / 2 - cy; const k = (x2 - x1) * (cy - y1) > (y2 - y1) * (cx - x1) ? -1 : 1; cells[triangles[i]].vn = cells[triangles[j]].v0 = [k * dx, k * dy]; } while ((node = node.next) !== hull); } return voronoi; } render(context) { const {points, halfedges, triangles} = this; for (let i = 0, n = halfedges.length; i < n; ++i) { const j = halfedges[i]; if (j < i) continue; const ti = triangles[i] * 2; const tj = triangles[j] * 2; context.moveTo(points[ti], points[ti + 1]); context.lineTo(points[tj], points[tj + 1]); } this.renderHull(context); } renderHull(context) { const {hull} = this; let node = hull; do { context.moveTo(node.x, node.y); context.lineTo(node.next.x, node.next.y); } while ((node = node.next) !== hull); } renderTriangle(i, context) { const {points, triangles} = this; const t0 = triangles[i *= 3] * 2; const t1 = triangles[i + 1] * 2; const t2 = triangles[i + 2] * 2; context.moveTo(points[t0], points[t0 + 1]); context.lineTo(points[t1], points[t1 + 1]); context.lineTo(points[t2], points[t2 + 1]); context.closePath(); } } Delaunay.from = function(points, fx, fy) { const {coords, halfedges, hull, triangles} = new Delaunator(points, fx, fy); return new Delaunay(coords, halfedges, hull, triangles); };