o: ActiveSupport::Cache::Entry	:@compressedF:@expires_in0:@created_atf1372843460.316243:@value"F;{I"
class:EFI"BundledAsset;�FI"logical_path;�FI"!Core/HeightmapTessellator.js;�TI"
pathname;�FI"Y/Users/bwrona/www/engines/cesium/app/assets/javascripts/Core/HeightmapTessellator.js;�TI"content_type;�FI"application/javascript;�FI"
mtime;�FI"2013-07-03T11:02:49+02:00;�FI"length;�Fi`9I"digest;�F"%63e38ee6bd1392425707280e81df5912I"source;�FI"`9/*global define*/

define([
        './defaultValue',
        './freezeObject',
        './DeveloperError',
        './Cartesian3',
        './Ellipsoid',
        './Math'
    ], function(
        defaultValue,
        freezeObject,
        DeveloperError,
        Cartesian3,
        Ellipsoid,
        CesiumMath) {
    "use strict";

    /**
     * Contains functions to create a mesh from a heightmap image.
     *
     * @exports HeightmapTessellator
     *
     * @see ExtentTessellator
     * @see CubeMapEllipsoidTessellator
     * @see BoxTessellator
     * @see PlaneTessellator
     */
    var HeightmapTessellator = {};

    /**
     * The default structure of a heightmap, as given to {@link HeightmapTessellator.computeVertices}.
     *
     * @memberof HeightmapTessellator
     */
    HeightmapTessellator.DEFAULT_STRUCTURE = freezeObject({
            heightScale : 1.0,
            heightOffset : 0.0,
            elementsPerHeight : 1,
            stride : 1,
            elementMultiplier : 256.0,
            isBigEndian : false
        });

    /**
     * Fills an array of vertices from a heightmap image.  On return, the vertex data is in the order
     * [X, Y, Z, H, U, V], where X, Y, and Z represent the Cartesian position of the vertex, H is the
     * height above the ellipsoid, and U and V are the texture coordinates.
     *
     * @memberof HeightmapTessellator
     *
     * @param {Array|Float32Array} description.vertices The array to use to store computed vertices.
     *                             If description.skirtHeight is 0.0, the array should have
     *                             description.width * description.height * 6 elements.  If
     *                             description.skirtHeight is greater than 0.0, the array should
     *                             have (description.width + 2) * (description.height * 2) * 6
     *                             elements.
     * @param {TypedArray} description.heightmap The heightmap to tessellate.
     * @param {Number} description.width The width of the heightmap, in height samples.
     * @param {Number} description.height The height of the heightmap, in height samples.
     * @param {Number} description.skirtHeight The height of skirts to drape at the edges of the heightmap.
     * @param {Extent} description.nativeExtent An extent in the native coordinates of the heightmap's projection.  For
     *                 a heightmap with a geographic projection, this is degrees.  For the web mercator
     *                 projection, this is meters.
     * @param {Extent} [description.extent] The extent covered by the heightmap, in geodetic coordinates with north, south, east and
     *                 west properties in radians.  Either extent or nativeExtent must be provided.  If both
     *                 are provided, they're assumed to be consistent.
     * @param {Boolean} [description.isGeographic=true] True if the heightmap uses a {@link GeographicProjection}, or false if it uses
     *                  a {@link WebMercatorProjection}.
     * @param {Cartesian3} [description.relativetoCenter=Cartesian3.ZERO] The positions will be computed as <code>worldPosition.subtract(relativeToCenter)</code>.
     * @param {Ellipsoid} [description.ellipsoid=Ellipsoid.WGS84] The ellipsoid to which the heightmap applies.
     * @param {Object} [description.structure] An object describing the structure of the height data.
     * @param {Number} [description.structure.heightScale=1.0] The factor by which to multiply height samples in order to obtain
     *                 the height above the heightOffset, in meters.  The heightOffset is added to the resulting
     *                 height after multiplying by the scale.
     * @param {Number} [description.structure.heightOffset=0.0] The offset to add to the scaled height to obtain the final
     *                 height in meters.  The offset is added after the height sample is multiplied by the
     *                 heightScale.
     * @param {Number} [description.structure.elementsPerHeight=1] The number of elements in the buffer that make up a single height
     *                 sample.  This is usually 1, indicating that each element is a separate height sample.  If
     *                 it is greater than 1, that number of elements together form the height sample, which is
     *                 computed according to the structure.elementMultiplier and structure.isBigEndian properties.
     * @param {Number} [description.structure.stride=1] The number of elements to skip to get from the first element of
     *                 one height to the first element of the next height.
     * @param {Number} [description.structure.elementMultiplier=256.0] The multiplier used to compute the height value when the
     *                 stride property is greater than 1.  For example, if the stride is 4 and the strideMultiplier
     *                 is 256, the height is computed as follows:
     *                 `height = buffer[index] + buffer[index + 1] * 256 + buffer[index + 2] * 256 * 256 + buffer[index + 3] * 256 * 256 * 256`
     *                 This is assuming that the isBigEndian property is false.  If it is true, the order of the
     *                 elements is reversed.
     * @param {Boolean} [description.structure.isBigEndian=false] Indicates endianness of the elements in the buffer when the
     *                  stride property is greater than 1.  If this property is false, the first element is the
     *                  low-order element.  If it is true, the first element is the high-order element.
     *
     * @example
     * var width = 5;
     * var height = 5;
     * var vertices = new Float32Array(width * height * 6);
     * var description = ;
     * HeightmapTessellator.computeVertices({
     *     vertices : vertices,
     *     heightmap : [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0],
     *     width : width,
     *     height : height,
     *     skirtHeight : 0.0,
     *     nativeExtent : {
     *         west : 10.0,
     *         east : 20.0,
     *         south : 30.0,
     *         north : 40.0
     *     }
     * });
     */
    HeightmapTessellator.computeVertices = function(description) {
        if (typeof description === 'undefined' || typeof description.heightmap === 'undefined') {
            throw new DeveloperError('description.heightmap is required.');
        }

        if (typeof description.width === 'undefined' || typeof description.height === 'undefined') {
            throw new DeveloperError('description.width and description.height are required.');
        }

        if (typeof description.vertices === 'undefined') {
            throw new DeveloperError('description.vertices is required.');
        }

        if (typeof description.nativeExtent === 'undefined') {
            throw new DeveloperError('description.nativeExtent is required.');
        }

        if (typeof description.skirtHeight === 'undefined') {
            throw new DeveloperError('description.skirtHeight is required.');
        }

        // This function tends to be a performance hotspot for terrain rendering,
        // so it employs a lot of inlining and unrolling as an optimization.
        // In particular, the functionality of Ellipsoid.cartographicToCartesian
        // is inlined.

        var cos = Math.cos;
        var sin = Math.sin;
        var sqrt = Math.sqrt;
        var atan = Math.atan;
        var exp = Math.exp;
        var piOverTwo = CesiumMath.PI_OVER_TWO;
        var toRadians = CesiumMath.toRadians;

        var vertices = description.vertices;
        var heightmap = description.heightmap;
        var width = description.width;
        var height = description.height;
        var skirtHeight = description.skirtHeight;

        var isGeographic = defaultValue(description.isGeographic, true);
        var ellipsoid = defaultValue(description.ellipsoid, Ellipsoid.WGS84);

        var oneOverCentralBodySemimajorAxis = 1.0 / ellipsoid.getMaximumRadius();

        var nativeExtent = description.nativeExtent;

        var geographicWest;
        var geographicSouth;
        var geographicEast;
        var geographicNorth;

        var extent = description.extent;
        if (typeof extent === 'undefined') {
            if (isGeographic) {
                geographicWest = toRadians(nativeExtent.west);
                geographicSouth = toRadians(nativeExtent.south);
                geographicEast = toRadians(nativeExtent.east);
                geographicNorth = toRadians(nativeExtent.north);
            } else {
                geographicWest = nativeExtent.west * oneOverCentralBodySemimajorAxis;
                geographicSouth = piOverTwo - (2.0 * atan(exp(-nativeExtent.south * oneOverCentralBodySemimajorAxis)));
                geographicEast = nativeExtent.east * oneOverCentralBodySemimajorAxis;
                geographicNorth = piOverTwo - (2.0 * atan(exp(-nativeExtent.north * oneOverCentralBodySemimajorAxis)));
            }
        } else {
            geographicWest = extent.west;
            geographicSouth = extent.south;
            geographicEast = extent.east;
            geographicNorth = extent.north;
        }

        var relativeToCenter = defaultValue(description.relativeToCenter, Cartesian3.ZERO);

        var structure = defaultValue(description.structure, HeightmapTessellator.DEFAULT_STRUCTURE);
        var heightScale = defaultValue(structure.heightScale, HeightmapTessellator.DEFAULT_STRUCTURE.heightScale);
        var heightOffset = defaultValue(structure.heightOffset, HeightmapTessellator.DEFAULT_STRUCTURE.heightOffset);
        var elementsPerHeight = defaultValue(structure.elementsPerHeight, HeightmapTessellator.DEFAULT_STRUCTURE.elementsPerHeight);
        var stride = defaultValue(structure.stride, HeightmapTessellator.DEFAULT_STRUCTURE.stride);
        var elementMultiplier = defaultValue(structure.elementMultiplier, HeightmapTessellator.DEFAULT_STRUCTURE.elementMultiplier);
        var isBigEndian = defaultValue(structure.isBigEndian, HeightmapTessellator.DEFAULT_STRUCTURE.isBigEndian);

        var granularityX = (nativeExtent.east - nativeExtent.west) / (width - 1);
        var granularityY = (nativeExtent.north - nativeExtent.south) / (height - 1);

        var radiiSquared = ellipsoid.getRadiiSquared();
        var radiiSquaredX = radiiSquared.x;
        var radiiSquaredY = radiiSquared.y;
        var radiiSquaredZ = radiiSquared.z;

        var vertexArrayIndex = 0;

        var minimumHeight = 65536.0;
        var maximumHeight = -65536.0;

        var startRow = 0;
        var endRow = height;
        var startCol = 0;
        var endCol = width;

        if (skirtHeight > 0) {
            --startRow;
            ++endRow;
            --startCol;
            ++endCol;
        }

        for ( var rowIndex = startRow; rowIndex < endRow; ++rowIndex) {
            var row = rowIndex;
            if (row < 0) {
                row = 0;
            }
            if (row >= height) {
                row = height - 1;
            }

            var latitude = nativeExtent.north - granularityY * row;

            if (!isGeographic) {
                latitude = piOverTwo - (2.0 * atan(exp(-latitude * oneOverCentralBodySemimajorAxis)));
            } else {
                latitude = toRadians(latitude);
            }

            var cosLatitude = cos(latitude);
            var nZ = sin(latitude);
            var kZ = radiiSquaredZ * nZ;

            var v = (latitude - geographicSouth) / (geographicNorth - geographicSouth);

            for ( var colIndex = startCol; colIndex < endCol; ++colIndex) {
                var col = colIndex;
                if (col < 0) {
                    col = 0;
                }
                if (col >= width) {
                    col = width - 1;
                }

                var longitude = nativeExtent.west + granularityX * col;

                if (!isGeographic) {
                    longitude = longitude * oneOverCentralBodySemimajorAxis;
                } else {
                    longitude = toRadians(longitude);
                }

                var terrainOffset = row * (width * stride) + col * stride;

                var heightSample;
                if (elementsPerHeight === 1) {
                    heightSample = heightmap[terrainOffset];
                } else {
                    heightSample = 0;

                    var elementOffset;
                    if (isBigEndian) {
                        for (elementOffset = 0; elementOffset < elementsPerHeight; ++elementOffset) {
                            heightSample = (heightSample * elementMultiplier) + heightmap[terrainOffset + elementOffset];
                        }
                    } else {
                        for (elementOffset = elementsPerHeight - 1; elementOffset >= 0; --elementOffset) {
                            heightSample = (heightSample * elementMultiplier) + heightmap[terrainOffset + elementOffset];
                        }
                    }
                }

                heightSample = heightSample * heightScale + heightOffset;

                maximumHeight = Math.max(maximumHeight, heightSample);
                minimumHeight = Math.min(minimumHeight, heightSample);

                if (colIndex !== col || rowIndex !== row) {
                    heightSample -= skirtHeight;
                }

                var nX = cosLatitude * cos(longitude);
                var nY = cosLatitude * sin(longitude);

                var kX = radiiSquaredX * nX;
                var kY = radiiSquaredY * nY;

                var gamma = sqrt((kX * nX) + (kY * nY) + (kZ * nZ));
                var oneOverGamma = 1.0 / gamma;

                var rSurfaceX = kX * oneOverGamma;
                var rSurfaceY = kY * oneOverGamma;
                var rSurfaceZ = kZ * oneOverGamma;

                vertices[vertexArrayIndex++] = rSurfaceX + nX * heightSample - relativeToCenter.x;
                vertices[vertexArrayIndex++] = rSurfaceY + nY * heightSample - relativeToCenter.y;
                vertices[vertexArrayIndex++] = rSurfaceZ + nZ * heightSample - relativeToCenter.z;

                vertices[vertexArrayIndex++] = heightSample;

                var u = (longitude - geographicWest) / (geographicEast - geographicWest);

                vertices[vertexArrayIndex++] = u;
                vertices[vertexArrayIndex++] = v;
            }
        }

        return {
            maximumHeight : maximumHeight,
            minimumHeight : minimumHeight
        };
    };

    return HeightmapTessellator;
});
;�FI"required_assets_digest;�F"%e01a45b3bc0544424749fb41cd726a6aI"
_version;�F"%6776f581a4329e299531e1d52aa59832