{"version":3,"file":"regular.mjs","sources":["../../../../../../../packages/components/overlays/wind/grid/regular.ts"],"sourcesContent":["// https://en.wikipedia.org/wiki/Regular_grid\n\nimport { RAD } from './consts'\nimport { decimalize, floorMod } from './math'\n// import REGULAR_FRAG from './regular.frag'\n\n/**\n * Creates a regular geographic grid. Each axis defines the \"start\" value in degrees, \"delta\" degrees between\n * ticks, and the \"size\" (number of ticks from the origin, inclusive). Positive deltas move eastward/northward. This\n * example creates a full 1° x 1° grid covering the earth starting at the south pole:\n *\n *     λaxis: {start: 0, delta: 1, size: 360}    where λ in the range [0, 359]\n *     φaxis: {start: -90, delta: 1, size: 181}  where φ in the range [-90, 90]\n *\n * A grid maps from [λ, φ] coordinates to grid point indices.\n *\n * @param λaxis longitude axis\n * @param φaxis latitude axis\n * @returns {*}\n */\nexport function regularGrid(λaxis, φaxis) {\n  const nx = Math.floor(λaxis.size) // number of lon points\n  const ny = Math.floor(φaxis.size) // number of lat points\n  const np = nx * ny // total number of points\n  const Δλ = decimalize(λaxis.delta) // distance between lon points\n  const Δφ = decimalize(φaxis.delta) // distance between lat points\n  const λ0 = decimalize(λaxis.start) // lon origin\n  const φ0 = decimalize(φaxis.start) // lat origin, expected to be on range [-90, 90]\n  const λ1 = λ0 + Δλ * (nx - 1) // lon upper bound\n  const φ1 = φ0 + Δφ * (ny - 1) // lat upper bound\n\n  const λlow = (λ0 - Δλ / 2) * RAD\n  const λhigh = (λ1 + Δλ / 2) * RAD\n  const λsize = λhigh - λlow\n  const φlow = (φ0 - Δφ / 2) * RAD\n  const φhigh = (φ1 + Δφ / 2) * RAD\n  const φsize = φhigh - φlow\n  const low = [λlow, φlow]\n  const size = [λsize, φsize]\n\n  const isCylinder = Math.floor(nx * Δλ) >= 360 // true if the grid forms a cylinder\n\n  //function iterator() {\n  //    const i = 0;\n  //    return {\n  //        next: function() {\n  //            if (i >= np) {\n  //                return {done: true};\n  //            }\n  //            const x = i % nx;\n  //            const y = Math.floor(i / nx);\n  //            const λ = λ0 + x * Δλ;\n  //            const φ = φ0 + y * Δφ;\n  //            return {value: [λ, φ, i++], done: false};\n  //        },\n  //    };\n  //}\n\n  /** @returns {{width: number, height: number}} dimensions of this grid */\n  function dimensions() {\n    return {\n      width: nx,\n      height: ny\n    }\n  }\n\n  /** @returns {boolean} true if the grid fully wraps around longitudinal axis */\n  function isCylindrical() {\n    return isCylinder\n  }\n\n  /**\n   * @param {Function} cb the callback ƒ(λ, φ, i), where a truthy return value terminates the iteration.\n   * @param {number?} start the starting grid index.\n   * @returns {number} the grid index of the next iteration, or NaN if iteration is finished.\n   */\n  function forEach(cb, start) {\n    for (let i = start || 0; i < np; i++) {\n      const x = i % nx\n      const y = Math.floor(i / nx)\n      const λ = λ0 + x * Δλ\n      const φ = φ0 + y * Δφ\n      if (cb(λ, φ, i)) {\n        return i + 1 // Terminate iteration and return next grid index.\n      }\n    }\n    return NaN // Iteration is finished.\n  }\n\n  /**\n   * @param {number} λ latitude (degrees)\n   * @param {number} φ longitude (degrees)\n   * @returns {number} index of closest grid point or NaN if further than Δλ/2 or Δφ/2 from the grid boundary.\n   */\n  function closest(λ, φ) {\n    if (λ === λ && φ === φ) {\n      const x = floorMod(λ - λ0, 360) / Δλ\n      const y = (φ - φ0) / Δφ\n      const rx = Math.round(x)\n      const ry = Math.round(y)\n\n      if (0 <= ry && ry < ny && 0 <= rx && (rx < nx || (rx === nx && isCylinder))) {\n        const i = ry * nx + rx\n        return rx === nx ? i - nx : i\n      }\n    }\n    return NaN\n  }\n\n  /**\n   * Identifies the four points surrounding the specified coordinates. The result is a six-element array:\n   *\n   *     0-3: the indices of the four points, in increasing order.\n   *     4,5: the fraction that λ,φ is away from the first point, normalized to the range [0, 1].\n   *\n   * Example:\n   * <pre>\n   *          1      2           After converting λ and φ to positions on the x and y grid axes, we find the\n   *         fx  x   cx          four points that enclose point [x, y]. These points are at the four\n   *          | =1.4 |           corners specified by the floor and ceiling of x and y. For example, given\n   *       --i00-|--i10-- fy 8   x = 1.4 and y = 8.3, the four surrounding grid points are [1, 8], [2, 8],\n   *     y ___|_ .   |           [1, 9] and [2, 9]. These points have index i00, i10, i01, i11, respectively,\n   *   =8.3   |      |           and result of this function is an array [i00, i10, i01, i11, 0.4, 0.3].\n   *       --i01----i11-- cy 9\n   *          |      |\n   * </pre>\n   *\n   * @param {number} λ latitude (degrees)\n   * @param {number} φ longitude (degrees)\n   * @returns {number[]} the indices of the four grid points surrounding the coordinate pair and the (x,y) fraction,\n   *          or [NaN, NaN, NaN, NaN, NaN, NaN] if all points are not found.\n   */\n  function closest4(λ, φ) {\n    if (λ === λ && φ === φ) {\n      const x = floorMod(λ - λ0, 360) / Δλ\n      const y = (φ - φ0) / Δφ\n      const fx = Math.floor(x)\n      const fy = Math.floor(y)\n      const cx = fx + 1\n      const cy = fy + 1\n      const Δx = x - fx\n      const Δy = y - fy\n\n      if (0 <= fy && cy < ny && 0 <= fx && (cx < nx || (cx === nx && isCylinder))) {\n        const i00 = fy * nx + fx\n        let i10 = i00 + 1\n        const i01 = i00 + nx\n        let i11 = i01 + 1\n        if (cx === nx) {\n          i10 -= nx\n          i11 -= nx\n        }\n        return [i00, i10, i01, i11, Δx, Δy]\n      }\n    }\n    return [NaN, NaN, NaN, NaN, NaN, NaN]\n  }\n\n  // function webgl() {\n  //   return {\n  //     shaderSource: REGULAR_FRAG,\n  //     uniforms: {\n  //       u_Low: low,\n  //       u_Size: size,\n  //     },\n  //   }\n  // }\n\n  return {\n    dimensions: dimensions,\n    isCylindrical: isCylindrical,\n    forEach: forEach,\n    closest: closest,\n    closest4: closest4\n    // webgl: webgl,\n  }\n}\n"],"names":[],"mappings":"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"}