{"version":3,"file":"index.d.ts","sources":["../src/viewport/math-utils.ts","../src/viewport/viewport.ts","../src/index.ts"],"sourcesContent":["import { vec4 } from 'gl-matrix';\n\nexport interface FrustumPlane {\n  distance: number;\n  normal: number[];\n}\n\nfunction lengthSquared(arr: number[]) {\n  let length = 0;\n  // eslint-disable-next-line @typescript-eslint/prefer-for-of\n  for (let i = 0; i < arr.length; ++i) {\n    length += arr[i] * arr[i];\n  }\n  return length;\n}\n\n// eslint-disable-next-line max-params\nfunction getFrustumPlane(a: number, b: number, c: number, d: number): FrustumPlane {\n  const scratchVector = [a, b, c];\n  const L = Math.sqrt(lengthSquared(scratchVector));\n  return {\n    distance: d / L,\n    normal: [-a / L, -b / L, -c / L],\n  };\n}\n\n// Helper, avoids low-precision 32 bit matrices from gl-matrix mat4.create()\nexport function createMat4(): number[] {\n  return [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1];\n}\n\nexport function mod(value: number, divisor: number): number {\n  const modulus = value % divisor;\n  return modulus < 0 ? divisor + modulus : modulus;\n}\n\nexport function getCameraPosition(viewMatrixInverse: number[] | Float32Array | Float64Array) {\n  // Read the translation from the inverse view matrix\n  return [viewMatrixInverse[12], viewMatrixInverse[13], viewMatrixInverse[14]];\n}\n\nexport interface FrustumPlanesInterface {\n  left: FrustumPlane;\n  right: FrustumPlane;\n  bottom: FrustumPlane;\n  top: FrustumPlane;\n  near: FrustumPlane;\n  far: FrustumPlane;\n}\n\n// https://www.gamedevs.org/uploads/fast-extraction-viewing-frustum-planes-from-world-view-projection-matrix.pdf\nexport function getFrustumPlanes(viewProjectionMatrix: number[] | Float32Array | Float64Array) {\n  const planes: FrustumPlanesInterface = {} as FrustumPlanesInterface;\n\n  planes.left = getFrustumPlane(\n    viewProjectionMatrix[3] + viewProjectionMatrix[0],\n    viewProjectionMatrix[7] + viewProjectionMatrix[4],\n    viewProjectionMatrix[11] + viewProjectionMatrix[8],\n    viewProjectionMatrix[15] + viewProjectionMatrix[12],\n  );\n  planes.right = getFrustumPlane(\n    viewProjectionMatrix[3] - viewProjectionMatrix[0],\n    viewProjectionMatrix[7] - viewProjectionMatrix[4],\n    viewProjectionMatrix[11] - viewProjectionMatrix[8],\n    viewProjectionMatrix[15] - viewProjectionMatrix[12],\n  );\n  planes.bottom = getFrustumPlane(\n    viewProjectionMatrix[3] + viewProjectionMatrix[1],\n    viewProjectionMatrix[7] + viewProjectionMatrix[5],\n    viewProjectionMatrix[11] + viewProjectionMatrix[9],\n    viewProjectionMatrix[15] + viewProjectionMatrix[13],\n  );\n  planes.top = getFrustumPlane(\n    viewProjectionMatrix[3] - viewProjectionMatrix[1],\n    viewProjectionMatrix[7] - viewProjectionMatrix[5],\n    viewProjectionMatrix[11] - viewProjectionMatrix[9],\n    viewProjectionMatrix[15] - viewProjectionMatrix[13],\n  );\n  planes.near = getFrustumPlane(\n    viewProjectionMatrix[3] + viewProjectionMatrix[2],\n    viewProjectionMatrix[7] + viewProjectionMatrix[6],\n    viewProjectionMatrix[11] + viewProjectionMatrix[10],\n    viewProjectionMatrix[15] + viewProjectionMatrix[14],\n  );\n  planes.far = getFrustumPlane(\n    viewProjectionMatrix[3] - viewProjectionMatrix[2],\n    viewProjectionMatrix[7] - viewProjectionMatrix[6],\n    viewProjectionMatrix[11] - viewProjectionMatrix[10],\n    viewProjectionMatrix[15] - viewProjectionMatrix[14],\n  );\n\n  return planes;\n}\n\nexport function transformVector(matrix: number[], vector: number[]) {\n  const result = vec4.transformMat4([], vector, matrix);\n  vec4.scale(result, result, 1 / result[3]);\n  return result;\n}\n","import { mat4, vec3, vec2 } from 'gl-matrix';\nimport { equals } from './common';\nimport type { FrustumPlanesInterface } from './math-utils';\nimport { createMat4, getCameraPosition, getFrustumPlanes } from './math-utils';\n\nimport {\n  getBounds,\n  addMetersToLngLat,\n  getDistanceScales,\n  getMeterZoom,\n  getProjectionParameters,\n  getViewMatrix,\n  lngLatToWorld,\n  pixelsToWorld,\n  worldToLngLat,\n  worldToPixels,\n} from './web-mercator-utils';\n\n\nexport enum PROJECTION_MODE {\n  WEB_MERCATOR = 1,\n  GLOBE = 2,\n\n  // This is automatically assigned by the project module\n  WEB_MERCATOR_AUTO_OFFSET = 4,\n\n  IDENTITY = 0,\n}\n\nexport enum COORDINATE_SYSTEM {\n  // `LNGLAT` if rendering into a geospatial viewport, `CARTESIAN` otherwise\n  DEFAULT = -1,\n  // Positions are interpreted as [lng, lat, elevation]\n  // lng lat are degrees, elevation is meters. distances as meters.\n  LNGLAT = 1,\n\n  // Positions are interpreted as meter offsets, distances as meters\n  METER_OFFSETS = 2,\n\n  // Positions are interpreted as lng lat offsets: [deltaLng, deltaLat, elevation]\n  // deltaLng, deltaLat are delta degrees, elevation is meters.\n  // distances as meters.\n  LNGLAT_OFFSETS = 3,\n\n  // Non-geospatial\n  CARTESIAN = 0,\n}\n\nconst DEGREES_TO_RADIANS = Math.PI / 180;\n\nconst IDENTITY = createMat4() as number[];\n\nconst ZERO_VECTOR = [0, 0, 0];\n\nconst DEFAULT_ZOOM = 0;\n\nconst DEFAULT_DISTANCE_SCALES = {\n  unitsPerMeter: [1, 1, 1],\n  metersPerUnit: [1, 1, 1],\n};\n\nexport interface IDistanceScales {\n  unitsPerMeter: number[];\n  metersPerUnit: number[];\n  unitsPerMeter2?: number[];\n  unitsPerDegree: number[];\n  degreesPerUnit: number[];\n  unitsPerDegree2?: number[];\n}\n\nexport interface IViewportOpts {\n  width: number;\n  height: number;\n\n  viewMatrix: number[];\n  longitude: number;\n  latitude: number;\n  zoom: number;\n\n  distanceScales: IDistanceScales;\n\n  // projection matrix parameters\n  orthographic: boolean;\n  fovyRadians: number;\n  aspect: number;\n  // TODO WebMercatorViewport is already carefully set up to \"focus\" on ground, so can't use focal distance\n  focalDistance: number;\n  near: number;\n  far: number;\n  fovy?: number;\n  position?: number[];\n  projectionMatrix?: number[];\n  modelMatrix?: number[];\n}\n\nexport interface IViewport extends IViewportOpts {\n  id: string | number;\n  x: number;\n  y: number;\n  pitch: number;\n  bearing: number;\n  nearZMultiplier: number;\n  farZMultiplier: number;\n  altitude: number;\n  worldOffset: number;\n  projectOffsetZoom: number;\n  repeat: boolean;\n}\n\nexport default class WebMercatorViewport {\n  public id: string | number;\n  public latitude: number;\n  public altitude: number;\n  public longitude: number;\n  public zoom: number;\n  public pitch: number;\n  public bearing: number;\n  public isGeospatial: boolean;\n  public scale: number;\n  public width: number;\n  public height: number;\n  public center: number[];\n\n  public modelMatrix: number[];\n  public viewMatrix: number[];\n  public viewMatrixInverse: number[];\n  public viewMatrixUncentered: number[];\n  public projectionMatrix: number[] | Float32Array;\n  public pixelProjectionMatrix: number[];\n  public pixelUnprojectionMatrix: number[];\n  public viewportMatrix: number[];\n  public viewProjectionMatrix: number[];\n\n  public cameraPosition: number[];\n  public focalDistance: number;\n  public distanceScales: IDistanceScales;\n  public position: number[];\n  public projectOffsetZoom: number;\n\n  private readonly _subViewports: WebMercatorViewport[] | undefined;\n  private meterOffset: number[];\n  private x: number;\n  private y: number;\n  private _frustumPlanes: FrustumPlanesInterface;\n  // @ts-ignore ignore type error\n  private orthographic: boolean;\n\n  /**\n   * Manages coordinate system transformations for deck.gl.\n   * Note: The WebMercatorViewport is immutable in the sense that it only has accessors.\n   * A new viewport instance should be created if any parameters have changed.\n   */\n  constructor(opts: Partial<IViewport>) {\n    const {\n      id,\n      // Window width/height in pixels (for pixel projection)\n      x = 0,\n      y = 0,\n      latitude = 0,\n      longitude = 0,\n      zoom = 11,\n      pitch = 0,\n      bearing = 0,\n      nearZMultiplier = 0.1,\n      farZMultiplier = 1.01,\n      orthographic = false,\n\n      repeat = false,\n      worldOffset = 0,\n      projectOffsetZoom = 12,\n    } = opts;\n\n    let { width, height, altitude = 1.5 } = opts;\n    const scale = Math.pow(2, zoom);\n\n    // Silently allow apps to send in 0,0 to facilitate isomorphic render etc\n    width = width || 1;\n    height = height || 1;\n\n    // Altitude - prevent division by 0\n    // TODO - just throw an Error instead?\n    altitude = Math.max(0.75, altitude);\n\n    const { fov, aspect, focalDistance, near, far } = getProjectionParameters({\n      width,\n      height,\n      pitch,\n      altitude,\n      nearZMultiplier,\n      farZMultiplier,\n    });\n\n    // The uncentered matrix allows us two move the center addition to the\n    // shader (cheap) which gives a coordinate system that has its center in\n    // the layer's center position. This makes rotations and other modelMatrx\n    // transforms much more useful.\n    let viewMatrixUncentered = getViewMatrix({\n      height,\n      pitch,\n      bearing,\n      scale,\n      altitude,\n      // @ts-ignore center typedef is incorrect\n      center: null,\n    });\n\n    if (worldOffset) {\n      const m = createMat4();\n      const viewOffset = mat4.translate(m, m, [512 * worldOffset, 0, 0]);\n      viewMatrixUncentered = mat4.multiply(viewOffset, viewMatrixUncentered, viewOffset) as number[];\n    }\n\n    this.id = id || 'viewport';\n\n    const viewportOpts = {\n      ...opts,\n      // x, y,\n      width,\n      height,\n\n      // view matrix\n      viewMatrix: viewMatrixUncentered,\n      longitude,\n      latitude,\n      zoom,\n\n      // projection matrix parameters\n      orthographic,\n      fovyRadians: fov,\n      aspect,\n      // TODO WebMercatorViewport is already carefully set up to \"focus\" on ground, so can't use focal distance\n      focalDistance: orthographic ? focalDistance : 1,\n      near,\n      far,\n    };\n\n    // Save parameters\n    this.latitude = latitude;\n    this.longitude = longitude;\n    this.zoom = zoom;\n    this.pitch = pitch;\n    this.bearing = bearing;\n    this.altitude = altitude;\n    this.projectOffsetZoom = projectOffsetZoom;\n\n    this.orthographic = orthographic;\n\n    this._subViewports = repeat ? [] : undefined;\n\n    this.x = x;\n    this.y = y;\n    // Silently allow apps to send in w,h = 0,0\n    this.width = width || 1;\n    this.height = height || 1;\n\n    // @ts-ignore\n    this._initViewMatrix(viewportOpts);\n    // @ts-ignore\n    this._initProjectionMatrix(viewportOpts);\n    this._initPixelMatrices();\n\n    // Bind methods for easy access\n    this.equals = this.equals.bind(this);\n    this.project = this.project.bind(this);\n    this.unproject = this.unproject.bind(this);\n    this.projectPosition = this.projectPosition.bind(this);\n    this.unprojectPosition = this.unprojectPosition.bind(this);\n    this.projectFlat = this.projectFlat.bind(this);\n    this.unprojectFlat = this.unprojectFlat.bind(this);\n  }\n\n  get metersPerPixel() {\n    return this.distanceScales.metersPerUnit[2] / this.scale;\n  }\n\n  get projectionMode() {\n    if (this.isGeospatial) {\n      return this.zoom < this.projectOffsetZoom\n        ? PROJECTION_MODE.WEB_MERCATOR\n        : PROJECTION_MODE.WEB_MERCATOR_AUTO_OFFSET;\n    }\n    return PROJECTION_MODE.IDENTITY;\n  }\n\n  /**\n   * Two viewports are equal if width and height are identical, and if\n      their view and projection matrices are (approximately) equal.\n   * @param viewport\n   */\n  equals(viewport: any): boolean {\n    if (!(viewport instanceof WebMercatorViewport)) {\n      return false;\n    }\n    if (this === viewport) {\n      return true;\n    }\n\n    return (\n      viewport.width === this.width &&\n      viewport.height === this.height &&\n      viewport.scale === this.scale &&\n      equals(viewport.projectionMatrix, this.projectionMatrix) &&\n      equals(viewport.viewMatrix, this.viewMatrix)\n    );\n  }\n\n  /**\n   * Projects xyz (possibly latitude and longitude) to pixel coordinates in window\n   * using viewport projection parameters\n   * - [longitude, latitude] to [x, y]\n   * - [longitude, latitude, Z] => [x, y, z]\n   * Note: By default, returns top-left coordinates for canvas/SVG type render\n   *\n   * @param {Array} lngLatZ - [lng, lat] or [lng, lat, Z]\n   * @param {Object} opts.topLeft=true - Whether projected coords are top left\n   * @return {Array} - [x, y] or [x, y, z] in top left coords\n   * @param xyz\n   */\n  project(\n    xyz: number[],\n    {\n      topLeft = true,\n    }: {\n      topLeft?: boolean;\n    } = {},\n  ): number[] {\n    const worldPosition = this.projectPosition(xyz);\n    const coord = worldToPixels(worldPosition, this.pixelProjectionMatrix);\n\n    const [x, y] = coord;\n    const y2 = topLeft ? y : this.height - y;\n    return xyz.length === 2 ? [x, y2] : [x, y2, coord[2]];\n  }\n\n  /**\n   * Unproject pixel coordinates on screen onto world coordinates,\n   * (possibly [lon, lat]) on map.\n   * - [x, y] => [lng, lat]\n   * - [x, y, z] => [lng, lat, Z]\n   * @param {Array} xyz -\n   * @param {Object} opts - options\n   * @param {Object} opts.topLeft=true - Whether origin is top left\n   * @return {Array|null} - [lng, lat, Z] or [X, Y, Z]\n   */\n  unproject(\n    xyz: number[],\n    {\n      topLeft = true,\n      targetZ,\n    }: {\n      topLeft?: boolean;\n      targetZ?: number;\n    } = {},\n  ): (number | undefined)[] {\n    const [x, y, z] = xyz;\n\n    const y2 = topLeft ? y : this.height - y;\n    const targetZWorld = targetZ && targetZ * this.distanceScales.unitsPerMeter[2];\n    const coord = pixelsToWorld([x, y2, z], this.pixelUnprojectionMatrix, targetZWorld);\n    const [X, Y, Z] = this.unprojectPosition(coord as number[]) as number[];\n\n    if (Number.isFinite(z)) {\n      return [X, Y, Z];\n    }\n    return Number.isFinite(targetZ) ? [X, Y, targetZ] : [X, Y];\n  }\n\n  // NON_LINEAR PROJECTION HOOKS\n  // Used for web meractor projection\n  projectPosition(xyz: number[]): number[] {\n    const [X, Y] = this.projectFlat(xyz);\n    const Z = (xyz[2] || 0) * this.distanceScales.unitsPerMeter[2];\n    return [X, Y, Z];\n  }\n\n  unprojectPosition(xyz: number[]): number[] {\n    const [X, Y] = this.unprojectFlat(xyz);\n    const Z = (xyz[2] || 0) * this.distanceScales.metersPerUnit[2];\n    return [X, Y, Z];\n  }\n\n  /**\n   * Project [lng,lat] on sphere onto [x,y] on 512*512 Mercator Zoom 0 tile.\n   * Performs the nonlinear part of the web mercator projection.\n   * Remaining projection is done with 4x4 matrices which also handles\n   * perspective.\n   *   Specifies a point on the sphere to project onto the map.\n   * @return {Array} [x,y] coordinates.\n   * @param xyz\n   */\n  projectFlat(xyz: number[]): number[] {\n    if (this.isGeospatial) {\n      return lngLatToWorld(xyz);\n    }\n    return xyz;\n  }\n\n  /**\n   * Unproject world point [x,y] on map onto {lat, lon} on sphere\n   *  representing point on projected map plane\n   * @return {GeoCoordinates} - object with {lat,lon} of point on sphere.\n   *   Has toArray method if you need a GeoJSON Array.\n   *   Per cartographic tradition, lat and lon are specified as degrees.\n   * @param xyz\n   */\n  unprojectFlat(xyz: number[]): number[] {\n    if (this.isGeospatial) {\n      return worldToLngLat(xyz);\n    }\n    return xyz;\n  }\n\n  getDistanceScales(coordinateOrigin: null | number[]) {\n    if (coordinateOrigin && Array.isArray(coordinateOrigin)) {\n      return getDistanceScales({\n        longitude: coordinateOrigin[0] as number,\n        latitude: coordinateOrigin[1] as number,\n        highPrecision: true,\n      });\n    }\n    return this.distanceScales;\n  }\n\n  /**\n   * Judge whether the position is in the range\n   * @param x\n   * @param y\n   * @param width\n   * @param height\n   */\n  containsPixel({ x, y, width = 1, height = 1 }: { x: number; y: number; width?: number; height?: number }) {\n    return x < this.x + this.width && this.x < x + width && y < this.y + this.height && this.y < y + height;\n  }\n\n  /**\n   * Extract frustum planes in common space\n   */\n  getFrustumPlanes(): FrustumPlanesInterface {\n    if (this._frustumPlanes?.near) {\n      return this._frustumPlanes;\n    }\n\n    this._frustumPlanes = getFrustumPlanes(this.viewProjectionMatrix);\n\n    return this._frustumPlanes;\n  }\n\n  // EXPERIMENTAL METHODS\n  getCameraPosition() {\n    return this.cameraPosition;\n  }\n\n  // INTERNAL METHODS\n  _createProjectionMatrix({\n    orthographic,\n    fovyRadians,\n    aspect,\n    focalDistance,\n    near,\n    far,\n  }: {\n    fovyRadians: number;\n    aspect: number;\n    focalDistance: number;\n    orthographic?: boolean;\n    near?: number;\n    far?: number;\n  }) {\n    const m = createMat4();\n    if (orthographic) {\n      if (fovyRadians > Math.PI * 2) {\n        throw Error('radians');\n      }\n      const halfY = fovyRadians / 2;\n      const top = focalDistance * Math.tan(halfY); // focus_plane is the distance from the camera\n      const right = top * aspect;\n\n      mat4.ortho(m, -right, right, -top, top, near!, far!);\n    } else {\n      mat4.perspective(m, fovyRadians, aspect, near!, far!);\n    }\n    return m;\n  }\n\n  _initViewMatrix(opts: IViewportOpts) {\n    const {\n      // view matrix\n      viewMatrix = IDENTITY,\n\n      longitude, // Anchor: lng lat zoom makes viewport work w/ geospatial coordinate systems\n      latitude,\n      zoom,\n\n      position = null, // Anchor position offset (in meters for geospatial viewports)\n      modelMatrix = null, // A model matrix to be applied to position, to match the layer props API\n      focalDistance = 1, // Only needed for orthographic views\n\n      distanceScales,\n    } = opts;\n\n    // Check if we have a geospatial anchor\n    this.isGeospatial = Number.isFinite(latitude) && Number.isFinite(longitude);\n\n    this.zoom = zoom;\n    if (!Number.isFinite(this.zoom)) {\n      this.zoom = this.isGeospatial\n        ? getMeterZoom({latitude}) + Math.log2(focalDistance)\n        : DEFAULT_ZOOM;\n    }\n    this.scale = Math.pow(2, this.zoom);\n\n    // Calculate distance scales if lng/lat/zoom are provided\n    this.distanceScales = this.isGeospatial\n      ? getDistanceScales({latitude, longitude})\n      : distanceScales || DEFAULT_DISTANCE_SCALES;\n\n    this.focalDistance = focalDistance;\n\n    this.position = ZERO_VECTOR;\n    this.meterOffset = ZERO_VECTOR;\n    if (position && modelMatrix) {\n      // Apply model matrix if supplied\n      this.position = position;\n      this.modelMatrix = modelMatrix;\n      this.meterOffset = modelMatrix ? (vec3.transformMat4([-0, -0, -0], position, modelMatrix) as number[]) : position;\n    }\n\n    if (this.isGeospatial) {\n      // Determine camera center\n      this.longitude = longitude;\n      this.latitude = latitude;\n      this.center = this._getCenterInWorld({ longitude, latitude });\n    } else {\n      this.center = position ? this.projectPosition(position) : [0, 0, 0];\n    }\n    this.viewMatrixUncentered = viewMatrix;\n    // Make a centered version of the matrix for projection modes without an offset\n    this.viewMatrix = createMat4();\n    mat4.multiply(this.viewMatrix, this.viewMatrixUncentered, this.viewMatrix);\n    mat4.translate(\n      this.viewMatrix,\n      this.viewMatrix,\n      (this.center || ZERO_VECTOR).map((i) => -i),\n    );\n  }\n\n  _initProjectionMatrix(opts: IViewportOpts) {\n    const {\n      // Projection matrix\n      projectionMatrix = null,\n\n      // Projection matrix parameters, used if projectionMatrix not supplied\n      orthographic = false,\n      fovyRadians,\n      fovy = 75,\n      near = 0.1, // Distance of near clipping plane\n      far = 1000, // Distance of far clipping plane\n      focalDistance = 1,\n    } = opts;\n\n    this.projectionMatrix =\n      projectionMatrix ||\n      this._createProjectionMatrix({\n        orthographic,\n        fovyRadians: fovyRadians || fovy * DEGREES_TO_RADIANS,\n        aspect: this.width / this.height,\n        focalDistance,\n        near,\n        far,\n      });\n  }\n\n  _initPixelMatrices() {\n    // Note: As usual, matrix operations should be applied in \"reverse\" order\n    // since vectors will be multiplied in from the right during transformation\n    const vpm = createMat4();\n    mat4.multiply(vpm, vpm, this.projectionMatrix);\n    mat4.multiply(vpm, vpm, this.viewMatrix);\n    this.viewProjectionMatrix = vpm;\n\n    // console.log('VPM', this.viewMatrix, this.projectionMatrix, this.viewProjectionMatrix);\n\n    // Calculate inverse view matrix\n    this.viewMatrixInverse = (mat4.invert([], this.viewMatrix) || this.viewMatrix) as number[];\n\n    // Decompose camera parameters\n    this.cameraPosition = getCameraPosition(this.viewMatrixInverse);\n\n    /*\n     * Builds matrices that converts preprojected lngLats to screen pixels\n     * and vice versa.\n     * Note: Currently returns bottom-left coordinates!\n     * Note: Starts with the GL projection matrix and adds steps to the\n     *       scale and translate that matrix onto the window.\n     * Note: WebGL controls clip space to screen projection with gl.viewport\n     *       and does not need this step.\n     */\n\n    // matrix for conversion from world location to screen (pixel) coordinates\n    const viewportMatrix = createMat4(); // matrix from NDC to viewport.\n    const pixelProjectionMatrix = createMat4(); // matrix from world space to viewport.\n    mat4.scale(viewportMatrix, viewportMatrix, [this.width / 2, -this.height / 2, 1]);\n    mat4.translate(viewportMatrix, viewportMatrix, [1, -1, 0]);\n    mat4.multiply(pixelProjectionMatrix, viewportMatrix, this.viewProjectionMatrix);\n    this.pixelProjectionMatrix = pixelProjectionMatrix;\n    this.viewportMatrix = viewportMatrix;\n\n    const m = createMat4();\n\n    this.pixelUnprojectionMatrix = mat4.invert(m, this.pixelProjectionMatrix) as number[];\n    if (!this.pixelUnprojectionMatrix) {\n      console.warn('Pixel project matrix not invertible');\n    }\n  }\n\n  _getCenterInWorld({ longitude, latitude }: { longitude: number; latitude: number }) {\n    const { meterOffset, distanceScales } = this;\n\n    // Make a centered version of the matrix for projection modes without an offset\n    const center = this.projectPosition([longitude, latitude, 0]);\n\n    if (meterOffset) {\n      const commonPosition = meterOffset;\n      // Convert to pixels in current zoom\n      for (let i = 0; i < commonPosition.length; ++i) {\n        commonPosition[i] *= distanceScales.unitsPerMeter[i];\n      }\n      for (let i = 0; i < center.length; ++i) {\n        center[i] += commonPosition[i];\n      }\n      // center.add(commonPosition);\n    }\n\n    return center;\n  }\n\n  get subViewports() {\n    if (this._subViewports && !this._subViewports.length) {\n      // Cache sub viewports so that we only calculate them once\n      const bounds = this.getBounds();\n\n      const minOffset = Math.floor((bounds[0] + 180) / 360);\n      const maxOffset = Math.ceil((bounds[2] - 180) / 360);\n\n      for (let x = minOffset; x <= maxOffset; x++) {\n        // @ts-ignore ignore type error\n        const offsetViewport = x ? new WebMercatorViewport({ ...this, worldOffset: x }) : this;\n        this._subViewports.push(offsetViewport);\n      }\n    }\n    return this._subViewports;\n  }\n\n  /**\n   * Add a meter delta to a base lnglat coordinate, returning a new lnglat array\n   *\n   * Note: Uses simple linear approximation around the viewport center\n   * Error increases with size of offset (roughly 1% per 100km)\n   *\n   * @return {[Number,Number]|[Number,Number,Number]) array of [lng,lat,z] deltas\n   * @param lngLatZ\n   * @param xyz\n   */\n  addMetersToLngLat(lngLatZ: number[], xyz: [number, number, number]) {\n    return addMetersToLngLat(lngLatZ, xyz);\n  }\n\n  /**\n   * Get the map center that place a given [lng, lat] coordinate at screen\n   * point [x, y]\n   *\n   * @param {Array} lngLat - [lng,lat] coordinates\n   *   Specifies a point on the sphere.\n   * @param {Array} pos - [x,y] coordinates\n   *   Specifies a point on the screen.\n   * @return {Array} [lng,lat] new map center.\n   */\n  getMapCenterByLngLatPosition({ lngLat, pos }: { lngLat: number[]; pos: number[] }): number[] {\n    const fromLocation = pixelsToWorld(pos, this.pixelUnprojectionMatrix);\n    const toLocation = this.projectFlat(lngLat);\n\n    const translate = vec2.add([], toLocation, vec2.negate([], fromLocation));\n    const newCenter = vec2.add([], this.center, translate);\n\n    return this.unprojectFlat(newCenter as number[]);\n  }\n\n  getBounds(options = {}) {\n    // @ts-ignore\n    const corners = getBounds(this, options.z || 0);\n\n    return [\n      Math.min(corners[0][0], corners[1][0], corners[2][0], corners[3][0]),\n      Math.min(corners[0][1], corners[1][1], corners[2][1], corners[3][1]),\n      Math.max(corners[0][0], corners[1][0], corners[2][0], corners[3][0]),\n      Math.max(corners[0][1], corners[1][1], corners[2][1], corners[3][1]),\n    ];\n  }\n}\n","import WebMercatorViewport, { PROJECTION_MODE, COORDINATE_SYSTEM } from './viewport/viewport';\nimport { getPlatformShaderDefines, getApplicationDefines, FRAGMENT_SHADER_PROLOGUE } from './utils';\nimport projectShader from './project.glsl';\nimport fp32shader from './fp32.glsl';\nimport { createMat4 } from './viewport/math-utils';\n\nexport type vec4 = [number, number, number, number] | Float32Array | number[];\nexport type mat4 =\n  | number[]\n  | [\n      number,\n      number,\n      number,\n      number,\n      number,\n      number,\n      number,\n      number,\n      number,\n      number,\n      number,\n      number,\n      number,\n      number,\n      number,\n      number,\n    ]\n  | Float32Array;\n\nexport interface IOptions {\n  viewport: WebMercatorViewport;\n  devicePixelRatio: number;\n  modelMatrix: number[] | null;\n  coordinateSystem: COORDINATE_SYSTEM;\n  coordinateOrigin?: number[];\n  autoWrapLongitude?: boolean;\n}\n\n// To quickly set a vector to zero\nconst ZERO_VECTOR: [number, number, number, number] | Float32Array = [0, 0, 0, 0];\nconst VECTOR_TO_POINT_MATRIX = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0];\nconst IDENTITY_MATRIX = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1];\nconst DEFAULT_COORDINATE_ORIGIN = [0, 0, 0];\nconst DEFAULT_PIXELS_PER_UNIT2: number[] | undefined = [0, 0, 0];\n\nconst INITIAL_MODULE_OPTIONS = {\n  // @ts-ignore\n  devicePixelRatio: window.devicePixelRatio || window.screen?.deviceXDPI / window.screen?.logicalXDPI || 1,\n};\n\nexport function isEqual(a: any, b: any): boolean {\n  if (a === b) {\n    return true;\n  }\n  if (Array.isArray(a)) {\n    // Special treatment for arrays: compare 1-level deep\n    // This is to support equality of matrix/coordinate props\n    const len = a.length;\n    if (!b || b.length !== len) {\n      return false;\n    }\n\n    for (let i = 0; i < len; i++) {\n      if (a[i] !== b[i]) {\n        return false;\n      }\n    }\n    return true;\n  }\n  return false;\n}\n\n/**\n * Speed up consecutive function calls by caching the result of calls with identical input\n * https://en.wikipedia.org/wiki/Memoization\n * @param {function} compute - the function to be memoized\n */\nexport function memoize(compute: (args: any) => any) {\n  let cachedArgs: {\n    [key: string]: any;\n  } = {};\n  let cachedResult: {\n    [key: string]: any;\n  };\n\n  return (args: any) => {\n    // eslint-disable-next-line no-restricted-syntax\n    for (const key in args) {\n      if (!isEqual(args[key], cachedArgs[key])) {\n        cachedResult = compute(args);\n        cachedArgs = args;\n        break;\n      }\n    }\n    return cachedResult;\n  };\n}\n\n/**\n * Multiplies two mat4s\n * @param {mat4} out the receiving matrix\n * @param {ReadonlyMat4} a the first operand\n * @param {ReadonlyMat4} b the second operand\n * @returns {mat4} out\n */\nexport function multiply(out: mat4, a: mat4 | number[], b: mat4 | number[]) {\n  const a00 = a[0];\n  const a01 = a[1];\n  const a02 = a[2];\n  const a03 = a[3];\n  const a10 = a[4];\n  const a11 = a[5];\n  const a12 = a[6];\n  const a13 = a[7];\n  const a20 = a[8];\n  const a21 = a[9];\n  const a22 = a[10];\n  const a23 = a[11];\n  const a30 = a[12];\n  const a31 = a[13];\n  const a32 = a[14];\n  const a33 = a[15]; // Cache only the current line of the second matrix\n\n  let b0 = b[0];\n  let b1 = b[1];\n  let b2 = b[2];\n  let b3 = b[3];\n  out[0] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;\n  out[1] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;\n  out[2] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;\n  out[3] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;\n  b0 = b[4];\n  b1 = b[5];\n  b2 = b[6];\n  b3 = b[7];\n  out[4] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;\n  out[5] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;\n  out[6] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;\n  out[7] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;\n  b0 = b[8];\n  b1 = b[9];\n  b2 = b[10];\n  b3 = b[11];\n  out[8] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;\n  out[9] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;\n  out[10] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;\n  out[11] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;\n  b0 = b[12];\n  b1 = b[13];\n  b2 = b[14];\n  b3 = b[15];\n  out[12] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;\n  out[13] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;\n  out[14] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;\n  out[15] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;\n  return out;\n}\n\n/**\n * Transforms the vec4 with a mat4.\n * @param {vec4} out the receiving vector\n * @param {ReadonlyVec4} a the vector to transform\n * @param {ReadonlyMat4} m matrix to transform with\n * @returns {vec4} out\n */\nexport function transformMat4(out: vec4, a: vec4, m: mat4 | number[]) {\n  const x = a[0];\n  const y = a[1];\n  const z = a[2];\n  const w = a[3];\n  out[0] = m[0] * x + m[4] * y + m[8] * z + m[12] * w;\n  out[1] = m[1] * x + m[5] * y + m[9] * z + m[13] * w;\n  out[2] = m[2] * x + m[6] * y + m[10] * z + m[14] * w;\n  out[3] = m[3] * x + m[7] * y + m[11] * z + m[15] * w;\n  return out;\n}\n\n/**\n * Inverts a mat4\n * @param out\n * @param a\n */\nexport function invert(out: vec4, a: vec4) {\n  const a00 = a[0];\n  const a01 = a[1];\n  const a02 = a[2];\n  const a03 = a[3];\n  const a10 = a[4];\n  const a11 = a[5];\n  const a12 = a[6];\n  const a13 = a[7];\n  const a20 = a[8];\n  const a21 = a[9];\n  const a22 = a[10];\n  const a23 = a[11];\n  const a30 = a[12];\n  const a31 = a[13];\n  const a32 = a[14];\n  const a33 = a[15];\n\n  const b00 = a00 * a11 - a01 * a10;\n  const b01 = a00 * a12 - a02 * a10;\n  const b02 = a00 * a13 - a03 * a10;\n  const b03 = a01 * a12 - a02 * a11;\n  const b04 = a01 * a13 - a03 * a11;\n  const b05 = a02 * a13 - a03 * a12;\n  const b06 = a20 * a31 - a21 * a30;\n  const b07 = a20 * a32 - a22 * a30;\n  const b08 = a20 * a33 - a23 * a30;\n  const b09 = a21 * a32 - a22 * a31;\n  const b10 = a21 * a33 - a23 * a31;\n  const b11 = a22 * a33 - a23 * a32;\n\n  // Calculate the determinant\n  let det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;\n\n  if (!det) {\n    return null;\n  }\n  det = 1.0 / det;\n\n  out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;\n  out[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det;\n  out[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det;\n  out[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det;\n  out[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det;\n  out[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det;\n  out[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det;\n  out[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det;\n  out[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det;\n  out[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det;\n  out[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det;\n  out[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det;\n  out[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det;\n  out[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det;\n  out[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det;\n  out[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det;\n\n  return out;\n}\n\nconst getMemoizedViewportUniforms = memoize(calculateViewportUniforms);\n\nexport function getOffsetOrigin(\n  viewport: WebMercatorViewport,\n  coordinateSystem: COORDINATE_SYSTEM,\n  coordinateOrigin = DEFAULT_COORDINATE_ORIGIN,\n) {\n  let shaderCoordinateOrigin = coordinateOrigin;\n  let geospatialOrigin;\n  let offsetMode = true;\n\n  if (coordinateSystem === COORDINATE_SYSTEM.LNGLAT_OFFSETS || coordinateSystem === COORDINATE_SYSTEM.METER_OFFSETS) {\n    geospatialOrigin = coordinateOrigin;\n  } else {\n    geospatialOrigin = viewport.isGeospatial\n      ? [Math.fround(viewport.longitude), Math.fround(viewport.latitude), 0]\n      : null;\n  }\n\n  switch (viewport.projectionMode) {\n    case PROJECTION_MODE.WEB_MERCATOR:\n      if (coordinateSystem === COORDINATE_SYSTEM.LNGLAT || coordinateSystem === COORDINATE_SYSTEM.CARTESIAN) {\n        offsetMode = false;\n      }\n      break;\n\n    case PROJECTION_MODE.WEB_MERCATOR_AUTO_OFFSET:\n      if (coordinateSystem === COORDINATE_SYSTEM.LNGLAT) {\n        // viewport center in world space\n        shaderCoordinateOrigin = geospatialOrigin as number[];\n      } else if (coordinateSystem === COORDINATE_SYSTEM.CARTESIAN) {\n        // viewport center in common space\n        shaderCoordinateOrigin = [Math.fround(viewport.center[0]), Math.fround(viewport.center[1]), 0];\n        // Geospatial origin (wgs84) must match shaderCoordinateOrigin (common)\n        geospatialOrigin = viewport.unprojectPosition(shaderCoordinateOrigin);\n        shaderCoordinateOrigin[0] -= coordinateOrigin[0];\n        shaderCoordinateOrigin[1] -= coordinateOrigin[1];\n        shaderCoordinateOrigin[2] -= coordinateOrigin[2];\n      }\n      break;\n\n    case PROJECTION_MODE.IDENTITY:\n      shaderCoordinateOrigin = viewport.position.map(Math.fround);\n      break;\n\n    default:\n      // Unknown projection mode\n      offsetMode = false;\n  }\n\n  shaderCoordinateOrigin[2] = shaderCoordinateOrigin[2] || 0;\n\n  return { geospatialOrigin, shaderCoordinateOrigin, offsetMode };\n}\n\nfunction calculateMatrixAndOffset(\n  viewport: WebMercatorViewport,\n  coordinateSystem: COORDINATE_SYSTEM,\n  coordinateOrigin?: number[],\n) {\n  const { viewMatrixUncentered, projectionMatrix } = viewport;\n  // eslint-disable-next-line prefer-const\n  let { viewMatrix, viewProjectionMatrix } = viewport as { viewMatrix: mat4; viewProjectionMatrix: mat4 };\n\n  let projectionCenter = ZERO_VECTOR as vec4;\n  let cameraPosCommon = viewport.cameraPosition;\n  const { geospatialOrigin, shaderCoordinateOrigin, offsetMode } = getOffsetOrigin(\n    viewport,\n    coordinateSystem,\n    coordinateOrigin,\n  );\n  let positionCommonSpace = [0, 0, 0, 0] as vec4;\n\n  if (offsetMode) {\n    // Calculate transformed projectionCenter (using 64 bit precision JS)\n    // This is the key to offset mode precision\n    // (avoids doing this addition in 32 bit precision in GLSL)\n    positionCommonSpace = viewport?.projectPosition(geospatialOrigin || shaderCoordinateOrigin);\n\n    cameraPosCommon = [\n      cameraPosCommon[0] - positionCommonSpace[0],\n      cameraPosCommon[1] - positionCommonSpace[1],\n      cameraPosCommon[2] - positionCommonSpace[2],\n    ];\n\n    positionCommonSpace[3] = 1;\n\n    // projectionCenter = new Matrix4(viewProjectionMatrix)\n    //   .transformVector([positionPixels[0], positionPixels[1], 0.0, 1.0]);\n    projectionCenter = transformMat4([], positionCommonSpace, viewProjectionMatrix) as vec4;\n\n    // Always apply uncentered projection matrix if available (shader adds center)\n    viewMatrix = viewMatrixUncentered || viewMatrix;\n\n    // Zero out 4th coordinate (\"after\" model matrix) - avoids further translations\n    // viewMatrix = new Matrix4(viewMatrixUncentered || viewMatrix)\n    //   .multiplyRight(VECTOR_TO_POINT_MATRIX);\n    viewProjectionMatrix = multiply(createMat4(), projectionMatrix, viewMatrix) as mat4;\n    viewProjectionMatrix = multiply(createMat4(), viewProjectionMatrix, VECTOR_TO_POINT_MATRIX) as mat4;\n  }\n\n  return {\n    viewMatrix,\n    viewProjectionMatrix,\n    projectionCenter,\n    geospatialOrigin,\n    shaderCoordinateOrigin,\n    cameraPosCommon,\n    originCommon: positionCommonSpace,\n  };\n}\n\nfunction calculateViewportUniforms(options: IOptions) {\n  const { viewport, devicePixelRatio, coordinateSystem, coordinateOrigin } = options;\n\n  const {\n    projectionCenter,\n    viewProjectionMatrix,\n    shaderCoordinateOrigin,\n    geospatialOrigin,\n    cameraPosCommon,\n    originCommon,\n  } = calculateMatrixAndOffset(viewport, coordinateSystem, coordinateOrigin);\n\n  // Calculate projection pixels per unit\n  const { distanceScales } = viewport;\n\n  const viewportSize = [viewport.width * devicePixelRatio, viewport.height * devicePixelRatio];\n\n  const uniforms = {\n    project_uCoordinateSystem: coordinateSystem,\n    project_uProjectionMode: viewport.projectionMode,\n\n    project_uCoordinateOrigin: shaderCoordinateOrigin,\n    project_uCenter: projectionCenter,\n    project_uAntimeridian: (viewport.longitude || 0) - 180,\n\n    // Screen size\n    project_uViewportSize: viewportSize,\n    project_uDevicePixelRatio: devicePixelRatio,\n\n    // Distance at which screen pixels are projected\n    project_uFocalDistance: viewport.focalDistance || 1,\n    project_uCommonUnitsPerMeter: distanceScales.unitsPerMeter,\n\n    project_uCommonUnitsPerWorldUnit: distanceScales.unitsPerMeter,\n    project_uCommonUnitsPerWorldUnit2: DEFAULT_PIXELS_PER_UNIT2,\n\n    project_uScale: viewport.scale, // This is the mercator scale (2 ** zoom)\n    project_uViewProjectionMatrix: viewProjectionMatrix,\n    project_uInverseViewProjectionMatrix: invert(createMat4(), viewProjectionMatrix as unknown as Float32Array),\n    project_metersPerPixel: distanceScales.metersPerUnit[2] / viewport.scale,\n\n    project_uCameraPosition: cameraPosCommon,\n    project_uCommonOrigin: originCommon.slice(0, 3),\n  };\n\n  if (geospatialOrigin) {\n    const distanceScalesAtOrigin = viewport.getDistanceScales(geospatialOrigin);\n    if (distanceScalesAtOrigin) {\n      switch (coordinateSystem) {\n        case COORDINATE_SYSTEM.METER_OFFSETS:\n          uniforms.project_uCommonUnitsPerWorldUnit = distanceScalesAtOrigin.unitsPerMeter;\n          uniforms.project_uCommonUnitsPerWorldUnit2 = distanceScalesAtOrigin.unitsPerMeter2;\n          break;\n\n        case COORDINATE_SYSTEM.LNGLAT:\n        case COORDINATE_SYSTEM.LNGLAT_OFFSETS:\n          uniforms.project_uCommonUnitsPerWorldUnit = distanceScalesAtOrigin.unitsPerDegree;\n          uniforms.project_uCommonUnitsPerWorldUnit2 = distanceScalesAtOrigin.unitsPerDegree2;\n          break;\n\n        // a.k.a \"preprojected\" positions\n        case COORDINATE_SYSTEM.CARTESIAN:\n          uniforms.project_uCommonUnitsPerWorldUnit = [1, 1, distanceScalesAtOrigin.unitsPerMeter[2]];\n          uniforms.project_uCommonUnitsPerWorldUnit2 = [0, 0, distanceScalesAtOrigin.unitsPerMeter2?.[2] || 0];\n          break;\n\n        default:\n          break;\n      }\n    }\n  }\n\n  return uniforms;\n}\n\n/**\n * Returns uniforms for shaders based on current projection\n * includes: projection matrix suitable for shaders\n * @param viewport\n * @param devicePixelRatio\n * @param modelMatrix\n * @param coordinateSystem\n * @param coordinateOrigin\n * @param autoWrapLongitude\n * @return {Float32Array} - 4x4 projection matrix that can be used in shaders\n */\nexport function getUniformsFromViewport({\n  viewport,\n  devicePixelRatio = INITIAL_MODULE_OPTIONS.devicePixelRatio,\n  modelMatrix = null,\n\n  coordinateSystem = COORDINATE_SYSTEM.DEFAULT,\n  coordinateOrigin,\n\n  autoWrapLongitude = false,\n}: IOptions) {\n  if (coordinateSystem === COORDINATE_SYSTEM.DEFAULT) {\n    coordinateSystem = viewport.isGeospatial ? COORDINATE_SYSTEM.LNGLAT : COORDINATE_SYSTEM.CARTESIAN;\n  }\n\n  const uniforms = getMemoizedViewportUniforms({\n    viewport,\n    devicePixelRatio,\n    coordinateSystem,\n    coordinateOrigin,\n  });\n\n  uniforms.project_uWrapLongitude = autoWrapLongitude;\n  uniforms.project_uModelMatrix = modelMatrix || IDENTITY_MATRIX;\n\n  return uniforms;\n}\n\nexport type MercatorUniformKeys = [\n  'project_uCoordinateSystem',\n  'project_uProjectionMode',\n  'project_uCoordinateOrigin',\n  'project_uCenter',\n  'project_uAntimeridian',\n  'project_uViewportSize',\n  'project_uDevicePixelRatio',\n  'project_uFocalDistance',\n  'project_uCommonUnitsPerMeter',\n  'project_uCommonUnitsPerWorldUnit',\n  'project_uCommonUnitsPerWorldUnit2',\n  'project_uScale',\n  'project_uViewProjectionMatrix',\n  'project_metersPerPixel',\n  'project_uModelMatrix',\n  'project_uWrapLongitude',\n  'project_uCameraPosition',\n  'project_uCommonOrigin',\n];\n\nexport function getUniformKeys(): MercatorUniformKeys {\n  return [\n    'project_uCoordinateSystem',\n    'project_uProjectionMode',\n    'project_uCoordinateOrigin',\n    'project_uCenter',\n    'project_uAntimeridian',\n    'project_uViewportSize',\n    'project_uDevicePixelRatio',\n    'project_uFocalDistance',\n    'project_uCommonUnitsPerMeter',\n    'project_uCommonUnitsPerWorldUnit',\n    'project_uCommonUnitsPerWorldUnit2',\n    'project_uScale',\n    'project_uViewProjectionMatrix',\n    'project_metersPerPixel',\n    'project_uModelMatrix',\n    'project_uWrapLongitude',\n    'project_uCameraPosition',\n    'project_uCommonOrigin',\n  ];\n}\n\nexport function getUniforms(opts: IOptions) {\n  if (opts.viewport) {\n    return getUniformsFromViewport(opts);\n  }\n  return {};\n}\n\nexport function highPrecisionLngLat(lngLat: number[], offset = 0, stride = 2) {\n  const numElements = Math.ceil((lngLat.length - offset) / stride);\n  const precisionData = new Float32Array(numElements * 2);\n  for (let i = 0; i < numElements; ++i) {\n    const lli = offset + i * stride;\n    const pi = i * 2;\n\n    precisionData[pi] = lngLat[lli] - Math.fround(lngLat[lli]);\n    precisionData[pi + 1] = lngLat[lli + 1] - Math.fround(lngLat[lli + 1]);\n  }\n\n  return precisionData;\n}\n\nexport function injectMercatorGLSL(\n  gl: WebGLRenderingContext | WebGL2RenderingContext,\n  source: string,\n  defines = {\n    PROJECT_OFFSET_THRESHOLD: '4096.0',\n  },\n): string {\n  const versionMatch = source.match(/#version \\d+(\\s+es)?\\s*\\n/);\n  const versionLine = versionMatch ? versionMatch[0] : '';\n\n  return `\\\n${versionLine}\n${getPlatformShaderDefines(gl)}\n${getApplicationDefines(defines)}\n${FRAGMENT_SHADER_PROLOGUE}\n${fp32shader}\n${projectShader}\n${source.replace(versionLine, '')}\n`;\n}\n\nexport const fp32 = {\n  name: 'fp32',\n  vs: fp32shader,\n  fs: null,\n};\n\nexport const project = {\n  name: 'project',\n  vs: projectShader,\n  fs: null,\n  inject: {},\n  dependencies: [fp32],\n  deprecations: [],\n  getUniforms,\n};\n\nexport { WebMercatorViewport };\n"],"names":[],"mappings":"AACO;AACP;AACA;AACA;AAIO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;;ACdO;AACP;AACA;AACA;AACA;AACA;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACe;AACf;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACnNO;AACA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACO;AACP;AACA;AACA;AACA;AACA;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACO;AACP;AACA;AACA;AACA;AACA;AACO;AACA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO;AACP;AACA;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO;AACA;AACP;AACA;AACO;AACA;AACP;AACA;AACO;AACP;AACA;AACA;AACA;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;"}