Skip to content

Commit 85fcbdb

Browse files
committed
Apply mapbox#49
1 parent 6854a05 commit 85fcbdb

File tree

1 file changed

+37
-19
lines changed

1 file changed

+37
-19
lines changed

polylabel.js

Lines changed: 37 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,25 @@ var Queue = require('tinyqueue');
55
module.exports = polylabel;
66
module.exports.default = polylabel;
77

8+
function getFitnessFunc(centroid, polygonSize) {
9+
var maxSize = Math.max(polygonSize[0], polygonSize[1]);
10+
11+
return (function (cellCenter, distancePolygon) {
12+
if (distancePolygon <= 0) {
13+
return distancePolygon;
14+
}
15+
16+
var d = [
17+
cellCenter[0] - centroid[0],
18+
cellCenter[1] - centroid[1]
19+
];
20+
21+
var distanceCentroid = Math.sqrt((d[0] * d[0]) + (d[1] * d[1]));
22+
23+
return distancePolygon * (1 - distanceCentroid / maxSize);
24+
});
25+
}
26+
827
function polylabel(polygon, precision, debug) {
928
precision = precision || 1.0;
1029

@@ -26,21 +45,20 @@ function polylabel(polygon, precision, debug) {
2645
if (cellSize === 0) return [minX, minY];
2746

2847
// a priority queue of cells in order of their "potential" (max distance to polygon)
29-
var cellQueue = new Queue(undefined, compareMax);
48+
var cellQueue = new Queue(null, compareMax);
49+
50+
var centroid = getCentroid(polygon);
51+
var fitnessFunc = getFitnessFunc(centroid, [width, height]);
3052

3153
// cover polygon with initial cells
3254
for (var x = minX; x < maxX; x += cellSize) {
3355
for (var y = minY; y < maxY; y += cellSize) {
34-
cellQueue.push(new Cell(x + h, y + h, h, polygon));
56+
cellQueue.push(new Cell(x + h, y + h, h, polygon, fitnessFunc));
3557
}
3658
}
3759

3860
// take centroid as the first best guess
39-
var bestCell = getCentroidCell(polygon);
40-
41-
// special case for rectangular polygons
42-
var bboxCell = new Cell(minX + width / 2, minY + height / 2, 0, polygon);
43-
if (bboxCell.d > bestCell.d) bestCell = bboxCell;
61+
var bestCell = new Cell(centroid[0], centroid[1], 0, polygon, fitnessFunc);
4462

4563
var numProbes = cellQueue.length;
4664

@@ -49,20 +67,20 @@ function polylabel(polygon, precision, debug) {
4967
var cell = cellQueue.pop();
5068

5169
// update the best cell if we found a better one
52-
if (cell.d > bestCell.d) {
70+
if (cell.fitness > bestCell.fitness) {
5371
bestCell = cell;
5472
if (debug) console.log('found best %d after %d probes', Math.round(1e4 * cell.d) / 1e4, numProbes);
5573
}
5674

5775
// do not drill down further if there's no chance of a better solution
58-
if (cell.max - bestCell.d <= precision) continue;
76+
if (cell.maxFitness - bestCell.fitness <= precision) continue;
5977

6078
// split the cell into four cells
6179
h = cell.h / 2;
62-
cellQueue.push(new Cell(cell.x - h, cell.y - h, h, polygon));
63-
cellQueue.push(new Cell(cell.x + h, cell.y - h, h, polygon));
64-
cellQueue.push(new Cell(cell.x - h, cell.y + h, h, polygon));
65-
cellQueue.push(new Cell(cell.x + h, cell.y + h, h, polygon));
80+
cellQueue.push(new Cell(cell.x - h, cell.y - h, h, polygon, fitnessFunc));
81+
cellQueue.push(new Cell(cell.x + h, cell.y - h, h, polygon, fitnessFunc));
82+
cellQueue.push(new Cell(cell.x - h, cell.y + h, h, polygon, fitnessFunc));
83+
cellQueue.push(new Cell(cell.x + h, cell.y + h, h, polygon, fitnessFunc));
6684
numProbes += 4;
6785
}
6886

@@ -75,15 +93,16 @@ function polylabel(polygon, precision, debug) {
7593
}
7694

7795
function compareMax(a, b) {
78-
return b.max - a.max;
96+
return b.maxFitness - a.maxFitness;
7997
}
8098

81-
function Cell(x, y, h, polygon) {
99+
function Cell(x, y, h, polygon, fitnessFunc) {
82100
this.x = x; // cell center x
83101
this.y = y; // cell center y
84102
this.h = h; // half the cell size
85103
this.d = pointToPolygonDist(x, y, polygon); // distance from cell center to polygon
86-
this.max = this.d + this.h * Math.SQRT2; // max distance to polygon within a cell
104+
this.fitness = fitnessFunc([x, y], this.d);
105+
this.maxFitness = fitnessFunc([x, y], this.d + this.h * Math.SQRT2); // max distance to polygon within a cell
87106
}
88107

89108
// signed distance from point to polygon outline (negative if point is outside)
@@ -109,7 +128,7 @@ function pointToPolygonDist(x, y, polygon) {
109128
}
110129

111130
// get polygon centroid
112-
function getCentroidCell(polygon) {
131+
function getCentroid(polygon) {
113132
var area = 0;
114133
var x = 0;
115134
var y = 0;
@@ -123,8 +142,7 @@ function getCentroidCell(polygon) {
123142
y += (a[1] + b[1]) * f;
124143
area += f * 3;
125144
}
126-
if (area === 0) return new Cell(points[0][0], points[0][1], 0, polygon);
127-
return new Cell(x / area, y / area, 0, polygon);
145+
return (area === 0) ? points[0] : [x / area, y / area];
128146
}
129147

130148
// get squared distance from a point to a segment

0 commit comments

Comments
 (0)