refactor(religions): render religions

This commit is contained in:
Azgaar 2022-08-29 00:42:37 +03:00
parent 707cdd77ac
commit 7a3a87e935
10 changed files with 137 additions and 55 deletions

View file

@ -1,40 +1,99 @@
import {MIN_LAND_HEIGHT} from "config/generation";
import {connectVertices} from "scripts/connectVertices";
import {isLake} from "utils/typeUtils";
export function getPaths(
cellNeighbors: number[][],
cellVertices: number[][],
vertices: IGraphVertices,
getType: (cellId: number) => number
) {
const paths: Dict<string> = {};
type TPath = {fill: string; waterGap: string; halo: string};
function addPath(index: number, points: TPoints) {
if (!paths[index]) paths[index] = "";
paths[index] += "M" + points.join("L") + "Z";
}
export function getPaths({
vertices,
getType,
features,
cells
}: {
vertices: IGraphVertices;
getType: (cellId: number) => number;
features: TPackFeatures;
cells: Pick<IPack["cells"], "c" | "v" | "b" | "h" | "f">;
}) {
const paths: Dict<TPath> = {};
const checkedCells = new Uint8Array(cellNeighbors.length);
for (let cellId = 0; cellId < cellNeighbors.length; cellId++) {
if (checkedCells[cellId]) continue;
if (!getType(cellId)) continue;
const checkedCells = new Uint8Array(cells.c.length);
const addToChecked = (cellId: number) => {
checkedCells[cellId] = 1;
};
const isChecked = (cellId: number) => checkedCells[cellId] === 1;
for (let cellId = 0; cellId < cells.c.length; cellId++) {
if (isChecked(cellId) || getType(cellId) === 0) continue;
addToChecked(cellId);
const type = getType(cellId);
const ofSameType = (cellId: number) => getType(cellId) === type;
const ofDifferentType = (cellId: number) => getType(cellId) !== type;
const isOnborder = cellNeighbors[cellId].some(cellId => !ofSameType(cellId));
if (!isOnborder) continue;
const onborderCell = cells.c[cellId].find(ofDifferentType);
if (onborderCell === undefined) continue;
const startingVertex = cellVertices[cellId].find(v => vertices.c[v].some(cellId => !ofSameType(cellId)));
if (startingVertex === undefined) throw new Error(`getPath: starting vertex for cell ${cellId} is not found`);
const feature = features[cells.f[onborderCell]];
if (isInnerLake(feature, ofSameType)) continue;
const chain = connectVertices({vertices, startingVertex, ofSameType, checkedCellsMutable: checkedCells});
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`);
if (chain.length < 3) continue;
const points = chain.map(v => vertices.p[v]);
const vertexChain = connectVertices({vertices, startingVertex, ofSameType, addToChecked, closeRing: true});
if (vertexChain.length < 3) continue;
addPath(type, points);
addPath(type, vertexChain);
}
return paths;
return Object.entries(paths);
function getVertexPoint(vertex: number) {
return vertices.p[vertex];
}
function getFillPath(vertexChain: number[]) {
const points: TPoints = vertexChain.map(getVertexPoint);
const firstPoint = points.shift();
return `M${firstPoint} L${points.join(" ")} Z`;
}
function getBorderPath(vertexChain: number[], discontinue: (vertex: number) => boolean) {
let discontinued = true;
const path = vertexChain.map(vertex => {
if (discontinue(vertex)) {
discontinued = true;
return "";
}
const operation = discontinued ? "M" : "L";
discontinued = false;
return ` ${operation}${getVertexPoint(vertex)}`;
});
return path.join("").trim();
}
function isBorderVertex(vertex: number) {
const adjacentCells = vertices.c[vertex];
return adjacentCells.some(i => cells.b[i]);
}
function isLandVertex(vertex: number) {
const adjacentCells = vertices.c[vertex];
return adjacentCells.every(i => cells.h[i] >= MIN_LAND_HEIGHT);
}
function addPath(index: number, vertexChain: number[]) {
if (!paths[index]) paths[index] = {fill: "", waterGap: "", halo: ""};
paths[index].fill += getFillPath(vertexChain);
paths[index].halo += getBorderPath(vertexChain, isBorderVertex);
paths[index].waterGap += getBorderPath(vertexChain, isLandVertex);
}
}
function isInnerLake(feature: 0 | TPackFeature, ofSameType: (cellId: number) => boolean) {
if (!isLake(feature)) return false;
return feature.shoreline.every(ofSameType);
}