feat: render states - separate pole detection from layer render

This commit is contained in:
Azgaar 2024-09-02 03:23:05 +02:00
parent 093014088c
commit c66e6e4645
5 changed files with 45 additions and 24 deletions

View file

@ -13,6 +13,8 @@ window.BurgsAndStates = (() => {
placeTowns(); placeTowns();
expandStates(); expandStates();
normalizeStates(); normalizeStates();
getPoles();
specifyBurgs(); specifyBurgs();
collectStatistics(); collectStatistics();
@ -468,8 +470,7 @@ window.BurgsAndStates = (() => {
const normalizeStates = () => { const normalizeStates = () => {
TIME && console.time("normalizeStates"); TIME && console.time("normalizeStates");
const cells = pack.cells, const {cells, burgs} = pack;
burgs = pack.burgs;
for (const i of cells.i) { for (const i of cells.i) {
if (cells.h[i] < 20 || cells.burg[i]) continue; // do not overwrite burgs if (cells.h[i] < 20 || cells.burg[i]) continue; // do not overwrite burgs
@ -486,6 +487,17 @@ window.BurgsAndStates = (() => {
TIME && console.timeEnd("normalizeStates"); 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 // Resets the cultures of all burgs and states to their
// cell or center cell's (respectively) culture. // cell or center cell's (respectively) culture.
const updateCultures = () => { const updateCultures = () => {
@ -1194,6 +1206,7 @@ window.BurgsAndStates = (() => {
generate, generate,
expandStates, expandStates,
normalizeStates, normalizeStates,
getPoles,
assignColors, assignColors,
drawBurgs, drawBurgs,
specifyBurgs, specifyBurgs,

View file

@ -845,6 +845,7 @@ function recalculateStates(must) {
if (!layerIsOn("toggleBorders")) toggleBorders(); if (!layerIsOn("toggleBorders")) toggleBorders();
else drawBorders(); else drawBorders();
if (layerIsOn("toggleProvinces")) drawProvinces(); if (layerIsOn("toggleProvinces")) drawProvinces();
BurgsAndStates.getPoles();
if (adjustLabels.checked) drawStateLabels(); if (adjustLabels.checked) drawStateLabels();
refreshStatesEditor(); refreshStatesEditor();
} }
@ -981,6 +982,7 @@ function applyStatesManualAssignent() {
if (affectedStates.length) { if (affectedStates.length) {
refreshStatesEditor(); refreshStatesEditor();
BurgsAndStates.getPoles();
layerIsOn("toggleStates") ? drawStates() : toggleStates(); layerIsOn("toggleStates") ? drawStates() : toggleStates();
if (adjustLabels.checked) drawStateLabels([...new Set(affectedStates)]); if (adjustLabels.checked) drawStateLabels([...new Set(affectedStates)]);
adjustProvinces([...new Set(affectedProvinces)]); adjustProvinces([...new Set(affectedProvinces)]);
@ -1415,6 +1417,7 @@ function openStateMergeDialog() {
unfog(); unfog();
debug.selectAll(".highlight").remove(); debug.selectAll(".highlight").remove();
BurgsAndStates.getPoles();
layerIsOn("toggleStates") ? drawStates() : toggleStates(); layerIsOn("toggleStates") ? drawStates() : toggleStates();
layerIsOn("toggleBorders") ? drawBorders() : toggleBorders(); layerIsOn("toggleBorders") ? drawBorders() : toggleBorders();
layerIsOn("toggleProvinces") && drawProvinces(); layerIsOn("toggleProvinces") && drawProvinces();

View file

@ -991,18 +991,14 @@ function drawStates() {
TIME && console.time("drawStates"); TIME && console.time("drawStates");
const {cells, states} = pack; 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 maxLength = states.length - 1;
const bodyPaths = new Array(maxLength); const bodyPaths = new Array(maxLength);
const clipPaths = new Array(maxLength); const clipPaths = new Array(maxLength);
const haloPaths = 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; const color = states[index].color;
bodyPaths.push( bodyPaths.push(
@ -1022,11 +1018,6 @@ function drawStates() {
byId("statePaths").innerHTML = renderHalo ? clipPaths.join("") : ""; byId("statePaths").innerHTML = renderHalo ? clipPaths.join("") : "";
byId("statesHalo").innerHTML = renderHalo ? haloPaths.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"); TIME && console.timeEnd("drawStates");
} }

View file

@ -152,6 +152,7 @@ function regenerateStates() {
pack.states = newStates; pack.states = newStates;
BurgsAndStates.expandStates(); BurgsAndStates.expandStates();
BurgsAndStates.normalizeStates(); BurgsAndStates.normalizeStates();
BurgsAndStates.getPoles();
BurgsAndStates.collectStatistics(); BurgsAndStates.collectStatistics();
BurgsAndStates.assignColors(); BurgsAndStates.assignColors();
BurgsAndStates.generateCampaigns(); BurgsAndStates.generateCampaigns();

View file

@ -1,9 +1,9 @@
"use strict"; "use strict";
// get continuous paths for all cells at once based on getType(cellId) comparison // get continuous paths (isolines) for all cells at once based on getType(cellId) comparison
function getVertexPaths({getType, options}) { function getIsolines(getType, options = {polygons: false, fill: false, halo: false, waterGap: false}) {
const {cells, vertices} = pack; const {cells, vertices} = pack;
const paths = {}; const isolines = {};
const checkedCells = new Uint8Array(cells.c.length); const checkedCells = new Uint8Array(cells.c.length);
const addToChecked = cellId => (checkedCells[cellId] = 1); const addToChecked = cellId => (checkedCells[cellId] = 1);
@ -32,10 +32,10 @@ function getVertexPaths({getType, options}) {
const vertexChain = connectVertices({startingVertex, ofSameType, addToChecked, closeRing: true}); const vertexChain = connectVertices({startingVertex, ofSameType, addToChecked, closeRing: true});
if (vertexChain.length < 3) continue; if (vertexChain.length < 3) continue;
addPath(type, vertexChain); addIsoline(type, vertexChain);
} }
return Object.entries(paths); return Object.entries(isolines);
function getBorderPath(vertexChain, discontinue) { function getBorderPath(vertexChain, discontinue) {
let discontinued = true; let discontinued = true;
@ -68,11 +68,12 @@ function getVertexPaths({getType, options}) {
return adjacentCells.every(i => cells.h[i] >= 20); return adjacentCells.every(i => cells.h[i] >= 20);
} }
function addPath(index, vertexChain) { function addIsoline(index, vertexChain) {
if (!paths[index]) paths[index] = {fill: "", waterGap: "", halo: ""}; if (!isolines[index]) isolines[index] = {polygons: [], fill: "", waterGap: "", halo: ""};
if (options.fill) paths[index].fill += getFillPath(vertexChain); if (options.polygons) isolines[index].polygons.push(vertexChain.map(getVertexPoint));
if (options.halo) paths[index].halo += getBorderPath(vertexChain, isBorderVertex); if (options.fill) isolines[index].fill += getFillPath(vertexChain);
if (options.waterGap) paths[index].waterGap += getBorderPath(vertexChain, isLandVertex); 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; 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}) { function connectVertices({startingVertex, ofSameType, addToChecked, closeRing}) {
const vertices = pack.vertices; const vertices = pack.vertices;
const MAX_ITERATIONS = pack.cells.i.length; const MAX_ITERATIONS = pack.cells.i.length;