function polylabel(polygon, precision, debug) {
precision = precision || 1.0;
if (isNaN(polygon[0][0][0])) {
var bestpoint = polylabel(polygon[0], precision, debug);
for (p = 1; p < polygon.length; p++) {
const thispoint = polylabel(polygon[p], precision, debug);
if (thispoint.distance > bestpoint.distance) {
bestpoint = thispoint;
}
}
return bestpoint;
}
var minX, minY, maxX, maxY;
for (var i = 0; i < polygon[0].length; i++) {
var p = polygon[0][i];
if (!i || p[0] < minX) minX = p[0];
if (!i || p[1] < minY) minY = p[1];
if (!i || p[0] > maxX) maxX = p[0];
if (!i || p[1] > maxY) maxY = p[1];
}
var width = maxX - minX;
var height = maxY - minY;
var cellSize = Math.min(width, height);
var h = cellSize / 2;
if (cellSize === 0) {
var degeneratePoleOfInaccessibility = [minX, minY];
degeneratePoleOfInaccessibility.distance = 0;
return degeneratePoleOfInaccessibility;
}
// a priority queue of cells in order of their "potential" (max distance to polygon)
var cellQueue = new TinyQueue(undefined, compareMax);
// cover polygon with initial cells
for (var x = minX; x < maxX; x += cellSize) {
for (var y = minY; y < maxY; y += cellSize) {
cellQueue.push(new Cell(x + h, y + h, h, polygon));
}
}
// take centroid as the first best guess
var bestCell = getCentroidCell(polygon);
// special case for rectangular polygons
var bboxCell = new Cell(minX + width / 2, minY + height / 2, 0, polygon);
if (bboxCell.d > bestCell.d) bestCell = bboxCell;
var numProbes = cellQueue.length;
while (cellQueue.length) {
// pick the most promising cell from the queue
var cell = cellQueue.pop();
// update the best cell if we found a better one
if (cell.d > bestCell.d) {
bestCell = cell;
if (debug) console.log('found best %d after %d probes', Math.round(1e4 * cell.d) / 1e4, numProbes);
}
// do not drill down further if there's no chance of a better solution
if (cell.max - bestCell.d <= precision) continue;
// split the cell into four cells
h = cell.h / 2;
cellQueue.push(new Cell(cell.x - h, cell.y - h, h, polygon));
cellQueue.push(new Cell(cell.x + h, cell.y - h, h, polygon));
cellQueue.push(new Cell(cell.x - h, cell.y + h, h, polygon));
cellQueue.push(new Cell(cell.x + h, cell.y + h, h, polygon));
numProbes += 4;
}
if (debug) {
console.log('num probes: ' + numProbes);
console.log('best distance: ' + bestCell.d);
console.log('best point: [' + bestCell.x + ', ' + bestCell.y + ']');
console.log(polygon);
}
var poleOfInaccessibility = [bestCell.x, bestCell.y];
poleOfInaccessibility.distance = bestCell.d;
return poleOfInaccessibility;
}