Migrate from main PhD-Code repo.

Link: https://git.starbeamrainbowlabs.com/sbrl/PhD-Code
This commit is contained in:
Starbeamrainbowlabs 2020-03-27 20:10:52 +00:00
parent 10c73cba3f
commit a9a66b82e1
Signed by: sbrl
GPG Key ID: 1BE5172E637709C2
26 changed files with 1404 additions and 4 deletions

479
package-lock.json generated
View File

@ -4,16 +4,242 @@
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"@iarna/toml": {
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/@iarna/toml/-/toml-2.2.3.tgz",
"integrity": "sha512-FmuxfCuolpLl0AnQ2NHSzoUKWEJDFl63qXjzdoWBVyFCXzMGm1spBzk7LeHNoVCiWCF7mRVms9e6jEV9+MoPbg=="
},
"applause-cli": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/applause-cli/-/applause-cli-1.2.0.tgz",
"integrity": "sha512-JPCHkBzaghitUPYWK4Jm6YNUklJIBjhlvzU3WLswjvjolMyQN8WVWR8qrGmMbs1skej2p/ZINisZVVvmuEFkog=="
},
"arr-flatten": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz",
"integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg=="
},
"atob-lite": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/atob-lite/-/atob-lite-2.0.0.tgz",
"integrity": "sha1-D+9a1G8b16hQLGVyfwNn1e5D1pY="
},
"bmp-js": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/bmp-js/-/bmp-js-0.1.0.tgz",
"integrity": "sha1-4Fpj95amwf8l9Hcex62twUjAcjM="
},
"chroma-js": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/chroma-js/-/chroma-js-2.1.0.tgz",
"integrity": "sha512-uiRdh4ZZy+UTPSrAdp8hqEdVb1EllLtTHOt5TMaOjJUvi+O54/83Fc5K2ld1P+TJX+dw5B+8/sCgzI6eaur/lg==",
"requires": {
"cross-env": "^6.0.3"
}
},
"clamp": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/clamp/-/clamp-1.0.1.tgz",
"integrity": "sha1-ZqDmQBGBbjcZaCj9yMjBRzEshjQ="
},
"color-id": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/color-id/-/color-id-1.1.0.tgz",
"integrity": "sha512-2iRtAn6dC/6/G7bBIo0uupVrIne1NsQJvJxZOBCzQOfk7jRq97feaDZ3RdzuHakRXXnHGNwglto3pqtRx1sX0g==",
"requires": {
"clamp": "^1.0.1"
}
},
"compute-dims": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/compute-dims/-/compute-dims-1.1.0.tgz",
"integrity": "sha512-YHMiIKjH/8Eom8zATk3g8/lH3HxGCZcVQyEfEoVrfWI7od/WRpTgRGShnei3jArYSx77mQqPxZNokjGHCdLfxg==",
"requires": {
"utils-copy": "^1.0.0",
"validate.io-array": "^1.0.6",
"validate.io-matrix-like": "^1.0.2",
"validate.io-ndarray-like": "^1.0.0",
"validate.io-positive-integer": "^1.0.0"
}
},
"const-max-uint32": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/const-max-uint32/-/const-max-uint32-1.0.2.tgz",
"integrity": "sha1-8Am7YjDmeO2HTdLWqc2ePL+rtnY="
},
"const-pinf-float64": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/const-pinf-float64/-/const-pinf-float64-1.0.0.tgz",
"integrity": "sha1-9u+w15+cCYbT558pI6v5twtj1yY="
},
"cross-env": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/cross-env/-/cross-env-6.0.3.tgz",
"integrity": "sha512-+KqxF6LCvfhWvADcDPqo64yVIB31gv/jQulX2NGzKS/g3GEVz6/pt4wjHFtFWsHMddebWD/sDthJemzM4MaAag==",
"requires": {
"cross-spawn": "^7.0.0"
}
},
"cross-spawn": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.1.tgz",
"integrity": "sha512-u7v4o84SwFpD32Z8IIcPZ6z1/ie24O6RU3RbtL5Y316l3KuHVPx9ItBgWQ6VlfAFnRnTtMUrsQ9MUUTuEZjogg==",
"requires": {
"path-key": "^3.1.0",
"shebang-command": "^2.0.0",
"which": "^2.0.1"
}
},
"dtype": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/dtype/-/dtype-2.0.0.tgz",
"integrity": "sha1-zQUjI84GFETs0uj1dI9popvihDQ="
},
"file-type": {
"version": "10.11.0",
"resolved": "https://registry.npmjs.org/file-type/-/file-type-10.11.0.tgz",
"integrity": "sha512-uzk64HRpUZyTGZtVuvrjP0FYxzQrBf4rojot6J65YMEbwBLB0CWm0CLojVpwpmFmxcE/lkvYICgfcGozbBq6rw=="
},
"flatten-vertex-data": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/flatten-vertex-data/-/flatten-vertex-data-1.0.2.tgz",
"integrity": "sha512-BvCBFK2NZqerFTdMDgqfHBwxYWnxeCkwONsw6PvBMcUXqo8U/KDWwmXhqx1x2kLIg7DqIsJfOaJFOmlua3Lxuw==",
"requires": {
"dtype": "^2.0.0"
}
},
"flip-pixels": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/flip-pixels/-/flip-pixels-1.0.2.tgz",
"integrity": "sha512-oXbJGbjDnfJRWPC7Va38EFhd+A8JWE5/hCiKcK8qjCdbLj9DTpsq6MEudwpRTH+V4qq+Jw7d3pUgQdSr3x3mTA=="
},
"fs-extra": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
"integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==",
"requires": {
"graceful-fs": "^4.2.0",
"jsonfile": "^4.0.0",
"universalify": "^0.1.0"
}
},
"graceful-fs": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz",
"integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ=="
},
"iconv-lite": {
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.5.1.tgz",
"integrity": "sha512-ONHr16SQvKZNSqjQT9gy5z24Jw+uqfO02/ngBSBoqChZ+W8qXX7GPRa1RoUnzGADw8K63R1BXUMzarCVQBpY8Q==",
"requires": {
"safer-buffer": ">= 2.1.2 < 3"
}
},
"image-encode": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/image-encode/-/image-encode-1.3.0.tgz",
"integrity": "sha512-2SzuDscMQGK38jGiVMSuygquz2z3DnW4Smget/LipWfqvEnc7+L/qbaQAPDtzi9hsHqKpGGU22SUjl6G8TprJg==",
"requires": {
"bmp-js": "^0.1.0",
"image-palette": "^2.0.1",
"image-type": "^3.0.0",
"is-plain-obj": "^1.1.0",
"jpeg-js": "^0.3.4",
"next-pow-2": "^1.0.0",
"object-assign": "^4.1.1",
"omggif": "^1.0.9",
"pngjs": "^3.3.3",
"pxls": "^2.3.1",
"to-array-buffer": "^3.0.0",
"utif": "^2.0.1"
}
},
"image-palette": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/image-palette/-/image-palette-2.1.0.tgz",
"integrity": "sha512-3ImSEWD26+xuQFdP0RWR4WSXadZwvgrFhjGNpMEapTG1tf2XrBFS2dlKK5hNgH4UIaSQlSUFRn1NeA+zULIWbQ==",
"requires": {
"color-id": "^1.1.0",
"pxls": "^2.0.0",
"quantize": "^1.0.2"
}
},
"image-type": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/image-type/-/image-type-3.1.0.tgz",
"integrity": "sha512-edYRXKQ3WD2yHXFGUbwoJVn5v7j1A6Z505uZUYIfzCwOOhPGLYSc3VOucF9fqbsaUbgb37DdjOU+WV4uo7ZooQ==",
"requires": {
"file-type": "^10.9.0"
}
},
"is-base64": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/is-base64/-/is-base64-0.1.0.tgz",
"integrity": "sha512-WRRyllsGXJM7ZN7gPTCCQ/6wNPTRDwiWdPK66l5sJzcU/oOzcIcRRf0Rux8bkpox/1yjt0F6VJRsQOIG2qz5sg=="
},
"is-blob": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/is-blob/-/is-blob-2.1.0.tgz",
"integrity": "sha512-SZ/fTft5eUhQM6oF/ZaASFDEdbFVe89Imltn9uZr03wdKMcWNVYSMjQPFtg05QuNkt5l5c135ElvXEQG0rk4tw=="
},
"is-browser": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/is-browser/-/is-browser-2.1.0.tgz",
"integrity": "sha512-F5rTJxDQ2sW81fcfOR1GnCXT6sVJC104fCyfj+mjpwNEwaPYSn5fte5jiHmBg3DHsIoL/l8Kvw5VN5SsTRcRFQ=="
},
"is-buffer": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz",
"integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A=="
},
"is-float-array": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-float-array/-/is-float-array-1.0.0.tgz",
"integrity": "sha512-4ew1Sx6B6kEAl3T3NOM0yB94J3NZnBdNt4paw0e8nY73yHHTeTEhyQ3Lj7EQEnv5LD+GxNTaT4L46jcKjjpLiQ=="
},
"is-plain-obj": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz",
"integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4="
},
"isexe": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
"integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA="
},
"jpeg-js": {
"version": "0.3.7",
"resolved": "https://registry.npmjs.org/jpeg-js/-/jpeg-js-0.3.7.tgz",
"integrity": "sha512-9IXdWudL61npZjvLuVe/ktHiA41iE8qFyLB+4VDTblEsWBzeg8WQTlktdUK4CdncUqtUgUg0bbOmTE2bKBKaBQ=="
},
"jsonfile": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
"integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=",
"requires": {
"graceful-fs": "^4.1.6"
}
},
"mgrs": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/mgrs/-/mgrs-1.0.0.tgz",
"integrity": "sha1-+5FYjnjJACVnI5XLQLJffNatGCk="
},
"nexline": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/nexline/-/nexline-1.2.0.tgz",
"integrity": "sha512-Xie4Lj/x0Lh9ntY/0n1zUZL4V4tvUvReE93iR3DxzZK8LVx15rmzAmeiaFuE0dzS1njS33n2+HRfgOBc5R7nfw==",
"requires": {
"fs-extra": "^8.1.0",
"iconv-lite": "^0.5.0"
}
},
"next-pow-2": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/next-pow-2/-/next-pow-2-1.0.0.tgz",
"integrity": "sha1-y1wvHa4EDFbN1c2h3FxqOjOPQ2c="
},
"nnng": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/nnng/-/nnng-1.0.0.tgz",
@ -22,6 +248,36 @@
"proj4": "^2.3.10"
}
},
"object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
},
"object-keys": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
"integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA=="
},
"omggif": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/omggif/-/omggif-1.0.10.tgz",
"integrity": "sha512-LMJTtvgc/nugXj0Vcrrs68Mn2D1r0zf630VNtqtpI1FEO7e+O9FP4gqs9AcnBaSEeoHIPm28u6qgPR0oyEpGSw=="
},
"pako": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
"integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="
},
"path-key": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="
},
"pngjs": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/pngjs/-/pngjs-3.4.0.tgz",
"integrity": "sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w=="
},
"proj4": {
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/proj4/-/proj4-2.6.0.tgz",
@ -31,14 +287,231 @@
"wkt-parser": "^1.2.0"
}
},
"terrain50": {
"pxls": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/pxls/-/pxls-2.3.2.tgz",
"integrity": "sha512-pQkwgbLqWPcuES5iEmGa10OlCf5xG0blkIF3dg7PpRZShbTYcvAdfFfGL03SMrkaSUaa/V0UpN9HWg40O2AIIw==",
"requires": {
"arr-flatten": "^1.1.0",
"compute-dims": "^1.1.0",
"flip-pixels": "^1.0.2",
"is-browser": "^2.1.0",
"is-buffer": "^2.0.3",
"to-uint8": "^1.4.1"
}
},
"quantize": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/quantize/-/quantize-1.0.2.tgz",
"integrity": "sha1-0lrCAKd7bXD0ASfKFxoQ4zyFRt4="
},
"regex-regex": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/terrain50/-/terrain50-1.0.0.tgz",
"integrity": "sha512-qEw69Sk9F6AiTmAa+mpElSRN5wScscxRCjN/6sie42QXlUOdqNLxSbWOnKSLGiBGg1BH6/Uhbwf3YjP5YFvpwQ==",
"resolved": "https://registry.npmjs.org/regex-regex/-/regex-regex-1.0.0.tgz",
"integrity": "sha1-kEih6uuHD01IDavHb8Qs3MC8OnI="
},
"safer-buffer": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
},
"shebang-command": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
"integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
"requires": {
"shebang-regex": "^3.0.0"
}
},
"shebang-regex": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="
},
"string-to-arraybuffer": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/string-to-arraybuffer/-/string-to-arraybuffer-1.0.2.tgz",
"integrity": "sha512-DaGZidzi93dwjQen5I2osxR9ERS/R7B1PFyufNMnzhj+fmlDQAc1DSDIJVJhgI8Oq221efIMbABUBdPHDRt43Q==",
"requires": {
"atob-lite": "^2.0.0",
"is-base64": "^0.1.0"
}
},
"terrain50": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/terrain50/-/terrain50-1.3.0.tgz",
"integrity": "sha512-BkQMAY6W67FsE1yWr24yHBhd46lQCdwON1/pMkZsLTWl1EYiaSPCNu+QCO4GV/7E8b9IXgiPUQpOqtiA5sZ6BQ==",
"requires": {
"nnng": "^1.0.0"
}
},
"to-array-buffer": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/to-array-buffer/-/to-array-buffer-3.2.0.tgz",
"integrity": "sha512-zN33mwi0gpL+7xW1ITLfJ48CEj6ZQW0ZAP0MU+2W3kEY0PAIncyuxmD4OqkUVhPAbTP7amq9j/iwvZKYS+lzSQ==",
"requires": {
"flatten-vertex-data": "^1.0.2",
"is-blob": "^2.0.1",
"string-to-arraybuffer": "^1.0.0"
}
},
"to-uint8": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/to-uint8/-/to-uint8-1.4.1.tgz",
"integrity": "sha512-o+ochsMlTZyucbww8It401FC2Rx+OP2RpDeYbA6h+y9HgedDl1UjdsJ9CmzKEG7AFP9es5PmJ4eDWeeeXihESg==",
"requires": {
"arr-flatten": "^1.1.0",
"clamp": "^1.0.1",
"is-base64": "^0.1.0",
"is-float-array": "^1.0.0",
"to-array-buffer": "^3.0.0"
}
},
"type-name": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/type-name/-/type-name-2.0.2.tgz",
"integrity": "sha1-7+fUEj2KxSr/9/QMfk3sUmYAj7Q="
},
"universalify": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
"integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg=="
},
"utif": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/utif/-/utif-2.0.1.tgz",
"integrity": "sha512-Z/S1fNKCicQTf375lIP9G8Sa1H/phcysstNrrSdZKj1f9g58J4NMgb5IgiEZN9/nLMPDwF0W7hdOe9Qq2IYoLg==",
"requires": {
"pako": "^1.0.5"
}
},
"utils-copy": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/utils-copy/-/utils-copy-1.1.1.tgz",
"integrity": "sha1-biuXmCqozXPhGCo+b4vsPA9AWKc=",
"requires": {
"const-pinf-float64": "^1.0.0",
"object-keys": "^1.0.9",
"type-name": "^2.0.0",
"utils-copy-error": "^1.0.0",
"utils-indexof": "^1.0.0",
"utils-regex-from-string": "^1.0.0",
"validate.io-array": "^1.0.3",
"validate.io-buffer": "^1.0.1",
"validate.io-nonnegative-integer": "^1.0.0"
}
},
"utils-copy-error": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/utils-copy-error/-/utils-copy-error-1.0.1.tgz",
"integrity": "sha1-eR3jk8DwmJCv1Z88vqY18HmpT6U=",
"requires": {
"object-keys": "^1.0.9",
"utils-copy": "^1.1.0"
}
},
"utils-indexof": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/utils-indexof/-/utils-indexof-1.0.0.tgz",
"integrity": "sha1-IP6r8J7xAYtSNkPoOA57yD7GG1w=",
"requires": {
"validate.io-array-like": "^1.0.1",
"validate.io-integer-primitive": "^1.0.0"
}
},
"utils-regex-from-string": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/utils-regex-from-string/-/utils-regex-from-string-1.0.0.tgz",
"integrity": "sha1-/hopCfjeD/DVGCyA+8ZU1qaH0Yk=",
"requires": {
"regex-regex": "^1.0.0",
"validate.io-string-primitive": "^1.0.0"
}
},
"validate.io-array": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/validate.io-array/-/validate.io-array-1.0.6.tgz",
"integrity": "sha1-W1osr9j4uFq7L4hroVPy2Tond00="
},
"validate.io-array-like": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/validate.io-array-like/-/validate.io-array-like-1.0.2.tgz",
"integrity": "sha1-evn363tRcVvrIhVmjsXM5U+t21o=",
"requires": {
"const-max-uint32": "^1.0.2",
"validate.io-integer-primitive": "^1.0.0"
}
},
"validate.io-buffer": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/validate.io-buffer/-/validate.io-buffer-1.0.2.tgz",
"integrity": "sha1-hS1nNAIZFNXROvwyUxdh43IO1E4="
},
"validate.io-integer": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/validate.io-integer/-/validate.io-integer-1.0.5.tgz",
"integrity": "sha1-FoSWSAuVviJH7EQ/IjPeT4mHgGg=",
"requires": {
"validate.io-number": "^1.0.3"
}
},
"validate.io-integer-primitive": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/validate.io-integer-primitive/-/validate.io-integer-primitive-1.0.0.tgz",
"integrity": "sha1-qaoBA1X+hoHA/qbBp0rSQZyt3cY=",
"requires": {
"validate.io-number-primitive": "^1.0.0"
}
},
"validate.io-matrix-like": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/validate.io-matrix-like/-/validate.io-matrix-like-1.0.2.tgz",
"integrity": "sha1-XsMqddCInaxzbepovdYUWxVe38M="
},
"validate.io-ndarray-like": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/validate.io-ndarray-like/-/validate.io-ndarray-like-1.0.0.tgz",
"integrity": "sha1-2KOw7RZbvx0vwNAHMnDPpVIpWRk="
},
"validate.io-nonnegative-integer": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/validate.io-nonnegative-integer/-/validate.io-nonnegative-integer-1.0.0.tgz",
"integrity": "sha1-gGkkOgjF+Y6VQTySnf17GPP28p8=",
"requires": {
"validate.io-integer": "^1.0.5"
}
},
"validate.io-number": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/validate.io-number/-/validate.io-number-1.0.3.tgz",
"integrity": "sha1-9j/+2iSL8opnqNSODjtGGhZluvg="
},
"validate.io-number-primitive": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/validate.io-number-primitive/-/validate.io-number-primitive-1.0.0.tgz",
"integrity": "sha1-0uAfICmJNp3PEVVElWQgOv5YTlU="
},
"validate.io-positive-integer": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/validate.io-positive-integer/-/validate.io-positive-integer-1.0.0.tgz",
"integrity": "sha1-ftLQO0wnVYzGagCqsPDpIYFKZYI=",
"requires": {
"validate.io-integer": "^1.0.5"
}
},
"validate.io-string-primitive": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/validate.io-string-primitive/-/validate.io-string-primitive-1.0.1.tgz",
"integrity": "sha1-uBNbn7E3K94C/dU60dDM1t55j+4="
},
"which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
"requires": {
"isexe": "^2.0.0"
}
},
"wkt-parser": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/wkt-parser/-/wkt-parser-1.2.4.tgz",

View File

@ -31,7 +31,14 @@
],
"homepage": "https://github.com/sbrl/terrain50-cli#readme",
"dependencies": {
"@iarna/toml": "^2.2.3",
"applause-cli": "^1.2.0",
"terrain50": "^1.0.0"
"chroma-js": "^2.1.0",
"image-encode": "^1.3.0",
"nexline": "^1.2.0",
"terrain50": "^1.3.0"
},
"bin": {
"terrain50": "./src/index.mjs"
}
}

109
src/Bootstrap/cli.mjs Normal file
View File

@ -0,0 +1,109 @@
"use strict";
import fs from 'fs';
import path from 'path';
import TOML from '@iarna/toml';
import CliParser from 'applause-cli';
import a from '../Helpers/Ansi.mjs';
import settings from './settings.mjs';
const __dirname = import.meta.url.slice(7, import.meta.url.lastIndexOf("/"));
const subcommand_directory = "../Subcommands";
async function get_actions() {
let dirs = await fs.promises.readdir(
path.resolve(
__dirname,
subcommand_directory
)
);
return dirs.map((dir) => {
let index_file = path.resolve(__dirname, `${subcommand_directory}/${dir}/`, "index.mjs");
if(!fs.existsSync(index_file))
return null;
return path.basename(path.dirname(index_file));
}).filter(x => x !== null);
}
async function get_actions_metadata() {
let result = {};
for (let action of await get_actions()) {
let filepath = path.resolve(
__dirname,
`${subcommand_directory}/${action}/`,
`meta.toml`
);
if(!fs.existsSync(filepath)) {
result[action] = {
description: `${a.locol}${a.italics}(No description found)${a.reset}`,
arguments: []
};
continue;
}
result[action] = TOML.parse(await fs.promises.readFile(filepath));
}
return result;
}
export default async function() {
let cli = new CliParser(path.resolve(__dirname, "../../package.json"));
// Disable ansi escape codes if requested
if(!settings.output.ansi_colour) {
a.enabled = false;
a.escape_codes();
}
let actions_meta = await get_actions_metadata();
for(let action in actions_meta) {
let subcommand = cli.subcommand(action, actions_meta[action].description);
if(!(actions_meta[action].arguments instanceof Array))
continue;
for(let argument of actions_meta[action].arguments) {
subcommand.argument(
argument.name,
argument.description,
argument.default_value,
argument.type
);
}
}
// 2: CLI Argument Parsing
settings.cli = cli.parse(process.argv.slice(2));
let action = cli.current_subcommand;
if(action == null) {
console.error(`${a.hicol}${a.fred}Error: No subcommand specified (try --help for usage information).${a.reset}`);
return;
}
// 3: Environment Variable Parsing
// process.env.XYZ
// 4: Run
console.error(`${a.fgreen}***** ${a.hicol}${action}${a.reset}${a.fgreen} *****${a.reset}`);
try {
await (await import(`${subcommand_directory}/${action}/index.mjs`)).default(settings);
}
catch(error) {
console.error(`\n\n`);
throw error;
}
// 5: Cleanup
}

View File

@ -0,0 +1,21 @@
"use strict";
import fs from 'fs';
import path from 'path';
const __dirname = import.meta.url.slice(7, import.meta.url.lastIndexOf("/"));
// Default settings object
// This is a (greatly) simplified stand-in for the much more advanced settings parsing system we have going on in our maina PhD-Code codebase.
export default {
cli: {
program_name: "terrain50",
description: "manipulates ordnance survey digital elevation model files"
},
output: {
ansi_colour: true
},
package: JSON.parse(fs.readFileSync(
path.resolve(__dirname, "../../package.json")
))
};

82
src/Helpers/Ansi.mjs Normal file
View File

@ -0,0 +1,82 @@
"use strict";
/**
* Generates various VT100 ANSI escape sequences.
* Ported from C#.
* @licence MPL-2.0 <https://www.mozilla.org/en-US/MPL/2.0/>
* @source https://gist.github.com/a4edd3204a03f4eedb79785751efb0f3#file-ansi-cs
* @author Starbeamrainbowlabs
* GitHub: @sbrl | Twitter: @SBRLabs | Reddit: u/Starbeamrainbowlabs
***** Changelog *****
* 27th March 2019:
* - Initial public release
* 9th March 2020:
* - Add Italics (\u001b[3m])
* - Export a new instance of it by default (makes it so that there's 1 global instance)
*/
class Ansi {
constructor() {
/**
* Whether we should *actually* emit ANSI escape codes or not.
* Useful when we want to output to a log file, for example
* @type {Boolean}
*/
this.enabled = true;
this.escape_codes();
}
escape_codes() {
// Solution on how to output ANSI escape codes in C# from here:
// https://www.jerriepelser.com/blog/using-ansi-color-codes-in-net-console-apps
this.reset = this.enabled ? "\u001b[0m" : "";
this.hicol = this.enabled ? "\u001b[1m" : "";
this.locol = this.enabled ? "\u001b[2m" : "";
this.italics = this.enabled ? "\u001b[3m" : "";
this.underline = this.enabled ? "\u001b[4m" : "";
this.inverse = this.enabled ? "\u001b[7m" : "";
this.fblack = this.enabled ? "\u001b[30m" : "";
this.fred = this.enabled ? "\u001b[31m" : "";
this.fgreen = this.enabled ? "\u001b[32m" : "";
this.fyellow = this.enabled ? "\u001b[33m" : "";
this.fblue = this.enabled ? "\u001b[34m" : "";
this.fmagenta = this.enabled ? "\u001b[35m" : "";
this.fcyan = this.enabled ? "\u001b[36m" : "";
this.fwhite = this.enabled ? "\u001b[37m" : "";
this.bblack = this.enabled ? "\u001b[40m" : "";
this.bred = this.enabled ? "\u001b[41m" : "";
this.bgreen = this.enabled ? "\u001b[42m" : "";
this.byellow = this.enabled ? "\u001b[43m" : "";
this.bblue = this.enabled ? "\u001b[44m" : "";
this.bmagenta = this.enabled ? "\u001b[45m" : "";
this.bcyan = this.enabled ? "\u001b[46m" : "";
this.bwhite = this.enabled ? "\u001b[47m" : "";
}
// Thanks to http://ascii-table.com/ansi-escape-sequences.php for the following ANSI escape sequences
up(lines = 1) {
return this.enabled ? `\u001b[${lines}A` : "";
}
down(lines = 1) {
return this.enabled ? `\u001b[${lines}B` : "";
}
right(lines = 1) {
return this.enabled ? `\u001b[${lines}C` : "";
}
left(lines = 1) {
return this.enabled ? `\u001b[${lines}D` : "";
}
jump_to(x, y) {
return this.enabled ? `\u001b[${y};${x}H` : "";
}
cursor_pos_save() {
return this.enabled ? `\u001b[s` : "";
}
cursor_pos_restore() {
return this.enabled ? `\u001b[u` : "";
}
}
export default (new Ansi());

