Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Draft] Alternative grids #1100

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 21 additions & 4 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -1616,6 +1616,22 @@
</td>
</tr>

<tr data-tip="Select points sampling algorithm. Defines structure of the underlying graph">
<td>
<i data-locked="0" id="lock_gridType" class="icon-lock-open"></i>
</td>
<td>Grid type</td>
<td>
<select id="gridType" data-stored="gridType">
<option value="jittered" selected>Jittered</option>
<option value="hexFlat">Hex flat</option>
<option value="hexPointy">Hex pointy</option>
<option value="square">Square</option>
</select>
</td>
<td></td>
</tr>

<tr data-tip="Define map name (will be used to name downloaded files)">
<td>
<i data-locked="0" id="lock_mapName" class="icon-lock-open"></i>
Expand Down Expand Up @@ -8080,7 +8096,7 @@
<script src="utils/commonUtils.js?v=1.89.29"></script>
<script src="utils/arrayUtils.js"></script>
<script src="utils/colorUtils.js"></script>
<script src="utils/graphUtils.js?v=1.96.00"></script>
<script src="utils/graphUtils.js?v=1.99.00"></script>
<script src="utils/nodeUtils.js"></script>
<script src="utils/numberUtils.js?v=1.89.08"></script>
<script src="utils/polyfills.js?v=1.95.03"></script>
Expand All @@ -8090,6 +8106,7 @@
<script src="utils/unitUtils.js?v=1.87.00"></script>

<script src="modules/voronoi.js"></script>
<script src="modules/points-generator.js"></script>
<script src="config/heightmap-templates.js"></script>
<script src="config/precreated-heightmaps.js"></script>
<script src="modules/heightmap-generator.js?v=1.88.00"></script>
Expand Down Expand Up @@ -8117,7 +8134,7 @@

<script src="modules/ui/general.js?v=1.98.01"></script>
<script src="modules/ui/options.js?v=1.98.04"></script>
<script src="main.js?v=1.98.01"></script>
<script src="main.js?v=1.99.00"></script>

<script defer src="modules/relief-icons.js"></script>
<script defer src="modules/ui/style.js?v=1.96.00"></script>
Expand Down Expand Up @@ -8158,8 +8175,8 @@
<script defer src="modules/coa-renderer.js?v=1.94.00"></script>
<script defer src="libs/rgbquant.min.js"></script>
<script defer src="libs/jquery.ui.touch-punch.min.js"></script>
<script defer src="modules/io/save.js?v=1.98.01"></script>
<script defer src="modules/io/load.js?v=1.98.01"></script>
<script defer src="modules/io/save.js?v=1.99.00"></script>
<script defer src="modules/io/load.js?v=1.99.00"></script>
<script defer src="modules/io/cloud.js?v=1.96.00"></script>
<script defer src="modules/io/export.js?v=1.98.05"></script>

Expand Down
96 changes: 80 additions & 16 deletions main.js
Original file line number Diff line number Diff line change
Expand Up @@ -310,12 +310,58 @@ async function checkLoadParameters() {
generateMapOnLoad();
}

function debugGrids() {
// debug
// .selectAll("circle.grid")
// .data(grid.points)
// .enter()
// .append("circle")
// .attr("data-id", (d, i) => "point-" + i)
// .attr("cx", d => d[0])
// .attr("cy", d => d[1])
// .attr("r", 0.5)
// .attr("fill", "blue");

let path = "";
grid.cells.i.forEach(i => (path += "M" + getGridPolygon(i)));
debug.append("path").attr("fill", "none").attr("stroke", "blue").attr("stroke-width", 0.3).attr("d", path);

// debug
// .selectAll("circle.boundary")
// .data(grid.boundary)
// .enter()
// .append("circle")
// .attr("cx", d => d[0])
// .attr("cy", d => d[1])
// .attr("r", 0.3)
// .attr("fill", "white");

zoom.translateExtent([
[-graphWidth / 2, -graphHeight / 2],
[graphWidth * 1.5, graphHeight * 1.5]
]);

const text = debug
.append("g")
.style("font-size", "0.5px")
.attr("text-anchor", "middle")
.attr("dominant-baseline", "central");

for (let x = 0; x < 100; x++) {
for (let y = 0; y < 100; y++) {
const cellId = findGridCell(x, y, grid);
text.append("text").attr("x", x).attr("y", y).text(cellId);
}
}
}

async function generateMapOnLoad() {
await applyStyleOnLoad(); // apply previously selected default or custom style
await generate(); // generate map
applyPreset(); // apply saved layers preset
fitMapToScreen();
focusOn(); // based on searchParams focus on point, cell or burg from MFCG
debugGrids();
}

