Skip to content

Commit ed542a8

Browse files
committed
First attempt at gravitating to centroid. Closes mapbox#49
1 parent cfa297f commit ed542a8

File tree

1 file changed

+28
-12
lines changed

1 file changed

+28
-12
lines changed

polylabel.js

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@ if (Queue.default) Queue = Queue.default; // temporary webpack fix
77
module.exports = polylabel;
88
module.exports.default = polylabel;
99

10-
function polylabel(polygon, precision, debug) {
10+
function polylabel(polygon, precision, debug, centroidWeight) {
1111
precision = precision || 1.0;
12+
centroidWeight = centroidWeight || 0;
1213

1314
// find the bounding box of the outer ring
1415
var minX, minY, maxX, maxY;
@@ -34,19 +35,26 @@ function polylabel(polygon, precision, debug) {
3435
// a priority queue of cells in order of their "potential" (max distance to polygon)
3536
var cellQueue = new Queue(undefined, compareMax);
3637

38+
var centroidCell = getCentroidCell(polygon);
39+
40+
// take centroid as the first best guess
41+
var bestCell = centroidCell;
42+
3743
// cover polygon with initial cells
3844
for (var x = minX; x < maxX; x += cellSize) {
3945
for (var y = minY; y < maxY; y += cellSize) {
40-
cellQueue.push(new Cell(x + h, y + h, h, polygon));
46+
cellQueue.push(new Cell(x + h, y + h, h, polygon, centroidCell));
4147
}
4248
}
4349

44-
// take centroid as the first best guess
45-
var bestCell = getCentroidCell(polygon);
50+
// the fitness function to be maximized
51+
function fitness(cell) {
52+
return cell.d - cell.distanceToCentroid * centroidWeight;
53+
}
4654

4755
// special case for rectangular polygons
48-
var bboxCell = new Cell(minX + width / 2, minY + height / 2, 0, polygon);
49-
if (bboxCell.d > bestCell.d) bestCell = bboxCell;
56+
var bboxCell = new Cell(minX + width / 2, minY + height / 2, 0, polygon, centroidCell);
57+
if (fitness(bboxCell) > fitness(bestCell)) bestCell = bboxCell;
5058

5159
var numProbes = cellQueue.length;
5260

@@ -55,7 +63,7 @@ function polylabel(polygon, precision, debug) {
5563
var cell = cellQueue.pop();
5664

5765
// update the best cell if we found a better one
58-
if (cell.d > bestCell.d) {
66+
if (fitness(cell) > fitness(bestCell)) {
5967
bestCell = cell;
6068
if (debug) console.log('found best %d after %d probes', Math.round(1e4 * cell.d) / 1e4, numProbes);
6169
}
@@ -65,10 +73,10 @@ function polylabel(polygon, precision, debug) {
6573

6674
// split the cell into four cells
6775
h = cell.h / 2;
68-
cellQueue.push(new Cell(cell.x - h, cell.y - h, h, polygon));
69-
cellQueue.push(new Cell(cell.x + h, cell.y - h, h, polygon));
70-
cellQueue.push(new Cell(cell.x - h, cell.y + h, h, polygon));
71-
cellQueue.push(new Cell(cell.x + h, cell.y + h, h, polygon));
76+
cellQueue.push(new Cell(cell.x - h, cell.y - h, h, polygon, centroidCell));
77+
cellQueue.push(new Cell(cell.x + h, cell.y - h, h, polygon, centroidCell));
78+
cellQueue.push(new Cell(cell.x - h, cell.y + h, h, polygon, centroidCell));
79+
cellQueue.push(new Cell(cell.x + h, cell.y + h, h, polygon, centroidCell));
7280
numProbes += 4;
7381
}
7482

@@ -86,14 +94,22 @@ function compareMax(a, b) {
8694
return b.max - a.max;
8795
}
8896

89-
function Cell(x, y, h, polygon) {
97+
function Cell(x, y, h, polygon, centroidCell) {
9098
this.x = x; // cell center x
9199
this.y = y; // cell center y
92100
this.h = h; // half the cell size
93101
this.d = pointToPolygonDist(x, y, polygon); // distance from cell center to polygon
102+
this.distanceToCentroid = centroidCell ? pointToPointDist(this, centroidCell) : 0;
94103
this.max = this.d + this.h * Math.SQRT2; // max distance to polygon within a cell
95104
}
96105

106+
// distance between two cells
107+
function pointToPointDist(cellA, cellB) {
108+
var dx = cellB.x - cellA.x;
109+
var dy = cellB.y - cellA.y;
110+
return Math.sqrt(dx * dx + dy * dy);
111+
}
112+
97113
// signed distance from point to polygon outline (negative if point is outside)
98114
function pointToPolygonDist(x, y, polygon) {
99115
var inside = false;

0 commit comments

Comments
 (0)