82
src/Helpers/Log.mjs Normal file
View File

@ -0,0 +1,82 @@
"use strict";
import a from './Ansi.mjs';
const LOG_LEVELS = {
DEBUG: 0,
INFO: 1,
LOG: 2,
WARN: 4,
ERROR: 8,
NONE: 2048
};
/**
* Provides a simple logging utility. Depends on Ansi.mjs, and originated in my
* personal project woppleblox (which may or may not actually get finished).
*/
class Log {
constructor() {
this.start = new Date();
this.level = LOG_LEVELS.DEBUG;
this.datetime_relative = false;
}
debug(...message) {
if(this.level > LOG_LEVELS.DEBUG) return;
this.__do_log("debug", ...message);
}
info(...message) {
if(this.level > LOG_LEVELS.INFO) return;
this.__do_log("info", ...message);
}
log(...message) {
if(this.level > LOG_LEVELS.LOG) return;
this.__do_log("log", ...message);
}
warn(...message) {
if(this.level > LOG_LEVELS.WARN) return;
this.__do_log("warn", ...message);
}
error(...message) {
if(this.level > LOG_LEVELS.ERROR) return;
this.__do_log("error", ...message);
}
__do_log(level, ...message) {
let part = `[ ${level} ]`;
switch(level) {
case "debug":
part = a.locol + part;
message.push(a.reset);
break;
case "warn":
part = a.fyellow + a.hicol + part;
message.push(a.reset);
break;
case "error":
part = a.fred + a.hicol + part;
message.push(a.reset);
break;
}
let date = this.datetime_relative ? ((new Date() - this.start) / 1000).toFixed(3) : (new Date()).toISOString();
message.unshift(`${part}`);
message.unshift(`${a.locol}[ ${date} ]${a.reset}`);
console.error(...message);
}
}
// You won't normally need these
export { LOG_LEVELS };
export default new Log();

View File

@ -0,0 +1,59 @@
"use strict";
import fs from 'fs';
import nexline from 'nexline';
import chroma from 'chroma-js';
import a from '../../Helpers/Ansi.mjs';
import l from '../../Helpers/Log.mjs';
import Terrain50 from 'terrain50';
async function process_filename(result, filename) {
let next_item = Terrain50.Parse(await fs.promises.readFile(filename, "utf-8"))
.to_geojson_feature();
next_item.properties.filename = filename;
let colour = chroma.random();
next_item.properties.fill = colour.hex();
next_item.properties.stroke = colour.darken().hex();
result.features.push(next_item);
}
export default async function(settings) {
let result = {
type: "FeatureCollection",
features: []
};
if(settings.cli.input instanceof Array) {
l.log(`Reading filenames from ${a.hicol}CLI arguments${a.reset}`);
for(let filename of settings.cli.input) {
l.log(`Processing ${a.hicol}${filename}${a.reset} from CLI argument`);
await process_filename(result, filename);
}
}
else {
l.log(`Reading filenames from ${a.hicol}stdin${a.reset}`);
let reader = nexline({
input: process.stdin
});
while(true) {
let filename = await reader.next();
if(filename == null)
break;
if(filename.length == 0) continue;
l.log(`Processing ${a.hicol}${filename}${a.reset} from stdin`);
await process_filename(result, filename);
}
}
l.log(`${a.hicol}${a.fgreen}Done${a.reset}`);
console.log(JSON.stringify(result));
}

View File

@ -0,0 +1,7 @@
description = "Convert 1 or more Terrain50 files to a GeoJSON bounding box"
[[arguments]]
name = "input"
description = "The input Terrain50 file(s) to operate on. May be specified multiple times."
# default_value = ""
type = "string_multi"

View File

@ -0,0 +1,110 @@
"use strict";
import chroma from 'chroma-js';
import encode from 'image-encode';
import l from '../../Helpers/Log.mjs';
class Terrain50Renderer {
constructor(in_scale_factor) {
this.scale_factor = in_scale_factor;
this.colour_scale = chroma.scale([
"#333333",
// chroma("white").alpha(0),
// "green"
"#efefef",
]).mode('lrgb');
this.colour_nodata = chroma("#f97153").rgba();
}
/**
* Actually does the rendering, returning a canvas with the image rendered
* onto it.
* You probably want the .render() method, which returns a buffer
* containing a png-encoded image.
* @param {Terrain50} terrain The Terrain50 object instance to render.
* @return {ArrayBuffer} A canvas with the image rendered on it.
*/
async do_render(terrain) {
let min = terrain.min_value, max = terrain.max_value;
let colour_domain = this.colour_scale.domain([
min, max
]);
let width = Math.floor(terrain.meta.ncols / this.scale_factor),
height = Math.floor(terrain.meta.nrows / this.scale_factor);
l.log(`[Terrain50Renderer] Colour domain: ${min} - ${max}`);
l.log(`[Terrain50Renderer] Dimensions: ${width}x${height}`);
// Create the image
let pixels = new ArrayBuffer(width * height * 4);
let view8 = new Uint8ClampedArray(pixels),
view32 = new Uint32Array(pixels); // For image generation by us
// let view32 = new Uint32Array(img.bitmap.data);
let count = 0;
for(let y = 0; y < height*this.scale_factor; y += this.scale_factor) {
for(let x = 0; x < width*this.scale_factor; x += this.scale_factor) {
// l.debug(`Processing (${x}, ${y})`)
let a_y = Math.floor(y / this.scale_factor),
a_x = Math.floor(x / this.scale_factor);
// chroma.js clamps automagically :D
let colour = this.colour_nodata;
if(typeof terrain.data[a_y] !== "undefined" &&
terrain.data[a_y][a_x] !== terrain.meta.NODATA_value) {
colour = colour_domain(
terrain.data[a_y][a_x]
).rgba(); // 0: r, 1: g, 2: b, a: 3
}
// colour = chroma("red").rgba();
colour[3] = Math.floor(colour[3] * 255); // Scale the alpha value from 0-1 to 0-255
if(colour[3] < 1) console.log(`(${x}, ${y})`, colour);
// img.bitmap.data[a_y*width + a_x + 0] = colour[0];
// img.bitmap.data[a_y*width + a_x + 1] = colour[1];
// img.bitmap.data[a_y*width + a_x + 2] = colour[2];
// img.bitmap.data[a_y*width + a_x + 3] = colour[3];
view32[count] =
(colour[3] << 24) | // a
(colour[2] << 16) | // b
(colour[1] << 8) | // g
colour[0]; // r
// img.bitmap.data[a_y*width + a_x] =
// (colour[0] << 24) | // r
// (colour[1] << 16) | // g
// (colour[2] << 8) | // b
// colour[3]; // a
// console.log(`(${x}, ${y}) -> (${a_x}, ${a_y}) @ SF ${this.scale_factor}`, terrain.data[y][x], colour);
count++;
}
}
l.log(`Written to ${count} pixels (${view32.length} present, ${((count/(width*height))*100).toFixed(2)}%)`);
console.log(view8);
return view8;
}
/**
* Renders the given Terrain50 object to an image.
* Returns a buffer containing a PNG-encoded image, which is ready to be
* written to disk for example.
* @param {Terrain50} terrain The terrain object to render.
* @return {Buffer} The terrain object as a png, represented as a buffer.
*/
async render(terrain) {
let width = Math.floor(terrain.meta.ncols / this.scale_factor),
height = Math.floor(terrain.meta.nrows / this.scale_factor);
let result = await this.do_render(terrain);
return Buffer.from(encode(result, [ width, height ], "png"));
}
}
export default Terrain50Renderer;

View File

@ -0,0 +1,36 @@
"use strict";
import fs from 'fs';
import l from '../../Helpers/Log.mjs';
import a from '../../Helpers/Ansi.mjs';
import Terrain50 from 'terrain50';
import Terrain50Renderer from './Terrain50Renderer.mjs';
export default async function(settings) {
if(typeof settings.cli.input !== "string") {
l.error("Error: No input file specified (try --filename path/to/file.asc)");
process.exit(1);
}
if(typeof settings.cli.output !== "string") {
l.error("Error: No output file specified (try --filename-output path/to/image.png)");
process.exit(1);
}
let terrain50 = Terrain50.Parse(
await fs.promises.readFile(settings.cli.input, "utf-8")
);
let renderer = new Terrain50Renderer(settings.scale_factor | 1);
let png_buffer = await renderer.render(terrain50);
if(!(png_buffer instanceof Buffer))
throw new Error(`Error: Renderer did not return Buffer (found unexpected ${png_buffer} instead)`);
await fs.promises.writeFile(
settings.cli.output,
png_buffer
);
l.log(`Written to ${a.hicol}${settings.cli.output}${a.reset}`);
}

View File

@ -0,0 +1,13 @@
description = "Convert a Terrain50 file into an image"
[[arguments]]
name = "input"
description = "The input Terrain50 file"
# default_value = ""
type = "string"
[[arguments]]
name = "output"
description = "The output file to write to"
# default_value = ""
type = "string"

View File

@ -0,0 +1,74 @@
#!/usr/local/bin/node --experimental-modules
"use strict";
import path from 'path';
import fs from 'fs';
import a from '../../Helpers/Ansi.mjs';
import l from '../../Helpers/Log.mjs';
import Terrain50 from './Terrain50.mjs';
// const __dirname = import.meta.url.slice(7, import.meta.url.lastIndexOf("/"));
export default async function(settings) {
if(typeof settings.cli.input !== "string") {
console.error(`${a.fred}${a.hicol}Error: No directory specified (try --filename path/to/directory)${a.reset}`);
process.exit(2);
}
if(typeof settings.cli.output !== "string") {
console.error(`${a.fred}${a.hicol}Error: No output file specified (try --filename-output path/to/filename.asc)${a.reset}`);
process.exit(2);
}
let files = await fs.promises.readdir(settings.cli.input);
l.log(`Parsing input files`);
let input_files = [];
let i = 0;
for(let file of files) {
process.stdout.write(`[${i+1} / ${files.length}] ${file}\r`);
let next = Terrain50.Parse(await fs.promises.readFile(
path.resolve(settings.cli.input, file),
{ encoding: "utf-8" }
));
input_files.push(next);
i++;
}
process.stdout.write("\n");
l.log(`done!`);
let big_tile = Terrain50.Merge(...input_files);
l.log(`Validating merge...`);
l.log(`Merge is ${big_tile.meta.ncols}x${big_tile.meta.nrows} @ (${big_tile.meta.xllcorner}, ${big_tile.meta.yllcorner}) on the OS National Grid`)
let validation_errors = big_tile.validate();
if(validation_errors.length > 0) {
l.warn(`Warning: ${validation_errors.length} validation issues detected with merge.`);
l.warn(`Details:`);
for(let error of validation_errors) {
switch(error.level) {
case "warning":
l.warn(error.toString());
break;
case "error":
l.error(error.toString());
break;
default:
l.log(error.toString());
break;
}
}
}
else {
l.log(`${a.fgreen}Validation complete, no issues detected${a.reset}`);
}
l.log("Serialising to file");
let stream_out = fs.createWriteStream(settings.cli.output);
await big_tile.serialise(stream_out);
stream_out.end();
l.log("done, merge complete");
}

View File

@ -0,0 +1,13 @@
description = "Merge multiple Terrain50 instances into a single file"
[[arguments]]
name = "input"
description = "The input directory to read Terrain50 files from"
# default_value = ""
type = "string"
[[arguments]]
name = "output"
description = "The output file to write the merged Terrain50 instances to"
# default_value = ""
type = "string"

View File

@ -0,0 +1,36 @@
"use strict";
import fs from 'fs';
import l from '../../Helpers/Log.mjs';
import Terrain50 from 'terrain50';
export default async function(settings) {
if(typeof settings.cli.input !== "string") {
l.error("Error: No input file specified (try --filename path/to/heightmap.asc)");
process.exit(1);
}
if(typeof settings.cli.output !== "string") {
l.error("Error: No output file specified (try --filename path/to/output.asc)");
process.exit(1);
}
if(typeof settings.cli.find !== "number") {
l.error("Error: No target value to find (try --find INTEGER_HERE)");
process.exit(1);
}
if(typeof settings.cli.replace !== "number") {
l.error("Error: No target value to replace (try --find INTEGER_HERE)");
process.exit(1);
}
l.log(`Reading input files`);
let heightmap = Terrain50.Parse(await fs.promises.readFile(settings.cli.input, "utf-8"));
l.log(`Replacing ${settings.cli.find} with ${settings.cli.replace}`);
heightmap.replace(settings.cli.find, settings.cli.replace);
l.log(`done`);
l.log(`Writing result to disk`);
await heightmap.serialise(fs.createWriteStream(settings.cli.output));
l.log(`Trimming complete!`);
}

View File

@ -0,0 +1,25 @@
description = "Find and replace values in an ascii Terrain50 file."
[[arguments]]
name = "input"
description = "The input Terrain50 file to operate on"
# default_value = ""
type = "string"
[[arguments]]
name = "output"
description = "The filepath to write the output to"
# default_value = ""
type = "string"
[[arguments]]
name = "find"
description = "The target value to find"
# default_value = ""
type = "integer"
[[arguments]]
name = "replace"
description = "The value to replace values that match the target value"
# default_value = ""
type = "integer"

View File

@ -0,0 +1,28 @@
"use strict";
import fs from 'fs';
import l from '../../Helpers/Log.mjs';
import Terrain50 from 'terrain50';
export default async function(settings) {
if(typeof settings.cli.input !== "string") {
l.error("Error: No input file specified (try --filename path/to/heightmap.asc)");
process.exit(1);
}
if(typeof settings.cli.output !== "string") {
l.error("Error: No output file specified (try --filename path/to/output.asc)");
process.exit(1);
}
l.log(`Reading input files`);
let heightmap = Terrain50.Parse(await fs.promises.readFile(settings.cli.input, "utf-8"));
l.log(`Rounding values`);
heightmap.round();
l.log(`done`);
l.log(`Writing result to disk`);
await heightmap.serialise(fs.createWriteStream(settings.cli.output));
l.log(`Trimming complete!`);
}

View File

@ -0,0 +1,13 @@
description = "Round values to the nearest integer in an ascii Terrain50 file."
[[arguments]]
name = "input"
description = "The input Terrain50 file to operate on"
# default_value = ""
type = "string"
[[arguments]]
name = "output"
description = "The filepath to write the output to"
# default_value = ""
type = "string"

View File

@ -0,0 +1,34 @@
"use strict";
import fs from 'fs';
import l from '../../Helpers/Log.mjs';
import Terrain50 from 'terrain50';
export default async function(settings) {
if(typeof settings.cli.input !== "string") {
l.error("Error: No input file specified (try --filename path/to/heightmap.asc)");
process.exit(1);
}
if(typeof settings.cli.output !== "string") {
l.error("Error: No output file specified (try --filename path/to/output.asc)");
process.exit(1);
}
if(typeof settings.cli.scale_factor !== "number") {
l.error("Error: No scale factor specified (try --scale-factor NUMBER_HERE)");
process.exit(1);
}
l.log(`Reading input files`);
let heightmap = Terrain50.Parse(await fs.promises.readFile(settings.cli.input, "utf-8"));
l.log(`Applying scale factor`);
heightmap.scale(settings.cli.scale_factor);
l.log(`Scaled by scale factor ${settings.cli.scale_factor}`);
l.log(`Writing result to disk`);
await heightmap.serialise(fs.createWriteStream(settings.cli.output));
l.log(`Scaling complete!`);
}

View File

@ -0,0 +1,19 @@
description = "Scales the size of a Terrain50 file by a given scale factor."
[[arguments]]
name = "input"
description = "The input Terrain50 file"
# default_value = ""
type = "string"
[[arguments]]
name = "output"
description = "The output filepath to write to"
# default_value = ""
type = "string"
[[arguments]]
name = "scale-factor"
description = "The scale factor to apply."
# default_value = ""
type = "float"

View File

@ -0,0 +1,34 @@
"use strict";
import fs from 'fs';
import l from '../../Helpers/Log.mjs';
import Terrain50 from 'terrain50';
export default async function(settings) {
if(typeof settings.cli.input !== "string") {
l.error("Error: No input file specified (try --filename path/to/heightmap.asc)");
process.exit(1);
}
if(typeof settings.cli.output !== "string") {
l.error("Error: No output file specified (try --filename path/to/output.asc)");
process.exit(1);
}
if(typeof settings.cli.min_value !== "number") {
l.error("Error: No new minimum value specified (try --min-value NUMBER_HERE)");
process.exit(1);
}
l.log(`Reading input files`);
let heightmap = Terrain50.Parse(await fs.promises.readFile(settings.cli.input, "utf-8"));
l.log(`Shifting values`);
let shift_amount = heightmap.shift(settings.cli.min_value);
l.log(`Shifted values by ${shift_amount}`);
l.log(`Writing result to disk`);
await heightmap.serialise(fs.createWriteStream(settings.cli.output));
l.log(`Shifting complete!`);
}

View File

@ -0,0 +1,19 @@
description = "Shift the values in a Terrain50 file such that the minimum value is a given number"
[[arguments]]
name = "input"
description = "The input Terrain50 file"
# default_value = ""
type = "string"
[[arguments]]
name = "output"
description = "The output filepath to write to"
# default_value = ""
type = "string"
[[arguments]]
name = "min-value"
description = "The new minimum value to shift to."
# default_value = ""
type = "integer"

View File

@ -0,0 +1,39 @@
"use strict";
import fs from 'fs';
import l from '../../Helpers/Log.mjs';
import Terrain50 from 'terrain50';
export default async function(settings) {
if(typeof settings.cli.input !== "string") {
l.error("Error: No input file specified (try --filename path/to/heightmap.asc)");
process.exit(1);
}
if(typeof settings.cli.reference !== "string") {
l.error("Error: No reference file specified (try --filename-reference path/to/another.asc)");
process.exit(1);
}
if(typeof settings.cli.output !== "string") {
l.error("Error: No output filename specified (try --filename-output path/to/file.asc)");
process.exit(1);
}
l.log(`Reading input files`);
let heightmap = Terrain50.Parse(await fs.promises.readFile(settings.cli.input, "utf-8")),
reference = Terrain50.Parse(await fs.promises.readFile(settings.cli.reference, "utf-8"));
l.log(`Trimming heightmap according to reference`);
heightmap.trim(reference.meta);
if(typeof settings.cli.replace !== "undefined") {
let [old_value, new_value] = settings.cli.replace.split(/,/g).map((x) => parseInt(x, 10));
l.log(`Replacing ${old_value} with ${new_value}`);
heightmap.replace(old_value, new_value);
l.log(`done`);
}
l.log(`Writing result to disk`);
await heightmap.serialise(fs.createWriteStream(settings.cli.output));
l.log(`Trimming complete!`);
}

View File

@ -0,0 +1,23 @@
description = "Trim a Terrain50 file down to match a 2nd reference Terrain50 file"
[[arguments]]
name = "input"
description = "The input Terrain50 file"
# default_value = ""
type = "string"
[[arguments]]
name = "reference"
description = "The reference Terrain50 to trim the input to"
[[arguments]]
name = "output"
description = "The output filepath to write to"
# default_value = ""
type = "string"
[[arguments]]
name = "replace"
description = "Replace 1 value with another while trimming. Argument value format is \"old_value,new_value\"."
# default_value = ""
type = "string" # We could really have used this being a JS file instead - and we could define a function here instead

View File

@ -0,0 +1,34 @@
"use strict";
import fs from 'fs';
import a from '../../Helpers/Ansi.mjs';
import Terrain50 from 'terrain50';
export default async function(_settings) {
// Read stdin into a string - ref https://stackoverflow.com/a/56012724/1460422
let source = fs.readFileSync(0, 'utf-8');
let errors = Terrain50.Validate(source);
if(errors.length > 0) {
for(let error of errors) {
switch(error.level) {
case "warning":
console.log(`${a.fyellow}${a.hicol}${error}${a.reset}`);
break;
case "error":
console.log(`${a.fred}${a.hicol}${error}${a.reset}`);
break;
default:
console.log(error);
break;
}
}
process.exit(1);
}
else {
console.log(`${a.fgreen}Validation completed successfully - no issues detected :D${a.reset}`);
}
}

View File

@ -0,0 +1 @@
description = "Read the Terrain50 file on stdin, validate it, and display any errors found"

9
src/index.mjs Executable file
View File

@ -0,0 +1,9 @@
#!/usr/bin/env node
import cli from './Bootstrap/cli.mjs';
(async () => {
"use strict";
await cli();
})();