refactor: detect feature vertex

This commit is contained in:
Azgaar 2022-07-15 01:51:08 +03:00
parent f82fcbae0f
commit 3410c48c58
5 changed files with 105 additions and 18 deletions

View file

@ -1,10 +1,13 @@
import * as d3 from "d3";
import {MIN_LAND_HEIGHT, DISTANCE_FIELD} from "config/generation"; import {MIN_LAND_HEIGHT, DISTANCE_FIELD} from "config/generation";
import {TIME} from "config/logging"; import {TIME} from "config/logging";
import {INT8_MAX} from "constants"; import {INT8_MAX} from "constants";
// @ts-expect-error js module // @ts-expect-error js module
import {aleaPRNG} from "scripts/aleaPRNG"; import {aleaPRNG} from "scripts/aleaPRNG";
import {createTypedArray} from "utils/arrayUtils"; import {createTypedArray} from "utils/arrayUtils";
import {dist2} from "utils/functionUtils"; import {dist2, pick} from "utils/functionUtils";
import {getColors} from "utils/colorUtils";
const {UNMARKED, LAND_COAST, WATER_COAST, LANDLOCKED, DEEPER_WATER} = DISTANCE_FIELD; const {UNMARKED, LAND_COAST, WATER_COAST, LANDLOCKED, DEEPER_WATER} = DISTANCE_FIELD;
@ -70,7 +73,11 @@ export function markupGridFeatures(grid: IGridWithHeights) {
} }
// define features (oceans, lakes, islands) add related details // define features (oceans, lakes, islands) add related details
export function markupPackFeatures(grid: IGrid, cells: Pick<IPack["cells"], "c" | "b" | "p" | "h">) { export function markupPackFeatures(
grid: IGrid,
vertices: IGraphVertices,
cells: Pick<IPack["cells"], "c" | "v" | "b" | "p" | "h">
) {
TIME && console.time("markupPackFeatures"); TIME && console.time("markupPackFeatures");
const packCellsNumber = cells.h.length; const packCellsNumber = cells.h.length;
@ -111,13 +118,22 @@ export function markupPackFeatures(grid: IGrid, cells: Pick<IPack["cells"], "c"
return "isle"; return "isle";
} }
function addIsland(featureId: number, border: boolean, firstCell: number, cells: number) { function addIsland(featureId: number, border: boolean, firstCell: number, cells: number, vertices: number[]) {
const group = defineIslandGroup(firstCell, cells); const group = defineIslandGroup(firstCell, cells);
const feature: IPackFeatureIsland = {i: featureId, type: "island", group, land: true, border, cells, firstCell}; const feature: IPackFeatureIsland = {
i: featureId,
type: "island",
group,
land: true,
border,
cells,
firstCell,
vertices
};
features.push(feature); features.push(feature);
} }
function addOcean(featureId: number, firstCell: number, cells: number) { function addOcean(featureId: number, firstCell: number, cells: number, vertices: number[]) {
const group = defineOceanGroup(cells); const group = defineOceanGroup(cells);
const feature: IPackFeatureOcean = { const feature: IPackFeatureOcean = {
i: featureId, i: featureId,
@ -126,12 +142,13 @@ export function markupPackFeatures(grid: IGrid, cells: Pick<IPack["cells"], "c"
land: false, land: false,
border: false, border: false,
cells, cells,
firstCell firstCell,
vertices
}; };
features.push(feature); features.push(feature);
} }
function addLake(featureId: number, firstCell: number, cells: number) { function addLake(featureId: number, firstCell: number, cells: number, vertices: number[]) {
const group = "freshwater"; // temp, to be defined later const group = "freshwater"; // temp, to be defined later
const name = ""; // temp, to be defined later const name = ""; // temp, to be defined later
const feature: IPackFeatureLake = { const feature: IPackFeatureLake = {
@ -142,7 +159,8 @@ export function markupPackFeatures(grid: IGrid, cells: Pick<IPack["cells"], "c"
land: false, land: false,
border: false, border: false,
cells, cells,
firstCell firstCell,
vertices
}; };
features.push(feature); features.push(feature);
} }
@ -156,6 +174,8 @@ export function markupPackFeatures(grid: IGrid, cells: Pick<IPack["cells"], "c"
let border = false; // true if feature touches map border let border = false; // true if feature touches map border
let cellNumber = 1; // count cells in a feature let cellNumber = 1; // count cells in a feature
const featureCells = [firstCell];
while (queue.length) { while (queue.length) {
const cellId = queue.pop()!; const cellId = queue.pop()!;
if (cells.b[cellId]) border = true; if (cells.b[cellId]) border = true;
@ -178,15 +198,44 @@ export function markupPackFeatures(grid: IGrid, cells: Pick<IPack["cells"], "c"
queue.push(neighborId); queue.push(neighborId);
featureIds[neighborId] = featureId; featureIds[neighborId] = featureId;
cellNumber++; cellNumber++;
featureCells.push(neighborId);
} }
} }
} }
// const vertices = detectFeatureVertices(cells, firstCell); const startingVertex = findStartingVertex(
firstCell,
border,
featureIds,
featureId,
vertices,
pick(cells, "c", "v"),
packCellsNumber
);
if (land) addIsland(featureId, border, firstCell, cellNumber); if (startingVertex === undefined || startingVertex > vertices.p.length) {
else if (border) addOcean(featureId, firstCell, cellNumber); debugger;
else addLake(featureId, firstCell, cellNumber); }
const color = featureId === 1 ? "#2274cc" : getColors(12)[featureId % 12];
const paths: TPoint[][] = featureCells.map(i => cells.v[i].map(v => vertices.p[v]));
d3.select("#cells")
.append("path")
.attr("d", "M" + paths.join("M"))
.attr("fill", color)
.attr("stroke", "#000")
.attr("stroke-width", "0.2");
const [x, y] = cells.p[firstCell];
d3.select("#debug").append("circle").attr("cx", x).attr("cy", y).attr("r", 1).attr("fill", "blue");
const [cx, cy] = vertices.p[startingVertex];
d3.select("#debug").append("circle").attr("cx", cx).attr("cy", cy).attr("r", 2).attr("fill", "red");
// const vertices: number[] = []; // connectVertices(startingVertex);
if (land) addIsland(featureId, border, firstCell, cellNumber, []);
else if (border) addOcean(featureId, firstCell, cellNumber, []);
else addLake(featureId, firstCell, cellNumber, []);
queue[0] = featureIds.findIndex(f => f === UNMARKED); // find unmarked cell queue[0] = featureIds.findIndex(f => f === UNMARKED); // find unmarked cell
} }
@ -230,8 +279,39 @@ function markup({
return distanceField; return distanceField;
} }
// connect vertices to chain function findStartingVertex(
function connectVertices(start, t) { firstCell: number,
border: boolean,
featureIds: Uint16Array,
featureId: number,
vertices: IGraphVertices,
cells: Pick<IPack["cells"], "c" | "v">,
packCellsNumber: number
) {
const neibCells = cells.c[firstCell];
const cellVertices = cells.v[firstCell];
if (border) {
const externalVertex = cellVertices.find(vertex => {
const [x, y] = vertices.p[vertex];
if (x < 0 || y < 0) return true;
return vertices.c[vertex].some(neibCell => neibCell >= packCellsNumber);
});
if (externalVertex !== undefined) return externalVertex;
}
const otherFeatureNeibs = neibCells.filter(neibCell => featureIds[neibCell] !== featureId);
if (!otherFeatureNeibs.length) {
throw new Error(`Markup: firstCell ${firstCell} of feature ${featureId} has no neighbors of other features`);
}
const index = neibCells.indexOf(d3.min(otherFeatureNeibs)!);
return cellVertices[index];
}
// connect vertices around feature
function connectVertices(start: number, t: number) {
const chain = []; // vertices chain to form a path const chain = []; // vertices chain to form a path
for (let i = 0, current = start; i === 0 || (current !== start && i < 50000); i++) { for (let i = 0, current = start; i === 0 || (current !== start && i < 50000); i++) {
const prev = chain[chain.length - 1]; // previous vertex in chain const prev = chain[chain.length - 1]; // previous vertex in chain

View file

@ -199,7 +199,9 @@ function changeMapSize() {
const maxWidth = Math.max(+mapWidthInput.value, graphWidth); const maxWidth = Math.max(+mapWidthInput.value, graphWidth);
const maxHeight = Math.max(+mapHeightInput.value, graphHeight); const maxHeight = Math.max(+mapHeightInput.value, graphHeight);
Zoom.translateExtent([0, 0, maxWidth, maxHeight]); Zoom.translateExtent([0, 0, maxWidth, maxHeight]);
landmass.select("rect").attr("x", 0).attr("y", 0).attr("width", maxWidth).attr("height", maxHeight); landmass.select("rect").attr("x", 0).attr("y", 0).attr("width", maxWidth).attr("height", maxHeight);
oceanPattern.select("rect").attr("x", 0).attr("y", 0).attr("width", maxWidth).attr("height", maxHeight); oceanPattern.select("rect").attr("x", 0).attr("y", 0).attr("width", maxWidth).attr("height", maxHeight);
oceanLayers.select("rect").attr("x", 0).attr("y", 0).attr("width", maxWidth).attr("height", maxHeight); oceanLayers.select("rect").attr("x", 0).attr("y", 0).attr("width", maxWidth).attr("height", maxHeight);
@ -221,7 +223,9 @@ export function applyMapSize() {
svgHeight = Math.min(graphHeight, window.innerHeight); svgHeight = Math.min(graphHeight, window.innerHeight);
svg.attr("width", svgWidth).attr("height", svgHeight); svg.attr("width", svgWidth).attr("height", svgHeight);
Zoom.translateExtent([0, 0, graphWidth, graphHeight]); // Zoom.translateExtent([0, 0, graphWidth, graphHeight]);
Zoom.translateExtent([-100, -100, graphWidth + 200, graphHeight + 200]);
Zoom.scaleExtent([zoomMin, zoomMax]); Zoom.scaleExtent([zoomMin, zoomMax]);
Zoom.scaleTo(svg, zoomMin); Zoom.scaleTo(svg, zoomMin);
} }

View file

@ -42,6 +42,9 @@ async function generate(options?: IGenerationOptions) {
const timeStart = performance.now(); const timeStart = performance.now();
const {seed: precreatedSeed, graph: precreatedGraph} = options || {}; const {seed: precreatedSeed, graph: precreatedGraph} = options || {};
// temp for testing:
hideLoading();
Zoom?.invoke(); Zoom?.invoke();
setSeed(precreatedSeed); setSeed(precreatedSeed);

View file

@ -23,9 +23,9 @@ const {Lakes, OceanLayers, Rivers, Biomes, Cultures, BurgsAndStates, Religions,
export function createPack(grid: IGrid): IPack { export function createPack(grid: IGrid): IPack {
const {vertices, cells} = repackGrid(grid); const {vertices, cells} = repackGrid(grid);
const markup = markupPackFeatures(grid, pick(cells, "c", "b", "p", "h")); const markup = markupPackFeatures(grid, vertices, pick(cells, "v", "c", "b", "p", "h"));
drawCoastline({vertices, cells}); // split into vertices definition and rendering // drawCoastline({vertices, cells}); // split into vertices definition and rendering
// Rivers.generate(newPack, grid); // Rivers.generate(newPack, grid);
// renderLayer("rivers", newPack); // renderLayer("rivers", newPack);

2
src/types/pack.d.ts vendored
View file

@ -42,7 +42,7 @@ interface IPackFeatureBase {
border: boolean; // if touches map border border: boolean; // if touches map border
cells: number; // number of cells cells: number; // number of cells
firstCell: number; // index of the top left cell firstCell: number; // index of the top left cell
vertices?: number[]; // indexes of perimetric vertices vertices: number[]; // indexes of perimetric vertices
} }
interface IPackFeatureOcean extends IPackFeatureBase { interface IPackFeatureOcean extends IPackFeatureBase {