function TerrainEncoding(
  center,
  axisAlignedBoundingBox,
  minimumHeight,
  maximumHeight,
  fromENU,
  hasVertexNormals,
  hasWebMercatorT,
  hasGeodeticSurfaceNormals,
  exaggeration,
  exaggerationRelativeHeight,
) {
  let quantization = TerrainQuantization.NONE;
  let toENU;
  let matrix;

  if (
    defined(axisAlignedBoundingBox) &&
    defined(minimumHeight) &&
    defined(maximumHeight) &&
    defined(fromENU)
  ) {
    const minimum = axisAlignedBoundingBox.minimum;
    const maximum = axisAlignedBoundingBox.maximum;

    const dimensions = Cartesian3.subtract(
      maximum,
      minimum,
      cartesian3DimScratch,
    );
    const hDim = maximumHeight - minimumHeight;
    const maxDim = Math.max(Cartesian3.maximumComponent(dimensions), hDim);

    if (maxDim < SHIFT_LEFT_12 - 1.0) {
      quantization = TerrainQuantization.BITS12;
    } else {
      quantization = TerrainQuantization.NONE;
    }

    toENU = Matrix4.inverseTransformation(fromENU, new Matrix4());

    const translation = Cartesian3.negate(minimum, cartesian3Scratch);
    Matrix4.multiply(
      Matrix4.fromTranslation(translation, matrix4Scratch),
      toENU,
      toENU,
    );

    const scale = cartesian3Scratch;
    scale.x = 1.0 / dimensions.x;
    scale.y = 1.0 / dimensions.y;
    scale.z = 1.0 / dimensions.z;
    Matrix4.multiply(Matrix4.fromScale(scale, matrix4Scratch), toENU, toENU);

    matrix = Matrix4.clone(fromENU);
    Matrix4.setTranslation(matrix, Cartesian3.ZERO, matrix);

    fromENU = Matrix4.clone(fromENU, new Matrix4());

    const translationMatrix = Matrix4.fromTranslation(minimum, matrix4Scratch);
    const scaleMatrix = Matrix4.fromScale(dimensions, matrix4Scratch2);
    const st = Matrix4.multiply(translationMatrix, scaleMatrix, matrix4Scratch);

    Matrix4.multiply(fromENU, st, fromENU);
    Matrix4.multiply(matrix, st, matrix);
  }

  /**
   * How the vertices of the mesh were compressed.
   * @type {TerrainQuantization}
   */
  this.quantization = quantization;

  /**
   * The minimum height of the tile including the skirts.
   * @type {number}
   */
  this.minimumHeight = minimumHeight;

  /**
   * The maximum height of the tile.
   * @type {number}
   */
  this.maximumHeight = maximumHeight;

  /**
   * The center of the tile.
   * @type {Cartesian3}
   */
  this.center = Cartesian3.clone(center);

  /**
   * A matrix that takes a vertex from the tile, transforms it to east-north-up at the center and scales
   * it so each component is in the [0, 1] range.
   * @type {Matrix4}
   */
  this.toScaledENU = toENU;

  /**
   * A matrix that restores a vertex transformed with toScaledENU back to the earth fixed reference frame
   * @type {Matrix4}
   */
  this.fromScaledENU = fromENU;

  /**
   * The matrix used to decompress the terrain vertices in the shader for RTE rendering.
   * @type {Matrix4}
   */
  this.matrix = matrix;

  /**
   * The terrain mesh contains normals.
   * @type {boolean}
   */
  this.hasVertexNormals = hasVertexNormals;

  /**
   * The terrain mesh contains a vertical texture coordinate following the Web Mercator projection.
   * @type {boolean}
   */
  this.hasWebMercatorT = hasWebMercatorT ?? false;

  /**
   * The terrain mesh contains geodetic surface normals, used for terrain exaggeration.
   * @type {boolean}
   */
  this.hasGeodeticSurfaceNormals = hasGeodeticSurfaceNormals ?? false;

  /**
   * A scalar used to exaggerate terrain.
   * @type {number}
   */
  this.exaggeration = exaggeration ?? 1.0;

  /**
   * The relative height from which terrain is exaggerated.
   */
  this.exaggerationRelativeHeight = exaggerationRelativeHeight ?? 0.0;

  /**
   * The number of components in each vertex. This value can differ with different quantizations.
   * @type {number}
   */
  this.stride = 0;

  this._offsetGeodeticSurfaceNormal = 0;
  this._offsetVertexNormal = 0;

  // Calculate the stride and offsets declared above
  this._calculateStrideAndOffsets();
}
Data used to quantize and pack the terrain mesh. The position can be unpacked for picking and all attributes
are unpacked in the vertex shader.

@alias TerrainEncoding
@constructor

@param {Cartesian3} center The center point of the vertices.
@param {AxisAlignedBoundingBox} axisAlignedBoundingBox The bounds of the tile in the east-north-up coordinates at the tiles center.
@param {number} minimumHeight The minimum height.
@param {number} maximumHeight The maximum height.
@param {Matrix4} fromENU The east-north-up to fixed frame matrix at the center of the terrain mesh.
@param {boolean} hasVertexNormals If the mesh has vertex normals.
@param {boolean} [hasWebMercatorT=false] true if the terrain data includes a Web Mercator texture coordinate; otherwise, false.
@param {boolean} [hasGeodeticSurfaceNormals=false] true if the terrain data includes geodetic surface normals; otherwise, false.
@param {number} [exaggeration=1.0] A scalar used to exaggerate terrain.
@param {number} [exaggerationRelativeHeight=0.0] The relative height from which terrain is exaggerated.

@private