mirror of
https://github.com/sbrl/terrain50-cli.git
synced 2024-11-29 08:02:59 +00:00
Migrate from main PhD-Code repo.
Link: https://git.starbeamrainbowlabs.com/sbrl/PhD-Code
This commit is contained in:
parent
10c73cba3f
commit
a9a66b82e1
26 changed files with 1404 additions and 4 deletions
479
package-lock.json
generated
479
package-lock.json
generated
|
@ -4,16 +4,242 @@
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"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": {
|
"applause-cli": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/applause-cli/-/applause-cli-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/applause-cli/-/applause-cli-1.2.0.tgz",
|
||||||
"integrity": "sha512-JPCHkBzaghitUPYWK4Jm6YNUklJIBjhlvzU3WLswjvjolMyQN8WVWR8qrGmMbs1skej2p/ZINisZVVvmuEFkog=="
|
"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": {
|
"mgrs": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/mgrs/-/mgrs-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/mgrs/-/mgrs-1.0.0.tgz",
|
||||||
"integrity": "sha1-+5FYjnjJACVnI5XLQLJffNatGCk="
|
"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": {
|
"nnng": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/nnng/-/nnng-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/nnng/-/nnng-1.0.0.tgz",
|
||||||
|
@ -22,6 +248,36 @@
|
||||||
"proj4": "^2.3.10"
|
"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": {
|
"proj4": {
|
||||||
"version": "2.6.0",
|
"version": "2.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/proj4/-/proj4-2.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/proj4/-/proj4-2.6.0.tgz",
|
||||||
|
@ -31,14 +287,231 @@
|
||||||
"wkt-parser": "^1.2.0"
|
"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",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/terrain50/-/terrain50-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/regex-regex/-/regex-regex-1.0.0.tgz",
|
||||||
"integrity": "sha512-qEw69Sk9F6AiTmAa+mpElSRN5wScscxRCjN/6sie42QXlUOdqNLxSbWOnKSLGiBGg1BH6/Uhbwf3YjP5YFvpwQ==",
|
"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": {
|
"requires": {
|
||||||
"nnng": "^1.0.0"
|
"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": {
|
"wkt-parser": {
|
||||||
"version": "1.2.4",
|
"version": "1.2.4",
|
||||||
"resolved": "https://registry.npmjs.org/wkt-parser/-/wkt-parser-1.2.4.tgz",
|
"resolved": "https://registry.npmjs.org/wkt-parser/-/wkt-parser-1.2.4.tgz",
|
||||||
|
|
|
@ -31,7 +31,14 @@
|
||||||
],
|
],
|
||||||
"homepage": "https://github.com/sbrl/terrain50-cli#readme",
|
"homepage": "https://github.com/sbrl/terrain50-cli#readme",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@iarna/toml": "^2.2.3",
|
||||||
"applause-cli": "^1.2.0",
|
"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
109
src/Bootstrap/cli.mjs
Normal 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
|
||||||
|
|
||||||
|
|
||||||
|
}
|
21
src/Bootstrap/settings.mjs
Normal file
21
src/Bootstrap/settings.mjs
Normal 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
82
src/Helpers/Ansi.mjs
Normal 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
82
src/Helpers/Log.mjs
Normal 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();
|
59
src/Subcommands/geojson/index.mjs
Normal file
59
src/Subcommands/geojson/index.mjs
Normal 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));
|
||||||
|
}
|
7
src/Subcommands/geojson/meta.toml
Normal file
7
src/Subcommands/geojson/meta.toml
Normal 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"
|
110
src/Subcommands/image/Terrain50Renderer.mjs
Normal file
110
src/Subcommands/image/Terrain50Renderer.mjs
Normal 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;
|
36
src/Subcommands/image/index.mjs
Normal file
36
src/Subcommands/image/index.mjs
Normal 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}`);
|
||||||
|
}
|
13
src/Subcommands/image/meta.toml
Normal file
13
src/Subcommands/image/meta.toml
Normal 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"
|
74
src/Subcommands/merge/index.mjs
Normal file
74
src/Subcommands/merge/index.mjs
Normal 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");
|
||||||
|
}
|
13
src/Subcommands/merge/meta.toml
Normal file
13
src/Subcommands/merge/meta.toml
Normal 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"
|
36
src/Subcommands/replace/index.mjs
Normal file
36
src/Subcommands/replace/index.mjs
Normal 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!`);
|
||||||
|
}
|
25
src/Subcommands/replace/meta.toml
Normal file
25
src/Subcommands/replace/meta.toml
Normal 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"
|
28
src/Subcommands/round/index.mjs
Normal file
28
src/Subcommands/round/index.mjs
Normal 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!`);
|
||||||
|
}
|
13
src/Subcommands/round/meta.toml
Normal file
13
src/Subcommands/round/meta.toml
Normal 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"
|
34
src/Subcommands/scale/index.mjs
Normal file
34
src/Subcommands/scale/index.mjs
Normal 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!`);
|
||||||
|
}
|
19
src/Subcommands/scale/meta.toml
Normal file
19
src/Subcommands/scale/meta.toml
Normal 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"
|
34
src/Subcommands/shift/index.mjs
Normal file
34
src/Subcommands/shift/index.mjs
Normal 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!`);
|
||||||
|
}
|
19
src/Subcommands/shift/meta.toml
Normal file
19
src/Subcommands/shift/meta.toml
Normal 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"
|
39
src/Subcommands/trim/index.mjs
Normal file
39
src/Subcommands/trim/index.mjs
Normal 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!`);
|
||||||
|
}
|
23
src/Subcommands/trim/meta.toml
Normal file
23
src/Subcommands/trim/meta.toml
Normal 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
|
34
src/Subcommands/validator/index.mjs
Normal file
34
src/Subcommands/validator/index.mjs
Normal 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}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
1
src/Subcommands/validator/meta.toml
Normal file
1
src/Subcommands/validator/meta.toml
Normal file
|
@ -0,0 +1 @@
|
||||||
|
description = "Read the Terrain50 file on stdin, validate it, and display any errors found"
|
9
src/index.mjs
Executable file
9
src/index.mjs
Executable file
|
@ -0,0 +1,9 @@
|
||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
import cli from './Bootstrap/cli.mjs';
|
||||||
|
|
||||||
|
(async () => {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
await cli();
|
||||||
|
})();
|
Loading…
Reference in a new issue