mirror of
https://github.com/Azgaar/Fantasy-Map-Generator.git
synced 2025-12-17 17:51:24 +01:00
refactor: roads generation - reduce curves on routes rendering
This commit is contained in:
parent
fc3e3b844d
commit
e427050369
5 changed files with 68 additions and 37 deletions
|
|
@ -1,5 +1,4 @@
|
||||||
import * as d3 from "d3";
|
import * as d3 from "d3";
|
||||||
import {drawPoint} from "utils/debugUtils";
|
|
||||||
|
|
||||||
import {round} from "utils/stringUtils";
|
import {round} from "utils/stringUtils";
|
||||||
|
|
||||||
|
|
@ -9,35 +8,16 @@ export function drawRoutes() {
|
||||||
const {cells, burgs} = pack;
|
const {cells, burgs} = pack;
|
||||||
const lineGen = d3.line().curve(d3.curveCatmullRom.alpha(0.1));
|
const lineGen = d3.line().curve(d3.curveCatmullRom.alpha(0.1));
|
||||||
|
|
||||||
const getBurgCoords = (burgId: number): TPoint => {
|
const SHARP_ANGLE = 135;
|
||||||
if (!burgId) throw new Error("burgId must be positive");
|
const VERY_SHARP_ANGLE = 115;
|
||||||
const burg = burgs[burgId] as IBurg;
|
|
||||||
return [burg.x, burg.y];
|
|
||||||
};
|
|
||||||
|
|
||||||
const getPathPoints = (cellIds: number[]): TPoints =>
|
|
||||||
cellIds.map(cellId => {
|
|
||||||
const burgId = cells.burg[cellId];
|
|
||||||
if (burgId) return getBurgCoords(burgId);
|
|
||||||
|
|
||||||
return cells.p[cellId];
|
|
||||||
});
|
|
||||||
|
|
||||||
const normalizePoints = (points: TPoints): TPoints =>
|
|
||||||
points.map(([x, y], index) => {
|
|
||||||
return [x, y];
|
|
||||||
|
|
||||||
if (i === 17) {
|
|
||||||
cells.forEach(cellId => drawPoint(pack.cells.p[cellId]));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
const points = adjustBurgPoints(); // mutable array of points
|
||||||
const routePaths: Dict<string[]> = {};
|
const routePaths: Dict<string[]> = {};
|
||||||
|
|
||||||
for (const {i, type, cells} of pack.routes) {
|
for (const {i, type, cells} of pack.routes) {
|
||||||
const points = getPathPoints(cells);
|
straightenPathAngles(cells); // mutates points
|
||||||
const normalizedPoints = normalizePoints(points);
|
const pathPoints = cells.map(cellId => points[cellId]);
|
||||||
const path = round(lineGen(normalizedPoints)!, 1);
|
const path = round(lineGen(pathPoints)!, 1);
|
||||||
|
|
||||||
if (!routePaths[type]) routePaths[type] = [];
|
if (!routePaths[type]) routePaths[type] = [];
|
||||||
routePaths[type].push(`<path id="${type}${i}" d="${path}"/>`);
|
routePaths[type].push(`<path id="${type}${i}" d="${path}"/>`);
|
||||||
|
|
@ -46,4 +26,49 @@ export function drawRoutes() {
|
||||||
for (const type in routePaths) {
|
for (const type in routePaths) {
|
||||||
routes.select(`[data-type=${type}]`).html(routePaths[type].join(""));
|
routes.select(`[data-type=${type}]`).html(routePaths[type].join(""));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function adjustBurgPoints() {
|
||||||
|
const points = Array.from(cells.p);
|
||||||
|
|
||||||
|
for (const burg of burgs) {
|
||||||
|
if (burg.i === 0) continue;
|
||||||
|
const {cell, x, y} = burg as IBurg;
|
||||||
|
points[cell] = [x, y];
|
||||||
|
}
|
||||||
|
|
||||||
|
return points;
|
||||||
|
}
|
||||||
|
|
||||||
|
function straightenPathAngles(cellIds: number[]) {
|
||||||
|
for (let i = 1; i < cellIds.length - 1; i++) {
|
||||||
|
const cellId = cellIds[i];
|
||||||
|
if (cells.burg[cellId]) continue;
|
||||||
|
|
||||||
|
const prev = points[cellIds[i - 1]];
|
||||||
|
const that = points[cellId];
|
||||||
|
const next = points[cellIds[i + 1]];
|
||||||
|
|
||||||
|
const dAx = prev[0] - that[0];
|
||||||
|
const dAy = prev[1] - that[1];
|
||||||
|
const dBx = next[0] - that[0];
|
||||||
|
const dBy = next[1] - that[1];
|
||||||
|
const angle = (Math.atan2(dAx * dBy - dAy * dBx, dAx * dBx + dAy * dBy) * 180) / Math.PI;
|
||||||
|
|
||||||
|
if (Math.abs(angle) < SHARP_ANGLE) {
|
||||||
|
const middleX = (prev[0] + next[0]) / 2;
|
||||||
|
const middleY = (prev[1] + next[1]) / 2;
|
||||||
|
|
||||||
|
if (Math.abs(angle) < VERY_SHARP_ANGLE) {
|
||||||
|
const newX = (that[0] + middleX * 2) / 3;
|
||||||
|
const newY = (that[1] + middleY * 2) / 3;
|
||||||
|
points[cellId] = [newX, newY];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const newX = (that[0] + middleX) / 2;
|
||||||
|
const newY = (that[1] + middleY) / 2;
|
||||||
|
points[cellId] = [newX, newY];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
import * as d3 from "d3";
|
import * as d3 from "d3";
|
||||||
|
|
||||||
import {TIME} from "config/logging";
|
import {TIME, DEBUG} from "config/logging";
|
||||||
import {last} from "utils/arrayUtils";
|
import {last} from "utils/arrayUtils";
|
||||||
import {rn} from "utils/numberUtils";
|
|
||||||
import {rand, P, gauss, ra, rw} from "utils/probabilityUtils";
|
import {rand, P, gauss, ra, rw} from "utils/probabilityUtils";
|
||||||
import {capitalize} from "utils/stringUtils";
|
import {capitalize} from "utils/stringUtils";
|
||||||
import {convertTemperature, getFriendlyHeight, getBurgPopulation} from "utils/unitUtils";
|
import {convertTemperature, getFriendlyHeight, getBurgPopulation} from "utils/unitUtils";
|
||||||
|
|
@ -112,8 +111,9 @@ window.Markers = (function () {
|
||||||
|
|
||||||
let candidates = Array.from(list(pack));
|
let candidates = Array.from(list(pack));
|
||||||
let quantity = getQuantity(candidates, min, each, multiplier);
|
let quantity = getQuantity(candidates, min, each, multiplier);
|
||||||
// uncomment for debugging:
|
|
||||||
// console.log(`${icon} ${type}: each ${each} of ${candidates.length}, min ${min} candidates. Got ${quantity}`);
|
DEBUG &&
|
||||||
|
console.info(`${icon} ${type}: each ${each} of ${candidates.length}, min ${min} candidates. Got ${quantity}`);
|
||||||
|
|
||||||
while (quantity && candidates.length) {
|
while (quantity && candidates.length) {
|
||||||
const [cell] = extractAnyElement(candidates);
|
const [cell] = extractAnyElement(candidates);
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import {TIME} from "config/logging";
|
import {INFO, TIME} from "config/logging";
|
||||||
import {getInputNumber} from "utils/nodeUtils";
|
import {getInputNumber} from "utils/nodeUtils";
|
||||||
import {MAX_HEIGHT, MIN_LAND_HEIGHT} from "config/generation";
|
import {MAX_HEIGHT, MIN_LAND_HEIGHT} from "config/generation";
|
||||||
|
|
||||||
|
|
@ -46,7 +46,7 @@ export function addLakesInDeepDepressions(heights: Uint8Array, neighbours: numbe
|
||||||
|
|
||||||
if (inDeepDepression) {
|
if (inDeepDepression) {
|
||||||
currentHeights[cellId] = MIN_LAND_HEIGHT - 1;
|
currentHeights[cellId] = MIN_LAND_HEIGHT - 1;
|
||||||
console.log(`ⓘ Added lake at deep depression. Cell: ${cellId}`);
|
INFO && console.info(`ⓘ Added lake at deep depression. Cell: ${cellId}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@ import FlatQueue from "flatqueue";
|
||||||
import {TIME} from "config/logging";
|
import {TIME} from "config/logging";
|
||||||
import {ELEVATION, MIN_LAND_HEIGHT, ROUTES} from "config/generation";
|
import {ELEVATION, MIN_LAND_HEIGHT, ROUTES} from "config/generation";
|
||||||
import {dist2} from "utils/functionUtils";
|
import {dist2} from "utils/functionUtils";
|
||||||
import {drawLine} from "utils/debugUtils";
|
|
||||||
|
|
||||||
export function generateRoutes(
|
export function generateRoutes(
|
||||||
burgs: TBurgs,
|
burgs: TBurgs,
|
||||||
|
|
@ -37,8 +36,6 @@ export function generateRoutes(
|
||||||
const points: TPoints = featureCapitals.map(burg => [burg.x, burg.y]);
|
const points: TPoints = featureCapitals.map(burg => [burg.x, burg.y]);
|
||||||
const urquhartEdges = calculateUrquhartEdges(points);
|
const urquhartEdges = calculateUrquhartEdges(points);
|
||||||
urquhartEdges.forEach(([fromId, toId]) => {
|
urquhartEdges.forEach(([fromId, toId]) => {
|
||||||
drawLine(points[fromId], points[toId], {stroke: "red", strokeWidth: 0.01});
|
|
||||||
|
|
||||||
const start = featureCapitals[fromId].cell;
|
const start = featureCapitals[fromId].cell;
|
||||||
const exit = featureCapitals[toId].cell;
|
const exit = featureCapitals[toId].cell;
|
||||||
|
|
||||||
|
|
@ -70,8 +67,6 @@ export function generateRoutes(
|
||||||
const points: TPoints = featureBurgs.map(burg => [burg.x, burg.y]);
|
const points: TPoints = featureBurgs.map(burg => [burg.x, burg.y]);
|
||||||
const urquhartEdges = calculateUrquhartEdges(points);
|
const urquhartEdges = calculateUrquhartEdges(points);
|
||||||
urquhartEdges.forEach(([fromId, toId]) => {
|
urquhartEdges.forEach(([fromId, toId]) => {
|
||||||
drawLine(points[fromId], points[toId], {strokeWidth: 0.01});
|
|
||||||
|
|
||||||
const start = featureBurgs[fromId].cell;
|
const start = featureBurgs[fromId].cell;
|
||||||
const exit = featureBurgs[toId].cell;
|
const exit = featureBurgs[toId].cell;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -44,3 +44,14 @@ export function drawArrow([x1, y1]: TPoint, [x2, y2]: TPoint, {width = 1, color
|
||||||
.attr("stroke", color)
|
.attr("stroke", color)
|
||||||
.attr("stroke-width", width / 2);
|
.attr("stroke-width", width / 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function drawText(text: string | number, [x, y]: TPoint, {size = 6, color = "black"} = {}) {
|
||||||
|
debug
|
||||||
|
.append("text")
|
||||||
|
.attr("x", x)
|
||||||
|
.attr("y", y)
|
||||||
|
.attr("font-size", size)
|
||||||
|
.attr("fill", color)
|
||||||
|
.attr("stroke", "none")
|
||||||
|
.text(text);
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue