From d2bd611412277c9b6bbbdc4840335ec5b474126e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9sz=C3=A1ros=20Gergely?= Date: Mon, 13 Sep 2021 15:58:55 +0200 Subject: [PATCH] better cell sampler --- modules/submap.js | 99 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 79 insertions(+), 20 deletions(-) diff --git a/modules/submap.js b/modules/submap.js index ef0618f8..f3eee5e8 100644 --- a/modules/submap.js +++ b/modules/submap.js @@ -40,19 +40,32 @@ window.Submap = (function () { grid.cells.h = new Uint8Array(n); // heightmap grid.cells.temp = new Int8Array(n); // temperature grid.cells.prec = new Int8Array(n); // precipitation + const reverseGridMap = new Uint32Array(n); // cellmap from new -> oldcell - const gridCells = parentMap.grid.cells; + const oldGrid = parentMap.grid; // build cache old -> [newcelllist] const forwardGridMap = parentMap.grid.points.map(_=>[]); resampler(grid.points, parentMap.pack.cells.q, (id, oldid) => { const cid = parentMap.pack.cells.g[oldid]; - grid.cells.h[id] = gridCells.h[cid]; - grid.cells.temp[id] = gridCells.temp[cid]; - grid.cells.prec[id] = gridCells.prec[cid]; + grid.cells.h[id] = oldGrid.cells.h[cid]; + grid.cells.temp[id] = oldGrid.cells.temp[cid]; + grid.cells.prec[id] = oldGrid.cells.prec[cid]; if (options.depressRivers) forwardGridMap[cid].push(id); + reverseGridMap[id] = cid; }) // TODO: add smooth/noise function for h, temp, prec n times + // smooth heightmap + // smoothing never should change cell type (land->water or water->land) + const gcells = grid.cells; + gcells.h.forEach((h,i) => { + const hs = gcells.c[i].map(c=>gcells.h[c]) + hs.push(h) + gcells.h[i] = h>=20 + ? Math.max(d3.mean(hs),20) + : Math.min(d3.mean(hs),19); + }); + if (options.depressRivers) { stage("Generating riverbeds.") const rbeds = new Uint16Array(grid.cells.i.length); @@ -60,7 +73,7 @@ window.Submap = (function () { // and erode riverbeds parentMap.pack.rivers.forEach(r => r.cells.forEach(oldpc => { - if (oldpc < 0) return; // ignore out of map marker (-1) + if (oldpc < 0) return; // ignore out-of-map marker (-1) const oldc = parentMap.pack.cells.g[oldpc]; const targetCells = forwardGridMap[oldc]; if (!targetCells) @@ -102,10 +115,12 @@ window.Submap = (function () { stage("Define coastline.") drawCoastline(); - // resample packed graph + /****************************************************/ + /* Packed Graph */ + /****************************************************/ const oldCells = parentMap.pack.cells; - const reverseMap = new Map(); // cellmap from new -> oldcell - const forwardMap = parentMap.pack.cells.p.map(_=>[]); // old -> [newcelllist] + // const reverseMap = new Map(); // cellmap from new -> oldcell + // const forwardMap = parentMap.pack.cells.p.map(_=>[]); // old -> [newcelllist] const pn = pack.cells.i.length; const cells = pack.cells; @@ -115,28 +130,72 @@ window.Submap = (function () { cells.religion = new Uint16Array(pn); cells.road = new Uint16Array(pn); cells.crossroad = new Uint16Array(pn); + cells.province = new Uint16Array(pn); stage("Resampling culture, state and religion map.") - resampler(cells.p, oldCells.q, (id, oldid) => { - if (cells.t[id] * oldCells.t[oldid] < 0) { - // fix missmaped cell: water instead of land or vice versa - WARN && console.warn('Type discrepancy detected:', id, oldid, `${pack.cells.t[id]} != ${oldCells.t[oldid]}`); - const aid = cells.t[id]<0 - ? cells.c[id].find(c=>cells.t[c]<0) - : cells.c[id].find(c=>cells.t[c]>0); - const [x, y] = cells.p[aid]; + + for(const [id, gridCellId] of cells.g.entries()) { + const oldGridId = reverseGridMap[gridCellId]; + if (!oldGridId) { + console.error("oldgridid must be defined for", gridCellId, reverseGridMap); + throw(new Error("oldgridid")) + } + // find old parent's children + const oldChildren = oldCells.i.filter(oid=>oldCells.g[oid]==oldGridId); + const isWater = x => x < 1? true: false; + let oldid; // matching cell on the original map + + if (!oldChildren.length) { + // it *must* be a (deleted) deep ocean cell + if (!oldGrid.cells.h[oldGridId] < 20) { + console.error(`Warning, ${gridCellId} should be water cell, not ${oldGrid.cells.h[oldGridId]}`); + continue; + } + // find replacement: closest water cell + const [ox, oy] = cells.p[id] const [tx, ty] = projection(x, y, true); oldid = oldCells.q.find(tx,ty,Infinity)[2]; - WARN && console.warn(`using cell ${aid}->${oldid} instead`); + if (!oldid) { + console.warn("Warning, no id found in quad", id, "parent", gridCellId); + continue; + } + } else { + // find closest children (packcell) on the parent map + const distance = x => (x[0]-cells.p[id][0])**2 + (x[1]-cells.p[id][1])**2; + let d = Infinity; + oldChildren.forEach(oid => { + // must be the same type (it should be always true!) + if (isWater(oldCells.t[oid]) !== isWater(cells.t[id])) { + console.error( + "should be the same", oid, id, oldCells.t[oid], cells.t[id], + "oldparent", oldCells.g[oid], "newparent", cells.g[id], + "oldheight:", oldGrid.cells.h[oldCells.g[oid]], + "newheight", grid.cells.h[cells.g[id]]) + throw new Error("should be the same type") + } + + const nd = distance(oldCells.p[oid]); + if (nd < d) [d, oldid] = [nd, oid]; + }) + if (!oldid) { + console.warn("Warning, no match for", id, "parent", gridCellId, "in"); + continue; + } + } + + if (isWater(cells.t[id]) !== isWater(oldCells.t[oldid])) { + // fix missmaped cell: water instead of land or vice versa + WARN && console.warn('Type discrepancy detected:', id, oldid, `${pack.cells.t[id]} != ${oldCells.t[oldid]}`); } cells.culture[id] = oldCells.culture[oldid]; cells.state[id] = oldCells.state[oldid]; cells.religion[id] = oldCells.religion[oldid]; - reverseMap.set(id, oldid) - forwardMap[oldid].push(id) - }) + cells.province[id] = oldCells.province[oldid]; + // reverseMap.set(id, oldid) + // forwardMap[oldid].push(id) + } stage("Regenerating river network.") Rivers.generate();