mirror of
https://github.com/Azgaar/Fantasy-Map-Generator.git
synced 2025-12-19 10:31:24 +01:00
refactor: drawIce
This commit is contained in:
parent
39516ce782
commit
e83726918b
10 changed files with 174 additions and 272 deletions
|
|
@ -1,16 +1,16 @@
|
|||
"use strict";
|
||||
|
||||
// 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;
|
||||
function getIsolines(graph, getType, options = {polygons: false, fill: false, halo: false, waterGap: false}) {
|
||||
const {cells, vertices} = graph;
|
||||
const isolines = {};
|
||||
|
||||
const checkedCells = new Uint8Array(cells.c.length);
|
||||
const checkedCells = new Uint8Array(cells.i.length);
|
||||
const addToChecked = cellId => (checkedCells[cellId] = 1);
|
||||
const isChecked = cellId => checkedCells[cellId] === 1;
|
||||
|
||||
for (let cellId = 0; cellId < cells.c.length; cellId++) {
|
||||
if (isChecked(cellId) || getType(cellId) === 0) continue;
|
||||
for (const cellId of cells.i) {
|
||||
if (isChecked(cellId) || !getType(cellId)) continue;
|
||||
addToChecked(cellId);
|
||||
|
||||
const type = getType(cellId);
|
||||
|
|
@ -20,73 +20,75 @@ function getIsolines(getType, options = {polygons: false, fill: false, halo: fal
|
|||
const onborderCell = cells.c[cellId].find(ofDifferentType);
|
||||
if (onborderCell === undefined) continue;
|
||||
|
||||
const feature = pack.features[cells.f[onborderCell]];
|
||||
if (feature.type === "lake") {
|
||||
if (!feature.shoreline) Lakes.getShoreline(feature);
|
||||
if (feature.shoreline.every(ofSameType)) continue; // inner lake
|
||||
}
|
||||
// check if inner lake. Note there is no shoreline for grid features
|
||||
const feature = graph.features[cells.f[onborderCell]];
|
||||
if (feature.type === "lake" && feature.shoreline?.every(ofSameType)) continue;
|
||||
|
||||
const startingVertex = cells.v[cellId].find(v => vertices.c[v].some(ofDifferentType));
|
||||
if (startingVertex === undefined) throw new Error(`Starting vertex for cell ${cellId} is not found`);
|
||||
|
||||
const vertexChain = connectVertices({startingVertex, ofSameType, addToChecked, closeRing: true});
|
||||
const vertexChain = connectVertices({vertices, startingVertex, ofSameType, addToChecked, closeRing: true});
|
||||
if (vertexChain.length < 3) continue;
|
||||
|
||||
addIsoline(type, vertexChain);
|
||||
addIsoline(type, vertices, vertexChain);
|
||||
}
|
||||
|
||||
return Object.entries(isolines);
|
||||
return isolines;
|
||||
|
||||
function getBorderPath(vertexChain, discontinue) {
|
||||
let discontinued = true;
|
||||
let lastOperation = "";
|
||||
const path = vertexChain.map(vertex => {
|
||||
if (discontinue(vertex)) {
|
||||
discontinued = true;
|
||||
return "";
|
||||
}
|
||||
function addIsoline(type, vertices, vertexChain) {
|
||||
if (!isolines[type]) isolines[type] = {};
|
||||
|
||||
const operation = discontinued ? "M" : "L";
|
||||
const command = operation === lastOperation ? "" : operation;
|
||||
if (options.polygons) {
|
||||
if (!isolines[type].polygons) isolines[type].polygons = [];
|
||||
isolines[type].polygons.push(vertexChain.map(vertexId => vertices.p[vertexId]));
|
||||
}
|
||||
|
||||
discontinued = false;
|
||||
lastOperation = operation;
|
||||
if (options.fill) {
|
||||
if (!isolines[type].fill) isolines[type].fill = "";
|
||||
isolines[type].fill += getFillPath(vertices, vertexChain);
|
||||
}
|
||||
|
||||
return ` ${command}${getVertexPoint(vertex)}`;
|
||||
});
|
||||
if (options.waterGap) {
|
||||
if (!isolines[type].waterGap) isolines[type].waterGap = "";
|
||||
const isLandVertex = vertexId => vertices.c[vertexId].every(i => cells.h[i] >= 20);
|
||||
isolines[type].waterGap += getBorderPath(vertices, vertexChain, isLandVertex);
|
||||
}
|
||||
|
||||
return path.join("").trim();
|
||||
}
|
||||
|
||||
function isBorderVertex(vertex) {
|
||||
const adjacentCells = vertices.c[vertex];
|
||||
return adjacentCells.some(i => cells.b[i]);
|
||||
}
|
||||
|
||||
function isLandVertex(vertex) {
|
||||
const adjacentCells = vertices.c[vertex];
|
||||
return adjacentCells.every(i => cells.h[i] >= 20);
|
||||
}
|
||||
|
||||
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);
|
||||
if (options.halo) {
|
||||
if (!isolines[type].halo) isolines[type].halo = "";
|
||||
const isBorderVertex = vertexId => vertices.c[vertexId].some(i => cells.b[i]);
|
||||
isolines[type].halo += getBorderPath(vertices, vertexChain, isBorderVertex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getVertexPoint(vertexId) {
|
||||
return pack.vertices.p[vertexId];
|
||||
}
|
||||
|
||||
function getFillPath(vertexChain) {
|
||||
const points = vertexChain.map(getVertexPoint);
|
||||
function getFillPath(vertices, vertexChain) {
|
||||
const points = vertexChain.map(vertexId => vertices.p[vertexId]);
|
||||
const firstPoint = points.shift();
|
||||
return `M${firstPoint} L${points.join(" ")} Z`;
|
||||
}
|
||||
|
||||
function getBorderPath(vertices, vertexChain, discontinue) {
|
||||
let discontinued = true;
|
||||
let lastOperation = "";
|
||||
const path = vertexChain.map(vertexId => {
|
||||
if (discontinue(vertexId)) {
|
||||
discontinued = true;
|
||||
return "";
|
||||
}
|
||||
|
||||
const operation = discontinued ? "M" : "L";
|
||||
const command = operation === lastOperation ? "" : operation;
|
||||
|
||||
discontinued = false;
|
||||
lastOperation = operation;
|
||||
|
||||
return ` ${command}${vertices.p[vertexId]}`;
|
||||
});
|
||||
|
||||
return path.join("").trim();
|
||||
}
|
||||
|
||||
// get single path for an non-continuous array of cells
|
||||
function getVertexPath(cellsArray) {
|
||||
const {cells, vertices} = pack;
|
||||
|
|
@ -116,7 +118,7 @@ function getVertexPath(cellsArray) {
|
|||
const startingVertex = cells.v[cellId].find(v => vertices.c[v].some(ofDifferentType));
|
||||
if (startingVertex === undefined) throw new Error(`Starting vertex for cell ${cellId} is not found`);
|
||||
|
||||
const vertexChain = connectVertices({startingVertex, ofSameType, addToChecked, closeRing: true});
|
||||
const vertexChain = connectVertices({vertices, startingVertex, ofSameType, addToChecked, closeRing: true});
|
||||
if (vertexChain.length < 3) continue;
|
||||
|
||||
path += getFillPath(vertexChain);
|
||||
|
|
@ -125,10 +127,10 @@ function getVertexPath(cellsArray) {
|
|||
return path;
|
||||
}
|
||||
|
||||
function getPolesOfInaccessibility(getType) {
|
||||
const isolines = getIsolines(getType, {polygons: true});
|
||||
function getPolesOfInaccessibility(graph, getType) {
|
||||
const isolines = getIsolines(graph, getType, {polygons: true});
|
||||
|
||||
const poles = isolines.map(([id, isoline]) => {
|
||||
const poles = Object.entries(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)]];
|
||||
|
|
@ -137,9 +139,8 @@ function getPolesOfInaccessibility(getType) {
|
|||
return Object.fromEntries(poles);
|
||||
}
|
||||
|
||||
function connectVertices({startingVertex, ofSameType, addToChecked, closeRing}) {
|
||||
const vertices = pack.vertices;
|
||||
const MAX_ITERATIONS = pack.cells.i.length;
|
||||
function connectVertices({vertices, startingVertex, ofSameType, addToChecked, closeRing}) {
|
||||
const MAX_ITERATIONS = vertices.c.length;
|
||||
const chain = []; // vertices chain to form a path
|
||||
|
||||
let next = startingVertex;
|
||||
|
|
@ -172,10 +173,3 @@ function connectVertices({startingVertex, ofSameType, addToChecked, closeRing})
|
|||
if (closeRing) chain.push(startingVertex);
|
||||
return chain;
|
||||
}
|
||||
|
||||
function drawFillWithGap(elementName, fill, waterGap, color, index) {
|
||||
return /* html */ `
|
||||
<path d="${fill}" fill="${color}" id="${elementName}${index}" />
|
||||
<path d="${waterGap}" fill="none" stroke="${color}" stroke-width="5" id="${elementName}-gap${index}" />
|
||||
`;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue