text: /*
   * Copyright (C) 2014 United States Government as represented by the Administrator of the
   * National Aeronautics and Space Administration. All Rights Reserved.
   */
  /**
   * @exports GeographicMesh
   */
  define([
          '../shapes/AbstractMesh',
          '../error/ArgumentError',
          '../shaders/BasicTextureProgram',
          '../geom/BoundingBox',
          '../util/Color',
          '../util/ImageSource',
          '../geom/Location',
          '../util/Logger',
          '../geom/Matrix',
          '../pick/PickedObject',
          '../geom/Position',
          '../shapes/ShapeAttributes',
          '../shapes/SurfacePolygon',
          '../geom/Vec2',
          '../geom/Vec3',
      ],
      function (AbstractMesh,
                ArgumentError,
                BasicTextureProgram,
                BoundingBox,
                Color,
                ImageSource,
                Location,
                Logger,
                Matrix,
                PickedObject,
                Position,
                ShapeAttributes,
                SurfacePolygon,
                Vec2,
                Vec3) {
          "use strict";
  
          /**
           * Constructs a geographic mesh.
           * @alias GeographicMesh
           * @constructor
           * @augments AbstractMesh
           * @classdesc Represents a 3D geographic mesh.
           * <p>
           *     Altitudes within the mesh's positions are interpreted according to the mesh's altitude mode, which
           *     can be one of the following:
           * <ul>
           *     <li>[WorldWind.ABSOLUTE]{@link WorldWind#ABSOLUTE}</li>
           *     <li>[WorldWind.RELATIVE_TO_GROUND]{@link WorldWind#RELATIVE_TO_GROUND}</li>
           *     <li>[WorldWind.CLAMP_TO_GROUND]{@link WorldWind#CLAMP_TO_GROUND}</li>
           * </ul>
           * If the latter, the mesh positions' altitudes are ignored. (If the mesh should be draped onto the
           * terrain, you might want to use {@link SurfacePolygon} instead.)
           * <p>
           *     Meshes have separate attributes for normal display and highlighted display. They use the interior and
           *     outline attributes of {@link ShapeAttributes}. If those attributes identify an image, that image is
           *     applied to the mesh. Texture coordinates for the image may be specified, but if not specified the full
           *     image is stretched over the full mesh. If texture coordinates are specified, there must be one texture
           *     coordinate for each vertex in the mesh.
           *
           * @param {Position[][]} positions A two-dimensional array containing the mesh vertices.
           * Each entry of the array specifies the vertices of one row of the mesh. The arrays for all rows must
           * have the same length. There must be at least two rows, and each row must have at least two vertices.
           * There must be no more than 65536 positions.
           * @param {ShapeAttributes} attributes The attributes to associate with this mesh. May be null, in which case
           * default attributes are associated.
           *
           * @throws {ArgumentError} If the specified positions array is null or undefined, the number of rows or the
           * number of vertices per row is less than 2, the array lengths are inconsistent, or too many positions are
           * specified (limit is 65536).
           */
          var GeographicMesh = function (positions, attributes) {
              if (!positions) {
                  throw new ArgumentError(
                      Logger.logMessage(Logger.LEVEL_SEVERE, "GeographicMesh", "constructor", "missingPositions"));
              }
  
              if (positions.length < 2 || positions[0].length < 2) {
                  throw new ArgumentError(
                      Logger.logMessage(Logger.LEVEL_SEVERE, "GeographicMesh", "constructor",
                          "Number of positions is insufficient."));
              }
  
              // Check for size limit, which is the max number of available indices for a 16-bit unsigned int.
              if (positions.length * positions[0].length > 65536) {
                  throw new ArgumentError(
                      Logger.logMessage(Logger.LEVEL_SEVERE, "GeographicMesh", "constructor",
                          "Too many positions. Must be fewer than 65536. Try using multiple meshes."));
              }
  
              var length = positions[0].length;
              for (var i = 1; i < positions.length; i++) {
                  if (positions[i].length !== length) {
                      throw new ArgumentError(
                          Logger.logMessage(Logger.LEVEL_SEVERE, "GeographicMesh", "constructor",
                              "Array lengths are inconsistent."));
                  }
              }
  
              var numRows = positions.length,
                  numCols = positions[0].length;
  
              AbstractMesh.call(this, attributes);
  
              /**
               * Indicates whether this mesh is pickable when the pick point intersects transparent pixels of the
               * image applied to this mesh. If no image is applied to this mesh, this property is ignored. If this
               * property is true and an image with fully transparent pixels is applied to the mesh, the mesh is
               * pickable at those transparent pixels, otherwise this mesh is not pickable at those transparent pixels.
               * @type {Boolean}
               * @default true
               */
              this.pickTransparentImagePixels = true;
  
              // Private. Documentation is with the defined property below and the constructor description above.
              this._positions = positions;
  
              // Private. Documentation is with the defined property below.
              this._altitudeScale = 1;
  
              // Internal. Intentionally not documented.
              this.numRows = numRows;
              this.numColumns = numCols;
  
              // Internal. Intentionally not documented.
              this._textureCoordinates = null;
  
              // Internal. Intentionally not documented.
              this.referencePosition = this.determineReferencePosition(this._positions);
          };
  
          GeographicMesh.prototype = Object.create(AbstractMesh.prototype);
  
          Object.defineProperties(GeographicMesh.prototype, {
              /**
               * This mesh's positions. Each array in the positions array specifies the geographic positions of one
               * row of the mesh.
               *
               * @type {Position[][]}
               * @memberof GeographicMesh.prototype
               */
              positions: {
                  get: function () {
                      return this._positions;
                  },
                  set: function (positions) {
                      if (!positions) {
                          throw new ArgumentError(
                              Logger.logMessage(Logger.LEVEL_SEVERE, "GeographicMesh", "positions", "missingPositions"));
                      }
  
                      if (positions.length < 2 || positions[0].length < 2) {
                          throw new ArgumentError(
                              Logger.logMessage(Logger.LEVEL_SEVERE, "GeographicMesh", "positions",
                                  "Number of positions is insufficient."));
                      }
  
                      var length = positions[0].length;
                      for (var i = 1; i < positions.length; i++) {
                          if (positions[i].length !== length) {
                              throw new ArgumentError(
                                  Logger.logMessage(Logger.LEVEL_SEVERE, "GeographicMesh", "positions",
                                      "Array lengths are inconsistent."));
                          }
                      }
  
                      this.numRows = positions.length;
                      this.numColumns = positions[0].length;
  
                      this._positions = positions;
                      this.referencePosition = this.determineReferencePosition(this._positions);
                      this.reset();
  
                      this.meshIndices = null;
                      this.outlineIndices = null;
                  }
              },
  
              /**
               * This mesh's texture coordinates if this mesh is textured. A texture coordinate must be
               * provided for each mesh position. The texture coordinates are specified as a two-dimensional array,
               * each entry of which specifies the texture coordinates for one row of the mesh. Each texture coordinate
               * is a {@link Vec2} containing the s and t coordinates. If no texture coordinates are specified and
               * the attributes associated with this mesh indicate an image source, then texture coordinates are
               * automatically generated for the mesh.
               * @type {Vec2[][]}
               * @default null
               * @memberof GeographicMesh.prototype
               */
              textureCoordinates: {
                  get: function () {
                      return this._textureCoordinates;
                  },
                  set: function (coords) {
  
                      if (coords && coords.length != this.numRows) {
                          throw new ArgumentError(
                              Logger.logMessage(Logger.LEVEL_SEVERE, "GeographicMesh", "textureCoordinates",
                                  "Number of texture coordinate rows is inconsistent with the currently specified positions."));
                      }
  
                      for (var i = 0; i < this.numRows; i++) {
                          if (coords[i].length !== this.numColumns) {
                              throw new ArgumentError(
                                  Logger.logMessage(Logger.LEVEL_SEVERE, "GeographicMesh", "textureCoordinates",
                                      "Texture coordinate row lengths are inconsistent with the currently specified positions."));
                          }
                      }
  
                      this._textureCoordinates = coords;
                      this.reset();
                      this.texCoords = null;
                  }
              },
          });
  
          GeographicMesh.makeGridIndices = function (nRows, nCols) {
              // Compute indices for individual triangles.
  
              var gridIndices = [],
                  i = 0;
  
              for (var r = 0; r < nRows - 1; r++) {
                  for (var c = 0; c < nCols - 1; c++) {
                      var k = r * nCols + c;
  
                      gridIndices[i++] = k;
                      gridIndices[i++] = k + 1;
                      gridIndices[i++] = k + nCols;
                      gridIndices[i++] = k + 1;
                      gridIndices[i++] = k + 1 + nCols;
                      gridIndices[i++] = k + nCols;
                  }
              }
  
              return gridIndices;
          };
  
          // Intentionally not documented.
          GeographicMesh.prototype.determineReferencePosition = function (positions) {
              // Assign the first position as the reference position.
              return positions[0][0];
          };
  
          // Overridden from AbstractShape base class.
          GeographicMesh.prototype.createSurfaceShape = function () {
              var boundaries = [];
  
              for (var c = 0; c < this.numColumns; c++) {
                  boundaries.push(this._positions[0][c]);
              }
  
              for (var r = 1; r < this.numRows; r++) {
                  boundaries.push(this._positions[r][this.numColumns - 1]);
              }
  
              for (c = this.numColumns - 2; c >= 0; c--) {
                  boundaries.push(this._positions[this.numRows - 1][c]);
              }
  
              for (r = this.numRows - 2; r > 0; r--) {
                  boundaries.push(this._positions[r][0]);
              }
  
              return new SurfacePolygon(boundaries, null);
          };
  
          GeographicMesh.prototype.computeMeshPoints = function (dc, currentData) {
              // Unwrap the mesh row arrays into one long array.
  
              var eyeDistSquared = Number.MAX_VALUE,
                  eyePoint = dc.navigatorState.eyePoint,
                  meshPoints = new Float32Array((this.numRows * this.numColumns) * 3),
                  pt = new Vec3(0, 0, 0),
                  k = 0,
                  pos, dSquared;
  
              for (var r = 0; r < this._positions.length; r++) {
                  for (var c = 0, len = this._positions[r].length; c < len; c++) {
                      pos = this._positions[r][c];
  
                      dc.surfacePointForMode(pos.latitude, pos.longitude, pos.altitude * this._altitudeScale,
                          this.altitudeMode, pt);
  
                      dSquared = pt.distanceToSquared(eyePoint);
                      if (dSquared < eyeDistSquared) {
                          eyeDistSquared = dSquared;
                      }
  
                      pt.subtract(this.currentData.referencePoint);
  
                      meshPoints[k++] = pt[0];
                      meshPoints[k++] = pt[1];
                      meshPoints[k++] = pt[2];
                  }
              }
  
              currentData.eyeDistance = Math.sqrt(eyeDistSquared);
  
              return meshPoints;
          };
  
          GeographicMesh.prototype.computeTexCoords = function () {
              if (this._textureCoordinates) {
                  return this.computeExplicitTexCoords();
              } else {
                  return this.computeImplicitTexCoords();
              }
          };
  
          // Intentionally not documented.
          GeographicMesh.prototype.computeExplicitTexCoords = function () {
              // Capture the texture coordinates to a single array parallel to the mesh points array.
  
              var texCoords = new Float32Array(2 * this.numRows * this.numColumns),
                  k = 0;
  
              for (var r = 0; r < this._textureCoordinates.length; r++) {
                  for (var c = 0, len = this._textureCoordinates[r].length; c < len; c++) {
                      var texCoord = this._textureCoordinates[r][c];
  
                      texCoords[k++] = texCoord[0];
                      texCoords[k++] = texCoord[1];
                  }
              }
  
              return texCoords;
          };
  
          // Intentionally not documented.
          GeographicMesh.prototype.computeImplicitTexCoords = function () {
              // Create texture coordinates that map the full image source into the full mesh.
  
              var texCoords = new Float32Array(2 * this.numRows * this.numColumns),
                  rowDelta = 1.0 / (this.numRows - 1),
                  columnDelta = 1.0 / (this.numColumns - 1),
                  k = 0;
  
              for (var r = 0; r < this._positions.length; r++) {
                  var t = (r === this.numRows - 1) ? 1.0 : r * rowDelta;
  
                  for (var c = 0, len = this._positions[r].length; c < len; c++) {
                      texCoords[k++] = (c === this.numColumns - 1) ? 1.0 : c * columnDelta;
                      texCoords[k++] = t;
                  }
              }
  
              return texCoords;
          };
  
          GeographicMesh.prototype.computeMeshIndices = function () {
              // Compute indices for individual triangles.
  
              var meshIndices = new Uint16Array((this.numRows - 1) * (this.numColumns - 1) * 6),
                  i = 0;
  
              for (var r = 0; r < this.numRows - 1; r++) {
                  for (var c = 0; c < this.numColumns - 1; c++) {
                      var k = r * this.numColumns + c;
  
                      meshIndices[i++] = k;
                      meshIndices[i++] = k + 1;
                      meshIndices[i++] = k + this.numColumns;
                      meshIndices[i++] = k + 1;
                      meshIndices[i++] = k + 1 + this.numColumns;
                      meshIndices[i++] = k + this.numColumns;
                  }
              }
  
              return meshIndices;
          };
  
          GeographicMesh.prototype.computeOutlineIndices = function () {
              // Walk the mesh boundary and capture those positions for the outline.
  
              var outlineIndices = new Uint16Array(2 * this.numRows + 2 * this.numColumns),
                  k = 0;
  
              for (var c = 0; c < this.numColumns; c++) {
                  outlineIndices[k++] = c;
              }
  
              for (var r = 1; r < this.numRows; r++) {
                  outlineIndices[k++] = (r + 1) * this.numColumns - 1;
              }
  
              for (c = this.numRows * this.numColumns - 2; c >= (this.numRows - 1) * this.numColumns; c--) {
                  outlineIndices[k++] = c;
              }
  
              for (r = this.numRows - 2; r >= 0; r--) {
                  outlineIndices[k++] = r * this.numColumns;
              }
  
              return outlineIndices;
          };
  
          return GeographicMesh;
      });