inversion tool

This commit is contained in:
Azgaar 2022-05-21 22:43:06 +03:00
parent 63db344e06
commit 2713f6bfda
4 changed files with 122 additions and 58 deletions

View file

@ -2959,6 +2959,7 @@
<button data-type="Trough" data-tip="Trough: elongated depression">T</button> <button data-type="Trough" data-tip="Trough: elongated depression">T</button>
<button data-type="Strait" data-tip="Strait: centered vertical or horizontal depression">S</button> <button data-type="Strait" data-tip="Strait: centered vertical or horizontal depression">S</button>
<button data-type="Mask" data-tip="Mask: lower cells near edges or in map center">M</button> <button data-type="Mask" data-tip="Mask: lower cells near edges or in map center">M</button>
<button data-type="Invert" data-tip="Invert heightmap along the axes">I</button>
<button data-type="Add" data-tip="Add or subtract value from all heights in range">+</button> <button data-type="Add" data-tip="Add or subtract value from all heights in range">+</button>
<button data-type="Multiply" data-tip="Multiply all heights in range by factor">*</button> <button data-type="Multiply" data-tip="Multiply all heights in range by factor">*</button>
<button data-type="Smooth" data-tip="Smooth the map replacing cell heights by an average values of its neighbors">~</button> <button data-type="Smooth" data-tip="Smooth the map replacing cell heights by an average values of its neighbors">~</button>

View file

@ -365,8 +365,8 @@ window.HeightmapGenerator = (function () {
const endX = vert ? Math.floor(graphWidth - startX - graphWidth * 0.1 + Math.random() * graphWidth * 0.2) : graphWidth - 5; const endX = vert ? Math.floor(graphWidth - startX - graphWidth * 0.1 + Math.random() * graphWidth * 0.2) : graphWidth - 5;
const endY = vert ? graphHeight - 5 : Math.floor(graphHeight - startY - graphHeight * 0.1 + Math.random() * graphHeight * 0.2); const endY = vert ? graphHeight - 5 : Math.floor(graphHeight - startY - graphHeight * 0.1 + Math.random() * graphHeight * 0.2);
const start = findGridCell(startX, startY), const start = findGridCell(startX, startY);
end = findGridCell(endX, endY); const end = findGridCell(endX, endY);
let range = getRange(start, end); let range = getRange(start, end);
const query = []; const query = [];
@ -446,6 +446,26 @@ window.HeightmapGenerator = (function () {
}); });
}; };
const invert = (count, axes) => {
if (!P(count)) return;
const invertX = axes !== "y";
const invertY = axes !== "x";
const {cellsX, cellsY} = grid;
const inverted = cells.h.map((h, i) => {
const x = i % cellsX;
const y = Math.floor(i / cellsX);
const nx = invertX ? cellsX - x - 1 : x;
const ny = invertY ? cellsY - y - 1 : y;
const invertedI = nx + ny * cellsX;
return cells.h[invertedI];
});
cells.h = inverted;
};
function getPointInRange(range, length) { function getPointInRange(range, length) {
if (typeof range !== "string") { if (typeof range !== "string") {
ERROR && console.error("Range should be a string"); ERROR && console.error("Range should be a string");
@ -465,5 +485,5 @@ window.HeightmapGenerator = (function () {
} }
} }
return {generate, addHill, addRange, addTrough, addStrait, addPit, smooth, modify, mask}; return {generate, addHill, addRange, addTrough, addStrait, addPit, smooth, modify, mask, invert};
})(); })();

View file

@ -69,7 +69,7 @@ window.HeightmapTemplates = (function () {
Hill .5 30-50 25-35 30-70 Hill .5 30-50 25-35 30-70
Smooth 1 0 0 0 Smooth 1 0 0 0
Multiply 0.2 25-100 0 0 Multiply 0.2 25-100 0 0
Hill .5 10-20 50-55 48-52`; Hill 0.5 10-20 50-55 48-52`;
const mediterranean = `Range 4-6 30-80 0-100 0-10 const mediterranean = `Range 4-6 30-80 0-100 0-10
Range 4-6 30-80 0-100 90-100 Range 4-6 30-80 0-100 90-100
@ -90,7 +90,8 @@ window.HeightmapTemplates = (function () {
Hill 3-4 3-5 5-95 80-100 Hill 3-4 3-5 5-95 80-100
Hill 1-2 3-5 5-95 40-60 Hill 1-2 3-5 5-95 40-60
Trough 5-6 10-25 5-95 5-95 Trough 5-6 10-25 5-95 5-95
Smooth 3 0 0 0`; Smooth 3 0 0 0
Invert 0.4 both 0 0`;
const pangea = `Hill 1-2 25-40 15-50 0-10 const pangea = `Hill 1-2 25-40 15-50 0-10
Hill 1-2 5-40 50-85 0-10 Hill 1-2 5-40 50-85 0-10
@ -113,7 +114,8 @@ window.HeightmapTemplates = (function () {
Trough 4-8 15-30 10-50 20-40 Trough 4-8 15-30 10-50 20-40
Trough 4-8 15-30 30-70 40-60 Trough 4-8 15-30 30-70 40-60
Trough 4-8 15-30 50-90 60-80 Trough 4-8 15-30 50-90 60-80
Trough 4-8 15-30 70-100 80-100`; Trough 4-8 15-30 70-100 80-100
Invert 0.25 x 0 0`;
const shattered = `Hill 8 35-40 15-85 30-70 const shattered = `Hill 8 35-40 15-85 30-70
Trough 10-20 40-50 5-95 5-95 Trough 10-20 40-50 5-95 5-95

View file

@ -613,9 +613,7 @@ function editHeightmap() {
const power = brushPower.valueAsNumber; const power = brushPower.valueAsNumber;
const interpolate = d3.interpolateRound(power, 1); const interpolate = d3.interpolateRound(power, 1);
const land = changeOnlyLand.checked; const land = changeOnlyLand.checked;
function lim(v) { const lim = v => minmax(v, land ? 20 : 0, 100);
return minmax(v, land ? 20 : 0, 100);
}
const h = grid.cells.h; const h = grid.cells.h;
const brush = document.querySelector("#brushesButtons > button.pressed").id; const brush = document.querySelector("#brushesButtons > button.pressed").id;
@ -674,15 +672,10 @@ function editHeightmap() {
} }
function startFromScratch() { function startFromScratch() {
if (changeOnlyLand.checked) { if (changeOnlyLand.checked) return tip("Not allowed when 'Change only land cells' mode is set", false, "error");
tip("Not allowed when 'Change only land cells' mode is set", false, "error");
return;
}
const someHeights = grid.cells.h.some(h => h); const someHeights = grid.cells.h.some(h => h);
if (!someHeights) { if (!someHeights) return tip("Heightmap is already cleared, please do not click twice if not required", false, "error");
tip("Heightmap is already cleared, please do not click twice if not required", false, "error");
return;
}
grid.cells.h = new Uint8Array(grid.cells.i.length); grid.cells.h = new Uint8Array(grid.cells.i.length);
viewbox.select("#heights").selectAll("*").remove(); viewbox.select("#heights").selectAll("*").remove();
updateHistory(); updateHistory();
@ -752,19 +745,21 @@ function editHeightmap() {
} }
function addStep(type, count, dist, arg4, arg5) { function addStep(type, count, dist, arg4, arg5) {
const body = byId("templateBody"); const $body = byId("templateBody");
body.insertAdjacentHTML("beforeend", getStepHTML(type, count, dist, arg4, arg5)); $body.insertAdjacentHTML("beforeend", getStepHTML(type, count, dist, arg4, arg5));
const elDist = body.querySelector("div:last-child").querySelector(".templateDist");
if (elDist) elDist.on("change", setRange); const $elDist = $body.querySelector("div:last-child > span > .templateDist");
if (dist && elDist && elDist.tagName === "SELECT") { if ($elDist) $elDist.on("change", setRange);
for (const o of elDist.options) {
if (o.value === dist) elDist.value = dist; if (dist && $elDist && $elDist.tagName === "SELECT") {
for (const option of $elDist.options) {
if (option.value === dist) $elDist.value = dist;
} }
if (elDist.value !== dist) { if ($elDist.value !== dist) {
const opt = document.createElement("option"); const opt = document.createElement("option");
opt.value = opt.innerHTML = dist; opt.value = opt.innerHTML = dist;
elDist.add(opt); $elDist.add(opt);
elDist.value = dist; $elDist.value = dist;
} }
} }
} }
@ -775,52 +770,97 @@ function editHeightmap() {
const Reorder = /* html */ `<i class="icon-resize-vertical" data-tip="Drag to reorder"></i>`; const Reorder = /* html */ `<i class="icon-resize-vertical" data-tip="Drag to reorder"></i>`;
const common = /* html */ `<div data-type="${type}">${Hide}<div style="width:4em">${type}</div>${Trash}${Reorder}`; const common = /* html */ `<div data-type="${type}">${Hide}<div style="width:4em">${type}</div>${Trash}${Reorder}`;
const TempY = /* html */ `<span>y:<input class="templateY" data-tip="Placement range percentage along Y axis (minY-maxY)" const TempY = /* html */ `<span>y:
value=${arg5 || "20-80"}></span>`; <input class="templateY" data-tip="Placement range percentage along Y axis (minY-maxY)" value=${arg5 || "20-80"} />
</span>`;
const TempX = /* html */ `<span>x:<input class="templateX" data-tip="Placement range percentage along X axis (minX-maxX)" const TempX = /* html */ `<span>x:
value=${arg4 || "15-85"}></span>`; <input class="templateX" data-tip="Placement range percentage along X axis (minX-maxX)" value=${arg4 || "15-85"} />
</span>`;
const Height = /* html */ `<span>h:<input class="templateHeight" data-tip="Blob maximum height, use hyphen to get a random number in range" const Height = /* html */ `<span>h:
value=${arg3 || "40-50"}></span>`; <input class="templateHeight" data-tip="Blob maximum height, use hyphen to get a random number in range" value=${arg3 || "40-50"} />
</span>`;
const Count = /* html */ `<span>n:<input class="templateCount" data-tip="Blobs to add, use hyphen to get a random number in range" const Count = /* html */ `<span>n:
value=${count || "1-2"}></span>`; <input class="templateCount" data-tip="Blobs to add, use hyphen to get a random number in range" value=${count || "1-2"} />
</span>`;
if (type === "Hill" || type === "Pit" || type === "Range" || type === "Trough") return /* html */ `${common}${TempY}${TempX}${Height}${Count}</div>`; if (type === "Hill" || type === "Pit" || type === "Range" || type === "Trough") return /* html */ `${common}${TempY}${TempX}${Height}${Count}</div>`;
if (type === "Strait") if (type === "Strait")
return /* html */ `${common}<span>d:<select class="templateDist" data-tip="Strait direction"> return /* html */ `${common}
<option value="vertical" selected>vertical</option> <span>d:
<option value="horizontal">horizontal</option> <select class="templateDist" data-tip="Strait direction">
</select></span> <option value="vertical" selected>vertical</option>
<span>w:<input class="templateCount" data-tip="Strait width, use hyphen to get a random number in range" value=${count || "2-7"}></span></div>`; <option value="horizontal">horizontal</option>
</select>
</span>
<span>w:
<input class="templateCount" data-tip="Strait width, use hyphen to get a random number in range" value=${count || "2-7"} />
</span>
</div>`;
if (type === "Invert")
return /* html */ `${common}
<span>by:
<select class="templateDist" data-tip="Mirror heightmap along axis" style="width: 7.8em">
<option value="x" selected>x</option>
<option value="y">y</option>
<option value="xy">both</option>
</select>
</span>
<span>n:
<input class="templateCount" data-tip="Probability of inversion, range 0-1" value=${count || "0.5"} />
</span>
</div>`;
if (type === "Mask") if (type === "Mask")
return /* html */ `${common}<span>f:<input class="templateCount" return /* html */ `${common}
data-tip="Set masking fraction. 1 - full insulation (prevent land on map edges), 2 - half-insulation, etc. Negative number to inverse the effect" <span>f:
type="number" min=-10 max=10 value=${count || 1}></span></div>`; <input class="templateCount"
data-tip="Set masking fraction. 1 - full insulation (prevent land on map edges), 2 - half-insulation, etc. Negative number to inverse the effect"
type="number" min=-10 max=10 value=${count || 1} />
</span>
</div>`;
if (type === "Add") if (type === "Add")
return /* html */ `${common}<span>to:<select class="templateDist" data-tip="Change only land or all cells"> return /* html */ `${common}
<option value="all" selected>all cells</option> <span>to:
<option value="land">land only</option> <select class="templateDist" data-tip="Change only land or all cells">
<option value="interval">interval</option> <option value="all" selected>all cells</option>
</select></span> <option value="land">land only</option>
<span>v:<input class="templateCount" data-tip="Add value to height of all cells (negative values are allowed)" <option value="interval">interval</option>
type="number" value=${count || -10} min=-100 max=100 step=1></span></div>`; </select>
</span>
<span>v:
<input class="templateCount" data-tip="Add value to height of all cells (negative values are allowed)"
type="number" value=${count || -10} min=-100 max=100 step=1 />
</span>
</div>`;
if (type === "Multiply") if (type === "Multiply")
return /* html */ `${common}<span>to:<select class="templateDist" data-tip="Change only land or all cells"> return /* html */ `${common}
<option value="all" selected>all cells</option> <span>to:
<option value="land">land only</option><option value="interval">interval</option> <select class="templateDist" data-tip="Change only land or all cells">
</select></span> <option value="all" selected>all cells</option>
<span>v:<input class="templateCount" data-tip="Multiply all cells Height by the value" type="number" <option value="land">land only</option>
value=${count || 1.1} min=0 max=10 step=.1></span></div>`; <option value="interval">interval</option>
</select>
</span>
<span>v:
<input class="templateCount" data-tip="Multiply all cells Height by the value" type="number"
value=${count || 1.1} min=0 max=10 step=.1 />
</span>
</div>`;
if (type === "Smooth") if (type === "Smooth")
return /* html */ `${common}<span>f:<input class="templateCount" data-tip="Set smooth fraction. 1 - full smooth, 2 - half-smooth, etc." return /* html */ `${common}
type="number" min=1 max=10 step=1 value=${count || 2}></span></div>`; <span>f:
<input class="templateCount" data-tip="Set smooth fraction. 1 - full smooth, 2 - half-smooth, etc."
type="number" min=1 max=10 step=1 value=${count || 2} />
</span>
</div>`;
} }
function setRange(event) { function setRange(event) {
@ -903,6 +943,7 @@ function editHeightmap() {
else if (type === "Trough") HeightmapGenerator.addTrough(count, height, x, y); else if (type === "Trough") HeightmapGenerator.addTrough(count, height, x, y);
else if (type === "Strait") HeightmapGenerator.addStrait(count, dist); else if (type === "Strait") HeightmapGenerator.addStrait(count, dist);
else if (type === "Mask") HeightmapGenerator.mask(+count); else if (type === "Mask") HeightmapGenerator.mask(+count);
else if (type === "Invert") HeightmapGenerator.invert(+count, dist);
else if (type === "Add") HeightmapGenerator.modify(dist, +count, 1); else if (type === "Add") HeightmapGenerator.modify(dist, +count, 1);
else if (type === "Multiply") HeightmapGenerator.modify(dist, 0, +count); else if (type === "Multiply") HeightmapGenerator.modify(dist, 0, +count);
else if (type === "Smooth") HeightmapGenerator.smooth(+count); else if (type === "Smooth") HeightmapGenerator.smooth(+count);