diff --git a/modules/burgs-and-states.js b/modules/burgs-and-states.js index 5d6d7a9e..86eca6d7 100644 --- a/modules/burgs-and-states.js +++ b/modules/burgs-and-states.js @@ -13,6 +13,8 @@ window.BurgsAndStates = (() => { placeTowns(); expandStates(); normalizeStates(); + getPoles(); + specifyBurgs(); collectStatistics(); @@ -468,8 +470,7 @@ window.BurgsAndStates = (() => { const normalizeStates = () => { TIME && console.time("normalizeStates"); - const cells = pack.cells, - burgs = pack.burgs; + const {cells, burgs} = pack; for (const i of cells.i) { if (cells.h[i] < 20 || cells.burg[i]) continue; // do not overwrite burgs @@ -486,6 +487,17 @@ window.BurgsAndStates = (() => { TIME && console.timeEnd("normalizeStates"); }; + // calculate pole of inaccessibility for each state + const getPoles = () => { + const getType = cellId => pack.cells.state[cellId]; + const poles = getPolesOfInaccessibility(getType); + + pack.states.forEach(s => { + if (!s.i || s.removed) return; + s.pole = poles[s.i] || [0, 0]; + }); + }; + // Resets the cultures of all burgs and states to their // cell or center cell's (respectively) culture. const updateCultures = () => { @@ -1194,6 +1206,7 @@ window.BurgsAndStates = (() => { generate, expandStates, normalizeStates, + getPoles, assignColors, drawBurgs, specifyBurgs, diff --git a/modules/dynamic/editors/states-editor.js b/modules/dynamic/editors/states-editor.js index 2e153543..2e6c6ea6 100644 --- a/modules/dynamic/editors/states-editor.js +++ b/modules/dynamic/editors/states-editor.js @@ -845,6 +845,7 @@ function recalculateStates(must) { if (!layerIsOn("toggleBorders")) toggleBorders(); else drawBorders(); if (layerIsOn("toggleProvinces")) drawProvinces(); + BurgsAndStates.getPoles(); if (adjustLabels.checked) drawStateLabels(); refreshStatesEditor(); } @@ -981,6 +982,7 @@ function applyStatesManualAssignent() { if (affectedStates.length) { refreshStatesEditor(); + BurgsAndStates.getPoles(); layerIsOn("toggleStates") ? drawStates() : toggleStates(); if (adjustLabels.checked) drawStateLabels([...new Set(affectedStates)]); adjustProvinces([...new Set(affectedProvinces)]); @@ -1415,6 +1417,7 @@ function openStateMergeDialog() { unfog(); debug.selectAll(".highlight").remove(); + BurgsAndStates.getPoles(); layerIsOn("toggleStates") ? drawStates() : toggleStates(); layerIsOn("toggleBorders") ? drawBorders() : toggleBorders(); layerIsOn("toggleProvinces") && drawProvinces(); diff --git a/modules/ui/layers.js b/modules/ui/layers.js index cde1b72c..fb2b73ed 100644 --- a/modules/ui/layers.js +++ b/modules/ui/layers.js @@ -991,18 +991,14 @@ function drawStates() { TIME && console.time("drawStates"); const {cells, states} = pack; - const renderHalo = shapeRendering.value === "geometricPrecision"; - const paths = getVertexPaths({ - getType: cellId => cells.state[cellId], - options: {fill: true, waterGap: true, halo: renderHalo} - }); - const maxLength = states.length - 1; const bodyPaths = new Array(maxLength); const clipPaths = new Array(maxLength); const haloPaths = new Array(maxLength); - for (const [index, {fill, waterGap, halo}] of paths) { + const renderHalo = shapeRendering.value === "geometricPrecision"; + const isolines = getIsolines(cellId => cells.state[cellId], {fill: true, waterGap: true, halo: renderHalo}); + for (const [index, {fill, waterGap, halo}] of isolines) { const color = states[index].color; bodyPaths.push( @@ -1022,11 +1018,6 @@ function drawStates() { byId("statePaths").innerHTML = renderHalo ? clipPaths.join("") : ""; byId("statesHalo").innerHTML = renderHalo ? haloPaths.join("") : ""; - // vArray.forEach((ar, i) => { - // const sorted = ar.sort((a, b) => b.length - a.length); // sort by points number - // states[i].pole = polylabel(sorted, 1.0); // pole of inaccessibility - // }); - TIME && console.timeEnd("drawStates"); } diff --git a/modules/ui/tools.js b/modules/ui/tools.js index 9dce15c5..9b3a8e9d 100644 --- a/modules/ui/tools.js +++ b/modules/ui/tools.js @@ -152,6 +152,7 @@ function regenerateStates() { pack.states = newStates; BurgsAndStates.expandStates(); BurgsAndStates.normalizeStates(); + BurgsAndStates.getPoles(); BurgsAndStates.collectStatistics(); BurgsAndStates.assignColors(); BurgsAndStates.generateCampaigns(); diff --git a/utils/pathUtils.js b/utils/pathUtils.js index df617e05..23194015 100644 --- a/utils/pathUtils.js +++ b/utils/pathUtils.js @@ -1,9 +1,9 @@ "use strict"; -// get continuous paths for all cells at once based on getType(cellId) comparison -function getVertexPaths({getType, options}) { +// get continuous paths (isolines) for all cells at once based on getType(cellId) comparison +function getIsolines(getType, options = {polygons: false, fill: false, halo: false, waterGap: false}) { const {cells, vertices} = pack; - const paths = {}; + const isolines = {}; const checkedCells = new Uint8Array(cells.c.length); const addToChecked = cellId => (checkedCells[cellId] = 1); @@ -32,10 +32,10 @@ function getVertexPaths({getType, options}) { const vertexChain = connectVertices({startingVertex, ofSameType, addToChecked, closeRing: true}); if (vertexChain.length < 3) continue; - addPath(type, vertexChain); + addIsoline(type, vertexChain); } - return Object.entries(paths); + return Object.entries(isolines); function getBorderPath(vertexChain, discontinue) { let discontinued = true; @@ -68,11 +68,12 @@ function getVertexPaths({getType, options}) { return adjacentCells.every(i => cells.h[i] >= 20); } - function addPath(index, vertexChain) { - if (!paths[index]) paths[index] = {fill: "", waterGap: "", halo: ""}; - if (options.fill) paths[index].fill += getFillPath(vertexChain); - if (options.halo) paths[index].halo += getBorderPath(vertexChain, isBorderVertex); - if (options.waterGap) paths[index].waterGap += getBorderPath(vertexChain, isLandVertex); + function addIsoline(index, vertexChain) { + if (!isolines[index]) isolines[index] = {polygons: [], fill: "", waterGap: "", halo: ""}; + if (options.polygons) isolines[index].polygons.push(vertexChain.map(getVertexPoint)); + if (options.fill) isolines[index].fill += getFillPath(vertexChain); + if (options.halo) isolines[index].halo += getBorderPath(vertexChain, isBorderVertex); + if (options.waterGap) isolines[index].waterGap += getBorderPath(vertexChain, isLandVertex); } } @@ -124,6 +125,18 @@ function getVertexPath(cellsArray) { return path; } +function getPolesOfInaccessibility(getType) { + const isolines = getIsolines(getType, {polygons: true}); + + const poles = isolines.map(([id, isoline]) => { + const multiPolygon = isoline.polygons.sort((a, b) => b.length - a.length); + const [x, y] = polylabel(multiPolygon, 20); + return [id, [rn(x), rn(y)]]; + }); + + return Object.fromEntries(poles); +} + function connectVertices({startingVertex, ofSameType, addToChecked, closeRing}) { const vertices = pack.vertices; const MAX_ITERATIONS = pack.cells.i.length;