// focus on coordinates, cell or burg provided in searchParams
Expand Down Expand Up @@ -1034,15 +1080,22 @@ function generatePrecipitation() {
const MAX_PASSABLE_ELEVATION = 85;

// define wind directions based on cells latitude and prevailing winds there
d3.range(0, cells.i.length, cellsX).forEach(function (c, i) {
d3.range(0, cells.i.length, cellsX).forEach(function (cellId, i) {
// debug
// .append("circle")
// .attr("cx", grid.points[cellId][0])
// .attr("cy", grid.points[cellId][1])
// .attr("r", 2)
// .attr("fill", "blue");

const lat = mapCoordinates.latN - (i / cellsY) * mapCoordinates.latT;
const latBand = ((Math.abs(lat) - 1) / 5) | 0;
const latMod = latitudeModifier[latBand];
const windTier = (Math.abs(lat - 89) / 30) | 0; // 30d tiers from 0 to 5 from N to S
const {isWest, isEast, isNorth, isSouth} = getWindDirections(windTier);

if (isWest) westerly.push([c, latMod, windTier]);
if (isEast) easterly.push([c + cellsX - 1, latMod, windTier]);
if (isWest) westerly.push([cellId, latMod, windTier]);
if (isEast) easterly.push([cellId + cellsX - 1, latMod, windTier]);
if (isNorth) northerly++;
if (isSouth) southerly++;
});
Expand All @@ -1066,6 +1119,8 @@ function generatePrecipitation() {
passWind(d3.range(cells.i.length - cellsX, cells.i.length, 1), maxPrecS, -cellsX, cellsY);
}

drawWindDirection();

function getWindDirections(tier) {
const angle = options.winds[tier];

Expand Down Expand Up @@ -1120,24 +1175,25 @@ function generatePrecipitation() {
return minmax(normalLoss + diff * mod, 1, humidity);
}

void (function drawWindDirection() {
function drawWindDirection() {
const wind = prec.append("g").attr("id", "wind");

d3.range(0, 6).forEach(function (t) {
options.winds.forEach((direction, tier) => {
if (westerly.length > 1) {
const west = westerly.filter(w => w[2] === t);
const west = westerly.filter(w => w[2] === tier);
if (west && west.length > 3) {
const from = west[0][0],
to = west[west.length - 1][0];
const from = west.at(0)[0];
const to = west.at(-1)[0];
const y = (grid.points[from][1] + grid.points[to][1]) / 2;
wind.append("text").attr("x", 20).attr("y", y).text("\u21C9");
}
}

if (easterly.length > 1) {
const east = easterly.filter(w => w[2] === t);
const east = easterly.filter(w => w[2] === tier);
if (east && east.length > 3) {
const from = east[0][0],
to = east[east.length - 1][0];
const from = east.at(0)[0];
const to = east.at(-1)[0];
const y = (grid.points[from][1] + grid.points[to][1]) / 2;
wind
.append("text")
Expand All @@ -1160,7 +1216,7 @@ function generatePrecipitation() {
.attr("x", graphWidth / 2)
.attr("y", graphHeight - 20)
.text("\u21C8");
})();
}

TIME && console.timeEnd("generatePrecipitation");
}
Expand All @@ -1169,20 +1225,24 @@ function generatePrecipitation() {
function reGraph() {
TIME && console.time("reGraph");
const {cells: gridCells, points, features} = grid;
const repackGridCells = grid.type === "jittered";
const newCells = {p: [], g: [], h: []}; // store new data
const spacing2 = grid.spacing ** 2;

for (const i of gridCells.i) {
const height = gridCells.h[i];
const type = gridCells.t[i];
if (height < 20 && type !== -1 && type !== -2) continue; // exclude all deep ocean points
if (type === -2 && (i % 4 === 0 || features[gridCells.f[i]].type === "lake")) continue; // exclude non-coastal lake points
const [x, y] = points[i];

if (repackGridCells) {
if (height < 20 && type !== -1 && type !== -2) continue; // exclude all deep ocean points
if (type === -2 && (i % 4 === 0 || features[gridCells.f[i]].type === "lake")) continue; // exclude non-coastal lake points
}

const [x, y] = points[i];
addNewPoint(i, x, y, height);

// add additional points for cells along coast
if (type === 1 || type === -1) {
if (repackGridCells && (type === 1 || type === -1)) {
if (gridCells.b[i]) continue; // not for near-border cells
gridCells.c[i].forEach(function (e) {
if (i > e) return;
Expand Down Expand Up @@ -1253,6 +1313,8 @@ function drawCoastline() {
vchain.map(v => vertices.p[v]),
1
);
if (points.length < 3) debugger;

const area = d3.polygonArea(points); // area with lakes/islands
if (area > 0 && features[f].type === "lake") {
points = points.reverse();
Expand Down Expand Up @@ -1962,6 +2024,8 @@ const regenerateMap = debounce(async function (options) {
fitMapToScreen();
shouldShowLoading && hideLoading();
clearMainTip();

debugGrids();
}, 250);

// clear the map
Expand Down
5 changes: 5 additions & 0 deletions modules/dynamic/auto-update.js
Original file line number Diff line number Diff line change
Expand Up @@ -858,4 +858,9 @@ export function resolveVersionConflicts(version) {
shiftCompass();
}
}

if (version < 1.99) {
// v1.99.00 added alternative graph point sampling methods
if (!graph.type) graph.type = "jittered";
}
}
2 changes: 1 addition & 1 deletion modules/io/load.js
Original file line number Diff line number Diff line change
Expand Up @@ -457,7 +457,7 @@ async function parseLoadedData(data, mapVersion) {
{
// dynamically import and run auto-update script
const versionNumber = parseFloat(params[0]);
const {resolveVersionConflicts} = await import("../dynamic/auto-update.js?v=1.98.00");
const {resolveVersionConflicts} = await import("../dynamic/auto-update.js?v=1.99.00");
resolveVersionConflicts(versionNumber);
}

Expand Down
101 changes: 101 additions & 0 deletions modules/points-generator.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
"use strict";

const pointsGenerators = {
jittered: generateJitteredPoints,
hexFlat: generateHexFlatPoints,
hexPointy: generateHexPointyPoints,
square: generateSquarePoints
};

function generatePoints() {
TIME && console.time("placePoints");
const cellsDesired = +byId("pointsInput").dataset.cells;
const spacing = Math.sqrt((graphWidth * graphHeight) / cellsDesired); // spacing between points
const boundary = getBoundaryPoints(graphWidth, graphHeight, spacing);

const type = byId("gridType").value;
const {points, cellsX, cellsY} = pointsGenerators[type](graphWidth, graphHeight, spacing);
TIME && console.timeEnd("placePoints");

return {spacing, cellsDesired, type, boundary, points, cellsX, cellsY};
}

function generateJitteredPoints(width, height, spacing) {
return generateSquareJitteredPoints(0.9, width, height, spacing);
}

function generateSquarePoints(width, height, spacing) {
return generateSquareJitteredPoints(0, width, height, spacing);
}

function generateSquareJitteredPoints(jittering, width, height, spacing) {
const radius = spacing / 2;
const maxDeviation = radius * jittering;
const jitter = () => (jittering ? Math.random() * maxDeviation * 2 - maxDeviation : 0);

let points = [];
for (let y = radius; y < height; y += spacing) {
for (let x = radius; x < width; x += spacing) {
const xj = Math.min(rn(x + jitter(), 2), width);
const yj = Math.min(rn(y + jitter(), 2), height);
points.push([xj, yj]);
}
}

const cellsX = Math.floor((width + 0.5 * spacing - 1e-10) / spacing);
const cellsY = Math.floor((height + 0.5 * spacing - 1e-10) / spacing);
return {points, cellsX, cellsY};
}

function generateHexFlatPoints(width, height, spacing) {
return generateHexPoints(false, width, height, spacing);
}

function generateHexPointyPoints(width, height, spacing) {
return generateHexPoints(true, width, height, spacing);
}

function generateHexPoints(isPointy, width, height, spacing) {
const hexRatio = Math.sqrt(3) / 2;
const spacingX = isPointy ? spacing / hexRatio : spacing * 2;
const spacingY = isPointy ? spacing : spacing / hexRatio / 2;
const maxWidth = width + spacingX / 2;
const maxHeight = height + spacingY / 2;
const indentionX = spacingX / 2;

let points = [];
for (let y = 0, row = 0; y < maxHeight; y += spacingY, row++) {
for (let x = row % 2 ? 0 : indentionX; x < maxWidth; x += spacingX) {
if (x > width) x = width;
if (y > height) y = height;
points.push([rn(x, 2), rn(y, 2)]);
}
}

const cellsX = Math.ceil(width / spacingX);
const cellsY = Math.ceil(height / spacingY);
return {points, cellsX, cellsY};
}

// add points along map edge to pseudo-clip voronoi cells
function getBoundaryPoints(width, height, spacing) {
const offset = rn(-1 * spacing);
const bSpacing = spacing * 2;
const w = width - offset * 2;
const h = height - offset * 2;
const numberX = Math.ceil(w / bSpacing) - 1;
const numberY = Math.ceil(h / bSpacing) - 1;
const points = [];

for (let i = 0.5; i < numberX; i++) {
let x = Math.ceil((w * i) / numberX + offset);
points.push([x, offset], [x, h + offset]);
}

for (let i = 0.5; i < numberY; i++) {
let y = Math.ceil((h * i) / numberY + offset);
points.push([offset, y], [w + offset, y]);
}

return points;
}
2 changes: 2 additions & 0 deletions modules/ui/general.js
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,8 @@ function showMapTooltip(point, e, i, g) {
const subgroup = path[path.length - 8].id;
const land = pack.cells.h[i] >= 20;

// console.log(findGridCell(point[0], point[1], grid));

// specific elements
if (group === "armies") return tip(e.target.parentNode.dataset.name + ". Click to edit");

Expand Down
Loading