mirror of
https://github.com/Azgaar/Fantasy-Map-Generator.git
synced 2025-12-22 03:51:23 +01:00
Ocean heightmap to v1.96 (#1044)
* feat: allow to render ocean heightmap * feat: allow to render ocean heightmap - test * feat: allow to render ocean heightmap - fix issue * feat: allow to render ocean heightmap - cleanup --------- Co-authored-by: Azgaar <azgaar.fmg@yandex.com>
This commit is contained in:
parent
83dff665c5
commit
a4c4db6150
25 changed files with 348 additions and 196 deletions
107
index.html
107
index.html
|
|
@ -827,6 +827,63 @@
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|
||||||
|
<tbody id="styleHeightmap">
|
||||||
|
<tr id="styleHeightmapRenderOceanOption" data-tip="Check to render ocean heights">
|
||||||
|
<td colspan="2">
|
||||||
|
<input id="styleHeightmapRenderOcean" class="checkbox" type="checkbox" />
|
||||||
|
<label for="styleHeightmapRenderOcean" class="checkbox-label">Render ocean heights</label>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr data-tip="Terracing rate. Set to 0 (toggle off) to improve performance">
|
||||||
|
<td>Terracing</td>
|
||||||
|
<td>
|
||||||
|
<input id="styleHeightmapTerracingInput" type="range" min="0" max="20" step="1" />
|
||||||
|
<output id="styleHeightmapTerracingOutput">0</output>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr data-tip="Layers reduction rate. Increase to improve performance">
|
||||||
|
<td>Reduce layers</td>
|
||||||
|
<td>
|
||||||
|
<input id="styleHeightmapSkipInput" type="range" min="0" max="10" step="1" value="5" />
|
||||||
|
<output id="styleHeightmapSkipOutput">5</output>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr data-tip="Line simplification rate. Increase to slightly improve performance">
|
||||||
|
<td>Simplify line</td>
|
||||||
|
<td>
|
||||||
|
<input id="styleHeightmapSimplificationInput" type="range" min="0" max="10" step="1" value="0" />
|
||||||
|
<output id="styleHeightmapSimplificationOutput">0</output>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr data-tip="Select line interpolation type">
|
||||||
|
<td>Line style</td>
|
||||||
|
<td>
|
||||||
|
<select id="styleHeightmapCurve">
|
||||||
|
<option value="curveBasisClosed" selected>Curved</option>
|
||||||
|
<option value="curveLinear">Linear</option>
|
||||||
|
<option value="curveStep">Rectangular</option>
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr data-tip="Select color scheme for the element">
|
||||||
|
<td>Color scheme</td>
|
||||||
|
<td>
|
||||||
|
<select id="styleHeightmapScheme"></select>
|
||||||
|
<button
|
||||||
|
id="openCreateHeightmapSchemeButton"
|
||||||
|
data-tip="Click to add a custom heightmap color scheme"
|
||||||
|
data-stops="#ffffff,#EEEECC,#D2B48C,#008000,#008080"
|
||||||
|
class="icon-plus sideButton"
|
||||||
|
></button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
|
||||||
<tbody id="styleOpacity" style="display: none">
|
<tbody id="styleOpacity" style="display: none">
|
||||||
<tr data-tip="Set opacity. 0: transparent, 1: solid">
|
<tr data-tip="Set opacity. 0: transparent, 1: solid">
|
||||||
<td>Opacity</td>
|
<td>Opacity</td>
|
||||||
|
|
@ -1284,56 +1341,6 @@
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|
||||||
<tbody id="styleHeightmap">
|
|
||||||
<tr data-tip="Terracing rate. Set to 0 (toggle off) to improve performance">
|
|
||||||
<td>Terracing</td>
|
|
||||||
<td>
|
|
||||||
<input id="styleHeightmapTerracingInput" type="range" min="0" max="20" step="1" />
|
|
||||||
<output id="styleHeightmapTerracingOutput">0</output>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr data-tip="Layers reduction rate. Increase to improve performance">
|
|
||||||
<td>Reduce layers</td>
|
|
||||||
<td>
|
|
||||||
<input id="styleHeightmapSkipInput" type="range" min="0" max="10" step="1" value="5" />
|
|
||||||
<output id="styleHeightmapSkipOutput">5</output>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr data-tip="Line simplification rate. Increase to slightly improve performance">
|
|
||||||
<td>Simplify line</td>
|
|
||||||
<td>
|
|
||||||
<input id="styleHeightmapSimplificationInput" type="range" min="0" max="10" step="1" value="0" />
|
|
||||||
<output id="styleHeightmapSimplificationOutput">0</output>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr data-tip="Select line interpolation type">
|
|
||||||
<td>Line style</td>
|
|
||||||
<td>
|
|
||||||
<select id="styleHeightmapCurve">
|
|
||||||
<option value="0" selected>Curved</option>
|
|
||||||
<option value="1">Linear</option>
|
|
||||||
<option value="2">Rectangular</option>
|
|
||||||
</select>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr data-tip="Select color scheme for the element">
|
|
||||||
<td>Color scheme</td>
|
|
||||||
<td>
|
|
||||||
<select id="styleHeightmapScheme"></select>
|
|
||||||
<button
|
|
||||||
id="openCreateHeightmapSchemeButton"
|
|
||||||
data-tip="Click to add a custom heightmap color scheme"
|
|
||||||
data-stops="#ffffff,#EEEECC,#D2B48C,#008000,#008080"
|
|
||||||
class="icon-plus sideButton"
|
|
||||||
></button>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
|
|
||||||
<tbody id="styleArmies">
|
<tbody id="styleArmies">
|
||||||
<tr data-tip="Set fill transparency. Set to 0 to make it fully transparent">
|
<tr data-tip="Set fill transparency. Set to 0 to make it fully transparent">
|
||||||
<td>Fill opacity</td>
|
<td>Fill opacity</td>
|
||||||
|
|
|
||||||
2
libs/polylabel.min.js
vendored
2
libs/polylabel.min.js
vendored
|
|
@ -1 +1 @@
|
||||||
!function(t){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=t();else if("function"==typeof define&&define.amd)define([],t);else{("undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this).polylabel=t()}}(function(){return function t(n,e,r){function o(a,u){if(!e[a]){if(!n[a]){var f="function"==typeof require&&require;if(!u&&f)return f(a,!0);if(i)return i(a,!0);var h=new Error("Cannot find module '"+a+"'");throw h.code="MODULE_NOT_FOUND",h}var s=e[a]={exports:{}};n[a][0].call(s.exports,function(t){var e=n[a][1][t];return o(e||t)},s,s.exports,t,n,e,r)}return e[a].exports}for(var i="function"==typeof require&&require,a=0;a<r.length;a++)o(r[a]);return o}({1:[function(t,n,e){"use strict";var r=t("tinyqueue");function o(t,n){return n.max-t.max}function i(t,n,e,r){this.x=t,this.y=n,this.h=e,this.d=function(t,n,e){for(var r=!1,o=1/0,i=0;i<e.length;i++)for(var u=e[i],f=0,h=u.length,s=h-1;f<h;s=f++){var d=u[f],l=u[s];d[1]>n!=l[1]>n&&t<(l[0]-d[0])*(n-d[1])/(l[1]-d[1])+d[0]&&(r=!r),o=Math.min(o,a(t,n,d,l))}return(r?1:-1)*Math.sqrt(o)}(t,n,r),this.max=this.d+this.h*Math.SQRT2}function a(t,n,e,r){var o=e[0],i=e[1],a=r[0]-o,u=r[1]-i;if(0!==a||0!==u){var f=((t-o)*a+(n-i)*u)/(a*a+u*u);f>1?(o=r[0],i=r[1]):f>0&&(o+=a*f,i+=u*f)}return(a=t-o)*a+(u=n-i)*u}n.exports=function(t,n,e){var a,u,f,h;n=n||1;for(var s=0;s<t[0].length;s++){var d=t[0][s];(!s||d[0]<a)&&(a=d[0]),(!s||d[1]<u)&&(u=d[1]),(!s||d[0]>f)&&(f=d[0]),(!s||d[1]>h)&&(h=d[1])}for(var l=f-a,p=h-u,c=Math.min(l,p),v=c/2,g=new r(null,o),x=a;x<f;x+=c)for(var y=u;y<h;y+=c)g.push(new i(x+v,y+v,v,t));var w=function(t){for(var n=0,e=0,r=0,o=t[0],a=0,u=o.length,f=u-1;a<u;f=a++){var h=o[a],s=o[f],d=h[0]*s[1]-s[0]*h[1];e+=(h[0]+s[0])*d,r+=(h[1]+s[1])*d,n+=3*d}return new i(e/n,r/n,0,t)}(t),m=g.length;for(;g.length;){var b=g.pop();b.d>w.d&&(w=b,e&&console.log("found best %d after %d probes",Math.round(1e4*b.d)/1e4,m)),b.max-w.d<=n||(v=b.h/2,g.push(new i(b.x-v,b.y-v,v,t)),g.push(new i(b.x+v,b.y-v,v,t)),g.push(new i(b.x-v,b.y+v,v,t)),g.push(new i(b.x+v,b.y+v,v,t)),m+=4)}e&&(console.log("num probes: "+m),console.log("best distance: "+w.d));return[w.x,w.y]}},{tinyqueue:2}],2:[function(t,n,e){"use strict";function r(t,n){if(!(this instanceof r))return new r(t,n);if(this.data=t||[],this.length=this.data.length,this.compare=n||o,t)for(var e=Math.floor(this.length/2);e>=0;e--)this._down(e)}function o(t,n){return t<n?-1:t>n?1:0}function i(t,n,e){var r=t[n];t[n]=t[e],t[e]=r}n.exports=r,r.prototype={push:function(t){this.data.push(t),this.length++,this._up(this.length-1)},pop:function(){var t=this.data[0];return this.data[0]=this.data[this.length-1],this.length--,this.data.pop(),this._down(0),t},peek:function(){return this.data[0]},_up:function(t){for(var n=this.data,e=this.compare;t>0;){var r=Math.floor((t-1)/2);if(!(e(n[t],n[r])<0))break;i(n,r,t),t=r}},_down:function(t){for(var n=this.data,e=this.compare,r=this.length;;){var o=2*t+1,a=o+1,u=t;if(o<r&&e(n[o],n[u])<0&&(u=o),a<r&&e(n[a],n[u])<0&&(u=a),u===t)return;i(n,u,t),t=u}}}},{}]},{},[1])(1)});
|
!function(t){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=t();else if("function"==typeof define&&define.amd)define([],t);else{("undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this).polylabel=t()}}(function(){return function t(n,e,r){function o(a,u){if(!e[a]){if(!n[a]){var f="function"==typeof require&&require;if(!u&&f)return f(a,!0);if(i)return i(a,!0);var h=new Error("Cannot find module '"+a+"'");throw h.code="MODULE_NOT_FOUND",h}var s=e[a]={exports:{}};n[a][0].call(s.exports,function(t){var e=n[a][1][t];return o(e||t)},s,s.exports,t,n,e,r)}return e[a].exports}for(var i="function"==typeof require&&require,a=0;a<r.length;a++)o(r[a]);return o}({1:[function(t,n,e){"use strict";var r=t("tinyqueue");function o(t,n){return n.max-t.max}function i(t,n,e,r){this.x=t,this.y=n,this.h=e,this.d=function(t,n,e){for(var r=!1,o=1/0,i=0;i<e.length;i++)for(var u=e[i],f=0,h=u.length,s=h-1;f<h;s=f++){var d=u[f],l=u[s];d[1]>n!=l[1]>n&&t<(l[0]-d[0])*(n-d[1])/(l[1]-d[1])+d[0]&&(r=!r),o=Math.min(o,a(t,n,d,l))}return(r?1:-1)*Math.sqrt(o)}(t,n,r),this.max=this.d+this.h*Math.SQRT2}function a(t,n,e,r){var o=e[0],i=e[1],a=r[0]-o,u=r[1]-i;if(0!==a||0!==u){var f=((t-o)*a+(n-i)*u)/(a*a+u*u);f>1?(o=r[0],i=r[1]):f>0&&(o+=a*f,i+=u*f)}return(a=t-o)*a+(u=n-i)*u}n.exports=function(t,n,e){var a,u,f,h;n=n||1;for(var s=0;s<t[0].length;s++){var d=t[0][s];(!s||d[0]<a)&&(a=d[0]),(!s||d[1]<u)&&(u=d[1]),(!s||d[0]>f)&&(f=d[0]),(!s||d[1]>h)&&(h=d[1])}for(var l=f-a,p=h-u,c=Math.min(l,p),v=c/2,g=new r(null,o),x=a;x<f;x+=c)for(var y=u;y<h;y+=c)g.push(new i(x+v,y+v,v,t));var w=function(t){for(var n=0,e=0,r=0,o=t[0],a=0,u=o.length,f=u-1;a<u;f=a++){var h=o[a],s=o[f],d=h[0]*s[1]-s[0]*h[1];e+=(h[0]+s[0])*d,r+=(h[1]+s[1])*d,n+=3*d}return new i(e/n,r/n,0,t)}(t),m=g.length;for(;g.length;){var b=g.pop();b.d>w.d&&(w=b,e&&console.info("found best %d after %d probes",Math.round(1e4*b.d)/1e4,m)),b.max-w.d<=n||(v=b.h/2,g.push(new i(b.x-v,b.y-v,v,t)),g.push(new i(b.x+v,b.y-v,v,t)),g.push(new i(b.x-v,b.y+v,v,t)),g.push(new i(b.x+v,b.y+v,v,t)),m+=4)}e&&(console.info("num probes: "+m),console.info("best distance: "+w.d));return[w.x,w.y]}},{tinyqueue:2}],2:[function(t,n,e){"use strict";function r(t,n){if(!(this instanceof r))return new r(t,n);if(this.data=t||[],this.length=this.data.length,this.compare=n||o,t)for(var e=Math.floor(this.length/2);e>=0;e--)this._down(e)}function o(t,n){return t<n?-1:t>n?1:0}function i(t,n,e){var r=t[n];t[n]=t[e],t[e]=r}n.exports=r,r.prototype={push:function(t){this.data.push(t),this.length++,this._up(this.length-1)},pop:function(){var t=this.data[0];return this.data[0]=this.data[this.length-1],this.length--,this.data.pop(),this._down(0),t},peek:function(){return this.data[0]},_up:function(t){for(var n=this.data,e=this.compare;t>0;){var r=Math.floor((t-1)/2);if(!(e(n[t],n[r])<0))break;i(n,r,t),t=r}},_down:function(t){for(var n=this.data,e=this.compare,r=this.length;;){var o=2*t+1,a=o+1,u=t;if(o<r&&e(n[o],n[u])<0&&(u=o),a<r&&e(n[a],n[u])<0&&(u=a),u===t)return;i(n,u,t),t=u}}}},{}]},{},[1])(1)});
|
||||||
2
libs/three.min.js
vendored
2
libs/three.min.js
vendored
File diff suppressed because one or more lines are too long
53
main.js
53
main.js
|
|
@ -92,16 +92,19 @@ let fogging = viewbox
|
||||||
let ruler = viewbox.append("g").attr("id", "ruler").style("display", "none");
|
let ruler = viewbox.append("g").attr("id", "ruler").style("display", "none");
|
||||||
let debug = viewbox.append("g").attr("id", "debug");
|
let debug = viewbox.append("g").attr("id", "debug");
|
||||||
|
|
||||||
// lake and coast groups
|
|
||||||
lakes.append("g").attr("id", "freshwater");
|
lakes.append("g").attr("id", "freshwater");
|
||||||
lakes.append("g").attr("id", "salt");
|
lakes.append("g").attr("id", "salt");
|
||||||
lakes.append("g").attr("id", "sinkhole");
|
lakes.append("g").attr("id", "sinkhole");
|
||||||
lakes.append("g").attr("id", "frozen");
|
lakes.append("g").attr("id", "frozen");
|
||||||
lakes.append("g").attr("id", "lava");
|
lakes.append("g").attr("id", "lava");
|
||||||
lakes.append("g").attr("id", "dry");
|
lakes.append("g").attr("id", "dry");
|
||||||
|
|
||||||
coastline.append("g").attr("id", "sea_island");
|
coastline.append("g").attr("id", "sea_island");
|
||||||
coastline.append("g").attr("id", "lake_island");
|
coastline.append("g").attr("id", "lake_island");
|
||||||
|
|
||||||
|
terrs.append("g").attr("id", "oceanHeights");
|
||||||
|
terrs.append("g").attr("id", "landHeights");
|
||||||
|
|
||||||
labels.append("g").attr("id", "states");
|
labels.append("g").attr("id", "states");
|
||||||
labels.append("g").attr("id", "addedLabels");
|
labels.append("g").attr("id", "addedLabels");
|
||||||
|
|
||||||
|
|
@ -840,8 +843,8 @@ function openNearSeaLakes() {
|
||||||
const LIMIT = 22; // max height that can be breached by water
|
const LIMIT = 22; // max height that can be breached by water
|
||||||
|
|
||||||
for (const i of cells.i) {
|
for (const i of cells.i) {
|
||||||
const lake = cells.f[i];
|
const lakeFeatureId = cells.f[i];
|
||||||
if (features[lake].type !== "lake") continue; // not a lake cell
|
if (features[lakeFeatureId].type !== "lake") continue; // not a lake
|
||||||
|
|
||||||
check_neighbours: for (const c of cells.c[i]) {
|
check_neighbours: for (const c of cells.c[i]) {
|
||||||
if (cells.t[c] !== 1 || cells.h[c] > LIMIT) continue; // water cannot break this
|
if (cells.t[c] !== 1 || cells.h[c] > LIMIT) continue; // water cannot break this
|
||||||
|
|
@ -849,20 +852,24 @@ function openNearSeaLakes() {
|
||||||
for (const n of cells.c[c]) {
|
for (const n of cells.c[c]) {
|
||||||
const ocean = cells.f[n];
|
const ocean = cells.f[n];
|
||||||
if (features[ocean].type !== "ocean") continue; // not an ocean
|
if (features[ocean].type !== "ocean") continue; // not an ocean
|
||||||
removeLake(c, lake, ocean);
|
removeLake(c, lakeFeatureId, ocean);
|
||||||
break check_neighbours;
|
break check_neighbours;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeLake(threshold, lake, ocean) {
|
function removeLake(thresholdCellId, lakeFeatureId, oceanFeatureId) {
|
||||||
cells.h[threshold] = 19;
|
cells.h[thresholdCellId] = 19;
|
||||||
cells.t[threshold] = -1;
|
cells.t[thresholdCellId] = -1;
|
||||||
cells.f[threshold] = ocean;
|
cells.f[thresholdCellId] = oceanFeatureId;
|
||||||
cells.c[threshold].forEach(function (c) {
|
cells.c[thresholdCellId].forEach(function (c) {
|
||||||
if (cells.h[c] >= 20) cells.t[c] = 1; // mark as coastline
|
if (cells.h[c] >= 20) cells.t[c] = 1; // mark as coastline
|
||||||
});
|
});
|
||||||
features[lake].type = "ocean"; // mark former lake as ocean
|
|
||||||
|
cells.i.forEach(i => {
|
||||||
|
if (cells.f[i] === lakeFeatureId) cells.f[i] = oceanFeatureId;
|
||||||
|
});
|
||||||
|
features[lakeFeatureId].type = "ocean"; // mark former lake as ocean
|
||||||
}
|
}
|
||||||
|
|
||||||
TIME && console.timeEnd("openLakes");
|
TIME && console.timeEnd("openLakes");
|
||||||
|
|
@ -1249,6 +1256,7 @@ function drawCoastline() {
|
||||||
features[f].vertices = vchain;
|
features[f].vertices = vchain;
|
||||||
|
|
||||||
const path = round(lineGen(points));
|
const path = round(lineGen(points));
|
||||||
|
|
||||||
if (features[f].type === "lake") {
|
if (features[f].type === "lake") {
|
||||||
landMask
|
landMask
|
||||||
.append("path")
|
.append("path")
|
||||||
|
|
@ -1346,22 +1354,14 @@ function drawCoastline() {
|
||||||
// Re-mark features (ocean, lakes, islands)
|
// Re-mark features (ocean, lakes, islands)
|
||||||
function reMarkFeatures() {
|
function reMarkFeatures() {
|
||||||
TIME && console.time("reMarkFeatures");
|
TIME && console.time("reMarkFeatures");
|
||||||
const cells = pack.cells,
|
const cells = pack.cells;
|
||||||
features = (pack.features = [0]);
|
const features = (pack.features = [0]);
|
||||||
|
|
||||||
cells.f = new Uint16Array(cells.i.length); // cell feature number
|
cells.f = new Uint16Array(cells.i.length); // cell feature number
|
||||||
cells.t = new Int8Array(cells.i.length); // cell type: 1 = land along coast; -1 = water along coast;
|
cells.t = new Int8Array(cells.i.length); // cell type: 1 = land along coast; -1 = water along coast;
|
||||||
cells.haven = cells.i.length < 65535 ? new Uint16Array(cells.i.length) : new Uint32Array(cells.i.length); // cell haven (opposite water cell);
|
cells.haven = cells.i.length < 65535 ? new Uint16Array(cells.i.length) : new Uint32Array(cells.i.length); // cell haven (opposite water cell);
|
||||||
cells.harbor = new Uint8Array(cells.i.length); // cell harbor (number of adjacent water cells);
|
cells.harbor = new Uint8Array(cells.i.length); // cell harbor (number of adjacent water cells);
|
||||||
|
|
||||||
const defineHaven = i => {
|
|
||||||
const water = cells.c[i].filter(c => cells.h[c] < 20);
|
|
||||||
const dist2 = water.map(c => (cells.p[i][0] - cells.p[c][0]) ** 2 + (cells.p[i][1] - cells.p[c][1]) ** 2);
|
|
||||||
const closest = water[dist2.indexOf(Math.min.apply(Math, dist2))];
|
|
||||||
|
|
||||||
cells.haven[i] = closest;
|
|
||||||
cells.harbor[i] = water.length;
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!cells.i.length) return; // no cells -> there is nothing to do
|
if (!cells.i.length) return; // no cells -> there is nothing to do
|
||||||
for (let i = 1, queue = [0]; queue[0] !== -1; i++) {
|
for (let i = 1, queue = [0]; queue[0] !== -1; i++) {
|
||||||
const start = queue[0]; // first cell
|
const start = queue[0]; // first cell
|
||||||
|
|
@ -1402,6 +1402,15 @@ function reMarkFeatures() {
|
||||||
// markupPackLand
|
// markupPackLand
|
||||||
markup(pack.cells, 3, 1, 0);
|
markup(pack.cells, 3, 1, 0);
|
||||||
|
|
||||||
|
function defineHaven(i) {
|
||||||
|
const water = cells.c[i].filter(c => cells.h[c] < 20);
|
||||||
|
const dist2 = water.map(c => (cells.p[i][0] - cells.p[c][0]) ** 2 + (cells.p[i][1] - cells.p[c][1]) ** 2);
|
||||||
|
const closest = water[dist2.indexOf(Math.min.apply(Math, dist2))];
|
||||||
|
|
||||||
|
cells.haven[i] = closest;
|
||||||
|
cells.harbor[i] = water.length;
|
||||||
|
}
|
||||||
|
|
||||||
function defineOceanGroup(number) {
|
function defineOceanGroup(number) {
|
||||||
if (number > grid.cells.i.length / 25) return "ocean";
|
if (number > grid.cells.i.length / 25) return "ocean";
|
||||||
if (number > grid.cells.i.length / 100) return "sea";
|
if (number > grid.cells.i.length / 100) return "sea";
|
||||||
|
|
@ -1924,7 +1933,7 @@ function showStatistics() {
|
||||||
|
|
||||||
mapId = Date.now(); // unique map id is it's creation date number
|
mapId = Date.now(); // unique map id is it's creation date number
|
||||||
mapHistory.push({seed, width: graphWidth, height: graphHeight, template: heightmap, created: mapId});
|
mapHistory.push({seed, width: graphWidth, height: graphHeight, template: heightmap, created: mapId});
|
||||||
INFO && console.log(stats);
|
INFO && console.info(stats);
|
||||||
}
|
}
|
||||||
|
|
||||||
const regenerateMap = debounce(async function (options) {
|
const regenerateMap = debounce(async function (options) {
|
||||||
|
|
|
||||||
|
|
@ -71,28 +71,31 @@ window.Cultures = (function () {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const cell = (c.center = placeCenter(c.sort ? c.sort : i => cells.s[i]));
|
const sortingFn = c.sort ? c.sort : i => cells.s[i];
|
||||||
centers.add(cells.p[cell]);
|
const center = placeCenter(sortingFn);
|
||||||
|
|
||||||
|
centers.add(cells.p[center]);
|
||||||
|
c.center = center;
|
||||||
c.i = newId;
|
c.i = newId;
|
||||||
delete c.odd;
|
delete c.odd;
|
||||||
delete c.sort;
|
delete c.sort;
|
||||||
c.color = colors[i];
|
c.color = colors[i];
|
||||||
c.type = defineCultureType(cell);
|
c.type = defineCultureType(center);
|
||||||
c.expansionism = defineCultureExpansionism(c.type);
|
c.expansionism = defineCultureExpansionism(c.type);
|
||||||
c.origins = [0];
|
c.origins = [0];
|
||||||
c.code = abbreviate(c.name, codes);
|
c.code = abbreviate(c.name, codes);
|
||||||
codes.push(c.code);
|
codes.push(c.code);
|
||||||
cultureIds[cell] = newId;
|
cultureIds[center] = newId;
|
||||||
if (emblemShape === "random") c.shield = getRandomShield();
|
if (emblemShape === "random") c.shield = getRandomShield();
|
||||||
});
|
});
|
||||||
|
|
||||||
cells.culture = cultureIds;
|
cells.culture = cultureIds;
|
||||||
|
|
||||||
function placeCenter(v) {
|
function placeCenter(sortingFn) {
|
||||||
let spacing = (graphWidth + graphHeight) / 2 / count;
|
let spacing = (graphWidth + graphHeight) / 2 / count;
|
||||||
const MAX_ATTEMPTS = 100;
|
const MAX_ATTEMPTS = 100;
|
||||||
|
|
||||||
const sorted = [...populated].sort((a, b) => v(b) - v(a));
|
const sorted = [...populated].sort((a, b) => sortingFn(b) - sortingFn(a));
|
||||||
const max = Math.floor(sorted.length / 2);
|
const max = Math.floor(sorted.length / 2);
|
||||||
|
|
||||||
let cellId = 0;
|
let cellId = 0;
|
||||||
|
|
|
||||||
|
|
@ -738,6 +738,46 @@ export function resolveVersionConflicts(version) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (version < 1.96) {
|
if (version < 1.96) {
|
||||||
|
// v1.96 added ocean rendering for heightmap
|
||||||
|
terrs.selectAll("*").remove();
|
||||||
|
|
||||||
|
const opacity = terrs.attr("opacity");
|
||||||
|
const filter = terrs.attr("filter");
|
||||||
|
const scheme = terrs.attr("scheme");
|
||||||
|
const terracing = terrs.attr("terracing");
|
||||||
|
const skip = terrs.attr("skip");
|
||||||
|
const relax = terrs.attr("relax");
|
||||||
|
|
||||||
|
const curveTypes = {0: "curveBasisClosed", 1: "curveLinear", 2: "curveStep"};
|
||||||
|
const curve = curveTypes[terrs.attr("curve")] || "curveBasisClosed";
|
||||||
|
|
||||||
|
terrs.attr("scheme", null).attr("terracing", null).attr("skip", null).attr("relax", null).attr("curve", null);
|
||||||
|
|
||||||
|
terrs
|
||||||
|
.append("g")
|
||||||
|
.attr("id", "oceanHeights")
|
||||||
|
.attr("data-render", 0)
|
||||||
|
.attr("opacity", opacity)
|
||||||
|
.attr("filter", filter)
|
||||||
|
.attr("scheme", scheme)
|
||||||
|
.attr("terracing", 0)
|
||||||
|
.attr("skip", 0)
|
||||||
|
.attr("relax", 1)
|
||||||
|
.attr("curve", curve);
|
||||||
|
terrs
|
||||||
|
.append("g")
|
||||||
|
.attr("id", "landHeights")
|
||||||
|
.attr("opacity", opacity)
|
||||||
|
.attr("scheme", scheme)
|
||||||
|
.attr("filter", filter)
|
||||||
|
.attr("terracing", terracing)
|
||||||
|
.attr("skip", skip)
|
||||||
|
.attr("relax", relax)
|
||||||
|
.attr("curve", curve)
|
||||||
|
.attr("mask", "url(#land)");
|
||||||
|
|
||||||
|
if (layerIsOn("toggleHeight")) drawHeightmap();
|
||||||
|
|
||||||
// v1.96.00 moved scaleBar options from units editor to style
|
// v1.96.00 moved scaleBar options from units editor to style
|
||||||
d3.select("#scaleBar").remove();
|
d3.select("#scaleBar").remove();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,7 @@ window.Cloud = (function () {
|
||||||
|
|
||||||
async save(fileName, contents) {
|
async save(fileName, contents) {
|
||||||
const resp = await this.call("filesUpload", {path: "/" + fileName, contents});
|
const resp = await this.call("filesUpload", {path: "/" + fileName, contents});
|
||||||
DEBUG && console.log("Dropbox response:", resp);
|
DEBUG && console.info("Dropbox response:", resp);
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -104,7 +104,7 @@ window.Cloud = (function () {
|
||||||
|
|
||||||
// Callback function for auth window
|
// Callback function for auth window
|
||||||
async setDropBoxToken(token) {
|
async setDropBoxToken(token) {
|
||||||
DEBUG && console.log("Access token:", token);
|
DEBUG && console.info("Access token:", token);
|
||||||
setToken(this.name, token);
|
setToken(this.name, token);
|
||||||
await this.connect(token);
|
await this.connect(token);
|
||||||
this.authWindow.close();
|
this.authWindow.close();
|
||||||
|
|
@ -131,7 +131,7 @@ window.Cloud = (function () {
|
||||||
allow_download: true
|
allow_download: true
|
||||||
};
|
};
|
||||||
const resp = await this.call("sharingCreateSharedLinkWithSettings", {path, settings});
|
const resp = await this.call("sharingCreateSharedLinkWithSettings", {path, settings});
|
||||||
DEBUG && console.log("Dropbox link object:", resp.result);
|
DEBUG && console.info("Dropbox link object:", resp.result);
|
||||||
return resp.result.url;
|
return resp.result.url;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ async function quickLoad() {
|
||||||
async function loadFromDropbox() {
|
async function loadFromDropbox() {
|
||||||
const mapPath = byId("loadFromDropboxSelect")?.value;
|
const mapPath = byId("loadFromDropboxSelect")?.value;
|
||||||
|
|
||||||
DEBUG && console.log("Loading map from Dropbox:", mapPath);
|
DEBUG && console.info("Loading map from Dropbox:", mapPath);
|
||||||
const blob = await Cloud.providers.dropbox.load(mapPath);
|
const blob = await Cloud.providers.dropbox.load(mapPath);
|
||||||
uploadMap(blob);
|
uploadMap(blob);
|
||||||
}
|
}
|
||||||
|
|
@ -461,10 +461,10 @@ async function parseLoadedData(data) {
|
||||||
|
|
||||||
{
|
{
|
||||||
// add custom heightmap color scheme if any
|
// add custom heightmap color scheme if any
|
||||||
const scheme = terrs.attr("scheme");
|
const oceanScheme = terrs.select("#oceanHeights").attr("scheme");
|
||||||
if (!(scheme in heightmapColorSchemes)) {
|
const landScheme = terrs.select("#landHeights").attr("scheme");
|
||||||
addCustomColorScheme(scheme);
|
if (!(oceanScheme in heightmapColorSchemes)) addCustomColorScheme(oceanScheme);
|
||||||
}
|
if (!(landScheme in heightmapColorSchemes)) addCustomColorScheme(landScheme);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ window.Submap = (function () {
|
||||||
|
|
||||||
const projection = options.projection;
|
const projection = options.projection;
|
||||||
const inverse = options.inverse;
|
const inverse = options.inverse;
|
||||||
const stage = s => INFO && console.log("SUBMAP:", s);
|
const stage = s => INFO && console.info("SUBMAP:", s);
|
||||||
const timeStart = performance.now();
|
const timeStart = performance.now();
|
||||||
invokeActiveZooming();
|
invokeActiveZooming();
|
||||||
|
|
||||||
|
|
@ -36,7 +36,7 @@ window.Submap = (function () {
|
||||||
seed = parentMap.seed;
|
seed = parentMap.seed;
|
||||||
Math.random = aleaPRNG(seed);
|
Math.random = aleaPRNG(seed);
|
||||||
INFO && console.group("SubMap with seed: " + seed);
|
INFO && console.group("SubMap with seed: " + seed);
|
||||||
DEBUG && console.log("Using Options:", options);
|
DEBUG && console.info("Using Options:", options);
|
||||||
|
|
||||||
// create new grid
|
// create new grid
|
||||||
applyGraphSize();
|
applyGraphSize();
|
||||||
|
|
@ -396,7 +396,7 @@ window.Submap = (function () {
|
||||||
b.removed = true;
|
b.removed = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
DEBUG && console.log(`Moving ${b.name} from ${cityCell} to ${newCell} near ${neighbor}.`);
|
DEBUG && console.info(`Moving ${b.name} from ${cityCell} to ${newCell} near ${neighbor}.`);
|
||||||
[b.x, b.y] = b.port ? getMiddlePoint(newCell, neighbor) : cells.p[newCell];
|
[b.x, b.y] = b.port ? getMiddlePoint(newCell, neighbor) : cells.p[newCell];
|
||||||
if (b.port) b.port = cells.f[neighbor]; // copy feature number
|
if (b.port) b.port = cells.f[neighbor]; // copy feature number
|
||||||
b.cell = newCell;
|
b.cell = newCell;
|
||||||
|
|
|
||||||
|
|
@ -188,92 +188,135 @@ function restoreLayers() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function toggleHeight(event) {
|
function toggleHeight(event) {
|
||||||
if (customization === 1) {
|
if (customization === 1) return tip("You cannot turn off the layer when heightmap is in edit mode", false, "error");
|
||||||
tip("You cannot turn off the layer when heightmap is in edit mode", false, "error");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!terrs.selectAll("*").size()) {
|
const children = terrs.selectAll("#oceanHeights > *, #landHeights > *");
|
||||||
|
if (!children.size()) {
|
||||||
turnButtonOn("toggleHeight");
|
turnButtonOn("toggleHeight");
|
||||||
drawHeightmap();
|
drawHeightmap();
|
||||||
if (event && isCtrlClick(event)) editStyle("terrs");
|
if (event && isCtrlClick(event)) editStyle("terrs");
|
||||||
} else {
|
} else {
|
||||||
if (event && isCtrlClick(event)) {
|
if (event && isCtrlClick(event)) return editStyle("terrs");
|
||||||
editStyle("terrs");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
turnButtonOff("toggleHeight");
|
turnButtonOff("toggleHeight");
|
||||||
terrs.selectAll("*").remove();
|
children.remove();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function drawHeightmap() {
|
function drawHeightmap() {
|
||||||
TIME && console.time("drawHeightmap");
|
TIME && console.time("drawHeightmap");
|
||||||
terrs.selectAll("*").remove();
|
|
||||||
|
|
||||||
const {cells, vertices} = pack;
|
const ocean = terrs.select("#oceanHeights");
|
||||||
const n = cells.i.length;
|
const land = terrs.select("#landHeights");
|
||||||
const used = new Uint8Array(cells.i.length);
|
|
||||||
const paths = new Array(101).fill("");
|
|
||||||
|
|
||||||
const scheme = getColorScheme(terrs.attr("scheme"));
|
ocean.selectAll("*").remove();
|
||||||
const terracing = terrs.attr("terracing") / 10; // add additional shifted darker layer for pseudo-3d effect
|
land.selectAll("*").remove();
|
||||||
const skip = +terrs.attr("skip") + 1;
|
|
||||||
const simplification = +terrs.attr("relax");
|
|
||||||
|
|
||||||
switch (+terrs.attr("curve")) {
|
const paths = new Array(101);
|
||||||
case 0:
|
|
||||||
lineGen.curve(d3.curveBasisClosed);
|
// ocean cells
|
||||||
break;
|
const renderOceanCells = Boolean(+ocean.attr("data-render"));
|
||||||
case 1:
|
if (renderOceanCells) {
|
||||||
lineGen.curve(d3.curveLinear);
|
const {cells, vertices} = grid;
|
||||||
break;
|
const used = new Uint8Array(cells.i.length);
|
||||||
case 2:
|
|
||||||
lineGen.curve(d3.curveStep);
|
const skip = +ocean.attr("skip") + 1 || 1;
|
||||||
break;
|
const relax = +ocean.attr("relax") || 0;
|
||||||
default:
|
lineGen.curve(d3[ocean.attr("curve") || "curveBasisClosed"]);
|
||||||
lineGen.curve(d3.curveBasisClosed);
|
|
||||||
|
let currentLayer = 0;
|
||||||
|
const heights = Array.from(cells.i).sort((a, b) => cells.h[a] - cells.h[b]);
|
||||||
|
|
||||||
|
for (const i of heights) {
|
||||||
|
const h = cells.h[i];
|
||||||
|
if (h > currentLayer) currentLayer += skip;
|
||||||
|
if (h < currentLayer) continue;
|
||||||
|
if (currentLayer >= 20) break;
|
||||||
|
if (used[i]) continue; // already marked
|
||||||
|
const onborder = cells.c[i].some(n => cells.h[n] < h);
|
||||||
|
if (!onborder) continue;
|
||||||
|
const vertex = cells.v[i].find(v => vertices.c[v].some(i => cells.h[i] < h));
|
||||||
|
const chain = connectVertices(cells, vertices, vertex, h, used);
|
||||||
|
if (chain.length < 3) continue;
|
||||||
|
const points = simplifyLine(chain, relax).map(v => vertices.p[v]);
|
||||||
|
if (!paths[h]) paths[h] = "";
|
||||||
|
paths[h] += round(lineGen(points));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let currentLayer = 20;
|
// land cells
|
||||||
const heights = cells.i.sort((a, b) => cells.h[a] - cells.h[b]);
|
{
|
||||||
for (const i of heights) {
|
const {cells, vertices} = pack;
|
||||||
const h = cells.h[i];
|
const used = new Uint8Array(cells.i.length);
|
||||||
if (h > currentLayer) currentLayer += skip;
|
|
||||||
if (currentLayer > 100) break; // no layers possible with height > 100
|
const skip = +land.attr("skip") + 1 || 1;
|
||||||
if (h < currentLayer) continue;
|
const relax = +land.attr("relax") || 0;
|
||||||
if (used[i]) continue; // already marked
|
lineGen.curve(d3[land.attr("curve") || "curveBasisClosed"]);
|
||||||
const onborder = cells.c[i].some(n => cells.h[n] < h);
|
|
||||||
if (!onborder) continue;
|
let currentLayer = 20;
|
||||||
const vertex = cells.v[i].find(v => vertices.c[v].some(i => cells.h[i] < h));
|
const heights = Array.from(cells.i).sort((a, b) => cells.h[a] - cells.h[b]);
|
||||||
const chain = connectVertices(vertex, h);
|
for (const i of heights) {
|
||||||
if (chain.length < 3) continue;
|
const h = cells.h[i];
|
||||||
const points = simplifyLine(chain).map(v => vertices.p[v]);
|
if (h > currentLayer) currentLayer += skip;
|
||||||
paths[h] += round(lineGen(points));
|
if (h < currentLayer) continue;
|
||||||
|
if (currentLayer > 100) break; // no layers possible with height > 100
|
||||||
|
if (used[i]) continue; // already marked
|
||||||
|
const onborder = cells.c[i].some(n => cells.h[n] < h);
|
||||||
|
if (!onborder) continue;
|
||||||
|
const vertex = cells.v[i].find(v => vertices.c[v].some(i => cells.h[i] < h));
|
||||||
|
const chain = connectVertices(cells, vertices, vertex, h, used);
|
||||||
|
if (chain.length < 3) continue;
|
||||||
|
const points = simplifyLine(chain, relax).map(v => vertices.p[v]);
|
||||||
|
if (!paths[h]) paths[h] = "";
|
||||||
|
paths[h] += round(lineGen(points));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
terrs
|
// render paths
|
||||||
.append("rect")
|
for (const height of d3.range(0, 101)) {
|
||||||
.attr("x", 0)
|
const group = height < 20 ? ocean : land;
|
||||||
.attr("y", 0)
|
const scheme = getColorScheme(group.attr("scheme"));
|
||||||
.attr("width", graphWidth)
|
|
||||||
.attr("height", graphHeight)
|
if (height === 0 && renderOceanCells) {
|
||||||
.attr("fill", scheme(0.8)); // draw base layer
|
// draw base ocean layer
|
||||||
for (const i of d3.range(20, 101)) {
|
group
|
||||||
if (paths[i].length < 10) continue;
|
.append("rect")
|
||||||
const color = getColor(i, scheme);
|
.attr("x", 0)
|
||||||
if (terracing)
|
.attr("y", 0)
|
||||||
terrs
|
.attr("width", graphWidth)
|
||||||
.append("path")
|
.attr("height", graphHeight)
|
||||||
.attr("d", paths[i])
|
.attr("fill", scheme(1));
|
||||||
.attr("transform", "translate(.7,1.4)")
|
}
|
||||||
.attr("fill", d3.color(color).darker(terracing))
|
|
||||||
.attr("data-height", i);
|
if (height === 20) {
|
||||||
terrs.append("path").attr("d", paths[i]).attr("fill", color).attr("data-height", i);
|
// draw base land layer
|
||||||
|
group
|
||||||
|
.append("rect")
|
||||||
|
.attr("x", 0)
|
||||||
|
.attr("y", 0)
|
||||||
|
.attr("width", graphWidth)
|
||||||
|
.attr("height", graphHeight)
|
||||||
|
.attr("fill", scheme(0.8));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (paths[height] && paths[height].length >= 10) {
|
||||||
|
const terracing = group.attr("terracing") / 10 || 0;
|
||||||
|
const color = getColor(height, scheme);
|
||||||
|
|
||||||
|
if (terracing) {
|
||||||
|
group
|
||||||
|
.append("path")
|
||||||
|
.attr("d", paths[height])
|
||||||
|
.attr("transform", "translate(.7,1.4)")
|
||||||
|
.attr("fill", d3.color(color).darker(terracing))
|
||||||
|
.attr("data-height", height);
|
||||||
|
}
|
||||||
|
group.append("path").attr("d", paths[height]).attr("fill", color).attr("data-height", height);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// connect vertices to chain
|
// connect vertices to chain
|
||||||
function connectVertices(start, h) {
|
function connectVertices(cells, vertices, start, h, used) {
|
||||||
|
const n = cells.i.length;
|
||||||
const chain = []; // vertices chain to form a path
|
const chain = []; // vertices chain to form a path
|
||||||
for (let i = 0, current = start; i === 0 || (current !== start && i < 20000); i++) {
|
for (let i = 0, current = start; i === 0 || (current !== start && i < 20000); i++) {
|
||||||
const prev = chain[chain.length - 1]; // previous vertex in chain
|
const prev = chain[chain.length - 1]; // previous vertex in chain
|
||||||
|
|
@ -295,7 +338,7 @@ function drawHeightmap() {
|
||||||
return chain;
|
return chain;
|
||||||
}
|
}
|
||||||
|
|
||||||
function simplifyLine(chain) {
|
function simplifyLine(chain, simplification) {
|
||||||
if (!simplification) return chain;
|
if (!simplification) return chain;
|
||||||
const n = simplification + 1; // filter each nth element
|
const n = simplification + 1; // filter each nth element
|
||||||
return chain.filter((d, i) => i % n === 0);
|
return chain.filter((d, i) => i % n === 0);
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,7 @@ function editStyle(element, group) {
|
||||||
|
|
||||||
styleElementSelect.classList.add("glow");
|
styleElementSelect.classList.add("glow");
|
||||||
if (group) styleGroupSelect.classList.add("glow");
|
if (group) styleGroupSelect.classList.add("glow");
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
styleElementSelect.classList.remove("glow");
|
styleElementSelect.classList.remove("glow");
|
||||||
if (group) styleGroupSelect.classList.remove("glow");
|
if (group) styleGroupSelect.classList.remove("glow");
|
||||||
|
|
@ -82,10 +83,10 @@ function selectStyleElement() {
|
||||||
styleIsOff.style.display = isLayerOff ? "block" : "none";
|
styleIsOff.style.display = isLayerOff ? "block" : "none";
|
||||||
|
|
||||||
// active group element
|
// active group element
|
||||||
const group = styleGroupSelect.value;
|
if (["routes", "labels", "coastline", "lakes", "anchors", "burgIcons", "borders", "terrs"].includes(styleElement)) {
|
||||||
if (["routes", "labels", "coastline", "lakes", "anchors", "burgIcons", "borders"].includes(styleElement)) {
|
const group = styleGroupSelect.value;
|
||||||
const gEl = group && el.select("#" + group);
|
const defaultGroupSelector = styleElement === "terrs" ? "#landHeights" : "g";
|
||||||
el = group && gEl.size() ? gEl : el.select("g");
|
el = group && el.select("#" + group).size() ? el.select("#" + group) : el.select(defaultGroupSelector);
|
||||||
}
|
}
|
||||||
|
|
||||||
// opacity
|
// opacity
|
||||||
|
|
@ -171,11 +172,14 @@ function selectStyleElement() {
|
||||||
|
|
||||||
if (styleElement === "terrs") {
|
if (styleElement === "terrs") {
|
||||||
styleHeightmap.style.display = "block";
|
styleHeightmap.style.display = "block";
|
||||||
styleHeightmapScheme.value = terrs.attr("scheme");
|
styleHeightmapRenderOceanOption.style.display = el.attr("id") === "oceanHeights" ? "block" : "none";
|
||||||
styleHeightmapTerracingInput.value = styleHeightmapTerracingOutput.value = terrs.attr("terracing");
|
styleHeightmapRenderOcean.checked = +el.attr("data-render");
|
||||||
styleHeightmapSkipInput.value = styleHeightmapSkipOutput.value = terrs.attr("skip");
|
|
||||||
styleHeightmapSimplificationInput.value = styleHeightmapSimplificationOutput.value = terrs.attr("relax");
|
styleHeightmapScheme.value = el.attr("scheme");
|
||||||
styleHeightmapCurve.value = terrs.attr("curve");
|
styleHeightmapTerracingInput.value = styleHeightmapTerracingOutput.value = el.attr("terracing");
|
||||||
|
styleHeightmapSkipInput.value = styleHeightmapSkipOutput.value = el.attr("skip");
|
||||||
|
styleHeightmapSimplificationInput.value = styleHeightmapSimplificationOutput.value = el.attr("relax");
|
||||||
|
styleHeightmapCurve.value = el.attr("curve");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (styleElement === "markers") {
|
if (styleElement === "markers") {
|
||||||
|
|
@ -337,7 +341,7 @@ function selectStyleElement() {
|
||||||
|
|
||||||
// update group options
|
// update group options
|
||||||
styleGroupSelect.options.length = 0; // remove all options
|
styleGroupSelect.options.length = 0; // remove all options
|
||||||
if (["routes", "labels", "coastline", "lakes", "anchors", "burgIcons", "borders"].includes(styleElement)) {
|
if (["routes", "labels", "coastline", "lakes", "anchors", "burgIcons", "borders", "terrs"].includes(styleElement)) {
|
||||||
const groups = byId(styleElement).querySelectorAll("g");
|
const groups = byId(styleElement).querySelectorAll("g");
|
||||||
groups.forEach(el => {
|
groups.forEach(el => {
|
||||||
if (el.id === "burgLabels") return;
|
if (el.id === "burgLabels") return;
|
||||||
|
|
@ -545,18 +549,16 @@ outlineLayers.addEventListener("change", function () {
|
||||||
});
|
});
|
||||||
|
|
||||||
styleHeightmapScheme.addEventListener("change", function () {
|
styleHeightmapScheme.addEventListener("change", function () {
|
||||||
terrs.attr("scheme", this.value);
|
getEl().attr("scheme", this.value);
|
||||||
drawHeightmap();
|
drawHeightmap();
|
||||||
});
|
});
|
||||||
|
|
||||||
openCreateHeightmapSchemeButton.addEventListener("click", function () {
|
openCreateHeightmapSchemeButton.addEventListener("click", function () {
|
||||||
// start with current scheme
|
// start with current scheme
|
||||||
this.dataset.stops = terrs.attr("scheme").startsWith("#")
|
const scheme = getEl().attr("scheme");
|
||||||
? terrs.attr("scheme")
|
this.dataset.stops = scheme.startsWith("#")
|
||||||
: (function () {
|
? scheme
|
||||||
const scheme = heightmapColorSchemes[terrs.attr("scheme")];
|
: (() => [0, 0.25, 0.5, 0.75, 1].map(heightmapColorSchemes[scheme]).map(toHEX).join(","))();
|
||||||
return [0, 0.25, 0.5, 0.75, 1].map(scheme).map(toHEX).join(",");
|
|
||||||
})();
|
|
||||||
|
|
||||||
// render dialog base structure
|
// render dialog base structure
|
||||||
alertMessage.innerHTML = /* html */ `<div>
|
alertMessage.innerHTML = /* html */ `<div>
|
||||||
|
|
@ -648,7 +650,7 @@ openCreateHeightmapSchemeButton.addEventListener("click", function () {
|
||||||
if (stops in heightmapColorSchemes) return tip("This scheme already exists", false, "error");
|
if (stops in heightmapColorSchemes) return tip("This scheme already exists", false, "error");
|
||||||
|
|
||||||
addCustomColorScheme(stops);
|
addCustomColorScheme(stops);
|
||||||
terrs.attr("scheme", stops);
|
getEl().attr("scheme", stops);
|
||||||
drawHeightmap();
|
drawHeightmap();
|
||||||
|
|
||||||
handleClose();
|
handleClose();
|
||||||
|
|
@ -670,23 +672,28 @@ openCreateHeightmapSchemeButton.addEventListener("click", function () {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
styleHeightmapRenderOcean.addEventListener("change", function () {
|
||||||
|
getEl().attr("data-render", +this.checked);
|
||||||
|
drawHeightmap();
|
||||||
|
});
|
||||||
|
|
||||||
styleHeightmapTerracingInput.addEventListener("input", function () {
|
styleHeightmapTerracingInput.addEventListener("input", function () {
|
||||||
terrs.attr("terracing", this.value);
|
getEl().attr("terracing", this.value);
|
||||||
drawHeightmap();
|
drawHeightmap();
|
||||||
});
|
});
|
||||||
|
|
||||||
styleHeightmapSkipInput.addEventListener("input", function () {
|
styleHeightmapSkipInput.addEventListener("input", function () {
|
||||||
terrs.attr("skip", this.value);
|
getEl().attr("skip", this.value);
|
||||||
drawHeightmap();
|
drawHeightmap();
|
||||||
});
|
});
|
||||||
|
|
||||||
styleHeightmapSimplificationInput.addEventListener("input", function () {
|
styleHeightmapSimplificationInput.addEventListener("input", function () {
|
||||||
terrs.attr("relax", this.value);
|
getEl().attr("relax", this.value);
|
||||||
drawHeightmap();
|
drawHeightmap();
|
||||||
});
|
});
|
||||||
|
|
||||||
styleHeightmapCurve.addEventListener("change", function () {
|
styleHeightmapCurve.addEventListener("change", function () {
|
||||||
terrs.attr("curve", this.value);
|
getEl().attr("curve", this.value);
|
||||||
drawHeightmap();
|
drawHeightmap();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -983,7 +990,7 @@ function textureProvideURL() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function fetchTextureURL(url) {
|
function fetchTextureURL(url) {
|
||||||
INFO && console.log("Provided URL is", url);
|
INFO && console.info("Provided URL is", url);
|
||||||
const img = new Image();
|
const img = new Image();
|
||||||
img.onload = function () {
|
img.onload = function () {
|
||||||
const canvas = byId("texturePreview");
|
const canvas = byId("texturePreview");
|
||||||
|
|
|
||||||
|
|
@ -242,7 +242,18 @@ function addStylePreset() {
|
||||||
"#oceanLayers": ["filter", "layers"],
|
"#oceanLayers": ["filter", "layers"],
|
||||||
"#oceanBase": ["fill"],
|
"#oceanBase": ["fill"],
|
||||||
"#oceanicPattern": ["href", "opacity"],
|
"#oceanicPattern": ["href", "opacity"],
|
||||||
"#terrs": ["opacity", "scheme", "terracing", "skip", "relax", "curve", "filter", "mask"],
|
"#terrs #oceanHeights": [
|
||||||
|
"data-render",
|
||||||
|
"opacity",
|
||||||
|
"scheme",
|
||||||
|
"terracing",
|
||||||
|
"skip",
|
||||||
|
"relax",
|
||||||
|
"curve",
|
||||||
|
"filter",
|
||||||
|
"mask"
|
||||||
|
],
|
||||||
|
"#terrs #landHeights": ["opacity", "scheme", "terracing", "skip", "relax", "curve", "filter", "mask"],
|
||||||
"#legend": [
|
"#legend": [
|
||||||
"data-size",
|
"data-size",
|
||||||
"font-size",
|
"font-size",
|
||||||
|
|
|
||||||
|
|
@ -292,7 +292,9 @@
|
||||||
"terracing": 0,
|
"terracing": 0,
|
||||||
"skip": 2,
|
"skip": 2,
|
||||||
"relax": 1,
|
"relax": 1,
|
||||||
"curve": 0,
|
"curve": "curveBasisClosed",
|
||||||
|
"skipOcean": 0,
|
||||||
|
"relaxOcean": 1,
|
||||||
"filter": "url(#blur3)",
|
"filter": "url(#blur3)",
|
||||||
"mask": "url(#land)"
|
"mask": "url(#land)"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -292,7 +292,9 @@
|
||||||
"terracing": 0,
|
"terracing": 0,
|
||||||
"skip": 0,
|
"skip": 0,
|
||||||
"relax": 0,
|
"relax": 0,
|
||||||
"curve": 0,
|
"curve": "curveBasisClosed",
|
||||||
|
"skipOcean": 0,
|
||||||
|
"relaxOcean": 1,
|
||||||
"filter": null,
|
"filter": null,
|
||||||
"mask": "url(#land)"
|
"mask": "url(#land)"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -294,7 +294,9 @@
|
||||||
"terracing": 0,
|
"terracing": 0,
|
||||||
"skip": 5,
|
"skip": 5,
|
||||||
"relax": 0,
|
"relax": 0,
|
||||||
"curve": 0,
|
"curve": "curveBasisClosed",
|
||||||
|
"skipOcean": 0,
|
||||||
|
"relaxOcean": 1,
|
||||||
"filter": null,
|
"filter": null,
|
||||||
"mask": "url(#land)"
|
"mask": "url(#land)"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -292,7 +292,9 @@
|
||||||
"terracing": 6,
|
"terracing": 6,
|
||||||
"skip": 0,
|
"skip": 0,
|
||||||
"relax": 2,
|
"relax": 2,
|
||||||
"curve": 0,
|
"curve": "curveBasisClosed",
|
||||||
|
"skipOcean": 0,
|
||||||
|
"relaxOcean": 1,
|
||||||
"filter": "",
|
"filter": "",
|
||||||
"mask": "url(#land)"
|
"mask": "url(#land)"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -286,13 +286,24 @@
|
||||||
"href": "./images/pattern1.png",
|
"href": "./images/pattern1.png",
|
||||||
"opacity": 0.2
|
"opacity": 0.2
|
||||||
},
|
},
|
||||||
"#terrs": {
|
"#terrs > #oceanHeights": {
|
||||||
"opacity": null,
|
"data-render": 0,
|
||||||
|
"opacity": 1,
|
||||||
|
"scheme": "bright",
|
||||||
|
"terracing": 0,
|
||||||
|
"skip": 0,
|
||||||
|
"relax": 1,
|
||||||
|
"curve": "curveBasisClosed",
|
||||||
|
"filter": null,
|
||||||
|
"mask": null
|
||||||
|
},
|
||||||
|
"#terrs > #landHeights": {
|
||||||
|
"opacity": 1,
|
||||||
"scheme": "bright",
|
"scheme": "bright",
|
||||||
"terracing": 0,
|
"terracing": 0,
|
||||||
"skip": 5,
|
"skip": 5,
|
||||||
"relax": 0,
|
"relax": 0,
|
||||||
"curve": 0,
|
"curve": "curveBasisClosed",
|
||||||
"filter": null,
|
"filter": null,
|
||||||
"mask": "url(#land)"
|
"mask": "url(#land)"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -294,7 +294,9 @@
|
||||||
"terracing": 2,
|
"terracing": 2,
|
||||||
"skip": 1,
|
"skip": 1,
|
||||||
"relax": 2,
|
"relax": 2,
|
||||||
"curve": 0,
|
"curve": "curveBasisClosed",
|
||||||
|
"skipOcean": 0,
|
||||||
|
"relaxOcean": 1,
|
||||||
"filter": "url(#filter-grayscale)",
|
"filter": "url(#filter-grayscale)",
|
||||||
"mask": "url(#land)"
|
"mask": "url(#land)"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -292,7 +292,9 @@
|
||||||
"terracing": 10,
|
"terracing": 10,
|
||||||
"skip": 5,
|
"skip": 5,
|
||||||
"relax": 0,
|
"relax": 0,
|
||||||
"curve": 0,
|
"curve": "curveBasisClosed",
|
||||||
|
"skipOcean": 0,
|
||||||
|
"relaxOcean": 1,
|
||||||
"filter": "url(#turbulence)",
|
"filter": "url(#turbulence)",
|
||||||
"mask": "url(#land)"
|
"mask": "url(#land)"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -287,7 +287,9 @@
|
||||||
"terracing": 0,
|
"terracing": 0,
|
||||||
"skip": 5,
|
"skip": 5,
|
||||||
"relax": 0,
|
"relax": 0,
|
||||||
"curve": 0,
|
"curve": "curveBasisClosed",
|
||||||
|
"skipOcean": 0,
|
||||||
|
"relaxOcean": 1,
|
||||||
"filter": "url(#blur3)",
|
"filter": "url(#blur3)",
|
||||||
"mask": "url(#land)"
|
"mask": "url(#land)"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -292,7 +292,9 @@
|
||||||
"terracing": 0,
|
"terracing": 0,
|
||||||
"skip": 10,
|
"skip": 10,
|
||||||
"relax": 0,
|
"relax": 0,
|
||||||
"curve": 0,
|
"curve": "curveBasisClosed",
|
||||||
|
"skipOcean": 0,
|
||||||
|
"relaxOcean": 1,
|
||||||
"filter": "url(#blurFilter)",
|
"filter": "url(#blurFilter)",
|
||||||
"mask": "url(#land)"
|
"mask": "url(#land)"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -292,7 +292,9 @@
|
||||||
"terracing": 0,
|
"terracing": 0,
|
||||||
"skip": 2,
|
"skip": 2,
|
||||||
"relax": 1,
|
"relax": 1,
|
||||||
"curve": 0,
|
"curve": "curveBasisClosed",
|
||||||
|
"skipOcean": 0,
|
||||||
|
"relaxOcean": 1,
|
||||||
"filter": "",
|
"filter": "",
|
||||||
"mask": "url(#land)"
|
"mask": "url(#land)"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -292,7 +292,9 @@
|
||||||
"terracing": 0,
|
"terracing": 0,
|
||||||
"skip": 5,
|
"skip": 5,
|
||||||
"relax": 1,
|
"relax": 1,
|
||||||
"curve": 0,
|
"curve": "curveBasisClosed",
|
||||||
|
"skipOcean": 0,
|
||||||
|
"relaxOcean": 1,
|
||||||
"filter": null,
|
"filter": null,
|
||||||
"mask": "url(#land)"
|
"mask": "url(#land)"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -329,7 +329,7 @@ function drawCellsValue(data) {
|
||||||
function drawPolygons(data) {
|
function drawPolygons(data) {
|
||||||
const max = d3.max(data),
|
const max = d3.max(data),
|
||||||
min = d3.min(data),
|
min = d3.min(data),
|
||||||
scheme = getColorScheme(terrs.attr("scheme"));
|
scheme = getColorScheme(terrs.select("#landHeights").attr("scheme"));
|
||||||
data = data.map(d => 1 - normalize(d, min, max));
|
data = data.map(d => 1 - normalize(d, min, max));
|
||||||
|
|
||||||
debug.selectAll("polygon").remove();
|
debug.selectAll("polygon").remove();
|
||||||
|
|
@ -338,7 +338,7 @@ function drawPolygons(data) {
|
||||||
.data(data)
|
.data(data)
|
||||||
.enter()
|
.enter()
|
||||||
.append("polygon")
|
.append("polygon")
|
||||||
.attr("points", (d, i) => getPackPolygon(i))
|
.attr("points", (d, i) => getGridPolygon(i))
|
||||||
.attr("fill", d => scheme(d))
|
.attr("fill", d => scheme(d))
|
||||||
.attr("stroke", d => scheme(d));
|
.attr("stroke", d => scheme(d));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ const version = "1.96.00"; // generator version, update each time
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
<strong>Latest changes:</strong>
|
<strong>Latest changes:</strong>
|
||||||
|
<li>Ability to render ocean heightmap</li>
|
||||||
<li>Vignette visual layer and vignette styling options</li>
|
<li>Vignette visual layer and vignette styling options</li>
|
||||||
<li>Ability to define custom heightmap color scheme</li>
|
<li>Ability to define custom heightmap color scheme</li>
|
||||||
<li>New style preset Night and new heightmap color schemes</li>
|
<li>New style preset Night and new heightmap color schemes</li>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue