Source: compute/makeGeography/makeTractNoise.js

  1. /** @module */
  2. // import SimplexNoise from 'https://cdn.skypack.dev/simplex-noise@3.0.1'
  3. import { SimplexNoise } from 'simplex-noise'
  4. // https://runkit-packages.com/14.x.x/1644541101130/simplex-noise/#simplex-noisejs
  5. // https://npm.runkit.com/simplex-noise
  6. // https://www.npmjs.com/package/simplex-noise
  7. /**
  8. * Generate a noisy 2D map with two noise sources per pixel.
  9. * @param {number} nx - Number of x pixels
  10. * @param {number} ny - Number of y pixels
  11. */
  12. export default function makeTractNoise(nx, ny) {
  13. // Simplex Noise Parameters
  14. const noiseWidth = 0.5
  15. const noiseHeight = 0.5
  16. // District Noise Parameters - amplitude of noise
  17. const xAmp = 100
  18. const yAmp = 100
  19. /** Generate simplex noise. */
  20. const sn = simplexNoise(nx, ny, noiseWidth, noiseHeight, xAmp, yAmp)
  21. return sn
  22. }
  23. /**
  24. * Generate a noisy 2D map with two noise sources per pixel.
  25. * @param {number} nx - Number of x pixels
  26. * @param {number} ny - Number of y pixels
  27. * @param {number} noiseWidth - A characteristic size of blobs, in pixels
  28. * @param {number} noiseHeight - A characteristic size of blobs, in pixels
  29. * @returns {number[][][]} - Noise in pixel displacement, indexed by row, col, dimension
  30. */
  31. export function simplexNoise(nx, ny, noiseWidth, noiseHeight, xAmp, yAmp) {
  32. // @ts-ignore
  33. const simplexX = new SimplexNoise('s')
  34. // @ts-ignore
  35. const simplexY = new SimplexNoise('seed')
  36. const map = zeros(nx, ny)
  37. let sumX = 0
  38. let sumY = 0
  39. range(nx).forEach((ix) => {
  40. range(ny).forEach((iy) => {
  41. // fractional coordinate divided by period of waves
  42. const x = (ix / nx) * (1 / noiseWidth)
  43. const y = (iy / ny) * (1 / noiseHeight)
  44. const noiseX = simplexX.noise2D(x, y)
  45. const noiseY = simplexY.noise2D(x, y)
  46. map[ix][iy][0] = (noiseX - 0.5)
  47. map[ix][iy][1] = (noiseY - 0.5)
  48. sumX += noiseX
  49. sumY += noiseY
  50. })
  51. })
  52. // normalize
  53. const meanX = sumX / (nx * ny) - 0.5
  54. const meanY = sumY / (nx * ny) - 0.5
  55. map.forEach((a) => { // array
  56. a.forEach((p) => { // pair
  57. // eslint-disable-next-line no-param-reassign
  58. p[0] = (p[0] - meanX) * xAmp
  59. // eslint-disable-next-line no-param-reassign
  60. p[1] = (p[1] - meanY) * yAmp
  61. })
  62. })
  63. return map
  64. }
  65. function zeros(nx, ny) {
  66. const empty = Array(nx).fill().map(() => Array(ny).fill().map(() => Array(2).fill(0)))
  67. return empty
  68. }
  69. function range(n) {
  70. return [...Array(n).keys()]
  71. }