mirror of
https://github.com/Azgaar/Fantasy-Map-Generator.git
synced 2026-02-04 17:41:23 +01:00
Ice Layer Data Model (#1262)
* prototype for ice seperation * feat: migrate ice data to new data model and update version to 1.110.0 * refactor: update ice data handling and rendering for improved performance * feat: integrate ice generation and recalculation in heightmap editing * fix ice selection(hopefully) * fix ice selection better(pls) * refactor: remove redundant element selection in ice editing functions * fix: clear ice data before generating glaciers and icebergs * sparse array implementation with reduced updates * fix logic chech in modules/dynamic/auto-update.js Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * fix: migrate ice data to new data model structure * refactor: streamline ice generation process and clean up rendering functions * refactor: simplify ice rendering logic by removing redundant clearing of old SVG * fix: update editIce function to accept element parameter and improve logic for glacier handling * ice drawing with only type on less occuring glaciers * feat: add compactPackData function to filter out undefined glaciers and icebergs * fix: clear existing ice elements before redrawing in editHeightmap function * fix compact problems on autosave * refactor: unify ice data structure and streamline ice element handling * refactor: improve getNextId function to fill gaps in ice element IDs(optional commit) * just to be sure * bump version in html * fix index.html script import --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
parent
b223dc62da
commit
e597d905eb
13 changed files with 402 additions and 118 deletions
|
|
@ -26,7 +26,7 @@ function clicked() {
|
|||
else if (ancestor.id === "labels" && el.tagName === "tspan") editLabel();
|
||||
else if (grand.id === "burgLabels") editBurg();
|
||||
else if (grand.id === "burgIcons") editBurg();
|
||||
else if (parent.id === "ice") editIce();
|
||||
else if (parent.id === "ice") editIce(el);
|
||||
else if (parent.id === "terrain") editReliefIcon();
|
||||
else if (grand.id === "markers" || great.id === "markers") editMarker();
|
||||
else if (grand.id === "coastline") editCoastline();
|
||||
|
|
|
|||
|
|
@ -259,6 +259,8 @@ function editHeightmap(options) {
|
|||
Rivers.specify();
|
||||
Lakes.defineNames();
|
||||
|
||||
Ice.generate();
|
||||
|
||||
Military.generate();
|
||||
Markers.generate();
|
||||
Zones.generate();
|
||||
|
|
@ -465,6 +467,10 @@ function editHeightmap(options) {
|
|||
.attr("id", d => base + d);
|
||||
});
|
||||
|
||||
// recalculate ice
|
||||
Ice.generate();
|
||||
ice.selectAll("*").remove();
|
||||
|
||||
TIME && console.timeEnd("restoreRiskedData");
|
||||
INFO && console.groupEnd("Edit Heightmap");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,26 +1,32 @@
|
|||
"use strict";
|
||||
function editIce() {
|
||||
function editIce(element) {
|
||||
if (customization) return;
|
||||
if (elSelected && element === elSelected.node()) return;
|
||||
|
||||
closeDialogs(".stable");
|
||||
if (!layerIsOn("toggleIce")) toggleIce();
|
||||
|
||||
elSelected = d3.select(d3.event.target);
|
||||
const type = elSelected.attr("type") ? "Glacier" : "Iceberg";
|
||||
document.getElementById("iceRandomize").style.display = type === "Glacier" ? "none" : "inline-block";
|
||||
document.getElementById("iceSize").style.display = type === "Glacier" ? "none" : "inline-block";
|
||||
if (type === "Iceberg") document.getElementById("iceSize").value = +elSelected.attr("size");
|
||||
const id = +elSelected.attr("data-id");
|
||||
const iceElement = pack.ice.find(el => el.i === id);
|
||||
const isGlacier = elSelected.attr("type") === "glacier";
|
||||
const type = isGlacier ? "Glacier" : "Iceberg";
|
||||
|
||||
document.getElementById("iceRandomize").style.display = isGlacier ? "none" : "inline-block";
|
||||
document.getElementById("iceSize").style.display = isGlacier ? "none" : "inline-block";
|
||||
if (!isGlacier) document.getElementById("iceSize").value = iceElement?.size || "";
|
||||
|
||||
ice.selectAll("*").classed("draggable", true).call(d3.drag().on("drag", dragElement));
|
||||
|
||||
$("#iceEditor").dialog({
|
||||
title: "Edit " + type,
|
||||
resizable: false,
|
||||
position: {my: "center top+60", at: "top", of: d3.event, collision: "fit"},
|
||||
position: { my: "center top+60", at: "top", of: d3.event, collision: "fit" },
|
||||
close: closeEditor
|
||||
});
|
||||
|
||||
if (modules.editIce) return;
|
||||
modules.editIce = true;
|
||||
|
||||
// add listeners
|
||||
document.getElementById("iceEditStyle").addEventListener("click", () => editStyle("ice"));
|
||||
document.getElementById("iceRandomize").addEventListener("click", randomizeShape);
|
||||
|
|
@ -28,29 +34,18 @@ function editIce() {
|
|||
document.getElementById("iceNew").addEventListener("click", toggleAdd);
|
||||
document.getElementById("iceRemove").addEventListener("click", removeIce);
|
||||
|
||||
|
||||
function randomizeShape() {
|
||||
const c = grid.points[+elSelected.attr("cell")];
|
||||
const s = +elSelected.attr("size");
|
||||
const i = ra(grid.cells.i),
|
||||
cn = grid.points[i];
|
||||
const poly = getGridPolygon(i).map(p => [p[0] - cn[0], p[1] - cn[1]]);
|
||||
const points = poly.map(p => [rn(c[0] + p[0] * s, 2), rn(c[1] + p[1] * s, 2)]);
|
||||
elSelected.attr("points", points);
|
||||
const selectedId = +elSelected.attr("data-id");
|
||||
Ice.randomizeIcebergShape(selectedId);
|
||||
redrawIceberg(selectedId);
|
||||
}
|
||||
|
||||
function changeSize() {
|
||||
const c = grid.points[+elSelected.attr("cell")];
|
||||
const s = +elSelected.attr("size");
|
||||
const flat = elSelected
|
||||
.attr("points")
|
||||
.split(",")
|
||||
.map(el => +el);
|
||||
const pairs = [];
|
||||
while (flat.length) pairs.push(flat.splice(0, 2));
|
||||
const poly = pairs.map(p => [(p[0] - c[0]) / s, (p[1] - c[1]) / s]);
|
||||
const size = +this.value;
|
||||
const points = poly.map(p => [rn(c[0] + p[0] * size, 2), rn(c[1] + p[1] * size, 2)]);
|
||||
elSelected.attr("points", points).attr("size", size);
|
||||
const newSize = +this.value;
|
||||
const selectedId = +elSelected.attr("data-id");
|
||||
Ice.changeIcebergSize(selectedId, newSize);
|
||||
redrawIceberg(selectedId);
|
||||
}
|
||||
|
||||
function toggleAdd() {
|
||||
|
|
@ -67,17 +62,15 @@ function editIce() {
|
|||
function addIcebergOnClick() {
|
||||
const [x, y] = d3.mouse(this);
|
||||
const i = findGridCell(x, y, grid);
|
||||
const [cx, cy] = grid.points[i];
|
||||
const size = +document.getElementById("iceSize")?.value || 1;
|
||||
|
||||
const points = getGridPolygon(i).map(([x, y]) => [rn(lerp(cx, x, size), 2), rn(lerp(cy, y, size), 2)]);
|
||||
const iceberg = ice.append("polygon").attr("points", points).attr("cell", i).attr("size", size);
|
||||
iceberg.call(d3.drag().on("drag", dragElement));
|
||||
Ice.addIceberg(i, size);
|
||||
|
||||
if (d3.event.shiftKey === false) toggleAdd();
|
||||
}
|
||||
|
||||
function removeIce() {
|
||||
const type = elSelected.attr("type") ? "Glacier" : "Iceberg";
|
||||
const type = elSelected.attr("type") === "glacier" ? "Glacier" : "Iceberg";
|
||||
alertMessage.innerHTML = /* html */ `Are you sure you want to remove the ${type}?`;
|
||||
$("#alert").dialog({
|
||||
resizable: false,
|
||||
|
|
@ -85,7 +78,7 @@ function editIce() {
|
|||
buttons: {
|
||||
Remove: function () {
|
||||
$(this).dialog("close");
|
||||
elSelected.remove();
|
||||
Ice.removeIce(+elSelected.attr("data-id"));
|
||||
$("#iceEditor").dialog("close");
|
||||
},
|
||||
Cancel: function () {
|
||||
|
|
@ -96,14 +89,24 @@ function editIce() {
|
|||
}
|
||||
|
||||
function dragElement() {
|
||||
const tr = parseTransform(this.getAttribute("transform"));
|
||||
const dx = +tr[0] - d3.event.x,
|
||||
dy = +tr[1] - d3.event.y;
|
||||
const selectedId = +elSelected.attr("data-id");
|
||||
const initialTransform = parseTransform(this.getAttribute("transform"));
|
||||
const dx = initialTransform[0] - d3.event.x;
|
||||
const dy = initialTransform[1] - d3.event.y;
|
||||
|
||||
d3.event.on("drag", function () {
|
||||
const x = d3.event.x,
|
||||
y = d3.event.y;
|
||||
this.setAttribute("transform", `translate(${dx + x},${dy + y})`);
|
||||
const x = d3.event.x;
|
||||
const y = d3.event.y;
|
||||
const transform = `translate(${dx + x},${dy + y})`;
|
||||
this.setAttribute("transform", transform);
|
||||
|
||||
// Update data model with new position
|
||||
const offset = [dx + x, dy + y];
|
||||
const iceData = pack.ice.find(element => element.i === selectedId);
|
||||
if (iceData) {
|
||||
// Store offset for visual positioning, actual geometry stays in points
|
||||
iceData.offset = offset;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -114,3 +117,4 @@ function editIce() {
|
|||
unselect();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -417,49 +417,6 @@ function toggleIce(event) {
|
|||
}
|
||||
}
|
||||
|
||||
function drawIce() {
|
||||
TIME && console.time("drawIce");
|
||||
|
||||
const {cells, features} = grid;
|
||||
const {temp, h} = cells;
|
||||
Math.random = aleaPRNG(seed);
|
||||
|
||||
const ICEBERG_MAX_TEMP = 0;
|
||||
const GLACIER_MAX_TEMP = -8;
|
||||
const minMaxTemp = d3.min(temp);
|
||||
|
||||
// cold land: draw glaciers
|
||||
{
|
||||
const type = "iceShield";
|
||||
const getType = cellId => (h[cellId] >= 20 && temp[cellId] <= GLACIER_MAX_TEMP ? type : null);
|
||||
const isolines = getIsolines(grid, getType, {polygons: true});
|
||||
isolines[type]?.polygons?.forEach(points => {
|
||||
const clipped = clipPoly(points);
|
||||
ice.append("polygon").attr("points", clipped).attr("type", type);
|
||||
});
|
||||
}
|
||||
|
||||
// cold water: draw icebergs
|
||||
for (const cellId of grid.cells.i) {
|
||||
const t = temp[cellId];
|
||||
if (h[cellId] >= 20) continue; // no icebergs on land
|
||||
if (t > ICEBERG_MAX_TEMP) continue; // too warm: no icebergs
|
||||
if (features[cells.f[cellId]].type === "lake") continue; // no icebers on lakes
|
||||
if (P(0.8)) continue; // skip most of eligible cells
|
||||
|
||||
const randomFactor = 0.8 + rand() * 0.4; // random size factor
|
||||
let baseSize = (1 - normalize(t, minMaxTemp, 1)) * 0.8; // size: 0 = zero size, 1 = full size
|
||||
if (cells.t[cellId] === -1) baseSize /= 1.3; // coasline: smaller icebergs
|
||||
const size = minmax(rn(baseSize * randomFactor, 2), 0.1, 1);
|
||||
|
||||
const [cx, cy] = grid.points[cellId];
|
||||
const points = getGridPolygon(cellId).map(([x, y]) => [rn(lerp(cx, x, size), 2), rn(lerp(cy, y, size), 2)]);
|
||||
ice.append("polygon").attr("points", points).attr("cell", cellId).attr("size", size);
|
||||
}
|
||||
|
||||
TIME && console.timeEnd("drawIce");
|
||||
}
|
||||
|
||||
function toggleCultures(event) {
|
||||
const cultures = pack.cultures.filter(c => c.i && !c.removed);
|
||||
const empty = !cults.selectAll("path").size();
|
||||
|
|
|
|||
|
|
@ -555,7 +555,7 @@ function regenerateMilitary() {
|
|||
|
||||
function regenerateIce() {
|
||||
if (!layerIsOn("toggleIce")) toggleIce();
|
||||
ice.selectAll("*").remove();
|
||||
Ice.generate();
|
||||
drawIce();
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue