mirror of
https://github.com/placeAtlas/atlas.git
synced 2024-12-28 07:14:42 +01:00
Added algorithm customizations
This commit is contained in:
parent
53a92f29c3
commit
1e52cdaa95
2 changed files with 28 additions and 16 deletions
|
@ -229,8 +229,8 @@ window.initDraw = function(){
|
||||||
|
|
||||||
|
|
||||||
function calculateCenter(path){
|
function calculateCenter(path){
|
||||||
let result = polylabel(path)
|
let result = polylabel(path, 0.5, true)
|
||||||
return [Math.floor(result[0]) + 0.5, Math.floor(result[1]) + 0.5]
|
return [Math.floor(result[0]) + 0.5, Math.floor(result[1]) + 0.5]
|
||||||
}
|
}
|
||||||
|
|
||||||
function undo(){
|
function undo(){
|
||||||
|
|
|
@ -5,7 +5,7 @@ import TinyQueue from 'https://cdn.jsdelivr.net/npm/tinyqueue@2.0.3/index.min.js
|
||||||
if (TinyQueue.default) TinyQueue = TinyQueue.default; // temporary webpack fix
|
if (TinyQueue.default) TinyQueue = TinyQueue.default; // temporary webpack fix
|
||||||
|
|
||||||
export default function polylabel(polygon, precision, debug) {
|
export default function polylabel(polygon, precision, debug) {
|
||||||
precision = precision || 1.0;
|
precision = precision || 0.5;
|
||||||
|
|
||||||
// find the bounding box of the outer ring
|
// find the bounding box of the outer ring
|
||||||
var minX, minY, maxX, maxY;
|
var minX, minY, maxX, maxY;
|
||||||
|
@ -31,28 +31,34 @@ export default function polylabel(polygon, precision, debug) {
|
||||||
// a priority queue of cells in order of their "potential" (max distance to polygon)
|
// a priority queue of cells in order of their "potential" (max distance to polygon)
|
||||||
var cellQueue = new TinyQueue(undefined, compareMax);
|
var cellQueue = new TinyQueue(undefined, compareMax);
|
||||||
|
|
||||||
|
let centroid = getCentroid(polygon);
|
||||||
|
|
||||||
// cover polygon with initial cells
|
// cover polygon with initial cells
|
||||||
for (var x = minX; x < maxX; x += cellSize) {
|
for (var x = minX; x < maxX; x += cellSize) {
|
||||||
for (var y = minY; y < maxY; y += cellSize) {
|
for (var y = minY; y < maxY; y += cellSize) {
|
||||||
cellQueue.push(new Cell(x + h, y + h, h, polygon));
|
cellQueue.push(new Cell(x + h, y + h, h, polygon, centroid));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// take centroid as the first best guess
|
// take centroid as the first best guess
|
||||||
var bestCell = getCentroidCell(polygon);
|
var bestCell = getCentroidCell(centroid, polygon);
|
||||||
|
|
||||||
// second guess: bounding box centroid
|
// second guess: bounding box centroid
|
||||||
var bboxCell = new Cell(minX + width / 2, minY + height / 2, 0, polygon);
|
var bboxCell = new Cell(minX + width / 2, minY + height / 2, 0, polygon, centroid);
|
||||||
if (bboxCell.d > bestCell.d) bestCell = bboxCell;
|
if (bboxCell.d > bestCell.d) bestCell = bboxCell;
|
||||||
|
|
||||||
var numProbes = cellQueue.length;
|
var numProbes = cellQueue.length;
|
||||||
|
let threshold = Math.log10(cellSize) / 3.0
|
||||||
|
|
||||||
while (cellQueue.length) {
|
while (cellQueue.length) {
|
||||||
// pick the most promising cell from the queue
|
// pick the most promising cell from the queue
|
||||||
var cell = cellQueue.pop();
|
var cell = cellQueue.pop();
|
||||||
|
|
||||||
// update the best cell if we found a better one
|
// update the best cell if we found a better one
|
||||||
if (cell.d > bestCell.d) {
|
if (cell.d > bestCell.d || (
|
||||||
|
cell.centerDist < bestCell.centerDist &&
|
||||||
|
cell.d > bestCell.d - threshold
|
||||||
|
)) {
|
||||||
bestCell = cell;
|
bestCell = cell;
|
||||||
if (debug) console.log('found best %f after %d probes', Math.round(1e4 * cell.d) / 1e4, numProbes);
|
if (debug) console.log('found best %f after %d probes', Math.round(1e4 * cell.d) / 1e4, numProbes);
|
||||||
}
|
}
|
||||||
|
@ -62,10 +68,10 @@ export default function polylabel(polygon, precision, debug) {
|
||||||
|
|
||||||
// split the cell into four cells
|
// split the cell into four cells
|
||||||
h = cell.h / 2;
|
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, centroid));
|
||||||
cellQueue.push(new Cell(cell.x + h, cell.y - h, h, polygon));
|
cellQueue.push(new Cell(cell.x + h, cell.y - h, h, polygon, centroid));
|
||||||
cellQueue.push(new Cell(cell.x - h, cell.y + h, h, polygon));
|
cellQueue.push(new Cell(cell.x - h, cell.y + h, h, polygon, centroid));
|
||||||
cellQueue.push(new Cell(cell.x + h, cell.y + h, h, polygon));
|
cellQueue.push(new Cell(cell.x + h, cell.y + h, h, polygon, centroid));
|
||||||
numProbes += 4;
|
numProbes += 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,15 +86,17 @@ export default function polylabel(polygon, precision, debug) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function compareMax(a, b) {
|
function compareMax(a, b) {
|
||||||
return b.max - a.max;
|
return b.weight - a.weight;
|
||||||
}
|
}
|
||||||
|
|
||||||
function Cell(x, y, h, polygon) {
|
function Cell(x, y, h, polygon, centroid) {
|
||||||
this.x = x; // cell center x
|
this.x = x; // cell center x
|
||||||
this.y = y; // cell center y
|
this.y = y; // cell center y
|
||||||
this.h = h; // half the cell size
|
this.h = h; // half the cell size
|
||||||
this.d = pointToPolygonDist(x, y, polygon); // distance from cell center to polygon
|
this.d = pointToPolygonDist(x, y, polygon); // distance from cell center to polygon
|
||||||
|
this.centerDist = (centroid[0] - x) ** 2 + (centroid[1] - y) ** 2
|
||||||
this.max = this.d + this.h * Math.SQRT2; // max distance to polygon within a cell
|
this.max = this.d + this.h * Math.SQRT2; // max distance to polygon within a cell
|
||||||
|
this.weight = -this.centerDist - this.max
|
||||||
}
|
}
|
||||||
|
|
||||||
// signed distance from point to polygon outline (negative if point is outside)
|
// signed distance from point to polygon outline (negative if point is outside)
|
||||||
|
@ -110,7 +118,7 @@ function pointToPolygonDist(x, y, polygon) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// get polygon centroid
|
// get polygon centroid
|
||||||
function getCentroidCell(polygon) {
|
function getCentroid(polygon) {
|
||||||
var area = 0;
|
var area = 0;
|
||||||
var x = 0;
|
var x = 0;
|
||||||
var y = 0;
|
var y = 0;
|
||||||
|
@ -123,8 +131,12 @@ function getCentroidCell(polygon) {
|
||||||
y += (a[1] + b[1]) * f;
|
y += (a[1] + b[1]) * f;
|
||||||
area += f * 3;
|
area += f * 3;
|
||||||
}
|
}
|
||||||
if (area === 0) return new Cell(polygon[0][0], polygon[0][1], 0, polygon);
|
if (area === 0) return [polygon[0][0], polygon[0][1]];
|
||||||
return new Cell(x / area, y / area, 0, polygon);
|
return [x / area, y / area];
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCentroidCell(centroid, polygon) {
|
||||||
|
return new Cell(centroid[0], centroid[1], 0, polygon, centroid);
|
||||||
}
|
}
|
||||||
|
|
||||||
// get squared distance from a point to a segment
|
// get squared distance from a point to a segment
|
||||||
|
|
Loading…
Reference in a new issue