mirror of
https://github.com/Azgaar/Fantasy-Map-Generator.git
synced 2026-02-04 17:41:23 +01:00
181 lines
5.1 KiB
TypeScript
181 lines
5.1 KiB
TypeScript
declare global {
|
|
var drawBorders: () => void;
|
|
}
|
|
|
|
const bordersRenderer = () => {
|
|
TIME && console.time("drawBorders");
|
|
const { cells, vertices } = pack;
|
|
|
|
const statePath: string[] = [];
|
|
const provincePath: string[] = [];
|
|
const checked: { [key: string]: boolean } = {};
|
|
|
|
const isLand = (cellId: number) => cells.h[cellId] >= 20;
|
|
|
|
for (let cellId = 0; cellId < cells.i.length; cellId++) {
|
|
if (!cells.state[cellId]) continue;
|
|
const provinceId = cells.province[cellId];
|
|
const stateId = cells.state[cellId];
|
|
|
|
// bordering cell of another province
|
|
if (provinceId) {
|
|
const provToCell = cells.c[cellId].find((neibId) => {
|
|
const neibProvinceId = cells.province[neibId];
|
|
return (
|
|
neibProvinceId &&
|
|
provinceId > neibProvinceId &&
|
|
!checked[`prov-${provinceId}-${neibProvinceId}-${cellId}`] &&
|
|
cells.state[neibId] === stateId
|
|
);
|
|
});
|
|
|
|
if (provToCell !== undefined) {
|
|
const addToChecked = (cellId: number) => {
|
|
checked[
|
|
`prov-${provinceId}-${cells.province[provToCell]}-${cellId}`
|
|
] = true;
|
|
};
|
|
const border = getBorder({
|
|
type: "province",
|
|
fromCell: cellId,
|
|
toCell: provToCell,
|
|
addToChecked,
|
|
});
|
|
|
|
if (border) {
|
|
provincePath.push(border);
|
|
cellId--; // check the same cell again
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
// if cell is on state border
|
|
const stateToCell = cells.c[cellId].find((neibId) => {
|
|
const neibStateId = cells.state[neibId];
|
|
return (
|
|
isLand(neibId) &&
|
|
stateId > neibStateId &&
|
|
!checked[`state-${stateId}-${neibStateId}-${cellId}`]
|
|
);
|
|
});
|
|
|
|
if (stateToCell !== undefined) {
|
|
const addToChecked = (cellId: number) => {
|
|
checked[`state-${stateId}-${cells.state[stateToCell]}-${cellId}`] =
|
|
true;
|
|
};
|
|
const border = getBorder({
|
|
type: "state",
|
|
fromCell: cellId,
|
|
toCell: stateToCell,
|
|
addToChecked,
|
|
});
|
|
|
|
if (border) {
|
|
statePath.push(border);
|
|
cellId--; // check the same cell again
|
|
}
|
|
}
|
|
}
|
|
|
|
svg.select("#borders").selectAll("path").remove();
|
|
svg.select("#stateBorders").append("path").attr("d", statePath.join(" "));
|
|
svg
|
|
.select("#provinceBorders")
|
|
.append("path")
|
|
.attr("d", provincePath.join(" "));
|
|
|
|
function getBorder({
|
|
type,
|
|
fromCell,
|
|
toCell,
|
|
addToChecked,
|
|
}: {
|
|
type: "state" | "province";
|
|
fromCell: number;
|
|
toCell: number;
|
|
addToChecked: (cellId: number) => void;
|
|
}): string | null {
|
|
const getType = (cellId: number) => cells[type][cellId];
|
|
const isTypeFrom = (cellId: number) =>
|
|
cellId < cells.i.length && getType(cellId) === getType(fromCell);
|
|
const isTypeTo = (cellId: number) =>
|
|
cellId < cells.i.length && getType(cellId) === getType(toCell);
|
|
|
|
addToChecked(fromCell);
|
|
const startingVertex = cells.v[fromCell].find((v) =>
|
|
vertices.c[v].some((i) => isLand(i) && isTypeTo(i)),
|
|
);
|
|
if (startingVertex === undefined) return null;
|
|
|
|
const checkVertex = (vertex: number) =>
|
|
vertices.c[vertex].some(isTypeFrom) &&
|
|
vertices.c[vertex].some((c) => isLand(c) && isTypeTo(c));
|
|
const chain = getVerticesLine({
|
|
vertices,
|
|
startingVertex,
|
|
checkCell: isTypeFrom,
|
|
checkVertex,
|
|
addToChecked,
|
|
});
|
|
if (chain.length > 1)
|
|
return `M${chain.map((cellId) => vertices.p[cellId]).join(" ")}`;
|
|
|
|
return null;
|
|
}
|
|
|
|
// connect vertices to chain to form a border
|
|
function getVerticesLine({
|
|
vertices,
|
|
startingVertex,
|
|
checkCell,
|
|
checkVertex,
|
|
addToChecked,
|
|
}: {
|
|
vertices: typeof pack.vertices;
|
|
startingVertex: number;
|
|
checkCell: (cellId: number) => boolean;
|
|
checkVertex: (vertex: number) => boolean;
|
|
addToChecked: (cellId: number) => void;
|
|
}) {
|
|
let chain = []; // vertices chain to form a path
|
|
let next = startingVertex;
|
|
const MAX_ITERATIONS = vertices.c.length;
|
|
|
|
for (let run = 0; run < 2; run++) {
|
|
// first run: from any vertex to a border edge
|
|
// second run: from found border edge to another edge
|
|
chain = [];
|
|
|
|
for (let i = 0; i < MAX_ITERATIONS; i++) {
|
|
const previous = chain.at(-1);
|
|
const current = next;
|
|
chain.push(current);
|
|
|
|
const neibCells = vertices.c[current];
|
|
neibCells.map(addToChecked);
|
|
|
|
const [c1, c2, c3] = neibCells.map(checkCell);
|
|
const [v1, v2, v3] = vertices.v[current].map(checkVertex);
|
|
const [vertex1, vertex2, vertex3] = vertices.v[current];
|
|
|
|
if (v1 && vertex1 !== previous && c1 !== c2) next = vertex1;
|
|
else if (v2 && vertex2 !== previous && c2 !== c3) next = vertex2;
|
|
else if (v3 && vertex3 !== previous && c1 !== c3) next = vertex3;
|
|
|
|
if (next === current || next === startingVertex) {
|
|
if (next === startingVertex) chain.push(startingVertex);
|
|
startingVertex = next;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return chain;
|
|
}
|
|
|
|
TIME && console.timeEnd("drawBorders");
|
|
};
|
|
|
|
window.drawBorders = bordersRenderer;
|