(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.CesiumVectorTile = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
|
"use strict";
|
var __importStar = (this && this.__importStar) || function (mod) {
|
if (mod && mod.__esModule) return mod;
|
var result = {};
|
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
|
result["default"] = mod;
|
return result;
|
}
|
Object.defineProperty(exports, "__esModule", { value: true });
|
var helpers_1 = require("@turf/helpers");
|
var invariant_1 = require("@turf/invariant");
|
var lineclip = __importStar(require("./lib/lineclip"));
|
/**
|
* Takes a {@link Feature} and a bbox and clips the feature to the bbox using
|
* [lineclip](https://github.com/mapbox/lineclip).
|
* May result in degenerate edges when clipping Polygons.
|
*
|
* @name bboxClip
|
* @param {Feature<LineString|MultiLineString|Polygon|MultiPolygon>} feature feature to clip to the bbox
|
* @param {BBox} bbox extent in [minX, minY, maxX, maxY] order
|
* @returns {Feature<LineString|MultiLineString|Polygon|MultiPolygon>} clipped Feature
|
* @example
|
* var bbox = [0, 0, 10, 10];
|
* var poly = turf.polygon([[[2, 2], [8, 4], [12, 8], [3, 7], [2, 2]]]);
|
*
|
* var clipped = turf.bboxClip(poly, bbox);
|
*
|
* //addToMap
|
* var addToMap = [bbox, poly, clipped]
|
*/
|
function bboxClip(feature, bbox) {
|
var geom = invariant_1.getGeom(feature);
|
var type = geom.type;
|
var properties = feature.type === "Feature" ? feature.properties : {};
|
var coords = geom.coordinates;
|
switch (type) {
|
case "LineString":
|
case "MultiLineString":
|
var lines_1 = [];
|
if (type === "LineString") {
|
coords = [coords];
|
}
|
coords.forEach(function (line) {
|
lineclip.polyline(line, bbox, lines_1);
|
});
|
if (lines_1.length === 1) {
|
return helpers_1.lineString(lines_1[0], properties);
|
}
|
return helpers_1.multiLineString(lines_1, properties);
|
case "Polygon":
|
return helpers_1.polygon(clipPolygon(coords, bbox), properties);
|
case "MultiPolygon":
|
return helpers_1.multiPolygon(coords.map(function (poly) {
|
return clipPolygon(poly, bbox);
|
}), properties);
|
default:
|
throw new Error("geometry " + type + " not supported");
|
}
|
}
|
exports.default = bboxClip;
|
function clipPolygon(rings, bbox) {
|
var outRings = [];
|
for (var _i = 0, rings_1 = rings; _i < rings_1.length; _i++) {
|
var ring = rings_1[_i];
|
var clipped = lineclip.polygon(ring, bbox);
|
if (clipped.length > 0) {
|
if (clipped[0][0] !== clipped[clipped.length - 1][0] || clipped[0][1] !== clipped[clipped.length - 1][1]) {
|
clipped.push(clipped[0]);
|
}
|
if (clipped.length >= 4) {
|
outRings.push(clipped);
|
}
|
}
|
}
|
return outRings;
|
}
|
|
},{"./lib/lineclip":2,"@turf/helpers":14,"@turf/invariant":17}],2:[function(require,module,exports){
|
'use strict';
|
|
module.exports = lineclip;
|
module.exports.default = lineclip;
|
|
lineclip.polyline = lineclip;
|
lineclip.polygon = polygonclip;
|
|
|
// Cohen-Sutherland line clippign algorithm, adapted to efficiently
|
// handle polylines rather than just segments
|
|
function lineclip(points, bbox, result) {
|
|
var len = points.length,
|
codeA = bitCode(points[0], bbox),
|
part = [],
|
i, a, b, codeB, lastCode;
|
|
if (!result) result = [];
|
|
for (i = 1; i < len; i++) {
|
a = points[i - 1];
|
b = points[i];
|
codeB = lastCode = bitCode(b, bbox);
|
|
while (true) {
|
|
if (!(codeA | codeB)) { // accept
|
part.push(a);
|
|
if (codeB !== lastCode) { // segment went outside
|
part.push(b);
|
|
if (i < len - 1) { // start a new line
|
result.push(part);
|
part = [];
|
}
|
} else if (i === len - 1) {
|
part.push(b);
|
}
|
break;
|
|
} else if (codeA & codeB) { // trivial reject
|
break;
|
|
} else if (codeA) { // a outside, intersect with clip edge
|
a = intersect(a, b, codeA, bbox);
|
codeA = bitCode(a, bbox);
|
|
} else { // b outside
|
b = intersect(a, b, codeB, bbox);
|
codeB = bitCode(b, bbox);
|
}
|
}
|
|
codeA = lastCode;
|
}
|
|
if (part.length) result.push(part);
|
|
return result;
|
}
|
|
// Sutherland-Hodgeman polygon clipping algorithm
|
|
function polygonclip(points, bbox) {
|
|
var result, edge, prev, prevInside, i, p, inside;
|
|
// clip against each side of the clip rectangle
|
for (edge = 1; edge <= 8; edge *= 2) {
|
result = [];
|
prev = points[points.length - 1];
|
prevInside = !(bitCode(prev, bbox) & edge);
|
|
for (i = 0; i < points.length; i++) {
|
p = points[i];
|
inside = !(bitCode(p, bbox) & edge);
|
|
// if segment goes through the clip window, add an intersection
|
if (inside !== prevInside) result.push(intersect(prev, p, edge, bbox));
|
|
if (inside) result.push(p); // add a point if it's inside
|
|
prev = p;
|
prevInside = inside;
|
}
|
|
points = result;
|
|
if (!points.length) break;
|
}
|
|
return result;
|
}
|
|
// intersect a segment against one of the 4 lines that make up the bbox
|
|
function intersect(a, b, edge, bbox) {
|
return edge & 8 ? [a[0] + (b[0] - a[0]) * (bbox[3] - a[1]) / (b[1] - a[1]), bbox[3]] : // top
|
edge & 4 ? [a[0] + (b[0] - a[0]) * (bbox[1] - a[1]) / (b[1] - a[1]), bbox[1]] : // bottom
|
edge & 2 ? [bbox[2], a[1] + (b[1] - a[1]) * (bbox[2] - a[0]) / (b[0] - a[0])] : // right
|
edge & 1 ? [bbox[0], a[1] + (b[1] - a[1]) * (bbox[0] - a[0]) / (b[0] - a[0])] : // left
|
null;
|
}
|
|
// bit code reflects the point position relative to the bbox:
|
|
// left mid right
|
// top 1001 1000 1010
|
// mid 0001 0000 0010
|
// bottom 0101 0100 0110
|
|
function bitCode(p, bbox) {
|
var code = 0;
|
|
if (p[0] < bbox[0]) code |= 1; // left
|
else if (p[0] > bbox[2]) code |= 2; // right
|
|
if (p[1] < bbox[1]) code |= 4; // bottom
|
else if (p[1] > bbox[3]) code |= 8; // top
|
|
return code;
|
}
|
|
},{}],3:[function(require,module,exports){
|
"use strict";
|
Object.defineProperty(exports, "__esModule", { value: true });
|
var helpers_1 = require("@turf/helpers");
|
/**
|
* Takes a bbox and returns an equivalent {@link Polygon|polygon}.
|
*
|
* @name bboxPolygon
|
* @param {BBox} bbox extent in [minX, minY, maxX, maxY] order
|
* @param {Object} [options={}] Optional parameters
|
* @param {Properties} [options.properties={}] Translate properties to Polygon
|
* @param {string|number} [options.id={}] Translate Id to Polygon
|
* @returns {Feature<Polygon>} a Polygon representation of the bounding box
|
* @example
|
* var bbox = [0, 0, 10, 10];
|
*
|
* var poly = turf.bboxPolygon(bbox);
|
*
|
* //addToMap
|
* var addToMap = [poly]
|
*/
|
function bboxPolygon(bbox, options) {
|
if (options === void 0) { options = {}; }
|
// Convert BBox positions to Numbers
|
// No performance loss for including Number()
|
// https://github.com/Turfjs/turf/issues/1119
|
var west = Number(bbox[0]);
|
var south = Number(bbox[1]);
|
var east = Number(bbox[2]);
|
var north = Number(bbox[3]);
|
if (bbox.length === 6) {
|
throw new Error("@turf/bbox-polygon does not support BBox with 6 positions");
|
}
|
var lowLeft = [west, south];
|
var topLeft = [west, north];
|
var topRight = [east, north];
|
var lowRight = [east, south];
|
return helpers_1.polygon([[
|
lowLeft,
|
lowRight,
|
topRight,
|
topLeft,
|
lowLeft,
|
]], options.properties, { bbox: bbox, id: options.id });
|
}
|
exports.default = bboxPolygon;
|
|
},{"@turf/helpers":14}],4:[function(require,module,exports){
|
"use strict";
|
Object.defineProperty(exports, "__esModule", { value: true });
|
var meta_1 = require("@turf/meta");
|
/**
|
* Takes a set of features, calculates the bbox of all input features, and returns a bounding box.
|
*
|
* @name bbox
|
* @param {GeoJSON} geojson any GeoJSON object
|
* @returns {BBox} bbox extent in [minX, minY, maxX, maxY] order
|
* @example
|
* var line = turf.lineString([[-74, 40], [-78, 42], [-82, 35]]);
|
* var bbox = turf.bbox(line);
|
* var bboxPolygon = turf.bboxPolygon(bbox);
|
*
|
* //addToMap
|
* var addToMap = [line, bboxPolygon]
|
*/
|
function bbox(geojson) {
|
var result = [Infinity, Infinity, -Infinity, -Infinity];
|
meta_1.coordEach(geojson, function (coord) {
|
if (result[0] > coord[0]) {
|
result[0] = coord[0];
|
}
|
if (result[1] > coord[1]) {
|
result[1] = coord[1];
|
}
|
if (result[2] < coord[0]) {
|
result[2] = coord[0];
|
}
|
if (result[3] < coord[1]) {
|
result[3] = coord[1];
|
}
|
});
|
return result;
|
}
|
exports.default = bbox;
|
|
},{"@turf/meta":18}],5:[function(require,module,exports){
|
"use strict";
|
Object.defineProperty(exports, "__esModule", { value: true });
|
var invariant_1 = require("@turf/invariant");
|
// http://en.wikipedia.org/wiki/Even%E2%80%93odd_rule
|
// modified from: https://github.com/substack/point-in-polygon/blob/master/index.js
|
// which was modified from http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
|
/**
|
* Takes a {@link Point} and a {@link Polygon} or {@link MultiPolygon} and determines if the point
|
* resides inside the polygon. The polygon can be convex or concave. The function accounts for holes.
|
*
|
* @name booleanPointInPolygon
|
* @param {Coord} point input point
|
* @param {Feature<Polygon|MultiPolygon>} polygon input polygon or multipolygon
|
* @param {Object} [options={}] Optional parameters
|
* @param {boolean} [options.ignoreBoundary=false] True if polygon boundary should be ignored when determining if
|
* the point is inside the polygon otherwise false.
|
* @returns {boolean} `true` if the Point is inside the Polygon; `false` if the Point is not inside the Polygon
|
* @example
|
* var pt = turf.point([-77, 44]);
|
* var poly = turf.polygon([[
|
* [-81, 41],
|
* [-81, 47],
|
* [-72, 47],
|
* [-72, 41],
|
* [-81, 41]
|
* ]]);
|
*
|
* turf.booleanPointInPolygon(pt, poly);
|
* //= true
|
*/
|
function booleanPointInPolygon(point, polygon, options) {
|
if (options === void 0) { options = {}; }
|
// validation
|
if (!point) {
|
throw new Error("point is required");
|
}
|
if (!polygon) {
|
throw new Error("polygon is required");
|
}
|
var pt = invariant_1.getCoord(point);
|
var geom = invariant_1.getGeom(polygon);
|
var type = geom.type;
|
var bbox = polygon.bbox;
|
var polys = geom.coordinates;
|
// Quick elimination if point is not inside bbox
|
if (bbox && inBBox(pt, bbox) === false) {
|
return false;
|
}
|
// normalize to multipolygon
|
if (type === "Polygon") {
|
polys = [polys];
|
}
|
var insidePoly = false;
|
for (var i = 0; i < polys.length && !insidePoly; i++) {
|
// check if it is in the outer ring first
|
if (inRing(pt, polys[i][0], options.ignoreBoundary)) {
|
var inHole = false;
|
var k = 1;
|
// check for the point in any of the holes
|
while (k < polys[i].length && !inHole) {
|
if (inRing(pt, polys[i][k], !options.ignoreBoundary)) {
|
inHole = true;
|
}
|
k++;
|
}
|
if (!inHole) {
|
insidePoly = true;
|
}
|
}
|
}
|
return insidePoly;
|
}
|
exports.default = booleanPointInPolygon;
|
/**
|
* inRing
|
*
|
* @private
|
* @param {Array<number>} pt [x,y]
|
* @param {Array<Array<number>>} ring [[x,y], [x,y],..]
|
* @param {boolean} ignoreBoundary ignoreBoundary
|
* @returns {boolean} inRing
|
*/
|
function inRing(pt, ring, ignoreBoundary) {
|
var isInside = false;
|
if (ring[0][0] === ring[ring.length - 1][0] && ring[0][1] === ring[ring.length - 1][1]) {
|
ring = ring.slice(0, ring.length - 1);
|
}
|
for (var i = 0, j = ring.length - 1; i < ring.length; j = i++) {
|
var xi = ring[i][0];
|
var yi = ring[i][1];
|
var xj = ring[j][0];
|
var yj = ring[j][1];
|
var onBoundary = (pt[1] * (xi - xj) + yi * (xj - pt[0]) + yj * (pt[0] - xi) === 0) &&
|
((xi - pt[0]) * (xj - pt[0]) <= 0) && ((yi - pt[1]) * (yj - pt[1]) <= 0);
|
if (onBoundary) {
|
return !ignoreBoundary;
|
}
|
var intersect = ((yi > pt[1]) !== (yj > pt[1])) &&
|
(pt[0] < (xj - xi) * (pt[1] - yi) / (yj - yi) + xi);
|
if (intersect) {
|
isInside = !isInside;
|
}
|
}
|
return isInside;
|
}
|
/**
|
* inBBox
|
*
|
* @private
|
* @param {Position} pt point [x,y]
|
* @param {BBox} bbox BBox [west, south, east, north]
|
* @returns {boolean} true/false if point is inside BBox
|
*/
|
function inBBox(pt, bbox) {
|
return bbox[0] <= pt[0] &&
|
bbox[1] <= pt[1] &&
|
bbox[2] >= pt[0] &&
|
bbox[3] >= pt[1];
|
}
|
|
},{"@turf/invariant":17}],6:[function(require,module,exports){
|
"use strict";
|
Object.defineProperty(exports, "__esModule", { value: true });
|
var convex_1 = require("@turf/convex");
|
var centroid_1 = require("@turf/centroid");
|
var helpers_1 = require("@turf/helpers");
|
var invariant_1 = require("@turf/invariant");
|
var meta_1 = require("@turf/meta");
|
/**
|
* Takes any {@link Feature} or a {@link FeatureCollection} and returns its [center of mass](https://en.wikipedia.org/wiki/Center_of_mass) using this formula: [Centroid of Polygon](https://en.wikipedia.org/wiki/Centroid#Centroid_of_polygon).
|
*
|
* @name centerOfMass
|
* @param {GeoJSON} geojson GeoJSON to be centered
|
* @param {Object} [options={}] Optional Parameters
|
* @param {Object} [options.properties={}] Translate Properties to Feature
|
* @returns {Feature<Point>} the center of mass
|
* @example
|
* var polygon = turf.polygon([[[-81, 41], [-88, 36], [-84, 31], [-80, 33], [-77, 39], [-81, 41]]]);
|
*
|
* var center = turf.centerOfMass(polygon);
|
*
|
* //addToMap
|
* var addToMap = [polygon, center]
|
*/
|
function centerOfMass(geojson, options) {
|
if (options === void 0) { options = {}; }
|
switch (invariant_1.getType(geojson)) {
|
case 'Point':
|
return geojson;
|
case 'Polygon':
|
var coords = [];
|
meta_1.coordEach(geojson, function (coord) {
|
coords.push(coord);
|
});
|
// First, we neutralize the feature (set it around coordinates [0,0]) to prevent rounding errors
|
// We take any point to translate all the points around 0
|
var centre = centroid_1.default(geojson, { properties: options.properties });
|
var translation = centre.geometry.coordinates;
|
var sx = 0;
|
var sy = 0;
|
var sArea = 0;
|
var i, pi, pj, xi, xj, yi, yj, a;
|
var neutralizedPoints = coords.map(function (point) {
|
return [
|
point[0] - translation[0],
|
point[1] - translation[1]
|
];
|
});
|
for (i = 0; i < coords.length - 1; i++) {
|
// pi is the current point
|
pi = neutralizedPoints[i];
|
xi = pi[0];
|
yi = pi[1];
|
// pj is the next point (pi+1)
|
pj = neutralizedPoints[i + 1];
|
xj = pj[0];
|
yj = pj[1];
|
// a is the common factor to compute the signed area and the final coordinates
|
a = xi * yj - xj * yi;
|
// sArea is the sum used to compute the signed area
|
sArea += a;
|
// sx and sy are the sums used to compute the final coordinates
|
sx += (xi + xj) * a;
|
sy += (yi + yj) * a;
|
}
|
// Shape has no area: fallback on turf.centroid
|
if (sArea === 0) {
|
return centre;
|
}
|
else {
|
// Compute the signed area, and factorize 1/6A
|
var area = sArea * 0.5;
|
var areaFactor = 1 / (6 * area);
|
// Compute the final coordinates, adding back the values that have been neutralized
|
return helpers_1.point([
|
translation[0] + areaFactor * sx,
|
translation[1] + areaFactor * sy
|
], options.properties);
|
}
|
default:
|
// Not a polygon: Compute the convex hull and work with that
|
var hull = convex_1.default(geojson);
|
if (hull)
|
return centerOfMass(hull, { properties: options.properties });
|
else
|
return centroid_1.default(geojson, { properties: options.properties });
|
}
|
}
|
exports.default = centerOfMass;
|
|
},{"@turf/centroid":8,"@turf/convex":12,"@turf/helpers":14,"@turf/invariant":17,"@turf/meta":18}],7:[function(require,module,exports){
|
"use strict";
|
Object.defineProperty(exports, "__esModule", { value: true });
|
var bbox_1 = require("@turf/bbox");
|
var helpers_1 = require("@turf/helpers");
|
/**
|
* Takes a {@link Feature} or {@link FeatureCollection} and returns the absolute center point of all features.
|
*
|
* @name center
|
* @param {GeoJSON} geojson GeoJSON to be centered
|
* @param {Object} [options={}] Optional parameters
|
* @param {Object} [options.properties={}] Translate GeoJSON Properties to Point
|
* @param {Object} [options.bbox={}] Translate GeoJSON BBox to Point
|
* @param {Object} [options.id={}] Translate GeoJSON Id to Point
|
* @returns {Feature<Point>} a Point feature at the absolute center point of all input features
|
* @example
|
* var features = turf.points([
|
* [-97.522259, 35.4691],
|
* [-97.502754, 35.463455],
|
* [-97.508269, 35.463245]
|
* ]);
|
*
|
* var center = turf.center(features);
|
*
|
* //addToMap
|
* var addToMap = [features, center]
|
* center.properties['marker-size'] = 'large';
|
* center.properties['marker-color'] = '#000';
|
*/
|
function center(geojson, options) {
|
if (options === void 0) { options = {}; }
|
var ext = bbox_1.default(geojson);
|
var x = (ext[0] + ext[2]) / 2;
|
var y = (ext[1] + ext[3]) / 2;
|
return helpers_1.point([x, y], options.properties, options);
|
}
|
exports.default = center;
|
|
},{"@turf/bbox":4,"@turf/helpers":14}],8:[function(require,module,exports){
|
"use strict";
|
Object.defineProperty(exports, "__esModule", { value: true });
|
var meta_1 = require("@turf/meta");
|
var helpers_1 = require("@turf/helpers");
|
/**
|
* Takes one or more features and calculates the centroid using the mean of all vertices.
|
* This lessens the effect of small islands and artifacts when calculating the centroid of a set of polygons.
|
*
|
* @name centroid
|
* @param {GeoJSON} geojson GeoJSON to be centered
|
* @param {Object} [options={}] Optional Parameters
|
* @param {Object} [options.properties={}] an Object that is used as the {@link Feature}'s properties
|
* @returns {Feature<Point>} the centroid of the input features
|
* @example
|
* var polygon = turf.polygon([[[-81, 41], [-88, 36], [-84, 31], [-80, 33], [-77, 39], [-81, 41]]]);
|
*
|
* var centroid = turf.centroid(polygon);
|
*
|
* //addToMap
|
* var addToMap = [polygon, centroid]
|
*/
|
function centroid(geojson, options) {
|
if (options === void 0) { options = {}; }
|
var xSum = 0;
|
var ySum = 0;
|
var len = 0;
|
meta_1.coordEach(geojson, function (coord) {
|
xSum += coord[0];
|
ySum += coord[1];
|
len++;
|
});
|
return helpers_1.point([xSum / len, ySum / len], options.properties);
|
}
|
exports.default = centroid;
|
|
},{"@turf/helpers":14,"@turf/meta":18}],9:[function(require,module,exports){
|
'use strict';
|
|
var helpers = require('@turf/helpers');
|
var invariant = require('@turf/invariant');
|
|
/**
|
* Removes redundant coordinates from any GeoJSON Geometry.
|
*
|
* @name cleanCoords
|
* @param {Geometry|Feature} geojson Feature or Geometry
|
* @param {Object} [options={}] Optional parameters
|
* @param {boolean} [options.mutate=false] allows GeoJSON input to be mutated
|
* @returns {Geometry|Feature} the cleaned input Feature/Geometry
|
* @example
|
* var line = turf.lineString([[0, 0], [0, 2], [0, 5], [0, 8], [0, 8], [0, 10]]);
|
* var multiPoint = turf.multiPoint([[0, 0], [0, 0], [2, 2]]);
|
*
|
* turf.cleanCoords(line).geometry.coordinates;
|
* //= [[0, 0], [0, 10]]
|
*
|
* turf.cleanCoords(multiPoint).geometry.coordinates;
|
* //= [[0, 0], [2, 2]]
|
*/
|
function cleanCoords(geojson, options) {
|
// Backwards compatible with v4.0
|
var mutate = (typeof options === 'object') ? options.mutate : options;
|
if (!geojson) throw new Error('geojson is required');
|
var type = invariant.getType(geojson);
|
|
// Store new "clean" points in this Array
|
var newCoords = [];
|
|
switch (type) {
|
case 'LineString':
|
newCoords = cleanLine(geojson);
|
break;
|
case 'MultiLineString':
|
case 'Polygon':
|
invariant.getCoords(geojson).forEach(function (line) {
|
newCoords.push(cleanLine(line));
|
});
|
break;
|
case 'MultiPolygon':
|
invariant.getCoords(geojson).forEach(function (polygons) {
|
var polyPoints = [];
|
polygons.forEach(function (ring) {
|
polyPoints.push(cleanLine(ring));
|
});
|
newCoords.push(polyPoints);
|
});
|
break;
|
case 'Point':
|
return geojson;
|
case 'MultiPoint':
|
var existing = {};
|
invariant.getCoords(geojson).forEach(function (coord) {
|
var key = coord.join('-');
|
if (!existing.hasOwnProperty(key)) {
|
newCoords.push(coord);
|
existing[key] = true;
|
}
|
});
|
break;
|
default:
|
throw new Error(type + ' geometry not supported');
|
}
|
|
// Support input mutation
|
if (geojson.coordinates) {
|
if (mutate === true) {
|
geojson.coordinates = newCoords;
|
return geojson;
|
}
|
return {type: type, coordinates: newCoords};
|
} else {
|
if (mutate === true) {
|
geojson.geometry.coordinates = newCoords;
|
return geojson;
|
}
|
return helpers.feature({type: type, coordinates: newCoords}, geojson.properties, geojson.bbox, geojson.id);
|
}
|
}
|
|
/**
|
* Clean Coords
|
*
|
* @private
|
* @param {Array<number>|LineString} line Line
|
* @returns {Array<number>} Cleaned coordinates
|
*/
|
function cleanLine(line) {
|
var points = invariant.getCoords(line);
|
// handle "clean" segment
|
if (points.length === 2 && !equals(points[0], points[1])) return points;
|
|
var prevPoint, point, nextPoint;
|
var newPoints = [];
|
var secondToLast = points.length - 1;
|
|
newPoints.push(points[0]);
|
for (var i = 1; i < secondToLast; i++) {
|
prevPoint = points[i - 1];
|
point = points[i];
|
nextPoint = points[i + 1];
|
|
if (!isPointOnLineSegment(prevPoint, nextPoint, point)) {
|
newPoints.push(point);
|
}
|
}
|
newPoints.push(nextPoint);
|
return newPoints;
|
}
|
|
/**
|
* Compares two points and returns if they are equals
|
*
|
* @private
|
* @param {Position} pt1 point
|
* @param {Position} pt2 point
|
* @returns {boolean} true if they are equals
|
*/
|
function equals(pt1, pt2) {
|
return pt1[0] === pt2[0] && pt1[1] === pt2[1];
|
}
|
|
/**
|
* Returns if `point` is on the segment between `start` and `end`.
|
* Borrowed from `@turf/boolean-point-on-line` to speed up the evaluation (instead of using the module as dependency)
|
*
|
* @private
|
* @param {Position} start coord pair of start of line
|
* @param {Position} end coord pair of end of line
|
* @param {Position} point coord pair of point to check
|
* @returns {boolean} true/false
|
*/
|
function isPointOnLineSegment(start, end, point) {
|
var x = point[0], y = point[1];
|
var startX = start[0], startY = start[1];
|
var endX = end[0], endY = end[1];
|
|
var dxc = x - startX;
|
var dyc = y - startY;
|
var dxl = endX - startX;
|
var dyl = endY - startY;
|
var cross = dxc * dyl - dyc * dxl;
|
|
if (cross !== 0) return false;
|
else if (Math.abs(dxl) >= Math.abs(dyl)) return dxl > 0 ? startX <= x && x <= endX : endX <= x && x <= startX;
|
else return dyl > 0 ? startY <= y && y <= endY : endY <= y && y <= startY;
|
}
|
|
module.exports = cleanCoords;
|
module.exports.default = cleanCoords;
|
|
},{"@turf/helpers":10,"@turf/invariant":11}],10:[function(require,module,exports){
|
'use strict';
|
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
/**
|
* Earth Radius used with the Harvesine formula and approximates using a spherical (non-ellipsoid) Earth.
|
*/
|
var earthRadius = 6371008.8;
|
|
/**
|
* Unit of measurement factors using a spherical (non-ellipsoid) earth radius.
|
*/
|
var factors = {
|
meters: earthRadius,
|
metres: earthRadius,
|
millimeters: earthRadius * 1000,
|
millimetres: earthRadius * 1000,
|
centimeters: earthRadius * 100,
|
centimetres: earthRadius * 100,
|
kilometers: earthRadius / 1000,
|
kilometres: earthRadius / 1000,
|
miles: earthRadius / 1609.344,
|
nauticalmiles: earthRadius / 1852,
|
inches: earthRadius * 39.370,
|
yards: earthRadius / 1.0936,
|
feet: earthRadius * 3.28084,
|
radians: 1,
|
degrees: earthRadius / 111325,
|
};
|
|
/**
|
* Units of measurement factors based on 1 meter.
|
*/
|
var unitsFactors = {
|
meters: 1,
|
metres: 1,
|
millimeters: 1000,
|
millimetres: 1000,
|
centimeters: 100,
|
centimetres: 100,
|
kilometers: 1 / 1000,
|
kilometres: 1 / 1000,
|
miles: 1 / 1609.344,
|
nauticalmiles: 1 / 1852,
|
inches: 39.370,
|
yards: 1 / 1.0936,
|
feet: 3.28084,
|
radians: 1 / earthRadius,
|
degrees: 1 / 111325,
|
};
|
|
/**
|
* Area of measurement factors based on 1 square meter.
|
*/
|
var areaFactors = {
|
meters: 1,
|
metres: 1,
|
millimeters: 1000000,
|
millimetres: 1000000,
|
centimeters: 10000,
|
centimetres: 10000,
|
kilometers: 0.000001,
|
kilometres: 0.000001,
|
acres: 0.000247105,
|
miles: 3.86e-7,
|
yards: 1.195990046,
|
feet: 10.763910417,
|
inches: 1550.003100006
|
};
|
|
/**
|
* Wraps a GeoJSON {@link Geometry} in a GeoJSON {@link Feature}.
|
*
|
* @name feature
|
* @param {Geometry} geometry input geometry
|
* @param {Object} [properties={}] an Object of key-value pairs to add as properties
|
* @param {Object} [options={}] Optional Parameters
|
* @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
|
* @param {string|number} [options.id] Identifier associated with the Feature
|
* @returns {Feature} a GeoJSON Feature
|
* @example
|
* var geometry = {
|
* "type": "Point",
|
* "coordinates": [110, 50]
|
* };
|
*
|
* var feature = turf.feature(geometry);
|
*
|
* //=feature
|
*/
|
function feature(geometry, properties, options) {
|
// Optional Parameters
|
options = options || {};
|
if (!isObject(options)) throw new Error('options is invalid');
|
var bbox = options.bbox;
|
var id = options.id;
|
|
// Validation
|
if (geometry === undefined) throw new Error('geometry is required');
|
if (properties && properties.constructor !== Object) throw new Error('properties must be an Object');
|
if (bbox) validateBBox(bbox);
|
if (id) validateId(id);
|
|
// Main
|
var feat = {type: 'Feature'};
|
if (id) feat.id = id;
|
if (bbox) feat.bbox = bbox;
|
feat.properties = properties || {};
|
feat.geometry = geometry;
|
return feat;
|
}
|
|
/**
|
* Creates a GeoJSON {@link Geometry} from a Geometry string type & coordinates.
|
* For GeometryCollection type use `helpers.geometryCollection`
|
*
|
* @name geometry
|
* @param {string} type Geometry Type
|
* @param {Array<number>} coordinates Coordinates
|
* @param {Object} [options={}] Optional Parameters
|
* @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Geometry
|
* @returns {Geometry} a GeoJSON Geometry
|
* @example
|
* var type = 'Point';
|
* var coordinates = [110, 50];
|
*
|
* var geometry = turf.geometry(type, coordinates);
|
*
|
* //=geometry
|
*/
|
function geometry(type, coordinates, options) {
|
// Optional Parameters
|
options = options || {};
|
if (!isObject(options)) throw new Error('options is invalid');
|
var bbox = options.bbox;
|
|
// Validation
|
if (!type) throw new Error('type is required');
|
if (!coordinates) throw new Error('coordinates is required');
|
if (!Array.isArray(coordinates)) throw new Error('coordinates must be an Array');
|
if (bbox) validateBBox(bbox);
|
|
// Main
|
var geom;
|
switch (type) {
|
case 'Point': geom = point(coordinates).geometry; break;
|
case 'LineString': geom = lineString(coordinates).geometry; break;
|
case 'Polygon': geom = polygon(coordinates).geometry; break;
|
case 'MultiPoint': geom = multiPoint(coordinates).geometry; break;
|
case 'MultiLineString': geom = multiLineString(coordinates).geometry; break;
|
case 'MultiPolygon': geom = multiPolygon(coordinates).geometry; break;
|
default: throw new Error(type + ' is invalid');
|
}
|
if (bbox) geom.bbox = bbox;
|
return geom;
|
}
|
|
/**
|
* Creates a {@link Point} {@link Feature} from a Position.
|
*
|
* @name point
|
* @param {Array<number>} coordinates longitude, latitude position (each in decimal degrees)
|
* @param {Object} [properties={}] an Object of key-value pairs to add as properties
|
* @param {Object} [options={}] Optional Parameters
|
* @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
|
* @param {string|number} [options.id] Identifier associated with the Feature
|
* @returns {Feature<Point>} a Point feature
|
* @example
|
* var point = turf.point([-75.343, 39.984]);
|
*
|
* //=point
|
*/
|
function point(coordinates, properties, options) {
|
if (!coordinates) throw new Error('coordinates is required');
|
if (!Array.isArray(coordinates)) throw new Error('coordinates must be an Array');
|
if (coordinates.length < 2) throw new Error('coordinates must be at least 2 numbers long');
|
if (!isNumber(coordinates[0]) || !isNumber(coordinates[1])) throw new Error('coordinates must contain numbers');
|
|
return feature({
|
type: 'Point',
|
coordinates: coordinates
|
}, properties, options);
|
}
|
|
/**
|
* Creates a {@link Point} {@link FeatureCollection} from an Array of Point coordinates.
|
*
|
* @name points
|
* @param {Array<Array<number>>} coordinates an array of Points
|
* @param {Object} [properties={}] Translate these properties to each Feature
|
* @param {Object} [options={}] Optional Parameters
|
* @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the FeatureCollection
|
* @param {string|number} [options.id] Identifier associated with the FeatureCollection
|
* @returns {FeatureCollection<Point>} Point Feature
|
* @example
|
* var points = turf.points([
|
* [-75, 39],
|
* [-80, 45],
|
* [-78, 50]
|
* ]);
|
*
|
* //=points
|
*/
|
function points(coordinates, properties, options) {
|
if (!coordinates) throw new Error('coordinates is required');
|
if (!Array.isArray(coordinates)) throw new Error('coordinates must be an Array');
|
|
return featureCollection(coordinates.map(function (coords) {
|
return point(coords, properties);
|
}), options);
|
}
|
|
/**
|
* Creates a {@link Polygon} {@link Feature} from an Array of LinearRings.
|
*
|
* @name polygon
|
* @param {Array<Array<Array<number>>>} coordinates an array of LinearRings
|
* @param {Object} [properties={}] an Object of key-value pairs to add as properties
|
* @param {Object} [options={}] Optional Parameters
|
* @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
|
* @param {string|number} [options.id] Identifier associated with the Feature
|
* @returns {Feature<Polygon>} Polygon Feature
|
* @example
|
* var polygon = turf.polygon([[[-5, 52], [-4, 56], [-2, 51], [-7, 54], [-5, 52]]], { name: 'poly1' });
|
*
|
* //=polygon
|
*/
|
function polygon(coordinates, properties, options) {
|
if (!coordinates) throw new Error('coordinates is required');
|
|
for (var i = 0; i < coordinates.length; i++) {
|
var ring = coordinates[i];
|
if (ring.length < 4) {
|
throw new Error('Each LinearRing of a Polygon must have 4 or more Positions.');
|
}
|
for (var j = 0; j < ring[ring.length - 1].length; j++) {
|
// Check if first point of Polygon contains two numbers
|
if (i === 0 && j === 0 && !isNumber(ring[0][0]) || !isNumber(ring[0][1])) throw new Error('coordinates must contain numbers');
|
if (ring[ring.length - 1][j] !== ring[0][j]) {
|
throw new Error('First and last Position are not equivalent.');
|
}
|
}
|
}
|
|
return feature({
|
type: 'Polygon',
|
coordinates: coordinates
|
}, properties, options);
|
}
|
|
/**
|
* Creates a {@link Polygon} {@link FeatureCollection} from an Array of Polygon coordinates.
|
*
|
* @name polygons
|
* @param {Array<Array<Array<Array<number>>>>} coordinates an array of Polygon coordinates
|
* @param {Object} [properties={}] an Object of key-value pairs to add as properties
|
* @param {Object} [options={}] Optional Parameters
|
* @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
|
* @param {string|number} [options.id] Identifier associated with the FeatureCollection
|
* @returns {FeatureCollection<Polygon>} Polygon FeatureCollection
|
* @example
|
* var polygons = turf.polygons([
|
* [[[-5, 52], [-4, 56], [-2, 51], [-7, 54], [-5, 52]]],
|
* [[[-15, 42], [-14, 46], [-12, 41], [-17, 44], [-15, 42]]],
|
* ]);
|
*
|
* //=polygons
|
*/
|
function polygons(coordinates, properties, options) {
|
if (!coordinates) throw new Error('coordinates is required');
|
if (!Array.isArray(coordinates)) throw new Error('coordinates must be an Array');
|
|
return featureCollection(coordinates.map(function (coords) {
|
return polygon(coords, properties);
|
}), options);
|
}
|
|
/**
|
* Creates a {@link LineString} {@link Feature} from an Array of Positions.
|
*
|
* @name lineString
|
* @param {Array<Array<number>>} coordinates an array of Positions
|
* @param {Object} [properties={}] an Object of key-value pairs to add as properties
|
* @param {Object} [options={}] Optional Parameters
|
* @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
|
* @param {string|number} [options.id] Identifier associated with the Feature
|
* @returns {Feature<LineString>} LineString Feature
|
* @example
|
* var linestring1 = turf.lineString([[-24, 63], [-23, 60], [-25, 65], [-20, 69]], {name: 'line 1'});
|
* var linestring2 = turf.lineString([[-14, 43], [-13, 40], [-15, 45], [-10, 49]], {name: 'line 2'});
|
*
|
* //=linestring1
|
* //=linestring2
|
*/
|
function lineString(coordinates, properties, options) {
|
if (!coordinates) throw new Error('coordinates is required');
|
if (coordinates.length < 2) throw new Error('coordinates must be an array of two or more positions');
|
// Check if first point of LineString contains two numbers
|
if (!isNumber(coordinates[0][1]) || !isNumber(coordinates[0][1])) throw new Error('coordinates must contain numbers');
|
|
return feature({
|
type: 'LineString',
|
coordinates: coordinates
|
}, properties, options);
|
}
|
|
/**
|
* Creates a {@link LineString} {@link FeatureCollection} from an Array of LineString coordinates.
|
*
|
* @name lineStrings
|
* @param {Array<Array<number>>} coordinates an array of LinearRings
|
* @param {Object} [properties={}] an Object of key-value pairs to add as properties
|
* @param {Object} [options={}] Optional Parameters
|
* @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the FeatureCollection
|
* @param {string|number} [options.id] Identifier associated with the FeatureCollection
|
* @returns {FeatureCollection<LineString>} LineString FeatureCollection
|
* @example
|
* var linestrings = turf.lineStrings([
|
* [[-24, 63], [-23, 60], [-25, 65], [-20, 69]],
|
* [[-14, 43], [-13, 40], [-15, 45], [-10, 49]]
|
* ]);
|
*
|
* //=linestrings
|
*/
|
function lineStrings(coordinates, properties, options) {
|
if (!coordinates) throw new Error('coordinates is required');
|
if (!Array.isArray(coordinates)) throw new Error('coordinates must be an Array');
|
|
return featureCollection(coordinates.map(function (coords) {
|
return lineString(coords, properties);
|
}), options);
|
}
|
|
/**
|
* Takes one or more {@link Feature|Features} and creates a {@link FeatureCollection}.
|
*
|
* @name featureCollection
|
* @param {Feature[]} features input features
|
* @param {Object} [options={}] Optional Parameters
|
* @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
|
* @param {string|number} [options.id] Identifier associated with the Feature
|
* @returns {FeatureCollection} FeatureCollection of Features
|
* @example
|
* var locationA = turf.point([-75.343, 39.984], {name: 'Location A'});
|
* var locationB = turf.point([-75.833, 39.284], {name: 'Location B'});
|
* var locationC = turf.point([-75.534, 39.123], {name: 'Location C'});
|
*
|
* var collection = turf.featureCollection([
|
* locationA,
|
* locationB,
|
* locationC
|
* ]);
|
*
|
* //=collection
|
*/
|
function featureCollection(features, options) {
|
// Optional Parameters
|
options = options || {};
|
if (!isObject(options)) throw new Error('options is invalid');
|
var bbox = options.bbox;
|
var id = options.id;
|
|
// Validation
|
if (!features) throw new Error('No features passed');
|
if (!Array.isArray(features)) throw new Error('features must be an Array');
|
if (bbox) validateBBox(bbox);
|
if (id) validateId(id);
|
|
// Main
|
var fc = {type: 'FeatureCollection'};
|
if (id) fc.id = id;
|
if (bbox) fc.bbox = bbox;
|
fc.features = features;
|
return fc;
|
}
|
|
/**
|
* Creates a {@link Feature<MultiLineString>} based on a
|
* coordinate array. Properties can be added optionally.
|
*
|
* @name multiLineString
|
* @param {Array<Array<Array<number>>>} coordinates an array of LineStrings
|
* @param {Object} [properties={}] an Object of key-value pairs to add as properties
|
* @param {Object} [options={}] Optional Parameters
|
* @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
|
* @param {string|number} [options.id] Identifier associated with the Feature
|
* @returns {Feature<MultiLineString>} a MultiLineString feature
|
* @throws {Error} if no coordinates are passed
|
* @example
|
* var multiLine = turf.multiLineString([[[0,0],[10,10]]]);
|
*
|
* //=multiLine
|
*/
|
function multiLineString(coordinates, properties, options) {
|
if (!coordinates) throw new Error('coordinates is required');
|
|
return feature({
|
type: 'MultiLineString',
|
coordinates: coordinates
|
}, properties, options);
|
}
|
|
/**
|
* Creates a {@link Feature<MultiPoint>} based on a
|
* coordinate array. Properties can be added optionally.
|
*
|
* @name multiPoint
|
* @param {Array<Array<number>>} coordinates an array of Positions
|
* @param {Object} [properties={}] an Object of key-value pairs to add as properties
|
* @param {Object} [options={}] Optional Parameters
|
* @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
|
* @param {string|number} [options.id] Identifier associated with the Feature
|
* @returns {Feature<MultiPoint>} a MultiPoint feature
|
* @throws {Error} if no coordinates are passed
|
* @example
|
* var multiPt = turf.multiPoint([[0,0],[10,10]]);
|
*
|
* //=multiPt
|
*/
|
function multiPoint(coordinates, properties, options) {
|
if (!coordinates) throw new Error('coordinates is required');
|
|
return feature({
|
type: 'MultiPoint',
|
coordinates: coordinates
|
}, properties, options);
|
}
|
|
/**
|
* Creates a {@link Feature<MultiPolygon>} based on a
|
* coordinate array. Properties can be added optionally.
|
*
|
* @name multiPolygon
|
* @param {Array<Array<Array<Array<number>>>>} coordinates an array of Polygons
|
* @param {Object} [properties={}] an Object of key-value pairs to add as properties
|
* @param {Object} [options={}] Optional Parameters
|
* @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
|
* @param {string|number} [options.id] Identifier associated with the Feature
|
* @returns {Feature<MultiPolygon>} a multipolygon feature
|
* @throws {Error} if no coordinates are passed
|
* @example
|
* var multiPoly = turf.multiPolygon([[[[0,0],[0,10],[10,10],[10,0],[0,0]]]]);
|
*
|
* //=multiPoly
|
*
|
*/
|
function multiPolygon(coordinates, properties, options) {
|
if (!coordinates) throw new Error('coordinates is required');
|
|
return feature({
|
type: 'MultiPolygon',
|
coordinates: coordinates
|
}, properties, options);
|
}
|
|
/**
|
* Creates a {@link Feature<GeometryCollection>} based on a
|
* coordinate array. Properties can be added optionally.
|
*
|
* @name geometryCollection
|
* @param {Array<Geometry>} geometries an array of GeoJSON Geometries
|
* @param {Object} [properties={}] an Object of key-value pairs to add as properties
|
* @param {Object} [options={}] Optional Parameters
|
* @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
|
* @param {string|number} [options.id] Identifier associated with the Feature
|
* @returns {Feature<GeometryCollection>} a GeoJSON GeometryCollection Feature
|
* @example
|
* var pt = {
|
* "type": "Point",
|
* "coordinates": [100, 0]
|
* };
|
* var line = {
|
* "type": "LineString",
|
* "coordinates": [ [101, 0], [102, 1] ]
|
* };
|
* var collection = turf.geometryCollection([pt, line]);
|
*
|
* //=collection
|
*/
|
function geometryCollection(geometries, properties, options) {
|
if (!geometries) throw new Error('geometries is required');
|
if (!Array.isArray(geometries)) throw new Error('geometries must be an Array');
|
|
return feature({
|
type: 'GeometryCollection',
|
geometries: geometries
|
}, properties, options);
|
}
|
|
/**
|
* Round number to precision
|
*
|
* @param {number} num Number
|
* @param {number} [precision=0] Precision
|
* @returns {number} rounded number
|
* @example
|
* turf.round(120.4321)
|
* //=120
|
*
|
* turf.round(120.4321, 2)
|
* //=120.43
|
*/
|
function round(num, precision) {
|
if (num === undefined || num === null || isNaN(num)) throw new Error('num is required');
|
if (precision && !(precision >= 0)) throw new Error('precision must be a positive number');
|
var multiplier = Math.pow(10, precision || 0);
|
return Math.round(num * multiplier) / multiplier;
|
}
|
|
/**
|
* Convert a distance measurement (assuming a spherical Earth) from radians to a more friendly unit.
|
* Valid units: miles, nauticalmiles, inches, yards, meters, metres, kilometers, centimeters, feet
|
*
|
* @name radiansToLength
|
* @param {number} radians in radians across the sphere
|
* @param {string} [units='kilometers'] can be degrees, radians, miles, or kilometers inches, yards, metres, meters, kilometres, kilometers.
|
* @returns {number} distance
|
*/
|
function radiansToLength(radians, units) {
|
if (radians === undefined || radians === null) throw new Error('radians is required');
|
|
if (units && typeof units !== 'string') throw new Error('units must be a string');
|
var factor = factors[units || 'kilometers'];
|
if (!factor) throw new Error(units + ' units is invalid');
|
return radians * factor;
|
}
|
|
/**
|
* Convert a distance measurement (assuming a spherical Earth) from a real-world unit into radians
|
* Valid units: miles, nauticalmiles, inches, yards, meters, metres, kilometers, centimeters, feet
|
*
|
* @name lengthToRadians
|
* @param {number} distance in real units
|
* @param {string} [units='kilometers'] can be degrees, radians, miles, or kilometers inches, yards, metres, meters, kilometres, kilometers.
|
* @returns {number} radians
|
*/
|
function lengthToRadians(distance, units) {
|
if (distance === undefined || distance === null) throw new Error('distance is required');
|
|
if (units && typeof units !== 'string') throw new Error('units must be a string');
|
var factor = factors[units || 'kilometers'];
|
if (!factor) throw new Error(units + ' units is invalid');
|
return distance / factor;
|
}
|
|
/**
|
* Convert a distance measurement (assuming a spherical Earth) from a real-world unit into degrees
|
* Valid units: miles, nauticalmiles, inches, yards, meters, metres, centimeters, kilometres, feet
|
*
|
* @name lengthToDegrees
|
* @param {number} distance in real units
|
* @param {string} [units='kilometers'] can be degrees, radians, miles, or kilometers inches, yards, metres, meters, kilometres, kilometers.
|
* @returns {number} degrees
|
*/
|
function lengthToDegrees(distance, units) {
|
return radiansToDegrees(lengthToRadians(distance, units));
|
}
|
|
/**
|
* Converts any bearing angle from the north line direction (positive clockwise)
|
* and returns an angle between 0-360 degrees (positive clockwise), 0 being the north line
|
*
|
* @name bearingToAzimuth
|
* @param {number} bearing angle, between -180 and +180 degrees
|
* @returns {number} angle between 0 and 360 degrees
|
*/
|
function bearingToAzimuth(bearing) {
|
if (bearing === null || bearing === undefined) throw new Error('bearing is required');
|
|
var angle = bearing % 360;
|
if (angle < 0) angle += 360;
|
return angle;
|
}
|
|
/**
|
* Converts an angle in radians to degrees
|
*
|
* @name radiansToDegrees
|
* @param {number} radians angle in radians
|
* @returns {number} degrees between 0 and 360 degrees
|
*/
|
function radiansToDegrees(radians) {
|
if (radians === null || radians === undefined) throw new Error('radians is required');
|
|
var degrees = radians % (2 * Math.PI);
|
return degrees * 180 / Math.PI;
|
}
|
|
/**
|
* Converts an angle in degrees to radians
|
*
|
* @name degreesToRadians
|
* @param {number} degrees angle between 0 and 360 degrees
|
* @returns {number} angle in radians
|
*/
|
function degreesToRadians(degrees) {
|
if (degrees === null || degrees === undefined) throw new Error('degrees is required');
|
|
var radians = degrees % 360;
|
return radians * Math.PI / 180;
|
}
|
|
/**
|
* Converts a length to the requested unit.
|
* Valid units: miles, nauticalmiles, inches, yards, meters, metres, kilometers, centimeters, feet
|
*
|
* @param {number} length to be converted
|
* @param {string} originalUnit of the length
|
* @param {string} [finalUnit='kilometers'] returned unit
|
* @returns {number} the converted length
|
*/
|
function convertLength(length, originalUnit, finalUnit) {
|
if (length === null || length === undefined) throw new Error('length is required');
|
if (!(length >= 0)) throw new Error('length must be a positive number');
|
|
return radiansToLength(lengthToRadians(length, originalUnit), finalUnit || 'kilometers');
|
}
|
|
/**
|
* Converts a area to the requested unit.
|
* Valid units: kilometers, kilometres, meters, metres, centimetres, millimeters, acres, miles, yards, feet, inches
|
* @param {number} area to be converted
|
* @param {string} [originalUnit='meters'] of the distance
|
* @param {string} [finalUnit='kilometers'] returned unit
|
* @returns {number} the converted distance
|
*/
|
function convertArea(area, originalUnit, finalUnit) {
|
if (area === null || area === undefined) throw new Error('area is required');
|
if (!(area >= 0)) throw new Error('area must be a positive number');
|
|
var startFactor = areaFactors[originalUnit || 'meters'];
|
if (!startFactor) throw new Error('invalid original units');
|
|
var finalFactor = areaFactors[finalUnit || 'kilometers'];
|
if (!finalFactor) throw new Error('invalid final units');
|
|
return (area / startFactor) * finalFactor;
|
}
|
|
/**
|
* isNumber
|
*
|
* @param {*} num Number to validate
|
* @returns {boolean} true/false
|
* @example
|
* turf.isNumber(123)
|
* //=true
|
* turf.isNumber('foo')
|
* //=false
|
*/
|
function isNumber(num) {
|
return !isNaN(num) && num !== null && !Array.isArray(num);
|
}
|
|
/**
|
* isObject
|
*
|
* @param {*} input variable to validate
|
* @returns {boolean} true/false
|
* @example
|
* turf.isObject({elevation: 10})
|
* //=true
|
* turf.isObject('foo')
|
* //=false
|
*/
|
function isObject(input) {
|
return (!!input) && (input.constructor === Object);
|
}
|
|
/**
|
* Validate BBox
|
*
|
* @private
|
* @param {Array<number>} bbox BBox to validate
|
* @returns {void}
|
* @throws Error if BBox is not valid
|
* @example
|
* validateBBox([-180, -40, 110, 50])
|
* //=OK
|
* validateBBox([-180, -40])
|
* //=Error
|
* validateBBox('Foo')
|
* //=Error
|
* validateBBox(5)
|
* //=Error
|
* validateBBox(null)
|
* //=Error
|
* validateBBox(undefined)
|
* //=Error
|
*/
|
function validateBBox(bbox) {
|
if (!bbox) throw new Error('bbox is required');
|
if (!Array.isArray(bbox)) throw new Error('bbox must be an Array');
|
if (bbox.length !== 4 && bbox.length !== 6) throw new Error('bbox must be an Array of 4 or 6 numbers');
|
bbox.forEach(function (num) {
|
if (!isNumber(num)) throw new Error('bbox must only contain numbers');
|
});
|
}
|
|
/**
|
* Validate Id
|
*
|
* @private
|
* @param {string|number} id Id to validate
|
* @returns {void}
|
* @throws Error if Id is not valid
|
* @example
|
* validateId([-180, -40, 110, 50])
|
* //=Error
|
* validateId([-180, -40])
|
* //=Error
|
* validateId('Foo')
|
* //=OK
|
* validateId(5)
|
* //=OK
|
* validateId(null)
|
* //=Error
|
* validateId(undefined)
|
* //=Error
|
*/
|
function validateId(id) {
|
if (!id) throw new Error('id is required');
|
if (['string', 'number'].indexOf(typeof id) === -1) throw new Error('id must be a number or a string');
|
}
|
|
// Deprecated methods
|
function radians2degrees() {
|
throw new Error('method has been renamed to `radiansToDegrees`');
|
}
|
|
function degrees2radians() {
|
throw new Error('method has been renamed to `degreesToRadians`');
|
}
|
|
function distanceToDegrees() {
|
throw new Error('method has been renamed to `lengthToDegrees`');
|
}
|
|
function distanceToRadians() {
|
throw new Error('method has been renamed to `lengthToRadians`');
|
}
|
|
function radiansToDistance() {
|
throw new Error('method has been renamed to `radiansToLength`');
|
}
|
|
function bearingToAngle() {
|
throw new Error('method has been renamed to `bearingToAzimuth`');
|
}
|
|
function convertDistance() {
|
throw new Error('method has been renamed to `convertLength`');
|
}
|
|
exports.earthRadius = earthRadius;
|
exports.factors = factors;
|
exports.unitsFactors = unitsFactors;
|
exports.areaFactors = areaFactors;
|
exports.feature = feature;
|
exports.geometry = geometry;
|
exports.point = point;
|
exports.points = points;
|
exports.polygon = polygon;
|
exports.polygons = polygons;
|
exports.lineString = lineString;
|
exports.lineStrings = lineStrings;
|
exports.featureCollection = featureCollection;
|
exports.multiLineString = multiLineString;
|
exports.multiPoint = multiPoint;
|
exports.multiPolygon = multiPolygon;
|
exports.geometryCollection = geometryCollection;
|
exports.round = round;
|
exports.radiansToLength = radiansToLength;
|
exports.lengthToRadians = lengthToRadians;
|
exports.lengthToDegrees = lengthToDegrees;
|
exports.bearingToAzimuth = bearingToAzimuth;
|
exports.radiansToDegrees = radiansToDegrees;
|
exports.degreesToRadians = degreesToRadians;
|
exports.convertLength = convertLength;
|
exports.convertArea = convertArea;
|
exports.isNumber = isNumber;
|
exports.isObject = isObject;
|
exports.validateBBox = validateBBox;
|
exports.validateId = validateId;
|
exports.radians2degrees = radians2degrees;
|
exports.degrees2radians = degrees2radians;
|
exports.distanceToDegrees = distanceToDegrees;
|
exports.distanceToRadians = distanceToRadians;
|
exports.radiansToDistance = radiansToDistance;
|
exports.bearingToAngle = bearingToAngle;
|
exports.convertDistance = convertDistance;
|
|
},{}],11:[function(require,module,exports){
|
'use strict';
|
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
var helpers = require('@turf/helpers');
|
|
/**
|
* Unwrap a coordinate from a Point Feature, Geometry or a single coordinate.
|
*
|
* @name getCoord
|
* @param {Array<number>|Geometry<Point>|Feature<Point>} coord GeoJSON Point or an Array of numbers
|
* @returns {Array<number>} coordinates
|
* @example
|
* var pt = turf.point([10, 10]);
|
*
|
* var coord = turf.getCoord(pt);
|
* //= [10, 10]
|
*/
|
function getCoord(coord) {
|
if (!coord) throw new Error('coord is required');
|
if (coord.type === 'Feature' && coord.geometry !== null && coord.geometry.type === 'Point') return coord.geometry.coordinates;
|
if (coord.type === 'Point') return coord.coordinates;
|
if (Array.isArray(coord) && coord.length >= 2 && coord[0].length === undefined && coord[1].length === undefined) return coord;
|
|
throw new Error('coord must be GeoJSON Point or an Array of numbers');
|
}
|
|
/**
|
* Unwrap coordinates from a Feature, Geometry Object or an Array
|
*
|
* @name getCoords
|
* @param {Array<any>|Geometry|Feature} coords Feature, Geometry Object or an Array
|
* @returns {Array<any>} coordinates
|
* @example
|
* var poly = turf.polygon([[[119.32, -8.7], [119.55, -8.69], [119.51, -8.54], [119.32, -8.7]]]);
|
*
|
* var coords = turf.getCoords(poly);
|
* //= [[[119.32, -8.7], [119.55, -8.69], [119.51, -8.54], [119.32, -8.7]]]
|
*/
|
function getCoords(coords) {
|
if (!coords) throw new Error('coords is required');
|
|
// Feature
|
if (coords.type === 'Feature' && coords.geometry !== null) return coords.geometry.coordinates;
|
|
// Geometry
|
if (coords.coordinates) return coords.coordinates;
|
|
// Array of numbers
|
if (Array.isArray(coords)) return coords;
|
|
throw new Error('coords must be GeoJSON Feature, Geometry Object or an Array');
|
}
|
|
/**
|
* Checks if coordinates contains a number
|
*
|
* @name containsNumber
|
* @param {Array<any>} coordinates GeoJSON Coordinates
|
* @returns {boolean} true if Array contains a number
|
*/
|
function containsNumber(coordinates) {
|
if (coordinates.length > 1 && helpers.isNumber(coordinates[0]) && helpers.isNumber(coordinates[1])) {
|
return true;
|
}
|
|
if (Array.isArray(coordinates[0]) && coordinates[0].length) {
|
return containsNumber(coordinates[0]);
|
}
|
throw new Error('coordinates must only contain numbers');
|
}
|
|
/**
|
* Enforce expectations about types of GeoJSON objects for Turf.
|
*
|
* @name geojsonType
|
* @param {GeoJSON} value any GeoJSON object
|
* @param {string} type expected GeoJSON type
|
* @param {string} name name of calling function
|
* @throws {Error} if value is not the expected type.
|
*/
|
function geojsonType(value, type, name) {
|
if (!type || !name) throw new Error('type and name required');
|
|
if (!value || value.type !== type) {
|
throw new Error('Invalid input to ' + name + ': must be a ' + type + ', given ' + value.type);
|
}
|
}
|
|
/**
|
* Enforce expectations about types of {@link Feature} inputs for Turf.
|
* Internally this uses {@link geojsonType} to judge geometry types.
|
*
|
* @name featureOf
|
* @param {Feature} feature a feature with an expected geometry type
|
* @param {string} type expected GeoJSON type
|
* @param {string} name name of calling function
|
* @throws {Error} error if value is not the expected type.
|
*/
|
function featureOf(feature, type, name) {
|
if (!feature) throw new Error('No feature passed');
|
if (!name) throw new Error('.featureOf() requires a name');
|
if (!feature || feature.type !== 'Feature' || !feature.geometry) {
|
throw new Error('Invalid input to ' + name + ', Feature with geometry required');
|
}
|
if (!feature.geometry || feature.geometry.type !== type) {
|
throw new Error('Invalid input to ' + name + ': must be a ' + type + ', given ' + feature.geometry.type);
|
}
|
}
|
|
/**
|
* Enforce expectations about types of {@link FeatureCollection} inputs for Turf.
|
* Internally this uses {@link geojsonType} to judge geometry types.
|
*
|
* @name collectionOf
|
* @param {FeatureCollection} featureCollection a FeatureCollection for which features will be judged
|
* @param {string} type expected GeoJSON type
|
* @param {string} name name of calling function
|
* @throws {Error} if value is not the expected type.
|
*/
|
function collectionOf(featureCollection, type, name) {
|
if (!featureCollection) throw new Error('No featureCollection passed');
|
if (!name) throw new Error('.collectionOf() requires a name');
|
if (!featureCollection || featureCollection.type !== 'FeatureCollection') {
|
throw new Error('Invalid input to ' + name + ', FeatureCollection required');
|
}
|
for (var i = 0; i < featureCollection.features.length; i++) {
|
var feature = featureCollection.features[i];
|
if (!feature || feature.type !== 'Feature' || !feature.geometry) {
|
throw new Error('Invalid input to ' + name + ', Feature with geometry required');
|
}
|
if (!feature.geometry || feature.geometry.type !== type) {
|
throw new Error('Invalid input to ' + name + ': must be a ' + type + ', given ' + feature.geometry.type);
|
}
|
}
|
}
|
|
/**
|
* Get Geometry from Feature or Geometry Object
|
*
|
* @param {Feature|Geometry} geojson GeoJSON Feature or Geometry Object
|
* @returns {Geometry|null} GeoJSON Geometry Object
|
* @throws {Error} if geojson is not a Feature or Geometry Object
|
* @example
|
* var point = {
|
* "type": "Feature",
|
* "properties": {},
|
* "geometry": {
|
* "type": "Point",
|
* "coordinates": [110, 40]
|
* }
|
* }
|
* var geom = turf.getGeom(point)
|
* //={"type": "Point", "coordinates": [110, 40]}
|
*/
|
function getGeom(geojson) {
|
if (!geojson) throw new Error('geojson is required');
|
if (geojson.geometry !== undefined) return geojson.geometry;
|
if (geojson.coordinates || geojson.geometries) return geojson;
|
throw new Error('geojson must be a valid Feature or Geometry Object');
|
}
|
|
/**
|
* Get Geometry Type from Feature or Geometry Object
|
*
|
* @throws {Error} **DEPRECATED** in v5.0.0 in favor of getType
|
*/
|
function getGeomType() {
|
throw new Error('invariant.getGeomType has been deprecated in v5.0 in favor of invariant.getType');
|
}
|
|
/**
|
* Get GeoJSON object's type, Geometry type is prioritize.
|
*
|
* @param {GeoJSON} geojson GeoJSON object
|
* @param {string} [name="geojson"] name of the variable to display in error message
|
* @returns {string} GeoJSON type
|
* @example
|
* var point = {
|
* "type": "Feature",
|
* "properties": {},
|
* "geometry": {
|
* "type": "Point",
|
* "coordinates": [110, 40]
|
* }
|
* }
|
* var geom = turf.getType(point)
|
* //="Point"
|
*/
|
function getType(geojson, name) {
|
if (!geojson) throw new Error((name || 'geojson') + ' is required');
|
// GeoJSON Feature & GeometryCollection
|
if (geojson.geometry && geojson.geometry.type) return geojson.geometry.type;
|
// GeoJSON Geometry & FeatureCollection
|
if (geojson.type) return geojson.type;
|
throw new Error((name || 'geojson') + ' is invalid');
|
}
|
|
exports.getCoord = getCoord;
|
exports.getCoords = getCoords;
|
exports.containsNumber = containsNumber;
|
exports.geojsonType = geojsonType;
|
exports.featureOf = featureOf;
|
exports.collectionOf = collectionOf;
|
exports.getGeom = getGeom;
|
exports.getGeomType = getGeomType;
|
exports.getType = getType;
|
|
},{"@turf/helpers":10}],12:[function(require,module,exports){
|
"use strict";
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
}
|
Object.defineProperty(exports, "__esModule", { value: true });
|
var helpers_1 = require("@turf/helpers");
|
var meta_1 = require("@turf/meta");
|
var concaveman_1 = __importDefault(require("concaveman"));
|
/**
|
* Takes a {@link Feature} or a {@link FeatureCollection} and returns a convex hull {@link Polygon}.
|
*
|
* Internally this uses
|
* the [convex-hull](https://github.com/mikolalysenko/convex-hull) module that implements a
|
* [monotone chain hull](http://en.wikibooks.org/wiki/Algorithm_Implementation/Geometry/Convex_hull/Monotone_chain).
|
*
|
* @name convex
|
* @param {GeoJSON} geojson input Feature or FeatureCollection
|
* @param {Object} [options={}] Optional parameters
|
* @param {number} [options.concavity=Infinity] 1 - thin shape. Infinity - convex hull.
|
* @param {Object} [options.properties={}] Translate Properties to Feature
|
* @returns {Feature<Polygon>} a convex hull
|
* @example
|
* var points = turf.featureCollection([
|
* turf.point([10.195312, 43.755225]),
|
* turf.point([10.404052, 43.8424511]),
|
* turf.point([10.579833, 43.659924]),
|
* turf.point([10.360107, 43.516688]),
|
* turf.point([10.14038, 43.588348]),
|
* turf.point([10.195312, 43.755225])
|
* ]);
|
*
|
* var hull = turf.convex(points);
|
*
|
* //addToMap
|
* var addToMap = [points, hull]
|
*/
|
function convex(geojson, options) {
|
if (options === void 0) { options = {}; }
|
// Default parameters
|
options.concavity = options.concavity || Infinity;
|
// Container
|
var points = [];
|
// Convert all points to flat 2D coordinate Array
|
meta_1.coordEach(geojson, function (coord) {
|
points.push([coord[0], coord[1]]);
|
});
|
if (!points.length) {
|
return null;
|
}
|
var convexHull = concaveman_1.default(points, options.concavity);
|
// Convex hull should have at least 3 different vertices in order to create a valid polygon
|
if (convexHull.length > 3) {
|
return helpers_1.polygon([convexHull]);
|
}
|
return null;
|
}
|
exports.default = convex;
|
|
},{"@turf/helpers":14,"@turf/meta":18,"concaveman":31}],13:[function(require,module,exports){
|
"use strict";
|
Object.defineProperty(exports, "__esModule", { value: true });
|
var invariant_1 = require("@turf/invariant");
|
var helpers_1 = require("@turf/helpers");
|
//http://en.wikipedia.org/wiki/Haversine_formula
|
//http://www.movable-type.co.uk/scripts/latlong.html
|
/**
|
* Calculates the distance between two {@link Point|points} in degrees, radians, miles, or kilometers.
|
* This uses the [Haversine formula](http://en.wikipedia.org/wiki/Haversine_formula) to account for global curvature.
|
*
|
* @name distance
|
* @param {Coord} from origin point
|
* @param {Coord} to destination point
|
* @param {Object} [options={}] Optional parameters
|
* @param {string} [options.units='kilometers'] can be degrees, radians, miles, or kilometers
|
* @returns {number} distance between the two points
|
* @example
|
* var from = turf.point([-75.343, 39.984]);
|
* var to = turf.point([-75.534, 39.123]);
|
* var options = {units: 'miles'};
|
*
|
* var distance = turf.distance(from, to, options);
|
*
|
* //addToMap
|
* var addToMap = [from, to];
|
* from.properties.distance = distance;
|
* to.properties.distance = distance;
|
*/
|
function distance(from, to, options) {
|
if (options === void 0) { options = {}; }
|
var coordinates1 = invariant_1.getCoord(from);
|
var coordinates2 = invariant_1.getCoord(to);
|
var dLat = helpers_1.degreesToRadians((coordinates2[1] - coordinates1[1]));
|
var dLon = helpers_1.degreesToRadians((coordinates2[0] - coordinates1[0]));
|
var lat1 = helpers_1.degreesToRadians(coordinates1[1]);
|
var lat2 = helpers_1.degreesToRadians(coordinates2[1]);
|
var a = Math.pow(Math.sin(dLat / 2), 2) +
|
Math.pow(Math.sin(dLon / 2), 2) * Math.cos(lat1) * Math.cos(lat2);
|
return helpers_1.radiansToLength(2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)), options.units);
|
}
|
exports.default = distance;
|
|
},{"@turf/helpers":14,"@turf/invariant":17}],14:[function(require,module,exports){
|
"use strict";
|
Object.defineProperty(exports, "__esModule", { value: true });
|
/**
|
* @module helpers
|
*/
|
/**
|
* Earth Radius used with the Harvesine formula and approximates using a spherical (non-ellipsoid) Earth.
|
*
|
* @memberof helpers
|
* @type {number}
|
*/
|
exports.earthRadius = 6371008.8;
|
/**
|
* Unit of measurement factors using a spherical (non-ellipsoid) earth radius.
|
*
|
* @memberof helpers
|
* @type {Object}
|
*/
|
exports.factors = {
|
centimeters: exports.earthRadius * 100,
|
centimetres: exports.earthRadius * 100,
|
degrees: exports.earthRadius / 111325,
|
feet: exports.earthRadius * 3.28084,
|
inches: exports.earthRadius * 39.370,
|
kilometers: exports.earthRadius / 1000,
|
kilometres: exports.earthRadius / 1000,
|
meters: exports.earthRadius,
|
metres: exports.earthRadius,
|
miles: exports.earthRadius / 1609.344,
|
millimeters: exports.earthRadius * 1000,
|
millimetres: exports.earthRadius * 1000,
|
nauticalmiles: exports.earthRadius / 1852,
|
radians: 1,
|
yards: exports.earthRadius / 1.0936,
|
};
|
/**
|
* Units of measurement factors based on 1 meter.
|
*
|
* @memberof helpers
|
* @type {Object}
|
*/
|
exports.unitsFactors = {
|
centimeters: 100,
|
centimetres: 100,
|
degrees: 1 / 111325,
|
feet: 3.28084,
|
inches: 39.370,
|
kilometers: 1 / 1000,
|
kilometres: 1 / 1000,
|
meters: 1,
|
metres: 1,
|
miles: 1 / 1609.344,
|
millimeters: 1000,
|
millimetres: 1000,
|
nauticalmiles: 1 / 1852,
|
radians: 1 / exports.earthRadius,
|
yards: 1 / 1.0936,
|
};
|
/**
|
* Area of measurement factors based on 1 square meter.
|
*
|
* @memberof helpers
|
* @type {Object}
|
*/
|
exports.areaFactors = {
|
acres: 0.000247105,
|
centimeters: 10000,
|
centimetres: 10000,
|
feet: 10.763910417,
|
inches: 1550.003100006,
|
kilometers: 0.000001,
|
kilometres: 0.000001,
|
meters: 1,
|
metres: 1,
|
miles: 3.86e-7,
|
millimeters: 1000000,
|
millimetres: 1000000,
|
yards: 1.195990046,
|
};
|
/**
|
* Wraps a GeoJSON {@link Geometry} in a GeoJSON {@link Feature}.
|
*
|
* @name feature
|
* @param {Geometry} geometry input geometry
|
* @param {Object} [properties={}] an Object of key-value pairs to add as properties
|
* @param {Object} [options={}] Optional Parameters
|
* @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
|
* @param {string|number} [options.id] Identifier associated with the Feature
|
* @returns {Feature} a GeoJSON Feature
|
* @example
|
* var geometry = {
|
* "type": "Point",
|
* "coordinates": [110, 50]
|
* };
|
*
|
* var feature = turf.feature(geometry);
|
*
|
* //=feature
|
*/
|
function feature(geom, properties, options) {
|
if (options === void 0) { options = {}; }
|
var feat = { type: "Feature" };
|
if (options.id === 0 || options.id) {
|
feat.id = options.id;
|
}
|
if (options.bbox) {
|
feat.bbox = options.bbox;
|
}
|
feat.properties = properties || {};
|
feat.geometry = geom;
|
return feat;
|
}
|
exports.feature = feature;
|
/**
|
* Creates a GeoJSON {@link Geometry} from a Geometry string type & coordinates.
|
* For GeometryCollection type use `helpers.geometryCollection`
|
*
|
* @name geometry
|
* @param {string} type Geometry Type
|
* @param {Array<any>} coordinates Coordinates
|
* @param {Object} [options={}] Optional Parameters
|
* @returns {Geometry} a GeoJSON Geometry
|
* @example
|
* var type = "Point";
|
* var coordinates = [110, 50];
|
* var geometry = turf.geometry(type, coordinates);
|
* // => geometry
|
*/
|
function geometry(type, coordinates, options) {
|
if (options === void 0) { options = {}; }
|
switch (type) {
|
case "Point": return point(coordinates).geometry;
|
case "LineString": return lineString(coordinates).geometry;
|
case "Polygon": return polygon(coordinates).geometry;
|
case "MultiPoint": return multiPoint(coordinates).geometry;
|
case "MultiLineString": return multiLineString(coordinates).geometry;
|
case "MultiPolygon": return multiPolygon(coordinates).geometry;
|
default: throw new Error(type + " is invalid");
|
}
|
}
|
exports.geometry = geometry;
|
/**
|
* Creates a {@link Point} {@link Feature} from a Position.
|
*
|
* @name point
|
* @param {Array<number>} coordinates longitude, latitude position (each in decimal degrees)
|
* @param {Object} [properties={}] an Object of key-value pairs to add as properties
|
* @param {Object} [options={}] Optional Parameters
|
* @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
|
* @param {string|number} [options.id] Identifier associated with the Feature
|
* @returns {Feature<Point>} a Point feature
|
* @example
|
* var point = turf.point([-75.343, 39.984]);
|
*
|
* //=point
|
*/
|
function point(coordinates, properties, options) {
|
if (options === void 0) { options = {}; }
|
var geom = {
|
type: "Point",
|
coordinates: coordinates,
|
};
|
return feature(geom, properties, options);
|
}
|
exports.point = point;
|
/**
|
* Creates a {@link Point} {@link FeatureCollection} from an Array of Point coordinates.
|
*
|
* @name points
|
* @param {Array<Array<number>>} coordinates an array of Points
|
* @param {Object} [properties={}] Translate these properties to each Feature
|
* @param {Object} [options={}] Optional Parameters
|
* @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north]
|
* associated with the FeatureCollection
|
* @param {string|number} [options.id] Identifier associated with the FeatureCollection
|
* @returns {FeatureCollection<Point>} Point Feature
|
* @example
|
* var points = turf.points([
|
* [-75, 39],
|
* [-80, 45],
|
* [-78, 50]
|
* ]);
|
*
|
* //=points
|
*/
|
function points(coordinates, properties, options) {
|
if (options === void 0) { options = {}; }
|
return featureCollection(coordinates.map(function (coords) {
|
return point(coords, properties);
|
}), options);
|
}
|
exports.points = points;
|
/**
|
* Creates a {@link Polygon} {@link Feature} from an Array of LinearRings.
|
*
|
* @name polygon
|
* @param {Array<Array<Array<number>>>} coordinates an array of LinearRings
|
* @param {Object} [properties={}] an Object of key-value pairs to add as properties
|
* @param {Object} [options={}] Optional Parameters
|
* @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
|
* @param {string|number} [options.id] Identifier associated with the Feature
|
* @returns {Feature<Polygon>} Polygon Feature
|
* @example
|
* var polygon = turf.polygon([[[-5, 52], [-4, 56], [-2, 51], [-7, 54], [-5, 52]]], { name: 'poly1' });
|
*
|
* //=polygon
|
*/
|
function polygon(coordinates, properties, options) {
|
if (options === void 0) { options = {}; }
|
for (var _i = 0, coordinates_1 = coordinates; _i < coordinates_1.length; _i++) {
|
var ring = coordinates_1[_i];
|
if (ring.length < 4) {
|
throw new Error("Each LinearRing of a Polygon must have 4 or more Positions.");
|
}
|
for (var j = 0; j < ring[ring.length - 1].length; j++) {
|
// Check if first point of Polygon contains two numbers
|
if (ring[ring.length - 1][j] !== ring[0][j]) {
|
throw new Error("First and last Position are not equivalent.");
|
}
|
}
|
}
|
var geom = {
|
type: "Polygon",
|
coordinates: coordinates,
|
};
|
return feature(geom, properties, options);
|
}
|
exports.polygon = polygon;
|
/**
|
* Creates a {@link Polygon} {@link FeatureCollection} from an Array of Polygon coordinates.
|
*
|
* @name polygons
|
* @param {Array<Array<Array<Array<number>>>>} coordinates an array of Polygon coordinates
|
* @param {Object} [properties={}] an Object of key-value pairs to add as properties
|
* @param {Object} [options={}] Optional Parameters
|
* @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
|
* @param {string|number} [options.id] Identifier associated with the FeatureCollection
|
* @returns {FeatureCollection<Polygon>} Polygon FeatureCollection
|
* @example
|
* var polygons = turf.polygons([
|
* [[[-5, 52], [-4, 56], [-2, 51], [-7, 54], [-5, 52]]],
|
* [[[-15, 42], [-14, 46], [-12, 41], [-17, 44], [-15, 42]]],
|
* ]);
|
*
|
* //=polygons
|
*/
|
function polygons(coordinates, properties, options) {
|
if (options === void 0) { options = {}; }
|
return featureCollection(coordinates.map(function (coords) {
|
return polygon(coords, properties);
|
}), options);
|
}
|
exports.polygons = polygons;
|
/**
|
* Creates a {@link LineString} {@link Feature} from an Array of Positions.
|
*
|
* @name lineString
|
* @param {Array<Array<number>>} coordinates an array of Positions
|
* @param {Object} [properties={}] an Object of key-value pairs to add as properties
|
* @param {Object} [options={}] Optional Parameters
|
* @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
|
* @param {string|number} [options.id] Identifier associated with the Feature
|
* @returns {Feature<LineString>} LineString Feature
|
* @example
|
* var linestring1 = turf.lineString([[-24, 63], [-23, 60], [-25, 65], [-20, 69]], {name: 'line 1'});
|
* var linestring2 = turf.lineString([[-14, 43], [-13, 40], [-15, 45], [-10, 49]], {name: 'line 2'});
|
*
|
* //=linestring1
|
* //=linestring2
|
*/
|
function lineString(coordinates, properties, options) {
|
if (options === void 0) { options = {}; }
|
if (coordinates.length < 2) {
|
throw new Error("coordinates must be an array of two or more positions");
|
}
|
var geom = {
|
type: "LineString",
|
coordinates: coordinates,
|
};
|
return feature(geom, properties, options);
|
}
|
exports.lineString = lineString;
|
/**
|
* Creates a {@link LineString} {@link FeatureCollection} from an Array of LineString coordinates.
|
*
|
* @name lineStrings
|
* @param {Array<Array<Array<number>>>} coordinates an array of LinearRings
|
* @param {Object} [properties={}] an Object of key-value pairs to add as properties
|
* @param {Object} [options={}] Optional Parameters
|
* @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north]
|
* associated with the FeatureCollection
|
* @param {string|number} [options.id] Identifier associated with the FeatureCollection
|
* @returns {FeatureCollection<LineString>} LineString FeatureCollection
|
* @example
|
* var linestrings = turf.lineStrings([
|
* [[-24, 63], [-23, 60], [-25, 65], [-20, 69]],
|
* [[-14, 43], [-13, 40], [-15, 45], [-10, 49]]
|
* ]);
|
*
|
* //=linestrings
|
*/
|
function lineStrings(coordinates, properties, options) {
|
if (options === void 0) { options = {}; }
|
return featureCollection(coordinates.map(function (coords) {
|
return lineString(coords, properties);
|
}), options);
|
}
|
exports.lineStrings = lineStrings;
|
/**
|
* Takes one or more {@link Feature|Features} and creates a {@link FeatureCollection}.
|
*
|
* @name featureCollection
|
* @param {Feature[]} features input features
|
* @param {Object} [options={}] Optional Parameters
|
* @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
|
* @param {string|number} [options.id] Identifier associated with the Feature
|
* @returns {FeatureCollection} FeatureCollection of Features
|
* @example
|
* var locationA = turf.point([-75.343, 39.984], {name: 'Location A'});
|
* var locationB = turf.point([-75.833, 39.284], {name: 'Location B'});
|
* var locationC = turf.point([-75.534, 39.123], {name: 'Location C'});
|
*
|
* var collection = turf.featureCollection([
|
* locationA,
|
* locationB,
|
* locationC
|
* ]);
|
*
|
* //=collection
|
*/
|
function featureCollection(features, options) {
|
if (options === void 0) { options = {}; }
|
var fc = { type: "FeatureCollection" };
|
if (options.id) {
|
fc.id = options.id;
|
}
|
if (options.bbox) {
|
fc.bbox = options.bbox;
|
}
|
fc.features = features;
|
return fc;
|
}
|
exports.featureCollection = featureCollection;
|
/**
|
* Creates a {@link Feature<MultiLineString>} based on a
|
* coordinate array. Properties can be added optionally.
|
*
|
* @name multiLineString
|
* @param {Array<Array<Array<number>>>} coordinates an array of LineStrings
|
* @param {Object} [properties={}] an Object of key-value pairs to add as properties
|
* @param {Object} [options={}] Optional Parameters
|
* @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
|
* @param {string|number} [options.id] Identifier associated with the Feature
|
* @returns {Feature<MultiLineString>} a MultiLineString feature
|
* @throws {Error} if no coordinates are passed
|
* @example
|
* var multiLine = turf.multiLineString([[[0,0],[10,10]]]);
|
*
|
* //=multiLine
|
*/
|
function multiLineString(coordinates, properties, options) {
|
if (options === void 0) { options = {}; }
|
var geom = {
|
type: "MultiLineString",
|
coordinates: coordinates,
|
};
|
return feature(geom, properties, options);
|
}
|
exports.multiLineString = multiLineString;
|
/**
|
* Creates a {@link Feature<MultiPoint>} based on a
|
* coordinate array. Properties can be added optionally.
|
*
|
* @name multiPoint
|
* @param {Array<Array<number>>} coordinates an array of Positions
|
* @param {Object} [properties={}] an Object of key-value pairs to add as properties
|
* @param {Object} [options={}] Optional Parameters
|
* @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
|
* @param {string|number} [options.id] Identifier associated with the Feature
|
* @returns {Feature<MultiPoint>} a MultiPoint feature
|
* @throws {Error} if no coordinates are passed
|
* @example
|
* var multiPt = turf.multiPoint([[0,0],[10,10]]);
|
*
|
* //=multiPt
|
*/
|
function multiPoint(coordinates, properties, options) {
|
if (options === void 0) { options = {}; }
|
var geom = {
|
type: "MultiPoint",
|
coordinates: coordinates,
|
};
|
return feature(geom, properties, options);
|
}
|
exports.multiPoint = multiPoint;
|
/**
|
* Creates a {@link Feature<MultiPolygon>} based on a
|
* coordinate array. Properties can be added optionally.
|
*
|
* @name multiPolygon
|
* @param {Array<Array<Array<Array<number>>>>} coordinates an array of Polygons
|
* @param {Object} [properties={}] an Object of key-value pairs to add as properties
|
* @param {Object} [options={}] Optional Parameters
|
* @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
|
* @param {string|number} [options.id] Identifier associated with the Feature
|
* @returns {Feature<MultiPolygon>} a multipolygon feature
|
* @throws {Error} if no coordinates are passed
|
* @example
|
* var multiPoly = turf.multiPolygon([[[[0,0],[0,10],[10,10],[10,0],[0,0]]]]);
|
*
|
* //=multiPoly
|
*
|
*/
|
function multiPolygon(coordinates, properties, options) {
|
if (options === void 0) { options = {}; }
|
var geom = {
|
type: "MultiPolygon",
|
coordinates: coordinates,
|
};
|
return feature(geom, properties, options);
|
}
|
exports.multiPolygon = multiPolygon;
|
/**
|
* Creates a {@link Feature<GeometryCollection>} based on a
|
* coordinate array. Properties can be added optionally.
|
*
|
* @name geometryCollection
|
* @param {Array<Geometry>} geometries an array of GeoJSON Geometries
|
* @param {Object} [properties={}] an Object of key-value pairs to add as properties
|
* @param {Object} [options={}] Optional Parameters
|
* @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
|
* @param {string|number} [options.id] Identifier associated with the Feature
|
* @returns {Feature<GeometryCollection>} a GeoJSON GeometryCollection Feature
|
* @example
|
* var pt = turf.geometry("Point", [100, 0]);
|
* var line = turf.geometry("LineString", [[101, 0], [102, 1]]);
|
* var collection = turf.geometryCollection([pt, line]);
|
*
|
* // => collection
|
*/
|
function geometryCollection(geometries, properties, options) {
|
if (options === void 0) { options = {}; }
|
var geom = {
|
type: "GeometryCollection",
|
geometries: geometries,
|
};
|
return feature(geom, properties, options);
|
}
|
exports.geometryCollection = geometryCollection;
|
/**
|
* Round number to precision
|
*
|
* @param {number} num Number
|
* @param {number} [precision=0] Precision
|
* @returns {number} rounded number
|
* @example
|
* turf.round(120.4321)
|
* //=120
|
*
|
* turf.round(120.4321, 2)
|
* //=120.43
|
*/
|
function round(num, precision) {
|
if (precision === void 0) { precision = 0; }
|
if (precision && !(precision >= 0)) {
|
throw new Error("precision must be a positive number");
|
}
|
var multiplier = Math.pow(10, precision || 0);
|
return Math.round(num * multiplier) / multiplier;
|
}
|
exports.round = round;
|
/**
|
* Convert a distance measurement (assuming a spherical Earth) from radians to a more friendly unit.
|
* Valid units: miles, nauticalmiles, inches, yards, meters, metres, kilometers, centimeters, feet
|
*
|
* @name radiansToLength
|
* @param {number} radians in radians across the sphere
|
* @param {string} [units="kilometers"] can be degrees, radians, miles, or kilometers inches, yards, metres,
|
* meters, kilometres, kilometers.
|
* @returns {number} distance
|
*/
|
function radiansToLength(radians, units) {
|
if (units === void 0) { units = "kilometers"; }
|
var factor = exports.factors[units];
|
if (!factor) {
|
throw new Error(units + " units is invalid");
|
}
|
return radians * factor;
|
}
|
exports.radiansToLength = radiansToLength;
|
/**
|
* Convert a distance measurement (assuming a spherical Earth) from a real-world unit into radians
|
* Valid units: miles, nauticalmiles, inches, yards, meters, metres, kilometers, centimeters, feet
|
*
|
* @name lengthToRadians
|
* @param {number} distance in real units
|
* @param {string} [units="kilometers"] can be degrees, radians, miles, or kilometers inches, yards, metres,
|
* meters, kilometres, kilometers.
|
* @returns {number} radians
|
*/
|
function lengthToRadians(distance, units) {
|
if (units === void 0) { units = "kilometers"; }
|
var factor = exports.factors[units];
|
if (!factor) {
|
throw new Error(units + " units is invalid");
|
}
|
return distance / factor;
|
}
|
exports.lengthToRadians = lengthToRadians;
|
/**
|
* Convert a distance measurement (assuming a spherical Earth) from a real-world unit into degrees
|
* Valid units: miles, nauticalmiles, inches, yards, meters, metres, centimeters, kilometres, feet
|
*
|
* @name lengthToDegrees
|
* @param {number} distance in real units
|
* @param {string} [units="kilometers"] can be degrees, radians, miles, or kilometers inches, yards, metres,
|
* meters, kilometres, kilometers.
|
* @returns {number} degrees
|
*/
|
function lengthToDegrees(distance, units) {
|
return radiansToDegrees(lengthToRadians(distance, units));
|
}
|
exports.lengthToDegrees = lengthToDegrees;
|
/**
|
* Converts any bearing angle from the north line direction (positive clockwise)
|
* and returns an angle between 0-360 degrees (positive clockwise), 0 being the north line
|
*
|
* @name bearingToAzimuth
|
* @param {number} bearing angle, between -180 and +180 degrees
|
* @returns {number} angle between 0 and 360 degrees
|
*/
|
function bearingToAzimuth(bearing) {
|
var angle = bearing % 360;
|
if (angle < 0) {
|
angle += 360;
|
}
|
return angle;
|
}
|
exports.bearingToAzimuth = bearingToAzimuth;
|
/**
|
* Converts an angle in radians to degrees
|
*
|
* @name radiansToDegrees
|
* @param {number} radians angle in radians
|
* @returns {number} degrees between 0 and 360 degrees
|
*/
|
function radiansToDegrees(radians) {
|
var degrees = radians % (2 * Math.PI);
|
return degrees * 180 / Math.PI;
|
}
|
exports.radiansToDegrees = radiansToDegrees;
|
/**
|
* Converts an angle in degrees to radians
|
*
|
* @name degreesToRadians
|
* @param {number} degrees angle between 0 and 360 degrees
|
* @returns {number} angle in radians
|
*/
|
function degreesToRadians(degrees) {
|
var radians = degrees % 360;
|
return radians * Math.PI / 180;
|
}
|
exports.degreesToRadians = degreesToRadians;
|
/**
|
* Converts a length to the requested unit.
|
* Valid units: miles, nauticalmiles, inches, yards, meters, metres, kilometers, centimeters, feet
|
*
|
* @param {number} length to be converted
|
* @param {Units} [originalUnit="kilometers"] of the length
|
* @param {Units} [finalUnit="kilometers"] returned unit
|
* @returns {number} the converted length
|
*/
|
function convertLength(length, originalUnit, finalUnit) {
|
if (originalUnit === void 0) { originalUnit = "kilometers"; }
|
if (finalUnit === void 0) { finalUnit = "kilometers"; }
|
if (!(length >= 0)) {
|
throw new Error("length must be a positive number");
|
}
|
return radiansToLength(lengthToRadians(length, originalUnit), finalUnit);
|
}
|
exports.convertLength = convertLength;
|
/**
|
* Converts a area to the requested unit.
|
* Valid units: kilometers, kilometres, meters, metres, centimetres, millimeters, acres, miles, yards, feet, inches
|
* @param {number} area to be converted
|
* @param {Units} [originalUnit="meters"] of the distance
|
* @param {Units} [finalUnit="kilometers"] returned unit
|
* @returns {number} the converted distance
|
*/
|
function convertArea(area, originalUnit, finalUnit) {
|
if (originalUnit === void 0) { originalUnit = "meters"; }
|
if (finalUnit === void 0) { finalUnit = "kilometers"; }
|
if (!(area >= 0)) {
|
throw new Error("area must be a positive number");
|
}
|
var startFactor = exports.areaFactors[originalUnit];
|
if (!startFactor) {
|
throw new Error("invalid original units");
|
}
|
var finalFactor = exports.areaFactors[finalUnit];
|
if (!finalFactor) {
|
throw new Error("invalid final units");
|
}
|
return (area / startFactor) * finalFactor;
|
}
|
exports.convertArea = convertArea;
|
/**
|
* isNumber
|
*
|
* @param {*} num Number to validate
|
* @returns {boolean} true/false
|
* @example
|
* turf.isNumber(123)
|
* //=true
|
* turf.isNumber('foo')
|
* //=false
|
*/
|
function isNumber(num) {
|
return !isNaN(num) && num !== null && !Array.isArray(num) && !/^\s*$/.test(num);
|
}
|
exports.isNumber = isNumber;
|
/**
|
* isObject
|
*
|
* @param {*} input variable to validate
|
* @returns {boolean} true/false
|
* @example
|
* turf.isObject({elevation: 10})
|
* //=true
|
* turf.isObject('foo')
|
* //=false
|
*/
|
function isObject(input) {
|
return (!!input) && (input.constructor === Object);
|
}
|
exports.isObject = isObject;
|
/**
|
* Validate BBox
|
*
|
* @private
|
* @param {Array<number>} bbox BBox to validate
|
* @returns {void}
|
* @throws Error if BBox is not valid
|
* @example
|
* validateBBox([-180, -40, 110, 50])
|
* //=OK
|
* validateBBox([-180, -40])
|
* //=Error
|
* validateBBox('Foo')
|
* //=Error
|
* validateBBox(5)
|
* //=Error
|
* validateBBox(null)
|
* //=Error
|
* validateBBox(undefined)
|
* //=Error
|
*/
|
function validateBBox(bbox) {
|
if (!bbox) {
|
throw new Error("bbox is required");
|
}
|
if (!Array.isArray(bbox)) {
|
throw new Error("bbox must be an Array");
|
}
|
if (bbox.length !== 4 && bbox.length !== 6) {
|
throw new Error("bbox must be an Array of 4 or 6 numbers");
|
}
|
bbox.forEach(function (num) {
|
if (!isNumber(num)) {
|
throw new Error("bbox must only contain numbers");
|
}
|
});
|
}
|
exports.validateBBox = validateBBox;
|
/**
|
* Validate Id
|
*
|
* @private
|
* @param {string|number} id Id to validate
|
* @returns {void}
|
* @throws Error if Id is not valid
|
* @example
|
* validateId([-180, -40, 110, 50])
|
* //=Error
|
* validateId([-180, -40])
|
* //=Error
|
* validateId('Foo')
|
* //=OK
|
* validateId(5)
|
* //=OK
|
* validateId(null)
|
* //=Error
|
* validateId(undefined)
|
* //=Error
|
*/
|
function validateId(id) {
|
if (!id) {
|
throw new Error("id is required");
|
}
|
if (["string", "number"].indexOf(typeof id) === -1) {
|
throw new Error("id must be a number or a string");
|
}
|
}
|
exports.validateId = validateId;
|
// Deprecated methods
|
function radians2degrees() {
|
throw new Error("method has been renamed to `radiansToDegrees`");
|
}
|
exports.radians2degrees = radians2degrees;
|
function degrees2radians() {
|
throw new Error("method has been renamed to `degreesToRadians`");
|
}
|
exports.degrees2radians = degrees2radians;
|
function distanceToDegrees() {
|
throw new Error("method has been renamed to `lengthToDegrees`");
|
}
|
exports.distanceToDegrees = distanceToDegrees;
|
function distanceToRadians() {
|
throw new Error("method has been renamed to `lengthToRadians`");
|
}
|
exports.distanceToRadians = distanceToRadians;
|
function radiansToDistance() {
|
throw new Error("method has been renamed to `radiansToLength`");
|
}
|
exports.radiansToDistance = radiansToDistance;
|
function bearingToAngle() {
|
throw new Error("method has been renamed to `bearingToAzimuth`");
|
}
|
exports.bearingToAngle = bearingToAngle;
|
function convertDistance() {
|
throw new Error("method has been renamed to `convertLength`");
|
}
|
exports.convertDistance = convertDistance;
|
|
},{}],15:[function(require,module,exports){
|
var invariant = require('@turf/invariant');
|
var getCoord = invariant.getCoord;
|
var getCoords = invariant.getCoords;
|
|
// http://en.wikipedia.org/wiki/Even%E2%80%93odd_rule
|
// modified from: https://github.com/substack/point-in-polygon/blob/master/index.js
|
// which was modified from http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
|
|
/**
|
* Takes a {@link Point} and a {@link Polygon} or {@link MultiPolygon} and determines if the point resides inside the polygon. The polygon can
|
* be convex or concave. The function accounts for holes.
|
*
|
* @name inside
|
* @param {Feature<Point>} point input point
|
* @param {Feature<Polygon|MultiPolygon>} polygon input polygon or multipolygon
|
* @param {boolean} [ignoreBoundary=false] True if polygon boundary should be ignored when determining if the point is inside the polygon otherwise false.
|
* @returns {boolean} `true` if the Point is inside the Polygon; `false` if the Point is not inside the Polygon
|
* @example
|
* var pt = turf.point([-77, 44]);
|
* var poly = turf.polygon([[
|
* [-81, 41],
|
* [-81, 47],
|
* [-72, 47],
|
* [-72, 41],
|
* [-81, 41]
|
* ]]);
|
*
|
* turf.inside(pt, poly);
|
* //= true
|
*/
|
module.exports = function (point, polygon, ignoreBoundary) {
|
// validation
|
if (!point) throw new Error('point is required');
|
if (!polygon) throw new Error('polygon is required');
|
|
var pt = getCoord(point);
|
var polys = getCoords(polygon);
|
var type = (polygon.geometry) ? polygon.geometry.type : polygon.type;
|
var bbox = polygon.bbox;
|
|
// Quick elimination if point is not inside bbox
|
if (bbox && inBBox(pt, bbox) === false) return false;
|
|
// normalize to multipolygon
|
if (type === 'Polygon') polys = [polys];
|
|
for (var i = 0, insidePoly = false; i < polys.length && !insidePoly; i++) {
|
// check if it is in the outer ring first
|
if (inRing(pt, polys[i][0], ignoreBoundary)) {
|
var inHole = false;
|
var k = 1;
|
// check for the point in any of the holes
|
while (k < polys[i].length && !inHole) {
|
if (inRing(pt, polys[i][k], !ignoreBoundary)) {
|
inHole = true;
|
}
|
k++;
|
}
|
if (!inHole) insidePoly = true;
|
}
|
}
|
return insidePoly;
|
};
|
|
/**
|
* inRing
|
*
|
* @private
|
* @param {[number, number]} pt [x,y]
|
* @param {Array<[number, number]>} ring [[x,y], [x,y],..]
|
* @param {boolean} ignoreBoundary ignoreBoundary
|
* @returns {boolean} inRing
|
*/
|
function inRing(pt, ring, ignoreBoundary) {
|
var isInside = false;
|
if (ring[0][0] === ring[ring.length - 1][0] && ring[0][1] === ring[ring.length - 1][1]) ring = ring.slice(0, ring.length - 1);
|
|
for (var i = 0, j = ring.length - 1; i < ring.length; j = i++) {
|
var xi = ring[i][0], yi = ring[i][1];
|
var xj = ring[j][0], yj = ring[j][1];
|
var onBoundary = (pt[1] * (xi - xj) + yi * (xj - pt[0]) + yj * (pt[0] - xi) === 0) &&
|
((xi - pt[0]) * (xj - pt[0]) <= 0) && ((yi - pt[1]) * (yj - pt[1]) <= 0);
|
if (onBoundary) return !ignoreBoundary;
|
var intersect = ((yi > pt[1]) !== (yj > pt[1])) &&
|
(pt[0] < (xj - xi) * (pt[1] - yi) / (yj - yi) + xi);
|
if (intersect) isInside = !isInside;
|
}
|
return isInside;
|
}
|
|
/**
|
* inBBox
|
*
|
* @private
|
* @param {[number, number]} pt point [x,y]
|
* @param {[number, number, number, number]} bbox BBox [west, south, east, north]
|
* @returns {boolean} true/false if point is inside BBox
|
*/
|
function inBBox(pt, bbox) {
|
return bbox[0] <= pt[0] &&
|
bbox[1] <= pt[1] &&
|
bbox[2] >= pt[0] &&
|
bbox[3] >= pt[1];
|
}
|
|
},{"@turf/invariant":16}],16:[function(require,module,exports){
|
/**
|
* Unwrap a coordinate from a Point Feature, Geometry or a single coordinate.
|
*
|
* @name getCoord
|
* @param {Array<number>|Geometry<Point>|Feature<Point>} obj Object
|
* @returns {Array<number>} coordinates
|
* @example
|
* var pt = turf.point([10, 10]);
|
*
|
* var coord = turf.getCoord(pt);
|
* //= [10, 10]
|
*/
|
function getCoord(obj) {
|
if (!obj) throw new Error('obj is required');
|
|
var coordinates = getCoords(obj);
|
|
// getCoord() must contain at least two numbers (Point)
|
if (coordinates.length > 1 &&
|
typeof coordinates[0] === 'number' &&
|
typeof coordinates[1] === 'number') {
|
return coordinates;
|
} else {
|
throw new Error('Coordinate is not a valid Point');
|
}
|
}
|
|
/**
|
* Unwrap coordinates from a Feature, Geometry Object or an Array of numbers
|
*
|
* @name getCoords
|
* @param {Array<number>|Geometry|Feature} obj Object
|
* @returns {Array<number>} coordinates
|
* @example
|
* var poly = turf.polygon([[[119.32, -8.7], [119.55, -8.69], [119.51, -8.54], [119.32, -8.7]]]);
|
*
|
* var coord = turf.getCoords(poly);
|
* //= [[[119.32, -8.7], [119.55, -8.69], [119.51, -8.54], [119.32, -8.7]]]
|
*/
|
function getCoords(obj) {
|
if (!obj) throw new Error('obj is required');
|
var coordinates;
|
|
// Array of numbers
|
if (obj.length) {
|
coordinates = obj;
|
|
// Geometry Object
|
} else if (obj.coordinates) {
|
coordinates = obj.coordinates;
|
|
// Feature
|
} else if (obj.geometry && obj.geometry.coordinates) {
|
coordinates = obj.geometry.coordinates;
|
}
|
// Checks if coordinates contains a number
|
if (coordinates) {
|
containsNumber(coordinates);
|
return coordinates;
|
}
|
throw new Error('No valid coordinates');
|
}
|
|
/**
|
* Checks if coordinates contains a number
|
*
|
* @name containsNumber
|
* @param {Array<any>} coordinates GeoJSON Coordinates
|
* @returns {boolean} true if Array contains a number
|
*/
|
function containsNumber(coordinates) {
|
if (coordinates.length > 1 &&
|
typeof coordinates[0] === 'number' &&
|
typeof coordinates[1] === 'number') {
|
return true;
|
}
|
|
if (Array.isArray(coordinates[0]) && coordinates[0].length) {
|
return containsNumber(coordinates[0]);
|
}
|
throw new Error('coordinates must only contain numbers');
|
}
|
|
/**
|
* Enforce expectations about types of GeoJSON objects for Turf.
|
*
|
* @name geojsonType
|
* @param {GeoJSON} value any GeoJSON object
|
* @param {string} type expected GeoJSON type
|
* @param {string} name name of calling function
|
* @throws {Error} if value is not the expected type.
|
*/
|
function geojsonType(value, type, name) {
|
if (!type || !name) throw new Error('type and name required');
|
|
if (!value || value.type !== type) {
|
throw new Error('Invalid input to ' + name + ': must be a ' + type + ', given ' + value.type);
|
}
|
}
|
|
/**
|
* Enforce expectations about types of {@link Feature} inputs for Turf.
|
* Internally this uses {@link geojsonType} to judge geometry types.
|
*
|
* @name featureOf
|
* @param {Feature} feature a feature with an expected geometry type
|
* @param {string} type expected GeoJSON type
|
* @param {string} name name of calling function
|
* @throws {Error} error if value is not the expected type.
|
*/
|
function featureOf(feature, type, name) {
|
if (!feature) throw new Error('No feature passed');
|
if (!name) throw new Error('.featureOf() requires a name');
|
if (!feature || feature.type !== 'Feature' || !feature.geometry) {
|
throw new Error('Invalid input to ' + name + ', Feature with geometry required');
|
}
|
if (!feature.geometry || feature.geometry.type !== type) {
|
throw new Error('Invalid input to ' + name + ': must be a ' + type + ', given ' + feature.geometry.type);
|
}
|
}
|
|
/**
|
* Enforce expectations about types of {@link FeatureCollection} inputs for Turf.
|
* Internally this uses {@link geojsonType} to judge geometry types.
|
*
|
* @name collectionOf
|
* @param {FeatureCollection} featureCollection a FeatureCollection for which features will be judged
|
* @param {string} type expected GeoJSON type
|
* @param {string} name name of calling function
|
* @throws {Error} if value is not the expected type.
|
*/
|
function collectionOf(featureCollection, type, name) {
|
if (!featureCollection) throw new Error('No featureCollection passed');
|
if (!name) throw new Error('.collectionOf() requires a name');
|
if (!featureCollection || featureCollection.type !== 'FeatureCollection') {
|
throw new Error('Invalid input to ' + name + ', FeatureCollection required');
|
}
|
for (var i = 0; i < featureCollection.features.length; i++) {
|
var feature = featureCollection.features[i];
|
if (!feature || feature.type !== 'Feature' || !feature.geometry) {
|
throw new Error('Invalid input to ' + name + ', Feature with geometry required');
|
}
|
if (!feature.geometry || feature.geometry.type !== type) {
|
throw new Error('Invalid input to ' + name + ': must be a ' + type + ', given ' + feature.geometry.type);
|
}
|
}
|
}
|
|
/**
|
* Get Geometry from Feature or Geometry Object
|
*
|
* @param {Feature|Geometry} geojson GeoJSON Feature or Geometry Object
|
* @returns {Geometry|null} GeoJSON Geometry Object
|
* @throws {Error} if geojson is not a Feature or Geometry Object
|
* @example
|
* var point = {
|
* "type": "Feature",
|
* "properties": {},
|
* "geometry": {
|
* "type": "Point",
|
* "coordinates": [110, 40]
|
* }
|
* }
|
* var geom = turf.getGeom(point)
|
* //={"type": "Point", "coordinates": [110, 40]}
|
*/
|
function getGeom(geojson) {
|
if (!geojson) throw new Error('geojson is required');
|
if (geojson.geometry !== undefined) return geojson.geometry;
|
if (geojson.coordinates || geojson.geometries) return geojson;
|
throw new Error('geojson must be a valid Feature or Geometry Object');
|
}
|
|
/**
|
* Get Geometry Type from Feature or Geometry Object
|
*
|
* @param {Feature|Geometry} geojson GeoJSON Feature or Geometry Object
|
* @returns {string} GeoJSON Geometry Type
|
* @throws {Error} if geojson is not a Feature or Geometry Object
|
* @example
|
* var point = {
|
* "type": "Feature",
|
* "properties": {},
|
* "geometry": {
|
* "type": "Point",
|
* "coordinates": [110, 40]
|
* }
|
* }
|
* var geom = turf.getGeomType(point)
|
* //="Point"
|
*/
|
function getGeomType(geojson) {
|
if (!geojson) throw new Error('geojson is required');
|
var geom = getGeom(geojson);
|
if (geom) return geom.type;
|
}
|
|
module.exports = {
|
geojsonType: geojsonType,
|
collectionOf: collectionOf,
|
featureOf: featureOf,
|
getCoord: getCoord,
|
getCoords: getCoords,
|
containsNumber: containsNumber,
|
getGeom: getGeom,
|
getGeomType: getGeomType
|
};
|
|
},{}],17:[function(require,module,exports){
|
"use strict";
|
Object.defineProperty(exports, "__esModule", { value: true });
|
var helpers_1 = require("@turf/helpers");
|
/**
|
* Unwrap a coordinate from a Point Feature, Geometry or a single coordinate.
|
*
|
* @name getCoord
|
* @param {Array<number>|Geometry<Point>|Feature<Point>} coord GeoJSON Point or an Array of numbers
|
* @returns {Array<number>} coordinates
|
* @example
|
* var pt = turf.point([10, 10]);
|
*
|
* var coord = turf.getCoord(pt);
|
* //= [10, 10]
|
*/
|
function getCoord(coord) {
|
if (!coord) {
|
throw new Error("coord is required");
|
}
|
if (!Array.isArray(coord)) {
|
if (coord.type === "Feature" && coord.geometry !== null && coord.geometry.type === "Point") {
|
return coord.geometry.coordinates;
|
}
|
if (coord.type === "Point") {
|
return coord.coordinates;
|
}
|
}
|
if (Array.isArray(coord) && coord.length >= 2 && !Array.isArray(coord[0]) && !Array.isArray(coord[1])) {
|
return coord;
|
}
|
throw new Error("coord must be GeoJSON Point or an Array of numbers");
|
}
|
exports.getCoord = getCoord;
|
/**
|
* Unwrap coordinates from a Feature, Geometry Object or an Array
|
*
|
* @name getCoords
|
* @param {Array<any>|Geometry|Feature} coords Feature, Geometry Object or an Array
|
* @returns {Array<any>} coordinates
|
* @example
|
* var poly = turf.polygon([[[119.32, -8.7], [119.55, -8.69], [119.51, -8.54], [119.32, -8.7]]]);
|
*
|
* var coords = turf.getCoords(poly);
|
* //= [[[119.32, -8.7], [119.55, -8.69], [119.51, -8.54], [119.32, -8.7]]]
|
*/
|
function getCoords(coords) {
|
if (Array.isArray(coords)) {
|
return coords;
|
}
|
// Feature
|
if (coords.type === "Feature") {
|
if (coords.geometry !== null) {
|
return coords.geometry.coordinates;
|
}
|
}
|
else {
|
// Geometry
|
if (coords.coordinates) {
|
return coords.coordinates;
|
}
|
}
|
throw new Error("coords must be GeoJSON Feature, Geometry Object or an Array");
|
}
|
exports.getCoords = getCoords;
|
/**
|
* Checks if coordinates contains a number
|
*
|
* @name containsNumber
|
* @param {Array<any>} coordinates GeoJSON Coordinates
|
* @returns {boolean} true if Array contains a number
|
*/
|
function containsNumber(coordinates) {
|
if (coordinates.length > 1 && helpers_1.isNumber(coordinates[0]) && helpers_1.isNumber(coordinates[1])) {
|
return true;
|
}
|
if (Array.isArray(coordinates[0]) && coordinates[0].length) {
|
return containsNumber(coordinates[0]);
|
}
|
throw new Error("coordinates must only contain numbers");
|
}
|
exports.containsNumber = containsNumber;
|
/**
|
* Enforce expectations about types of GeoJSON objects for Turf.
|
*
|
* @name geojsonType
|
* @param {GeoJSON} value any GeoJSON object
|
* @param {string} type expected GeoJSON type
|
* @param {string} name name of calling function
|
* @throws {Error} if value is not the expected type.
|
*/
|
function geojsonType(value, type, name) {
|
if (!type || !name) {
|
throw new Error("type and name required");
|
}
|
if (!value || value.type !== type) {
|
throw new Error("Invalid input to " + name + ": must be a " + type + ", given " + value.type);
|
}
|
}
|
exports.geojsonType = geojsonType;
|
/**
|
* Enforce expectations about types of {@link Feature} inputs for Turf.
|
* Internally this uses {@link geojsonType} to judge geometry types.
|
*
|
* @name featureOf
|
* @param {Feature} feature a feature with an expected geometry type
|
* @param {string} type expected GeoJSON type
|
* @param {string} name name of calling function
|
* @throws {Error} error if value is not the expected type.
|
*/
|
function featureOf(feature, type, name) {
|
if (!feature) {
|
throw new Error("No feature passed");
|
}
|
if (!name) {
|
throw new Error(".featureOf() requires a name");
|
}
|
if (!feature || feature.type !== "Feature" || !feature.geometry) {
|
throw new Error("Invalid input to " + name + ", Feature with geometry required");
|
}
|
if (!feature.geometry || feature.geometry.type !== type) {
|
throw new Error("Invalid input to " + name + ": must be a " + type + ", given " + feature.geometry.type);
|
}
|
}
|
exports.featureOf = featureOf;
|
/**
|
* Enforce expectations about types of {@link FeatureCollection} inputs for Turf.
|
* Internally this uses {@link geojsonType} to judge geometry types.
|
*
|
* @name collectionOf
|
* @param {FeatureCollection} featureCollection a FeatureCollection for which features will be judged
|
* @param {string} type expected GeoJSON type
|
* @param {string} name name of calling function
|
* @throws {Error} if value is not the expected type.
|
*/
|
function collectionOf(featureCollection, type, name) {
|
if (!featureCollection) {
|
throw new Error("No featureCollection passed");
|
}
|
if (!name) {
|
throw new Error(".collectionOf() requires a name");
|
}
|
if (!featureCollection || featureCollection.type !== "FeatureCollection") {
|
throw new Error("Invalid input to " + name + ", FeatureCollection required");
|
}
|
for (var _i = 0, _a = featureCollection.features; _i < _a.length; _i++) {
|
var feature = _a[_i];
|
if (!feature || feature.type !== "Feature" || !feature.geometry) {
|
throw new Error("Invalid input to " + name + ", Feature with geometry required");
|
}
|
if (!feature.geometry || feature.geometry.type !== type) {
|
throw new Error("Invalid input to " + name + ": must be a " + type + ", given " + feature.geometry.type);
|
}
|
}
|
}
|
exports.collectionOf = collectionOf;
|
/**
|
* Get Geometry from Feature or Geometry Object
|
*
|
* @param {Feature|Geometry} geojson GeoJSON Feature or Geometry Object
|
* @returns {Geometry|null} GeoJSON Geometry Object
|
* @throws {Error} if geojson is not a Feature or Geometry Object
|
* @example
|
* var point = {
|
* "type": "Feature",
|
* "properties": {},
|
* "geometry": {
|
* "type": "Point",
|
* "coordinates": [110, 40]
|
* }
|
* }
|
* var geom = turf.getGeom(point)
|
* //={"type": "Point", "coordinates": [110, 40]}
|
*/
|
function getGeom(geojson) {
|
if (geojson.type === "Feature") {
|
return geojson.geometry;
|
}
|
return geojson;
|
}
|
exports.getGeom = getGeom;
|
/**
|
* Get GeoJSON object's type, Geometry type is prioritize.
|
*
|
* @param {GeoJSON} geojson GeoJSON object
|
* @param {string} [name="geojson"] name of the variable to display in error message
|
* @returns {string} GeoJSON type
|
* @example
|
* var point = {
|
* "type": "Feature",
|
* "properties": {},
|
* "geometry": {
|
* "type": "Point",
|
* "coordinates": [110, 40]
|
* }
|
* }
|
* var geom = turf.getType(point)
|
* //="Point"
|
*/
|
function getType(geojson, name) {
|
if (geojson.type === "FeatureCollection") {
|
return "FeatureCollection";
|
}
|
if (geojson.type === "GeometryCollection") {
|
return "GeometryCollection";
|
}
|
if (geojson.type === "Feature" && geojson.geometry !== null) {
|
return geojson.geometry.type;
|
}
|
return geojson.type;
|
}
|
exports.getType = getType;
|
|
},{"@turf/helpers":14}],18:[function(require,module,exports){
|
'use strict';
|
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
var helpers = require('@turf/helpers');
|
|
/**
|
* Callback for coordEach
|
*
|
* @callback coordEachCallback
|
* @param {Array<number>} currentCoord The current coordinate being processed.
|
* @param {number} coordIndex The current index of the coordinate being processed.
|
* @param {number} featureIndex The current index of the Feature being processed.
|
* @param {number} multiFeatureIndex The current index of the Multi-Feature being processed.
|
* @param {number} geometryIndex The current index of the Geometry being processed.
|
*/
|
|
/**
|
* Iterate over coordinates in any GeoJSON object, similar to Array.forEach()
|
*
|
* @name coordEach
|
* @param {FeatureCollection|Feature|Geometry} geojson any GeoJSON object
|
* @param {Function} callback a method that takes (currentCoord, coordIndex, featureIndex, multiFeatureIndex)
|
* @param {boolean} [excludeWrapCoord=false] whether or not to include the final coordinate of LinearRings that wraps the ring in its iteration.
|
* @returns {void}
|
* @example
|
* var features = turf.featureCollection([
|
* turf.point([26, 37], {"foo": "bar"}),
|
* turf.point([36, 53], {"hello": "world"})
|
* ]);
|
*
|
* turf.coordEach(features, function (currentCoord, coordIndex, featureIndex, multiFeatureIndex, geometryIndex) {
|
* //=currentCoord
|
* //=coordIndex
|
* //=featureIndex
|
* //=multiFeatureIndex
|
* //=geometryIndex
|
* });
|
*/
|
function coordEach(geojson, callback, excludeWrapCoord) {
|
// Handles null Geometry -- Skips this GeoJSON
|
if (geojson === null) return;
|
var j, k, l, geometry, stopG, coords,
|
geometryMaybeCollection,
|
wrapShrink = 0,
|
coordIndex = 0,
|
isGeometryCollection,
|
type = geojson.type,
|
isFeatureCollection = type === 'FeatureCollection',
|
isFeature = type === 'Feature',
|
stop = isFeatureCollection ? geojson.features.length : 1;
|
|
// This logic may look a little weird. The reason why it is that way
|
// is because it's trying to be fast. GeoJSON supports multiple kinds
|
// of objects at its root: FeatureCollection, Features, Geometries.
|
// This function has the responsibility of handling all of them, and that
|
// means that some of the `for` loops you see below actually just don't apply
|
// to certain inputs. For instance, if you give this just a
|
// Point geometry, then both loops are short-circuited and all we do
|
// is gradually rename the input until it's called 'geometry'.
|
//
|
// This also aims to allocate as few resources as possible: just a
|
// few numbers and booleans, rather than any temporary arrays as would
|
// be required with the normalization approach.
|
for (var featureIndex = 0; featureIndex < stop; featureIndex++) {
|
geometryMaybeCollection = (isFeatureCollection ? geojson.features[featureIndex].geometry :
|
(isFeature ? geojson.geometry : geojson));
|
isGeometryCollection = (geometryMaybeCollection) ? geometryMaybeCollection.type === 'GeometryCollection' : false;
|
stopG = isGeometryCollection ? geometryMaybeCollection.geometries.length : 1;
|
|
for (var geomIndex = 0; geomIndex < stopG; geomIndex++) {
|
var multiFeatureIndex = 0;
|
var geometryIndex = 0;
|
geometry = isGeometryCollection ?
|
geometryMaybeCollection.geometries[geomIndex] : geometryMaybeCollection;
|
|
// Handles null Geometry -- Skips this geometry
|
if (geometry === null) continue;
|
coords = geometry.coordinates;
|
var geomType = geometry.type;
|
|
wrapShrink = (excludeWrapCoord && (geomType === 'Polygon' || geomType === 'MultiPolygon')) ? 1 : 0;
|
|
switch (geomType) {
|
case null:
|
break;
|
case 'Point':
|
if (callback(coords, coordIndex, featureIndex, multiFeatureIndex, geometryIndex) === false) return false;
|
coordIndex++;
|
multiFeatureIndex++;
|
break;
|
case 'LineString':
|
case 'MultiPoint':
|
for (j = 0; j < coords.length; j++) {
|
if (callback(coords[j], coordIndex, featureIndex, multiFeatureIndex, geometryIndex) === false) return false;
|
coordIndex++;
|
if (geomType === 'MultiPoint') multiFeatureIndex++;
|
}
|
if (geomType === 'LineString') multiFeatureIndex++;
|
break;
|
case 'Polygon':
|
case 'MultiLineString':
|
for (j = 0; j < coords.length; j++) {
|
for (k = 0; k < coords[j].length - wrapShrink; k++) {
|
if (callback(coords[j][k], coordIndex, featureIndex, multiFeatureIndex, geometryIndex) === false) return false;
|
coordIndex++;
|
}
|
if (geomType === 'MultiLineString') multiFeatureIndex++;
|
if (geomType === 'Polygon') geometryIndex++;
|
}
|
if (geomType === 'Polygon') multiFeatureIndex++;
|
break;
|
case 'MultiPolygon':
|
for (j = 0; j < coords.length; j++) {
|
geometryIndex = 0;
|
for (k = 0; k < coords[j].length; k++) {
|
for (l = 0; l < coords[j][k].length - wrapShrink; l++) {
|
if (callback(coords[j][k][l], coordIndex, featureIndex, multiFeatureIndex, geometryIndex) === false) return false;
|
coordIndex++;
|
}
|
geometryIndex++;
|
}
|
multiFeatureIndex++;
|
}
|
break;
|
case 'GeometryCollection':
|
for (j = 0; j < geometry.geometries.length; j++)
|
if (coordEach(geometry.geometries[j], callback, excludeWrapCoord) === false) return false;
|
break;
|
default:
|
throw new Error('Unknown Geometry Type');
|
}
|
}
|
}
|
}
|
|
/**
|
* Callback for coordReduce
|
*
|
* The first time the callback function is called, the values provided as arguments depend
|
* on whether the reduce method has an initialValue argument.
|
*
|
* If an initialValue is provided to the reduce method:
|
* - The previousValue argument is initialValue.
|
* - The currentValue argument is the value of the first element present in the array.
|
*
|
* If an initialValue is not provided:
|
* - The previousValue argument is the value of the first element present in the array.
|
* - The currentValue argument is the value of the second element present in the array.
|
*
|
* @callback coordReduceCallback
|
* @param {*} previousValue The accumulated value previously returned in the last invocation
|
* of the callback, or initialValue, if supplied.
|
* @param {Array<number>} currentCoord The current coordinate being processed.
|
* @param {number} coordIndex The current index of the coordinate being processed.
|
* Starts at index 0, if an initialValue is provided, and at index 1 otherwise.
|
* @param {number} featureIndex The current index of the Feature being processed.
|
* @param {number} multiFeatureIndex The current index of the Multi-Feature being processed.
|
* @param {number} geometryIndex The current index of the Geometry being processed.
|
*/
|
|
/**
|
* Reduce coordinates in any GeoJSON object, similar to Array.reduce()
|
*
|
* @name coordReduce
|
* @param {FeatureCollection|Geometry|Feature} geojson any GeoJSON object
|
* @param {Function} callback a method that takes (previousValue, currentCoord, coordIndex)
|
* @param {*} [initialValue] Value to use as the first argument to the first call of the callback.
|
* @param {boolean} [excludeWrapCoord=false] whether or not to include the final coordinate of LinearRings that wraps the ring in its iteration.
|
* @returns {*} The value that results from the reduction.
|
* @example
|
* var features = turf.featureCollection([
|
* turf.point([26, 37], {"foo": "bar"}),
|
* turf.point([36, 53], {"hello": "world"})
|
* ]);
|
*
|
* turf.coordReduce(features, function (previousValue, currentCoord, coordIndex, featureIndex, multiFeatureIndex, geometryIndex) {
|
* //=previousValue
|
* //=currentCoord
|
* //=coordIndex
|
* //=featureIndex
|
* //=multiFeatureIndex
|
* //=geometryIndex
|
* return currentCoord;
|
* });
|
*/
|
function coordReduce(geojson, callback, initialValue, excludeWrapCoord) {
|
var previousValue = initialValue;
|
coordEach(geojson, function (currentCoord, coordIndex, featureIndex, multiFeatureIndex, geometryIndex) {
|
if (coordIndex === 0 && initialValue === undefined) previousValue = currentCoord;
|
else previousValue = callback(previousValue, currentCoord, coordIndex, featureIndex, multiFeatureIndex, geometryIndex);
|
}, excludeWrapCoord);
|
return previousValue;
|
}
|
|
/**
|
* Callback for propEach
|
*
|
* @callback propEachCallback
|
* @param {Object} currentProperties The current Properties being processed.
|
* @param {number} featureIndex The current index of the Feature being processed.
|
*/
|
|
/**
|
* Iterate over properties in any GeoJSON object, similar to Array.forEach()
|
*
|
* @name propEach
|
* @param {FeatureCollection|Feature} geojson any GeoJSON object
|
* @param {Function} callback a method that takes (currentProperties, featureIndex)
|
* @returns {void}
|
* @example
|
* var features = turf.featureCollection([
|
* turf.point([26, 37], {foo: 'bar'}),
|
* turf.point([36, 53], {hello: 'world'})
|
* ]);
|
*
|
* turf.propEach(features, function (currentProperties, featureIndex) {
|
* //=currentProperties
|
* //=featureIndex
|
* });
|
*/
|
function propEach(geojson, callback) {
|
var i;
|
switch (geojson.type) {
|
case 'FeatureCollection':
|
for (i = 0; i < geojson.features.length; i++) {
|
if (callback(geojson.features[i].properties, i) === false) break;
|
}
|
break;
|
case 'Feature':
|
callback(geojson.properties, 0);
|
break;
|
}
|
}
|
|
|
/**
|
* Callback for propReduce
|
*
|
* The first time the callback function is called, the values provided as arguments depend
|
* on whether the reduce method has an initialValue argument.
|
*
|
* If an initialValue is provided to the reduce method:
|
* - The previousValue argument is initialValue.
|
* - The currentValue argument is the value of the first element present in the array.
|
*
|
* If an initialValue is not provided:
|
* - The previousValue argument is the value of the first element present in the array.
|
* - The currentValue argument is the value of the second element present in the array.
|
*
|
* @callback propReduceCallback
|
* @param {*} previousValue The accumulated value previously returned in the last invocation
|
* of the callback, or initialValue, if supplied.
|
* @param {*} currentProperties The current Properties being processed.
|
* @param {number} featureIndex The current index of the Feature being processed.
|
*/
|
|
/**
|
* Reduce properties in any GeoJSON object into a single value,
|
* similar to how Array.reduce works. However, in this case we lazily run
|
* the reduction, so an array of all properties is unnecessary.
|
*
|
* @name propReduce
|
* @param {FeatureCollection|Feature} geojson any GeoJSON object
|
* @param {Function} callback a method that takes (previousValue, currentProperties, featureIndex)
|
* @param {*} [initialValue] Value to use as the first argument to the first call of the callback.
|
* @returns {*} The value that results from the reduction.
|
* @example
|
* var features = turf.featureCollection([
|
* turf.point([26, 37], {foo: 'bar'}),
|
* turf.point([36, 53], {hello: 'world'})
|
* ]);
|
*
|
* turf.propReduce(features, function (previousValue, currentProperties, featureIndex) {
|
* //=previousValue
|
* //=currentProperties
|
* //=featureIndex
|
* return currentProperties
|
* });
|
*/
|
function propReduce(geojson, callback, initialValue) {
|
var previousValue = initialValue;
|
propEach(geojson, function (currentProperties, featureIndex) {
|
if (featureIndex === 0 && initialValue === undefined) previousValue = currentProperties;
|
else previousValue = callback(previousValue, currentProperties, featureIndex);
|
});
|
return previousValue;
|
}
|
|
/**
|
* Callback for featureEach
|
*
|
* @callback featureEachCallback
|
* @param {Feature<any>} currentFeature The current Feature being processed.
|
* @param {number} featureIndex The current index of the Feature being processed.
|
*/
|
|
/**
|
* Iterate over features in any GeoJSON object, similar to
|
* Array.forEach.
|
*
|
* @name featureEach
|
* @param {FeatureCollection|Feature|Geometry} geojson any GeoJSON object
|
* @param {Function} callback a method that takes (currentFeature, featureIndex)
|
* @returns {void}
|
* @example
|
* var features = turf.featureCollection([
|
* turf.point([26, 37], {foo: 'bar'}),
|
* turf.point([36, 53], {hello: 'world'})
|
* ]);
|
*
|
* turf.featureEach(features, function (currentFeature, featureIndex) {
|
* //=currentFeature
|
* //=featureIndex
|
* });
|
*/
|
function featureEach(geojson, callback) {
|
if (geojson.type === 'Feature') {
|
callback(geojson, 0);
|
} else if (geojson.type === 'FeatureCollection') {
|
for (var i = 0; i < geojson.features.length; i++) {
|
if (callback(geojson.features[i], i) === false) break;
|
}
|
}
|
}
|
|
/**
|
* Callback for featureReduce
|
*
|
* The first time the callback function is called, the values provided as arguments depend
|
* on whether the reduce method has an initialValue argument.
|
*
|
* If an initialValue is provided to the reduce method:
|
* - The previousValue argument is initialValue.
|
* - The currentValue argument is the value of the first element present in the array.
|
*
|
* If an initialValue is not provided:
|
* - The previousValue argument is the value of the first element present in the array.
|
* - The currentValue argument is the value of the second element present in the array.
|
*
|
* @callback featureReduceCallback
|
* @param {*} previousValue The accumulated value previously returned in the last invocation
|
* of the callback, or initialValue, if supplied.
|
* @param {Feature} currentFeature The current Feature being processed.
|
* @param {number} featureIndex The current index of the Feature being processed.
|
*/
|
|
/**
|
* Reduce features in any GeoJSON object, similar to Array.reduce().
|
*
|
* @name featureReduce
|
* @param {FeatureCollection|Feature|Geometry} geojson any GeoJSON object
|
* @param {Function} callback a method that takes (previousValue, currentFeature, featureIndex)
|
* @param {*} [initialValue] Value to use as the first argument to the first call of the callback.
|
* @returns {*} The value that results from the reduction.
|
* @example
|
* var features = turf.featureCollection([
|
* turf.point([26, 37], {"foo": "bar"}),
|
* turf.point([36, 53], {"hello": "world"})
|
* ]);
|
*
|
* turf.featureReduce(features, function (previousValue, currentFeature, featureIndex) {
|
* //=previousValue
|
* //=currentFeature
|
* //=featureIndex
|
* return currentFeature
|
* });
|
*/
|
function featureReduce(geojson, callback, initialValue) {
|
var previousValue = initialValue;
|
featureEach(geojson, function (currentFeature, featureIndex) {
|
if (featureIndex === 0 && initialValue === undefined) previousValue = currentFeature;
|
else previousValue = callback(previousValue, currentFeature, featureIndex);
|
});
|
return previousValue;
|
}
|
|
/**
|
* Get all coordinates from any GeoJSON object.
|
*
|
* @name coordAll
|
* @param {FeatureCollection|Feature|Geometry} geojson any GeoJSON object
|
* @returns {Array<Array<number>>} coordinate position array
|
* @example
|
* var features = turf.featureCollection([
|
* turf.point([26, 37], {foo: 'bar'}),
|
* turf.point([36, 53], {hello: 'world'})
|
* ]);
|
*
|
* var coords = turf.coordAll(features);
|
* //= [[26, 37], [36, 53]]
|
*/
|
function coordAll(geojson) {
|
var coords = [];
|
coordEach(geojson, function (coord) {
|
coords.push(coord);
|
});
|
return coords;
|
}
|
|
/**
|
* Callback for geomEach
|
*
|
* @callback geomEachCallback
|
* @param {Geometry} currentGeometry The current Geometry being processed.
|
* @param {number} featureIndex The current index of the Feature being processed.
|
* @param {Object} featureProperties The current Feature Properties being processed.
|
* @param {Array<number>} featureBBox The current Feature BBox being processed.
|
* @param {number|string} featureId The current Feature Id being processed.
|
*/
|
|
/**
|
* Iterate over each geometry in any GeoJSON object, similar to Array.forEach()
|
*
|
* @name geomEach
|
* @param {FeatureCollection|Feature|Geometry} geojson any GeoJSON object
|
* @param {Function} callback a method that takes (currentGeometry, featureIndex, featureProperties, featureBBox, featureId)
|
* @returns {void}
|
* @example
|
* var features = turf.featureCollection([
|
* turf.point([26, 37], {foo: 'bar'}),
|
* turf.point([36, 53], {hello: 'world'})
|
* ]);
|
*
|
* turf.geomEach(features, function (currentGeometry, featureIndex, featureProperties, featureBBox, featureId) {
|
* //=currentGeometry
|
* //=featureIndex
|
* //=featureProperties
|
* //=featureBBox
|
* //=featureId
|
* });
|
*/
|
function geomEach(geojson, callback) {
|
var i, j, g, geometry, stopG,
|
geometryMaybeCollection,
|
isGeometryCollection,
|
featureProperties,
|
featureBBox,
|
featureId,
|
featureIndex = 0,
|
isFeatureCollection = geojson.type === 'FeatureCollection',
|
isFeature = geojson.type === 'Feature',
|
stop = isFeatureCollection ? geojson.features.length : 1;
|
|
// This logic may look a little weird. The reason why it is that way
|
// is because it's trying to be fast. GeoJSON supports multiple kinds
|
// of objects at its root: FeatureCollection, Features, Geometries.
|
// This function has the responsibility of handling all of them, and that
|
// means that some of the `for` loops you see below actually just don't apply
|
// to certain inputs. For instance, if you give this just a
|
// Point geometry, then both loops are short-circuited and all we do
|
// is gradually rename the input until it's called 'geometry'.
|
//
|
// This also aims to allocate as few resources as possible: just a
|
// few numbers and booleans, rather than any temporary arrays as would
|
// be required with the normalization approach.
|
for (i = 0; i < stop; i++) {
|
|
geometryMaybeCollection = (isFeatureCollection ? geojson.features[i].geometry :
|
(isFeature ? geojson.geometry : geojson));
|
featureProperties = (isFeatureCollection ? geojson.features[i].properties :
|
(isFeature ? geojson.properties : {}));
|
featureBBox = (isFeatureCollection ? geojson.features[i].bbox :
|
(isFeature ? geojson.bbox : undefined));
|
featureId = (isFeatureCollection ? geojson.features[i].id :
|
(isFeature ? geojson.id : undefined));
|
isGeometryCollection = (geometryMaybeCollection) ? geometryMaybeCollection.type === 'GeometryCollection' : false;
|
stopG = isGeometryCollection ? geometryMaybeCollection.geometries.length : 1;
|
|
for (g = 0; g < stopG; g++) {
|
geometry = isGeometryCollection ?
|
geometryMaybeCollection.geometries[g] : geometryMaybeCollection;
|
|
// Handle null Geometry
|
if (geometry === null) {
|
if (callback(null, featureIndex, featureProperties, featureBBox, featureId) === false) return false;
|
continue;
|
}
|
switch (geometry.type) {
|
case 'Point':
|
case 'LineString':
|
case 'MultiPoint':
|
case 'Polygon':
|
case 'MultiLineString':
|
case 'MultiPolygon': {
|
if (callback(geometry, featureIndex, featureProperties, featureBBox, featureId) === false) return false;
|
break;
|
}
|
case 'GeometryCollection': {
|
for (j = 0; j < geometry.geometries.length; j++) {
|
if (callback(geometry.geometries[j], featureIndex, featureProperties, featureBBox, featureId) === false) return false;
|
}
|
break;
|
}
|
default:
|
throw new Error('Unknown Geometry Type');
|
}
|
}
|
// Only increase `featureIndex` per each feature
|
featureIndex++;
|
}
|
}
|
|
/**
|
* Callback for geomReduce
|
*
|
* The first time the callback function is called, the values provided as arguments depend
|
* on whether the reduce method has an initialValue argument.
|
*
|
* If an initialValue is provided to the reduce method:
|
* - The previousValue argument is initialValue.
|
* - The currentValue argument is the value of the first element present in the array.
|
*
|
* If an initialValue is not provided:
|
* - The previousValue argument is the value of the first element present in the array.
|
* - The currentValue argument is the value of the second element present in the array.
|
*
|
* @callback geomReduceCallback
|
* @param {*} previousValue The accumulated value previously returned in the last invocation
|
* of the callback, or initialValue, if supplied.
|
* @param {Geometry} currentGeometry The current Geometry being processed.
|
* @param {number} featureIndex The current index of the Feature being processed.
|
* @param {Object} featureProperties The current Feature Properties being processed.
|
* @param {Array<number>} featureBBox The current Feature BBox being processed.
|
* @param {number|string} featureId The current Feature Id being processed.
|
*/
|
|
/**
|
* Reduce geometry in any GeoJSON object, similar to Array.reduce().
|
*
|
* @name geomReduce
|
* @param {FeatureCollection|Feature|Geometry} geojson any GeoJSON object
|
* @param {Function} callback a method that takes (previousValue, currentGeometry, featureIndex, featureProperties, featureBBox, featureId)
|
* @param {*} [initialValue] Value to use as the first argument to the first call of the callback.
|
* @returns {*} The value that results from the reduction.
|
* @example
|
* var features = turf.featureCollection([
|
* turf.point([26, 37], {foo: 'bar'}),
|
* turf.point([36, 53], {hello: 'world'})
|
* ]);
|
*
|
* turf.geomReduce(features, function (previousValue, currentGeometry, featureIndex, featureProperties, featureBBox, featureId) {
|
* //=previousValue
|
* //=currentGeometry
|
* //=featureIndex
|
* //=featureProperties
|
* //=featureBBox
|
* //=featureId
|
* return currentGeometry
|
* });
|
*/
|
function geomReduce(geojson, callback, initialValue) {
|
var previousValue = initialValue;
|
geomEach(geojson, function (currentGeometry, featureIndex, featureProperties, featureBBox, featureId) {
|
if (featureIndex === 0 && initialValue === undefined) previousValue = currentGeometry;
|
else previousValue = callback(previousValue, currentGeometry, featureIndex, featureProperties, featureBBox, featureId);
|
});
|
return previousValue;
|
}
|
|
/**
|
* Callback for flattenEach
|
*
|
* @callback flattenEachCallback
|
* @param {Feature} currentFeature The current flattened feature being processed.
|
* @param {number} featureIndex The current index of the Feature being processed.
|
* @param {number} multiFeatureIndex The current index of the Multi-Feature being processed.
|
*/
|
|
/**
|
* Iterate over flattened features in any GeoJSON object, similar to
|
* Array.forEach.
|
*
|
* @name flattenEach
|
* @param {FeatureCollection|Feature|Geometry} geojson any GeoJSON object
|
* @param {Function} callback a method that takes (currentFeature, featureIndex, multiFeatureIndex)
|
* @example
|
* var features = turf.featureCollection([
|
* turf.point([26, 37], {foo: 'bar'}),
|
* turf.multiPoint([[40, 30], [36, 53]], {hello: 'world'})
|
* ]);
|
*
|
* turf.flattenEach(features, function (currentFeature, featureIndex, multiFeatureIndex) {
|
* //=currentFeature
|
* //=featureIndex
|
* //=multiFeatureIndex
|
* });
|
*/
|
function flattenEach(geojson, callback) {
|
geomEach(geojson, function (geometry, featureIndex, properties, bbox, id) {
|
// Callback for single geometry
|
var type = (geometry === null) ? null : geometry.type;
|
switch (type) {
|
case null:
|
case 'Point':
|
case 'LineString':
|
case 'Polygon':
|
if (callback(helpers.feature(geometry, properties, {bbox: bbox, id: id}), featureIndex, 0) === false) return false;
|
return;
|
}
|
|
var geomType;
|
|
// Callback for multi-geometry
|
switch (type) {
|
case 'MultiPoint':
|
geomType = 'Point';
|
break;
|
case 'MultiLineString':
|
geomType = 'LineString';
|
break;
|
case 'MultiPolygon':
|
geomType = 'Polygon';
|
break;
|
}
|
|
for (var multiFeatureIndex = 0; multiFeatureIndex < geometry.coordinates.length; multiFeatureIndex++) {
|
var coordinate = geometry.coordinates[multiFeatureIndex];
|
var geom = {
|
type: geomType,
|
coordinates: coordinate
|
};
|
if (callback(helpers.feature(geom, properties), featureIndex, multiFeatureIndex) === false) return false;
|
}
|
});
|
}
|
|
/**
|
* Callback for flattenReduce
|
*
|
* The first time the callback function is called, the values provided as arguments depend
|
* on whether the reduce method has an initialValue argument.
|
*
|
* If an initialValue is provided to the reduce method:
|
* - The previousValue argument is initialValue.
|
* - The currentValue argument is the value of the first element present in the array.
|
*
|
* If an initialValue is not provided:
|
* - The previousValue argument is the value of the first element present in the array.
|
* - The currentValue argument is the value of the second element present in the array.
|
*
|
* @callback flattenReduceCallback
|
* @param {*} previousValue The accumulated value previously returned in the last invocation
|
* of the callback, or initialValue, if supplied.
|
* @param {Feature} currentFeature The current Feature being processed.
|
* @param {number} featureIndex The current index of the Feature being processed.
|
* @param {number} multiFeatureIndex The current index of the Multi-Feature being processed.
|
*/
|
|
/**
|
* Reduce flattened features in any GeoJSON object, similar to Array.reduce().
|
*
|
* @name flattenReduce
|
* @param {FeatureCollection|Feature|Geometry} geojson any GeoJSON object
|
* @param {Function} callback a method that takes (previousValue, currentFeature, featureIndex, multiFeatureIndex)
|
* @param {*} [initialValue] Value to use as the first argument to the first call of the callback.
|
* @returns {*} The value that results from the reduction.
|
* @example
|
* var features = turf.featureCollection([
|
* turf.point([26, 37], {foo: 'bar'}),
|
* turf.multiPoint([[40, 30], [36, 53]], {hello: 'world'})
|
* ]);
|
*
|
* turf.flattenReduce(features, function (previousValue, currentFeature, featureIndex, multiFeatureIndex) {
|
* //=previousValue
|
* //=currentFeature
|
* //=featureIndex
|
* //=multiFeatureIndex
|
* return currentFeature
|
* });
|
*/
|
function flattenReduce(geojson, callback, initialValue) {
|
var previousValue = initialValue;
|
flattenEach(geojson, function (currentFeature, featureIndex, multiFeatureIndex) {
|
if (featureIndex === 0 && multiFeatureIndex === 0 && initialValue === undefined) previousValue = currentFeature;
|
else previousValue = callback(previousValue, currentFeature, featureIndex, multiFeatureIndex);
|
});
|
return previousValue;
|
}
|
|
/**
|
* Callback for segmentEach
|
*
|
* @callback segmentEachCallback
|
* @param {Feature<LineString>} currentSegment The current Segment being processed.
|
* @param {number} featureIndex The current index of the Feature being processed.
|
* @param {number} multiFeatureIndex The current index of the Multi-Feature being processed.
|
* @param {number} geometryIndex The current index of the Geometry being processed.
|
* @param {number} segmentIndex The current index of the Segment being processed.
|
* @returns {void}
|
*/
|
|
/**
|
* Iterate over 2-vertex line segment in any GeoJSON object, similar to Array.forEach()
|
* (Multi)Point geometries do not contain segments therefore they are ignored during this operation.
|
*
|
* @param {FeatureCollection|Feature|Geometry} geojson any GeoJSON
|
* @param {Function} callback a method that takes (currentSegment, featureIndex, multiFeatureIndex, geometryIndex, segmentIndex)
|
* @returns {void}
|
* @example
|
* var polygon = turf.polygon([[[-50, 5], [-40, -10], [-50, -10], [-40, 5], [-50, 5]]]);
|
*
|
* // Iterate over GeoJSON by 2-vertex segments
|
* turf.segmentEach(polygon, function (currentSegment, featureIndex, multiFeatureIndex, geometryIndex, segmentIndex) {
|
* //=currentSegment
|
* //=featureIndex
|
* //=multiFeatureIndex
|
* //=geometryIndex
|
* //=segmentIndex
|
* });
|
*
|
* // Calculate the total number of segments
|
* var total = 0;
|
* turf.segmentEach(polygon, function () {
|
* total++;
|
* });
|
*/
|
function segmentEach(geojson, callback) {
|
flattenEach(geojson, function (feature, featureIndex, multiFeatureIndex) {
|
var segmentIndex = 0;
|
|
// Exclude null Geometries
|
if (!feature.geometry) return;
|
// (Multi)Point geometries do not contain segments therefore they are ignored during this operation.
|
var type = feature.geometry.type;
|
if (type === 'Point' || type === 'MultiPoint') return;
|
|
// Generate 2-vertex line segments
|
var previousCoords;
|
var previousFeatureIndex = 0;
|
var previousMultiIndex = 0;
|
var prevGeomIndex = 0;
|
if (coordEach(feature, function (currentCoord, coordIndex, featureIndexCoord, multiPartIndexCoord, geometryIndex) {
|
// Simulating a meta.coordReduce() since `reduce` operations cannot be stopped by returning `false`
|
if (previousCoords === undefined || featureIndex > previousFeatureIndex || multiPartIndexCoord > previousMultiIndex || geometryIndex > prevGeomIndex) {
|
previousCoords = currentCoord;
|
previousFeatureIndex = featureIndex;
|
previousMultiIndex = multiPartIndexCoord;
|
prevGeomIndex = geometryIndex;
|
segmentIndex = 0;
|
return;
|
}
|
var currentSegment = helpers.lineString([previousCoords, currentCoord], feature.properties);
|
if (callback(currentSegment, featureIndex, multiFeatureIndex, geometryIndex, segmentIndex) === false) return false;
|
segmentIndex++;
|
previousCoords = currentCoord;
|
}) === false) return false;
|
});
|
}
|
|
/**
|
* Callback for segmentReduce
|
*
|
* The first time the callback function is called, the values provided as arguments depend
|
* on whether the reduce method has an initialValue argument.
|
*
|
* If an initialValue is provided to the reduce method:
|
* - The previousValue argument is initialValue.
|
* - The currentValue argument is the value of the first element present in the array.
|
*
|
* If an initialValue is not provided:
|
* - The previousValue argument is the value of the first element present in the array.
|
* - The currentValue argument is the value of the second element present in the array.
|
*
|
* @callback segmentReduceCallback
|
* @param {*} previousValue The accumulated value previously returned in the last invocation
|
* of the callback, or initialValue, if supplied.
|
* @param {Feature<LineString>} currentSegment The current Segment being processed.
|
* @param {number} featureIndex The current index of the Feature being processed.
|
* @param {number} multiFeatureIndex The current index of the Multi-Feature being processed.
|
* @param {number} geometryIndex The current index of the Geometry being processed.
|
* @param {number} segmentIndex The current index of the Segment being processed.
|
*/
|
|
/**
|
* Reduce 2-vertex line segment in any GeoJSON object, similar to Array.reduce()
|
* (Multi)Point geometries do not contain segments therefore they are ignored during this operation.
|
*
|
* @param {FeatureCollection|Feature|Geometry} geojson any GeoJSON
|
* @param {Function} callback a method that takes (previousValue, currentSegment, currentIndex)
|
* @param {*} [initialValue] Value to use as the first argument to the first call of the callback.
|
* @returns {void}
|
* @example
|
* var polygon = turf.polygon([[[-50, 5], [-40, -10], [-50, -10], [-40, 5], [-50, 5]]]);
|
*
|
* // Iterate over GeoJSON by 2-vertex segments
|
* turf.segmentReduce(polygon, function (previousSegment, currentSegment, featureIndex, multiFeatureIndex, geometryIndex, segmentIndex) {
|
* //= previousSegment
|
* //= currentSegment
|
* //= featureIndex
|
* //= multiFeatureIndex
|
* //= geometryIndex
|
* //= segmentInex
|
* return currentSegment
|
* });
|
*
|
* // Calculate the total number of segments
|
* var initialValue = 0
|
* var total = turf.segmentReduce(polygon, function (previousValue) {
|
* previousValue++;
|
* return previousValue;
|
* }, initialValue);
|
*/
|
function segmentReduce(geojson, callback, initialValue) {
|
var previousValue = initialValue;
|
var started = false;
|
segmentEach(geojson, function (currentSegment, featureIndex, multiFeatureIndex, geometryIndex, segmentIndex) {
|
if (started === false && initialValue === undefined) previousValue = currentSegment;
|
else previousValue = callback(previousValue, currentSegment, featureIndex, multiFeatureIndex, geometryIndex, segmentIndex);
|
started = true;
|
});
|
return previousValue;
|
}
|
|
/**
|
* Callback for lineEach
|
*
|
* @callback lineEachCallback
|
* @param {Feature<LineString>} currentLine The current LineString|LinearRing being processed
|
* @param {number} featureIndex The current index of the Feature being processed
|
* @param {number} multiFeatureIndex The current index of the Multi-Feature being processed
|
* @param {number} geometryIndex The current index of the Geometry being processed
|
*/
|
|
/**
|
* Iterate over line or ring coordinates in LineString, Polygon, MultiLineString, MultiPolygon Features or Geometries,
|
* similar to Array.forEach.
|
*
|
* @name lineEach
|
* @param {Geometry|Feature<LineString|Polygon|MultiLineString|MultiPolygon>} geojson object
|
* @param {Function} callback a method that takes (currentLine, featureIndex, multiFeatureIndex, geometryIndex)
|
* @example
|
* var multiLine = turf.multiLineString([
|
* [[26, 37], [35, 45]],
|
* [[36, 53], [38, 50], [41, 55]]
|
* ]);
|
*
|
* turf.lineEach(multiLine, function (currentLine, featureIndex, multiFeatureIndex, geometryIndex) {
|
* //=currentLine
|
* //=featureIndex
|
* //=multiFeatureIndex
|
* //=geometryIndex
|
* });
|
*/
|
function lineEach(geojson, callback) {
|
// validation
|
if (!geojson) throw new Error('geojson is required');
|
|
flattenEach(geojson, function (feature, featureIndex, multiFeatureIndex) {
|
if (feature.geometry === null) return;
|
var type = feature.geometry.type;
|
var coords = feature.geometry.coordinates;
|
switch (type) {
|
case 'LineString':
|
if (callback(feature, featureIndex, multiFeatureIndex, 0, 0) === false) return false;
|
break;
|
case 'Polygon':
|
for (var geometryIndex = 0; geometryIndex < coords.length; geometryIndex++) {
|
if (callback(helpers.lineString(coords[geometryIndex], feature.properties), featureIndex, multiFeatureIndex, geometryIndex) === false) return false;
|
}
|
break;
|
}
|
});
|
}
|
|
/**
|
* Callback for lineReduce
|
*
|
* The first time the callback function is called, the values provided as arguments depend
|
* on whether the reduce method has an initialValue argument.
|
*
|
* If an initialValue is provided to the reduce method:
|
* - The previousValue argument is initialValue.
|
* - The currentValue argument is the value of the first element present in the array.
|
*
|
* If an initialValue is not provided:
|
* - The previousValue argument is the value of the first element present in the array.
|
* - The currentValue argument is the value of the second element present in the array.
|
*
|
* @callback lineReduceCallback
|
* @param {*} previousValue The accumulated value previously returned in the last invocation
|
* of the callback, or initialValue, if supplied.
|
* @param {Feature<LineString>} currentLine The current LineString|LinearRing being processed.
|
* @param {number} featureIndex The current index of the Feature being processed
|
* @param {number} multiFeatureIndex The current index of the Multi-Feature being processed
|
* @param {number} geometryIndex The current index of the Geometry being processed
|
*/
|
|
/**
|
* Reduce features in any GeoJSON object, similar to Array.reduce().
|
*
|
* @name lineReduce
|
* @param {Geometry|Feature<LineString|Polygon|MultiLineString|MultiPolygon>} geojson object
|
* @param {Function} callback a method that takes (previousValue, currentLine, featureIndex, multiFeatureIndex, geometryIndex)
|
* @param {*} [initialValue] Value to use as the first argument to the first call of the callback.
|
* @returns {*} The value that results from the reduction.
|
* @example
|
* var multiPoly = turf.multiPolygon([
|
* turf.polygon([[[12,48],[2,41],[24,38],[12,48]], [[9,44],[13,41],[13,45],[9,44]]]),
|
* turf.polygon([[[5, 5], [0, 0], [2, 2], [4, 4], [5, 5]]])
|
* ]);
|
*
|
* turf.lineReduce(multiPoly, function (previousValue, currentLine, featureIndex, multiFeatureIndex, geometryIndex) {
|
* //=previousValue
|
* //=currentLine
|
* //=featureIndex
|
* //=multiFeatureIndex
|
* //=geometryIndex
|
* return currentLine
|
* });
|
*/
|
function lineReduce(geojson, callback, initialValue) {
|
var previousValue = initialValue;
|
lineEach(geojson, function (currentLine, featureIndex, multiFeatureIndex, geometryIndex) {
|
if (featureIndex === 0 && initialValue === undefined) previousValue = currentLine;
|
else previousValue = callback(previousValue, currentLine, featureIndex, multiFeatureIndex, geometryIndex);
|
});
|
return previousValue;
|
}
|
|
/**
|
* Finds a particular 2-vertex LineString Segment from a GeoJSON using `@turf/meta` indexes.
|
*
|
* Negative indexes are permitted.
|
* Point & MultiPoint will always return null.
|
*
|
* @param {FeatureCollection|Feature|Geometry} geojson Any GeoJSON Feature or Geometry
|
* @param {Object} [options={}] Optional parameters
|
* @param {number} [options.featureIndex=0] Feature Index
|
* @param {number} [options.multiFeatureIndex=0] Multi-Feature Index
|
* @param {number} [options.geometryIndex=0] Geometry Index
|
* @param {number} [options.segmentIndex=0] Segment Index
|
* @param {Object} [options.properties={}] Translate Properties to output LineString
|
* @param {BBox} [options.bbox={}] Translate BBox to output LineString
|
* @param {number|string} [options.id={}] Translate Id to output LineString
|
* @returns {Feature<LineString>} 2-vertex GeoJSON Feature LineString
|
* @example
|
* var multiLine = turf.multiLineString([
|
* [[10, 10], [50, 30], [30, 40]],
|
* [[-10, -10], [-50, -30], [-30, -40]]
|
* ]);
|
*
|
* // First Segment (defaults are 0)
|
* turf.findSegment(multiLine);
|
* // => Feature<LineString<[[10, 10], [50, 30]]>>
|
*
|
* // First Segment of 2nd Multi Feature
|
* turf.findSegment(multiLine, {multiFeatureIndex: 1});
|
* // => Feature<LineString<[[-10, -10], [-50, -30]]>>
|
*
|
* // Last Segment of Last Multi Feature
|
* turf.findSegment(multiLine, {multiFeatureIndex: -1, segmentIndex: -1});
|
* // => Feature<LineString<[[-50, -30], [-30, -40]]>>
|
*/
|
function findSegment(geojson, options) {
|
// Optional Parameters
|
options = options || {};
|
if (!helpers.isObject(options)) throw new Error('options is invalid');
|
var featureIndex = options.featureIndex || 0;
|
var multiFeatureIndex = options.multiFeatureIndex || 0;
|
var geometryIndex = options.geometryIndex || 0;
|
var segmentIndex = options.segmentIndex || 0;
|
|
// Find FeatureIndex
|
var properties = options.properties;
|
var geometry;
|
|
switch (geojson.type) {
|
case 'FeatureCollection':
|
if (featureIndex < 0) featureIndex = geojson.features.length + featureIndex;
|
properties = properties || geojson.features[featureIndex].properties;
|
geometry = geojson.features[featureIndex].geometry;
|
break;
|
case 'Feature':
|
properties = properties || geojson.properties;
|
geometry = geojson.geometry;
|
break;
|
case 'Point':
|
case 'MultiPoint':
|
return null;
|
case 'LineString':
|
case 'Polygon':
|
case 'MultiLineString':
|
case 'MultiPolygon':
|
geometry = geojson;
|
break;
|
default:
|
throw new Error('geojson is invalid');
|
}
|
|
// Find SegmentIndex
|
if (geometry === null) return null;
|
var coords = geometry.coordinates;
|
switch (geometry.type) {
|
case 'Point':
|
case 'MultiPoint':
|
return null;
|
case 'LineString':
|
if (segmentIndex < 0) segmentIndex = coords.length + segmentIndex - 1;
|
return helpers.lineString([coords[segmentIndex], coords[segmentIndex + 1]], properties, options);
|
case 'Polygon':
|
if (geometryIndex < 0) geometryIndex = coords.length + geometryIndex;
|
if (segmentIndex < 0) segmentIndex = coords[geometryIndex].length + segmentIndex - 1;
|
return helpers.lineString([coords[geometryIndex][segmentIndex], coords[geometryIndex][segmentIndex + 1]], properties, options);
|
case 'MultiLineString':
|
if (multiFeatureIndex < 0) multiFeatureIndex = coords.length + multiFeatureIndex;
|
if (segmentIndex < 0) segmentIndex = coords[multiFeatureIndex].length + segmentIndex - 1;
|
return helpers.lineString([coords[multiFeatureIndex][segmentIndex], coords[multiFeatureIndex][segmentIndex + 1]], properties, options);
|
case 'MultiPolygon':
|
if (multiFeatureIndex < 0) multiFeatureIndex = coords.length + multiFeatureIndex;
|
if (geometryIndex < 0) geometryIndex = coords[multiFeatureIndex].length + geometryIndex;
|
if (segmentIndex < 0) segmentIndex = coords[multiFeatureIndex][geometryIndex].length - segmentIndex - 1;
|
return helpers.lineString([coords[multiFeatureIndex][geometryIndex][segmentIndex], coords[multiFeatureIndex][geometryIndex][segmentIndex + 1]], properties, options);
|
}
|
throw new Error('geojson is invalid');
|
}
|
|
/**
|
* Finds a particular Point from a GeoJSON using `@turf/meta` indexes.
|
*
|
* Negative indexes are permitted.
|
*
|
* @param {FeatureCollection|Feature|Geometry} geojson Any GeoJSON Feature or Geometry
|
* @param {Object} [options={}] Optional parameters
|
* @param {number} [options.featureIndex=0] Feature Index
|
* @param {number} [options.multiFeatureIndex=0] Multi-Feature Index
|
* @param {number} [options.geometryIndex=0] Geometry Index
|
* @param {number} [options.coordIndex=0] Coord Index
|
* @param {Object} [options.properties={}] Translate Properties to output Point
|
* @param {BBox} [options.bbox={}] Translate BBox to output Point
|
* @param {number|string} [options.id={}] Translate Id to output Point
|
* @returns {Feature<Point>} 2-vertex GeoJSON Feature Point
|
* @example
|
* var multiLine = turf.multiLineString([
|
* [[10, 10], [50, 30], [30, 40]],
|
* [[-10, -10], [-50, -30], [-30, -40]]
|
* ]);
|
*
|
* // First Segment (defaults are 0)
|
* turf.findPoint(multiLine);
|
* // => Feature<Point<[10, 10]>>
|
*
|
* // First Segment of the 2nd Multi-Feature
|
* turf.findPoint(multiLine, {multiFeatureIndex: 1});
|
* // => Feature<Point<[-10, -10]>>
|
*
|
* // Last Segment of last Multi-Feature
|
* turf.findPoint(multiLine, {multiFeatureIndex: -1, coordIndex: -1});
|
* // => Feature<Point<[-30, -40]>>
|
*/
|
function findPoint(geojson, options) {
|
// Optional Parameters
|
options = options || {};
|
if (!helpers.isObject(options)) throw new Error('options is invalid');
|
var featureIndex = options.featureIndex || 0;
|
var multiFeatureIndex = options.multiFeatureIndex || 0;
|
var geometryIndex = options.geometryIndex || 0;
|
var coordIndex = options.coordIndex || 0;
|
|
// Find FeatureIndex
|
var properties = options.properties;
|
var geometry;
|
|
switch (geojson.type) {
|
case 'FeatureCollection':
|
if (featureIndex < 0) featureIndex = geojson.features.length + featureIndex;
|
properties = properties || geojson.features[featureIndex].properties;
|
geometry = geojson.features[featureIndex].geometry;
|
break;
|
case 'Feature':
|
properties = properties || geojson.properties;
|
geometry = geojson.geometry;
|
break;
|
case 'Point':
|
case 'MultiPoint':
|
return null;
|
case 'LineString':
|
case 'Polygon':
|
case 'MultiLineString':
|
case 'MultiPolygon':
|
geometry = geojson;
|
break;
|
default:
|
throw new Error('geojson is invalid');
|
}
|
|
// Find Coord Index
|
if (geometry === null) return null;
|
var coords = geometry.coordinates;
|
switch (geometry.type) {
|
case 'Point':
|
return helpers.point(coords, properties, options);
|
case 'MultiPoint':
|
if (multiFeatureIndex < 0) multiFeatureIndex = coords.length + multiFeatureIndex;
|
return helpers.point(coords[multiFeatureIndex], properties, options);
|
case 'LineString':
|
if (coordIndex < 0) coordIndex = coords.length + coordIndex;
|
return helpers.point(coords[coordIndex], properties, options);
|
case 'Polygon':
|
if (geometryIndex < 0) geometryIndex = coords.length + geometryIndex;
|
if (coordIndex < 0) coordIndex = coords[geometryIndex].length + coordIndex;
|
return helpers.point(coords[geometryIndex][coordIndex], properties, options);
|
case 'MultiLineString':
|
if (multiFeatureIndex < 0) multiFeatureIndex = coords.length + multiFeatureIndex;
|
if (coordIndex < 0) coordIndex = coords[multiFeatureIndex].length + coordIndex;
|
return helpers.point(coords[multiFeatureIndex][coordIndex], properties, options);
|
case 'MultiPolygon':
|
if (multiFeatureIndex < 0) multiFeatureIndex = coords.length + multiFeatureIndex;
|
if (geometryIndex < 0) geometryIndex = coords[multiFeatureIndex].length + geometryIndex;
|
if (coordIndex < 0) coordIndex = coords[multiFeatureIndex][geometryIndex].length - coordIndex;
|
return helpers.point(coords[multiFeatureIndex][geometryIndex][coordIndex], properties, options);
|
}
|
throw new Error('geojson is invalid');
|
}
|
|
exports.coordEach = coordEach;
|
exports.coordReduce = coordReduce;
|
exports.propEach = propEach;
|
exports.propReduce = propReduce;
|
exports.featureEach = featureEach;
|
exports.featureReduce = featureReduce;
|
exports.coordAll = coordAll;
|
exports.geomEach = geomEach;
|
exports.geomReduce = geomReduce;
|
exports.flattenEach = flattenEach;
|
exports.flattenReduce = flattenReduce;
|
exports.segmentEach = segmentEach;
|
exports.segmentReduce = segmentReduce;
|
exports.lineEach = lineEach;
|
exports.lineReduce = lineReduce;
|
exports.findSegment = findSegment;
|
exports.findPoint = findPoint;
|
|
},{"@turf/helpers":14}],19:[function(require,module,exports){
|
"use strict";
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
}
|
Object.defineProperty(exports, "__esModule", { value: true });
|
// Taken from http://geomalgorithms.com/a02-_lines.html
|
var distance_1 = __importDefault(require("@turf/distance"));
|
var helpers_1 = require("@turf/helpers");
|
var invariant_1 = require("@turf/invariant");
|
var meta_1 = require("@turf/meta");
|
var rhumb_distance_1 = __importDefault(require("@turf/rhumb-distance"));
|
/**
|
* Returns the minimum distance between a {@link Point} and a {@link LineString}, being the distance from a line the
|
* minimum distance between the point and any segment of the `LineString`.
|
*
|
* @name pointToLineDistance
|
* @param {Feature<Point>|Array<number>} pt Feature or Geometry
|
* @param {Feature<LineString>} line GeoJSON Feature or Geometry
|
* @param {Object} [options={}] Optional parameters
|
* @param {string} [options.units="kilometers"] can be anything supported by turf/convertLength
|
* (ex: degrees, radians, miles, or kilometers)
|
* @param {string} [options.method="geodesic"] wether to calculate the distance based on geodesic (spheroid) or
|
* planar (flat) method. Valid options are 'geodesic' or 'planar'.
|
* @returns {number} distance between point and line
|
* @example
|
* var pt = turf.point([0, 0]);
|
* var line = turf.lineString([[1, 1],[-1, 1]]);
|
*
|
* var distance = turf.pointToLineDistance(pt, line, {units: 'miles'});
|
* //=69.11854715938406
|
*/
|
function pointToLineDistance(pt, line, options) {
|
if (options === void 0) { options = {}; }
|
// Optional parameters
|
if (!options.method) {
|
options.method = "geodesic";
|
}
|
if (!options.units) {
|
options.units = "kilometers";
|
}
|
// validation
|
if (!pt) {
|
throw new Error("pt is required");
|
}
|
if (Array.isArray(pt)) {
|
pt = helpers_1.point(pt);
|
}
|
else if (pt.type === "Point") {
|
pt = helpers_1.feature(pt);
|
}
|
else {
|
invariant_1.featureOf(pt, "Point", "point");
|
}
|
if (!line) {
|
throw new Error("line is required");
|
}
|
if (Array.isArray(line)) {
|
line = helpers_1.lineString(line);
|
}
|
else if (line.type === "LineString") {
|
line = helpers_1.feature(line);
|
}
|
else {
|
invariant_1.featureOf(line, "LineString", "line");
|
}
|
var distance = Infinity;
|
var p = pt.geometry.coordinates;
|
meta_1.segmentEach(line, function (segment) {
|
var a = segment.geometry.coordinates[0];
|
var b = segment.geometry.coordinates[1];
|
var d = distanceToSegment(p, a, b, options);
|
if (d < distance) {
|
distance = d;
|
}
|
});
|
return helpers_1.convertLength(distance, "degrees", options.units);
|
}
|
/**
|
* Returns the distance between a point P on a segment AB.
|
*
|
* @private
|
* @param {Array<number>} p external point
|
* @param {Array<number>} a first segment point
|
* @param {Array<number>} b second segment point
|
* @param {Object} [options={}] Optional parameters
|
* @returns {number} distance
|
*/
|
function distanceToSegment(p, a, b, options) {
|
var v = [b[0] - a[0], b[1] - a[1]];
|
var w = [p[0] - a[0], p[1] - a[1]];
|
var c1 = dot(w, v);
|
if (c1 <= 0) {
|
return calcDistance(p, a, { method: options.method, units: "degrees" });
|
}
|
var c2 = dot(v, v);
|
if (c2 <= c1) {
|
return calcDistance(p, b, { method: options.method, units: "degrees" });
|
}
|
var b2 = c1 / c2;
|
var Pb = [a[0] + (b2 * v[0]), a[1] + (b2 * v[1])];
|
return calcDistance(p, Pb, { method: options.method, units: "degrees" });
|
}
|
function dot(u, v) {
|
return (u[0] * v[0] + u[1] * v[1]);
|
}
|
function calcDistance(a, b, options) {
|
return options.method === "planar" ? rhumb_distance_1.default(a, b, options) : distance_1.default(a, b, options);
|
}
|
exports.default = pointToLineDistance;
|
|
},{"@turf/distance":13,"@turf/helpers":14,"@turf/invariant":17,"@turf/meta":18,"@turf/rhumb-distance":21}],20:[function(require,module,exports){
|
"use strict";
|
Object.defineProperty(exports, "__esModule", { value: true });
|
var helpers_1 = require("@turf/helpers");
|
var invariant_1 = require("@turf/invariant");
|
/**
|
* Converts a {@link Polygon} to {@link LineString|(Multi)LineString} or {@link MultiPolygon} to a
|
* {@link FeatureCollection} of {@link LineString|(Multi)LineString}.
|
*
|
* @name polygonToLine
|
* @param {Feature<Polygon|MultiPolygon>} poly Feature to convert
|
* @param {Object} [options={}] Optional parameters
|
* @param {Object} [options.properties={}] translates GeoJSON properties to Feature
|
* @returns {FeatureCollection|Feature<LineString|MultiLinestring>} converted (Multi)Polygon to (Multi)LineString
|
* @example
|
* var poly = turf.polygon([[[125, -30], [145, -30], [145, -20], [125, -20], [125, -30]]]);
|
*
|
* var line = turf.polygonToLine(poly);
|
*
|
* //addToMap
|
* var addToMap = [line];
|
*/
|
function default_1(poly, options) {
|
if (options === void 0) { options = {}; }
|
var geom = invariant_1.getGeom(poly);
|
if (!options.properties && poly.type === "Feature") {
|
options.properties = poly.properties;
|
}
|
switch (geom.type) {
|
case "Polygon": return polygonToLine(geom, options);
|
case "MultiPolygon": return multiPolygonToLine(geom, options);
|
default: throw new Error("invalid poly");
|
}
|
}
|
exports.default = default_1;
|
/**
|
* @private
|
*/
|
function polygonToLine(poly, options) {
|
if (options === void 0) { options = {}; }
|
var geom = invariant_1.getGeom(poly);
|
var type = geom.type;
|
var coords = geom.coordinates;
|
var properties = options.properties ? options.properties : poly.type === "Feature" ? poly.properties : {};
|
return coordsToLine(coords, properties);
|
}
|
exports.polygonToLine = polygonToLine;
|
/**
|
* @private
|
*/
|
function multiPolygonToLine(multiPoly, options) {
|
if (options === void 0) { options = {}; }
|
var geom = invariant_1.getGeom(multiPoly);
|
var type = geom.type;
|
var coords = geom.coordinates;
|
var properties = options.properties ? options.properties :
|
multiPoly.type === "Feature" ? multiPoly.properties : {};
|
var lines = [];
|
coords.forEach(function (coord) {
|
lines.push(coordsToLine(coord, properties));
|
});
|
return helpers_1.featureCollection(lines);
|
}
|
exports.multiPolygonToLine = multiPolygonToLine;
|
/**
|
* @private
|
*/
|
function coordsToLine(coords, properties) {
|
if (coords.length > 1) {
|
return helpers_1.multiLineString(coords, properties);
|
}
|
return helpers_1.lineString(coords[0], properties);
|
}
|
exports.coordsToLine = coordsToLine;
|
|
},{"@turf/helpers":14,"@turf/invariant":17}],21:[function(require,module,exports){
|
"use strict";
|
Object.defineProperty(exports, "__esModule", { value: true });
|
// https://en.wikipedia.org/wiki/Rhumb_line
|
var helpers_1 = require("@turf/helpers");
|
var invariant_1 = require("@turf/invariant");
|
/**
|
* Calculates the distance along a rhumb line between two {@link Point|points} in degrees, radians,
|
* miles, or kilometers.
|
*
|
* @name rhumbDistance
|
* @param {Coord} from origin point
|
* @param {Coord} to destination point
|
* @param {Object} [options] Optional parameters
|
* @param {string} [options.units="kilometers"] can be degrees, radians, miles, or kilometers
|
* @returns {number} distance between the two points
|
* @example
|
* var from = turf.point([-75.343, 39.984]);
|
* var to = turf.point([-75.534, 39.123]);
|
* var options = {units: 'miles'};
|
*
|
* var distance = turf.rhumbDistance(from, to, options);
|
*
|
* //addToMap
|
* var addToMap = [from, to];
|
* from.properties.distance = distance;
|
* to.properties.distance = distance;
|
*/
|
function rhumbDistance(from, to, options) {
|
if (options === void 0) { options = {}; }
|
var origin = invariant_1.getCoord(from);
|
var destination = invariant_1.getCoord(to);
|
// compensate the crossing of the 180th meridian (https://macwright.org/2016/09/26/the-180th-meridian.html)
|
// solution from https://github.com/mapbox/mapbox-gl-js/issues/3250#issuecomment-294887678
|
destination[0] += (destination[0] - origin[0] > 180) ? -360 : (origin[0] - destination[0] > 180) ? 360 : 0;
|
var distanceInMeters = calculateRhumbDistance(origin, destination);
|
var distance = helpers_1.convertLength(distanceInMeters, "meters", options.units);
|
return distance;
|
}
|
/**
|
* Returns the distance travelling from ‘this’ point to destination point along a rhumb line.
|
* Adapted from Geodesy: https://github.com/chrisveness/geodesy/blob/master/latlon-spherical.js
|
*
|
* @private
|
* @param {Array<number>} origin point.
|
* @param {Array<number>} destination point.
|
* @param {number} [radius=6371e3] - (Mean) radius of earth (defaults to radius in metres).
|
* @returns {number} Distance in km between this point and destination point (same units as radius).
|
*
|
* @example
|
* var p1 = new LatLon(51.127, 1.338);
|
* var p2 = new LatLon(50.964, 1.853);
|
* var d = p1.distanceTo(p2); // 40.31 km
|
*/
|
function calculateRhumbDistance(origin, destination, radius) {
|
// φ => phi
|
// λ => lambda
|
// ψ => psi
|
// Δ => Delta
|
// δ => delta
|
// θ => theta
|
radius = (radius === undefined) ? helpers_1.earthRadius : Number(radius);
|
// see www.edwilliams.org/avform.htm#Rhumb
|
var R = radius;
|
var phi1 = origin[1] * Math.PI / 180;
|
var phi2 = destination[1] * Math.PI / 180;
|
var DeltaPhi = phi2 - phi1;
|
var DeltaLambda = Math.abs(destination[0] - origin[0]) * Math.PI / 180;
|
// if dLon over 180° take shorter rhumb line across the anti-meridian:
|
if (DeltaLambda > Math.PI) {
|
DeltaLambda -= 2 * Math.PI;
|
}
|
// on Mercator projection, longitude distances shrink by latitude; q is the 'stretch factor'
|
// q becomes ill-conditioned along E-W line (0/0); use empirical tolerance to avoid it
|
var DeltaPsi = Math.log(Math.tan(phi2 / 2 + Math.PI / 4) / Math.tan(phi1 / 2 + Math.PI / 4));
|
var q = Math.abs(DeltaPsi) > 10e-12 ? DeltaPhi / DeltaPsi : Math.cos(phi1);
|
// distance is pythagoras on 'stretched' Mercator projection
|
var delta = Math.sqrt(DeltaPhi * DeltaPhi + q * q * DeltaLambda * DeltaLambda); // angular distance in radians
|
var dist = delta * R;
|
return dist;
|
}
|
exports.default = rhumbDistance;
|
|
},{"@turf/helpers":14,"@turf/invariant":17}],22:[function(require,module,exports){
|
'use strict';
|
|
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
|
|
var cleanCoords = _interopDefault(require('@turf/clean-coords'));
|
var clone = _interopDefault(require('@turf/clone'));
|
var meta = require('@turf/meta');
|
var helpers = require('@turf/helpers');
|
|
/*
|
(c) 2013, Vladimir Agafonkin
|
Simplify.js, a high-performance JS polyline simplification library
|
mourner.github.io/simplify-js
|
*/
|
|
// to suit your point format, run search/replace for '.x' and '.y';
|
// for 3D version, see 3d branch (configurability would draw significant performance overhead)
|
|
// square distance between 2 points
|
function getSqDist(p1, p2) {
|
|
var dx = p1.x - p2.x,
|
dy = p1.y - p2.y;
|
|
return dx * dx + dy * dy;
|
}
|
|
// square distance from a point to a segment
|
function getSqSegDist(p, p1, p2) {
|
|
var x = p1.x,
|
y = p1.y,
|
dx = p2.x - x,
|
dy = p2.y - y;
|
|
if (dx !== 0 || dy !== 0) {
|
|
var t = ((p.x - x) * dx + (p.y - y) * dy) / (dx * dx + dy * dy);
|
|
if (t > 1) {
|
x = p2.x;
|
y = p2.y;
|
|
} else if (t > 0) {
|
x += dx * t;
|
y += dy * t;
|
}
|
}
|
|
dx = p.x - x;
|
dy = p.y - y;
|
|
return dx * dx + dy * dy;
|
}
|
// rest of the code doesn't care about point format
|
|
// basic distance-based simplification
|
function simplifyRadialDist(points, sqTolerance) {
|
|
var prevPoint = points[0],
|
newPoints = [prevPoint],
|
point;
|
|
for (var i = 1, len = points.length; i < len; i++) {
|
point = points[i];
|
|
if (getSqDist(point, prevPoint) > sqTolerance) {
|
newPoints.push(point);
|
prevPoint = point;
|
}
|
}
|
|
if (prevPoint !== point) newPoints.push(point);
|
|
return newPoints;
|
}
|
|
function simplifyDPStep(points, first, last, sqTolerance, simplified) {
|
var maxSqDist = sqTolerance,
|
index;
|
|
for (var i = first + 1; i < last; i++) {
|
var sqDist = getSqSegDist(points[i], points[first], points[last]);
|
|
if (sqDist > maxSqDist) {
|
index = i;
|
maxSqDist = sqDist;
|
}
|
}
|
|
if (maxSqDist > sqTolerance) {
|
if (index - first > 1) simplifyDPStep(points, first, index, sqTolerance, simplified);
|
simplified.push(points[index]);
|
if (last - index > 1) simplifyDPStep(points, index, last, sqTolerance, simplified);
|
}
|
}
|
|
// simplification using Ramer-Douglas-Peucker algorithm
|
function simplifyDouglasPeucker(points, sqTolerance) {
|
var last = points.length - 1;
|
|
var simplified = [points[0]];
|
simplifyDPStep(points, 0, last, sqTolerance, simplified);
|
simplified.push(points[last]);
|
|
return simplified;
|
}
|
|
// both algorithms combined for awesome performance
|
function simplify$2(points, tolerance, highestQuality) {
|
|
if (points.length <= 2) return points;
|
|
var sqTolerance = tolerance !== undefined ? tolerance * tolerance : 1;
|
|
points = highestQuality ? points : simplifyRadialDist(points, sqTolerance);
|
points = simplifyDouglasPeucker(points, sqTolerance);
|
|
return points;
|
}
|
|
/**
|
* Takes a {@link GeoJSON} object and returns a simplified version. Internally uses
|
* [simplify-js](http://mourner.github.io/simplify-js/) to perform simplification using the Ramer-Douglas-Peucker algorithm.
|
*
|
* @name simplify
|
* @param {GeoJSON} geojson object to be simplified
|
* @param {Object} [options={}] Optional parameters
|
* @param {number} [options.tolerance=1] simplification tolerance
|
* @param {boolean} [options.highQuality=false] whether or not to spend more time to create a higher-quality simplification with a different algorithm
|
* @param {boolean} [options.mutate=false] allows GeoJSON input to be mutated (significant performance increase if true)
|
* @returns {GeoJSON} a simplified GeoJSON
|
* @example
|
* var geojson = turf.polygon([[
|
* [-70.603637, -33.399918],
|
* [-70.614624, -33.395332],
|
* [-70.639343, -33.392466],
|
* [-70.659942, -33.394759],
|
* [-70.683975, -33.404504],
|
* [-70.697021, -33.419406],
|
* [-70.701141, -33.434306],
|
* [-70.700454, -33.446339],
|
* [-70.694274, -33.458369],
|
* [-70.682601, -33.465816],
|
* [-70.668869, -33.472117],
|
* [-70.646209, -33.473835],
|
* [-70.624923, -33.472117],
|
* [-70.609817, -33.468107],
|
* [-70.595397, -33.458369],
|
* [-70.587158, -33.442901],
|
* [-70.587158, -33.426283],
|
* [-70.590591, -33.414248],
|
* [-70.594711, -33.406224],
|
* [-70.603637, -33.399918]
|
* ]]);
|
* var options = {tolerance: 0.01, highQuality: false};
|
* var simplified = turf.simplify(geojson, options);
|
*
|
* //addToMap
|
* var addToMap = [geojson, simplified]
|
*/
|
function simplify(geojson, options) {
|
// Optional parameters
|
options = options || {};
|
if (!helpers.isObject(options)) throw new Error('options is invalid');
|
var tolerance = options.tolerance !== undefined ? options.tolerance : 1;
|
var highQuality = options.highQuality || false;
|
var mutate = options.mutate || false;
|
|
if (!geojson) throw new Error('geojson is required');
|
if (tolerance && tolerance < 0) throw new Error('invalid tolerance');
|
|
// Clone geojson to avoid side effects
|
if (mutate !== true) geojson = clone(geojson);
|
|
meta.geomEach(geojson, function (geom) {
|
simplifyGeom(geom, tolerance, highQuality);
|
});
|
return geojson;
|
}
|
|
/**
|
* Simplifies a feature's coordinates
|
*
|
* @private
|
* @param {Geometry} geometry to be simplified
|
* @param {number} [tolerance=1] simplification tolerance
|
* @param {boolean} [highQuality=false] whether or not to spend more time to create a higher-quality simplification with a different algorithm
|
* @returns {Geometry} output
|
*/
|
function simplifyGeom(geometry, tolerance, highQuality) {
|
var type = geometry.type;
|
|
// "unsimplyfiable" geometry types
|
if (type === 'Point' || type === 'MultiPoint') return geometry;
|
|
// Remove any extra coordinates
|
cleanCoords(geometry, true);
|
|
var coordinates = geometry.coordinates;
|
switch (type) {
|
case 'LineString':
|
geometry['coordinates'] = simplifyLine(coordinates, tolerance, highQuality);
|
break;
|
case 'MultiLineString':
|
geometry['coordinates'] = coordinates.map(function (lines) {
|
return simplifyLine(lines, tolerance, highQuality);
|
});
|
break;
|
case 'Polygon':
|
geometry['coordinates'] = simplifyPolygon(coordinates, tolerance, highQuality);
|
break;
|
case 'MultiPolygon':
|
geometry['coordinates'] = coordinates.map(function (rings) {
|
return simplifyPolygon(rings, tolerance, highQuality);
|
});
|
}
|
return geometry;
|
}
|
|
|
/**
|
* Simplifies the coordinates of a LineString with simplify-js
|
*
|
* @private
|
* @param {Array<number>} coordinates to be processed
|
* @param {number} tolerance simplification tolerance
|
* @param {boolean} highQuality whether or not to spend more time to create a higher-quality
|
* @returns {Array<Array<number>>} simplified coords
|
*/
|
function simplifyLine(coordinates, tolerance, highQuality) {
|
return simplify$2(coordinates.map(function (coord) {
|
return {x: coord[0], y: coord[1], z: coord[2]};
|
}), tolerance, highQuality).map(function (coords) {
|
return (coords.z) ? [coords.x, coords.y, coords.z] : [coords.x, coords.y];
|
});
|
}
|
|
|
/**
|
* Simplifies the coordinates of a Polygon with simplify-js
|
*
|
* @private
|
* @param {Array<number>} coordinates to be processed
|
* @param {number} tolerance simplification tolerance
|
* @param {boolean} highQuality whether or not to spend more time to create a higher-quality
|
* @returns {Array<Array<Array<number>>>} simplified coords
|
*/
|
function simplifyPolygon(coordinates, tolerance, highQuality) {
|
return coordinates.map(function (ring) {
|
var pts = ring.map(function (coord) {
|
return {x: coord[0], y: coord[1]};
|
});
|
if (pts.length < 4) {
|
throw new Error('invalid polygon');
|
}
|
var simpleRing = simplify$2(pts, tolerance, highQuality).map(function (coords) {
|
return [coords.x, coords.y];
|
});
|
//remove 1 percent of tolerance until enough points to make a triangle
|
while (!checkValidity(simpleRing)) {
|
tolerance -= tolerance * 0.01;
|
simpleRing = simplify$2(pts, tolerance, highQuality).map(function (coords) {
|
return [coords.x, coords.y];
|
});
|
}
|
if (
|
(simpleRing[simpleRing.length - 1][0] !== simpleRing[0][0]) ||
|
(simpleRing[simpleRing.length - 1][1] !== simpleRing[0][1])) {
|
simpleRing.push(simpleRing[0]);
|
}
|
return simpleRing;
|
});
|
}
|
|
|
/**
|
* Returns true if ring has at least 3 coordinates and its first coordinate is the same as its last
|
*
|
* @private
|
* @param {Array<number>} ring coordinates to be checked
|
* @returns {boolean} true if valid
|
*/
|
function checkValidity(ring) {
|
if (ring.length < 3) return false;
|
//if the last point is the same as the first, it's not a triangle
|
return !(ring.length === 3 && ((ring[2][0] === ring[0][0]) && (ring[2][1] === ring[0][1])));
|
}
|
|
module.exports = simplify;
|
module.exports.default = simplify;
|
|
},{"@turf/clean-coords":9,"@turf/clone":23,"@turf/helpers":24,"@turf/meta":25}],23:[function(require,module,exports){
|
'use strict';
|
|
/**
|
* Returns a cloned copy of the passed GeoJSON Object, including possible 'Foreign Members'.
|
* ~3-5x faster than the common JSON.parse + JSON.stringify combo method.
|
*
|
* @name clone
|
* @param {GeoJSON} geojson GeoJSON Object
|
* @returns {GeoJSON} cloned GeoJSON Object
|
* @example
|
* var line = turf.lineString([[-74, 40], [-78, 42], [-82, 35]], {color: 'red'});
|
*
|
* var lineCloned = turf.clone(line);
|
*/
|
function clone(geojson) {
|
if (!geojson) throw new Error('geojson is required');
|
|
switch (geojson.type) {
|
case 'Feature':
|
return cloneFeature(geojson);
|
case 'FeatureCollection':
|
return cloneFeatureCollection(geojson);
|
case 'Point':
|
case 'LineString':
|
case 'Polygon':
|
case 'MultiPoint':
|
case 'MultiLineString':
|
case 'MultiPolygon':
|
case 'GeometryCollection':
|
return cloneGeometry(geojson);
|
default:
|
throw new Error('unknown GeoJSON type');
|
}
|
}
|
|
/**
|
* Clone Feature
|
*
|
* @private
|
* @param {Feature<any>} geojson GeoJSON Feature
|
* @returns {Feature<any>} cloned Feature
|
*/
|
function cloneFeature(geojson) {
|
var cloned = {type: 'Feature'};
|
// Preserve Foreign Members
|
Object.keys(geojson).forEach(function (key) {
|
switch (key) {
|
case 'type':
|
case 'properties':
|
case 'geometry':
|
return;
|
default:
|
cloned[key] = geojson[key];
|
}
|
});
|
// Add properties & geometry last
|
cloned.properties = cloneProperties(geojson.properties);
|
cloned.geometry = cloneGeometry(geojson.geometry);
|
return cloned;
|
}
|
|
/**
|
* Clone Properties
|
*
|
* @private
|
* @param {Object} properties GeoJSON Properties
|
* @returns {Object} cloned Properties
|
*/
|
function cloneProperties(properties) {
|
var cloned = {};
|
if (!properties) return cloned;
|
Object.keys(properties).forEach(function (key) {
|
var value = properties[key];
|
if (typeof value === 'object') {
|
if (value === null) {
|
// handle null
|
cloned[key] = null;
|
} else if (value.length) {
|
// handle Array
|
cloned[key] = value.map(function (item) {
|
return item;
|
});
|
} else {
|
// handle generic Object
|
cloned[key] = cloneProperties(value);
|
}
|
} else cloned[key] = value;
|
});
|
return cloned;
|
}
|
|
/**
|
* Clone Feature Collection
|
*
|
* @private
|
* @param {FeatureCollection<any>} geojson GeoJSON Feature Collection
|
* @returns {FeatureCollection<any>} cloned Feature Collection
|
*/
|
function cloneFeatureCollection(geojson) {
|
var cloned = {type: 'FeatureCollection'};
|
|
// Preserve Foreign Members
|
Object.keys(geojson).forEach(function (key) {
|
switch (key) {
|
case 'type':
|
case 'features':
|
return;
|
default:
|
cloned[key] = geojson[key];
|
}
|
});
|
// Add features
|
cloned.features = geojson.features.map(function (feature) {
|
return cloneFeature(feature);
|
});
|
return cloned;
|
}
|
|
/**
|
* Clone Geometry
|
*
|
* @private
|
* @param {Geometry<any>} geometry GeoJSON Geometry
|
* @returns {Geometry<any>} cloned Geometry
|
*/
|
function cloneGeometry(geometry) {
|
var geom = {type: geometry.type};
|
if (geometry.bbox) geom.bbox = geometry.bbox;
|
|
if (geometry.type === 'GeometryCollection') {
|
geom.geometries = geometry.geometries.map(function (geom) {
|
return cloneGeometry(geom);
|
});
|
return geom;
|
}
|
geom.coordinates = deepSlice(geometry.coordinates);
|
return geom;
|
}
|
|
/**
|
* Deep Slice coordinates
|
*
|
* @private
|
* @param {Coordinates} coords Coordinates
|
* @returns {Coordinates} all coordinates sliced
|
*/
|
function deepSlice(coords) {
|
if (typeof coords[0] !== 'object') { return coords.slice(); }
|
return coords.map(function (coord) {
|
return deepSlice(coord);
|
});
|
}
|
|
module.exports = clone;
|
module.exports.default = clone;
|
|
},{}],24:[function(require,module,exports){
|
arguments[4][10][0].apply(exports,arguments)
|
},{"dup":10}],25:[function(require,module,exports){
|
'use strict';
|
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
var helpers = require('@turf/helpers');
|
|
/**
|
* Callback for coordEach
|
*
|
* @callback coordEachCallback
|
* @param {Array<number>} currentCoord The current coordinate being processed.
|
* @param {number} coordIndex The current index of the coordinate being processed.
|
* @param {number} featureIndex The current index of the Feature being processed.
|
* @param {number} multiFeatureIndex The current index of the Multi-Feature being processed.
|
* @param {number} geometryIndex The current index of the Geometry being processed.
|
*/
|
|
/**
|
* Iterate over coordinates in any GeoJSON object, similar to Array.forEach()
|
*
|
* @name coordEach
|
* @param {FeatureCollection|Feature|Geometry} geojson any GeoJSON object
|
* @param {Function} callback a method that takes (currentCoord, coordIndex, featureIndex, multiFeatureIndex)
|
* @param {boolean} [excludeWrapCoord=false] whether or not to include the final coordinate of LinearRings that wraps the ring in its iteration.
|
* @returns {void}
|
* @example
|
* var features = turf.featureCollection([
|
* turf.point([26, 37], {"foo": "bar"}),
|
* turf.point([36, 53], {"hello": "world"})
|
* ]);
|
*
|
* turf.coordEach(features, function (currentCoord, coordIndex, featureIndex, multiFeatureIndex, geometryIndex) {
|
* //=currentCoord
|
* //=coordIndex
|
* //=featureIndex
|
* //=multiFeatureIndex
|
* //=geometryIndex
|
* });
|
*/
|
function coordEach(geojson, callback, excludeWrapCoord) {
|
// Handles null Geometry -- Skips this GeoJSON
|
if (geojson === null) return;
|
var j, k, l, geometry, stopG, coords,
|
geometryMaybeCollection,
|
wrapShrink = 0,
|
coordIndex = 0,
|
isGeometryCollection,
|
type = geojson.type,
|
isFeatureCollection = type === 'FeatureCollection',
|
isFeature = type === 'Feature',
|
stop = isFeatureCollection ? geojson.features.length : 1;
|
|
// This logic may look a little weird. The reason why it is that way
|
// is because it's trying to be fast. GeoJSON supports multiple kinds
|
// of objects at its root: FeatureCollection, Features, Geometries.
|
// This function has the responsibility of handling all of them, and that
|
// means that some of the `for` loops you see below actually just don't apply
|
// to certain inputs. For instance, if you give this just a
|
// Point geometry, then both loops are short-circuited and all we do
|
// is gradually rename the input until it's called 'geometry'.
|
//
|
// This also aims to allocate as few resources as possible: just a
|
// few numbers and booleans, rather than any temporary arrays as would
|
// be required with the normalization approach.
|
for (var featureIndex = 0; featureIndex < stop; featureIndex++) {
|
geometryMaybeCollection = (isFeatureCollection ? geojson.features[featureIndex].geometry :
|
(isFeature ? geojson.geometry : geojson));
|
isGeometryCollection = (geometryMaybeCollection) ? geometryMaybeCollection.type === 'GeometryCollection' : false;
|
stopG = isGeometryCollection ? geometryMaybeCollection.geometries.length : 1;
|
|
for (var geomIndex = 0; geomIndex < stopG; geomIndex++) {
|
var multiFeatureIndex = 0;
|
var geometryIndex = 0;
|
geometry = isGeometryCollection ?
|
geometryMaybeCollection.geometries[geomIndex] : geometryMaybeCollection;
|
|
// Handles null Geometry -- Skips this geometry
|
if (geometry === null) continue;
|
coords = geometry.coordinates;
|
var geomType = geometry.type;
|
|
wrapShrink = (excludeWrapCoord && (geomType === 'Polygon' || geomType === 'MultiPolygon')) ? 1 : 0;
|
|
switch (geomType) {
|
case null:
|
break;
|
case 'Point':
|
if (callback(coords, coordIndex, featureIndex, multiFeatureIndex, geometryIndex) === false) return false;
|
coordIndex++;
|
multiFeatureIndex++;
|
break;
|
case 'LineString':
|
case 'MultiPoint':
|
for (j = 0; j < coords.length; j++) {
|
if (callback(coords[j], coordIndex, featureIndex, multiFeatureIndex, geometryIndex) === false) return false;
|
coordIndex++;
|
if (geomType === 'MultiPoint') multiFeatureIndex++;
|
}
|
if (geomType === 'LineString') multiFeatureIndex++;
|
break;
|
case 'Polygon':
|
case 'MultiLineString':
|
for (j = 0; j < coords.length; j++) {
|
for (k = 0; k < coords[j].length - wrapShrink; k++) {
|
if (callback(coords[j][k], coordIndex, featureIndex, multiFeatureIndex, geometryIndex) === false) return false;
|
coordIndex++;
|
}
|
if (geomType === 'MultiLineString') multiFeatureIndex++;
|
if (geomType === 'Polygon') geometryIndex++;
|
}
|
if (geomType === 'Polygon') multiFeatureIndex++;
|
break;
|
case 'MultiPolygon':
|
for (j = 0; j < coords.length; j++) {
|
if (geomType === 'MultiPolygon') geometryIndex = 0;
|
for (k = 0; k < coords[j].length; k++) {
|
for (l = 0; l < coords[j][k].length - wrapShrink; l++) {
|
if (callback(coords[j][k][l], coordIndex, featureIndex, multiFeatureIndex, geometryIndex) === false) return false;
|
coordIndex++;
|
}
|
geometryIndex++;
|
}
|
multiFeatureIndex++;
|
}
|
break;
|
case 'GeometryCollection':
|
for (j = 0; j < geometry.geometries.length; j++)
|
if (coordEach(geometry.geometries[j], callback, excludeWrapCoord) === false) return false;
|
break;
|
default:
|
throw new Error('Unknown Geometry Type');
|
}
|
}
|
}
|
}
|
|
/**
|
* Callback for coordReduce
|
*
|
* The first time the callback function is called, the values provided as arguments depend
|
* on whether the reduce method has an initialValue argument.
|
*
|
* If an initialValue is provided to the reduce method:
|
* - The previousValue argument is initialValue.
|
* - The currentValue argument is the value of the first element present in the array.
|
*
|
* If an initialValue is not provided:
|
* - The previousValue argument is the value of the first element present in the array.
|
* - The currentValue argument is the value of the second element present in the array.
|
*
|
* @callback coordReduceCallback
|
* @param {*} previousValue The accumulated value previously returned in the last invocation
|
* of the callback, or initialValue, if supplied.
|
* @param {Array<number>} currentCoord The current coordinate being processed.
|
* @param {number} coordIndex The current index of the coordinate being processed.
|
* Starts at index 0, if an initialValue is provided, and at index 1 otherwise.
|
* @param {number} featureIndex The current index of the Feature being processed.
|
* @param {number} multiFeatureIndex The current index of the Multi-Feature being processed.
|
* @param {number} geometryIndex The current index of the Geometry being processed.
|
*/
|
|
/**
|
* Reduce coordinates in any GeoJSON object, similar to Array.reduce()
|
*
|
* @name coordReduce
|
* @param {FeatureCollection|Geometry|Feature} geojson any GeoJSON object
|
* @param {Function} callback a method that takes (previousValue, currentCoord, coordIndex)
|
* @param {*} [initialValue] Value to use as the first argument to the first call of the callback.
|
* @param {boolean} [excludeWrapCoord=false] whether or not to include the final coordinate of LinearRings that wraps the ring in its iteration.
|
* @returns {*} The value that results from the reduction.
|
* @example
|
* var features = turf.featureCollection([
|
* turf.point([26, 37], {"foo": "bar"}),
|
* turf.point([36, 53], {"hello": "world"})
|
* ]);
|
*
|
* turf.coordReduce(features, function (previousValue, currentCoord, coordIndex, featureIndex, multiFeatureIndex, geometryIndex) {
|
* //=previousValue
|
* //=currentCoord
|
* //=coordIndex
|
* //=featureIndex
|
* //=multiFeatureIndex
|
* //=geometryIndex
|
* return currentCoord;
|
* });
|
*/
|
function coordReduce(geojson, callback, initialValue, excludeWrapCoord) {
|
var previousValue = initialValue;
|
coordEach(geojson, function (currentCoord, coordIndex, featureIndex, multiFeatureIndex, geometryIndex) {
|
if (coordIndex === 0 && initialValue === undefined) previousValue = currentCoord;
|
else previousValue = callback(previousValue, currentCoord, coordIndex, featureIndex, multiFeatureIndex, geometryIndex);
|
}, excludeWrapCoord);
|
return previousValue;
|
}
|
|
/**
|
* Callback for propEach
|
*
|
* @callback propEachCallback
|
* @param {Object} currentProperties The current Properties being processed.
|
* @param {number} featureIndex The current index of the Feature being processed.
|
*/
|
|
/**
|
* Iterate over properties in any GeoJSON object, similar to Array.forEach()
|
*
|
* @name propEach
|
* @param {FeatureCollection|Feature} geojson any GeoJSON object
|
* @param {Function} callback a method that takes (currentProperties, featureIndex)
|
* @returns {void}
|
* @example
|
* var features = turf.featureCollection([
|
* turf.point([26, 37], {foo: 'bar'}),
|
* turf.point([36, 53], {hello: 'world'})
|
* ]);
|
*
|
* turf.propEach(features, function (currentProperties, featureIndex) {
|
* //=currentProperties
|
* //=featureIndex
|
* });
|
*/
|
function propEach(geojson, callback) {
|
var i;
|
switch (geojson.type) {
|
case 'FeatureCollection':
|
for (i = 0; i < geojson.features.length; i++) {
|
if (callback(geojson.features[i].properties, i) === false) break;
|
}
|
break;
|
case 'Feature':
|
callback(geojson.properties, 0);
|
break;
|
}
|
}
|
|
|
/**
|
* Callback for propReduce
|
*
|
* The first time the callback function is called, the values provided as arguments depend
|
* on whether the reduce method has an initialValue argument.
|
*
|
* If an initialValue is provided to the reduce method:
|
* - The previousValue argument is initialValue.
|
* - The currentValue argument is the value of the first element present in the array.
|
*
|
* If an initialValue is not provided:
|
* - The previousValue argument is the value of the first element present in the array.
|
* - The currentValue argument is the value of the second element present in the array.
|
*
|
* @callback propReduceCallback
|
* @param {*} previousValue The accumulated value previously returned in the last invocation
|
* of the callback, or initialValue, if supplied.
|
* @param {*} currentProperties The current Properties being processed.
|
* @param {number} featureIndex The current index of the Feature being processed.
|
*/
|
|
/**
|
* Reduce properties in any GeoJSON object into a single value,
|
* similar to how Array.reduce works. However, in this case we lazily run
|
* the reduction, so an array of all properties is unnecessary.
|
*
|
* @name propReduce
|
* @param {FeatureCollection|Feature} geojson any GeoJSON object
|
* @param {Function} callback a method that takes (previousValue, currentProperties, featureIndex)
|
* @param {*} [initialValue] Value to use as the first argument to the first call of the callback.
|
* @returns {*} The value that results from the reduction.
|
* @example
|
* var features = turf.featureCollection([
|
* turf.point([26, 37], {foo: 'bar'}),
|
* turf.point([36, 53], {hello: 'world'})
|
* ]);
|
*
|
* turf.propReduce(features, function (previousValue, currentProperties, featureIndex) {
|
* //=previousValue
|
* //=currentProperties
|
* //=featureIndex
|
* return currentProperties
|
* });
|
*/
|
function propReduce(geojson, callback, initialValue) {
|
var previousValue = initialValue;
|
propEach(geojson, function (currentProperties, featureIndex) {
|
if (featureIndex === 0 && initialValue === undefined) previousValue = currentProperties;
|
else previousValue = callback(previousValue, currentProperties, featureIndex);
|
});
|
return previousValue;
|
}
|
|
/**
|
* Callback for featureEach
|
*
|
* @callback featureEachCallback
|
* @param {Feature<any>} currentFeature The current Feature being processed.
|
* @param {number} featureIndex The current index of the Feature being processed.
|
*/
|
|
/**
|
* Iterate over features in any GeoJSON object, similar to
|
* Array.forEach.
|
*
|
* @name featureEach
|
* @param {FeatureCollection|Feature|Geometry} geojson any GeoJSON object
|
* @param {Function} callback a method that takes (currentFeature, featureIndex)
|
* @returns {void}
|
* @example
|
* var features = turf.featureCollection([
|
* turf.point([26, 37], {foo: 'bar'}),
|
* turf.point([36, 53], {hello: 'world'})
|
* ]);
|
*
|
* turf.featureEach(features, function (currentFeature, featureIndex) {
|
* //=currentFeature
|
* //=featureIndex
|
* });
|
*/
|
function featureEach(geojson, callback) {
|
if (geojson.type === 'Feature') {
|
callback(geojson, 0);
|
} else if (geojson.type === 'FeatureCollection') {
|
for (var i = 0; i < geojson.features.length; i++) {
|
if (callback(geojson.features[i], i) === false) break;
|
}
|
}
|
}
|
|
/**
|
* Callback for featureReduce
|
*
|
* The first time the callback function is called, the values provided as arguments depend
|
* on whether the reduce method has an initialValue argument.
|
*
|
* If an initialValue is provided to the reduce method:
|
* - The previousValue argument is initialValue.
|
* - The currentValue argument is the value of the first element present in the array.
|
*
|
* If an initialValue is not provided:
|
* - The previousValue argument is the value of the first element present in the array.
|
* - The currentValue argument is the value of the second element present in the array.
|
*
|
* @callback featureReduceCallback
|
* @param {*} previousValue The accumulated value previously returned in the last invocation
|
* of the callback, or initialValue, if supplied.
|
* @param {Feature} currentFeature The current Feature being processed.
|
* @param {number} featureIndex The current index of the Feature being processed.
|
*/
|
|
/**
|
* Reduce features in any GeoJSON object, similar to Array.reduce().
|
*
|
* @name featureReduce
|
* @param {FeatureCollection|Feature|Geometry} geojson any GeoJSON object
|
* @param {Function} callback a method that takes (previousValue, currentFeature, featureIndex)
|
* @param {*} [initialValue] Value to use as the first argument to the first call of the callback.
|
* @returns {*} The value that results from the reduction.
|
* @example
|
* var features = turf.featureCollection([
|
* turf.point([26, 37], {"foo": "bar"}),
|
* turf.point([36, 53], {"hello": "world"})
|
* ]);
|
*
|
* turf.featureReduce(features, function (previousValue, currentFeature, featureIndex) {
|
* //=previousValue
|
* //=currentFeature
|
* //=featureIndex
|
* return currentFeature
|
* });
|
*/
|
function featureReduce(geojson, callback, initialValue) {
|
var previousValue = initialValue;
|
featureEach(geojson, function (currentFeature, featureIndex) {
|
if (featureIndex === 0 && initialValue === undefined) previousValue = currentFeature;
|
else previousValue = callback(previousValue, currentFeature, featureIndex);
|
});
|
return previousValue;
|
}
|
|
/**
|
* Get all coordinates from any GeoJSON object.
|
*
|
* @name coordAll
|
* @param {FeatureCollection|Feature|Geometry} geojson any GeoJSON object
|
* @returns {Array<Array<number>>} coordinate position array
|
* @example
|
* var features = turf.featureCollection([
|
* turf.point([26, 37], {foo: 'bar'}),
|
* turf.point([36, 53], {hello: 'world'})
|
* ]);
|
*
|
* var coords = turf.coordAll(features);
|
* //= [[26, 37], [36, 53]]
|
*/
|
function coordAll(geojson) {
|
var coords = [];
|
coordEach(geojson, function (coord) {
|
coords.push(coord);
|
});
|
return coords;
|
}
|
|
/**
|
* Callback for geomEach
|
*
|
* @callback geomEachCallback
|
* @param {Geometry} currentGeometry The current Geometry being processed.
|
* @param {number} featureIndex The current index of the Feature being processed.
|
* @param {Object} featureProperties The current Feature Properties being processed.
|
* @param {Array<number>} featureBBox The current Feature BBox being processed.
|
* @param {number|string} featureId The current Feature Id being processed.
|
*/
|
|
/**
|
* Iterate over each geometry in any GeoJSON object, similar to Array.forEach()
|
*
|
* @name geomEach
|
* @param {FeatureCollection|Feature|Geometry} geojson any GeoJSON object
|
* @param {Function} callback a method that takes (currentGeometry, featureIndex, featureProperties, featureBBox, featureId)
|
* @returns {void}
|
* @example
|
* var features = turf.featureCollection([
|
* turf.point([26, 37], {foo: 'bar'}),
|
* turf.point([36, 53], {hello: 'world'})
|
* ]);
|
*
|
* turf.geomEach(features, function (currentGeometry, featureIndex, featureProperties, featureBBox, featureId) {
|
* //=currentGeometry
|
* //=featureIndex
|
* //=featureProperties
|
* //=featureBBox
|
* //=featureId
|
* });
|
*/
|
function geomEach(geojson, callback) {
|
var i, j, g, geometry, stopG,
|
geometryMaybeCollection,
|
isGeometryCollection,
|
featureProperties,
|
featureBBox,
|
featureId,
|
featureIndex = 0,
|
isFeatureCollection = geojson.type === 'FeatureCollection',
|
isFeature = geojson.type === 'Feature',
|
stop = isFeatureCollection ? geojson.features.length : 1;
|
|
// This logic may look a little weird. The reason why it is that way
|
// is because it's trying to be fast. GeoJSON supports multiple kinds
|
// of objects at its root: FeatureCollection, Features, Geometries.
|
// This function has the responsibility of handling all of them, and that
|
// means that some of the `for` loops you see below actually just don't apply
|
// to certain inputs. For instance, if you give this just a
|
// Point geometry, then both loops are short-circuited and all we do
|
// is gradually rename the input until it's called 'geometry'.
|
//
|
// This also aims to allocate as few resources as possible: just a
|
// few numbers and booleans, rather than any temporary arrays as would
|
// be required with the normalization approach.
|
for (i = 0; i < stop; i++) {
|
|
geometryMaybeCollection = (isFeatureCollection ? geojson.features[i].geometry :
|
(isFeature ? geojson.geometry : geojson));
|
featureProperties = (isFeatureCollection ? geojson.features[i].properties :
|
(isFeature ? geojson.properties : {}));
|
featureBBox = (isFeatureCollection ? geojson.features[i].bbox :
|
(isFeature ? geojson.bbox : undefined));
|
featureId = (isFeatureCollection ? geojson.features[i].id :
|
(isFeature ? geojson.id : undefined));
|
isGeometryCollection = (geometryMaybeCollection) ? geometryMaybeCollection.type === 'GeometryCollection' : false;
|
stopG = isGeometryCollection ? geometryMaybeCollection.geometries.length : 1;
|
|
for (g = 0; g < stopG; g++) {
|
geometry = isGeometryCollection ?
|
geometryMaybeCollection.geometries[g] : geometryMaybeCollection;
|
|
// Handle null Geometry
|
if (geometry === null) {
|
if (callback(null, featureIndex, featureProperties, featureBBox, featureId) === false) return false;
|
continue;
|
}
|
switch (geometry.type) {
|
case 'Point':
|
case 'LineString':
|
case 'MultiPoint':
|
case 'Polygon':
|
case 'MultiLineString':
|
case 'MultiPolygon': {
|
if (callback(geometry, featureIndex, featureProperties, featureBBox, featureId) === false) return false;
|
break;
|
}
|
case 'GeometryCollection': {
|
for (j = 0; j < geometry.geometries.length; j++) {
|
if (callback(geometry.geometries[j], featureIndex, featureProperties, featureBBox, featureId) === false) return false;
|
}
|
break;
|
}
|
default:
|
throw new Error('Unknown Geometry Type');
|
}
|
}
|
// Only increase `featureIndex` per each feature
|
featureIndex++;
|
}
|
}
|
|
/**
|
* Callback for geomReduce
|
*
|
* The first time the callback function is called, the values provided as arguments depend
|
* on whether the reduce method has an initialValue argument.
|
*
|
* If an initialValue is provided to the reduce method:
|
* - The previousValue argument is initialValue.
|
* - The currentValue argument is the value of the first element present in the array.
|
*
|
* If an initialValue is not provided:
|
* - The previousValue argument is the value of the first element present in the array.
|
* - The currentValue argument is the value of the second element present in the array.
|
*
|
* @callback geomReduceCallback
|
* @param {*} previousValue The accumulated value previously returned in the last invocation
|
* of the callback, or initialValue, if supplied.
|
* @param {Geometry} currentGeometry The current Geometry being processed.
|
* @param {number} featureIndex The current index of the Feature being processed.
|
* @param {Object} featureProperties The current Feature Properties being processed.
|
* @param {Array<number>} featureBBox The current Feature BBox being processed.
|
* @param {number|string} featureId The current Feature Id being processed.
|
*/
|
|
/**
|
* Reduce geometry in any GeoJSON object, similar to Array.reduce().
|
*
|
* @name geomReduce
|
* @param {FeatureCollection|Feature|Geometry} geojson any GeoJSON object
|
* @param {Function} callback a method that takes (previousValue, currentGeometry, featureIndex, featureProperties, featureBBox, featureId)
|
* @param {*} [initialValue] Value to use as the first argument to the first call of the callback.
|
* @returns {*} The value that results from the reduction.
|
* @example
|
* var features = turf.featureCollection([
|
* turf.point([26, 37], {foo: 'bar'}),
|
* turf.point([36, 53], {hello: 'world'})
|
* ]);
|
*
|
* turf.geomReduce(features, function (previousValue, currentGeometry, featureIndex, featureProperties, featureBBox, featureId) {
|
* //=previousValue
|
* //=currentGeometry
|
* //=featureIndex
|
* //=featureProperties
|
* //=featureBBox
|
* //=featureId
|
* return currentGeometry
|
* });
|
*/
|
function geomReduce(geojson, callback, initialValue) {
|
var previousValue = initialValue;
|
geomEach(geojson, function (currentGeometry, featureIndex, featureProperties, featureBBox, featureId) {
|
if (featureIndex === 0 && initialValue === undefined) previousValue = currentGeometry;
|
else previousValue = callback(previousValue, currentGeometry, featureIndex, featureProperties, featureBBox, featureId);
|
});
|
return previousValue;
|
}
|
|
/**
|
* Callback for flattenEach
|
*
|
* @callback flattenEachCallback
|
* @param {Feature} currentFeature The current flattened feature being processed.
|
* @param {number} featureIndex The current index of the Feature being processed.
|
* @param {number} multiFeatureIndex The current index of the Multi-Feature being processed.
|
*/
|
|
/**
|
* Iterate over flattened features in any GeoJSON object, similar to
|
* Array.forEach.
|
*
|
* @name flattenEach
|
* @param {FeatureCollection|Feature|Geometry} geojson any GeoJSON object
|
* @param {Function} callback a method that takes (currentFeature, featureIndex, multiFeatureIndex)
|
* @example
|
* var features = turf.featureCollection([
|
* turf.point([26, 37], {foo: 'bar'}),
|
* turf.multiPoint([[40, 30], [36, 53]], {hello: 'world'})
|
* ]);
|
*
|
* turf.flattenEach(features, function (currentFeature, featureIndex, multiFeatureIndex) {
|
* //=currentFeature
|
* //=featureIndex
|
* //=multiFeatureIndex
|
* });
|
*/
|
function flattenEach(geojson, callback) {
|
geomEach(geojson, function (geometry, featureIndex, properties, bbox, id) {
|
// Callback for single geometry
|
var type = (geometry === null) ? null : geometry.type;
|
switch (type) {
|
case null:
|
case 'Point':
|
case 'LineString':
|
case 'Polygon':
|
if (callback(helpers.feature(geometry, properties, {bbox: bbox, id: id}), featureIndex, 0) === false) return false;
|
return;
|
}
|
|
var geomType;
|
|
// Callback for multi-geometry
|
switch (type) {
|
case 'MultiPoint':
|
geomType = 'Point';
|
break;
|
case 'MultiLineString':
|
geomType = 'LineString';
|
break;
|
case 'MultiPolygon':
|
geomType = 'Polygon';
|
break;
|
}
|
|
for (var multiFeatureIndex = 0; multiFeatureIndex < geometry.coordinates.length; multiFeatureIndex++) {
|
var coordinate = geometry.coordinates[multiFeatureIndex];
|
var geom = {
|
type: geomType,
|
coordinates: coordinate
|
};
|
if (callback(helpers.feature(geom, properties), featureIndex, multiFeatureIndex) === false) return false;
|
}
|
});
|
}
|
|
/**
|
* Callback for flattenReduce
|
*
|
* The first time the callback function is called, the values provided as arguments depend
|
* on whether the reduce method has an initialValue argument.
|
*
|
* If an initialValue is provided to the reduce method:
|
* - The previousValue argument is initialValue.
|
* - The currentValue argument is the value of the first element present in the array.
|
*
|
* If an initialValue is not provided:
|
* - The previousValue argument is the value of the first element present in the array.
|
* - The currentValue argument is the value of the second element present in the array.
|
*
|
* @callback flattenReduceCallback
|
* @param {*} previousValue The accumulated value previously returned in the last invocation
|
* of the callback, or initialValue, if supplied.
|
* @param {Feature} currentFeature The current Feature being processed.
|
* @param {number} featureIndex The current index of the Feature being processed.
|
* @param {number} multiFeatureIndex The current index of the Multi-Feature being processed.
|
*/
|
|
/**
|
* Reduce flattened features in any GeoJSON object, similar to Array.reduce().
|
*
|
* @name flattenReduce
|
* @param {FeatureCollection|Feature|Geometry} geojson any GeoJSON object
|
* @param {Function} callback a method that takes (previousValue, currentFeature, featureIndex, multiFeatureIndex)
|
* @param {*} [initialValue] Value to use as the first argument to the first call of the callback.
|
* @returns {*} The value that results from the reduction.
|
* @example
|
* var features = turf.featureCollection([
|
* turf.point([26, 37], {foo: 'bar'}),
|
* turf.multiPoint([[40, 30], [36, 53]], {hello: 'world'})
|
* ]);
|
*
|
* turf.flattenReduce(features, function (previousValue, currentFeature, featureIndex, multiFeatureIndex) {
|
* //=previousValue
|
* //=currentFeature
|
* //=featureIndex
|
* //=multiFeatureIndex
|
* return currentFeature
|
* });
|
*/
|
function flattenReduce(geojson, callback, initialValue) {
|
var previousValue = initialValue;
|
flattenEach(geojson, function (currentFeature, featureIndex, multiFeatureIndex) {
|
if (featureIndex === 0 && multiFeatureIndex === 0 && initialValue === undefined) previousValue = currentFeature;
|
else previousValue = callback(previousValue, currentFeature, featureIndex, multiFeatureIndex);
|
});
|
return previousValue;
|
}
|
|
/**
|
* Callback for segmentEach
|
*
|
* @callback segmentEachCallback
|
* @param {Feature<LineString>} currentSegment The current Segment being processed.
|
* @param {number} featureIndex The current index of the Feature being processed.
|
* @param {number} multiFeatureIndex The current index of the Multi-Feature being processed.
|
* @param {number} geometryIndex The current index of the Geometry being processed.
|
* @param {number} segmentIndex The current index of the Segment being processed.
|
* @returns {void}
|
*/
|
|
/**
|
* Iterate over 2-vertex line segment in any GeoJSON object, similar to Array.forEach()
|
* (Multi)Point geometries do not contain segments therefore they are ignored during this operation.
|
*
|
* @param {FeatureCollection|Feature|Geometry} geojson any GeoJSON
|
* @param {Function} callback a method that takes (currentSegment, featureIndex, multiFeatureIndex, geometryIndex, segmentIndex)
|
* @returns {void}
|
* @example
|
* var polygon = turf.polygon([[[-50, 5], [-40, -10], [-50, -10], [-40, 5], [-50, 5]]]);
|
*
|
* // Iterate over GeoJSON by 2-vertex segments
|
* turf.segmentEach(polygon, function (currentSegment, featureIndex, multiFeatureIndex, geometryIndex, segmentIndex) {
|
* //=currentSegment
|
* //=featureIndex
|
* //=multiFeatureIndex
|
* //=geometryIndex
|
* //=segmentIndex
|
* });
|
*
|
* // Calculate the total number of segments
|
* var total = 0;
|
* turf.segmentEach(polygon, function () {
|
* total++;
|
* });
|
*/
|
function segmentEach(geojson, callback) {
|
flattenEach(geojson, function (feature$$1, featureIndex, multiFeatureIndex) {
|
var segmentIndex = 0;
|
|
// Exclude null Geometries
|
if (!feature$$1.geometry) return;
|
// (Multi)Point geometries do not contain segments therefore they are ignored during this operation.
|
var type = feature$$1.geometry.type;
|
if (type === 'Point' || type === 'MultiPoint') return;
|
|
// Generate 2-vertex line segments
|
var previousCoords;
|
if (coordEach(feature$$1, function (currentCoord, coordIndex, featureIndexCoord, mutliPartIndexCoord, geometryIndex) {
|
// Simulating a meta.coordReduce() since `reduce` operations cannot be stopped by returning `false`
|
if (previousCoords === undefined) {
|
previousCoords = currentCoord;
|
return;
|
}
|
var currentSegment = helpers.lineString([previousCoords, currentCoord], feature$$1.properties);
|
if (callback(currentSegment, featureIndex, multiFeatureIndex, geometryIndex, segmentIndex) === false) return false;
|
segmentIndex++;
|
previousCoords = currentCoord;
|
}) === false) return false;
|
});
|
}
|
|
/**
|
* Callback for segmentReduce
|
*
|
* The first time the callback function is called, the values provided as arguments depend
|
* on whether the reduce method has an initialValue argument.
|
*
|
* If an initialValue is provided to the reduce method:
|
* - The previousValue argument is initialValue.
|
* - The currentValue argument is the value of the first element present in the array.
|
*
|
* If an initialValue is not provided:
|
* - The previousValue argument is the value of the first element present in the array.
|
* - The currentValue argument is the value of the second element present in the array.
|
*
|
* @callback segmentReduceCallback
|
* @param {*} previousValue The accumulated value previously returned in the last invocation
|
* of the callback, or initialValue, if supplied.
|
* @param {Feature<LineString>} currentSegment The current Segment being processed.
|
* @param {number} featureIndex The current index of the Feature being processed.
|
* @param {number} multiFeatureIndex The current index of the Multi-Feature being processed.
|
* @param {number} geometryIndex The current index of the Geometry being processed.
|
* @param {number} segmentIndex The current index of the Segment being processed.
|
*/
|
|
/**
|
* Reduce 2-vertex line segment in any GeoJSON object, similar to Array.reduce()
|
* (Multi)Point geometries do not contain segments therefore they are ignored during this operation.
|
*
|
* @param {FeatureCollection|Feature|Geometry} geojson any GeoJSON
|
* @param {Function} callback a method that takes (previousValue, currentSegment, currentIndex)
|
* @param {*} [initialValue] Value to use as the first argument to the first call of the callback.
|
* @returns {void}
|
* @example
|
* var polygon = turf.polygon([[[-50, 5], [-40, -10], [-50, -10], [-40, 5], [-50, 5]]]);
|
*
|
* // Iterate over GeoJSON by 2-vertex segments
|
* turf.segmentReduce(polygon, function (previousSegment, currentSegment, featureIndex, multiFeatureIndex, geometryIndex, segmentIndex) {
|
* //= previousSegment
|
* //= currentSegment
|
* //= featureIndex
|
* //= multiFeatureIndex
|
* //= geometryIndex
|
* //= segmentInex
|
* return currentSegment
|
* });
|
*
|
* // Calculate the total number of segments
|
* var initialValue = 0
|
* var total = turf.segmentReduce(polygon, function (previousValue) {
|
* previousValue++;
|
* return previousValue;
|
* }, initialValue);
|
*/
|
function segmentReduce(geojson, callback, initialValue) {
|
var previousValue = initialValue;
|
var started = false;
|
segmentEach(geojson, function (currentSegment, featureIndex, multiFeatureIndex, geometryIndex, segmentIndex) {
|
if (started === false && initialValue === undefined) previousValue = currentSegment;
|
else previousValue = callback(previousValue, currentSegment, featureIndex, multiFeatureIndex, geometryIndex, segmentIndex);
|
started = true;
|
});
|
return previousValue;
|
}
|
|
/**
|
* Callback for lineEach
|
*
|
* @callback lineEachCallback
|
* @param {Feature<LineString>} currentLine The current LineString|LinearRing being processed
|
* @param {number} featureIndex The current index of the Feature being processed
|
* @param {number} multiFeatureIndex The current index of the Multi-Feature being processed
|
* @param {number} geometryIndex The current index of the Geometry being processed
|
*/
|
|
/**
|
* Iterate over line or ring coordinates in LineString, Polygon, MultiLineString, MultiPolygon Features or Geometries,
|
* similar to Array.forEach.
|
*
|
* @name lineEach
|
* @param {Geometry|Feature<LineString|Polygon|MultiLineString|MultiPolygon>} geojson object
|
* @param {Function} callback a method that takes (currentLine, featureIndex, multiFeatureIndex, geometryIndex)
|
* @example
|
* var multiLine = turf.multiLineString([
|
* [[26, 37], [35, 45]],
|
* [[36, 53], [38, 50], [41, 55]]
|
* ]);
|
*
|
* turf.lineEach(multiLine, function (currentLine, featureIndex, multiFeatureIndex, geometryIndex) {
|
* //=currentLine
|
* //=featureIndex
|
* //=multiFeatureIndex
|
* //=geometryIndex
|
* });
|
*/
|
function lineEach(geojson, callback) {
|
// validation
|
if (!geojson) throw new Error('geojson is required');
|
|
flattenEach(geojson, function (feature$$1, featureIndex, multiFeatureIndex) {
|
if (feature$$1.geometry === null) return;
|
var type = feature$$1.geometry.type;
|
var coords = feature$$1.geometry.coordinates;
|
switch (type) {
|
case 'LineString':
|
if (callback(feature$$1, featureIndex, multiFeatureIndex, 0, 0) === false) return false;
|
break;
|
case 'Polygon':
|
for (var geometryIndex = 0; geometryIndex < coords.length; geometryIndex++) {
|
if (callback(helpers.lineString(coords[geometryIndex], feature$$1.properties), featureIndex, multiFeatureIndex, geometryIndex) === false) return false;
|
}
|
break;
|
}
|
});
|
}
|
|
/**
|
* Callback for lineReduce
|
*
|
* The first time the callback function is called, the values provided as arguments depend
|
* on whether the reduce method has an initialValue argument.
|
*
|
* If an initialValue is provided to the reduce method:
|
* - The previousValue argument is initialValue.
|
* - The currentValue argument is the value of the first element present in the array.
|
*
|
* If an initialValue is not provided:
|
* - The previousValue argument is the value of the first element present in the array.
|
* - The currentValue argument is the value of the second element present in the array.
|
*
|
* @callback lineReduceCallback
|
* @param {*} previousValue The accumulated value previously returned in the last invocation
|
* of the callback, or initialValue, if supplied.
|
* @param {Feature<LineString>} currentLine The current LineString|LinearRing being processed.
|
* @param {number} featureIndex The current index of the Feature being processed
|
* @param {number} multiFeatureIndex The current index of the Multi-Feature being processed
|
* @param {number} geometryIndex The current index of the Geometry being processed
|
*/
|
|
/**
|
* Reduce features in any GeoJSON object, similar to Array.reduce().
|
*
|
* @name lineReduce
|
* @param {Geometry|Feature<LineString|Polygon|MultiLineString|MultiPolygon>} geojson object
|
* @param {Function} callback a method that takes (previousValue, currentLine, featureIndex, multiFeatureIndex, geometryIndex)
|
* @param {*} [initialValue] Value to use as the first argument to the first call of the callback.
|
* @returns {*} The value that results from the reduction.
|
* @example
|
* var multiPoly = turf.multiPolygon([
|
* turf.polygon([[[12,48],[2,41],[24,38],[12,48]], [[9,44],[13,41],[13,45],[9,44]]]),
|
* turf.polygon([[[5, 5], [0, 0], [2, 2], [4, 4], [5, 5]]])
|
* ]);
|
*
|
* turf.lineReduce(multiPoly, function (previousValue, currentLine, featureIndex, multiFeatureIndex, geometryIndex) {
|
* //=previousValue
|
* //=currentLine
|
* //=featureIndex
|
* //=multiFeatureIndex
|
* //=geometryIndex
|
* return currentLine
|
* });
|
*/
|
function lineReduce(geojson, callback, initialValue) {
|
var previousValue = initialValue;
|
lineEach(geojson, function (currentLine, featureIndex, multiFeatureIndex, geometryIndex) {
|
if (featureIndex === 0 && initialValue === undefined) previousValue = currentLine;
|
else previousValue = callback(previousValue, currentLine, featureIndex, multiFeatureIndex, geometryIndex);
|
});
|
return previousValue;
|
}
|
|
/**
|
* Finds a particular 2-vertex LineString Segment from a GeoJSON using `@turf/meta` indexes.
|
*
|
* Negative indexes are permitted.
|
* Point & MultiPoint will always return null.
|
*
|
* @param {FeatureCollection|Feature|Geometry} geojson Any GeoJSON Feature or Geometry
|
* @param {Object} [options={}] Optional parameters
|
* @param {number} [options.featureIndex=0] Feature Index
|
* @param {number} [options.multiFeatureIndex=0] Multi-Feature Index
|
* @param {number} [options.geometryIndex=0] Geometry Index
|
* @param {number} [options.segmentIndex=0] Segment Index
|
* @param {Object} [options.properties={}] Translate Properties to output LineString
|
* @param {BBox} [options.bbox={}] Translate BBox to output LineString
|
* @param {number|string} [options.id={}] Translate Id to output LineString
|
* @returns {Feature<LineString>} 2-vertex GeoJSON Feature LineString
|
* @example
|
* var multiLine = turf.multiLineString([
|
* [[10, 10], [50, 30], [30, 40]],
|
* [[-10, -10], [-50, -30], [-30, -40]]
|
* ]);
|
*
|
* // First Segment (defaults are 0)
|
* turf.findSegment(multiLine);
|
* // => Feature<LineString<[[10, 10], [50, 30]]>>
|
*
|
* // First Segment of 2nd Multi Feature
|
* turf.findSegment(multiLine, {multiFeatureIndex: 1});
|
* // => Feature<LineString<[[-10, -10], [-50, -30]]>>
|
*
|
* // Last Segment of Last Multi Feature
|
* turf.findSegment(multiLine, {multiFeatureIndex: -1, segmentIndex: -1});
|
* // => Feature<LineString<[[-50, -30], [-30, -40]]>>
|
*/
|
function findSegment(geojson, options) {
|
// Optional Parameters
|
options = options || {};
|
if (!helpers.isObject(options)) throw new Error('options is invalid');
|
var featureIndex = options.featureIndex || 0;
|
var multiFeatureIndex = options.multiFeatureIndex || 0;
|
var geometryIndex = options.geometryIndex || 0;
|
var segmentIndex = options.segmentIndex || 0;
|
|
// Find FeatureIndex
|
var properties = options.properties;
|
var geometry;
|
|
switch (geojson.type) {
|
case 'FeatureCollection':
|
if (featureIndex < 0) featureIndex = geojson.features.length + featureIndex;
|
properties = properties || geojson.features[featureIndex].properties;
|
geometry = geojson.features[featureIndex].geometry;
|
break;
|
case 'Feature':
|
properties = properties || geojson.properties;
|
geometry = geojson.geometry;
|
break;
|
case 'Point':
|
case 'MultiPoint':
|
return null;
|
case 'LineString':
|
case 'Polygon':
|
case 'MultiLineString':
|
case 'MultiPolygon':
|
geometry = geojson;
|
break;
|
default:
|
throw new Error('geojson is invalid');
|
}
|
|
// Find SegmentIndex
|
if (geometry === null) return null;
|
var coords = geometry.coordinates;
|
switch (geometry.type) {
|
case 'Point':
|
case 'MultiPoint':
|
return null;
|
case 'LineString':
|
if (segmentIndex < 0) segmentIndex = coords.length + segmentIndex - 1;
|
return helpers.lineString([coords[segmentIndex], coords[segmentIndex + 1]], properties, options);
|
case 'Polygon':
|
if (geometryIndex < 0) geometryIndex = coords.length + geometryIndex;
|
if (segmentIndex < 0) segmentIndex = coords[geometryIndex].length + segmentIndex - 1;
|
return helpers.lineString([coords[geometryIndex][segmentIndex], coords[geometryIndex][segmentIndex + 1]], properties, options);
|
case 'MultiLineString':
|
if (multiFeatureIndex < 0) multiFeatureIndex = coords.length + multiFeatureIndex;
|
if (segmentIndex < 0) segmentIndex = coords[multiFeatureIndex].length + segmentIndex - 1;
|
return helpers.lineString([coords[multiFeatureIndex][segmentIndex], coords[multiFeatureIndex][segmentIndex + 1]], properties, options);
|
case 'MultiPolygon':
|
if (multiFeatureIndex < 0) multiFeatureIndex = coords.length + multiFeatureIndex;
|
if (geometryIndex < 0) geometryIndex = coords[multiFeatureIndex].length + geometryIndex;
|
if (segmentIndex < 0) segmentIndex = coords[multiFeatureIndex][geometryIndex].length - segmentIndex - 1;
|
return helpers.lineString([coords[multiFeatureIndex][geometryIndex][segmentIndex], coords[multiFeatureIndex][geometryIndex][segmentIndex + 1]], properties, options);
|
}
|
throw new Error('geojson is invalid');
|
}
|
|
/**
|
* Finds a particular Point from a GeoJSON using `@turf/meta` indexes.
|
*
|
* Negative indexes are permitted.
|
*
|
* @param {FeatureCollection|Feature|Geometry} geojson Any GeoJSON Feature or Geometry
|
* @param {Object} [options={}] Optional parameters
|
* @param {number} [options.featureIndex=0] Feature Index
|
* @param {number} [options.multiFeatureIndex=0] Multi-Feature Index
|
* @param {number} [options.geometryIndex=0] Geometry Index
|
* @param {number} [options.coordIndex=0] Coord Index
|
* @param {Object} [options.properties={}] Translate Properties to output Point
|
* @param {BBox} [options.bbox={}] Translate BBox to output Point
|
* @param {number|string} [options.id={}] Translate Id to output Point
|
* @returns {Feature<Point>} 2-vertex GeoJSON Feature Point
|
* @example
|
* var multiLine = turf.multiLineString([
|
* [[10, 10], [50, 30], [30, 40]],
|
* [[-10, -10], [-50, -30], [-30, -40]]
|
* ]);
|
*
|
* // First Segment (defaults are 0)
|
* turf.findPoint(multiLine);
|
* // => Feature<Point<[10, 10]>>
|
*
|
* // First Segment of the 2nd Multi-Feature
|
* turf.findPoint(multiLine, {multiFeatureIndex: 1});
|
* // => Feature<Point<[-10, -10]>>
|
*
|
* // Last Segment of last Multi-Feature
|
* turf.findPoint(multiLine, {multiFeatureIndex: -1, coordIndex: -1});
|
* // => Feature<Point<[-30, -40]>>
|
*/
|
function findPoint(geojson, options) {
|
// Optional Parameters
|
options = options || {};
|
if (!helpers.isObject(options)) throw new Error('options is invalid');
|
var featureIndex = options.featureIndex || 0;
|
var multiFeatureIndex = options.multiFeatureIndex || 0;
|
var geometryIndex = options.geometryIndex || 0;
|
var coordIndex = options.coordIndex || 0;
|
|
// Find FeatureIndex
|
var properties = options.properties;
|
var geometry;
|
|
switch (geojson.type) {
|
case 'FeatureCollection':
|
if (featureIndex < 0) featureIndex = geojson.features.length + featureIndex;
|
properties = properties || geojson.features[featureIndex].properties;
|
geometry = geojson.features[featureIndex].geometry;
|
break;
|
case 'Feature':
|
properties = properties || geojson.properties;
|
geometry = geojson.geometry;
|
break;
|
case 'Point':
|
case 'MultiPoint':
|
return null;
|
case 'LineString':
|
case 'Polygon':
|
case 'MultiLineString':
|
case 'MultiPolygon':
|
geometry = geojson;
|
break;
|
default:
|
throw new Error('geojson is invalid');
|
}
|
|
// Find Coord Index
|
if (geometry === null) return null;
|
var coords = geometry.coordinates;
|
switch (geometry.type) {
|
case 'Point':
|
return helpers.point(coords, properties, options);
|
case 'MultiPoint':
|
if (multiFeatureIndex < 0) multiFeatureIndex = coords.length + multiFeatureIndex;
|
return helpers.point(coords[multiFeatureIndex], properties, options);
|
case 'LineString':
|
if (coordIndex < 0) coordIndex = coords.length + coordIndex;
|
return helpers.point(coords[coordIndex], properties, options);
|
case 'Polygon':
|
if (geometryIndex < 0) geometryIndex = coords.length + geometryIndex;
|
if (coordIndex < 0) coordIndex = coords[geometryIndex].length + coordIndex;
|
return helpers.point(coords[geometryIndex][coordIndex], properties, options);
|
case 'MultiLineString':
|
if (multiFeatureIndex < 0) multiFeatureIndex = coords.length + multiFeatureIndex;
|
if (coordIndex < 0) coordIndex = coords[multiFeatureIndex].length + coordIndex;
|
return helpers.point(coords[multiFeatureIndex][coordIndex], properties, options);
|
case 'MultiPolygon':
|
if (multiFeatureIndex < 0) multiFeatureIndex = coords.length + multiFeatureIndex;
|
if (geometryIndex < 0) geometryIndex = coords[multiFeatureIndex].length + geometryIndex;
|
if (coordIndex < 0) coordIndex = coords[multiFeatureIndex][geometryIndex].length - coordIndex;
|
return helpers.point(coords[multiFeatureIndex][geometryIndex][coordIndex], properties, options);
|
}
|
throw new Error('geojson is invalid');
|
}
|
|
exports.coordEach = coordEach;
|
exports.coordReduce = coordReduce;
|
exports.propEach = propEach;
|
exports.propReduce = propReduce;
|
exports.featureEach = featureEach;
|
exports.featureReduce = featureReduce;
|
exports.coordAll = coordAll;
|
exports.geomEach = geomEach;
|
exports.geomReduce = geomReduce;
|
exports.flattenEach = flattenEach;
|
exports.flattenReduce = flattenReduce;
|
exports.segmentEach = segmentEach;
|
exports.segmentReduce = segmentReduce;
|
exports.lineEach = lineEach;
|
exports.lineReduce = lineReduce;
|
exports.findSegment = findSegment;
|
exports.findPoint = findPoint;
|
|
},{"@turf/helpers":24}],26:[function(require,module,exports){
|
var inside = require('@turf/inside');
|
var featureCollection = require('@turf/helpers').featureCollection;
|
|
/**
|
* Takes a set of {@link Point|points} and a set of {@link Polygon|polygons} and returns the points that fall within the polygons.
|
*
|
* @name within
|
* @param {FeatureCollection<Point>} points input points
|
* @param {FeatureCollection<Polygon>} polygons input polygons
|
* @returns {FeatureCollection<Point>} points that land within at least one polygon
|
* @example
|
* var searchWithin = turf.featureCollection([
|
* turf.polygon([[
|
* [-46.653,-23.543],
|
* [-46.634,-23.5346],
|
* [-46.613,-23.543],
|
* [-46.614,-23.559],
|
* [-46.631,-23.567],
|
* [-46.653,-23.560],
|
* [-46.653,-23.543]
|
* ]])
|
* ]);
|
* var points = turf.featureCollection([
|
* turf.point([-46.6318, -23.5523]),
|
* turf.point([-46.6246, -23.5325]),
|
* turf.point([-46.6062, -23.5513]),
|
* turf.point([-46.663, -23.554]),
|
* turf.point([-46.643, -23.557])
|
* ]);
|
*
|
* var ptsWithin = turf.within(points, searchWithin);
|
*
|
* //addToMap
|
* var addToMap = [points, searchWithin, ptsWithin]
|
* turf.featureEach(ptsWithin, function (currentFeature) {
|
* currentFeature.properties['marker-size'] = 'large';
|
* currentFeature.properties['marker-color'] = '#000';
|
* });
|
*/
|
module.exports = function (points, polygons) {
|
var pointsWithin = featureCollection([]);
|
for (var i = 0; i < polygons.features.length; i++) {
|
for (var j = 0; j < points.features.length; j++) {
|
var isInside = inside(points.features[j], polygons.features[i]);
|
if (isInside) {
|
pointsWithin.features.push(points.features[j]);
|
}
|
}
|
}
|
return pointsWithin;
|
};
|
|
},{"@turf/helpers":27,"@turf/inside":15}],27:[function(require,module,exports){
|
/**
|
* Wraps a GeoJSON {@link Geometry} in a GeoJSON {@link Feature}.
|
*
|
* @name feature
|
* @param {Geometry} geometry input geometry
|
* @param {Object} [properties={}] an Object of key-value pairs to add as properties
|
* @param {Array<number>} [bbox] BBox [west, south, east, north]
|
* @param {string|number} [id] Identifier
|
* @returns {Feature} a GeoJSON Feature
|
* @example
|
* var geometry = {
|
* "type": "Point",
|
* "coordinates": [110, 50]
|
* };
|
*
|
* var feature = turf.feature(geometry);
|
*
|
* //=feature
|
*/
|
function feature(geometry, properties, bbox, id) {
|
if (geometry === undefined) throw new Error('geometry is required');
|
if (properties && properties.constructor !== Object) throw new Error('properties must be an Object');
|
if (bbox && bbox.length !== 4) throw new Error('bbox must be an Array of 4 numbers');
|
if (id && ['string', 'number'].indexOf(typeof id) === -1) throw new Error('id must be a number or a string');
|
|
var feat = {type: 'Feature'};
|
if (id) feat.id = id;
|
if (bbox) feat.bbox = bbox;
|
feat.properties = properties || {};
|
feat.geometry = geometry;
|
return feat;
|
}
|
|
/**
|
* Creates a GeoJSON {@link Geometry} from a Geometry string type & coordinates.
|
* For GeometryCollection type use `helpers.geometryCollection`
|
*
|
* @name geometry
|
* @param {string} type Geometry Type
|
* @param {Array<number>} coordinates Coordinates
|
* @param {Array<number>} [bbox] BBox [west, south, east, north]
|
* @returns {Geometry} a GeoJSON Geometry
|
* @example
|
* var type = 'Point';
|
* var coordinates = [110, 50];
|
*
|
* var geometry = turf.geometry(type, coordinates);
|
*
|
* //=geometry
|
*/
|
function geometry(type, coordinates, bbox) {
|
// Validation
|
if (!type) throw new Error('type is required');
|
if (!coordinates) throw new Error('coordinates is required');
|
if (!Array.isArray(coordinates)) throw new Error('coordinates must be an Array');
|
if (bbox && bbox.length !== 4) throw new Error('bbox must be an Array of 4 numbers');
|
|
var geom;
|
switch (type) {
|
case 'Point': geom = point(coordinates).geometry; break;
|
case 'LineString': geom = lineString(coordinates).geometry; break;
|
case 'Polygon': geom = polygon(coordinates).geometry; break;
|
case 'MultiPoint': geom = multiPoint(coordinates).geometry; break;
|
case 'MultiLineString': geom = multiLineString(coordinates).geometry; break;
|
case 'MultiPolygon': geom = multiPolygon(coordinates).geometry; break;
|
default: throw new Error(type + ' is invalid');
|
}
|
if (bbox) geom.bbox = bbox;
|
return geom;
|
}
|
|
/**
|
* Takes coordinates and properties (optional) and returns a new {@link Point} feature.
|
*
|
* @name point
|
* @param {Array<number>} coordinates longitude, latitude position (each in decimal degrees)
|
* @param {Object} [properties={}] an Object of key-value pairs to add as properties
|
* @param {Array<number>} [bbox] BBox [west, south, east, north]
|
* @param {string|number} [id] Identifier
|
* @returns {Feature<Point>} a Point feature
|
* @example
|
* var point = turf.point([-75.343, 39.984]);
|
*
|
* //=point
|
*/
|
function point(coordinates, properties, bbox, id) {
|
if (!coordinates) throw new Error('No coordinates passed');
|
if (coordinates.length === undefined) throw new Error('Coordinates must be an array');
|
if (coordinates.length < 2) throw new Error('Coordinates must be at least 2 numbers long');
|
if (!isNumber(coordinates[0]) || !isNumber(coordinates[1])) throw new Error('Coordinates must contain numbers');
|
|
return feature({
|
type: 'Point',
|
coordinates: coordinates
|
}, properties, bbox, id);
|
}
|
|
/**
|
* Takes an array of LinearRings and optionally an {@link Object} with properties and returns a {@link Polygon} feature.
|
*
|
* @name polygon
|
* @param {Array<Array<Array<number>>>} coordinates an array of LinearRings
|
* @param {Object} [properties={}] an Object of key-value pairs to add as properties
|
* @param {Array<number>} [bbox] BBox [west, south, east, north]
|
* @param {string|number} [id] Identifier
|
* @returns {Feature<Polygon>} a Polygon feature
|
* @throws {Error} throw an error if a LinearRing of the polygon has too few positions
|
* or if a LinearRing of the Polygon does not have matching Positions at the beginning & end.
|
* @example
|
* var polygon = turf.polygon([[
|
* [-2.275543, 53.464547],
|
* [-2.275543, 53.489271],
|
* [-2.215118, 53.489271],
|
* [-2.215118, 53.464547],
|
* [-2.275543, 53.464547]
|
* ]], { name: 'poly1', population: 400});
|
*
|
* //=polygon
|
*/
|
function polygon(coordinates, properties, bbox, id) {
|
if (!coordinates) throw new Error('No coordinates passed');
|
|
for (var i = 0; i < coordinates.length; i++) {
|
var ring = coordinates[i];
|
if (ring.length < 4) {
|
throw new Error('Each LinearRing of a Polygon must have 4 or more Positions.');
|
}
|
for (var j = 0; j < ring[ring.length - 1].length; j++) {
|
// Check if first point of Polygon contains two numbers
|
if (i === 0 && j === 0 && !isNumber(ring[0][0]) || !isNumber(ring[0][1])) throw new Error('Coordinates must contain numbers');
|
if (ring[ring.length - 1][j] !== ring[0][j]) {
|
throw new Error('First and last Position are not equivalent.');
|
}
|
}
|
}
|
|
return feature({
|
type: 'Polygon',
|
coordinates: coordinates
|
}, properties, bbox, id);
|
}
|
|
/**
|
* Creates a {@link LineString} based on a
|
* coordinate array. Properties can be added optionally.
|
*
|
* @name lineString
|
* @param {Array<Array<number>>} coordinates an array of Positions
|
* @param {Object} [properties={}] an Object of key-value pairs to add as properties
|
* @param {Array<number>} [bbox] BBox [west, south, east, north]
|
* @param {string|number} [id] Identifier
|
* @returns {Feature<LineString>} a LineString feature
|
* @throws {Error} if no coordinates are passed
|
* @example
|
* var linestring1 = turf.lineString([
|
* [-21.964416, 64.148203],
|
* [-21.956176, 64.141316],
|
* [-21.93901, 64.135924],
|
* [-21.927337, 64.136673]
|
* ]);
|
* var linestring2 = turf.lineString([
|
* [-21.929054, 64.127985],
|
* [-21.912918, 64.134726],
|
* [-21.916007, 64.141016],
|
* [-21.930084, 64.14446]
|
* ], {name: 'line 1', distance: 145});
|
*
|
* //=linestring1
|
*
|
* //=linestring2
|
*/
|
function lineString(coordinates, properties, bbox, id) {
|
if (!coordinates) throw new Error('No coordinates passed');
|
if (coordinates.length < 2) throw new Error('Coordinates must be an array of two or more positions');
|
// Check if first point of LineString contains two numbers
|
if (!isNumber(coordinates[0][1]) || !isNumber(coordinates[0][1])) throw new Error('Coordinates must contain numbers');
|
|
return feature({
|
type: 'LineString',
|
coordinates: coordinates
|
}, properties, bbox, id);
|
}
|
|
/**
|
* Takes one or more {@link Feature|Features} and creates a {@link FeatureCollection}.
|
*
|
* @name featureCollection
|
* @param {Feature[]} features input features
|
* @param {Array<number>} [bbox] BBox [west, south, east, north]
|
* @param {string|number} [id] Identifier
|
* @returns {FeatureCollection} a FeatureCollection of input features
|
* @example
|
* var features = [
|
* turf.point([-75.343, 39.984], {name: 'Location A'}),
|
* turf.point([-75.833, 39.284], {name: 'Location B'}),
|
* turf.point([-75.534, 39.123], {name: 'Location C'})
|
* ];
|
*
|
* var collection = turf.featureCollection(features);
|
*
|
* //=collection
|
*/
|
function featureCollection(features, bbox, id) {
|
if (!features) throw new Error('No features passed');
|
if (!Array.isArray(features)) throw new Error('features must be an Array');
|
if (bbox && bbox.length !== 4) throw new Error('bbox must be an Array of 4 numbers');
|
if (id && ['string', 'number'].indexOf(typeof id) === -1) throw new Error('id must be a number or a string');
|
|
var fc = {type: 'FeatureCollection'};
|
if (id) fc.id = id;
|
if (bbox) fc.bbox = bbox;
|
fc.features = features;
|
return fc;
|
}
|
|
/**
|
* Creates a {@link Feature<MultiLineString>} based on a
|
* coordinate array. Properties can be added optionally.
|
*
|
* @name multiLineString
|
* @param {Array<Array<Array<number>>>} coordinates an array of LineStrings
|
* @param {Object} [properties={}] an Object of key-value pairs to add as properties
|
* @param {Array<number>} [bbox] BBox [west, south, east, north]
|
* @param {string|number} [id] Identifier
|
* @returns {Feature<MultiLineString>} a MultiLineString feature
|
* @throws {Error} if no coordinates are passed
|
* @example
|
* var multiLine = turf.multiLineString([[[0,0],[10,10]]]);
|
*
|
* //=multiLine
|
*/
|
function multiLineString(coordinates, properties, bbox, id) {
|
if (!coordinates) throw new Error('No coordinates passed');
|
|
return feature({
|
type: 'MultiLineString',
|
coordinates: coordinates
|
}, properties, bbox, id);
|
}
|
|
/**
|
* Creates a {@link Feature<MultiPoint>} based on a
|
* coordinate array. Properties can be added optionally.
|
*
|
* @name multiPoint
|
* @param {Array<Array<number>>} coordinates an array of Positions
|
* @param {Object} [properties={}] an Object of key-value pairs to add as properties
|
* @param {Array<number>} [bbox] BBox [west, south, east, north]
|
* @param {string|number} [id] Identifier
|
* @returns {Feature<MultiPoint>} a MultiPoint feature
|
* @throws {Error} if no coordinates are passed
|
* @example
|
* var multiPt = turf.multiPoint([[0,0],[10,10]]);
|
*
|
* //=multiPt
|
*/
|
function multiPoint(coordinates, properties, bbox, id) {
|
if (!coordinates) throw new Error('No coordinates passed');
|
|
return feature({
|
type: 'MultiPoint',
|
coordinates: coordinates
|
}, properties, bbox, id);
|
}
|
|
/**
|
* Creates a {@link Feature<MultiPolygon>} based on a
|
* coordinate array. Properties can be added optionally.
|
*
|
* @name multiPolygon
|
* @param {Array<Array<Array<Array<number>>>>} coordinates an array of Polygons
|
* @param {Object} [properties={}] an Object of key-value pairs to add as properties
|
* @param {Array<number>} [bbox] BBox [west, south, east, north]
|
* @param {string|number} [id] Identifier
|
* @returns {Feature<MultiPolygon>} a multipolygon feature
|
* @throws {Error} if no coordinates are passed
|
* @example
|
* var multiPoly = turf.multiPolygon([[[[0,0],[0,10],[10,10],[10,0],[0,0]]]]);
|
*
|
* //=multiPoly
|
*
|
*/
|
function multiPolygon(coordinates, properties, bbox, id) {
|
if (!coordinates) throw new Error('No coordinates passed');
|
|
return feature({
|
type: 'MultiPolygon',
|
coordinates: coordinates
|
}, properties, bbox, id);
|
}
|
|
/**
|
* Creates a {@link Feature<GeometryCollection>} based on a
|
* coordinate array. Properties can be added optionally.
|
*
|
* @name geometryCollection
|
* @param {Array<Geometry>} geometries an array of GeoJSON Geometries
|
* @param {Object} [properties={}] an Object of key-value pairs to add as properties
|
* @param {Array<number>} [bbox] BBox [west, south, east, north]
|
* @param {string|number} [id] Identifier
|
* @returns {Feature<GeometryCollection>} a GeoJSON GeometryCollection Feature
|
* @example
|
* var pt = {
|
* "type": "Point",
|
* "coordinates": [100, 0]
|
* };
|
* var line = {
|
* "type": "LineString",
|
* "coordinates": [ [101, 0], [102, 1] ]
|
* };
|
* var collection = turf.geometryCollection([pt, line]);
|
*
|
* //=collection
|
*/
|
function geometryCollection(geometries, properties, bbox, id) {
|
if (!geometries) throw new Error('geometries is required');
|
if (!Array.isArray(geometries)) throw new Error('geometries must be an Array');
|
|
return feature({
|
type: 'GeometryCollection',
|
geometries: geometries
|
}, properties, bbox, id);
|
}
|
|
// https://en.wikipedia.org/wiki/Great-circle_distance#Radius_for_spherical_Earth
|
var factors = {
|
miles: 3960,
|
nauticalmiles: 3441.145,
|
degrees: 57.2957795,
|
radians: 1,
|
inches: 250905600,
|
yards: 6969600,
|
meters: 6373000,
|
metres: 6373000,
|
centimeters: 6.373e+8,
|
centimetres: 6.373e+8,
|
kilometers: 6373,
|
kilometres: 6373,
|
feet: 20908792.65
|
};
|
|
var areaFactors = {
|
kilometers: 0.000001,
|
kilometres: 0.000001,
|
meters: 1,
|
metres: 1,
|
centimetres: 10000,
|
millimeter: 1000000,
|
acres: 0.000247105,
|
miles: 3.86e-7,
|
yards: 1.195990046,
|
feet: 10.763910417,
|
inches: 1550.003100006
|
};
|
/**
|
* Round number to precision
|
*
|
* @param {number} num Number
|
* @param {number} [precision=0] Precision
|
* @returns {number} rounded number
|
* @example
|
* turf.round(120.4321)
|
* //=120
|
*
|
* turf.round(120.4321, 2)
|
* //=120.43
|
*/
|
function round(num, precision) {
|
if (num === undefined || num === null || isNaN(num)) throw new Error('num is required');
|
if (precision && !(precision >= 0)) throw new Error('precision must be a positive number');
|
var multiplier = Math.pow(10, precision || 0);
|
return Math.round(num * multiplier) / multiplier;
|
}
|
|
/**
|
* Convert a distance measurement (assuming a spherical Earth) from radians to a more friendly unit.
|
* Valid units: miles, nauticalmiles, inches, yards, meters, metres, kilometers, centimeters, feet
|
*
|
* @name radiansToDistance
|
* @param {number} radians in radians across the sphere
|
* @param {string} [units=kilometers] can be degrees, radians, miles, or kilometers inches, yards, metres, meters, kilometres, kilometers.
|
* @returns {number} distance
|
*/
|
function radiansToDistance(radians, units) {
|
if (radians === undefined || radians === null) throw new Error('radians is required');
|
|
var factor = factors[units || 'kilometers'];
|
if (!factor) throw new Error('units is invalid');
|
return radians * factor;
|
}
|
|
/**
|
* Convert a distance measurement (assuming a spherical Earth) from a real-world unit into radians
|
* Valid units: miles, nauticalmiles, inches, yards, meters, metres, kilometers, centimeters, feet
|
*
|
* @name distanceToRadians
|
* @param {number} distance in real units
|
* @param {string} [units=kilometers] can be degrees, radians, miles, or kilometers inches, yards, metres, meters, kilometres, kilometers.
|
* @returns {number} radians
|
*/
|
function distanceToRadians(distance, units) {
|
if (distance === undefined || distance === null) throw new Error('distance is required');
|
|
var factor = factors[units || 'kilometers'];
|
if (!factor) throw new Error('units is invalid');
|
return distance / factor;
|
}
|
|
/**
|
* Convert a distance measurement (assuming a spherical Earth) from a real-world unit into degrees
|
* Valid units: miles, nauticalmiles, inches, yards, meters, metres, centimeters, kilometres, feet
|
*
|
* @name distanceToDegrees
|
* @param {number} distance in real units
|
* @param {string} [units=kilometers] can be degrees, radians, miles, or kilometers inches, yards, metres, meters, kilometres, kilometers.
|
* @returns {number} degrees
|
*/
|
function distanceToDegrees(distance, units) {
|
return radians2degrees(distanceToRadians(distance, units));
|
}
|
|
/**
|
* Converts any bearing angle from the north line direction (positive clockwise)
|
* and returns an angle between 0-360 degrees (positive clockwise), 0 being the north line
|
*
|
* @name bearingToAngle
|
* @param {number} bearing angle, between -180 and +180 degrees
|
* @returns {number} angle between 0 and 360 degrees
|
*/
|
function bearingToAngle(bearing) {
|
if (bearing === null || bearing === undefined) throw new Error('bearing is required');
|
|
var angle = bearing % 360;
|
if (angle < 0) angle += 360;
|
return angle;
|
}
|
|
/**
|
* Converts an angle in radians to degrees
|
*
|
* @name radians2degrees
|
* @param {number} radians angle in radians
|
* @returns {number} degrees between 0 and 360 degrees
|
*/
|
function radians2degrees(radians) {
|
if (radians === null || radians === undefined) throw new Error('radians is required');
|
|
var degrees = radians % (2 * Math.PI);
|
return degrees * 180 / Math.PI;
|
}
|
|
/**
|
* Converts an angle in degrees to radians
|
*
|
* @name degrees2radians
|
* @param {number} degrees angle between 0 and 360 degrees
|
* @returns {number} angle in radians
|
*/
|
function degrees2radians(degrees) {
|
if (degrees === null || degrees === undefined) throw new Error('degrees is required');
|
|
var radians = degrees % 360;
|
return radians * Math.PI / 180;
|
}
|
|
|
/**
|
* Converts a distance to the requested unit.
|
* Valid units: miles, nauticalmiles, inches, yards, meters, metres, kilometers, centimeters, feet
|
*
|
* @param {number} distance to be converted
|
* @param {string} originalUnit of the distance
|
* @param {string} [finalUnit=kilometers] returned unit
|
* @returns {number} the converted distance
|
*/
|
function convertDistance(distance, originalUnit, finalUnit) {
|
if (distance === null || distance === undefined) throw new Error('distance is required');
|
if (!(distance >= 0)) throw new Error('distance must be a positive number');
|
|
var convertedDistance = radiansToDistance(distanceToRadians(distance, originalUnit), finalUnit || 'kilometers');
|
return convertedDistance;
|
}
|
|
/**
|
* Converts a area to the requested unit.
|
* Valid units: kilometers, kilometres, meters, metres, centimetres, millimeter, acre, mile, yard, foot, inch
|
* @param {number} area to be converted
|
* @param {string} [originalUnit=meters] of the distance
|
* @param {string} [finalUnit=kilometers] returned unit
|
* @returns {number} the converted distance
|
*/
|
function convertArea(area, originalUnit, finalUnit) {
|
if (area === null || area === undefined) throw new Error('area is required');
|
if (!(area >= 0)) throw new Error('area must be a positive number');
|
|
var startFactor = areaFactors[originalUnit || 'meters'];
|
if (!startFactor) throw new Error('invalid original units');
|
|
var finalFactor = areaFactors[finalUnit || 'kilometers'];
|
if (!finalFactor) throw new Error('invalid final units');
|
|
return (area / startFactor) * finalFactor;
|
}
|
|
/**
|
* isNumber
|
*
|
* @param {*} num Number to validate
|
* @returns {boolean} true/false
|
* @example
|
* turf.isNumber(123)
|
* //=true
|
* turf.isNumber('foo')
|
* //=false
|
*/
|
function isNumber(num) {
|
return !isNaN(num) && num !== null && !Array.isArray(num);
|
}
|
|
module.exports = {
|
feature: feature,
|
geometry: geometry,
|
featureCollection: featureCollection,
|
geometryCollection: geometryCollection,
|
point: point,
|
multiPoint: multiPoint,
|
lineString: lineString,
|
multiLineString: multiLineString,
|
polygon: polygon,
|
multiPolygon: multiPolygon,
|
radiansToDistance: radiansToDistance,
|
distanceToRadians: distanceToRadians,
|
distanceToDegrees: distanceToDegrees,
|
radians2degrees: radians2degrees,
|
degrees2radians: degrees2radians,
|
bearingToAngle: bearingToAngle,
|
convertDistance: convertDistance,
|
convertArea: convertArea,
|
round: round,
|
isNumber: isNumber
|
};
|
|
},{}],28:[function(require,module,exports){
|
'use strict'
|
|
exports.byteLength = byteLength
|
exports.toByteArray = toByteArray
|
exports.fromByteArray = fromByteArray
|
|
var lookup = []
|
var revLookup = []
|
var Arr = typeof Uint8Array !== 'undefined' ? Uint8Array : Array
|
|
var code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
|
for (var i = 0, len = code.length; i < len; ++i) {
|
lookup[i] = code[i]
|
revLookup[code.charCodeAt(i)] = i
|
}
|
|
// Support decoding URL-safe base64 strings, as Node.js does.
|
// See: https://en.wikipedia.org/wiki/Base64#URL_applications
|
revLookup['-'.charCodeAt(0)] = 62
|
revLookup['_'.charCodeAt(0)] = 63
|
|
function getLens (b64) {
|
var len = b64.length
|
|
if (len % 4 > 0) {
|
throw new Error('Invalid string. Length must be a multiple of 4')
|
}
|
|
// Trim off extra bytes after placeholder bytes are found
|
// See: https://github.com/beatgammit/base64-js/issues/42
|
var validLen = b64.indexOf('=')
|
if (validLen === -1) validLen = len
|
|
var placeHoldersLen = validLen === len
|
? 0
|
: 4 - (validLen % 4)
|
|
return [validLen, placeHoldersLen]
|
}
|
|
// base64 is 4/3 + up to two characters of the original data
|
function byteLength (b64) {
|
var lens = getLens(b64)
|
var validLen = lens[0]
|
var placeHoldersLen = lens[1]
|
return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen
|
}
|
|
function _byteLength (b64, validLen, placeHoldersLen) {
|
return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen
|
}
|
|
function toByteArray (b64) {
|
var tmp
|
var lens = getLens(b64)
|
var validLen = lens[0]
|
var placeHoldersLen = lens[1]
|
|
var arr = new Arr(_byteLength(b64, validLen, placeHoldersLen))
|
|
var curByte = 0
|
|
// if there are placeholders, only get up to the last complete 4 chars
|
var len = placeHoldersLen > 0
|
? validLen - 4
|
: validLen
|
|
var i
|
for (i = 0; i < len; i += 4) {
|
tmp =
|
(revLookup[b64.charCodeAt(i)] << 18) |
|
(revLookup[b64.charCodeAt(i + 1)] << 12) |
|
(revLookup[b64.charCodeAt(i + 2)] << 6) |
|
revLookup[b64.charCodeAt(i + 3)]
|
arr[curByte++] = (tmp >> 16) & 0xFF
|
arr[curByte++] = (tmp >> 8) & 0xFF
|
arr[curByte++] = tmp & 0xFF
|
}
|
|
if (placeHoldersLen === 2) {
|
tmp =
|
(revLookup[b64.charCodeAt(i)] << 2) |
|
(revLookup[b64.charCodeAt(i + 1)] >> 4)
|
arr[curByte++] = tmp & 0xFF
|
}
|
|
if (placeHoldersLen === 1) {
|
tmp =
|
(revLookup[b64.charCodeAt(i)] << 10) |
|
(revLookup[b64.charCodeAt(i + 1)] << 4) |
|
(revLookup[b64.charCodeAt(i + 2)] >> 2)
|
arr[curByte++] = (tmp >> 8) & 0xFF
|
arr[curByte++] = tmp & 0xFF
|
}
|
|
return arr
|
}
|
|
function tripletToBase64 (num) {
|
return lookup[num >> 18 & 0x3F] +
|
lookup[num >> 12 & 0x3F] +
|
lookup[num >> 6 & 0x3F] +
|
lookup[num & 0x3F]
|
}
|
|
function encodeChunk (uint8, start, end) {
|
var tmp
|
var output = []
|
for (var i = start; i < end; i += 3) {
|
tmp =
|
((uint8[i] << 16) & 0xFF0000) +
|
((uint8[i + 1] << 8) & 0xFF00) +
|
(uint8[i + 2] & 0xFF)
|
output.push(tripletToBase64(tmp))
|
}
|
return output.join('')
|
}
|
|
function fromByteArray (uint8) {
|
var tmp
|
var len = uint8.length
|
var extraBytes = len % 3 // if we have 1 byte left, pad 2 bytes
|
var parts = []
|
var maxChunkLength = 16383 // must be multiple of 3
|
|
// go through the array every three bytes, we'll deal with trailing stuff later
|
for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) {
|
parts.push(encodeChunk(
|
uint8, i, (i + maxChunkLength) > len2 ? len2 : (i + maxChunkLength)
|
))
|
}
|
|
// pad the end with zeros, but make sure to not forget the extra bytes
|
if (extraBytes === 1) {
|
tmp = uint8[len - 1]
|
parts.push(
|
lookup[tmp >> 2] +
|
lookup[(tmp << 4) & 0x3F] +
|
'=='
|
)
|
} else if (extraBytes === 2) {
|
tmp = (uint8[len - 2] << 8) + uint8[len - 1]
|
parts.push(
|
lookup[tmp >> 10] +
|
lookup[(tmp >> 4) & 0x3F] +
|
lookup[(tmp << 2) & 0x3F] +
|
'='
|
)
|
}
|
|
return parts.join('')
|
}
|
|
},{}],29:[function(require,module,exports){
|
|
},{}],30:[function(require,module,exports){
|
(function (Buffer){
|
/*!
|
* The buffer module from node.js, for the browser.
|
*
|
* @author Feross Aboukhadijeh <https://feross.org>
|
* @license MIT
|
*/
|
/* eslint-disable no-proto */
|
|
'use strict'
|
|
var base64 = require('base64-js')
|
var ieee754 = require('ieee754')
|
var customInspectSymbol =
|
(typeof Symbol === 'function' && typeof Symbol.for === 'function')
|
? Symbol.for('nodejs.util.inspect.custom')
|
: null
|
|
exports.Buffer = Buffer
|
exports.SlowBuffer = SlowBuffer
|
exports.INSPECT_MAX_BYTES = 50
|
|
var K_MAX_LENGTH = 0x7fffffff
|
exports.kMaxLength = K_MAX_LENGTH
|
|
/**
|
* If `Buffer.TYPED_ARRAY_SUPPORT`:
|
* === true Use Uint8Array implementation (fastest)
|
* === false Print warning and recommend using `buffer` v4.x which has an Object
|
* implementation (most compatible, even IE6)
|
*
|
* Browsers that support typed arrays are IE 10+, Firefox 4+, Chrome 7+, Safari 5.1+,
|
* Opera 11.6+, iOS 4.2+.
|
*
|
* We report that the browser does not support typed arrays if the are not subclassable
|
* using __proto__. Firefox 4-29 lacks support for adding new properties to `Uint8Array`
|
* (See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438). IE 10 lacks support
|
* for __proto__ and has a buggy typed array implementation.
|
*/
|
Buffer.TYPED_ARRAY_SUPPORT = typedArraySupport()
|
|
if (!Buffer.TYPED_ARRAY_SUPPORT && typeof console !== 'undefined' &&
|
typeof console.error === 'function') {
|
console.error(
|
'This browser lacks typed array (Uint8Array) support which is required by ' +
|
'`buffer` v5.x. Use `buffer` v4.x if you require old browser support.'
|
)
|
}
|
|
function typedArraySupport () {
|
// Can typed array instances can be augmented?
|
try {
|
var arr = new Uint8Array(1)
|
var proto = { foo: function () { return 42 } }
|
Object.setPrototypeOf(proto, Uint8Array.prototype)
|
Object.setPrototypeOf(arr, proto)
|
return arr.foo() === 42
|
} catch (e) {
|
return false
|
}
|
}
|
|
Object.defineProperty(Buffer.prototype, 'parent', {
|
enumerable: true,
|
get: function () {
|
if (!Buffer.isBuffer(this)) return undefined
|
return this.buffer
|
}
|
})
|
|
Object.defineProperty(Buffer.prototype, 'offset', {
|
enumerable: true,
|
get: function () {
|
if (!Buffer.isBuffer(this)) return undefined
|
return this.byteOffset
|
}
|
})
|
|
function createBuffer (length) {
|
if (length > K_MAX_LENGTH) {
|
throw new RangeError('The value "' + length + '" is invalid for option "size"')
|
}
|
// Return an augmented `Uint8Array` instance
|
var buf = new Uint8Array(length)
|
Object.setPrototypeOf(buf, Buffer.prototype)
|
return buf
|
}
|
|
/**
|
* The Buffer constructor returns instances of `Uint8Array` that have their
|
* prototype changed to `Buffer.prototype`. Furthermore, `Buffer` is a subclass of
|
* `Uint8Array`, so the returned instances will have all the node `Buffer` methods
|
* and the `Uint8Array` methods. Square bracket notation works as expected -- it
|
* returns a single octet.
|
*
|
* The `Uint8Array` prototype remains unmodified.
|
*/
|
|
function Buffer (arg, encodingOrOffset, length) {
|
// Common case.
|
if (typeof arg === 'number') {
|
if (typeof encodingOrOffset === 'string') {
|
throw new TypeError(
|
'The "string" argument must be of type string. Received type number'
|
)
|
}
|
return allocUnsafe(arg)
|
}
|
return from(arg, encodingOrOffset, length)
|
}
|
|
// Fix subarray() in ES2016. See: https://github.com/feross/buffer/pull/97
|
if (typeof Symbol !== 'undefined' && Symbol.species != null &&
|
Buffer[Symbol.species] === Buffer) {
|
Object.defineProperty(Buffer, Symbol.species, {
|
value: null,
|
configurable: true,
|
enumerable: false,
|
writable: false
|
})
|
}
|
|
Buffer.poolSize = 8192 // not used by this implementation
|
|
function from (value, encodingOrOffset, length) {
|
if (typeof value === 'string') {
|
return fromString(value, encodingOrOffset)
|
}
|
|
if (ArrayBuffer.isView(value)) {
|
return fromArrayLike(value)
|
}
|
|
if (value == null) {
|
throw new TypeError(
|
'The first argument must be one of type string, Buffer, ArrayBuffer, Array, ' +
|
'or Array-like Object. Received type ' + (typeof value)
|
)
|
}
|
|
if (isInstance(value, ArrayBuffer) ||
|
(value && isInstance(value.buffer, ArrayBuffer))) {
|
return fromArrayBuffer(value, encodingOrOffset, length)
|
}
|
|
if (typeof SharedArrayBuffer !== 'undefined' &&
|
(isInstance(value, SharedArrayBuffer) ||
|
(value && isInstance(value.buffer, SharedArrayBuffer)))) {
|
return fromArrayBuffer(value, encodingOrOffset, length)
|
}
|
|
if (typeof value === 'number') {
|
throw new TypeError(
|
'The "value" argument must not be of type number. Received type number'
|
)
|
}
|
|
var valueOf = value.valueOf && value.valueOf()
|
if (valueOf != null && valueOf !== value) {
|
return Buffer.from(valueOf, encodingOrOffset, length)
|
}
|
|
var b = fromObject(value)
|
if (b) return b
|
|
if (typeof Symbol !== 'undefined' && Symbol.toPrimitive != null &&
|
typeof value[Symbol.toPrimitive] === 'function') {
|
return Buffer.from(
|
value[Symbol.toPrimitive]('string'), encodingOrOffset, length
|
)
|
}
|
|
throw new TypeError(
|
'The first argument must be one of type string, Buffer, ArrayBuffer, Array, ' +
|
'or Array-like Object. Received type ' + (typeof value)
|
)
|
}
|
|
/**
|
* Functionally equivalent to Buffer(arg, encoding) but throws a TypeError
|
* if value is a number.
|
* Buffer.from(str[, encoding])
|
* Buffer.from(array)
|
* Buffer.from(buffer)
|
* Buffer.from(arrayBuffer[, byteOffset[, length]])
|
**/
|
Buffer.from = function (value, encodingOrOffset, length) {
|
return from(value, encodingOrOffset, length)
|
}
|
|
// Note: Change prototype *after* Buffer.from is defined to workaround Chrome bug:
|
// https://github.com/feross/buffer/pull/148
|
Object.setPrototypeOf(Buffer.prototype, Uint8Array.prototype)
|
Object.setPrototypeOf(Buffer, Uint8Array)
|
|
function assertSize (size) {
|
if (typeof size !== 'number') {
|
throw new TypeError('"size" argument must be of type number')
|
} else if (size < 0) {
|
throw new RangeError('The value "' + size + '" is invalid for option "size"')
|
}
|
}
|
|
function alloc (size, fill, encoding) {
|
assertSize(size)
|
if (size <= 0) {
|
return createBuffer(size)
|
}
|
if (fill !== undefined) {
|
// Only pay attention to encoding if it's a string. This
|
// prevents accidentally sending in a number that would
|
// be interpretted as a start offset.
|
return typeof encoding === 'string'
|
? createBuffer(size).fill(fill, encoding)
|
: createBuffer(size).fill(fill)
|
}
|
return createBuffer(size)
|
}
|
|
/**
|
* Creates a new filled Buffer instance.
|
* alloc(size[, fill[, encoding]])
|
**/
|
Buffer.alloc = function (size, fill, encoding) {
|
return alloc(size, fill, encoding)
|
}
|
|
function allocUnsafe (size) {
|
assertSize(size)
|
return createBuffer(size < 0 ? 0 : checked(size) | 0)
|
}
|
|
/**
|
* Equivalent to Buffer(num), by default creates a non-zero-filled Buffer instance.
|
* */
|
Buffer.allocUnsafe = function (size) {
|
return allocUnsafe(size)
|
}
|
/**
|
* Equivalent to SlowBuffer(num), by default creates a non-zero-filled Buffer instance.
|
*/
|
Buffer.allocUnsafeSlow = function (size) {
|
return allocUnsafe(size)
|
}
|
|
function fromString (string, encoding) {
|
if (typeof encoding !== 'string' || encoding === '') {
|
encoding = 'utf8'
|
}
|
|
if (!Buffer.isEncoding(encoding)) {
|
throw new TypeError('Unknown encoding: ' + encoding)
|
}
|
|
var length = byteLength(string, encoding) | 0
|
var buf = createBuffer(length)
|
|
var actual = buf.write(string, encoding)
|
|
if (actual !== length) {
|
// Writing a hex string, for example, that contains invalid characters will
|
// cause everything after the first invalid character to be ignored. (e.g.
|
// 'abxxcd' will be treated as 'ab')
|
buf = buf.slice(0, actual)
|
}
|
|
return buf
|
}
|
|
function fromArrayLike (array) {
|
var length = array.length < 0 ? 0 : checked(array.length) | 0
|
var buf = createBuffer(length)
|
for (var i = 0; i < length; i += 1) {
|
buf[i] = array[i] & 255
|
}
|
return buf
|
}
|
|
function fromArrayBuffer (array, byteOffset, length) {
|
if (byteOffset < 0 || array.byteLength < byteOffset) {
|
throw new RangeError('"offset" is outside of buffer bounds')
|
}
|
|
if (array.byteLength < byteOffset + (length || 0)) {
|
throw new RangeError('"length" is outside of buffer bounds')
|
}
|
|
var buf
|
if (byteOffset === undefined && length === undefined) {
|
buf = new Uint8Array(array)
|
} else if (length === undefined) {
|
buf = new Uint8Array(array, byteOffset)
|
} else {
|
buf = new Uint8Array(array, byteOffset, length)
|
}
|
|
// Return an augmented `Uint8Array` instance
|
Object.setPrototypeOf(buf, Buffer.prototype)
|
|
return buf
|
}
|
|
function fromObject (obj) {
|
if (Buffer.isBuffer(obj)) {
|
var len = checked(obj.length) | 0
|
var buf = createBuffer(len)
|
|
if (buf.length === 0) {
|
return buf
|
}
|
|
obj.copy(buf, 0, 0, len)
|
return buf
|
}
|
|
if (obj.length !== undefined) {
|
if (typeof obj.length !== 'number' || numberIsNaN(obj.length)) {
|
return createBuffer(0)
|
}
|
return fromArrayLike(obj)
|
}
|
|
if (obj.type === 'Buffer' && Array.isArray(obj.data)) {
|
return fromArrayLike(obj.data)
|
}
|
}
|
|
function checked (length) {
|
// Note: cannot use `length < K_MAX_LENGTH` here because that fails when
|
// length is NaN (which is otherwise coerced to zero.)
|
if (length >= K_MAX_LENGTH) {
|
throw new RangeError('Attempt to allocate Buffer larger than maximum ' +
|
'size: 0x' + K_MAX_LENGTH.toString(16) + ' bytes')
|
}
|
return length | 0
|
}
|
|
function SlowBuffer (length) {
|
if (+length != length) { // eslint-disable-line eqeqeq
|
length = 0
|
}
|
return Buffer.alloc(+length)
|
}
|
|
Buffer.isBuffer = function isBuffer (b) {
|
return b != null && b._isBuffer === true &&
|
b !== Buffer.prototype // so Buffer.isBuffer(Buffer.prototype) will be false
|
}
|
|
Buffer.compare = function compare (a, b) {
|
if (isInstance(a, Uint8Array)) a = Buffer.from(a, a.offset, a.byteLength)
|
if (isInstance(b, Uint8Array)) b = Buffer.from(b, b.offset, b.byteLength)
|
if (!Buffer.isBuffer(a) || !Buffer.isBuffer(b)) {
|
throw new TypeError(
|
'The "buf1", "buf2" arguments must be one of type Buffer or Uint8Array'
|
)
|
}
|
|
if (a === b) return 0
|
|
var x = a.length
|
var y = b.length
|
|
for (var i = 0, len = Math.min(x, y); i < len; ++i) {
|
if (a[i] !== b[i]) {
|
x = a[i]
|
y = b[i]
|
break
|
}
|
}
|
|
if (x < y) return -1
|
if (y < x) return 1
|
return 0
|
}
|
|
Buffer.isEncoding = function isEncoding (encoding) {
|
switch (String(encoding).toLowerCase()) {
|
case 'hex':
|
case 'utf8':
|
case 'utf-8':
|
case 'ascii':
|
case 'latin1':
|
case 'binary':
|
case 'base64':
|
case 'ucs2':
|
case 'ucs-2':
|
case 'utf16le':
|
case 'utf-16le':
|
return true
|
default:
|
return false
|
}
|
}
|
|
Buffer.concat = function concat (list, length) {
|
if (!Array.isArray(list)) {
|
throw new TypeError('"list" argument must be an Array of Buffers')
|
}
|
|
if (list.length === 0) {
|
return Buffer.alloc(0)
|
}
|
|
var i
|
if (length === undefined) {
|
length = 0
|
for (i = 0; i < list.length; ++i) {
|
length += list[i].length
|
}
|
}
|
|
var buffer = Buffer.allocUnsafe(length)
|
var pos = 0
|
for (i = 0; i < list.length; ++i) {
|
var buf = list[i]
|
if (isInstance(buf, Uint8Array)) {
|
buf = Buffer.from(buf)
|
}
|
if (!Buffer.isBuffer(buf)) {
|
throw new TypeError('"list" argument must be an Array of Buffers')
|
}
|
buf.copy(buffer, pos)
|
pos += buf.length
|
}
|
return buffer
|
}
|
|
function byteLength (string, encoding) {
|
if (Buffer.isBuffer(string)) {
|
return string.length
|
}
|
if (ArrayBuffer.isView(string) || isInstance(string, ArrayBuffer)) {
|
return string.byteLength
|
}
|
if (typeof string !== 'string') {
|
throw new TypeError(
|
'The "string" argument must be one of type string, Buffer, or ArrayBuffer. ' +
|
'Received type ' + typeof string
|
)
|
}
|
|
var len = string.length
|
var mustMatch = (arguments.length > 2 && arguments[2] === true)
|
if (!mustMatch && len === 0) return 0
|
|
// Use a for loop to avoid recursion
|
var loweredCase = false
|
for (;;) {
|
switch (encoding) {
|
case 'ascii':
|
case 'latin1':
|
case 'binary':
|
return len
|
case 'utf8':
|
case 'utf-8':
|
return utf8ToBytes(string).length
|
case 'ucs2':
|
case 'ucs-2':
|
case 'utf16le':
|
case 'utf-16le':
|
return len * 2
|
case 'hex':
|
return len >>> 1
|
case 'base64':
|
return base64ToBytes(string).length
|
default:
|
if (loweredCase) {
|
return mustMatch ? -1 : utf8ToBytes(string).length // assume utf8
|
}
|
encoding = ('' + encoding).toLowerCase()
|
loweredCase = true
|
}
|
}
|
}
|
Buffer.byteLength = byteLength
|
|
function slowToString (encoding, start, end) {
|
var loweredCase = false
|
|
// No need to verify that "this.length <= MAX_UINT32" since it's a read-only
|
// property of a typed array.
|
|
// This behaves neither like String nor Uint8Array in that we set start/end
|
// to their upper/lower bounds if the value passed is out of range.
|
// undefined is handled specially as per ECMA-262 6th Edition,
|
// Section 13.3.3.7 Runtime Semantics: KeyedBindingInitialization.
|
if (start === undefined || start < 0) {
|
start = 0
|
}
|
// Return early if start > this.length. Done here to prevent potential uint32
|
// coercion fail below.
|
if (start > this.length) {
|
return ''
|
}
|
|
if (end === undefined || end > this.length) {
|
end = this.length
|
}
|
|
if (end <= 0) {
|
return ''
|
}
|
|
// Force coersion to uint32. This will also coerce falsey/NaN values to 0.
|
end >>>= 0
|
start >>>= 0
|
|
if (end <= start) {
|
return ''
|
}
|
|
if (!encoding) encoding = 'utf8'
|
|
while (true) {
|
switch (encoding) {
|
case 'hex':
|
return hexSlice(this, start, end)
|
|
case 'utf8':
|
case 'utf-8':
|
return utf8Slice(this, start, end)
|
|
case 'ascii':
|
return asciiSlice(this, start, end)
|
|
case 'latin1':
|
case 'binary':
|
return latin1Slice(this, start, end)
|
|
case 'base64':
|
return base64Slice(this, start, end)
|
|
case 'ucs2':
|
case 'ucs-2':
|
case 'utf16le':
|
case 'utf-16le':
|
return utf16leSlice(this, start, end)
|
|
default:
|
if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding)
|
encoding = (encoding + '').toLowerCase()
|
loweredCase = true
|
}
|
}
|
}
|
|
// This property is used by `Buffer.isBuffer` (and the `is-buffer` npm package)
|
// to detect a Buffer instance. It's not possible to use `instanceof Buffer`
|
// reliably in a browserify context because there could be multiple different
|
// copies of the 'buffer' package in use. This method works even for Buffer
|
// instances that were created from another copy of the `buffer` package.
|
// See: https://github.com/feross/buffer/issues/154
|
Buffer.prototype._isBuffer = true
|
|
function swap (b, n, m) {
|
var i = b[n]
|
b[n] = b[m]
|
b[m] = i
|
}
|
|
Buffer.prototype.swap16 = function swap16 () {
|
var len = this.length
|
if (len % 2 !== 0) {
|
throw new RangeError('Buffer size must be a multiple of 16-bits')
|
}
|
for (var i = 0; i < len; i += 2) {
|
swap(this, i, i + 1)
|
}
|
return this
|
}
|
|
Buffer.prototype.swap32 = function swap32 () {
|
var len = this.length
|
if (len % 4 !== 0) {
|
throw new RangeError('Buffer size must be a multiple of 32-bits')
|
}
|
for (var i = 0; i < len; i += 4) {
|
swap(this, i, i + 3)
|
swap(this, i + 1, i + 2)
|
}
|
return this
|
}
|
|
Buffer.prototype.swap64 = function swap64 () {
|
var len = this.length
|
if (len % 8 !== 0) {
|
throw new RangeError('Buffer size must be a multiple of 64-bits')
|
}
|
for (var i = 0; i < len; i += 8) {
|
swap(this, i, i + 7)
|
swap(this, i + 1, i + 6)
|
swap(this, i + 2, i + 5)
|
swap(this, i + 3, i + 4)
|
}
|
return this
|
}
|
|
Buffer.prototype.toString = function toString () {
|
var length = this.length
|
if (length === 0) return ''
|
if (arguments.length === 0) return utf8Slice(this, 0, length)
|
return slowToString.apply(this, arguments)
|
}
|
|
Buffer.prototype.toLocaleString = Buffer.prototype.toString
|
|
Buffer.prototype.equals = function equals (b) {
|
if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer')
|
if (this === b) return true
|
return Buffer.compare(this, b) === 0
|
}
|
|
Buffer.prototype.inspect = function inspect () {
|
var str = ''
|
var max = exports.INSPECT_MAX_BYTES
|
str = this.toString('hex', 0, max).replace(/(.{2})/g, '$1 ').trim()
|
if (this.length > max) str += ' ... '
|
return '<Buffer ' + str + '>'
|
}
|
if (customInspectSymbol) {
|
Buffer.prototype[customInspectSymbol] = Buffer.prototype.inspect
|
}
|
|
Buffer.prototype.compare = function compare (target, start, end, thisStart, thisEnd) {
|
if (isInstance(target, Uint8Array)) {
|
target = Buffer.from(target, target.offset, target.byteLength)
|
}
|
if (!Buffer.isBuffer(target)) {
|
throw new TypeError(
|
'The "target" argument must be one of type Buffer or Uint8Array. ' +
|
'Received type ' + (typeof target)
|
)
|
}
|
|
if (start === undefined) {
|
start = 0
|
}
|
if (end === undefined) {
|
end = target ? target.length : 0
|
}
|
if (thisStart === undefined) {
|
thisStart = 0
|
}
|
if (thisEnd === undefined) {
|
thisEnd = this.length
|
}
|
|
if (start < 0 || end > target.length || thisStart < 0 || thisEnd > this.length) {
|
throw new RangeError('out of range index')
|
}
|
|
if (thisStart >= thisEnd && start >= end) {
|
return 0
|
}
|
if (thisStart >= thisEnd) {
|
return -1
|
}
|
if (start >= end) {
|
return 1
|
}
|
|
start >>>= 0
|
end >>>= 0
|
thisStart >>>= 0
|
thisEnd >>>= 0
|
|
if (this === target) return 0
|
|
var x = thisEnd - thisStart
|
var y = end - start
|
var len = Math.min(x, y)
|
|
var thisCopy = this.slice(thisStart, thisEnd)
|
var targetCopy = target.slice(start, end)
|
|
for (var i = 0; i < len; ++i) {
|
if (thisCopy[i] !== targetCopy[i]) {
|
x = thisCopy[i]
|
y = targetCopy[i]
|
break
|
}
|
}
|
|
if (x < y) return -1
|
if (y < x) return 1
|
return 0
|
}
|
|
// Finds either the first index of `val` in `buffer` at offset >= `byteOffset`,
|
// OR the last index of `val` in `buffer` at offset <= `byteOffset`.
|
//
|
// Arguments:
|
// - buffer - a Buffer to search
|
// - val - a string, Buffer, or number
|
// - byteOffset - an index into `buffer`; will be clamped to an int32
|
// - encoding - an optional encoding, relevant is val is a string
|
// - dir - true for indexOf, false for lastIndexOf
|
function bidirectionalIndexOf (buffer, val, byteOffset, encoding, dir) {
|
// Empty buffer means no match
|
if (buffer.length === 0) return -1
|
|
// Normalize byteOffset
|
if (typeof byteOffset === 'string') {
|
encoding = byteOffset
|
byteOffset = 0
|
} else if (byteOffset > 0x7fffffff) {
|
byteOffset = 0x7fffffff
|
} else if (byteOffset < -0x80000000) {
|
byteOffset = -0x80000000
|
}
|
byteOffset = +byteOffset // Coerce to Number.
|
if (numberIsNaN(byteOffset)) {
|
// byteOffset: it it's undefined, null, NaN, "foo", etc, search whole buffer
|
byteOffset = dir ? 0 : (buffer.length - 1)
|
}
|
|
// Normalize byteOffset: negative offsets start from the end of the buffer
|
if (byteOffset < 0) byteOffset = buffer.length + byteOffset
|
if (byteOffset >= buffer.length) {
|
if (dir) return -1
|
else byteOffset = buffer.length - 1
|
} else if (byteOffset < 0) {
|
if (dir) byteOffset = 0
|
else return -1
|
}
|
|
// Normalize val
|
if (typeof val === 'string') {
|
val = Buffer.from(val, encoding)
|
}
|
|
// Finally, search either indexOf (if dir is true) or lastIndexOf
|
if (Buffer.isBuffer(val)) {
|
// Special case: looking for empty string/buffer always fails
|
if (val.length === 0) {
|
return -1
|
}
|
return arrayIndexOf(buffer, val, byteOffset, encoding, dir)
|
} else if (typeof val === 'number') {
|
val = val & 0xFF // Search for a byte value [0-255]
|
if (typeof Uint8Array.prototype.indexOf === 'function') {
|
if (dir) {
|
return Uint8Array.prototype.indexOf.call(buffer, val, byteOffset)
|
} else {
|
return Uint8Array.prototype.lastIndexOf.call(buffer, val, byteOffset)
|
}
|
}
|
return arrayIndexOf(buffer, [val], byteOffset, encoding, dir)
|
}
|
|
throw new TypeError('val must be string, number or Buffer')
|
}
|
|
function arrayIndexOf (arr, val, byteOffset, encoding, dir) {
|
var indexSize = 1
|
var arrLength = arr.length
|
var valLength = val.length
|
|
if (encoding !== undefined) {
|
encoding = String(encoding).toLowerCase()
|
if (encoding === 'ucs2' || encoding === 'ucs-2' ||
|
encoding === 'utf16le' || encoding === 'utf-16le') {
|
if (arr.length < 2 || val.length < 2) {
|
return -1
|
}
|
indexSize = 2
|
arrLength /= 2
|
valLength /= 2
|
byteOffset /= 2
|
}
|
}
|
|
function read (buf, i) {
|
if (indexSize === 1) {
|
return buf[i]
|
} else {
|
return buf.readUInt16BE(i * indexSize)
|
}
|
}
|
|
var i
|
if (dir) {
|
var foundIndex = -1
|
for (i = byteOffset; i < arrLength; i++) {
|
if (read(arr, i) === read(val, foundIndex === -1 ? 0 : i - foundIndex)) {
|
if (foundIndex === -1) foundIndex = i
|
if (i - foundIndex + 1 === valLength) return foundIndex * indexSize
|
} else {
|
if (foundIndex !== -1) i -= i - foundIndex
|
foundIndex = -1
|
}
|
}
|
} else {
|
if (byteOffset + valLength > arrLength) byteOffset = arrLength - valLength
|
for (i = byteOffset; i >= 0; i--) {
|
var found = true
|
for (var j = 0; j < valLength; j++) {
|
if (read(arr, i + j) !== read(val, j)) {
|
found = false
|
break
|
}
|
}
|
if (found) return i
|
}
|
}
|
|
return -1
|
}
|
|
Buffer.prototype.includes = function includes (val, byteOffset, encoding) {
|
return this.indexOf(val, byteOffset, encoding) !== -1
|
}
|
|
Buffer.prototype.indexOf = function indexOf (val, byteOffset, encoding) {
|
return bidirectionalIndexOf(this, val, byteOffset, encoding, true)
|
}
|
|
Buffer.prototype.lastIndexOf = function lastIndexOf (val, byteOffset, encoding) {
|
return bidirectionalIndexOf(this, val, byteOffset, encoding, false)
|
}
|
|
function hexWrite (buf, string, offset, length) {
|
offset = Number(offset) || 0
|
var remaining = buf.length - offset
|
if (!length) {
|
length = remaining
|
} else {
|
length = Number(length)
|
if (length > remaining) {
|
length = remaining
|
}
|
}
|
|
var strLen = string.length
|
|
if (length > strLen / 2) {
|
length = strLen / 2
|
}
|
for (var i = 0; i < length; ++i) {
|
var parsed = parseInt(string.substr(i * 2, 2), 16)
|
if (numberIsNaN(parsed)) return i
|
buf[offset + i] = parsed
|
}
|
return i
|
}
|
|
function utf8Write (buf, string, offset, length) {
|
return blitBuffer(utf8ToBytes(string, buf.length - offset), buf, offset, length)
|
}
|
|
function asciiWrite (buf, string, offset, length) {
|
return blitBuffer(asciiToBytes(string), buf, offset, length)
|
}
|
|
function latin1Write (buf, string, offset, length) {
|
return asciiWrite(buf, string, offset, length)
|
}
|
|
function base64Write (buf, string, offset, length) {
|
return blitBuffer(base64ToBytes(string), buf, offset, length)
|
}
|
|
function ucs2Write (buf, string, offset, length) {
|
return blitBuffer(utf16leToBytes(string, buf.length - offset), buf, offset, length)
|
}
|
|
Buffer.prototype.write = function write (string, offset, length, encoding) {
|
// Buffer#write(string)
|
if (offset === undefined) {
|
encoding = 'utf8'
|
length = this.length
|
offset = 0
|
// Buffer#write(string, encoding)
|
} else if (length === undefined && typeof offset === 'string') {
|
encoding = offset
|
length = this.length
|
offset = 0
|
// Buffer#write(string, offset[, length][, encoding])
|
} else if (isFinite(offset)) {
|
offset = offset >>> 0
|
if (isFinite(length)) {
|
length = length >>> 0
|
if (encoding === undefined) encoding = 'utf8'
|
} else {
|
encoding = length
|
length = undefined
|
}
|
} else {
|
throw new Error(
|
'Buffer.write(string, encoding, offset[, length]) is no longer supported'
|
)
|
}
|
|
var remaining = this.length - offset
|
if (length === undefined || length > remaining) length = remaining
|
|
if ((string.length > 0 && (length < 0 || offset < 0)) || offset > this.length) {
|
throw new RangeError('Attempt to write outside buffer bounds')
|
}
|
|
if (!encoding) encoding = 'utf8'
|
|
var loweredCase = false
|
for (;;) {
|
switch (encoding) {
|
case 'hex':
|
return hexWrite(this, string, offset, length)
|
|
case 'utf8':
|
case 'utf-8':
|
return utf8Write(this, string, offset, length)
|
|
case 'ascii':
|
return asciiWrite(this, string, offset, length)
|
|
case 'latin1':
|
case 'binary':
|
return latin1Write(this, string, offset, length)
|
|
case 'base64':
|
// Warning: maxLength not taken into account in base64Write
|
return base64Write(this, string, offset, length)
|
|
case 'ucs2':
|
case 'ucs-2':
|
case 'utf16le':
|
case 'utf-16le':
|
return ucs2Write(this, string, offset, length)
|
|
default:
|
if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding)
|
encoding = ('' + encoding).toLowerCase()
|
loweredCase = true
|
}
|
}
|
}
|
|
Buffer.prototype.toJSON = function toJSON () {
|
return {
|
type: 'Buffer',
|
data: Array.prototype.slice.call(this._arr || this, 0)
|
}
|
}
|
|
function base64Slice (buf, start, end) {
|
if (start === 0 && end === buf.length) {
|
return base64.fromByteArray(buf)
|
} else {
|
return base64.fromByteArray(buf.slice(start, end))
|
}
|
}
|
|
function utf8Slice (buf, start, end) {
|
end = Math.min(buf.length, end)
|
var res = []
|
|
var i = start
|
while (i < end) {
|
var firstByte = buf[i]
|
var codePoint = null
|
var bytesPerSequence = (firstByte > 0xEF) ? 4
|
: (firstByte > 0xDF) ? 3
|
: (firstByte > 0xBF) ? 2
|
: 1
|
|
if (i + bytesPerSequence <= end) {
|
var secondByte, thirdByte, fourthByte, tempCodePoint
|
|
switch (bytesPerSequence) {
|
case 1:
|
if (firstByte < 0x80) {
|
codePoint = firstByte
|
}
|
break
|
case 2:
|
secondByte = buf[i + 1]
|
if ((secondByte & 0xC0) === 0x80) {
|
tempCodePoint = (firstByte & 0x1F) << 0x6 | (secondByte & 0x3F)
|
if (tempCodePoint > 0x7F) {
|
codePoint = tempCodePoint
|
}
|
}
|
break
|
case 3:
|
secondByte = buf[i + 1]
|
thirdByte = buf[i + 2]
|
if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80) {
|
tempCodePoint = (firstByte & 0xF) << 0xC | (secondByte & 0x3F) << 0x6 | (thirdByte & 0x3F)
|
if (tempCodePoint > 0x7FF && (tempCodePoint < 0xD800 || tempCodePoint > 0xDFFF)) {
|
codePoint = tempCodePoint
|
}
|
}
|
break
|
case 4:
|
secondByte = buf[i + 1]
|
thirdByte = buf[i + 2]
|
fourthByte = buf[i + 3]
|
if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80 && (fourthByte & 0xC0) === 0x80) {
|
tempCodePoint = (firstByte & 0xF) << 0x12 | (secondByte & 0x3F) << 0xC | (thirdByte & 0x3F) << 0x6 | (fourthByte & 0x3F)
|
if (tempCodePoint > 0xFFFF && tempCodePoint < 0x110000) {
|
codePoint = tempCodePoint
|
}
|
}
|
}
|
}
|
|
if (codePoint === null) {
|
// we did not generate a valid codePoint so insert a
|
// replacement char (U+FFFD) and advance only 1 byte
|
codePoint = 0xFFFD
|
bytesPerSequence = 1
|
} else if (codePoint > 0xFFFF) {
|
// encode to utf16 (surrogate pair dance)
|
codePoint -= 0x10000
|
res.push(codePoint >>> 10 & 0x3FF | 0xD800)
|
codePoint = 0xDC00 | codePoint & 0x3FF
|
}
|
|
res.push(codePoint)
|
i += bytesPerSequence
|
}
|
|
return decodeCodePointsArray(res)
|
}
|
|
// Based on http://stackoverflow.com/a/22747272/680742, the browser with
|
// the lowest limit is Chrome, with 0x10000 args.
|
// We go 1 magnitude less, for safety
|
var MAX_ARGUMENTS_LENGTH = 0x1000
|
|
function decodeCodePointsArray (codePoints) {
|
var len = codePoints.length
|
if (len <= MAX_ARGUMENTS_LENGTH) {
|
return String.fromCharCode.apply(String, codePoints) // avoid extra slice()
|
}
|
|
// Decode in chunks to avoid "call stack size exceeded".
|
var res = ''
|
var i = 0
|
while (i < len) {
|
res += String.fromCharCode.apply(
|
String,
|
codePoints.slice(i, i += MAX_ARGUMENTS_LENGTH)
|
)
|
}
|
return res
|
}
|
|
function asciiSlice (buf, start, end) {
|
var ret = ''
|
end = Math.min(buf.length, end)
|
|
for (var i = start; i < end; ++i) {
|
ret += String.fromCharCode(buf[i] & 0x7F)
|
}
|
return ret
|
}
|
|
function latin1Slice (buf, start, end) {
|
var ret = ''
|
end = Math.min(buf.length, end)
|
|
for (var i = start; i < end; ++i) {
|
ret += String.fromCharCode(buf[i])
|
}
|
return ret
|
}
|
|
function hexSlice (buf, start, end) {
|
var len = buf.length
|
|
if (!start || start < 0) start = 0
|
if (!end || end < 0 || end > len) end = len
|
|
var out = ''
|
for (var i = start; i < end; ++i) {
|
out += hexSliceLookupTable[buf[i]]
|
}
|
return out
|
}
|
|
function utf16leSlice (buf, start, end) {
|
var bytes = buf.slice(start, end)
|
var res = ''
|
for (var i = 0; i < bytes.length; i += 2) {
|
res += String.fromCharCode(bytes[i] + (bytes[i + 1] * 256))
|
}
|
return res
|
}
|
|
Buffer.prototype.slice = function slice (start, end) {
|
var len = this.length
|
start = ~~start
|
end = end === undefined ? len : ~~end
|
|
if (start < 0) {
|
start += len
|
if (start < 0) start = 0
|
} else if (start > len) {
|
start = len
|
}
|
|
if (end < 0) {
|
end += len
|
if (end < 0) end = 0
|
} else if (end > len) {
|
end = len
|
}
|
|
if (end < start) end = start
|
|
var newBuf = this.subarray(start, end)
|
// Return an augmented `Uint8Array` instance
|
Object.setPrototypeOf(newBuf, Buffer.prototype)
|
|
return newBuf
|
}
|
|
/*
|
* Need to make sure that buffer isn't trying to write out of bounds.
|
*/
|
function checkOffset (offset, ext, length) {
|
if ((offset % 1) !== 0 || offset < 0) throw new RangeError('offset is not uint')
|
if (offset + ext > length) throw new RangeError('Trying to access beyond buffer length')
|
}
|
|
Buffer.prototype.readUIntLE = function readUIntLE (offset, byteLength, noAssert) {
|
offset = offset >>> 0
|
byteLength = byteLength >>> 0
|
if (!noAssert) checkOffset(offset, byteLength, this.length)
|
|
var val = this[offset]
|
var mul = 1
|
var i = 0
|
while (++i < byteLength && (mul *= 0x100)) {
|
val += this[offset + i] * mul
|
}
|
|
return val
|
}
|
|
Buffer.prototype.readUIntBE = function readUIntBE (offset, byteLength, noAssert) {
|
offset = offset >>> 0
|
byteLength = byteLength >>> 0
|
if (!noAssert) {
|
checkOffset(offset, byteLength, this.length)
|
}
|
|
var val = this[offset + --byteLength]
|
var mul = 1
|
while (byteLength > 0 && (mul *= 0x100)) {
|
val += this[offset + --byteLength] * mul
|
}
|
|
return val
|
}
|
|
Buffer.prototype.readUInt8 = function readUInt8 (offset, noAssert) {
|
offset = offset >>> 0
|
if (!noAssert) checkOffset(offset, 1, this.length)
|
return this[offset]
|
}
|
|
Buffer.prototype.readUInt16LE = function readUInt16LE (offset, noAssert) {
|
offset = offset >>> 0
|
if (!noAssert) checkOffset(offset, 2, this.length)
|
return this[offset] | (this[offset + 1] << 8)
|
}
|
|
Buffer.prototype.readUInt16BE = function readUInt16BE (offset, noAssert) {
|
offset = offset >>> 0
|
if (!noAssert) checkOffset(offset, 2, this.length)
|
return (this[offset] << 8) | this[offset + 1]
|
}
|
|
Buffer.prototype.readUInt32LE = function readUInt32LE (offset, noAssert) {
|
offset = offset >>> 0
|
if (!noAssert) checkOffset(offset, 4, this.length)
|
|
return ((this[offset]) |
|
(this[offset + 1] << 8) |
|
(this[offset + 2] << 16)) +
|
(this[offset + 3] * 0x1000000)
|
}
|
|
Buffer.prototype.readUInt32BE = function readUInt32BE (offset, noAssert) {
|
offset = offset >>> 0
|
if (!noAssert) checkOffset(offset, 4, this.length)
|
|
return (this[offset] * 0x1000000) +
|
((this[offset + 1] << 16) |
|
(this[offset + 2] << 8) |
|
this[offset + 3])
|
}
|
|
Buffer.prototype.readIntLE = function readIntLE (offset, byteLength, noAssert) {
|
offset = offset >>> 0
|
byteLength = byteLength >>> 0
|
if (!noAssert) checkOffset(offset, byteLength, this.length)
|
|
var val = this[offset]
|
var mul = 1
|
var i = 0
|
while (++i < byteLength && (mul *= 0x100)) {
|
val += this[offset + i] * mul
|
}
|
mul *= 0x80
|
|
if (val >= mul) val -= Math.pow(2, 8 * byteLength)
|
|
return val
|
}
|
|
Buffer.prototype.readIntBE = function readIntBE (offset, byteLength, noAssert) {
|
offset = offset >>> 0
|
byteLength = byteLength >>> 0
|
if (!noAssert) checkOffset(offset, byteLength, this.length)
|
|
var i = byteLength
|
var mul = 1
|
var val = this[offset + --i]
|
while (i > 0 && (mul *= 0x100)) {
|
val += this[offset + --i] * mul
|
}
|
mul *= 0x80
|
|
if (val >= mul) val -= Math.pow(2, 8 * byteLength)
|
|
return val
|
}
|
|
Buffer.prototype.readInt8 = function readInt8 (offset, noAssert) {
|
offset = offset >>> 0
|
if (!noAssert) checkOffset(offset, 1, this.length)
|
if (!(this[offset] & 0x80)) return (this[offset])
|
return ((0xff - this[offset] + 1) * -1)
|
}
|
|
Buffer.prototype.readInt16LE = function readInt16LE (offset, noAssert) {
|
offset = offset >>> 0
|
if (!noAssert) checkOffset(offset, 2, this.length)
|
var val = this[offset] | (this[offset + 1] << 8)
|
return (val & 0x8000) ? val | 0xFFFF0000 : val
|
}
|
|
Buffer.prototype.readInt16BE = function readInt16BE (offset, noAssert) {
|
offset = offset >>> 0
|
if (!noAssert) checkOffset(offset, 2, this.length)
|
var val = this[offset + 1] | (this[offset] << 8)
|
return (val & 0x8000) ? val | 0xFFFF0000 : val
|
}
|
|
Buffer.prototype.readInt32LE = function readInt32LE (offset, noAssert) {
|
offset = offset >>> 0
|
if (!noAssert) checkOffset(offset, 4, this.length)
|
|
return (this[offset]) |
|
(this[offset + 1] << 8) |
|
(this[offset + 2] << 16) |
|
(this[offset + 3] << 24)
|
}
|
|
Buffer.prototype.readInt32BE = function readInt32BE (offset, noAssert) {
|
offset = offset >>> 0
|
if (!noAssert) checkOffset(offset, 4, this.length)
|
|
return (this[offset] << 24) |
|
(this[offset + 1] << 16) |
|
(this[offset + 2] << 8) |
|
(this[offset + 3])
|
}
|
|
Buffer.prototype.readFloatLE = function readFloatLE (offset, noAssert) {
|
offset = offset >>> 0
|
if (!noAssert) checkOffset(offset, 4, this.length)
|
return ieee754.read(this, offset, true, 23, 4)
|
}
|
|
Buffer.prototype.readFloatBE = function readFloatBE (offset, noAssert) {
|
offset = offset >>> 0
|
if (!noAssert) checkOffset(offset, 4, this.length)
|
return ieee754.read(this, offset, false, 23, 4)
|
}
|
|
Buffer.prototype.readDoubleLE = function readDoubleLE (offset, noAssert) {
|
offset = offset >>> 0
|
if (!noAssert) checkOffset(offset, 8, this.length)
|
return ieee754.read(this, offset, true, 52, 8)
|
}
|
|
Buffer.prototype.readDoubleBE = function readDoubleBE (offset, noAssert) {
|
offset = offset >>> 0
|
if (!noAssert) checkOffset(offset, 8, this.length)
|
return ieee754.read(this, offset, false, 52, 8)
|
}
|
|
function checkInt (buf, value, offset, ext, max, min) {
|
if (!Buffer.isBuffer(buf)) throw new TypeError('"buffer" argument must be a Buffer instance')
|
if (value > max || value < min) throw new RangeError('"value" argument is out of bounds')
|
if (offset + ext > buf.length) throw new RangeError('Index out of range')
|
}
|
|
Buffer.prototype.writeUIntLE = function writeUIntLE (value, offset, byteLength, noAssert) {
|
value = +value
|
offset = offset >>> 0
|
byteLength = byteLength >>> 0
|
if (!noAssert) {
|
var maxBytes = Math.pow(2, 8 * byteLength) - 1
|
checkInt(this, value, offset, byteLength, maxBytes, 0)
|
}
|
|
var mul = 1
|
var i = 0
|
this[offset] = value & 0xFF
|
while (++i < byteLength && (mul *= 0x100)) {
|
this[offset + i] = (value / mul) & 0xFF
|
}
|
|
return offset + byteLength
|
}
|
|
Buffer.prototype.writeUIntBE = function writeUIntBE (value, offset, byteLength, noAssert) {
|
value = +value
|
offset = offset >>> 0
|
byteLength = byteLength >>> 0
|
if (!noAssert) {
|
var maxBytes = Math.pow(2, 8 * byteLength) - 1
|
checkInt(this, value, offset, byteLength, maxBytes, 0)
|
}
|
|
var i = byteLength - 1
|
var mul = 1
|
this[offset + i] = value & 0xFF
|
while (--i >= 0 && (mul *= 0x100)) {
|
this[offset + i] = (value / mul) & 0xFF
|
}
|
|
return offset + byteLength
|
}
|
|
Buffer.prototype.writeUInt8 = function writeUInt8 (value, offset, noAssert) {
|
value = +value
|
offset = offset >>> 0
|
if (!noAssert) checkInt(this, value, offset, 1, 0xff, 0)
|
this[offset] = (value & 0xff)
|
return offset + 1
|
}
|
|
Buffer.prototype.writeUInt16LE = function writeUInt16LE (value, offset, noAssert) {
|
value = +value
|
offset = offset >>> 0
|
if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0)
|
this[offset] = (value & 0xff)
|
this[offset + 1] = (value >>> 8)
|
return offset + 2
|
}
|
|
Buffer.prototype.writeUInt16BE = function writeUInt16BE (value, offset, noAssert) {
|
value = +value
|
offset = offset >>> 0
|
if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0)
|
this[offset] = (value >>> 8)
|
this[offset + 1] = (value & 0xff)
|
return offset + 2
|
}
|
|
Buffer.prototype.writeUInt32LE = function writeUInt32LE (value, offset, noAssert) {
|
value = +value
|
offset = offset >>> 0
|
if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0)
|
this[offset + 3] = (value >>> 24)
|
this[offset + 2] = (value >>> 16)
|
this[offset + 1] = (value >>> 8)
|
this[offset] = (value & 0xff)
|
return offset + 4
|
}
|
|
Buffer.prototype.writeUInt32BE = function writeUInt32BE (value, offset, noAssert) {
|
value = +value
|
offset = offset >>> 0
|
if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0)
|
this[offset] = (value >>> 24)
|
this[offset + 1] = (value >>> 16)
|
this[offset + 2] = (value >>> 8)
|
this[offset + 3] = (value & 0xff)
|
return offset + 4
|
}
|
|
Buffer.prototype.writeIntLE = function writeIntLE (value, offset, byteLength, noAssert) {
|
value = +value
|
offset = offset >>> 0
|
if (!noAssert) {
|
var limit = Math.pow(2, (8 * byteLength) - 1)
|
|
checkInt(this, value, offset, byteLength, limit - 1, -limit)
|
}
|
|
var i = 0
|
var mul = 1
|
var sub = 0
|
this[offset] = value & 0xFF
|
while (++i < byteLength && (mul *= 0x100)) {
|
if (value < 0 && sub === 0 && this[offset + i - 1] !== 0) {
|
sub = 1
|
}
|
this[offset + i] = ((value / mul) >> 0) - sub & 0xFF
|
}
|
|
return offset + byteLength
|
}
|
|
Buffer.prototype.writeIntBE = function writeIntBE (value, offset, byteLength, noAssert) {
|
value = +value
|
offset = offset >>> 0
|
if (!noAssert) {
|
var limit = Math.pow(2, (8 * byteLength) - 1)
|
|
checkInt(this, value, offset, byteLength, limit - 1, -limit)
|
}
|
|
var i = byteLength - 1
|
var mul = 1
|
var sub = 0
|
this[offset + i] = value & 0xFF
|
while (--i >= 0 && (mul *= 0x100)) {
|
if (value < 0 && sub === 0 && this[offset + i + 1] !== 0) {
|
sub = 1
|
}
|
this[offset + i] = ((value / mul) >> 0) - sub & 0xFF
|
}
|
|
return offset + byteLength
|
}
|
|
Buffer.prototype.writeInt8 = function writeInt8 (value, offset, noAssert) {
|
value = +value
|
offset = offset >>> 0
|
if (!noAssert) checkInt(this, value, offset, 1, 0x7f, -0x80)
|
if (value < 0) value = 0xff + value + 1
|
this[offset] = (value & 0xff)
|
return offset + 1
|
}
|
|
Buffer.prototype.writeInt16LE = function writeInt16LE (value, offset, noAssert) {
|
value = +value
|
offset = offset >>> 0
|
if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000)
|
this[offset] = (value & 0xff)
|
this[offset + 1] = (value >>> 8)
|
return offset + 2
|
}
|
|
Buffer.prototype.writeInt16BE = function writeInt16BE (value, offset, noAssert) {
|
value = +value
|
offset = offset >>> 0
|
if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000)
|
this[offset] = (value >>> 8)
|
this[offset + 1] = (value & 0xff)
|
return offset + 2
|
}
|
|
Buffer.prototype.writeInt32LE = function writeInt32LE (value, offset, noAssert) {
|
value = +value
|
offset = offset >>> 0
|
if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000)
|
this[offset] = (value & 0xff)
|
this[offset + 1] = (value >>> 8)
|
this[offset + 2] = (value >>> 16)
|
this[offset + 3] = (value >>> 24)
|
return offset + 4
|
}
|
|
Buffer.prototype.writeInt32BE = function writeInt32BE (value, offset, noAssert) {
|
value = +value
|
offset = offset >>> 0
|
if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000)
|
if (value < 0) value = 0xffffffff + value + 1
|
this[offset] = (value >>> 24)
|
this[offset + 1] = (value >>> 16)
|
this[offset + 2] = (value >>> 8)
|
this[offset + 3] = (value & 0xff)
|
return offset + 4
|
}
|
|
function checkIEEE754 (buf, value, offset, ext, max, min) {
|
if (offset + ext > buf.length) throw new RangeError('Index out of range')
|
if (offset < 0) throw new RangeError('Index out of range')
|
}
|
|
function writeFloat (buf, value, offset, littleEndian, noAssert) {
|
value = +value
|
offset = offset >>> 0
|
if (!noAssert) {
|
checkIEEE754(buf, value, offset, 4, 3.4028234663852886e+38, -3.4028234663852886e+38)
|
}
|
ieee754.write(buf, value, offset, littleEndian, 23, 4)
|
return offset + 4
|
}
|
|
Buffer.prototype.writeFloatLE = function writeFloatLE (value, offset, noAssert) {
|
return writeFloat(this, value, offset, true, noAssert)
|
}
|
|
Buffer.prototype.writeFloatBE = function writeFloatBE (value, offset, noAssert) {
|
return writeFloat(this, value, offset, false, noAssert)
|
}
|
|
function writeDouble (buf, value, offset, littleEndian, noAssert) {
|
value = +value
|
offset = offset >>> 0
|
if (!noAssert) {
|
checkIEEE754(buf, value, offset, 8, 1.7976931348623157E+308, -1.7976931348623157E+308)
|
}
|
ieee754.write(buf, value, offset, littleEndian, 52, 8)
|
return offset + 8
|
}
|
|
Buffer.prototype.writeDoubleLE = function writeDoubleLE (value, offset, noAssert) {
|
return writeDouble(this, value, offset, true, noAssert)
|
}
|
|
Buffer.prototype.writeDoubleBE = function writeDoubleBE (value, offset, noAssert) {
|
return writeDouble(this, value, offset, false, noAssert)
|
}
|
|
// copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length)
|
Buffer.prototype.copy = function copy (target, targetStart, start, end) {
|
if (!Buffer.isBuffer(target)) throw new TypeError('argument should be a Buffer')
|
if (!start) start = 0
|
if (!end && end !== 0) end = this.length
|
if (targetStart >= target.length) targetStart = target.length
|
if (!targetStart) targetStart = 0
|
if (end > 0 && end < start) end = start
|
|
// Copy 0 bytes; we're done
|
if (end === start) return 0
|
if (target.length === 0 || this.length === 0) return 0
|
|
// Fatal error conditions
|
if (targetStart < 0) {
|
throw new RangeError('targetStart out of bounds')
|
}
|
if (start < 0 || start >= this.length) throw new RangeError('Index out of range')
|
if (end < 0) throw new RangeError('sourceEnd out of bounds')
|
|
// Are we oob?
|
if (end > this.length) end = this.length
|
if (target.length - targetStart < end - start) {
|
end = target.length - targetStart + start
|
}
|
|
var len = end - start
|
|
if (this === target && typeof Uint8Array.prototype.copyWithin === 'function') {
|
// Use built-in when available, missing from IE11
|
this.copyWithin(targetStart, start, end)
|
} else if (this === target && start < targetStart && targetStart < end) {
|
// descending copy from end
|
for (var i = len - 1; i >= 0; --i) {
|
target[i + targetStart] = this[i + start]
|
}
|
} else {
|
Uint8Array.prototype.set.call(
|
target,
|
this.subarray(start, end),
|
targetStart
|
)
|
}
|
|
return len
|
}
|
|
// Usage:
|
// buffer.fill(number[, offset[, end]])
|
// buffer.fill(buffer[, offset[, end]])
|
// buffer.fill(string[, offset[, end]][, encoding])
|
Buffer.prototype.fill = function fill (val, start, end, encoding) {
|
// Handle string cases:
|
if (typeof val === 'string') {
|
if (typeof start === 'string') {
|
encoding = start
|
start = 0
|
end = this.length
|
} else if (typeof end === 'string') {
|
encoding = end
|
end = this.length
|
}
|
if (encoding !== undefined && typeof encoding !== 'string') {
|
throw new TypeError('encoding must be a string')
|
}
|
if (typeof encoding === 'string' && !Buffer.isEncoding(encoding)) {
|
throw new TypeError('Unknown encoding: ' + encoding)
|
}
|
if (val.length === 1) {
|
var code = val.charCodeAt(0)
|
if ((encoding === 'utf8' && code < 128) ||
|
encoding === 'latin1') {
|
// Fast path: If `val` fits into a single byte, use that numeric value.
|
val = code
|
}
|
}
|
} else if (typeof val === 'number') {
|
val = val & 255
|
} else if (typeof val === 'boolean') {
|
val = Number(val)
|
}
|
|
// Invalid ranges are not set to a default, so can range check early.
|
if (start < 0 || this.length < start || this.length < end) {
|
throw new RangeError('Out of range index')
|
}
|
|
if (end <= start) {
|
return this
|
}
|
|
start = start >>> 0
|
end = end === undefined ? this.length : end >>> 0
|
|
if (!val) val = 0
|
|
var i
|
if (typeof val === 'number') {
|
for (i = start; i < end; ++i) {
|
this[i] = val
|
}
|
} else {
|
var bytes = Buffer.isBuffer(val)
|
? val
|
: Buffer.from(val, encoding)
|
var len = bytes.length
|
if (len === 0) {
|
throw new TypeError('The value "' + val +
|
'" is invalid for argument "value"')
|
}
|
for (i = 0; i < end - start; ++i) {
|
this[i + start] = bytes[i % len]
|
}
|
}
|
|
return this
|
}
|
|
// HELPER FUNCTIONS
|
// ================
|
|
var INVALID_BASE64_RE = /[^+/0-9A-Za-z-_]/g
|
|
function base64clean (str) {
|
// Node takes equal signs as end of the Base64 encoding
|
str = str.split('=')[0]
|
// Node strips out invalid characters like \n and \t from the string, base64-js does not
|
str = str.trim().replace(INVALID_BASE64_RE, '')
|
// Node converts strings with length < 2 to ''
|
if (str.length < 2) return ''
|
// Node allows for non-padded base64 strings (missing trailing ===), base64-js does not
|
while (str.length % 4 !== 0) {
|
str = str + '='
|
}
|
return str
|
}
|
|
function utf8ToBytes (string, units) {
|
units = units || Infinity
|
var codePoint
|
var length = string.length
|
var leadSurrogate = null
|
var bytes = []
|
|
for (var i = 0; i < length; ++i) {
|
codePoint = string.charCodeAt(i)
|
|
// is surrogate component
|
if (codePoint > 0xD7FF && codePoint < 0xE000) {
|
// last char was a lead
|
if (!leadSurrogate) {
|
// no lead yet
|
if (codePoint > 0xDBFF) {
|
// unexpected trail
|
if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)
|
continue
|
} else if (i + 1 === length) {
|
// unpaired lead
|
if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)
|
continue
|
}
|
|
// valid lead
|
leadSurrogate = codePoint
|
|
continue
|
}
|
|
// 2 leads in a row
|
if (codePoint < 0xDC00) {
|
if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)
|
leadSurrogate = codePoint
|
continue
|
}
|
|
// valid surrogate pair
|
codePoint = (leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00) + 0x10000
|
} else if (leadSurrogate) {
|
// valid bmp char, but last char was a lead
|
if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)
|
}
|
|
leadSurrogate = null
|
|
// encode utf8
|
if (codePoint < 0x80) {
|
if ((units -= 1) < 0) break
|
bytes.push(codePoint)
|
} else if (codePoint < 0x800) {
|
if ((units -= 2) < 0) break
|
bytes.push(
|
codePoint >> 0x6 | 0xC0,
|
codePoint & 0x3F | 0x80
|
)
|
} else if (codePoint < 0x10000) {
|
if ((units -= 3) < 0) break
|
bytes.push(
|
codePoint >> 0xC | 0xE0,
|
codePoint >> 0x6 & 0x3F | 0x80,
|
codePoint & 0x3F | 0x80
|
)
|
} else if (codePoint < 0x110000) {
|
if ((units -= 4) < 0) break
|
bytes.push(
|
codePoint >> 0x12 | 0xF0,
|
codePoint >> 0xC & 0x3F | 0x80,
|
codePoint >> 0x6 & 0x3F | 0x80,
|
codePoint & 0x3F | 0x80
|
)
|
} else {
|
throw new Error('Invalid code point')
|
}
|
}
|
|
return bytes
|
}
|
|
function asciiToBytes (str) {
|
var byteArray = []
|
for (var i = 0; i < str.length; ++i) {
|
// Node's code seems to be doing this and not & 0x7F..
|
byteArray.push(str.charCodeAt(i) & 0xFF)
|
}
|
return byteArray
|
}
|
|
function utf16leToBytes (str, units) {
|
var c, hi, lo
|
var byteArray = []
|
for (var i = 0; i < str.length; ++i) {
|
if ((units -= 2) < 0) break
|
|
c = str.charCodeAt(i)
|
hi = c >> 8
|
lo = c % 256
|
byteArray.push(lo)
|
byteArray.push(hi)
|
}
|
|
return byteArray
|
}
|
|
function base64ToBytes (str) {
|
return base64.toByteArray(base64clean(str))
|
}
|
|
function blitBuffer (src, dst, offset, length) {
|
for (var i = 0; i < length; ++i) {
|
if ((i + offset >= dst.length) || (i >= src.length)) break
|
dst[i + offset] = src[i]
|
}
|
return i
|
}
|
|
// ArrayBuffer or Uint8Array objects from other contexts (i.e. iframes) do not pass
|
// the `instanceof` check but they should be treated as of that type.
|
// See: https://github.com/feross/buffer/issues/166
|
function isInstance (obj, type) {
|
return obj instanceof type ||
|
(obj != null && obj.constructor != null && obj.constructor.name != null &&
|
obj.constructor.name === type.name)
|
}
|
function numberIsNaN (obj) {
|
// For IE11 support
|
return obj !== obj // eslint-disable-line no-self-compare
|
}
|
|
// Create lookup table for `toString('hex')`
|
// See: https://github.com/feross/buffer/issues/219
|
var hexSliceLookupTable = (function () {
|
var alphabet = '0123456789abcdef'
|
var table = new Array(256)
|
for (var i = 0; i < 16; ++i) {
|
var i16 = i * 16
|
for (var j = 0; j < 16; ++j) {
|
table[i16 + j] = alphabet[i] + alphabet[j]
|
}
|
}
|
return table
|
})()
|
|
}).call(this,require("buffer").Buffer)
|
|
},{"base64-js":28,"buffer":30,"ieee754":32}],31:[function(require,module,exports){
|
'use strict';
|
|
var rbush = require('rbush');
|
var convexHull = require('monotone-convex-hull-2d');
|
var Queue = require('tinyqueue');
|
var pointInPolygon = require('point-in-polygon');
|
var orient = require('robust-orientation')[3];
|
|
module.exports = concaveman;
|
module.exports.default = concaveman;
|
|
function concaveman(points, concavity, lengthThreshold) {
|
// a relative measure of concavity; higher value means simpler hull
|
concavity = Math.max(0, concavity === undefined ? 2 : concavity);
|
|
// when a segment goes below this length threshold, it won't be drilled down further
|
lengthThreshold = lengthThreshold || 0;
|
|
// start with a convex hull of the points
|
var hull = fastConvexHull(points);
|
|
// index the points with an R-tree
|
var tree = rbush(16, ['[0]', '[1]', '[0]', '[1]']).load(points);
|
|
// turn the convex hull into a linked list and populate the initial edge queue with the nodes
|
var queue = [];
|
for (var i = 0, last; i < hull.length; i++) {
|
var p = hull[i];
|
tree.remove(p);
|
last = insertNode(p, last);
|
queue.push(last);
|
}
|
|
// index the segments with an R-tree (for intersection checks)
|
var segTree = rbush(16);
|
for (i = 0; i < queue.length; i++) segTree.insert(updateBBox(queue[i]));
|
|
var sqConcavity = concavity * concavity;
|
var sqLenThreshold = lengthThreshold * lengthThreshold;
|
|
// process edges one by one
|
while (queue.length) {
|
var node = queue.shift();
|
var a = node.p;
|
var b = node.next.p;
|
|
// skip the edge if it's already short enough
|
var sqLen = getSqDist(a, b);
|
if (sqLen < sqLenThreshold) continue;
|
|
var maxSqLen = sqLen / sqConcavity;
|
|
// find the best connection point for the current edge to flex inward to
|
p = findCandidate(tree, node.prev.p, a, b, node.next.next.p, maxSqLen, segTree);
|
|
// if we found a connection and it satisfies our concavity measure
|
if (p && Math.min(getSqDist(p, a), getSqDist(p, b)) <= maxSqLen) {
|
// connect the edge endpoints through this point and add 2 new edges to the queue
|
queue.push(node);
|
queue.push(insertNode(p, node));
|
|
// update point and segment indexes
|
tree.remove(p);
|
segTree.remove(node);
|
segTree.insert(updateBBox(node));
|
segTree.insert(updateBBox(node.next));
|
}
|
}
|
|
// convert the resulting hull linked list to an array of points
|
node = last;
|
var concave = [];
|
do {
|
concave.push(node.p);
|
node = node.next;
|
} while (node !== last);
|
|
concave.push(node.p);
|
|
return concave;
|
}
|
|
function findCandidate(tree, a, b, c, d, maxDist, segTree) {
|
var queue = new Queue(null, compareDist);
|
var node = tree.data;
|
|
// search through the point R-tree with a depth-first search using a priority queue
|
// in the order of distance to the edge (b, c)
|
while (node) {
|
for (var i = 0; i < node.children.length; i++) {
|
var child = node.children[i];
|
|
var dist = node.leaf ? sqSegDist(child, b, c) : sqSegBoxDist(b, c, child);
|
if (dist > maxDist) continue; // skip the node if it's farther than we ever need
|
|
queue.push({
|
node: child,
|
dist: dist
|
});
|
}
|
|
while (queue.length && !queue.peek().node.children) {
|
var item = queue.pop();
|
var p = item.node;
|
|
// skip all points that are as close to adjacent edges (a,b) and (c,d),
|
// and points that would introduce self-intersections when connected
|
var d0 = sqSegDist(p, a, b);
|
var d1 = sqSegDist(p, c, d);
|
if (item.dist < d0 && item.dist < d1 &&
|
noIntersections(b, p, segTree) &&
|
noIntersections(c, p, segTree)) return p;
|
}
|
|
node = queue.pop();
|
if (node) node = node.node;
|
}
|
|
return null;
|
}
|
|
function compareDist(a, b) {
|
return a.dist - b.dist;
|
}
|
|
// square distance from a segment bounding box to the given one
|
function sqSegBoxDist(a, b, bbox) {
|
if (inside(a, bbox) || inside(b, bbox)) return 0;
|
var d1 = sqSegSegDist(a[0], a[1], b[0], b[1], bbox.minX, bbox.minY, bbox.maxX, bbox.minY);
|
if (d1 === 0) return 0;
|
var d2 = sqSegSegDist(a[0], a[1], b[0], b[1], bbox.minX, bbox.minY, bbox.minX, bbox.maxY);
|
if (d2 === 0) return 0;
|
var d3 = sqSegSegDist(a[0], a[1], b[0], b[1], bbox.maxX, bbox.minY, bbox.maxX, bbox.maxY);
|
if (d3 === 0) return 0;
|
var d4 = sqSegSegDist(a[0], a[1], b[0], b[1], bbox.minX, bbox.maxY, bbox.maxX, bbox.maxY);
|
if (d4 === 0) return 0;
|
return Math.min(d1, d2, d3, d4);
|
}
|
|
function inside(a, bbox) {
|
return a[0] >= bbox.minX &&
|
a[0] <= bbox.maxX &&
|
a[1] >= bbox.minY &&
|
a[1] <= bbox.maxY;
|
}
|
|
// check if the edge (a,b) doesn't intersect any other edges
|
function noIntersections(a, b, segTree) {
|
var minX = Math.min(a[0], b[0]);
|
var minY = Math.min(a[1], b[1]);
|
var maxX = Math.max(a[0], b[0]);
|
var maxY = Math.max(a[1], b[1]);
|
|
var edges = segTree.search({minX: minX, minY: minY, maxX: maxX, maxY: maxY});
|
for (var i = 0; i < edges.length; i++) {
|
if (intersects(edges[i].p, edges[i].next.p, a, b)) return false;
|
}
|
return true;
|
}
|
|
// check if the edges (p1,q1) and (p2,q2) intersect
|
function intersects(p1, q1, p2, q2) {
|
return p1 !== q2 && q1 !== p2 &&
|
orient(p1, q1, p2) > 0 !== orient(p1, q1, q2) > 0 &&
|
orient(p2, q2, p1) > 0 !== orient(p2, q2, q1) > 0;
|
}
|
|
// update the bounding box of a node's edge
|
function updateBBox(node) {
|
var p1 = node.p;
|
var p2 = node.next.p;
|
node.minX = Math.min(p1[0], p2[0]);
|
node.minY = Math.min(p1[1], p2[1]);
|
node.maxX = Math.max(p1[0], p2[0]);
|
node.maxY = Math.max(p1[1], p2[1]);
|
return node;
|
}
|
|
// speed up convex hull by filtering out points inside quadrilateral formed by 4 extreme points
|
function fastConvexHull(points) {
|
var left = points[0];
|
var top = points[0];
|
var right = points[0];
|
var bottom = points[0];
|
|
// find the leftmost, rightmost, topmost and bottommost points
|
for (var i = 0; i < points.length; i++) {
|
var p = points[i];
|
if (p[0] < left[0]) left = p;
|
if (p[0] > right[0]) right = p;
|
if (p[1] < top[1]) top = p;
|
if (p[1] > bottom[1]) bottom = p;
|
}
|
|
// filter out points that are inside the resulting quadrilateral
|
var cull = [left, top, right, bottom];
|
var filtered = cull.slice();
|
for (i = 0; i < points.length; i++) {
|
if (!pointInPolygon(points[i], cull)) filtered.push(points[i]);
|
}
|
|
// get convex hull around the filtered points
|
var indices = convexHull(filtered);
|
|
// return the hull as array of points (rather than indices)
|
var hull = [];
|
for (i = 0; i < indices.length; i++) hull.push(filtered[indices[i]]);
|
return hull;
|
}
|
|
// create a new node in a doubly linked list
|
function insertNode(p, prev) {
|
var node = {
|
p: p,
|
prev: null,
|
next: null,
|
minX: 0,
|
minY: 0,
|
maxX: 0,
|
maxY: 0
|
};
|
|
if (!prev) {
|
node.prev = node;
|
node.next = node;
|
|
} else {
|
node.next = prev.next;
|
node.prev = prev;
|
prev.next.prev = node;
|
prev.next = node;
|
}
|
return node;
|
}
|
|
// square distance between 2 points
|
function getSqDist(p1, p2) {
|
|
var dx = p1[0] - p2[0],
|
dy = p1[1] - p2[1];
|
|
return dx * dx + dy * dy;
|
}
|
|
// square distance from a point to a segment
|
function sqSegDist(p, p1, p2) {
|
|
var x = p1[0],
|
y = p1[1],
|
dx = p2[0] - x,
|
dy = p2[1] - y;
|
|
if (dx !== 0 || dy !== 0) {
|
|
var t = ((p[0] - x) * dx + (p[1] - y) * dy) / (dx * dx + dy * dy);
|
|
if (t > 1) {
|
x = p2[0];
|
y = p2[1];
|
|
} else if (t > 0) {
|
x += dx * t;
|
y += dy * t;
|
}
|
}
|
|
dx = p[0] - x;
|
dy = p[1] - y;
|
|
return dx * dx + dy * dy;
|
}
|
|
// segment to segment distance, ported from http://geomalgorithms.com/a07-_distance.html by Dan Sunday
|
function sqSegSegDist(x0, y0, x1, y1, x2, y2, x3, y3) {
|
var ux = x1 - x0;
|
var uy = y1 - y0;
|
var vx = x3 - x2;
|
var vy = y3 - y2;
|
var wx = x0 - x2;
|
var wy = y0 - y2;
|
var a = ux * ux + uy * uy;
|
var b = ux * vx + uy * vy;
|
var c = vx * vx + vy * vy;
|
var d = ux * wx + uy * wy;
|
var e = vx * wx + vy * wy;
|
var D = a * c - b * b;
|
|
var sc, sN, tc, tN;
|
var sD = D;
|
var tD = D;
|
|
if (D === 0) {
|
sN = 0;
|
sD = 1;
|
tN = e;
|
tD = c;
|
} else {
|
sN = b * e - c * d;
|
tN = a * e - b * d;
|
if (sN < 0) {
|
sN = 0;
|
tN = e;
|
tD = c;
|
} else if (sN > sD) {
|
sN = sD;
|
tN = e + b;
|
tD = c;
|
}
|
}
|
|
if (tN < 0.0) {
|
tN = 0.0;
|
if (-d < 0.0) sN = 0.0;
|
else if (-d > a) sN = sD;
|
else {
|
sN = -d;
|
sD = a;
|
}
|
} else if (tN > tD) {
|
tN = tD;
|
if ((-d + b) < 0.0) sN = 0;
|
else if (-d + b > a) sN = sD;
|
else {
|
sN = -d + b;
|
sD = a;
|
}
|
}
|
|
sc = sN === 0 ? 0 : sN / sD;
|
tc = tN === 0 ? 0 : tN / tD;
|
|
var cx = (1 - sc) * x0 + sc * x1;
|
var cy = (1 - sc) * y0 + sc * y1;
|
var cx2 = (1 - tc) * x2 + tc * x3;
|
var cy2 = (1 - tc) * y2 + tc * y3;
|
var dx = cx2 - cx;
|
var dy = cy2 - cy;
|
|
return dx * dx + dy * dy;
|
}
|
|
},{"monotone-convex-hull-2d":61,"point-in-polygon":80,"rbush":84,"robust-orientation":85,"tinyqueue":97}],32:[function(require,module,exports){
|
exports.read = function (buffer, offset, isLE, mLen, nBytes) {
|
var e, m
|
var eLen = (nBytes * 8) - mLen - 1
|
var eMax = (1 << eLen) - 1
|
var eBias = eMax >> 1
|
var nBits = -7
|
var i = isLE ? (nBytes - 1) : 0
|
var d = isLE ? -1 : 1
|
var s = buffer[offset + i]
|
|
i += d
|
|
e = s & ((1 << (-nBits)) - 1)
|
s >>= (-nBits)
|
nBits += eLen
|
for (; nBits > 0; e = (e * 256) + buffer[offset + i], i += d, nBits -= 8) {}
|
|
m = e & ((1 << (-nBits)) - 1)
|
e >>= (-nBits)
|
nBits += mLen
|
for (; nBits > 0; m = (m * 256) + buffer[offset + i], i += d, nBits -= 8) {}
|
|
if (e === 0) {
|
e = 1 - eBias
|
} else if (e === eMax) {
|
return m ? NaN : ((s ? -1 : 1) * Infinity)
|
} else {
|
m = m + Math.pow(2, mLen)
|
e = e - eBias
|
}
|
return (s ? -1 : 1) * m * Math.pow(2, e - mLen)
|
}
|
|
exports.write = function (buffer, value, offset, isLE, mLen, nBytes) {
|
var e, m, c
|
var eLen = (nBytes * 8) - mLen - 1
|
var eMax = (1 << eLen) - 1
|
var eBias = eMax >> 1
|
var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0)
|
var i = isLE ? 0 : (nBytes - 1)
|
var d = isLE ? 1 : -1
|
var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0
|
|
value = Math.abs(value)
|
|
if (isNaN(value) || value === Infinity) {
|
m = isNaN(value) ? 1 : 0
|
e = eMax
|
} else {
|
e = Math.floor(Math.log(value) / Math.LN2)
|
if (value * (c = Math.pow(2, -e)) < 1) {
|
e--
|
c *= 2
|
}
|
if (e + eBias >= 1) {
|
value += rt / c
|
} else {
|
value += rt * Math.pow(2, 1 - eBias)
|
}
|
if (value * c >= 2) {
|
e++
|
c /= 2
|
}
|
|
if (e + eBias >= eMax) {
|
m = 0
|
e = eMax
|
} else if (e + eBias >= 1) {
|
m = ((value * c) - 1) * Math.pow(2, mLen)
|
e = e + eBias
|
} else {
|
m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen)
|
e = 0
|
}
|
}
|
|
for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {}
|
|
e = (e << mLen) | m
|
eLen += mLen
|
for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {}
|
|
buffer[offset + i - d] |= s * 128
|
}
|
|
},{}],33:[function(require,module,exports){
|
(function (global){
|
'use strict';
|
var Mutation = global.MutationObserver || global.WebKitMutationObserver;
|
|
var scheduleDrain;
|
|
{
|
if (Mutation) {
|
var called = 0;
|
var observer = new Mutation(nextTick);
|
var element = global.document.createTextNode('');
|
observer.observe(element, {
|
characterData: true
|
});
|
scheduleDrain = function () {
|
element.data = (called = ++called % 2);
|
};
|
} else if (!global.setImmediate && typeof global.MessageChannel !== 'undefined') {
|
var channel = new global.MessageChannel();
|
channel.port1.onmessage = nextTick;
|
scheduleDrain = function () {
|
channel.port2.postMessage(0);
|
};
|
} else if ('document' in global && 'onreadystatechange' in global.document.createElement('script')) {
|
scheduleDrain = function () {
|
|
// Create a <script> element; its readystatechange event will be fired asynchronously once it is inserted
|
// into the document. Do so, thus queuing up the task. Remember to clean up once it's been called.
|
var scriptEl = global.document.createElement('script');
|
scriptEl.onreadystatechange = function () {
|
nextTick();
|
|
scriptEl.onreadystatechange = null;
|
scriptEl.parentNode.removeChild(scriptEl);
|
scriptEl = null;
|
};
|
global.document.documentElement.appendChild(scriptEl);
|
};
|
} else {
|
scheduleDrain = function () {
|
setTimeout(nextTick, 0);
|
};
|
}
|
}
|
|
var draining;
|
var queue = [];
|
//named nextTick for less confusing stack traces
|
function nextTick() {
|
draining = true;
|
var i, oldQueue;
|
var len = queue.length;
|
while (len) {
|
oldQueue = queue;
|
queue = [];
|
i = -1;
|
while (++i < len) {
|
oldQueue[i]();
|
}
|
len = queue.length;
|
}
|
draining = false;
|
}
|
|
module.exports = immediate;
|
function immediate(task) {
|
if (queue.push(task) === 1 && !draining) {
|
scheduleDrain();
|
}
|
}
|
|
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
|
|
},{}],34:[function(require,module,exports){
|
'use strict';
|
var DataReader = require('./dataReader');
|
|
function ArrayReader(data) {
|
if (data) {
|
this.data = data;
|
this.length = this.data.length;
|
this.index = 0;
|
this.zero = 0;
|
|
for(var i = 0; i < this.data.length; i++) {
|
data[i] = data[i] & 0xFF;
|
}
|
}
|
}
|
ArrayReader.prototype = new DataReader();
|
/**
|
* @see DataReader.byteAt
|
*/
|
ArrayReader.prototype.byteAt = function(i) {
|
return this.data[this.zero + i];
|
};
|
/**
|
* @see DataReader.lastIndexOfSignature
|
*/
|
ArrayReader.prototype.lastIndexOfSignature = function(sig) {
|
var sig0 = sig.charCodeAt(0),
|
sig1 = sig.charCodeAt(1),
|
sig2 = sig.charCodeAt(2),
|
sig3 = sig.charCodeAt(3);
|
for (var i = this.length - 4; i >= 0; --i) {
|
if (this.data[i] === sig0 && this.data[i + 1] === sig1 && this.data[i + 2] === sig2 && this.data[i + 3] === sig3) {
|
return i - this.zero;
|
}
|
}
|
|
return -1;
|
};
|
/**
|
* @see DataReader.readData
|
*/
|
ArrayReader.prototype.readData = function(size) {
|
this.checkOffset(size);
|
if(size === 0) {
|
return [];
|
}
|
var result = this.data.slice(this.zero + this.index, this.zero + this.index + size);
|
this.index += size;
|
return result;
|
};
|
module.exports = ArrayReader;
|
|
},{"./dataReader":39}],35:[function(require,module,exports){
|
'use strict';
|
// private property
|
var _keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
|
|
|
// public method for encoding
|
exports.encode = function(input, utf8) {
|
var output = "";
|
var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
|
var i = 0;
|
|
while (i < input.length) {
|
|
chr1 = input.charCodeAt(i++);
|
chr2 = input.charCodeAt(i++);
|
chr3 = input.charCodeAt(i++);
|
|
enc1 = chr1 >> 2;
|
enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
|
enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
|
enc4 = chr3 & 63;
|
|
if (isNaN(chr2)) {
|
enc3 = enc4 = 64;
|
}
|
else if (isNaN(chr3)) {
|
enc4 = 64;
|
}
|
|
output = output + _keyStr.charAt(enc1) + _keyStr.charAt(enc2) + _keyStr.charAt(enc3) + _keyStr.charAt(enc4);
|
|
}
|
|
return output;
|
};
|
|
// public method for decoding
|
exports.decode = function(input, utf8) {
|
var output = "";
|
var chr1, chr2, chr3;
|
var enc1, enc2, enc3, enc4;
|
var i = 0;
|
|
input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
|
|
while (i < input.length) {
|
|
enc1 = _keyStr.indexOf(input.charAt(i++));
|
enc2 = _keyStr.indexOf(input.charAt(i++));
|
enc3 = _keyStr.indexOf(input.charAt(i++));
|
enc4 = _keyStr.indexOf(input.charAt(i++));
|
|
chr1 = (enc1 << 2) | (enc2 >> 4);
|
chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
|
chr3 = ((enc3 & 3) << 6) | enc4;
|
|
output = output + String.fromCharCode(chr1);
|
|
if (enc3 != 64) {
|
output = output + String.fromCharCode(chr2);
|
}
|
if (enc4 != 64) {
|
output = output + String.fromCharCode(chr3);
|
}
|
|
}
|
|
return output;
|
|
};
|
|
},{}],36:[function(require,module,exports){
|
'use strict';
|
function CompressedObject() {
|
this.compressedSize = 0;
|
this.uncompressedSize = 0;
|
this.crc32 = 0;
|
this.compressionMethod = null;
|
this.compressedContent = null;
|
}
|
|
CompressedObject.prototype = {
|
/**
|
* Return the decompressed content in an unspecified format.
|
* The format will depend on the decompressor.
|
* @return {Object} the decompressed content.
|
*/
|
getContent: function() {
|
return null; // see implementation
|
},
|
/**
|
* Return the compressed content in an unspecified format.
|
* The format will depend on the compressed conten source.
|
* @return {Object} the compressed content.
|
*/
|
getCompressedContent: function() {
|
return null; // see implementation
|
}
|
};
|
module.exports = CompressedObject;
|
|
},{}],37:[function(require,module,exports){
|
'use strict';
|
exports.STORE = {
|
magic: "\x00\x00",
|
compress: function(content, compressionOptions) {
|
return content; // no compression
|
},
|
uncompress: function(content) {
|
return content; // no compression
|
},
|
compressInputType: null,
|
uncompressInputType: null
|
};
|
exports.DEFLATE = require('./flate');
|
|
},{"./flate":42}],38:[function(require,module,exports){
|
'use strict';
|
|
var utils = require('./utils');
|
|
var table = [
|
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
|
0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
|
0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
|
0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
|
0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
|
0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
|
0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
|
0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
|
0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
|
0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
|
0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
|
0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
|
0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
|
0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
|
0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
|
0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
|
0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
|
0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
|
0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
|
0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
|
0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
|
0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
|
0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
|
0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
|
0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
|
0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
|
0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
|
0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
|
0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
|
0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
|
0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
|
0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
|
0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
|
0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
|
0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
|
0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
|
0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
|
0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
|
0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
|
0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
|
0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
|
0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
|
0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
|
0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
|
0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
|
0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
|
0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
|
0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
|
0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
|
0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
|
0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
|
0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
|
0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
|
0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
|
0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
|
0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
|
0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
|
0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
|
0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
|
0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
|
0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
|
0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
|
0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
|
0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
|
];
|
|
/**
|
*
|
* Javascript crc32
|
* http://www.webtoolkit.info/
|
*
|
*/
|
module.exports = function crc32(input, crc) {
|
if (typeof input === "undefined" || !input.length) {
|
return 0;
|
}
|
|
var isArray = utils.getTypeOf(input) !== "string";
|
|
if (typeof(crc) == "undefined") {
|
crc = 0;
|
}
|
var x = 0;
|
var y = 0;
|
var b = 0;
|
|
crc = crc ^ (-1);
|
for (var i = 0, iTop = input.length; i < iTop; i++) {
|
b = isArray ? input[i] : input.charCodeAt(i);
|
y = (crc ^ b) & 0xFF;
|
x = table[y];
|
crc = (crc >>> 8) ^ x;
|
}
|
|
return crc ^ (-1);
|
};
|
// vim: set shiftwidth=4 softtabstop=4:
|
|
},{"./utils":55}],39:[function(require,module,exports){
|
'use strict';
|
var utils = require('./utils');
|
|
function DataReader(data) {
|
this.data = null; // type : see implementation
|
this.length = 0;
|
this.index = 0;
|
this.zero = 0;
|
}
|
DataReader.prototype = {
|
/**
|
* Check that the offset will not go too far.
|
* @param {string} offset the additional offset to check.
|
* @throws {Error} an Error if the offset is out of bounds.
|
*/
|
checkOffset: function(offset) {
|
this.checkIndex(this.index + offset);
|
},
|
/**
|
* Check that the specifed index will not be too far.
|
* @param {string} newIndex the index to check.
|
* @throws {Error} an Error if the index is out of bounds.
|
*/
|
checkIndex: function(newIndex) {
|
if (this.length < this.zero + newIndex || newIndex < 0) {
|
throw new Error("End of data reached (data length = " + this.length + ", asked index = " + (newIndex) + "). Corrupted zip ?");
|
}
|
},
|
/**
|
* Change the index.
|
* @param {number} newIndex The new index.
|
* @throws {Error} if the new index is out of the data.
|
*/
|
setIndex: function(newIndex) {
|
this.checkIndex(newIndex);
|
this.index = newIndex;
|
},
|
/**
|
* Skip the next n bytes.
|
* @param {number} n the number of bytes to skip.
|
* @throws {Error} if the new index is out of the data.
|
*/
|
skip: function(n) {
|
this.setIndex(this.index + n);
|
},
|
/**
|
* Get the byte at the specified index.
|
* @param {number} i the index to use.
|
* @return {number} a byte.
|
*/
|
byteAt: function(i) {
|
// see implementations
|
},
|
/**
|
* Get the next number with a given byte size.
|
* @param {number} size the number of bytes to read.
|
* @return {number} the corresponding number.
|
*/
|
readInt: function(size) {
|
var result = 0,
|
i;
|
this.checkOffset(size);
|
for (i = this.index + size - 1; i >= this.index; i--) {
|
result = (result << 8) + this.byteAt(i);
|
}
|
this.index += size;
|
return result;
|
},
|
/**
|
* Get the next string with a given byte size.
|
* @param {number} size the number of bytes to read.
|
* @return {string} the corresponding string.
|
*/
|
readString: function(size) {
|
return utils.transformTo("string", this.readData(size));
|
},
|
/**
|
* Get raw data without conversion, <size> bytes.
|
* @param {number} size the number of bytes to read.
|
* @return {Object} the raw data, implementation specific.
|
*/
|
readData: function(size) {
|
// see implementations
|
},
|
/**
|
* Find the last occurence of a zip signature (4 bytes).
|
* @param {string} sig the signature to find.
|
* @return {number} the index of the last occurence, -1 if not found.
|
*/
|
lastIndexOfSignature: function(sig) {
|
// see implementations
|
},
|
/**
|
* Get the next date.
|
* @return {Date} the date.
|
*/
|
readDate: function() {
|
var dostime = this.readInt(4);
|
return new Date(
|
((dostime >> 25) & 0x7f) + 1980, // year
|
((dostime >> 21) & 0x0f) - 1, // month
|
(dostime >> 16) & 0x1f, // day
|
(dostime >> 11) & 0x1f, // hour
|
(dostime >> 5) & 0x3f, // minute
|
(dostime & 0x1f) << 1); // second
|
}
|
};
|
module.exports = DataReader;
|
|
},{"./utils":55}],40:[function(require,module,exports){
|
'use strict';
|
exports.base64 = false;
|
exports.binary = false;
|
exports.dir = false;
|
exports.createFolders = false;
|
exports.date = null;
|
exports.compression = null;
|
exports.compressionOptions = null;
|
exports.comment = null;
|
exports.unixPermissions = null;
|
exports.dosPermissions = null;
|
|
},{}],41:[function(require,module,exports){
|
'use strict';
|
var utils = require('./utils');
|
|
/**
|
* @deprecated
|
* This function will be removed in a future version without replacement.
|
*/
|
exports.string2binary = function(str) {
|
return utils.string2binary(str);
|
};
|
|
/**
|
* @deprecated
|
* This function will be removed in a future version without replacement.
|
*/
|
exports.string2Uint8Array = function(str) {
|
return utils.transformTo("uint8array", str);
|
};
|
|
/**
|
* @deprecated
|
* This function will be removed in a future version without replacement.
|
*/
|
exports.uint8Array2String = function(array) {
|
return utils.transformTo("string", array);
|
};
|
|
/**
|
* @deprecated
|
* This function will be removed in a future version without replacement.
|
*/
|
exports.string2Blob = function(str) {
|
var buffer = utils.transformTo("arraybuffer", str);
|
return utils.arrayBuffer2Blob(buffer);
|
};
|
|
/**
|
* @deprecated
|
* This function will be removed in a future version without replacement.
|
*/
|
exports.arrayBuffer2Blob = function(buffer) {
|
return utils.arrayBuffer2Blob(buffer);
|
};
|
|
/**
|
* @deprecated
|
* This function will be removed in a future version without replacement.
|
*/
|
exports.transformTo = function(outputType, input) {
|
return utils.transformTo(outputType, input);
|
};
|
|
/**
|
* @deprecated
|
* This function will be removed in a future version without replacement.
|
*/
|
exports.getTypeOf = function(input) {
|
return utils.getTypeOf(input);
|
};
|
|
/**
|
* @deprecated
|
* This function will be removed in a future version without replacement.
|
*/
|
exports.checkSupport = function(type) {
|
return utils.checkSupport(type);
|
};
|
|
/**
|
* @deprecated
|
* This value will be removed in a future version without replacement.
|
*/
|
exports.MAX_VALUE_16BITS = utils.MAX_VALUE_16BITS;
|
|
/**
|
* @deprecated
|
* This value will be removed in a future version without replacement.
|
*/
|
exports.MAX_VALUE_32BITS = utils.MAX_VALUE_32BITS;
|
|
|
/**
|
* @deprecated
|
* This function will be removed in a future version without replacement.
|
*/
|
exports.pretty = function(str) {
|
return utils.pretty(str);
|
};
|
|
/**
|
* @deprecated
|
* This function will be removed in a future version without replacement.
|
*/
|
exports.findCompression = function(compressionMethod) {
|
return utils.findCompression(compressionMethod);
|
};
|
|
/**
|
* @deprecated
|
* This function will be removed in a future version without replacement.
|
*/
|
exports.isRegExp = function (object) {
|
return utils.isRegExp(object);
|
};
|
|
|
},{"./utils":55}],42:[function(require,module,exports){
|
'use strict';
|
var USE_TYPEDARRAY = (typeof Uint8Array !== 'undefined') && (typeof Uint16Array !== 'undefined') && (typeof Uint32Array !== 'undefined');
|
|
var pako = require("pako");
|
exports.uncompressInputType = USE_TYPEDARRAY ? "uint8array" : "array";
|
exports.compressInputType = USE_TYPEDARRAY ? "uint8array" : "array";
|
|
exports.magic = "\x08\x00";
|
exports.compress = function(input, compressionOptions) {
|
return pako.deflateRaw(input, {
|
level : compressionOptions.level || -1 // default compression
|
});
|
};
|
exports.uncompress = function(input) {
|
return pako.inflateRaw(input);
|
};
|
|
},{"pako":62}],43:[function(require,module,exports){
|
'use strict';
|
|
var base64 = require('./base64');
|
|
/**
|
Usage:
|
zip = new JSZip();
|
zip.file("hello.txt", "Hello, World!").file("tempfile", "nothing");
|
zip.folder("images").file("smile.gif", base64Data, {base64: true});
|
zip.file("Xmas.txt", "Ho ho ho !", {date : new Date("December 25, 2007 00:00:01")});
|
zip.remove("tempfile");
|
|
base64zip = zip.generate();
|
|
**/
|
|
/**
|
* Representation a of zip file in js
|
* @constructor
|
* @param {String=|ArrayBuffer=|Uint8Array=} data the data to load, if any (optional).
|
* @param {Object=} options the options for creating this objects (optional).
|
*/
|
function JSZip(data, options) {
|
// if this constructor is used without `new`, it adds `new` before itself:
|
if(!(this instanceof JSZip)) return new JSZip(data, options);
|
|
// object containing the files :
|
// {
|
// "folder/" : {...},
|
// "folder/data.txt" : {...}
|
// }
|
this.files = {};
|
|
this.comment = null;
|
|
// Where we are in the hierarchy
|
this.root = "";
|
if (data) {
|
this.load(data, options);
|
}
|
this.clone = function() {
|
var newObj = new JSZip();
|
for (var i in this) {
|
if (typeof this[i] !== "function") {
|
newObj[i] = this[i];
|
}
|
}
|
return newObj;
|
};
|
}
|
JSZip.prototype = require('./object');
|
JSZip.prototype.load = require('./load');
|
JSZip.support = require('./support');
|
JSZip.defaults = require('./defaults');
|
|
/**
|
* @deprecated
|
* This namespace will be removed in a future version without replacement.
|
*/
|
JSZip.utils = require('./deprecatedPublicUtils');
|
|
JSZip.base64 = {
|
/**
|
* @deprecated
|
* This method will be removed in a future version without replacement.
|
*/
|
encode : function(input) {
|
return base64.encode(input);
|
},
|
/**
|
* @deprecated
|
* This method will be removed in a future version without replacement.
|
*/
|
decode : function(input) {
|
return base64.decode(input);
|
}
|
};
|
JSZip.compressions = require('./compressions');
|
module.exports = JSZip;
|
|
},{"./base64":35,"./compressions":37,"./defaults":40,"./deprecatedPublicUtils":41,"./load":44,"./object":47,"./support":51}],44:[function(require,module,exports){
|
'use strict';
|
var base64 = require('./base64');
|
var utf8 = require('./utf8');
|
var utils = require('./utils');
|
var ZipEntries = require('./zipEntries');
|
module.exports = function(data, options) {
|
var files, zipEntries, i, input;
|
options = utils.extend(options || {}, {
|
base64: false,
|
checkCRC32: false,
|
optimizedBinaryString : false,
|
createFolders: false,
|
decodeFileName: utf8.utf8decode
|
});
|
if (options.base64) {
|
data = base64.decode(data);
|
}
|
|
zipEntries = new ZipEntries(data, options);
|
files = zipEntries.files;
|
for (i = 0; i < files.length; i++) {
|
input = files[i];
|
this.file(input.fileNameStr, input.decompressed, {
|
binary: true,
|
optimizedBinaryString: true,
|
date: input.date,
|
dir: input.dir,
|
comment : input.fileCommentStr.length ? input.fileCommentStr : null,
|
unixPermissions : input.unixPermissions,
|
dosPermissions : input.dosPermissions,
|
createFolders: options.createFolders
|
});
|
}
|
if (zipEntries.zipComment.length) {
|
this.comment = zipEntries.zipComment;
|
}
|
|
return this;
|
};
|
|
},{"./base64":35,"./utf8":54,"./utils":55,"./zipEntries":56}],45:[function(require,module,exports){
|
(function (Buffer){
|
'use strict';
|
module.exports = function(data, encoding){
|
return new Buffer(data, encoding);
|
};
|
module.exports.test = function(b){
|
return Buffer.isBuffer(b);
|
};
|
|
}).call(this,require("buffer").Buffer)
|
|
},{"buffer":30}],46:[function(require,module,exports){
|
'use strict';
|
var Uint8ArrayReader = require('./uint8ArrayReader');
|
|
function NodeBufferReader(data) {
|
this.data = data;
|
this.length = this.data.length;
|
this.index = 0;
|
this.zero = 0;
|
}
|
NodeBufferReader.prototype = new Uint8ArrayReader();
|
|
/**
|
* @see DataReader.readData
|
*/
|
NodeBufferReader.prototype.readData = function(size) {
|
this.checkOffset(size);
|
var result = this.data.slice(this.zero + this.index, this.zero + this.index + size);
|
this.index += size;
|
return result;
|
};
|
module.exports = NodeBufferReader;
|
|
},{"./uint8ArrayReader":52}],47:[function(require,module,exports){
|
'use strict';
|
var support = require('./support');
|
var utils = require('./utils');
|
var crc32 = require('./crc32');
|
var signature = require('./signature');
|
var defaults = require('./defaults');
|
var base64 = require('./base64');
|
var compressions = require('./compressions');
|
var CompressedObject = require('./compressedObject');
|
var nodeBuffer = require('./nodeBuffer');
|
var utf8 = require('./utf8');
|
var StringWriter = require('./stringWriter');
|
var Uint8ArrayWriter = require('./uint8ArrayWriter');
|
|
/**
|
* Returns the raw data of a ZipObject, decompress the content if necessary.
|
* @param {ZipObject} file the file to use.
|
* @return {String|ArrayBuffer|Uint8Array|Buffer} the data.
|
*/
|
var getRawData = function(file) {
|
if (file._data instanceof CompressedObject) {
|
file._data = file._data.getContent();
|
file.options.binary = true;
|
file.options.base64 = false;
|
|
if (utils.getTypeOf(file._data) === "uint8array") {
|
var copy = file._data;
|
// when reading an arraybuffer, the CompressedObject mechanism will keep it and subarray() a Uint8Array.
|
// if we request a file in the same format, we might get the same Uint8Array or its ArrayBuffer (the original zip file).
|
file._data = new Uint8Array(copy.length);
|
// with an empty Uint8Array, Opera fails with a "Offset larger than array size"
|
if (copy.length !== 0) {
|
file._data.set(copy, 0);
|
}
|
}
|
}
|
return file._data;
|
};
|
|
/**
|
* Returns the data of a ZipObject in a binary form. If the content is an unicode string, encode it.
|
* @param {ZipObject} file the file to use.
|
* @return {String|ArrayBuffer|Uint8Array|Buffer} the data.
|
*/
|
var getBinaryData = function(file) {
|
var result = getRawData(file),
|
type = utils.getTypeOf(result);
|
if (type === "string") {
|
if (!file.options.binary) {
|
// unicode text !
|
// unicode string => binary string is a painful process, check if we can avoid it.
|
if (support.nodebuffer) {
|
return nodeBuffer(result, "utf-8");
|
}
|
}
|
return file.asBinary();
|
}
|
return result;
|
};
|
|
/**
|
* Transform this._data into a string.
|
* @param {function} filter a function String -> String, applied if not null on the result.
|
* @return {String} the string representing this._data.
|
*/
|
var dataToString = function(asUTF8) {
|
var result = getRawData(this);
|
if (result === null || typeof result === "undefined") {
|
return "";
|
}
|
// if the data is a base64 string, we decode it before checking the encoding !
|
if (this.options.base64) {
|
result = base64.decode(result);
|
}
|
if (asUTF8 && this.options.binary) {
|
// JSZip.prototype.utf8decode supports arrays as input
|
// skip to array => string step, utf8decode will do it.
|
result = out.utf8decode(result);
|
}
|
else {
|
// no utf8 transformation, do the array => string step.
|
result = utils.transformTo("string", result);
|
}
|
|
if (!asUTF8 && !this.options.binary) {
|
result = utils.transformTo("string", out.utf8encode(result));
|
}
|
return result;
|
};
|
/**
|
* A simple object representing a file in the zip file.
|
* @constructor
|
* @param {string} name the name of the file
|
* @param {String|ArrayBuffer|Uint8Array|Buffer} data the data
|
* @param {Object} options the options of the file
|
*/
|
var ZipObject = function(name, data, options) {
|
this.name = name;
|
this.dir = options.dir;
|
this.date = options.date;
|
this.comment = options.comment;
|
this.unixPermissions = options.unixPermissions;
|
this.dosPermissions = options.dosPermissions;
|
|
this._data = data;
|
this.options = options;
|
|
/*
|
* This object contains initial values for dir and date.
|
* With them, we can check if the user changed the deprecated metadata in
|
* `ZipObject#options` or not.
|
*/
|
this._initialMetadata = {
|
dir : options.dir,
|
date : options.date
|
};
|
};
|
|
ZipObject.prototype = {
|
/**
|
* Return the content as UTF8 string.
|
* @return {string} the UTF8 string.
|
*/
|
asText: function() {
|
return dataToString.call(this, true);
|
},
|
/**
|
* Returns the binary content.
|
* @return {string} the content as binary.
|
*/
|
asBinary: function() {
|
return dataToString.call(this, false);
|
},
|
/**
|
* Returns the content as a nodejs Buffer.
|
* @return {Buffer} the content as a Buffer.
|
*/
|
asNodeBuffer: function() {
|
var result = getBinaryData(this);
|
return utils.transformTo("nodebuffer", result);
|
},
|
/**
|
* Returns the content as an Uint8Array.
|
* @return {Uint8Array} the content as an Uint8Array.
|
*/
|
asUint8Array: function() {
|
var result = getBinaryData(this);
|
return utils.transformTo("uint8array", result);
|
},
|
/**
|
* Returns the content as an ArrayBuffer.
|
* @return {ArrayBuffer} the content as an ArrayBufer.
|
*/
|
asArrayBuffer: function() {
|
return this.asUint8Array().buffer;
|
}
|
};
|
|
/**
|
* Transform an integer into a string in hexadecimal.
|
* @private
|
* @param {number} dec the number to convert.
|
* @param {number} bytes the number of bytes to generate.
|
* @returns {string} the result.
|
*/
|
var decToHex = function(dec, bytes) {
|
var hex = "",
|
i;
|
for (i = 0; i < bytes; i++) {
|
hex += String.fromCharCode(dec & 0xff);
|
dec = dec >>> 8;
|
}
|
return hex;
|
};
|
|
/**
|
* Transforms the (incomplete) options from the user into the complete
|
* set of options to create a file.
|
* @private
|
* @param {Object} o the options from the user.
|
* @return {Object} the complete set of options.
|
*/
|
var prepareFileAttrs = function(o) {
|
o = o || {};
|
if (o.base64 === true && (o.binary === null || o.binary === undefined)) {
|
o.binary = true;
|
}
|
o = utils.extend(o, defaults);
|
o.date = o.date || new Date();
|
if (o.compression !== null) o.compression = o.compression.toUpperCase();
|
|
return o;
|
};
|
|
/**
|
* Add a file in the current folder.
|
* @private
|
* @param {string} name the name of the file
|
* @param {String|ArrayBuffer|Uint8Array|Buffer} data the data of the file
|
* @param {Object} o the options of the file
|
* @return {Object} the new file.
|
*/
|
var fileAdd = function(name, data, o) {
|
// be sure sub folders exist
|
var dataType = utils.getTypeOf(data),
|
parent;
|
|
o = prepareFileAttrs(o);
|
|
if (typeof o.unixPermissions === "string") {
|
o.unixPermissions = parseInt(o.unixPermissions, 8);
|
}
|
|
// UNX_IFDIR 0040000 see zipinfo.c
|
if (o.unixPermissions && (o.unixPermissions & 0x4000)) {
|
o.dir = true;
|
}
|
// Bit 4 Directory
|
if (o.dosPermissions && (o.dosPermissions & 0x0010)) {
|
o.dir = true;
|
}
|
|
if (o.dir) {
|
name = forceTrailingSlash(name);
|
}
|
|
if (o.createFolders && (parent = parentFolder(name))) {
|
folderAdd.call(this, parent, true);
|
}
|
|
if (o.dir || data === null || typeof data === "undefined") {
|
o.base64 = false;
|
o.binary = false;
|
data = null;
|
dataType = null;
|
}
|
else if (dataType === "string") {
|
if (o.binary && !o.base64) {
|
// optimizedBinaryString == true means that the file has already been filtered with a 0xFF mask
|
if (o.optimizedBinaryString !== true) {
|
// this is a string, not in a base64 format.
|
// Be sure that this is a correct "binary string"
|
data = utils.string2binary(data);
|
}
|
}
|
}
|
else { // arraybuffer, uint8array, ...
|
o.base64 = false;
|
o.binary = true;
|
|
if (!dataType && !(data instanceof CompressedObject)) {
|
throw new Error("The data of '" + name + "' is in an unsupported format !");
|
}
|
|
// special case : it's way easier to work with Uint8Array than with ArrayBuffer
|
if (dataType === "arraybuffer") {
|
data = utils.transformTo("uint8array", data);
|
}
|
}
|
|
var object = new ZipObject(name, data, o);
|
this.files[name] = object;
|
return object;
|
};
|
|
/**
|
* Find the parent folder of the path.
|
* @private
|
* @param {string} path the path to use
|
* @return {string} the parent folder, or ""
|
*/
|
var parentFolder = function (path) {
|
if (path.slice(-1) == '/') {
|
path = path.substring(0, path.length - 1);
|
}
|
var lastSlash = path.lastIndexOf('/');
|
return (lastSlash > 0) ? path.substring(0, lastSlash) : "";
|
};
|
|
|
/**
|
* Returns the path with a slash at the end.
|
* @private
|
* @param {String} path the path to check.
|
* @return {String} the path with a trailing slash.
|
*/
|
var forceTrailingSlash = function(path) {
|
// Check the name ends with a /
|
if (path.slice(-1) != "/") {
|
path += "/"; // IE doesn't like substr(-1)
|
}
|
return path;
|
};
|
/**
|
* Add a (sub) folder in the current folder.
|
* @private
|
* @param {string} name the folder's name
|
* @param {boolean=} [createFolders] If true, automatically create sub
|
* folders. Defaults to false.
|
* @return {Object} the new folder.
|
*/
|
var folderAdd = function(name, createFolders) {
|
createFolders = (typeof createFolders !== 'undefined') ? createFolders : false;
|
|
name = forceTrailingSlash(name);
|
|
// Does this folder already exist?
|
if (!this.files[name]) {
|
fileAdd.call(this, name, null, {
|
dir: true,
|
createFolders: createFolders
|
});
|
}
|
return this.files[name];
|
};
|
|
/**
|
* Generate a JSZip.CompressedObject for a given zipOject.
|
* @param {ZipObject} file the object to read.
|
* @param {JSZip.compression} compression the compression to use.
|
* @param {Object} compressionOptions the options to use when compressing.
|
* @return {JSZip.CompressedObject} the compressed result.
|
*/
|
var generateCompressedObjectFrom = function(file, compression, compressionOptions) {
|
var result = new CompressedObject(),
|
content;
|
|
// the data has not been decompressed, we might reuse things !
|
if (file._data instanceof CompressedObject) {
|
result.uncompressedSize = file._data.uncompressedSize;
|
result.crc32 = file._data.crc32;
|
|
if (result.uncompressedSize === 0 || file.dir) {
|
compression = compressions['STORE'];
|
result.compressedContent = "";
|
result.crc32 = 0;
|
}
|
else if (file._data.compressionMethod === compression.magic) {
|
result.compressedContent = file._data.getCompressedContent();
|
}
|
else {
|
content = file._data.getContent();
|
// need to decompress / recompress
|
result.compressedContent = compression.compress(utils.transformTo(compression.compressInputType, content), compressionOptions);
|
}
|
}
|
else {
|
// have uncompressed data
|
content = getBinaryData(file);
|
if (!content || content.length === 0 || file.dir) {
|
compression = compressions['STORE'];
|
content = "";
|
}
|
result.uncompressedSize = content.length;
|
result.crc32 = crc32(content);
|
result.compressedContent = compression.compress(utils.transformTo(compression.compressInputType, content), compressionOptions);
|
}
|
|
result.compressedSize = result.compressedContent.length;
|
result.compressionMethod = compression.magic;
|
|
return result;
|
};
|
|
|
|
|
/**
|
* Generate the UNIX part of the external file attributes.
|
* @param {Object} unixPermissions the unix permissions or null.
|
* @param {Boolean} isDir true if the entry is a directory, false otherwise.
|
* @return {Number} a 32 bit integer.
|
*
|
* adapted from http://unix.stackexchange.com/questions/14705/the-zip-formats-external-file-attribute :
|
*
|
* TTTTsstrwxrwxrwx0000000000ADVSHR
|
* ^^^^____________________________ file type, see zipinfo.c (UNX_*)
|
* ^^^_________________________ setuid, setgid, sticky
|
* ^^^^^^^^^________________ permissions
|
* ^^^^^^^^^^______ not used ?
|
* ^^^^^^ DOS attribute bits : Archive, Directory, Volume label, System file, Hidden, Read only
|
*/
|
var generateUnixExternalFileAttr = function (unixPermissions, isDir) {
|
|
var result = unixPermissions;
|
if (!unixPermissions) {
|
// I can't use octal values in strict mode, hence the hexa.
|
// 040775 => 0x41fd
|
// 0100664 => 0x81b4
|
result = isDir ? 0x41fd : 0x81b4;
|
}
|
|
return (result & 0xFFFF) << 16;
|
};
|
|
/**
|
* Generate the DOS part of the external file attributes.
|
* @param {Object} dosPermissions the dos permissions or null.
|
* @param {Boolean} isDir true if the entry is a directory, false otherwise.
|
* @return {Number} a 32 bit integer.
|
*
|
* Bit 0 Read-Only
|
* Bit 1 Hidden
|
* Bit 2 System
|
* Bit 3 Volume Label
|
* Bit 4 Directory
|
* Bit 5 Archive
|
*/
|
var generateDosExternalFileAttr = function (dosPermissions, isDir) {
|
|
// the dir flag is already set for compatibility
|
|
return (dosPermissions || 0) & 0x3F;
|
};
|
|
/**
|
* Generate the various parts used in the construction of the final zip file.
|
* @param {string} name the file name.
|
* @param {ZipObject} file the file content.
|
* @param {JSZip.CompressedObject} compressedObject the compressed object.
|
* @param {number} offset the current offset from the start of the zip file.
|
* @param {String} platform let's pretend we are this platform (change platform dependents fields)
|
* @param {Function} encodeFileName the function to encode the file name / comment.
|
* @return {object} the zip parts.
|
*/
|
var generateZipParts = function(name, file, compressedObject, offset, platform, encodeFileName) {
|
var data = compressedObject.compressedContent,
|
useCustomEncoding = encodeFileName !== utf8.utf8encode,
|
encodedFileName = utils.transformTo("string", encodeFileName(file.name)),
|
utfEncodedFileName = utils.transformTo("string", utf8.utf8encode(file.name)),
|
comment = file.comment || "",
|
encodedComment = utils.transformTo("string", encodeFileName(comment)),
|
utfEncodedComment = utils.transformTo("string", utf8.utf8encode(comment)),
|
useUTF8ForFileName = utfEncodedFileName.length !== file.name.length,
|
useUTF8ForComment = utfEncodedComment.length !== comment.length,
|
o = file.options,
|
dosTime,
|
dosDate,
|
extraFields = "",
|
unicodePathExtraField = "",
|
unicodeCommentExtraField = "",
|
dir, date;
|
|
|
// handle the deprecated options.dir
|
if (file._initialMetadata.dir !== file.dir) {
|
dir = file.dir;
|
} else {
|
dir = o.dir;
|
}
|
|
// handle the deprecated options.date
|
if(file._initialMetadata.date !== file.date) {
|
date = file.date;
|
} else {
|
date = o.date;
|
}
|
|
var extFileAttr = 0;
|
var versionMadeBy = 0;
|
if (dir) {
|
// dos or unix, we set the dos dir flag
|
extFileAttr |= 0x00010;
|
}
|
if(platform === "UNIX") {
|
versionMadeBy = 0x031E; // UNIX, version 3.0
|
extFileAttr |= generateUnixExternalFileAttr(file.unixPermissions, dir);
|
} else { // DOS or other, fallback to DOS
|
versionMadeBy = 0x0014; // DOS, version 2.0
|
extFileAttr |= generateDosExternalFileAttr(file.dosPermissions, dir);
|
}
|
|
// date
|
// @see http://www.delorie.com/djgpp/doc/rbinter/it/52/13.html
|
// @see http://www.delorie.com/djgpp/doc/rbinter/it/65/16.html
|
// @see http://www.delorie.com/djgpp/doc/rbinter/it/66/16.html
|
|
dosTime = date.getHours();
|
dosTime = dosTime << 6;
|
dosTime = dosTime | date.getMinutes();
|
dosTime = dosTime << 5;
|
dosTime = dosTime | date.getSeconds() / 2;
|
|
dosDate = date.getFullYear() - 1980;
|
dosDate = dosDate << 4;
|
dosDate = dosDate | (date.getMonth() + 1);
|
dosDate = dosDate << 5;
|
dosDate = dosDate | date.getDate();
|
|
if (useUTF8ForFileName) {
|
// set the unicode path extra field. unzip needs at least one extra
|
// field to correctly handle unicode path, so using the path is as good
|
// as any other information. This could improve the situation with
|
// other archive managers too.
|
// This field is usually used without the utf8 flag, with a non
|
// unicode path in the header (winrar, winzip). This helps (a bit)
|
// with the messy Windows' default compressed folders feature but
|
// breaks on p7zip which doesn't seek the unicode path extra field.
|
// So for now, UTF-8 everywhere !
|
unicodePathExtraField =
|
// Version
|
decToHex(1, 1) +
|
// NameCRC32
|
decToHex(crc32(encodedFileName), 4) +
|
// UnicodeName
|
utfEncodedFileName;
|
|
extraFields +=
|
// Info-ZIP Unicode Path Extra Field
|
"\x75\x70" +
|
// size
|
decToHex(unicodePathExtraField.length, 2) +
|
// content
|
unicodePathExtraField;
|
}
|
|
if(useUTF8ForComment) {
|
|
unicodeCommentExtraField =
|
// Version
|
decToHex(1, 1) +
|
// CommentCRC32
|
decToHex(this.crc32(encodedComment), 4) +
|
// UnicodeName
|
utfEncodedComment;
|
|
extraFields +=
|
// Info-ZIP Unicode Path Extra Field
|
"\x75\x63" +
|
// size
|
decToHex(unicodeCommentExtraField.length, 2) +
|
// content
|
unicodeCommentExtraField;
|
}
|
|
var header = "";
|
|
// version needed to extract
|
header += "\x0A\x00";
|
// general purpose bit flag
|
// set bit 11 if utf8
|
header += !useCustomEncoding && (useUTF8ForFileName || useUTF8ForComment) ? "\x00\x08" : "\x00\x00";
|
// compression method
|
header += compressedObject.compressionMethod;
|
// last mod file time
|
header += decToHex(dosTime, 2);
|
// last mod file date
|
header += decToHex(dosDate, 2);
|
// crc-32
|
header += decToHex(compressedObject.crc32, 4);
|
// compressed size
|
header += decToHex(compressedObject.compressedSize, 4);
|
// uncompressed size
|
header += decToHex(compressedObject.uncompressedSize, 4);
|
// file name length
|
header += decToHex(encodedFileName.length, 2);
|
// extra field length
|
header += decToHex(extraFields.length, 2);
|
|
|
var fileRecord = signature.LOCAL_FILE_HEADER + header + encodedFileName + extraFields;
|
|
var dirRecord = signature.CENTRAL_FILE_HEADER +
|
// version made by (00: DOS)
|
decToHex(versionMadeBy, 2) +
|
// file header (common to file and central directory)
|
header +
|
// file comment length
|
decToHex(encodedComment.length, 2) +
|
// disk number start
|
"\x00\x00" +
|
// internal file attributes TODO
|
"\x00\x00" +
|
// external file attributes
|
decToHex(extFileAttr, 4) +
|
// relative offset of local header
|
decToHex(offset, 4) +
|
// file name
|
encodedFileName +
|
// extra field
|
extraFields +
|
// file comment
|
encodedComment;
|
|
return {
|
fileRecord: fileRecord,
|
dirRecord: dirRecord,
|
compressedObject: compressedObject
|
};
|
};
|
|
|
// return the actual prototype of JSZip
|
var out = {
|
/**
|
* Read an existing zip and merge the data in the current JSZip object.
|
* The implementation is in jszip-load.js, don't forget to include it.
|
* @param {String|ArrayBuffer|Uint8Array|Buffer} stream The stream to load
|
* @param {Object} options Options for loading the stream.
|
* options.base64 : is the stream in base64 ? default : false
|
* @return {JSZip} the current JSZip object
|
*/
|
load: function(stream, options) {
|
throw new Error("Load method is not defined. Is the file jszip-load.js included ?");
|
},
|
|
/**
|
* Filter nested files/folders with the specified function.
|
* @param {Function} search the predicate to use :
|
* function (relativePath, file) {...}
|
* It takes 2 arguments : the relative path and the file.
|
* @return {Array} An array of matching elements.
|
*/
|
filter: function(search) {
|
var result = [],
|
filename, relativePath, file, fileClone;
|
for (filename in this.files) {
|
if (!this.files.hasOwnProperty(filename)) {
|
continue;
|
}
|
file = this.files[filename];
|
// return a new object, don't let the user mess with our internal objects :)
|
fileClone = new ZipObject(file.name, file._data, utils.extend(file.options));
|
relativePath = filename.slice(this.root.length, filename.length);
|
if (filename.slice(0, this.root.length) === this.root && // the file is in the current root
|
search(relativePath, fileClone)) { // and the file matches the function
|
result.push(fileClone);
|
}
|
}
|
return result;
|
},
|
|
/**
|
* Add a file to the zip file, or search a file.
|
* @param {string|RegExp} name The name of the file to add (if data is defined),
|
* the name of the file to find (if no data) or a regex to match files.
|
* @param {String|ArrayBuffer|Uint8Array|Buffer} data The file data, either raw or base64 encoded
|
* @param {Object} o File options
|
* @return {JSZip|Object|Array} this JSZip object (when adding a file),
|
* a file (when searching by string) or an array of files (when searching by regex).
|
*/
|
file: function(name, data, o) {
|
if (arguments.length === 1) {
|
if (utils.isRegExp(name)) {
|
var regexp = name;
|
return this.filter(function(relativePath, file) {
|
return !file.dir && regexp.test(relativePath);
|
});
|
}
|
else { // text
|
return this.filter(function(relativePath, file) {
|
return !file.dir && relativePath === name;
|
})[0] || null;
|
}
|
}
|
else { // more than one argument : we have data !
|
name = this.root + name;
|
fileAdd.call(this, name, data, o);
|
}
|
return this;
|
},
|
|
/**
|
* Add a directory to the zip file, or search.
|
* @param {String|RegExp} arg The name of the directory to add, or a regex to search folders.
|
* @return {JSZip} an object with the new directory as the root, or an array containing matching folders.
|
*/
|
folder: function(arg) {
|
if (!arg) {
|
return this;
|
}
|
|
if (utils.isRegExp(arg)) {
|
return this.filter(function(relativePath, file) {
|
return file.dir && arg.test(relativePath);
|
});
|
}
|
|
// else, name is a new folder
|
var name = this.root + arg;
|
var newFolder = folderAdd.call(this, name);
|
|
// Allow chaining by returning a new object with this folder as the root
|
var ret = this.clone();
|
ret.root = newFolder.name;
|
return ret;
|
},
|
|
/**
|
* Delete a file, or a directory and all sub-files, from the zip
|
* @param {string} name the name of the file to delete
|
* @return {JSZip} this JSZip object
|
*/
|
remove: function(name) {
|
name = this.root + name;
|
var file = this.files[name];
|
if (!file) {
|
// Look for any folders
|
if (name.slice(-1) != "/") {
|
name += "/";
|
}
|
file = this.files[name];
|
}
|
|
if (file && !file.dir) {
|
// file
|
delete this.files[name];
|
} else {
|
// maybe a folder, delete recursively
|
var kids = this.filter(function(relativePath, file) {
|
return file.name.slice(0, name.length) === name;
|
});
|
for (var i = 0; i < kids.length; i++) {
|
delete this.files[kids[i].name];
|
}
|
}
|
|
return this;
|
},
|
|
/**
|
* Generate the complete zip file
|
* @param {Object} options the options to generate the zip file :
|
* - base64, (deprecated, use type instead) true to generate base64.
|
* - compression, "STORE" by default.
|
* - type, "base64" by default. Values are : string, base64, uint8array, arraybuffer, blob.
|
* @return {String|Uint8Array|ArrayBuffer|Buffer|Blob} the zip file
|
*/
|
generate: function(options) {
|
options = utils.extend(options || {}, {
|
base64: true,
|
compression: "STORE",
|
compressionOptions : null,
|
type: "base64",
|
platform: "DOS",
|
comment: null,
|
mimeType: 'application/zip',
|
encodeFileName: utf8.utf8encode
|
});
|
|
utils.checkSupport(options.type);
|
|
// accept nodejs `process.platform`
|
if(
|
options.platform === 'darwin' ||
|
options.platform === 'freebsd' ||
|
options.platform === 'linux' ||
|
options.platform === 'sunos'
|
) {
|
options.platform = "UNIX";
|
}
|
if (options.platform === 'win32') {
|
options.platform = "DOS";
|
}
|
|
var zipData = [],
|
localDirLength = 0,
|
centralDirLength = 0,
|
writer, i,
|
encodedComment = utils.transformTo("string", options.encodeFileName(options.comment || this.comment || ""));
|
|
// first, generate all the zip parts.
|
for (var name in this.files) {
|
if (!this.files.hasOwnProperty(name)) {
|
continue;
|
}
|
var file = this.files[name];
|
|
var compressionName = file.options.compression || options.compression.toUpperCase();
|
var compression = compressions[compressionName];
|
if (!compression) {
|
throw new Error(compressionName + " is not a valid compression method !");
|
}
|
var compressionOptions = file.options.compressionOptions || options.compressionOptions || {};
|
|
var compressedObject = generateCompressedObjectFrom.call(this, file, compression, compressionOptions);
|
|
var zipPart = generateZipParts.call(this, name, file, compressedObject, localDirLength, options.platform, options.encodeFileName);
|
localDirLength += zipPart.fileRecord.length + compressedObject.compressedSize;
|
centralDirLength += zipPart.dirRecord.length;
|
zipData.push(zipPart);
|
}
|
|
var dirEnd = "";
|
|
// end of central dir signature
|
dirEnd = signature.CENTRAL_DIRECTORY_END +
|
// number of this disk
|
"\x00\x00" +
|
// number of the disk with the start of the central directory
|
"\x00\x00" +
|
// total number of entries in the central directory on this disk
|
decToHex(zipData.length, 2) +
|
// total number of entries in the central directory
|
decToHex(zipData.length, 2) +
|
// size of the central directory 4 bytes
|
decToHex(centralDirLength, 4) +
|
// offset of start of central directory with respect to the starting disk number
|
decToHex(localDirLength, 4) +
|
// .ZIP file comment length
|
decToHex(encodedComment.length, 2) +
|
// .ZIP file comment
|
encodedComment;
|
|
|
// we have all the parts (and the total length)
|
// time to create a writer !
|
var typeName = options.type.toLowerCase();
|
if(typeName==="uint8array"||typeName==="arraybuffer"||typeName==="blob"||typeName==="nodebuffer") {
|
writer = new Uint8ArrayWriter(localDirLength + centralDirLength + dirEnd.length);
|
}else{
|
writer = new StringWriter(localDirLength + centralDirLength + dirEnd.length);
|
}
|
|
for (i = 0; i < zipData.length; i++) {
|
writer.append(zipData[i].fileRecord);
|
writer.append(zipData[i].compressedObject.compressedContent);
|
}
|
for (i = 0; i < zipData.length; i++) {
|
writer.append(zipData[i].dirRecord);
|
}
|
|
writer.append(dirEnd);
|
|
var zip = writer.finalize();
|
|
|
|
switch(options.type.toLowerCase()) {
|
// case "zip is an Uint8Array"
|
case "uint8array" :
|
case "arraybuffer" :
|
case "nodebuffer" :
|
return utils.transformTo(options.type.toLowerCase(), zip);
|
case "blob" :
|
return utils.arrayBuffer2Blob(utils.transformTo("arraybuffer", zip), options.mimeType);
|
// case "zip is a string"
|
case "base64" :
|
return (options.base64) ? base64.encode(zip) : zip;
|
default : // case "string" :
|
return zip;
|
}
|
|
},
|
|
/**
|
* @deprecated
|
* This method will be removed in a future version without replacement.
|
*/
|
crc32: function (input, crc) {
|
return crc32(input, crc);
|
},
|
|
/**
|
* @deprecated
|
* This method will be removed in a future version without replacement.
|
*/
|
utf8encode: function (string) {
|
return utils.transformTo("string", utf8.utf8encode(string));
|
},
|
|
/**
|
* @deprecated
|
* This method will be removed in a future version without replacement.
|
*/
|
utf8decode: function (input) {
|
return utf8.utf8decode(input);
|
}
|
};
|
module.exports = out;
|
|
},{"./base64":35,"./compressedObject":36,"./compressions":37,"./crc32":38,"./defaults":40,"./nodeBuffer":45,"./signature":48,"./stringWriter":50,"./support":51,"./uint8ArrayWriter":53,"./utf8":54,"./utils":55}],48:[function(require,module,exports){
|
'use strict';
|
exports.LOCAL_FILE_HEADER = "PK\x03\x04";
|
exports.CENTRAL_FILE_HEADER = "PK\x01\x02";
|
exports.CENTRAL_DIRECTORY_END = "PK\x05\x06";
|
exports.ZIP64_CENTRAL_DIRECTORY_LOCATOR = "PK\x06\x07";
|
exports.ZIP64_CENTRAL_DIRECTORY_END = "PK\x06\x06";
|
exports.DATA_DESCRIPTOR = "PK\x07\x08";
|
|
},{}],49:[function(require,module,exports){
|
'use strict';
|
var DataReader = require('./dataReader');
|
var utils = require('./utils');
|
|
function StringReader(data, optimizedBinaryString) {
|
this.data = data;
|
if (!optimizedBinaryString) {
|
this.data = utils.string2binary(this.data);
|
}
|
this.length = this.data.length;
|
this.index = 0;
|
this.zero = 0;
|
}
|
StringReader.prototype = new DataReader();
|
/**
|
* @see DataReader.byteAt
|
*/
|
StringReader.prototype.byteAt = function(i) {
|
return this.data.charCodeAt(this.zero + i);
|
};
|
/**
|
* @see DataReader.lastIndexOfSignature
|
*/
|
StringReader.prototype.lastIndexOfSignature = function(sig) {
|
return this.data.lastIndexOf(sig) - this.zero;
|
};
|
/**
|
* @see DataReader.readData
|
*/
|
StringReader.prototype.readData = function(size) {
|
this.checkOffset(size);
|
// this will work because the constructor applied the "& 0xff" mask.
|
var result = this.data.slice(this.zero + this.index, this.zero + this.index + size);
|
this.index += size;
|
return result;
|
};
|
module.exports = StringReader;
|
|
},{"./dataReader":39,"./utils":55}],50:[function(require,module,exports){
|
'use strict';
|
|
var utils = require('./utils');
|
|
/**
|
* An object to write any content to a string.
|
* @constructor
|
*/
|
var StringWriter = function() {
|
this.data = [];
|
};
|
StringWriter.prototype = {
|
/**
|
* Append any content to the current string.
|
* @param {Object} input the content to add.
|
*/
|
append: function(input) {
|
input = utils.transformTo("string", input);
|
this.data.push(input);
|
},
|
/**
|
* Finalize the construction an return the result.
|
* @return {string} the generated string.
|
*/
|
finalize: function() {
|
return this.data.join("");
|
}
|
};
|
|
module.exports = StringWriter;
|
|
},{"./utils":55}],51:[function(require,module,exports){
|
(function (Buffer){
|
'use strict';
|
exports.base64 = true;
|
exports.array = true;
|
exports.string = true;
|
exports.arraybuffer = typeof ArrayBuffer !== "undefined" && typeof Uint8Array !== "undefined";
|
// contains true if JSZip can read/generate nodejs Buffer, false otherwise.
|
// Browserify will provide a Buffer implementation for browsers, which is
|
// an augmented Uint8Array (i.e., can be used as either Buffer or U8).
|
exports.nodebuffer = typeof Buffer !== "undefined";
|
// contains true if JSZip can read/generate Uint8Array, false otherwise.
|
exports.uint8array = typeof Uint8Array !== "undefined";
|
|
if (typeof ArrayBuffer === "undefined") {
|
exports.blob = false;
|
}
|
else {
|
var buffer = new ArrayBuffer(0);
|
try {
|
exports.blob = new Blob([buffer], {
|
type: "application/zip"
|
}).size === 0;
|
}
|
catch (e) {
|
try {
|
var Builder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder || window.MSBlobBuilder;
|
var builder = new Builder();
|
builder.append(buffer);
|
exports.blob = builder.getBlob('application/zip').size === 0;
|
}
|
catch (e) {
|
exports.blob = false;
|
}
|
}
|
}
|
|
}).call(this,require("buffer").Buffer)
|
|
},{"buffer":30}],52:[function(require,module,exports){
|
'use strict';
|
var ArrayReader = require('./arrayReader');
|
|
function Uint8ArrayReader(data) {
|
if (data) {
|
this.data = data;
|
this.length = this.data.length;
|
this.index = 0;
|
this.zero = 0;
|
}
|
}
|
Uint8ArrayReader.prototype = new ArrayReader();
|
/**
|
* @see DataReader.readData
|
*/
|
Uint8ArrayReader.prototype.readData = function(size) {
|
this.checkOffset(size);
|
if(size === 0) {
|
// in IE10, when using subarray(idx, idx), we get the array [0x00] instead of [].
|
return new Uint8Array(0);
|
}
|
var result = this.data.subarray(this.zero + this.index, this.zero + this.index + size);
|
this.index += size;
|
return result;
|
};
|
module.exports = Uint8ArrayReader;
|
|
},{"./arrayReader":34}],53:[function(require,module,exports){
|
'use strict';
|
|
var utils = require('./utils');
|
|
/**
|
* An object to write any content to an Uint8Array.
|
* @constructor
|
* @param {number} length The length of the array.
|
*/
|
var Uint8ArrayWriter = function(length) {
|
this.data = new Uint8Array(length);
|
this.index = 0;
|
};
|
Uint8ArrayWriter.prototype = {
|
/**
|
* Append any content to the current array.
|
* @param {Object} input the content to add.
|
*/
|
append: function(input) {
|
if (input.length !== 0) {
|
// with an empty Uint8Array, Opera fails with a "Offset larger than array size"
|
input = utils.transformTo("uint8array", input);
|
this.data.set(input, this.index);
|
this.index += input.length;
|
}
|
},
|
/**
|
* Finalize the construction an return the result.
|
* @return {Uint8Array} the generated array.
|
*/
|
finalize: function() {
|
return this.data;
|
}
|
};
|
|
module.exports = Uint8ArrayWriter;
|
|
},{"./utils":55}],54:[function(require,module,exports){
|
'use strict';
|
|
var utils = require('./utils');
|
var support = require('./support');
|
var nodeBuffer = require('./nodeBuffer');
|
|
/**
|
* The following functions come from pako, from pako/lib/utils/strings
|
* released under the MIT license, see pako https://github.com/nodeca/pako/
|
*/
|
|
// Table with utf8 lengths (calculated by first byte of sequence)
|
// Note, that 5 & 6-byte values and some 4-byte values can not be represented in JS,
|
// because max possible codepoint is 0x10ffff
|
var _utf8len = new Array(256);
|
for (var i=0; i<256; i++) {
|
_utf8len[i] = (i >= 252 ? 6 : i >= 248 ? 5 : i >= 240 ? 4 : i >= 224 ? 3 : i >= 192 ? 2 : 1);
|
}
|
_utf8len[254]=_utf8len[254]=1; // Invalid sequence start
|
|
// convert string to array (typed, when possible)
|
var string2buf = function (str) {
|
var buf, c, c2, m_pos, i, str_len = str.length, buf_len = 0;
|
|
// count binary size
|
for (m_pos = 0; m_pos < str_len; m_pos++) {
|
c = str.charCodeAt(m_pos);
|
if ((c & 0xfc00) === 0xd800 && (m_pos+1 < str_len)) {
|
c2 = str.charCodeAt(m_pos+1);
|
if ((c2 & 0xfc00) === 0xdc00) {
|
c = 0x10000 + ((c - 0xd800) << 10) + (c2 - 0xdc00);
|
m_pos++;
|
}
|
}
|
buf_len += c < 0x80 ? 1 : c < 0x800 ? 2 : c < 0x10000 ? 3 : 4;
|
}
|
|
// allocate buffer
|
if (support.uint8array) {
|
buf = new Uint8Array(buf_len);
|
} else {
|
buf = new Array(buf_len);
|
}
|
|
// convert
|
for (i=0, m_pos = 0; i < buf_len; m_pos++) {
|
c = str.charCodeAt(m_pos);
|
if ((c & 0xfc00) === 0xd800 && (m_pos+1 < str_len)) {
|
c2 = str.charCodeAt(m_pos+1);
|
if ((c2 & 0xfc00) === 0xdc00) {
|
c = 0x10000 + ((c - 0xd800) << 10) + (c2 - 0xdc00);
|
m_pos++;
|
}
|
}
|
if (c < 0x80) {
|
/* one byte */
|
buf[i++] = c;
|
} else if (c < 0x800) {
|
/* two bytes */
|
buf[i++] = 0xC0 | (c >>> 6);
|
buf[i++] = 0x80 | (c & 0x3f);
|
} else if (c < 0x10000) {
|
/* three bytes */
|
buf[i++] = 0xE0 | (c >>> 12);
|
buf[i++] = 0x80 | (c >>> 6 & 0x3f);
|
buf[i++] = 0x80 | (c & 0x3f);
|
} else {
|
/* four bytes */
|
buf[i++] = 0xf0 | (c >>> 18);
|
buf[i++] = 0x80 | (c >>> 12 & 0x3f);
|
buf[i++] = 0x80 | (c >>> 6 & 0x3f);
|
buf[i++] = 0x80 | (c & 0x3f);
|
}
|
}
|
|
return buf;
|
};
|
|
// Calculate max possible position in utf8 buffer,
|
// that will not break sequence. If that's not possible
|
// - (very small limits) return max size as is.
|
//
|
// buf[] - utf8 bytes array
|
// max - length limit (mandatory);
|
var utf8border = function(buf, max) {
|
var pos;
|
|
max = max || buf.length;
|
if (max > buf.length) { max = buf.length; }
|
|
// go back from last position, until start of sequence found
|
pos = max-1;
|
while (pos >= 0 && (buf[pos] & 0xC0) === 0x80) { pos--; }
|
|
// Fuckup - very small and broken sequence,
|
// return max, because we should return something anyway.
|
if (pos < 0) { return max; }
|
|
// If we came to start of buffer - that means vuffer is too small,
|
// return max too.
|
if (pos === 0) { return max; }
|
|
return (pos + _utf8len[buf[pos]] > max) ? pos : max;
|
};
|
|
// convert array to string
|
var buf2string = function (buf) {
|
var str, i, out, c, c_len;
|
var len = buf.length;
|
|
// Reserve max possible length (2 words per char)
|
// NB: by unknown reasons, Array is significantly faster for
|
// String.fromCharCode.apply than Uint16Array.
|
var utf16buf = new Array(len*2);
|
|
for (out=0, i=0; i<len;) {
|
c = buf[i++];
|
// quick process ascii
|
if (c < 0x80) { utf16buf[out++] = c; continue; }
|
|
c_len = _utf8len[c];
|
// skip 5 & 6 byte codes
|
if (c_len > 4) { utf16buf[out++] = 0xfffd; i += c_len-1; continue; }
|
|
// apply mask on first byte
|
c &= c_len === 2 ? 0x1f : c_len === 3 ? 0x0f : 0x07;
|
// join the rest
|
while (c_len > 1 && i < len) {
|
c = (c << 6) | (buf[i++] & 0x3f);
|
c_len--;
|
}
|
|
// terminated by end of string?
|
if (c_len > 1) { utf16buf[out++] = 0xfffd; continue; }
|
|
if (c < 0x10000) {
|
utf16buf[out++] = c;
|
} else {
|
c -= 0x10000;
|
utf16buf[out++] = 0xd800 | ((c >> 10) & 0x3ff);
|
utf16buf[out++] = 0xdc00 | (c & 0x3ff);
|
}
|
}
|
|
// shrinkBuf(utf16buf, out)
|
if (utf16buf.length !== out) {
|
if(utf16buf.subarray) {
|
utf16buf = utf16buf.subarray(0, out);
|
} else {
|
utf16buf.length = out;
|
}
|
}
|
|
// return String.fromCharCode.apply(null, utf16buf);
|
return utils.applyFromCharCode(utf16buf);
|
};
|
|
|
// That's all for the pako functions.
|
|
|
/**
|
* Transform a javascript string into an array (typed if possible) of bytes,
|
* UTF-8 encoded.
|
* @param {String} str the string to encode
|
* @return {Array|Uint8Array|Buffer} the UTF-8 encoded string.
|
*/
|
exports.utf8encode = function utf8encode(str) {
|
if (support.nodebuffer) {
|
return nodeBuffer(str, "utf-8");
|
}
|
|
return string2buf(str);
|
};
|
|
|
/**
|
* Transform a bytes array (or a representation) representing an UTF-8 encoded
|
* string into a javascript string.
|
* @param {Array|Uint8Array|Buffer} buf the data de decode
|
* @return {String} the decoded string.
|
*/
|
exports.utf8decode = function utf8decode(buf) {
|
if (support.nodebuffer) {
|
return utils.transformTo("nodebuffer", buf).toString("utf-8");
|
}
|
|
buf = utils.transformTo(support.uint8array ? "uint8array" : "array", buf);
|
|
// return buf2string(buf);
|
// Chrome prefers to work with "small" chunks of data
|
// for the method buf2string.
|
// Firefox and Chrome has their own shortcut, IE doesn't seem to really care.
|
var result = [], k = 0, len = buf.length, chunk = 65536;
|
while (k < len) {
|
var nextBoundary = utf8border(buf, Math.min(k + chunk, len));
|
if (support.uint8array) {
|
result.push(buf2string(buf.subarray(k, nextBoundary)));
|
} else {
|
result.push(buf2string(buf.slice(k, nextBoundary)));
|
}
|
k = nextBoundary;
|
}
|
return result.join("");
|
|
};
|
// vim: set shiftwidth=4 softtabstop=4:
|
|
},{"./nodeBuffer":45,"./support":51,"./utils":55}],55:[function(require,module,exports){
|
'use strict';
|
var support = require('./support');
|
var compressions = require('./compressions');
|
var nodeBuffer = require('./nodeBuffer');
|
/**
|
* Convert a string to a "binary string" : a string containing only char codes between 0 and 255.
|
* @param {string} str the string to transform.
|
* @return {String} the binary string.
|
*/
|
exports.string2binary = function(str) {
|
var result = "";
|
for (var i = 0; i < str.length; i++) {
|
result += String.fromCharCode(str.charCodeAt(i) & 0xff);
|
}
|
return result;
|
};
|
exports.arrayBuffer2Blob = function(buffer, mimeType) {
|
exports.checkSupport("blob");
|
mimeType = mimeType || 'application/zip';
|
|
try {
|
// Blob constructor
|
return new Blob([buffer], {
|
type: mimeType
|
});
|
}
|
catch (e) {
|
|
try {
|
// deprecated, browser only, old way
|
var Builder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder || window.MSBlobBuilder;
|
var builder = new Builder();
|
builder.append(buffer);
|
return builder.getBlob(mimeType);
|
}
|
catch (e) {
|
|
// well, fuck ?!
|
throw new Error("Bug : can't construct the Blob.");
|
}
|
}
|
|
|
};
|
/**
|
* The identity function.
|
* @param {Object} input the input.
|
* @return {Object} the same input.
|
*/
|
function identity(input) {
|
return input;
|
}
|
|
/**
|
* Fill in an array with a string.
|
* @param {String} str the string to use.
|
* @param {Array|ArrayBuffer|Uint8Array|Buffer} array the array to fill in (will be mutated).
|
* @return {Array|ArrayBuffer|Uint8Array|Buffer} the updated array.
|
*/
|
function stringToArrayLike(str, array) {
|
for (var i = 0; i < str.length; ++i) {
|
array[i] = str.charCodeAt(i) & 0xFF;
|
}
|
return array;
|
}
|
|
/**
|
* Transform an array-like object to a string.
|
* @param {Array|ArrayBuffer|Uint8Array|Buffer} array the array to transform.
|
* @return {String} the result.
|
*/
|
function arrayLikeToString(array) {
|
// Performances notes :
|
// --------------------
|
// String.fromCharCode.apply(null, array) is the fastest, see
|
// see http://jsperf.com/converting-a-uint8array-to-a-string/2
|
// but the stack is limited (and we can get huge arrays !).
|
//
|
// result += String.fromCharCode(array[i]); generate too many strings !
|
//
|
// This code is inspired by http://jsperf.com/arraybuffer-to-string-apply-performance/2
|
var chunk = 65536;
|
var result = [],
|
len = array.length,
|
type = exports.getTypeOf(array),
|
k = 0,
|
canUseApply = true;
|
try {
|
switch(type) {
|
case "uint8array":
|
String.fromCharCode.apply(null, new Uint8Array(0));
|
break;
|
case "nodebuffer":
|
String.fromCharCode.apply(null, nodeBuffer(0));
|
break;
|
}
|
} catch(e) {
|
canUseApply = false;
|
}
|
|
// no apply : slow and painful algorithm
|
// default browser on android 4.*
|
if (!canUseApply) {
|
var resultStr = "";
|
for(var i = 0; i < array.length;i++) {
|
resultStr += String.fromCharCode(array[i]);
|
}
|
return resultStr;
|
}
|
while (k < len && chunk > 1) {
|
try {
|
if (type === "array" || type === "nodebuffer") {
|
result.push(String.fromCharCode.apply(null, array.slice(k, Math.min(k + chunk, len))));
|
}
|
else {
|
result.push(String.fromCharCode.apply(null, array.subarray(k, Math.min(k + chunk, len))));
|
}
|
k += chunk;
|
}
|
catch (e) {
|
chunk = Math.floor(chunk / 2);
|
}
|
}
|
return result.join("");
|
}
|
|
exports.applyFromCharCode = arrayLikeToString;
|
|
|
/**
|
* Copy the data from an array-like to an other array-like.
|
* @param {Array|ArrayBuffer|Uint8Array|Buffer} arrayFrom the origin array.
|
* @param {Array|ArrayBuffer|Uint8Array|Buffer} arrayTo the destination array which will be mutated.
|
* @return {Array|ArrayBuffer|Uint8Array|Buffer} the updated destination array.
|
*/
|
function arrayLikeToArrayLike(arrayFrom, arrayTo) {
|
for (var i = 0; i < arrayFrom.length; i++) {
|
arrayTo[i] = arrayFrom[i];
|
}
|
return arrayTo;
|
}
|
|
// a matrix containing functions to transform everything into everything.
|
var transform = {};
|
|
// string to ?
|
transform["string"] = {
|
"string": identity,
|
"array": function(input) {
|
return stringToArrayLike(input, new Array(input.length));
|
},
|
"arraybuffer": function(input) {
|
return transform["string"]["uint8array"](input).buffer;
|
},
|
"uint8array": function(input) {
|
return stringToArrayLike(input, new Uint8Array(input.length));
|
},
|
"nodebuffer": function(input) {
|
return stringToArrayLike(input, nodeBuffer(input.length));
|
}
|
};
|
|
// array to ?
|
transform["array"] = {
|
"string": arrayLikeToString,
|
"array": identity,
|
"arraybuffer": function(input) {
|
return (new Uint8Array(input)).buffer;
|
},
|
"uint8array": function(input) {
|
return new Uint8Array(input);
|
},
|
"nodebuffer": function(input) {
|
return nodeBuffer(input);
|
}
|
};
|
|
// arraybuffer to ?
|
transform["arraybuffer"] = {
|
"string": function(input) {
|
return arrayLikeToString(new Uint8Array(input));
|
},
|
"array": function(input) {
|
return arrayLikeToArrayLike(new Uint8Array(input), new Array(input.byteLength));
|
},
|
"arraybuffer": identity,
|
"uint8array": function(input) {
|
return new Uint8Array(input);
|
},
|
"nodebuffer": function(input) {
|
return nodeBuffer(new Uint8Array(input));
|
}
|
};
|
|
// uint8array to ?
|
transform["uint8array"] = {
|
"string": arrayLikeToString,
|
"array": function(input) {
|
return arrayLikeToArrayLike(input, new Array(input.length));
|
},
|
"arraybuffer": function(input) {
|
return input.buffer;
|
},
|
"uint8array": identity,
|
"nodebuffer": function(input) {
|
return nodeBuffer(input);
|
}
|
};
|
|
// nodebuffer to ?
|
transform["nodebuffer"] = {
|
"string": arrayLikeToString,
|
"array": function(input) {
|
return arrayLikeToArrayLike(input, new Array(input.length));
|
},
|
"arraybuffer": function(input) {
|
return transform["nodebuffer"]["uint8array"](input).buffer;
|
},
|
"uint8array": function(input) {
|
return arrayLikeToArrayLike(input, new Uint8Array(input.length));
|
},
|
"nodebuffer": identity
|
};
|
|
/**
|
* Transform an input into any type.
|
* The supported output type are : string, array, uint8array, arraybuffer, nodebuffer.
|
* If no output type is specified, the unmodified input will be returned.
|
* @param {String} outputType the output type.
|
* @param {String|Array|ArrayBuffer|Uint8Array|Buffer} input the input to convert.
|
* @throws {Error} an Error if the browser doesn't support the requested output type.
|
*/
|
exports.transformTo = function(outputType, input) {
|
if (!input) {
|
// undefined, null, etc
|
// an empty string won't harm.
|
input = "";
|
}
|
if (!outputType) {
|
return input;
|
}
|
exports.checkSupport(outputType);
|
var inputType = exports.getTypeOf(input);
|
var result = transform[inputType][outputType](input);
|
return result;
|
};
|
|
/**
|
* Return the type of the input.
|
* The type will be in a format valid for JSZip.utils.transformTo : string, array, uint8array, arraybuffer.
|
* @param {Object} input the input to identify.
|
* @return {String} the (lowercase) type of the input.
|
*/
|
exports.getTypeOf = function(input) {
|
if (typeof input === "string") {
|
return "string";
|
}
|
if (Object.prototype.toString.call(input) === "[object Array]") {
|
return "array";
|
}
|
if (support.nodebuffer && nodeBuffer.test(input)) {
|
return "nodebuffer";
|
}
|
if (support.uint8array && input instanceof Uint8Array) {
|
return "uint8array";
|
}
|
if (support.arraybuffer && input instanceof ArrayBuffer) {
|
return "arraybuffer";
|
}
|
};
|
|
/**
|
* Throw an exception if the type is not supported.
|
* @param {String} type the type to check.
|
* @throws {Error} an Error if the browser doesn't support the requested type.
|
*/
|
exports.checkSupport = function(type) {
|
var supported = support[type.toLowerCase()];
|
if (!supported) {
|
throw new Error(type + " is not supported by this browser");
|
}
|
};
|
exports.MAX_VALUE_16BITS = 65535;
|
exports.MAX_VALUE_32BITS = -1; // well, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" is parsed as -1
|
|
/**
|
* Prettify a string read as binary.
|
* @param {string} str the string to prettify.
|
* @return {string} a pretty string.
|
*/
|
exports.pretty = function(str) {
|
var res = '',
|
code, i;
|
for (i = 0; i < (str || "").length; i++) {
|
code = str.charCodeAt(i);
|
res += '\\x' + (code < 16 ? "0" : "") + code.toString(16).toUpperCase();
|
}
|
return res;
|
};
|
|
/**
|
* Find a compression registered in JSZip.
|
* @param {string} compressionMethod the method magic to find.
|
* @return {Object|null} the JSZip compression object, null if none found.
|
*/
|
exports.findCompression = function(compressionMethod) {
|
for (var method in compressions) {
|
if (!compressions.hasOwnProperty(method)) {
|
continue;
|
}
|
if (compressions[method].magic === compressionMethod) {
|
return compressions[method];
|
}
|
}
|
return null;
|
};
|
/**
|
* Cross-window, cross-Node-context regular expression detection
|
* @param {Object} object Anything
|
* @return {Boolean} true if the object is a regular expression,
|
* false otherwise
|
*/
|
exports.isRegExp = function (object) {
|
return Object.prototype.toString.call(object) === "[object RegExp]";
|
};
|
|
/**
|
* Merge the objects passed as parameters into a new one.
|
* @private
|
* @param {...Object} var_args All objects to merge.
|
* @return {Object} a new object with the data of the others.
|
*/
|
exports.extend = function() {
|
var result = {}, i, attr;
|
for (i = 0; i < arguments.length; i++) { // arguments is not enumerable in some browsers
|
for (attr in arguments[i]) {
|
if (arguments[i].hasOwnProperty(attr) && typeof result[attr] === "undefined") {
|
result[attr] = arguments[i][attr];
|
}
|
}
|
}
|
return result;
|
};
|
|
|
},{"./compressions":37,"./nodeBuffer":45,"./support":51}],56:[function(require,module,exports){
|
'use strict';
|
var StringReader = require('./stringReader');
|
var NodeBufferReader = require('./nodeBufferReader');
|
var Uint8ArrayReader = require('./uint8ArrayReader');
|
var ArrayReader = require('./arrayReader');
|
var utils = require('./utils');
|
var sig = require('./signature');
|
var ZipEntry = require('./zipEntry');
|
var support = require('./support');
|
var jszipProto = require('./object');
|
// class ZipEntries {{{
|
/**
|
* All the entries in the zip file.
|
* @constructor
|
* @param {String|ArrayBuffer|Uint8Array} data the binary stream to load.
|
* @param {Object} loadOptions Options for loading the stream.
|
*/
|
function ZipEntries(data, loadOptions) {
|
this.files = [];
|
this.loadOptions = loadOptions;
|
if (data) {
|
this.load(data);
|
}
|
}
|
ZipEntries.prototype = {
|
/**
|
* Check that the reader is on the speficied signature.
|
* @param {string} expectedSignature the expected signature.
|
* @throws {Error} if it is an other signature.
|
*/
|
checkSignature: function(expectedSignature) {
|
var signature = this.reader.readString(4);
|
if (signature !== expectedSignature) {
|
throw new Error("Corrupted zip or bug : unexpected signature " + "(" + utils.pretty(signature) + ", expected " + utils.pretty(expectedSignature) + ")");
|
}
|
},
|
/**
|
* Check if the given signature is at the given index.
|
* @param {number} askedIndex the index to check.
|
* @param {string} expectedSignature the signature to expect.
|
* @return {boolean} true if the signature is here, false otherwise.
|
*/
|
isSignature: function(askedIndex, expectedSignature) {
|
var currentIndex = this.reader.index;
|
this.reader.setIndex(askedIndex);
|
var signature = this.reader.readString(4);
|
var result = signature === expectedSignature;
|
this.reader.setIndex(currentIndex);
|
return result;
|
},
|
/**
|
* Read the end of the central directory.
|
*/
|
readBlockEndOfCentral: function() {
|
this.diskNumber = this.reader.readInt(2);
|
this.diskWithCentralDirStart = this.reader.readInt(2);
|
this.centralDirRecordsOnThisDisk = this.reader.readInt(2);
|
this.centralDirRecords = this.reader.readInt(2);
|
this.centralDirSize = this.reader.readInt(4);
|
this.centralDirOffset = this.reader.readInt(4);
|
|
this.zipCommentLength = this.reader.readInt(2);
|
// warning : the encoding depends of the system locale
|
// On a linux machine with LANG=en_US.utf8, this field is utf8 encoded.
|
// On a windows machine, this field is encoded with the localized windows code page.
|
var zipComment = this.reader.readData(this.zipCommentLength);
|
var decodeParamType = support.uint8array ? "uint8array" : "array";
|
// To get consistent behavior with the generation part, we will assume that
|
// this is utf8 encoded unless specified otherwise.
|
var decodeContent = utils.transformTo(decodeParamType, zipComment);
|
this.zipComment = this.loadOptions.decodeFileName(decodeContent);
|
},
|
/**
|
* Read the end of the Zip 64 central directory.
|
* Not merged with the method readEndOfCentral :
|
* The end of central can coexist with its Zip64 brother,
|
* I don't want to read the wrong number of bytes !
|
*/
|
readBlockZip64EndOfCentral: function() {
|
this.zip64EndOfCentralSize = this.reader.readInt(8);
|
this.versionMadeBy = this.reader.readString(2);
|
this.versionNeeded = this.reader.readInt(2);
|
this.diskNumber = this.reader.readInt(4);
|
this.diskWithCentralDirStart = this.reader.readInt(4);
|
this.centralDirRecordsOnThisDisk = this.reader.readInt(8);
|
this.centralDirRecords = this.reader.readInt(8);
|
this.centralDirSize = this.reader.readInt(8);
|
this.centralDirOffset = this.reader.readInt(8);
|
|
this.zip64ExtensibleData = {};
|
var extraDataSize = this.zip64EndOfCentralSize - 44,
|
index = 0,
|
extraFieldId,
|
extraFieldLength,
|
extraFieldValue;
|
while (index < extraDataSize) {
|
extraFieldId = this.reader.readInt(2);
|
extraFieldLength = this.reader.readInt(4);
|
extraFieldValue = this.reader.readString(extraFieldLength);
|
this.zip64ExtensibleData[extraFieldId] = {
|
id: extraFieldId,
|
length: extraFieldLength,
|
value: extraFieldValue
|
};
|
}
|
},
|
/**
|
* Read the end of the Zip 64 central directory locator.
|
*/
|
readBlockZip64EndOfCentralLocator: function() {
|
this.diskWithZip64CentralDirStart = this.reader.readInt(4);
|
this.relativeOffsetEndOfZip64CentralDir = this.reader.readInt(8);
|
this.disksCount = this.reader.readInt(4);
|
if (this.disksCount > 1) {
|
throw new Error("Multi-volumes zip are not supported");
|
}
|
},
|
/**
|
* Read the local files, based on the offset read in the central part.
|
*/
|
readLocalFiles: function() {
|
var i, file;
|
for (i = 0; i < this.files.length; i++) {
|
file = this.files[i];
|
this.reader.setIndex(file.localHeaderOffset);
|
this.checkSignature(sig.LOCAL_FILE_HEADER);
|
file.readLocalPart(this.reader);
|
file.handleUTF8();
|
file.processAttributes();
|
}
|
},
|
/**
|
* Read the central directory.
|
*/
|
readCentralDir: function() {
|
var file;
|
|
this.reader.setIndex(this.centralDirOffset);
|
while (this.reader.readString(4) === sig.CENTRAL_FILE_HEADER) {
|
file = new ZipEntry({
|
zip64: this.zip64
|
}, this.loadOptions);
|
file.readCentralPart(this.reader);
|
this.files.push(file);
|
}
|
|
if (this.centralDirRecords !== this.files.length) {
|
if (this.centralDirRecords !== 0 && this.files.length === 0) {
|
// We expected some records but couldn't find ANY.
|
// This is really suspicious, as if something went wrong.
|
throw new Error("Corrupted zip or bug: expected " + this.centralDirRecords + " records in central dir, got " + this.files.length);
|
} else {
|
// We found some records but not all.
|
// Something is wrong but we got something for the user: no error here.
|
// console.warn("expected", this.centralDirRecords, "records in central dir, got", this.files.length);
|
}
|
}
|
},
|
/**
|
* Read the end of central directory.
|
*/
|
readEndOfCentral: function() {
|
var offset = this.reader.lastIndexOfSignature(sig.CENTRAL_DIRECTORY_END);
|
if (offset < 0) {
|
// Check if the content is a truncated zip or complete garbage.
|
// A "LOCAL_FILE_HEADER" is not required at the beginning (auto
|
// extractible zip for example) but it can give a good hint.
|
// If an ajax request was used without responseType, we will also
|
// get unreadable data.
|
var isGarbage = !this.isSignature(0, sig.LOCAL_FILE_HEADER);
|
|
if (isGarbage) {
|
throw new Error("Can't find end of central directory : is this a zip file ? " +
|
"If it is, see http://stuk.github.io/jszip/documentation/howto/read_zip.html");
|
} else {
|
throw new Error("Corrupted zip : can't find end of central directory");
|
}
|
}
|
this.reader.setIndex(offset);
|
var endOfCentralDirOffset = offset;
|
this.checkSignature(sig.CENTRAL_DIRECTORY_END);
|
this.readBlockEndOfCentral();
|
|
|
/* extract from the zip spec :
|
4) If one of the fields in the end of central directory
|
record is too small to hold required data, the field
|
should be set to -1 (0xFFFF or 0xFFFFFFFF) and the
|
ZIP64 format record should be created.
|
5) The end of central directory record and the
|
Zip64 end of central directory locator record must
|
reside on the same disk when splitting or spanning
|
an archive.
|
*/
|
if (this.diskNumber === utils.MAX_VALUE_16BITS || this.diskWithCentralDirStart === utils.MAX_VALUE_16BITS || this.centralDirRecordsOnThisDisk === utils.MAX_VALUE_16BITS || this.centralDirRecords === utils.MAX_VALUE_16BITS || this.centralDirSize === utils.MAX_VALUE_32BITS || this.centralDirOffset === utils.MAX_VALUE_32BITS) {
|
this.zip64 = true;
|
|
/*
|
Warning : the zip64 extension is supported, but ONLY if the 64bits integer read from
|
the zip file can fit into a 32bits integer. This cannot be solved : Javascript represents
|
all numbers as 64-bit double precision IEEE 754 floating point numbers.
|
So, we have 53bits for integers and bitwise operations treat everything as 32bits.
|
see https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/Bitwise_Operators
|
and http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-262.pdf section 8.5
|
*/
|
|
// should look for a zip64 EOCD locator
|
offset = this.reader.lastIndexOfSignature(sig.ZIP64_CENTRAL_DIRECTORY_LOCATOR);
|
if (offset < 0) {
|
throw new Error("Corrupted zip : can't find the ZIP64 end of central directory locator");
|
}
|
this.reader.setIndex(offset);
|
this.checkSignature(sig.ZIP64_CENTRAL_DIRECTORY_LOCATOR);
|
this.readBlockZip64EndOfCentralLocator();
|
|
// now the zip64 EOCD record
|
if (!this.isSignature(this.relativeOffsetEndOfZip64CentralDir, sig.ZIP64_CENTRAL_DIRECTORY_END)) {
|
// console.warn("ZIP64 end of central directory not where expected.");
|
this.relativeOffsetEndOfZip64CentralDir = this.reader.lastIndexOfSignature(sig.ZIP64_CENTRAL_DIRECTORY_END);
|
if (this.relativeOffsetEndOfZip64CentralDir < 0) {
|
throw new Error("Corrupted zip : can't find the ZIP64 end of central directory");
|
}
|
}
|
this.reader.setIndex(this.relativeOffsetEndOfZip64CentralDir);
|
this.checkSignature(sig.ZIP64_CENTRAL_DIRECTORY_END);
|
this.readBlockZip64EndOfCentral();
|
}
|
|
var expectedEndOfCentralDirOffset = this.centralDirOffset + this.centralDirSize;
|
if (this.zip64) {
|
expectedEndOfCentralDirOffset += 20; // end of central dir 64 locator
|
expectedEndOfCentralDirOffset += 12 /* should not include the leading 12 bytes */ + this.zip64EndOfCentralSize;
|
}
|
|
var extraBytes = endOfCentralDirOffset - expectedEndOfCentralDirOffset;
|
|
if (extraBytes > 0) {
|
// console.warn(extraBytes, "extra bytes at beginning or within zipfile");
|
if (this.isSignature(endOfCentralDirOffset, sig.CENTRAL_FILE_HEADER)) {
|
// The offsets seem wrong, but we have something at the specified offset.
|
// So… we keep it.
|
} else {
|
// the offset is wrong, update the "zero" of the reader
|
// this happens if data has been prepended (crx files for example)
|
this.reader.zero = extraBytes;
|
}
|
} else if (extraBytes < 0) {
|
throw new Error("Corrupted zip: missing " + Math.abs(extraBytes) + " bytes.");
|
}
|
},
|
prepareReader: function(data) {
|
var type = utils.getTypeOf(data);
|
utils.checkSupport(type);
|
if (type === "string" && !support.uint8array) {
|
this.reader = new StringReader(data, this.loadOptions.optimizedBinaryString);
|
}
|
else if (type === "nodebuffer") {
|
this.reader = new NodeBufferReader(data);
|
}
|
else if (support.uint8array) {
|
this.reader = new Uint8ArrayReader(utils.transformTo("uint8array", data));
|
} else if (support.array) {
|
this.reader = new ArrayReader(utils.transformTo("array", data));
|
} else {
|
throw new Error("Unexpected error: unsupported type '" + type + "'");
|
}
|
},
|
/**
|
* Read a zip file and create ZipEntries.
|
* @param {String|ArrayBuffer|Uint8Array|Buffer} data the binary string representing a zip file.
|
*/
|
load: function(data) {
|
this.prepareReader(data);
|
this.readEndOfCentral();
|
this.readCentralDir();
|
this.readLocalFiles();
|
}
|
};
|
// }}} end of ZipEntries
|
module.exports = ZipEntries;
|
|
},{"./arrayReader":34,"./nodeBufferReader":46,"./object":47,"./signature":48,"./stringReader":49,"./support":51,"./uint8ArrayReader":52,"./utils":55,"./zipEntry":57}],57:[function(require,module,exports){
|
'use strict';
|
var StringReader = require('./stringReader');
|
var utils = require('./utils');
|
var CompressedObject = require('./compressedObject');
|
var jszipProto = require('./object');
|
var support = require('./support');
|
|
var MADE_BY_DOS = 0x00;
|
var MADE_BY_UNIX = 0x03;
|
|
// class ZipEntry {{{
|
/**
|
* An entry in the zip file.
|
* @constructor
|
* @param {Object} options Options of the current file.
|
* @param {Object} loadOptions Options for loading the stream.
|
*/
|
function ZipEntry(options, loadOptions) {
|
this.options = options;
|
this.loadOptions = loadOptions;
|
}
|
ZipEntry.prototype = {
|
/**
|
* say if the file is encrypted.
|
* @return {boolean} true if the file is encrypted, false otherwise.
|
*/
|
isEncrypted: function() {
|
// bit 1 is set
|
return (this.bitFlag & 0x0001) === 0x0001;
|
},
|
/**
|
* say if the file has utf-8 filename/comment.
|
* @return {boolean} true if the filename/comment is in utf-8, false otherwise.
|
*/
|
useUTF8: function() {
|
// bit 11 is set
|
return (this.bitFlag & 0x0800) === 0x0800;
|
},
|
/**
|
* Prepare the function used to generate the compressed content from this ZipFile.
|
* @param {DataReader} reader the reader to use.
|
* @param {number} from the offset from where we should read the data.
|
* @param {number} length the length of the data to read.
|
* @return {Function} the callback to get the compressed content (the type depends of the DataReader class).
|
*/
|
prepareCompressedContent: function(reader, from, length) {
|
return function() {
|
var previousIndex = reader.index;
|
reader.setIndex(from);
|
var compressedFileData = reader.readData(length);
|
reader.setIndex(previousIndex);
|
|
return compressedFileData;
|
};
|
},
|
/**
|
* Prepare the function used to generate the uncompressed content from this ZipFile.
|
* @param {DataReader} reader the reader to use.
|
* @param {number} from the offset from where we should read the data.
|
* @param {number} length the length of the data to read.
|
* @param {JSZip.compression} compression the compression used on this file.
|
* @param {number} uncompressedSize the uncompressed size to expect.
|
* @return {Function} the callback to get the uncompressed content (the type depends of the DataReader class).
|
*/
|
prepareContent: function(reader, from, length, compression, uncompressedSize) {
|
return function() {
|
|
var compressedFileData = utils.transformTo(compression.uncompressInputType, this.getCompressedContent());
|
var uncompressedFileData = compression.uncompress(compressedFileData);
|
|
if (uncompressedFileData.length !== uncompressedSize) {
|
throw new Error("Bug : uncompressed data size mismatch");
|
}
|
|
return uncompressedFileData;
|
};
|
},
|
/**
|
* Read the local part of a zip file and add the info in this object.
|
* @param {DataReader} reader the reader to use.
|
*/
|
readLocalPart: function(reader) {
|
var compression, localExtraFieldsLength;
|
|
// we already know everything from the central dir !
|
// If the central dir data are false, we are doomed.
|
// On the bright side, the local part is scary : zip64, data descriptors, both, etc.
|
// The less data we get here, the more reliable this should be.
|
// Let's skip the whole header and dash to the data !
|
reader.skip(22);
|
// in some zip created on windows, the filename stored in the central dir contains \ instead of /.
|
// Strangely, the filename here is OK.
|
// I would love to treat these zip files as corrupted (see http://www.info-zip.org/FAQ.html#backslashes
|
// or APPNOTE#4.4.17.1, "All slashes MUST be forward slashes '/'") but there are a lot of bad zip generators...
|
// Search "unzip mismatching "local" filename continuing with "central" filename version" on
|
// the internet.
|
//
|
// I think I see the logic here : the central directory is used to display
|
// content and the local directory is used to extract the files. Mixing / and \
|
// may be used to display \ to windows users and use / when extracting the files.
|
// Unfortunately, this lead also to some issues : http://seclists.org/fulldisclosure/2009/Sep/394
|
this.fileNameLength = reader.readInt(2);
|
localExtraFieldsLength = reader.readInt(2); // can't be sure this will be the same as the central dir
|
this.fileName = reader.readData(this.fileNameLength);
|
reader.skip(localExtraFieldsLength);
|
|
if (this.compressedSize == -1 || this.uncompressedSize == -1) {
|
throw new Error("Bug or corrupted zip : didn't get enough informations from the central directory " + "(compressedSize == -1 || uncompressedSize == -1)");
|
}
|
|
compression = utils.findCompression(this.compressionMethod);
|
if (compression === null) { // no compression found
|
throw new Error("Corrupted zip : compression " + utils.pretty(this.compressionMethod) + " unknown (inner file : " + utils.transformTo("string", this.fileName) + ")");
|
}
|
this.decompressed = new CompressedObject();
|
this.decompressed.compressedSize = this.compressedSize;
|
this.decompressed.uncompressedSize = this.uncompressedSize;
|
this.decompressed.crc32 = this.crc32;
|
this.decompressed.compressionMethod = this.compressionMethod;
|
this.decompressed.getCompressedContent = this.prepareCompressedContent(reader, reader.index, this.compressedSize, compression);
|
this.decompressed.getContent = this.prepareContent(reader, reader.index, this.compressedSize, compression, this.uncompressedSize);
|
|
// we need to compute the crc32...
|
if (this.loadOptions.checkCRC32) {
|
this.decompressed = utils.transformTo("string", this.decompressed.getContent());
|
if (jszipProto.crc32(this.decompressed) !== this.crc32) {
|
throw new Error("Corrupted zip : CRC32 mismatch");
|
}
|
}
|
},
|
|
/**
|
* Read the central part of a zip file and add the info in this object.
|
* @param {DataReader} reader the reader to use.
|
*/
|
readCentralPart: function(reader) {
|
this.versionMadeBy = reader.readInt(2);
|
this.versionNeeded = reader.readInt(2);
|
this.bitFlag = reader.readInt(2);
|
this.compressionMethod = reader.readString(2);
|
this.date = reader.readDate();
|
this.crc32 = reader.readInt(4);
|
this.compressedSize = reader.readInt(4);
|
this.uncompressedSize = reader.readInt(4);
|
this.fileNameLength = reader.readInt(2);
|
this.extraFieldsLength = reader.readInt(2);
|
this.fileCommentLength = reader.readInt(2);
|
this.diskNumberStart = reader.readInt(2);
|
this.internalFileAttributes = reader.readInt(2);
|
this.externalFileAttributes = reader.readInt(4);
|
this.localHeaderOffset = reader.readInt(4);
|
|
if (this.isEncrypted()) {
|
throw new Error("Encrypted zip are not supported");
|
}
|
|
this.fileName = reader.readData(this.fileNameLength);
|
this.readExtraFields(reader);
|
this.parseZIP64ExtraField(reader);
|
this.fileComment = reader.readData(this.fileCommentLength);
|
},
|
|
/**
|
* Parse the external file attributes and get the unix/dos permissions.
|
*/
|
processAttributes: function () {
|
this.unixPermissions = null;
|
this.dosPermissions = null;
|
var madeBy = this.versionMadeBy >> 8;
|
|
// Check if we have the DOS directory flag set.
|
// We look for it in the DOS and UNIX permissions
|
// but some unknown platform could set it as a compatibility flag.
|
this.dir = this.externalFileAttributes & 0x0010 ? true : false;
|
|
if(madeBy === MADE_BY_DOS) {
|
// first 6 bits (0 to 5)
|
this.dosPermissions = this.externalFileAttributes & 0x3F;
|
}
|
|
if(madeBy === MADE_BY_UNIX) {
|
this.unixPermissions = (this.externalFileAttributes >> 16) & 0xFFFF;
|
// the octal permissions are in (this.unixPermissions & 0x01FF).toString(8);
|
}
|
|
// fail safe : if the name ends with a / it probably means a folder
|
if (!this.dir && this.fileNameStr.slice(-1) === '/') {
|
this.dir = true;
|
}
|
},
|
|
/**
|
* Parse the ZIP64 extra field and merge the info in the current ZipEntry.
|
* @param {DataReader} reader the reader to use.
|
*/
|
parseZIP64ExtraField: function(reader) {
|
|
if (!this.extraFields[0x0001]) {
|
return;
|
}
|
|
// should be something, preparing the extra reader
|
var extraReader = new StringReader(this.extraFields[0x0001].value);
|
|
// I really hope that these 64bits integer can fit in 32 bits integer, because js
|
// won't let us have more.
|
if (this.uncompressedSize === utils.MAX_VALUE_32BITS) {
|
this.uncompressedSize = extraReader.readInt(8);
|
}
|
if (this.compressedSize === utils.MAX_VALUE_32BITS) {
|
this.compressedSize = extraReader.readInt(8);
|
}
|
if (this.localHeaderOffset === utils.MAX_VALUE_32BITS) {
|
this.localHeaderOffset = extraReader.readInt(8);
|
}
|
if (this.diskNumberStart === utils.MAX_VALUE_32BITS) {
|
this.diskNumberStart = extraReader.readInt(4);
|
}
|
},
|
/**
|
* Read the central part of a zip file and add the info in this object.
|
* @param {DataReader} reader the reader to use.
|
*/
|
readExtraFields: function(reader) {
|
var start = reader.index,
|
extraFieldId,
|
extraFieldLength,
|
extraFieldValue;
|
|
this.extraFields = this.extraFields || {};
|
|
while (reader.index < start + this.extraFieldsLength) {
|
extraFieldId = reader.readInt(2);
|
extraFieldLength = reader.readInt(2);
|
extraFieldValue = reader.readString(extraFieldLength);
|
|
this.extraFields[extraFieldId] = {
|
id: extraFieldId,
|
length: extraFieldLength,
|
value: extraFieldValue
|
};
|
}
|
},
|
/**
|
* Apply an UTF8 transformation if needed.
|
*/
|
handleUTF8: function() {
|
var decodeParamType = support.uint8array ? "uint8array" : "array";
|
if (this.useUTF8()) {
|
this.fileNameStr = jszipProto.utf8decode(this.fileName);
|
this.fileCommentStr = jszipProto.utf8decode(this.fileComment);
|
} else {
|
var upath = this.findExtraFieldUnicodePath();
|
if (upath !== null) {
|
this.fileNameStr = upath;
|
} else {
|
var fileNameByteArray = utils.transformTo(decodeParamType, this.fileName);
|
this.fileNameStr = this.loadOptions.decodeFileName(fileNameByteArray);
|
}
|
|
var ucomment = this.findExtraFieldUnicodeComment();
|
if (ucomment !== null) {
|
this.fileCommentStr = ucomment;
|
} else {
|
var commentByteArray = utils.transformTo(decodeParamType, this.fileComment);
|
this.fileCommentStr = this.loadOptions.decodeFileName(commentByteArray);
|
}
|
}
|
},
|
|
/**
|
* Find the unicode path declared in the extra field, if any.
|
* @return {String} the unicode path, null otherwise.
|
*/
|
findExtraFieldUnicodePath: function() {
|
var upathField = this.extraFields[0x7075];
|
if (upathField) {
|
var extraReader = new StringReader(upathField.value);
|
|
// wrong version
|
if (extraReader.readInt(1) !== 1) {
|
return null;
|
}
|
|
// the crc of the filename changed, this field is out of date.
|
if (jszipProto.crc32(this.fileName) !== extraReader.readInt(4)) {
|
return null;
|
}
|
|
return jszipProto.utf8decode(extraReader.readString(upathField.length - 5));
|
}
|
return null;
|
},
|
|
/**
|
* Find the unicode comment declared in the extra field, if any.
|
* @return {String} the unicode comment, null otherwise.
|
*/
|
findExtraFieldUnicodeComment: function() {
|
var ucommentField = this.extraFields[0x6375];
|
if (ucommentField) {
|
var extraReader = new StringReader(ucommentField.value);
|
|
// wrong version
|
if (extraReader.readInt(1) !== 1) {
|
return null;
|
}
|
|
// the crc of the comment changed, this field is out of date.
|
if (jszipProto.crc32(this.fileComment) !== extraReader.readInt(4)) {
|
return null;
|
}
|
|
return jszipProto.utf8decode(extraReader.readString(ucommentField.length - 5));
|
}
|
return null;
|
}
|
};
|
module.exports = ZipEntry;
|
|
},{"./compressedObject":36,"./object":47,"./stringReader":49,"./support":51,"./utils":55}],58:[function(require,module,exports){
|
'use strict';
|
var immediate = require('immediate');
|
|
/* istanbul ignore next */
|
function INTERNAL() {}
|
|
var handlers = {};
|
|
var REJECTED = ['REJECTED'];
|
var FULFILLED = ['FULFILLED'];
|
var PENDING = ['PENDING'];
|
|
module.exports = Promise;
|
|
function Promise(resolver) {
|
if (typeof resolver !== 'function') {
|
throw new TypeError('resolver must be a function');
|
}
|
this.state = PENDING;
|
this.queue = [];
|
this.outcome = void 0;
|
if (resolver !== INTERNAL) {
|
safelyResolveThenable(this, resolver);
|
}
|
}
|
|
Promise.prototype["finally"] = function (callback) {
|
if (typeof callback !== 'function') {
|
return this;
|
}
|
var p = this.constructor;
|
return this.then(resolve, reject);
|
|
function resolve(value) {
|
function yes () {
|
return value;
|
}
|
return p.resolve(callback()).then(yes);
|
}
|
function reject(reason) {
|
function no () {
|
throw reason;
|
}
|
return p.resolve(callback()).then(no);
|
}
|
};
|
Promise.prototype["catch"] = function (onRejected) {
|
return this.then(null, onRejected);
|
};
|
Promise.prototype.then = function (onFulfilled, onRejected) {
|
if (typeof onFulfilled !== 'function' && this.state === FULFILLED ||
|
typeof onRejected !== 'function' && this.state === REJECTED) {
|
return this;
|
}
|
var promise = new this.constructor(INTERNAL);
|
if (this.state !== PENDING) {
|
var resolver = this.state === FULFILLED ? onFulfilled : onRejected;
|
unwrap(promise, resolver, this.outcome);
|
} else {
|
this.queue.push(new QueueItem(promise, onFulfilled, onRejected));
|
}
|
|
return promise;
|
};
|
function QueueItem(promise, onFulfilled, onRejected) {
|
this.promise = promise;
|
if (typeof onFulfilled === 'function') {
|
this.onFulfilled = onFulfilled;
|
this.callFulfilled = this.otherCallFulfilled;
|
}
|
if (typeof onRejected === 'function') {
|
this.onRejected = onRejected;
|
this.callRejected = this.otherCallRejected;
|
}
|
}
|
QueueItem.prototype.callFulfilled = function (value) {
|
handlers.resolve(this.promise, value);
|
};
|
QueueItem.prototype.otherCallFulfilled = function (value) {
|
unwrap(this.promise, this.onFulfilled, value);
|
};
|
QueueItem.prototype.callRejected = function (value) {
|
handlers.reject(this.promise, value);
|
};
|
QueueItem.prototype.otherCallRejected = function (value) {
|
unwrap(this.promise, this.onRejected, value);
|
};
|
|
function unwrap(promise, func, value) {
|
immediate(function () {
|
var returnValue;
|
try {
|
returnValue = func(value);
|
} catch (e) {
|
return handlers.reject(promise, e);
|
}
|
if (returnValue === promise) {
|
handlers.reject(promise, new TypeError('Cannot resolve promise with itself'));
|
} else {
|
handlers.resolve(promise, returnValue);
|
}
|
});
|
}
|
|
handlers.resolve = function (self, value) {
|
var result = tryCatch(getThen, value);
|
if (result.status === 'error') {
|
return handlers.reject(self, result.value);
|
}
|
var thenable = result.value;
|
|
if (thenable) {
|
safelyResolveThenable(self, thenable);
|
} else {
|
self.state = FULFILLED;
|
self.outcome = value;
|
var i = -1;
|
var len = self.queue.length;
|
while (++i < len) {
|
self.queue[i].callFulfilled(value);
|
}
|
}
|
return self;
|
};
|
handlers.reject = function (self, error) {
|
self.state = REJECTED;
|
self.outcome = error;
|
var i = -1;
|
var len = self.queue.length;
|
while (++i < len) {
|
self.queue[i].callRejected(error);
|
}
|
return self;
|
};
|
|
function getThen(obj) {
|
// Make sure we only access the accessor once as required by the spec
|
var then = obj && obj.then;
|
if (obj && (typeof obj === 'object' || typeof obj === 'function') && typeof then === 'function') {
|
return function appyThen() {
|
then.apply(obj, arguments);
|
};
|
}
|
}
|
|
function safelyResolveThenable(self, thenable) {
|
// Either fulfill, reject or reject with error
|
var called = false;
|
function onError(value) {
|
if (called) {
|
return;
|
}
|
called = true;
|
handlers.reject(self, value);
|
}
|
|
function onSuccess(value) {
|
if (called) {
|
return;
|
}
|
called = true;
|
handlers.resolve(self, value);
|
}
|
|
function tryToUnwrap() {
|
thenable(onSuccess, onError);
|
}
|
|
var result = tryCatch(tryToUnwrap);
|
if (result.status === 'error') {
|
onError(result.value);
|
}
|
}
|
|
function tryCatch(func, value) {
|
var out = {};
|
try {
|
out.value = func(value);
|
out.status = 'success';
|
} catch (e) {
|
out.status = 'error';
|
out.value = e;
|
}
|
return out;
|
}
|
|
Promise.resolve = resolve;
|
function resolve(value) {
|
if (value instanceof this) {
|
return value;
|
}
|
return handlers.resolve(new this(INTERNAL), value);
|
}
|
|
Promise.reject = reject;
|
function reject(reason) {
|
var promise = new this(INTERNAL);
|
return handlers.reject(promise, reason);
|
}
|
|
Promise.all = all;
|
function all(iterable) {
|
var self = this;
|
if (Object.prototype.toString.call(iterable) !== '[object Array]') {
|
return this.reject(new TypeError('must be an array'));
|
}
|
|
var len = iterable.length;
|
var called = false;
|
if (!len) {
|
return this.resolve([]);
|
}
|
|
var values = new Array(len);
|
var resolved = 0;
|
var i = -1;
|
var promise = new this(INTERNAL);
|
|
while (++i < len) {
|
allResolver(iterable[i], i);
|
}
|
return promise;
|
function allResolver(value, i) {
|
self.resolve(value).then(resolveFromAll, function (error) {
|
if (!called) {
|
called = true;
|
handlers.reject(promise, error);
|
}
|
});
|
function resolveFromAll(outValue) {
|
values[i] = outValue;
|
if (++resolved === len && !called) {
|
called = true;
|
handlers.resolve(promise, values);
|
}
|
}
|
}
|
}
|
|
Promise.race = race;
|
function race(iterable) {
|
var self = this;
|
if (Object.prototype.toString.call(iterable) !== '[object Array]') {
|
return this.reject(new TypeError('must be an array'));
|
}
|
|
var len = iterable.length;
|
var called = false;
|
if (!len) {
|
return this.resolve([]);
|
}
|
|
var i = -1;
|
var promise = new this(INTERNAL);
|
|
while (++i < len) {
|
resolver(iterable[i]);
|
}
|
return promise;
|
function resolver(value) {
|
self.resolve(value).then(function (response) {
|
if (!called) {
|
called = true;
|
handlers.resolve(promise, response);
|
}
|
}, function (error) {
|
if (!called) {
|
called = true;
|
handlers.reject(promise, error);
|
}
|
});
|
}
|
}
|
|
},{"immediate":33}],59:[function(require,module,exports){
|
;(function () { // closure for web browsers
|
|
if (typeof module === 'object' && module.exports) {
|
module.exports = LRUCache
|
} else {
|
// just set the global for non-node platforms.
|
this.LRUCache = LRUCache
|
}
|
|
function hOP (obj, key) {
|
return Object.prototype.hasOwnProperty.call(obj, key)
|
}
|
|
function naiveLength () { return 1 }
|
|
var didTypeWarning = false
|
function typeCheckKey(key) {
|
if (!didTypeWarning && typeof key !== 'string' && typeof key !== 'number') {
|
didTypeWarning = true
|
console.error(new TypeError("LRU: key must be a string or number. Almost certainly a bug! " + typeof key).stack)
|
}
|
}
|
|
function LRUCache (options) {
|
if (!(this instanceof LRUCache))
|
return new LRUCache(options)
|
|
if (typeof options === 'number')
|
options = { max: options }
|
|
if (!options)
|
options = {}
|
|
this._max = options.max
|
// Kind of weird to have a default max of Infinity, but oh well.
|
if (!this._max || !(typeof this._max === "number") || this._max <= 0 )
|
this._max = Infinity
|
|
this._lengthCalculator = options.length || naiveLength
|
if (typeof this._lengthCalculator !== "function")
|
this._lengthCalculator = naiveLength
|
|
this._allowStale = options.stale || false
|
this._maxAge = options.maxAge || null
|
this._dispose = options.dispose
|
this.reset()
|
}
|
|
// resize the cache when the max changes.
|
Object.defineProperty(LRUCache.prototype, "max",
|
{ set : function (mL) {
|
if (!mL || !(typeof mL === "number") || mL <= 0 ) mL = Infinity
|
this._max = mL
|
if (this._length > this._max) trim(this)
|
}
|
, get : function () { return this._max }
|
, enumerable : true
|
})
|
|
// resize the cache when the lengthCalculator changes.
|
Object.defineProperty(LRUCache.prototype, "lengthCalculator",
|
{ set : function (lC) {
|
if (typeof lC !== "function") {
|
this._lengthCalculator = naiveLength
|
this._length = this._itemCount
|
for (var key in this._cache) {
|
this._cache[key].length = 1
|
}
|
} else {
|
this._lengthCalculator = lC
|
this._length = 0
|
for (var key in this._cache) {
|
this._cache[key].length = this._lengthCalculator(this._cache[key].value)
|
this._length += this._cache[key].length
|
}
|
}
|
|
if (this._length > this._max) trim(this)
|
}
|
, get : function () { return this._lengthCalculator }
|
, enumerable : true
|
})
|
|
Object.defineProperty(LRUCache.prototype, "length",
|
{ get : function () { return this._length }
|
, enumerable : true
|
})
|
|
|
Object.defineProperty(LRUCache.prototype, "itemCount",
|
{ get : function () { return this._itemCount }
|
, enumerable : true
|
})
|
|
LRUCache.prototype.forEach = function (fn, thisp) {
|
thisp = thisp || this
|
var i = 0
|
var itemCount = this._itemCount
|
|
for (var k = this._mru - 1; k >= 0 && i < itemCount; k--) if (this._lruList[k]) {
|
i++
|
var hit = this._lruList[k]
|
if (isStale(this, hit)) {
|
del(this, hit)
|
if (!this._allowStale) hit = undefined
|
}
|
if (hit) {
|
fn.call(thisp, hit.value, hit.key, this)
|
}
|
}
|
}
|
|
LRUCache.prototype.keys = function () {
|
var keys = new Array(this._itemCount)
|
var i = 0
|
for (var k = this._mru - 1; k >= 0 && i < this._itemCount; k--) if (this._lruList[k]) {
|
var hit = this._lruList[k]
|
keys[i++] = hit.key
|
}
|
return keys
|
}
|
|
LRUCache.prototype.values = function () {
|
var values = new Array(this._itemCount)
|
var i = 0
|
for (var k = this._mru - 1; k >= 0 && i < this._itemCount; k--) if (this._lruList[k]) {
|
var hit = this._lruList[k]
|
values[i++] = hit.value
|
}
|
return values
|
}
|
|
LRUCache.prototype.reset = function () {
|
if (this._dispose && this._cache) {
|
for (var k in this._cache) {
|
this._dispose(k, this._cache[k].value)
|
}
|
}
|
|
this._cache = Object.create(null) // hash of items by key
|
this._lruList = Object.create(null) // list of items in order of use recency
|
this._mru = 0 // most recently used
|
this._lru = 0 // least recently used
|
this._length = 0 // number of items in the list
|
this._itemCount = 0
|
}
|
|
LRUCache.prototype.dump = function () {
|
var arr = []
|
var i = 0
|
|
for (var k = this._mru - 1; k >= 0 && i < this._itemCount; k--) if (this._lruList[k]) {
|
var hit = this._lruList[k]
|
if (!isStale(this, hit)) {
|
//Do not store staled hits
|
++i
|
arr.push({
|
k: hit.key,
|
v: hit.value,
|
e: hit.now + (hit.maxAge || 0)
|
});
|
}
|
}
|
//arr has the most read first
|
return arr
|
}
|
|
LRUCache.prototype.dumpLru = function () {
|
return this._lruList
|
}
|
|
LRUCache.prototype.set = function (key, value, maxAge) {
|
maxAge = maxAge || this._maxAge
|
typeCheckKey(key)
|
|
var now = maxAge ? Date.now() : 0
|
var len = this._lengthCalculator(value)
|
|
if (hOP(this._cache, key)) {
|
if (len > this._max) {
|
del(this, this._cache[key])
|
return false
|
}
|
// dispose of the old one before overwriting
|
if (this._dispose)
|
this._dispose(key, this._cache[key].value)
|
|
this._cache[key].now = now
|
this._cache[key].maxAge = maxAge
|
this._cache[key].value = value
|
this._length += (len - this._cache[key].length)
|
this._cache[key].length = len
|
this.get(key)
|
|
if (this._length > this._max)
|
trim(this)
|
|
return true
|
}
|
|
var hit = new Entry(key, value, this._mru++, len, now, maxAge)
|
|
// oversized objects fall out of cache automatically.
|
if (hit.length > this._max) {
|
if (this._dispose) this._dispose(key, value)
|
return false
|
}
|
|
this._length += hit.length
|
this._lruList[hit.lu] = this._cache[key] = hit
|
this._itemCount ++
|
|
if (this._length > this._max)
|
trim(this)
|
|
return true
|
}
|
|
LRUCache.prototype.has = function (key) {
|
typeCheckKey(key)
|
if (!hOP(this._cache, key)) return false
|
var hit = this._cache[key]
|
if (isStale(this, hit)) {
|
return false
|
}
|
return true
|
}
|
|
LRUCache.prototype.get = function (key) {
|
typeCheckKey(key)
|
return get(this, key, true)
|
}
|
|
LRUCache.prototype.peek = function (key) {
|
typeCheckKey(key)
|
return get(this, key, false)
|
}
|
|
LRUCache.prototype.pop = function () {
|
var hit = this._lruList[this._lru]
|
del(this, hit)
|
return hit || null
|
}
|
|
LRUCache.prototype.del = function (key) {
|
typeCheckKey(key)
|
del(this, this._cache[key])
|
}
|
|
LRUCache.prototype.load = function (arr) {
|
//reset the cache
|
this.reset();
|
|
var now = Date.now()
|
//A previous serialized cache has the most recent items first
|
for (var l = arr.length - 1; l >= 0; l-- ) {
|
var hit = arr[l]
|
typeCheckKey(hit.k)
|
var expiresAt = hit.e || 0
|
if (expiresAt === 0) {
|
//the item was created without expiration in a non aged cache
|
this.set(hit.k, hit.v)
|
} else {
|
var maxAge = expiresAt - now
|
//dont add already expired items
|
if (maxAge > 0) this.set(hit.k, hit.v, maxAge)
|
}
|
}
|
}
|
|
function get (self, key, doUse) {
|
typeCheckKey(key)
|
var hit = self._cache[key]
|
if (hit) {
|
if (isStale(self, hit)) {
|
del(self, hit)
|
if (!self._allowStale) hit = undefined
|
} else {
|
if (doUse) use(self, hit)
|
}
|
if (hit) hit = hit.value
|
}
|
return hit
|
}
|
|
function isStale(self, hit) {
|
if (!hit || (!hit.maxAge && !self._maxAge)) return false
|
var stale = false;
|
var diff = Date.now() - hit.now
|
if (hit.maxAge) {
|
stale = diff > hit.maxAge
|
} else {
|
stale = self._maxAge && (diff > self._maxAge)
|
}
|
return stale;
|
}
|
|
function use (self, hit) {
|
shiftLU(self, hit)
|
hit.lu = self._mru ++
|
self._lruList[hit.lu] = hit
|
}
|
|
function trim (self) {
|
while (self._lru < self._mru && self._length > self._max)
|
del(self, self._lruList[self._lru])
|
}
|
|
function shiftLU (self, hit) {
|
delete self._lruList[ hit.lu ]
|
while (self._lru < self._mru && !self._lruList[self._lru]) self._lru ++
|
}
|
|
function del (self, hit) {
|
if (hit) {
|
if (self._dispose) self._dispose(hit.key, hit.value)
|
self._length -= hit.length
|
self._itemCount --
|
delete self._cache[ hit.key ]
|
shiftLU(self, hit)
|
}
|
}
|
|
// classy, since V8 prefers predictable objects.
|
function Entry (key, value, lu, length, now, maxAge) {
|
this.key = key
|
this.value = value
|
this.lu = lu
|
this.length = length
|
this.now = now
|
if (maxAge) this.maxAge = maxAge
|
}
|
|
})()
|
|
},{}],60:[function(require,module,exports){
|
/*
|
https://github.com/banksean wrapped Makoto Matsumoto and Takuji Nishimura's code in a namespace
|
so it's better encapsulated. Now you can have multiple random number generators
|
and they won't stomp all over eachother's state.
|
|
If you want to use this as a substitute for Math.random(), use the random()
|
method like so:
|
|
var m = new MersenneTwister();
|
var randomNumber = m.random();
|
|
You can also call the other genrand_{foo}() methods on the instance.
|
|
If you want to use a specific seed in order to get a repeatable random
|
sequence, pass an integer into the constructor:
|
|
var m = new MersenneTwister(123);
|
|
and that will always produce the same random sequence.
|
|
Sean McCullough (banksean@gmail.com)
|
*/
|
|
/*
|
A C-program for MT19937, with initialization improved 2002/1/26.
|
Coded by Takuji Nishimura and Makoto Matsumoto.
|
|
Before using, initialize the state by using init_seed(seed)
|
or init_by_array(init_key, key_length).
|
|
Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura,
|
All rights reserved.
|
|
Redistribution and use in source and binary forms, with or without
|
modification, are permitted provided that the following conditions
|
are met:
|
|
1. Redistributions of source code must retain the above copyright
|
notice, this list of conditions and the following disclaimer.
|
|
2. Redistributions in binary form must reproduce the above copyright
|
notice, this list of conditions and the following disclaimer in the
|
documentation and/or other materials provided with the distribution.
|
|
3. The names of its contributors may not be used to endorse or promote
|
products derived from this software without specific prior written
|
permission.
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
Any feedback is very welcome.
|
http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html
|
email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space)
|
*/
|
|
var MersenneTwister = function(seed) {
|
if (seed == undefined) {
|
seed = new Date().getTime();
|
}
|
|
/* Period parameters */
|
this.N = 624;
|
this.M = 397;
|
this.MATRIX_A = 0x9908b0df; /* constant vector a */
|
this.UPPER_MASK = 0x80000000; /* most significant w-r bits */
|
this.LOWER_MASK = 0x7fffffff; /* least significant r bits */
|
|
this.mt = new Array(this.N); /* the array for the state vector */
|
this.mti=this.N+1; /* mti==N+1 means mt[N] is not initialized */
|
|
if (seed.constructor == Array) {
|
this.init_by_array(seed, seed.length);
|
}
|
else {
|
this.init_seed(seed);
|
}
|
}
|
|
/* initializes mt[N] with a seed */
|
/* origin name init_genrand */
|
MersenneTwister.prototype.init_seed = function(s) {
|
this.mt[0] = s >>> 0;
|
for (this.mti=1; this.mti<this.N; this.mti++) {
|
var s = this.mt[this.mti-1] ^ (this.mt[this.mti-1] >>> 30);
|
this.mt[this.mti] = (((((s & 0xffff0000) >>> 16) * 1812433253) << 16) + (s & 0x0000ffff) * 1812433253)
|
+ this.mti;
|
/* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */
|
/* In the previous versions, MSBs of the seed affect */
|
/* only MSBs of the array mt[]. */
|
/* 2002/01/09 modified by Makoto Matsumoto */
|
this.mt[this.mti] >>>= 0;
|
/* for >32 bit machines */
|
}
|
}
|
|
/* initialize by an array with array-length */
|
/* init_key is the array for initializing keys */
|
/* key_length is its length */
|
/* slight change for C++, 2004/2/26 */
|
MersenneTwister.prototype.init_by_array = function(init_key, key_length) {
|
var i, j, k;
|
this.init_seed(19650218);
|
i=1; j=0;
|
k = (this.N>key_length ? this.N : key_length);
|
for (; k; k--) {
|
var s = this.mt[i-1] ^ (this.mt[i-1] >>> 30)
|
this.mt[i] = (this.mt[i] ^ (((((s & 0xffff0000) >>> 16) * 1664525) << 16) + ((s & 0x0000ffff) * 1664525)))
|
+ init_key[j] + j; /* non linear */
|
this.mt[i] >>>= 0; /* for WORDSIZE > 32 machines */
|
i++; j++;
|
if (i>=this.N) { this.mt[0] = this.mt[this.N-1]; i=1; }
|
if (j>=key_length) j=0;
|
}
|
for (k=this.N-1; k; k--) {
|
var s = this.mt[i-1] ^ (this.mt[i-1] >>> 30);
|
this.mt[i] = (this.mt[i] ^ (((((s & 0xffff0000) >>> 16) * 1566083941) << 16) + (s & 0x0000ffff) * 1566083941))
|
- i; /* non linear */
|
this.mt[i] >>>= 0; /* for WORDSIZE > 32 machines */
|
i++;
|
if (i>=this.N) { this.mt[0] = this.mt[this.N-1]; i=1; }
|
}
|
|
this.mt[0] = 0x80000000; /* MSB is 1; assuring non-zero initial array */
|
}
|
|
/* generates a random number on [0,0xffffffff]-interval */
|
/* origin name genrand_int32 */
|
MersenneTwister.prototype.random_int = function() {
|
var y;
|
var mag01 = new Array(0x0, this.MATRIX_A);
|
/* mag01[x] = x * MATRIX_A for x=0,1 */
|
|
if (this.mti >= this.N) { /* generate N words at one time */
|
var kk;
|
|
if (this.mti == this.N+1) /* if init_seed() has not been called, */
|
this.init_seed(5489); /* a default initial seed is used */
|
|
for (kk=0;kk<this.N-this.M;kk++) {
|
y = (this.mt[kk]&this.UPPER_MASK)|(this.mt[kk+1]&this.LOWER_MASK);
|
this.mt[kk] = this.mt[kk+this.M] ^ (y >>> 1) ^ mag01[y & 0x1];
|
}
|
for (;kk<this.N-1;kk++) {
|
y = (this.mt[kk]&this.UPPER_MASK)|(this.mt[kk+1]&this.LOWER_MASK);
|
this.mt[kk] = this.mt[kk+(this.M-this.N)] ^ (y >>> 1) ^ mag01[y & 0x1];
|
}
|
y = (this.mt[this.N-1]&this.UPPER_MASK)|(this.mt[0]&this.LOWER_MASK);
|
this.mt[this.N-1] = this.mt[this.M-1] ^ (y >>> 1) ^ mag01[y & 0x1];
|
|
this.mti = 0;
|
}
|
|
y = this.mt[this.mti++];
|
|
/* Tempering */
|
y ^= (y >>> 11);
|
y ^= (y << 7) & 0x9d2c5680;
|
y ^= (y << 15) & 0xefc60000;
|
y ^= (y >>> 18);
|
|
return y >>> 0;
|
}
|
|
/* generates a random number on [0,0x7fffffff]-interval */
|
/* origin name genrand_int31 */
|
MersenneTwister.prototype.random_int31 = function() {
|
return (this.random_int()>>>1);
|
}
|
|
/* generates a random number on [0,1]-real-interval */
|
/* origin name genrand_real1 */
|
MersenneTwister.prototype.random_incl = function() {
|
return this.random_int()*(1.0/4294967295.0);
|
/* divided by 2^32-1 */
|
}
|
|
/* generates a random number on [0,1)-real-interval */
|
MersenneTwister.prototype.random = function() {
|
return this.random_int()*(1.0/4294967296.0);
|
/* divided by 2^32 */
|
}
|
|
/* generates a random number on (0,1)-real-interval */
|
/* origin name genrand_real3 */
|
MersenneTwister.prototype.random_excl = function() {
|
return (this.random_int() + 0.5)*(1.0/4294967296.0);
|
/* divided by 2^32 */
|
}
|
|
/* generates a random number on [0,1) with 53-bit resolution*/
|
/* origin name genrand_res53 */
|
MersenneTwister.prototype.random_long = function() {
|
var a=this.random_int()>>>5, b=this.random_int()>>>6;
|
return(a*67108864.0+b)*(1.0/9007199254740992.0);
|
}
|
|
/* These real versions are due to Isaku Wada, 2002/01/09 added */
|
|
module.exports = MersenneTwister;
|
|
},{}],61:[function(require,module,exports){
|
'use strict'
|
|
module.exports = monotoneConvexHull2D
|
|
var orient = require('robust-orientation')[3]
|
|
function monotoneConvexHull2D(points) {
|
var n = points.length
|
|
if(n < 3) {
|
var result = new Array(n)
|
for(var i=0; i<n; ++i) {
|
result[i] = i
|
}
|
|
if(n === 2 &&
|
points[0][0] === points[1][0] &&
|
points[0][1] === points[1][1]) {
|
return [0]
|
}
|
|
return result
|
}
|
|
//Sort point indices along x-axis
|
var sorted = new Array(n)
|
for(var i=0; i<n; ++i) {
|
sorted[i] = i
|
}
|
sorted.sort(function(a,b) {
|
var d = points[a][0]-points[b][0]
|
if(d) {
|
return d
|
}
|
return points[a][1] - points[b][1]
|
})
|
|
//Construct upper and lower hulls
|
var lower = [sorted[0], sorted[1]]
|
var upper = [sorted[0], sorted[1]]
|
|
for(var i=2; i<n; ++i) {
|
var idx = sorted[i]
|
var p = points[idx]
|
|
//Insert into lower list
|
var m = lower.length
|
while(m > 1 && orient(
|
points[lower[m-2]],
|
points[lower[m-1]],
|
p) <= 0) {
|
m -= 1
|
lower.pop()
|
}
|
lower.push(idx)
|
|
//Insert into upper list
|
m = upper.length
|
while(m > 1 && orient(
|
points[upper[m-2]],
|
points[upper[m-1]],
|
p) >= 0) {
|
m -= 1
|
upper.pop()
|
}
|
upper.push(idx)
|
}
|
|
//Merge lists together
|
var result = new Array(upper.length + lower.length - 2)
|
var ptr = 0
|
for(var i=0, nl=lower.length; i<nl; ++i) {
|
result[ptr++] = lower[i]
|
}
|
for(var j=upper.length-2; j>0; --j) {
|
result[ptr++] = upper[j]
|
}
|
|
//Return result
|
return result
|
}
|
},{"robust-orientation":85}],62:[function(require,module,exports){
|
// Top level file is just a mixin of submodules & constants
|
'use strict';
|
|
var assign = require('./lib/utils/common').assign;
|
|
var deflate = require('./lib/deflate');
|
var inflate = require('./lib/inflate');
|
var constants = require('./lib/zlib/constants');
|
|
var pako = {};
|
|
assign(pako, deflate, inflate, constants);
|
|
module.exports = pako;
|
|
},{"./lib/deflate":63,"./lib/inflate":64,"./lib/utils/common":65,"./lib/zlib/constants":68}],63:[function(require,module,exports){
|
'use strict';
|
|
|
var zlib_deflate = require('./zlib/deflate');
|
var utils = require('./utils/common');
|
var strings = require('./utils/strings');
|
var msg = require('./zlib/messages');
|
var ZStream = require('./zlib/zstream');
|
|
var toString = Object.prototype.toString;
|
|
/* Public constants ==========================================================*/
|
/* ===========================================================================*/
|
|
var Z_NO_FLUSH = 0;
|
var Z_FINISH = 4;
|
|
var Z_OK = 0;
|
var Z_STREAM_END = 1;
|
var Z_SYNC_FLUSH = 2;
|
|
var Z_DEFAULT_COMPRESSION = -1;
|
|
var Z_DEFAULT_STRATEGY = 0;
|
|
var Z_DEFLATED = 8;
|
|
/* ===========================================================================*/
|
|
|
/**
|
* class Deflate
|
*
|
* Generic JS-style wrapper for zlib calls. If you don't need
|
* streaming behaviour - use more simple functions: [[deflate]],
|
* [[deflateRaw]] and [[gzip]].
|
**/
|
|
/* internal
|
* Deflate.chunks -> Array
|
*
|
* Chunks of output data, if [[Deflate#onData]] not overridden.
|
**/
|
|
/**
|
* Deflate.result -> Uint8Array|Array
|
*
|
* Compressed result, generated by default [[Deflate#onData]]
|
* and [[Deflate#onEnd]] handlers. Filled after you push last chunk
|
* (call [[Deflate#push]] with `Z_FINISH` / `true` param) or if you
|
* push a chunk with explicit flush (call [[Deflate#push]] with
|
* `Z_SYNC_FLUSH` param).
|
**/
|
|
/**
|
* Deflate.err -> Number
|
*
|
* Error code after deflate finished. 0 (Z_OK) on success.
|
* You will not need it in real life, because deflate errors
|
* are possible only on wrong options or bad `onData` / `onEnd`
|
* custom handlers.
|
**/
|
|
/**
|
* Deflate.msg -> String
|
*
|
* Error message, if [[Deflate.err]] != 0
|
**/
|
|
|
/**
|
* new Deflate(options)
|
* - options (Object): zlib deflate options.
|
*
|
* Creates new deflator instance with specified params. Throws exception
|
* on bad params. Supported options:
|
*
|
* - `level`
|
* - `windowBits`
|
* - `memLevel`
|
* - `strategy`
|
* - `dictionary`
|
*
|
* [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced)
|
* for more information on these.
|
*
|
* Additional options, for internal needs:
|
*
|
* - `chunkSize` - size of generated data chunks (16K by default)
|
* - `raw` (Boolean) - do raw deflate
|
* - `gzip` (Boolean) - create gzip wrapper
|
* - `to` (String) - if equal to 'string', then result will be "binary string"
|
* (each char code [0..255])
|
* - `header` (Object) - custom header for gzip
|
* - `text` (Boolean) - true if compressed data believed to be text
|
* - `time` (Number) - modification time, unix timestamp
|
* - `os` (Number) - operation system code
|
* - `extra` (Array) - array of bytes with extra data (max 65536)
|
* - `name` (String) - file name (binary string)
|
* - `comment` (String) - comment (binary string)
|
* - `hcrc` (Boolean) - true if header crc should be added
|
*
|
* ##### Example:
|
*
|
* ```javascript
|
* var pako = require('pako')
|
* , chunk1 = Uint8Array([1,2,3,4,5,6,7,8,9])
|
* , chunk2 = Uint8Array([10,11,12,13,14,15,16,17,18,19]);
|
*
|
* var deflate = new pako.Deflate({ level: 3});
|
*
|
* deflate.push(chunk1, false);
|
* deflate.push(chunk2, true); // true -> last chunk
|
*
|
* if (deflate.err) { throw new Error(deflate.err); }
|
*
|
* console.log(deflate.result);
|
* ```
|
**/
|
function Deflate(options) {
|
if (!(this instanceof Deflate)) return new Deflate(options);
|
|
this.options = utils.assign({
|
level: Z_DEFAULT_COMPRESSION,
|
method: Z_DEFLATED,
|
chunkSize: 16384,
|
windowBits: 15,
|
memLevel: 8,
|
strategy: Z_DEFAULT_STRATEGY,
|
to: ''
|
}, options || {});
|
|
var opt = this.options;
|
|
if (opt.raw && (opt.windowBits > 0)) {
|
opt.windowBits = -opt.windowBits;
|
}
|
|
else if (opt.gzip && (opt.windowBits > 0) && (opt.windowBits < 16)) {
|
opt.windowBits += 16;
|
}
|
|
this.err = 0; // error code, if happens (0 = Z_OK)
|
this.msg = ''; // error message
|
this.ended = false; // used to avoid multiple onEnd() calls
|
this.chunks = []; // chunks of compressed data
|
|
this.strm = new ZStream();
|
this.strm.avail_out = 0;
|
|
var status = zlib_deflate.deflateInit2(
|
this.strm,
|
opt.level,
|
opt.method,
|
opt.windowBits,
|
opt.memLevel,
|
opt.strategy
|
);
|
|
if (status !== Z_OK) {
|
throw new Error(msg[status]);
|
}
|
|
if (opt.header) {
|
zlib_deflate.deflateSetHeader(this.strm, opt.header);
|
}
|
|
if (opt.dictionary) {
|
var dict;
|
// Convert data if needed
|
if (typeof opt.dictionary === 'string') {
|
// If we need to compress text, change encoding to utf8.
|
dict = strings.string2buf(opt.dictionary);
|
} else if (toString.call(opt.dictionary) === '[object ArrayBuffer]') {
|
dict = new Uint8Array(opt.dictionary);
|
} else {
|
dict = opt.dictionary;
|
}
|
|
status = zlib_deflate.deflateSetDictionary(this.strm, dict);
|
|
if (status !== Z_OK) {
|
throw new Error(msg[status]);
|
}
|
|
this._dict_set = true;
|
}
|
}
|
|
/**
|
* Deflate#push(data[, mode]) -> Boolean
|
* - data (Uint8Array|Array|ArrayBuffer|String): input data. Strings will be
|
* converted to utf8 byte sequence.
|
* - mode (Number|Boolean): 0..6 for corresponding Z_NO_FLUSH..Z_TREE modes.
|
* See constants. Skipped or `false` means Z_NO_FLUSH, `true` means Z_FINISH.
|
*
|
* Sends input data to deflate pipe, generating [[Deflate#onData]] calls with
|
* new compressed chunks. Returns `true` on success. The last data block must have
|
* mode Z_FINISH (or `true`). That will flush internal pending buffers and call
|
* [[Deflate#onEnd]]. For interim explicit flushes (without ending the stream) you
|
* can use mode Z_SYNC_FLUSH, keeping the compression context.
|
*
|
* On fail call [[Deflate#onEnd]] with error code and return false.
|
*
|
* We strongly recommend to use `Uint8Array` on input for best speed (output
|
* array format is detected automatically). Also, don't skip last param and always
|
* use the same type in your code (boolean or number). That will improve JS speed.
|
*
|
* For regular `Array`-s make sure all elements are [0..255].
|
*
|
* ##### Example
|
*
|
* ```javascript
|
* push(chunk, false); // push one of data chunks
|
* ...
|
* push(chunk, true); // push last chunk
|
* ```
|
**/
|
Deflate.prototype.push = function (data, mode) {
|
var strm = this.strm;
|
var chunkSize = this.options.chunkSize;
|
var status, _mode;
|
|
if (this.ended) { return false; }
|
|
_mode = (mode === ~~mode) ? mode : ((mode === true) ? Z_FINISH : Z_NO_FLUSH);
|
|
// Convert data if needed
|
if (typeof data === 'string') {
|
// If we need to compress text, change encoding to utf8.
|
strm.input = strings.string2buf(data);
|
} else if (toString.call(data) === '[object ArrayBuffer]') {
|
strm.input = new Uint8Array(data);
|
} else {
|
strm.input = data;
|
}
|
|
strm.next_in = 0;
|
strm.avail_in = strm.input.length;
|
|
do {
|
if (strm.avail_out === 0) {
|
strm.output = new utils.Buf8(chunkSize);
|
strm.next_out = 0;
|
strm.avail_out = chunkSize;
|
}
|
status = zlib_deflate.deflate(strm, _mode); /* no bad return value */
|
|
if (status !== Z_STREAM_END && status !== Z_OK) {
|
this.onEnd(status);
|
this.ended = true;
|
return false;
|
}
|
if (strm.avail_out === 0 || (strm.avail_in === 0 && (_mode === Z_FINISH || _mode === Z_SYNC_FLUSH))) {
|
if (this.options.to === 'string') {
|
this.onData(strings.buf2binstring(utils.shrinkBuf(strm.output, strm.next_out)));
|
} else {
|
this.onData(utils.shrinkBuf(strm.output, strm.next_out));
|
}
|
}
|
} while ((strm.avail_in > 0 || strm.avail_out === 0) && status !== Z_STREAM_END);
|
|
// Finalize on the last chunk.
|
if (_mode === Z_FINISH) {
|
status = zlib_deflate.deflateEnd(this.strm);
|
this.onEnd(status);
|
this.ended = true;
|
return status === Z_OK;
|
}
|
|
// callback interim results if Z_SYNC_FLUSH.
|
if (_mode === Z_SYNC_FLUSH) {
|
this.onEnd(Z_OK);
|
strm.avail_out = 0;
|
return true;
|
}
|
|
return true;
|
};
|
|
|
/**
|
* Deflate#onData(chunk) -> Void
|
* - chunk (Uint8Array|Array|String): output data. Type of array depends
|
* on js engine support. When string output requested, each chunk
|
* will be string.
|
*
|
* By default, stores data blocks in `chunks[]` property and glue
|
* those in `onEnd`. Override this handler, if you need another behaviour.
|
**/
|
Deflate.prototype.onData = function (chunk) {
|
this.chunks.push(chunk);
|
};
|
|
|
/**
|
* Deflate#onEnd(status) -> Void
|
* - status (Number): deflate status. 0 (Z_OK) on success,
|
* other if not.
|
*
|
* Called once after you tell deflate that the input stream is
|
* complete (Z_FINISH) or should be flushed (Z_SYNC_FLUSH)
|
* or if an error happened. By default - join collected chunks,
|
* free memory and fill `results` / `err` properties.
|
**/
|
Deflate.prototype.onEnd = function (status) {
|
// On success - join
|
if (status === Z_OK) {
|
if (this.options.to === 'string') {
|
this.result = this.chunks.join('');
|
} else {
|
this.result = utils.flattenChunks(this.chunks);
|
}
|
}
|
this.chunks = [];
|
this.err = status;
|
this.msg = this.strm.msg;
|
};
|
|
|
/**
|
* deflate(data[, options]) -> Uint8Array|Array|String
|
* - data (Uint8Array|Array|String): input data to compress.
|
* - options (Object): zlib deflate options.
|
*
|
* Compress `data` with deflate algorithm and `options`.
|
*
|
* Supported options are:
|
*
|
* - level
|
* - windowBits
|
* - memLevel
|
* - strategy
|
* - dictionary
|
*
|
* [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced)
|
* for more information on these.
|
*
|
* Sugar (options):
|
*
|
* - `raw` (Boolean) - say that we work with raw stream, if you don't wish to specify
|
* negative windowBits implicitly.
|
* - `to` (String) - if equal to 'string', then result will be "binary string"
|
* (each char code [0..255])
|
*
|
* ##### Example:
|
*
|
* ```javascript
|
* var pako = require('pako')
|
* , data = Uint8Array([1,2,3,4,5,6,7,8,9]);
|
*
|
* console.log(pako.deflate(data));
|
* ```
|
**/
|
function deflate(input, options) {
|
var deflator = new Deflate(options);
|
|
deflator.push(input, true);
|
|
// That will never happens, if you don't cheat with options :)
|
if (deflator.err) { throw deflator.msg || msg[deflator.err]; }
|
|
return deflator.result;
|
}
|
|
|
/**
|
* deflateRaw(data[, options]) -> Uint8Array|Array|String
|
* - data (Uint8Array|Array|String): input data to compress.
|
* - options (Object): zlib deflate options.
|
*
|
* The same as [[deflate]], but creates raw data, without wrapper
|
* (header and adler32 crc).
|
**/
|
function deflateRaw(input, options) {
|
options = options || {};
|
options.raw = true;
|
return deflate(input, options);
|
}
|
|
|
/**
|
* gzip(data[, options]) -> Uint8Array|Array|String
|
* - data (Uint8Array|Array|String): input data to compress.
|
* - options (Object): zlib deflate options.
|
*
|
* The same as [[deflate]], but create gzip wrapper instead of
|
* deflate one.
|
**/
|
function gzip(input, options) {
|
options = options || {};
|
options.gzip = true;
|
return deflate(input, options);
|
}
|
|
|
exports.Deflate = Deflate;
|
exports.deflate = deflate;
|
exports.deflateRaw = deflateRaw;
|
exports.gzip = gzip;
|
|
},{"./utils/common":65,"./utils/strings":66,"./zlib/deflate":70,"./zlib/messages":75,"./zlib/zstream":77}],64:[function(require,module,exports){
|
'use strict';
|
|
|
var zlib_inflate = require('./zlib/inflate');
|
var utils = require('./utils/common');
|
var strings = require('./utils/strings');
|
var c = require('./zlib/constants');
|
var msg = require('./zlib/messages');
|
var ZStream = require('./zlib/zstream');
|
var GZheader = require('./zlib/gzheader');
|
|
var toString = Object.prototype.toString;
|
|
/**
|
* class Inflate
|
*
|
* Generic JS-style wrapper for zlib calls. If you don't need
|
* streaming behaviour - use more simple functions: [[inflate]]
|
* and [[inflateRaw]].
|
**/
|
|
/* internal
|
* inflate.chunks -> Array
|
*
|
* Chunks of output data, if [[Inflate#onData]] not overridden.
|
**/
|
|
/**
|
* Inflate.result -> Uint8Array|Array|String
|
*
|
* Uncompressed result, generated by default [[Inflate#onData]]
|
* and [[Inflate#onEnd]] handlers. Filled after you push last chunk
|
* (call [[Inflate#push]] with `Z_FINISH` / `true` param) or if you
|
* push a chunk with explicit flush (call [[Inflate#push]] with
|
* `Z_SYNC_FLUSH` param).
|
**/
|
|
/**
|
* Inflate.err -> Number
|
*
|
* Error code after inflate finished. 0 (Z_OK) on success.
|
* Should be checked if broken data possible.
|
**/
|
|
/**
|
* Inflate.msg -> String
|
*
|
* Error message, if [[Inflate.err]] != 0
|
**/
|
|
|
/**
|
* new Inflate(options)
|
* - options (Object): zlib inflate options.
|
*
|
* Creates new inflator instance with specified params. Throws exception
|
* on bad params. Supported options:
|
*
|
* - `windowBits`
|
* - `dictionary`
|
*
|
* [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced)
|
* for more information on these.
|
*
|
* Additional options, for internal needs:
|
*
|
* - `chunkSize` - size of generated data chunks (16K by default)
|
* - `raw` (Boolean) - do raw inflate
|
* - `to` (String) - if equal to 'string', then result will be converted
|
* from utf8 to utf16 (javascript) string. When string output requested,
|
* chunk length can differ from `chunkSize`, depending on content.
|
*
|
* By default, when no options set, autodetect deflate/gzip data format via
|
* wrapper header.
|
*
|
* ##### Example:
|
*
|
* ```javascript
|
* var pako = require('pako')
|
* , chunk1 = Uint8Array([1,2,3,4,5,6,7,8,9])
|
* , chunk2 = Uint8Array([10,11,12,13,14,15,16,17,18,19]);
|
*
|
* var inflate = new pako.Inflate({ level: 3});
|
*
|
* inflate.push(chunk1, false);
|
* inflate.push(chunk2, true); // true -> last chunk
|
*
|
* if (inflate.err) { throw new Error(inflate.err); }
|
*
|
* console.log(inflate.result);
|
* ```
|
**/
|
function Inflate(options) {
|
if (!(this instanceof Inflate)) return new Inflate(options);
|
|
this.options = utils.assign({
|
chunkSize: 16384,
|
windowBits: 0,
|
to: ''
|
}, options || {});
|
|
var opt = this.options;
|
|
// Force window size for `raw` data, if not set directly,
|
// because we have no header for autodetect.
|
if (opt.raw && (opt.windowBits >= 0) && (opt.windowBits < 16)) {
|
opt.windowBits = -opt.windowBits;
|
if (opt.windowBits === 0) { opt.windowBits = -15; }
|
}
|
|
// If `windowBits` not defined (and mode not raw) - set autodetect flag for gzip/deflate
|
if ((opt.windowBits >= 0) && (opt.windowBits < 16) &&
|
!(options && options.windowBits)) {
|
opt.windowBits += 32;
|
}
|
|
// Gzip header has no info about windows size, we can do autodetect only
|
// for deflate. So, if window size not set, force it to max when gzip possible
|
if ((opt.windowBits > 15) && (opt.windowBits < 48)) {
|
// bit 3 (16) -> gzipped data
|
// bit 4 (32) -> autodetect gzip/deflate
|
if ((opt.windowBits & 15) === 0) {
|
opt.windowBits |= 15;
|
}
|
}
|
|
this.err = 0; // error code, if happens (0 = Z_OK)
|
this.msg = ''; // error message
|
this.ended = false; // used to avoid multiple onEnd() calls
|
this.chunks = []; // chunks of compressed data
|
|
this.strm = new ZStream();
|
this.strm.avail_out = 0;
|
|
var status = zlib_inflate.inflateInit2(
|
this.strm,
|
opt.windowBits
|
);
|
|
if (status !== c.Z_OK) {
|
throw new Error(msg[status]);
|
}
|
|
this.header = new GZheader();
|
|
zlib_inflate.inflateGetHeader(this.strm, this.header);
|
|
// Setup dictionary
|
if (opt.dictionary) {
|
// Convert data if needed
|
if (typeof opt.dictionary === 'string') {
|
opt.dictionary = strings.string2buf(opt.dictionary);
|
} else if (toString.call(opt.dictionary) === '[object ArrayBuffer]') {
|
opt.dictionary = new Uint8Array(opt.dictionary);
|
}
|
if (opt.raw) { //In raw mode we need to set the dictionary early
|
status = zlib_inflate.inflateSetDictionary(this.strm, opt.dictionary);
|
if (status !== c.Z_OK) {
|
throw new Error(msg[status]);
|
}
|
}
|
}
|
}
|
|
/**
|
* Inflate#push(data[, mode]) -> Boolean
|
* - data (Uint8Array|Array|ArrayBuffer|String): input data
|
* - mode (Number|Boolean): 0..6 for corresponding Z_NO_FLUSH..Z_TREE modes.
|
* See constants. Skipped or `false` means Z_NO_FLUSH, `true` means Z_FINISH.
|
*
|
* Sends input data to inflate pipe, generating [[Inflate#onData]] calls with
|
* new output chunks. Returns `true` on success. The last data block must have
|
* mode Z_FINISH (or `true`). That will flush internal pending buffers and call
|
* [[Inflate#onEnd]]. For interim explicit flushes (without ending the stream) you
|
* can use mode Z_SYNC_FLUSH, keeping the decompression context.
|
*
|
* On fail call [[Inflate#onEnd]] with error code and return false.
|
*
|
* We strongly recommend to use `Uint8Array` on input for best speed (output
|
* format is detected automatically). Also, don't skip last param and always
|
* use the same type in your code (boolean or number). That will improve JS speed.
|
*
|
* For regular `Array`-s make sure all elements are [0..255].
|
*
|
* ##### Example
|
*
|
* ```javascript
|
* push(chunk, false); // push one of data chunks
|
* ...
|
* push(chunk, true); // push last chunk
|
* ```
|
**/
|
Inflate.prototype.push = function (data, mode) {
|
var strm = this.strm;
|
var chunkSize = this.options.chunkSize;
|
var dictionary = this.options.dictionary;
|
var status, _mode;
|
var next_out_utf8, tail, utf8str;
|
|
// Flag to properly process Z_BUF_ERROR on testing inflate call
|
// when we check that all output data was flushed.
|
var allowBufError = false;
|
|
if (this.ended) { return false; }
|
_mode = (mode === ~~mode) ? mode : ((mode === true) ? c.Z_FINISH : c.Z_NO_FLUSH);
|
|
// Convert data if needed
|
if (typeof data === 'string') {
|
// Only binary strings can be decompressed on practice
|
strm.input = strings.binstring2buf(data);
|
} else if (toString.call(data) === '[object ArrayBuffer]') {
|
strm.input = new Uint8Array(data);
|
} else {
|
strm.input = data;
|
}
|
|
strm.next_in = 0;
|
strm.avail_in = strm.input.length;
|
|
do {
|
if (strm.avail_out === 0) {
|
strm.output = new utils.Buf8(chunkSize);
|
strm.next_out = 0;
|
strm.avail_out = chunkSize;
|
}
|
|
status = zlib_inflate.inflate(strm, c.Z_NO_FLUSH); /* no bad return value */
|
|
if (status === c.Z_NEED_DICT && dictionary) {
|
status = zlib_inflate.inflateSetDictionary(this.strm, dictionary);
|
}
|
|
if (status === c.Z_BUF_ERROR && allowBufError === true) {
|
status = c.Z_OK;
|
allowBufError = false;
|
}
|
|
if (status !== c.Z_STREAM_END && status !== c.Z_OK) {
|
this.onEnd(status);
|
this.ended = true;
|
return false;
|
}
|
|
if (strm.next_out) {
|
if (strm.avail_out === 0 || status === c.Z_STREAM_END || (strm.avail_in === 0 && (_mode === c.Z_FINISH || _mode === c.Z_SYNC_FLUSH))) {
|
|
if (this.options.to === 'string') {
|
|
next_out_utf8 = strings.utf8border(strm.output, strm.next_out);
|
|
tail = strm.next_out - next_out_utf8;
|
utf8str = strings.buf2string(strm.output, next_out_utf8);
|
|
// move tail
|
strm.next_out = tail;
|
strm.avail_out = chunkSize - tail;
|
if (tail) { utils.arraySet(strm.output, strm.output, next_out_utf8, tail, 0); }
|
|
this.onData(utf8str);
|
|
} else {
|
this.onData(utils.shrinkBuf(strm.output, strm.next_out));
|
}
|
}
|
}
|
|
// When no more input data, we should check that internal inflate buffers
|
// are flushed. The only way to do it when avail_out = 0 - run one more
|
// inflate pass. But if output data not exists, inflate return Z_BUF_ERROR.
|
// Here we set flag to process this error properly.
|
//
|
// NOTE. Deflate does not return error in this case and does not needs such
|
// logic.
|
if (strm.avail_in === 0 && strm.avail_out === 0) {
|
allowBufError = true;
|
}
|
|
} while ((strm.avail_in > 0 || strm.avail_out === 0) && status !== c.Z_STREAM_END);
|
|
if (status === c.Z_STREAM_END) {
|
_mode = c.Z_FINISH;
|
}
|
|
// Finalize on the last chunk.
|
if (_mode === c.Z_FINISH) {
|
status = zlib_inflate.inflateEnd(this.strm);
|
this.onEnd(status);
|
this.ended = true;
|
return status === c.Z_OK;
|
}
|
|
// callback interim results if Z_SYNC_FLUSH.
|
if (_mode === c.Z_SYNC_FLUSH) {
|
this.onEnd(c.Z_OK);
|
strm.avail_out = 0;
|
return true;
|
}
|
|
return true;
|
};
|
|
|
/**
|
* Inflate#onData(chunk) -> Void
|
* - chunk (Uint8Array|Array|String): output data. Type of array depends
|
* on js engine support. When string output requested, each chunk
|
* will be string.
|
*
|
* By default, stores data blocks in `chunks[]` property and glue
|
* those in `onEnd`. Override this handler, if you need another behaviour.
|
**/
|
Inflate.prototype.onData = function (chunk) {
|
this.chunks.push(chunk);
|
};
|
|
|
/**
|
* Inflate#onEnd(status) -> Void
|
* - status (Number): inflate status. 0 (Z_OK) on success,
|
* other if not.
|
*
|
* Called either after you tell inflate that the input stream is
|
* complete (Z_FINISH) or should be flushed (Z_SYNC_FLUSH)
|
* or if an error happened. By default - join collected chunks,
|
* free memory and fill `results` / `err` properties.
|
**/
|
Inflate.prototype.onEnd = function (status) {
|
// On success - join
|
if (status === c.Z_OK) {
|
if (this.options.to === 'string') {
|
// Glue & convert here, until we teach pako to send
|
// utf8 aligned strings to onData
|
this.result = this.chunks.join('');
|
} else {
|
this.result = utils.flattenChunks(this.chunks);
|
}
|
}
|
this.chunks = [];
|
this.err = status;
|
this.msg = this.strm.msg;
|
};
|
|
|
/**
|
* inflate(data[, options]) -> Uint8Array|Array|String
|
* - data (Uint8Array|Array|String): input data to decompress.
|
* - options (Object): zlib inflate options.
|
*
|
* Decompress `data` with inflate/ungzip and `options`. Autodetect
|
* format via wrapper header by default. That's why we don't provide
|
* separate `ungzip` method.
|
*
|
* Supported options are:
|
*
|
* - windowBits
|
*
|
* [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced)
|
* for more information.
|
*
|
* Sugar (options):
|
*
|
* - `raw` (Boolean) - say that we work with raw stream, if you don't wish to specify
|
* negative windowBits implicitly.
|
* - `to` (String) - if equal to 'string', then result will be converted
|
* from utf8 to utf16 (javascript) string. When string output requested,
|
* chunk length can differ from `chunkSize`, depending on content.
|
*
|
*
|
* ##### Example:
|
*
|
* ```javascript
|
* var pako = require('pako')
|
* , input = pako.deflate([1,2,3,4,5,6,7,8,9])
|
* , output;
|
*
|
* try {
|
* output = pako.inflate(input);
|
* } catch (err)
|
* console.log(err);
|
* }
|
* ```
|
**/
|
function inflate(input, options) {
|
var inflator = new Inflate(options);
|
|
inflator.push(input, true);
|
|
// That will never happens, if you don't cheat with options :)
|
if (inflator.err) { throw inflator.msg || msg[inflator.err]; }
|
|
return inflator.result;
|
}
|
|
|
/**
|
* inflateRaw(data[, options]) -> Uint8Array|Array|String
|
* - data (Uint8Array|Array|String): input data to decompress.
|
* - options (Object): zlib inflate options.
|
*
|
* The same as [[inflate]], but creates raw data, without wrapper
|
* (header and adler32 crc).
|
**/
|
function inflateRaw(input, options) {
|
options = options || {};
|
options.raw = true;
|
return inflate(input, options);
|
}
|
|
|
/**
|
* ungzip(data[, options]) -> Uint8Array|Array|String
|
* - data (Uint8Array|Array|String): input data to decompress.
|
* - options (Object): zlib inflate options.
|
*
|
* Just shortcut to [[inflate]], because it autodetects format
|
* by header.content. Done for convenience.
|
**/
|
|
|
exports.Inflate = Inflate;
|
exports.inflate = inflate;
|
exports.inflateRaw = inflateRaw;
|
exports.ungzip = inflate;
|
|
},{"./utils/common":65,"./utils/strings":66,"./zlib/constants":68,"./zlib/gzheader":71,"./zlib/inflate":73,"./zlib/messages":75,"./zlib/zstream":77}],65:[function(require,module,exports){
|
'use strict';
|
|
|
var TYPED_OK = (typeof Uint8Array !== 'undefined') &&
|
(typeof Uint16Array !== 'undefined') &&
|
(typeof Int32Array !== 'undefined');
|
|
function _has(obj, key) {
|
return Object.prototype.hasOwnProperty.call(obj, key);
|
}
|
|
exports.assign = function (obj /*from1, from2, from3, ...*/) {
|
var sources = Array.prototype.slice.call(arguments, 1);
|
while (sources.length) {
|
var source = sources.shift();
|
if (!source) { continue; }
|
|
if (typeof source !== 'object') {
|
throw new TypeError(source + 'must be non-object');
|
}
|
|
for (var p in source) {
|
if (_has(source, p)) {
|
obj[p] = source[p];
|
}
|
}
|
}
|
|
return obj;
|
};
|
|
|
// reduce buffer size, avoiding mem copy
|
exports.shrinkBuf = function (buf, size) {
|
if (buf.length === size) { return buf; }
|
if (buf.subarray) { return buf.subarray(0, size); }
|
buf.length = size;
|
return buf;
|
};
|
|
|
var fnTyped = {
|
arraySet: function (dest, src, src_offs, len, dest_offs) {
|
if (src.subarray && dest.subarray) {
|
dest.set(src.subarray(src_offs, src_offs + len), dest_offs);
|
return;
|
}
|
// Fallback to ordinary array
|
for (var i = 0; i < len; i++) {
|
dest[dest_offs + i] = src[src_offs + i];
|
}
|
},
|
// Join array of chunks to single array.
|
flattenChunks: function (chunks) {
|
var i, l, len, pos, chunk, result;
|
|
// calculate data length
|
len = 0;
|
for (i = 0, l = chunks.length; i < l; i++) {
|
len += chunks[i].length;
|
}
|
|
// join chunks
|
result = new Uint8Array(len);
|
pos = 0;
|
for (i = 0, l = chunks.length; i < l; i++) {
|
chunk = chunks[i];
|
result.set(chunk, pos);
|
pos += chunk.length;
|
}
|
|
return result;
|
}
|
};
|
|
var fnUntyped = {
|
arraySet: function (dest, src, src_offs, len, dest_offs) {
|
for (var i = 0; i < len; i++) {
|
dest[dest_offs + i] = src[src_offs + i];
|
}
|
},
|
// Join array of chunks to single array.
|
flattenChunks: function (chunks) {
|
return [].concat.apply([], chunks);
|
}
|
};
|
|
|
// Enable/Disable typed arrays use, for testing
|
//
|
exports.setTyped = function (on) {
|
if (on) {
|
exports.Buf8 = Uint8Array;
|
exports.Buf16 = Uint16Array;
|
exports.Buf32 = Int32Array;
|
exports.assign(exports, fnTyped);
|
} else {
|
exports.Buf8 = Array;
|
exports.Buf16 = Array;
|
exports.Buf32 = Array;
|
exports.assign(exports, fnUntyped);
|
}
|
};
|
|
exports.setTyped(TYPED_OK);
|
|
},{}],66:[function(require,module,exports){
|
// String encode/decode helpers
|
'use strict';
|
|
|
var utils = require('./common');
|
|
|
// Quick check if we can use fast array to bin string conversion
|
//
|
// - apply(Array) can fail on Android 2.2
|
// - apply(Uint8Array) can fail on iOS 5.1 Safari
|
//
|
var STR_APPLY_OK = true;
|
var STR_APPLY_UIA_OK = true;
|
|
try { String.fromCharCode.apply(null, [ 0 ]); } catch (__) { STR_APPLY_OK = false; }
|
try { String.fromCharCode.apply(null, new Uint8Array(1)); } catch (__) { STR_APPLY_UIA_OK = false; }
|
|
|
// Table with utf8 lengths (calculated by first byte of sequence)
|
// Note, that 5 & 6-byte values and some 4-byte values can not be represented in JS,
|
// because max possible codepoint is 0x10ffff
|
var _utf8len = new utils.Buf8(256);
|
for (var q = 0; q < 256; q++) {
|
_utf8len[q] = (q >= 252 ? 6 : q >= 248 ? 5 : q >= 240 ? 4 : q >= 224 ? 3 : q >= 192 ? 2 : 1);
|
}
|
_utf8len[254] = _utf8len[254] = 1; // Invalid sequence start
|
|
|
// convert string to array (typed, when possible)
|
exports.string2buf = function (str) {
|
var buf, c, c2, m_pos, i, str_len = str.length, buf_len = 0;
|
|
// count binary size
|
for (m_pos = 0; m_pos < str_len; m_pos++) {
|
c = str.charCodeAt(m_pos);
|
if ((c & 0xfc00) === 0xd800 && (m_pos + 1 < str_len)) {
|
c2 = str.charCodeAt(m_pos + 1);
|
if ((c2 & 0xfc00) === 0xdc00) {
|
c = 0x10000 + ((c - 0xd800) << 10) + (c2 - 0xdc00);
|
m_pos++;
|
}
|
}
|
buf_len += c < 0x80 ? 1 : c < 0x800 ? 2 : c < 0x10000 ? 3 : 4;
|
}
|
|
// allocate buffer
|
buf = new utils.Buf8(buf_len);
|
|
// convert
|
for (i = 0, m_pos = 0; i < buf_len; m_pos++) {
|
c = str.charCodeAt(m_pos);
|
if ((c & 0xfc00) === 0xd800 && (m_pos + 1 < str_len)) {
|
c2 = str.charCodeAt(m_pos + 1);
|
if ((c2 & 0xfc00) === 0xdc00) {
|
c = 0x10000 + ((c - 0xd800) << 10) + (c2 - 0xdc00);
|
m_pos++;
|
}
|
}
|
if (c < 0x80) {
|
/* one byte */
|
buf[i++] = c;
|
} else if (c < 0x800) {
|
/* two bytes */
|
buf[i++] = 0xC0 | (c >>> 6);
|
buf[i++] = 0x80 | (c & 0x3f);
|
} else if (c < 0x10000) {
|
/* three bytes */
|
buf[i++] = 0xE0 | (c >>> 12);
|
buf[i++] = 0x80 | (c >>> 6 & 0x3f);
|
buf[i++] = 0x80 | (c & 0x3f);
|
} else {
|
/* four bytes */
|
buf[i++] = 0xf0 | (c >>> 18);
|
buf[i++] = 0x80 | (c >>> 12 & 0x3f);
|
buf[i++] = 0x80 | (c >>> 6 & 0x3f);
|
buf[i++] = 0x80 | (c & 0x3f);
|
}
|
}
|
|
return buf;
|
};
|
|
// Helper (used in 2 places)
|
function buf2binstring(buf, len) {
|
// On Chrome, the arguments in a function call that are allowed is `65534`.
|
// If the length of the buffer is smaller than that, we can use this optimization,
|
// otherwise we will take a slower path.
|
if (len < 65534) {
|
if ((buf.subarray && STR_APPLY_UIA_OK) || (!buf.subarray && STR_APPLY_OK)) {
|
return String.fromCharCode.apply(null, utils.shrinkBuf(buf, len));
|
}
|
}
|
|
var result = '';
|
for (var i = 0; i < len; i++) {
|
result += String.fromCharCode(buf[i]);
|
}
|
return result;
|
}
|
|
|
// Convert byte array to binary string
|
exports.buf2binstring = function (buf) {
|
return buf2binstring(buf, buf.length);
|
};
|
|
|
// Convert binary string (typed, when possible)
|
exports.binstring2buf = function (str) {
|
var buf = new utils.Buf8(str.length);
|
for (var i = 0, len = buf.length; i < len; i++) {
|
buf[i] = str.charCodeAt(i);
|
}
|
return buf;
|
};
|
|
|
// convert array to string
|
exports.buf2string = function (buf, max) {
|
var i, out, c, c_len;
|
var len = max || buf.length;
|
|
// Reserve max possible length (2 words per char)
|
// NB: by unknown reasons, Array is significantly faster for
|
// String.fromCharCode.apply than Uint16Array.
|
var utf16buf = new Array(len * 2);
|
|
for (out = 0, i = 0; i < len;) {
|
c = buf[i++];
|
// quick process ascii
|
if (c < 0x80) { utf16buf[out++] = c; continue; }
|
|
c_len = _utf8len[c];
|
// skip 5 & 6 byte codes
|
if (c_len > 4) { utf16buf[out++] = 0xfffd; i += c_len - 1; continue; }
|
|
// apply mask on first byte
|
c &= c_len === 2 ? 0x1f : c_len === 3 ? 0x0f : 0x07;
|
// join the rest
|
while (c_len > 1 && i < len) {
|
c = (c << 6) | (buf[i++] & 0x3f);
|
c_len--;
|
}
|
|
// terminated by end of string?
|
if (c_len > 1) { utf16buf[out++] = 0xfffd; continue; }
|
|
if (c < 0x10000) {
|
utf16buf[out++] = c;
|
} else {
|
c -= 0x10000;
|
utf16buf[out++] = 0xd800 | ((c >> 10) & 0x3ff);
|
utf16buf[out++] = 0xdc00 | (c & 0x3ff);
|
}
|
}
|
|
return buf2binstring(utf16buf, out);
|
};
|
|
|
// Calculate max possible position in utf8 buffer,
|
// that will not break sequence. If that's not possible
|
// - (very small limits) return max size as is.
|
//
|
// buf[] - utf8 bytes array
|
// max - length limit (mandatory);
|
exports.utf8border = function (buf, max) {
|
var pos;
|
|
max = max || buf.length;
|
if (max > buf.length) { max = buf.length; }
|
|
// go back from last position, until start of sequence found
|
pos = max - 1;
|
while (pos >= 0 && (buf[pos] & 0xC0) === 0x80) { pos--; }
|
|
// Very small and broken sequence,
|
// return max, because we should return something anyway.
|
if (pos < 0) { return max; }
|
|
// If we came to start of buffer - that means buffer is too small,
|
// return max too.
|
if (pos === 0) { return max; }
|
|
return (pos + _utf8len[buf[pos]] > max) ? pos : max;
|
};
|
|
},{"./common":65}],67:[function(require,module,exports){
|
'use strict';
|
|
// Note: adler32 takes 12% for level 0 and 2% for level 6.
|
// It isn't worth it to make additional optimizations as in original.
|
// Small size is preferable.
|
|
// (C) 1995-2013 Jean-loup Gailly and Mark Adler
|
// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
|
//
|
// This software is provided 'as-is', without any express or implied
|
// warranty. In no event will the authors be held liable for any damages
|
// arising from the use of this software.
|
//
|
// Permission is granted to anyone to use this software for any purpose,
|
// including commercial applications, and to alter it and redistribute it
|
// freely, subject to the following restrictions:
|
//
|
// 1. The origin of this software must not be misrepresented; you must not
|
// claim that you wrote the original software. If you use this software
|
// in a product, an acknowledgment in the product documentation would be
|
// appreciated but is not required.
|
// 2. Altered source versions must be plainly marked as such, and must not be
|
// misrepresented as being the original software.
|
// 3. This notice may not be removed or altered from any source distribution.
|
|
function adler32(adler, buf, len, pos) {
|
var s1 = (adler & 0xffff) |0,
|
s2 = ((adler >>> 16) & 0xffff) |0,
|
n = 0;
|
|
while (len !== 0) {
|
// Set limit ~ twice less than 5552, to keep
|
// s2 in 31-bits, because we force signed ints.
|
// in other case %= will fail.
|
n = len > 2000 ? 2000 : len;
|
len -= n;
|
|
do {
|
s1 = (s1 + buf[pos++]) |0;
|
s2 = (s2 + s1) |0;
|
} while (--n);
|
|
s1 %= 65521;
|
s2 %= 65521;
|
}
|
|
return (s1 | (s2 << 16)) |0;
|
}
|
|
|
module.exports = adler32;
|
|
},{}],68:[function(require,module,exports){
|
'use strict';
|
|
// (C) 1995-2013 Jean-loup Gailly and Mark Adler
|
// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
|
//
|
// This software is provided 'as-is', without any express or implied
|
// warranty. In no event will the authors be held liable for any damages
|
// arising from the use of this software.
|
//
|
// Permission is granted to anyone to use this software for any purpose,
|
// including commercial applications, and to alter it and redistribute it
|
// freely, subject to the following restrictions:
|
//
|
// 1. The origin of this software must not be misrepresented; you must not
|
// claim that you wrote the original software. If you use this software
|
// in a product, an acknowledgment in the product documentation would be
|
// appreciated but is not required.
|
// 2. Altered source versions must be plainly marked as such, and must not be
|
// misrepresented as being the original software.
|
// 3. This notice may not be removed or altered from any source distribution.
|
|
module.exports = {
|
|
/* Allowed flush values; see deflate() and inflate() below for details */
|
Z_NO_FLUSH: 0,
|
Z_PARTIAL_FLUSH: 1,
|
Z_SYNC_FLUSH: 2,
|
Z_FULL_FLUSH: 3,
|
Z_FINISH: 4,
|
Z_BLOCK: 5,
|
Z_TREES: 6,
|
|
/* Return codes for the compression/decompression functions. Negative values
|
* are errors, positive values are used for special but normal events.
|
*/
|
Z_OK: 0,
|
Z_STREAM_END: 1,
|
Z_NEED_DICT: 2,
|
Z_ERRNO: -1,
|
Z_STREAM_ERROR: -2,
|
Z_DATA_ERROR: -3,
|
//Z_MEM_ERROR: -4,
|
Z_BUF_ERROR: -5,
|
//Z_VERSION_ERROR: -6,
|
|
/* compression levels */
|
Z_NO_COMPRESSION: 0,
|
Z_BEST_SPEED: 1,
|
Z_BEST_COMPRESSION: 9,
|
Z_DEFAULT_COMPRESSION: -1,
|
|
|
Z_FILTERED: 1,
|
Z_HUFFMAN_ONLY: 2,
|
Z_RLE: 3,
|
Z_FIXED: 4,
|
Z_DEFAULT_STRATEGY: 0,
|
|
/* Possible values of the data_type field (though see inflate()) */
|
Z_BINARY: 0,
|
Z_TEXT: 1,
|
//Z_ASCII: 1, // = Z_TEXT (deprecated)
|
Z_UNKNOWN: 2,
|
|
/* The deflate compression method */
|
Z_DEFLATED: 8
|
//Z_NULL: null // Use -1 or null inline, depending on var type
|
};
|
|
},{}],69:[function(require,module,exports){
|
'use strict';
|
|
// Note: we can't get significant speed boost here.
|
// So write code to minimize size - no pregenerated tables
|
// and array tools dependencies.
|
|
// (C) 1995-2013 Jean-loup Gailly and Mark Adler
|
// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
|
//
|
// This software is provided 'as-is', without any express or implied
|
// warranty. In no event will the authors be held liable for any damages
|
// arising from the use of this software.
|
//
|
// Permission is granted to anyone to use this software for any purpose,
|
// including commercial applications, and to alter it and redistribute it
|
// freely, subject to the following restrictions:
|
//
|
// 1. The origin of this software must not be misrepresented; you must not
|
// claim that you wrote the original software. If you use this software
|
// in a product, an acknowledgment in the product documentation would be
|
// appreciated but is not required.
|
// 2. Altered source versions must be plainly marked as such, and must not be
|
// misrepresented as being the original software.
|
// 3. This notice may not be removed or altered from any source distribution.
|
|
// Use ordinary array, since untyped makes no boost here
|
function makeTable() {
|
var c, table = [];
|
|
for (var n = 0; n < 256; n++) {
|
c = n;
|
for (var k = 0; k < 8; k++) {
|
c = ((c & 1) ? (0xEDB88320 ^ (c >>> 1)) : (c >>> 1));
|
}
|
table[n] = c;
|
}
|
|
return table;
|
}
|
|
// Create table on load. Just 255 signed longs. Not a problem.
|
var crcTable = makeTable();
|
|
|
function crc32(crc, buf, len, pos) {
|
var t = crcTable,
|
end = pos + len;
|
|
crc ^= -1;
|
|
for (var i = pos; i < end; i++) {
|
crc = (crc >>> 8) ^ t[(crc ^ buf[i]) & 0xFF];
|
}
|
|
return (crc ^ (-1)); // >>> 0;
|
}
|
|
|
module.exports = crc32;
|
|
},{}],70:[function(require,module,exports){
|
'use strict';
|
|
// (C) 1995-2013 Jean-loup Gailly and Mark Adler
|
// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
|
//
|
// This software is provided 'as-is', without any express or implied
|
// warranty. In no event will the authors be held liable for any damages
|
// arising from the use of this software.
|
//
|
// Permission is granted to anyone to use this software for any purpose,
|
// including commercial applications, and to alter it and redistribute it
|
// freely, subject to the following restrictions:
|
//
|
// 1. The origin of this software must not be misrepresented; you must not
|
// claim that you wrote the original software. If you use this software
|
// in a product, an acknowledgment in the product documentation would be
|
// appreciated but is not required.
|
// 2. Altered source versions must be plainly marked as such, and must not be
|
// misrepresented as being the original software.
|
// 3. This notice may not be removed or altered from any source distribution.
|
|
var utils = require('../utils/common');
|
var trees = require('./trees');
|
var adler32 = require('./adler32');
|
var crc32 = require('./crc32');
|
var msg = require('./messages');
|
|
/* Public constants ==========================================================*/
|
/* ===========================================================================*/
|
|
|
/* Allowed flush values; see deflate() and inflate() below for details */
|
var Z_NO_FLUSH = 0;
|
var Z_PARTIAL_FLUSH = 1;
|
//var Z_SYNC_FLUSH = 2;
|
var Z_FULL_FLUSH = 3;
|
var Z_FINISH = 4;
|
var Z_BLOCK = 5;
|
//var Z_TREES = 6;
|
|
|
/* Return codes for the compression/decompression functions. Negative values
|
* are errors, positive values are used for special but normal events.
|
*/
|
var Z_OK = 0;
|
var Z_STREAM_END = 1;
|
//var Z_NEED_DICT = 2;
|
//var Z_ERRNO = -1;
|
var Z_STREAM_ERROR = -2;
|
var Z_DATA_ERROR = -3;
|
//var Z_MEM_ERROR = -4;
|
var Z_BUF_ERROR = -5;
|
//var Z_VERSION_ERROR = -6;
|
|
|
/* compression levels */
|
//var Z_NO_COMPRESSION = 0;
|
//var Z_BEST_SPEED = 1;
|
//var Z_BEST_COMPRESSION = 9;
|
var Z_DEFAULT_COMPRESSION = -1;
|
|
|
var Z_FILTERED = 1;
|
var Z_HUFFMAN_ONLY = 2;
|
var Z_RLE = 3;
|
var Z_FIXED = 4;
|
var Z_DEFAULT_STRATEGY = 0;
|
|
/* Possible values of the data_type field (though see inflate()) */
|
//var Z_BINARY = 0;
|
//var Z_TEXT = 1;
|
//var Z_ASCII = 1; // = Z_TEXT
|
var Z_UNKNOWN = 2;
|
|
|
/* The deflate compression method */
|
var Z_DEFLATED = 8;
|
|
/*============================================================================*/
|
|
|
var MAX_MEM_LEVEL = 9;
|
/* Maximum value for memLevel in deflateInit2 */
|
var MAX_WBITS = 15;
|
/* 32K LZ77 window */
|
var DEF_MEM_LEVEL = 8;
|
|
|
var LENGTH_CODES = 29;
|
/* number of length codes, not counting the special END_BLOCK code */
|
var LITERALS = 256;
|
/* number of literal bytes 0..255 */
|
var L_CODES = LITERALS + 1 + LENGTH_CODES;
|
/* number of Literal or Length codes, including the END_BLOCK code */
|
var D_CODES = 30;
|
/* number of distance codes */
|
var BL_CODES = 19;
|
/* number of codes used to transfer the bit lengths */
|
var HEAP_SIZE = 2 * L_CODES + 1;
|
/* maximum heap size */
|
var MAX_BITS = 15;
|
/* All codes must not exceed MAX_BITS bits */
|
|
var MIN_MATCH = 3;
|
var MAX_MATCH = 258;
|
var MIN_LOOKAHEAD = (MAX_MATCH + MIN_MATCH + 1);
|
|
var PRESET_DICT = 0x20;
|
|
var INIT_STATE = 42;
|
var EXTRA_STATE = 69;
|
var NAME_STATE = 73;
|
var COMMENT_STATE = 91;
|
var HCRC_STATE = 103;
|
var BUSY_STATE = 113;
|
var FINISH_STATE = 666;
|
|
var BS_NEED_MORE = 1; /* block not completed, need more input or more output */
|
var BS_BLOCK_DONE = 2; /* block flush performed */
|
var BS_FINISH_STARTED = 3; /* finish started, need only more output at next deflate */
|
var BS_FINISH_DONE = 4; /* finish done, accept no more input or output */
|
|
var OS_CODE = 0x03; // Unix :) . Don't detect, use this default.
|
|
function err(strm, errorCode) {
|
strm.msg = msg[errorCode];
|
return errorCode;
|
}
|
|
function rank(f) {
|
return ((f) << 1) - ((f) > 4 ? 9 : 0);
|
}
|
|
function zero(buf) { var len = buf.length; while (--len >= 0) { buf[len] = 0; } }
|
|
|
/* =========================================================================
|
* Flush as much pending output as possible. All deflate() output goes
|
* through this function so some applications may wish to modify it
|
* to avoid allocating a large strm->output buffer and copying into it.
|
* (See also read_buf()).
|
*/
|
function flush_pending(strm) {
|
var s = strm.state;
|
|
//_tr_flush_bits(s);
|
var len = s.pending;
|
if (len > strm.avail_out) {
|
len = strm.avail_out;
|
}
|
if (len === 0) { return; }
|
|
utils.arraySet(strm.output, s.pending_buf, s.pending_out, len, strm.next_out);
|
strm.next_out += len;
|
s.pending_out += len;
|
strm.total_out += len;
|
strm.avail_out -= len;
|
s.pending -= len;
|
if (s.pending === 0) {
|
s.pending_out = 0;
|
}
|
}
|
|
|
function flush_block_only(s, last) {
|
trees._tr_flush_block(s, (s.block_start >= 0 ? s.block_start : -1), s.strstart - s.block_start, last);
|
s.block_start = s.strstart;
|
flush_pending(s.strm);
|
}
|
|
|
function put_byte(s, b) {
|
s.pending_buf[s.pending++] = b;
|
}
|
|
|
/* =========================================================================
|
* Put a short in the pending buffer. The 16-bit value is put in MSB order.
|
* IN assertion: the stream state is correct and there is enough room in
|
* pending_buf.
|
*/
|
function putShortMSB(s, b) {
|
// put_byte(s, (Byte)(b >> 8));
|
// put_byte(s, (Byte)(b & 0xff));
|
s.pending_buf[s.pending++] = (b >>> 8) & 0xff;
|
s.pending_buf[s.pending++] = b & 0xff;
|
}
|
|
|
/* ===========================================================================
|
* Read a new buffer from the current input stream, update the adler32
|
* and total number of bytes read. All deflate() input goes through
|
* this function so some applications may wish to modify it to avoid
|
* allocating a large strm->input buffer and copying from it.
|
* (See also flush_pending()).
|
*/
|
function read_buf(strm, buf, start, size) {
|
var len = strm.avail_in;
|
|
if (len > size) { len = size; }
|
if (len === 0) { return 0; }
|
|
strm.avail_in -= len;
|
|
// zmemcpy(buf, strm->next_in, len);
|
utils.arraySet(buf, strm.input, strm.next_in, len, start);
|
if (strm.state.wrap === 1) {
|
strm.adler = adler32(strm.adler, buf, len, start);
|
}
|
|
else if (strm.state.wrap === 2) {
|
strm.adler = crc32(strm.adler, buf, len, start);
|
}
|
|
strm.next_in += len;
|
strm.total_in += len;
|
|
return len;
|
}
|
|
|
/* ===========================================================================
|
* Set match_start to the longest match starting at the given string and
|
* return its length. Matches shorter or equal to prev_length are discarded,
|
* in which case the result is equal to prev_length and match_start is
|
* garbage.
|
* IN assertions: cur_match is the head of the hash chain for the current
|
* string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
|
* OUT assertion: the match length is not greater than s->lookahead.
|
*/
|
function longest_match(s, cur_match) {
|
var chain_length = s.max_chain_length; /* max hash chain length */
|
var scan = s.strstart; /* current string */
|
var match; /* matched string */
|
var len; /* length of current match */
|
var best_len = s.prev_length; /* best match length so far */
|
var nice_match = s.nice_match; /* stop if match long enough */
|
var limit = (s.strstart > (s.w_size - MIN_LOOKAHEAD)) ?
|
s.strstart - (s.w_size - MIN_LOOKAHEAD) : 0/*NIL*/;
|
|
var _win = s.window; // shortcut
|
|
var wmask = s.w_mask;
|
var prev = s.prev;
|
|
/* Stop when cur_match becomes <= limit. To simplify the code,
|
* we prevent matches with the string of window index 0.
|
*/
|
|
var strend = s.strstart + MAX_MATCH;
|
var scan_end1 = _win[scan + best_len - 1];
|
var scan_end = _win[scan + best_len];
|
|
/* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
|
* It is easy to get rid of this optimization if necessary.
|
*/
|
// Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
|
|
/* Do not waste too much time if we already have a good match: */
|
if (s.prev_length >= s.good_match) {
|
chain_length >>= 2;
|
}
|
/* Do not look for matches beyond the end of the input. This is necessary
|
* to make deflate deterministic.
|
*/
|
if (nice_match > s.lookahead) { nice_match = s.lookahead; }
|
|
// Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
|
|
do {
|
// Assert(cur_match < s->strstart, "no future");
|
match = cur_match;
|
|
/* Skip to next match if the match length cannot increase
|
* or if the match length is less than 2. Note that the checks below
|
* for insufficient lookahead only occur occasionally for performance
|
* reasons. Therefore uninitialized memory will be accessed, and
|
* conditional jumps will be made that depend on those values.
|
* However the length of the match is limited to the lookahead, so
|
* the output of deflate is not affected by the uninitialized values.
|
*/
|
|
if (_win[match + best_len] !== scan_end ||
|
_win[match + best_len - 1] !== scan_end1 ||
|
_win[match] !== _win[scan] ||
|
_win[++match] !== _win[scan + 1]) {
|
continue;
|
}
|
|
/* The check at best_len-1 can be removed because it will be made
|
* again later. (This heuristic is not always a win.)
|
* It is not necessary to compare scan[2] and match[2] since they
|
* are always equal when the other bytes match, given that
|
* the hash keys are equal and that HASH_BITS >= 8.
|
*/
|
scan += 2;
|
match++;
|
// Assert(*scan == *match, "match[2]?");
|
|
/* We check for insufficient lookahead only every 8th comparison;
|
* the 256th check will be made at strstart+258.
|
*/
|
do {
|
/*jshint noempty:false*/
|
} while (_win[++scan] === _win[++match] && _win[++scan] === _win[++match] &&
|
_win[++scan] === _win[++match] && _win[++scan] === _win[++match] &&
|
_win[++scan] === _win[++match] && _win[++scan] === _win[++match] &&
|
_win[++scan] === _win[++match] && _win[++scan] === _win[++match] &&
|
scan < strend);
|
|
// Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
|
|
len = MAX_MATCH - (strend - scan);
|
scan = strend - MAX_MATCH;
|
|
if (len > best_len) {
|
s.match_start = cur_match;
|
best_len = len;
|
if (len >= nice_match) {
|
break;
|
}
|
scan_end1 = _win[scan + best_len - 1];
|
scan_end = _win[scan + best_len];
|
}
|
} while ((cur_match = prev[cur_match & wmask]) > limit && --chain_length !== 0);
|
|
if (best_len <= s.lookahead) {
|
return best_len;
|
}
|
return s.lookahead;
|
}
|
|
|
/* ===========================================================================
|
* Fill the window when the lookahead becomes insufficient.
|
* Updates strstart and lookahead.
|
*
|
* IN assertion: lookahead < MIN_LOOKAHEAD
|
* OUT assertions: strstart <= window_size-MIN_LOOKAHEAD
|
* At least one byte has been read, or avail_in == 0; reads are
|
* performed for at least two bytes (required for the zip translate_eol
|
* option -- not supported here).
|
*/
|
function fill_window(s) {
|
var _w_size = s.w_size;
|
var p, n, m, more, str;
|
|
//Assert(s->lookahead < MIN_LOOKAHEAD, "already enough lookahead");
|
|
do {
|
more = s.window_size - s.lookahead - s.strstart;
|
|
// JS ints have 32 bit, block below not needed
|
/* Deal with !@#$% 64K limit: */
|
//if (sizeof(int) <= 2) {
|
// if (more == 0 && s->strstart == 0 && s->lookahead == 0) {
|
// more = wsize;
|
//
|
// } else if (more == (unsigned)(-1)) {
|
// /* Very unlikely, but possible on 16 bit machine if
|
// * strstart == 0 && lookahead == 1 (input done a byte at time)
|
// */
|
// more--;
|
// }
|
//}
|
|
|
/* If the window is almost full and there is insufficient lookahead,
|
* move the upper half to the lower one to make room in the upper half.
|
*/
|
if (s.strstart >= _w_size + (_w_size - MIN_LOOKAHEAD)) {
|
|
utils.arraySet(s.window, s.window, _w_size, _w_size, 0);
|
s.match_start -= _w_size;
|
s.strstart -= _w_size;
|
/* we now have strstart >= MAX_DIST */
|
s.block_start -= _w_size;
|
|
/* Slide the hash table (could be avoided with 32 bit values
|
at the expense of memory usage). We slide even when level == 0
|
to keep the hash table consistent if we switch back to level > 0
|
later. (Using level 0 permanently is not an optimal usage of
|
zlib, so we don't care about this pathological case.)
|
*/
|
|
n = s.hash_size;
|
p = n;
|
do {
|
m = s.head[--p];
|
s.head[p] = (m >= _w_size ? m - _w_size : 0);
|
} while (--n);
|
|
n = _w_size;
|
p = n;
|
do {
|
m = s.prev[--p];
|
s.prev[p] = (m >= _w_size ? m - _w_size : 0);
|
/* If n is not on any hash chain, prev[n] is garbage but
|
* its value will never be used.
|
*/
|
} while (--n);
|
|
more += _w_size;
|
}
|
if (s.strm.avail_in === 0) {
|
break;
|
}
|
|
/* If there was no sliding:
|
* strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&
|
* more == window_size - lookahead - strstart
|
* => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)
|
* => more >= window_size - 2*WSIZE + 2
|
* In the BIG_MEM or MMAP case (not yet supported),
|
* window_size == input_size + MIN_LOOKAHEAD &&
|
* strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD.
|
* Otherwise, window_size == 2*WSIZE so more >= 2.
|
* If there was sliding, more >= WSIZE. So in all cases, more >= 2.
|
*/
|
//Assert(more >= 2, "more < 2");
|
n = read_buf(s.strm, s.window, s.strstart + s.lookahead, more);
|
s.lookahead += n;
|
|
/* Initialize the hash value now that we have some input: */
|
if (s.lookahead + s.insert >= MIN_MATCH) {
|
str = s.strstart - s.insert;
|
s.ins_h = s.window[str];
|
|
/* UPDATE_HASH(s, s->ins_h, s->window[str + 1]); */
|
s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[str + 1]) & s.hash_mask;
|
//#if MIN_MATCH != 3
|
// Call update_hash() MIN_MATCH-3 more times
|
//#endif
|
while (s.insert) {
|
/* UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); */
|
s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[str + MIN_MATCH - 1]) & s.hash_mask;
|
|
s.prev[str & s.w_mask] = s.head[s.ins_h];
|
s.head[s.ins_h] = str;
|
str++;
|
s.insert--;
|
if (s.lookahead + s.insert < MIN_MATCH) {
|
break;
|
}
|
}
|
}
|
/* If the whole input has less than MIN_MATCH bytes, ins_h is garbage,
|
* but this is not important since only literal bytes will be emitted.
|
*/
|
|
} while (s.lookahead < MIN_LOOKAHEAD && s.strm.avail_in !== 0);
|
|
/* If the WIN_INIT bytes after the end of the current data have never been
|
* written, then zero those bytes in order to avoid memory check reports of
|
* the use of uninitialized (or uninitialised as Julian writes) bytes by
|
* the longest match routines. Update the high water mark for the next
|
* time through here. WIN_INIT is set to MAX_MATCH since the longest match
|
* routines allow scanning to strstart + MAX_MATCH, ignoring lookahead.
|
*/
|
// if (s.high_water < s.window_size) {
|
// var curr = s.strstart + s.lookahead;
|
// var init = 0;
|
//
|
// if (s.high_water < curr) {
|
// /* Previous high water mark below current data -- zero WIN_INIT
|
// * bytes or up to end of window, whichever is less.
|
// */
|
// init = s.window_size - curr;
|
// if (init > WIN_INIT)
|
// init = WIN_INIT;
|
// zmemzero(s->window + curr, (unsigned)init);
|
// s->high_water = curr + init;
|
// }
|
// else if (s->high_water < (ulg)curr + WIN_INIT) {
|
// /* High water mark at or above current data, but below current data
|
// * plus WIN_INIT -- zero out to current data plus WIN_INIT, or up
|
// * to end of window, whichever is less.
|
// */
|
// init = (ulg)curr + WIN_INIT - s->high_water;
|
// if (init > s->window_size - s->high_water)
|
// init = s->window_size - s->high_water;
|
// zmemzero(s->window + s->high_water, (unsigned)init);
|
// s->high_water += init;
|
// }
|
// }
|
//
|
// Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD,
|
// "not enough room for search");
|
}
|
|
/* ===========================================================================
|
* Copy without compression as much as possible from the input stream, return
|
* the current block state.
|
* This function does not insert new strings in the dictionary since
|
* uncompressible data is probably not useful. This function is used
|
* only for the level=0 compression option.
|
* NOTE: this function should be optimized to avoid extra copying from
|
* window to pending_buf.
|
*/
|
function deflate_stored(s, flush) {
|
/* Stored blocks are limited to 0xffff bytes, pending_buf is limited
|
* to pending_buf_size, and each stored block has a 5 byte header:
|
*/
|
var max_block_size = 0xffff;
|
|
if (max_block_size > s.pending_buf_size - 5) {
|
max_block_size = s.pending_buf_size - 5;
|
}
|
|
/* Copy as much as possible from input to output: */
|
for (;;) {
|
/* Fill the window as much as possible: */
|
if (s.lookahead <= 1) {
|
|
//Assert(s->strstart < s->w_size+MAX_DIST(s) ||
|
// s->block_start >= (long)s->w_size, "slide too late");
|
// if (!(s.strstart < s.w_size + (s.w_size - MIN_LOOKAHEAD) ||
|
// s.block_start >= s.w_size)) {
|
// throw new Error("slide too late");
|
// }
|
|
fill_window(s);
|
if (s.lookahead === 0 && flush === Z_NO_FLUSH) {
|
return BS_NEED_MORE;
|
}
|
|
if (s.lookahead === 0) {
|
break;
|
}
|
/* flush the current block */
|
}
|
//Assert(s->block_start >= 0L, "block gone");
|
// if (s.block_start < 0) throw new Error("block gone");
|
|
s.strstart += s.lookahead;
|
s.lookahead = 0;
|
|
/* Emit a stored block if pending_buf will be full: */
|
var max_start = s.block_start + max_block_size;
|
|
if (s.strstart === 0 || s.strstart >= max_start) {
|
/* strstart == 0 is possible when wraparound on 16-bit machine */
|
s.lookahead = s.strstart - max_start;
|
s.strstart = max_start;
|
/*** FLUSH_BLOCK(s, 0); ***/
|
flush_block_only(s, false);
|
if (s.strm.avail_out === 0) {
|
return BS_NEED_MORE;
|
}
|
/***/
|
|
|
}
|
/* Flush if we may have to slide, otherwise block_start may become
|
* negative and the data will be gone:
|
*/
|
if (s.strstart - s.block_start >= (s.w_size - MIN_LOOKAHEAD)) {
|
/*** FLUSH_BLOCK(s, 0); ***/
|
flush_block_only(s, false);
|
if (s.strm.avail_out === 0) {
|
return BS_NEED_MORE;
|
}
|
/***/
|
}
|
}
|
|
s.insert = 0;
|
|
if (flush === Z_FINISH) {
|
/*** FLUSH_BLOCK(s, 1); ***/
|
flush_block_only(s, true);
|
if (s.strm.avail_out === 0) {
|
return BS_FINISH_STARTED;
|
}
|
/***/
|
return BS_FINISH_DONE;
|
}
|
|
if (s.strstart > s.block_start) {
|
/*** FLUSH_BLOCK(s, 0); ***/
|
flush_block_only(s, false);
|
if (s.strm.avail_out === 0) {
|
return BS_NEED_MORE;
|
}
|
/***/
|
}
|
|
return BS_NEED_MORE;
|
}
|
|
/* ===========================================================================
|
* Compress as much as possible from the input stream, return the current
|
* block state.
|
* This function does not perform lazy evaluation of matches and inserts
|
* new strings in the dictionary only for unmatched strings or for short
|
* matches. It is used only for the fast compression options.
|
*/
|
function deflate_fast(s, flush) {
|
var hash_head; /* head of the hash chain */
|
var bflush; /* set if current block must be flushed */
|
|
for (;;) {
|
/* Make sure that we always have enough lookahead, except
|
* at the end of the input file. We need MAX_MATCH bytes
|
* for the next match, plus MIN_MATCH bytes to insert the
|
* string following the next match.
|
*/
|
if (s.lookahead < MIN_LOOKAHEAD) {
|
fill_window(s);
|
if (s.lookahead < MIN_LOOKAHEAD && flush === Z_NO_FLUSH) {
|
return BS_NEED_MORE;
|
}
|
if (s.lookahead === 0) {
|
break; /* flush the current block */
|
}
|
}
|
|
/* Insert the string window[strstart .. strstart+2] in the
|
* dictionary, and set hash_head to the head of the hash chain:
|
*/
|
hash_head = 0/*NIL*/;
|
if (s.lookahead >= MIN_MATCH) {
|
/*** INSERT_STRING(s, s.strstart, hash_head); ***/
|
s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask;
|
hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h];
|
s.head[s.ins_h] = s.strstart;
|
/***/
|
}
|
|
/* Find the longest match, discarding those <= prev_length.
|
* At this point we have always match_length < MIN_MATCH
|
*/
|
if (hash_head !== 0/*NIL*/ && ((s.strstart - hash_head) <= (s.w_size - MIN_LOOKAHEAD))) {
|
/* To simplify the code, we prevent matches with the string
|
* of window index 0 (in particular we have to avoid a match
|
* of the string with itself at the start of the input file).
|
*/
|
s.match_length = longest_match(s, hash_head);
|
/* longest_match() sets match_start */
|
}
|
if (s.match_length >= MIN_MATCH) {
|
// check_match(s, s.strstart, s.match_start, s.match_length); // for debug only
|
|
/*** _tr_tally_dist(s, s.strstart - s.match_start,
|
s.match_length - MIN_MATCH, bflush); ***/
|
bflush = trees._tr_tally(s, s.strstart - s.match_start, s.match_length - MIN_MATCH);
|
|
s.lookahead -= s.match_length;
|
|
/* Insert new strings in the hash table only if the match length
|
* is not too large. This saves time but degrades compression.
|
*/
|
if (s.match_length <= s.max_lazy_match/*max_insert_length*/ && s.lookahead >= MIN_MATCH) {
|
s.match_length--; /* string at strstart already in table */
|
do {
|
s.strstart++;
|
/*** INSERT_STRING(s, s.strstart, hash_head); ***/
|
s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask;
|
hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h];
|
s.head[s.ins_h] = s.strstart;
|
/***/
|
/* strstart never exceeds WSIZE-MAX_MATCH, so there are
|
* always MIN_MATCH bytes ahead.
|
*/
|
} while (--s.match_length !== 0);
|
s.strstart++;
|
} else
|
{
|
s.strstart += s.match_length;
|
s.match_length = 0;
|
s.ins_h = s.window[s.strstart];
|
/* UPDATE_HASH(s, s.ins_h, s.window[s.strstart+1]); */
|
s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + 1]) & s.hash_mask;
|
|
//#if MIN_MATCH != 3
|
// Call UPDATE_HASH() MIN_MATCH-3 more times
|
//#endif
|
/* If lookahead < MIN_MATCH, ins_h is garbage, but it does not
|
* matter since it will be recomputed at next deflate call.
|
*/
|
}
|
} else {
|
/* No match, output a literal byte */
|
//Tracevv((stderr,"%c", s.window[s.strstart]));
|
/*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/
|
bflush = trees._tr_tally(s, 0, s.window[s.strstart]);
|
|
s.lookahead--;
|
s.strstart++;
|
}
|
if (bflush) {
|
/*** FLUSH_BLOCK(s, 0); ***/
|
flush_block_only(s, false);
|
if (s.strm.avail_out === 0) {
|
return BS_NEED_MORE;
|
}
|
/***/
|
}
|
}
|
s.insert = ((s.strstart < (MIN_MATCH - 1)) ? s.strstart : MIN_MATCH - 1);
|
if (flush === Z_FINISH) {
|
/*** FLUSH_BLOCK(s, 1); ***/
|
flush_block_only(s, true);
|
if (s.strm.avail_out === 0) {
|
return BS_FINISH_STARTED;
|
}
|
/***/
|
return BS_FINISH_DONE;
|
}
|
if (s.last_lit) {
|
/*** FLUSH_BLOCK(s, 0); ***/
|
flush_block_only(s, false);
|
if (s.strm.avail_out === 0) {
|
return BS_NEED_MORE;
|
}
|
/***/
|
}
|
return BS_BLOCK_DONE;
|
}
|
|
/* ===========================================================================
|
* Same as above, but achieves better compression. We use a lazy
|
* evaluation for matches: a match is finally adopted only if there is
|
* no better match at the next window position.
|
*/
|
function deflate_slow(s, flush) {
|
var hash_head; /* head of hash chain */
|
var bflush; /* set if current block must be flushed */
|
|
var max_insert;
|
|
/* Process the input block. */
|
for (;;) {
|
/* Make sure that we always have enough lookahead, except
|
* at the end of the input file. We need MAX_MATCH bytes
|
* for the next match, plus MIN_MATCH bytes to insert the
|
* string following the next match.
|
*/
|
if (s.lookahead < MIN_LOOKAHEAD) {
|
fill_window(s);
|
if (s.lookahead < MIN_LOOKAHEAD && flush === Z_NO_FLUSH) {
|
return BS_NEED_MORE;
|
}
|
if (s.lookahead === 0) { break; } /* flush the current block */
|
}
|
|
/* Insert the string window[strstart .. strstart+2] in the
|
* dictionary, and set hash_head to the head of the hash chain:
|
*/
|
hash_head = 0/*NIL*/;
|
if (s.lookahead >= MIN_MATCH) {
|
/*** INSERT_STRING(s, s.strstart, hash_head); ***/
|
s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask;
|
hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h];
|
s.head[s.ins_h] = s.strstart;
|
/***/
|
}
|
|
/* Find the longest match, discarding those <= prev_length.
|
*/
|
s.prev_length = s.match_length;
|
s.prev_match = s.match_start;
|
s.match_length = MIN_MATCH - 1;
|
|
if (hash_head !== 0/*NIL*/ && s.prev_length < s.max_lazy_match &&
|
s.strstart - hash_head <= (s.w_size - MIN_LOOKAHEAD)/*MAX_DIST(s)*/) {
|
/* To simplify the code, we prevent matches with the string
|
* of window index 0 (in particular we have to avoid a match
|
* of the string with itself at the start of the input file).
|
*/
|
s.match_length = longest_match(s, hash_head);
|
/* longest_match() sets match_start */
|
|
if (s.match_length <= 5 &&
|
(s.strategy === Z_FILTERED || (s.match_length === MIN_MATCH && s.strstart - s.match_start > 4096/*TOO_FAR*/))) {
|
|
/* If prev_match is also MIN_MATCH, match_start is garbage
|
* but we will ignore the current match anyway.
|
*/
|
s.match_length = MIN_MATCH - 1;
|
}
|
}
|
/* If there was a match at the previous step and the current
|
* match is not better, output the previous match:
|
*/
|
if (s.prev_length >= MIN_MATCH && s.match_length <= s.prev_length) {
|
max_insert = s.strstart + s.lookahead - MIN_MATCH;
|
/* Do not insert strings in hash table beyond this. */
|
|
//check_match(s, s.strstart-1, s.prev_match, s.prev_length);
|
|
/***_tr_tally_dist(s, s.strstart - 1 - s.prev_match,
|
s.prev_length - MIN_MATCH, bflush);***/
|
bflush = trees._tr_tally(s, s.strstart - 1 - s.prev_match, s.prev_length - MIN_MATCH);
|
/* Insert in hash table all strings up to the end of the match.
|
* strstart-1 and strstart are already inserted. If there is not
|
* enough lookahead, the last two strings are not inserted in
|
* the hash table.
|
*/
|
s.lookahead -= s.prev_length - 1;
|
s.prev_length -= 2;
|
do {
|
if (++s.strstart <= max_insert) {
|
/*** INSERT_STRING(s, s.strstart, hash_head); ***/
|
s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask;
|
hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h];
|
s.head[s.ins_h] = s.strstart;
|
/***/
|
}
|
} while (--s.prev_length !== 0);
|
s.match_available = 0;
|
s.match_length = MIN_MATCH - 1;
|
s.strstart++;
|
|
if (bflush) {
|
/*** FLUSH_BLOCK(s, 0); ***/
|
flush_block_only(s, false);
|
if (s.strm.avail_out === 0) {
|
return BS_NEED_MORE;
|
}
|
/***/
|
}
|
|
} else if (s.match_available) {
|
/* If there was no match at the previous position, output a
|
* single literal. If there was a match but the current match
|
* is longer, truncate the previous match to a single literal.
|
*/
|
//Tracevv((stderr,"%c", s->window[s->strstart-1]));
|
/*** _tr_tally_lit(s, s.window[s.strstart-1], bflush); ***/
|
bflush = trees._tr_tally(s, 0, s.window[s.strstart - 1]);
|
|
if (bflush) {
|
/*** FLUSH_BLOCK_ONLY(s, 0) ***/
|
flush_block_only(s, false);
|
/***/
|
}
|
s.strstart++;
|
s.lookahead--;
|
if (s.strm.avail_out === 0) {
|
return BS_NEED_MORE;
|
}
|
} else {
|
/* There is no previous match to compare with, wait for
|
* the next step to decide.
|
*/
|
s.match_available = 1;
|
s.strstart++;
|
s.lookahead--;
|
}
|
}
|
//Assert (flush != Z_NO_FLUSH, "no flush?");
|
if (s.match_available) {
|
//Tracevv((stderr,"%c", s->window[s->strstart-1]));
|
/*** _tr_tally_lit(s, s.window[s.strstart-1], bflush); ***/
|
bflush = trees._tr_tally(s, 0, s.window[s.strstart - 1]);
|
|
s.match_available = 0;
|
}
|
s.insert = s.strstart < MIN_MATCH - 1 ? s.strstart : MIN_MATCH - 1;
|
if (flush === Z_FINISH) {
|
/*** FLUSH_BLOCK(s, 1); ***/
|
flush_block_only(s, true);
|
if (s.strm.avail_out === 0) {
|
return BS_FINISH_STARTED;
|
}
|
/***/
|
return BS_FINISH_DONE;
|
}
|
if (s.last_lit) {
|
/*** FLUSH_BLOCK(s, 0); ***/
|
flush_block_only(s, false);
|
if (s.strm.avail_out === 0) {
|
return BS_NEED_MORE;
|
}
|
/***/
|
}
|
|
return BS_BLOCK_DONE;
|
}
|
|
|
/* ===========================================================================
|
* For Z_RLE, simply look for runs of bytes, generate matches only of distance
|
* one. Do not maintain a hash table. (It will be regenerated if this run of
|
* deflate switches away from Z_RLE.)
|
*/
|
function deflate_rle(s, flush) {
|
var bflush; /* set if current block must be flushed */
|
var prev; /* byte at distance one to match */
|
var scan, strend; /* scan goes up to strend for length of run */
|
|
var _win = s.window;
|
|
for (;;) {
|
/* Make sure that we always have enough lookahead, except
|
* at the end of the input file. We need MAX_MATCH bytes
|
* for the longest run, plus one for the unrolled loop.
|
*/
|
if (s.lookahead <= MAX_MATCH) {
|
fill_window(s);
|
if (s.lookahead <= MAX_MATCH && flush === Z_NO_FLUSH) {
|
return BS_NEED_MORE;
|
}
|
if (s.lookahead === 0) { break; } /* flush the current block */
|
}
|
|
/* See how many times the previous byte repeats */
|
s.match_length = 0;
|
if (s.lookahead >= MIN_MATCH && s.strstart > 0) {
|
scan = s.strstart - 1;
|
prev = _win[scan];
|
if (prev === _win[++scan] && prev === _win[++scan] && prev === _win[++scan]) {
|
strend = s.strstart + MAX_MATCH;
|
do {
|
/*jshint noempty:false*/
|
} while (prev === _win[++scan] && prev === _win[++scan] &&
|
prev === _win[++scan] && prev === _win[++scan] &&
|
prev === _win[++scan] && prev === _win[++scan] &&
|
prev === _win[++scan] && prev === _win[++scan] &&
|
scan < strend);
|
s.match_length = MAX_MATCH - (strend - scan);
|
if (s.match_length > s.lookahead) {
|
s.match_length = s.lookahead;
|
}
|
}
|
//Assert(scan <= s->window+(uInt)(s->window_size-1), "wild scan");
|
}
|
|
/* Emit match if have run of MIN_MATCH or longer, else emit literal */
|
if (s.match_length >= MIN_MATCH) {
|
//check_match(s, s.strstart, s.strstart - 1, s.match_length);
|
|
/*** _tr_tally_dist(s, 1, s.match_length - MIN_MATCH, bflush); ***/
|
bflush = trees._tr_tally(s, 1, s.match_length - MIN_MATCH);
|
|
s.lookahead -= s.match_length;
|
s.strstart += s.match_length;
|
s.match_length = 0;
|
} else {
|
/* No match, output a literal byte */
|
//Tracevv((stderr,"%c", s->window[s->strstart]));
|
/*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/
|
bflush = trees._tr_tally(s, 0, s.window[s.strstart]);
|
|
s.lookahead--;
|
s.strstart++;
|
}
|
if (bflush) {
|
/*** FLUSH_BLOCK(s, 0); ***/
|
flush_block_only(s, false);
|
if (s.strm.avail_out === 0) {
|
return BS_NEED_MORE;
|
}
|
/***/
|
}
|
}
|
s.insert = 0;
|
if (flush === Z_FINISH) {
|
/*** FLUSH_BLOCK(s, 1); ***/
|
flush_block_only(s, true);
|
if (s.strm.avail_out === 0) {
|
return BS_FINISH_STARTED;
|
}
|
/***/
|
return BS_FINISH_DONE;
|
}
|
if (s.last_lit) {
|
/*** FLUSH_BLOCK(s, 0); ***/
|
flush_block_only(s, false);
|
if (s.strm.avail_out === 0) {
|
return BS_NEED_MORE;
|
}
|
/***/
|
}
|
return BS_BLOCK_DONE;
|
}
|
|
/* ===========================================================================
|
* For Z_HUFFMAN_ONLY, do not look for matches. Do not maintain a hash table.
|
* (It will be regenerated if this run of deflate switches away from Huffman.)
|
*/
|
function deflate_huff(s, flush) {
|
var bflush; /* set if current block must be flushed */
|
|
for (;;) {
|
/* Make sure that we have a literal to write. */
|
if (s.lookahead === 0) {
|
fill_window(s);
|
if (s.lookahead === 0) {
|
if (flush === Z_NO_FLUSH) {
|
return BS_NEED_MORE;
|
}
|
break; /* flush the current block */
|
}
|
}
|
|
/* Output a literal byte */
|
s.match_length = 0;
|
//Tracevv((stderr,"%c", s->window[s->strstart]));
|
/*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/
|
bflush = trees._tr_tally(s, 0, s.window[s.strstart]);
|
s.lookahead--;
|
s.strstart++;
|
if (bflush) {
|
/*** FLUSH_BLOCK(s, 0); ***/
|
flush_block_only(s, false);
|
if (s.strm.avail_out === 0) {
|
return BS_NEED_MORE;
|
}
|
/***/
|
}
|
}
|
s.insert = 0;
|
if (flush === Z_FINISH) {
|
/*** FLUSH_BLOCK(s, 1); ***/
|
flush_block_only(s, true);
|
if (s.strm.avail_out === 0) {
|
return BS_FINISH_STARTED;
|
}
|
/***/
|
return BS_FINISH_DONE;
|
}
|
if (s.last_lit) {
|
/*** FLUSH_BLOCK(s, 0); ***/
|
flush_block_only(s, false);
|
if (s.strm.avail_out === 0) {
|
return BS_NEED_MORE;
|
}
|
/***/
|
}
|
return BS_BLOCK_DONE;
|
}
|
|
/* Values for max_lazy_match, good_match and max_chain_length, depending on
|
* the desired pack level (0..9). The values given below have been tuned to
|
* exclude worst case performance for pathological files. Better values may be
|
* found for specific files.
|
*/
|
function Config(good_length, max_lazy, nice_length, max_chain, func) {
|
this.good_length = good_length;
|
this.max_lazy = max_lazy;
|
this.nice_length = nice_length;
|
this.max_chain = max_chain;
|
this.func = func;
|
}
|
|
var configuration_table;
|
|
configuration_table = [
|
/* good lazy nice chain */
|
new Config(0, 0, 0, 0, deflate_stored), /* 0 store only */
|
new Config(4, 4, 8, 4, deflate_fast), /* 1 max speed, no lazy matches */
|
new Config(4, 5, 16, 8, deflate_fast), /* 2 */
|
new Config(4, 6, 32, 32, deflate_fast), /* 3 */
|
|
new Config(4, 4, 16, 16, deflate_slow), /* 4 lazy matches */
|
new Config(8, 16, 32, 32, deflate_slow), /* 5 */
|
new Config(8, 16, 128, 128, deflate_slow), /* 6 */
|
new Config(8, 32, 128, 256, deflate_slow), /* 7 */
|
new Config(32, 128, 258, 1024, deflate_slow), /* 8 */
|
new Config(32, 258, 258, 4096, deflate_slow) /* 9 max compression */
|
];
|
|
|
/* ===========================================================================
|
* Initialize the "longest match" routines for a new zlib stream
|
*/
|
function lm_init(s) {
|
s.window_size = 2 * s.w_size;
|
|
/*** CLEAR_HASH(s); ***/
|
zero(s.head); // Fill with NIL (= 0);
|
|
/* Set the default configuration parameters:
|
*/
|
s.max_lazy_match = configuration_table[s.level].max_lazy;
|
s.good_match = configuration_table[s.level].good_length;
|
s.nice_match = configuration_table[s.level].nice_length;
|
s.max_chain_length = configuration_table[s.level].max_chain;
|
|
s.strstart = 0;
|
s.block_start = 0;
|
s.lookahead = 0;
|
s.insert = 0;
|
s.match_length = s.prev_length = MIN_MATCH - 1;
|
s.match_available = 0;
|
s.ins_h = 0;
|
}
|
|
|
function DeflateState() {
|
this.strm = null; /* pointer back to this zlib stream */
|
this.status = 0; /* as the name implies */
|
this.pending_buf = null; /* output still pending */
|
this.pending_buf_size = 0; /* size of pending_buf */
|
this.pending_out = 0; /* next pending byte to output to the stream */
|
this.pending = 0; /* nb of bytes in the pending buffer */
|
this.wrap = 0; /* bit 0 true for zlib, bit 1 true for gzip */
|
this.gzhead = null; /* gzip header information to write */
|
this.gzindex = 0; /* where in extra, name, or comment */
|
this.method = Z_DEFLATED; /* can only be DEFLATED */
|
this.last_flush = -1; /* value of flush param for previous deflate call */
|
|
this.w_size = 0; /* LZ77 window size (32K by default) */
|
this.w_bits = 0; /* log2(w_size) (8..16) */
|
this.w_mask = 0; /* w_size - 1 */
|
|
this.window = null;
|
/* Sliding window. Input bytes are read into the second half of the window,
|
* and move to the first half later to keep a dictionary of at least wSize
|
* bytes. With this organization, matches are limited to a distance of
|
* wSize-MAX_MATCH bytes, but this ensures that IO is always
|
* performed with a length multiple of the block size.
|
*/
|
|
this.window_size = 0;
|
/* Actual size of window: 2*wSize, except when the user input buffer
|
* is directly used as sliding window.
|
*/
|
|
this.prev = null;
|
/* Link to older string with same hash index. To limit the size of this
|
* array to 64K, this link is maintained only for the last 32K strings.
|
* An index in this array is thus a window index modulo 32K.
|
*/
|
|
this.head = null; /* Heads of the hash chains or NIL. */
|
|
this.ins_h = 0; /* hash index of string to be inserted */
|
this.hash_size = 0; /* number of elements in hash table */
|
this.hash_bits = 0; /* log2(hash_size) */
|
this.hash_mask = 0; /* hash_size-1 */
|
|
this.hash_shift = 0;
|
/* Number of bits by which ins_h must be shifted at each input
|
* step. It must be such that after MIN_MATCH steps, the oldest
|
* byte no longer takes part in the hash key, that is:
|
* hash_shift * MIN_MATCH >= hash_bits
|
*/
|
|
this.block_start = 0;
|
/* Window position at the beginning of the current output block. Gets
|
* negative when the window is moved backwards.
|
*/
|
|
this.match_length = 0; /* length of best match */
|
this.prev_match = 0; /* previous match */
|
this.match_available = 0; /* set if previous match exists */
|
this.strstart = 0; /* start of string to insert */
|
this.match_start = 0; /* start of matching string */
|
this.lookahead = 0; /* number of valid bytes ahead in window */
|
|
this.prev_length = 0;
|
/* Length of the best match at previous step. Matches not greater than this
|
* are discarded. This is used in the lazy match evaluation.
|
*/
|
|
this.max_chain_length = 0;
|
/* To speed up deflation, hash chains are never searched beyond this
|
* length. A higher limit improves compression ratio but degrades the
|
* speed.
|
*/
|
|
this.max_lazy_match = 0;
|
/* Attempt to find a better match only when the current match is strictly
|
* smaller than this value. This mechanism is used only for compression
|
* levels >= 4.
|
*/
|
// That's alias to max_lazy_match, don't use directly
|
//this.max_insert_length = 0;
|
/* Insert new strings in the hash table only if the match length is not
|
* greater than this length. This saves time but degrades compression.
|
* max_insert_length is used only for compression levels <= 3.
|
*/
|
|
this.level = 0; /* compression level (1..9) */
|
this.strategy = 0; /* favor or force Huffman coding*/
|
|
this.good_match = 0;
|
/* Use a faster search when the previous match is longer than this */
|
|
this.nice_match = 0; /* Stop searching when current match exceeds this */
|
|
/* used by trees.c: */
|
|
/* Didn't use ct_data typedef below to suppress compiler warning */
|
|
// struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */
|
// struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */
|
// struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */
|
|
// Use flat array of DOUBLE size, with interleaved fata,
|
// because JS does not support effective
|
this.dyn_ltree = new utils.Buf16(HEAP_SIZE * 2);
|
this.dyn_dtree = new utils.Buf16((2 * D_CODES + 1) * 2);
|
this.bl_tree = new utils.Buf16((2 * BL_CODES + 1) * 2);
|
zero(this.dyn_ltree);
|
zero(this.dyn_dtree);
|
zero(this.bl_tree);
|
|
this.l_desc = null; /* desc. for literal tree */
|
this.d_desc = null; /* desc. for distance tree */
|
this.bl_desc = null; /* desc. for bit length tree */
|
|
//ush bl_count[MAX_BITS+1];
|
this.bl_count = new utils.Buf16(MAX_BITS + 1);
|
/* number of codes at each bit length for an optimal tree */
|
|
//int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */
|
this.heap = new utils.Buf16(2 * L_CODES + 1); /* heap used to build the Huffman trees */
|
zero(this.heap);
|
|
this.heap_len = 0; /* number of elements in the heap */
|
this.heap_max = 0; /* element of largest frequency */
|
/* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
|
* The same heap array is used to build all trees.
|
*/
|
|
this.depth = new utils.Buf16(2 * L_CODES + 1); //uch depth[2*L_CODES+1];
|
zero(this.depth);
|
/* Depth of each subtree used as tie breaker for trees of equal frequency
|
*/
|
|
this.l_buf = 0; /* buffer index for literals or lengths */
|
|
this.lit_bufsize = 0;
|
/* Size of match buffer for literals/lengths. There are 4 reasons for
|
* limiting lit_bufsize to 64K:
|
* - frequencies can be kept in 16 bit counters
|
* - if compression is not successful for the first block, all input
|
* data is still in the window so we can still emit a stored block even
|
* when input comes from standard input. (This can also be done for
|
* all blocks if lit_bufsize is not greater than 32K.)
|
* - if compression is not successful for a file smaller than 64K, we can
|
* even emit a stored file instead of a stored block (saving 5 bytes).
|
* This is applicable only for zip (not gzip or zlib).
|
* - creating new Huffman trees less frequently may not provide fast
|
* adaptation to changes in the input data statistics. (Take for
|
* example a binary file with poorly compressible code followed by
|
* a highly compressible string table.) Smaller buffer sizes give
|
* fast adaptation but have of course the overhead of transmitting
|
* trees more frequently.
|
* - I can't count above 4
|
*/
|
|
this.last_lit = 0; /* running index in l_buf */
|
|
this.d_buf = 0;
|
/* Buffer index for distances. To simplify the code, d_buf and l_buf have
|
* the same number of elements. To use different lengths, an extra flag
|
* array would be necessary.
|
*/
|
|
this.opt_len = 0; /* bit length of current block with optimal trees */
|
this.static_len = 0; /* bit length of current block with static trees */
|
this.matches = 0; /* number of string matches in current block */
|
this.insert = 0; /* bytes at end of window left to insert */
|
|
|
this.bi_buf = 0;
|
/* Output buffer. bits are inserted starting at the bottom (least
|
* significant bits).
|
*/
|
this.bi_valid = 0;
|
/* Number of valid bits in bi_buf. All bits above the last valid bit
|
* are always zero.
|
*/
|
|
// Used for window memory init. We safely ignore it for JS. That makes
|
// sense only for pointers and memory check tools.
|
//this.high_water = 0;
|
/* High water mark offset in window for initialized bytes -- bytes above
|
* this are set to zero in order to avoid memory check warnings when
|
* longest match routines access bytes past the input. This is then
|
* updated to the new high water mark.
|
*/
|
}
|
|
|
function deflateResetKeep(strm) {
|
var s;
|
|
if (!strm || !strm.state) {
|
return err(strm, Z_STREAM_ERROR);
|
}
|
|
strm.total_in = strm.total_out = 0;
|
strm.data_type = Z_UNKNOWN;
|
|
s = strm.state;
|
s.pending = 0;
|
s.pending_out = 0;
|
|
if (s.wrap < 0) {
|
s.wrap = -s.wrap;
|
/* was made negative by deflate(..., Z_FINISH); */
|
}
|
s.status = (s.wrap ? INIT_STATE : BUSY_STATE);
|
strm.adler = (s.wrap === 2) ?
|
0 // crc32(0, Z_NULL, 0)
|
:
|
1; // adler32(0, Z_NULL, 0)
|
s.last_flush = Z_NO_FLUSH;
|
trees._tr_init(s);
|
return Z_OK;
|
}
|
|
|
function deflateReset(strm) {
|
var ret = deflateResetKeep(strm);
|
if (ret === Z_OK) {
|
lm_init(strm.state);
|
}
|
return ret;
|
}
|
|
|
function deflateSetHeader(strm, head) {
|
if (!strm || !strm.state) { return Z_STREAM_ERROR; }
|
if (strm.state.wrap !== 2) { return Z_STREAM_ERROR; }
|
strm.state.gzhead = head;
|
return Z_OK;
|
}
|
|
|
function deflateInit2(strm, level, method, windowBits, memLevel, strategy) {
|
if (!strm) { // === Z_NULL
|
return Z_STREAM_ERROR;
|
}
|
var wrap = 1;
|
|
if (level === Z_DEFAULT_COMPRESSION) {
|
level = 6;
|
}
|
|
if (windowBits < 0) { /* suppress zlib wrapper */
|
wrap = 0;
|
windowBits = -windowBits;
|
}
|
|
else if (windowBits > 15) {
|
wrap = 2; /* write gzip wrapper instead */
|
windowBits -= 16;
|
}
|
|
|
if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method !== Z_DEFLATED ||
|
windowBits < 8 || windowBits > 15 || level < 0 || level > 9 ||
|
strategy < 0 || strategy > Z_FIXED) {
|
return err(strm, Z_STREAM_ERROR);
|
}
|
|
|
if (windowBits === 8) {
|
windowBits = 9;
|
}
|
/* until 256-byte window bug fixed */
|
|
var s = new DeflateState();
|
|
strm.state = s;
|
s.strm = strm;
|
|
s.wrap = wrap;
|
s.gzhead = null;
|
s.w_bits = windowBits;
|
s.w_size = 1 << s.w_bits;
|
s.w_mask = s.w_size - 1;
|
|
s.hash_bits = memLevel + 7;
|
s.hash_size = 1 << s.hash_bits;
|
s.hash_mask = s.hash_size - 1;
|
s.hash_shift = ~~((s.hash_bits + MIN_MATCH - 1) / MIN_MATCH);
|
|
s.window = new utils.Buf8(s.w_size * 2);
|
s.head = new utils.Buf16(s.hash_size);
|
s.prev = new utils.Buf16(s.w_size);
|
|
// Don't need mem init magic for JS.
|
//s.high_water = 0; /* nothing written to s->window yet */
|
|
s.lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */
|
|
s.pending_buf_size = s.lit_bufsize * 4;
|
|
//overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2);
|
//s->pending_buf = (uchf *) overlay;
|
s.pending_buf = new utils.Buf8(s.pending_buf_size);
|
|
// It is offset from `s.pending_buf` (size is `s.lit_bufsize * 2`)
|
//s->d_buf = overlay + s->lit_bufsize/sizeof(ush);
|
s.d_buf = 1 * s.lit_bufsize;
|
|
//s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize;
|
s.l_buf = (1 + 2) * s.lit_bufsize;
|
|
s.level = level;
|
s.strategy = strategy;
|
s.method = method;
|
|
return deflateReset(strm);
|
}
|
|
function deflateInit(strm, level) {
|
return deflateInit2(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY);
|
}
|
|
|
function deflate(strm, flush) {
|
var old_flush, s;
|
var beg, val; // for gzip header write only
|
|
if (!strm || !strm.state ||
|
flush > Z_BLOCK || flush < 0) {
|
return strm ? err(strm, Z_STREAM_ERROR) : Z_STREAM_ERROR;
|
}
|
|
s = strm.state;
|
|
if (!strm.output ||
|
(!strm.input && strm.avail_in !== 0) ||
|
(s.status === FINISH_STATE && flush !== Z_FINISH)) {
|
return err(strm, (strm.avail_out === 0) ? Z_BUF_ERROR : Z_STREAM_ERROR);
|
}
|
|
s.strm = strm; /* just in case */
|
old_flush = s.last_flush;
|
s.last_flush = flush;
|
|
/* Write the header */
|
if (s.status === INIT_STATE) {
|
|
if (s.wrap === 2) { // GZIP header
|
strm.adler = 0; //crc32(0L, Z_NULL, 0);
|
put_byte(s, 31);
|
put_byte(s, 139);
|
put_byte(s, 8);
|
if (!s.gzhead) { // s->gzhead == Z_NULL
|
put_byte(s, 0);
|
put_byte(s, 0);
|
put_byte(s, 0);
|
put_byte(s, 0);
|
put_byte(s, 0);
|
put_byte(s, s.level === 9 ? 2 :
|
(s.strategy >= Z_HUFFMAN_ONLY || s.level < 2 ?
|
4 : 0));
|
put_byte(s, OS_CODE);
|
s.status = BUSY_STATE;
|
}
|
else {
|
put_byte(s, (s.gzhead.text ? 1 : 0) +
|
(s.gzhead.hcrc ? 2 : 0) +
|
(!s.gzhead.extra ? 0 : 4) +
|
(!s.gzhead.name ? 0 : 8) +
|
(!s.gzhead.comment ? 0 : 16)
|
);
|
put_byte(s, s.gzhead.time & 0xff);
|
put_byte(s, (s.gzhead.time >> 8) & 0xff);
|
put_byte(s, (s.gzhead.time >> 16) & 0xff);
|
put_byte(s, (s.gzhead.time >> 24) & 0xff);
|
put_byte(s, s.level === 9 ? 2 :
|
(s.strategy >= Z_HUFFMAN_ONLY || s.level < 2 ?
|
4 : 0));
|
put_byte(s, s.gzhead.os & 0xff);
|
if (s.gzhead.extra && s.gzhead.extra.length) {
|
put_byte(s, s.gzhead.extra.length & 0xff);
|
put_byte(s, (s.gzhead.extra.length >> 8) & 0xff);
|
}
|
if (s.gzhead.hcrc) {
|
strm.adler = crc32(strm.adler, s.pending_buf, s.pending, 0);
|
}
|
s.gzindex = 0;
|
s.status = EXTRA_STATE;
|
}
|
}
|
else // DEFLATE header
|
{
|
var header = (Z_DEFLATED + ((s.w_bits - 8) << 4)) << 8;
|
var level_flags = -1;
|
|
if (s.strategy >= Z_HUFFMAN_ONLY || s.level < 2) {
|
level_flags = 0;
|
} else if (s.level < 6) {
|
level_flags = 1;
|
} else if (s.level === 6) {
|
level_flags = 2;
|
} else {
|
level_flags = 3;
|
}
|
header |= (level_flags << 6);
|
if (s.strstart !== 0) { header |= PRESET_DICT; }
|
header += 31 - (header % 31);
|
|
s.status = BUSY_STATE;
|
putShortMSB(s, header);
|
|
/* Save the adler32 of the preset dictionary: */
|
if (s.strstart !== 0) {
|
putShortMSB(s, strm.adler >>> 16);
|
putShortMSB(s, strm.adler & 0xffff);
|
}
|
strm.adler = 1; // adler32(0L, Z_NULL, 0);
|
}
|
}
|
|
//#ifdef GZIP
|
if (s.status === EXTRA_STATE) {
|
if (s.gzhead.extra/* != Z_NULL*/) {
|
beg = s.pending; /* start of bytes to update crc */
|
|
while (s.gzindex < (s.gzhead.extra.length & 0xffff)) {
|
if (s.pending === s.pending_buf_size) {
|
if (s.gzhead.hcrc && s.pending > beg) {
|
strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);
|
}
|
flush_pending(strm);
|
beg = s.pending;
|
if (s.pending === s.pending_buf_size) {
|
break;
|
}
|
}
|
put_byte(s, s.gzhead.extra[s.gzindex] & 0xff);
|
s.gzindex++;
|
}
|
if (s.gzhead.hcrc && s.pending > beg) {
|
strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);
|
}
|
if (s.gzindex === s.gzhead.extra.length) {
|
s.gzindex = 0;
|
s.status = NAME_STATE;
|
}
|
}
|
else {
|
s.status = NAME_STATE;
|
}
|
}
|
if (s.status === NAME_STATE) {
|
if (s.gzhead.name/* != Z_NULL*/) {
|
beg = s.pending; /* start of bytes to update crc */
|
//int val;
|
|
do {
|
if (s.pending === s.pending_buf_size) {
|
if (s.gzhead.hcrc && s.pending > beg) {
|
strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);
|
}
|
flush_pending(strm);
|
beg = s.pending;
|
if (s.pending === s.pending_buf_size) {
|
val = 1;
|
break;
|
}
|
}
|
// JS specific: little magic to add zero terminator to end of string
|
if (s.gzindex < s.gzhead.name.length) {
|
val = s.gzhead.name.charCodeAt(s.gzindex++) & 0xff;
|
} else {
|
val = 0;
|
}
|
put_byte(s, val);
|
} while (val !== 0);
|
|
if (s.gzhead.hcrc && s.pending > beg) {
|
strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);
|
}
|
if (val === 0) {
|
s.gzindex = 0;
|
s.status = COMMENT_STATE;
|
}
|
}
|
else {
|
s.status = COMMENT_STATE;
|
}
|
}
|
if (s.status === COMMENT_STATE) {
|
if (s.gzhead.comment/* != Z_NULL*/) {
|
beg = s.pending; /* start of bytes to update crc */
|
//int val;
|
|
do {
|
if (s.pending === s.pending_buf_size) {
|
if (s.gzhead.hcrc && s.pending > beg) {
|
strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);
|
}
|
flush_pending(strm);
|
beg = s.pending;
|
if (s.pending === s.pending_buf_size) {
|
val = 1;
|
break;
|
}
|
}
|
// JS specific: little magic to add zero terminator to end of string
|
if (s.gzindex < s.gzhead.comment.length) {
|
val = s.gzhead.comment.charCodeAt(s.gzindex++) & 0xff;
|
} else {
|
val = 0;
|
}
|
put_byte(s, val);
|
} while (val !== 0);
|
|
if (s.gzhead.hcrc && s.pending > beg) {
|
strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);
|
}
|
if (val === 0) {
|
s.status = HCRC_STATE;
|
}
|
}
|
else {
|
s.status = HCRC_STATE;
|
}
|
}
|
if (s.status === HCRC_STATE) {
|
if (s.gzhead.hcrc) {
|
if (s.pending + 2 > s.pending_buf_size) {
|
flush_pending(strm);
|
}
|
if (s.pending + 2 <= s.pending_buf_size) {
|
put_byte(s, strm.adler & 0xff);
|
put_byte(s, (strm.adler >> 8) & 0xff);
|
strm.adler = 0; //crc32(0L, Z_NULL, 0);
|
s.status = BUSY_STATE;
|
}
|
}
|
else {
|
s.status = BUSY_STATE;
|
}
|
}
|
//#endif
|
|
/* Flush as much pending output as possible */
|
if (s.pending !== 0) {
|
flush_pending(strm);
|
if (strm.avail_out === 0) {
|
/* Since avail_out is 0, deflate will be called again with
|
* more output space, but possibly with both pending and
|
* avail_in equal to zero. There won't be anything to do,
|
* but this is not an error situation so make sure we
|
* return OK instead of BUF_ERROR at next call of deflate:
|
*/
|
s.last_flush = -1;
|
return Z_OK;
|
}
|
|
/* Make sure there is something to do and avoid duplicate consecutive
|
* flushes. For repeated and useless calls with Z_FINISH, we keep
|
* returning Z_STREAM_END instead of Z_BUF_ERROR.
|
*/
|
} else if (strm.avail_in === 0 && rank(flush) <= rank(old_flush) &&
|
flush !== Z_FINISH) {
|
return err(strm, Z_BUF_ERROR);
|
}
|
|
/* User must not provide more input after the first FINISH: */
|
if (s.status === FINISH_STATE && strm.avail_in !== 0) {
|
return err(strm, Z_BUF_ERROR);
|
}
|
|
/* Start a new block or continue the current one.
|
*/
|
if (strm.avail_in !== 0 || s.lookahead !== 0 ||
|
(flush !== Z_NO_FLUSH && s.status !== FINISH_STATE)) {
|
var bstate = (s.strategy === Z_HUFFMAN_ONLY) ? deflate_huff(s, flush) :
|
(s.strategy === Z_RLE ? deflate_rle(s, flush) :
|
configuration_table[s.level].func(s, flush));
|
|
if (bstate === BS_FINISH_STARTED || bstate === BS_FINISH_DONE) {
|
s.status = FINISH_STATE;
|
}
|
if (bstate === BS_NEED_MORE || bstate === BS_FINISH_STARTED) {
|
if (strm.avail_out === 0) {
|
s.last_flush = -1;
|
/* avoid BUF_ERROR next call, see above */
|
}
|
return Z_OK;
|
/* If flush != Z_NO_FLUSH && avail_out == 0, the next call
|
* of deflate should use the same flush parameter to make sure
|
* that the flush is complete. So we don't have to output an
|
* empty block here, this will be done at next call. This also
|
* ensures that for a very small output buffer, we emit at most
|
* one empty block.
|
*/
|
}
|
if (bstate === BS_BLOCK_DONE) {
|
if (flush === Z_PARTIAL_FLUSH) {
|
trees._tr_align(s);
|
}
|
else if (flush !== Z_BLOCK) { /* FULL_FLUSH or SYNC_FLUSH */
|
|
trees._tr_stored_block(s, 0, 0, false);
|
/* For a full flush, this empty block will be recognized
|
* as a special marker by inflate_sync().
|
*/
|
if (flush === Z_FULL_FLUSH) {
|
/*** CLEAR_HASH(s); ***/ /* forget history */
|
zero(s.head); // Fill with NIL (= 0);
|
|
if (s.lookahead === 0) {
|
s.strstart = 0;
|
s.block_start = 0;
|
s.insert = 0;
|
}
|
}
|
}
|
flush_pending(strm);
|
if (strm.avail_out === 0) {
|
s.last_flush = -1; /* avoid BUF_ERROR at next call, see above */
|
return Z_OK;
|
}
|
}
|
}
|
//Assert(strm->avail_out > 0, "bug2");
|
//if (strm.avail_out <= 0) { throw new Error("bug2");}
|
|
if (flush !== Z_FINISH) { return Z_OK; }
|
if (s.wrap <= 0) { return Z_STREAM_END; }
|
|
/* Write the trailer */
|
if (s.wrap === 2) {
|
put_byte(s, strm.adler & 0xff);
|
put_byte(s, (strm.adler >> 8) & 0xff);
|
put_byte(s, (strm.adler >> 16) & 0xff);
|
put_byte(s, (strm.adler >> 24) & 0xff);
|
put_byte(s, strm.total_in & 0xff);
|
put_byte(s, (strm.total_in >> 8) & 0xff);
|
put_byte(s, (strm.total_in >> 16) & 0xff);
|
put_byte(s, (strm.total_in >> 24) & 0xff);
|
}
|
else
|
{
|
putShortMSB(s, strm.adler >>> 16);
|
putShortMSB(s, strm.adler & 0xffff);
|
}
|
|
flush_pending(strm);
|
/* If avail_out is zero, the application will call deflate again
|
* to flush the rest.
|
*/
|
if (s.wrap > 0) { s.wrap = -s.wrap; }
|
/* write the trailer only once! */
|
return s.pending !== 0 ? Z_OK : Z_STREAM_END;
|
}
|
|
function deflateEnd(strm) {
|
var status;
|
|
if (!strm/*== Z_NULL*/ || !strm.state/*== Z_NULL*/) {
|
return Z_STREAM_ERROR;
|
}
|
|
status = strm.state.status;
|
if (status !== INIT_STATE &&
|
status !== EXTRA_STATE &&
|
status !== NAME_STATE &&
|
status !== COMMENT_STATE &&
|
status !== HCRC_STATE &&
|
status !== BUSY_STATE &&
|
status !== FINISH_STATE
|
) {
|
return err(strm, Z_STREAM_ERROR);
|
}
|
|
strm.state = null;
|
|
return status === BUSY_STATE ? err(strm, Z_DATA_ERROR) : Z_OK;
|
}
|
|
|
/* =========================================================================
|
* Initializes the compression dictionary from the given byte
|
* sequence without producing any compressed output.
|
*/
|
function deflateSetDictionary(strm, dictionary) {
|
var dictLength = dictionary.length;
|
|
var s;
|
var str, n;
|
var wrap;
|
var avail;
|
var next;
|
var input;
|
var tmpDict;
|
|
if (!strm/*== Z_NULL*/ || !strm.state/*== Z_NULL*/) {
|
return Z_STREAM_ERROR;
|
}
|
|
s = strm.state;
|
wrap = s.wrap;
|
|
if (wrap === 2 || (wrap === 1 && s.status !== INIT_STATE) || s.lookahead) {
|
return Z_STREAM_ERROR;
|
}
|
|
/* when using zlib wrappers, compute Adler-32 for provided dictionary */
|
if (wrap === 1) {
|
/* adler32(strm->adler, dictionary, dictLength); */
|
strm.adler = adler32(strm.adler, dictionary, dictLength, 0);
|
}
|
|
s.wrap = 0; /* avoid computing Adler-32 in read_buf */
|
|
/* if dictionary would fill window, just replace the history */
|
if (dictLength >= s.w_size) {
|
if (wrap === 0) { /* already empty otherwise */
|
/*** CLEAR_HASH(s); ***/
|
zero(s.head); // Fill with NIL (= 0);
|
s.strstart = 0;
|
s.block_start = 0;
|
s.insert = 0;
|
}
|
/* use the tail */
|
// dictionary = dictionary.slice(dictLength - s.w_size);
|
tmpDict = new utils.Buf8(s.w_size);
|
utils.arraySet(tmpDict, dictionary, dictLength - s.w_size, s.w_size, 0);
|
dictionary = tmpDict;
|
dictLength = s.w_size;
|
}
|
/* insert dictionary into window and hash */
|
avail = strm.avail_in;
|
next = strm.next_in;
|
input = strm.input;
|
strm.avail_in = dictLength;
|
strm.next_in = 0;
|
strm.input = dictionary;
|
fill_window(s);
|
while (s.lookahead >= MIN_MATCH) {
|
str = s.strstart;
|
n = s.lookahead - (MIN_MATCH - 1);
|
do {
|
/* UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); */
|
s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[str + MIN_MATCH - 1]) & s.hash_mask;
|
|
s.prev[str & s.w_mask] = s.head[s.ins_h];
|
|
s.head[s.ins_h] = str;
|
str++;
|
} while (--n);
|
s.strstart = str;
|
s.lookahead = MIN_MATCH - 1;
|
fill_window(s);
|
}
|
s.strstart += s.lookahead;
|
s.block_start = s.strstart;
|
s.insert = s.lookahead;
|
s.lookahead = 0;
|
s.match_length = s.prev_length = MIN_MATCH - 1;
|
s.match_available = 0;
|
strm.next_in = next;
|
strm.input = input;
|
strm.avail_in = avail;
|
s.wrap = wrap;
|
return Z_OK;
|
}
|
|
|
exports.deflateInit = deflateInit;
|
exports.deflateInit2 = deflateInit2;
|
exports.deflateReset = deflateReset;
|
exports.deflateResetKeep = deflateResetKeep;
|
exports.deflateSetHeader = deflateSetHeader;
|
exports.deflate = deflate;
|
exports.deflateEnd = deflateEnd;
|
exports.deflateSetDictionary = deflateSetDictionary;
|
exports.deflateInfo = 'pako deflate (from Nodeca project)';
|
|
/* Not implemented
|
exports.deflateBound = deflateBound;
|
exports.deflateCopy = deflateCopy;
|
exports.deflateParams = deflateParams;
|
exports.deflatePending = deflatePending;
|
exports.deflatePrime = deflatePrime;
|
exports.deflateTune = deflateTune;
|
*/
|
|
},{"../utils/common":65,"./adler32":67,"./crc32":69,"./messages":75,"./trees":76}],71:[function(require,module,exports){
|
'use strict';
|
|
// (C) 1995-2013 Jean-loup Gailly and Mark Adler
|
// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
|
//
|
// This software is provided 'as-is', without any express or implied
|
// warranty. In no event will the authors be held liable for any damages
|
// arising from the use of this software.
|
//
|
// Permission is granted to anyone to use this software for any purpose,
|
// including commercial applications, and to alter it and redistribute it
|
// freely, subject to the following restrictions:
|
//
|
// 1. The origin of this software must not be misrepresented; you must not
|
// claim that you wrote the original software. If you use this software
|
// in a product, an acknowledgment in the product documentation would be
|
// appreciated but is not required.
|
// 2. Altered source versions must be plainly marked as such, and must not be
|
// misrepresented as being the original software.
|
// 3. This notice may not be removed or altered from any source distribution.
|
|
function GZheader() {
|
/* true if compressed data believed to be text */
|
this.text = 0;
|
/* modification time */
|
this.time = 0;
|
/* extra flags (not used when writing a gzip file) */
|
this.xflags = 0;
|
/* operating system */
|
this.os = 0;
|
/* pointer to extra field or Z_NULL if none */
|
this.extra = null;
|
/* extra field length (valid if extra != Z_NULL) */
|
this.extra_len = 0; // Actually, we don't need it in JS,
|
// but leave for few code modifications
|
|
//
|
// Setup limits is not necessary because in js we should not preallocate memory
|
// for inflate use constant limit in 65536 bytes
|
//
|
|
/* space at extra (only when reading header) */
|
// this.extra_max = 0;
|
/* pointer to zero-terminated file name or Z_NULL */
|
this.name = '';
|
/* space at name (only when reading header) */
|
// this.name_max = 0;
|
/* pointer to zero-terminated comment or Z_NULL */
|
this.comment = '';
|
/* space at comment (only when reading header) */
|
// this.comm_max = 0;
|
/* true if there was or will be a header crc */
|
this.hcrc = 0;
|
/* true when done reading gzip header (not used when writing a gzip file) */
|
this.done = false;
|
}
|
|
module.exports = GZheader;
|
|
},{}],72:[function(require,module,exports){
|
'use strict';
|
|
// (C) 1995-2013 Jean-loup Gailly and Mark Adler
|
// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
|
//
|
// This software is provided 'as-is', without any express or implied
|
// warranty. In no event will the authors be held liable for any damages
|
// arising from the use of this software.
|
//
|
// Permission is granted to anyone to use this software for any purpose,
|
// including commercial applications, and to alter it and redistribute it
|
// freely, subject to the following restrictions:
|
//
|
// 1. The origin of this software must not be misrepresented; you must not
|
// claim that you wrote the original software. If you use this software
|
// in a product, an acknowledgment in the product documentation would be
|
// appreciated but is not required.
|
// 2. Altered source versions must be plainly marked as such, and must not be
|
// misrepresented as being the original software.
|
// 3. This notice may not be removed or altered from any source distribution.
|
|
// See state defs from inflate.js
|
var BAD = 30; /* got a data error -- remain here until reset */
|
var TYPE = 12; /* i: waiting for type bits, including last-flag bit */
|
|
/*
|
Decode literal, length, and distance codes and write out the resulting
|
literal and match bytes until either not enough input or output is
|
available, an end-of-block is encountered, or a data error is encountered.
|
When large enough input and output buffers are supplied to inflate(), for
|
example, a 16K input buffer and a 64K output buffer, more than 95% of the
|
inflate execution time is spent in this routine.
|
|
Entry assumptions:
|
|
state.mode === LEN
|
strm.avail_in >= 6
|
strm.avail_out >= 258
|
start >= strm.avail_out
|
state.bits < 8
|
|
On return, state.mode is one of:
|
|
LEN -- ran out of enough output space or enough available input
|
TYPE -- reached end of block code, inflate() to interpret next block
|
BAD -- error in block data
|
|
Notes:
|
|
- The maximum input bits used by a length/distance pair is 15 bits for the
|
length code, 5 bits for the length extra, 15 bits for the distance code,
|
and 13 bits for the distance extra. This totals 48 bits, or six bytes.
|
Therefore if strm.avail_in >= 6, then there is enough input to avoid
|
checking for available input while decoding.
|
|
- The maximum bytes that a single length/distance pair can output is 258
|
bytes, which is the maximum length that can be coded. inflate_fast()
|
requires strm.avail_out >= 258 for each loop to avoid checking for
|
output space.
|
*/
|
module.exports = function inflate_fast(strm, start) {
|
var state;
|
var _in; /* local strm.input */
|
var last; /* have enough input while in < last */
|
var _out; /* local strm.output */
|
var beg; /* inflate()'s initial strm.output */
|
var end; /* while out < end, enough space available */
|
//#ifdef INFLATE_STRICT
|
var dmax; /* maximum distance from zlib header */
|
//#endif
|
var wsize; /* window size or zero if not using window */
|
var whave; /* valid bytes in the window */
|
var wnext; /* window write index */
|
// Use `s_window` instead `window`, avoid conflict with instrumentation tools
|
var s_window; /* allocated sliding window, if wsize != 0 */
|
var hold; /* local strm.hold */
|
var bits; /* local strm.bits */
|
var lcode; /* local strm.lencode */
|
var dcode; /* local strm.distcode */
|
var lmask; /* mask for first level of length codes */
|
var dmask; /* mask for first level of distance codes */
|
var here; /* retrieved table entry */
|
var op; /* code bits, operation, extra bits, or */
|
/* window position, window bytes to copy */
|
var len; /* match length, unused bytes */
|
var dist; /* match distance */
|
var from; /* where to copy match from */
|
var from_source;
|
|
|
var input, output; // JS specific, because we have no pointers
|
|
/* copy state to local variables */
|
state = strm.state;
|
//here = state.here;
|
_in = strm.next_in;
|
input = strm.input;
|
last = _in + (strm.avail_in - 5);
|
_out = strm.next_out;
|
output = strm.output;
|
beg = _out - (start - strm.avail_out);
|
end = _out + (strm.avail_out - 257);
|
//#ifdef INFLATE_STRICT
|
dmax = state.dmax;
|
//#endif
|
wsize = state.wsize;
|
whave = state.whave;
|
wnext = state.wnext;
|
s_window = state.window;
|
hold = state.hold;
|
bits = state.bits;
|
lcode = state.lencode;
|
dcode = state.distcode;
|
lmask = (1 << state.lenbits) - 1;
|
dmask = (1 << state.distbits) - 1;
|
|
|
/* decode literals and length/distances until end-of-block or not enough
|
input data or output space */
|
|
top:
|
do {
|
if (bits < 15) {
|
hold += input[_in++] << bits;
|
bits += 8;
|
hold += input[_in++] << bits;
|
bits += 8;
|
}
|
|
here = lcode[hold & lmask];
|
|
dolen:
|
for (;;) { // Goto emulation
|
op = here >>> 24/*here.bits*/;
|
hold >>>= op;
|
bits -= op;
|
op = (here >>> 16) & 0xff/*here.op*/;
|
if (op === 0) { /* literal */
|
//Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?
|
// "inflate: literal '%c'\n" :
|
// "inflate: literal 0x%02x\n", here.val));
|
output[_out++] = here & 0xffff/*here.val*/;
|
}
|
else if (op & 16) { /* length base */
|
len = here & 0xffff/*here.val*/;
|
op &= 15; /* number of extra bits */
|
if (op) {
|
if (bits < op) {
|
hold += input[_in++] << bits;
|
bits += 8;
|
}
|
len += hold & ((1 << op) - 1);
|
hold >>>= op;
|
bits -= op;
|
}
|
//Tracevv((stderr, "inflate: length %u\n", len));
|
if (bits < 15) {
|
hold += input[_in++] << bits;
|
bits += 8;
|
hold += input[_in++] << bits;
|
bits += 8;
|
}
|
here = dcode[hold & dmask];
|
|
dodist:
|
for (;;) { // goto emulation
|
op = here >>> 24/*here.bits*/;
|
hold >>>= op;
|
bits -= op;
|
op = (here >>> 16) & 0xff/*here.op*/;
|
|
if (op & 16) { /* distance base */
|
dist = here & 0xffff/*here.val*/;
|
op &= 15; /* number of extra bits */
|
if (bits < op) {
|
hold += input[_in++] << bits;
|
bits += 8;
|
if (bits < op) {
|
hold += input[_in++] << bits;
|
bits += 8;
|
}
|
}
|
dist += hold & ((1 << op) - 1);
|
//#ifdef INFLATE_STRICT
|
if (dist > dmax) {
|
strm.msg = 'invalid distance too far back';
|
state.mode = BAD;
|
break top;
|
}
|
//#endif
|
hold >>>= op;
|
bits -= op;
|
//Tracevv((stderr, "inflate: distance %u\n", dist));
|
op = _out - beg; /* max distance in output */
|
if (dist > op) { /* see if copy from window */
|
op = dist - op; /* distance back in window */
|
if (op > whave) {
|
if (state.sane) {
|
strm.msg = 'invalid distance too far back';
|
state.mode = BAD;
|
break top;
|
}
|
|
// (!) This block is disabled in zlib defaults,
|
// don't enable it for binary compatibility
|
//#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
|
// if (len <= op - whave) {
|
// do {
|
// output[_out++] = 0;
|
// } while (--len);
|
// continue top;
|
// }
|
// len -= op - whave;
|
// do {
|
// output[_out++] = 0;
|
// } while (--op > whave);
|
// if (op === 0) {
|
// from = _out - dist;
|
// do {
|
// output[_out++] = output[from++];
|
// } while (--len);
|
// continue top;
|
// }
|
//#endif
|
}
|
from = 0; // window index
|
from_source = s_window;
|
if (wnext === 0) { /* very common case */
|
from += wsize - op;
|
if (op < len) { /* some from window */
|
len -= op;
|
do {
|
output[_out++] = s_window[from++];
|
} while (--op);
|
from = _out - dist; /* rest from output */
|
from_source = output;
|
}
|
}
|
else if (wnext < op) { /* wrap around window */
|
from += wsize + wnext - op;
|
op -= wnext;
|
if (op < len) { /* some from end of window */
|
len -= op;
|
do {
|
output[_out++] = s_window[from++];
|
} while (--op);
|
from = 0;
|
if (wnext < len) { /* some from start of window */
|
op = wnext;
|
len -= op;
|
do {
|
output[_out++] = s_window[from++];
|
} while (--op);
|
from = _out - dist; /* rest from output */
|
from_source = output;
|
}
|
}
|
}
|
else { /* contiguous in window */
|
from += wnext - op;
|
if (op < len) { /* some from window */
|
len -= op;
|
do {
|
output[_out++] = s_window[from++];
|
} while (--op);
|
from = _out - dist; /* rest from output */
|
from_source = output;
|
}
|
}
|
while (len > 2) {
|
output[_out++] = from_source[from++];
|
output[_out++] = from_source[from++];
|
output[_out++] = from_source[from++];
|
len -= 3;
|
}
|
if (len) {
|
output[_out++] = from_source[from++];
|
if (len > 1) {
|
output[_out++] = from_source[from++];
|
}
|
}
|
}
|
else {
|
from = _out - dist; /* copy direct from output */
|
do { /* minimum length is three */
|
output[_out++] = output[from++];
|
output[_out++] = output[from++];
|
output[_out++] = output[from++];
|
len -= 3;
|
} while (len > 2);
|
if (len) {
|
output[_out++] = output[from++];
|
if (len > 1) {
|
output[_out++] = output[from++];
|
}
|
}
|
}
|
}
|
else if ((op & 64) === 0) { /* 2nd level distance code */
|
here = dcode[(here & 0xffff)/*here.val*/ + (hold & ((1 << op) - 1))];
|
continue dodist;
|
}
|
else {
|
strm.msg = 'invalid distance code';
|
state.mode = BAD;
|
break top;
|
}
|
|
break; // need to emulate goto via "continue"
|
}
|
}
|
else if ((op & 64) === 0) { /* 2nd level length code */
|
here = lcode[(here & 0xffff)/*here.val*/ + (hold & ((1 << op) - 1))];
|
continue dolen;
|
}
|
else if (op & 32) { /* end-of-block */
|
//Tracevv((stderr, "inflate: end of block\n"));
|
state.mode = TYPE;
|
break top;
|
}
|
else {
|
strm.msg = 'invalid literal/length code';
|
state.mode = BAD;
|
break top;
|
}
|
|
break; // need to emulate goto via "continue"
|
}
|
} while (_in < last && _out < end);
|
|
/* return unused bytes (on entry, bits < 8, so in won't go too far back) */
|
len = bits >> 3;
|
_in -= len;
|
bits -= len << 3;
|
hold &= (1 << bits) - 1;
|
|
/* update state and return */
|
strm.next_in = _in;
|
strm.next_out = _out;
|
strm.avail_in = (_in < last ? 5 + (last - _in) : 5 - (_in - last));
|
strm.avail_out = (_out < end ? 257 + (end - _out) : 257 - (_out - end));
|
state.hold = hold;
|
state.bits = bits;
|
return;
|
};
|
|
},{}],73:[function(require,module,exports){
|
'use strict';
|
|
// (C) 1995-2013 Jean-loup Gailly and Mark Adler
|
// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
|
//
|
// This software is provided 'as-is', without any express or implied
|
// warranty. In no event will the authors be held liable for any damages
|
// arising from the use of this software.
|
//
|
// Permission is granted to anyone to use this software for any purpose,
|
// including commercial applications, and to alter it and redistribute it
|
// freely, subject to the following restrictions:
|
//
|
// 1. The origin of this software must not be misrepresented; you must not
|
// claim that you wrote the original software. If you use this software
|
// in a product, an acknowledgment in the product documentation would be
|
// appreciated but is not required.
|
// 2. Altered source versions must be plainly marked as such, and must not be
|
// misrepresented as being the original software.
|
// 3. This notice may not be removed or altered from any source distribution.
|
|
var utils = require('../utils/common');
|
var adler32 = require('./adler32');
|
var crc32 = require('./crc32');
|
var inflate_fast = require('./inffast');
|
var inflate_table = require('./inftrees');
|
|
var CODES = 0;
|
var LENS = 1;
|
var DISTS = 2;
|
|
/* Public constants ==========================================================*/
|
/* ===========================================================================*/
|
|
|
/* Allowed flush values; see deflate() and inflate() below for details */
|
//var Z_NO_FLUSH = 0;
|
//var Z_PARTIAL_FLUSH = 1;
|
//var Z_SYNC_FLUSH = 2;
|
//var Z_FULL_FLUSH = 3;
|
var Z_FINISH = 4;
|
var Z_BLOCK = 5;
|
var Z_TREES = 6;
|
|
|
/* Return codes for the compression/decompression functions. Negative values
|
* are errors, positive values are used for special but normal events.
|
*/
|
var Z_OK = 0;
|
var Z_STREAM_END = 1;
|
var Z_NEED_DICT = 2;
|
//var Z_ERRNO = -1;
|
var Z_STREAM_ERROR = -2;
|
var Z_DATA_ERROR = -3;
|
var Z_MEM_ERROR = -4;
|
var Z_BUF_ERROR = -5;
|
//var Z_VERSION_ERROR = -6;
|
|
/* The deflate compression method */
|
var Z_DEFLATED = 8;
|
|
|
/* STATES ====================================================================*/
|
/* ===========================================================================*/
|
|
|
var HEAD = 1; /* i: waiting for magic header */
|
var FLAGS = 2; /* i: waiting for method and flags (gzip) */
|
var TIME = 3; /* i: waiting for modification time (gzip) */
|
var OS = 4; /* i: waiting for extra flags and operating system (gzip) */
|
var EXLEN = 5; /* i: waiting for extra length (gzip) */
|
var EXTRA = 6; /* i: waiting for extra bytes (gzip) */
|
var NAME = 7; /* i: waiting for end of file name (gzip) */
|
var COMMENT = 8; /* i: waiting for end of comment (gzip) */
|
var HCRC = 9; /* i: waiting for header crc (gzip) */
|
var DICTID = 10; /* i: waiting for dictionary check value */
|
var DICT = 11; /* waiting for inflateSetDictionary() call */
|
var TYPE = 12; /* i: waiting for type bits, including last-flag bit */
|
var TYPEDO = 13; /* i: same, but skip check to exit inflate on new block */
|
var STORED = 14; /* i: waiting for stored size (length and complement) */
|
var COPY_ = 15; /* i/o: same as COPY below, but only first time in */
|
var COPY = 16; /* i/o: waiting for input or output to copy stored block */
|
var TABLE = 17; /* i: waiting for dynamic block table lengths */
|
var LENLENS = 18; /* i: waiting for code length code lengths */
|
var CODELENS = 19; /* i: waiting for length/lit and distance code lengths */
|
var LEN_ = 20; /* i: same as LEN below, but only first time in */
|
var LEN = 21; /* i: waiting for length/lit/eob code */
|
var LENEXT = 22; /* i: waiting for length extra bits */
|
var DIST = 23; /* i: waiting for distance code */
|
var DISTEXT = 24; /* i: waiting for distance extra bits */
|
var MATCH = 25; /* o: waiting for output space to copy string */
|
var LIT = 26; /* o: waiting for output space to write literal */
|
var CHECK = 27; /* i: waiting for 32-bit check value */
|
var LENGTH = 28; /* i: waiting for 32-bit length (gzip) */
|
var DONE = 29; /* finished check, done -- remain here until reset */
|
var BAD = 30; /* got a data error -- remain here until reset */
|
var MEM = 31; /* got an inflate() memory error -- remain here until reset */
|
var SYNC = 32; /* looking for synchronization bytes to restart inflate() */
|
|
/* ===========================================================================*/
|
|
|
|
var ENOUGH_LENS = 852;
|
var ENOUGH_DISTS = 592;
|
//var ENOUGH = (ENOUGH_LENS+ENOUGH_DISTS);
|
|
var MAX_WBITS = 15;
|
/* 32K LZ77 window */
|
var DEF_WBITS = MAX_WBITS;
|
|
|
function zswap32(q) {
|
return (((q >>> 24) & 0xff) +
|
((q >>> 8) & 0xff00) +
|
((q & 0xff00) << 8) +
|
((q & 0xff) << 24));
|
}
|
|
|
function InflateState() {
|
this.mode = 0; /* current inflate mode */
|
this.last = false; /* true if processing last block */
|
this.wrap = 0; /* bit 0 true for zlib, bit 1 true for gzip */
|
this.havedict = false; /* true if dictionary provided */
|
this.flags = 0; /* gzip header method and flags (0 if zlib) */
|
this.dmax = 0; /* zlib header max distance (INFLATE_STRICT) */
|
this.check = 0; /* protected copy of check value */
|
this.total = 0; /* protected copy of output count */
|
// TODO: may be {}
|
this.head = null; /* where to save gzip header information */
|
|
/* sliding window */
|
this.wbits = 0; /* log base 2 of requested window size */
|
this.wsize = 0; /* window size or zero if not using window */
|
this.whave = 0; /* valid bytes in the window */
|
this.wnext = 0; /* window write index */
|
this.window = null; /* allocated sliding window, if needed */
|
|
/* bit accumulator */
|
this.hold = 0; /* input bit accumulator */
|
this.bits = 0; /* number of bits in "in" */
|
|
/* for string and stored block copying */
|
this.length = 0; /* literal or length of data to copy */
|
this.offset = 0; /* distance back to copy string from */
|
|
/* for table and code decoding */
|
this.extra = 0; /* extra bits needed */
|
|
/* fixed and dynamic code tables */
|
this.lencode = null; /* starting table for length/literal codes */
|
this.distcode = null; /* starting table for distance codes */
|
this.lenbits = 0; /* index bits for lencode */
|
this.distbits = 0; /* index bits for distcode */
|
|
/* dynamic table building */
|
this.ncode = 0; /* number of code length code lengths */
|
this.nlen = 0; /* number of length code lengths */
|
this.ndist = 0; /* number of distance code lengths */
|
this.have = 0; /* number of code lengths in lens[] */
|
this.next = null; /* next available space in codes[] */
|
|
this.lens = new utils.Buf16(320); /* temporary storage for code lengths */
|
this.work = new utils.Buf16(288); /* work area for code table building */
|
|
/*
|
because we don't have pointers in js, we use lencode and distcode directly
|
as buffers so we don't need codes
|
*/
|
//this.codes = new utils.Buf32(ENOUGH); /* space for code tables */
|
this.lendyn = null; /* dynamic table for length/literal codes (JS specific) */
|
this.distdyn = null; /* dynamic table for distance codes (JS specific) */
|
this.sane = 0; /* if false, allow invalid distance too far */
|
this.back = 0; /* bits back of last unprocessed length/lit */
|
this.was = 0; /* initial length of match */
|
}
|
|
function inflateResetKeep(strm) {
|
var state;
|
|
if (!strm || !strm.state) { return Z_STREAM_ERROR; }
|
state = strm.state;
|
strm.total_in = strm.total_out = state.total = 0;
|
strm.msg = ''; /*Z_NULL*/
|
if (state.wrap) { /* to support ill-conceived Java test suite */
|
strm.adler = state.wrap & 1;
|
}
|
state.mode = HEAD;
|
state.last = 0;
|
state.havedict = 0;
|
state.dmax = 32768;
|
state.head = null/*Z_NULL*/;
|
state.hold = 0;
|
state.bits = 0;
|
//state.lencode = state.distcode = state.next = state.codes;
|
state.lencode = state.lendyn = new utils.Buf32(ENOUGH_LENS);
|
state.distcode = state.distdyn = new utils.Buf32(ENOUGH_DISTS);
|
|
state.sane = 1;
|
state.back = -1;
|
//Tracev((stderr, "inflate: reset\n"));
|
return Z_OK;
|
}
|
|
function inflateReset(strm) {
|
var state;
|
|
if (!strm || !strm.state) { return Z_STREAM_ERROR; }
|
state = strm.state;
|
state.wsize = 0;
|
state.whave = 0;
|
state.wnext = 0;
|
return inflateResetKeep(strm);
|
|
}
|
|
function inflateReset2(strm, windowBits) {
|
var wrap;
|
var state;
|
|
/* get the state */
|
if (!strm || !strm.state) { return Z_STREAM_ERROR; }
|
state = strm.state;
|
|
/* extract wrap request from windowBits parameter */
|
if (windowBits < 0) {
|
wrap = 0;
|
windowBits = -windowBits;
|
}
|
else {
|
wrap = (windowBits >> 4) + 1;
|
if (windowBits < 48) {
|
windowBits &= 15;
|
}
|
}
|
|
/* set number of window bits, free window if different */
|
if (windowBits && (windowBits < 8 || windowBits > 15)) {
|
return Z_STREAM_ERROR;
|
}
|
if (state.window !== null && state.wbits !== windowBits) {
|
state.window = null;
|
}
|
|
/* update state and reset the rest of it */
|
state.wrap = wrap;
|
state.wbits = windowBits;
|
return inflateReset(strm);
|
}
|
|
function inflateInit2(strm, windowBits) {
|
var ret;
|
var state;
|
|
if (!strm) { return Z_STREAM_ERROR; }
|
//strm.msg = Z_NULL; /* in case we return an error */
|
|
state = new InflateState();
|
|
//if (state === Z_NULL) return Z_MEM_ERROR;
|
//Tracev((stderr, "inflate: allocated\n"));
|
strm.state = state;
|
state.window = null/*Z_NULL*/;
|
ret = inflateReset2(strm, windowBits);
|
if (ret !== Z_OK) {
|
strm.state = null/*Z_NULL*/;
|
}
|
return ret;
|
}
|
|
function inflateInit(strm) {
|
return inflateInit2(strm, DEF_WBITS);
|
}
|
|
|
/*
|
Return state with length and distance decoding tables and index sizes set to
|
fixed code decoding. Normally this returns fixed tables from inffixed.h.
|
If BUILDFIXED is defined, then instead this routine builds the tables the
|
first time it's called, and returns those tables the first time and
|
thereafter. This reduces the size of the code by about 2K bytes, in
|
exchange for a little execution time. However, BUILDFIXED should not be
|
used for threaded applications, since the rewriting of the tables and virgin
|
may not be thread-safe.
|
*/
|
var virgin = true;
|
|
var lenfix, distfix; // We have no pointers in JS, so keep tables separate
|
|
function fixedtables(state) {
|
/* build fixed huffman tables if first call (may not be thread safe) */
|
if (virgin) {
|
var sym;
|
|
lenfix = new utils.Buf32(512);
|
distfix = new utils.Buf32(32);
|
|
/* literal/length table */
|
sym = 0;
|
while (sym < 144) { state.lens[sym++] = 8; }
|
while (sym < 256) { state.lens[sym++] = 9; }
|
while (sym < 280) { state.lens[sym++] = 7; }
|
while (sym < 288) { state.lens[sym++] = 8; }
|
|
inflate_table(LENS, state.lens, 0, 288, lenfix, 0, state.work, { bits: 9 });
|
|
/* distance table */
|
sym = 0;
|
while (sym < 32) { state.lens[sym++] = 5; }
|
|
inflate_table(DISTS, state.lens, 0, 32, distfix, 0, state.work, { bits: 5 });
|
|
/* do this just once */
|
virgin = false;
|
}
|
|
state.lencode = lenfix;
|
state.lenbits = 9;
|
state.distcode = distfix;
|
state.distbits = 5;
|
}
|
|
|
/*
|
Update the window with the last wsize (normally 32K) bytes written before
|
returning. If window does not exist yet, create it. This is only called
|
when a window is already in use, or when output has been written during this
|
inflate call, but the end of the deflate stream has not been reached yet.
|
It is also called to create a window for dictionary data when a dictionary
|
is loaded.
|
|
Providing output buffers larger than 32K to inflate() should provide a speed
|
advantage, since only the last 32K of output is copied to the sliding window
|
upon return from inflate(), and since all distances after the first 32K of
|
output will fall in the output data, making match copies simpler and faster.
|
The advantage may be dependent on the size of the processor's data caches.
|
*/
|
function updatewindow(strm, src, end, copy) {
|
var dist;
|
var state = strm.state;
|
|
/* if it hasn't been done already, allocate space for the window */
|
if (state.window === null) {
|
state.wsize = 1 << state.wbits;
|
state.wnext = 0;
|
state.whave = 0;
|
|
state.window = new utils.Buf8(state.wsize);
|
}
|
|
/* copy state->wsize or less output bytes into the circular window */
|
if (copy >= state.wsize) {
|
utils.arraySet(state.window, src, end - state.wsize, state.wsize, 0);
|
state.wnext = 0;
|
state.whave = state.wsize;
|
}
|
else {
|
dist = state.wsize - state.wnext;
|
if (dist > copy) {
|
dist = copy;
|
}
|
//zmemcpy(state->window + state->wnext, end - copy, dist);
|
utils.arraySet(state.window, src, end - copy, dist, state.wnext);
|
copy -= dist;
|
if (copy) {
|
//zmemcpy(state->window, end - copy, copy);
|
utils.arraySet(state.window, src, end - copy, copy, 0);
|
state.wnext = copy;
|
state.whave = state.wsize;
|
}
|
else {
|
state.wnext += dist;
|
if (state.wnext === state.wsize) { state.wnext = 0; }
|
if (state.whave < state.wsize) { state.whave += dist; }
|
}
|
}
|
return 0;
|
}
|
|
function inflate(strm, flush) {
|
var state;
|
var input, output; // input/output buffers
|
var next; /* next input INDEX */
|
var put; /* next output INDEX */
|
var have, left; /* available input and output */
|
var hold; /* bit buffer */
|
var bits; /* bits in bit buffer */
|
var _in, _out; /* save starting available input and output */
|
var copy; /* number of stored or match bytes to copy */
|
var from; /* where to copy match bytes from */
|
var from_source;
|
var here = 0; /* current decoding table entry */
|
var here_bits, here_op, here_val; // paked "here" denormalized (JS specific)
|
//var last; /* parent table entry */
|
var last_bits, last_op, last_val; // paked "last" denormalized (JS specific)
|
var len; /* length to copy for repeats, bits to drop */
|
var ret; /* return code */
|
var hbuf = new utils.Buf8(4); /* buffer for gzip header crc calculation */
|
var opts;
|
|
var n; // temporary var for NEED_BITS
|
|
var order = /* permutation of code lengths */
|
[ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 ];
|
|
|
if (!strm || !strm.state || !strm.output ||
|
(!strm.input && strm.avail_in !== 0)) {
|
return Z_STREAM_ERROR;
|
}
|
|
state = strm.state;
|
if (state.mode === TYPE) { state.mode = TYPEDO; } /* skip check */
|
|
|
//--- LOAD() ---
|
put = strm.next_out;
|
output = strm.output;
|
left = strm.avail_out;
|
next = strm.next_in;
|
input = strm.input;
|
have = strm.avail_in;
|
hold = state.hold;
|
bits = state.bits;
|
//---
|
|
_in = have;
|
_out = left;
|
ret = Z_OK;
|
|
inf_leave: // goto emulation
|
for (;;) {
|
switch (state.mode) {
|
case HEAD:
|
if (state.wrap === 0) {
|
state.mode = TYPEDO;
|
break;
|
}
|
//=== NEEDBITS(16);
|
while (bits < 16) {
|
if (have === 0) { break inf_leave; }
|
have--;
|
hold += input[next++] << bits;
|
bits += 8;
|
}
|
//===//
|
if ((state.wrap & 2) && hold === 0x8b1f) { /* gzip header */
|
state.check = 0/*crc32(0L, Z_NULL, 0)*/;
|
//=== CRC2(state.check, hold);
|
hbuf[0] = hold & 0xff;
|
hbuf[1] = (hold >>> 8) & 0xff;
|
state.check = crc32(state.check, hbuf, 2, 0);
|
//===//
|
|
//=== INITBITS();
|
hold = 0;
|
bits = 0;
|
//===//
|
state.mode = FLAGS;
|
break;
|
}
|
state.flags = 0; /* expect zlib header */
|
if (state.head) {
|
state.head.done = false;
|
}
|
if (!(state.wrap & 1) || /* check if zlib header allowed */
|
(((hold & 0xff)/*BITS(8)*/ << 8) + (hold >> 8)) % 31) {
|
strm.msg = 'incorrect header check';
|
state.mode = BAD;
|
break;
|
}
|
if ((hold & 0x0f)/*BITS(4)*/ !== Z_DEFLATED) {
|
strm.msg = 'unknown compression method';
|
state.mode = BAD;
|
break;
|
}
|
//--- DROPBITS(4) ---//
|
hold >>>= 4;
|
bits -= 4;
|
//---//
|
len = (hold & 0x0f)/*BITS(4)*/ + 8;
|
if (state.wbits === 0) {
|
state.wbits = len;
|
}
|
else if (len > state.wbits) {
|
strm.msg = 'invalid window size';
|
state.mode = BAD;
|
break;
|
}
|
state.dmax = 1 << len;
|
//Tracev((stderr, "inflate: zlib header ok\n"));
|
strm.adler = state.check = 1/*adler32(0L, Z_NULL, 0)*/;
|
state.mode = hold & 0x200 ? DICTID : TYPE;
|
//=== INITBITS();
|
hold = 0;
|
bits = 0;
|
//===//
|
break;
|
case FLAGS:
|
//=== NEEDBITS(16); */
|
while (bits < 16) {
|
if (have === 0) { break inf_leave; }
|
have--;
|
hold += input[next++] << bits;
|
bits += 8;
|
}
|
//===//
|
state.flags = hold;
|
if ((state.flags & 0xff) !== Z_DEFLATED) {
|
strm.msg = 'unknown compression method';
|
state.mode = BAD;
|
break;
|
}
|
if (state.flags & 0xe000) {
|
strm.msg = 'unknown header flags set';
|
state.mode = BAD;
|
break;
|
}
|
if (state.head) {
|
state.head.text = ((hold >> 8) & 1);
|
}
|
if (state.flags & 0x0200) {
|
//=== CRC2(state.check, hold);
|
hbuf[0] = hold & 0xff;
|
hbuf[1] = (hold >>> 8) & 0xff;
|
state.check = crc32(state.check, hbuf, 2, 0);
|
//===//
|
}
|
//=== INITBITS();
|
hold = 0;
|
bits = 0;
|
//===//
|
state.mode = TIME;
|
/* falls through */
|
case TIME:
|
//=== NEEDBITS(32); */
|
while (bits < 32) {
|
if (have === 0) { break inf_leave; }
|
have--;
|
hold += input[next++] << bits;
|
bits += 8;
|
}
|
//===//
|
if (state.head) {
|
state.head.time = hold;
|
}
|
if (state.flags & 0x0200) {
|
//=== CRC4(state.check, hold)
|
hbuf[0] = hold & 0xff;
|
hbuf[1] = (hold >>> 8) & 0xff;
|
hbuf[2] = (hold >>> 16) & 0xff;
|
hbuf[3] = (hold >>> 24) & 0xff;
|
state.check = crc32(state.check, hbuf, 4, 0);
|
//===
|
}
|
//=== INITBITS();
|
hold = 0;
|
bits = 0;
|
//===//
|
state.mode = OS;
|
/* falls through */
|
case OS:
|
//=== NEEDBITS(16); */
|
while (bits < 16) {
|
if (have === 0) { break inf_leave; }
|
have--;
|
hold += input[next++] << bits;
|
bits += 8;
|
}
|
//===//
|
if (state.head) {
|
state.head.xflags = (hold & 0xff);
|
state.head.os = (hold >> 8);
|
}
|
if (state.flags & 0x0200) {
|
//=== CRC2(state.check, hold);
|
hbuf[0] = hold & 0xff;
|
hbuf[1] = (hold >>> 8) & 0xff;
|
state.check = crc32(state.check, hbuf, 2, 0);
|
//===//
|
}
|
//=== INITBITS();
|
hold = 0;
|
bits = 0;
|
//===//
|
state.mode = EXLEN;
|
/* falls through */
|
case EXLEN:
|
if (state.flags & 0x0400) {
|
//=== NEEDBITS(16); */
|
while (bits < 16) {
|
if (have === 0) { break inf_leave; }
|
have--;
|
hold += input[next++] << bits;
|
bits += 8;
|
}
|
//===//
|
state.length = hold;
|
if (state.head) {
|
state.head.extra_len = hold;
|
}
|
if (state.flags & 0x0200) {
|
//=== CRC2(state.check, hold);
|
hbuf[0] = hold & 0xff;
|
hbuf[1] = (hold >>> 8) & 0xff;
|
state.check = crc32(state.check, hbuf, 2, 0);
|
//===//
|
}
|
//=== INITBITS();
|
hold = 0;
|
bits = 0;
|
//===//
|
}
|
else if (state.head) {
|
state.head.extra = null/*Z_NULL*/;
|
}
|
state.mode = EXTRA;
|
/* falls through */
|
case EXTRA:
|
if (state.flags & 0x0400) {
|
copy = state.length;
|
if (copy > have) { copy = have; }
|
if (copy) {
|
if (state.head) {
|
len = state.head.extra_len - state.length;
|
if (!state.head.extra) {
|
// Use untyped array for more convenient processing later
|
state.head.extra = new Array(state.head.extra_len);
|
}
|
utils.arraySet(
|
state.head.extra,
|
input,
|
next,
|
// extra field is limited to 65536 bytes
|
// - no need for additional size check
|
copy,
|
/*len + copy > state.head.extra_max - len ? state.head.extra_max : copy,*/
|
len
|
);
|
//zmemcpy(state.head.extra + len, next,
|
// len + copy > state.head.extra_max ?
|
// state.head.extra_max - len : copy);
|
}
|
if (state.flags & 0x0200) {
|
state.check = crc32(state.check, input, copy, next);
|
}
|
have -= copy;
|
next += copy;
|
state.length -= copy;
|
}
|
if (state.length) { break inf_leave; }
|
}
|
state.length = 0;
|
state.mode = NAME;
|
/* falls through */
|
case NAME:
|
if (state.flags & 0x0800) {
|
if (have === 0) { break inf_leave; }
|
copy = 0;
|
do {
|
// TODO: 2 or 1 bytes?
|
len = input[next + copy++];
|
/* use constant limit because in js we should not preallocate memory */
|
if (state.head && len &&
|
(state.length < 65536 /*state.head.name_max*/)) {
|
state.head.name += String.fromCharCode(len);
|
}
|
} while (len && copy < have);
|
|
if (state.flags & 0x0200) {
|
state.check = crc32(state.check, input, copy, next);
|
}
|
have -= copy;
|
next += copy;
|
if (len) { break inf_leave; }
|
}
|
else if (state.head) {
|
state.head.name = null;
|
}
|
state.length = 0;
|
state.mode = COMMENT;
|
/* falls through */
|
case COMMENT:
|
if (state.flags & 0x1000) {
|
if (have === 0) { break inf_leave; }
|
copy = 0;
|
do {
|
len = input[next + copy++];
|
/* use constant limit because in js we should not preallocate memory */
|
if (state.head && len &&
|
(state.length < 65536 /*state.head.comm_max*/)) {
|
state.head.comment += String.fromCharCode(len);
|
}
|
} while (len && copy < have);
|
if (state.flags & 0x0200) {
|
state.check = crc32(state.check, input, copy, next);
|
}
|
have -= copy;
|
next += copy;
|
if (len) { break inf_leave; }
|
}
|
else if (state.head) {
|
state.head.comment = null;
|
}
|
state.mode = HCRC;
|
/* falls through */
|
case HCRC:
|
if (state.flags & 0x0200) {
|
//=== NEEDBITS(16); */
|
while (bits < 16) {
|
if (have === 0) { break inf_leave; }
|
have--;
|
hold += input[next++] << bits;
|
bits += 8;
|
}
|
//===//
|
if (hold !== (state.check & 0xffff)) {
|
strm.msg = 'header crc mismatch';
|
state.mode = BAD;
|
break;
|
}
|
//=== INITBITS();
|
hold = 0;
|
bits = 0;
|
//===//
|
}
|
if (state.head) {
|
state.head.hcrc = ((state.flags >> 9) & 1);
|
state.head.done = true;
|
}
|
strm.adler = state.check = 0;
|
state.mode = TYPE;
|
break;
|
case DICTID:
|
//=== NEEDBITS(32); */
|
while (bits < 32) {
|
if (have === 0) { break inf_leave; }
|
have--;
|
hold += input[next++] << bits;
|
bits += 8;
|
}
|
//===//
|
strm.adler = state.check = zswap32(hold);
|
//=== INITBITS();
|
hold = 0;
|
bits = 0;
|
//===//
|
state.mode = DICT;
|
/* falls through */
|
case DICT:
|
if (state.havedict === 0) {
|
//--- RESTORE() ---
|
strm.next_out = put;
|
strm.avail_out = left;
|
strm.next_in = next;
|
strm.avail_in = have;
|
state.hold = hold;
|
state.bits = bits;
|
//---
|
return Z_NEED_DICT;
|
}
|
strm.adler = state.check = 1/*adler32(0L, Z_NULL, 0)*/;
|
state.mode = TYPE;
|
/* falls through */
|
case TYPE:
|
if (flush === Z_BLOCK || flush === Z_TREES) { break inf_leave; }
|
/* falls through */
|
case TYPEDO:
|
if (state.last) {
|
//--- BYTEBITS() ---//
|
hold >>>= bits & 7;
|
bits -= bits & 7;
|
//---//
|
state.mode = CHECK;
|
break;
|
}
|
//=== NEEDBITS(3); */
|
while (bits < 3) {
|
if (have === 0) { break inf_leave; }
|
have--;
|
hold += input[next++] << bits;
|
bits += 8;
|
}
|
//===//
|
state.last = (hold & 0x01)/*BITS(1)*/;
|
//--- DROPBITS(1) ---//
|
hold >>>= 1;
|
bits -= 1;
|
//---//
|
|
switch ((hold & 0x03)/*BITS(2)*/) {
|
case 0: /* stored block */
|
//Tracev((stderr, "inflate: stored block%s\n",
|
// state.last ? " (last)" : ""));
|
state.mode = STORED;
|
break;
|
case 1: /* fixed block */
|
fixedtables(state);
|
//Tracev((stderr, "inflate: fixed codes block%s\n",
|
// state.last ? " (last)" : ""));
|
state.mode = LEN_; /* decode codes */
|
if (flush === Z_TREES) {
|
//--- DROPBITS(2) ---//
|
hold >>>= 2;
|
bits -= 2;
|
//---//
|
break inf_leave;
|
}
|
break;
|
case 2: /* dynamic block */
|
//Tracev((stderr, "inflate: dynamic codes block%s\n",
|
// state.last ? " (last)" : ""));
|
state.mode = TABLE;
|
break;
|
case 3:
|
strm.msg = 'invalid block type';
|
state.mode = BAD;
|
}
|
//--- DROPBITS(2) ---//
|
hold >>>= 2;
|
bits -= 2;
|
//---//
|
break;
|
case STORED:
|
//--- BYTEBITS() ---// /* go to byte boundary */
|
hold >>>= bits & 7;
|
bits -= bits & 7;
|
//---//
|
//=== NEEDBITS(32); */
|
while (bits < 32) {
|
if (have === 0) { break inf_leave; }
|
have--;
|
hold += input[next++] << bits;
|
bits += 8;
|
}
|
//===//
|
if ((hold & 0xffff) !== ((hold >>> 16) ^ 0xffff)) {
|
strm.msg = 'invalid stored block lengths';
|
state.mode = BAD;
|
break;
|
}
|
state.length = hold & 0xffff;
|
//Tracev((stderr, "inflate: stored length %u\n",
|
// state.length));
|
//=== INITBITS();
|
hold = 0;
|
bits = 0;
|
//===//
|
state.mode = COPY_;
|
if (flush === Z_TREES) { break inf_leave; }
|
/* falls through */
|
case COPY_:
|
state.mode = COPY;
|
/* falls through */
|
case COPY:
|
copy = state.length;
|
if (copy) {
|
if (copy > have) { copy = have; }
|
if (copy > left) { copy = left; }
|
if (copy === 0) { break inf_leave; }
|
//--- zmemcpy(put, next, copy); ---
|
utils.arraySet(output, input, next, copy, put);
|
//---//
|
have -= copy;
|
next += copy;
|
left -= copy;
|
put += copy;
|
state.length -= copy;
|
break;
|
}
|
//Tracev((stderr, "inflate: stored end\n"));
|
state.mode = TYPE;
|
break;
|
case TABLE:
|
//=== NEEDBITS(14); */
|
while (bits < 14) {
|
if (have === 0) { break inf_leave; }
|
have--;
|
hold += input[next++] << bits;
|
bits += 8;
|
}
|
//===//
|
state.nlen = (hold & 0x1f)/*BITS(5)*/ + 257;
|
//--- DROPBITS(5) ---//
|
hold >>>= 5;
|
bits -= 5;
|
//---//
|
state.ndist = (hold & 0x1f)/*BITS(5)*/ + 1;
|
//--- DROPBITS(5) ---//
|
hold >>>= 5;
|
bits -= 5;
|
//---//
|
state.ncode = (hold & 0x0f)/*BITS(4)*/ + 4;
|
//--- DROPBITS(4) ---//
|
hold >>>= 4;
|
bits -= 4;
|
//---//
|
//#ifndef PKZIP_BUG_WORKAROUND
|
if (state.nlen > 286 || state.ndist > 30) {
|
strm.msg = 'too many length or distance symbols';
|
state.mode = BAD;
|
break;
|
}
|
//#endif
|
//Tracev((stderr, "inflate: table sizes ok\n"));
|
state.have = 0;
|
state.mode = LENLENS;
|
/* falls through */
|
case LENLENS:
|
while (state.have < state.ncode) {
|
//=== NEEDBITS(3);
|
while (bits < 3) {
|
if (have === 0) { break inf_leave; }
|
have--;
|
hold += input[next++] << bits;
|
bits += 8;
|
}
|
//===//
|
state.lens[order[state.have++]] = (hold & 0x07);//BITS(3);
|
//--- DROPBITS(3) ---//
|
hold >>>= 3;
|
bits -= 3;
|
//---//
|
}
|
while (state.have < 19) {
|
state.lens[order[state.have++]] = 0;
|
}
|
// We have separate tables & no pointers. 2 commented lines below not needed.
|
//state.next = state.codes;
|
//state.lencode = state.next;
|
// Switch to use dynamic table
|
state.lencode = state.lendyn;
|
state.lenbits = 7;
|
|
opts = { bits: state.lenbits };
|
ret = inflate_table(CODES, state.lens, 0, 19, state.lencode, 0, state.work, opts);
|
state.lenbits = opts.bits;
|
|
if (ret) {
|
strm.msg = 'invalid code lengths set';
|
state.mode = BAD;
|
break;
|
}
|
//Tracev((stderr, "inflate: code lengths ok\n"));
|
state.have = 0;
|
state.mode = CODELENS;
|
/* falls through */
|
case CODELENS:
|
while (state.have < state.nlen + state.ndist) {
|
for (;;) {
|
here = state.lencode[hold & ((1 << state.lenbits) - 1)];/*BITS(state.lenbits)*/
|
here_bits = here >>> 24;
|
here_op = (here >>> 16) & 0xff;
|
here_val = here & 0xffff;
|
|
if ((here_bits) <= bits) { break; }
|
//--- PULLBYTE() ---//
|
if (have === 0) { break inf_leave; }
|
have--;
|
hold += input[next++] << bits;
|
bits += 8;
|
//---//
|
}
|
if (here_val < 16) {
|
//--- DROPBITS(here.bits) ---//
|
hold >>>= here_bits;
|
bits -= here_bits;
|
//---//
|
state.lens[state.have++] = here_val;
|
}
|
else {
|
if (here_val === 16) {
|
//=== NEEDBITS(here.bits + 2);
|
n = here_bits + 2;
|
while (bits < n) {
|
if (have === 0) { break inf_leave; }
|
have--;
|
hold += input[next++] << bits;
|
bits += 8;
|
}
|
//===//
|
//--- DROPBITS(here.bits) ---//
|
hold >>>= here_bits;
|
bits -= here_bits;
|
//---//
|
if (state.have === 0) {
|
strm.msg = 'invalid bit length repeat';
|
state.mode = BAD;
|
break;
|
}
|
len = state.lens[state.have - 1];
|
copy = 3 + (hold & 0x03);//BITS(2);
|
//--- DROPBITS(2) ---//
|
hold >>>= 2;
|
bits -= 2;
|
//---//
|
}
|
else if (here_val === 17) {
|
//=== NEEDBITS(here.bits + 3);
|
n = here_bits + 3;
|
while (bits < n) {
|
if (have === 0) { break inf_leave; }
|
have--;
|
hold += input[next++] << bits;
|
bits += 8;
|
}
|
//===//
|
//--- DROPBITS(here.bits) ---//
|
hold >>>= here_bits;
|
bits -= here_bits;
|
//---//
|
len = 0;
|
copy = 3 + (hold & 0x07);//BITS(3);
|
//--- DROPBITS(3) ---//
|
hold >>>= 3;
|
bits -= 3;
|
//---//
|
}
|
else {
|
//=== NEEDBITS(here.bits + 7);
|
n = here_bits + 7;
|
while (bits < n) {
|
if (have === 0) { break inf_leave; }
|
have--;
|
hold += input[next++] << bits;
|
bits += 8;
|
}
|
//===//
|
//--- DROPBITS(here.bits) ---//
|
hold >>>= here_bits;
|
bits -= here_bits;
|
//---//
|
len = 0;
|
copy = 11 + (hold & 0x7f);//BITS(7);
|
//--- DROPBITS(7) ---//
|
hold >>>= 7;
|
bits -= 7;
|
//---//
|
}
|
if (state.have + copy > state.nlen + state.ndist) {
|
strm.msg = 'invalid bit length repeat';
|
state.mode = BAD;
|
break;
|
}
|
while (copy--) {
|
state.lens[state.have++] = len;
|
}
|
}
|
}
|
|
/* handle error breaks in while */
|
if (state.mode === BAD) { break; }
|
|
/* check for end-of-block code (better have one) */
|
if (state.lens[256] === 0) {
|
strm.msg = 'invalid code -- missing end-of-block';
|
state.mode = BAD;
|
break;
|
}
|
|
/* build code tables -- note: do not change the lenbits or distbits
|
values here (9 and 6) without reading the comments in inftrees.h
|
concerning the ENOUGH constants, which depend on those values */
|
state.lenbits = 9;
|
|
opts = { bits: state.lenbits };
|
ret = inflate_table(LENS, state.lens, 0, state.nlen, state.lencode, 0, state.work, opts);
|
// We have separate tables & no pointers. 2 commented lines below not needed.
|
// state.next_index = opts.table_index;
|
state.lenbits = opts.bits;
|
// state.lencode = state.next;
|
|
if (ret) {
|
strm.msg = 'invalid literal/lengths set';
|
state.mode = BAD;
|
break;
|
}
|
|
state.distbits = 6;
|
//state.distcode.copy(state.codes);
|
// Switch to use dynamic table
|
state.distcode = state.distdyn;
|
opts = { bits: state.distbits };
|
ret = inflate_table(DISTS, state.lens, state.nlen, state.ndist, state.distcode, 0, state.work, opts);
|
// We have separate tables & no pointers. 2 commented lines below not needed.
|
// state.next_index = opts.table_index;
|
state.distbits = opts.bits;
|
// state.distcode = state.next;
|
|
if (ret) {
|
strm.msg = 'invalid distances set';
|
state.mode = BAD;
|
break;
|
}
|
//Tracev((stderr, 'inflate: codes ok\n'));
|
state.mode = LEN_;
|
if (flush === Z_TREES) { break inf_leave; }
|
/* falls through */
|
case LEN_:
|
state.mode = LEN;
|
/* falls through */
|
case LEN:
|
if (have >= 6 && left >= 258) {
|
//--- RESTORE() ---
|
strm.next_out = put;
|
strm.avail_out = left;
|
strm.next_in = next;
|
strm.avail_in = have;
|
state.hold = hold;
|
state.bits = bits;
|
//---
|
inflate_fast(strm, _out);
|
//--- LOAD() ---
|
put = strm.next_out;
|
output = strm.output;
|
left = strm.avail_out;
|
next = strm.next_in;
|
input = strm.input;
|
have = strm.avail_in;
|
hold = state.hold;
|
bits = state.bits;
|
//---
|
|
if (state.mode === TYPE) {
|
state.back = -1;
|
}
|
break;
|
}
|
state.back = 0;
|
for (;;) {
|
here = state.lencode[hold & ((1 << state.lenbits) - 1)]; /*BITS(state.lenbits)*/
|
here_bits = here >>> 24;
|
here_op = (here >>> 16) & 0xff;
|
here_val = here & 0xffff;
|
|
if (here_bits <= bits) { break; }
|
//--- PULLBYTE() ---//
|
if (have === 0) { break inf_leave; }
|
have--;
|
hold += input[next++] << bits;
|
bits += 8;
|
//---//
|
}
|
if (here_op && (here_op & 0xf0) === 0) {
|
last_bits = here_bits;
|
last_op = here_op;
|
last_val = here_val;
|
for (;;) {
|
here = state.lencode[last_val +
|
((hold & ((1 << (last_bits + last_op)) - 1))/*BITS(last.bits + last.op)*/ >> last_bits)];
|
here_bits = here >>> 24;
|
here_op = (here >>> 16) & 0xff;
|
here_val = here & 0xffff;
|
|
if ((last_bits + here_bits) <= bits) { break; }
|
//--- PULLBYTE() ---//
|
if (have === 0) { break inf_leave; }
|
have--;
|
hold += input[next++] << bits;
|
bits += 8;
|
//---//
|
}
|
//--- DROPBITS(last.bits) ---//
|
hold >>>= last_bits;
|
bits -= last_bits;
|
//---//
|
state.back += last_bits;
|
}
|
//--- DROPBITS(here.bits) ---//
|
hold >>>= here_bits;
|
bits -= here_bits;
|
//---//
|
state.back += here_bits;
|
state.length = here_val;
|
if (here_op === 0) {
|
//Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?
|
// "inflate: literal '%c'\n" :
|
// "inflate: literal 0x%02x\n", here.val));
|
state.mode = LIT;
|
break;
|
}
|
if (here_op & 32) {
|
//Tracevv((stderr, "inflate: end of block\n"));
|
state.back = -1;
|
state.mode = TYPE;
|
break;
|
}
|
if (here_op & 64) {
|
strm.msg = 'invalid literal/length code';
|
state.mode = BAD;
|
break;
|
}
|
state.extra = here_op & 15;
|
state.mode = LENEXT;
|
/* falls through */
|
case LENEXT:
|
if (state.extra) {
|
//=== NEEDBITS(state.extra);
|
n = state.extra;
|
while (bits < n) {
|
if (have === 0) { break inf_leave; }
|
have--;
|
hold += input[next++] << bits;
|
bits += 8;
|
}
|
//===//
|
state.length += hold & ((1 << state.extra) - 1)/*BITS(state.extra)*/;
|
//--- DROPBITS(state.extra) ---//
|
hold >>>= state.extra;
|
bits -= state.extra;
|
//---//
|
state.back += state.extra;
|
}
|
//Tracevv((stderr, "inflate: length %u\n", state.length));
|
state.was = state.length;
|
state.mode = DIST;
|
/* falls through */
|
case DIST:
|
for (;;) {
|
here = state.distcode[hold & ((1 << state.distbits) - 1)];/*BITS(state.distbits)*/
|
here_bits = here >>> 24;
|
here_op = (here >>> 16) & 0xff;
|
here_val = here & 0xffff;
|
|
if ((here_bits) <= bits) { break; }
|
//--- PULLBYTE() ---//
|
if (have === 0) { break inf_leave; }
|
have--;
|
hold += input[next++] << bits;
|
bits += 8;
|
//---//
|
}
|
if ((here_op & 0xf0) === 0) {
|
last_bits = here_bits;
|
last_op = here_op;
|
last_val = here_val;
|
for (;;) {
|
here = state.distcode[last_val +
|
((hold & ((1 << (last_bits + last_op)) - 1))/*BITS(last.bits + last.op)*/ >> last_bits)];
|
here_bits = here >>> 24;
|
here_op = (here >>> 16) & 0xff;
|
here_val = here & 0xffff;
|
|
if ((last_bits + here_bits) <= bits) { break; }
|
//--- PULLBYTE() ---//
|
if (have === 0) { break inf_leave; }
|
have--;
|
hold += input[next++] << bits;
|
bits += 8;
|
//---//
|
}
|
//--- DROPBITS(last.bits) ---//
|
hold >>>= last_bits;
|
bits -= last_bits;
|
//---//
|
state.back += last_bits;
|
}
|
//--- DROPBITS(here.bits) ---//
|
hold >>>= here_bits;
|
bits -= here_bits;
|
//---//
|
state.back += here_bits;
|
if (here_op & 64) {
|
strm.msg = 'invalid distance code';
|
state.mode = BAD;
|
break;
|
}
|
state.offset = here_val;
|
state.extra = (here_op) & 15;
|
state.mode = DISTEXT;
|
/* falls through */
|
case DISTEXT:
|
if (state.extra) {
|
//=== NEEDBITS(state.extra);
|
n = state.extra;
|
while (bits < n) {
|
if (have === 0) { break inf_leave; }
|
have--;
|
hold += input[next++] << bits;
|
bits += 8;
|
}
|
//===//
|
state.offset += hold & ((1 << state.extra) - 1)/*BITS(state.extra)*/;
|
//--- DROPBITS(state.extra) ---//
|
hold >>>= state.extra;
|
bits -= state.extra;
|
//---//
|
state.back += state.extra;
|
}
|
//#ifdef INFLATE_STRICT
|
if (state.offset > state.dmax) {
|
strm.msg = 'invalid distance too far back';
|
state.mode = BAD;
|
break;
|
}
|
//#endif
|
//Tracevv((stderr, "inflate: distance %u\n", state.offset));
|
state.mode = MATCH;
|
/* falls through */
|
case MATCH:
|
if (left === 0) { break inf_leave; }
|
copy = _out - left;
|
if (state.offset > copy) { /* copy from window */
|
copy = state.offset - copy;
|
if (copy > state.whave) {
|
if (state.sane) {
|
strm.msg = 'invalid distance too far back';
|
state.mode = BAD;
|
break;
|
}
|
// (!) This block is disabled in zlib defaults,
|
// don't enable it for binary compatibility
|
//#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
|
// Trace((stderr, "inflate.c too far\n"));
|
// copy -= state.whave;
|
// if (copy > state.length) { copy = state.length; }
|
// if (copy > left) { copy = left; }
|
// left -= copy;
|
// state.length -= copy;
|
// do {
|
// output[put++] = 0;
|
// } while (--copy);
|
// if (state.length === 0) { state.mode = LEN; }
|
// break;
|
//#endif
|
}
|
if (copy > state.wnext) {
|
copy -= state.wnext;
|
from = state.wsize - copy;
|
}
|
else {
|
from = state.wnext - copy;
|
}
|
if (copy > state.length) { copy = state.length; }
|
from_source = state.window;
|
}
|
else { /* copy from output */
|
from_source = output;
|
from = put - state.offset;
|
copy = state.length;
|
}
|
if (copy > left) { copy = left; }
|
left -= copy;
|
state.length -= copy;
|
do {
|
output[put++] = from_source[from++];
|
} while (--copy);
|
if (state.length === 0) { state.mode = LEN; }
|
break;
|
case LIT:
|
if (left === 0) { break inf_leave; }
|
output[put++] = state.length;
|
left--;
|
state.mode = LEN;
|
break;
|
case CHECK:
|
if (state.wrap) {
|
//=== NEEDBITS(32);
|
while (bits < 32) {
|
if (have === 0) { break inf_leave; }
|
have--;
|
// Use '|' instead of '+' to make sure that result is signed
|
hold |= input[next++] << bits;
|
bits += 8;
|
}
|
//===//
|
_out -= left;
|
strm.total_out += _out;
|
state.total += _out;
|
if (_out) {
|
strm.adler = state.check =
|
/*UPDATE(state.check, put - _out, _out);*/
|
(state.flags ? crc32(state.check, output, _out, put - _out) : adler32(state.check, output, _out, put - _out));
|
|
}
|
_out = left;
|
// NB: crc32 stored as signed 32-bit int, zswap32 returns signed too
|
if ((state.flags ? hold : zswap32(hold)) !== state.check) {
|
strm.msg = 'incorrect data check';
|
state.mode = BAD;
|
break;
|
}
|
//=== INITBITS();
|
hold = 0;
|
bits = 0;
|
//===//
|
//Tracev((stderr, "inflate: check matches trailer\n"));
|
}
|
state.mode = LENGTH;
|
/* falls through */
|
case LENGTH:
|
if (state.wrap && state.flags) {
|
//=== NEEDBITS(32);
|
while (bits < 32) {
|
if (have === 0) { break inf_leave; }
|
have--;
|
hold += input[next++] << bits;
|
bits += 8;
|
}
|
//===//
|
if (hold !== (state.total & 0xffffffff)) {
|
strm.msg = 'incorrect length check';
|
state.mode = BAD;
|
break;
|
}
|
//=== INITBITS();
|
hold = 0;
|
bits = 0;
|
//===//
|
//Tracev((stderr, "inflate: length matches trailer\n"));
|
}
|
state.mode = DONE;
|
/* falls through */
|
case DONE:
|
ret = Z_STREAM_END;
|
break inf_leave;
|
case BAD:
|
ret = Z_DATA_ERROR;
|
break inf_leave;
|
case MEM:
|
return Z_MEM_ERROR;
|
case SYNC:
|
/* falls through */
|
default:
|
return Z_STREAM_ERROR;
|
}
|
}
|
|
// inf_leave <- here is real place for "goto inf_leave", emulated via "break inf_leave"
|
|
/*
|
Return from inflate(), updating the total counts and the check value.
|
If there was no progress during the inflate() call, return a buffer
|
error. Call updatewindow() to create and/or update the window state.
|
Note: a memory error from inflate() is non-recoverable.
|
*/
|
|
//--- RESTORE() ---
|
strm.next_out = put;
|
strm.avail_out = left;
|
strm.next_in = next;
|
strm.avail_in = have;
|
state.hold = hold;
|
state.bits = bits;
|
//---
|
|
if (state.wsize || (_out !== strm.avail_out && state.mode < BAD &&
|
(state.mode < CHECK || flush !== Z_FINISH))) {
|
if (updatewindow(strm, strm.output, strm.next_out, _out - strm.avail_out)) {
|
state.mode = MEM;
|
return Z_MEM_ERROR;
|
}
|
}
|
_in -= strm.avail_in;
|
_out -= strm.avail_out;
|
strm.total_in += _in;
|
strm.total_out += _out;
|
state.total += _out;
|
if (state.wrap && _out) {
|
strm.adler = state.check = /*UPDATE(state.check, strm.next_out - _out, _out);*/
|
(state.flags ? crc32(state.check, output, _out, strm.next_out - _out) : adler32(state.check, output, _out, strm.next_out - _out));
|
}
|
strm.data_type = state.bits + (state.last ? 64 : 0) +
|
(state.mode === TYPE ? 128 : 0) +
|
(state.mode === LEN_ || state.mode === COPY_ ? 256 : 0);
|
if (((_in === 0 && _out === 0) || flush === Z_FINISH) && ret === Z_OK) {
|
ret = Z_BUF_ERROR;
|
}
|
return ret;
|
}
|
|
function inflateEnd(strm) {
|
|
if (!strm || !strm.state /*|| strm->zfree == (free_func)0*/) {
|
return Z_STREAM_ERROR;
|
}
|
|
var state = strm.state;
|
if (state.window) {
|
state.window = null;
|
}
|
strm.state = null;
|
return Z_OK;
|
}
|
|
function inflateGetHeader(strm, head) {
|
var state;
|
|
/* check state */
|
if (!strm || !strm.state) { return Z_STREAM_ERROR; }
|
state = strm.state;
|
if ((state.wrap & 2) === 0) { return Z_STREAM_ERROR; }
|
|
/* save header structure */
|
state.head = head;
|
head.done = false;
|
return Z_OK;
|
}
|
|
function inflateSetDictionary(strm, dictionary) {
|
var dictLength = dictionary.length;
|
|
var state;
|
var dictid;
|
var ret;
|
|
/* check state */
|
if (!strm /* == Z_NULL */ || !strm.state /* == Z_NULL */) { return Z_STREAM_ERROR; }
|
state = strm.state;
|
|
if (state.wrap !== 0 && state.mode !== DICT) {
|
return Z_STREAM_ERROR;
|
}
|
|
/* check for correct dictionary identifier */
|
if (state.mode === DICT) {
|
dictid = 1; /* adler32(0, null, 0)*/
|
/* dictid = adler32(dictid, dictionary, dictLength); */
|
dictid = adler32(dictid, dictionary, dictLength, 0);
|
if (dictid !== state.check) {
|
return Z_DATA_ERROR;
|
}
|
}
|
/* copy dictionary to window using updatewindow(), which will amend the
|
existing dictionary if appropriate */
|
ret = updatewindow(strm, dictionary, dictLength, dictLength);
|
if (ret) {
|
state.mode = MEM;
|
return Z_MEM_ERROR;
|
}
|
state.havedict = 1;
|
// Tracev((stderr, "inflate: dictionary set\n"));
|
return Z_OK;
|
}
|
|
exports.inflateReset = inflateReset;
|
exports.inflateReset2 = inflateReset2;
|
exports.inflateResetKeep = inflateResetKeep;
|
exports.inflateInit = inflateInit;
|
exports.inflateInit2 = inflateInit2;
|
exports.inflate = inflate;
|
exports.inflateEnd = inflateEnd;
|
exports.inflateGetHeader = inflateGetHeader;
|
exports.inflateSetDictionary = inflateSetDictionary;
|
exports.inflateInfo = 'pako inflate (from Nodeca project)';
|
|
/* Not implemented
|
exports.inflateCopy = inflateCopy;
|
exports.inflateGetDictionary = inflateGetDictionary;
|
exports.inflateMark = inflateMark;
|
exports.inflatePrime = inflatePrime;
|
exports.inflateSync = inflateSync;
|
exports.inflateSyncPoint = inflateSyncPoint;
|
exports.inflateUndermine = inflateUndermine;
|
*/
|
|
},{"../utils/common":65,"./adler32":67,"./crc32":69,"./inffast":72,"./inftrees":74}],74:[function(require,module,exports){
|
'use strict';
|
|
// (C) 1995-2013 Jean-loup Gailly and Mark Adler
|
// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
|
//
|
// This software is provided 'as-is', without any express or implied
|
// warranty. In no event will the authors be held liable for any damages
|
// arising from the use of this software.
|
//
|
// Permission is granted to anyone to use this software for any purpose,
|
// including commercial applications, and to alter it and redistribute it
|
// freely, subject to the following restrictions:
|
//
|
// 1. The origin of this software must not be misrepresented; you must not
|
// claim that you wrote the original software. If you use this software
|
// in a product, an acknowledgment in the product documentation would be
|
// appreciated but is not required.
|
// 2. Altered source versions must be plainly marked as such, and must not be
|
// misrepresented as being the original software.
|
// 3. This notice may not be removed or altered from any source distribution.
|
|
var utils = require('../utils/common');
|
|
var MAXBITS = 15;
|
var ENOUGH_LENS = 852;
|
var ENOUGH_DISTS = 592;
|
//var ENOUGH = (ENOUGH_LENS+ENOUGH_DISTS);
|
|
var CODES = 0;
|
var LENS = 1;
|
var DISTS = 2;
|
|
var lbase = [ /* Length codes 257..285 base */
|
3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
|
35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0
|
];
|
|
var lext = [ /* Length codes 257..285 extra */
|
16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18,
|
19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 72, 78
|
];
|
|
var dbase = [ /* Distance codes 0..29 base */
|
1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
|
257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
|
8193, 12289, 16385, 24577, 0, 0
|
];
|
|
var dext = [ /* Distance codes 0..29 extra */
|
16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22,
|
23, 23, 24, 24, 25, 25, 26, 26, 27, 27,
|
28, 28, 29, 29, 64, 64
|
];
|
|
module.exports = function inflate_table(type, lens, lens_index, codes, table, table_index, work, opts)
|
{
|
var bits = opts.bits;
|
//here = opts.here; /* table entry for duplication */
|
|
var len = 0; /* a code's length in bits */
|
var sym = 0; /* index of code symbols */
|
var min = 0, max = 0; /* minimum and maximum code lengths */
|
var root = 0; /* number of index bits for root table */
|
var curr = 0; /* number of index bits for current table */
|
var drop = 0; /* code bits to drop for sub-table */
|
var left = 0; /* number of prefix codes available */
|
var used = 0; /* code entries in table used */
|
var huff = 0; /* Huffman code */
|
var incr; /* for incrementing code, index */
|
var fill; /* index for replicating entries */
|
var low; /* low bits for current root entry */
|
var mask; /* mask for low root bits */
|
var next; /* next available space in table */
|
var base = null; /* base value table to use */
|
var base_index = 0;
|
// var shoextra; /* extra bits table to use */
|
var end; /* use base and extra for symbol > end */
|
var count = new utils.Buf16(MAXBITS + 1); //[MAXBITS+1]; /* number of codes of each length */
|
var offs = new utils.Buf16(MAXBITS + 1); //[MAXBITS+1]; /* offsets in table for each length */
|
var extra = null;
|
var extra_index = 0;
|
|
var here_bits, here_op, here_val;
|
|
/*
|
Process a set of code lengths to create a canonical Huffman code. The
|
code lengths are lens[0..codes-1]. Each length corresponds to the
|
symbols 0..codes-1. The Huffman code is generated by first sorting the
|
symbols by length from short to long, and retaining the symbol order
|
for codes with equal lengths. Then the code starts with all zero bits
|
for the first code of the shortest length, and the codes are integer
|
increments for the same length, and zeros are appended as the length
|
increases. For the deflate format, these bits are stored backwards
|
from their more natural integer increment ordering, and so when the
|
decoding tables are built in the large loop below, the integer codes
|
are incremented backwards.
|
|
This routine assumes, but does not check, that all of the entries in
|
lens[] are in the range 0..MAXBITS. The caller must assure this.
|
1..MAXBITS is interpreted as that code length. zero means that that
|
symbol does not occur in this code.
|
|
The codes are sorted by computing a count of codes for each length,
|
creating from that a table of starting indices for each length in the
|
sorted table, and then entering the symbols in order in the sorted
|
table. The sorted table is work[], with that space being provided by
|
the caller.
|
|
The length counts are used for other purposes as well, i.e. finding
|
the minimum and maximum length codes, determining if there are any
|
codes at all, checking for a valid set of lengths, and looking ahead
|
at length counts to determine sub-table sizes when building the
|
decoding tables.
|
*/
|
|
/* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */
|
for (len = 0; len <= MAXBITS; len++) {
|
count[len] = 0;
|
}
|
for (sym = 0; sym < codes; sym++) {
|
count[lens[lens_index + sym]]++;
|
}
|
|
/* bound code lengths, force root to be within code lengths */
|
root = bits;
|
for (max = MAXBITS; max >= 1; max--) {
|
if (count[max] !== 0) { break; }
|
}
|
if (root > max) {
|
root = max;
|
}
|
if (max === 0) { /* no symbols to code at all */
|
//table.op[opts.table_index] = 64; //here.op = (var char)64; /* invalid code marker */
|
//table.bits[opts.table_index] = 1; //here.bits = (var char)1;
|
//table.val[opts.table_index++] = 0; //here.val = (var short)0;
|
table[table_index++] = (1 << 24) | (64 << 16) | 0;
|
|
|
//table.op[opts.table_index] = 64;
|
//table.bits[opts.table_index] = 1;
|
//table.val[opts.table_index++] = 0;
|
table[table_index++] = (1 << 24) | (64 << 16) | 0;
|
|
opts.bits = 1;
|
return 0; /* no symbols, but wait for decoding to report error */
|
}
|
for (min = 1; min < max; min++) {
|
if (count[min] !== 0) { break; }
|
}
|
if (root < min) {
|
root = min;
|
}
|
|
/* check for an over-subscribed or incomplete set of lengths */
|
left = 1;
|
for (len = 1; len <= MAXBITS; len++) {
|
left <<= 1;
|
left -= count[len];
|
if (left < 0) {
|
return -1;
|
} /* over-subscribed */
|
}
|
if (left > 0 && (type === CODES || max !== 1)) {
|
return -1; /* incomplete set */
|
}
|
|
/* generate offsets into symbol table for each length for sorting */
|
offs[1] = 0;
|
for (len = 1; len < MAXBITS; len++) {
|
offs[len + 1] = offs[len] + count[len];
|
}
|
|
/* sort symbols by length, by symbol order within each length */
|
for (sym = 0; sym < codes; sym++) {
|
if (lens[lens_index + sym] !== 0) {
|
work[offs[lens[lens_index + sym]]++] = sym;
|
}
|
}
|
|
/*
|
Create and fill in decoding tables. In this loop, the table being
|
filled is at next and has curr index bits. The code being used is huff
|
with length len. That code is converted to an index by dropping drop
|
bits off of the bottom. For codes where len is less than drop + curr,
|
those top drop + curr - len bits are incremented through all values to
|
fill the table with replicated entries.
|
|
root is the number of index bits for the root table. When len exceeds
|
root, sub-tables are created pointed to by the root entry with an index
|
of the low root bits of huff. This is saved in low to check for when a
|
new sub-table should be started. drop is zero when the root table is
|
being filled, and drop is root when sub-tables are being filled.
|
|
When a new sub-table is needed, it is necessary to look ahead in the
|
code lengths to determine what size sub-table is needed. The length
|
counts are used for this, and so count[] is decremented as codes are
|
entered in the tables.
|
|
used keeps track of how many table entries have been allocated from the
|
provided *table space. It is checked for LENS and DIST tables against
|
the constants ENOUGH_LENS and ENOUGH_DISTS to guard against changes in
|
the initial root table size constants. See the comments in inftrees.h
|
for more information.
|
|
sym increments through all symbols, and the loop terminates when
|
all codes of length max, i.e. all codes, have been processed. This
|
routine permits incomplete codes, so another loop after this one fills
|
in the rest of the decoding tables with invalid code markers.
|
*/
|
|
/* set up for code type */
|
// poor man optimization - use if-else instead of switch,
|
// to avoid deopts in old v8
|
if (type === CODES) {
|
base = extra = work; /* dummy value--not used */
|
end = 19;
|
|
} else if (type === LENS) {
|
base = lbase;
|
base_index -= 257;
|
extra = lext;
|
extra_index -= 257;
|
end = 256;
|
|
} else { /* DISTS */
|
base = dbase;
|
extra = dext;
|
end = -1;
|
}
|
|
/* initialize opts for loop */
|
huff = 0; /* starting code */
|
sym = 0; /* starting code symbol */
|
len = min; /* starting code length */
|
next = table_index; /* current table to fill in */
|
curr = root; /* current table index bits */
|
drop = 0; /* current bits to drop from code for index */
|
low = -1; /* trigger new sub-table when len > root */
|
used = 1 << root; /* use root table entries */
|
mask = used - 1; /* mask for comparing low */
|
|
/* check available table space */
|
if ((type === LENS && used > ENOUGH_LENS) ||
|
(type === DISTS && used > ENOUGH_DISTS)) {
|
return 1;
|
}
|
|
/* process all codes and make table entries */
|
for (;;) {
|
/* create table entry */
|
here_bits = len - drop;
|
if (work[sym] < end) {
|
here_op = 0;
|
here_val = work[sym];
|
}
|
else if (work[sym] > end) {
|
here_op = extra[extra_index + work[sym]];
|
here_val = base[base_index + work[sym]];
|
}
|
else {
|
here_op = 32 + 64; /* end of block */
|
here_val = 0;
|
}
|
|
/* replicate for those indices with low len bits equal to huff */
|
incr = 1 << (len - drop);
|
fill = 1 << curr;
|
min = fill; /* save offset to next table */
|
do {
|
fill -= incr;
|
table[next + (huff >> drop) + fill] = (here_bits << 24) | (here_op << 16) | here_val |0;
|
} while (fill !== 0);
|
|
/* backwards increment the len-bit code huff */
|
incr = 1 << (len - 1);
|
while (huff & incr) {
|
incr >>= 1;
|
}
|
if (incr !== 0) {
|
huff &= incr - 1;
|
huff += incr;
|
} else {
|
huff = 0;
|
}
|
|
/* go to next symbol, update count, len */
|
sym++;
|
if (--count[len] === 0) {
|
if (len === max) { break; }
|
len = lens[lens_index + work[sym]];
|
}
|
|
/* create new sub-table if needed */
|
if (len > root && (huff & mask) !== low) {
|
/* if first time, transition to sub-tables */
|
if (drop === 0) {
|
drop = root;
|
}
|
|
/* increment past last table */
|
next += min; /* here min is 1 << curr */
|
|
/* determine length of next table */
|
curr = len - drop;
|
left = 1 << curr;
|
while (curr + drop < max) {
|
left -= count[curr + drop];
|
if (left <= 0) { break; }
|
curr++;
|
left <<= 1;
|
}
|
|
/* check for enough space */
|
used += 1 << curr;
|
if ((type === LENS && used > ENOUGH_LENS) ||
|
(type === DISTS && used > ENOUGH_DISTS)) {
|
return 1;
|
}
|
|
/* point entry in root table to sub-table */
|
low = huff & mask;
|
/*table.op[low] = curr;
|
table.bits[low] = root;
|
table.val[low] = next - opts.table_index;*/
|
table[low] = (root << 24) | (curr << 16) | (next - table_index) |0;
|
}
|
}
|
|
/* fill in remaining table entry if code is incomplete (guaranteed to have
|
at most one remaining entry, since if the code is incomplete, the
|
maximum code length that was allowed to get this far is one bit) */
|
if (huff !== 0) {
|
//table.op[next + huff] = 64; /* invalid code marker */
|
//table.bits[next + huff] = len - drop;
|
//table.val[next + huff] = 0;
|
table[next + huff] = ((len - drop) << 24) | (64 << 16) |0;
|
}
|
|
/* set return parameters */
|
//opts.table_index += used;
|
opts.bits = root;
|
return 0;
|
};
|
|
},{"../utils/common":65}],75:[function(require,module,exports){
|
'use strict';
|
|
// (C) 1995-2013 Jean-loup Gailly and Mark Adler
|
// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
|
//
|
// This software is provided 'as-is', without any express or implied
|
// warranty. In no event will the authors be held liable for any damages
|
// arising from the use of this software.
|
//
|
// Permission is granted to anyone to use this software for any purpose,
|
// including commercial applications, and to alter it and redistribute it
|
// freely, subject to the following restrictions:
|
//
|
// 1. The origin of this software must not be misrepresented; you must not
|
// claim that you wrote the original software. If you use this software
|
// in a product, an acknowledgment in the product documentation would be
|
// appreciated but is not required.
|
// 2. Altered source versions must be plainly marked as such, and must not be
|
// misrepresented as being the original software.
|
// 3. This notice may not be removed or altered from any source distribution.
|
|
module.exports = {
|
2: 'need dictionary', /* Z_NEED_DICT 2 */
|
1: 'stream end', /* Z_STREAM_END 1 */
|
0: '', /* Z_OK 0 */
|
'-1': 'file error', /* Z_ERRNO (-1) */
|
'-2': 'stream error', /* Z_STREAM_ERROR (-2) */
|
'-3': 'data error', /* Z_DATA_ERROR (-3) */
|
'-4': 'insufficient memory', /* Z_MEM_ERROR (-4) */
|
'-5': 'buffer error', /* Z_BUF_ERROR (-5) */
|
'-6': 'incompatible version' /* Z_VERSION_ERROR (-6) */
|
};
|
|
},{}],76:[function(require,module,exports){
|
'use strict';
|
|
// (C) 1995-2013 Jean-loup Gailly and Mark Adler
|
// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
|
//
|
// This software is provided 'as-is', without any express or implied
|
// warranty. In no event will the authors be held liable for any damages
|
// arising from the use of this software.
|
//
|
// Permission is granted to anyone to use this software for any purpose,
|
// including commercial applications, and to alter it and redistribute it
|
// freely, subject to the following restrictions:
|
//
|
// 1. The origin of this software must not be misrepresented; you must not
|
// claim that you wrote the original software. If you use this software
|
// in a product, an acknowledgment in the product documentation would be
|
// appreciated but is not required.
|
// 2. Altered source versions must be plainly marked as such, and must not be
|
// misrepresented as being the original software.
|
// 3. This notice may not be removed or altered from any source distribution.
|
|
/* eslint-disable space-unary-ops */
|
|
var utils = require('../utils/common');
|
|
/* Public constants ==========================================================*/
|
/* ===========================================================================*/
|
|
|
//var Z_FILTERED = 1;
|
//var Z_HUFFMAN_ONLY = 2;
|
//var Z_RLE = 3;
|
var Z_FIXED = 4;
|
//var Z_DEFAULT_STRATEGY = 0;
|
|
/* Possible values of the data_type field (though see inflate()) */
|
var Z_BINARY = 0;
|
var Z_TEXT = 1;
|
//var Z_ASCII = 1; // = Z_TEXT
|
var Z_UNKNOWN = 2;
|
|
/*============================================================================*/
|
|
|
function zero(buf) { var len = buf.length; while (--len >= 0) { buf[len] = 0; } }
|
|
// From zutil.h
|
|
var STORED_BLOCK = 0;
|
var STATIC_TREES = 1;
|
var DYN_TREES = 2;
|
/* The three kinds of block type */
|
|
var MIN_MATCH = 3;
|
var MAX_MATCH = 258;
|
/* The minimum and maximum match lengths */
|
|
// From deflate.h
|
/* ===========================================================================
|
* Internal compression state.
|
*/
|
|
var LENGTH_CODES = 29;
|
/* number of length codes, not counting the special END_BLOCK code */
|
|
var LITERALS = 256;
|
/* number of literal bytes 0..255 */
|
|
var L_CODES = LITERALS + 1 + LENGTH_CODES;
|
/* number of Literal or Length codes, including the END_BLOCK code */
|
|
var D_CODES = 30;
|
/* number of distance codes */
|
|
var BL_CODES = 19;
|
/* number of codes used to transfer the bit lengths */
|
|
var HEAP_SIZE = 2 * L_CODES + 1;
|
/* maximum heap size */
|
|
var MAX_BITS = 15;
|
/* All codes must not exceed MAX_BITS bits */
|
|
var Buf_size = 16;
|
/* size of bit buffer in bi_buf */
|
|
|
/* ===========================================================================
|
* Constants
|
*/
|
|
var MAX_BL_BITS = 7;
|
/* Bit length codes must not exceed MAX_BL_BITS bits */
|
|
var END_BLOCK = 256;
|
/* end of block literal code */
|
|
var REP_3_6 = 16;
|
/* repeat previous bit length 3-6 times (2 bits of repeat count) */
|
|
var REPZ_3_10 = 17;
|
/* repeat a zero length 3-10 times (3 bits of repeat count) */
|
|
var REPZ_11_138 = 18;
|
/* repeat a zero length 11-138 times (7 bits of repeat count) */
|
|
/* eslint-disable comma-spacing,array-bracket-spacing */
|
var extra_lbits = /* extra bits for each length code */
|
[0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0];
|
|
var extra_dbits = /* extra bits for each distance code */
|
[0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13];
|
|
var extra_blbits = /* extra bits for each bit length code */
|
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7];
|
|
var bl_order =
|
[16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15];
|
/* eslint-enable comma-spacing,array-bracket-spacing */
|
|
/* The lengths of the bit length codes are sent in order of decreasing
|
* probability, to avoid transmitting the lengths for unused bit length codes.
|
*/
|
|
/* ===========================================================================
|
* Local data. These are initialized only once.
|
*/
|
|
// We pre-fill arrays with 0 to avoid uninitialized gaps
|
|
var DIST_CODE_LEN = 512; /* see definition of array dist_code below */
|
|
// !!!! Use flat array instead of structure, Freq = i*2, Len = i*2+1
|
var static_ltree = new Array((L_CODES + 2) * 2);
|
zero(static_ltree);
|
/* The static literal tree. Since the bit lengths are imposed, there is no
|
* need for the L_CODES extra codes used during heap construction. However
|
* The codes 286 and 287 are needed to build a canonical tree (see _tr_init
|
* below).
|
*/
|
|
var static_dtree = new Array(D_CODES * 2);
|
zero(static_dtree);
|
/* The static distance tree. (Actually a trivial tree since all codes use
|
* 5 bits.)
|
*/
|
|
var _dist_code = new Array(DIST_CODE_LEN);
|
zero(_dist_code);
|
/* Distance codes. The first 256 values correspond to the distances
|
* 3 .. 258, the last 256 values correspond to the top 8 bits of
|
* the 15 bit distances.
|
*/
|
|
var _length_code = new Array(MAX_MATCH - MIN_MATCH + 1);
|
zero(_length_code);
|
/* length code for each normalized match length (0 == MIN_MATCH) */
|
|
var base_length = new Array(LENGTH_CODES);
|
zero(base_length);
|
/* First normalized length for each code (0 = MIN_MATCH) */
|
|
var base_dist = new Array(D_CODES);
|
zero(base_dist);
|
/* First normalized distance for each code (0 = distance of 1) */
|
|
|
function StaticTreeDesc(static_tree, extra_bits, extra_base, elems, max_length) {
|
|
this.static_tree = static_tree; /* static tree or NULL */
|
this.extra_bits = extra_bits; /* extra bits for each code or NULL */
|
this.extra_base = extra_base; /* base index for extra_bits */
|
this.elems = elems; /* max number of elements in the tree */
|
this.max_length = max_length; /* max bit length for the codes */
|
|
// show if `static_tree` has data or dummy - needed for monomorphic objects
|
this.has_stree = static_tree && static_tree.length;
|
}
|
|
|
var static_l_desc;
|
var static_d_desc;
|
var static_bl_desc;
|
|
|
function TreeDesc(dyn_tree, stat_desc) {
|
this.dyn_tree = dyn_tree; /* the dynamic tree */
|
this.max_code = 0; /* largest code with non zero frequency */
|
this.stat_desc = stat_desc; /* the corresponding static tree */
|
}
|
|
|
|
function d_code(dist) {
|
return dist < 256 ? _dist_code[dist] : _dist_code[256 + (dist >>> 7)];
|
}
|
|
|
/* ===========================================================================
|
* Output a short LSB first on the stream.
|
* IN assertion: there is enough room in pendingBuf.
|
*/
|
function put_short(s, w) {
|
// put_byte(s, (uch)((w) & 0xff));
|
// put_byte(s, (uch)((ush)(w) >> 8));
|
s.pending_buf[s.pending++] = (w) & 0xff;
|
s.pending_buf[s.pending++] = (w >>> 8) & 0xff;
|
}
|
|
|
/* ===========================================================================
|
* Send a value on a given number of bits.
|
* IN assertion: length <= 16 and value fits in length bits.
|
*/
|
function send_bits(s, value, length) {
|
if (s.bi_valid > (Buf_size - length)) {
|
s.bi_buf |= (value << s.bi_valid) & 0xffff;
|
put_short(s, s.bi_buf);
|
s.bi_buf = value >> (Buf_size - s.bi_valid);
|
s.bi_valid += length - Buf_size;
|
} else {
|
s.bi_buf |= (value << s.bi_valid) & 0xffff;
|
s.bi_valid += length;
|
}
|
}
|
|
|
function send_code(s, c, tree) {
|
send_bits(s, tree[c * 2]/*.Code*/, tree[c * 2 + 1]/*.Len*/);
|
}
|
|
|
/* ===========================================================================
|
* Reverse the first len bits of a code, using straightforward code (a faster
|
* method would use a table)
|
* IN assertion: 1 <= len <= 15
|
*/
|
function bi_reverse(code, len) {
|
var res = 0;
|
do {
|
res |= code & 1;
|
code >>>= 1;
|
res <<= 1;
|
} while (--len > 0);
|
return res >>> 1;
|
}
|
|
|
/* ===========================================================================
|
* Flush the bit buffer, keeping at most 7 bits in it.
|
*/
|
function bi_flush(s) {
|
if (s.bi_valid === 16) {
|
put_short(s, s.bi_buf);
|
s.bi_buf = 0;
|
s.bi_valid = 0;
|
|
} else if (s.bi_valid >= 8) {
|
s.pending_buf[s.pending++] = s.bi_buf & 0xff;
|
s.bi_buf >>= 8;
|
s.bi_valid -= 8;
|
}
|
}
|
|
|
/* ===========================================================================
|
* Compute the optimal bit lengths for a tree and update the total bit length
|
* for the current block.
|
* IN assertion: the fields freq and dad are set, heap[heap_max] and
|
* above are the tree nodes sorted by increasing frequency.
|
* OUT assertions: the field len is set to the optimal bit length, the
|
* array bl_count contains the frequencies for each bit length.
|
* The length opt_len is updated; static_len is also updated if stree is
|
* not null.
|
*/
|
function gen_bitlen(s, desc)
|
// deflate_state *s;
|
// tree_desc *desc; /* the tree descriptor */
|
{
|
var tree = desc.dyn_tree;
|
var max_code = desc.max_code;
|
var stree = desc.stat_desc.static_tree;
|
var has_stree = desc.stat_desc.has_stree;
|
var extra = desc.stat_desc.extra_bits;
|
var base = desc.stat_desc.extra_base;
|
var max_length = desc.stat_desc.max_length;
|
var h; /* heap index */
|
var n, m; /* iterate over the tree elements */
|
var bits; /* bit length */
|
var xbits; /* extra bits */
|
var f; /* frequency */
|
var overflow = 0; /* number of elements with bit length too large */
|
|
for (bits = 0; bits <= MAX_BITS; bits++) {
|
s.bl_count[bits] = 0;
|
}
|
|
/* In a first pass, compute the optimal bit lengths (which may
|
* overflow in the case of the bit length tree).
|
*/
|
tree[s.heap[s.heap_max] * 2 + 1]/*.Len*/ = 0; /* root of the heap */
|
|
for (h = s.heap_max + 1; h < HEAP_SIZE; h++) {
|
n = s.heap[h];
|
bits = tree[tree[n * 2 + 1]/*.Dad*/ * 2 + 1]/*.Len*/ + 1;
|
if (bits > max_length) {
|
bits = max_length;
|
overflow++;
|
}
|
tree[n * 2 + 1]/*.Len*/ = bits;
|
/* We overwrite tree[n].Dad which is no longer needed */
|
|
if (n > max_code) { continue; } /* not a leaf node */
|
|
s.bl_count[bits]++;
|
xbits = 0;
|
if (n >= base) {
|
xbits = extra[n - base];
|
}
|
f = tree[n * 2]/*.Freq*/;
|
s.opt_len += f * (bits + xbits);
|
if (has_stree) {
|
s.static_len += f * (stree[n * 2 + 1]/*.Len*/ + xbits);
|
}
|
}
|
if (overflow === 0) { return; }
|
|
// Trace((stderr,"\nbit length overflow\n"));
|
/* This happens for example on obj2 and pic of the Calgary corpus */
|
|
/* Find the first bit length which could increase: */
|
do {
|
bits = max_length - 1;
|
while (s.bl_count[bits] === 0) { bits--; }
|
s.bl_count[bits]--; /* move one leaf down the tree */
|
s.bl_count[bits + 1] += 2; /* move one overflow item as its brother */
|
s.bl_count[max_length]--;
|
/* The brother of the overflow item also moves one step up,
|
* but this does not affect bl_count[max_length]
|
*/
|
overflow -= 2;
|
} while (overflow > 0);
|
|
/* Now recompute all bit lengths, scanning in increasing frequency.
|
* h is still equal to HEAP_SIZE. (It is simpler to reconstruct all
|
* lengths instead of fixing only the wrong ones. This idea is taken
|
* from 'ar' written by Haruhiko Okumura.)
|
*/
|
for (bits = max_length; bits !== 0; bits--) {
|
n = s.bl_count[bits];
|
while (n !== 0) {
|
m = s.heap[--h];
|
if (m > max_code) { continue; }
|
if (tree[m * 2 + 1]/*.Len*/ !== bits) {
|
// Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits));
|
s.opt_len += (bits - tree[m * 2 + 1]/*.Len*/) * tree[m * 2]/*.Freq*/;
|
tree[m * 2 + 1]/*.Len*/ = bits;
|
}
|
n--;
|
}
|
}
|
}
|
|
|
/* ===========================================================================
|
* Generate the codes for a given tree and bit counts (which need not be
|
* optimal).
|
* IN assertion: the array bl_count contains the bit length statistics for
|
* the given tree and the field len is set for all tree elements.
|
* OUT assertion: the field code is set for all tree elements of non
|
* zero code length.
|
*/
|
function gen_codes(tree, max_code, bl_count)
|
// ct_data *tree; /* the tree to decorate */
|
// int max_code; /* largest code with non zero frequency */
|
// ushf *bl_count; /* number of codes at each bit length */
|
{
|
var next_code = new Array(MAX_BITS + 1); /* next code value for each bit length */
|
var code = 0; /* running code value */
|
var bits; /* bit index */
|
var n; /* code index */
|
|
/* The distribution counts are first used to generate the code values
|
* without bit reversal.
|
*/
|
for (bits = 1; bits <= MAX_BITS; bits++) {
|
next_code[bits] = code = (code + bl_count[bits - 1]) << 1;
|
}
|
/* Check that the bit counts in bl_count are consistent. The last code
|
* must be all ones.
|
*/
|
//Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1,
|
// "inconsistent bit counts");
|
//Tracev((stderr,"\ngen_codes: max_code %d ", max_code));
|
|
for (n = 0; n <= max_code; n++) {
|
var len = tree[n * 2 + 1]/*.Len*/;
|
if (len === 0) { continue; }
|
/* Now reverse the bits */
|
tree[n * 2]/*.Code*/ = bi_reverse(next_code[len]++, len);
|
|
//Tracecv(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ",
|
// n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1));
|
}
|
}
|
|
|
/* ===========================================================================
|
* Initialize the various 'constant' tables.
|
*/
|
function tr_static_init() {
|
var n; /* iterates over tree elements */
|
var bits; /* bit counter */
|
var length; /* length value */
|
var code; /* code value */
|
var dist; /* distance index */
|
var bl_count = new Array(MAX_BITS + 1);
|
/* number of codes at each bit length for an optimal tree */
|
|
// do check in _tr_init()
|
//if (static_init_done) return;
|
|
/* For some embedded targets, global variables are not initialized: */
|
/*#ifdef NO_INIT_GLOBAL_POINTERS
|
static_l_desc.static_tree = static_ltree;
|
static_l_desc.extra_bits = extra_lbits;
|
static_d_desc.static_tree = static_dtree;
|
static_d_desc.extra_bits = extra_dbits;
|
static_bl_desc.extra_bits = extra_blbits;
|
#endif*/
|
|
/* Initialize the mapping length (0..255) -> length code (0..28) */
|
length = 0;
|
for (code = 0; code < LENGTH_CODES - 1; code++) {
|
base_length[code] = length;
|
for (n = 0; n < (1 << extra_lbits[code]); n++) {
|
_length_code[length++] = code;
|
}
|
}
|
//Assert (length == 256, "tr_static_init: length != 256");
|
/* Note that the length 255 (match length 258) can be represented
|
* in two different ways: code 284 + 5 bits or code 285, so we
|
* overwrite length_code[255] to use the best encoding:
|
*/
|
_length_code[length - 1] = code;
|
|
/* Initialize the mapping dist (0..32K) -> dist code (0..29) */
|
dist = 0;
|
for (code = 0; code < 16; code++) {
|
base_dist[code] = dist;
|
for (n = 0; n < (1 << extra_dbits[code]); n++) {
|
_dist_code[dist++] = code;
|
}
|
}
|
//Assert (dist == 256, "tr_static_init: dist != 256");
|
dist >>= 7; /* from now on, all distances are divided by 128 */
|
for (; code < D_CODES; code++) {
|
base_dist[code] = dist << 7;
|
for (n = 0; n < (1 << (extra_dbits[code] - 7)); n++) {
|
_dist_code[256 + dist++] = code;
|
}
|
}
|
//Assert (dist == 256, "tr_static_init: 256+dist != 512");
|
|
/* Construct the codes of the static literal tree */
|
for (bits = 0; bits <= MAX_BITS; bits++) {
|
bl_count[bits] = 0;
|
}
|
|
n = 0;
|
while (n <= 143) {
|
static_ltree[n * 2 + 1]/*.Len*/ = 8;
|
n++;
|
bl_count[8]++;
|
}
|
while (n <= 255) {
|
static_ltree[n * 2 + 1]/*.Len*/ = 9;
|
n++;
|
bl_count[9]++;
|
}
|
while (n <= 279) {
|
static_ltree[n * 2 + 1]/*.Len*/ = 7;
|
n++;
|
bl_count[7]++;
|
}
|
while (n <= 287) {
|
static_ltree[n * 2 + 1]/*.Len*/ = 8;
|
n++;
|
bl_count[8]++;
|
}
|
/* Codes 286 and 287 do not exist, but we must include them in the
|
* tree construction to get a canonical Huffman tree (longest code
|
* all ones)
|
*/
|
gen_codes(static_ltree, L_CODES + 1, bl_count);
|
|
/* The static distance tree is trivial: */
|
for (n = 0; n < D_CODES; n++) {
|
static_dtree[n * 2 + 1]/*.Len*/ = 5;
|
static_dtree[n * 2]/*.Code*/ = bi_reverse(n, 5);
|
}
|
|
// Now data ready and we can init static trees
|
static_l_desc = new StaticTreeDesc(static_ltree, extra_lbits, LITERALS + 1, L_CODES, MAX_BITS);
|
static_d_desc = new StaticTreeDesc(static_dtree, extra_dbits, 0, D_CODES, MAX_BITS);
|
static_bl_desc = new StaticTreeDesc(new Array(0), extra_blbits, 0, BL_CODES, MAX_BL_BITS);
|
|
//static_init_done = true;
|
}
|
|
|
/* ===========================================================================
|
* Initialize a new block.
|
*/
|
function init_block(s) {
|
var n; /* iterates over tree elements */
|
|
/* Initialize the trees. */
|
for (n = 0; n < L_CODES; n++) { s.dyn_ltree[n * 2]/*.Freq*/ = 0; }
|
for (n = 0; n < D_CODES; n++) { s.dyn_dtree[n * 2]/*.Freq*/ = 0; }
|
for (n = 0; n < BL_CODES; n++) { s.bl_tree[n * 2]/*.Freq*/ = 0; }
|
|
s.dyn_ltree[END_BLOCK * 2]/*.Freq*/ = 1;
|
s.opt_len = s.static_len = 0;
|
s.last_lit = s.matches = 0;
|
}
|
|
|
/* ===========================================================================
|
* Flush the bit buffer and align the output on a byte boundary
|
*/
|
function bi_windup(s)
|
{
|
if (s.bi_valid > 8) {
|
put_short(s, s.bi_buf);
|
} else if (s.bi_valid > 0) {
|
//put_byte(s, (Byte)s->bi_buf);
|
s.pending_buf[s.pending++] = s.bi_buf;
|
}
|
s.bi_buf = 0;
|
s.bi_valid = 0;
|
}
|
|
/* ===========================================================================
|
* Copy a stored block, storing first the length and its
|
* one's complement if requested.
|
*/
|
function copy_block(s, buf, len, header)
|
//DeflateState *s;
|
//charf *buf; /* the input data */
|
//unsigned len; /* its length */
|
//int header; /* true if block header must be written */
|
{
|
bi_windup(s); /* align on byte boundary */
|
|
if (header) {
|
put_short(s, len);
|
put_short(s, ~len);
|
}
|
// while (len--) {
|
// put_byte(s, *buf++);
|
// }
|
utils.arraySet(s.pending_buf, s.window, buf, len, s.pending);
|
s.pending += len;
|
}
|
|
/* ===========================================================================
|
* Compares to subtrees, using the tree depth as tie breaker when
|
* the subtrees have equal frequency. This minimizes the worst case length.
|
*/
|
function smaller(tree, n, m, depth) {
|
var _n2 = n * 2;
|
var _m2 = m * 2;
|
return (tree[_n2]/*.Freq*/ < tree[_m2]/*.Freq*/ ||
|
(tree[_n2]/*.Freq*/ === tree[_m2]/*.Freq*/ && depth[n] <= depth[m]));
|
}
|
|
/* ===========================================================================
|
* Restore the heap property by moving down the tree starting at node k,
|
* exchanging a node with the smallest of its two sons if necessary, stopping
|
* when the heap property is re-established (each father smaller than its
|
* two sons).
|
*/
|
function pqdownheap(s, tree, k)
|
// deflate_state *s;
|
// ct_data *tree; /* the tree to restore */
|
// int k; /* node to move down */
|
{
|
var v = s.heap[k];
|
var j = k << 1; /* left son of k */
|
while (j <= s.heap_len) {
|
/* Set j to the smallest of the two sons: */
|
if (j < s.heap_len &&
|
smaller(tree, s.heap[j + 1], s.heap[j], s.depth)) {
|
j++;
|
}
|
/* Exit if v is smaller than both sons */
|
if (smaller(tree, v, s.heap[j], s.depth)) { break; }
|
|
/* Exchange v with the smallest son */
|
s.heap[k] = s.heap[j];
|
k = j;
|
|
/* And continue down the tree, setting j to the left son of k */
|
j <<= 1;
|
}
|
s.heap[k] = v;
|
}
|
|
|
// inlined manually
|
// var SMALLEST = 1;
|
|
/* ===========================================================================
|
* Send the block data compressed using the given Huffman trees
|
*/
|
function compress_block(s, ltree, dtree)
|
// deflate_state *s;
|
// const ct_data *ltree; /* literal tree */
|
// const ct_data *dtree; /* distance tree */
|
{
|
var dist; /* distance of matched string */
|
var lc; /* match length or unmatched char (if dist == 0) */
|
var lx = 0; /* running index in l_buf */
|
var code; /* the code to send */
|
var extra; /* number of extra bits to send */
|
|
if (s.last_lit !== 0) {
|
do {
|
dist = (s.pending_buf[s.d_buf + lx * 2] << 8) | (s.pending_buf[s.d_buf + lx * 2 + 1]);
|
lc = s.pending_buf[s.l_buf + lx];
|
lx++;
|
|
if (dist === 0) {
|
send_code(s, lc, ltree); /* send a literal byte */
|
//Tracecv(isgraph(lc), (stderr," '%c' ", lc));
|
} else {
|
/* Here, lc is the match length - MIN_MATCH */
|
code = _length_code[lc];
|
send_code(s, code + LITERALS + 1, ltree); /* send the length code */
|
extra = extra_lbits[code];
|
if (extra !== 0) {
|
lc -= base_length[code];
|
send_bits(s, lc, extra); /* send the extra length bits */
|
}
|
dist--; /* dist is now the match distance - 1 */
|
code = d_code(dist);
|
//Assert (code < D_CODES, "bad d_code");
|
|
send_code(s, code, dtree); /* send the distance code */
|
extra = extra_dbits[code];
|
if (extra !== 0) {
|
dist -= base_dist[code];
|
send_bits(s, dist, extra); /* send the extra distance bits */
|
}
|
} /* literal or match pair ? */
|
|
/* Check that the overlay between pending_buf and d_buf+l_buf is ok: */
|
//Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx,
|
// "pendingBuf overflow");
|
|
} while (lx < s.last_lit);
|
}
|
|
send_code(s, END_BLOCK, ltree);
|
}
|
|
|
/* ===========================================================================
|
* Construct one Huffman tree and assigns the code bit strings and lengths.
|
* Update the total bit length for the current block.
|
* IN assertion: the field freq is set for all tree elements.
|
* OUT assertions: the fields len and code are set to the optimal bit length
|
* and corresponding code. The length opt_len is updated; static_len is
|
* also updated if stree is not null. The field max_code is set.
|
*/
|
function build_tree(s, desc)
|
// deflate_state *s;
|
// tree_desc *desc; /* the tree descriptor */
|
{
|
var tree = desc.dyn_tree;
|
var stree = desc.stat_desc.static_tree;
|
var has_stree = desc.stat_desc.has_stree;
|
var elems = desc.stat_desc.elems;
|
var n, m; /* iterate over heap elements */
|
var max_code = -1; /* largest code with non zero frequency */
|
var node; /* new node being created */
|
|
/* Construct the initial heap, with least frequent element in
|
* heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
|
* heap[0] is not used.
|
*/
|
s.heap_len = 0;
|
s.heap_max = HEAP_SIZE;
|
|
for (n = 0; n < elems; n++) {
|
if (tree[n * 2]/*.Freq*/ !== 0) {
|
s.heap[++s.heap_len] = max_code = n;
|
s.depth[n] = 0;
|
|
} else {
|
tree[n * 2 + 1]/*.Len*/ = 0;
|
}
|
}
|
|
/* The pkzip format requires that at least one distance code exists,
|
* and that at least one bit should be sent even if there is only one
|
* possible code. So to avoid special checks later on we force at least
|
* two codes of non zero frequency.
|
*/
|
while (s.heap_len < 2) {
|
node = s.heap[++s.heap_len] = (max_code < 2 ? ++max_code : 0);
|
tree[node * 2]/*.Freq*/ = 1;
|
s.depth[node] = 0;
|
s.opt_len--;
|
|
if (has_stree) {
|
s.static_len -= stree[node * 2 + 1]/*.Len*/;
|
}
|
/* node is 0 or 1 so it does not have extra bits */
|
}
|
desc.max_code = max_code;
|
|
/* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
|
* establish sub-heaps of increasing lengths:
|
*/
|
for (n = (s.heap_len >> 1/*int /2*/); n >= 1; n--) { pqdownheap(s, tree, n); }
|
|
/* Construct the Huffman tree by repeatedly combining the least two
|
* frequent nodes.
|
*/
|
node = elems; /* next internal node of the tree */
|
do {
|
//pqremove(s, tree, n); /* n = node of least frequency */
|
/*** pqremove ***/
|
n = s.heap[1/*SMALLEST*/];
|
s.heap[1/*SMALLEST*/] = s.heap[s.heap_len--];
|
pqdownheap(s, tree, 1/*SMALLEST*/);
|
/***/
|
|
m = s.heap[1/*SMALLEST*/]; /* m = node of next least frequency */
|
|
s.heap[--s.heap_max] = n; /* keep the nodes sorted by frequency */
|
s.heap[--s.heap_max] = m;
|
|
/* Create a new node father of n and m */
|
tree[node * 2]/*.Freq*/ = tree[n * 2]/*.Freq*/ + tree[m * 2]/*.Freq*/;
|
s.depth[node] = (s.depth[n] >= s.depth[m] ? s.depth[n] : s.depth[m]) + 1;
|
tree[n * 2 + 1]/*.Dad*/ = tree[m * 2 + 1]/*.Dad*/ = node;
|
|
/* and insert the new node in the heap */
|
s.heap[1/*SMALLEST*/] = node++;
|
pqdownheap(s, tree, 1/*SMALLEST*/);
|
|
} while (s.heap_len >= 2);
|
|
s.heap[--s.heap_max] = s.heap[1/*SMALLEST*/];
|
|
/* At this point, the fields freq and dad are set. We can now
|
* generate the bit lengths.
|
*/
|
gen_bitlen(s, desc);
|
|
/* The field len is now set, we can generate the bit codes */
|
gen_codes(tree, max_code, s.bl_count);
|
}
|
|
|
/* ===========================================================================
|
* Scan a literal or distance tree to determine the frequencies of the codes
|
* in the bit length tree.
|
*/
|
function scan_tree(s, tree, max_code)
|
// deflate_state *s;
|
// ct_data *tree; /* the tree to be scanned */
|
// int max_code; /* and its largest code of non zero frequency */
|
{
|
var n; /* iterates over all tree elements */
|
var prevlen = -1; /* last emitted length */
|
var curlen; /* length of current code */
|
|
var nextlen = tree[0 * 2 + 1]/*.Len*/; /* length of next code */
|
|
var count = 0; /* repeat count of the current code */
|
var max_count = 7; /* max repeat count */
|
var min_count = 4; /* min repeat count */
|
|
if (nextlen === 0) {
|
max_count = 138;
|
min_count = 3;
|
}
|
tree[(max_code + 1) * 2 + 1]/*.Len*/ = 0xffff; /* guard */
|
|
for (n = 0; n <= max_code; n++) {
|
curlen = nextlen;
|
nextlen = tree[(n + 1) * 2 + 1]/*.Len*/;
|
|
if (++count < max_count && curlen === nextlen) {
|
continue;
|
|
} else if (count < min_count) {
|
s.bl_tree[curlen * 2]/*.Freq*/ += count;
|
|
} else if (curlen !== 0) {
|
|
if (curlen !== prevlen) { s.bl_tree[curlen * 2]/*.Freq*/++; }
|
s.bl_tree[REP_3_6 * 2]/*.Freq*/++;
|
|
} else if (count <= 10) {
|
s.bl_tree[REPZ_3_10 * 2]/*.Freq*/++;
|
|
} else {
|
s.bl_tree[REPZ_11_138 * 2]/*.Freq*/++;
|
}
|
|
count = 0;
|
prevlen = curlen;
|
|
if (nextlen === 0) {
|
max_count = 138;
|
min_count = 3;
|
|
} else if (curlen === nextlen) {
|
max_count = 6;
|
min_count = 3;
|
|
} else {
|
max_count = 7;
|
min_count = 4;
|
}
|
}
|
}
|
|
|
/* ===========================================================================
|
* Send a literal or distance tree in compressed form, using the codes in
|
* bl_tree.
|
*/
|
function send_tree(s, tree, max_code)
|
// deflate_state *s;
|
// ct_data *tree; /* the tree to be scanned */
|
// int max_code; /* and its largest code of non zero frequency */
|
{
|
var n; /* iterates over all tree elements */
|
var prevlen = -1; /* last emitted length */
|
var curlen; /* length of current code */
|
|
var nextlen = tree[0 * 2 + 1]/*.Len*/; /* length of next code */
|
|
var count = 0; /* repeat count of the current code */
|
var max_count = 7; /* max repeat count */
|
var min_count = 4; /* min repeat count */
|
|
/* tree[max_code+1].Len = -1; */ /* guard already set */
|
if (nextlen === 0) {
|
max_count = 138;
|
min_count = 3;
|
}
|
|
for (n = 0; n <= max_code; n++) {
|
curlen = nextlen;
|
nextlen = tree[(n + 1) * 2 + 1]/*.Len*/;
|
|
if (++count < max_count && curlen === nextlen) {
|
continue;
|
|
} else if (count < min_count) {
|
do { send_code(s, curlen, s.bl_tree); } while (--count !== 0);
|
|
} else if (curlen !== 0) {
|
if (curlen !== prevlen) {
|
send_code(s, curlen, s.bl_tree);
|
count--;
|
}
|
//Assert(count >= 3 && count <= 6, " 3_6?");
|
send_code(s, REP_3_6, s.bl_tree);
|
send_bits(s, count - 3, 2);
|
|
} else if (count <= 10) {
|
send_code(s, REPZ_3_10, s.bl_tree);
|
send_bits(s, count - 3, 3);
|
|
} else {
|
send_code(s, REPZ_11_138, s.bl_tree);
|
send_bits(s, count - 11, 7);
|
}
|
|
count = 0;
|
prevlen = curlen;
|
if (nextlen === 0) {
|
max_count = 138;
|
min_count = 3;
|
|
} else if (curlen === nextlen) {
|
max_count = 6;
|
min_count = 3;
|
|
} else {
|
max_count = 7;
|
min_count = 4;
|
}
|
}
|
}
|
|
|
/* ===========================================================================
|
* Construct the Huffman tree for the bit lengths and return the index in
|
* bl_order of the last bit length code to send.
|
*/
|
function build_bl_tree(s) {
|
var max_blindex; /* index of last bit length code of non zero freq */
|
|
/* Determine the bit length frequencies for literal and distance trees */
|
scan_tree(s, s.dyn_ltree, s.l_desc.max_code);
|
scan_tree(s, s.dyn_dtree, s.d_desc.max_code);
|
|
/* Build the bit length tree: */
|
build_tree(s, s.bl_desc);
|
/* opt_len now includes the length of the tree representations, except
|
* the lengths of the bit lengths codes and the 5+5+4 bits for the counts.
|
*/
|
|
/* Determine the number of bit length codes to send. The pkzip format
|
* requires that at least 4 bit length codes be sent. (appnote.txt says
|
* 3 but the actual value used is 4.)
|
*/
|
for (max_blindex = BL_CODES - 1; max_blindex >= 3; max_blindex--) {
|
if (s.bl_tree[bl_order[max_blindex] * 2 + 1]/*.Len*/ !== 0) {
|
break;
|
}
|
}
|
/* Update opt_len to include the bit length tree and counts */
|
s.opt_len += 3 * (max_blindex + 1) + 5 + 5 + 4;
|
//Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld",
|
// s->opt_len, s->static_len));
|
|
return max_blindex;
|
}
|
|
|
/* ===========================================================================
|
* Send the header for a block using dynamic Huffman trees: the counts, the
|
* lengths of the bit length codes, the literal tree and the distance tree.
|
* IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
|
*/
|
function send_all_trees(s, lcodes, dcodes, blcodes)
|
// deflate_state *s;
|
// int lcodes, dcodes, blcodes; /* number of codes for each tree */
|
{
|
var rank; /* index in bl_order */
|
|
//Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes");
|
//Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES,
|
// "too many codes");
|
//Tracev((stderr, "\nbl counts: "));
|
send_bits(s, lcodes - 257, 5); /* not +255 as stated in appnote.txt */
|
send_bits(s, dcodes - 1, 5);
|
send_bits(s, blcodes - 4, 4); /* not -3 as stated in appnote.txt */
|
for (rank = 0; rank < blcodes; rank++) {
|
//Tracev((stderr, "\nbl code %2d ", bl_order[rank]));
|
send_bits(s, s.bl_tree[bl_order[rank] * 2 + 1]/*.Len*/, 3);
|
}
|
//Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent));
|
|
send_tree(s, s.dyn_ltree, lcodes - 1); /* literal tree */
|
//Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent));
|
|
send_tree(s, s.dyn_dtree, dcodes - 1); /* distance tree */
|
//Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent));
|
}
|
|
|
/* ===========================================================================
|
* Check if the data type is TEXT or BINARY, using the following algorithm:
|
* - TEXT if the two conditions below are satisfied:
|
* a) There are no non-portable control characters belonging to the
|
* "black list" (0..6, 14..25, 28..31).
|
* b) There is at least one printable character belonging to the
|
* "white list" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255).
|
* - BINARY otherwise.
|
* - The following partially-portable control characters form a
|
* "gray list" that is ignored in this detection algorithm:
|
* (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}).
|
* IN assertion: the fields Freq of dyn_ltree are set.
|
*/
|
function detect_data_type(s) {
|
/* black_mask is the bit mask of black-listed bytes
|
* set bits 0..6, 14..25, and 28..31
|
* 0xf3ffc07f = binary 11110011111111111100000001111111
|
*/
|
var black_mask = 0xf3ffc07f;
|
var n;
|
|
/* Check for non-textual ("black-listed") bytes. */
|
for (n = 0; n <= 31; n++, black_mask >>>= 1) {
|
if ((black_mask & 1) && (s.dyn_ltree[n * 2]/*.Freq*/ !== 0)) {
|
return Z_BINARY;
|
}
|
}
|
|
/* Check for textual ("white-listed") bytes. */
|
if (s.dyn_ltree[9 * 2]/*.Freq*/ !== 0 || s.dyn_ltree[10 * 2]/*.Freq*/ !== 0 ||
|
s.dyn_ltree[13 * 2]/*.Freq*/ !== 0) {
|
return Z_TEXT;
|
}
|
for (n = 32; n < LITERALS; n++) {
|
if (s.dyn_ltree[n * 2]/*.Freq*/ !== 0) {
|
return Z_TEXT;
|
}
|
}
|
|
/* There are no "black-listed" or "white-listed" bytes:
|
* this stream either is empty or has tolerated ("gray-listed") bytes only.
|
*/
|
return Z_BINARY;
|
}
|
|
|
var static_init_done = false;
|
|
/* ===========================================================================
|
* Initialize the tree data structures for a new zlib stream.
|
*/
|
function _tr_init(s)
|
{
|
|
if (!static_init_done) {
|
tr_static_init();
|
static_init_done = true;
|
}
|
|
s.l_desc = new TreeDesc(s.dyn_ltree, static_l_desc);
|
s.d_desc = new TreeDesc(s.dyn_dtree, static_d_desc);
|
s.bl_desc = new TreeDesc(s.bl_tree, static_bl_desc);
|
|
s.bi_buf = 0;
|
s.bi_valid = 0;
|
|
/* Initialize the first block of the first file: */
|
init_block(s);
|
}
|
|
|
/* ===========================================================================
|
* Send a stored block
|
*/
|
function _tr_stored_block(s, buf, stored_len, last)
|
//DeflateState *s;
|
//charf *buf; /* input block */
|
//ulg stored_len; /* length of input block */
|
//int last; /* one if this is the last block for a file */
|
{
|
send_bits(s, (STORED_BLOCK << 1) + (last ? 1 : 0), 3); /* send block type */
|
copy_block(s, buf, stored_len, true); /* with header */
|
}
|
|
|
/* ===========================================================================
|
* Send one empty static block to give enough lookahead for inflate.
|
* This takes 10 bits, of which 7 may remain in the bit buffer.
|
*/
|
function _tr_align(s) {
|
send_bits(s, STATIC_TREES << 1, 3);
|
send_code(s, END_BLOCK, static_ltree);
|
bi_flush(s);
|
}
|
|
|
/* ===========================================================================
|
* Determine the best encoding for the current block: dynamic trees, static
|
* trees or store, and output the encoded block to the zip file.
|
*/
|
function _tr_flush_block(s, buf, stored_len, last)
|
//DeflateState *s;
|
//charf *buf; /* input block, or NULL if too old */
|
//ulg stored_len; /* length of input block */
|
//int last; /* one if this is the last block for a file */
|
{
|
var opt_lenb, static_lenb; /* opt_len and static_len in bytes */
|
var max_blindex = 0; /* index of last bit length code of non zero freq */
|
|
/* Build the Huffman trees unless a stored block is forced */
|
if (s.level > 0) {
|
|
/* Check if the file is binary or text */
|
if (s.strm.data_type === Z_UNKNOWN) {
|
s.strm.data_type = detect_data_type(s);
|
}
|
|
/* Construct the literal and distance trees */
|
build_tree(s, s.l_desc);
|
// Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len,
|
// s->static_len));
|
|
build_tree(s, s.d_desc);
|
// Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len,
|
// s->static_len));
|
/* At this point, opt_len and static_len are the total bit lengths of
|
* the compressed block data, excluding the tree representations.
|
*/
|
|
/* Build the bit length tree for the above two trees, and get the index
|
* in bl_order of the last bit length code to send.
|
*/
|
max_blindex = build_bl_tree(s);
|
|
/* Determine the best encoding. Compute the block lengths in bytes. */
|
opt_lenb = (s.opt_len + 3 + 7) >>> 3;
|
static_lenb = (s.static_len + 3 + 7) >>> 3;
|
|
// Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ",
|
// opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len,
|
// s->last_lit));
|
|
if (static_lenb <= opt_lenb) { opt_lenb = static_lenb; }
|
|
} else {
|
// Assert(buf != (char*)0, "lost buf");
|
opt_lenb = static_lenb = stored_len + 5; /* force a stored block */
|
}
|
|
if ((stored_len + 4 <= opt_lenb) && (buf !== -1)) {
|
/* 4: two words for the lengths */
|
|
/* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
|
* Otherwise we can't have processed more than WSIZE input bytes since
|
* the last block flush, because compression would have been
|
* successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
|
* transform a block into a stored block.
|
*/
|
_tr_stored_block(s, buf, stored_len, last);
|
|
} else if (s.strategy === Z_FIXED || static_lenb === opt_lenb) {
|
|
send_bits(s, (STATIC_TREES << 1) + (last ? 1 : 0), 3);
|
compress_block(s, static_ltree, static_dtree);
|
|
} else {
|
send_bits(s, (DYN_TREES << 1) + (last ? 1 : 0), 3);
|
send_all_trees(s, s.l_desc.max_code + 1, s.d_desc.max_code + 1, max_blindex + 1);
|
compress_block(s, s.dyn_ltree, s.dyn_dtree);
|
}
|
// Assert (s->compressed_len == s->bits_sent, "bad compressed size");
|
/* The above check is made mod 2^32, for files larger than 512 MB
|
* and uLong implemented on 32 bits.
|
*/
|
init_block(s);
|
|
if (last) {
|
bi_windup(s);
|
}
|
// Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3,
|
// s->compressed_len-7*last));
|
}
|
|
/* ===========================================================================
|
* Save the match info and tally the frequency counts. Return true if
|
* the current block must be flushed.
|
*/
|
function _tr_tally(s, dist, lc)
|
// deflate_state *s;
|
// unsigned dist; /* distance of matched string */
|
// unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */
|
{
|
//var out_length, in_length, dcode;
|
|
s.pending_buf[s.d_buf + s.last_lit * 2] = (dist >>> 8) & 0xff;
|
s.pending_buf[s.d_buf + s.last_lit * 2 + 1] = dist & 0xff;
|
|
s.pending_buf[s.l_buf + s.last_lit] = lc & 0xff;
|
s.last_lit++;
|
|
if (dist === 0) {
|
/* lc is the unmatched char */
|
s.dyn_ltree[lc * 2]/*.Freq*/++;
|
} else {
|
s.matches++;
|
/* Here, lc is the match length - MIN_MATCH */
|
dist--; /* dist = match distance - 1 */
|
//Assert((ush)dist < (ush)MAX_DIST(s) &&
|
// (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) &&
|
// (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match");
|
|
s.dyn_ltree[(_length_code[lc] + LITERALS + 1) * 2]/*.Freq*/++;
|
s.dyn_dtree[d_code(dist) * 2]/*.Freq*/++;
|
}
|
|
// (!) This block is disabled in zlib defaults,
|
// don't enable it for binary compatibility
|
|
//#ifdef TRUNCATE_BLOCK
|
// /* Try to guess if it is profitable to stop the current block here */
|
// if ((s.last_lit & 0x1fff) === 0 && s.level > 2) {
|
// /* Compute an upper bound for the compressed length */
|
// out_length = s.last_lit*8;
|
// in_length = s.strstart - s.block_start;
|
//
|
// for (dcode = 0; dcode < D_CODES; dcode++) {
|
// out_length += s.dyn_dtree[dcode*2]/*.Freq*/ * (5 + extra_dbits[dcode]);
|
// }
|
// out_length >>>= 3;
|
// //Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ",
|
// // s->last_lit, in_length, out_length,
|
// // 100L - out_length*100L/in_length));
|
// if (s.matches < (s.last_lit>>1)/*int /2*/ && out_length < (in_length>>1)/*int /2*/) {
|
// return true;
|
// }
|
// }
|
//#endif
|
|
return (s.last_lit === s.lit_bufsize - 1);
|
/* We avoid equality with lit_bufsize because of wraparound at 64K
|
* on 16 bit machines and because stored blocks are restricted to
|
* 64K-1 bytes.
|
*/
|
}
|
|
exports._tr_init = _tr_init;
|
exports._tr_stored_block = _tr_stored_block;
|
exports._tr_flush_block = _tr_flush_block;
|
exports._tr_tally = _tr_tally;
|
exports._tr_align = _tr_align;
|
|
},{"../utils/common":65}],77:[function(require,module,exports){
|
'use strict';
|
|
// (C) 1995-2013 Jean-loup Gailly and Mark Adler
|
// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
|
//
|
// This software is provided 'as-is', without any express or implied
|
// warranty. In no event will the authors be held liable for any damages
|
// arising from the use of this software.
|
//
|
// Permission is granted to anyone to use this software for any purpose,
|
// including commercial applications, and to alter it and redistribute it
|
// freely, subject to the following restrictions:
|
//
|
// 1. The origin of this software must not be misrepresented; you must not
|
// claim that you wrote the original software. If you use this software
|
// in a product, an acknowledgment in the product documentation would be
|
// appreciated but is not required.
|
// 2. Altered source versions must be plainly marked as such, and must not be
|
// misrepresented as being the original software.
|
// 3. This notice may not be removed or altered from any source distribution.
|
|
function ZStream() {
|
/* next input byte */
|
this.input = null; // JS specific, because we have no pointers
|
this.next_in = 0;
|
/* number of bytes available at input */
|
this.avail_in = 0;
|
/* total number of input bytes read so far */
|
this.total_in = 0;
|
/* next output byte should be put there */
|
this.output = null; // JS specific, because we have no pointers
|
this.next_out = 0;
|
/* remaining free space at output */
|
this.avail_out = 0;
|
/* total number of bytes output so far */
|
this.total_out = 0;
|
/* last error message, NULL if no error */
|
this.msg = ''/*Z_NULL*/;
|
/* not visible by applications */
|
this.state = null;
|
/* best guess about the data type: binary or text */
|
this.data_type = 2/*Z_UNKNOWN*/;
|
/* adler32 value of the uncompressed data */
|
this.adler = 0;
|
}
|
|
module.exports = ZStream;
|
|
},{}],78:[function(require,module,exports){
|
require('text-encoding-polyfill');
|
var StringDecoder = require('string_decoder').StringDecoder;
|
function defaultDecoder(data) {
|
var decoder = new StringDecoder();
|
var out = decoder.write(data) + decoder.end();
|
return out.replace(/\0/g, '').trim();
|
}
|
module.exports = createDecoder;
|
var regex = /^(?:ASNI\s)?(\d+)$/m;
|
function createDecoder(encoding) {
|
if (!encoding) {
|
return defaultDecoder;
|
}
|
try {
|
new TextDecoder(encoding.trim());
|
} catch(e) {
|
var match = regex.exec(encoding);
|
if (match) {
|
encoding = 'windows-' + match[1];
|
}
|
}
|
return browserDecoder;
|
function browserDecoder(buffer) {
|
var decoder = new TextDecoder(encoding);
|
var out = decoder.decode(buffer, {
|
stream: true
|
}) + decoder.decode();
|
return out.replace(/\0/g, '').trim();
|
}
|
}
|
|
},{"string_decoder":94,"text-encoding-polyfill":95}],79:[function(require,module,exports){
|
var createDecoder = require('./decoder');
|
function dbfHeader(data) {
|
var out = {};
|
out.lastUpdated = new Date(data.readUInt8(1) + 1900, data.readUInt8(2), data.readUInt8(3));
|
out.records = data.readUInt32LE(4);
|
out.headerLen = data.readUInt16LE(8);
|
out.recLen = data.readUInt16LE(10);
|
return out;
|
}
|
|
function dbfRowHeader(data, headerLen, decoder) {
|
var out = [];
|
var offset = 32;
|
while (offset < headerLen) {
|
out.push({
|
name: decoder(data.slice(offset, offset + 11)),
|
dataType: String.fromCharCode(data.readUInt8(offset + 11)),
|
len: data.readUInt8(offset + 16),
|
decimal: data.readUInt8(offset + 17)
|
});
|
if (data.readUInt8(offset + 32) === 13) {
|
break;
|
} else {
|
offset += 32;
|
}
|
}
|
return out;
|
}
|
|
function rowFuncs(buffer, offset, len, type, decoder) {
|
var data = buffer.slice(offset, offset + len);
|
var textData = decoder(data);
|
switch (type) {
|
case 'N':
|
case 'F':
|
case 'O':
|
return parseFloat(textData, 10);
|
case 'D':
|
return new Date(textData.slice(0, 4), parseInt(textData.slice(4, 6), 10) - 1, textData.slice(6, 8));
|
case 'L':
|
return textData.toLowerCase() === 'y' || textData.toLowerCase() === 't';
|
default:
|
return textData;
|
}
|
}
|
|
function parseRow(buffer, offset, rowHeaders, decoder) {
|
var out = {};
|
var i = 0;
|
var len = rowHeaders.length;
|
var field;
|
var header;
|
while (i < len) {
|
header = rowHeaders[i];
|
field = rowFuncs(buffer, offset, header.len, header.dataType, decoder);
|
offset += header.len;
|
if (typeof field !== 'undefined') {
|
out[header.name] = field;
|
}
|
i++;
|
}
|
return out;
|
}
|
|
module.exports = function(buffer, encoding) {
|
var decoder = createDecoder(encoding);
|
var header = dbfHeader(buffer);
|
var rowHeaders = dbfRowHeader(buffer, header.headerLen - 1, decoder);
|
|
var offset = ((rowHeaders.length + 1) << 5) + 2;
|
var recLen = header.recLen;
|
var records = header.records;
|
var out = [];
|
while (records) {
|
out.push(parseRow(buffer, offset, rowHeaders, decoder));
|
offset += recLen;
|
records--;
|
}
|
return out;
|
};
|
|
},{"./decoder":78}],80:[function(require,module,exports){
|
module.exports = function (point, vs) {
|
// ray-casting algorithm based on
|
// http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
|
|
var x = point[0], y = point[1];
|
|
var inside = false;
|
for (var i = 0, j = vs.length - 1; i < vs.length; j = i++) {
|
var xi = vs[i][0], yi = vs[i][1];
|
var xj = vs[j][0], yj = vs[j][1];
|
|
var intersect = ((yi > y) != (yj > y))
|
&& (x < (xj - xi) * (y - yi) / (yj - yi) + xi);
|
if (intersect) inside = !inside;
|
}
|
|
return inside;
|
};
|
|
},{}],81:[function(require,module,exports){
|
// shim for using process in browser
|
var process = module.exports = {};
|
|
// cached from whatever global is present so that test runners that stub it
|
// don't break things. But we need to wrap it in a try catch in case it is
|
// wrapped in strict mode code which doesn't define any globals. It's inside a
|
// function because try/catches deoptimize in certain engines.
|
|
var cachedSetTimeout;
|
var cachedClearTimeout;
|
|
function defaultSetTimout() {
|
throw new Error('setTimeout has not been defined');
|
}
|
function defaultClearTimeout () {
|
throw new Error('clearTimeout has not been defined');
|
}
|
(function () {
|
try {
|
if (typeof setTimeout === 'function') {
|
cachedSetTimeout = setTimeout;
|
} else {
|
cachedSetTimeout = defaultSetTimout;
|
}
|
} catch (e) {
|
cachedSetTimeout = defaultSetTimout;
|
}
|
try {
|
if (typeof clearTimeout === 'function') {
|
cachedClearTimeout = clearTimeout;
|
} else {
|
cachedClearTimeout = defaultClearTimeout;
|
}
|
} catch (e) {
|
cachedClearTimeout = defaultClearTimeout;
|
}
|
} ())
|
function runTimeout(fun) {
|
if (cachedSetTimeout === setTimeout) {
|
//normal enviroments in sane situations
|
return setTimeout(fun, 0);
|
}
|
// if setTimeout wasn't available but was latter defined
|
if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) {
|
cachedSetTimeout = setTimeout;
|
return setTimeout(fun, 0);
|
}
|
try {
|
// when when somebody has screwed with setTimeout but no I.E. maddness
|
return cachedSetTimeout(fun, 0);
|
} catch(e){
|
try {
|
// When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
|
return cachedSetTimeout.call(null, fun, 0);
|
} catch(e){
|
// same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error
|
return cachedSetTimeout.call(this, fun, 0);
|
}
|
}
|
|
|
}
|
function runClearTimeout(marker) {
|
if (cachedClearTimeout === clearTimeout) {
|
//normal enviroments in sane situations
|
return clearTimeout(marker);
|
}
|
// if clearTimeout wasn't available but was latter defined
|
if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) {
|
cachedClearTimeout = clearTimeout;
|
return clearTimeout(marker);
|
}
|
try {
|
// when when somebody has screwed with setTimeout but no I.E. maddness
|
return cachedClearTimeout(marker);
|
} catch (e){
|
try {
|
// When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
|
return cachedClearTimeout.call(null, marker);
|
} catch (e){
|
// same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error.
|
// Some versions of I.E. have different rules for clearTimeout vs setTimeout
|
return cachedClearTimeout.call(this, marker);
|
}
|
}
|
|
|
|
}
|
var queue = [];
|
var draining = false;
|
var currentQueue;
|
var queueIndex = -1;
|
|
function cleanUpNextTick() {
|
if (!draining || !currentQueue) {
|
return;
|
}
|
draining = false;
|
if (currentQueue.length) {
|
queue = currentQueue.concat(queue);
|
} else {
|
queueIndex = -1;
|
}
|
if (queue.length) {
|
drainQueue();
|
}
|
}
|
|
function drainQueue() {
|
if (draining) {
|
return;
|
}
|
var timeout = runTimeout(cleanUpNextTick);
|
draining = true;
|
|
var len = queue.length;
|
while(len) {
|
currentQueue = queue;
|
queue = [];
|
while (++queueIndex < len) {
|
if (currentQueue) {
|
currentQueue[queueIndex].run();
|
}
|
}
|
queueIndex = -1;
|
len = queue.length;
|
}
|
currentQueue = null;
|
draining = false;
|
runClearTimeout(timeout);
|
}
|
|
process.nextTick = function (fun) {
|
var args = new Array(arguments.length - 1);
|
if (arguments.length > 1) {
|
for (var i = 1; i < arguments.length; i++) {
|
args[i - 1] = arguments[i];
|
}
|
}
|
queue.push(new Item(fun, args));
|
if (queue.length === 1 && !draining) {
|
runTimeout(drainQueue);
|
}
|
};
|
|
// v8 likes predictible objects
|
function Item(fun, array) {
|
this.fun = fun;
|
this.array = array;
|
}
|
Item.prototype.run = function () {
|
this.fun.apply(null, this.array);
|
};
|
process.title = 'browser';
|
process.browser = true;
|
process.env = {};
|
process.argv = [];
|
process.version = ''; // empty string to avoid regexp issues
|
process.versions = {};
|
|
function noop() {}
|
|
process.on = noop;
|
process.addListener = noop;
|
process.once = noop;
|
process.off = noop;
|
process.removeListener = noop;
|
process.removeAllListeners = noop;
|
process.emit = noop;
|
process.prependListener = noop;
|
process.prependOnceListener = noop;
|
|
process.listeners = function (name) { return [] }
|
|
process.binding = function (name) {
|
throw new Error('process.binding is not supported');
|
};
|
|
process.cwd = function () { return '/' };
|
process.chdir = function (dir) {
|
throw new Error('process.chdir is not supported');
|
};
|
process.umask = function() { return 0; };
|
|
},{}],82:[function(require,module,exports){
|
(function (global, factory) {
|
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
|
typeof define === 'function' && define.amd ? define(factory) :
|
(global.proj4 = factory());
|
}(this, (function () { 'use strict';
|
|
var globals = function(defs) {
|
defs('EPSG:4326', "+title=WGS 84 (long/lat) +proj=longlat +ellps=WGS84 +datum=WGS84 +units=degrees");
|
defs('EPSG:4269', "+title=NAD83 (long/lat) +proj=longlat +a=6378137.0 +b=6356752.31414036 +ellps=GRS80 +datum=NAD83 +units=degrees");
|
defs('EPSG:3857', "+title=WGS 84 / Pseudo-Mercator +proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +no_defs");
|
|
defs.WGS84 = defs['EPSG:4326'];
|
defs['EPSG:3785'] = defs['EPSG:3857']; // maintain backward compat, official code is 3857
|
defs.GOOGLE = defs['EPSG:3857'];
|
defs['EPSG:900913'] = defs['EPSG:3857'];
|
defs['EPSG:102113'] = defs['EPSG:3857'];
|
};
|
|
var PJD_3PARAM = 1;
|
var PJD_7PARAM = 2;
|
var PJD_WGS84 = 4; // WGS84 or equivalent
|
var PJD_NODATUM = 5; // WGS84 or equivalent
|
var SEC_TO_RAD = 4.84813681109535993589914102357e-6;
|
var HALF_PI = Math.PI/2;
|
// ellipoid pj_set_ell.c
|
var SIXTH = 0.1666666666666666667;
|
/* 1/6 */
|
var RA4 = 0.04722222222222222222;
|
/* 17/360 */
|
var RA6 = 0.02215608465608465608;
|
var EPSLN = 1.0e-10;
|
// you'd think you could use Number.EPSILON above but that makes
|
// Mollweide get into an infinate loop.
|
|
var D2R = 0.01745329251994329577;
|
var R2D = 57.29577951308232088;
|
var FORTPI = Math.PI/4;
|
var TWO_PI = Math.PI * 2;
|
// SPI is slightly greater than Math.PI, so values that exceed the -180..180
|
// degree range by a tiny amount don't get wrapped. This prevents points that
|
// have drifted from their original location along the 180th meridian (due to
|
// floating point error) from changing their sign.
|
var SPI = 3.14159265359;
|
|
var exports$1 = {};
|
exports$1.greenwich = 0.0; //"0dE",
|
exports$1.lisbon = -9.131906111111; //"9d07'54.862\"W",
|
exports$1.paris = 2.337229166667; //"2d20'14.025\"E",
|
exports$1.bogota = -74.080916666667; //"74d04'51.3\"W",
|
exports$1.madrid = -3.687938888889; //"3d41'16.58\"W",
|
exports$1.rome = 12.452333333333; //"12d27'8.4\"E",
|
exports$1.bern = 7.439583333333; //"7d26'22.5\"E",
|
exports$1.jakarta = 106.807719444444; //"106d48'27.79\"E",
|
exports$1.ferro = -17.666666666667; //"17d40'W",
|
exports$1.brussels = 4.367975; //"4d22'4.71\"E",
|
exports$1.stockholm = 18.058277777778; //"18d3'29.8\"E",
|
exports$1.athens = 23.7163375; //"23d42'58.815\"E",
|
exports$1.oslo = 10.722916666667; //"10d43'22.5\"E"
|
|
var units = {
|
ft: {to_meter: 0.3048},
|
'us-ft': {to_meter: 1200 / 3937}
|
};
|
|
var ignoredChar = /[\s_\-\/\(\)]/g;
|
function match(obj, key) {
|
if (obj[key]) {
|
return obj[key];
|
}
|
var keys = Object.keys(obj);
|
var lkey = key.toLowerCase().replace(ignoredChar, '');
|
var i = -1;
|
var testkey, processedKey;
|
while (++i < keys.length) {
|
testkey = keys[i];
|
processedKey = testkey.toLowerCase().replace(ignoredChar, '');
|
if (processedKey === lkey) {
|
return obj[testkey];
|
}
|
}
|
}
|
|
var parseProj = function(defData) {
|
var self = {};
|
var paramObj = defData.split('+').map(function(v) {
|
return v.trim();
|
}).filter(function(a) {
|
return a;
|
}).reduce(function(p, a) {
|
var split = a.split('=');
|
split.push(true);
|
p[split[0].toLowerCase()] = split[1];
|
return p;
|
}, {});
|
var paramName, paramVal, paramOutname;
|
var params = {
|
proj: 'projName',
|
datum: 'datumCode',
|
rf: function(v) {
|
self.rf = parseFloat(v);
|
},
|
lat_0: function(v) {
|
self.lat0 = v * D2R;
|
},
|
lat_1: function(v) {
|
self.lat1 = v * D2R;
|
},
|
lat_2: function(v) {
|
self.lat2 = v * D2R;
|
},
|
lat_ts: function(v) {
|
self.lat_ts = v * D2R;
|
},
|
lon_0: function(v) {
|
self.long0 = v * D2R;
|
},
|
lon_1: function(v) {
|
self.long1 = v * D2R;
|
},
|
lon_2: function(v) {
|
self.long2 = v * D2R;
|
},
|
alpha: function(v) {
|
self.alpha = parseFloat(v) * D2R;
|
},
|
lonc: function(v) {
|
self.longc = v * D2R;
|
},
|
x_0: function(v) {
|
self.x0 = parseFloat(v);
|
},
|
y_0: function(v) {
|
self.y0 = parseFloat(v);
|
},
|
k_0: function(v) {
|
self.k0 = parseFloat(v);
|
},
|
k: function(v) {
|
self.k0 = parseFloat(v);
|
},
|
a: function(v) {
|
self.a = parseFloat(v);
|
},
|
b: function(v) {
|
self.b = parseFloat(v);
|
},
|
r_a: function() {
|
self.R_A = true;
|
},
|
zone: function(v) {
|
self.zone = parseInt(v, 10);
|
},
|
south: function() {
|
self.utmSouth = true;
|
},
|
towgs84: function(v) {
|
self.datum_params = v.split(",").map(function(a) {
|
return parseFloat(a);
|
});
|
},
|
to_meter: function(v) {
|
self.to_meter = parseFloat(v);
|
},
|
units: function(v) {
|
self.units = v;
|
var unit = match(units, v);
|
if (unit) {
|
self.to_meter = unit.to_meter;
|
}
|
},
|
from_greenwich: function(v) {
|
self.from_greenwich = v * D2R;
|
},
|
pm: function(v) {
|
var pm = match(exports$1, v);
|
self.from_greenwich = (pm ? pm : parseFloat(v)) * D2R;
|
},
|
nadgrids: function(v) {
|
if (v === '@null') {
|
self.datumCode = 'none';
|
}
|
else {
|
self.nadgrids = v;
|
}
|
},
|
axis: function(v) {
|
var legalAxis = "ewnsud";
|
if (v.length === 3 && legalAxis.indexOf(v.substr(0, 1)) !== -1 && legalAxis.indexOf(v.substr(1, 1)) !== -1 && legalAxis.indexOf(v.substr(2, 1)) !== -1) {
|
self.axis = v;
|
}
|
}
|
};
|
for (paramName in paramObj) {
|
paramVal = paramObj[paramName];
|
if (paramName in params) {
|
paramOutname = params[paramName];
|
if (typeof paramOutname === 'function') {
|
paramOutname(paramVal);
|
}
|
else {
|
self[paramOutname] = paramVal;
|
}
|
}
|
else {
|
self[paramName] = paramVal;
|
}
|
}
|
if(typeof self.datumCode === 'string' && self.datumCode !== "WGS84"){
|
self.datumCode = self.datumCode.toLowerCase();
|
}
|
return self;
|
};
|
|
var NEUTRAL = 1;
|
var KEYWORD = 2;
|
var NUMBER = 3;
|
var QUOTED = 4;
|
var AFTERQUOTE = 5;
|
var ENDED = -1;
|
var whitespace = /\s/;
|
var latin = /[A-Za-z]/;
|
var keyword = /[A-Za-z84]/;
|
var endThings = /[,\]]/;
|
var digets = /[\d\.E\-\+]/;
|
// const ignoredChar = /[\s_\-\/\(\)]/g;
|
function Parser(text) {
|
if (typeof text !== 'string') {
|
throw new Error('not a string');
|
}
|
this.text = text.trim();
|
this.level = 0;
|
this.place = 0;
|
this.root = null;
|
this.stack = [];
|
this.currentObject = null;
|
this.state = NEUTRAL;
|
}
|
Parser.prototype.readCharicter = function() {
|
var char = this.text[this.place++];
|
if (this.state !== QUOTED) {
|
while (whitespace.test(char)) {
|
if (this.place >= this.text.length) {
|
return;
|
}
|
char = this.text[this.place++];
|
}
|
}
|
switch (this.state) {
|
case NEUTRAL:
|
return this.neutral(char);
|
case KEYWORD:
|
return this.keyword(char)
|
case QUOTED:
|
return this.quoted(char);
|
case AFTERQUOTE:
|
return this.afterquote(char);
|
case NUMBER:
|
return this.number(char);
|
case ENDED:
|
return;
|
}
|
};
|
Parser.prototype.afterquote = function(char) {
|
if (char === '"') {
|
this.word += '"';
|
this.state = QUOTED;
|
return;
|
}
|
if (endThings.test(char)) {
|
this.word = this.word.trim();
|
this.afterItem(char);
|
return;
|
}
|
throw new Error('havn\'t handled "' +char + '" in afterquote yet, index ' + this.place);
|
};
|
Parser.prototype.afterItem = function(char) {
|
if (char === ',') {
|
if (this.word !== null) {
|
this.currentObject.push(this.word);
|
}
|
this.word = null;
|
this.state = NEUTRAL;
|
return;
|
}
|
if (char === ']') {
|
this.level--;
|
if (this.word !== null) {
|
this.currentObject.push(this.word);
|
this.word = null;
|
}
|
this.state = NEUTRAL;
|
this.currentObject = this.stack.pop();
|
if (!this.currentObject) {
|
this.state = ENDED;
|
}
|
|
return;
|
}
|
};
|
Parser.prototype.number = function(char) {
|
if (digets.test(char)) {
|
this.word += char;
|
return;
|
}
|
if (endThings.test(char)) {
|
this.word = parseFloat(this.word);
|
this.afterItem(char);
|
return;
|
}
|
throw new Error('havn\'t handled "' +char + '" in number yet, index ' + this.place);
|
};
|
Parser.prototype.quoted = function(char) {
|
if (char === '"') {
|
this.state = AFTERQUOTE;
|
return;
|
}
|
this.word += char;
|
return;
|
};
|
Parser.prototype.keyword = function(char) {
|
if (keyword.test(char)) {
|
this.word += char;
|
return;
|
}
|
if (char === '[') {
|
var newObjects = [];
|
newObjects.push(this.word);
|
this.level++;
|
if (this.root === null) {
|
this.root = newObjects;
|
} else {
|
this.currentObject.push(newObjects);
|
}
|
this.stack.push(this.currentObject);
|
this.currentObject = newObjects;
|
this.state = NEUTRAL;
|
return;
|
}
|
if (endThings.test(char)) {
|
this.afterItem(char);
|
return;
|
}
|
throw new Error('havn\'t handled "' +char + '" in keyword yet, index ' + this.place);
|
};
|
Parser.prototype.neutral = function(char) {
|
if (latin.test(char)) {
|
this.word = char;
|
this.state = KEYWORD;
|
return;
|
}
|
if (char === '"') {
|
this.word = '';
|
this.state = QUOTED;
|
return;
|
}
|
if (digets.test(char)) {
|
this.word = char;
|
this.state = NUMBER;
|
return;
|
}
|
if (endThings.test(char)) {
|
this.afterItem(char);
|
return;
|
}
|
throw new Error('havn\'t handled "' +char + '" in neutral yet, index ' + this.place);
|
};
|
Parser.prototype.output = function() {
|
while (this.place < this.text.length) {
|
this.readCharicter();
|
}
|
if (this.state === ENDED) {
|
return this.root;
|
}
|
throw new Error('unable to parse string "' +this.text + '". State is ' + this.state);
|
};
|
|
function parseString(txt) {
|
var parser = new Parser(txt);
|
return parser.output();
|
}
|
|
function mapit(obj, key, value) {
|
if (Array.isArray(key)) {
|
value.unshift(key);
|
key = null;
|
}
|
var thing = key ? {} : obj;
|
|
var out = value.reduce(function(newObj, item) {
|
sExpr(item, newObj);
|
return newObj
|
}, thing);
|
if (key) {
|
obj[key] = out;
|
}
|
}
|
|
function sExpr(v, obj) {
|
if (!Array.isArray(v)) {
|
obj[v] = true;
|
return;
|
}
|
var key = v.shift();
|
if (key === 'PARAMETER') {
|
key = v.shift();
|
}
|
if (v.length === 1) {
|
if (Array.isArray(v[0])) {
|
obj[key] = {};
|
sExpr(v[0], obj[key]);
|
return;
|
}
|
obj[key] = v[0];
|
return;
|
}
|
if (!v.length) {
|
obj[key] = true;
|
return;
|
}
|
if (key === 'TOWGS84') {
|
obj[key] = v;
|
return;
|
}
|
if (!Array.isArray(key)) {
|
obj[key] = {};
|
}
|
|
var i;
|
switch (key) {
|
case 'UNIT':
|
case 'PRIMEM':
|
case 'VERT_DATUM':
|
obj[key] = {
|
name: v[0].toLowerCase(),
|
convert: v[1]
|
};
|
if (v.length === 3) {
|
sExpr(v[2], obj[key]);
|
}
|
return;
|
case 'SPHEROID':
|
case 'ELLIPSOID':
|
obj[key] = {
|
name: v[0],
|
a: v[1],
|
rf: v[2]
|
};
|
if (v.length === 4) {
|
sExpr(v[3], obj[key]);
|
}
|
return;
|
case 'PROJECTEDCRS':
|
case 'PROJCRS':
|
case 'GEOGCS':
|
case 'GEOCCS':
|
case 'PROJCS':
|
case 'LOCAL_CS':
|
case 'GEODCRS':
|
case 'GEODETICCRS':
|
case 'GEODETICDATUM':
|
case 'EDATUM':
|
case 'ENGINEERINGDATUM':
|
case 'VERT_CS':
|
case 'VERTCRS':
|
case 'VERTICALCRS':
|
case 'COMPD_CS':
|
case 'COMPOUNDCRS':
|
case 'ENGINEERINGCRS':
|
case 'ENGCRS':
|
case 'FITTED_CS':
|
case 'LOCAL_DATUM':
|
case 'DATUM':
|
v[0] = ['name', v[0]];
|
mapit(obj, key, v);
|
return;
|
default:
|
i = -1;
|
while (++i < v.length) {
|
if (!Array.isArray(v[i])) {
|
return sExpr(v, obj[key]);
|
}
|
}
|
return mapit(obj, key, v);
|
}
|
}
|
|
var D2R$1 = 0.01745329251994329577;
|
function rename(obj, params) {
|
var outName = params[0];
|
var inName = params[1];
|
if (!(outName in obj) && (inName in obj)) {
|
obj[outName] = obj[inName];
|
if (params.length === 3) {
|
obj[outName] = params[2](obj[outName]);
|
}
|
}
|
}
|
|
function d2r(input) {
|
return input * D2R$1;
|
}
|
|
function cleanWKT(wkt) {
|
if (wkt.type === 'GEOGCS') {
|
wkt.projName = 'longlat';
|
} else if (wkt.type === 'LOCAL_CS') {
|
wkt.projName = 'identity';
|
wkt.local = true;
|
} else {
|
if (typeof wkt.PROJECTION === 'object') {
|
wkt.projName = Object.keys(wkt.PROJECTION)[0];
|
} else {
|
wkt.projName = wkt.PROJECTION;
|
}
|
}
|
if (wkt.UNIT) {
|
wkt.units = wkt.UNIT.name.toLowerCase();
|
if (wkt.units === 'metre') {
|
wkt.units = 'meter';
|
}
|
if (wkt.UNIT.convert) {
|
if (wkt.type === 'GEOGCS') {
|
if (wkt.DATUM && wkt.DATUM.SPHEROID) {
|
wkt.to_meter = wkt.UNIT.convert*wkt.DATUM.SPHEROID.a;
|
}
|
} else {
|
wkt.to_meter = wkt.UNIT.convert;
|
}
|
}
|
}
|
var geogcs = wkt.GEOGCS;
|
if (wkt.type === 'GEOGCS') {
|
geogcs = wkt;
|
}
|
if (geogcs) {
|
//if(wkt.GEOGCS.PRIMEM&&wkt.GEOGCS.PRIMEM.convert){
|
// wkt.from_greenwich=wkt.GEOGCS.PRIMEM.convert*D2R;
|
//}
|
if (geogcs.DATUM) {
|
wkt.datumCode = geogcs.DATUM.name.toLowerCase();
|
} else {
|
wkt.datumCode = geogcs.name.toLowerCase();
|
}
|
if (wkt.datumCode.slice(0, 2) === 'd_') {
|
wkt.datumCode = wkt.datumCode.slice(2);
|
}
|
if (wkt.datumCode === 'new_zealand_geodetic_datum_1949' || wkt.datumCode === 'new_zealand_1949') {
|
wkt.datumCode = 'nzgd49';
|
}
|
if (wkt.datumCode === 'wgs_1984') {
|
if (wkt.PROJECTION === 'Mercator_Auxiliary_Sphere') {
|
wkt.sphere = true;
|
}
|
wkt.datumCode = 'wgs84';
|
}
|
if (wkt.datumCode.slice(-6) === '_ferro') {
|
wkt.datumCode = wkt.datumCode.slice(0, - 6);
|
}
|
if (wkt.datumCode.slice(-8) === '_jakarta') {
|
wkt.datumCode = wkt.datumCode.slice(0, - 8);
|
}
|
if (~wkt.datumCode.indexOf('belge')) {
|
wkt.datumCode = 'rnb72';
|
}
|
if (geogcs.DATUM && geogcs.DATUM.SPHEROID) {
|
wkt.ellps = geogcs.DATUM.SPHEROID.name.replace('_19', '').replace(/[Cc]larke\_18/, 'clrk');
|
if (wkt.ellps.toLowerCase().slice(0, 13) === 'international') {
|
wkt.ellps = 'intl';
|
}
|
|
wkt.a = geogcs.DATUM.SPHEROID.a;
|
wkt.rf = parseFloat(geogcs.DATUM.SPHEROID.rf, 10);
|
}
|
|
if (geogcs.DATUM && geogcs.DATUM.TOWGS84) {
|
wkt.datum_params = geogcs.DATUM.TOWGS84;
|
}
|
if (~wkt.datumCode.indexOf('osgb_1936')) {
|
wkt.datumCode = 'osgb36';
|
}
|
if (~wkt.datumCode.indexOf('osni_1952')) {
|
wkt.datumCode = 'osni52';
|
}
|
if (~wkt.datumCode.indexOf('tm65')
|
|| ~wkt.datumCode.indexOf('geodetic_datum_of_1965')) {
|
wkt.datumCode = 'ire65';
|
}
|
if (wkt.datumCode === 'ch1903+') {
|
wkt.datumCode = 'ch1903';
|
}
|
if (~wkt.datumCode.indexOf('israel')) {
|
wkt.datumCode = 'isr93';
|
}
|
}
|
if (wkt.b && !isFinite(wkt.b)) {
|
wkt.b = wkt.a;
|
}
|
|
function toMeter(input) {
|
var ratio = wkt.to_meter || 1;
|
return input * ratio;
|
}
|
var renamer = function(a) {
|
return rename(wkt, a);
|
};
|
var list = [
|
['standard_parallel_1', 'Standard_Parallel_1'],
|
['standard_parallel_2', 'Standard_Parallel_2'],
|
['false_easting', 'False_Easting'],
|
['false_northing', 'False_Northing'],
|
['central_meridian', 'Central_Meridian'],
|
['latitude_of_origin', 'Latitude_Of_Origin'],
|
['latitude_of_origin', 'Central_Parallel'],
|
['scale_factor', 'Scale_Factor'],
|
['k0', 'scale_factor'],
|
['latitude_of_center', 'Latitude_Of_Center'],
|
['latitude_of_center', 'Latitude_of_center'],
|
['lat0', 'latitude_of_center', d2r],
|
['longitude_of_center', 'Longitude_Of_Center'],
|
['longitude_of_center', 'Longitude_of_center'],
|
['longc', 'longitude_of_center', d2r],
|
['x0', 'false_easting', toMeter],
|
['y0', 'false_northing', toMeter],
|
['long0', 'central_meridian', d2r],
|
['lat0', 'latitude_of_origin', d2r],
|
['lat0', 'standard_parallel_1', d2r],
|
['lat1', 'standard_parallel_1', d2r],
|
['lat2', 'standard_parallel_2', d2r],
|
['azimuth', 'Azimuth'],
|
['alpha', 'azimuth', d2r],
|
['srsCode', 'name']
|
];
|
list.forEach(renamer);
|
if (!wkt.long0 && wkt.longc && (wkt.projName === 'Albers_Conic_Equal_Area' || wkt.projName === 'Lambert_Azimuthal_Equal_Area')) {
|
wkt.long0 = wkt.longc;
|
}
|
if (!wkt.lat_ts && wkt.lat1 && (wkt.projName === 'Stereographic_South_Pole' || wkt.projName === 'Polar Stereographic (variant B)')) {
|
wkt.lat0 = d2r(wkt.lat1 > 0 ? 90 : -90);
|
wkt.lat_ts = wkt.lat1;
|
}
|
}
|
var wkt = function(wkt) {
|
var lisp = parseString(wkt);
|
var type = lisp.shift();
|
var name = lisp.shift();
|
lisp.unshift(['name', name]);
|
lisp.unshift(['type', type]);
|
var obj = {};
|
sExpr(lisp, obj);
|
cleanWKT(obj);
|
return obj;
|
};
|
|
function defs(name) {
|
/*global console*/
|
var that = this;
|
if (arguments.length === 2) {
|
var def = arguments[1];
|
if (typeof def === 'string') {
|
if (def.charAt(0) === '+') {
|
defs[name] = parseProj(arguments[1]);
|
}
|
else {
|
defs[name] = wkt(arguments[1]);
|
}
|
} else {
|
defs[name] = def;
|
}
|
}
|
else if (arguments.length === 1) {
|
if (Array.isArray(name)) {
|
return name.map(function(v) {
|
if (Array.isArray(v)) {
|
defs.apply(that, v);
|
}
|
else {
|
defs(v);
|
}
|
});
|
}
|
else if (typeof name === 'string') {
|
if (name in defs) {
|
return defs[name];
|
}
|
}
|
else if ('EPSG' in name) {
|
defs['EPSG:' + name.EPSG] = name;
|
}
|
else if ('ESRI' in name) {
|
defs['ESRI:' + name.ESRI] = name;
|
}
|
else if ('IAU2000' in name) {
|
defs['IAU2000:' + name.IAU2000] = name;
|
}
|
else {
|
console.log(name);
|
}
|
return;
|
}
|
|
|
}
|
globals(defs);
|
|
function testObj(code){
|
return typeof code === 'string';
|
}
|
function testDef(code){
|
return code in defs;
|
}
|
var codeWords = ['PROJECTEDCRS', 'PROJCRS', 'GEOGCS','GEOCCS','PROJCS','LOCAL_CS', 'GEODCRS', 'GEODETICCRS', 'GEODETICDATUM', 'ENGCRS', 'ENGINEERINGCRS'];
|
function testWKT(code){
|
return codeWords.some(function (word) {
|
return code.indexOf(word) > -1;
|
});
|
}
|
var codes = ['3857', '900913', '3785', '102113'];
|
function checkMercator(item) {
|
var auth = match(item, 'authority');
|
if (!auth) {
|
return;
|
}
|
var code = match(auth, 'epsg');
|
return code && codes.indexOf(code) > -1;
|
}
|
function checkProjStr(item) {
|
var ext = match(item, 'extension');
|
if (!ext) {
|
return;
|
}
|
return match(ext, 'proj4');
|
}
|
function testProj(code){
|
return code[0] === '+';
|
}
|
function parse(code){
|
if (testObj(code)) {
|
//check to see if this is a WKT string
|
if (testDef(code)) {
|
return defs[code];
|
}
|
if (testWKT(code)) {
|
var out = wkt(code);
|
// test of spetial case, due to this being a very common and often malformed
|
if (checkMercator(out)) {
|
return defs['EPSG:3857'];
|
}
|
var maybeProjStr = checkProjStr(out);
|
if (maybeProjStr) {
|
return parseProj(maybeProjStr);
|
}
|
return out;
|
}
|
if (testProj(code)) {
|
return parseProj(code);
|
}
|
}else{
|
return code;
|
}
|
}
|
|
var extend = function(destination, source) {
|
destination = destination || {};
|
var value, property;
|
if (!source) {
|
return destination;
|
}
|
for (property in source) {
|
value = source[property];
|
if (value !== undefined) {
|
destination[property] = value;
|
}
|
}
|
return destination;
|
};
|
|
var msfnz = function(eccent, sinphi, cosphi) {
|
var con = eccent * sinphi;
|
return cosphi / (Math.sqrt(1 - con * con));
|
};
|
|
var sign = function(x) {
|
return x<0 ? -1 : 1;
|
};
|
|
var adjust_lon = function(x) {
|
return (Math.abs(x) <= SPI) ? x : (x - (sign(x) * TWO_PI));
|
};
|
|
var tsfnz = function(eccent, phi, sinphi) {
|
var con = eccent * sinphi;
|
var com = 0.5 * eccent;
|
con = Math.pow(((1 - con) / (1 + con)), com);
|
return (Math.tan(0.5 * (HALF_PI - phi)) / con);
|
};
|
|
var phi2z = function(eccent, ts) {
|
var eccnth = 0.5 * eccent;
|
var con, dphi;
|
var phi = HALF_PI - 2 * Math.atan(ts);
|
for (var i = 0; i <= 15; i++) {
|
con = eccent * Math.sin(phi);
|
dphi = HALF_PI - 2 * Math.atan(ts * (Math.pow(((1 - con) / (1 + con)), eccnth))) - phi;
|
phi += dphi;
|
if (Math.abs(dphi) <= 0.0000000001) {
|
return phi;
|
}
|
}
|
//console.log("phi2z has NoConvergence");
|
return -9999;
|
};
|
|
function init() {
|
var con = this.b / this.a;
|
this.es = 1 - con * con;
|
if(!('x0' in this)){
|
this.x0 = 0;
|
}
|
if(!('y0' in this)){
|
this.y0 = 0;
|
}
|
this.e = Math.sqrt(this.es);
|
if (this.lat_ts) {
|
if (this.sphere) {
|
this.k0 = Math.cos(this.lat_ts);
|
}
|
else {
|
this.k0 = msfnz(this.e, Math.sin(this.lat_ts), Math.cos(this.lat_ts));
|
}
|
}
|
else {
|
if (!this.k0) {
|
if (this.k) {
|
this.k0 = this.k;
|
}
|
else {
|
this.k0 = 1;
|
}
|
}
|
}
|
}
|
|
/* Mercator forward equations--mapping lat,long to x,y
|
--------------------------------------------------*/
|
|
function forward(p) {
|
var lon = p.x;
|
var lat = p.y;
|
// convert to radians
|
if (lat * R2D > 90 && lat * R2D < -90 && lon * R2D > 180 && lon * R2D < -180) {
|
return null;
|
}
|
|
var x, y;
|
if (Math.abs(Math.abs(lat) - HALF_PI) <= EPSLN) {
|
return null;
|
}
|
else {
|
if (this.sphere) {
|
x = this.x0 + this.a * this.k0 * adjust_lon(lon - this.long0);
|
y = this.y0 + this.a * this.k0 * Math.log(Math.tan(FORTPI + 0.5 * lat));
|
}
|
else {
|
var sinphi = Math.sin(lat);
|
var ts = tsfnz(this.e, lat, sinphi);
|
x = this.x0 + this.a * this.k0 * adjust_lon(lon - this.long0);
|
y = this.y0 - this.a * this.k0 * Math.log(ts);
|
}
|
p.x = x;
|
p.y = y;
|
return p;
|
}
|
}
|
|
/* Mercator inverse equations--mapping x,y to lat/long
|
--------------------------------------------------*/
|
function inverse(p) {
|
|
var x = p.x - this.x0;
|
var y = p.y - this.y0;
|
var lon, lat;
|
|
if (this.sphere) {
|
lat = HALF_PI - 2 * Math.atan(Math.exp(-y / (this.a * this.k0)));
|
}
|
else {
|
var ts = Math.exp(-y / (this.a * this.k0));
|
lat = phi2z(this.e, ts);
|
if (lat === -9999) {
|
return null;
|
}
|
}
|
lon = adjust_lon(this.long0 + x / (this.a * this.k0));
|
|
p.x = lon;
|
p.y = lat;
|
return p;
|
}
|
|
var names$1 = ["Mercator", "Popular Visualisation Pseudo Mercator", "Mercator_1SP", "Mercator_Auxiliary_Sphere", "merc"];
|
var merc = {
|
init: init,
|
forward: forward,
|
inverse: inverse,
|
names: names$1
|
};
|
|
function init$1() {
|
//no-op for longlat
|
}
|
|
function identity(pt) {
|
return pt;
|
}
|
var names$2 = ["longlat", "identity"];
|
var longlat = {
|
init: init$1,
|
forward: identity,
|
inverse: identity,
|
names: names$2
|
};
|
|
var projs = [merc, longlat];
|
var names = {};
|
var projStore = [];
|
|
function add(proj, i) {
|
var len = projStore.length;
|
if (!proj.names) {
|
console.log(i);
|
return true;
|
}
|
projStore[len] = proj;
|
proj.names.forEach(function(n) {
|
names[n.toLowerCase()] = len;
|
});
|
return this;
|
}
|
|
function get(name) {
|
if (!name) {
|
return false;
|
}
|
var n = name.toLowerCase();
|
if (typeof names[n] !== 'undefined' && projStore[names[n]]) {
|
return projStore[names[n]];
|
}
|
}
|
|
function start() {
|
projs.forEach(add);
|
}
|
var projections = {
|
start: start,
|
add: add,
|
get: get
|
};
|
|
var exports$2 = {};
|
exports$2.MERIT = {
|
a: 6378137.0,
|
rf: 298.257,
|
ellipseName: "MERIT 1983"
|
};
|
|
exports$2.SGS85 = {
|
a: 6378136.0,
|
rf: 298.257,
|
ellipseName: "Soviet Geodetic System 85"
|
};
|
|
exports$2.GRS80 = {
|
a: 6378137.0,
|
rf: 298.257222101,
|
ellipseName: "GRS 1980(IUGG, 1980)"
|
};
|
|
exports$2.IAU76 = {
|
a: 6378140.0,
|
rf: 298.257,
|
ellipseName: "IAU 1976"
|
};
|
|
exports$2.airy = {
|
a: 6377563.396,
|
b: 6356256.910,
|
ellipseName: "Airy 1830"
|
};
|
|
exports$2.APL4 = {
|
a: 6378137,
|
rf: 298.25,
|
ellipseName: "Appl. Physics. 1965"
|
};
|
|
exports$2.NWL9D = {
|
a: 6378145.0,
|
rf: 298.25,
|
ellipseName: "Naval Weapons Lab., 1965"
|
};
|
|
exports$2.mod_airy = {
|
a: 6377340.189,
|
b: 6356034.446,
|
ellipseName: "Modified Airy"
|
};
|
|
exports$2.andrae = {
|
a: 6377104.43,
|
rf: 300.0,
|
ellipseName: "Andrae 1876 (Den., Iclnd.)"
|
};
|
|
exports$2.aust_SA = {
|
a: 6378160.0,
|
rf: 298.25,
|
ellipseName: "Australian Natl & S. Amer. 1969"
|
};
|
|
exports$2.GRS67 = {
|
a: 6378160.0,
|
rf: 298.2471674270,
|
ellipseName: "GRS 67(IUGG 1967)"
|
};
|
|
exports$2.bessel = {
|
a: 6377397.155,
|
rf: 299.1528128,
|
ellipseName: "Bessel 1841"
|
};
|
|
exports$2.bess_nam = {
|
a: 6377483.865,
|
rf: 299.1528128,
|
ellipseName: "Bessel 1841 (Namibia)"
|
};
|
|
exports$2.clrk66 = {
|
a: 6378206.4,
|
b: 6356583.8,
|
ellipseName: "Clarke 1866"
|
};
|
|
exports$2.clrk80 = {
|
a: 6378249.145,
|
rf: 293.4663,
|
ellipseName: "Clarke 1880 mod."
|
};
|
|
exports$2.clrk58 = {
|
a: 6378293.645208759,
|
rf: 294.2606763692654,
|
ellipseName: "Clarke 1858"
|
};
|
|
exports$2.CPM = {
|
a: 6375738.7,
|
rf: 334.29,
|
ellipseName: "Comm. des Poids et Mesures 1799"
|
};
|
|
exports$2.delmbr = {
|
a: 6376428.0,
|
rf: 311.5,
|
ellipseName: "Delambre 1810 (Belgium)"
|
};
|
|
exports$2.engelis = {
|
a: 6378136.05,
|
rf: 298.2566,
|
ellipseName: "Engelis 1985"
|
};
|
|
exports$2.evrst30 = {
|
a: 6377276.345,
|
rf: 300.8017,
|
ellipseName: "Everest 1830"
|
};
|
|
exports$2.evrst48 = {
|
a: 6377304.063,
|
rf: 300.8017,
|
ellipseName: "Everest 1948"
|
};
|
|
exports$2.evrst56 = {
|
a: 6377301.243,
|
rf: 300.8017,
|
ellipseName: "Everest 1956"
|
};
|
|
exports$2.evrst69 = {
|
a: 6377295.664,
|
rf: 300.8017,
|
ellipseName: "Everest 1969"
|
};
|
|
exports$2.evrstSS = {
|
a: 6377298.556,
|
rf: 300.8017,
|
ellipseName: "Everest (Sabah & Sarawak)"
|
};
|
|
exports$2.fschr60 = {
|
a: 6378166.0,
|
rf: 298.3,
|
ellipseName: "Fischer (Mercury Datum) 1960"
|
};
|
|
exports$2.fschr60m = {
|
a: 6378155.0,
|
rf: 298.3,
|
ellipseName: "Fischer 1960"
|
};
|
|
exports$2.fschr68 = {
|
a: 6378150.0,
|
rf: 298.3,
|
ellipseName: "Fischer 1968"
|
};
|
|
exports$2.helmert = {
|
a: 6378200.0,
|
rf: 298.3,
|
ellipseName: "Helmert 1906"
|
};
|
|
exports$2.hough = {
|
a: 6378270.0,
|
rf: 297.0,
|
ellipseName: "Hough"
|
};
|
|
exports$2.intl = {
|
a: 6378388.0,
|
rf: 297.0,
|
ellipseName: "International 1909 (Hayford)"
|
};
|
|
exports$2.kaula = {
|
a: 6378163.0,
|
rf: 298.24,
|
ellipseName: "Kaula 1961"
|
};
|
|
exports$2.lerch = {
|
a: 6378139.0,
|
rf: 298.257,
|
ellipseName: "Lerch 1979"
|
};
|
|
exports$2.mprts = {
|
a: 6397300.0,
|
rf: 191.0,
|
ellipseName: "Maupertius 1738"
|
};
|
|
exports$2.new_intl = {
|
a: 6378157.5,
|
b: 6356772.2,
|
ellipseName: "New International 1967"
|
};
|
|
exports$2.plessis = {
|
a: 6376523.0,
|
rf: 6355863.0,
|
ellipseName: "Plessis 1817 (France)"
|
};
|
|
exports$2.krass = {
|
a: 6378245.0,
|
rf: 298.3,
|
ellipseName: "Krassovsky, 1942"
|
};
|
|
exports$2.SEasia = {
|
a: 6378155.0,
|
b: 6356773.3205,
|
ellipseName: "Southeast Asia"
|
};
|
|
exports$2.walbeck = {
|
a: 6376896.0,
|
b: 6355834.8467,
|
ellipseName: "Walbeck"
|
};
|
|
exports$2.WGS60 = {
|
a: 6378165.0,
|
rf: 298.3,
|
ellipseName: "WGS 60"
|
};
|
|
exports$2.WGS66 = {
|
a: 6378145.0,
|
rf: 298.25,
|
ellipseName: "WGS 66"
|
};
|
|
exports$2.WGS7 = {
|
a: 6378135.0,
|
rf: 298.26,
|
ellipseName: "WGS 72"
|
};
|
|
var WGS84 = exports$2.WGS84 = {
|
a: 6378137.0,
|
rf: 298.257223563,
|
ellipseName: "WGS 84"
|
};
|
|
exports$2.sphere = {
|
a: 6370997.0,
|
b: 6370997.0,
|
ellipseName: "Normal Sphere (r=6370997)"
|
};
|
|
function eccentricity(a, b, rf, R_A) {
|
var a2 = a * a; // used in geocentric
|
var b2 = b * b; // used in geocentric
|
var es = (a2 - b2) / a2; // e ^ 2
|
var e = 0;
|
if (R_A) {
|
a *= 1 - es * (SIXTH + es * (RA4 + es * RA6));
|
a2 = a * a;
|
es = 0;
|
} else {
|
e = Math.sqrt(es); // eccentricity
|
}
|
var ep2 = (a2 - b2) / b2; // used in geocentric
|
return {
|
es: es,
|
e: e,
|
ep2: ep2
|
};
|
}
|
function sphere(a, b, rf, ellps, sphere) {
|
if (!a) { // do we have an ellipsoid?
|
var ellipse = match(exports$2, ellps);
|
if (!ellipse) {
|
ellipse = WGS84;
|
}
|
a = ellipse.a;
|
b = ellipse.b;
|
rf = ellipse.rf;
|
}
|
|
if (rf && !b) {
|
b = (1.0 - 1.0 / rf) * a;
|
}
|
if (rf === 0 || Math.abs(a - b) < EPSLN) {
|
sphere = true;
|
b = a;
|
}
|
return {
|
a: a,
|
b: b,
|
rf: rf,
|
sphere: sphere
|
};
|
}
|
|
var exports$3 = {};
|
exports$3.wgs84 = {
|
towgs84: "0,0,0",
|
ellipse: "WGS84",
|
datumName: "WGS84"
|
};
|
|
exports$3.ch1903 = {
|
towgs84: "674.374,15.056,405.346",
|
ellipse: "bessel",
|
datumName: "swiss"
|
};
|
|
exports$3.ggrs87 = {
|
towgs84: "-199.87,74.79,246.62",
|
ellipse: "GRS80",
|
datumName: "Greek_Geodetic_Reference_System_1987"
|
};
|
|
exports$3.nad83 = {
|
towgs84: "0,0,0",
|
ellipse: "GRS80",
|
datumName: "North_American_Datum_1983"
|
};
|
|
exports$3.nad27 = {
|
nadgrids: "@conus,@alaska,@ntv2_0.gsb,@ntv1_can.dat",
|
ellipse: "clrk66",
|
datumName: "North_American_Datum_1927"
|
};
|
|
exports$3.potsdam = {
|
towgs84: "606.0,23.0,413.0",
|
ellipse: "bessel",
|
datumName: "Potsdam Rauenberg 1950 DHDN"
|
};
|
|
exports$3.carthage = {
|
towgs84: "-263.0,6.0,431.0",
|
ellipse: "clark80",
|
datumName: "Carthage 1934 Tunisia"
|
};
|
|
exports$3.hermannskogel = {
|
towgs84: "653.0,-212.0,449.0",
|
ellipse: "bessel",
|
datumName: "Hermannskogel"
|
};
|
|
exports$3.osni52 = {
|
towgs84: "482.530,-130.596,564.557,-1.042,-0.214,-0.631,8.15",
|
ellipse: "airy",
|
datumName: "Irish National"
|
};
|
|
exports$3.ire65 = {
|
towgs84: "482.530,-130.596,564.557,-1.042,-0.214,-0.631,8.15",
|
ellipse: "mod_airy",
|
datumName: "Ireland 1965"
|
};
|
|
exports$3.rassadiran = {
|
towgs84: "-133.63,-157.5,-158.62",
|
ellipse: "intl",
|
datumName: "Rassadiran"
|
};
|
|
exports$3.nzgd49 = {
|
towgs84: "59.47,-5.04,187.44,0.47,-0.1,1.024,-4.5993",
|
ellipse: "intl",
|
datumName: "New Zealand Geodetic Datum 1949"
|
};
|
|
exports$3.osgb36 = {
|
towgs84: "446.448,-125.157,542.060,0.1502,0.2470,0.8421,-20.4894",
|
ellipse: "airy",
|
datumName: "Airy 1830"
|
};
|
|
exports$3.s_jtsk = {
|
towgs84: "589,76,480",
|
ellipse: 'bessel',
|
datumName: 'S-JTSK (Ferro)'
|
};
|
|
exports$3.beduaram = {
|
towgs84: '-106,-87,188',
|
ellipse: 'clrk80',
|
datumName: 'Beduaram'
|
};
|
|
exports$3.gunung_segara = {
|
towgs84: '-403,684,41',
|
ellipse: 'bessel',
|
datumName: 'Gunung Segara Jakarta'
|
};
|
|
exports$3.rnb72 = {
|
towgs84: "106.869,-52.2978,103.724,-0.33657,0.456955,-1.84218,1",
|
ellipse: "intl",
|
datumName: "Reseau National Belge 1972"
|
};
|
|
function datum(datumCode, datum_params, a, b, es, ep2) {
|
var out = {};
|
|
if (datumCode === undefined || datumCode === 'none') {
|
out.datum_type = PJD_NODATUM;
|
} else {
|
out.datum_type = PJD_WGS84;
|
}
|
|
if (datum_params) {
|
out.datum_params = datum_params.map(parseFloat);
|
if (out.datum_params[0] !== 0 || out.datum_params[1] !== 0 || out.datum_params[2] !== 0) {
|
out.datum_type = PJD_3PARAM;
|
}
|
if (out.datum_params.length > 3) {
|
if (out.datum_params[3] !== 0 || out.datum_params[4] !== 0 || out.datum_params[5] !== 0 || out.datum_params[6] !== 0) {
|
out.datum_type = PJD_7PARAM;
|
out.datum_params[3] *= SEC_TO_RAD;
|
out.datum_params[4] *= SEC_TO_RAD;
|
out.datum_params[5] *= SEC_TO_RAD;
|
out.datum_params[6] = (out.datum_params[6] / 1000000.0) + 1.0;
|
}
|
}
|
}
|
|
out.a = a; //datum object also uses these values
|
out.b = b;
|
out.es = es;
|
out.ep2 = ep2;
|
return out;
|
}
|
|
function Projection(srsCode,callback) {
|
if (!(this instanceof Projection)) {
|
return new Projection(srsCode);
|
}
|
callback = callback || function(error){
|
if(error){
|
throw error;
|
}
|
};
|
var json = parse(srsCode);
|
if(typeof json !== 'object'){
|
callback(srsCode);
|
return;
|
}
|
var ourProj = Projection.projections.get(json.projName);
|
if(!ourProj){
|
callback(srsCode);
|
return;
|
}
|
if (json.datumCode && json.datumCode !== 'none') {
|
var datumDef = match(exports$3, json.datumCode);
|
if (datumDef) {
|
json.datum_params = datumDef.towgs84 ? datumDef.towgs84.split(',') : null;
|
json.ellps = datumDef.ellipse;
|
json.datumName = datumDef.datumName ? datumDef.datumName : json.datumCode;
|
}
|
}
|
json.k0 = json.k0 || 1.0;
|
json.axis = json.axis || 'enu';
|
json.ellps = json.ellps || 'wgs84';
|
var sphere_ = sphere(json.a, json.b, json.rf, json.ellps, json.sphere);
|
var ecc = eccentricity(sphere_.a, sphere_.b, sphere_.rf, json.R_A);
|
var datumObj = json.datum || datum(json.datumCode, json.datum_params, sphere_.a, sphere_.b, ecc.es, ecc.ep2);
|
|
extend(this, json); // transfer everything over from the projection because we don't know what we'll need
|
extend(this, ourProj); // transfer all the methods from the projection
|
|
// copy the 4 things over we calulated in deriveConstants.sphere
|
this.a = sphere_.a;
|
this.b = sphere_.b;
|
this.rf = sphere_.rf;
|
this.sphere = sphere_.sphere;
|
|
// copy the 3 things we calculated in deriveConstants.eccentricity
|
this.es = ecc.es;
|
this.e = ecc.e;
|
this.ep2 = ecc.ep2;
|
|
// add in the datum object
|
this.datum = datumObj;
|
|
// init the projection
|
this.init();
|
|
// legecy callback from back in the day when it went to spatialreference.org
|
callback(null, this);
|
|
}
|
Projection.projections = projections;
|
Projection.projections.start();
|
|
'use strict';
|
function compareDatums(source, dest) {
|
if (source.datum_type !== dest.datum_type) {
|
return false; // false, datums are not equal
|
} else if (source.a !== dest.a || Math.abs(source.es - dest.es) > 0.000000000050) {
|
// the tolerance for es is to ensure that GRS80 and WGS84
|
// are considered identical
|
return false;
|
} else if (source.datum_type === PJD_3PARAM) {
|
return (source.datum_params[0] === dest.datum_params[0] && source.datum_params[1] === dest.datum_params[1] && source.datum_params[2] === dest.datum_params[2]);
|
} else if (source.datum_type === PJD_7PARAM) {
|
return (source.datum_params[0] === dest.datum_params[0] && source.datum_params[1] === dest.datum_params[1] && source.datum_params[2] === dest.datum_params[2] && source.datum_params[3] === dest.datum_params[3] && source.datum_params[4] === dest.datum_params[4] && source.datum_params[5] === dest.datum_params[5] && source.datum_params[6] === dest.datum_params[6]);
|
} else {
|
return true; // datums are equal
|
}
|
} // cs_compare_datums()
|
|
/*
|
* The function Convert_Geodetic_To_Geocentric converts geodetic coordinates
|
* (latitude, longitude, and height) to geocentric coordinates (X, Y, Z),
|
* according to the current ellipsoid parameters.
|
*
|
* Latitude : Geodetic latitude in radians (input)
|
* Longitude : Geodetic longitude in radians (input)
|
* Height : Geodetic height, in meters (input)
|
* X : Calculated Geocentric X coordinate, in meters (output)
|
* Y : Calculated Geocentric Y coordinate, in meters (output)
|
* Z : Calculated Geocentric Z coordinate, in meters (output)
|
*
|
*/
|
function geodeticToGeocentric(p, es, a) {
|
var Longitude = p.x;
|
var Latitude = p.y;
|
var Height = p.z ? p.z : 0; //Z value not always supplied
|
|
var Rn; /* Earth radius at location */
|
var Sin_Lat; /* Math.sin(Latitude) */
|
var Sin2_Lat; /* Square of Math.sin(Latitude) */
|
var Cos_Lat; /* Math.cos(Latitude) */
|
|
/*
|
** Don't blow up if Latitude is just a little out of the value
|
** range as it may just be a rounding issue. Also removed longitude
|
** test, it should be wrapped by Math.cos() and Math.sin(). NFW for PROJ.4, Sep/2001.
|
*/
|
if (Latitude < -HALF_PI && Latitude > -1.001 * HALF_PI) {
|
Latitude = -HALF_PI;
|
} else if (Latitude > HALF_PI && Latitude < 1.001 * HALF_PI) {
|
Latitude = HALF_PI;
|
} else if (Latitude < -HALF_PI) {
|
/* Latitude out of range */
|
//..reportError('geocent:lat out of range:' + Latitude);
|
return { x: -Infinity, y: -Infinity, z: p.z };
|
} else if (Latitude > HALF_PI) {
|
/* Latitude out of range */
|
return { x: Infinity, y: Infinity, z: p.z };
|
}
|
|
if (Longitude > Math.PI) {
|
Longitude -= (2 * Math.PI);
|
}
|
Sin_Lat = Math.sin(Latitude);
|
Cos_Lat = Math.cos(Latitude);
|
Sin2_Lat = Sin_Lat * Sin_Lat;
|
Rn = a / (Math.sqrt(1.0e0 - es * Sin2_Lat));
|
return {
|
x: (Rn + Height) * Cos_Lat * Math.cos(Longitude),
|
y: (Rn + Height) * Cos_Lat * Math.sin(Longitude),
|
z: ((Rn * (1 - es)) + Height) * Sin_Lat
|
};
|
} // cs_geodetic_to_geocentric()
|
|
function geocentricToGeodetic(p, es, a, b) {
|
/* local defintions and variables */
|
/* end-criterium of loop, accuracy of sin(Latitude) */
|
var genau = 1e-12;
|
var genau2 = (genau * genau);
|
var maxiter = 30;
|
|
var P; /* distance between semi-minor axis and location */
|
var RR; /* distance between center and location */
|
var CT; /* sin of geocentric latitude */
|
var ST; /* cos of geocentric latitude */
|
var RX;
|
var RK;
|
var RN; /* Earth radius at location */
|
var CPHI0; /* cos of start or old geodetic latitude in iterations */
|
var SPHI0; /* sin of start or old geodetic latitude in iterations */
|
var CPHI; /* cos of searched geodetic latitude */
|
var SPHI; /* sin of searched geodetic latitude */
|
var SDPHI; /* end-criterium: addition-theorem of sin(Latitude(iter)-Latitude(iter-1)) */
|
var iter; /* # of continous iteration, max. 30 is always enough (s.a.) */
|
|
var X = p.x;
|
var Y = p.y;
|
var Z = p.z ? p.z : 0.0; //Z value not always supplied
|
var Longitude;
|
var Latitude;
|
var Height;
|
|
P = Math.sqrt(X * X + Y * Y);
|
RR = Math.sqrt(X * X + Y * Y + Z * Z);
|
|
/* special cases for latitude and longitude */
|
if (P / a < genau) {
|
|
/* special case, if P=0. (X=0., Y=0.) */
|
Longitude = 0.0;
|
|
/* if (X,Y,Z)=(0.,0.,0.) then Height becomes semi-minor axis
|
* of ellipsoid (=center of mass), Latitude becomes PI/2 */
|
if (RR / a < genau) {
|
Latitude = HALF_PI;
|
Height = -b;
|
return {
|
x: p.x,
|
y: p.y,
|
z: p.z
|
};
|
}
|
} else {
|
/* ellipsoidal (geodetic) longitude
|
* interval: -PI < Longitude <= +PI */
|
Longitude = Math.atan2(Y, X);
|
}
|
|
/* --------------------------------------------------------------
|
* Following iterative algorithm was developped by
|
* "Institut for Erdmessung", University of Hannover, July 1988.
|
* Internet: www.ife.uni-hannover.de
|
* Iterative computation of CPHI,SPHI and Height.
|
* Iteration of CPHI and SPHI to 10**-12 radian resp.
|
* 2*10**-7 arcsec.
|
* --------------------------------------------------------------
|
*/
|
CT = Z / RR;
|
ST = P / RR;
|
RX = 1.0 / Math.sqrt(1.0 - es * (2.0 - es) * ST * ST);
|
CPHI0 = ST * (1.0 - es) * RX;
|
SPHI0 = CT * RX;
|
iter = 0;
|
|
/* loop to find sin(Latitude) resp. Latitude
|
* until |sin(Latitude(iter)-Latitude(iter-1))| < genau */
|
do {
|
iter++;
|
RN = a / Math.sqrt(1.0 - es * SPHI0 * SPHI0);
|
|
/* ellipsoidal (geodetic) height */
|
Height = P * CPHI0 + Z * SPHI0 - RN * (1.0 - es * SPHI0 * SPHI0);
|
|
RK = es * RN / (RN + Height);
|
RX = 1.0 / Math.sqrt(1.0 - RK * (2.0 - RK) * ST * ST);
|
CPHI = ST * (1.0 - RK) * RX;
|
SPHI = CT * RX;
|
SDPHI = SPHI * CPHI0 - CPHI * SPHI0;
|
CPHI0 = CPHI;
|
SPHI0 = SPHI;
|
}
|
while (SDPHI * SDPHI > genau2 && iter < maxiter);
|
|
/* ellipsoidal (geodetic) latitude */
|
Latitude = Math.atan(SPHI / Math.abs(CPHI));
|
return {
|
x: Longitude,
|
y: Latitude,
|
z: Height
|
};
|
} // cs_geocentric_to_geodetic()
|
|
/****************************************************************/
|
// pj_geocentic_to_wgs84( p )
|
// p = point to transform in geocentric coordinates (x,y,z)
|
|
|
/** point object, nothing fancy, just allows values to be
|
passed back and forth by reference rather than by value.
|
Other point classes may be used as long as they have
|
x and y properties, which will get modified in the transform method.
|
*/
|
function geocentricToWgs84(p, datum_type, datum_params) {
|
|
if (datum_type === PJD_3PARAM) {
|
// if( x[io] === HUGE_VAL )
|
// continue;
|
return {
|
x: p.x + datum_params[0],
|
y: p.y + datum_params[1],
|
z: p.z + datum_params[2],
|
};
|
} else if (datum_type === PJD_7PARAM) {
|
var Dx_BF = datum_params[0];
|
var Dy_BF = datum_params[1];
|
var Dz_BF = datum_params[2];
|
var Rx_BF = datum_params[3];
|
var Ry_BF = datum_params[4];
|
var Rz_BF = datum_params[5];
|
var M_BF = datum_params[6];
|
// if( x[io] === HUGE_VAL )
|
// continue;
|
return {
|
x: M_BF * (p.x - Rz_BF * p.y + Ry_BF * p.z) + Dx_BF,
|
y: M_BF * (Rz_BF * p.x + p.y - Rx_BF * p.z) + Dy_BF,
|
z: M_BF * (-Ry_BF * p.x + Rx_BF * p.y + p.z) + Dz_BF
|
};
|
}
|
} // cs_geocentric_to_wgs84
|
|
/****************************************************************/
|
// pj_geocentic_from_wgs84()
|
// coordinate system definition,
|
// point to transform in geocentric coordinates (x,y,z)
|
function geocentricFromWgs84(p, datum_type, datum_params) {
|
|
if (datum_type === PJD_3PARAM) {
|
//if( x[io] === HUGE_VAL )
|
// continue;
|
return {
|
x: p.x - datum_params[0],
|
y: p.y - datum_params[1],
|
z: p.z - datum_params[2],
|
};
|
|
} else if (datum_type === PJD_7PARAM) {
|
var Dx_BF = datum_params[0];
|
var Dy_BF = datum_params[1];
|
var Dz_BF = datum_params[2];
|
var Rx_BF = datum_params[3];
|
var Ry_BF = datum_params[4];
|
var Rz_BF = datum_params[5];
|
var M_BF = datum_params[6];
|
var x_tmp = (p.x - Dx_BF) / M_BF;
|
var y_tmp = (p.y - Dy_BF) / M_BF;
|
var z_tmp = (p.z - Dz_BF) / M_BF;
|
//if( x[io] === HUGE_VAL )
|
// continue;
|
|
return {
|
x: x_tmp + Rz_BF * y_tmp - Ry_BF * z_tmp,
|
y: -Rz_BF * x_tmp + y_tmp + Rx_BF * z_tmp,
|
z: Ry_BF * x_tmp - Rx_BF * y_tmp + z_tmp
|
};
|
} //cs_geocentric_from_wgs84()
|
}
|
|
function checkParams(type) {
|
return (type === PJD_3PARAM || type === PJD_7PARAM);
|
}
|
|
var datum_transform = function(source, dest, point) {
|
// Short cut if the datums are identical.
|
if (compareDatums(source, dest)) {
|
return point; // in this case, zero is sucess,
|
// whereas cs_compare_datums returns 1 to indicate TRUE
|
// confusing, should fix this
|
}
|
|
// Explicitly skip datum transform by setting 'datum=none' as parameter for either source or dest
|
if (source.datum_type === PJD_NODATUM || dest.datum_type === PJD_NODATUM) {
|
return point;
|
}
|
|
// If this datum requires grid shifts, then apply it to geodetic coordinates.
|
|
// Do we need to go through geocentric coordinates?
|
if (source.es === dest.es && source.a === dest.a && !checkParams(source.datum_type) && !checkParams(dest.datum_type)) {
|
return point;
|
}
|
|
// Convert to geocentric coordinates.
|
point = geodeticToGeocentric(point, source.es, source.a);
|
// Convert between datums
|
if (checkParams(source.datum_type)) {
|
point = geocentricToWgs84(point, source.datum_type, source.datum_params);
|
}
|
if (checkParams(dest.datum_type)) {
|
point = geocentricFromWgs84(point, dest.datum_type, dest.datum_params);
|
}
|
return geocentricToGeodetic(point, dest.es, dest.a, dest.b);
|
|
};
|
|
var adjust_axis = function(crs, denorm, point) {
|
var xin = point.x,
|
yin = point.y,
|
zin = point.z || 0.0;
|
var v, t, i;
|
var out = {};
|
for (i = 0; i < 3; i++) {
|
if (denorm && i === 2 && point.z === undefined) {
|
continue;
|
}
|
if (i === 0) {
|
v = xin;
|
t = 'x';
|
}
|
else if (i === 1) {
|
v = yin;
|
t = 'y';
|
}
|
else {
|
v = zin;
|
t = 'z';
|
}
|
switch (crs.axis[i]) {
|
case 'e':
|
out[t] = v;
|
break;
|
case 'w':
|
out[t] = -v;
|
break;
|
case 'n':
|
out[t] = v;
|
break;
|
case 's':
|
out[t] = -v;
|
break;
|
case 'u':
|
if (point[t] !== undefined) {
|
out.z = v;
|
}
|
break;
|
case 'd':
|
if (point[t] !== undefined) {
|
out.z = -v;
|
}
|
break;
|
default:
|
//console.log("ERROR: unknow axis ("+crs.axis[i]+") - check definition of "+crs.projName);
|
return null;
|
}
|
}
|
return out;
|
};
|
|
var toPoint = function (array){
|
var out = {
|
x: array[0],
|
y: array[1]
|
};
|
if (array.length>2) {
|
out.z = array[2];
|
}
|
if (array.length>3) {
|
out.m = array[3];
|
}
|
return out;
|
};
|
|
var checkSanity = function (point) {
|
checkCoord(point.x);
|
checkCoord(point.y);
|
};
|
function checkCoord(num) {
|
if (typeof Number.isFinite === 'function') {
|
if (Number.isFinite(num)) {
|
return;
|
}
|
throw new TypeError('coordinates must be finite numbers');
|
}
|
if (typeof num !== 'number' || num !== num || !isFinite(num)) {
|
throw new TypeError('coordinates must be finite numbers');
|
}
|
}
|
|
function checkNotWGS(source, dest) {
|
return ((source.datum.datum_type === PJD_3PARAM || source.datum.datum_type === PJD_7PARAM) && dest.datumCode !== 'WGS84') || ((dest.datum.datum_type === PJD_3PARAM || dest.datum.datum_type === PJD_7PARAM) && source.datumCode !== 'WGS84');
|
}
|
|
function transform(source, dest, point) {
|
var wgs84;
|
if (Array.isArray(point)) {
|
point = toPoint(point);
|
}
|
checkSanity(point);
|
// Workaround for datum shifts towgs84, if either source or destination projection is not wgs84
|
if (source.datum && dest.datum && checkNotWGS(source, dest)) {
|
wgs84 = new Projection('WGS84');
|
point = transform(source, wgs84, point);
|
source = wgs84;
|
}
|
// DGR, 2010/11/12
|
if (source.axis !== 'enu') {
|
point = adjust_axis(source, false, point);
|
}
|
// Transform source points to long/lat, if they aren't already.
|
if (source.projName === 'longlat') {
|
point = {
|
x: point.x * D2R,
|
y: point.y * D2R,
|
z: point.z || 0
|
};
|
} else {
|
if (source.to_meter) {
|
point = {
|
x: point.x * source.to_meter,
|
y: point.y * source.to_meter,
|
z: point.z || 0
|
};
|
}
|
point = source.inverse(point); // Convert Cartesian to longlat
|
}
|
// Adjust for the prime meridian if necessary
|
if (source.from_greenwich) {
|
point.x += source.from_greenwich;
|
}
|
|
// Convert datums if needed, and if possible.
|
point = datum_transform(source.datum, dest.datum, point);
|
|
// Adjust for the prime meridian if necessary
|
if (dest.from_greenwich) {
|
point = {
|
x: point.x - dest.from_greenwich,
|
y: point.y,
|
z: point.z || 0
|
};
|
}
|
|
if (dest.projName === 'longlat') {
|
// convert radians to decimal degrees
|
point = {
|
x: point.x * R2D,
|
y: point.y * R2D,
|
z: point.z || 0
|
};
|
} else { // else project
|
point = dest.forward(point);
|
if (dest.to_meter) {
|
point = {
|
x: point.x / dest.to_meter,
|
y: point.y / dest.to_meter,
|
z: point.z || 0
|
};
|
}
|
}
|
|
// DGR, 2010/11/12
|
if (dest.axis !== 'enu') {
|
return adjust_axis(dest, true, point);
|
}
|
|
return point;
|
}
|
|
var wgs84 = Projection('WGS84');
|
|
function transformer(from, to, coords) {
|
var transformedArray, out, keys;
|
if (Array.isArray(coords)) {
|
transformedArray = transform(from, to, coords) || {x: NaN, y: NaN};
|
if (coords.length > 2) {
|
if ((typeof from.name !== 'undefined' && from.name === 'geocent') || (typeof to.name !== 'undefined' && to.name === 'geocent')) {
|
if (typeof transformedArray.z === 'number') {
|
return [transformedArray.x, transformedArray.y, transformedArray.z].concat(coords.splice(3));
|
} else {
|
return [transformedArray.x, transformedArray.y, coords[2]].concat(coords.splice(3));
|
}
|
} else {
|
return [transformedArray.x, transformedArray.y].concat(coords.splice(2));
|
}
|
} else {
|
return [transformedArray.x, transformedArray.y];
|
}
|
} else {
|
out = transform(from, to, coords);
|
keys = Object.keys(coords);
|
if (keys.length === 2) {
|
return out;
|
}
|
keys.forEach(function (key) {
|
if ((typeof from.name !== 'undefined' && from.name === 'geocent') || (typeof to.name !== 'undefined' && to.name === 'geocent')) {
|
if (key === 'x' || key === 'y' || key === 'z') {
|
return;
|
}
|
} else {
|
if (key === 'x' || key === 'y') {
|
return;
|
}
|
}
|
out[key] = coords[key];
|
});
|
return out;
|
}
|
}
|
|
function checkProj(item) {
|
if (item instanceof Projection) {
|
return item;
|
}
|
if (item.oProj) {
|
return item.oProj;
|
}
|
return Projection(item);
|
}
|
|
function proj4$1(fromProj, toProj, coord) {
|
fromProj = checkProj(fromProj);
|
var single = false;
|
var obj;
|
if (typeof toProj === 'undefined') {
|
toProj = fromProj;
|
fromProj = wgs84;
|
single = true;
|
} else if (typeof toProj.x !== 'undefined' || Array.isArray(toProj)) {
|
coord = toProj;
|
toProj = fromProj;
|
fromProj = wgs84;
|
single = true;
|
}
|
toProj = checkProj(toProj);
|
if (coord) {
|
return transformer(fromProj, toProj, coord);
|
} else {
|
obj = {
|
forward: function (coords) {
|
return transformer(fromProj, toProj, coords);
|
},
|
inverse: function (coords) {
|
return transformer(toProj, fromProj, coords);
|
}
|
};
|
if (single) {
|
obj.oProj = toProj;
|
}
|
return obj;
|
}
|
}
|
|
/**
|
* UTM zones are grouped, and assigned to one of a group of 6
|
* sets.
|
*
|
* {int} @private
|
*/
|
var NUM_100K_SETS = 6;
|
|
/**
|
* The column letters (for easting) of the lower left value, per
|
* set.
|
*
|
* {string} @private
|
*/
|
var SET_ORIGIN_COLUMN_LETTERS = 'AJSAJS';
|
|
/**
|
* The row letters (for northing) of the lower left value, per
|
* set.
|
*
|
* {string} @private
|
*/
|
var SET_ORIGIN_ROW_LETTERS = 'AFAFAF';
|
|
var A = 65; // A
|
var I = 73; // I
|
var O = 79; // O
|
var V = 86; // V
|
var Z = 90; // Z
|
var mgrs = {
|
forward: forward$1,
|
inverse: inverse$1,
|
toPoint: toPoint$1
|
};
|
/**
|
* Conversion of lat/lon to MGRS.
|
*
|
* @param {object} ll Object literal with lat and lon properties on a
|
* WGS84 ellipsoid.
|
* @param {int} accuracy Accuracy in digits (5 for 1 m, 4 for 10 m, 3 for
|
* 100 m, 2 for 1000 m or 1 for 10000 m). Optional, default is 5.
|
* @return {string} the MGRS string for the given location and accuracy.
|
*/
|
function forward$1(ll, accuracy) {
|
accuracy = accuracy || 5; // default accuracy 1m
|
return encode(LLtoUTM({
|
lat: ll[1],
|
lon: ll[0]
|
}), accuracy);
|
}
|
|
/**
|
* Conversion of MGRS to lat/lon.
|
*
|
* @param {string} mgrs MGRS string.
|
* @return {array} An array with left (longitude), bottom (latitude), right
|
* (longitude) and top (latitude) values in WGS84, representing the
|
* bounding box for the provided MGRS reference.
|
*/
|
function inverse$1(mgrs) {
|
var bbox = UTMtoLL(decode(mgrs.toUpperCase()));
|
if (bbox.lat && bbox.lon) {
|
return [bbox.lon, bbox.lat, bbox.lon, bbox.lat];
|
}
|
return [bbox.left, bbox.bottom, bbox.right, bbox.top];
|
}
|
|
function toPoint$1(mgrs) {
|
var bbox = UTMtoLL(decode(mgrs.toUpperCase()));
|
if (bbox.lat && bbox.lon) {
|
return [bbox.lon, bbox.lat];
|
}
|
return [(bbox.left + bbox.right) / 2, (bbox.top + bbox.bottom) / 2];
|
}
|
/**
|
* Conversion from degrees to radians.
|
*
|
* @private
|
* @param {number} deg the angle in degrees.
|
* @return {number} the angle in radians.
|
*/
|
function degToRad(deg) {
|
return (deg * (Math.PI / 180.0));
|
}
|
|
/**
|
* Conversion from radians to degrees.
|
*
|
* @private
|
* @param {number} rad the angle in radians.
|
* @return {number} the angle in degrees.
|
*/
|
function radToDeg(rad) {
|
return (180.0 * (rad / Math.PI));
|
}
|
|
/**
|
* Converts a set of Longitude and Latitude co-ordinates to UTM
|
* using the WGS84 ellipsoid.
|
*
|
* @private
|
* @param {object} ll Object literal with lat and lon properties
|
* representing the WGS84 coordinate to be converted.
|
* @return {object} Object literal containing the UTM value with easting,
|
* northing, zoneNumber and zoneLetter properties, and an optional
|
* accuracy property in digits. Returns null if the conversion failed.
|
*/
|
function LLtoUTM(ll) {
|
var Lat = ll.lat;
|
var Long = ll.lon;
|
var a = 6378137.0; //ellip.radius;
|
var eccSquared = 0.00669438; //ellip.eccsq;
|
var k0 = 0.9996;
|
var LongOrigin;
|
var eccPrimeSquared;
|
var N, T, C, A, M;
|
var LatRad = degToRad(Lat);
|
var LongRad = degToRad(Long);
|
var LongOriginRad;
|
var ZoneNumber;
|
// (int)
|
ZoneNumber = Math.floor((Long + 180) / 6) + 1;
|
|
//Make sure the longitude 180.00 is in Zone 60
|
if (Long === 180) {
|
ZoneNumber = 60;
|
}
|
|
// Special zone for Norway
|
if (Lat >= 56.0 && Lat < 64.0 && Long >= 3.0 && Long < 12.0) {
|
ZoneNumber = 32;
|
}
|
|
// Special zones for Svalbard
|
if (Lat >= 72.0 && Lat < 84.0) {
|
if (Long >= 0.0 && Long < 9.0) {
|
ZoneNumber = 31;
|
}
|
else if (Long >= 9.0 && Long < 21.0) {
|
ZoneNumber = 33;
|
}
|
else if (Long >= 21.0 && Long < 33.0) {
|
ZoneNumber = 35;
|
}
|
else if (Long >= 33.0 && Long < 42.0) {
|
ZoneNumber = 37;
|
}
|
}
|
|
LongOrigin = (ZoneNumber - 1) * 6 - 180 + 3; //+3 puts origin
|
// in middle of
|
// zone
|
LongOriginRad = degToRad(LongOrigin);
|
|
eccPrimeSquared = (eccSquared) / (1 - eccSquared);
|
|
N = a / Math.sqrt(1 - eccSquared * Math.sin(LatRad) * Math.sin(LatRad));
|
T = Math.tan(LatRad) * Math.tan(LatRad);
|
C = eccPrimeSquared * Math.cos(LatRad) * Math.cos(LatRad);
|
A = Math.cos(LatRad) * (LongRad - LongOriginRad);
|
|
M = a * ((1 - eccSquared / 4 - 3 * eccSquared * eccSquared / 64 - 5 * eccSquared * eccSquared * eccSquared / 256) * LatRad - (3 * eccSquared / 8 + 3 * eccSquared * eccSquared / 32 + 45 * eccSquared * eccSquared * eccSquared / 1024) * Math.sin(2 * LatRad) + (15 * eccSquared * eccSquared / 256 + 45 * eccSquared * eccSquared * eccSquared / 1024) * Math.sin(4 * LatRad) - (35 * eccSquared * eccSquared * eccSquared / 3072) * Math.sin(6 * LatRad));
|
|
var UTMEasting = (k0 * N * (A + (1 - T + C) * A * A * A / 6.0 + (5 - 18 * T + T * T + 72 * C - 58 * eccPrimeSquared) * A * A * A * A * A / 120.0) + 500000.0);
|
|
var UTMNorthing = (k0 * (M + N * Math.tan(LatRad) * (A * A / 2 + (5 - T + 9 * C + 4 * C * C) * A * A * A * A / 24.0 + (61 - 58 * T + T * T + 600 * C - 330 * eccPrimeSquared) * A * A * A * A * A * A / 720.0)));
|
if (Lat < 0.0) {
|
UTMNorthing += 10000000.0; //10000000 meter offset for
|
// southern hemisphere
|
}
|
|
return {
|
northing: Math.round(UTMNorthing),
|
easting: Math.round(UTMEasting),
|
zoneNumber: ZoneNumber,
|
zoneLetter: getLetterDesignator(Lat)
|
};
|
}
|
|
/**
|
* Converts UTM coords to lat/long, using the WGS84 ellipsoid. This is a convenience
|
* class where the Zone can be specified as a single string eg."60N" which
|
* is then broken down into the ZoneNumber and ZoneLetter.
|
*
|
* @private
|
* @param {object} utm An object literal with northing, easting, zoneNumber
|
* and zoneLetter properties. If an optional accuracy property is
|
* provided (in meters), a bounding box will be returned instead of
|
* latitude and longitude.
|
* @return {object} An object literal containing either lat and lon values
|
* (if no accuracy was provided), or top, right, bottom and left values
|
* for the bounding box calculated according to the provided accuracy.
|
* Returns null if the conversion failed.
|
*/
|
function UTMtoLL(utm) {
|
|
var UTMNorthing = utm.northing;
|
var UTMEasting = utm.easting;
|
var zoneLetter = utm.zoneLetter;
|
var zoneNumber = utm.zoneNumber;
|
// check the ZoneNummber is valid
|
if (zoneNumber < 0 || zoneNumber > 60) {
|
return null;
|
}
|
|
var k0 = 0.9996;
|
var a = 6378137.0; //ellip.radius;
|
var eccSquared = 0.00669438; //ellip.eccsq;
|
var eccPrimeSquared;
|
var e1 = (1 - Math.sqrt(1 - eccSquared)) / (1 + Math.sqrt(1 - eccSquared));
|
var N1, T1, C1, R1, D, M;
|
var LongOrigin;
|
var mu, phi1Rad;
|
|
// remove 500,000 meter offset for longitude
|
var x = UTMEasting - 500000.0;
|
var y = UTMNorthing;
|
|
// We must know somehow if we are in the Northern or Southern
|
// hemisphere, this is the only time we use the letter So even
|
// if the Zone letter isn't exactly correct it should indicate
|
// the hemisphere correctly
|
if (zoneLetter < 'N') {
|
y -= 10000000.0; // remove 10,000,000 meter offset used
|
// for southern hemisphere
|
}
|
|
// There are 60 zones with zone 1 being at West -180 to -174
|
LongOrigin = (zoneNumber - 1) * 6 - 180 + 3; // +3 puts origin
|
// in middle of
|
// zone
|
|
eccPrimeSquared = (eccSquared) / (1 - eccSquared);
|
|
M = y / k0;
|
mu = M / (a * (1 - eccSquared / 4 - 3 * eccSquared * eccSquared / 64 - 5 * eccSquared * eccSquared * eccSquared / 256));
|
|
phi1Rad = mu + (3 * e1 / 2 - 27 * e1 * e1 * e1 / 32) * Math.sin(2 * mu) + (21 * e1 * e1 / 16 - 55 * e1 * e1 * e1 * e1 / 32) * Math.sin(4 * mu) + (151 * e1 * e1 * e1 / 96) * Math.sin(6 * mu);
|
// double phi1 = ProjMath.radToDeg(phi1Rad);
|
|
N1 = a / Math.sqrt(1 - eccSquared * Math.sin(phi1Rad) * Math.sin(phi1Rad));
|
T1 = Math.tan(phi1Rad) * Math.tan(phi1Rad);
|
C1 = eccPrimeSquared * Math.cos(phi1Rad) * Math.cos(phi1Rad);
|
R1 = a * (1 - eccSquared) / Math.pow(1 - eccSquared * Math.sin(phi1Rad) * Math.sin(phi1Rad), 1.5);
|
D = x / (N1 * k0);
|
|
var lat = phi1Rad - (N1 * Math.tan(phi1Rad) / R1) * (D * D / 2 - (5 + 3 * T1 + 10 * C1 - 4 * C1 * C1 - 9 * eccPrimeSquared) * D * D * D * D / 24 + (61 + 90 * T1 + 298 * C1 + 45 * T1 * T1 - 252 * eccPrimeSquared - 3 * C1 * C1) * D * D * D * D * D * D / 720);
|
lat = radToDeg(lat);
|
|
var lon = (D - (1 + 2 * T1 + C1) * D * D * D / 6 + (5 - 2 * C1 + 28 * T1 - 3 * C1 * C1 + 8 * eccPrimeSquared + 24 * T1 * T1) * D * D * D * D * D / 120) / Math.cos(phi1Rad);
|
lon = LongOrigin + radToDeg(lon);
|
|
var result;
|
if (utm.accuracy) {
|
var topRight = UTMtoLL({
|
northing: utm.northing + utm.accuracy,
|
easting: utm.easting + utm.accuracy,
|
zoneLetter: utm.zoneLetter,
|
zoneNumber: utm.zoneNumber
|
});
|
result = {
|
top: topRight.lat,
|
right: topRight.lon,
|
bottom: lat,
|
left: lon
|
};
|
}
|
else {
|
result = {
|
lat: lat,
|
lon: lon
|
};
|
}
|
return result;
|
}
|
|
/**
|
* Calculates the MGRS letter designator for the given latitude.
|
*
|
* @private
|
* @param {number} lat The latitude in WGS84 to get the letter designator
|
* for.
|
* @return {char} The letter designator.
|
*/
|
function getLetterDesignator(lat) {
|
//This is here as an error flag to show that the Latitude is
|
//outside MGRS limits
|
var LetterDesignator = 'Z';
|
|
if ((84 >= lat) && (lat >= 72)) {
|
LetterDesignator = 'X';
|
}
|
else if ((72 > lat) && (lat >= 64)) {
|
LetterDesignator = 'W';
|
}
|
else if ((64 > lat) && (lat >= 56)) {
|
LetterDesignator = 'V';
|
}
|
else if ((56 > lat) && (lat >= 48)) {
|
LetterDesignator = 'U';
|
}
|
else if ((48 > lat) && (lat >= 40)) {
|
LetterDesignator = 'T';
|
}
|
else if ((40 > lat) && (lat >= 32)) {
|
LetterDesignator = 'S';
|
}
|
else if ((32 > lat) && (lat >= 24)) {
|
LetterDesignator = 'R';
|
}
|
else if ((24 > lat) && (lat >= 16)) {
|
LetterDesignator = 'Q';
|
}
|
else if ((16 > lat) && (lat >= 8)) {
|
LetterDesignator = 'P';
|
}
|
else if ((8 > lat) && (lat >= 0)) {
|
LetterDesignator = 'N';
|
}
|
else if ((0 > lat) && (lat >= -8)) {
|
LetterDesignator = 'M';
|
}
|
else if ((-8 > lat) && (lat >= -16)) {
|
LetterDesignator = 'L';
|
}
|
else if ((-16 > lat) && (lat >= -24)) {
|
LetterDesignator = 'K';
|
}
|
else if ((-24 > lat) && (lat >= -32)) {
|
LetterDesignator = 'J';
|
}
|
else if ((-32 > lat) && (lat >= -40)) {
|
LetterDesignator = 'H';
|
}
|
else if ((-40 > lat) && (lat >= -48)) {
|
LetterDesignator = 'G';
|
}
|
else if ((-48 > lat) && (lat >= -56)) {
|
LetterDesignator = 'F';
|
}
|
else if ((-56 > lat) && (lat >= -64)) {
|
LetterDesignator = 'E';
|
}
|
else if ((-64 > lat) && (lat >= -72)) {
|
LetterDesignator = 'D';
|
}
|
else if ((-72 > lat) && (lat >= -80)) {
|
LetterDesignator = 'C';
|
}
|
return LetterDesignator;
|
}
|
|
/**
|
* Encodes a UTM location as MGRS string.
|
*
|
* @private
|
* @param {object} utm An object literal with easting, northing,
|
* zoneLetter, zoneNumber
|
* @param {number} accuracy Accuracy in digits (1-5).
|
* @return {string} MGRS string for the given UTM location.
|
*/
|
function encode(utm, accuracy) {
|
// prepend with leading zeroes
|
var seasting = "00000" + utm.easting,
|
snorthing = "00000" + utm.northing;
|
|
return utm.zoneNumber + utm.zoneLetter + get100kID(utm.easting, utm.northing, utm.zoneNumber) + seasting.substr(seasting.length - 5, accuracy) + snorthing.substr(snorthing.length - 5, accuracy);
|
}
|
|
/**
|
* Get the two letter 100k designator for a given UTM easting,
|
* northing and zone number value.
|
*
|
* @private
|
* @param {number} easting
|
* @param {number} northing
|
* @param {number} zoneNumber
|
* @return the two letter 100k designator for the given UTM location.
|
*/
|
function get100kID(easting, northing, zoneNumber) {
|
var setParm = get100kSetForZone(zoneNumber);
|
var setColumn = Math.floor(easting / 100000);
|
var setRow = Math.floor(northing / 100000) % 20;
|
return getLetter100kID(setColumn, setRow, setParm);
|
}
|
|
/**
|
* Given a UTM zone number, figure out the MGRS 100K set it is in.
|
*
|
* @private
|
* @param {number} i An UTM zone number.
|
* @return {number} the 100k set the UTM zone is in.
|
*/
|
function get100kSetForZone(i) {
|
var setParm = i % NUM_100K_SETS;
|
if (setParm === 0) {
|
setParm = NUM_100K_SETS;
|
}
|
|
return setParm;
|
}
|
|
/**
|
* Get the two-letter MGRS 100k designator given information
|
* translated from the UTM northing, easting and zone number.
|
*
|
* @private
|
* @param {number} column the column index as it relates to the MGRS
|
* 100k set spreadsheet, created from the UTM easting.
|
* Values are 1-8.
|
* @param {number} row the row index as it relates to the MGRS 100k set
|
* spreadsheet, created from the UTM northing value. Values
|
* are from 0-19.
|
* @param {number} parm the set block, as it relates to the MGRS 100k set
|
* spreadsheet, created from the UTM zone. Values are from
|
* 1-60.
|
* @return two letter MGRS 100k code.
|
*/
|
function getLetter100kID(column, row, parm) {
|
// colOrigin and rowOrigin are the letters at the origin of the set
|
var index = parm - 1;
|
var colOrigin = SET_ORIGIN_COLUMN_LETTERS.charCodeAt(index);
|
var rowOrigin = SET_ORIGIN_ROW_LETTERS.charCodeAt(index);
|
|
// colInt and rowInt are the letters to build to return
|
var colInt = colOrigin + column - 1;
|
var rowInt = rowOrigin + row;
|
var rollover = false;
|
|
if (colInt > Z) {
|
colInt = colInt - Z + A - 1;
|
rollover = true;
|
}
|
|
if (colInt === I || (colOrigin < I && colInt > I) || ((colInt > I || colOrigin < I) && rollover)) {
|
colInt++;
|
}
|
|
if (colInt === O || (colOrigin < O && colInt > O) || ((colInt > O || colOrigin < O) && rollover)) {
|
colInt++;
|
|
if (colInt === I) {
|
colInt++;
|
}
|
}
|
|
if (colInt > Z) {
|
colInt = colInt - Z + A - 1;
|
}
|
|
if (rowInt > V) {
|
rowInt = rowInt - V + A - 1;
|
rollover = true;
|
}
|
else {
|
rollover = false;
|
}
|
|
if (((rowInt === I) || ((rowOrigin < I) && (rowInt > I))) || (((rowInt > I) || (rowOrigin < I)) && rollover)) {
|
rowInt++;
|
}
|
|
if (((rowInt === O) || ((rowOrigin < O) && (rowInt > O))) || (((rowInt > O) || (rowOrigin < O)) && rollover)) {
|
rowInt++;
|
|
if (rowInt === I) {
|
rowInt++;
|
}
|
}
|
|
if (rowInt > V) {
|
rowInt = rowInt - V + A - 1;
|
}
|
|
var twoLetter = String.fromCharCode(colInt) + String.fromCharCode(rowInt);
|
return twoLetter;
|
}
|
|
/**
|
* Decode the UTM parameters from a MGRS string.
|
*
|
* @private
|
* @param {string} mgrsString an UPPERCASE coordinate string is expected.
|
* @return {object} An object literal with easting, northing, zoneLetter,
|
* zoneNumber and accuracy (in meters) properties.
|
*/
|
function decode(mgrsString) {
|
|
if (mgrsString && mgrsString.length === 0) {
|
throw ("MGRSPoint coverting from nothing");
|
}
|
|
var length = mgrsString.length;
|
|
var hunK = null;
|
var sb = "";
|
var testChar;
|
var i = 0;
|
|
// get Zone number
|
while (!(/[A-Z]/).test(testChar = mgrsString.charAt(i))) {
|
if (i >= 2) {
|
throw ("MGRSPoint bad conversion from: " + mgrsString);
|
}
|
sb += testChar;
|
i++;
|
}
|
|
var zoneNumber = parseInt(sb, 10);
|
|
if (i === 0 || i + 3 > length) {
|
// A good MGRS string has to be 4-5 digits long,
|
// ##AAA/#AAA at least.
|
throw ("MGRSPoint bad conversion from: " + mgrsString);
|
}
|
|
var zoneLetter = mgrsString.charAt(i++);
|
|
// Should we check the zone letter here? Why not.
|
if (zoneLetter <= 'A' || zoneLetter === 'B' || zoneLetter === 'Y' || zoneLetter >= 'Z' || zoneLetter === 'I' || zoneLetter === 'O') {
|
throw ("MGRSPoint zone letter " + zoneLetter + " not handled: " + mgrsString);
|
}
|
|
hunK = mgrsString.substring(i, i += 2);
|
|
var set = get100kSetForZone(zoneNumber);
|
|
var east100k = getEastingFromChar(hunK.charAt(0), set);
|
var north100k = getNorthingFromChar(hunK.charAt(1), set);
|
|
// We have a bug where the northing may be 2000000 too low.
|
// How
|
// do we know when to roll over?
|
|
while (north100k < getMinNorthing(zoneLetter)) {
|
north100k += 2000000;
|
}
|
|
// calculate the char index for easting/northing separator
|
var remainder = length - i;
|
|
if (remainder % 2 !== 0) {
|
throw ("MGRSPoint has to have an even number \nof digits after the zone letter and two 100km letters - front \nhalf for easting meters, second half for \nnorthing meters" + mgrsString);
|
}
|
|
var sep = remainder / 2;
|
|
var sepEasting = 0.0;
|
var sepNorthing = 0.0;
|
var accuracyBonus, sepEastingString, sepNorthingString, easting, northing;
|
if (sep > 0) {
|
accuracyBonus = 100000.0 / Math.pow(10, sep);
|
sepEastingString = mgrsString.substring(i, i + sep);
|
sepEasting = parseFloat(sepEastingString) * accuracyBonus;
|
sepNorthingString = mgrsString.substring(i + sep);
|
sepNorthing = parseFloat(sepNorthingString) * accuracyBonus;
|
}
|
|
easting = sepEasting + east100k;
|
northing = sepNorthing + north100k;
|
|
return {
|
easting: easting,
|
northing: northing,
|
zoneLetter: zoneLetter,
|
zoneNumber: zoneNumber,
|
accuracy: accuracyBonus
|
};
|
}
|
|
/**
|
* Given the first letter from a two-letter MGRS 100k zone, and given the
|
* MGRS table set for the zone number, figure out the easting value that
|
* should be added to the other, secondary easting value.
|
*
|
* @private
|
* @param {char} e The first letter from a two-letter MGRS 100´k zone.
|
* @param {number} set The MGRS table set for the zone number.
|
* @return {number} The easting value for the given letter and set.
|
*/
|
function getEastingFromChar(e, set) {
|
// colOrigin is the letter at the origin of the set for the
|
// column
|
var curCol = SET_ORIGIN_COLUMN_LETTERS.charCodeAt(set - 1);
|
var eastingValue = 100000.0;
|
var rewindMarker = false;
|
|
while (curCol !== e.charCodeAt(0)) {
|
curCol++;
|
if (curCol === I) {
|
curCol++;
|
}
|
if (curCol === O) {
|
curCol++;
|
}
|
if (curCol > Z) {
|
if (rewindMarker) {
|
throw ("Bad character: " + e);
|
}
|
curCol = A;
|
rewindMarker = true;
|
}
|
eastingValue += 100000.0;
|
}
|
|
return eastingValue;
|
}
|
|
/**
|
* Given the second letter from a two-letter MGRS 100k zone, and given the
|
* MGRS table set for the zone number, figure out the northing value that
|
* should be added to the other, secondary northing value. You have to
|
* remember that Northings are determined from the equator, and the vertical
|
* cycle of letters mean a 2000000 additional northing meters. This happens
|
* approx. every 18 degrees of latitude. This method does *NOT* count any
|
* additional northings. You have to figure out how many 2000000 meters need
|
* to be added for the zone letter of the MGRS coordinate.
|
*
|
* @private
|
* @param {char} n Second letter of the MGRS 100k zone
|
* @param {number} set The MGRS table set number, which is dependent on the
|
* UTM zone number.
|
* @return {number} The northing value for the given letter and set.
|
*/
|
function getNorthingFromChar(n, set) {
|
|
if (n > 'V') {
|
throw ("MGRSPoint given invalid Northing " + n);
|
}
|
|
// rowOrigin is the letter at the origin of the set for the
|
// column
|
var curRow = SET_ORIGIN_ROW_LETTERS.charCodeAt(set - 1);
|
var northingValue = 0.0;
|
var rewindMarker = false;
|
|
while (curRow !== n.charCodeAt(0)) {
|
curRow++;
|
if (curRow === I) {
|
curRow++;
|
}
|
if (curRow === O) {
|
curRow++;
|
}
|
// fixing a bug making whole application hang in this loop
|
// when 'n' is a wrong character
|
if (curRow > V) {
|
if (rewindMarker) { // making sure that this loop ends
|
throw ("Bad character: " + n);
|
}
|
curRow = A;
|
rewindMarker = true;
|
}
|
northingValue += 100000.0;
|
}
|
|
return northingValue;
|
}
|
|
/**
|
* The function getMinNorthing returns the minimum northing value of a MGRS
|
* zone.
|
*
|
* Ported from Geotrans' c Lattitude_Band_Value structure table.
|
*
|
* @private
|
* @param {char} zoneLetter The MGRS zone to get the min northing for.
|
* @return {number}
|
*/
|
function getMinNorthing(zoneLetter) {
|
var northing;
|
switch (zoneLetter) {
|
case 'C':
|
northing = 1100000.0;
|
break;
|
case 'D':
|
northing = 2000000.0;
|
break;
|
case 'E':
|
northing = 2800000.0;
|
break;
|
case 'F':
|
northing = 3700000.0;
|
break;
|
case 'G':
|
northing = 4600000.0;
|
break;
|
case 'H':
|
northing = 5500000.0;
|
break;
|
case 'J':
|
northing = 6400000.0;
|
break;
|
case 'K':
|
northing = 7300000.0;
|
break;
|
case 'L':
|
northing = 8200000.0;
|
break;
|
case 'M':
|
northing = 9100000.0;
|
break;
|
case 'N':
|
northing = 0.0;
|
break;
|
case 'P':
|
northing = 800000.0;
|
break;
|
case 'Q':
|
northing = 1700000.0;
|
break;
|
case 'R':
|
northing = 2600000.0;
|
break;
|
case 'S':
|
northing = 3500000.0;
|
break;
|
case 'T':
|
northing = 4400000.0;
|
break;
|
case 'U':
|
northing = 5300000.0;
|
break;
|
case 'V':
|
northing = 6200000.0;
|
break;
|
case 'W':
|
northing = 7000000.0;
|
break;
|
case 'X':
|
northing = 7900000.0;
|
break;
|
default:
|
northing = -1.0;
|
}
|
if (northing >= 0.0) {
|
return northing;
|
}
|
else {
|
throw ("Invalid zone letter: " + zoneLetter);
|
}
|
|
}
|
|
function Point(x, y, z) {
|
if (!(this instanceof Point)) {
|
return new Point(x, y, z);
|
}
|
if (Array.isArray(x)) {
|
this.x = x[0];
|
this.y = x[1];
|
this.z = x[2] || 0.0;
|
} else if(typeof x === 'object') {
|
this.x = x.x;
|
this.y = x.y;
|
this.z = x.z || 0.0;
|
} else if (typeof x === 'string' && typeof y === 'undefined') {
|
var coords = x.split(',');
|
this.x = parseFloat(coords[0], 10);
|
this.y = parseFloat(coords[1], 10);
|
this.z = parseFloat(coords[2], 10) || 0.0;
|
} else {
|
this.x = x;
|
this.y = y;
|
this.z = z || 0.0;
|
}
|
console.warn('proj4.Point will be removed in version 3, use proj4.toPoint');
|
}
|
|
Point.fromMGRS = function(mgrsStr) {
|
return new Point(toPoint$1(mgrsStr));
|
};
|
Point.prototype.toMGRS = function(accuracy) {
|
return forward$1([this.x, this.y], accuracy);
|
};
|
|
var C00 = 1;
|
var C02 = 0.25;
|
var C04 = 0.046875;
|
var C06 = 0.01953125;
|
var C08 = 0.01068115234375;
|
var C22 = 0.75;
|
var C44 = 0.46875;
|
var C46 = 0.01302083333333333333;
|
var C48 = 0.00712076822916666666;
|
var C66 = 0.36458333333333333333;
|
var C68 = 0.00569661458333333333;
|
var C88 = 0.3076171875;
|
|
var pj_enfn = function(es) {
|
var en = [];
|
en[0] = C00 - es * (C02 + es * (C04 + es * (C06 + es * C08)));
|
en[1] = es * (C22 - es * (C04 + es * (C06 + es * C08)));
|
var t = es * es;
|
en[2] = t * (C44 - es * (C46 + es * C48));
|
t *= es;
|
en[3] = t * (C66 - es * C68);
|
en[4] = t * es * C88;
|
return en;
|
};
|
|
var pj_mlfn = function(phi, sphi, cphi, en) {
|
cphi *= sphi;
|
sphi *= sphi;
|
return (en[0] * phi - cphi * (en[1] + sphi * (en[2] + sphi * (en[3] + sphi * en[4]))));
|
};
|
|
var MAX_ITER = 20;
|
|
var pj_inv_mlfn = function(arg, es, en) {
|
var k = 1 / (1 - es);
|
var phi = arg;
|
for (var i = MAX_ITER; i; --i) { /* rarely goes over 2 iterations */
|
var s = Math.sin(phi);
|
var t = 1 - es * s * s;
|
//t = this.pj_mlfn(phi, s, Math.cos(phi), en) - arg;
|
//phi -= t * (t * Math.sqrt(t)) * k;
|
t = (pj_mlfn(phi, s, Math.cos(phi), en) - arg) * (t * Math.sqrt(t)) * k;
|
phi -= t;
|
if (Math.abs(t) < EPSLN) {
|
return phi;
|
}
|
}
|
//..reportError("cass:pj_inv_mlfn: Convergence error");
|
return phi;
|
};
|
|
// Heavily based on this tmerc projection implementation
|
// https://github.com/mbloch/mapshaper-proj/blob/master/src/projections/tmerc.js
|
|
function init$2() {
|
this.x0 = this.x0 !== undefined ? this.x0 : 0;
|
this.y0 = this.y0 !== undefined ? this.y0 : 0;
|
this.long0 = this.long0 !== undefined ? this.long0 : 0;
|
this.lat0 = this.lat0 !== undefined ? this.lat0 : 0;
|
|
if (this.es) {
|
this.en = pj_enfn(this.es);
|
this.ml0 = pj_mlfn(this.lat0, Math.sin(this.lat0), Math.cos(this.lat0), this.en);
|
}
|
}
|
|
/**
|
Transverse Mercator Forward - long/lat to x/y
|
long/lat in radians
|
*/
|
function forward$2(p) {
|
var lon = p.x;
|
var lat = p.y;
|
|
var delta_lon = adjust_lon(lon - this.long0);
|
var con;
|
var x, y;
|
var sin_phi = Math.sin(lat);
|
var cos_phi = Math.cos(lat);
|
|
if (!this.es) {
|
var b = cos_phi * Math.sin(delta_lon);
|
|
if ((Math.abs(Math.abs(b) - 1)) < EPSLN) {
|
return (93);
|
}
|
else {
|
x = 0.5 * this.a * this.k0 * Math.log((1 + b) / (1 - b)) + this.x0;
|
y = cos_phi * Math.cos(delta_lon) / Math.sqrt(1 - Math.pow(b, 2));
|
b = Math.abs(y);
|
|
if (b >= 1) {
|
if ((b - 1) > EPSLN) {
|
return (93);
|
}
|
else {
|
y = 0;
|
}
|
}
|
else {
|
y = Math.acos(y);
|
}
|
|
if (lat < 0) {
|
y = -y;
|
}
|
|
y = this.a * this.k0 * (y - this.lat0) + this.y0;
|
}
|
}
|
else {
|
var al = cos_phi * delta_lon;
|
var als = Math.pow(al, 2);
|
var c = this.ep2 * Math.pow(cos_phi, 2);
|
var cs = Math.pow(c, 2);
|
var tq = Math.abs(cos_phi) > EPSLN ? Math.tan(lat) : 0;
|
var t = Math.pow(tq, 2);
|
var ts = Math.pow(t, 2);
|
con = 1 - this.es * Math.pow(sin_phi, 2);
|
al = al / Math.sqrt(con);
|
var ml = pj_mlfn(lat, sin_phi, cos_phi, this.en);
|
|
x = this.a * (this.k0 * al * (1 +
|
als / 6 * (1 - t + c +
|
als / 20 * (5 - 18 * t + ts + 14 * c - 58 * t * c +
|
als / 42 * (61 + 179 * ts - ts * t - 479 * t))))) +
|
this.x0;
|
|
y = this.a * (this.k0 * (ml - this.ml0 +
|
sin_phi * delta_lon * al / 2 * (1 +
|
als / 12 * (5 - t + 9 * c + 4 * cs +
|
als / 30 * (61 + ts - 58 * t + 270 * c - 330 * t * c +
|
als / 56 * (1385 + 543 * ts - ts * t - 3111 * t)))))) +
|
this.y0;
|
}
|
|
p.x = x;
|
p.y = y;
|
|
return p;
|
}
|
|
/**
|
Transverse Mercator Inverse - x/y to long/lat
|
*/
|
function inverse$2(p) {
|
var con, phi;
|
var lat, lon;
|
var x = (p.x - this.x0) * (1 / this.a);
|
var y = (p.y - this.y0) * (1 / this.a);
|
|
if (!this.es) {
|
var f = Math.exp(x / this.k0);
|
var g = 0.5 * (f - 1 / f);
|
var temp = this.lat0 + y / this.k0;
|
var h = Math.cos(temp);
|
con = Math.sqrt((1 - Math.pow(h, 2)) / (1 + Math.pow(g, 2)));
|
lat = Math.asin(con);
|
|
if (y < 0) {
|
lat = -lat;
|
}
|
|
if ((g === 0) && (h === 0)) {
|
lon = 0;
|
}
|
else {
|
lon = adjust_lon(Math.atan2(g, h) + this.long0);
|
}
|
}
|
else { // ellipsoidal form
|
con = this.ml0 + y / this.k0;
|
phi = pj_inv_mlfn(con, this.es, this.en);
|
|
if (Math.abs(phi) < HALF_PI) {
|
var sin_phi = Math.sin(phi);
|
var cos_phi = Math.cos(phi);
|
var tan_phi = Math.abs(cos_phi) > EPSLN ? Math.tan(phi) : 0;
|
var c = this.ep2 * Math.pow(cos_phi, 2);
|
var cs = Math.pow(c, 2);
|
var t = Math.pow(tan_phi, 2);
|
var ts = Math.pow(t, 2);
|
con = 1 - this.es * Math.pow(sin_phi, 2);
|
var d = x * Math.sqrt(con) / this.k0;
|
var ds = Math.pow(d, 2);
|
con = con * tan_phi;
|
|
lat = phi - (con * ds / (1 - this.es)) * 0.5 * (1 -
|
ds / 12 * (5 + 3 * t - 9 * c * t + c - 4 * cs -
|
ds / 30 * (61 + 90 * t - 252 * c * t + 45 * ts + 46 * c -
|
ds / 56 * (1385 + 3633 * t + 4095 * ts + 1574 * ts * t))));
|
|
lon = adjust_lon(this.long0 + (d * (1 -
|
ds / 6 * (1 + 2 * t + c -
|
ds / 20 * (5 + 28 * t + 24 * ts + 8 * c * t + 6 * c -
|
ds / 42 * (61 + 662 * t + 1320 * ts + 720 * ts * t)))) / cos_phi));
|
}
|
else {
|
lat = HALF_PI * sign(y);
|
lon = 0;
|
}
|
}
|
|
p.x = lon;
|
p.y = lat;
|
|
return p;
|
}
|
|
var names$3 = ["Transverse_Mercator", "Transverse Mercator", "tmerc"];
|
var tmerc = {
|
init: init$2,
|
forward: forward$2,
|
inverse: inverse$2,
|
names: names$3
|
};
|
|
var sinh = function(x) {
|
var r = Math.exp(x);
|
r = (r - 1 / r) / 2;
|
return r;
|
};
|
|
var hypot = function(x, y) {
|
x = Math.abs(x);
|
y = Math.abs(y);
|
var a = Math.max(x, y);
|
var b = Math.min(x, y) / (a ? a : 1);
|
|
return a * Math.sqrt(1 + Math.pow(b, 2));
|
};
|
|
var log1py = function(x) {
|
var y = 1 + x;
|
var z = y - 1;
|
|
return z === 0 ? x : x * Math.log(y) / z;
|
};
|
|
var asinhy = function(x) {
|
var y = Math.abs(x);
|
y = log1py(y * (1 + y / (hypot(1, y) + 1)));
|
|
return x < 0 ? -y : y;
|
};
|
|
var gatg = function(pp, B) {
|
var cos_2B = 2 * Math.cos(2 * B);
|
var i = pp.length - 1;
|
var h1 = pp[i];
|
var h2 = 0;
|
var h;
|
|
while (--i >= 0) {
|
h = -h2 + cos_2B * h1 + pp[i];
|
h2 = h1;
|
h1 = h;
|
}
|
|
return (B + h * Math.sin(2 * B));
|
};
|
|
var clens = function(pp, arg_r) {
|
var r = 2 * Math.cos(arg_r);
|
var i = pp.length - 1;
|
var hr1 = pp[i];
|
var hr2 = 0;
|
var hr;
|
|
while (--i >= 0) {
|
hr = -hr2 + r * hr1 + pp[i];
|
hr2 = hr1;
|
hr1 = hr;
|
}
|
|
return Math.sin(arg_r) * hr;
|
};
|
|
var cosh = function(x) {
|
var r = Math.exp(x);
|
r = (r + 1 / r) / 2;
|
return r;
|
};
|
|
var clens_cmplx = function(pp, arg_r, arg_i) {
|
var sin_arg_r = Math.sin(arg_r);
|
var cos_arg_r = Math.cos(arg_r);
|
var sinh_arg_i = sinh(arg_i);
|
var cosh_arg_i = cosh(arg_i);
|
var r = 2 * cos_arg_r * cosh_arg_i;
|
var i = -2 * sin_arg_r * sinh_arg_i;
|
var j = pp.length - 1;
|
var hr = pp[j];
|
var hi1 = 0;
|
var hr1 = 0;
|
var hi = 0;
|
var hr2;
|
var hi2;
|
|
while (--j >= 0) {
|
hr2 = hr1;
|
hi2 = hi1;
|
hr1 = hr;
|
hi1 = hi;
|
hr = -hr2 + r * hr1 - i * hi1 + pp[j];
|
hi = -hi2 + i * hr1 + r * hi1;
|
}
|
|
r = sin_arg_r * cosh_arg_i;
|
i = cos_arg_r * sinh_arg_i;
|
|
return [r * hr - i * hi, r * hi + i * hr];
|
};
|
|
// Heavily based on this etmerc projection implementation
|
// https://github.com/mbloch/mapshaper-proj/blob/master/src/projections/etmerc.js
|
|
function init$3() {
|
if (this.es === undefined || this.es <= 0) {
|
throw new Error('incorrect elliptical usage');
|
}
|
|
this.x0 = this.x0 !== undefined ? this.x0 : 0;
|
this.y0 = this.y0 !== undefined ? this.y0 : 0;
|
this.long0 = this.long0 !== undefined ? this.long0 : 0;
|
this.lat0 = this.lat0 !== undefined ? this.lat0 : 0;
|
|
this.cgb = [];
|
this.cbg = [];
|
this.utg = [];
|
this.gtu = [];
|
|
var f = this.es / (1 + Math.sqrt(1 - this.es));
|
var n = f / (2 - f);
|
var np = n;
|
|
this.cgb[0] = n * (2 + n * (-2 / 3 + n * (-2 + n * (116 / 45 + n * (26 / 45 + n * (-2854 / 675 ))))));
|
this.cbg[0] = n * (-2 + n * ( 2 / 3 + n * ( 4 / 3 + n * (-82 / 45 + n * (32 / 45 + n * (4642 / 4725))))));
|
|
np = np * n;
|
this.cgb[1] = np * (7 / 3 + n * (-8 / 5 + n * (-227 / 45 + n * (2704 / 315 + n * (2323 / 945)))));
|
this.cbg[1] = np * (5 / 3 + n * (-16 / 15 + n * ( -13 / 9 + n * (904 / 315 + n * (-1522 / 945)))));
|
|
np = np * n;
|
this.cgb[2] = np * (56 / 15 + n * (-136 / 35 + n * (-1262 / 105 + n * (73814 / 2835))));
|
this.cbg[2] = np * (-26 / 15 + n * (34 / 21 + n * (8 / 5 + n * (-12686 / 2835))));
|
|
np = np * n;
|
this.cgb[3] = np * (4279 / 630 + n * (-332 / 35 + n * (-399572 / 14175)));
|
this.cbg[3] = np * (1237 / 630 + n * (-12 / 5 + n * ( -24832 / 14175)));
|
|
np = np * n;
|
this.cgb[4] = np * (4174 / 315 + n * (-144838 / 6237));
|
this.cbg[4] = np * (-734 / 315 + n * (109598 / 31185));
|
|
np = np * n;
|
this.cgb[5] = np * (601676 / 22275);
|
this.cbg[5] = np * (444337 / 155925);
|
|
np = Math.pow(n, 2);
|
this.Qn = this.k0 / (1 + n) * (1 + np * (1 / 4 + np * (1 / 64 + np / 256)));
|
|
this.utg[0] = n * (-0.5 + n * ( 2 / 3 + n * (-37 / 96 + n * ( 1 / 360 + n * (81 / 512 + n * (-96199 / 604800))))));
|
this.gtu[0] = n * (0.5 + n * (-2 / 3 + n * (5 / 16 + n * (41 / 180 + n * (-127 / 288 + n * (7891 / 37800))))));
|
|
this.utg[1] = np * (-1 / 48 + n * (-1 / 15 + n * (437 / 1440 + n * (-46 / 105 + n * (1118711 / 3870720)))));
|
this.gtu[1] = np * (13 / 48 + n * (-3 / 5 + n * (557 / 1440 + n * (281 / 630 + n * (-1983433 / 1935360)))));
|
|
np = np * n;
|
this.utg[2] = np * (-17 / 480 + n * (37 / 840 + n * (209 / 4480 + n * (-5569 / 90720 ))));
|
this.gtu[2] = np * (61 / 240 + n * (-103 / 140 + n * (15061 / 26880 + n * (167603 / 181440))));
|
|
np = np * n;
|
this.utg[3] = np * (-4397 / 161280 + n * (11 / 504 + n * (830251 / 7257600)));
|
this.gtu[3] = np * (49561 / 161280 + n * (-179 / 168 + n * (6601661 / 7257600)));
|
|
np = np * n;
|
this.utg[4] = np * (-4583 / 161280 + n * (108847 / 3991680));
|
this.gtu[4] = np * (34729 / 80640 + n * (-3418889 / 1995840));
|
|
np = np * n;
|
this.utg[5] = np * (-20648693 / 638668800);
|
this.gtu[5] = np * (212378941 / 319334400);
|
|
var Z = gatg(this.cbg, this.lat0);
|
this.Zb = -this.Qn * (Z + clens(this.gtu, 2 * Z));
|
}
|
|
function forward$3(p) {
|
var Ce = adjust_lon(p.x - this.long0);
|
var Cn = p.y;
|
|
Cn = gatg(this.cbg, Cn);
|
var sin_Cn = Math.sin(Cn);
|
var cos_Cn = Math.cos(Cn);
|
var sin_Ce = Math.sin(Ce);
|
var cos_Ce = Math.cos(Ce);
|
|
Cn = Math.atan2(sin_Cn, cos_Ce * cos_Cn);
|
Ce = Math.atan2(sin_Ce * cos_Cn, hypot(sin_Cn, cos_Cn * cos_Ce));
|
Ce = asinhy(Math.tan(Ce));
|
|
var tmp = clens_cmplx(this.gtu, 2 * Cn, 2 * Ce);
|
|
Cn = Cn + tmp[0];
|
Ce = Ce + tmp[1];
|
|
var x;
|
var y;
|
|
if (Math.abs(Ce) <= 2.623395162778) {
|
x = this.a * (this.Qn * Ce) + this.x0;
|
y = this.a * (this.Qn * Cn + this.Zb) + this.y0;
|
}
|
else {
|
x = Infinity;
|
y = Infinity;
|
}
|
|
p.x = x;
|
p.y = y;
|
|
return p;
|
}
|
|
function inverse$3(p) {
|
var Ce = (p.x - this.x0) * (1 / this.a);
|
var Cn = (p.y - this.y0) * (1 / this.a);
|
|
Cn = (Cn - this.Zb) / this.Qn;
|
Ce = Ce / this.Qn;
|
|
var lon;
|
var lat;
|
|
if (Math.abs(Ce) <= 2.623395162778) {
|
var tmp = clens_cmplx(this.utg, 2 * Cn, 2 * Ce);
|
|
Cn = Cn + tmp[0];
|
Ce = Ce + tmp[1];
|
Ce = Math.atan(sinh(Ce));
|
|
var sin_Cn = Math.sin(Cn);
|
var cos_Cn = Math.cos(Cn);
|
var sin_Ce = Math.sin(Ce);
|
var cos_Ce = Math.cos(Ce);
|
|
Cn = Math.atan2(sin_Cn * cos_Ce, hypot(sin_Ce, cos_Ce * cos_Cn));
|
Ce = Math.atan2(sin_Ce, cos_Ce * cos_Cn);
|
|
lon = adjust_lon(Ce + this.long0);
|
lat = gatg(this.cgb, Cn);
|
}
|
else {
|
lon = Infinity;
|
lat = Infinity;
|
}
|
|
p.x = lon;
|
p.y = lat;
|
|
return p;
|
}
|
|
var names$4 = ["Extended_Transverse_Mercator", "Extended Transverse Mercator", "etmerc"];
|
var etmerc = {
|
init: init$3,
|
forward: forward$3,
|
inverse: inverse$3,
|
names: names$4
|
};
|
|
var adjust_zone = function(zone, lon) {
|
if (zone === undefined) {
|
zone = Math.floor((adjust_lon(lon) + Math.PI) * 30 / Math.PI) + 1;
|
|
if (zone < 0) {
|
return 0;
|
} else if (zone > 60) {
|
return 60;
|
}
|
}
|
return zone;
|
};
|
|
var dependsOn = 'etmerc';
|
function init$4() {
|
var zone = adjust_zone(this.zone, this.long0);
|
if (zone === undefined) {
|
throw new Error('unknown utm zone');
|
}
|
this.lat0 = 0;
|
this.long0 = ((6 * Math.abs(zone)) - 183) * D2R;
|
this.x0 = 500000;
|
this.y0 = this.utmSouth ? 10000000 : 0;
|
this.k0 = 0.9996;
|
|
etmerc.init.apply(this);
|
this.forward = etmerc.forward;
|
this.inverse = etmerc.inverse;
|
}
|
|
var names$5 = ["Universal Transverse Mercator System", "utm"];
|
var utm = {
|
init: init$4,
|
names: names$5,
|
dependsOn: dependsOn
|
};
|
|
var srat = function(esinp, exp) {
|
return (Math.pow((1 - esinp) / (1 + esinp), exp));
|
};
|
|
var MAX_ITER$1 = 20;
|
function init$6() {
|
var sphi = Math.sin(this.lat0);
|
var cphi = Math.cos(this.lat0);
|
cphi *= cphi;
|
this.rc = Math.sqrt(1 - this.es) / (1 - this.es * sphi * sphi);
|
this.C = Math.sqrt(1 + this.es * cphi * cphi / (1 - this.es));
|
this.phic0 = Math.asin(sphi / this.C);
|
this.ratexp = 0.5 * this.C * this.e;
|
this.K = Math.tan(0.5 * this.phic0 + FORTPI) / (Math.pow(Math.tan(0.5 * this.lat0 + FORTPI), this.C) * srat(this.e * sphi, this.ratexp));
|
}
|
|
function forward$5(p) {
|
var lon = p.x;
|
var lat = p.y;
|
|
p.y = 2 * Math.atan(this.K * Math.pow(Math.tan(0.5 * lat + FORTPI), this.C) * srat(this.e * Math.sin(lat), this.ratexp)) - HALF_PI;
|
p.x = this.C * lon;
|
return p;
|
}
|
|
function inverse$5(p) {
|
var DEL_TOL = 1e-14;
|
var lon = p.x / this.C;
|
var lat = p.y;
|
var num = Math.pow(Math.tan(0.5 * lat + FORTPI) / this.K, 1 / this.C);
|
for (var i = MAX_ITER$1; i > 0; --i) {
|
lat = 2 * Math.atan(num * srat(this.e * Math.sin(p.y), - 0.5 * this.e)) - HALF_PI;
|
if (Math.abs(lat - p.y) < DEL_TOL) {
|
break;
|
}
|
p.y = lat;
|
}
|
/* convergence failed */
|
if (!i) {
|
return null;
|
}
|
p.x = lon;
|
p.y = lat;
|
return p;
|
}
|
|
var names$7 = ["gauss"];
|
var gauss = {
|
init: init$6,
|
forward: forward$5,
|
inverse: inverse$5,
|
names: names$7
|
};
|
|
function init$5() {
|
gauss.init.apply(this);
|
if (!this.rc) {
|
return;
|
}
|
this.sinc0 = Math.sin(this.phic0);
|
this.cosc0 = Math.cos(this.phic0);
|
this.R2 = 2 * this.rc;
|
if (!this.title) {
|
this.title = "Oblique Stereographic Alternative";
|
}
|
}
|
|
function forward$4(p) {
|
var sinc, cosc, cosl, k;
|
p.x = adjust_lon(p.x - this.long0);
|
gauss.forward.apply(this, [p]);
|
sinc = Math.sin(p.y);
|
cosc = Math.cos(p.y);
|
cosl = Math.cos(p.x);
|
k = this.k0 * this.R2 / (1 + this.sinc0 * sinc + this.cosc0 * cosc * cosl);
|
p.x = k * cosc * Math.sin(p.x);
|
p.y = k * (this.cosc0 * sinc - this.sinc0 * cosc * cosl);
|
p.x = this.a * p.x + this.x0;
|
p.y = this.a * p.y + this.y0;
|
return p;
|
}
|
|
function inverse$4(p) {
|
var sinc, cosc, lon, lat, rho;
|
p.x = (p.x - this.x0) / this.a;
|
p.y = (p.y - this.y0) / this.a;
|
|
p.x /= this.k0;
|
p.y /= this.k0;
|
if ((rho = Math.sqrt(p.x * p.x + p.y * p.y))) {
|
var c = 2 * Math.atan2(rho, this.R2);
|
sinc = Math.sin(c);
|
cosc = Math.cos(c);
|
lat = Math.asin(cosc * this.sinc0 + p.y * sinc * this.cosc0 / rho);
|
lon = Math.atan2(p.x * sinc, rho * this.cosc0 * cosc - p.y * this.sinc0 * sinc);
|
}
|
else {
|
lat = this.phic0;
|
lon = 0;
|
}
|
|
p.x = lon;
|
p.y = lat;
|
gauss.inverse.apply(this, [p]);
|
p.x = adjust_lon(p.x + this.long0);
|
return p;
|
}
|
|
var names$6 = ["Stereographic_North_Pole", "Oblique_Stereographic", "Polar_Stereographic", "sterea","Oblique Stereographic Alternative","Double_Stereographic"];
|
var sterea = {
|
init: init$5,
|
forward: forward$4,
|
inverse: inverse$4,
|
names: names$6
|
};
|
|
function ssfn_(phit, sinphi, eccen) {
|
sinphi *= eccen;
|
return (Math.tan(0.5 * (HALF_PI + phit)) * Math.pow((1 - sinphi) / (1 + sinphi), 0.5 * eccen));
|
}
|
|
function init$7() {
|
this.coslat0 = Math.cos(this.lat0);
|
this.sinlat0 = Math.sin(this.lat0);
|
if (this.sphere) {
|
if (this.k0 === 1 && !isNaN(this.lat_ts) && Math.abs(this.coslat0) <= EPSLN) {
|
this.k0 = 0.5 * (1 + sign(this.lat0) * Math.sin(this.lat_ts));
|
}
|
}
|
else {
|
if (Math.abs(this.coslat0) <= EPSLN) {
|
if (this.lat0 > 0) {
|
//North pole
|
//trace('stere:north pole');
|
this.con = 1;
|
}
|
else {
|
//South pole
|
//trace('stere:south pole');
|
this.con = -1;
|
}
|
}
|
this.cons = Math.sqrt(Math.pow(1 + this.e, 1 + this.e) * Math.pow(1 - this.e, 1 - this.e));
|
if (this.k0 === 1 && !isNaN(this.lat_ts) && Math.abs(this.coslat0) <= EPSLN) {
|
this.k0 = 0.5 * this.cons * msfnz(this.e, Math.sin(this.lat_ts), Math.cos(this.lat_ts)) / tsfnz(this.e, this.con * this.lat_ts, this.con * Math.sin(this.lat_ts));
|
}
|
this.ms1 = msfnz(this.e, this.sinlat0, this.coslat0);
|
this.X0 = 2 * Math.atan(this.ssfn_(this.lat0, this.sinlat0, this.e)) - HALF_PI;
|
this.cosX0 = Math.cos(this.X0);
|
this.sinX0 = Math.sin(this.X0);
|
}
|
}
|
|
// Stereographic forward equations--mapping lat,long to x,y
|
function forward$6(p) {
|
var lon = p.x;
|
var lat = p.y;
|
var sinlat = Math.sin(lat);
|
var coslat = Math.cos(lat);
|
var A, X, sinX, cosX, ts, rh;
|
var dlon = adjust_lon(lon - this.long0);
|
|
if (Math.abs(Math.abs(lon - this.long0) - Math.PI) <= EPSLN && Math.abs(lat + this.lat0) <= EPSLN) {
|
//case of the origine point
|
//trace('stere:this is the origin point');
|
p.x = NaN;
|
p.y = NaN;
|
return p;
|
}
|
if (this.sphere) {
|
//trace('stere:sphere case');
|
A = 2 * this.k0 / (1 + this.sinlat0 * sinlat + this.coslat0 * coslat * Math.cos(dlon));
|
p.x = this.a * A * coslat * Math.sin(dlon) + this.x0;
|
p.y = this.a * A * (this.coslat0 * sinlat - this.sinlat0 * coslat * Math.cos(dlon)) + this.y0;
|
return p;
|
}
|
else {
|
X = 2 * Math.atan(this.ssfn_(lat, sinlat, this.e)) - HALF_PI;
|
cosX = Math.cos(X);
|
sinX = Math.sin(X);
|
if (Math.abs(this.coslat0) <= EPSLN) {
|
ts = tsfnz(this.e, lat * this.con, this.con * sinlat);
|
rh = 2 * this.a * this.k0 * ts / this.cons;
|
p.x = this.x0 + rh * Math.sin(lon - this.long0);
|
p.y = this.y0 - this.con * rh * Math.cos(lon - this.long0);
|
//trace(p.toString());
|
return p;
|
}
|
else if (Math.abs(this.sinlat0) < EPSLN) {
|
//Eq
|
//trace('stere:equateur');
|
A = 2 * this.a * this.k0 / (1 + cosX * Math.cos(dlon));
|
p.y = A * sinX;
|
}
|
else {
|
//other case
|
//trace('stere:normal case');
|
A = 2 * this.a * this.k0 * this.ms1 / (this.cosX0 * (1 + this.sinX0 * sinX + this.cosX0 * cosX * Math.cos(dlon)));
|
p.y = A * (this.cosX0 * sinX - this.sinX0 * cosX * Math.cos(dlon)) + this.y0;
|
}
|
p.x = A * cosX * Math.sin(dlon) + this.x0;
|
}
|
//trace(p.toString());
|
return p;
|
}
|
|
//* Stereographic inverse equations--mapping x,y to lat/long
|
function inverse$6(p) {
|
p.x -= this.x0;
|
p.y -= this.y0;
|
var lon, lat, ts, ce, Chi;
|
var rh = Math.sqrt(p.x * p.x + p.y * p.y);
|
if (this.sphere) {
|
var c = 2 * Math.atan(rh / (2 * this.a * this.k0));
|
lon = this.long0;
|
lat = this.lat0;
|
if (rh <= EPSLN) {
|
p.x = lon;
|
p.y = lat;
|
return p;
|
}
|
lat = Math.asin(Math.cos(c) * this.sinlat0 + p.y * Math.sin(c) * this.coslat0 / rh);
|
if (Math.abs(this.coslat0) < EPSLN) {
|
if (this.lat0 > 0) {
|
lon = adjust_lon(this.long0 + Math.atan2(p.x, - 1 * p.y));
|
}
|
else {
|
lon = adjust_lon(this.long0 + Math.atan2(p.x, p.y));
|
}
|
}
|
else {
|
lon = adjust_lon(this.long0 + Math.atan2(p.x * Math.sin(c), rh * this.coslat0 * Math.cos(c) - p.y * this.sinlat0 * Math.sin(c)));
|
}
|
p.x = lon;
|
p.y = lat;
|
return p;
|
}
|
else {
|
if (Math.abs(this.coslat0) <= EPSLN) {
|
if (rh <= EPSLN) {
|
lat = this.lat0;
|
lon = this.long0;
|
p.x = lon;
|
p.y = lat;
|
//trace(p.toString());
|
return p;
|
}
|
p.x *= this.con;
|
p.y *= this.con;
|
ts = rh * this.cons / (2 * this.a * this.k0);
|
lat = this.con * phi2z(this.e, ts);
|
lon = this.con * adjust_lon(this.con * this.long0 + Math.atan2(p.x, - 1 * p.y));
|
}
|
else {
|
ce = 2 * Math.atan(rh * this.cosX0 / (2 * this.a * this.k0 * this.ms1));
|
lon = this.long0;
|
if (rh <= EPSLN) {
|
Chi = this.X0;
|
}
|
else {
|
Chi = Math.asin(Math.cos(ce) * this.sinX0 + p.y * Math.sin(ce) * this.cosX0 / rh);
|
lon = adjust_lon(this.long0 + Math.atan2(p.x * Math.sin(ce), rh * this.cosX0 * Math.cos(ce) - p.y * this.sinX0 * Math.sin(ce)));
|
}
|
lat = -1 * phi2z(this.e, Math.tan(0.5 * (HALF_PI + Chi)));
|
}
|
}
|
p.x = lon;
|
p.y = lat;
|
|
//trace(p.toString());
|
return p;
|
|
}
|
|
var names$8 = ["stere", "Stereographic_South_Pole", "Polar Stereographic (variant B)"];
|
var stere = {
|
init: init$7,
|
forward: forward$6,
|
inverse: inverse$6,
|
names: names$8,
|
ssfn_: ssfn_
|
};
|
|
/*
|
references:
|
Formules et constantes pour le Calcul pour la
|
projection cylindrique conforme à axe oblique et pour la transformation entre
|
des systèmes de référence.
|
http://www.swisstopo.admin.ch/internet/swisstopo/fr/home/topics/survey/sys/refsys/switzerland.parsysrelated1.31216.downloadList.77004.DownloadFile.tmp/swissprojectionfr.pdf
|
*/
|
|
function init$8() {
|
var phy0 = this.lat0;
|
this.lambda0 = this.long0;
|
var sinPhy0 = Math.sin(phy0);
|
var semiMajorAxis = this.a;
|
var invF = this.rf;
|
var flattening = 1 / invF;
|
var e2 = 2 * flattening - Math.pow(flattening, 2);
|
var e = this.e = Math.sqrt(e2);
|
this.R = this.k0 * semiMajorAxis * Math.sqrt(1 - e2) / (1 - e2 * Math.pow(sinPhy0, 2));
|
this.alpha = Math.sqrt(1 + e2 / (1 - e2) * Math.pow(Math.cos(phy0), 4));
|
this.b0 = Math.asin(sinPhy0 / this.alpha);
|
var k1 = Math.log(Math.tan(Math.PI / 4 + this.b0 / 2));
|
var k2 = Math.log(Math.tan(Math.PI / 4 + phy0 / 2));
|
var k3 = Math.log((1 + e * sinPhy0) / (1 - e * sinPhy0));
|
this.K = k1 - this.alpha * k2 + this.alpha * e / 2 * k3;
|
}
|
|
function forward$7(p) {
|
var Sa1 = Math.log(Math.tan(Math.PI / 4 - p.y / 2));
|
var Sa2 = this.e / 2 * Math.log((1 + this.e * Math.sin(p.y)) / (1 - this.e * Math.sin(p.y)));
|
var S = -this.alpha * (Sa1 + Sa2) + this.K;
|
|
// spheric latitude
|
var b = 2 * (Math.atan(Math.exp(S)) - Math.PI / 4);
|
|
// spheric longitude
|
var I = this.alpha * (p.x - this.lambda0);
|
|
// psoeudo equatorial rotation
|
var rotI = Math.atan(Math.sin(I) / (Math.sin(this.b0) * Math.tan(b) + Math.cos(this.b0) * Math.cos(I)));
|
|
var rotB = Math.asin(Math.cos(this.b0) * Math.sin(b) - Math.sin(this.b0) * Math.cos(b) * Math.cos(I));
|
|
p.y = this.R / 2 * Math.log((1 + Math.sin(rotB)) / (1 - Math.sin(rotB))) + this.y0;
|
p.x = this.R * rotI + this.x0;
|
return p;
|
}
|
|
function inverse$7(p) {
|
var Y = p.x - this.x0;
|
var X = p.y - this.y0;
|
|
var rotI = Y / this.R;
|
var rotB = 2 * (Math.atan(Math.exp(X / this.R)) - Math.PI / 4);
|
|
var b = Math.asin(Math.cos(this.b0) * Math.sin(rotB) + Math.sin(this.b0) * Math.cos(rotB) * Math.cos(rotI));
|
var I = Math.atan(Math.sin(rotI) / (Math.cos(this.b0) * Math.cos(rotI) - Math.sin(this.b0) * Math.tan(rotB)));
|
|
var lambda = this.lambda0 + I / this.alpha;
|
|
var S = 0;
|
var phy = b;
|
var prevPhy = -1000;
|
var iteration = 0;
|
while (Math.abs(phy - prevPhy) > 0.0000001) {
|
if (++iteration > 20) {
|
//...reportError("omercFwdInfinity");
|
return;
|
}
|
//S = Math.log(Math.tan(Math.PI / 4 + phy / 2));
|
S = 1 / this.alpha * (Math.log(Math.tan(Math.PI / 4 + b / 2)) - this.K) + this.e * Math.log(Math.tan(Math.PI / 4 + Math.asin(this.e * Math.sin(phy)) / 2));
|
prevPhy = phy;
|
phy = 2 * Math.atan(Math.exp(S)) - Math.PI / 2;
|
}
|
|
p.x = lambda;
|
p.y = phy;
|
return p;
|
}
|
|
var names$9 = ["somerc"];
|
var somerc = {
|
init: init$8,
|
forward: forward$7,
|
inverse: inverse$7,
|
names: names$9
|
};
|
|
/* Initialize the Oblique Mercator projection
|
------------------------------------------*/
|
function init$9() {
|
this.no_off = this.no_off || false;
|
this.no_rot = this.no_rot || false;
|
|
if (isNaN(this.k0)) {
|
this.k0 = 1;
|
}
|
var sinlat = Math.sin(this.lat0);
|
var coslat = Math.cos(this.lat0);
|
var con = this.e * sinlat;
|
|
this.bl = Math.sqrt(1 + this.es / (1 - this.es) * Math.pow(coslat, 4));
|
this.al = this.a * this.bl * this.k0 * Math.sqrt(1 - this.es) / (1 - con * con);
|
var t0 = tsfnz(this.e, this.lat0, sinlat);
|
var dl = this.bl / coslat * Math.sqrt((1 - this.es) / (1 - con * con));
|
if (dl * dl < 1) {
|
dl = 1;
|
}
|
var fl;
|
var gl;
|
if (!isNaN(this.longc)) {
|
//Central point and azimuth method
|
|
if (this.lat0 >= 0) {
|
fl = dl + Math.sqrt(dl * dl - 1);
|
}
|
else {
|
fl = dl - Math.sqrt(dl * dl - 1);
|
}
|
this.el = fl * Math.pow(t0, this.bl);
|
gl = 0.5 * (fl - 1 / fl);
|
this.gamma0 = Math.asin(Math.sin(this.alpha) / dl);
|
this.long0 = this.longc - Math.asin(gl * Math.tan(this.gamma0)) / this.bl;
|
|
}
|
else {
|
//2 points method
|
var t1 = tsfnz(this.e, this.lat1, Math.sin(this.lat1));
|
var t2 = tsfnz(this.e, this.lat2, Math.sin(this.lat2));
|
if (this.lat0 >= 0) {
|
this.el = (dl + Math.sqrt(dl * dl - 1)) * Math.pow(t0, this.bl);
|
}
|
else {
|
this.el = (dl - Math.sqrt(dl * dl - 1)) * Math.pow(t0, this.bl);
|
}
|
var hl = Math.pow(t1, this.bl);
|
var ll = Math.pow(t2, this.bl);
|
fl = this.el / hl;
|
gl = 0.5 * (fl - 1 / fl);
|
var jl = (this.el * this.el - ll * hl) / (this.el * this.el + ll * hl);
|
var pl = (ll - hl) / (ll + hl);
|
var dlon12 = adjust_lon(this.long1 - this.long2);
|
this.long0 = 0.5 * (this.long1 + this.long2) - Math.atan(jl * Math.tan(0.5 * this.bl * (dlon12)) / pl) / this.bl;
|
this.long0 = adjust_lon(this.long0);
|
var dlon10 = adjust_lon(this.long1 - this.long0);
|
this.gamma0 = Math.atan(Math.sin(this.bl * (dlon10)) / gl);
|
this.alpha = Math.asin(dl * Math.sin(this.gamma0));
|
}
|
|
if (this.no_off) {
|
this.uc = 0;
|
}
|
else {
|
if (this.lat0 >= 0) {
|
this.uc = this.al / this.bl * Math.atan2(Math.sqrt(dl * dl - 1), Math.cos(this.alpha));
|
}
|
else {
|
this.uc = -1 * this.al / this.bl * Math.atan2(Math.sqrt(dl * dl - 1), Math.cos(this.alpha));
|
}
|
}
|
|
}
|
|
/* Oblique Mercator forward equations--mapping lat,long to x,y
|
----------------------------------------------------------*/
|
function forward$8(p) {
|
var lon = p.x;
|
var lat = p.y;
|
var dlon = adjust_lon(lon - this.long0);
|
var us, vs;
|
var con;
|
if (Math.abs(Math.abs(lat) - HALF_PI) <= EPSLN) {
|
if (lat > 0) {
|
con = -1;
|
}
|
else {
|
con = 1;
|
}
|
vs = this.al / this.bl * Math.log(Math.tan(FORTPI + con * this.gamma0 * 0.5));
|
us = -1 * con * HALF_PI * this.al / this.bl;
|
}
|
else {
|
var t = tsfnz(this.e, lat, Math.sin(lat));
|
var ql = this.el / Math.pow(t, this.bl);
|
var sl = 0.5 * (ql - 1 / ql);
|
var tl = 0.5 * (ql + 1 / ql);
|
var vl = Math.sin(this.bl * (dlon));
|
var ul = (sl * Math.sin(this.gamma0) - vl * Math.cos(this.gamma0)) / tl;
|
if (Math.abs(Math.abs(ul) - 1) <= EPSLN) {
|
vs = Number.POSITIVE_INFINITY;
|
}
|
else {
|
vs = 0.5 * this.al * Math.log((1 - ul) / (1 + ul)) / this.bl;
|
}
|
if (Math.abs(Math.cos(this.bl * (dlon))) <= EPSLN) {
|
us = this.al * this.bl * (dlon);
|
}
|
else {
|
us = this.al * Math.atan2(sl * Math.cos(this.gamma0) + vl * Math.sin(this.gamma0), Math.cos(this.bl * dlon)) / this.bl;
|
}
|
}
|
|
if (this.no_rot) {
|
p.x = this.x0 + us;
|
p.y = this.y0 + vs;
|
}
|
else {
|
|
us -= this.uc;
|
p.x = this.x0 + vs * Math.cos(this.alpha) + us * Math.sin(this.alpha);
|
p.y = this.y0 + us * Math.cos(this.alpha) - vs * Math.sin(this.alpha);
|
}
|
return p;
|
}
|
|
function inverse$8(p) {
|
var us, vs;
|
if (this.no_rot) {
|
vs = p.y - this.y0;
|
us = p.x - this.x0;
|
}
|
else {
|
vs = (p.x - this.x0) * Math.cos(this.alpha) - (p.y - this.y0) * Math.sin(this.alpha);
|
us = (p.y - this.y0) * Math.cos(this.alpha) + (p.x - this.x0) * Math.sin(this.alpha);
|
us += this.uc;
|
}
|
var qp = Math.exp(-1 * this.bl * vs / this.al);
|
var sp = 0.5 * (qp - 1 / qp);
|
var tp = 0.5 * (qp + 1 / qp);
|
var vp = Math.sin(this.bl * us / this.al);
|
var up = (vp * Math.cos(this.gamma0) + sp * Math.sin(this.gamma0)) / tp;
|
var ts = Math.pow(this.el / Math.sqrt((1 + up) / (1 - up)), 1 / this.bl);
|
if (Math.abs(up - 1) < EPSLN) {
|
p.x = this.long0;
|
p.y = HALF_PI;
|
}
|
else if (Math.abs(up + 1) < EPSLN) {
|
p.x = this.long0;
|
p.y = -1 * HALF_PI;
|
}
|
else {
|
p.y = phi2z(this.e, ts);
|
p.x = adjust_lon(this.long0 - Math.atan2(sp * Math.cos(this.gamma0) - vp * Math.sin(this.gamma0), Math.cos(this.bl * us / this.al)) / this.bl);
|
}
|
return p;
|
}
|
|
var names$10 = ["Hotine_Oblique_Mercator", "Hotine Oblique Mercator", "Hotine_Oblique_Mercator_Azimuth_Natural_Origin", "Hotine_Oblique_Mercator_Azimuth_Center", "omerc"];
|
var omerc = {
|
init: init$9,
|
forward: forward$8,
|
inverse: inverse$8,
|
names: names$10
|
};
|
|
function init$10() {
|
|
// array of: r_maj,r_min,lat1,lat2,c_lon,c_lat,false_east,false_north
|
//double c_lat; /* center latitude */
|
//double c_lon; /* center longitude */
|
//double lat1; /* first standard parallel */
|
//double lat2; /* second standard parallel */
|
//double r_maj; /* major axis */
|
//double r_min; /* minor axis */
|
//double false_east; /* x offset in meters */
|
//double false_north; /* y offset in meters */
|
|
if (!this.lat2) {
|
this.lat2 = this.lat1;
|
} //if lat2 is not defined
|
if (!this.k0) {
|
this.k0 = 1;
|
}
|
this.x0 = this.x0 || 0;
|
this.y0 = this.y0 || 0;
|
// Standard Parallels cannot be equal and on opposite sides of the equator
|
if (Math.abs(this.lat1 + this.lat2) < EPSLN) {
|
return;
|
}
|
|
var temp = this.b / this.a;
|
this.e = Math.sqrt(1 - temp * temp);
|
|
var sin1 = Math.sin(this.lat1);
|
var cos1 = Math.cos(this.lat1);
|
var ms1 = msfnz(this.e, sin1, cos1);
|
var ts1 = tsfnz(this.e, this.lat1, sin1);
|
|
var sin2 = Math.sin(this.lat2);
|
var cos2 = Math.cos(this.lat2);
|
var ms2 = msfnz(this.e, sin2, cos2);
|
var ts2 = tsfnz(this.e, this.lat2, sin2);
|
|
var ts0 = tsfnz(this.e, this.lat0, Math.sin(this.lat0));
|
|
if (Math.abs(this.lat1 - this.lat2) > EPSLN) {
|
this.ns = Math.log(ms1 / ms2) / Math.log(ts1 / ts2);
|
}
|
else {
|
this.ns = sin1;
|
}
|
if (isNaN(this.ns)) {
|
this.ns = sin1;
|
}
|
this.f0 = ms1 / (this.ns * Math.pow(ts1, this.ns));
|
this.rh = this.a * this.f0 * Math.pow(ts0, this.ns);
|
if (!this.title) {
|
this.title = "Lambert Conformal Conic";
|
}
|
}
|
|
// Lambert Conformal conic forward equations--mapping lat,long to x,y
|
// -----------------------------------------------------------------
|
function forward$9(p) {
|
|
var lon = p.x;
|
var lat = p.y;
|
|
// singular cases :
|
if (Math.abs(2 * Math.abs(lat) - Math.PI) <= EPSLN) {
|
lat = sign(lat) * (HALF_PI - 2 * EPSLN);
|
}
|
|
var con = Math.abs(Math.abs(lat) - HALF_PI);
|
var ts, rh1;
|
if (con > EPSLN) {
|
ts = tsfnz(this.e, lat, Math.sin(lat));
|
rh1 = this.a * this.f0 * Math.pow(ts, this.ns);
|
}
|
else {
|
con = lat * this.ns;
|
if (con <= 0) {
|
return null;
|
}
|
rh1 = 0;
|
}
|
var theta = this.ns * adjust_lon(lon - this.long0);
|
p.x = this.k0 * (rh1 * Math.sin(theta)) + this.x0;
|
p.y = this.k0 * (this.rh - rh1 * Math.cos(theta)) + this.y0;
|
|
return p;
|
}
|
|
// Lambert Conformal Conic inverse equations--mapping x,y to lat/long
|
// -----------------------------------------------------------------
|
function inverse$9(p) {
|
|
var rh1, con, ts;
|
var lat, lon;
|
var x = (p.x - this.x0) / this.k0;
|
var y = (this.rh - (p.y - this.y0) / this.k0);
|
if (this.ns > 0) {
|
rh1 = Math.sqrt(x * x + y * y);
|
con = 1;
|
}
|
else {
|
rh1 = -Math.sqrt(x * x + y * y);
|
con = -1;
|
}
|
var theta = 0;
|
if (rh1 !== 0) {
|
theta = Math.atan2((con * x), (con * y));
|
}
|
if ((rh1 !== 0) || (this.ns > 0)) {
|
con = 1 / this.ns;
|
ts = Math.pow((rh1 / (this.a * this.f0)), con);
|
lat = phi2z(this.e, ts);
|
if (lat === -9999) {
|
return null;
|
}
|
}
|
else {
|
lat = -HALF_PI;
|
}
|
lon = adjust_lon(theta / this.ns + this.long0);
|
|
p.x = lon;
|
p.y = lat;
|
return p;
|
}
|
|
var names$11 = ["Lambert Tangential Conformal Conic Projection", "Lambert_Conformal_Conic", "Lambert_Conformal_Conic_2SP", "lcc"];
|
var lcc = {
|
init: init$10,
|
forward: forward$9,
|
inverse: inverse$9,
|
names: names$11
|
};
|
|
function init$11() {
|
this.a = 6377397.155;
|
this.es = 0.006674372230614;
|
this.e = Math.sqrt(this.es);
|
if (!this.lat0) {
|
this.lat0 = 0.863937979737193;
|
}
|
if (!this.long0) {
|
this.long0 = 0.7417649320975901 - 0.308341501185665;
|
}
|
/* if scale not set default to 0.9999 */
|
if (!this.k0) {
|
this.k0 = 0.9999;
|
}
|
this.s45 = 0.785398163397448; /* 45 */
|
this.s90 = 2 * this.s45;
|
this.fi0 = this.lat0;
|
this.e2 = this.es;
|
this.e = Math.sqrt(this.e2);
|
this.alfa = Math.sqrt(1 + (this.e2 * Math.pow(Math.cos(this.fi0), 4)) / (1 - this.e2));
|
this.uq = 1.04216856380474;
|
this.u0 = Math.asin(Math.sin(this.fi0) / this.alfa);
|
this.g = Math.pow((1 + this.e * Math.sin(this.fi0)) / (1 - this.e * Math.sin(this.fi0)), this.alfa * this.e / 2);
|
this.k = Math.tan(this.u0 / 2 + this.s45) / Math.pow(Math.tan(this.fi0 / 2 + this.s45), this.alfa) * this.g;
|
this.k1 = this.k0;
|
this.n0 = this.a * Math.sqrt(1 - this.e2) / (1 - this.e2 * Math.pow(Math.sin(this.fi0), 2));
|
this.s0 = 1.37008346281555;
|
this.n = Math.sin(this.s0);
|
this.ro0 = this.k1 * this.n0 / Math.tan(this.s0);
|
this.ad = this.s90 - this.uq;
|
}
|
|
/* ellipsoid */
|
/* calculate xy from lat/lon */
|
/* Constants, identical to inverse transform function */
|
function forward$10(p) {
|
var gfi, u, deltav, s, d, eps, ro;
|
var lon = p.x;
|
var lat = p.y;
|
var delta_lon = adjust_lon(lon - this.long0);
|
/* Transformation */
|
gfi = Math.pow(((1 + this.e * Math.sin(lat)) / (1 - this.e * Math.sin(lat))), (this.alfa * this.e / 2));
|
u = 2 * (Math.atan(this.k * Math.pow(Math.tan(lat / 2 + this.s45), this.alfa) / gfi) - this.s45);
|
deltav = -delta_lon * this.alfa;
|
s = Math.asin(Math.cos(this.ad) * Math.sin(u) + Math.sin(this.ad) * Math.cos(u) * Math.cos(deltav));
|
d = Math.asin(Math.cos(u) * Math.sin(deltav) / Math.cos(s));
|
eps = this.n * d;
|
ro = this.ro0 * Math.pow(Math.tan(this.s0 / 2 + this.s45), this.n) / Math.pow(Math.tan(s / 2 + this.s45), this.n);
|
p.y = ro * Math.cos(eps) / 1;
|
p.x = ro * Math.sin(eps) / 1;
|
|
if (!this.czech) {
|
p.y *= -1;
|
p.x *= -1;
|
}
|
return (p);
|
}
|
|
/* calculate lat/lon from xy */
|
function inverse$10(p) {
|
var u, deltav, s, d, eps, ro, fi1;
|
var ok;
|
|
/* Transformation */
|
/* revert y, x*/
|
var tmp = p.x;
|
p.x = p.y;
|
p.y = tmp;
|
if (!this.czech) {
|
p.y *= -1;
|
p.x *= -1;
|
}
|
ro = Math.sqrt(p.x * p.x + p.y * p.y);
|
eps = Math.atan2(p.y, p.x);
|
d = eps / Math.sin(this.s0);
|
s = 2 * (Math.atan(Math.pow(this.ro0 / ro, 1 / this.n) * Math.tan(this.s0 / 2 + this.s45)) - this.s45);
|
u = Math.asin(Math.cos(this.ad) * Math.sin(s) - Math.sin(this.ad) * Math.cos(s) * Math.cos(d));
|
deltav = Math.asin(Math.cos(s) * Math.sin(d) / Math.cos(u));
|
p.x = this.long0 - deltav / this.alfa;
|
fi1 = u;
|
ok = 0;
|
var iter = 0;
|
do {
|
p.y = 2 * (Math.atan(Math.pow(this.k, - 1 / this.alfa) * Math.pow(Math.tan(u / 2 + this.s45), 1 / this.alfa) * Math.pow((1 + this.e * Math.sin(fi1)) / (1 - this.e * Math.sin(fi1)), this.e / 2)) - this.s45);
|
if (Math.abs(fi1 - p.y) < 0.0000000001) {
|
ok = 1;
|
}
|
fi1 = p.y;
|
iter += 1;
|
} while (ok === 0 && iter < 15);
|
if (iter >= 15) {
|
return null;
|
}
|
|
return (p);
|
}
|
|
var names$12 = ["Krovak", "krovak"];
|
var krovak = {
|
init: init$11,
|
forward: forward$10,
|
inverse: inverse$10,
|
names: names$12
|
};
|
|
var mlfn = function(e0, e1, e2, e3, phi) {
|
return (e0 * phi - e1 * Math.sin(2 * phi) + e2 * Math.sin(4 * phi) - e3 * Math.sin(6 * phi));
|
};
|
|
var e0fn = function(x) {
|
return (1 - 0.25 * x * (1 + x / 16 * (3 + 1.25 * x)));
|
};
|
|
var e1fn = function(x) {
|
return (0.375 * x * (1 + 0.25 * x * (1 + 0.46875 * x)));
|
};
|
|
var e2fn = function(x) {
|
return (0.05859375 * x * x * (1 + 0.75 * x));
|
};
|
|
var e3fn = function(x) {
|
return (x * x * x * (35 / 3072));
|
};
|
|
var gN = function(a, e, sinphi) {
|
var temp = e * sinphi;
|
return a / Math.sqrt(1 - temp * temp);
|
};
|
|
var adjust_lat = function(x) {
|
return (Math.abs(x) < HALF_PI) ? x : (x - (sign(x) * Math.PI));
|
};
|
|
var imlfn = function(ml, e0, e1, e2, e3) {
|
var phi;
|
var dphi;
|
|
phi = ml / e0;
|
for (var i = 0; i < 15; i++) {
|
dphi = (ml - (e0 * phi - e1 * Math.sin(2 * phi) + e2 * Math.sin(4 * phi) - e3 * Math.sin(6 * phi))) / (e0 - 2 * e1 * Math.cos(2 * phi) + 4 * e2 * Math.cos(4 * phi) - 6 * e3 * Math.cos(6 * phi));
|
phi += dphi;
|
if (Math.abs(dphi) <= 0.0000000001) {
|
return phi;
|
}
|
}
|
|
//..reportError("IMLFN-CONV:Latitude failed to converge after 15 iterations");
|
return NaN;
|
};
|
|
function init$12() {
|
if (!this.sphere) {
|
this.e0 = e0fn(this.es);
|
this.e1 = e1fn(this.es);
|
this.e2 = e2fn(this.es);
|
this.e3 = e3fn(this.es);
|
this.ml0 = this.a * mlfn(this.e0, this.e1, this.e2, this.e3, this.lat0);
|
}
|
}
|
|
/* Cassini forward equations--mapping lat,long to x,y
|
-----------------------------------------------------------------------*/
|
function forward$11(p) {
|
|
/* Forward equations
|
-----------------*/
|
var x, y;
|
var lam = p.x;
|
var phi = p.y;
|
lam = adjust_lon(lam - this.long0);
|
|
if (this.sphere) {
|
x = this.a * Math.asin(Math.cos(phi) * Math.sin(lam));
|
y = this.a * (Math.atan2(Math.tan(phi), Math.cos(lam)) - this.lat0);
|
}
|
else {
|
//ellipsoid
|
var sinphi = Math.sin(phi);
|
var cosphi = Math.cos(phi);
|
var nl = gN(this.a, this.e, sinphi);
|
var tl = Math.tan(phi) * Math.tan(phi);
|
var al = lam * Math.cos(phi);
|
var asq = al * al;
|
var cl = this.es * cosphi * cosphi / (1 - this.es);
|
var ml = this.a * mlfn(this.e0, this.e1, this.e2, this.e3, phi);
|
|
x = nl * al * (1 - asq * tl * (1 / 6 - (8 - tl + 8 * cl) * asq / 120));
|
y = ml - this.ml0 + nl * sinphi / cosphi * asq * (0.5 + (5 - tl + 6 * cl) * asq / 24);
|
|
|
}
|
|
p.x = x + this.x0;
|
p.y = y + this.y0;
|
return p;
|
}
|
|
/* Inverse equations
|
-----------------*/
|
function inverse$11(p) {
|
p.x -= this.x0;
|
p.y -= this.y0;
|
var x = p.x / this.a;
|
var y = p.y / this.a;
|
var phi, lam;
|
|
if (this.sphere) {
|
var dd = y + this.lat0;
|
phi = Math.asin(Math.sin(dd) * Math.cos(x));
|
lam = Math.atan2(Math.tan(x), Math.cos(dd));
|
}
|
else {
|
/* ellipsoid */
|
var ml1 = this.ml0 / this.a + y;
|
var phi1 = imlfn(ml1, this.e0, this.e1, this.e2, this.e3);
|
if (Math.abs(Math.abs(phi1) - HALF_PI) <= EPSLN) {
|
p.x = this.long0;
|
p.y = HALF_PI;
|
if (y < 0) {
|
p.y *= -1;
|
}
|
return p;
|
}
|
var nl1 = gN(this.a, this.e, Math.sin(phi1));
|
|
var rl1 = nl1 * nl1 * nl1 / this.a / this.a * (1 - this.es);
|
var tl1 = Math.pow(Math.tan(phi1), 2);
|
var dl = x * this.a / nl1;
|
var dsq = dl * dl;
|
phi = phi1 - nl1 * Math.tan(phi1) / rl1 * dl * dl * (0.5 - (1 + 3 * tl1) * dl * dl / 24);
|
lam = dl * (1 - dsq * (tl1 / 3 + (1 + 3 * tl1) * tl1 * dsq / 15)) / Math.cos(phi1);
|
|
}
|
|
p.x = adjust_lon(lam + this.long0);
|
p.y = adjust_lat(phi);
|
return p;
|
|
}
|
|
var names$13 = ["Cassini", "Cassini_Soldner", "cass"];
|
var cass = {
|
init: init$12,
|
forward: forward$11,
|
inverse: inverse$11,
|
names: names$13
|
};
|
|
var qsfnz = function(eccent, sinphi) {
|
var con;
|
if (eccent > 1.0e-7) {
|
con = eccent * sinphi;
|
return ((1 - eccent * eccent) * (sinphi / (1 - con * con) - (0.5 / eccent) * Math.log((1 - con) / (1 + con))));
|
}
|
else {
|
return (2 * sinphi);
|
}
|
};
|
|
/*
|
reference
|
"New Equal-Area Map Projections for Noncircular Regions", John P. Snyder,
|
The American Cartographer, Vol 15, No. 4, October 1988, pp. 341-355.
|
*/
|
|
var S_POLE = 1;
|
|
var N_POLE = 2;
|
var EQUIT = 3;
|
var OBLIQ = 4;
|
|
/* Initialize the Lambert Azimuthal Equal Area projection
|
------------------------------------------------------*/
|
function init$13() {
|
var t = Math.abs(this.lat0);
|
if (Math.abs(t - HALF_PI) < EPSLN) {
|
this.mode = this.lat0 < 0 ? this.S_POLE : this.N_POLE;
|
}
|
else if (Math.abs(t) < EPSLN) {
|
this.mode = this.EQUIT;
|
}
|
else {
|
this.mode = this.OBLIQ;
|
}
|
if (this.es > 0) {
|
var sinphi;
|
|
this.qp = qsfnz(this.e, 1);
|
this.mmf = 0.5 / (1 - this.es);
|
this.apa = authset(this.es);
|
switch (this.mode) {
|
case this.N_POLE:
|
this.dd = 1;
|
break;
|
case this.S_POLE:
|
this.dd = 1;
|
break;
|
case this.EQUIT:
|
this.rq = Math.sqrt(0.5 * this.qp);
|
this.dd = 1 / this.rq;
|
this.xmf = 1;
|
this.ymf = 0.5 * this.qp;
|
break;
|
case this.OBLIQ:
|
this.rq = Math.sqrt(0.5 * this.qp);
|
sinphi = Math.sin(this.lat0);
|
this.sinb1 = qsfnz(this.e, sinphi) / this.qp;
|
this.cosb1 = Math.sqrt(1 - this.sinb1 * this.sinb1);
|
this.dd = Math.cos(this.lat0) / (Math.sqrt(1 - this.es * sinphi * sinphi) * this.rq * this.cosb1);
|
this.ymf = (this.xmf = this.rq) / this.dd;
|
this.xmf *= this.dd;
|
break;
|
}
|
}
|
else {
|
if (this.mode === this.OBLIQ) {
|
this.sinph0 = Math.sin(this.lat0);
|
this.cosph0 = Math.cos(this.lat0);
|
}
|
}
|
}
|
|
/* Lambert Azimuthal Equal Area forward equations--mapping lat,long to x,y
|
-----------------------------------------------------------------------*/
|
function forward$12(p) {
|
|
/* Forward equations
|
-----------------*/
|
var x, y, coslam, sinlam, sinphi, q, sinb, cosb, b, cosphi;
|
var lam = p.x;
|
var phi = p.y;
|
|
lam = adjust_lon(lam - this.long0);
|
if (this.sphere) {
|
sinphi = Math.sin(phi);
|
cosphi = Math.cos(phi);
|
coslam = Math.cos(lam);
|
if (this.mode === this.OBLIQ || this.mode === this.EQUIT) {
|
y = (this.mode === this.EQUIT) ? 1 + cosphi * coslam : 1 + this.sinph0 * sinphi + this.cosph0 * cosphi * coslam;
|
if (y <= EPSLN) {
|
return null;
|
}
|
y = Math.sqrt(2 / y);
|
x = y * cosphi * Math.sin(lam);
|
y *= (this.mode === this.EQUIT) ? sinphi : this.cosph0 * sinphi - this.sinph0 * cosphi * coslam;
|
}
|
else if (this.mode === this.N_POLE || this.mode === this.S_POLE) {
|
if (this.mode === this.N_POLE) {
|
coslam = -coslam;
|
}
|
if (Math.abs(phi + this.phi0) < EPSLN) {
|
return null;
|
}
|
y = FORTPI - phi * 0.5;
|
y = 2 * ((this.mode === this.S_POLE) ? Math.cos(y) : Math.sin(y));
|
x = y * Math.sin(lam);
|
y *= coslam;
|
}
|
}
|
else {
|
sinb = 0;
|
cosb = 0;
|
b = 0;
|
coslam = Math.cos(lam);
|
sinlam = Math.sin(lam);
|
sinphi = Math.sin(phi);
|
q = qsfnz(this.e, sinphi);
|
if (this.mode === this.OBLIQ || this.mode === this.EQUIT) {
|
sinb = q / this.qp;
|
cosb = Math.sqrt(1 - sinb * sinb);
|
}
|
switch (this.mode) {
|
case this.OBLIQ:
|
b = 1 + this.sinb1 * sinb + this.cosb1 * cosb * coslam;
|
break;
|
case this.EQUIT:
|
b = 1 + cosb * coslam;
|
break;
|
case this.N_POLE:
|
b = HALF_PI + phi;
|
q = this.qp - q;
|
break;
|
case this.S_POLE:
|
b = phi - HALF_PI;
|
q = this.qp + q;
|
break;
|
}
|
if (Math.abs(b) < EPSLN) {
|
return null;
|
}
|
switch (this.mode) {
|
case this.OBLIQ:
|
case this.EQUIT:
|
b = Math.sqrt(2 / b);
|
if (this.mode === this.OBLIQ) {
|
y = this.ymf * b * (this.cosb1 * sinb - this.sinb1 * cosb * coslam);
|
}
|
else {
|
y = (b = Math.sqrt(2 / (1 + cosb * coslam))) * sinb * this.ymf;
|
}
|
x = this.xmf * b * cosb * sinlam;
|
break;
|
case this.N_POLE:
|
case this.S_POLE:
|
if (q >= 0) {
|
x = (b = Math.sqrt(q)) * sinlam;
|
y = coslam * ((this.mode === this.S_POLE) ? b : -b);
|
}
|
else {
|
x = y = 0;
|
}
|
break;
|
}
|
}
|
|
p.x = this.a * x + this.x0;
|
p.y = this.a * y + this.y0;
|
return p;
|
}
|
|
/* Inverse equations
|
-----------------*/
|
function inverse$12(p) {
|
p.x -= this.x0;
|
p.y -= this.y0;
|
var x = p.x / this.a;
|
var y = p.y / this.a;
|
var lam, phi, cCe, sCe, q, rho, ab;
|
if (this.sphere) {
|
var cosz = 0,
|
rh, sinz = 0;
|
|
rh = Math.sqrt(x * x + y * y);
|
phi = rh * 0.5;
|
if (phi > 1) {
|
return null;
|
}
|
phi = 2 * Math.asin(phi);
|
if (this.mode === this.OBLIQ || this.mode === this.EQUIT) {
|
sinz = Math.sin(phi);
|
cosz = Math.cos(phi);
|
}
|
switch (this.mode) {
|
case this.EQUIT:
|
phi = (Math.abs(rh) <= EPSLN) ? 0 : Math.asin(y * sinz / rh);
|
x *= sinz;
|
y = cosz * rh;
|
break;
|
case this.OBLIQ:
|
phi = (Math.abs(rh) <= EPSLN) ? this.phi0 : Math.asin(cosz * this.sinph0 + y * sinz * this.cosph0 / rh);
|
x *= sinz * this.cosph0;
|
y = (cosz - Math.sin(phi) * this.sinph0) * rh;
|
break;
|
case this.N_POLE:
|
y = -y;
|
phi = HALF_PI - phi;
|
break;
|
case this.S_POLE:
|
phi -= HALF_PI;
|
break;
|
}
|
lam = (y === 0 && (this.mode === this.EQUIT || this.mode === this.OBLIQ)) ? 0 : Math.atan2(x, y);
|
}
|
else {
|
ab = 0;
|
if (this.mode === this.OBLIQ || this.mode === this.EQUIT) {
|
x /= this.dd;
|
y *= this.dd;
|
rho = Math.sqrt(x * x + y * y);
|
if (rho < EPSLN) {
|
p.x = 0;
|
p.y = this.phi0;
|
return p;
|
}
|
sCe = 2 * Math.asin(0.5 * rho / this.rq);
|
cCe = Math.cos(sCe);
|
x *= (sCe = Math.sin(sCe));
|
if (this.mode === this.OBLIQ) {
|
ab = cCe * this.sinb1 + y * sCe * this.cosb1 / rho;
|
q = this.qp * ab;
|
y = rho * this.cosb1 * cCe - y * this.sinb1 * sCe;
|
}
|
else {
|
ab = y * sCe / rho;
|
q = this.qp * ab;
|
y = rho * cCe;
|
}
|
}
|
else if (this.mode === this.N_POLE || this.mode === this.S_POLE) {
|
if (this.mode === this.N_POLE) {
|
y = -y;
|
}
|
q = (x * x + y * y);
|
if (!q) {
|
p.x = 0;
|
p.y = this.phi0;
|
return p;
|
}
|
ab = 1 - q / this.qp;
|
if (this.mode === this.S_POLE) {
|
ab = -ab;
|
}
|
}
|
lam = Math.atan2(x, y);
|
phi = authlat(Math.asin(ab), this.apa);
|
}
|
|
p.x = adjust_lon(this.long0 + lam);
|
p.y = phi;
|
return p;
|
}
|
|
/* determine latitude from authalic latitude */
|
var P00 = 0.33333333333333333333;
|
|
var P01 = 0.17222222222222222222;
|
var P02 = 0.10257936507936507936;
|
var P10 = 0.06388888888888888888;
|
var P11 = 0.06640211640211640211;
|
var P20 = 0.01641501294219154443;
|
|
function authset(es) {
|
var t;
|
var APA = [];
|
APA[0] = es * P00;
|
t = es * es;
|
APA[0] += t * P01;
|
APA[1] = t * P10;
|
t *= es;
|
APA[0] += t * P02;
|
APA[1] += t * P11;
|
APA[2] = t * P20;
|
return APA;
|
}
|
|
function authlat(beta, APA) {
|
var t = beta + beta;
|
return (beta + APA[0] * Math.sin(t) + APA[1] * Math.sin(t + t) + APA[2] * Math.sin(t + t + t));
|
}
|
|
var names$14 = ["Lambert Azimuthal Equal Area", "Lambert_Azimuthal_Equal_Area", "laea"];
|
var laea = {
|
init: init$13,
|
forward: forward$12,
|
inverse: inverse$12,
|
names: names$14,
|
S_POLE: S_POLE,
|
N_POLE: N_POLE,
|
EQUIT: EQUIT,
|
OBLIQ: OBLIQ
|
};
|
|
var asinz = function(x) {
|
if (Math.abs(x) > 1) {
|
x = (x > 1) ? 1 : -1;
|
}
|
return Math.asin(x);
|
};
|
|
function init$14() {
|
|
if (Math.abs(this.lat1 + this.lat2) < EPSLN) {
|
return;
|
}
|
this.temp = this.b / this.a;
|
this.es = 1 - Math.pow(this.temp, 2);
|
this.e3 = Math.sqrt(this.es);
|
|
this.sin_po = Math.sin(this.lat1);
|
this.cos_po = Math.cos(this.lat1);
|
this.t1 = this.sin_po;
|
this.con = this.sin_po;
|
this.ms1 = msfnz(this.e3, this.sin_po, this.cos_po);
|
this.qs1 = qsfnz(this.e3, this.sin_po, this.cos_po);
|
|
this.sin_po = Math.sin(this.lat2);
|
this.cos_po = Math.cos(this.lat2);
|
this.t2 = this.sin_po;
|
this.ms2 = msfnz(this.e3, this.sin_po, this.cos_po);
|
this.qs2 = qsfnz(this.e3, this.sin_po, this.cos_po);
|
|
this.sin_po = Math.sin(this.lat0);
|
this.cos_po = Math.cos(this.lat0);
|
this.t3 = this.sin_po;
|
this.qs0 = qsfnz(this.e3, this.sin_po, this.cos_po);
|
|
if (Math.abs(this.lat1 - this.lat2) > EPSLN) {
|
this.ns0 = (this.ms1 * this.ms1 - this.ms2 * this.ms2) / (this.qs2 - this.qs1);
|
}
|
else {
|
this.ns0 = this.con;
|
}
|
this.c = this.ms1 * this.ms1 + this.ns0 * this.qs1;
|
this.rh = this.a * Math.sqrt(this.c - this.ns0 * this.qs0) / this.ns0;
|
}
|
|
/* Albers Conical Equal Area forward equations--mapping lat,long to x,y
|
-------------------------------------------------------------------*/
|
function forward$13(p) {
|
|
var lon = p.x;
|
var lat = p.y;
|
|
this.sin_phi = Math.sin(lat);
|
this.cos_phi = Math.cos(lat);
|
|
var qs = qsfnz(this.e3, this.sin_phi, this.cos_phi);
|
var rh1 = this.a * Math.sqrt(this.c - this.ns0 * qs) / this.ns0;
|
var theta = this.ns0 * adjust_lon(lon - this.long0);
|
var x = rh1 * Math.sin(theta) + this.x0;
|
var y = this.rh - rh1 * Math.cos(theta) + this.y0;
|
|
p.x = x;
|
p.y = y;
|
return p;
|
}
|
|
function inverse$13(p) {
|
var rh1, qs, con, theta, lon, lat;
|
|
p.x -= this.x0;
|
p.y = this.rh - p.y + this.y0;
|
if (this.ns0 >= 0) {
|
rh1 = Math.sqrt(p.x * p.x + p.y * p.y);
|
con = 1;
|
}
|
else {
|
rh1 = -Math.sqrt(p.x * p.x + p.y * p.y);
|
con = -1;
|
}
|
theta = 0;
|
if (rh1 !== 0) {
|
theta = Math.atan2(con * p.x, con * p.y);
|
}
|
con = rh1 * this.ns0 / this.a;
|
if (this.sphere) {
|
lat = Math.asin((this.c - con * con) / (2 * this.ns0));
|
}
|
else {
|
qs = (this.c - con * con) / this.ns0;
|
lat = this.phi1z(this.e3, qs);
|
}
|
|
lon = adjust_lon(theta / this.ns0 + this.long0);
|
p.x = lon;
|
p.y = lat;
|
return p;
|
}
|
|
/* Function to compute phi1, the latitude for the inverse of the
|
Albers Conical Equal-Area projection.
|
-------------------------------------------*/
|
function phi1z(eccent, qs) {
|
var sinphi, cosphi, con, com, dphi;
|
var phi = asinz(0.5 * qs);
|
if (eccent < EPSLN) {
|
return phi;
|
}
|
|
var eccnts = eccent * eccent;
|
for (var i = 1; i <= 25; i++) {
|
sinphi = Math.sin(phi);
|
cosphi = Math.cos(phi);
|
con = eccent * sinphi;
|
com = 1 - con * con;
|
dphi = 0.5 * com * com / cosphi * (qs / (1 - eccnts) - sinphi / com + 0.5 / eccent * Math.log((1 - con) / (1 + con)));
|
phi = phi + dphi;
|
if (Math.abs(dphi) <= 1e-7) {
|
return phi;
|
}
|
}
|
return null;
|
}
|
|
var names$15 = ["Albers_Conic_Equal_Area", "Albers", "aea"];
|
var aea = {
|
init: init$14,
|
forward: forward$13,
|
inverse: inverse$13,
|
names: names$15,
|
phi1z: phi1z
|
};
|
|
/*
|
reference:
|
Wolfram Mathworld "Gnomonic Projection"
|
http://mathworld.wolfram.com/GnomonicProjection.html
|
Accessed: 12th November 2009
|
*/
|
function init$15() {
|
|
/* Place parameters in static storage for common use
|
-------------------------------------------------*/
|
this.sin_p14 = Math.sin(this.lat0);
|
this.cos_p14 = Math.cos(this.lat0);
|
// Approximation for projecting points to the horizon (infinity)
|
this.infinity_dist = 1000 * this.a;
|
this.rc = 1;
|
}
|
|
/* Gnomonic forward equations--mapping lat,long to x,y
|
---------------------------------------------------*/
|
function forward$14(p) {
|
var sinphi, cosphi; /* sin and cos value */
|
var dlon; /* delta longitude value */
|
var coslon; /* cos of longitude */
|
var ksp; /* scale factor */
|
var g;
|
var x, y;
|
var lon = p.x;
|
var lat = p.y;
|
/* Forward equations
|
-----------------*/
|
dlon = adjust_lon(lon - this.long0);
|
|
sinphi = Math.sin(lat);
|
cosphi = Math.cos(lat);
|
|
coslon = Math.cos(dlon);
|
g = this.sin_p14 * sinphi + this.cos_p14 * cosphi * coslon;
|
ksp = 1;
|
if ((g > 0) || (Math.abs(g) <= EPSLN)) {
|
x = this.x0 + this.a * ksp * cosphi * Math.sin(dlon) / g;
|
y = this.y0 + this.a * ksp * (this.cos_p14 * sinphi - this.sin_p14 * cosphi * coslon) / g;
|
}
|
else {
|
|
// Point is in the opposing hemisphere and is unprojectable
|
// We still need to return a reasonable point, so we project
|
// to infinity, on a bearing
|
// equivalent to the northern hemisphere equivalent
|
// This is a reasonable approximation for short shapes and lines that
|
// straddle the horizon.
|
|
x = this.x0 + this.infinity_dist * cosphi * Math.sin(dlon);
|
y = this.y0 + this.infinity_dist * (this.cos_p14 * sinphi - this.sin_p14 * cosphi * coslon);
|
|
}
|
p.x = x;
|
p.y = y;
|
return p;
|
}
|
|
function inverse$14(p) {
|
var rh; /* Rho */
|
var sinc, cosc;
|
var c;
|
var lon, lat;
|
|
/* Inverse equations
|
-----------------*/
|
p.x = (p.x - this.x0) / this.a;
|
p.y = (p.y - this.y0) / this.a;
|
|
p.x /= this.k0;
|
p.y /= this.k0;
|
|
if ((rh = Math.sqrt(p.x * p.x + p.y * p.y))) {
|
c = Math.atan2(rh, this.rc);
|
sinc = Math.sin(c);
|
cosc = Math.cos(c);
|
|
lat = asinz(cosc * this.sin_p14 + (p.y * sinc * this.cos_p14) / rh);
|
lon = Math.atan2(p.x * sinc, rh * this.cos_p14 * cosc - p.y * this.sin_p14 * sinc);
|
lon = adjust_lon(this.long0 + lon);
|
}
|
else {
|
lat = this.phic0;
|
lon = 0;
|
}
|
|
p.x = lon;
|
p.y = lat;
|
return p;
|
}
|
|
var names$16 = ["gnom"];
|
var gnom = {
|
init: init$15,
|
forward: forward$14,
|
inverse: inverse$14,
|
names: names$16
|
};
|
|
var iqsfnz = function(eccent, q) {
|
var temp = 1 - (1 - eccent * eccent) / (2 * eccent) * Math.log((1 - eccent) / (1 + eccent));
|
if (Math.abs(Math.abs(q) - temp) < 1.0E-6) {
|
if (q < 0) {
|
return (-1 * HALF_PI);
|
}
|
else {
|
return HALF_PI;
|
}
|
}
|
//var phi = 0.5* q/(1-eccent*eccent);
|
var phi = Math.asin(0.5 * q);
|
var dphi;
|
var sin_phi;
|
var cos_phi;
|
var con;
|
for (var i = 0; i < 30; i++) {
|
sin_phi = Math.sin(phi);
|
cos_phi = Math.cos(phi);
|
con = eccent * sin_phi;
|
dphi = Math.pow(1 - con * con, 2) / (2 * cos_phi) * (q / (1 - eccent * eccent) - sin_phi / (1 - con * con) + 0.5 / eccent * Math.log((1 - con) / (1 + con)));
|
phi += dphi;
|
if (Math.abs(dphi) <= 0.0000000001) {
|
return phi;
|
}
|
}
|
|
//console.log("IQSFN-CONV:Latitude failed to converge after 30 iterations");
|
return NaN;
|
};
|
|
/*
|
reference:
|
"Cartographic Projection Procedures for the UNIX Environment-
|
A User's Manual" by Gerald I. Evenden,
|
USGS Open File Report 90-284and Release 4 Interim Reports (2003)
|
*/
|
function init$16() {
|
//no-op
|
if (!this.sphere) {
|
this.k0 = msfnz(this.e, Math.sin(this.lat_ts), Math.cos(this.lat_ts));
|
}
|
}
|
|
/* Cylindrical Equal Area forward equations--mapping lat,long to x,y
|
------------------------------------------------------------*/
|
function forward$15(p) {
|
var lon = p.x;
|
var lat = p.y;
|
var x, y;
|
/* Forward equations
|
-----------------*/
|
var dlon = adjust_lon(lon - this.long0);
|
if (this.sphere) {
|
x = this.x0 + this.a * dlon * Math.cos(this.lat_ts);
|
y = this.y0 + this.a * Math.sin(lat) / Math.cos(this.lat_ts);
|
}
|
else {
|
var qs = qsfnz(this.e, Math.sin(lat));
|
x = this.x0 + this.a * this.k0 * dlon;
|
y = this.y0 + this.a * qs * 0.5 / this.k0;
|
}
|
|
p.x = x;
|
p.y = y;
|
return p;
|
}
|
|
/* Cylindrical Equal Area inverse equations--mapping x,y to lat/long
|
------------------------------------------------------------*/
|
function inverse$15(p) {
|
p.x -= this.x0;
|
p.y -= this.y0;
|
var lon, lat;
|
|
if (this.sphere) {
|
lon = adjust_lon(this.long0 + (p.x / this.a) / Math.cos(this.lat_ts));
|
lat = Math.asin((p.y / this.a) * Math.cos(this.lat_ts));
|
}
|
else {
|
lat = iqsfnz(this.e, 2 * p.y * this.k0 / this.a);
|
lon = adjust_lon(this.long0 + p.x / (this.a * this.k0));
|
}
|
|
p.x = lon;
|
p.y = lat;
|
return p;
|
}
|
|
var names$17 = ["cea"];
|
var cea = {
|
init: init$16,
|
forward: forward$15,
|
inverse: inverse$15,
|
names: names$17
|
};
|
|
function init$17() {
|
|
this.x0 = this.x0 || 0;
|
this.y0 = this.y0 || 0;
|
this.lat0 = this.lat0 || 0;
|
this.long0 = this.long0 || 0;
|
this.lat_ts = this.lat_ts || 0;
|
this.title = this.title || "Equidistant Cylindrical (Plate Carre)";
|
|
this.rc = Math.cos(this.lat_ts);
|
}
|
|
// forward equations--mapping lat,long to x,y
|
// -----------------------------------------------------------------
|
function forward$16(p) {
|
|
var lon = p.x;
|
var lat = p.y;
|
|
var dlon = adjust_lon(lon - this.long0);
|
var dlat = adjust_lat(lat - this.lat0);
|
p.x = this.x0 + (this.a * dlon * this.rc);
|
p.y = this.y0 + (this.a * dlat);
|
return p;
|
}
|
|
// inverse equations--mapping x,y to lat/long
|
// -----------------------------------------------------------------
|
function inverse$16(p) {
|
|
var x = p.x;
|
var y = p.y;
|
|
p.x = adjust_lon(this.long0 + ((x - this.x0) / (this.a * this.rc)));
|
p.y = adjust_lat(this.lat0 + ((y - this.y0) / (this.a)));
|
return p;
|
}
|
|
var names$18 = ["Equirectangular", "Equidistant_Cylindrical", "eqc"];
|
var eqc = {
|
init: init$17,
|
forward: forward$16,
|
inverse: inverse$16,
|
names: names$18
|
};
|
|
var MAX_ITER$2 = 20;
|
|
function init$18() {
|
/* Place parameters in static storage for common use
|
-------------------------------------------------*/
|
this.temp = this.b / this.a;
|
this.es = 1 - Math.pow(this.temp, 2); // devait etre dans tmerc.js mais n y est pas donc je commente sinon retour de valeurs nulles
|
this.e = Math.sqrt(this.es);
|
this.e0 = e0fn(this.es);
|
this.e1 = e1fn(this.es);
|
this.e2 = e2fn(this.es);
|
this.e3 = e3fn(this.es);
|
this.ml0 = this.a * mlfn(this.e0, this.e1, this.e2, this.e3, this.lat0); //si que des zeros le calcul ne se fait pas
|
}
|
|
/* Polyconic forward equations--mapping lat,long to x,y
|
---------------------------------------------------*/
|
function forward$17(p) {
|
var lon = p.x;
|
var lat = p.y;
|
var x, y, el;
|
var dlon = adjust_lon(lon - this.long0);
|
el = dlon * Math.sin(lat);
|
if (this.sphere) {
|
if (Math.abs(lat) <= EPSLN) {
|
x = this.a * dlon;
|
y = -1 * this.a * this.lat0;
|
}
|
else {
|
x = this.a * Math.sin(el) / Math.tan(lat);
|
y = this.a * (adjust_lat(lat - this.lat0) + (1 - Math.cos(el)) / Math.tan(lat));
|
}
|
}
|
else {
|
if (Math.abs(lat) <= EPSLN) {
|
x = this.a * dlon;
|
y = -1 * this.ml0;
|
}
|
else {
|
var nl = gN(this.a, this.e, Math.sin(lat)) / Math.tan(lat);
|
x = nl * Math.sin(el);
|
y = this.a * mlfn(this.e0, this.e1, this.e2, this.e3, lat) - this.ml0 + nl * (1 - Math.cos(el));
|
}
|
|
}
|
p.x = x + this.x0;
|
p.y = y + this.y0;
|
return p;
|
}
|
|
/* Inverse equations
|
-----------------*/
|
function inverse$17(p) {
|
var lon, lat, x, y, i;
|
var al, bl;
|
var phi, dphi;
|
x = p.x - this.x0;
|
y = p.y - this.y0;
|
|
if (this.sphere) {
|
if (Math.abs(y + this.a * this.lat0) <= EPSLN) {
|
lon = adjust_lon(x / this.a + this.long0);
|
lat = 0;
|
}
|
else {
|
al = this.lat0 + y / this.a;
|
bl = x * x / this.a / this.a + al * al;
|
phi = al;
|
var tanphi;
|
for (i = MAX_ITER$2; i; --i) {
|
tanphi = Math.tan(phi);
|
dphi = -1 * (al * (phi * tanphi + 1) - phi - 0.5 * (phi * phi + bl) * tanphi) / ((phi - al) / tanphi - 1);
|
phi += dphi;
|
if (Math.abs(dphi) <= EPSLN) {
|
lat = phi;
|
break;
|
}
|
}
|
lon = adjust_lon(this.long0 + (Math.asin(x * Math.tan(phi) / this.a)) / Math.sin(lat));
|
}
|
}
|
else {
|
if (Math.abs(y + this.ml0) <= EPSLN) {
|
lat = 0;
|
lon = adjust_lon(this.long0 + x / this.a);
|
}
|
else {
|
|
al = (this.ml0 + y) / this.a;
|
bl = x * x / this.a / this.a + al * al;
|
phi = al;
|
var cl, mln, mlnp, ma;
|
var con;
|
for (i = MAX_ITER$2; i; --i) {
|
con = this.e * Math.sin(phi);
|
cl = Math.sqrt(1 - con * con) * Math.tan(phi);
|
mln = this.a * mlfn(this.e0, this.e1, this.e2, this.e3, phi);
|
mlnp = this.e0 - 2 * this.e1 * Math.cos(2 * phi) + 4 * this.e2 * Math.cos(4 * phi) - 6 * this.e3 * Math.cos(6 * phi);
|
ma = mln / this.a;
|
dphi = (al * (cl * ma + 1) - ma - 0.5 * cl * (ma * ma + bl)) / (this.es * Math.sin(2 * phi) * (ma * ma + bl - 2 * al * ma) / (4 * cl) + (al - ma) * (cl * mlnp - 2 / Math.sin(2 * phi)) - mlnp);
|
phi -= dphi;
|
if (Math.abs(dphi) <= EPSLN) {
|
lat = phi;
|
break;
|
}
|
}
|
|
//lat=phi4z(this.e,this.e0,this.e1,this.e2,this.e3,al,bl,0,0);
|
cl = Math.sqrt(1 - this.es * Math.pow(Math.sin(lat), 2)) * Math.tan(lat);
|
lon = adjust_lon(this.long0 + Math.asin(x * cl / this.a) / Math.sin(lat));
|
}
|
}
|
|
p.x = lon;
|
p.y = lat;
|
return p;
|
}
|
|
var names$19 = ["Polyconic", "poly"];
|
var poly = {
|
init: init$18,
|
forward: forward$17,
|
inverse: inverse$17,
|
names: names$19
|
};
|
|
/*
|
reference
|
Department of Land and Survey Technical Circular 1973/32
|
http://www.linz.govt.nz/docs/miscellaneous/nz-map-definition.pdf
|
OSG Technical Report 4.1
|
http://www.linz.govt.nz/docs/miscellaneous/nzmg.pdf
|
*/
|
|
/**
|
* iterations: Number of iterations to refine inverse transform.
|
* 0 -> km accuracy
|
* 1 -> m accuracy -- suitable for most mapping applications
|
* 2 -> mm accuracy
|
*/
|
|
|
function init$19() {
|
this.A = [];
|
this.A[1] = 0.6399175073;
|
this.A[2] = -0.1358797613;
|
this.A[3] = 0.063294409;
|
this.A[4] = -0.02526853;
|
this.A[5] = 0.0117879;
|
this.A[6] = -0.0055161;
|
this.A[7] = 0.0026906;
|
this.A[8] = -0.001333;
|
this.A[9] = 0.00067;
|
this.A[10] = -0.00034;
|
|
this.B_re = [];
|
this.B_im = [];
|
this.B_re[1] = 0.7557853228;
|
this.B_im[1] = 0;
|
this.B_re[2] = 0.249204646;
|
this.B_im[2] = 0.003371507;
|
this.B_re[3] = -0.001541739;
|
this.B_im[3] = 0.041058560;
|
this.B_re[4] = -0.10162907;
|
this.B_im[4] = 0.01727609;
|
this.B_re[5] = -0.26623489;
|
this.B_im[5] = -0.36249218;
|
this.B_re[6] = -0.6870983;
|
this.B_im[6] = -1.1651967;
|
|
this.C_re = [];
|
this.C_im = [];
|
this.C_re[1] = 1.3231270439;
|
this.C_im[1] = 0;
|
this.C_re[2] = -0.577245789;
|
this.C_im[2] = -0.007809598;
|
this.C_re[3] = 0.508307513;
|
this.C_im[3] = -0.112208952;
|
this.C_re[4] = -0.15094762;
|
this.C_im[4] = 0.18200602;
|
this.C_re[5] = 1.01418179;
|
this.C_im[5] = 1.64497696;
|
this.C_re[6] = 1.9660549;
|
this.C_im[6] = 2.5127645;
|
|
this.D = [];
|
this.D[1] = 1.5627014243;
|
this.D[2] = 0.5185406398;
|
this.D[3] = -0.03333098;
|
this.D[4] = -0.1052906;
|
this.D[5] = -0.0368594;
|
this.D[6] = 0.007317;
|
this.D[7] = 0.01220;
|
this.D[8] = 0.00394;
|
this.D[9] = -0.0013;
|
}
|
|
/**
|
New Zealand Map Grid Forward - long/lat to x/y
|
long/lat in radians
|
*/
|
function forward$18(p) {
|
var n;
|
var lon = p.x;
|
var lat = p.y;
|
|
var delta_lat = lat - this.lat0;
|
var delta_lon = lon - this.long0;
|
|
// 1. Calculate d_phi and d_psi ... // and d_lambda
|
// For this algorithm, delta_latitude is in seconds of arc x 10-5, so we need to scale to those units. Longitude is radians.
|
var d_phi = delta_lat / SEC_TO_RAD * 1E-5;
|
var d_lambda = delta_lon;
|
var d_phi_n = 1; // d_phi^0
|
|
var d_psi = 0;
|
for (n = 1; n <= 10; n++) {
|
d_phi_n = d_phi_n * d_phi;
|
d_psi = d_psi + this.A[n] * d_phi_n;
|
}
|
|
// 2. Calculate theta
|
var th_re = d_psi;
|
var th_im = d_lambda;
|
|
// 3. Calculate z
|
var th_n_re = 1;
|
var th_n_im = 0; // theta^0
|
var th_n_re1;
|
var th_n_im1;
|
|
var z_re = 0;
|
var z_im = 0;
|
for (n = 1; n <= 6; n++) {
|
th_n_re1 = th_n_re * th_re - th_n_im * th_im;
|
th_n_im1 = th_n_im * th_re + th_n_re * th_im;
|
th_n_re = th_n_re1;
|
th_n_im = th_n_im1;
|
z_re = z_re + this.B_re[n] * th_n_re - this.B_im[n] * th_n_im;
|
z_im = z_im + this.B_im[n] * th_n_re + this.B_re[n] * th_n_im;
|
}
|
|
// 4. Calculate easting and northing
|
p.x = (z_im * this.a) + this.x0;
|
p.y = (z_re * this.a) + this.y0;
|
|
return p;
|
}
|
|
/**
|
New Zealand Map Grid Inverse - x/y to long/lat
|
*/
|
function inverse$18(p) {
|
var n;
|
var x = p.x;
|
var y = p.y;
|
|
var delta_x = x - this.x0;
|
var delta_y = y - this.y0;
|
|
// 1. Calculate z
|
var z_re = delta_y / this.a;
|
var z_im = delta_x / this.a;
|
|
// 2a. Calculate theta - first approximation gives km accuracy
|
var z_n_re = 1;
|
var z_n_im = 0; // z^0
|
var z_n_re1;
|
var z_n_im1;
|
|
var th_re = 0;
|
var th_im = 0;
|
for (n = 1; n <= 6; n++) {
|
z_n_re1 = z_n_re * z_re - z_n_im * z_im;
|
z_n_im1 = z_n_im * z_re + z_n_re * z_im;
|
z_n_re = z_n_re1;
|
z_n_im = z_n_im1;
|
th_re = th_re + this.C_re[n] * z_n_re - this.C_im[n] * z_n_im;
|
th_im = th_im + this.C_im[n] * z_n_re + this.C_re[n] * z_n_im;
|
}
|
|
// 2b. Iterate to refine the accuracy of the calculation
|
// 0 iterations gives km accuracy
|
// 1 iteration gives m accuracy -- good enough for most mapping applications
|
// 2 iterations bives mm accuracy
|
for (var i = 0; i < this.iterations; i++) {
|
var th_n_re = th_re;
|
var th_n_im = th_im;
|
var th_n_re1;
|
var th_n_im1;
|
|
var num_re = z_re;
|
var num_im = z_im;
|
for (n = 2; n <= 6; n++) {
|
th_n_re1 = th_n_re * th_re - th_n_im * th_im;
|
th_n_im1 = th_n_im * th_re + th_n_re * th_im;
|
th_n_re = th_n_re1;
|
th_n_im = th_n_im1;
|
num_re = num_re + (n - 1) * (this.B_re[n] * th_n_re - this.B_im[n] * th_n_im);
|
num_im = num_im + (n - 1) * (this.B_im[n] * th_n_re + this.B_re[n] * th_n_im);
|
}
|
|
th_n_re = 1;
|
th_n_im = 0;
|
var den_re = this.B_re[1];
|
var den_im = this.B_im[1];
|
for (n = 2; n <= 6; n++) {
|
th_n_re1 = th_n_re * th_re - th_n_im * th_im;
|
th_n_im1 = th_n_im * th_re + th_n_re * th_im;
|
th_n_re = th_n_re1;
|
th_n_im = th_n_im1;
|
den_re = den_re + n * (this.B_re[n] * th_n_re - this.B_im[n] * th_n_im);
|
den_im = den_im + n * (this.B_im[n] * th_n_re + this.B_re[n] * th_n_im);
|
}
|
|
// Complex division
|
var den2 = den_re * den_re + den_im * den_im;
|
th_re = (num_re * den_re + num_im * den_im) / den2;
|
th_im = (num_im * den_re - num_re * den_im) / den2;
|
}
|
|
// 3. Calculate d_phi ... // and d_lambda
|
var d_psi = th_re;
|
var d_lambda = th_im;
|
var d_psi_n = 1; // d_psi^0
|
|
var d_phi = 0;
|
for (n = 1; n <= 9; n++) {
|
d_psi_n = d_psi_n * d_psi;
|
d_phi = d_phi + this.D[n] * d_psi_n;
|
}
|
|
// 4. Calculate latitude and longitude
|
// d_phi is calcuated in second of arc * 10^-5, so we need to scale back to radians. d_lambda is in radians.
|
var lat = this.lat0 + (d_phi * SEC_TO_RAD * 1E5);
|
var lon = this.long0 + d_lambda;
|
|
p.x = lon;
|
p.y = lat;
|
|
return p;
|
}
|
|
var names$20 = ["New_Zealand_Map_Grid", "nzmg"];
|
var nzmg = {
|
init: init$19,
|
forward: forward$18,
|
inverse: inverse$18,
|
names: names$20
|
};
|
|
/*
|
reference
|
"New Equal-Area Map Projections for Noncircular Regions", John P. Snyder,
|
The American Cartographer, Vol 15, No. 4, October 1988, pp. 341-355.
|
*/
|
|
|
/* Initialize the Miller Cylindrical projection
|
-------------------------------------------*/
|
function init$20() {
|
//no-op
|
}
|
|
/* Miller Cylindrical forward equations--mapping lat,long to x,y
|
------------------------------------------------------------*/
|
function forward$19(p) {
|
var lon = p.x;
|
var lat = p.y;
|
/* Forward equations
|
-----------------*/
|
var dlon = adjust_lon(lon - this.long0);
|
var x = this.x0 + this.a * dlon;
|
var y = this.y0 + this.a * Math.log(Math.tan((Math.PI / 4) + (lat / 2.5))) * 1.25;
|
|
p.x = x;
|
p.y = y;
|
return p;
|
}
|
|
/* Miller Cylindrical inverse equations--mapping x,y to lat/long
|
------------------------------------------------------------*/
|
function inverse$19(p) {
|
p.x -= this.x0;
|
p.y -= this.y0;
|
|
var lon = adjust_lon(this.long0 + p.x / this.a);
|
var lat = 2.5 * (Math.atan(Math.exp(0.8 * p.y / this.a)) - Math.PI / 4);
|
|
p.x = lon;
|
p.y = lat;
|
return p;
|
}
|
|
var names$21 = ["Miller_Cylindrical", "mill"];
|
var mill = {
|
init: init$20,
|
forward: forward$19,
|
inverse: inverse$19,
|
names: names$21
|
};
|
|
var MAX_ITER$3 = 20;
|
function init$21() {
|
/* Place parameters in static storage for common use
|
-------------------------------------------------*/
|
|
|
if (!this.sphere) {
|
this.en = pj_enfn(this.es);
|
}
|
else {
|
this.n = 1;
|
this.m = 0;
|
this.es = 0;
|
this.C_y = Math.sqrt((this.m + 1) / this.n);
|
this.C_x = this.C_y / (this.m + 1);
|
}
|
|
}
|
|
/* Sinusoidal forward equations--mapping lat,long to x,y
|
-----------------------------------------------------*/
|
function forward$20(p) {
|
var x, y;
|
var lon = p.x;
|
var lat = p.y;
|
/* Forward equations
|
-----------------*/
|
lon = adjust_lon(lon - this.long0);
|
|
if (this.sphere) {
|
if (!this.m) {
|
lat = this.n !== 1 ? Math.asin(this.n * Math.sin(lat)) : lat;
|
}
|
else {
|
var k = this.n * Math.sin(lat);
|
for (var i = MAX_ITER$3; i; --i) {
|
var V = (this.m * lat + Math.sin(lat) - k) / (this.m + Math.cos(lat));
|
lat -= V;
|
if (Math.abs(V) < EPSLN) {
|
break;
|
}
|
}
|
}
|
x = this.a * this.C_x * lon * (this.m + Math.cos(lat));
|
y = this.a * this.C_y * lat;
|
|
}
|
else {
|
|
var s = Math.sin(lat);
|
var c = Math.cos(lat);
|
y = this.a * pj_mlfn(lat, s, c, this.en);
|
x = this.a * lon * c / Math.sqrt(1 - this.es * s * s);
|
}
|
|
p.x = x;
|
p.y = y;
|
return p;
|
}
|
|
function inverse$20(p) {
|
var lat, temp, lon, s;
|
|
p.x -= this.x0;
|
lon = p.x / this.a;
|
p.y -= this.y0;
|
lat = p.y / this.a;
|
|
if (this.sphere) {
|
lat /= this.C_y;
|
lon = lon / (this.C_x * (this.m + Math.cos(lat)));
|
if (this.m) {
|
lat = asinz((this.m * lat + Math.sin(lat)) / this.n);
|
}
|
else if (this.n !== 1) {
|
lat = asinz(Math.sin(lat) / this.n);
|
}
|
lon = adjust_lon(lon + this.long0);
|
lat = adjust_lat(lat);
|
}
|
else {
|
lat = pj_inv_mlfn(p.y / this.a, this.es, this.en);
|
s = Math.abs(lat);
|
if (s < HALF_PI) {
|
s = Math.sin(lat);
|
temp = this.long0 + p.x * Math.sqrt(1 - this.es * s * s) / (this.a * Math.cos(lat));
|
//temp = this.long0 + p.x / (this.a * Math.cos(lat));
|
lon = adjust_lon(temp);
|
}
|
else if ((s - EPSLN) < HALF_PI) {
|
lon = this.long0;
|
}
|
}
|
p.x = lon;
|
p.y = lat;
|
return p;
|
}
|
|
var names$22 = ["Sinusoidal", "sinu"];
|
var sinu = {
|
init: init$21,
|
forward: forward$20,
|
inverse: inverse$20,
|
names: names$22
|
};
|
|
function init$22() {}
|
/* Mollweide forward equations--mapping lat,long to x,y
|
----------------------------------------------------*/
|
function forward$21(p) {
|
|
/* Forward equations
|
-----------------*/
|
var lon = p.x;
|
var lat = p.y;
|
|
var delta_lon = adjust_lon(lon - this.long0);
|
var theta = lat;
|
var con = Math.PI * Math.sin(lat);
|
|
/* Iterate using the Newton-Raphson method to find theta
|
-----------------------------------------------------*/
|
while (true) {
|
var delta_theta = -(theta + Math.sin(theta) - con) / (1 + Math.cos(theta));
|
theta += delta_theta;
|
if (Math.abs(delta_theta) < EPSLN) {
|
break;
|
}
|
}
|
theta /= 2;
|
|
/* If the latitude is 90 deg, force the x coordinate to be "0 + false easting"
|
this is done here because of precision problems with "cos(theta)"
|
--------------------------------------------------------------------------*/
|
if (Math.PI / 2 - Math.abs(lat) < EPSLN) {
|
delta_lon = 0;
|
}
|
var x = 0.900316316158 * this.a * delta_lon * Math.cos(theta) + this.x0;
|
var y = 1.4142135623731 * this.a * Math.sin(theta) + this.y0;
|
|
p.x = x;
|
p.y = y;
|
return p;
|
}
|
|
function inverse$21(p) {
|
var theta;
|
var arg;
|
|
/* Inverse equations
|
-----------------*/
|
p.x -= this.x0;
|
p.y -= this.y0;
|
arg = p.y / (1.4142135623731 * this.a);
|
|
/* Because of division by zero problems, 'arg' can not be 1. Therefore
|
a number very close to one is used instead.
|
-------------------------------------------------------------------*/
|
if (Math.abs(arg) > 0.999999999999) {
|
arg = 0.999999999999;
|
}
|
theta = Math.asin(arg);
|
var lon = adjust_lon(this.long0 + (p.x / (0.900316316158 * this.a * Math.cos(theta))));
|
if (lon < (-Math.PI)) {
|
lon = -Math.PI;
|
}
|
if (lon > Math.PI) {
|
lon = Math.PI;
|
}
|
arg = (2 * theta + Math.sin(2 * theta)) / Math.PI;
|
if (Math.abs(arg) > 1) {
|
arg = 1;
|
}
|
var lat = Math.asin(arg);
|
|
p.x = lon;
|
p.y = lat;
|
return p;
|
}
|
|
var names$23 = ["Mollweide", "moll"];
|
var moll = {
|
init: init$22,
|
forward: forward$21,
|
inverse: inverse$21,
|
names: names$23
|
};
|
|
function init$23() {
|
|
/* Place parameters in static storage for common use
|
-------------------------------------------------*/
|
// Standard Parallels cannot be equal and on opposite sides of the equator
|
if (Math.abs(this.lat1 + this.lat2) < EPSLN) {
|
return;
|
}
|
this.lat2 = this.lat2 || this.lat1;
|
this.temp = this.b / this.a;
|
this.es = 1 - Math.pow(this.temp, 2);
|
this.e = Math.sqrt(this.es);
|
this.e0 = e0fn(this.es);
|
this.e1 = e1fn(this.es);
|
this.e2 = e2fn(this.es);
|
this.e3 = e3fn(this.es);
|
|
this.sinphi = Math.sin(this.lat1);
|
this.cosphi = Math.cos(this.lat1);
|
|
this.ms1 = msfnz(this.e, this.sinphi, this.cosphi);
|
this.ml1 = mlfn(this.e0, this.e1, this.e2, this.e3, this.lat1);
|
|
if (Math.abs(this.lat1 - this.lat2) < EPSLN) {
|
this.ns = this.sinphi;
|
}
|
else {
|
this.sinphi = Math.sin(this.lat2);
|
this.cosphi = Math.cos(this.lat2);
|
this.ms2 = msfnz(this.e, this.sinphi, this.cosphi);
|
this.ml2 = mlfn(this.e0, this.e1, this.e2, this.e3, this.lat2);
|
this.ns = (this.ms1 - this.ms2) / (this.ml2 - this.ml1);
|
}
|
this.g = this.ml1 + this.ms1 / this.ns;
|
this.ml0 = mlfn(this.e0, this.e1, this.e2, this.e3, this.lat0);
|
this.rh = this.a * (this.g - this.ml0);
|
}
|
|
/* Equidistant Conic forward equations--mapping lat,long to x,y
|
-----------------------------------------------------------*/
|
function forward$22(p) {
|
var lon = p.x;
|
var lat = p.y;
|
var rh1;
|
|
/* Forward equations
|
-----------------*/
|
if (this.sphere) {
|
rh1 = this.a * (this.g - lat);
|
}
|
else {
|
var ml = mlfn(this.e0, this.e1, this.e2, this.e3, lat);
|
rh1 = this.a * (this.g - ml);
|
}
|
var theta = this.ns * adjust_lon(lon - this.long0);
|
var x = this.x0 + rh1 * Math.sin(theta);
|
var y = this.y0 + this.rh - rh1 * Math.cos(theta);
|
p.x = x;
|
p.y = y;
|
return p;
|
}
|
|
/* Inverse equations
|
-----------------*/
|
function inverse$22(p) {
|
p.x -= this.x0;
|
p.y = this.rh - p.y + this.y0;
|
var con, rh1, lat, lon;
|
if (this.ns >= 0) {
|
rh1 = Math.sqrt(p.x * p.x + p.y * p.y);
|
con = 1;
|
}
|
else {
|
rh1 = -Math.sqrt(p.x * p.x + p.y * p.y);
|
con = -1;
|
}
|
var theta = 0;
|
if (rh1 !== 0) {
|
theta = Math.atan2(con * p.x, con * p.y);
|
}
|
|
if (this.sphere) {
|
lon = adjust_lon(this.long0 + theta / this.ns);
|
lat = adjust_lat(this.g - rh1 / this.a);
|
p.x = lon;
|
p.y = lat;
|
return p;
|
}
|
else {
|
var ml = this.g - rh1 / this.a;
|
lat = imlfn(ml, this.e0, this.e1, this.e2, this.e3);
|
lon = adjust_lon(this.long0 + theta / this.ns);
|
p.x = lon;
|
p.y = lat;
|
return p;
|
}
|
|
}
|
|
var names$24 = ["Equidistant_Conic", "eqdc"];
|
var eqdc = {
|
init: init$23,
|
forward: forward$22,
|
inverse: inverse$22,
|
names: names$24
|
};
|
|
/* Initialize the Van Der Grinten projection
|
----------------------------------------*/
|
function init$24() {
|
//this.R = 6370997; //Radius of earth
|
this.R = this.a;
|
}
|
|
function forward$23(p) {
|
|
var lon = p.x;
|
var lat = p.y;
|
|
/* Forward equations
|
-----------------*/
|
var dlon = adjust_lon(lon - this.long0);
|
var x, y;
|
|
if (Math.abs(lat) <= EPSLN) {
|
x = this.x0 + this.R * dlon;
|
y = this.y0;
|
}
|
var theta = asinz(2 * Math.abs(lat / Math.PI));
|
if ((Math.abs(dlon) <= EPSLN) || (Math.abs(Math.abs(lat) - HALF_PI) <= EPSLN)) {
|
x = this.x0;
|
if (lat >= 0) {
|
y = this.y0 + Math.PI * this.R * Math.tan(0.5 * theta);
|
}
|
else {
|
y = this.y0 + Math.PI * this.R * -Math.tan(0.5 * theta);
|
}
|
// return(OK);
|
}
|
var al = 0.5 * Math.abs((Math.PI / dlon) - (dlon / Math.PI));
|
var asq = al * al;
|
var sinth = Math.sin(theta);
|
var costh = Math.cos(theta);
|
|
var g = costh / (sinth + costh - 1);
|
var gsq = g * g;
|
var m = g * (2 / sinth - 1);
|
var msq = m * m;
|
var con = Math.PI * this.R * (al * (g - msq) + Math.sqrt(asq * (g - msq) * (g - msq) - (msq + asq) * (gsq - msq))) / (msq + asq);
|
if (dlon < 0) {
|
con = -con;
|
}
|
x = this.x0 + con;
|
//con = Math.abs(con / (Math.PI * this.R));
|
var q = asq + g;
|
con = Math.PI * this.R * (m * q - al * Math.sqrt((msq + asq) * (asq + 1) - q * q)) / (msq + asq);
|
if (lat >= 0) {
|
//y = this.y0 + Math.PI * this.R * Math.sqrt(1 - con * con - 2 * al * con);
|
y = this.y0 + con;
|
}
|
else {
|
//y = this.y0 - Math.PI * this.R * Math.sqrt(1 - con * con - 2 * al * con);
|
y = this.y0 - con;
|
}
|
p.x = x;
|
p.y = y;
|
return p;
|
}
|
|
/* Van Der Grinten inverse equations--mapping x,y to lat/long
|
---------------------------------------------------------*/
|
function inverse$23(p) {
|
var lon, lat;
|
var xx, yy, xys, c1, c2, c3;
|
var a1;
|
var m1;
|
var con;
|
var th1;
|
var d;
|
|
/* inverse equations
|
-----------------*/
|
p.x -= this.x0;
|
p.y -= this.y0;
|
con = Math.PI * this.R;
|
xx = p.x / con;
|
yy = p.y / con;
|
xys = xx * xx + yy * yy;
|
c1 = -Math.abs(yy) * (1 + xys);
|
c2 = c1 - 2 * yy * yy + xx * xx;
|
c3 = -2 * c1 + 1 + 2 * yy * yy + xys * xys;
|
d = yy * yy / c3 + (2 * c2 * c2 * c2 / c3 / c3 / c3 - 9 * c1 * c2 / c3 / c3) / 27;
|
a1 = (c1 - c2 * c2 / 3 / c3) / c3;
|
m1 = 2 * Math.sqrt(-a1 / 3);
|
con = ((3 * d) / a1) / m1;
|
if (Math.abs(con) > 1) {
|
if (con >= 0) {
|
con = 1;
|
}
|
else {
|
con = -1;
|
}
|
}
|
th1 = Math.acos(con) / 3;
|
if (p.y >= 0) {
|
lat = (-m1 * Math.cos(th1 + Math.PI / 3) - c2 / 3 / c3) * Math.PI;
|
}
|
else {
|
lat = -(-m1 * Math.cos(th1 + Math.PI / 3) - c2 / 3 / c3) * Math.PI;
|
}
|
|
if (Math.abs(xx) < EPSLN) {
|
lon = this.long0;
|
}
|
else {
|
lon = adjust_lon(this.long0 + Math.PI * (xys - 1 + Math.sqrt(1 + 2 * (xx * xx - yy * yy) + xys * xys)) / 2 / xx);
|
}
|
|
p.x = lon;
|
p.y = lat;
|
return p;
|
}
|
|
var names$25 = ["Van_der_Grinten_I", "VanDerGrinten", "vandg"];
|
var vandg = {
|
init: init$24,
|
forward: forward$23,
|
inverse: inverse$23,
|
names: names$25
|
};
|
|
function init$25() {
|
this.sin_p12 = Math.sin(this.lat0);
|
this.cos_p12 = Math.cos(this.lat0);
|
}
|
|
function forward$24(p) {
|
var lon = p.x;
|
var lat = p.y;
|
var sinphi = Math.sin(p.y);
|
var cosphi = Math.cos(p.y);
|
var dlon = adjust_lon(lon - this.long0);
|
var e0, e1, e2, e3, Mlp, Ml, tanphi, Nl1, Nl, psi, Az, G, H, GH, Hs, c, kp, cos_c, s, s2, s3, s4, s5;
|
if (this.sphere) {
|
if (Math.abs(this.sin_p12 - 1) <= EPSLN) {
|
//North Pole case
|
p.x = this.x0 + this.a * (HALF_PI - lat) * Math.sin(dlon);
|
p.y = this.y0 - this.a * (HALF_PI - lat) * Math.cos(dlon);
|
return p;
|
}
|
else if (Math.abs(this.sin_p12 + 1) <= EPSLN) {
|
//South Pole case
|
p.x = this.x0 + this.a * (HALF_PI + lat) * Math.sin(dlon);
|
p.y = this.y0 + this.a * (HALF_PI + lat) * Math.cos(dlon);
|
return p;
|
}
|
else {
|
//default case
|
cos_c = this.sin_p12 * sinphi + this.cos_p12 * cosphi * Math.cos(dlon);
|
c = Math.acos(cos_c);
|
kp = c / Math.sin(c);
|
p.x = this.x0 + this.a * kp * cosphi * Math.sin(dlon);
|
p.y = this.y0 + this.a * kp * (this.cos_p12 * sinphi - this.sin_p12 * cosphi * Math.cos(dlon));
|
return p;
|
}
|
}
|
else {
|
e0 = e0fn(this.es);
|
e1 = e1fn(this.es);
|
e2 = e2fn(this.es);
|
e3 = e3fn(this.es);
|
if (Math.abs(this.sin_p12 - 1) <= EPSLN) {
|
//North Pole case
|
Mlp = this.a * mlfn(e0, e1, e2, e3, HALF_PI);
|
Ml = this.a * mlfn(e0, e1, e2, e3, lat);
|
p.x = this.x0 + (Mlp - Ml) * Math.sin(dlon);
|
p.y = this.y0 - (Mlp - Ml) * Math.cos(dlon);
|
return p;
|
}
|
else if (Math.abs(this.sin_p12 + 1) <= EPSLN) {
|
//South Pole case
|
Mlp = this.a * mlfn(e0, e1, e2, e3, HALF_PI);
|
Ml = this.a * mlfn(e0, e1, e2, e3, lat);
|
p.x = this.x0 + (Mlp + Ml) * Math.sin(dlon);
|
p.y = this.y0 + (Mlp + Ml) * Math.cos(dlon);
|
return p;
|
}
|
else {
|
//Default case
|
tanphi = sinphi / cosphi;
|
Nl1 = gN(this.a, this.e, this.sin_p12);
|
Nl = gN(this.a, this.e, sinphi);
|
psi = Math.atan((1 - this.es) * tanphi + this.es * Nl1 * this.sin_p12 / (Nl * cosphi));
|
Az = Math.atan2(Math.sin(dlon), this.cos_p12 * Math.tan(psi) - this.sin_p12 * Math.cos(dlon));
|
if (Az === 0) {
|
s = Math.asin(this.cos_p12 * Math.sin(psi) - this.sin_p12 * Math.cos(psi));
|
}
|
else if (Math.abs(Math.abs(Az) - Math.PI) <= EPSLN) {
|
s = -Math.asin(this.cos_p12 * Math.sin(psi) - this.sin_p12 * Math.cos(psi));
|
}
|
else {
|
s = Math.asin(Math.sin(dlon) * Math.cos(psi) / Math.sin(Az));
|
}
|
G = this.e * this.sin_p12 / Math.sqrt(1 - this.es);
|
H = this.e * this.cos_p12 * Math.cos(Az) / Math.sqrt(1 - this.es);
|
GH = G * H;
|
Hs = H * H;
|
s2 = s * s;
|
s3 = s2 * s;
|
s4 = s3 * s;
|
s5 = s4 * s;
|
c = Nl1 * s * (1 - s2 * Hs * (1 - Hs) / 6 + s3 / 8 * GH * (1 - 2 * Hs) + s4 / 120 * (Hs * (4 - 7 * Hs) - 3 * G * G * (1 - 7 * Hs)) - s5 / 48 * GH);
|
p.x = this.x0 + c * Math.sin(Az);
|
p.y = this.y0 + c * Math.cos(Az);
|
return p;
|
}
|
}
|
|
|
}
|
|
function inverse$24(p) {
|
p.x -= this.x0;
|
p.y -= this.y0;
|
var rh, z, sinz, cosz, lon, lat, con, e0, e1, e2, e3, Mlp, M, N1, psi, Az, cosAz, tmp, A, B, D, Ee, F;
|
if (this.sphere) {
|
rh = Math.sqrt(p.x * p.x + p.y * p.y);
|
if (rh > (2 * HALF_PI * this.a)) {
|
return;
|
}
|
z = rh / this.a;
|
|
sinz = Math.sin(z);
|
cosz = Math.cos(z);
|
|
lon = this.long0;
|
if (Math.abs(rh) <= EPSLN) {
|
lat = this.lat0;
|
}
|
else {
|
lat = asinz(cosz * this.sin_p12 + (p.y * sinz * this.cos_p12) / rh);
|
con = Math.abs(this.lat0) - HALF_PI;
|
if (Math.abs(con) <= EPSLN) {
|
if (this.lat0 >= 0) {
|
lon = adjust_lon(this.long0 + Math.atan2(p.x, - p.y));
|
}
|
else {
|
lon = adjust_lon(this.long0 - Math.atan2(-p.x, p.y));
|
}
|
}
|
else {
|
/*con = cosz - this.sin_p12 * Math.sin(lat);
|
if ((Math.abs(con) < EPSLN) && (Math.abs(p.x) < EPSLN)) {
|
//no-op, just keep the lon value as is
|
} else {
|
var temp = Math.atan2((p.x * sinz * this.cos_p12), (con * rh));
|
lon = adjust_lon(this.long0 + Math.atan2((p.x * sinz * this.cos_p12), (con * rh)));
|
}*/
|
lon = adjust_lon(this.long0 + Math.atan2(p.x * sinz, rh * this.cos_p12 * cosz - p.y * this.sin_p12 * sinz));
|
}
|
}
|
|
p.x = lon;
|
p.y = lat;
|
return p;
|
}
|
else {
|
e0 = e0fn(this.es);
|
e1 = e1fn(this.es);
|
e2 = e2fn(this.es);
|
e3 = e3fn(this.es);
|
if (Math.abs(this.sin_p12 - 1) <= EPSLN) {
|
//North pole case
|
Mlp = this.a * mlfn(e0, e1, e2, e3, HALF_PI);
|
rh = Math.sqrt(p.x * p.x + p.y * p.y);
|
M = Mlp - rh;
|
lat = imlfn(M / this.a, e0, e1, e2, e3);
|
lon = adjust_lon(this.long0 + Math.atan2(p.x, - 1 * p.y));
|
p.x = lon;
|
p.y = lat;
|
return p;
|
}
|
else if (Math.abs(this.sin_p12 + 1) <= EPSLN) {
|
//South pole case
|
Mlp = this.a * mlfn(e0, e1, e2, e3, HALF_PI);
|
rh = Math.sqrt(p.x * p.x + p.y * p.y);
|
M = rh - Mlp;
|
|
lat = imlfn(M / this.a, e0, e1, e2, e3);
|
lon = adjust_lon(this.long0 + Math.atan2(p.x, p.y));
|
p.x = lon;
|
p.y = lat;
|
return p;
|
}
|
else {
|
//default case
|
rh = Math.sqrt(p.x * p.x + p.y * p.y);
|
Az = Math.atan2(p.x, p.y);
|
N1 = gN(this.a, this.e, this.sin_p12);
|
cosAz = Math.cos(Az);
|
tmp = this.e * this.cos_p12 * cosAz;
|
A = -tmp * tmp / (1 - this.es);
|
B = 3 * this.es * (1 - A) * this.sin_p12 * this.cos_p12 * cosAz / (1 - this.es);
|
D = rh / N1;
|
Ee = D - A * (1 + A) * Math.pow(D, 3) / 6 - B * (1 + 3 * A) * Math.pow(D, 4) / 24;
|
F = 1 - A * Ee * Ee / 2 - D * Ee * Ee * Ee / 6;
|
psi = Math.asin(this.sin_p12 * Math.cos(Ee) + this.cos_p12 * Math.sin(Ee) * cosAz);
|
lon = adjust_lon(this.long0 + Math.asin(Math.sin(Az) * Math.sin(Ee) / Math.cos(psi)));
|
lat = Math.atan((1 - this.es * F * this.sin_p12 / Math.sin(psi)) * Math.tan(psi) / (1 - this.es));
|
p.x = lon;
|
p.y = lat;
|
return p;
|
}
|
}
|
|
}
|
|
var names$26 = ["Azimuthal_Equidistant", "aeqd"];
|
var aeqd = {
|
init: init$25,
|
forward: forward$24,
|
inverse: inverse$24,
|
names: names$26
|
};
|
|
function init$26() {
|
//double temp; /* temporary variable */
|
|
/* Place parameters in static storage for common use
|
-------------------------------------------------*/
|
this.sin_p14 = Math.sin(this.lat0);
|
this.cos_p14 = Math.cos(this.lat0);
|
}
|
|
/* Orthographic forward equations--mapping lat,long to x,y
|
---------------------------------------------------*/
|
function forward$25(p) {
|
var sinphi, cosphi; /* sin and cos value */
|
var dlon; /* delta longitude value */
|
var coslon; /* cos of longitude */
|
var ksp; /* scale factor */
|
var g, x, y;
|
var lon = p.x;
|
var lat = p.y;
|
/* Forward equations
|
-----------------*/
|
dlon = adjust_lon(lon - this.long0);
|
|
sinphi = Math.sin(lat);
|
cosphi = Math.cos(lat);
|
|
coslon = Math.cos(dlon);
|
g = this.sin_p14 * sinphi + this.cos_p14 * cosphi * coslon;
|
ksp = 1;
|
if ((g > 0) || (Math.abs(g) <= EPSLN)) {
|
x = this.a * ksp * cosphi * Math.sin(dlon);
|
y = this.y0 + this.a * ksp * (this.cos_p14 * sinphi - this.sin_p14 * cosphi * coslon);
|
}
|
p.x = x;
|
p.y = y;
|
return p;
|
}
|
|
function inverse$25(p) {
|
var rh; /* height above ellipsoid */
|
var z; /* angle */
|
var sinz, cosz; /* sin of z and cos of z */
|
var con;
|
var lon, lat;
|
/* Inverse equations
|
-----------------*/
|
p.x -= this.x0;
|
p.y -= this.y0;
|
rh = Math.sqrt(p.x * p.x + p.y * p.y);
|
z = asinz(rh / this.a);
|
|
sinz = Math.sin(z);
|
cosz = Math.cos(z);
|
|
lon = this.long0;
|
if (Math.abs(rh) <= EPSLN) {
|
lat = this.lat0;
|
p.x = lon;
|
p.y = lat;
|
return p;
|
}
|
lat = asinz(cosz * this.sin_p14 + (p.y * sinz * this.cos_p14) / rh);
|
con = Math.abs(this.lat0) - HALF_PI;
|
if (Math.abs(con) <= EPSLN) {
|
if (this.lat0 >= 0) {
|
lon = adjust_lon(this.long0 + Math.atan2(p.x, - p.y));
|
}
|
else {
|
lon = adjust_lon(this.long0 - Math.atan2(-p.x, p.y));
|
}
|
p.x = lon;
|
p.y = lat;
|
return p;
|
}
|
lon = adjust_lon(this.long0 + Math.atan2((p.x * sinz), rh * this.cos_p14 * cosz - p.y * this.sin_p14 * sinz));
|
p.x = lon;
|
p.y = lat;
|
return p;
|
}
|
|
var names$27 = ["ortho"];
|
var ortho = {
|
init: init$26,
|
forward: forward$25,
|
inverse: inverse$25,
|
names: names$27
|
};
|
|
// QSC projection rewritten from the original PROJ4
|
// https://github.com/OSGeo/proj.4/blob/master/src/PJ_qsc.c
|
|
/* constants */
|
var FACE_ENUM = {
|
FRONT: 1,
|
RIGHT: 2,
|
BACK: 3,
|
LEFT: 4,
|
TOP: 5,
|
BOTTOM: 6
|
};
|
|
var AREA_ENUM = {
|
AREA_0: 1,
|
AREA_1: 2,
|
AREA_2: 3,
|
AREA_3: 4
|
};
|
|
function init$27() {
|
|
this.x0 = this.x0 || 0;
|
this.y0 = this.y0 || 0;
|
this.lat0 = this.lat0 || 0;
|
this.long0 = this.long0 || 0;
|
this.lat_ts = this.lat_ts || 0;
|
this.title = this.title || "Quadrilateralized Spherical Cube";
|
|
/* Determine the cube face from the center of projection. */
|
if (this.lat0 >= HALF_PI - FORTPI / 2.0) {
|
this.face = FACE_ENUM.TOP;
|
} else if (this.lat0 <= -(HALF_PI - FORTPI / 2.0)) {
|
this.face = FACE_ENUM.BOTTOM;
|
} else if (Math.abs(this.long0) <= FORTPI) {
|
this.face = FACE_ENUM.FRONT;
|
} else if (Math.abs(this.long0) <= HALF_PI + FORTPI) {
|
this.face = this.long0 > 0.0 ? FACE_ENUM.RIGHT : FACE_ENUM.LEFT;
|
} else {
|
this.face = FACE_ENUM.BACK;
|
}
|
|
/* Fill in useful values for the ellipsoid <-> sphere shift
|
* described in [LK12]. */
|
if (this.es !== 0) {
|
this.one_minus_f = 1 - (this.a - this.b) / this.a;
|
this.one_minus_f_squared = this.one_minus_f * this.one_minus_f;
|
}
|
}
|
|
// QSC forward equations--mapping lat,long to x,y
|
// -----------------------------------------------------------------
|
function forward$26(p) {
|
var xy = {x: 0, y: 0};
|
var lat, lon;
|
var theta, phi;
|
var t, mu;
|
/* nu; */
|
var area = {value: 0};
|
|
// move lon according to projection's lon
|
p.x -= this.long0;
|
|
/* Convert the geodetic latitude to a geocentric latitude.
|
* This corresponds to the shift from the ellipsoid to the sphere
|
* described in [LK12]. */
|
if (this.es !== 0) {//if (P->es != 0) {
|
lat = Math.atan(this.one_minus_f_squared * Math.tan(p.y));
|
} else {
|
lat = p.y;
|
}
|
|
/* Convert the input lat, lon into theta, phi as used by QSC.
|
* This depends on the cube face and the area on it.
|
* For the top and bottom face, we can compute theta and phi
|
* directly from phi, lam. For the other faces, we must use
|
* unit sphere cartesian coordinates as an intermediate step. */
|
lon = p.x; //lon = lp.lam;
|
if (this.face === FACE_ENUM.TOP) {
|
phi = HALF_PI - lat;
|
if (lon >= FORTPI && lon <= HALF_PI + FORTPI) {
|
area.value = AREA_ENUM.AREA_0;
|
theta = lon - HALF_PI;
|
} else if (lon > HALF_PI + FORTPI || lon <= -(HALF_PI + FORTPI)) {
|
area.value = AREA_ENUM.AREA_1;
|
theta = (lon > 0.0 ? lon - SPI : lon + SPI);
|
} else if (lon > -(HALF_PI + FORTPI) && lon <= -FORTPI) {
|
area.value = AREA_ENUM.AREA_2;
|
theta = lon + HALF_PI;
|
} else {
|
area.value = AREA_ENUM.AREA_3;
|
theta = lon;
|
}
|
} else if (this.face === FACE_ENUM.BOTTOM) {
|
phi = HALF_PI + lat;
|
if (lon >= FORTPI && lon <= HALF_PI + FORTPI) {
|
area.value = AREA_ENUM.AREA_0;
|
theta = -lon + HALF_PI;
|
} else if (lon < FORTPI && lon >= -FORTPI) {
|
area.value = AREA_ENUM.AREA_1;
|
theta = -lon;
|
} else if (lon < -FORTPI && lon >= -(HALF_PI + FORTPI)) {
|
area.value = AREA_ENUM.AREA_2;
|
theta = -lon - HALF_PI;
|
} else {
|
area.value = AREA_ENUM.AREA_3;
|
theta = (lon > 0.0 ? -lon + SPI : -lon - SPI);
|
}
|
} else {
|
var q, r, s;
|
var sinlat, coslat;
|
var sinlon, coslon;
|
|
if (this.face === FACE_ENUM.RIGHT) {
|
lon = qsc_shift_lon_origin(lon, +HALF_PI);
|
} else if (this.face === FACE_ENUM.BACK) {
|
lon = qsc_shift_lon_origin(lon, +SPI);
|
} else if (this.face === FACE_ENUM.LEFT) {
|
lon = qsc_shift_lon_origin(lon, -HALF_PI);
|
}
|
sinlat = Math.sin(lat);
|
coslat = Math.cos(lat);
|
sinlon = Math.sin(lon);
|
coslon = Math.cos(lon);
|
q = coslat * coslon;
|
r = coslat * sinlon;
|
s = sinlat;
|
|
if (this.face === FACE_ENUM.FRONT) {
|
phi = Math.acos(q);
|
theta = qsc_fwd_equat_face_theta(phi, s, r, area);
|
} else if (this.face === FACE_ENUM.RIGHT) {
|
phi = Math.acos(r);
|
theta = qsc_fwd_equat_face_theta(phi, s, -q, area);
|
} else if (this.face === FACE_ENUM.BACK) {
|
phi = Math.acos(-q);
|
theta = qsc_fwd_equat_face_theta(phi, s, -r, area);
|
} else if (this.face === FACE_ENUM.LEFT) {
|
phi = Math.acos(-r);
|
theta = qsc_fwd_equat_face_theta(phi, s, q, area);
|
} else {
|
/* Impossible */
|
phi = theta = 0;
|
area.value = AREA_ENUM.AREA_0;
|
}
|
}
|
|
/* Compute mu and nu for the area of definition.
|
* For mu, see Eq. (3-21) in [OL76], but note the typos:
|
* compare with Eq. (3-14). For nu, see Eq. (3-38). */
|
mu = Math.atan((12 / SPI) * (theta + Math.acos(Math.sin(theta) * Math.cos(FORTPI)) - HALF_PI));
|
t = Math.sqrt((1 - Math.cos(phi)) / (Math.cos(mu) * Math.cos(mu)) / (1 - Math.cos(Math.atan(1 / Math.cos(theta)))));
|
|
/* Apply the result to the real area. */
|
if (area.value === AREA_ENUM.AREA_1) {
|
mu += HALF_PI;
|
} else if (area.value === AREA_ENUM.AREA_2) {
|
mu += SPI;
|
} else if (area.value === AREA_ENUM.AREA_3) {
|
mu += 1.5 * SPI;
|
}
|
|
/* Now compute x, y from mu and nu */
|
xy.x = t * Math.cos(mu);
|
xy.y = t * Math.sin(mu);
|
xy.x = xy.x * this.a + this.x0;
|
xy.y = xy.y * this.a + this.y0;
|
|
p.x = xy.x;
|
p.y = xy.y;
|
return p;
|
}
|
|
// QSC inverse equations--mapping x,y to lat/long
|
// -----------------------------------------------------------------
|
function inverse$26(p) {
|
var lp = {lam: 0, phi: 0};
|
var mu, nu, cosmu, tannu;
|
var tantheta, theta, cosphi, phi;
|
var t;
|
var area = {value: 0};
|
|
/* de-offset */
|
p.x = (p.x - this.x0) / this.a;
|
p.y = (p.y - this.y0) / this.a;
|
|
/* Convert the input x, y to the mu and nu angles as used by QSC.
|
* This depends on the area of the cube face. */
|
nu = Math.atan(Math.sqrt(p.x * p.x + p.y * p.y));
|
mu = Math.atan2(p.y, p.x);
|
if (p.x >= 0.0 && p.x >= Math.abs(p.y)) {
|
area.value = AREA_ENUM.AREA_0;
|
} else if (p.y >= 0.0 && p.y >= Math.abs(p.x)) {
|
area.value = AREA_ENUM.AREA_1;
|
mu -= HALF_PI;
|
} else if (p.x < 0.0 && -p.x >= Math.abs(p.y)) {
|
area.value = AREA_ENUM.AREA_2;
|
mu = (mu < 0.0 ? mu + SPI : mu - SPI);
|
} else {
|
area.value = AREA_ENUM.AREA_3;
|
mu += HALF_PI;
|
}
|
|
/* Compute phi and theta for the area of definition.
|
* The inverse projection is not described in the original paper, but some
|
* good hints can be found here (as of 2011-12-14):
|
* http://fits.gsfc.nasa.gov/fitsbits/saf.93/saf.9302
|
* (search for "Message-Id: <9302181759.AA25477 at fits.cv.nrao.edu>") */
|
t = (SPI / 12) * Math.tan(mu);
|
tantheta = Math.sin(t) / (Math.cos(t) - (1 / Math.sqrt(2)));
|
theta = Math.atan(tantheta);
|
cosmu = Math.cos(mu);
|
tannu = Math.tan(nu);
|
cosphi = 1 - cosmu * cosmu * tannu * tannu * (1 - Math.cos(Math.atan(1 / Math.cos(theta))));
|
if (cosphi < -1) {
|
cosphi = -1;
|
} else if (cosphi > +1) {
|
cosphi = +1;
|
}
|
|
/* Apply the result to the real area on the cube face.
|
* For the top and bottom face, we can compute phi and lam directly.
|
* For the other faces, we must use unit sphere cartesian coordinates
|
* as an intermediate step. */
|
if (this.face === FACE_ENUM.TOP) {
|
phi = Math.acos(cosphi);
|
lp.phi = HALF_PI - phi;
|
if (area.value === AREA_ENUM.AREA_0) {
|
lp.lam = theta + HALF_PI;
|
} else if (area.value === AREA_ENUM.AREA_1) {
|
lp.lam = (theta < 0.0 ? theta + SPI : theta - SPI);
|
} else if (area.value === AREA_ENUM.AREA_2) {
|
lp.lam = theta - HALF_PI;
|
} else /* area.value == AREA_ENUM.AREA_3 */ {
|
lp.lam = theta;
|
}
|
} else if (this.face === FACE_ENUM.BOTTOM) {
|
phi = Math.acos(cosphi);
|
lp.phi = phi - HALF_PI;
|
if (area.value === AREA_ENUM.AREA_0) {
|
lp.lam = -theta + HALF_PI;
|
} else if (area.value === AREA_ENUM.AREA_1) {
|
lp.lam = -theta;
|
} else if (area.value === AREA_ENUM.AREA_2) {
|
lp.lam = -theta - HALF_PI;
|
} else /* area.value == AREA_ENUM.AREA_3 */ {
|
lp.lam = (theta < 0.0 ? -theta - SPI : -theta + SPI);
|
}
|
} else {
|
/* Compute phi and lam via cartesian unit sphere coordinates. */
|
var q, r, s;
|
q = cosphi;
|
t = q * q;
|
if (t >= 1) {
|
s = 0;
|
} else {
|
s = Math.sqrt(1 - t) * Math.sin(theta);
|
}
|
t += s * s;
|
if (t >= 1) {
|
r = 0;
|
} else {
|
r = Math.sqrt(1 - t);
|
}
|
/* Rotate q,r,s into the correct area. */
|
if (area.value === AREA_ENUM.AREA_1) {
|
t = r;
|
r = -s;
|
s = t;
|
} else if (area.value === AREA_ENUM.AREA_2) {
|
r = -r;
|
s = -s;
|
} else if (area.value === AREA_ENUM.AREA_3) {
|
t = r;
|
r = s;
|
s = -t;
|
}
|
/* Rotate q,r,s into the correct cube face. */
|
if (this.face === FACE_ENUM.RIGHT) {
|
t = q;
|
q = -r;
|
r = t;
|
} else if (this.face === FACE_ENUM.BACK) {
|
q = -q;
|
r = -r;
|
} else if (this.face === FACE_ENUM.LEFT) {
|
t = q;
|
q = r;
|
r = -t;
|
}
|
/* Now compute phi and lam from the unit sphere coordinates. */
|
lp.phi = Math.acos(-s) - HALF_PI;
|
lp.lam = Math.atan2(r, q);
|
if (this.face === FACE_ENUM.RIGHT) {
|
lp.lam = qsc_shift_lon_origin(lp.lam, -HALF_PI);
|
} else if (this.face === FACE_ENUM.BACK) {
|
lp.lam = qsc_shift_lon_origin(lp.lam, -SPI);
|
} else if (this.face === FACE_ENUM.LEFT) {
|
lp.lam = qsc_shift_lon_origin(lp.lam, +HALF_PI);
|
}
|
}
|
|
/* Apply the shift from the sphere to the ellipsoid as described
|
* in [LK12]. */
|
if (this.es !== 0) {
|
var invert_sign;
|
var tanphi, xa;
|
invert_sign = (lp.phi < 0 ? 1 : 0);
|
tanphi = Math.tan(lp.phi);
|
xa = this.b / Math.sqrt(tanphi * tanphi + this.one_minus_f_squared);
|
lp.phi = Math.atan(Math.sqrt(this.a * this.a - xa * xa) / (this.one_minus_f * xa));
|
if (invert_sign) {
|
lp.phi = -lp.phi;
|
}
|
}
|
|
lp.lam += this.long0;
|
p.x = lp.lam;
|
p.y = lp.phi;
|
return p;
|
}
|
|
/* Helper function for forward projection: compute the theta angle
|
* and determine the area number. */
|
function qsc_fwd_equat_face_theta(phi, y, x, area) {
|
var theta;
|
if (phi < EPSLN) {
|
area.value = AREA_ENUM.AREA_0;
|
theta = 0.0;
|
} else {
|
theta = Math.atan2(y, x);
|
if (Math.abs(theta) <= FORTPI) {
|
area.value = AREA_ENUM.AREA_0;
|
} else if (theta > FORTPI && theta <= HALF_PI + FORTPI) {
|
area.value = AREA_ENUM.AREA_1;
|
theta -= HALF_PI;
|
} else if (theta > HALF_PI + FORTPI || theta <= -(HALF_PI + FORTPI)) {
|
area.value = AREA_ENUM.AREA_2;
|
theta = (theta >= 0.0 ? theta - SPI : theta + SPI);
|
} else {
|
area.value = AREA_ENUM.AREA_3;
|
theta += HALF_PI;
|
}
|
}
|
return theta;
|
}
|
|
/* Helper function: shift the longitude. */
|
function qsc_shift_lon_origin(lon, offset) {
|
var slon = lon + offset;
|
if (slon < -SPI) {
|
slon += TWO_PI;
|
} else if (slon > +SPI) {
|
slon -= TWO_PI;
|
}
|
return slon;
|
}
|
|
var names$28 = ["Quadrilateralized Spherical Cube", "Quadrilateralized_Spherical_Cube", "qsc"];
|
var qsc = {
|
init: init$27,
|
forward: forward$26,
|
inverse: inverse$26,
|
names: names$28
|
};
|
|
// Robinson projection
|
// Based on https://github.com/OSGeo/proj.4/blob/master/src/PJ_robin.c
|
// Polynomial coeficients from http://article.gmane.org/gmane.comp.gis.proj-4.devel/6039
|
|
var COEFS_X = [
|
[1.0000, 2.2199e-17, -7.15515e-05, 3.1103e-06],
|
[0.9986, -0.000482243, -2.4897e-05, -1.3309e-06],
|
[0.9954, -0.00083103, -4.48605e-05, -9.86701e-07],
|
[0.9900, -0.00135364, -5.9661e-05, 3.6777e-06],
|
[0.9822, -0.00167442, -4.49547e-06, -5.72411e-06],
|
[0.9730, -0.00214868, -9.03571e-05, 1.8736e-08],
|
[0.9600, -0.00305085, -9.00761e-05, 1.64917e-06],
|
[0.9427, -0.00382792, -6.53386e-05, -2.6154e-06],
|
[0.9216, -0.00467746, -0.00010457, 4.81243e-06],
|
[0.8962, -0.00536223, -3.23831e-05, -5.43432e-06],
|
[0.8679, -0.00609363, -0.000113898, 3.32484e-06],
|
[0.8350, -0.00698325, -6.40253e-05, 9.34959e-07],
|
[0.7986, -0.00755338, -5.00009e-05, 9.35324e-07],
|
[0.7597, -0.00798324, -3.5971e-05, -2.27626e-06],
|
[0.7186, -0.00851367, -7.01149e-05, -8.6303e-06],
|
[0.6732, -0.00986209, -0.000199569, 1.91974e-05],
|
[0.6213, -0.010418, 8.83923e-05, 6.24051e-06],
|
[0.5722, -0.00906601, 0.000182, 6.24051e-06],
|
[0.5322, -0.00677797, 0.000275608, 6.24051e-06]
|
];
|
|
var COEFS_Y = [
|
[-5.20417e-18, 0.0124, 1.21431e-18, -8.45284e-11],
|
[0.0620, 0.0124, -1.26793e-09, 4.22642e-10],
|
[0.1240, 0.0124, 5.07171e-09, -1.60604e-09],
|
[0.1860, 0.0123999, -1.90189e-08, 6.00152e-09],
|
[0.2480, 0.0124002, 7.10039e-08, -2.24e-08],
|
[0.3100, 0.0123992, -2.64997e-07, 8.35986e-08],
|
[0.3720, 0.0124029, 9.88983e-07, -3.11994e-07],
|
[0.4340, 0.0123893, -3.69093e-06, -4.35621e-07],
|
[0.4958, 0.0123198, -1.02252e-05, -3.45523e-07],
|
[0.5571, 0.0121916, -1.54081e-05, -5.82288e-07],
|
[0.6176, 0.0119938, -2.41424e-05, -5.25327e-07],
|
[0.6769, 0.011713, -3.20223e-05, -5.16405e-07],
|
[0.7346, 0.0113541, -3.97684e-05, -6.09052e-07],
|
[0.7903, 0.0109107, -4.89042e-05, -1.04739e-06],
|
[0.8435, 0.0103431, -6.4615e-05, -1.40374e-09],
|
[0.8936, 0.00969686, -6.4636e-05, -8.547e-06],
|
[0.9394, 0.00840947, -0.000192841, -4.2106e-06],
|
[0.9761, 0.00616527, -0.000256, -4.2106e-06],
|
[1.0000, 0.00328947, -0.000319159, -4.2106e-06]
|
];
|
|
var FXC = 0.8487;
|
var FYC = 1.3523;
|
var C1 = R2D/5; // rad to 5-degree interval
|
var RC1 = 1/C1;
|
var NODES = 18;
|
|
var poly3_val = function(coefs, x) {
|
return coefs[0] + x * (coefs[1] + x * (coefs[2] + x * coefs[3]));
|
};
|
|
var poly3_der = function(coefs, x) {
|
return coefs[1] + x * (2 * coefs[2] + x * 3 * coefs[3]);
|
};
|
|
function newton_rapshon(f_df, start, max_err, iters) {
|
var x = start;
|
for (; iters; --iters) {
|
var upd = f_df(x);
|
x -= upd;
|
if (Math.abs(upd) < max_err) {
|
break;
|
}
|
}
|
return x;
|
}
|
|
function init$28() {
|
this.x0 = this.x0 || 0;
|
this.y0 = this.y0 || 0;
|
this.long0 = this.long0 || 0;
|
this.es = 0;
|
this.title = this.title || "Robinson";
|
}
|
|
function forward$27(ll) {
|
var lon = adjust_lon(ll.x - this.long0);
|
|
var dphi = Math.abs(ll.y);
|
var i = Math.floor(dphi * C1);
|
if (i < 0) {
|
i = 0;
|
} else if (i >= NODES) {
|
i = NODES - 1;
|
}
|
dphi = R2D * (dphi - RC1 * i);
|
var xy = {
|
x: poly3_val(COEFS_X[i], dphi) * lon,
|
y: poly3_val(COEFS_Y[i], dphi)
|
};
|
if (ll.y < 0) {
|
xy.y = -xy.y;
|
}
|
|
xy.x = xy.x * this.a * FXC + this.x0;
|
xy.y = xy.y * this.a * FYC + this.y0;
|
return xy;
|
}
|
|
function inverse$27(xy) {
|
var ll = {
|
x: (xy.x - this.x0) / (this.a * FXC),
|
y: Math.abs(xy.y - this.y0) / (this.a * FYC)
|
};
|
|
if (ll.y >= 1) { // pathologic case
|
ll.x /= COEFS_X[NODES][0];
|
ll.y = xy.y < 0 ? -HALF_PI : HALF_PI;
|
} else {
|
// find table interval
|
var i = Math.floor(ll.y * NODES);
|
if (i < 0) {
|
i = 0;
|
} else if (i >= NODES) {
|
i = NODES - 1;
|
}
|
for (;;) {
|
if (COEFS_Y[i][0] > ll.y) {
|
--i;
|
} else if (COEFS_Y[i+1][0] <= ll.y) {
|
++i;
|
} else {
|
break;
|
}
|
}
|
// linear interpolation in 5 degree interval
|
var coefs = COEFS_Y[i];
|
var t = 5 * (ll.y - coefs[0]) / (COEFS_Y[i+1][0] - coefs[0]);
|
// find t so that poly3_val(coefs, t) = ll.y
|
t = newton_rapshon(function(x) {
|
return (poly3_val(coefs, x) - ll.y) / poly3_der(coefs, x);
|
}, t, EPSLN, 100);
|
|
ll.x /= poly3_val(COEFS_X[i], t);
|
ll.y = (5 * i + t) * D2R;
|
if (xy.y < 0) {
|
ll.y = -ll.y;
|
}
|
}
|
|
ll.x = adjust_lon(ll.x + this.long0);
|
return ll;
|
}
|
|
var names$29 = ["Robinson", "robin"];
|
var robin = {
|
init: init$28,
|
forward: forward$27,
|
inverse: inverse$27,
|
names: names$29
|
};
|
|
function init$29() {
|
this.name = 'geocent';
|
|
}
|
|
function forward$28(p) {
|
var point = geodeticToGeocentric(p, this.es, this.a);
|
return point;
|
}
|
|
function inverse$28(p) {
|
var point = geocentricToGeodetic(p, this.es, this.a, this.b);
|
return point;
|
}
|
|
var names$30 = ["Geocentric", 'geocentric', "geocent", "Geocent"];
|
var geocent = {
|
init: init$29,
|
forward: forward$28,
|
inverse: inverse$28,
|
names: names$30
|
};
|
|
var includedProjections = function(proj4){
|
proj4.Proj.projections.add(tmerc);
|
proj4.Proj.projections.add(etmerc);
|
proj4.Proj.projections.add(utm);
|
proj4.Proj.projections.add(sterea);
|
proj4.Proj.projections.add(stere);
|
proj4.Proj.projections.add(somerc);
|
proj4.Proj.projections.add(omerc);
|
proj4.Proj.projections.add(lcc);
|
proj4.Proj.projections.add(krovak);
|
proj4.Proj.projections.add(cass);
|
proj4.Proj.projections.add(laea);
|
proj4.Proj.projections.add(aea);
|
proj4.Proj.projections.add(gnom);
|
proj4.Proj.projections.add(cea);
|
proj4.Proj.projections.add(eqc);
|
proj4.Proj.projections.add(poly);
|
proj4.Proj.projections.add(nzmg);
|
proj4.Proj.projections.add(mill);
|
proj4.Proj.projections.add(sinu);
|
proj4.Proj.projections.add(moll);
|
proj4.Proj.projections.add(eqdc);
|
proj4.Proj.projections.add(vandg);
|
proj4.Proj.projections.add(aeqd);
|
proj4.Proj.projections.add(ortho);
|
proj4.Proj.projections.add(qsc);
|
proj4.Proj.projections.add(robin);
|
proj4.Proj.projections.add(geocent);
|
};
|
|
proj4$1.defaultDatum = 'WGS84'; //default datum
|
proj4$1.Proj = Projection;
|
proj4$1.WGS84 = new proj4$1.Proj('WGS84');
|
proj4$1.Point = Point;
|
proj4$1.toPoint = toPoint;
|
proj4$1.defs = defs;
|
proj4$1.transform = transform;
|
proj4$1.mgrs = mgrs;
|
proj4$1.version = '2.6.0';
|
includedProjections(proj4$1);
|
|
return proj4$1;
|
|
})));
|
|
},{}],83:[function(require,module,exports){
|
(function (global, factory) {
|
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
|
typeof define === 'function' && define.amd ? define(factory) :
|
(global.quickselect = factory());
|
}(this, (function () { 'use strict';
|
|
function quickselect(arr, k, left, right, compare) {
|
quickselectStep(arr, k, left || 0, right || (arr.length - 1), compare || defaultCompare);
|
}
|
|
function quickselectStep(arr, k, left, right, compare) {
|
|
while (right > left) {
|
if (right - left > 600) {
|
var n = right - left + 1;
|
var m = k - left + 1;
|
var z = Math.log(n);
|
var s = 0.5 * Math.exp(2 * z / 3);
|
var sd = 0.5 * Math.sqrt(z * s * (n - s) / n) * (m - n / 2 < 0 ? -1 : 1);
|
var newLeft = Math.max(left, Math.floor(k - m * s / n + sd));
|
var newRight = Math.min(right, Math.floor(k + (n - m) * s / n + sd));
|
quickselectStep(arr, k, newLeft, newRight, compare);
|
}
|
|
var t = arr[k];
|
var i = left;
|
var j = right;
|
|
swap(arr, left, k);
|
if (compare(arr[right], t) > 0) swap(arr, left, right);
|
|
while (i < j) {
|
swap(arr, i, j);
|
i++;
|
j--;
|
while (compare(arr[i], t) < 0) i++;
|
while (compare(arr[j], t) > 0) j--;
|
}
|
|
if (compare(arr[left], t) === 0) swap(arr, left, j);
|
else {
|
j++;
|
swap(arr, j, right);
|
}
|
|
if (j <= k) left = j + 1;
|
if (k <= j) right = j - 1;
|
}
|
}
|
|
function swap(arr, i, j) {
|
var tmp = arr[i];
|
arr[i] = arr[j];
|
arr[j] = tmp;
|
}
|
|
function defaultCompare(a, b) {
|
return a < b ? -1 : a > b ? 1 : 0;
|
}
|
|
return quickselect;
|
|
})));
|
|
},{}],84:[function(require,module,exports){
|
'use strict';
|
|
module.exports = rbush;
|
module.exports.default = rbush;
|
|
var quickselect = require('quickselect');
|
|
function rbush(maxEntries, format) {
|
if (!(this instanceof rbush)) return new rbush(maxEntries, format);
|
|
// max entries in a node is 9 by default; min node fill is 40% for best performance
|
this._maxEntries = Math.max(4, maxEntries || 9);
|
this._minEntries = Math.max(2, Math.ceil(this._maxEntries * 0.4));
|
|
if (format) {
|
this._initFormat(format);
|
}
|
|
this.clear();
|
}
|
|
rbush.prototype = {
|
|
all: function () {
|
return this._all(this.data, []);
|
},
|
|
search: function (bbox) {
|
|
var node = this.data,
|
result = [],
|
toBBox = this.toBBox;
|
|
if (!intersects(bbox, node)) return result;
|
|
var nodesToSearch = [],
|
i, len, child, childBBox;
|
|
while (node) {
|
for (i = 0, len = node.children.length; i < len; i++) {
|
|
child = node.children[i];
|
childBBox = node.leaf ? toBBox(child) : child;
|
|
if (intersects(bbox, childBBox)) {
|
if (node.leaf) result.push(child);
|
else if (contains(bbox, childBBox)) this._all(child, result);
|
else nodesToSearch.push(child);
|
}
|
}
|
node = nodesToSearch.pop();
|
}
|
|
return result;
|
},
|
|
collides: function (bbox) {
|
|
var node = this.data,
|
toBBox = this.toBBox;
|
|
if (!intersects(bbox, node)) return false;
|
|
var nodesToSearch = [],
|
i, len, child, childBBox;
|
|
while (node) {
|
for (i = 0, len = node.children.length; i < len; i++) {
|
|
child = node.children[i];
|
childBBox = node.leaf ? toBBox(child) : child;
|
|
if (intersects(bbox, childBBox)) {
|
if (node.leaf || contains(bbox, childBBox)) return true;
|
nodesToSearch.push(child);
|
}
|
}
|
node = nodesToSearch.pop();
|
}
|
|
return false;
|
},
|
|
load: function (data) {
|
if (!(data && data.length)) return this;
|
|
if (data.length < this._minEntries) {
|
for (var i = 0, len = data.length; i < len; i++) {
|
this.insert(data[i]);
|
}
|
return this;
|
}
|
|
// recursively build the tree with the given data from scratch using OMT algorithm
|
var node = this._build(data.slice(), 0, data.length - 1, 0);
|
|
if (!this.data.children.length) {
|
// save as is if tree is empty
|
this.data = node;
|
|
} else if (this.data.height === node.height) {
|
// split root if trees have the same height
|
this._splitRoot(this.data, node);
|
|
} else {
|
if (this.data.height < node.height) {
|
// swap trees if inserted one is bigger
|
var tmpNode = this.data;
|
this.data = node;
|
node = tmpNode;
|
}
|
|
// insert the small tree into the large tree at appropriate level
|
this._insert(node, this.data.height - node.height - 1, true);
|
}
|
|
return this;
|
},
|
|
insert: function (item) {
|
if (item) this._insert(item, this.data.height - 1);
|
return this;
|
},
|
|
clear: function () {
|
this.data = createNode([]);
|
return this;
|
},
|
|
remove: function (item, equalsFn) {
|
if (!item) return this;
|
|
var node = this.data,
|
bbox = this.toBBox(item),
|
path = [],
|
indexes = [],
|
i, parent, index, goingUp;
|
|
// depth-first iterative tree traversal
|
while (node || path.length) {
|
|
if (!node) { // go up
|
node = path.pop();
|
parent = path[path.length - 1];
|
i = indexes.pop();
|
goingUp = true;
|
}
|
|
if (node.leaf) { // check current node
|
index = findItem(item, node.children, equalsFn);
|
|
if (index !== -1) {
|
// item found, remove the item and condense tree upwards
|
node.children.splice(index, 1);
|
path.push(node);
|
this._condense(path);
|
return this;
|
}
|
}
|
|
if (!goingUp && !node.leaf && contains(node, bbox)) { // go down
|
path.push(node);
|
indexes.push(i);
|
i = 0;
|
parent = node;
|
node = node.children[0];
|
|
} else if (parent) { // go right
|
i++;
|
node = parent.children[i];
|
goingUp = false;
|
|
} else node = null; // nothing found
|
}
|
|
return this;
|
},
|
|
toBBox: function (item) { return item; },
|
|
compareMinX: compareNodeMinX,
|
compareMinY: compareNodeMinY,
|
|
toJSON: function () { return this.data; },
|
|
fromJSON: function (data) {
|
this.data = data;
|
return this;
|
},
|
|
_all: function (node, result) {
|
var nodesToSearch = [];
|
while (node) {
|
if (node.leaf) result.push.apply(result, node.children);
|
else nodesToSearch.push.apply(nodesToSearch, node.children);
|
|
node = nodesToSearch.pop();
|
}
|
return result;
|
},
|
|
_build: function (items, left, right, height) {
|
|
var N = right - left + 1,
|
M = this._maxEntries,
|
node;
|
|
if (N <= M) {
|
// reached leaf level; return leaf
|
node = createNode(items.slice(left, right + 1));
|
calcBBox(node, this.toBBox);
|
return node;
|
}
|
|
if (!height) {
|
// target height of the bulk-loaded tree
|
height = Math.ceil(Math.log(N) / Math.log(M));
|
|
// target number of root entries to maximize storage utilization
|
M = Math.ceil(N / Math.pow(M, height - 1));
|
}
|
|
node = createNode([]);
|
node.leaf = false;
|
node.height = height;
|
|
// split the items into M mostly square tiles
|
|
var N2 = Math.ceil(N / M),
|
N1 = N2 * Math.ceil(Math.sqrt(M)),
|
i, j, right2, right3;
|
|
multiSelect(items, left, right, N1, this.compareMinX);
|
|
for (i = left; i <= right; i += N1) {
|
|
right2 = Math.min(i + N1 - 1, right);
|
|
multiSelect(items, i, right2, N2, this.compareMinY);
|
|
for (j = i; j <= right2; j += N2) {
|
|
right3 = Math.min(j + N2 - 1, right2);
|
|
// pack each entry recursively
|
node.children.push(this._build(items, j, right3, height - 1));
|
}
|
}
|
|
calcBBox(node, this.toBBox);
|
|
return node;
|
},
|
|
_chooseSubtree: function (bbox, node, level, path) {
|
|
var i, len, child, targetNode, area, enlargement, minArea, minEnlargement;
|
|
while (true) {
|
path.push(node);
|
|
if (node.leaf || path.length - 1 === level) break;
|
|
minArea = minEnlargement = Infinity;
|
|
for (i = 0, len = node.children.length; i < len; i++) {
|
child = node.children[i];
|
area = bboxArea(child);
|
enlargement = enlargedArea(bbox, child) - area;
|
|
// choose entry with the least area enlargement
|
if (enlargement < minEnlargement) {
|
minEnlargement = enlargement;
|
minArea = area < minArea ? area : minArea;
|
targetNode = child;
|
|
} else if (enlargement === minEnlargement) {
|
// otherwise choose one with the smallest area
|
if (area < minArea) {
|
minArea = area;
|
targetNode = child;
|
}
|
}
|
}
|
|
node = targetNode || node.children[0];
|
}
|
|
return node;
|
},
|
|
_insert: function (item, level, isNode) {
|
|
var toBBox = this.toBBox,
|
bbox = isNode ? item : toBBox(item),
|
insertPath = [];
|
|
// find the best node for accommodating the item, saving all nodes along the path too
|
var node = this._chooseSubtree(bbox, this.data, level, insertPath);
|
|
// put the item into the node
|
node.children.push(item);
|
extend(node, bbox);
|
|
// split on node overflow; propagate upwards if necessary
|
while (level >= 0) {
|
if (insertPath[level].children.length > this._maxEntries) {
|
this._split(insertPath, level);
|
level--;
|
} else break;
|
}
|
|
// adjust bboxes along the insertion path
|
this._adjustParentBBoxes(bbox, insertPath, level);
|
},
|
|
// split overflowed node into two
|
_split: function (insertPath, level) {
|
|
var node = insertPath[level],
|
M = node.children.length,
|
m = this._minEntries;
|
|
this._chooseSplitAxis(node, m, M);
|
|
var splitIndex = this._chooseSplitIndex(node, m, M);
|
|
var newNode = createNode(node.children.splice(splitIndex, node.children.length - splitIndex));
|
newNode.height = node.height;
|
newNode.leaf = node.leaf;
|
|
calcBBox(node, this.toBBox);
|
calcBBox(newNode, this.toBBox);
|
|
if (level) insertPath[level - 1].children.push(newNode);
|
else this._splitRoot(node, newNode);
|
},
|
|
_splitRoot: function (node, newNode) {
|
// split root node
|
this.data = createNode([node, newNode]);
|
this.data.height = node.height + 1;
|
this.data.leaf = false;
|
calcBBox(this.data, this.toBBox);
|
},
|
|
_chooseSplitIndex: function (node, m, M) {
|
|
var i, bbox1, bbox2, overlap, area, minOverlap, minArea, index;
|
|
minOverlap = minArea = Infinity;
|
|
for (i = m; i <= M - m; i++) {
|
bbox1 = distBBox(node, 0, i, this.toBBox);
|
bbox2 = distBBox(node, i, M, this.toBBox);
|
|
overlap = intersectionArea(bbox1, bbox2);
|
area = bboxArea(bbox1) + bboxArea(bbox2);
|
|
// choose distribution with minimum overlap
|
if (overlap < minOverlap) {
|
minOverlap = overlap;
|
index = i;
|
|
minArea = area < minArea ? area : minArea;
|
|
} else if (overlap === minOverlap) {
|
// otherwise choose distribution with minimum area
|
if (area < minArea) {
|
minArea = area;
|
index = i;
|
}
|
}
|
}
|
|
return index;
|
},
|
|
// sorts node children by the best axis for split
|
_chooseSplitAxis: function (node, m, M) {
|
|
var compareMinX = node.leaf ? this.compareMinX : compareNodeMinX,
|
compareMinY = node.leaf ? this.compareMinY : compareNodeMinY,
|
xMargin = this._allDistMargin(node, m, M, compareMinX),
|
yMargin = this._allDistMargin(node, m, M, compareMinY);
|
|
// if total distributions margin value is minimal for x, sort by minX,
|
// otherwise it's already sorted by minY
|
if (xMargin < yMargin) node.children.sort(compareMinX);
|
},
|
|
// total margin of all possible split distributions where each node is at least m full
|
_allDistMargin: function (node, m, M, compare) {
|
|
node.children.sort(compare);
|
|
var toBBox = this.toBBox,
|
leftBBox = distBBox(node, 0, m, toBBox),
|
rightBBox = distBBox(node, M - m, M, toBBox),
|
margin = bboxMargin(leftBBox) + bboxMargin(rightBBox),
|
i, child;
|
|
for (i = m; i < M - m; i++) {
|
child = node.children[i];
|
extend(leftBBox, node.leaf ? toBBox(child) : child);
|
margin += bboxMargin(leftBBox);
|
}
|
|
for (i = M - m - 1; i >= m; i--) {
|
child = node.children[i];
|
extend(rightBBox, node.leaf ? toBBox(child) : child);
|
margin += bboxMargin(rightBBox);
|
}
|
|
return margin;
|
},
|
|
_adjustParentBBoxes: function (bbox, path, level) {
|
// adjust bboxes along the given tree path
|
for (var i = level; i >= 0; i--) {
|
extend(path[i], bbox);
|
}
|
},
|
|
_condense: function (path) {
|
// go through the path, removing empty nodes and updating bboxes
|
for (var i = path.length - 1, siblings; i >= 0; i--) {
|
if (path[i].children.length === 0) {
|
if (i > 0) {
|
siblings = path[i - 1].children;
|
siblings.splice(siblings.indexOf(path[i]), 1);
|
|
} else this.clear();
|
|
} else calcBBox(path[i], this.toBBox);
|
}
|
},
|
|
_initFormat: function (format) {
|
// data format (minX, minY, maxX, maxY accessors)
|
|
// uses eval-type function compilation instead of just accepting a toBBox function
|
// because the algorithms are very sensitive to sorting functions performance,
|
// so they should be dead simple and without inner calls
|
|
var compareArr = ['return a', ' - b', ';'];
|
|
this.compareMinX = new Function('a', 'b', compareArr.join(format[0]));
|
this.compareMinY = new Function('a', 'b', compareArr.join(format[1]));
|
|
this.toBBox = new Function('a',
|
'return {minX: a' + format[0] +
|
', minY: a' + format[1] +
|
', maxX: a' + format[2] +
|
', maxY: a' + format[3] + '};');
|
}
|
};
|
|
function findItem(item, items, equalsFn) {
|
if (!equalsFn) return items.indexOf(item);
|
|
for (var i = 0; i < items.length; i++) {
|
if (equalsFn(item, items[i])) return i;
|
}
|
return -1;
|
}
|
|
// calculate node's bbox from bboxes of its children
|
function calcBBox(node, toBBox) {
|
distBBox(node, 0, node.children.length, toBBox, node);
|
}
|
|
// min bounding rectangle of node children from k to p-1
|
function distBBox(node, k, p, toBBox, destNode) {
|
if (!destNode) destNode = createNode(null);
|
destNode.minX = Infinity;
|
destNode.minY = Infinity;
|
destNode.maxX = -Infinity;
|
destNode.maxY = -Infinity;
|
|
for (var i = k, child; i < p; i++) {
|
child = node.children[i];
|
extend(destNode, node.leaf ? toBBox(child) : child);
|
}
|
|
return destNode;
|
}
|
|
function extend(a, b) {
|
a.minX = Math.min(a.minX, b.minX);
|
a.minY = Math.min(a.minY, b.minY);
|
a.maxX = Math.max(a.maxX, b.maxX);
|
a.maxY = Math.max(a.maxY, b.maxY);
|
return a;
|
}
|
|
function compareNodeMinX(a, b) { return a.minX - b.minX; }
|
function compareNodeMinY(a, b) { return a.minY - b.minY; }
|
|
function bboxArea(a) { return (a.maxX - a.minX) * (a.maxY - a.minY); }
|
function bboxMargin(a) { return (a.maxX - a.minX) + (a.maxY - a.minY); }
|
|
function enlargedArea(a, b) {
|
return (Math.max(b.maxX, a.maxX) - Math.min(b.minX, a.minX)) *
|
(Math.max(b.maxY, a.maxY) - Math.min(b.minY, a.minY));
|
}
|
|
function intersectionArea(a, b) {
|
var minX = Math.max(a.minX, b.minX),
|
minY = Math.max(a.minY, b.minY),
|
maxX = Math.min(a.maxX, b.maxX),
|
maxY = Math.min(a.maxY, b.maxY);
|
|
return Math.max(0, maxX - minX) *
|
Math.max(0, maxY - minY);
|
}
|
|
function contains(a, b) {
|
return a.minX <= b.minX &&
|
a.minY <= b.minY &&
|
b.maxX <= a.maxX &&
|
b.maxY <= a.maxY;
|
}
|
|
function intersects(a, b) {
|
return b.minX <= a.maxX &&
|
b.minY <= a.maxY &&
|
b.maxX >= a.minX &&
|
b.maxY >= a.minY;
|
}
|
|
function createNode(children) {
|
return {
|
children: children,
|
height: 1,
|
leaf: true,
|
minX: Infinity,
|
minY: Infinity,
|
maxX: -Infinity,
|
maxY: -Infinity
|
};
|
}
|
|
// sort an array so that items come in groups of n unsorted items, with groups sorted between each other;
|
// combines selection algorithm with binary divide & conquer approach
|
|
function multiSelect(arr, left, right, n, compare) {
|
var stack = [left, right],
|
mid;
|
|
while (stack.length) {
|
right = stack.pop();
|
left = stack.pop();
|
|
if (right - left <= n) continue;
|
|
mid = left + Math.ceil((right - left) / n / 2) * n;
|
quickselect(arr, mid, left, right, compare);
|
|
stack.push(left, mid, mid, right);
|
}
|
}
|
|
},{"quickselect":83}],85:[function(require,module,exports){
|
"use strict"
|
|
var twoProduct = require("two-product")
|
var robustSum = require("robust-sum")
|
var robustScale = require("robust-scale")
|
var robustSubtract = require("robust-subtract")
|
|
var NUM_EXPAND = 5
|
|
var EPSILON = 1.1102230246251565e-16
|
var ERRBOUND3 = (3.0 + 16.0 * EPSILON) * EPSILON
|
var ERRBOUND4 = (7.0 + 56.0 * EPSILON) * EPSILON
|
|
function cofactor(m, c) {
|
var result = new Array(m.length-1)
|
for(var i=1; i<m.length; ++i) {
|
var r = result[i-1] = new Array(m.length-1)
|
for(var j=0,k=0; j<m.length; ++j) {
|
if(j === c) {
|
continue
|
}
|
r[k++] = m[i][j]
|
}
|
}
|
return result
|
}
|
|
function matrix(n) {
|
var result = new Array(n)
|
for(var i=0; i<n; ++i) {
|
result[i] = new Array(n)
|
for(var j=0; j<n; ++j) {
|
result[i][j] = ["m", j, "[", (n-i-1), "]"].join("")
|
}
|
}
|
return result
|
}
|
|
function sign(n) {
|
if(n & 1) {
|
return "-"
|
}
|
return ""
|
}
|
|
function generateSum(expr) {
|
if(expr.length === 1) {
|
return expr[0]
|
} else if(expr.length === 2) {
|
return ["sum(", expr[0], ",", expr[1], ")"].join("")
|
} else {
|
var m = expr.length>>1
|
return ["sum(", generateSum(expr.slice(0, m)), ",", generateSum(expr.slice(m)), ")"].join("")
|
}
|
}
|
|
function determinant(m) {
|
if(m.length === 2) {
|
return [["sum(prod(", m[0][0], ",", m[1][1], "),prod(-", m[0][1], ",", m[1][0], "))"].join("")]
|
} else {
|
var expr = []
|
for(var i=0; i<m.length; ++i) {
|
expr.push(["scale(", generateSum(determinant(cofactor(m, i))), ",", sign(i), m[0][i], ")"].join(""))
|
}
|
return expr
|
}
|
}
|
|
function orientation(n) {
|
var pos = []
|
var neg = []
|
var m = matrix(n)
|
var args = []
|
for(var i=0; i<n; ++i) {
|
if((i&1)===0) {
|
pos.push.apply(pos, determinant(cofactor(m, i)))
|
} else {
|
neg.push.apply(neg, determinant(cofactor(m, i)))
|
}
|
args.push("m" + i)
|
}
|
var posExpr = generateSum(pos)
|
var negExpr = generateSum(neg)
|
var funcName = "orientation" + n + "Exact"
|
var code = ["function ", funcName, "(", args.join(), "){var p=", posExpr, ",n=", negExpr, ",d=sub(p,n);\
|
return d[d.length-1];};return ", funcName].join("")
|
var proc = new Function("sum", "prod", "scale", "sub", code)
|
return proc(robustSum, twoProduct, robustScale, robustSubtract)
|
}
|
|
var orientation3Exact = orientation(3)
|
var orientation4Exact = orientation(4)
|
|
var CACHED = [
|
function orientation0() { return 0 },
|
function orientation1() { return 0 },
|
function orientation2(a, b) {
|
return b[0] - a[0]
|
},
|
function orientation3(a, b, c) {
|
var l = (a[1] - c[1]) * (b[0] - c[0])
|
var r = (a[0] - c[0]) * (b[1] - c[1])
|
var det = l - r
|
var s
|
if(l > 0) {
|
if(r <= 0) {
|
return det
|
} else {
|
s = l + r
|
}
|
} else if(l < 0) {
|
if(r >= 0) {
|
return det
|
} else {
|
s = -(l + r)
|
}
|
} else {
|
return det
|
}
|
var tol = ERRBOUND3 * s
|
if(det >= tol || det <= -tol) {
|
return det
|
}
|
return orientation3Exact(a, b, c)
|
},
|
function orientation4(a,b,c,d) {
|
var adx = a[0] - d[0]
|
var bdx = b[0] - d[0]
|
var cdx = c[0] - d[0]
|
var ady = a[1] - d[1]
|
var bdy = b[1] - d[1]
|
var cdy = c[1] - d[1]
|
var adz = a[2] - d[2]
|
var bdz = b[2] - d[2]
|
var cdz = c[2] - d[2]
|
var bdxcdy = bdx * cdy
|
var cdxbdy = cdx * bdy
|
var cdxady = cdx * ady
|
var adxcdy = adx * cdy
|
var adxbdy = adx * bdy
|
var bdxady = bdx * ady
|
var det = adz * (bdxcdy - cdxbdy)
|
+ bdz * (cdxady - adxcdy)
|
+ cdz * (adxbdy - bdxady)
|
var permanent = (Math.abs(bdxcdy) + Math.abs(cdxbdy)) * Math.abs(adz)
|
+ (Math.abs(cdxady) + Math.abs(adxcdy)) * Math.abs(bdz)
|
+ (Math.abs(adxbdy) + Math.abs(bdxady)) * Math.abs(cdz)
|
var tol = ERRBOUND4 * permanent
|
if ((det > tol) || (-det > tol)) {
|
return det
|
}
|
return orientation4Exact(a,b,c,d)
|
}
|
]
|
|
function slowOrient(args) {
|
var proc = CACHED[args.length]
|
if(!proc) {
|
proc = CACHED[args.length] = orientation(args.length)
|
}
|
return proc.apply(undefined, args)
|
}
|
|
function generateOrientationProc() {
|
while(CACHED.length <= NUM_EXPAND) {
|
CACHED.push(orientation(CACHED.length))
|
}
|
var args = []
|
var procArgs = ["slow"]
|
for(var i=0; i<=NUM_EXPAND; ++i) {
|
args.push("a" + i)
|
procArgs.push("o" + i)
|
}
|
var code = [
|
"function getOrientation(", args.join(), "){switch(arguments.length){case 0:case 1:return 0;"
|
]
|
for(var i=2; i<=NUM_EXPAND; ++i) {
|
code.push("case ", i, ":return o", i, "(", args.slice(0, i).join(), ");")
|
}
|
code.push("}var s=new Array(arguments.length);for(var i=0;i<arguments.length;++i){s[i]=arguments[i]};return slow(s);}return getOrientation")
|
procArgs.push(code.join(""))
|
|
var proc = Function.apply(undefined, procArgs)
|
module.exports = proc.apply(undefined, [slowOrient].concat(CACHED))
|
for(var i=0; i<=NUM_EXPAND; ++i) {
|
module.exports[i] = CACHED[i]
|
}
|
}
|
|
generateOrientationProc()
|
},{"robust-scale":86,"robust-subtract":87,"robust-sum":88,"two-product":98}],86:[function(require,module,exports){
|
"use strict"
|
|
var twoProduct = require("two-product")
|
var twoSum = require("two-sum")
|
|
module.exports = scaleLinearExpansion
|
|
function scaleLinearExpansion(e, scale) {
|
var n = e.length
|
if(n === 1) {
|
var ts = twoProduct(e[0], scale)
|
if(ts[0]) {
|
return ts
|
}
|
return [ ts[1] ]
|
}
|
var g = new Array(2 * n)
|
var q = [0.1, 0.1]
|
var t = [0.1, 0.1]
|
var count = 0
|
twoProduct(e[0], scale, q)
|
if(q[0]) {
|
g[count++] = q[0]
|
}
|
for(var i=1; i<n; ++i) {
|
twoProduct(e[i], scale, t)
|
var pq = q[1]
|
twoSum(pq, t[0], q)
|
if(q[0]) {
|
g[count++] = q[0]
|
}
|
var a = t[1]
|
var b = q[1]
|
var x = a + b
|
var bv = x - a
|
var y = b - bv
|
q[1] = x
|
if(y) {
|
g[count++] = y
|
}
|
}
|
if(q[1]) {
|
g[count++] = q[1]
|
}
|
if(count === 0) {
|
g[count++] = 0.0
|
}
|
g.length = count
|
return g
|
}
|
},{"two-product":98,"two-sum":99}],87:[function(require,module,exports){
|
"use strict"
|
|
module.exports = robustSubtract
|
|
//Easy case: Add two scalars
|
function scalarScalar(a, b) {
|
var x = a + b
|
var bv = x - a
|
var av = x - bv
|
var br = b - bv
|
var ar = a - av
|
var y = ar + br
|
if(y) {
|
return [y, x]
|
}
|
return [x]
|
}
|
|
function robustSubtract(e, f) {
|
var ne = e.length|0
|
var nf = f.length|0
|
if(ne === 1 && nf === 1) {
|
return scalarScalar(e[0], -f[0])
|
}
|
var n = ne + nf
|
var g = new Array(n)
|
var count = 0
|
var eptr = 0
|
var fptr = 0
|
var abs = Math.abs
|
var ei = e[eptr]
|
var ea = abs(ei)
|
var fi = -f[fptr]
|
var fa = abs(fi)
|
var a, b
|
if(ea < fa) {
|
b = ei
|
eptr += 1
|
if(eptr < ne) {
|
ei = e[eptr]
|
ea = abs(ei)
|
}
|
} else {
|
b = fi
|
fptr += 1
|
if(fptr < nf) {
|
fi = -f[fptr]
|
fa = abs(fi)
|
}
|
}
|
if((eptr < ne && ea < fa) || (fptr >= nf)) {
|
a = ei
|
eptr += 1
|
if(eptr < ne) {
|
ei = e[eptr]
|
ea = abs(ei)
|
}
|
} else {
|
a = fi
|
fptr += 1
|
if(fptr < nf) {
|
fi = -f[fptr]
|
fa = abs(fi)
|
}
|
}
|
var x = a + b
|
var bv = x - a
|
var y = b - bv
|
var q0 = y
|
var q1 = x
|
var _x, _bv, _av, _br, _ar
|
while(eptr < ne && fptr < nf) {
|
if(ea < fa) {
|
a = ei
|
eptr += 1
|
if(eptr < ne) {
|
ei = e[eptr]
|
ea = abs(ei)
|
}
|
} else {
|
a = fi
|
fptr += 1
|
if(fptr < nf) {
|
fi = -f[fptr]
|
fa = abs(fi)
|
}
|
}
|
b = q0
|
x = a + b
|
bv = x - a
|
y = b - bv
|
if(y) {
|
g[count++] = y
|
}
|
_x = q1 + x
|
_bv = _x - q1
|
_av = _x - _bv
|
_br = x - _bv
|
_ar = q1 - _av
|
q0 = _ar + _br
|
q1 = _x
|
}
|
while(eptr < ne) {
|
a = ei
|
b = q0
|
x = a + b
|
bv = x - a
|
y = b - bv
|
if(y) {
|
g[count++] = y
|
}
|
_x = q1 + x
|
_bv = _x - q1
|
_av = _x - _bv
|
_br = x - _bv
|
_ar = q1 - _av
|
q0 = _ar + _br
|
q1 = _x
|
eptr += 1
|
if(eptr < ne) {
|
ei = e[eptr]
|
}
|
}
|
while(fptr < nf) {
|
a = fi
|
b = q0
|
x = a + b
|
bv = x - a
|
y = b - bv
|
if(y) {
|
g[count++] = y
|
}
|
_x = q1 + x
|
_bv = _x - q1
|
_av = _x - _bv
|
_br = x - _bv
|
_ar = q1 - _av
|
q0 = _ar + _br
|
q1 = _x
|
fptr += 1
|
if(fptr < nf) {
|
fi = -f[fptr]
|
}
|
}
|
if(q0) {
|
g[count++] = q0
|
}
|
if(q1) {
|
g[count++] = q1
|
}
|
if(!count) {
|
g[count++] = 0.0
|
}
|
g.length = count
|
return g
|
}
|
},{}],88:[function(require,module,exports){
|
"use strict"
|
|
module.exports = linearExpansionSum
|
|
//Easy case: Add two scalars
|
function scalarScalar(a, b) {
|
var x = a + b
|
var bv = x - a
|
var av = x - bv
|
var br = b - bv
|
var ar = a - av
|
var y = ar + br
|
if(y) {
|
return [y, x]
|
}
|
return [x]
|
}
|
|
function linearExpansionSum(e, f) {
|
var ne = e.length|0
|
var nf = f.length|0
|
if(ne === 1 && nf === 1) {
|
return scalarScalar(e[0], f[0])
|
}
|
var n = ne + nf
|
var g = new Array(n)
|
var count = 0
|
var eptr = 0
|
var fptr = 0
|
var abs = Math.abs
|
var ei = e[eptr]
|
var ea = abs(ei)
|
var fi = f[fptr]
|
var fa = abs(fi)
|
var a, b
|
if(ea < fa) {
|
b = ei
|
eptr += 1
|
if(eptr < ne) {
|
ei = e[eptr]
|
ea = abs(ei)
|
}
|
} else {
|
b = fi
|
fptr += 1
|
if(fptr < nf) {
|
fi = f[fptr]
|
fa = abs(fi)
|
}
|
}
|
if((eptr < ne && ea < fa) || (fptr >= nf)) {
|
a = ei
|
eptr += 1
|
if(eptr < ne) {
|
ei = e[eptr]
|
ea = abs(ei)
|
}
|
} else {
|
a = fi
|
fptr += 1
|
if(fptr < nf) {
|
fi = f[fptr]
|
fa = abs(fi)
|
}
|
}
|
var x = a + b
|
var bv = x - a
|
var y = b - bv
|
var q0 = y
|
var q1 = x
|
var _x, _bv, _av, _br, _ar
|
while(eptr < ne && fptr < nf) {
|
if(ea < fa) {
|
a = ei
|
eptr += 1
|
if(eptr < ne) {
|
ei = e[eptr]
|
ea = abs(ei)
|
}
|
} else {
|
a = fi
|
fptr += 1
|
if(fptr < nf) {
|
fi = f[fptr]
|
fa = abs(fi)
|
}
|
}
|
b = q0
|
x = a + b
|
bv = x - a
|
y = b - bv
|
if(y) {
|
g[count++] = y
|
}
|
_x = q1 + x
|
_bv = _x - q1
|
_av = _x - _bv
|
_br = x - _bv
|
_ar = q1 - _av
|
q0 = _ar + _br
|
q1 = _x
|
}
|
while(eptr < ne) {
|
a = ei
|
b = q0
|
x = a + b
|
bv = x - a
|
y = b - bv
|
if(y) {
|
g[count++] = y
|
}
|
_x = q1 + x
|
_bv = _x - q1
|
_av = _x - _bv
|
_br = x - _bv
|
_ar = q1 - _av
|
q0 = _ar + _br
|
q1 = _x
|
eptr += 1
|
if(eptr < ne) {
|
ei = e[eptr]
|
}
|
}
|
while(fptr < nf) {
|
a = fi
|
b = q0
|
x = a + b
|
bv = x - a
|
y = b - bv
|
if(y) {
|
g[count++] = y
|
}
|
_x = q1 + x
|
_bv = _x - q1
|
_av = _x - _bv
|
_br = x - _bv
|
_ar = q1 - _av
|
q0 = _ar + _br
|
q1 = _x
|
fptr += 1
|
if(fptr < nf) {
|
fi = f[fptr]
|
}
|
}
|
if(q0) {
|
g[count++] = q0
|
}
|
if(q1) {
|
g[count++] = q1
|
}
|
if(!count) {
|
g[count++] = 0.0
|
}
|
g.length = count
|
return g
|
}
|
},{}],89:[function(require,module,exports){
|
/* eslint-disable node/no-deprecated-api */
|
var buffer = require('buffer')
|
var Buffer = buffer.Buffer
|
|
// alternative to using Object.keys for old browsers
|
function copyProps (src, dst) {
|
for (var key in src) {
|
dst[key] = src[key]
|
}
|
}
|
if (Buffer.from && Buffer.alloc && Buffer.allocUnsafe && Buffer.allocUnsafeSlow) {
|
module.exports = buffer
|
} else {
|
// Copy properties from require('buffer')
|
copyProps(buffer, exports)
|
exports.Buffer = SafeBuffer
|
}
|
|
function SafeBuffer (arg, encodingOrOffset, length) {
|
return Buffer(arg, encodingOrOffset, length)
|
}
|
|
SafeBuffer.prototype = Object.create(Buffer.prototype)
|
|
// Copy static methods from Buffer
|
copyProps(Buffer, SafeBuffer)
|
|
SafeBuffer.from = function (arg, encodingOrOffset, length) {
|
if (typeof arg === 'number') {
|
throw new TypeError('Argument must not be a number')
|
}
|
return Buffer(arg, encodingOrOffset, length)
|
}
|
|
SafeBuffer.alloc = function (size, fill, encoding) {
|
if (typeof size !== 'number') {
|
throw new TypeError('Argument must be a number')
|
}
|
var buf = Buffer(size)
|
if (fill !== undefined) {
|
if (typeof encoding === 'string') {
|
buf.fill(fill, encoding)
|
} else {
|
buf.fill(fill)
|
}
|
} else {
|
buf.fill(0)
|
}
|
return buf
|
}
|
|
SafeBuffer.allocUnsafe = function (size) {
|
if (typeof size !== 'number') {
|
throw new TypeError('Argument must be a number')
|
}
|
return Buffer(size)
|
}
|
|
SafeBuffer.allocUnsafeSlow = function (size) {
|
if (typeof size !== 'number') {
|
throw new TypeError('Argument must be a number')
|
}
|
return buffer.SlowBuffer(size)
|
}
|
|
},{"buffer":30}],90:[function(require,module,exports){
|
(function (Buffer){
|
'use strict';
|
var Promise = require('lie');
|
module.exports = binaryAjax;
|
function binaryAjax(url){
|
return new Promise(function(resolve,reject){
|
var type = url.slice(-3);
|
var ajax = new XMLHttpRequest();
|
ajax.open('GET',url,true);
|
if(type !== 'prj' && type !== 'cpg'){
|
ajax.responseType='arraybuffer';
|
}
|
ajax.addEventListener('load', function (){
|
if(ajax.status>399){
|
if(type==='prj' || type === 'cpg'){
|
return resolve(false);
|
}else{
|
return reject(new Error(ajax.status));
|
}
|
}
|
if(type !== 'prj' && type !== 'cpg'){
|
return resolve(new Buffer(ajax.response));
|
} else {
|
return resolve(ajax.response);
|
}
|
}, false);
|
ajax.send();
|
});
|
}
|
|
}).call(this,require("buffer").Buffer)
|
|
},{"buffer":30,"lie":58}],91:[function(require,module,exports){
|
(function (global,Buffer){
|
'use strict';
|
var proj4 = require('proj4');
|
if (proj4.default) {
|
proj4 = proj4.default;
|
}
|
var unzip = require('./unzip');
|
var binaryAjax = require('./binaryajax');
|
var parseShp = require('./parseShp');
|
var parseDbf = require('parsedbf');
|
var Promise = require('lie');
|
var Cache = require('lru-cache');
|
var cache = new Cache({
|
max: 20
|
});
|
|
function toBuffer(b) {
|
if (!b) {
|
throw new Error('forgot to pass buffer');
|
}
|
if (Buffer.isBuffer(b)) {
|
return b;
|
}
|
if (b instanceof global.ArrayBuffer) {
|
return new Buffer(b);
|
}
|
if (b.buffer instanceof global.ArrayBuffer) {
|
if (b.BYTES_PER_ELEMENT === 1) {
|
return new Buffer(b);
|
}
|
return new Buffer(b.buffer);
|
}
|
}
|
|
function shp(base, whiteList) {
|
if (typeof base === 'string' && cache.has(base)) {
|
return Promise.resolve(cache.get(base));
|
}
|
return shp.getShapefile(base, whiteList).then(function(resp) {
|
if (typeof base === 'string') {
|
cache.set(base, resp);
|
}
|
return resp;
|
});
|
}
|
shp.combine = function(arr) {
|
var out = {};
|
out.type = 'FeatureCollection';
|
out.features = [];
|
var i = 0;
|
var len = arr[0].length;
|
while (i < len) {
|
out.features.push({
|
'type': 'Feature',
|
'geometry': arr[0][i],
|
'properties': arr[1][i]
|
});
|
i++;
|
}
|
return out;
|
};
|
shp.parseZip = function(buffer, whiteList) {
|
var key;
|
buffer = toBuffer(buffer);
|
var zip = unzip(buffer);
|
var names = [];
|
whiteList = whiteList || [];
|
for (key in zip) {
|
if (key.indexOf('__MACOSX') !== -1) {
|
continue;
|
}
|
if (key.slice(-3).toLowerCase() === 'shp') {
|
names.push(key.slice(0, -4));
|
zip[key.slice(0, -3) + key.slice(-3).toLowerCase()] = zip[key];
|
} else if (key.slice(-3).toLowerCase() === 'prj') {
|
zip[key.slice(0, -3) + key.slice(-3).toLowerCase()] = proj4(zip[key]);
|
} else if (key.slice(-4).toLowerCase() === 'json' || whiteList.indexOf(key.split('.').pop()) > -1) {
|
names.push(key.slice(0, -3) + key.slice(-3).toLowerCase());
|
} else if (key.slice(-3).toLowerCase() === 'dbf' || key.slice(-3).toLowerCase() === 'cpg') {
|
zip[key.slice(0, -3) + key.slice(-3).toLowerCase()] = zip[key];
|
}
|
}
|
if (!names.length) {
|
throw new Error('no layers founds');
|
}
|
var geojson = names.map(function(name) {
|
var parsed, dbf;
|
var lastDotIdx = name.lastIndexOf('.');
|
if (lastDotIdx > -1 && name.slice(lastDotIdx).indexOf('json') > -1) {
|
parsed = JSON.parse(zip[name]);
|
parsed.fileName = name.slice(0, lastDotIdx);
|
} else if (whiteList.indexOf(name.slice(lastDotIdx + 1)) > -1) {
|
parsed = zip[name];
|
parsed.fileName = name;
|
} else {
|
if (zip[name + '.dbf']) {
|
dbf = parseDbf(zip[name + '.dbf'], zip[name + '.cpg']);
|
}
|
parsed = shp.combine([parseShp(zip[name + '.shp'], zip[name + '.prj']), dbf]);
|
parsed.fileName = name;
|
}
|
return parsed;
|
});
|
if (geojson.length === 1) {
|
return geojson[0];
|
} else {
|
return geojson;
|
}
|
};
|
|
function getZip(base, whiteList) {
|
return binaryAjax(base).then(function(a) {
|
return shp.parseZip(a, whiteList);
|
});
|
}
|
shp.getShapefile = function(base, whiteList) {
|
if (typeof base === 'string') {
|
if (base.slice(-4).toLowerCase() === '.zip') {
|
return getZip(base, whiteList);
|
} else {
|
return Promise.all([
|
Promise.all([
|
binaryAjax(base + '.shp'),
|
binaryAjax(base + '.prj')
|
]).then(function(args) {
|
return parseShp(args[0], args[1] ? proj4(args[1]) : false);
|
}),
|
Promise.all([
|
binaryAjax(base + '.dbf'),
|
binaryAjax(base + '.cpg')
|
]).then(function(args) {
|
return parseDbf(args[0], args[1]);
|
})
|
]).then(shp.combine);
|
}
|
} else {
|
return new Promise(function(resolve) {
|
resolve(shp.parseZip(base));
|
});
|
}
|
};
|
shp.parseShp = function(shp, prj) {
|
shp = toBuffer(shp);
|
if (Buffer.isBuffer(prj)) {
|
prj = prj.toString();
|
}
|
if (typeof prj === 'string') {
|
prj = proj4(prj);
|
return parseShp(shp, prj);
|
} else {
|
return parseShp(shp);
|
}
|
};
|
shp.parseDbf = function(dbf, cpg) {
|
dbf = toBuffer(dbf);
|
return parseDbf(dbf, cpg);
|
};
|
module.exports = shp;
|
|
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {},require("buffer").Buffer)
|
|
},{"./binaryajax":90,"./parseShp":92,"./unzip":93,"buffer":30,"lie":58,"lru-cache":59,"parsedbf":79,"proj4":82}],92:[function(require,module,exports){
|
'use strict';
|
|
function isClockWise(array) {
|
var sum = 0;
|
var i = 1;
|
var len = array.length;
|
var prev, cur;
|
while (i < len) {
|
prev = cur || array[0];
|
cur = array[i];
|
sum += ((cur[0] - prev[0]) * (cur[1] + prev[1]));
|
i++;
|
}
|
return sum > 0;
|
}
|
|
function polyReduce(a, b) {
|
if (isClockWise(b) || !a.length) {
|
a.push([b]);
|
} else {
|
a[a.length - 1].push(b);
|
}
|
return a;
|
}
|
ParseShp.prototype.parsePoint = function(data) {
|
return {
|
'type': 'Point',
|
'coordinates': this.parseCoord(data, 0)
|
};
|
};
|
ParseShp.prototype.parseZPoint = function(data) {
|
var pointXY = this.parsePoint(data);
|
pointXY.coordinates.push(data.readDoubleLE(16));
|
return pointXY;
|
};
|
ParseShp.prototype.parsePointArray = function(data, offset, num) {
|
var out = [];
|
var done = 0;
|
while (done < num) {
|
out.push(this.parseCoord(data, offset));
|
offset += 16;
|
done++;
|
}
|
return out;
|
};
|
ParseShp.prototype.parseZPointArray = function(data, zOffset, num, coordinates) {
|
var i = 0;
|
while (i < num) {
|
coordinates[i].push(data.readDoubleLE(zOffset));
|
i++;
|
zOffset += 8;
|
}
|
return coordinates;
|
};
|
ParseShp.prototype.parseArrayGroup = function(data, offset, partOffset, num, tot) {
|
var out = [];
|
var done = 0;
|
var curNum, nextNum = 0,
|
pointNumber;
|
while (done < num) {
|
done++;
|
partOffset += 4;
|
curNum = nextNum;
|
if (done === num) {
|
nextNum = tot;
|
} else {
|
nextNum = data.readInt32LE(partOffset);
|
}
|
pointNumber = nextNum - curNum;
|
if (!pointNumber) {
|
continue;
|
}
|
out.push(this.parsePointArray(data, offset, pointNumber));
|
offset += (pointNumber << 4);
|
}
|
return out;
|
};
|
ParseShp.prototype.parseZArrayGroup = function(data, zOffset, num, coordinates) {
|
var i = 0;
|
while (i < num) {
|
coordinates[i] = this.parseZPointArray(data, zOffset, coordinates[i].length, coordinates[i]);
|
zOffset += (coordinates[i].length << 3);
|
i++;
|
}
|
return coordinates;
|
};
|
ParseShp.prototype.parseMultiPoint = function(data) {
|
var out = {};
|
var mins = this.parseCoord(data, 0);
|
var maxs = this.parseCoord(data, 16);
|
out.bbox = [
|
mins[0],
|
mins[1],
|
maxs[0],
|
maxs[1]
|
];
|
var num = data.readInt32LE(32, true);
|
var offset = 36;
|
if (num === 1) {
|
out.type = 'Point';
|
out.coordinates = this.parseCoord(data, offset);
|
} else {
|
out.type = 'MultiPoint';
|
out.coordinates = this.parsePointArray(data, offset, num);
|
}
|
return out;
|
};
|
ParseShp.prototype.parseZMultiPoint = function(data) {
|
var geoJson = this.parseMultiPoint(data);
|
var num;
|
if (geoJson.type === 'Point') {
|
geoJson.coordinates.push(data.readDoubleLE(72));
|
return geoJson;
|
} else {
|
num = geoJson.coordinates.length;
|
}
|
var zOffset = 52 + (num << 4);
|
geoJson.coordinates = this.parseZPointArray(data, zOffset, num, geoJson.coordinates);
|
return geoJson;
|
};
|
ParseShp.prototype.parsePolyline = function(data) {
|
var out = {};
|
var mins = this.parseCoord(data, 0);
|
var maxs = this.parseCoord(data, 16);
|
out.bbox = [
|
mins[0],
|
mins[1],
|
maxs[0],
|
maxs[1]
|
];
|
var numParts = data.readInt32LE(32);
|
var num = data.readInt32LE(36);
|
var offset, partOffset;
|
if (numParts === 1) {
|
out.type = 'LineString';
|
offset = 44;
|
out.coordinates = this.parsePointArray(data, offset, num);
|
} else {
|
out.type = 'MultiLineString';
|
offset = 40 + (numParts << 2);
|
partOffset = 40;
|
out.coordinates = this.parseArrayGroup(data, offset, partOffset, numParts, num);
|
}
|
return out;
|
};
|
ParseShp.prototype.parseZPolyline = function(data) {
|
var geoJson = this.parsePolyline(data);
|
var num = geoJson.coordinates.length;
|
var zOffset;
|
if (geoJson.type === 'LineString') {
|
zOffset = 60 + (num << 4);
|
geoJson.coordinates = this.parseZPointArray(data, zOffset, num, geoJson.coordinates);
|
return geoJson;
|
} else {
|
var totalPoints = geoJson.coordinates.reduce(function(a, v) {
|
return a + v.length;
|
}, 0);
|
zOffset = 56 + (totalPoints << 4) + (num << 2);
|
geoJson.coordinates = this.parseZArrayGroup(data, zOffset, num, geoJson.coordinates);
|
return geoJson;
|
}
|
};
|
ParseShp.prototype.polyFuncs = function(out) {
|
if (out.type === 'LineString') {
|
out.type = 'Polygon';
|
out.coordinates = [out.coordinates];
|
return out;
|
} else {
|
out.coordinates = out.coordinates.reduce(polyReduce, []);
|
if (out.coordinates.length === 1) {
|
out.type = 'Polygon';
|
out.coordinates = out.coordinates[0];
|
return out;
|
} else {
|
out.type = 'MultiPolygon';
|
return out;
|
}
|
}
|
};
|
ParseShp.prototype.parsePolygon = function(data) {
|
return this.polyFuncs(this.parsePolyline(data));
|
};
|
ParseShp.prototype.parseZPolygon = function(data) {
|
return this.polyFuncs(this.parseZPolyline(data));
|
};
|
var shpFuncObj = {
|
1: 'parsePoint',
|
3: 'parsePolyline',
|
5: 'parsePolygon',
|
8: 'parseMultiPoint',
|
11: 'parseZPoint',
|
13: 'parseZPolyline',
|
15: 'parseZPolygon',
|
18: 'parseZMultiPoint'
|
};
|
|
|
|
function makeParseCoord(trans) {
|
if (trans) {
|
return function(data, offset) {
|
var coord=[data.readDoubleLE(offset), data.readDoubleLE(offset + 8)]
|
if(isNaN(coord[0])||isNaN(coord[1]))return coord;
|
return trans.inverse(coord);
|
};
|
} else {
|
return function(data, offset) {
|
var coord=[data.readDoubleLE(offset), data.readDoubleLE(offset + 8)]
|
return coord;
|
};
|
}
|
}
|
|
function ParseShp(buffer, trans) {
|
if (!(this instanceof ParseShp)) {
|
return new ParseShp(buffer, trans);
|
}
|
this.buffer = buffer;
|
this.shpFuncs(trans);
|
this.rows = this.getRows();
|
}
|
ParseShp.prototype.shpFuncs = function(tran) {
|
var num = this.getShpCode();
|
if (num > 20) {
|
num -= 20;
|
}
|
if (!(num in shpFuncObj)) {
|
throw new Error('I don\'t know that shp type');
|
}
|
this.parseFunc = this[shpFuncObj[num]];
|
this.parseCoord = makeParseCoord(tran);
|
};
|
ParseShp.prototype.getShpCode = function() {
|
return this.parseHeader().shpCode;
|
};
|
ParseShp.prototype.parseHeader = function() {
|
var view = this.buffer.slice(0, 100);
|
return {
|
length: view.readInt32BE(6 << 2),
|
version: view.readInt32LE(7 << 2),
|
shpCode: view.readInt32LE(8 << 2),
|
bbox: [
|
view.readDoubleLE(9 << 2),
|
view.readDoubleLE(11 << 2),
|
view.readDoubleLE(13 << 2),
|
view.readDoubleLE(13 << 2)
|
]
|
};
|
};
|
ParseShp.prototype.getRows = function() {
|
var offset = 100;
|
var len = this.buffer.byteLength;
|
var out = [];
|
var current;
|
while (offset < len) {
|
current = this.getRow(offset);
|
offset += 8;
|
offset += current.len;
|
if (current.type) {
|
out.push(this.parseFunc(current.data));
|
}
|
}
|
return out;
|
};
|
ParseShp.prototype.getRow = function(offset) {
|
var view = this.buffer.slice(offset, offset + 12);
|
var len = view.readInt32BE(4) << 1;
|
var data = this.buffer.slice(offset + 12, offset + len + 8);
|
|
return {
|
id: view.readInt32BE(0),
|
len: len,
|
data: data,
|
type: view.readInt32LE(8)
|
};
|
};
|
module.exports = function(buffer, trans) {
|
return new ParseShp(buffer, trans).rows;
|
};
|
|
},{}],93:[function(require,module,exports){
|
'use strict';
|
|
var JSZip = require('jszip');
|
module.exports = function(buffer) {
|
var zip = new JSZip(buffer);
|
var files = zip.file(/.+/);
|
var out = {};
|
files.forEach(function(a) {
|
if (a.name.slice(-3).toLowerCase() === 'shp' || a.name.slice(-3).toLowerCase() === 'dbf') {
|
out[a.name] = a.asNodeBuffer();
|
}
|
else {
|
out[a.name] = a.asText();
|
}
|
});
|
return out;
|
};
|
|
},{"jszip":43}],94:[function(require,module,exports){
|
// Copyright Joyent, Inc. and other Node contributors.
|
//
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
// copy of this software and associated documentation files (the
|
// "Software"), to deal in the Software without restriction, including
|
// without limitation the rights to use, copy, modify, merge, publish,
|
// distribute, sublicense, and/or sell copies of the Software, and to permit
|
// persons to whom the Software is furnished to do so, subject to the
|
// following conditions:
|
//
|
// The above copyright notice and this permission notice shall be included
|
// in all copies or substantial portions of the Software.
|
//
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
'use strict';
|
|
/*<replacement>*/
|
|
var Buffer = require('safe-buffer').Buffer;
|
/*</replacement>*/
|
|
var isEncoding = Buffer.isEncoding || function (encoding) {
|
encoding = '' + encoding;
|
switch (encoding && encoding.toLowerCase()) {
|
case 'hex':case 'utf8':case 'utf-8':case 'ascii':case 'binary':case 'base64':case 'ucs2':case 'ucs-2':case 'utf16le':case 'utf-16le':case 'raw':
|
return true;
|
default:
|
return false;
|
}
|
};
|
|
function _normalizeEncoding(enc) {
|
if (!enc) return 'utf8';
|
var retried;
|
while (true) {
|
switch (enc) {
|
case 'utf8':
|
case 'utf-8':
|
return 'utf8';
|
case 'ucs2':
|
case 'ucs-2':
|
case 'utf16le':
|
case 'utf-16le':
|
return 'utf16le';
|
case 'latin1':
|
case 'binary':
|
return 'latin1';
|
case 'base64':
|
case 'ascii':
|
case 'hex':
|
return enc;
|
default:
|
if (retried) return; // undefined
|
enc = ('' + enc).toLowerCase();
|
retried = true;
|
}
|
}
|
};
|
|
// Do not cache `Buffer.isEncoding` when checking encoding names as some
|
// modules monkey-patch it to support additional encodings
|
function normalizeEncoding(enc) {
|
var nenc = _normalizeEncoding(enc);
|
if (typeof nenc !== 'string' && (Buffer.isEncoding === isEncoding || !isEncoding(enc))) throw new Error('Unknown encoding: ' + enc);
|
return nenc || enc;
|
}
|
|
// StringDecoder provides an interface for efficiently splitting a series of
|
// buffers into a series of JS strings without breaking apart multi-byte
|
// characters.
|
exports.StringDecoder = StringDecoder;
|
function StringDecoder(encoding) {
|
this.encoding = normalizeEncoding(encoding);
|
var nb;
|
switch (this.encoding) {
|
case 'utf16le':
|
this.text = utf16Text;
|
this.end = utf16End;
|
nb = 4;
|
break;
|
case 'utf8':
|
this.fillLast = utf8FillLast;
|
nb = 4;
|
break;
|
case 'base64':
|
this.text = base64Text;
|
this.end = base64End;
|
nb = 3;
|
break;
|
default:
|
this.write = simpleWrite;
|
this.end = simpleEnd;
|
return;
|
}
|
this.lastNeed = 0;
|
this.lastTotal = 0;
|
this.lastChar = Buffer.allocUnsafe(nb);
|
}
|
|
StringDecoder.prototype.write = function (buf) {
|
if (buf.length === 0) return '';
|
var r;
|
var i;
|
if (this.lastNeed) {
|
r = this.fillLast(buf);
|
if (r === undefined) return '';
|
i = this.lastNeed;
|
this.lastNeed = 0;
|
} else {
|
i = 0;
|
}
|
if (i < buf.length) return r ? r + this.text(buf, i) : this.text(buf, i);
|
return r || '';
|
};
|
|
StringDecoder.prototype.end = utf8End;
|
|
// Returns only complete characters in a Buffer
|
StringDecoder.prototype.text = utf8Text;
|
|
// Attempts to complete a partial non-UTF-8 character using bytes from a Buffer
|
StringDecoder.prototype.fillLast = function (buf) {
|
if (this.lastNeed <= buf.length) {
|
buf.copy(this.lastChar, this.lastTotal - this.lastNeed, 0, this.lastNeed);
|
return this.lastChar.toString(this.encoding, 0, this.lastTotal);
|
}
|
buf.copy(this.lastChar, this.lastTotal - this.lastNeed, 0, buf.length);
|
this.lastNeed -= buf.length;
|
};
|
|
// Checks the type of a UTF-8 byte, whether it's ASCII, a leading byte, or a
|
// continuation byte. If an invalid byte is detected, -2 is returned.
|
function utf8CheckByte(byte) {
|
if (byte <= 0x7F) return 0;else if (byte >> 5 === 0x06) return 2;else if (byte >> 4 === 0x0E) return 3;else if (byte >> 3 === 0x1E) return 4;
|
return byte >> 6 === 0x02 ? -1 : -2;
|
}
|
|
// Checks at most 3 bytes at the end of a Buffer in order to detect an
|
// incomplete multi-byte UTF-8 character. The total number of bytes (2, 3, or 4)
|
// needed to complete the UTF-8 character (if applicable) are returned.
|
function utf8CheckIncomplete(self, buf, i) {
|
var j = buf.length - 1;
|
if (j < i) return 0;
|
var nb = utf8CheckByte(buf[j]);
|
if (nb >= 0) {
|
if (nb > 0) self.lastNeed = nb - 1;
|
return nb;
|
}
|
if (--j < i || nb === -2) return 0;
|
nb = utf8CheckByte(buf[j]);
|
if (nb >= 0) {
|
if (nb > 0) self.lastNeed = nb - 2;
|
return nb;
|
}
|
if (--j < i || nb === -2) return 0;
|
nb = utf8CheckByte(buf[j]);
|
if (nb >= 0) {
|
if (nb > 0) {
|
if (nb === 2) nb = 0;else self.lastNeed = nb - 3;
|
}
|
return nb;
|
}
|
return 0;
|
}
|
|
// Validates as many continuation bytes for a multi-byte UTF-8 character as
|
// needed or are available. If we see a non-continuation byte where we expect
|
// one, we "replace" the validated continuation bytes we've seen so far with
|
// a single UTF-8 replacement character ('\ufffd'), to match v8's UTF-8 decoding
|
// behavior. The continuation byte check is included three times in the case
|
// where all of the continuation bytes for a character exist in the same buffer.
|
// It is also done this way as a slight performance increase instead of using a
|
// loop.
|
function utf8CheckExtraBytes(self, buf, p) {
|
if ((buf[0] & 0xC0) !== 0x80) {
|
self.lastNeed = 0;
|
return '\ufffd';
|
}
|
if (self.lastNeed > 1 && buf.length > 1) {
|
if ((buf[1] & 0xC0) !== 0x80) {
|
self.lastNeed = 1;
|
return '\ufffd';
|
}
|
if (self.lastNeed > 2 && buf.length > 2) {
|
if ((buf[2] & 0xC0) !== 0x80) {
|
self.lastNeed = 2;
|
return '\ufffd';
|
}
|
}
|
}
|
}
|
|
// Attempts to complete a multi-byte UTF-8 character using bytes from a Buffer.
|
function utf8FillLast(buf) {
|
var p = this.lastTotal - this.lastNeed;
|
var r = utf8CheckExtraBytes(this, buf, p);
|
if (r !== undefined) return r;
|
if (this.lastNeed <= buf.length) {
|
buf.copy(this.lastChar, p, 0, this.lastNeed);
|
return this.lastChar.toString(this.encoding, 0, this.lastTotal);
|
}
|
buf.copy(this.lastChar, p, 0, buf.length);
|
this.lastNeed -= buf.length;
|
}
|
|
// Returns all complete UTF-8 characters in a Buffer. If the Buffer ended on a
|
// partial character, the character's bytes are buffered until the required
|
// number of bytes are available.
|
function utf8Text(buf, i) {
|
var total = utf8CheckIncomplete(this, buf, i);
|
if (!this.lastNeed) return buf.toString('utf8', i);
|
this.lastTotal = total;
|
var end = buf.length - (total - this.lastNeed);
|
buf.copy(this.lastChar, 0, end);
|
return buf.toString('utf8', i, end);
|
}
|
|
// For UTF-8, a replacement character is added when ending on a partial
|
// character.
|
function utf8End(buf) {
|
var r = buf && buf.length ? this.write(buf) : '';
|
if (this.lastNeed) return r + '\ufffd';
|
return r;
|
}
|
|
// UTF-16LE typically needs two bytes per character, but even if we have an even
|
// number of bytes available, we need to check if we end on a leading/high
|
// surrogate. In that case, we need to wait for the next two bytes in order to
|
// decode the last character properly.
|
function utf16Text(buf, i) {
|
if ((buf.length - i) % 2 === 0) {
|
var r = buf.toString('utf16le', i);
|
if (r) {
|
var c = r.charCodeAt(r.length - 1);
|
if (c >= 0xD800 && c <= 0xDBFF) {
|
this.lastNeed = 2;
|
this.lastTotal = 4;
|
this.lastChar[0] = buf[buf.length - 2];
|
this.lastChar[1] = buf[buf.length - 1];
|
return r.slice(0, -1);
|
}
|
}
|
return r;
|
}
|
this.lastNeed = 1;
|
this.lastTotal = 2;
|
this.lastChar[0] = buf[buf.length - 1];
|
return buf.toString('utf16le', i, buf.length - 1);
|
}
|
|
// For UTF-16LE we do not explicitly append special replacement characters if we
|
// end on a partial character, we simply let v8 handle that.
|
function utf16End(buf) {
|
var r = buf && buf.length ? this.write(buf) : '';
|
if (this.lastNeed) {
|
var end = this.lastTotal - this.lastNeed;
|
return r + this.lastChar.toString('utf16le', 0, end);
|
}
|
return r;
|
}
|
|
function base64Text(buf, i) {
|
var n = (buf.length - i) % 3;
|
if (n === 0) return buf.toString('base64', i);
|
this.lastNeed = 3 - n;
|
this.lastTotal = 3;
|
if (n === 1) {
|
this.lastChar[0] = buf[buf.length - 1];
|
} else {
|
this.lastChar[0] = buf[buf.length - 2];
|
this.lastChar[1] = buf[buf.length - 1];
|
}
|
return buf.toString('base64', i, buf.length - n);
|
}
|
|
function base64End(buf) {
|
var r = buf && buf.length ? this.write(buf) : '';
|
if (this.lastNeed) return r + this.lastChar.toString('base64', 0, 3 - this.lastNeed);
|
return r;
|
}
|
|
// Pass bytes on through for single-byte encodings (e.g. ascii, latin1, hex)
|
function simpleWrite(buf) {
|
return buf.toString(this.encoding);
|
}
|
|
function simpleEnd(buf) {
|
return buf && buf.length ? this.write(buf) : '';
|
}
|
},{"safe-buffer":89}],95:[function(require,module,exports){
|
// This is free and unencumbered software released into the public domain.
|
// See LICENSE.md for more information.
|
|
module.exports = require("./lib/encoding.js");
|
|
},{"./lib/encoding.js":96}],96:[function(require,module,exports){
|
// This is free and unencumbered software released into the public domain.
|
// See LICENSE.md for more information.
|
|
/**
|
* @fileoverview Global |this| required for resolving indexes in node.
|
* @suppress {globalThis}
|
*/
|
(function(global) {
|
'use strict';
|
|
// If we're in node require encoding-indexes and attach it to the global.
|
if (typeof module !== "undefined" && module.exports &&
|
!global["encoding-indexes"]) {
|
require("./encoding-indexes.js");
|
}
|
|
//
|
// Utilities
|
//
|
|
/**
|
* @param {number} a The number to test.
|
* @param {number} min The minimum value in the range, inclusive.
|
* @param {number} max The maximum value in the range, inclusive.
|
* @return {boolean} True if a >= min and a <= max.
|
*/
|
function inRange(a, min, max) {
|
return min <= a && a <= max;
|
}
|
|
/**
|
* @param {!Array.<*>} array The array to check.
|
* @param {*} item The item to look for in the array.
|
* @return {boolean} True if the item appears in the array.
|
*/
|
function includes(array, item) {
|
return array.indexOf(item) !== -1;
|
}
|
|
var floor = Math.floor;
|
|
/**
|
* @param {*} o
|
* @return {Object}
|
*/
|
function ToDictionary(o) {
|
if (o === undefined) return {};
|
if (o === Object(o)) return o;
|
throw TypeError('Could not convert argument to dictionary');
|
}
|
|
/**
|
* @param {string} string Input string of UTF-16 code units.
|
* @return {!Array.<number>} Code points.
|
*/
|
function stringToCodePoints(string) {
|
// https://heycam.github.io/webidl/#dfn-obtain-unicode
|
|
// 1. Let S be the DOMString value.
|
var s = String(string);
|
|
// 2. Let n be the length of S.
|
var n = s.length;
|
|
// 3. Initialize i to 0.
|
var i = 0;
|
|
// 4. Initialize U to be an empty sequence of Unicode characters.
|
var u = [];
|
|
// 5. While i < n:
|
while (i < n) {
|
|
// 1. Let c be the code unit in S at index i.
|
var c = s.charCodeAt(i);
|
|
// 2. Depending on the value of c:
|
|
// c < 0xD800 or c > 0xDFFF
|
if (c < 0xD800 || c > 0xDFFF) {
|
// Append to U the Unicode character with code point c.
|
u.push(c);
|
}
|
|
// 0xDC00 ≤ c ≤ 0xDFFF
|
else if (0xDC00 <= c && c <= 0xDFFF) {
|
// Append to U a U+FFFD REPLACEMENT CHARACTER.
|
u.push(0xFFFD);
|
}
|
|
// 0xD800 ≤ c ≤ 0xDBFF
|
else if (0xD800 <= c && c <= 0xDBFF) {
|
// 1. If i = n−1, then append to U a U+FFFD REPLACEMENT
|
// CHARACTER.
|
if (i === n - 1) {
|
u.push(0xFFFD);
|
}
|
// 2. Otherwise, i < n−1:
|
else {
|
// 1. Let d be the code unit in S at index i+1.
|
var d = s.charCodeAt(i + 1);
|
|
// 2. If 0xDC00 ≤ d ≤ 0xDFFF, then:
|
if (0xDC00 <= d && d <= 0xDFFF) {
|
// 1. Let a be c & 0x3FF.
|
var a = c & 0x3FF;
|
|
// 2. Let b be d & 0x3FF.
|
var b = d & 0x3FF;
|
|
// 3. Append to U the Unicode character with code point
|
// 2^16+2^10*a+b.
|
u.push(0x10000 + (a << 10) + b);
|
|
// 4. Set i to i+1.
|
i += 1;
|
}
|
|
// 3. Otherwise, d < 0xDC00 or d > 0xDFFF. Append to U a
|
// U+FFFD REPLACEMENT CHARACTER.
|
else {
|
u.push(0xFFFD);
|
}
|
}
|
}
|
|
// 3. Set i to i+1.
|
i += 1;
|
}
|
|
// 6. Return U.
|
return u;
|
}
|
|
/**
|
* @param {!Array.<number>} code_points Array of code points.
|
* @return {string} string String of UTF-16 code units.
|
*/
|
function codePointsToString(code_points) {
|
var s = '';
|
for (var i = 0; i < code_points.length; ++i) {
|
var cp = code_points[i];
|
if (cp <= 0xFFFF) {
|
s += String.fromCharCode(cp);
|
} else {
|
cp -= 0x10000;
|
s += String.fromCharCode((cp >> 10) + 0xD800,
|
(cp & 0x3FF) + 0xDC00);
|
}
|
}
|
return s;
|
}
|
|
|
//
|
// Implementation of Encoding specification
|
// https://encoding.spec.whatwg.org/
|
//
|
|
//
|
// 4. Terminology
|
//
|
|
/**
|
* An ASCII byte is a byte in the range 0x00 to 0x7F, inclusive.
|
* @param {number} a The number to test.
|
* @return {boolean} True if a is in the range 0x00 to 0x7F, inclusive.
|
*/
|
function isASCIIByte(a) {
|
return 0x00 <= a && a <= 0x7F;
|
}
|
|
/**
|
* An ASCII code point is a code point in the range U+0000 to
|
* U+007F, inclusive.
|
*/
|
var isASCIICodePoint = isASCIIByte;
|
|
|
/**
|
* End-of-stream is a special token that signifies no more tokens
|
* are in the stream.
|
* @const
|
*/ var end_of_stream = -1;
|
|
/**
|
* A stream represents an ordered sequence of tokens.
|
*
|
* @constructor
|
* @param {!(Array.<number>|Uint8Array)} tokens Array of tokens that provide
|
* the stream.
|
*/
|
function Stream(tokens) {
|
/** @type {!Array.<number>} */
|
this.tokens = [].slice.call(tokens);
|
// Reversed as push/pop is more efficient than shift/unshift.
|
this.tokens.reverse();
|
}
|
|
Stream.prototype = {
|
/**
|
* @return {boolean} True if end-of-stream has been hit.
|
*/
|
endOfStream: function() {
|
return !this.tokens.length;
|
},
|
|
/**
|
* When a token is read from a stream, the first token in the
|
* stream must be returned and subsequently removed, and
|
* end-of-stream must be returned otherwise.
|
*
|
* @return {number} Get the next token from the stream, or
|
* end_of_stream.
|
*/
|
read: function() {
|
if (!this.tokens.length)
|
return end_of_stream;
|
return this.tokens.pop();
|
},
|
|
/**
|
* When one or more tokens are prepended to a stream, those tokens
|
* must be inserted, in given order, before the first token in the
|
* stream.
|
*
|
* @param {(number|!Array.<number>)} token The token(s) to prepend to the
|
* stream.
|
*/
|
prepend: function(token) {
|
if (Array.isArray(token)) {
|
var tokens = /**@type {!Array.<number>}*/(token);
|
while (tokens.length)
|
this.tokens.push(tokens.pop());
|
} else {
|
this.tokens.push(token);
|
}
|
},
|
|
/**
|
* When one or more tokens are pushed to a stream, those tokens
|
* must be inserted, in given order, after the last token in the
|
* stream.
|
*
|
* @param {(number|!Array.<number>)} token The tokens(s) to push to the
|
* stream.
|
*/
|
push: function(token) {
|
if (Array.isArray(token)) {
|
var tokens = /**@type {!Array.<number>}*/(token);
|
while (tokens.length)
|
this.tokens.unshift(tokens.shift());
|
} else {
|
this.tokens.unshift(token);
|
}
|
}
|
};
|
|
//
|
// 5. Encodings
|
//
|
|
// 5.1 Encoders and decoders
|
|
/** @const */
|
var finished = -1;
|
|
/**
|
* @param {boolean} fatal If true, decoding errors raise an exception.
|
* @param {number=} opt_code_point Override the standard fallback code point.
|
* @return {number} The code point to insert on a decoding error.
|
*/
|
function decoderError(fatal, opt_code_point) {
|
if (fatal)
|
throw TypeError('Decoder error');
|
return opt_code_point || 0xFFFD;
|
}
|
|
/**
|
* @param {number} code_point The code point that could not be encoded.
|
* @return {number} Always throws, no value is actually returned.
|
*/
|
function encoderError(code_point) {
|
throw TypeError('The code point ' + code_point + ' could not be encoded.');
|
}
|
|
/** @interface */
|
function Decoder() {}
|
Decoder.prototype = {
|
/**
|
* @param {Stream} stream The stream of bytes being decoded.
|
* @param {number} bite The next byte read from the stream.
|
* @return {?(number|!Array.<number>)} The next code point(s)
|
* decoded, or null if not enough data exists in the input
|
* stream to decode a complete code point, or |finished|.
|
*/
|
handler: function(stream, bite) {}
|
};
|
|
/** @interface */
|
function Encoder() {}
|
Encoder.prototype = {
|
/**
|
* @param {Stream} stream The stream of code points being encoded.
|
* @param {number} code_point Next code point read from the stream.
|
* @return {(number|!Array.<number>)} Byte(s) to emit, or |finished|.
|
*/
|
handler: function(stream, code_point) {}
|
};
|
|
// 5.2 Names and labels
|
|
// TODO: Define @typedef for Encoding: {name:string,labels:Array.<string>}
|
// https://github.com/google/closure-compiler/issues/247
|
|
/**
|
* @param {string} label The encoding label.
|
* @return {?{name:string,labels:Array.<string>}}
|
*/
|
function getEncoding(label) {
|
// 1. Remove any leading and trailing ASCII whitespace from label.
|
label = String(label).trim().toLowerCase();
|
|
// 2. If label is an ASCII case-insensitive match for any of the
|
// labels listed in the table below, return the corresponding
|
// encoding, and failure otherwise.
|
if (Object.prototype.hasOwnProperty.call(label_to_encoding, label)) {
|
return label_to_encoding[label];
|
}
|
return null;
|
}
|
|
/**
|
* Encodings table: https://encoding.spec.whatwg.org/encodings.json
|
* @const
|
* @type {!Array.<{
|
* heading: string,
|
* encodings: Array.<{name:string,labels:Array.<string>}>
|
* }>}
|
*/
|
var encodings = [
|
{
|
"encodings": [
|
{
|
"labels": [
|
"unicode-1-1-utf-8",
|
"utf-8",
|
"utf8"
|
],
|
"name": "UTF-8"
|
}
|
],
|
"heading": "The Encoding"
|
},
|
{
|
"encodings": [
|
{
|
"labels": [
|
"866",
|
"cp866",
|
"csibm866",
|
"ibm866"
|
],
|
"name": "IBM866"
|
},
|
{
|
"labels": [
|
"csisolatin2",
|
"iso-8859-2",
|
"iso-ir-101",
|
"iso8859-2",
|
"iso88592",
|
"iso_8859-2",
|
"iso_8859-2:1987",
|
"l2",
|
"latin2"
|
],
|
"name": "ISO-8859-2"
|
},
|
{
|
"labels": [
|
"csisolatin3",
|
"iso-8859-3",
|
"iso-ir-109",
|
"iso8859-3",
|
"iso88593",
|
"iso_8859-3",
|
"iso_8859-3:1988",
|
"l3",
|
"latin3"
|
],
|
"name": "ISO-8859-3"
|
},
|
{
|
"labels": [
|
"csisolatin4",
|
"iso-8859-4",
|
"iso-ir-110",
|
"iso8859-4",
|
"iso88594",
|
"iso_8859-4",
|
"iso_8859-4:1988",
|
"l4",
|
"latin4"
|
],
|
"name": "ISO-8859-4"
|
},
|
{
|
"labels": [
|
"csisolatincyrillic",
|
"cyrillic",
|
"iso-8859-5",
|
"iso-ir-144",
|
"iso8859-5",
|
"iso88595",
|
"iso_8859-5",
|
"iso_8859-5:1988"
|
],
|
"name": "ISO-8859-5"
|
},
|
{
|
"labels": [
|
"arabic",
|
"asmo-708",
|
"csiso88596e",
|
"csiso88596i",
|
"csisolatinarabic",
|
"ecma-114",
|
"iso-8859-6",
|
"iso-8859-6-e",
|
"iso-8859-6-i",
|
"iso-ir-127",
|
"iso8859-6",
|
"iso88596",
|
"iso_8859-6",
|
"iso_8859-6:1987"
|
],
|
"name": "ISO-8859-6"
|
},
|
{
|
"labels": [
|
"csisolatingreek",
|
"ecma-118",
|
"elot_928",
|
"greek",
|
"greek8",
|
"iso-8859-7",
|
"iso-ir-126",
|
"iso8859-7",
|
"iso88597",
|
"iso_8859-7",
|
"iso_8859-7:1987",
|
"sun_eu_greek"
|
],
|
"name": "ISO-8859-7"
|
},
|
{
|
"labels": [
|
"csiso88598e",
|
"csisolatinhebrew",
|
"hebrew",
|
"iso-8859-8",
|
"iso-8859-8-e",
|
"iso-ir-138",
|
"iso8859-8",
|
"iso88598",
|
"iso_8859-8",
|
"iso_8859-8:1988",
|
"visual"
|
],
|
"name": "ISO-8859-8"
|
},
|
{
|
"labels": [
|
"csiso88598i",
|
"iso-8859-8-i",
|
"logical"
|
],
|
"name": "ISO-8859-8-I"
|
},
|
{
|
"labels": [
|
"csisolatin6",
|
"iso-8859-10",
|
"iso-ir-157",
|
"iso8859-10",
|
"iso885910",
|
"l6",
|
"latin6"
|
],
|
"name": "ISO-8859-10"
|
},
|
{
|
"labels": [
|
"iso-8859-13",
|
"iso8859-13",
|
"iso885913"
|
],
|
"name": "ISO-8859-13"
|
},
|
{
|
"labels": [
|
"iso-8859-14",
|
"iso8859-14",
|
"iso885914"
|
],
|
"name": "ISO-8859-14"
|
},
|
{
|
"labels": [
|
"csisolatin9",
|
"iso-8859-15",
|
"iso8859-15",
|
"iso885915",
|
"iso_8859-15",
|
"l9"
|
],
|
"name": "ISO-8859-15"
|
},
|
{
|
"labels": [
|
"iso-8859-16"
|
],
|
"name": "ISO-8859-16"
|
},
|
{
|
"labels": [
|
"cskoi8r",
|
"koi",
|
"koi8",
|
"koi8-r",
|
"koi8_r"
|
],
|
"name": "KOI8-R"
|
},
|
{
|
"labels": [
|
"koi8-ru",
|
"koi8-u"
|
],
|
"name": "KOI8-U"
|
},
|
{
|
"labels": [
|
"csmacintosh",
|
"mac",
|
"macintosh",
|
"x-mac-roman"
|
],
|
"name": "macintosh"
|
},
|
{
|
"labels": [
|
"dos-874",
|
"iso-8859-11",
|
"iso8859-11",
|
"iso885911",
|
"tis-620",
|
"windows-874"
|
],
|
"name": "windows-874"
|
},
|
{
|
"labels": [
|
"cp1250",
|
"windows-1250",
|
"x-cp1250"
|
],
|
"name": "windows-1250"
|
},
|
{
|
"labels": [
|
"cp1251",
|
"windows-1251",
|
"x-cp1251"
|
],
|
"name": "windows-1251"
|
},
|
{
|
"labels": [
|
"ansi_x3.4-1968",
|
"ascii",
|
"cp1252",
|
"cp819",
|
"csisolatin1",
|
"ibm819",
|
"iso-8859-1",
|
"iso-ir-100",
|
"iso8859-1",
|
"iso88591",
|
"iso_8859-1",
|
"iso_8859-1:1987",
|
"l1",
|
"latin1",
|
"us-ascii",
|
"windows-1252",
|
"x-cp1252"
|
],
|
"name": "windows-1252"
|
},
|
{
|
"labels": [
|
"cp1253",
|
"windows-1253",
|
"x-cp1253"
|
],
|
"name": "windows-1253"
|
},
|
{
|
"labels": [
|
"cp1254",
|
"csisolatin5",
|
"iso-8859-9",
|
"iso-ir-148",
|
"iso8859-9",
|
"iso88599",
|
"iso_8859-9",
|
"iso_8859-9:1989",
|
"l5",
|
"latin5",
|
"windows-1254",
|
"x-cp1254"
|
],
|
"name": "windows-1254"
|
},
|
{
|
"labels": [
|
"cp1255",
|
"windows-1255",
|
"x-cp1255"
|
],
|
"name": "windows-1255"
|
},
|
{
|
"labels": [
|
"cp1256",
|
"windows-1256",
|
"x-cp1256"
|
],
|
"name": "windows-1256"
|
},
|
{
|
"labels": [
|
"cp1257",
|
"windows-1257",
|
"x-cp1257"
|
],
|
"name": "windows-1257"
|
},
|
{
|
"labels": [
|
"cp1258",
|
"windows-1258",
|
"x-cp1258"
|
],
|
"name": "windows-1258"
|
},
|
{
|
"labels": [
|
"x-mac-cyrillic",
|
"x-mac-ukrainian"
|
],
|
"name": "x-mac-cyrillic"
|
}
|
],
|
"heading": "Legacy single-byte encodings"
|
},
|
{
|
"encodings": [
|
{
|
"labels": [
|
"chinese",
|
"csgb2312",
|
"csiso58gb231280",
|
"gb2312",
|
"gb_2312",
|
"gb_2312-80",
|
"gbk",
|
"iso-ir-58",
|
"x-gbk"
|
],
|
"name": "GBK"
|
},
|
{
|
"labels": [
|
"gb18030"
|
],
|
"name": "gb18030"
|
}
|
],
|
"heading": "Legacy multi-byte Chinese (simplified) encodings"
|
},
|
{
|
"encodings": [
|
{
|
"labels": [
|
"big5",
|
"big5-hkscs",
|
"cn-big5",
|
"csbig5",
|
"x-x-big5"
|
],
|
"name": "Big5"
|
}
|
],
|
"heading": "Legacy multi-byte Chinese (traditional) encodings"
|
},
|
{
|
"encodings": [
|
{
|
"labels": [
|
"cseucpkdfmtjapanese",
|
"euc-jp",
|
"x-euc-jp"
|
],
|
"name": "EUC-JP"
|
},
|
{
|
"labels": [
|
"csiso2022jp",
|
"iso-2022-jp"
|
],
|
"name": "ISO-2022-JP"
|
},
|
{
|
"labels": [
|
"csshiftjis",
|
"ms932",
|
"ms_kanji",
|
"shift-jis",
|
"shift_jis",
|
"sjis",
|
"windows-31j",
|
"x-sjis"
|
],
|
"name": "Shift_JIS"
|
}
|
],
|
"heading": "Legacy multi-byte Japanese encodings"
|
},
|
{
|
"encodings": [
|
{
|
"labels": [
|
"cseuckr",
|
"csksc56011987",
|
"euc-kr",
|
"iso-ir-149",
|
"korean",
|
"ks_c_5601-1987",
|
"ks_c_5601-1989",
|
"ksc5601",
|
"ksc_5601",
|
"windows-949"
|
],
|
"name": "EUC-KR"
|
}
|
],
|
"heading": "Legacy multi-byte Korean encodings"
|
},
|
{
|
"encodings": [
|
{
|
"labels": [
|
"csiso2022kr",
|
"hz-gb-2312",
|
"iso-2022-cn",
|
"iso-2022-cn-ext",
|
"iso-2022-kr"
|
],
|
"name": "replacement"
|
},
|
{
|
"labels": [
|
"utf-16be"
|
],
|
"name": "UTF-16BE"
|
},
|
{
|
"labels": [
|
"utf-16",
|
"utf-16le"
|
],
|
"name": "UTF-16LE"
|
},
|
{
|
"labels": [
|
"x-user-defined"
|
],
|
"name": "x-user-defined"
|
}
|
],
|
"heading": "Legacy miscellaneous encodings"
|
}
|
];
|
|
// Label to encoding registry.
|
/** @type {Object.<string,{name:string,labels:Array.<string>}>} */
|
var label_to_encoding = {};
|
encodings.forEach(function(category) {
|
category.encodings.forEach(function(encoding) {
|
encoding.labels.forEach(function(label) {
|
label_to_encoding[label] = encoding;
|
});
|
});
|
});
|
|
// Registry of of encoder/decoder factories, by encoding name.
|
/** @type {Object.<string, function({fatal:boolean}): Encoder>} */
|
var encoders = {};
|
/** @type {Object.<string, function({fatal:boolean}): Decoder>} */
|
var decoders = {};
|
|
//
|
// 6. Indexes
|
//
|
|
/**
|
* @param {number} pointer The |pointer| to search for.
|
* @param {(!Array.<?number>|undefined)} index The |index| to search within.
|
* @return {?number} The code point corresponding to |pointer| in |index|,
|
* or null if |code point| is not in |index|.
|
*/
|
function indexCodePointFor(pointer, index) {
|
if (!index) return null;
|
return index[pointer] || null;
|
}
|
|
/**
|
* @param {number} code_point The |code point| to search for.
|
* @param {!Array.<?number>} index The |index| to search within.
|
* @return {?number} The first pointer corresponding to |code point| in
|
* |index|, or null if |code point| is not in |index|.
|
*/
|
function indexPointerFor(code_point, index) {
|
var pointer = index.indexOf(code_point);
|
return pointer === -1 ? null : pointer;
|
}
|
|
/**
|
* @param {string} name Name of the index.
|
* @return {(!Array.<number>|!Array.<Array.<number>>)}
|
* */
|
function index(name) {
|
if (!('encoding-indexes' in global)) {
|
throw Error("Indexes missing." +
|
" Did you forget to include encoding-indexes.js first?");
|
}
|
return global['encoding-indexes'][name];
|
}
|
|
/**
|
* @param {number} pointer The |pointer| to search for in the gb18030 index.
|
* @return {?number} The code point corresponding to |pointer| in |index|,
|
* or null if |code point| is not in the gb18030 index.
|
*/
|
function indexGB18030RangesCodePointFor(pointer) {
|
// 1. If pointer is greater than 39419 and less than 189000, or
|
// pointer is greater than 1237575, return null.
|
if ((pointer > 39419 && pointer < 189000) || (pointer > 1237575))
|
return null;
|
|
// 2. If pointer is 7457, return code point U+E7C7.
|
if (pointer === 7457) return 0xE7C7;
|
|
// 3. Let offset be the last pointer in index gb18030 ranges that
|
// is equal to or less than pointer and let code point offset be
|
// its corresponding code point.
|
var offset = 0;
|
var code_point_offset = 0;
|
var idx = index('gb18030-ranges');
|
var i;
|
for (i = 0; i < idx.length; ++i) {
|
/** @type {!Array.<number>} */
|
var entry = idx[i];
|
if (entry[0] <= pointer) {
|
offset = entry[0];
|
code_point_offset = entry[1];
|
} else {
|
break;
|
}
|
}
|
|
// 4. Return a code point whose value is code point offset +
|
// pointer − offset.
|
return code_point_offset + pointer - offset;
|
}
|
|
/**
|
* @param {number} code_point The |code point| to locate in the gb18030 index.
|
* @return {number} The first pointer corresponding to |code point| in the
|
* gb18030 index.
|
*/
|
function indexGB18030RangesPointerFor(code_point) {
|
// 1. If code point is U+E7C7, return pointer 7457.
|
if (code_point === 0xE7C7) return 7457;
|
|
// 2. Let offset be the last code point in index gb18030 ranges
|
// that is equal to or less than code point and let pointer offset
|
// be its corresponding pointer.
|
var offset = 0;
|
var pointer_offset = 0;
|
var idx = index('gb18030-ranges');
|
var i;
|
for (i = 0; i < idx.length; ++i) {
|
/** @type {!Array.<number>} */
|
var entry = idx[i];
|
if (entry[1] <= code_point) {
|
offset = entry[1];
|
pointer_offset = entry[0];
|
} else {
|
break;
|
}
|
}
|
|
// 3. Return a pointer whose value is pointer offset + code point
|
// − offset.
|
return pointer_offset + code_point - offset;
|
}
|
|
/**
|
* @param {number} code_point The |code_point| to search for in the Shift_JIS
|
* index.
|
* @return {?number} The code point corresponding to |pointer| in |index|,
|
* or null if |code point| is not in the Shift_JIS index.
|
*/
|
function indexShiftJISPointerFor(code_point) {
|
// 1. Let index be index jis0208 excluding all entries whose
|
// pointer is in the range 8272 to 8835, inclusive.
|
shift_jis_index = shift_jis_index ||
|
index('jis0208').map(function(code_point, pointer) {
|
return inRange(pointer, 8272, 8835) ? null : code_point;
|
});
|
var index_ = shift_jis_index;
|
|
// 2. Return the index pointer for code point in index.
|
return index_.indexOf(code_point);
|
}
|
var shift_jis_index;
|
|
/**
|
* @param {number} code_point The |code_point| to search for in the big5
|
* index.
|
* @return {?number} The code point corresponding to |pointer| in |index|,
|
* or null if |code point| is not in the big5 index.
|
*/
|
function indexBig5PointerFor(code_point) {
|
// 1. Let index be index Big5 excluding all entries whose pointer
|
big5_index_no_hkscs = big5_index_no_hkscs ||
|
index('big5').map(function(code_point, pointer) {
|
return (pointer < (0xA1 - 0x81) * 157) ? null : code_point;
|
});
|
var index_ = big5_index_no_hkscs;
|
|
// 2. If code point is U+2550, U+255E, U+2561, U+256A, U+5341, or
|
// U+5345, return the last pointer corresponding to code point in
|
// index.
|
if (code_point === 0x2550 || code_point === 0x255E ||
|
code_point === 0x2561 || code_point === 0x256A ||
|
code_point === 0x5341 || code_point === 0x5345) {
|
return index_.lastIndexOf(code_point);
|
}
|
|
// 3. Return the index pointer for code point in index.
|
return indexPointerFor(code_point, index_);
|
}
|
var big5_index_no_hkscs;
|
|
//
|
// 8. API
|
//
|
|
/** @const */ var DEFAULT_ENCODING = 'utf-8';
|
|
// 8.1 Interface TextDecoder
|
|
/**
|
* @constructor
|
* @param {string=} label The label of the encoding;
|
* defaults to 'utf-8'.
|
* @param {Object=} options
|
*/
|
function TextDecoder(label, options) {
|
// Web IDL conventions
|
if (!(this instanceof TextDecoder))
|
throw TypeError('Called as a function. Did you forget \'new\'?');
|
label = label !== undefined ? String(label) : DEFAULT_ENCODING;
|
options = ToDictionary(options);
|
|
// A TextDecoder object has an associated encoding, decoder,
|
// stream, ignore BOM flag (initially unset), BOM seen flag
|
// (initially unset), error mode (initially replacement), and do
|
// not flush flag (initially unset).
|
|
/** @private */
|
this._encoding = null;
|
/** @private @type {?Decoder} */
|
this._decoder = null;
|
/** @private @type {boolean} */
|
this._ignoreBOM = false;
|
/** @private @type {boolean} */
|
this._BOMseen = false;
|
/** @private @type {string} */
|
this._error_mode = 'replacement';
|
/** @private @type {boolean} */
|
this._do_not_flush = false;
|
|
|
// 1. Let encoding be the result of getting an encoding from
|
// label.
|
var encoding = getEncoding(label);
|
|
// 2. If encoding is failure or replacement, throw a RangeError.
|
if (encoding === null || encoding.name === 'replacement')
|
throw RangeError('Unknown encoding: ' + label);
|
if (!decoders[encoding.name]) {
|
throw Error('Decoder not present.' +
|
' Did you forget to include encoding-indexes.js first?');
|
}
|
|
// 3. Let dec be a new TextDecoder object.
|
var dec = this;
|
|
// 4. Set dec's encoding to encoding.
|
dec._encoding = encoding;
|
|
// 5. If options's fatal member is true, set dec's error mode to
|
// fatal.
|
if (Boolean(options['fatal']))
|
dec._error_mode = 'fatal';
|
|
// 6. If options's ignoreBOM member is true, set dec's ignore BOM
|
// flag.
|
if (Boolean(options['ignoreBOM']))
|
dec._ignoreBOM = true;
|
|
// For pre-ES5 runtimes:
|
if (!Object.defineProperty) {
|
this.encoding = dec._encoding.name.toLowerCase();
|
this.fatal = dec._error_mode === 'fatal';
|
this.ignoreBOM = dec._ignoreBOM;
|
}
|
|
// 7. Return dec.
|
return dec;
|
}
|
|
if (Object.defineProperty) {
|
// The encoding attribute's getter must return encoding's name.
|
Object.defineProperty(TextDecoder.prototype, 'encoding', {
|
/** @this {TextDecoder} */
|
get: function() { return this._encoding.name.toLowerCase(); }
|
});
|
|
// The fatal attribute's getter must return true if error mode
|
// is fatal, and false otherwise.
|
Object.defineProperty(TextDecoder.prototype, 'fatal', {
|
/** @this {TextDecoder} */
|
get: function() { return this._error_mode === 'fatal'; }
|
});
|
|
// The ignoreBOM attribute's getter must return true if ignore
|
// BOM flag is set, and false otherwise.
|
Object.defineProperty(TextDecoder.prototype, 'ignoreBOM', {
|
/** @this {TextDecoder} */
|
get: function() { return this._ignoreBOM; }
|
});
|
}
|
|
/**
|
* @param {BufferSource=} input The buffer of bytes to decode.
|
* @param {Object=} options
|
* @return {string} The decoded string.
|
*/
|
TextDecoder.prototype.decode = function decode(input, options) {
|
var bytes;
|
if (typeof input === 'object' && input instanceof ArrayBuffer) {
|
bytes = new Uint8Array(input);
|
} else if (typeof input === 'object' && 'buffer' in input &&
|
input.buffer instanceof ArrayBuffer) {
|
bytes = new Uint8Array(input.buffer,
|
input.byteOffset,
|
input.byteLength);
|
} else {
|
bytes = new Uint8Array(0);
|
}
|
|
options = ToDictionary(options);
|
|
// 1. If the do not flush flag is unset, set decoder to a new
|
// encoding's decoder, set stream to a new stream, and unset the
|
// BOM seen flag.
|
if (!this._do_not_flush) {
|
this._decoder = decoders[this._encoding.name]({
|
fatal: this._error_mode === 'fatal'});
|
this._BOMseen = false;
|
}
|
|
// 2. If options's stream is true, set the do not flush flag, and
|
// unset the do not flush flag otherwise.
|
this._do_not_flush = Boolean(options['stream']);
|
|
// 3. If input is given, push a copy of input to stream.
|
// TODO: Align with spec algorithm - maintain stream on instance.
|
var input_stream = new Stream(bytes);
|
|
// 4. Let output be a new stream.
|
var output = [];
|
|
/** @type {?(number|!Array.<number>)} */
|
var result;
|
|
// 5. While true:
|
while (true) {
|
// 1. Let token be the result of reading from stream.
|
var token = input_stream.read();
|
|
// 2. If token is end-of-stream and the do not flush flag is
|
// set, return output, serialized.
|
// TODO: Align with spec algorithm.
|
if (token === end_of_stream)
|
break;
|
|
// 3. Otherwise, run these subsubsteps:
|
|
// 1. Let result be the result of processing token for decoder,
|
// stream, output, and error mode.
|
result = this._decoder.handler(input_stream, token);
|
|
// 2. If result is finished, return output, serialized.
|
if (result === finished)
|
break;
|
|
if (result !== null) {
|
if (Array.isArray(result))
|
output.push.apply(output, /**@type {!Array.<number>}*/(result));
|
else
|
output.push(result);
|
}
|
|
// 3. Otherwise, if result is error, throw a TypeError.
|
// (Thrown in handler)
|
|
// 4. Otherwise, do nothing.
|
}
|
// TODO: Align with spec algorithm.
|
if (!this._do_not_flush) {
|
do {
|
result = this._decoder.handler(input_stream, input_stream.read());
|
if (result === finished)
|
break;
|
if (result === null)
|
continue;
|
if (Array.isArray(result))
|
output.push.apply(output, /**@type {!Array.<number>}*/(result));
|
else
|
output.push(result);
|
} while (!input_stream.endOfStream());
|
this._decoder = null;
|
}
|
|
// A TextDecoder object also has an associated serialize stream
|
// algorithm...
|
/**
|
* @param {!Array.<number>} stream
|
* @return {string}
|
* @this {TextDecoder}
|
*/
|
function serializeStream(stream) {
|
// 1. Let token be the result of reading from stream.
|
// (Done in-place on array, rather than as a stream)
|
|
// 2. If encoding is UTF-8, UTF-16BE, or UTF-16LE, and ignore
|
// BOM flag and BOM seen flag are unset, run these subsubsteps:
|
if (includes(['UTF-8', 'UTF-16LE', 'UTF-16BE'], this._encoding.name) &&
|
!this._ignoreBOM && !this._BOMseen) {
|
if (stream.length > 0 && stream[0] === 0xFEFF) {
|
// 1. If token is U+FEFF, set BOM seen flag.
|
this._BOMseen = true;
|
stream.shift();
|
} else if (stream.length > 0) {
|
// 2. Otherwise, if token is not end-of-stream, set BOM seen
|
// flag and append token to stream.
|
this._BOMseen = true;
|
} else {
|
// 3. Otherwise, if token is not end-of-stream, append token
|
// to output.
|
// (no-op)
|
}
|
}
|
// 4. Otherwise, return output.
|
return codePointsToString(stream);
|
}
|
|
return serializeStream.call(this, output);
|
};
|
|
// 8.2 Interface TextEncoder
|
|
/**
|
* @constructor
|
* @param {string=} label The label of the encoding. NONSTANDARD.
|
* @param {Object=} options NONSTANDARD.
|
*/
|
function TextEncoder(label, options) {
|
// Web IDL conventions
|
if (!(this instanceof TextEncoder))
|
throw TypeError('Called as a function. Did you forget \'new\'?');
|
options = ToDictionary(options);
|
|
// A TextEncoder object has an associated encoding and encoder.
|
|
/** @private */
|
this._encoding = null;
|
/** @private @type {?Encoder} */
|
this._encoder = null;
|
|
// Non-standard
|
/** @private @type {boolean} */
|
this._do_not_flush = false;
|
/** @private @type {string} */
|
this._fatal = Boolean(options['fatal']) ? 'fatal' : 'replacement';
|
|
// 1. Let enc be a new TextEncoder object.
|
var enc = this;
|
|
// 2. Set enc's encoding to UTF-8's encoder.
|
if (Boolean(options['NONSTANDARD_allowLegacyEncoding'])) {
|
// NONSTANDARD behavior.
|
label = label !== undefined ? String(label) : DEFAULT_ENCODING;
|
var encoding = getEncoding(label);
|
if (encoding === null || encoding.name === 'replacement')
|
throw RangeError('Unknown encoding: ' + label);
|
if (!encoders[encoding.name]) {
|
throw Error('Encoder not present.' +
|
' Did you forget to include encoding-indexes.js first?');
|
}
|
enc._encoding = encoding;
|
} else {
|
// Standard behavior.
|
enc._encoding = getEncoding('utf-8');
|
|
if (label !== undefined && 'console' in global) {
|
console.warn('TextEncoder constructor called with encoding label, '
|
+ 'which is ignored.');
|
}
|
}
|
|
// For pre-ES5 runtimes:
|
if (!Object.defineProperty)
|
this.encoding = enc._encoding.name.toLowerCase();
|
|
// 3. Return enc.
|
return enc;
|
}
|
|
if (Object.defineProperty) {
|
// The encoding attribute's getter must return encoding's name.
|
Object.defineProperty(TextEncoder.prototype, 'encoding', {
|
/** @this {TextEncoder} */
|
get: function() { return this._encoding.name.toLowerCase(); }
|
});
|
}
|
|
/**
|
* @param {string=} opt_string The string to encode.
|
* @param {Object=} options
|
* @return {!Uint8Array} Encoded bytes, as a Uint8Array.
|
*/
|
TextEncoder.prototype.encode = function encode(opt_string, options) {
|
opt_string = opt_string === undefined ? '' : String(opt_string);
|
options = ToDictionary(options);
|
|
// NOTE: This option is nonstandard. None of the encodings
|
// permitted for encoding (i.e. UTF-8, UTF-16) are stateful when
|
// the input is a USVString so streaming is not necessary.
|
if (!this._do_not_flush)
|
this._encoder = encoders[this._encoding.name]({
|
fatal: this._fatal === 'fatal'});
|
this._do_not_flush = Boolean(options['stream']);
|
|
// 1. Convert input to a stream.
|
var input = new Stream(stringToCodePoints(opt_string));
|
|
// 2. Let output be a new stream
|
var output = [];
|
|
/** @type {?(number|!Array.<number>)} */
|
var result;
|
// 3. While true, run these substeps:
|
while (true) {
|
// 1. Let token be the result of reading from input.
|
var token = input.read();
|
if (token === end_of_stream)
|
break;
|
// 2. Let result be the result of processing token for encoder,
|
// input, output.
|
result = this._encoder.handler(input, token);
|
if (result === finished)
|
break;
|
if (Array.isArray(result))
|
output.push.apply(output, /**@type {!Array.<number>}*/(result));
|
else
|
output.push(result);
|
}
|
// TODO: Align with spec algorithm.
|
if (!this._do_not_flush) {
|
while (true) {
|
result = this._encoder.handler(input, input.read());
|
if (result === finished)
|
break;
|
if (Array.isArray(result))
|
output.push.apply(output, /**@type {!Array.<number>}*/(result));
|
else
|
output.push(result);
|
}
|
this._encoder = null;
|
}
|
// 3. If result is finished, convert output into a byte sequence,
|
// and then return a Uint8Array object wrapping an ArrayBuffer
|
// containing output.
|
return new Uint8Array(output);
|
};
|
|
|
//
|
// 9. The encoding
|
//
|
|
// 9.1 utf-8
|
|
// 9.1.1 utf-8 decoder
|
/**
|
* @constructor
|
* @implements {Decoder}
|
* @param {{fatal: boolean}} options
|
*/
|
function UTF8Decoder(options) {
|
var fatal = options.fatal;
|
|
// utf-8's decoder's has an associated utf-8 code point, utf-8
|
// bytes seen, and utf-8 bytes needed (all initially 0), a utf-8
|
// lower boundary (initially 0x80), and a utf-8 upper boundary
|
// (initially 0xBF).
|
var /** @type {number} */ utf8_code_point = 0,
|
/** @type {number} */ utf8_bytes_seen = 0,
|
/** @type {number} */ utf8_bytes_needed = 0,
|
/** @type {number} */ utf8_lower_boundary = 0x80,
|
/** @type {number} */ utf8_upper_boundary = 0xBF;
|
|
/**
|
* @param {Stream} stream The stream of bytes being decoded.
|
* @param {number} bite The next byte read from the stream.
|
* @return {?(number|!Array.<number>)} The next code point(s)
|
* decoded, or null if not enough data exists in the input
|
* stream to decode a complete code point.
|
*/
|
this.handler = function(stream, bite) {
|
// 1. If byte is end-of-stream and utf-8 bytes needed is not 0,
|
// set utf-8 bytes needed to 0 and return error.
|
if (bite === end_of_stream && utf8_bytes_needed !== 0) {
|
utf8_bytes_needed = 0;
|
return decoderError(fatal);
|
}
|
|
// 2. If byte is end-of-stream, return finished.
|
if (bite === end_of_stream)
|
return finished;
|
|
// 3. If utf-8 bytes needed is 0, based on byte:
|
if (utf8_bytes_needed === 0) {
|
|
// 0x00 to 0x7F
|
if (inRange(bite, 0x00, 0x7F)) {
|
// Return a code point whose value is byte.
|
return bite;
|
}
|
|
// 0xC2 to 0xDF
|
else if (inRange(bite, 0xC2, 0xDF)) {
|
// 1. Set utf-8 bytes needed to 1.
|
utf8_bytes_needed = 1;
|
|
// 2. Set UTF-8 code point to byte & 0x1F.
|
utf8_code_point = bite & 0x1F;
|
}
|
|
// 0xE0 to 0xEF
|
else if (inRange(bite, 0xE0, 0xEF)) {
|
// 1. If byte is 0xE0, set utf-8 lower boundary to 0xA0.
|
if (bite === 0xE0)
|
utf8_lower_boundary = 0xA0;
|
// 2. If byte is 0xED, set utf-8 upper boundary to 0x9F.
|
if (bite === 0xED)
|
utf8_upper_boundary = 0x9F;
|
// 3. Set utf-8 bytes needed to 2.
|
utf8_bytes_needed = 2;
|
// 4. Set UTF-8 code point to byte & 0xF.
|
utf8_code_point = bite & 0xF;
|
}
|
|
// 0xF0 to 0xF4
|
else if (inRange(bite, 0xF0, 0xF4)) {
|
// 1. If byte is 0xF0, set utf-8 lower boundary to 0x90.
|
if (bite === 0xF0)
|
utf8_lower_boundary = 0x90;
|
// 2. If byte is 0xF4, set utf-8 upper boundary to 0x8F.
|
if (bite === 0xF4)
|
utf8_upper_boundary = 0x8F;
|
// 3. Set utf-8 bytes needed to 3.
|
utf8_bytes_needed = 3;
|
// 4. Set UTF-8 code point to byte & 0x7.
|
utf8_code_point = bite & 0x7;
|
}
|
|
// Otherwise
|
else {
|
// Return error.
|
return decoderError(fatal);
|
}
|
|
// Return continue.
|
return null;
|
}
|
|
// 4. If byte is not in the range utf-8 lower boundary to utf-8
|
// upper boundary, inclusive, run these substeps:
|
if (!inRange(bite, utf8_lower_boundary, utf8_upper_boundary)) {
|
|
// 1. Set utf-8 code point, utf-8 bytes needed, and utf-8
|
// bytes seen to 0, set utf-8 lower boundary to 0x80, and set
|
// utf-8 upper boundary to 0xBF.
|
utf8_code_point = utf8_bytes_needed = utf8_bytes_seen = 0;
|
utf8_lower_boundary = 0x80;
|
utf8_upper_boundary = 0xBF;
|
|
// 2. Prepend byte to stream.
|
stream.prepend(bite);
|
|
// 3. Return error.
|
return decoderError(fatal);
|
}
|
|
// 5. Set utf-8 lower boundary to 0x80 and utf-8 upper boundary
|
// to 0xBF.
|
utf8_lower_boundary = 0x80;
|
utf8_upper_boundary = 0xBF;
|
|
// 6. Set UTF-8 code point to (UTF-8 code point << 6) | (byte &
|
// 0x3F)
|
utf8_code_point = (utf8_code_point << 6) | (bite & 0x3F);
|
|
// 7. Increase utf-8 bytes seen by one.
|
utf8_bytes_seen += 1;
|
|
// 8. If utf-8 bytes seen is not equal to utf-8 bytes needed,
|
// continue.
|
if (utf8_bytes_seen !== utf8_bytes_needed)
|
return null;
|
|
// 9. Let code point be utf-8 code point.
|
var code_point = utf8_code_point;
|
|
// 10. Set utf-8 code point, utf-8 bytes needed, and utf-8 bytes
|
// seen to 0.
|
utf8_code_point = utf8_bytes_needed = utf8_bytes_seen = 0;
|
|
// 11. Return a code point whose value is code point.
|
return code_point;
|
};
|
}
|
|
// 9.1.2 utf-8 encoder
|
/**
|
* @constructor
|
* @implements {Encoder}
|
* @param {{fatal: boolean}} options
|
*/
|
function UTF8Encoder(options) {
|
var fatal = options.fatal;
|
/**
|
* @param {Stream} stream Input stream.
|
* @param {number} code_point Next code point read from the stream.
|
* @return {(number|!Array.<number>)} Byte(s) to emit.
|
*/
|
this.handler = function(stream, code_point) {
|
// 1. If code point is end-of-stream, return finished.
|
if (code_point === end_of_stream)
|
return finished;
|
|
// 2. If code point is an ASCII code point, return a byte whose
|
// value is code point.
|
if (isASCIICodePoint(code_point))
|
return code_point;
|
|
// 3. Set count and offset based on the range code point is in:
|
var count, offset;
|
// U+0080 to U+07FF, inclusive:
|
if (inRange(code_point, 0x0080, 0x07FF)) {
|
// 1 and 0xC0
|
count = 1;
|
offset = 0xC0;
|
}
|
// U+0800 to U+FFFF, inclusive:
|
else if (inRange(code_point, 0x0800, 0xFFFF)) {
|
// 2 and 0xE0
|
count = 2;
|
offset = 0xE0;
|
}
|
// U+10000 to U+10FFFF, inclusive:
|
else if (inRange(code_point, 0x10000, 0x10FFFF)) {
|
// 3 and 0xF0
|
count = 3;
|
offset = 0xF0;
|
}
|
|
// 4. Let bytes be a byte sequence whose first byte is (code
|
// point >> (6 × count)) + offset.
|
var bytes = [(code_point >> (6 * count)) + offset];
|
|
// 5. Run these substeps while count is greater than 0:
|
while (count > 0) {
|
|
// 1. Set temp to code point >> (6 × (count − 1)).
|
var temp = code_point >> (6 * (count - 1));
|
|
// 2. Append to bytes 0x80 | (temp & 0x3F).
|
bytes.push(0x80 | (temp & 0x3F));
|
|
// 3. Decrease count by one.
|
count -= 1;
|
}
|
|
// 6. Return bytes bytes, in order.
|
return bytes;
|
};
|
}
|
|
/** @param {{fatal: boolean}} options */
|
encoders['UTF-8'] = function(options) {
|
return new UTF8Encoder(options);
|
};
|
/** @param {{fatal: boolean}} options */
|
decoders['UTF-8'] = function(options) {
|
return new UTF8Decoder(options);
|
};
|
|
//
|
// 10. Legacy single-byte encodings
|
//
|
|
// 10.1 single-byte decoder
|
/**
|
* @constructor
|
* @implements {Decoder}
|
* @param {!Array.<number>} index The encoding index.
|
* @param {{fatal: boolean}} options
|
*/
|
function SingleByteDecoder(index, options) {
|
var fatal = options.fatal;
|
/**
|
* @param {Stream} stream The stream of bytes being decoded.
|
* @param {number} bite The next byte read from the stream.
|
* @return {?(number|!Array.<number>)} The next code point(s)
|
* decoded, or null if not enough data exists in the input
|
* stream to decode a complete code point.
|
*/
|
this.handler = function(stream, bite) {
|
// 1. If byte is end-of-stream, return finished.
|
if (bite === end_of_stream)
|
return finished;
|
|
// 2. If byte is an ASCII byte, return a code point whose value
|
// is byte.
|
if (isASCIIByte(bite))
|
return bite;
|
|
// 3. Let code point be the index code point for byte − 0x80 in
|
// index single-byte.
|
var code_point = index[bite - 0x80];
|
|
// 4. If code point is null, return error.
|
if (code_point === null)
|
return decoderError(fatal);
|
|
// 5. Return a code point whose value is code point.
|
return code_point;
|
};
|
}
|
|
// 10.2 single-byte encoder
|
/**
|
* @constructor
|
* @implements {Encoder}
|
* @param {!Array.<?number>} index The encoding index.
|
* @param {{fatal: boolean}} options
|
*/
|
function SingleByteEncoder(index, options) {
|
var fatal = options.fatal;
|
/**
|
* @param {Stream} stream Input stream.
|
* @param {number} code_point Next code point read from the stream.
|
* @return {(number|!Array.<number>)} Byte(s) to emit.
|
*/
|
this.handler = function(stream, code_point) {
|
// 1. If code point is end-of-stream, return finished.
|
if (code_point === end_of_stream)
|
return finished;
|
|
// 2. If code point is an ASCII code point, return a byte whose
|
// value is code point.
|
if (isASCIICodePoint(code_point))
|
return code_point;
|
|
// 3. Let pointer be the index pointer for code point in index
|
// single-byte.
|
var pointer = indexPointerFor(code_point, index);
|
|
// 4. If pointer is null, return error with code point.
|
if (pointer === null)
|
encoderError(code_point);
|
|
// 5. Return a byte whose value is pointer + 0x80.
|
return pointer + 0x80;
|
};
|
}
|
|
(function() {
|
if (!('encoding-indexes' in global))
|
return;
|
encodings.forEach(function(category) {
|
if (category.heading !== 'Legacy single-byte encodings')
|
return;
|
category.encodings.forEach(function(encoding) {
|
var name = encoding.name;
|
var idx = index(name.toLowerCase());
|
/** @param {{fatal: boolean}} options */
|
decoders[name] = function(options) {
|
return new SingleByteDecoder(idx, options);
|
};
|
/** @param {{fatal: boolean}} options */
|
encoders[name] = function(options) {
|
return new SingleByteEncoder(idx, options);
|
};
|
});
|
});
|
}());
|
|
//
|
// 11. Legacy multi-byte Chinese (simplified) encodings
|
//
|
|
// 11.1 gbk
|
|
// 11.1.1 gbk decoder
|
// gbk's decoder is gb18030's decoder.
|
/** @param {{fatal: boolean}} options */
|
decoders['GBK'] = function(options) {
|
return new GB18030Decoder(options);
|
};
|
|
// 11.1.2 gbk encoder
|
// gbk's encoder is gb18030's encoder with its gbk flag set.
|
/** @param {{fatal: boolean}} options */
|
encoders['GBK'] = function(options) {
|
return new GB18030Encoder(options, true);
|
};
|
|
// 11.2 gb18030
|
|
// 11.2.1 gb18030 decoder
|
/**
|
* @constructor
|
* @implements {Decoder}
|
* @param {{fatal: boolean}} options
|
*/
|
function GB18030Decoder(options) {
|
var fatal = options.fatal;
|
// gb18030's decoder has an associated gb18030 first, gb18030
|
// second, and gb18030 third (all initially 0x00).
|
var /** @type {number} */ gb18030_first = 0x00,
|
/** @type {number} */ gb18030_second = 0x00,
|
/** @type {number} */ gb18030_third = 0x00;
|
/**
|
* @param {Stream} stream The stream of bytes being decoded.
|
* @param {number} bite The next byte read from the stream.
|
* @return {?(number|!Array.<number>)} The next code point(s)
|
* decoded, or null if not enough data exists in the input
|
* stream to decode a complete code point.
|
*/
|
this.handler = function(stream, bite) {
|
// 1. If byte is end-of-stream and gb18030 first, gb18030
|
// second, and gb18030 third are 0x00, return finished.
|
if (bite === end_of_stream && gb18030_first === 0x00 &&
|
gb18030_second === 0x00 && gb18030_third === 0x00) {
|
return finished;
|
}
|
// 2. If byte is end-of-stream, and gb18030 first, gb18030
|
// second, or gb18030 third is not 0x00, set gb18030 first,
|
// gb18030 second, and gb18030 third to 0x00, and return error.
|
if (bite === end_of_stream &&
|
(gb18030_first !== 0x00 || gb18030_second !== 0x00 ||
|
gb18030_third !== 0x00)) {
|
gb18030_first = 0x00;
|
gb18030_second = 0x00;
|
gb18030_third = 0x00;
|
decoderError(fatal);
|
}
|
var code_point;
|
// 3. If gb18030 third is not 0x00, run these substeps:
|
if (gb18030_third !== 0x00) {
|
// 1. Let code point be null.
|
code_point = null;
|
// 2. If byte is in the range 0x30 to 0x39, inclusive, set
|
// code point to the index gb18030 ranges code point for
|
// (((gb18030 first − 0x81) × 10 + gb18030 second − 0x30) ×
|
// 126 + gb18030 third − 0x81) × 10 + byte − 0x30.
|
if (inRange(bite, 0x30, 0x39)) {
|
code_point = indexGB18030RangesCodePointFor(
|
(((gb18030_first - 0x81) * 10 + gb18030_second - 0x30) * 126 +
|
gb18030_third - 0x81) * 10 + bite - 0x30);
|
}
|
|
// 3. Let buffer be a byte sequence consisting of gb18030
|
// second, gb18030 third, and byte, in order.
|
var buffer = [gb18030_second, gb18030_third, bite];
|
|
// 4. Set gb18030 first, gb18030 second, and gb18030 third to
|
// 0x00.
|
gb18030_first = 0x00;
|
gb18030_second = 0x00;
|
gb18030_third = 0x00;
|
|
// 5. If code point is null, prepend buffer to stream and
|
// return error.
|
if (code_point === null) {
|
stream.prepend(buffer);
|
return decoderError(fatal);
|
}
|
|
// 6. Return a code point whose value is code point.
|
return code_point;
|
}
|
|
// 4. If gb18030 second is not 0x00, run these substeps:
|
if (gb18030_second !== 0x00) {
|
|
// 1. If byte is in the range 0x81 to 0xFE, inclusive, set
|
// gb18030 third to byte and return continue.
|
if (inRange(bite, 0x81, 0xFE)) {
|
gb18030_third = bite;
|
return null;
|
}
|
|
// 2. Prepend gb18030 second followed by byte to stream, set
|
// gb18030 first and gb18030 second to 0x00, and return error.
|
stream.prepend([gb18030_second, bite]);
|
gb18030_first = 0x00;
|
gb18030_second = 0x00;
|
return decoderError(fatal);
|
}
|
|
// 5. If gb18030 first is not 0x00, run these substeps:
|
if (gb18030_first !== 0x00) {
|
|
// 1. If byte is in the range 0x30 to 0x39, inclusive, set
|
// gb18030 second to byte and return continue.
|
if (inRange(bite, 0x30, 0x39)) {
|
gb18030_second = bite;
|
return null;
|
}
|
|
// 2. Let lead be gb18030 first, let pointer be null, and set
|
// gb18030 first to 0x00.
|
var lead = gb18030_first;
|
var pointer = null;
|
gb18030_first = 0x00;
|
|
// 3. Let offset be 0x40 if byte is less than 0x7F and 0x41
|
// otherwise.
|
var offset = bite < 0x7F ? 0x40 : 0x41;
|
|
// 4. If byte is in the range 0x40 to 0x7E, inclusive, or 0x80
|
// to 0xFE, inclusive, set pointer to (lead − 0x81) × 190 +
|
// (byte − offset).
|
if (inRange(bite, 0x40, 0x7E) || inRange(bite, 0x80, 0xFE))
|
pointer = (lead - 0x81) * 190 + (bite - offset);
|
|
// 5. Let code point be null if pointer is null and the index
|
// code point for pointer in index gb18030 otherwise.
|
code_point = pointer === null ? null :
|
indexCodePointFor(pointer, index('gb18030'));
|
|
// 6. If code point is null and byte is an ASCII byte, prepend
|
// byte to stream.
|
if (code_point === null && isASCIIByte(bite))
|
stream.prepend(bite);
|
|
// 7. If code point is null, return error.
|
if (code_point === null)
|
return decoderError(fatal);
|
|
// 8. Return a code point whose value is code point.
|
return code_point;
|
}
|
|
// 6. If byte is an ASCII byte, return a code point whose value
|
// is byte.
|
if (isASCIIByte(bite))
|
return bite;
|
|
// 7. If byte is 0x80, return code point U+20AC.
|
if (bite === 0x80)
|
return 0x20AC;
|
|
// 8. If byte is in the range 0x81 to 0xFE, inclusive, set
|
// gb18030 first to byte and return continue.
|
if (inRange(bite, 0x81, 0xFE)) {
|
gb18030_first = bite;
|
return null;
|
}
|
|
// 9. Return error.
|
return decoderError(fatal);
|
};
|
}
|
|
// 11.2.2 gb18030 encoder
|
/**
|
* @constructor
|
* @implements {Encoder}
|
* @param {{fatal: boolean}} options
|
* @param {boolean=} gbk_flag
|
*/
|
function GB18030Encoder(options, gbk_flag) {
|
var fatal = options.fatal;
|
// gb18030's decoder has an associated gbk flag (initially unset).
|
/**
|
* @param {Stream} stream Input stream.
|
* @param {number} code_point Next code point read from the stream.
|
* @return {(number|!Array.<number>)} Byte(s) to emit.
|
*/
|
this.handler = function(stream, code_point) {
|
// 1. If code point is end-of-stream, return finished.
|
if (code_point === end_of_stream)
|
return finished;
|
|
// 2. If code point is an ASCII code point, return a byte whose
|
// value is code point.
|
if (isASCIICodePoint(code_point))
|
return code_point;
|
|
// 3. If code point is U+E5E5, return error with code point.
|
if (code_point === 0xE5E5)
|
return encoderError(code_point);
|
|
// 4. If the gbk flag is set and code point is U+20AC, return
|
// byte 0x80.
|
if (gbk_flag && code_point === 0x20AC)
|
return 0x80;
|
|
// 5. Let pointer be the index pointer for code point in index
|
// gb18030.
|
var pointer = indexPointerFor(code_point, index('gb18030'));
|
|
// 6. If pointer is not null, run these substeps:
|
if (pointer !== null) {
|
|
// 1. Let lead be floor(pointer / 190) + 0x81.
|
var lead = floor(pointer / 190) + 0x81;
|
|
// 2. Let trail be pointer % 190.
|
var trail = pointer % 190;
|
|
// 3. Let offset be 0x40 if trail is less than 0x3F and 0x41 otherwise.
|
var offset = trail < 0x3F ? 0x40 : 0x41;
|
|
// 4. Return two bytes whose values are lead and trail + offset.
|
return [lead, trail + offset];
|
}
|
|
// 7. If gbk flag is set, return error with code point.
|
if (gbk_flag)
|
return encoderError(code_point);
|
|
// 8. Set pointer to the index gb18030 ranges pointer for code
|
// point.
|
pointer = indexGB18030RangesPointerFor(code_point);
|
|
// 9. Let byte1 be floor(pointer / 10 / 126 / 10).
|
var byte1 = floor(pointer / 10 / 126 / 10);
|
|
// 10. Set pointer to pointer − byte1 × 10 × 126 × 10.
|
pointer = pointer - byte1 * 10 * 126 * 10;
|
|
// 11. Let byte2 be floor(pointer / 10 / 126).
|
var byte2 = floor(pointer / 10 / 126);
|
|
// 12. Set pointer to pointer − byte2 × 10 × 126.
|
pointer = pointer - byte2 * 10 * 126;
|
|
// 13. Let byte3 be floor(pointer / 10).
|
var byte3 = floor(pointer / 10);
|
|
// 14. Let byte4 be pointer − byte3 × 10.
|
var byte4 = pointer - byte3 * 10;
|
|
// 15. Return four bytes whose values are byte1 + 0x81, byte2 +
|
// 0x30, byte3 + 0x81, byte4 + 0x30.
|
return [byte1 + 0x81,
|
byte2 + 0x30,
|
byte3 + 0x81,
|
byte4 + 0x30];
|
};
|
}
|
|
/** @param {{fatal: boolean}} options */
|
encoders['gb18030'] = function(options) {
|
return new GB18030Encoder(options);
|
};
|
/** @param {{fatal: boolean}} options */
|
decoders['gb18030'] = function(options) {
|
return new GB18030Decoder(options);
|
};
|
|
|
//
|
// 12. Legacy multi-byte Chinese (traditional) encodings
|
//
|
|
// 12.1 Big5
|
|
// 12.1.1 Big5 decoder
|
/**
|
* @constructor
|
* @implements {Decoder}
|
* @param {{fatal: boolean}} options
|
*/
|
function Big5Decoder(options) {
|
var fatal = options.fatal;
|
// Big5's decoder has an associated Big5 lead (initially 0x00).
|
var /** @type {number} */ Big5_lead = 0x00;
|
|
/**
|
* @param {Stream} stream The stream of bytes being decoded.
|
* @param {number} bite The next byte read from the stream.
|
* @return {?(number|!Array.<number>)} The next code point(s)
|
* decoded, or null if not enough data exists in the input
|
* stream to decode a complete code point.
|
*/
|
this.handler = function(stream, bite) {
|
// 1. If byte is end-of-stream and Big5 lead is not 0x00, set
|
// Big5 lead to 0x00 and return error.
|
if (bite === end_of_stream && Big5_lead !== 0x00) {
|
Big5_lead = 0x00;
|
return decoderError(fatal);
|
}
|
|
// 2. If byte is end-of-stream and Big5 lead is 0x00, return
|
// finished.
|
if (bite === end_of_stream && Big5_lead === 0x00)
|
return finished;
|
|
// 3. If Big5 lead is not 0x00, let lead be Big5 lead, let
|
// pointer be null, set Big5 lead to 0x00, and then run these
|
// substeps:
|
if (Big5_lead !== 0x00) {
|
var lead = Big5_lead;
|
var pointer = null;
|
Big5_lead = 0x00;
|
|
// 1. Let offset be 0x40 if byte is less than 0x7F and 0x62
|
// otherwise.
|
var offset = bite < 0x7F ? 0x40 : 0x62;
|
|
// 2. If byte is in the range 0x40 to 0x7E, inclusive, or 0xA1
|
// to 0xFE, inclusive, set pointer to (lead − 0x81) × 157 +
|
// (byte − offset).
|
if (inRange(bite, 0x40, 0x7E) || inRange(bite, 0xA1, 0xFE))
|
pointer = (lead - 0x81) * 157 + (bite - offset);
|
|
// 3. If there is a row in the table below whose first column
|
// is pointer, return the two code points listed in its second
|
// column
|
// Pointer | Code points
|
// --------+--------------
|
// 1133 | U+00CA U+0304
|
// 1135 | U+00CA U+030C
|
// 1164 | U+00EA U+0304
|
// 1166 | U+00EA U+030C
|
switch (pointer) {
|
case 1133: return [0x00CA, 0x0304];
|
case 1135: return [0x00CA, 0x030C];
|
case 1164: return [0x00EA, 0x0304];
|
case 1166: return [0x00EA, 0x030C];
|
}
|
|
// 4. Let code point be null if pointer is null and the index
|
// code point for pointer in index Big5 otherwise.
|
var code_point = (pointer === null) ? null :
|
indexCodePointFor(pointer, index('big5'));
|
|
// 5. If code point is null and byte is an ASCII byte, prepend
|
// byte to stream.
|
if (code_point === null && isASCIIByte(bite))
|
stream.prepend(bite);
|
|
// 6. If code point is null, return error.
|
if (code_point === null)
|
return decoderError(fatal);
|
|
// 7. Return a code point whose value is code point.
|
return code_point;
|
}
|
|
// 4. If byte is an ASCII byte, return a code point whose value
|
// is byte.
|
if (isASCIIByte(bite))
|
return bite;
|
|
// 5. If byte is in the range 0x81 to 0xFE, inclusive, set Big5
|
// lead to byte and return continue.
|
if (inRange(bite, 0x81, 0xFE)) {
|
Big5_lead = bite;
|
return null;
|
}
|
|
// 6. Return error.
|
return decoderError(fatal);
|
};
|
}
|
|
// 12.1.2 Big5 encoder
|
/**
|
* @constructor
|
* @implements {Encoder}
|
* @param {{fatal: boolean}} options
|
*/
|
function Big5Encoder(options) {
|
var fatal = options.fatal;
|
/**
|
* @param {Stream} stream Input stream.
|
* @param {number} code_point Next code point read from the stream.
|
* @return {(number|!Array.<number>)} Byte(s) to emit.
|
*/
|
this.handler = function(stream, code_point) {
|
// 1. If code point is end-of-stream, return finished.
|
if (code_point === end_of_stream)
|
return finished;
|
|
// 2. If code point is an ASCII code point, return a byte whose
|
// value is code point.
|
if (isASCIICodePoint(code_point))
|
return code_point;
|
|
// 3. Let pointer be the index Big5 pointer for code point.
|
var pointer = indexBig5PointerFor(code_point);
|
|
// 4. If pointer is null, return error with code point.
|
if (pointer === null)
|
return encoderError(code_point);
|
|
// 5. Let lead be floor(pointer / 157) + 0x81.
|
var lead = floor(pointer / 157) + 0x81;
|
|
// 6. If lead is less than 0xA1, return error with code point.
|
if (lead < 0xA1)
|
return encoderError(code_point);
|
|
// 7. Let trail be pointer % 157.
|
var trail = pointer % 157;
|
|
// 8. Let offset be 0x40 if trail is less than 0x3F and 0x62
|
// otherwise.
|
var offset = trail < 0x3F ? 0x40 : 0x62;
|
|
// Return two bytes whose values are lead and trail + offset.
|
return [lead, trail + offset];
|
};
|
}
|
|
/** @param {{fatal: boolean}} options */
|
encoders['Big5'] = function(options) {
|
return new Big5Encoder(options);
|
};
|
/** @param {{fatal: boolean}} options */
|
decoders['Big5'] = function(options) {
|
return new Big5Decoder(options);
|
};
|
|
|
//
|
// 13. Legacy multi-byte Japanese encodings
|
//
|
|
// 13.1 euc-jp
|
|
// 13.1.1 euc-jp decoder
|
/**
|
* @constructor
|
* @implements {Decoder}
|
* @param {{fatal: boolean}} options
|
*/
|
function EUCJPDecoder(options) {
|
var fatal = options.fatal;
|
|
// euc-jp's decoder has an associated euc-jp jis0212 flag
|
// (initially unset) and euc-jp lead (initially 0x00).
|
var /** @type {boolean} */ eucjp_jis0212_flag = false,
|
/** @type {number} */ eucjp_lead = 0x00;
|
|
/**
|
* @param {Stream} stream The stream of bytes being decoded.
|
* @param {number} bite The next byte read from the stream.
|
* @return {?(number|!Array.<number>)} The next code point(s)
|
* decoded, or null if not enough data exists in the input
|
* stream to decode a complete code point.
|
*/
|
this.handler = function(stream, bite) {
|
// 1. If byte is end-of-stream and euc-jp lead is not 0x00, set
|
// euc-jp lead to 0x00, and return error.
|
if (bite === end_of_stream && eucjp_lead !== 0x00) {
|
eucjp_lead = 0x00;
|
return decoderError(fatal);
|
}
|
|
// 2. If byte is end-of-stream and euc-jp lead is 0x00, return
|
// finished.
|
if (bite === end_of_stream && eucjp_lead === 0x00)
|
return finished;
|
|
// 3. If euc-jp lead is 0x8E and byte is in the range 0xA1 to
|
// 0xDF, inclusive, set euc-jp lead to 0x00 and return a code
|
// point whose value is 0xFF61 − 0xA1 + byte.
|
if (eucjp_lead === 0x8E && inRange(bite, 0xA1, 0xDF)) {
|
eucjp_lead = 0x00;
|
return 0xFF61 - 0xA1 + bite;
|
}
|
|
// 4. If euc-jp lead is 0x8F and byte is in the range 0xA1 to
|
// 0xFE, inclusive, set the euc-jp jis0212 flag, set euc-jp lead
|
// to byte, and return continue.
|
if (eucjp_lead === 0x8F && inRange(bite, 0xA1, 0xFE)) {
|
eucjp_jis0212_flag = true;
|
eucjp_lead = bite;
|
return null;
|
}
|
|
// 5. If euc-jp lead is not 0x00, let lead be euc-jp lead, set
|
// euc-jp lead to 0x00, and run these substeps:
|
if (eucjp_lead !== 0x00) {
|
var lead = eucjp_lead;
|
eucjp_lead = 0x00;
|
|
// 1. Let code point be null.
|
var code_point = null;
|
|
// 2. If lead and byte are both in the range 0xA1 to 0xFE,
|
// inclusive, set code point to the index code point for (lead
|
// − 0xA1) × 94 + byte − 0xA1 in index jis0208 if the euc-jp
|
// jis0212 flag is unset and in index jis0212 otherwise.
|
if (inRange(lead, 0xA1, 0xFE) && inRange(bite, 0xA1, 0xFE)) {
|
code_point = indexCodePointFor(
|
(lead - 0xA1) * 94 + (bite - 0xA1),
|
index(!eucjp_jis0212_flag ? 'jis0208' : 'jis0212'));
|
}
|
|
// 3. Unset the euc-jp jis0212 flag.
|
eucjp_jis0212_flag = false;
|
|
// 4. If byte is not in the range 0xA1 to 0xFE, inclusive,
|
// prepend byte to stream.
|
if (!inRange(bite, 0xA1, 0xFE))
|
stream.prepend(bite);
|
|
// 5. If code point is null, return error.
|
if (code_point === null)
|
return decoderError(fatal);
|
|
// 6. Return a code point whose value is code point.
|
return code_point;
|
}
|
|
// 6. If byte is an ASCII byte, return a code point whose value
|
// is byte.
|
if (isASCIIByte(bite))
|
return bite;
|
|
// 7. If byte is 0x8E, 0x8F, or in the range 0xA1 to 0xFE,
|
// inclusive, set euc-jp lead to byte and return continue.
|
if (bite === 0x8E || bite === 0x8F || inRange(bite, 0xA1, 0xFE)) {
|
eucjp_lead = bite;
|
return null;
|
}
|
|
// 8. Return error.
|
return decoderError(fatal);
|
};
|
}
|
|
// 13.1.2 euc-jp encoder
|
/**
|
* @constructor
|
* @implements {Encoder}
|
* @param {{fatal: boolean}} options
|
*/
|
function EUCJPEncoder(options) {
|
var fatal = options.fatal;
|
/**
|
* @param {Stream} stream Input stream.
|
* @param {number} code_point Next code point read from the stream.
|
* @return {(number|!Array.<number>)} Byte(s) to emit.
|
*/
|
this.handler = function(stream, code_point) {
|
// 1. If code point is end-of-stream, return finished.
|
if (code_point === end_of_stream)
|
return finished;
|
|
// 2. If code point is an ASCII code point, return a byte whose
|
// value is code point.
|
if (isASCIICodePoint(code_point))
|
return code_point;
|
|
// 3. If code point is U+00A5, return byte 0x5C.
|
if (code_point === 0x00A5)
|
return 0x5C;
|
|
// 4. If code point is U+203E, return byte 0x7E.
|
if (code_point === 0x203E)
|
return 0x7E;
|
|
// 5. If code point is in the range U+FF61 to U+FF9F, inclusive,
|
// return two bytes whose values are 0x8E and code point −
|
// 0xFF61 + 0xA1.
|
if (inRange(code_point, 0xFF61, 0xFF9F))
|
return [0x8E, code_point - 0xFF61 + 0xA1];
|
|
// 6. If code point is U+2212, set it to U+FF0D.
|
if (code_point === 0x2212)
|
code_point = 0xFF0D;
|
|
// 7. Let pointer be the index pointer for code point in index
|
// jis0208.
|
var pointer = indexPointerFor(code_point, index('jis0208'));
|
|
// 8. If pointer is null, return error with code point.
|
if (pointer === null)
|
return encoderError(code_point);
|
|
// 9. Let lead be floor(pointer / 94) + 0xA1.
|
var lead = floor(pointer / 94) + 0xA1;
|
|
// 10. Let trail be pointer % 94 + 0xA1.
|
var trail = pointer % 94 + 0xA1;
|
|
// 11. Return two bytes whose values are lead and trail.
|
return [lead, trail];
|
};
|
}
|
|
/** @param {{fatal: boolean}} options */
|
encoders['EUC-JP'] = function(options) {
|
return new EUCJPEncoder(options);
|
};
|
/** @param {{fatal: boolean}} options */
|
decoders['EUC-JP'] = function(options) {
|
return new EUCJPDecoder(options);
|
};
|
|
// 13.2 iso-2022-jp
|
|
// 13.2.1 iso-2022-jp decoder
|
/**
|
* @constructor
|
* @implements {Decoder}
|
* @param {{fatal: boolean}} options
|
*/
|
function ISO2022JPDecoder(options) {
|
var fatal = options.fatal;
|
/** @enum */
|
var states = {
|
ASCII: 0,
|
Roman: 1,
|
Katakana: 2,
|
LeadByte: 3,
|
TrailByte: 4,
|
EscapeStart: 5,
|
Escape: 6
|
};
|
// iso-2022-jp's decoder has an associated iso-2022-jp decoder
|
// state (initially ASCII), iso-2022-jp decoder output state
|
// (initially ASCII), iso-2022-jp lead (initially 0x00), and
|
// iso-2022-jp output flag (initially unset).
|
var /** @type {number} */ iso2022jp_decoder_state = states.ASCII,
|
/** @type {number} */ iso2022jp_decoder_output_state = states.ASCII,
|
/** @type {number} */ iso2022jp_lead = 0x00,
|
/** @type {boolean} */ iso2022jp_output_flag = false;
|
/**
|
* @param {Stream} stream The stream of bytes being decoded.
|
* @param {number} bite The next byte read from the stream.
|
* @return {?(number|!Array.<number>)} The next code point(s)
|
* decoded, or null if not enough data exists in the input
|
* stream to decode a complete code point.
|
*/
|
this.handler = function(stream, bite) {
|
// switching on iso-2022-jp decoder state:
|
switch (iso2022jp_decoder_state) {
|
default:
|
case states.ASCII:
|
// ASCII
|
// Based on byte:
|
|
// 0x1B
|
if (bite === 0x1B) {
|
// Set iso-2022-jp decoder state to escape start and return
|
// continue.
|
iso2022jp_decoder_state = states.EscapeStart;
|
return null;
|
}
|
|
// 0x00 to 0x7F, excluding 0x0E, 0x0F, and 0x1B
|
if (inRange(bite, 0x00, 0x7F) && bite !== 0x0E
|
&& bite !== 0x0F && bite !== 0x1B) {
|
// Unset the iso-2022-jp output flag and return a code point
|
// whose value is byte.
|
iso2022jp_output_flag = false;
|
return bite;
|
}
|
|
// end-of-stream
|
if (bite === end_of_stream) {
|
// Return finished.
|
return finished;
|
}
|
|
// Otherwise
|
// Unset the iso-2022-jp output flag and return error.
|
iso2022jp_output_flag = false;
|
return decoderError(fatal);
|
|
case states.Roman:
|
// Roman
|
// Based on byte:
|
|
// 0x1B
|
if (bite === 0x1B) {
|
// Set iso-2022-jp decoder state to escape start and return
|
// continue.
|
iso2022jp_decoder_state = states.EscapeStart;
|
return null;
|
}
|
|
// 0x5C
|
if (bite === 0x5C) {
|
// Unset the iso-2022-jp output flag and return code point
|
// U+00A5.
|
iso2022jp_output_flag = false;
|
return 0x00A5;
|
}
|
|
// 0x7E
|
if (bite === 0x7E) {
|
// Unset the iso-2022-jp output flag and return code point
|
// U+203E.
|
iso2022jp_output_flag = false;
|
return 0x203E;
|
}
|
|
// 0x00 to 0x7F, excluding 0x0E, 0x0F, 0x1B, 0x5C, and 0x7E
|
if (inRange(bite, 0x00, 0x7F) && bite !== 0x0E && bite !== 0x0F
|
&& bite !== 0x1B && bite !== 0x5C && bite !== 0x7E) {
|
// Unset the iso-2022-jp output flag and return a code point
|
// whose value is byte.
|
iso2022jp_output_flag = false;
|
return bite;
|
}
|
|
// end-of-stream
|
if (bite === end_of_stream) {
|
// Return finished.
|
return finished;
|
}
|
|
// Otherwise
|
// Unset the iso-2022-jp output flag and return error.
|
iso2022jp_output_flag = false;
|
return decoderError(fatal);
|
|
case states.Katakana:
|
// Katakana
|
// Based on byte:
|
|
// 0x1B
|
if (bite === 0x1B) {
|
// Set iso-2022-jp decoder state to escape start and return
|
// continue.
|
iso2022jp_decoder_state = states.EscapeStart;
|
return null;
|
}
|
|
// 0x21 to 0x5F
|
if (inRange(bite, 0x21, 0x5F)) {
|
// Unset the iso-2022-jp output flag and return a code point
|
// whose value is 0xFF61 − 0x21 + byte.
|
iso2022jp_output_flag = false;
|
return 0xFF61 - 0x21 + bite;
|
}
|
|
// end-of-stream
|
if (bite === end_of_stream) {
|
// Return finished.
|
return finished;
|
}
|
|
// Otherwise
|
// Unset the iso-2022-jp output flag and return error.
|
iso2022jp_output_flag = false;
|
return decoderError(fatal);
|
|
case states.LeadByte:
|
// Lead byte
|
// Based on byte:
|
|
// 0x1B
|
if (bite === 0x1B) {
|
// Set iso-2022-jp decoder state to escape start and return
|
// continue.
|
iso2022jp_decoder_state = states.EscapeStart;
|
return null;
|
}
|
|
// 0x21 to 0x7E
|
if (inRange(bite, 0x21, 0x7E)) {
|
// Unset the iso-2022-jp output flag, set iso-2022-jp lead
|
// to byte, iso-2022-jp decoder state to trail byte, and
|
// return continue.
|
iso2022jp_output_flag = false;
|
iso2022jp_lead = bite;
|
iso2022jp_decoder_state = states.TrailByte;
|
return null;
|
}
|
|
// end-of-stream
|
if (bite === end_of_stream) {
|
// Return finished.
|
return finished;
|
}
|
|
// Otherwise
|
// Unset the iso-2022-jp output flag and return error.
|
iso2022jp_output_flag = false;
|
return decoderError(fatal);
|
|
case states.TrailByte:
|
// Trail byte
|
// Based on byte:
|
|
// 0x1B
|
if (bite === 0x1B) {
|
// Set iso-2022-jp decoder state to escape start and return
|
// continue.
|
iso2022jp_decoder_state = states.EscapeStart;
|
return decoderError(fatal);
|
}
|
|
// 0x21 to 0x7E
|
if (inRange(bite, 0x21, 0x7E)) {
|
// 1. Set the iso-2022-jp decoder state to lead byte.
|
iso2022jp_decoder_state = states.LeadByte;
|
|
// 2. Let pointer be (iso-2022-jp lead − 0x21) × 94 + byte − 0x21.
|
var pointer = (iso2022jp_lead - 0x21) * 94 + bite - 0x21;
|
|
// 3. Let code point be the index code point for pointer in
|
// index jis0208.
|
var code_point = indexCodePointFor(pointer, index('jis0208'));
|
|
// 4. If code point is null, return error.
|
if (code_point === null)
|
return decoderError(fatal);
|
|
// 5. Return a code point whose value is code point.
|
return code_point;
|
}
|
|
// end-of-stream
|
if (bite === end_of_stream) {
|
// Set the iso-2022-jp decoder state to lead byte, prepend
|
// byte to stream, and return error.
|
iso2022jp_decoder_state = states.LeadByte;
|
stream.prepend(bite);
|
return decoderError(fatal);
|
}
|
|
// Otherwise
|
// Set iso-2022-jp decoder state to lead byte and return
|
// error.
|
iso2022jp_decoder_state = states.LeadByte;
|
return decoderError(fatal);
|
|
case states.EscapeStart:
|
// Escape start
|
|
// 1. If byte is either 0x24 or 0x28, set iso-2022-jp lead to
|
// byte, iso-2022-jp decoder state to escape, and return
|
// continue.
|
if (bite === 0x24 || bite === 0x28) {
|
iso2022jp_lead = bite;
|
iso2022jp_decoder_state = states.Escape;
|
return null;
|
}
|
|
// 2. Prepend byte to stream.
|
stream.prepend(bite);
|
|
// 3. Unset the iso-2022-jp output flag, set iso-2022-jp
|
// decoder state to iso-2022-jp decoder output state, and
|
// return error.
|
iso2022jp_output_flag = false;
|
iso2022jp_decoder_state = iso2022jp_decoder_output_state;
|
return decoderError(fatal);
|
|
case states.Escape:
|
// Escape
|
|
// 1. Let lead be iso-2022-jp lead and set iso-2022-jp lead to
|
// 0x00.
|
var lead = iso2022jp_lead;
|
iso2022jp_lead = 0x00;
|
|
// 2. Let state be null.
|
var state = null;
|
|
// 3. If lead is 0x28 and byte is 0x42, set state to ASCII.
|
if (lead === 0x28 && bite === 0x42)
|
state = states.ASCII;
|
|
// 4. If lead is 0x28 and byte is 0x4A, set state to Roman.
|
if (lead === 0x28 && bite === 0x4A)
|
state = states.Roman;
|
|
// 5. If lead is 0x28 and byte is 0x49, set state to Katakana.
|
if (lead === 0x28 && bite === 0x49)
|
state = states.Katakana;
|
|
// 6. If lead is 0x24 and byte is either 0x40 or 0x42, set
|
// state to lead byte.
|
if (lead === 0x24 && (bite === 0x40 || bite === 0x42))
|
state = states.LeadByte;
|
|
// 7. If state is non-null, run these substeps:
|
if (state !== null) {
|
// 1. Set iso-2022-jp decoder state and iso-2022-jp decoder
|
// output state to states.
|
iso2022jp_decoder_state = iso2022jp_decoder_state = state;
|
|
// 2. Let output flag be the iso-2022-jp output flag.
|
var output_flag = iso2022jp_output_flag;
|
|
// 3. Set the iso-2022-jp output flag.
|
iso2022jp_output_flag = true;
|
|
// 4. Return continue, if output flag is unset, and error
|
// otherwise.
|
return !output_flag ? null : decoderError(fatal);
|
}
|
|
// 8. Prepend lead and byte to stream.
|
stream.prepend([lead, bite]);
|
|
// 9. Unset the iso-2022-jp output flag, set iso-2022-jp
|
// decoder state to iso-2022-jp decoder output state and
|
// return error.
|
iso2022jp_output_flag = false;
|
iso2022jp_decoder_state = iso2022jp_decoder_output_state;
|
return decoderError(fatal);
|
}
|
};
|
}
|
|
// 13.2.2 iso-2022-jp encoder
|
/**
|
* @constructor
|
* @implements {Encoder}
|
* @param {{fatal: boolean}} options
|
*/
|
function ISO2022JPEncoder(options) {
|
var fatal = options.fatal;
|
// iso-2022-jp's encoder has an associated iso-2022-jp encoder
|
// state which is one of ASCII, Roman, and jis0208 (initially
|
// ASCII).
|
/** @enum */
|
var states = {
|
ASCII: 0,
|
Roman: 1,
|
jis0208: 2
|
};
|
var /** @type {number} */ iso2022jp_state = states.ASCII;
|
/**
|
* @param {Stream} stream Input stream.
|
* @param {number} code_point Next code point read from the stream.
|
* @return {(number|!Array.<number>)} Byte(s) to emit.
|
*/
|
this.handler = function(stream, code_point) {
|
// 1. If code point is end-of-stream and iso-2022-jp encoder
|
// state is not ASCII, prepend code point to stream, set
|
// iso-2022-jp encoder state to ASCII, and return three bytes
|
// 0x1B 0x28 0x42.
|
if (code_point === end_of_stream &&
|
iso2022jp_state !== states.ASCII) {
|
stream.prepend(code_point);
|
iso2022jp_state = states.ASCII;
|
return [0x1B, 0x28, 0x42];
|
}
|
|
// 2. If code point is end-of-stream and iso-2022-jp encoder
|
// state is ASCII, return finished.
|
if (code_point === end_of_stream && iso2022jp_state === states.ASCII)
|
return finished;
|
|
// 3. If ISO-2022-JP encoder state is ASCII or Roman, and code
|
// point is U+000E, U+000F, or U+001B, return error with U+FFFD.
|
if ((iso2022jp_state === states.ASCII ||
|
iso2022jp_state === states.Roman) &&
|
(code_point === 0x000E || code_point === 0x000F ||
|
code_point === 0x001B)) {
|
return encoderError(0xFFFD);
|
}
|
|
// 4. If iso-2022-jp encoder state is ASCII and code point is an
|
// ASCII code point, return a byte whose value is code point.
|
if (iso2022jp_state === states.ASCII &&
|
isASCIICodePoint(code_point))
|
return code_point;
|
|
// 5. If iso-2022-jp encoder state is Roman and code point is an
|
// ASCII code point, excluding U+005C and U+007E, or is U+00A5
|
// or U+203E, run these substeps:
|
if (iso2022jp_state === states.Roman &&
|
((isASCIICodePoint(code_point) &&
|
code_point !== 0x005C && code_point !== 0x007E) ||
|
(code_point == 0x00A5 || code_point == 0x203E))) {
|
|
// 1. If code point is an ASCII code point, return a byte
|
// whose value is code point.
|
if (isASCIICodePoint(code_point))
|
return code_point;
|
|
// 2. If code point is U+00A5, return byte 0x5C.
|
if (code_point === 0x00A5)
|
return 0x5C;
|
|
// 3. If code point is U+203E, return byte 0x7E.
|
if (code_point === 0x203E)
|
return 0x7E;
|
}
|
|
// 6. If code point is an ASCII code point, and iso-2022-jp
|
// encoder state is not ASCII, prepend code point to stream, set
|
// iso-2022-jp encoder state to ASCII, and return three bytes
|
// 0x1B 0x28 0x42.
|
if (isASCIICodePoint(code_point) &&
|
iso2022jp_state !== states.ASCII) {
|
stream.prepend(code_point);
|
iso2022jp_state = states.ASCII;
|
return [0x1B, 0x28, 0x42];
|
}
|
|
// 7. If code point is either U+00A5 or U+203E, and iso-2022-jp
|
// encoder state is not Roman, prepend code point to stream, set
|
// iso-2022-jp encoder state to Roman, and return three bytes
|
// 0x1B 0x28 0x4A.
|
if ((code_point === 0x00A5 || code_point === 0x203E) &&
|
iso2022jp_state !== states.Roman) {
|
stream.prepend(code_point);
|
iso2022jp_state = states.Roman;
|
return [0x1B, 0x28, 0x4A];
|
}
|
|
// 8. If code point is U+2212, set it to U+FF0D.
|
if (code_point === 0x2212)
|
code_point = 0xFF0D;
|
|
// 9. Let pointer be the index pointer for code point in index
|
// jis0208.
|
var pointer = indexPointerFor(code_point, index('jis0208'));
|
|
// 10. If pointer is null, return error with code point.
|
if (pointer === null)
|
return encoderError(code_point);
|
|
// 11. If iso-2022-jp encoder state is not jis0208, prepend code
|
// point to stream, set iso-2022-jp encoder state to jis0208,
|
// and return three bytes 0x1B 0x24 0x42.
|
if (iso2022jp_state !== states.jis0208) {
|
stream.prepend(code_point);
|
iso2022jp_state = states.jis0208;
|
return [0x1B, 0x24, 0x42];
|
}
|
|
// 12. Let lead be floor(pointer / 94) + 0x21.
|
var lead = floor(pointer / 94) + 0x21;
|
|
// 13. Let trail be pointer % 94 + 0x21.
|
var trail = pointer % 94 + 0x21;
|
|
// 14. Return two bytes whose values are lead and trail.
|
return [lead, trail];
|
};
|
}
|
|
/** @param {{fatal: boolean}} options */
|
encoders['ISO-2022-JP'] = function(options) {
|
return new ISO2022JPEncoder(options);
|
};
|
/** @param {{fatal: boolean}} options */
|
decoders['ISO-2022-JP'] = function(options) {
|
return new ISO2022JPDecoder(options);
|
};
|
|
// 13.3 Shift_JIS
|
|
// 13.3.1 Shift_JIS decoder
|
/**
|
* @constructor
|
* @implements {Decoder}
|
* @param {{fatal: boolean}} options
|
*/
|
function ShiftJISDecoder(options) {
|
var fatal = options.fatal;
|
// Shift_JIS's decoder has an associated Shift_JIS lead (initially
|
// 0x00).
|
var /** @type {number} */ Shift_JIS_lead = 0x00;
|
/**
|
* @param {Stream} stream The stream of bytes being decoded.
|
* @param {number} bite The next byte read from the stream.
|
* @return {?(number|!Array.<number>)} The next code point(s)
|
* decoded, or null if not enough data exists in the input
|
* stream to decode a complete code point.
|
*/
|
this.handler = function(stream, bite) {
|
// 1. If byte is end-of-stream and Shift_JIS lead is not 0x00,
|
// set Shift_JIS lead to 0x00 and return error.
|
if (bite === end_of_stream && Shift_JIS_lead !== 0x00) {
|
Shift_JIS_lead = 0x00;
|
return decoderError(fatal);
|
}
|
|
// 2. If byte is end-of-stream and Shift_JIS lead is 0x00,
|
// return finished.
|
if (bite === end_of_stream && Shift_JIS_lead === 0x00)
|
return finished;
|
|
// 3. If Shift_JIS lead is not 0x00, let lead be Shift_JIS lead,
|
// let pointer be null, set Shift_JIS lead to 0x00, and then run
|
// these substeps:
|
if (Shift_JIS_lead !== 0x00) {
|
var lead = Shift_JIS_lead;
|
var pointer = null;
|
Shift_JIS_lead = 0x00;
|
|
// 1. Let offset be 0x40, if byte is less than 0x7F, and 0x41
|
// otherwise.
|
var offset = (bite < 0x7F) ? 0x40 : 0x41;
|
|
// 2. Let lead offset be 0x81, if lead is less than 0xA0, and
|
// 0xC1 otherwise.
|
var lead_offset = (lead < 0xA0) ? 0x81 : 0xC1;
|
|
// 3. If byte is in the range 0x40 to 0x7E, inclusive, or 0x80
|
// to 0xFC, inclusive, set pointer to (lead − lead offset) ×
|
// 188 + byte − offset.
|
if (inRange(bite, 0x40, 0x7E) || inRange(bite, 0x80, 0xFC))
|
pointer = (lead - lead_offset) * 188 + bite - offset;
|
|
// 4. If pointer is in the range 8836 to 10715, inclusive,
|
// return a code point whose value is 0xE000 − 8836 + pointer.
|
if (inRange(pointer, 8836, 10715))
|
return 0xE000 - 8836 + pointer;
|
|
// 5. Let code point be null, if pointer is null, and the
|
// index code point for pointer in index jis0208 otherwise.
|
var code_point = (pointer === null) ? null :
|
indexCodePointFor(pointer, index('jis0208'));
|
|
// 6. If code point is null and byte is an ASCII byte, prepend
|
// byte to stream.
|
if (code_point === null && isASCIIByte(bite))
|
stream.prepend(bite);
|
|
// 7. If code point is null, return error.
|
if (code_point === null)
|
return decoderError(fatal);
|
|
// 8. Return a code point whose value is code point.
|
return code_point;
|
}
|
|
// 4. If byte is an ASCII byte or 0x80, return a code point
|
// whose value is byte.
|
if (isASCIIByte(bite) || bite === 0x80)
|
return bite;
|
|
// 5. If byte is in the range 0xA1 to 0xDF, inclusive, return a
|
// code point whose value is 0xFF61 − 0xA1 + byte.
|
if (inRange(bite, 0xA1, 0xDF))
|
return 0xFF61 - 0xA1 + bite;
|
|
// 6. If byte is in the range 0x81 to 0x9F, inclusive, or 0xE0
|
// to 0xFC, inclusive, set Shift_JIS lead to byte and return
|
// continue.
|
if (inRange(bite, 0x81, 0x9F) || inRange(bite, 0xE0, 0xFC)) {
|
Shift_JIS_lead = bite;
|
return null;
|
}
|
|
// 7. Return error.
|
return decoderError(fatal);
|
};
|
}
|
|
// 13.3.2 Shift_JIS encoder
|
/**
|
* @constructor
|
* @implements {Encoder}
|
* @param {{fatal: boolean}} options
|
*/
|
function ShiftJISEncoder(options) {
|
var fatal = options.fatal;
|
/**
|
* @param {Stream} stream Input stream.
|
* @param {number} code_point Next code point read from the stream.
|
* @return {(number|!Array.<number>)} Byte(s) to emit.
|
*/
|
this.handler = function(stream, code_point) {
|
// 1. If code point is end-of-stream, return finished.
|
if (code_point === end_of_stream)
|
return finished;
|
|
// 2. If code point is an ASCII code point or U+0080, return a
|
// byte whose value is code point.
|
if (isASCIICodePoint(code_point) || code_point === 0x0080)
|
return code_point;
|
|
// 3. If code point is U+00A5, return byte 0x5C.
|
if (code_point === 0x00A5)
|
return 0x5C;
|
|
// 4. If code point is U+203E, return byte 0x7E.
|
if (code_point === 0x203E)
|
return 0x7E;
|
|
// 5. If code point is in the range U+FF61 to U+FF9F, inclusive,
|
// return a byte whose value is code point − 0xFF61 + 0xA1.
|
if (inRange(code_point, 0xFF61, 0xFF9F))
|
return code_point - 0xFF61 + 0xA1;
|
|
// 6. If code point is U+2212, set it to U+FF0D.
|
if (code_point === 0x2212)
|
code_point = 0xFF0D;
|
|
// 7. Let pointer be the index Shift_JIS pointer for code point.
|
var pointer = indexShiftJISPointerFor(code_point);
|
|
// 8. If pointer is null, return error with code point.
|
if (pointer === null)
|
return encoderError(code_point);
|
|
// 9. Let lead be floor(pointer / 188).
|
var lead = floor(pointer / 188);
|
|
// 10. Let lead offset be 0x81, if lead is less than 0x1F, and
|
// 0xC1 otherwise.
|
var lead_offset = (lead < 0x1F) ? 0x81 : 0xC1;
|
|
// 11. Let trail be pointer % 188.
|
var trail = pointer % 188;
|
|
// 12. Let offset be 0x40, if trail is less than 0x3F, and 0x41
|
// otherwise.
|
var offset = (trail < 0x3F) ? 0x40 : 0x41;
|
|
// 13. Return two bytes whose values are lead + lead offset and
|
// trail + offset.
|
return [lead + lead_offset, trail + offset];
|
};
|
}
|
|
/** @param {{fatal: boolean}} options */
|
encoders['Shift_JIS'] = function(options) {
|
return new ShiftJISEncoder(options);
|
};
|
/** @param {{fatal: boolean}} options */
|
decoders['Shift_JIS'] = function(options) {
|
return new ShiftJISDecoder(options);
|
};
|
|
//
|
// 14. Legacy multi-byte Korean encodings
|
//
|
|
// 14.1 euc-kr
|
|
// 14.1.1 euc-kr decoder
|
/**
|
* @constructor
|
* @implements {Decoder}
|
* @param {{fatal: boolean}} options
|
*/
|
function EUCKRDecoder(options) {
|
var fatal = options.fatal;
|
|
// euc-kr's decoder has an associated euc-kr lead (initially 0x00).
|
var /** @type {number} */ euckr_lead = 0x00;
|
/**
|
* @param {Stream} stream The stream of bytes being decoded.
|
* @param {number} bite The next byte read from the stream.
|
* @return {?(number|!Array.<number>)} The next code point(s)
|
* decoded, or null if not enough data exists in the input
|
* stream to decode a complete code point.
|
*/
|
this.handler = function(stream, bite) {
|
// 1. If byte is end-of-stream and euc-kr lead is not 0x00, set
|
// euc-kr lead to 0x00 and return error.
|
if (bite === end_of_stream && euckr_lead !== 0) {
|
euckr_lead = 0x00;
|
return decoderError(fatal);
|
}
|
|
// 2. If byte is end-of-stream and euc-kr lead is 0x00, return
|
// finished.
|
if (bite === end_of_stream && euckr_lead === 0)
|
return finished;
|
|
// 3. If euc-kr lead is not 0x00, let lead be euc-kr lead, let
|
// pointer be null, set euc-kr lead to 0x00, and then run these
|
// substeps:
|
if (euckr_lead !== 0x00) {
|
var lead = euckr_lead;
|
var pointer = null;
|
euckr_lead = 0x00;
|
|
// 1. If byte is in the range 0x41 to 0xFE, inclusive, set
|
// pointer to (lead − 0x81) × 190 + (byte − 0x41).
|
if (inRange(bite, 0x41, 0xFE))
|
pointer = (lead - 0x81) * 190 + (bite - 0x41);
|
|
// 2. Let code point be null, if pointer is null, and the
|
// index code point for pointer in index euc-kr otherwise.
|
var code_point = (pointer === null)
|
? null : indexCodePointFor(pointer, index('euc-kr'));
|
|
// 3. If code point is null and byte is an ASCII byte, prepend
|
// byte to stream.
|
if (pointer === null && isASCIIByte(bite))
|
stream.prepend(bite);
|
|
// 4. If code point is null, return error.
|
if (code_point === null)
|
return decoderError(fatal);
|
|
// 5. Return a code point whose value is code point.
|
return code_point;
|
}
|
|
// 4. If byte is an ASCII byte, return a code point whose value
|
// is byte.
|
if (isASCIIByte(bite))
|
return bite;
|
|
// 5. If byte is in the range 0x81 to 0xFE, inclusive, set
|
// euc-kr lead to byte and return continue.
|
if (inRange(bite, 0x81, 0xFE)) {
|
euckr_lead = bite;
|
return null;
|
}
|
|
// 6. Return error.
|
return decoderError(fatal);
|
};
|
}
|
|
// 14.1.2 euc-kr encoder
|
/**
|
* @constructor
|
* @implements {Encoder}
|
* @param {{fatal: boolean}} options
|
*/
|
function EUCKREncoder(options) {
|
var fatal = options.fatal;
|
/**
|
* @param {Stream} stream Input stream.
|
* @param {number} code_point Next code point read from the stream.
|
* @return {(number|!Array.<number>)} Byte(s) to emit.
|
*/
|
this.handler = function(stream, code_point) {
|
// 1. If code point is end-of-stream, return finished.
|
if (code_point === end_of_stream)
|
return finished;
|
|
// 2. If code point is an ASCII code point, return a byte whose
|
// value is code point.
|
if (isASCIICodePoint(code_point))
|
return code_point;
|
|
// 3. Let pointer be the index pointer for code point in index
|
// euc-kr.
|
var pointer = indexPointerFor(code_point, index('euc-kr'));
|
|
// 4. If pointer is null, return error with code point.
|
if (pointer === null)
|
return encoderError(code_point);
|
|
// 5. Let lead be floor(pointer / 190) + 0x81.
|
var lead = floor(pointer / 190) + 0x81;
|
|
// 6. Let trail be pointer % 190 + 0x41.
|
var trail = (pointer % 190) + 0x41;
|
|
// 7. Return two bytes whose values are lead and trail.
|
return [lead, trail];
|
};
|
}
|
|
/** @param {{fatal: boolean}} options */
|
encoders['EUC-KR'] = function(options) {
|
return new EUCKREncoder(options);
|
};
|
/** @param {{fatal: boolean}} options */
|
decoders['EUC-KR'] = function(options) {
|
return new EUCKRDecoder(options);
|
};
|
|
|
//
|
// 15. Legacy miscellaneous encodings
|
//
|
|
// 15.1 replacement
|
|
// Not needed - API throws RangeError
|
|
// 15.2 Common infrastructure for utf-16be and utf-16le
|
|
/**
|
* @param {number} code_unit
|
* @param {boolean} utf16be
|
* @return {!Array.<number>} bytes
|
*/
|
function convertCodeUnitToBytes(code_unit, utf16be) {
|
// 1. Let byte1 be code unit >> 8.
|
var byte1 = code_unit >> 8;
|
|
// 2. Let byte2 be code unit & 0x00FF.
|
var byte2 = code_unit & 0x00FF;
|
|
// 3. Then return the bytes in order:
|
// utf-16be flag is set: byte1, then byte2.
|
if (utf16be)
|
return [byte1, byte2];
|
// utf-16be flag is unset: byte2, then byte1.
|
return [byte2, byte1];
|
}
|
|
// 15.2.1 shared utf-16 decoder
|
/**
|
* @constructor
|
* @implements {Decoder}
|
* @param {boolean} utf16_be True if big-endian, false if little-endian.
|
* @param {{fatal: boolean}} options
|
*/
|
function UTF16Decoder(utf16_be, options) {
|
var fatal = options.fatal;
|
var /** @type {?number} */ utf16_lead_byte = null,
|
/** @type {?number} */ utf16_lead_surrogate = null;
|
/**
|
* @param {Stream} stream The stream of bytes being decoded.
|
* @param {number} bite The next byte read from the stream.
|
* @return {?(number|!Array.<number>)} The next code point(s)
|
* decoded, or null if not enough data exists in the input
|
* stream to decode a complete code point.
|
*/
|
this.handler = function(stream, bite) {
|
// 1. If byte is end-of-stream and either utf-16 lead byte or
|
// utf-16 lead surrogate is not null, set utf-16 lead byte and
|
// utf-16 lead surrogate to null, and return error.
|
if (bite === end_of_stream && (utf16_lead_byte !== null ||
|
utf16_lead_surrogate !== null)) {
|
return decoderError(fatal);
|
}
|
|
// 2. If byte is end-of-stream and utf-16 lead byte and utf-16
|
// lead surrogate are null, return finished.
|
if (bite === end_of_stream && utf16_lead_byte === null &&
|
utf16_lead_surrogate === null) {
|
return finished;
|
}
|
|
// 3. If utf-16 lead byte is null, set utf-16 lead byte to byte
|
// and return continue.
|
if (utf16_lead_byte === null) {
|
utf16_lead_byte = bite;
|
return null;
|
}
|
|
// 4. Let code unit be the result of:
|
var code_unit;
|
if (utf16_be) {
|
// utf-16be decoder flag is set
|
// (utf-16 lead byte << 8) + byte.
|
code_unit = (utf16_lead_byte << 8) + bite;
|
} else {
|
// utf-16be decoder flag is unset
|
// (byte << 8) + utf-16 lead byte.
|
code_unit = (bite << 8) + utf16_lead_byte;
|
}
|
// Then set utf-16 lead byte to null.
|
utf16_lead_byte = null;
|
|
// 5. If utf-16 lead surrogate is not null, let lead surrogate
|
// be utf-16 lead surrogate, set utf-16 lead surrogate to null,
|
// and then run these substeps:
|
if (utf16_lead_surrogate !== null) {
|
var lead_surrogate = utf16_lead_surrogate;
|
utf16_lead_surrogate = null;
|
|
// 1. If code unit is in the range U+DC00 to U+DFFF,
|
// inclusive, return a code point whose value is 0x10000 +
|
// ((lead surrogate − 0xD800) << 10) + (code unit − 0xDC00).
|
if (inRange(code_unit, 0xDC00, 0xDFFF)) {
|
return 0x10000 + (lead_surrogate - 0xD800) * 0x400 +
|
(code_unit - 0xDC00);
|
}
|
|
// 2. Prepend the sequence resulting of converting code unit
|
// to bytes using utf-16be decoder flag to stream and return
|
// error.
|
stream.prepend(convertCodeUnitToBytes(code_unit, utf16_be));
|
return decoderError(fatal);
|
}
|
|
// 6. If code unit is in the range U+D800 to U+DBFF, inclusive,
|
// set utf-16 lead surrogate to code unit and return continue.
|
if (inRange(code_unit, 0xD800, 0xDBFF)) {
|
utf16_lead_surrogate = code_unit;
|
return null;
|
}
|
|
// 7. If code unit is in the range U+DC00 to U+DFFF, inclusive,
|
// return error.
|
if (inRange(code_unit, 0xDC00, 0xDFFF))
|
return decoderError(fatal);
|
|
// 8. Return code point code unit.
|
return code_unit;
|
};
|
}
|
|
// 15.2.2 shared utf-16 encoder
|
/**
|
* @constructor
|
* @implements {Encoder}
|
* @param {boolean} utf16_be True if big-endian, false if little-endian.
|
* @param {{fatal: boolean}} options
|
*/
|
function UTF16Encoder(utf16_be, options) {
|
var fatal = options.fatal;
|
/**
|
* @param {Stream} stream Input stream.
|
* @param {number} code_point Next code point read from the stream.
|
* @return {(number|!Array.<number>)} Byte(s) to emit.
|
*/
|
this.handler = function(stream, code_point) {
|
// 1. If code point is end-of-stream, return finished.
|
if (code_point === end_of_stream)
|
return finished;
|
|
// 2. If code point is in the range U+0000 to U+FFFF, inclusive,
|
// return the sequence resulting of converting code point to
|
// bytes using utf-16be encoder flag.
|
if (inRange(code_point, 0x0000, 0xFFFF))
|
return convertCodeUnitToBytes(code_point, utf16_be);
|
|
// 3. Let lead be ((code point − 0x10000) >> 10) + 0xD800,
|
// converted to bytes using utf-16be encoder flag.
|
var lead = convertCodeUnitToBytes(
|
((code_point - 0x10000) >> 10) + 0xD800, utf16_be);
|
|
// 4. Let trail be ((code point − 0x10000) & 0x3FF) + 0xDC00,
|
// converted to bytes using utf-16be encoder flag.
|
var trail = convertCodeUnitToBytes(
|
((code_point - 0x10000) & 0x3FF) + 0xDC00, utf16_be);
|
|
// 5. Return a byte sequence of lead followed by trail.
|
return lead.concat(trail);
|
};
|
}
|
|
// 15.3 utf-16be
|
// 15.3.1 utf-16be decoder
|
/** @param {{fatal: boolean}} options */
|
encoders['UTF-16BE'] = function(options) {
|
return new UTF16Encoder(true, options);
|
};
|
// 15.3.2 utf-16be encoder
|
/** @param {{fatal: boolean}} options */
|
decoders['UTF-16BE'] = function(options) {
|
return new UTF16Decoder(true, options);
|
};
|
|
// 15.4 utf-16le
|
// 15.4.1 utf-16le decoder
|
/** @param {{fatal: boolean}} options */
|
encoders['UTF-16LE'] = function(options) {
|
return new UTF16Encoder(false, options);
|
};
|
// 15.4.2 utf-16le encoder
|
/** @param {{fatal: boolean}} options */
|
decoders['UTF-16LE'] = function(options) {
|
return new UTF16Decoder(false, options);
|
};
|
|
// 15.5 x-user-defined
|
|
// 15.5.1 x-user-defined decoder
|
/**
|
* @constructor
|
* @implements {Decoder}
|
* @param {{fatal: boolean}} options
|
*/
|
function XUserDefinedDecoder(options) {
|
var fatal = options.fatal;
|
/**
|
* @param {Stream} stream The stream of bytes being decoded.
|
* @param {number} bite The next byte read from the stream.
|
* @return {?(number|!Array.<number>)} The next code point(s)
|
* decoded, or null if not enough data exists in the input
|
* stream to decode a complete code point.
|
*/
|
this.handler = function(stream, bite) {
|
// 1. If byte is end-of-stream, return finished.
|
if (bite === end_of_stream)
|
return finished;
|
|
// 2. If byte is an ASCII byte, return a code point whose value
|
// is byte.
|
if (isASCIIByte(bite))
|
return bite;
|
|
// 3. Return a code point whose value is 0xF780 + byte − 0x80.
|
return 0xF780 + bite - 0x80;
|
};
|
}
|
|
// 15.5.2 x-user-defined encoder
|
/**
|
* @constructor
|
* @implements {Encoder}
|
* @param {{fatal: boolean}} options
|
*/
|
function XUserDefinedEncoder(options) {
|
var fatal = options.fatal;
|
/**
|
* @param {Stream} stream Input stream.
|
* @param {number} code_point Next code point read from the stream.
|
* @return {(number|!Array.<number>)} Byte(s) to emit.
|
*/
|
this.handler = function(stream, code_point) {
|
// 1.If code point is end-of-stream, return finished.
|
if (code_point === end_of_stream)
|
return finished;
|
|
// 2. If code point is an ASCII code point, return a byte whose
|
// value is code point.
|
if (isASCIICodePoint(code_point))
|
return code_point;
|
|
// 3. If code point is in the range U+F780 to U+F7FF, inclusive,
|
// return a byte whose value is code point − 0xF780 + 0x80.
|
if (inRange(code_point, 0xF780, 0xF7FF))
|
return code_point - 0xF780 + 0x80;
|
|
// 4. Return error with code point.
|
return encoderError(code_point);
|
};
|
}
|
|
/** @param {{fatal: boolean}} options */
|
encoders['x-user-defined'] = function(options) {
|
return new XUserDefinedEncoder(options);
|
};
|
/** @param {{fatal: boolean}} options */
|
decoders['x-user-defined'] = function(options) {
|
return new XUserDefinedDecoder(options);
|
};
|
|
if (!global['TextEncoder'])
|
global['TextEncoder'] = TextEncoder;
|
if (!global['TextDecoder'])
|
global['TextDecoder'] = TextDecoder;
|
|
if (typeof module !== "undefined" && module.exports) {
|
module.exports = {
|
TextEncoder: global['TextEncoder'],
|
TextDecoder: global['TextDecoder'],
|
EncodingIndexes: global["encoding-indexes"]
|
};
|
}
|
|
// For strict environments where `this` inside the global scope
|
// is `undefined`, take a pure object instead
|
}(this || {}));
|
|
},{"./encoding-indexes.js":29}],97:[function(require,module,exports){
|
'use strict';
|
|
module.exports = TinyQueue;
|
module.exports.default = TinyQueue;
|
|
function TinyQueue(data, compare) {
|
if (!(this instanceof TinyQueue)) return new TinyQueue(data, compare);
|
|
this.data = data || [];
|
this.length = this.data.length;
|
this.compare = compare || defaultCompare;
|
|
if (this.length > 0) {
|
for (var i = (this.length >> 1) - 1; i >= 0; i--) this._down(i);
|
}
|
}
|
|
function defaultCompare(a, b) {
|
return a < b ? -1 : a > b ? 1 : 0;
|
}
|
|
TinyQueue.prototype = {
|
|
push: function (item) {
|
this.data.push(item);
|
this.length++;
|
this._up(this.length - 1);
|
},
|
|
pop: function () {
|
if (this.length === 0) return undefined;
|
|
var top = this.data[0];
|
this.length--;
|
|
if (this.length > 0) {
|
this.data[0] = this.data[this.length];
|
this._down(0);
|
}
|
this.data.pop();
|
|
return top;
|
},
|
|
peek: function () {
|
return this.data[0];
|
},
|
|
_up: function (pos) {
|
var data = this.data;
|
var compare = this.compare;
|
var item = data[pos];
|
|
while (pos > 0) {
|
var parent = (pos - 1) >> 1;
|
var current = data[parent];
|
if (compare(item, current) >= 0) break;
|
data[pos] = current;
|
pos = parent;
|
}
|
|
data[pos] = item;
|
},
|
|
_down: function (pos) {
|
var data = this.data;
|
var compare = this.compare;
|
var halfLength = this.length >> 1;
|
var item = data[pos];
|
|
while (pos < halfLength) {
|
var left = (pos << 1) + 1;
|
var right = left + 1;
|
var best = data[left];
|
|
if (right < this.length && compare(data[right], best) < 0) {
|
left = right;
|
best = data[right];
|
}
|
if (compare(best, item) >= 0) break;
|
|
data[pos] = best;
|
pos = left;
|
}
|
|
data[pos] = item;
|
}
|
};
|
|
},{}],98:[function(require,module,exports){
|
"use strict"
|
|
module.exports = twoProduct
|
|
var SPLITTER = +(Math.pow(2, 27) + 1.0)
|
|
function twoProduct(a, b, result) {
|
var x = a * b
|
|
var c = SPLITTER * a
|
var abig = c - a
|
var ahi = c - abig
|
var alo = a - ahi
|
|
var d = SPLITTER * b
|
var bbig = d - b
|
var bhi = d - bbig
|
var blo = b - bhi
|
|
var err1 = x - (ahi * bhi)
|
var err2 = err1 - (alo * bhi)
|
var err3 = err2 - (ahi * blo)
|
|
var y = alo * blo - err3
|
|
if(result) {
|
result[0] = y
|
result[1] = x
|
return result
|
}
|
|
return [ y, x ]
|
}
|
},{}],99:[function(require,module,exports){
|
"use strict"
|
|
module.exports = fastTwoSum
|
|
function fastTwoSum(a, b, result) {
|
var x = a + b
|
var bv = x - a
|
var av = x - bv
|
var br = b - bv
|
var ar = a - av
|
if(result) {
|
result[0] = ar + br
|
result[1] = x
|
return result
|
}
|
return [ar+br, x]
|
}
|
},{}],100:[function(require,module,exports){
|
/**
|
* @fileOverview
|
*
|
* URI support as per rfc3986
|
* - Client and Serverside ECMA-262 v3 compatible, node.js friendly
|
* - All classes extend the native String implementation
|
* - Full test suite can be launched by running URI.Test();
|
*
|
* @author Nathan <http://webr3.org/nathan#me>
|
* @version 2010-06-22T16:55:00Z
|
* @license http://creativecommons.org/publicdomain/zero/1.0/
|
*
|
* source: <http://github.com/webr3/URI>
|
* To the extent possible under law, <http://webr3.org/nathan#me>
|
* has waived all copyright and related or neighboring rights to
|
* this work.
|
*/
|
|
/**
|
* URI Class
|
*
|
* @constructor
|
* @extends String
|
* @param {String} value
|
* @requires URI.HeirPart
|
* @requires URI.Authority
|
* @requires URI.Path
|
* @return void
|
*/
|
(URI = function( value ) {
|
this.value = value;
|
this.length = value.length;
|
String.call( this , value );
|
}).prototype = {
|
__proto__: String.prototype,
|
value: '', length: 0,
|
toString: function() { return this.value.toString(); },
|
valueOf: function() { return this.value; },
|
/**
|
* @member URI
|
* @return {URI} The URI with any fragment removed
|
*/
|
defrag: function() {
|
var i = this.indexOf("#");
|
if (i < 0) return this;
|
return new URI( this.slice( 0, i ) );
|
},
|
/**
|
* @member URI
|
* @return {String} The scheme of this URI or null if schemeless
|
*/
|
scheme: function() {
|
var scheme = this.match(/^[a-z0-9\-\+\.]+:/i);
|
if (scheme == null ) return null;
|
return scheme.shift();
|
},
|
/**
|
* @member URI
|
* @return {URI.HeirPart} The heir-part of this URI containing authority and path
|
*/
|
heirpart: function() {
|
var heirpart = this.value;
|
var q = heirpart.indexOf("?")
|
if( q >= 0 ) {
|
heirpart = heirpart.substring(0,q);
|
} else {
|
q = heirpart.indexOf("#")
|
if( q >= 0 ) {
|
heirpart = heirpart.substring(0,q);
|
}
|
}
|
q = this.scheme();
|
if( q ) {
|
heirpart = heirpart.slice( q.length );
|
}
|
return new URI.HeirPart(heirpart);
|
},
|
/**
|
* @member URI
|
* @return {String} The query of the URI or null if no query
|
*/
|
querystring: function() {
|
var q = this.indexOf("?");
|
if (q < 0) return null;
|
var f = this.indexOf("#");
|
if (f < 0) return this.slice(q);
|
return this.substring( q , f );
|
},
|
/**
|
* @member URI
|
* @return {String} The fragment of the URI or null if no fragment
|
*/
|
fragment: function() {
|
var i = this.indexOf("#");
|
if (i < 0) return null;
|
return this.slice( i );
|
},
|
/**
|
* @member URI
|
* @return {Boolean} True if the URI is an Absolute URI
|
*/
|
isAbsolute: function() {
|
return this.scheme() != null && this.heirpart() != null && this.fragment() == null;
|
},
|
/**
|
* @member URI
|
* @return {URI} A normalised Absolute URI with paths resolved and fragment removed
|
*/
|
toAbsolute: function() {
|
if( this.scheme() == null || this.heirpart() == null ) throw 'URI must have a scheme and a hierpart.';
|
var out = this.resolveReference( this );
|
return out.defrag();
|
},
|
/**
|
* Implementation of remove-dot-segments from rfc3986
|
*
|
* @private
|
* @member URI
|
* @param {String} input
|
* @return {String}
|
*/
|
removeDotSegments: function( input ) {
|
var output = '';
|
var q = null;
|
while( input.length > 0 ) {
|
if( input.substr(0,3) == '../' || input.substr(0,2) == './' ) {
|
input = input.slice(input.indexOf('/'));
|
} else if( input == '/.' ) {
|
input = '/';
|
} else if( input.substr(0,3) == '/./' ) {
|
input = input.slice(2);
|
} else if( input.substr(0,4) == '/../' || input == '/..' ) {
|
if( input == '/..' ) {
|
input = '/';
|
} else {
|
input = input.slice(3);
|
}
|
q = output.lastIndexOf('/');
|
if( q ) {
|
output = output.substring(0,q);
|
} else {
|
output = '';
|
}
|
} else if( input.substr(0,2) == '..' || input.substr(0,1) == '.' ) {
|
input = input.slice(input.indexOf('.'));
|
q = input.indexOf('.');
|
if(q) {
|
input = input.slice(q);
|
}
|
} else {
|
if( input.substr(0,1) == '/' ) {
|
output += '/';
|
input = input.slice(1);
|
}
|
q = input.indexOf('/');
|
if( q < 0 ) {
|
output += input;
|
input = '';
|
} else {
|
output += input.substring(0,q);
|
input = input.slice(q);
|
}
|
}
|
}
|
return output;
|
},
|
/**
|
* Implementation of Reference Resolution from rfc3986
|
* Resolves a URI Reference using the current instance as Base URI
|
*
|
* @member URI
|
* @param {String} reference The URI Reference to resolve
|
* @return {URI} Resolved URI Reference
|
*/
|
resolveReference: function( reference ) {
|
if(typeof reference == 'string') {
|
reference = new URI(reference);
|
}
|
if( !(reference instanceof URI ) ) {
|
throw 'Expected an URI or a String';
|
}
|
var T = { scheme:'',authority:'',path:'',query:'',fragment:''};
|
var q = null;
|
if( reference.scheme() ) {
|
T.scheme = reference.scheme();
|
q = reference.heirpart().authority();
|
T.authority += q ? '//' + q : '';
|
T.path = this.removeDotSegments( reference.heirpart().path() );
|
q = reference.querystring();
|
T.query += q ? q : '';
|
} else {
|
q = reference.heirpart().authority();
|
if( q ) {
|
T.authority = q ? '//' + q : '';
|
T.path = this.removeDotSegments( reference.heirpart().path() );
|
q = reference.querystring();
|
T.query += q ? q : '';
|
} else {
|
q = reference.heirpart().path();
|
if( q == "" ) {
|
T.path = this.heirpart().path();
|
q = reference.querystring();
|
if( q ) {
|
T.query += q ? q : '';
|
} else {
|
q = this.querystring();
|
T.query += q ? q : '';
|
}
|
} else {
|
if( q.substring(0,1) == '/' ) {
|
T.path = this.removeDotSegments( q );
|
} else {
|
if( this.heirpart().path() ) {
|
q = this.heirpart().path().lastIndexOf('/');
|
if( q ) {
|
T.path = this.heirpart().path().substring(0,++q);
|
}
|
T.path += reference.heirpart().path();
|
} else {
|
T.path = '/' + q;
|
}
|
T.path = this.removeDotSegments( T.path );
|
}
|
q = reference.querystring();
|
T.query += q ? q : '';
|
}
|
q = this.heirpart().authority();
|
T.authority = q ? '//' + q : '';
|
}
|
T.scheme = this.scheme();
|
}
|
q = reference.fragment();
|
T.fragment = q ? q : '';
|
return new URI( T.scheme + T.authority + T.path + T.query + T.fragment );
|
}
|
};
|
/**
|
* URI.HeirPart
|
*
|
* @constructor
|
* @extends String
|
* @param {String} value
|
* @return void
|
*/
|
(URI.HeirPart = function( value ) {
|
this.value = value;
|
this.length = value.length;
|
String.call( this , value );
|
}).prototype = {
|
__proto__: String.prototype,
|
toString: function() { return this.value.toString(); },
|
valueOf: function() { return this.value; },
|
/**
|
* @member URI.HeirPart
|
* @return URI.Authority The Authority of the URI or null
|
*/
|
authority: function() {
|
if( '//' != this.substring(0,2) ) {
|
return null;
|
}
|
var authority = this.slice(2);
|
var q = authority.indexOf('/');
|
if( q >= 0 ) {
|
authority = authority.substr(0,q);
|
}
|
return new URI.Authority(authority);
|
},
|
/**
|
* @member URI.HeirPart
|
* @return URI.Path The Path of the URI
|
*/
|
path: function() {
|
var q = this.authority();
|
if( !q ) return new URI.Path(this);
|
return new URI.Path( this.slice(q.length + 2) );
|
}
|
};
|
|
/**
|
* URI.Authority
|
*
|
* @constructor
|
* @extends String
|
* @param {String} value
|
* @return void
|
*/
|
(URI.Authority = function( value ) {
|
this.value = value;
|
this.length = value.length;
|
String.call( this , value );
|
}).prototype = {
|
__proto__: String.prototype,
|
toString: function() { return this.value.toString(); },
|
valueOf: function() { return this.value; },
|
/**
|
* @member URI.Authority
|
* @return String The user-info of the URI or null
|
*/
|
userinfo: function() {
|
var q = this.indexOf("@");
|
if(q < 0) return null;
|
return this.substr(0,q);
|
},
|
/**
|
* @member URI.Authority
|
* @return String The host of the URI, one of ipv4, ipv6, ipvFuture or reg-name
|
*/
|
host: function() {
|
var host = this.value;
|
// check if userinfo and remove
|
var q = host.indexOf("@");
|
if(q >= 0) host = host.slice(++q);
|
// check if ipv6 or ipfuture
|
if( host.indexOf("[") == 0 ) {
|
q = host.indexOf("]");
|
if( q > 0 ) return host.substring(0,++q);
|
}
|
// check if we have a port and remove
|
q = host.lastIndexOf(":");
|
if( q >= 0 ) return host.substring(0,q);
|
return host;
|
},
|
/**
|
* @member URI.Authority
|
* @return String The port of the URI or null
|
*/
|
port: function() {
|
var port = this.value;
|
// remove user and pass
|
var q = port.indexOf("@");
|
if(q >= 0) port = port.slice(q);
|
// strip ipv6 or ipfuture if we have one
|
if( port.indexOf("[") == 0 ) {
|
q = port.indexOf("]");
|
if( q > 0 ) port = port.slice(q);
|
}
|
// check if we have a port return
|
q = port.lastIndexOf(":");
|
if( q < 0 ) {
|
return null;
|
}
|
port = port.slice(++q);
|
return ( port.length == 0 ) ? null : port;
|
}
|
};
|
|
/**
|
* URI.Path
|
*
|
* @constructor
|
* @extends String
|
* @param {String} value
|
* @return void
|
*/
|
(URI.Path = function( value ) {
|
this.value = value;
|
this.length = value.length;
|
String.call( this , value );
|
}).prototype = {
|
__proto__: String.prototype,
|
toString: function() { return this.value.toString(); },
|
valueOf: function() { return this.value; }
|
};
|
|
module.exports = URI;
|
},{}],101:[function(require,module,exports){
|
/** @license MIT License (c) copyright 2010-2014 original author or authors */
|
/** @author Brian Cavalier */
|
/** @author John Hann */
|
|
(function(define) { 'use strict';
|
define(function (require) {
|
|
var makePromise = require('./makePromise');
|
var Scheduler = require('./Scheduler');
|
var async = require('./env').asap;
|
|
return makePromise({
|
scheduler: new Scheduler(async)
|
});
|
|
});
|
})(typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); });
|
|
},{"./Scheduler":102,"./env":114,"./makePromise":116}],102:[function(require,module,exports){
|
/** @license MIT License (c) copyright 2010-2014 original author or authors */
|
/** @author Brian Cavalier */
|
/** @author John Hann */
|
|
(function(define) { 'use strict';
|
define(function() {
|
|
// Credit to Twisol (https://github.com/Twisol) for suggesting
|
// this type of extensible queue + trampoline approach for next-tick conflation.
|
|
/**
|
* Async task scheduler
|
* @param {function} async function to schedule a single async function
|
* @constructor
|
*/
|
function Scheduler(async) {
|
this._async = async;
|
this._running = false;
|
|
this._queue = this;
|
this._queueLen = 0;
|
this._afterQueue = {};
|
this._afterQueueLen = 0;
|
|
var self = this;
|
this.drain = function() {
|
self._drain();
|
};
|
}
|
|
/**
|
* Enqueue a task
|
* @param {{ run:function }} task
|
*/
|
Scheduler.prototype.enqueue = function(task) {
|
this._queue[this._queueLen++] = task;
|
this.run();
|
};
|
|
/**
|
* Enqueue a task to run after the main task queue
|
* @param {{ run:function }} task
|
*/
|
Scheduler.prototype.afterQueue = function(task) {
|
this._afterQueue[this._afterQueueLen++] = task;
|
this.run();
|
};
|
|
Scheduler.prototype.run = function() {
|
if (!this._running) {
|
this._running = true;
|
this._async(this.drain);
|
}
|
};
|
|
/**
|
* Drain the handler queue entirely, and then the after queue
|
*/
|
Scheduler.prototype._drain = function() {
|
var i = 0;
|
for (; i < this._queueLen; ++i) {
|
this._queue[i].run();
|
this._queue[i] = void 0;
|
}
|
|
this._queueLen = 0;
|
this._running = false;
|
|
for (i = 0; i < this._afterQueueLen; ++i) {
|
this._afterQueue[i].run();
|
this._afterQueue[i] = void 0;
|
}
|
|
this._afterQueueLen = 0;
|
};
|
|
return Scheduler;
|
|
});
|
}(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(); }));
|
|
},{}],103:[function(require,module,exports){
|
/** @license MIT License (c) copyright 2010-2014 original author or authors */
|
/** @author Brian Cavalier */
|
/** @author John Hann */
|
|
(function(define) { 'use strict';
|
define(function() {
|
|
/**
|
* Custom error type for promises rejected by promise.timeout
|
* @param {string} message
|
* @constructor
|
*/
|
function TimeoutError (message) {
|
Error.call(this);
|
this.message = message;
|
this.name = TimeoutError.name;
|
if (typeof Error.captureStackTrace === 'function') {
|
Error.captureStackTrace(this, TimeoutError);
|
}
|
}
|
|
TimeoutError.prototype = Object.create(Error.prototype);
|
TimeoutError.prototype.constructor = TimeoutError;
|
|
return TimeoutError;
|
});
|
}(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(); }));
|
},{}],104:[function(require,module,exports){
|
/** @license MIT License (c) copyright 2010-2014 original author or authors */
|
/** @author Brian Cavalier */
|
/** @author John Hann */
|
|
(function(define) { 'use strict';
|
define(function() {
|
|
makeApply.tryCatchResolve = tryCatchResolve;
|
|
return makeApply;
|
|
function makeApply(Promise, call) {
|
if(arguments.length < 2) {
|
call = tryCatchResolve;
|
}
|
|
return apply;
|
|
function apply(f, thisArg, args) {
|
var p = Promise._defer();
|
var l = args.length;
|
var params = new Array(l);
|
callAndResolve({ f:f, thisArg:thisArg, args:args, params:params, i:l-1, call:call }, p._handler);
|
|
return p;
|
}
|
|
function callAndResolve(c, h) {
|
if(c.i < 0) {
|
return call(c.f, c.thisArg, c.params, h);
|
}
|
|
var handler = Promise._handler(c.args[c.i]);
|
handler.fold(callAndResolveNext, c, void 0, h);
|
}
|
|
function callAndResolveNext(c, x, h) {
|
c.params[c.i] = x;
|
c.i -= 1;
|
callAndResolve(c, h);
|
}
|
}
|
|
function tryCatchResolve(f, thisArg, args, resolver) {
|
try {
|
resolver.resolve(f.apply(thisArg, args));
|
} catch(e) {
|
resolver.reject(e);
|
}
|
}
|
|
});
|
}(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(); }));
|
|
|
|
},{}],105:[function(require,module,exports){
|
/** @license MIT License (c) copyright 2010-2014 original author or authors */
|
/** @author Brian Cavalier */
|
/** @author John Hann */
|
|
(function(define) { 'use strict';
|
define(function(require) {
|
|
var state = require('../state');
|
var applier = require('../apply');
|
|
return function array(Promise) {
|
|
var applyFold = applier(Promise);
|
var toPromise = Promise.resolve;
|
var all = Promise.all;
|
|
var ar = Array.prototype.reduce;
|
var arr = Array.prototype.reduceRight;
|
var slice = Array.prototype.slice;
|
|
// Additional array combinators
|
|
Promise.any = any;
|
Promise.some = some;
|
Promise.settle = settle;
|
|
Promise.map = map;
|
Promise.filter = filter;
|
Promise.reduce = reduce;
|
Promise.reduceRight = reduceRight;
|
|
/**
|
* When this promise fulfills with an array, do
|
* onFulfilled.apply(void 0, array)
|
* @param {function} onFulfilled function to apply
|
* @returns {Promise} promise for the result of applying onFulfilled
|
*/
|
Promise.prototype.spread = function(onFulfilled) {
|
return this.then(all).then(function(array) {
|
return onFulfilled.apply(this, array);
|
});
|
};
|
|
return Promise;
|
|
/**
|
* One-winner competitive race.
|
* Return a promise that will fulfill when one of the promises
|
* in the input array fulfills, or will reject when all promises
|
* have rejected.
|
* @param {array} promises
|
* @returns {Promise} promise for the first fulfilled value
|
*/
|
function any(promises) {
|
var p = Promise._defer();
|
var resolver = p._handler;
|
var l = promises.length>>>0;
|
|
var pending = l;
|
var errors = [];
|
|
for (var h, x, i = 0; i < l; ++i) {
|
x = promises[i];
|
if(x === void 0 && !(i in promises)) {
|
--pending;
|
continue;
|
}
|
|
h = Promise._handler(x);
|
if(h.state() > 0) {
|
resolver.become(h);
|
Promise._visitRemaining(promises, i, h);
|
break;
|
} else {
|
h.visit(resolver, handleFulfill, handleReject);
|
}
|
}
|
|
if(pending === 0) {
|
resolver.reject(new RangeError('any(): array must not be empty'));
|
}
|
|
return p;
|
|
function handleFulfill(x) {
|
/*jshint validthis:true*/
|
errors = null;
|
this.resolve(x); // this === resolver
|
}
|
|
function handleReject(e) {
|
/*jshint validthis:true*/
|
if(this.resolved) { // this === resolver
|
return;
|
}
|
|
errors.push(e);
|
if(--pending === 0) {
|
this.reject(errors);
|
}
|
}
|
}
|
|
/**
|
* N-winner competitive race
|
* Return a promise that will fulfill when n input promises have
|
* fulfilled, or will reject when it becomes impossible for n
|
* input promises to fulfill (ie when promises.length - n + 1
|
* have rejected)
|
* @param {array} promises
|
* @param {number} n
|
* @returns {Promise} promise for the earliest n fulfillment values
|
*
|
* @deprecated
|
*/
|
function some(promises, n) {
|
/*jshint maxcomplexity:7*/
|
var p = Promise._defer();
|
var resolver = p._handler;
|
|
var results = [];
|
var errors = [];
|
|
var l = promises.length>>>0;
|
var nFulfill = 0;
|
var nReject;
|
var x, i; // reused in both for() loops
|
|
// First pass: count actual array items
|
for(i=0; i<l; ++i) {
|
x = promises[i];
|
if(x === void 0 && !(i in promises)) {
|
continue;
|
}
|
++nFulfill;
|
}
|
|
// Compute actual goals
|
n = Math.max(n, 0);
|
nReject = (nFulfill - n + 1);
|
nFulfill = Math.min(n, nFulfill);
|
|
if(n > nFulfill) {
|
resolver.reject(new RangeError('some(): array must contain at least '
|
+ n + ' item(s), but had ' + nFulfill));
|
} else if(nFulfill === 0) {
|
resolver.resolve(results);
|
}
|
|
// Second pass: observe each array item, make progress toward goals
|
for(i=0; i<l; ++i) {
|
x = promises[i];
|
if(x === void 0 && !(i in promises)) {
|
continue;
|
}
|
|
Promise._handler(x).visit(resolver, fulfill, reject, resolver.notify);
|
}
|
|
return p;
|
|
function fulfill(x) {
|
/*jshint validthis:true*/
|
if(this.resolved) { // this === resolver
|
return;
|
}
|
|
results.push(x);
|
if(--nFulfill === 0) {
|
errors = null;
|
this.resolve(results);
|
}
|
}
|
|
function reject(e) {
|
/*jshint validthis:true*/
|
if(this.resolved) { // this === resolver
|
return;
|
}
|
|
errors.push(e);
|
if(--nReject === 0) {
|
results = null;
|
this.reject(errors);
|
}
|
}
|
}
|
|
/**
|
* Apply f to the value of each promise in a list of promises
|
* and return a new list containing the results.
|
* @param {array} promises
|
* @param {function(x:*, index:Number):*} f mapping function
|
* @returns {Promise}
|
*/
|
function map(promises, f) {
|
return Promise._traverse(f, promises);
|
}
|
|
/**
|
* Filter the provided array of promises using the provided predicate. Input may
|
* contain promises and values
|
* @param {Array} promises array of promises and values
|
* @param {function(x:*, index:Number):boolean} predicate filtering predicate.
|
* Must return truthy (or promise for truthy) for items to retain.
|
* @returns {Promise} promise that will fulfill with an array containing all items
|
* for which predicate returned truthy.
|
*/
|
function filter(promises, predicate) {
|
var a = slice.call(promises);
|
return Promise._traverse(predicate, a).then(function(keep) {
|
return filterSync(a, keep);
|
});
|
}
|
|
function filterSync(promises, keep) {
|
// Safe because we know all promises have fulfilled if we've made it this far
|
var l = keep.length;
|
var filtered = new Array(l);
|
for(var i=0, j=0; i<l; ++i) {
|
if(keep[i]) {
|
filtered[j++] = Promise._handler(promises[i]).value;
|
}
|
}
|
filtered.length = j;
|
return filtered;
|
|
}
|
|
/**
|
* Return a promise that will always fulfill with an array containing
|
* the outcome states of all input promises. The returned promise
|
* will never reject.
|
* @param {Array} promises
|
* @returns {Promise} promise for array of settled state descriptors
|
*/
|
function settle(promises) {
|
return all(promises.map(settleOne));
|
}
|
|
function settleOne(p) {
|
// Optimize the case where we get an already-resolved when.js promise
|
// by extracting its state:
|
var handler;
|
if (p instanceof Promise) {
|
// This is our own Promise type and we can reach its handler internals:
|
handler = p._handler.join();
|
}
|
if((handler && handler.state() === 0) || !handler) {
|
// Either still pending, or not a Promise at all:
|
return toPromise(p).then(state.fulfilled, state.rejected);
|
}
|
|
// The promise is our own, but it is already resolved. Take a shortcut.
|
// Since we're not actually handling the resolution, we need to disable
|
// rejection reporting.
|
handler._unreport();
|
return state.inspect(handler);
|
}
|
|
/**
|
* Traditional reduce function, similar to `Array.prototype.reduce()`, but
|
* input may contain promises and/or values, and reduceFunc
|
* may return either a value or a promise, *and* initialValue may
|
* be a promise for the starting value.
|
* @param {Array|Promise} promises array or promise for an array of anything,
|
* may contain a mix of promises and values.
|
* @param {function(accumulated:*, x:*, index:Number):*} f reduce function
|
* @returns {Promise} that will resolve to the final reduced value
|
*/
|
function reduce(promises, f /*, initialValue */) {
|
return arguments.length > 2 ? ar.call(promises, liftCombine(f), arguments[2])
|
: ar.call(promises, liftCombine(f));
|
}
|
|
/**
|
* Traditional reduce function, similar to `Array.prototype.reduceRight()`, but
|
* input may contain promises and/or values, and reduceFunc
|
* may return either a value or a promise, *and* initialValue may
|
* be a promise for the starting value.
|
* @param {Array|Promise} promises array or promise for an array of anything,
|
* may contain a mix of promises and values.
|
* @param {function(accumulated:*, x:*, index:Number):*} f reduce function
|
* @returns {Promise} that will resolve to the final reduced value
|
*/
|
function reduceRight(promises, f /*, initialValue */) {
|
return arguments.length > 2 ? arr.call(promises, liftCombine(f), arguments[2])
|
: arr.call(promises, liftCombine(f));
|
}
|
|
function liftCombine(f) {
|
return function(z, x, i) {
|
return applyFold(f, void 0, [z,x,i]);
|
};
|
}
|
};
|
|
});
|
}(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(require); }));
|
|
},{"../apply":104,"../state":117}],106:[function(require,module,exports){
|
/** @license MIT License (c) copyright 2010-2014 original author or authors */
|
/** @author Brian Cavalier */
|
/** @author John Hann */
|
|
(function(define) { 'use strict';
|
define(function() {
|
|
return function flow(Promise) {
|
|
var resolve = Promise.resolve;
|
var reject = Promise.reject;
|
var origCatch = Promise.prototype['catch'];
|
|
/**
|
* Handle the ultimate fulfillment value or rejection reason, and assume
|
* responsibility for all errors. If an error propagates out of result
|
* or handleFatalError, it will be rethrown to the host, resulting in a
|
* loud stack track on most platforms and a crash on some.
|
* @param {function?} onResult
|
* @param {function?} onError
|
* @returns {undefined}
|
*/
|
Promise.prototype.done = function(onResult, onError) {
|
this._handler.visit(this._handler.receiver, onResult, onError);
|
};
|
|
/**
|
* Add Error-type and predicate matching to catch. Examples:
|
* promise.catch(TypeError, handleTypeError)
|
* .catch(predicate, handleMatchedErrors)
|
* .catch(handleRemainingErrors)
|
* @param onRejected
|
* @returns {*}
|
*/
|
Promise.prototype['catch'] = Promise.prototype.otherwise = function(onRejected) {
|
if (arguments.length < 2) {
|
return origCatch.call(this, onRejected);
|
}
|
|
if(typeof onRejected !== 'function') {
|
return this.ensure(rejectInvalidPredicate);
|
}
|
|
return origCatch.call(this, createCatchFilter(arguments[1], onRejected));
|
};
|
|
/**
|
* Wraps the provided catch handler, so that it will only be called
|
* if the predicate evaluates truthy
|
* @param {?function} handler
|
* @param {function} predicate
|
* @returns {function} conditional catch handler
|
*/
|
function createCatchFilter(handler, predicate) {
|
return function(e) {
|
return evaluatePredicate(e, predicate)
|
? handler.call(this, e)
|
: reject(e);
|
};
|
}
|
|
/**
|
* Ensures that onFulfilledOrRejected will be called regardless of whether
|
* this promise is fulfilled or rejected. onFulfilledOrRejected WILL NOT
|
* receive the promises' value or reason. Any returned value will be disregarded.
|
* onFulfilledOrRejected may throw or return a rejected promise to signal
|
* an additional error.
|
* @param {function} handler handler to be called regardless of
|
* fulfillment or rejection
|
* @returns {Promise}
|
*/
|
Promise.prototype['finally'] = Promise.prototype.ensure = function(handler) {
|
if(typeof handler !== 'function') {
|
return this;
|
}
|
|
return this.then(function(x) {
|
return runSideEffect(handler, this, identity, x);
|
}, function(e) {
|
return runSideEffect(handler, this, reject, e);
|
});
|
};
|
|
function runSideEffect (handler, thisArg, propagate, value) {
|
var result = handler.call(thisArg);
|
return maybeThenable(result)
|
? propagateValue(result, propagate, value)
|
: propagate(value);
|
}
|
|
function propagateValue (result, propagate, x) {
|
return resolve(result).then(function () {
|
return propagate(x);
|
});
|
}
|
|
/**
|
* Recover from a failure by returning a defaultValue. If defaultValue
|
* is a promise, it's fulfillment value will be used. If defaultValue is
|
* a promise that rejects, the returned promise will reject with the
|
* same reason.
|
* @param {*} defaultValue
|
* @returns {Promise} new promise
|
*/
|
Promise.prototype['else'] = Promise.prototype.orElse = function(defaultValue) {
|
return this.then(void 0, function() {
|
return defaultValue;
|
});
|
};
|
|
/**
|
* Shortcut for .then(function() { return value; })
|
* @param {*} value
|
* @return {Promise} a promise that:
|
* - is fulfilled if value is not a promise, or
|
* - if value is a promise, will fulfill with its value, or reject
|
* with its reason.
|
*/
|
Promise.prototype['yield'] = function(value) {
|
return this.then(function() {
|
return value;
|
});
|
};
|
|
/**
|
* Runs a side effect when this promise fulfills, without changing the
|
* fulfillment value.
|
* @param {function} onFulfilledSideEffect
|
* @returns {Promise}
|
*/
|
Promise.prototype.tap = function(onFulfilledSideEffect) {
|
return this.then(onFulfilledSideEffect)['yield'](this);
|
};
|
|
return Promise;
|
};
|
|
function rejectInvalidPredicate() {
|
throw new TypeError('catch predicate must be a function');
|
}
|
|
function evaluatePredicate(e, predicate) {
|
return isError(predicate) ? e instanceof predicate : predicate(e);
|
}
|
|
function isError(predicate) {
|
return predicate === Error
|
|| (predicate != null && predicate.prototype instanceof Error);
|
}
|
|
function maybeThenable(x) {
|
return (typeof x === 'object' || typeof x === 'function') && x !== null;
|
}
|
|
function identity(x) {
|
return x;
|
}
|
|
});
|
}(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(); }));
|
|
},{}],107:[function(require,module,exports){
|
/** @license MIT License (c) copyright 2010-2014 original author or authors */
|
/** @author Brian Cavalier */
|
/** @author John Hann */
|
/** @author Jeff Escalante */
|
|
(function(define) { 'use strict';
|
define(function() {
|
|
return function fold(Promise) {
|
|
Promise.prototype.fold = function(f, z) {
|
var promise = this._beget();
|
|
this._handler.fold(function(z, x, to) {
|
Promise._handler(z).fold(function(x, z, to) {
|
to.resolve(f.call(this, z, x));
|
}, x, this, to);
|
}, z, promise._handler.receiver, promise._handler);
|
|
return promise;
|
};
|
|
return Promise;
|
};
|
|
});
|
}(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(); }));
|
|
},{}],108:[function(require,module,exports){
|
/** @license MIT License (c) copyright 2010-2014 original author or authors */
|
/** @author Brian Cavalier */
|
/** @author John Hann */
|
|
(function(define) { 'use strict';
|
define(function(require) {
|
|
var inspect = require('../state').inspect;
|
|
return function inspection(Promise) {
|
|
Promise.prototype.inspect = function() {
|
return inspect(Promise._handler(this));
|
};
|
|
return Promise;
|
};
|
|
});
|
}(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(require); }));
|
|
},{"../state":117}],109:[function(require,module,exports){
|
/** @license MIT License (c) copyright 2010-2014 original author or authors */
|
/** @author Brian Cavalier */
|
/** @author John Hann */
|
|
(function(define) { 'use strict';
|
define(function() {
|
|
return function generate(Promise) {
|
|
var resolve = Promise.resolve;
|
|
Promise.iterate = iterate;
|
Promise.unfold = unfold;
|
|
return Promise;
|
|
/**
|
* @deprecated Use github.com/cujojs/most streams and most.iterate
|
* Generate a (potentially infinite) stream of promised values:
|
* x, f(x), f(f(x)), etc. until condition(x) returns true
|
* @param {function} f function to generate a new x from the previous x
|
* @param {function} condition function that, given the current x, returns
|
* truthy when the iterate should stop
|
* @param {function} handler function to handle the value produced by f
|
* @param {*|Promise} x starting value, may be a promise
|
* @return {Promise} the result of the last call to f before
|
* condition returns true
|
*/
|
function iterate(f, condition, handler, x) {
|
return unfold(function(x) {
|
return [x, f(x)];
|
}, condition, handler, x);
|
}
|
|
/**
|
* @deprecated Use github.com/cujojs/most streams and most.unfold
|
* Generate a (potentially infinite) stream of promised values
|
* by applying handler(generator(seed)) iteratively until
|
* condition(seed) returns true.
|
* @param {function} unspool function that generates a [value, newSeed]
|
* given a seed.
|
* @param {function} condition function that, given the current seed, returns
|
* truthy when the unfold should stop
|
* @param {function} handler function to handle the value produced by unspool
|
* @param x {*|Promise} starting value, may be a promise
|
* @return {Promise} the result of the last value produced by unspool before
|
* condition returns true
|
*/
|
function unfold(unspool, condition, handler, x) {
|
return resolve(x).then(function(seed) {
|
return resolve(condition(seed)).then(function(done) {
|
return done ? seed : resolve(unspool(seed)).spread(next);
|
});
|
});
|
|
function next(item, newSeed) {
|
return resolve(handler(item)).then(function() {
|
return unfold(unspool, condition, handler, newSeed);
|
});
|
}
|
}
|
};
|
|
});
|
}(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(); }));
|
|
},{}],110:[function(require,module,exports){
|
/** @license MIT License (c) copyright 2010-2014 original author or authors */
|
/** @author Brian Cavalier */
|
/** @author John Hann */
|
|
(function(define) { 'use strict';
|
define(function() {
|
|
return function progress(Promise) {
|
|
/**
|
* @deprecated
|
* Register a progress handler for this promise
|
* @param {function} onProgress
|
* @returns {Promise}
|
*/
|
Promise.prototype.progress = function(onProgress) {
|
return this.then(void 0, void 0, onProgress);
|
};
|
|
return Promise;
|
};
|
|
});
|
}(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(); }));
|
|
},{}],111:[function(require,module,exports){
|
/** @license MIT License (c) copyright 2010-2014 original author or authors */
|
/** @author Brian Cavalier */
|
/** @author John Hann */
|
|
(function(define) { 'use strict';
|
define(function(require) {
|
|
var env = require('../env');
|
var TimeoutError = require('../TimeoutError');
|
|
function setTimeout(f, ms, x, y) {
|
return env.setTimer(function() {
|
f(x, y, ms);
|
}, ms);
|
}
|
|
return function timed(Promise) {
|
/**
|
* Return a new promise whose fulfillment value is revealed only
|
* after ms milliseconds
|
* @param {number} ms milliseconds
|
* @returns {Promise}
|
*/
|
Promise.prototype.delay = function(ms) {
|
var p = this._beget();
|
this._handler.fold(handleDelay, ms, void 0, p._handler);
|
return p;
|
};
|
|
function handleDelay(ms, x, h) {
|
setTimeout(resolveDelay, ms, x, h);
|
}
|
|
function resolveDelay(x, h) {
|
h.resolve(x);
|
}
|
|
/**
|
* Return a new promise that rejects after ms milliseconds unless
|
* this promise fulfills earlier, in which case the returned promise
|
* fulfills with the same value.
|
* @param {number} ms milliseconds
|
* @param {Error|*=} reason optional rejection reason to use, defaults
|
* to a TimeoutError if not provided
|
* @returns {Promise}
|
*/
|
Promise.prototype.timeout = function(ms, reason) {
|
var p = this._beget();
|
var h = p._handler;
|
|
var t = setTimeout(onTimeout, ms, reason, p._handler);
|
|
this._handler.visit(h,
|
function onFulfill(x) {
|
env.clearTimer(t);
|
this.resolve(x); // this = h
|
},
|
function onReject(x) {
|
env.clearTimer(t);
|
this.reject(x); // this = h
|
},
|
h.notify);
|
|
return p;
|
};
|
|
function onTimeout(reason, h, ms) {
|
var e = typeof reason === 'undefined'
|
? new TimeoutError('timed out after ' + ms + 'ms')
|
: reason;
|
h.reject(e);
|
}
|
|
return Promise;
|
};
|
|
});
|
}(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(require); }));
|
|
},{"../TimeoutError":103,"../env":114}],112:[function(require,module,exports){
|
/** @license MIT License (c) copyright 2010-2014 original author or authors */
|
/** @author Brian Cavalier */
|
/** @author John Hann */
|
|
(function(define) { 'use strict';
|
define(function(require) {
|
|
var setTimer = require('../env').setTimer;
|
var format = require('../format');
|
|
return function unhandledRejection(Promise) {
|
|
var logError = noop;
|
var logInfo = noop;
|
var localConsole;
|
|
if(typeof console !== 'undefined') {
|
// Alias console to prevent things like uglify's drop_console option from
|
// removing console.log/error. Unhandled rejections fall into the same
|
// category as uncaught exceptions, and build tools shouldn't silence them.
|
localConsole = console;
|
logError = typeof localConsole.error !== 'undefined'
|
? function (e) { localConsole.error(e); }
|
: function (e) { localConsole.log(e); };
|
|
logInfo = typeof localConsole.info !== 'undefined'
|
? function (e) { localConsole.info(e); }
|
: function (e) { localConsole.log(e); };
|
}
|
|
Promise.onPotentiallyUnhandledRejection = function(rejection) {
|
enqueue(report, rejection);
|
};
|
|
Promise.onPotentiallyUnhandledRejectionHandled = function(rejection) {
|
enqueue(unreport, rejection);
|
};
|
|
Promise.onFatalRejection = function(rejection) {
|
enqueue(throwit, rejection.value);
|
};
|
|
var tasks = [];
|
var reported = [];
|
var running = null;
|
|
function report(r) {
|
if(!r.handled) {
|
reported.push(r);
|
logError('Potentially unhandled rejection [' + r.id + '] ' + format.formatError(r.value));
|
}
|
}
|
|
function unreport(r) {
|
var i = reported.indexOf(r);
|
if(i >= 0) {
|
reported.splice(i, 1);
|
logInfo('Handled previous rejection [' + r.id + '] ' + format.formatObject(r.value));
|
}
|
}
|
|
function enqueue(f, x) {
|
tasks.push(f, x);
|
if(running === null) {
|
running = setTimer(flush, 0);
|
}
|
}
|
|
function flush() {
|
running = null;
|
while(tasks.length > 0) {
|
tasks.shift()(tasks.shift());
|
}
|
}
|
|
return Promise;
|
};
|
|
function throwit(e) {
|
throw e;
|
}
|
|
function noop() {}
|
|
});
|
}(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(require); }));
|
|
},{"../env":114,"../format":115}],113:[function(require,module,exports){
|
/** @license MIT License (c) copyright 2010-2014 original author or authors */
|
/** @author Brian Cavalier */
|
/** @author John Hann */
|
|
(function(define) { 'use strict';
|
define(function() {
|
|
return function addWith(Promise) {
|
/**
|
* Returns a promise whose handlers will be called with `this` set to
|
* the supplied receiver. Subsequent promises derived from the
|
* returned promise will also have their handlers called with receiver
|
* as `this`. Calling `with` with undefined or no arguments will return
|
* a promise whose handlers will again be called in the usual Promises/A+
|
* way (no `this`) thus safely undoing any previous `with` in the
|
* promise chain.
|
*
|
* WARNING: Promises returned from `with`/`withThis` are NOT Promises/A+
|
* compliant, specifically violating 2.2.5 (http://promisesaplus.com/#point-41)
|
*
|
* @param {object} receiver `this` value for all handlers attached to
|
* the returned promise.
|
* @returns {Promise}
|
*/
|
Promise.prototype['with'] = Promise.prototype.withThis = function(receiver) {
|
var p = this._beget();
|
var child = p._handler;
|
child.receiver = receiver;
|
this._handler.chain(child, receiver);
|
return p;
|
};
|
|
return Promise;
|
};
|
|
});
|
}(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(); }));
|
|
|
},{}],114:[function(require,module,exports){
|
(function (process){
|
/** @license MIT License (c) copyright 2010-2014 original author or authors */
|
/** @author Brian Cavalier */
|
/** @author John Hann */
|
|
/*global process,document,setTimeout,clearTimeout,MutationObserver,WebKitMutationObserver*/
|
(function(define) { 'use strict';
|
define(function(require) {
|
/*jshint maxcomplexity:6*/
|
|
// Sniff "best" async scheduling option
|
// Prefer process.nextTick or MutationObserver, then check for
|
// setTimeout, and finally vertx, since its the only env that doesn't
|
// have setTimeout
|
|
var MutationObs;
|
var capturedSetTimeout = typeof setTimeout !== 'undefined' && setTimeout;
|
|
// Default env
|
var setTimer = function(f, ms) { return setTimeout(f, ms); };
|
var clearTimer = function(t) { return clearTimeout(t); };
|
var asap = function (f) { return capturedSetTimeout(f, 0); };
|
|
// Detect specific env
|
if (isNode()) { // Node
|
asap = function (f) { return process.nextTick(f); };
|
|
} else if (MutationObs = hasMutationObserver()) { // Modern browser
|
asap = initMutationObserver(MutationObs);
|
|
} else if (!capturedSetTimeout) { // vert.x
|
var vertxRequire = require;
|
var vertx = vertxRequire('vertx');
|
setTimer = function (f, ms) { return vertx.setTimer(ms, f); };
|
clearTimer = vertx.cancelTimer;
|
asap = vertx.runOnLoop || vertx.runOnContext;
|
}
|
|
return {
|
setTimer: setTimer,
|
clearTimer: clearTimer,
|
asap: asap
|
};
|
|
function isNode () {
|
return typeof process !== 'undefined' &&
|
Object.prototype.toString.call(process) === '[object process]';
|
}
|
|
function hasMutationObserver () {
|
return (typeof MutationObserver !== 'undefined' && MutationObserver) ||
|
(typeof WebKitMutationObserver !== 'undefined' && WebKitMutationObserver);
|
}
|
|
function initMutationObserver(MutationObserver) {
|
var scheduled;
|
var node = document.createTextNode('');
|
var o = new MutationObserver(run);
|
o.observe(node, { characterData: true });
|
|
function run() {
|
var f = scheduled;
|
scheduled = void 0;
|
f();
|
}
|
|
var i = 0;
|
return function (f) {
|
scheduled = f;
|
node.data = (i ^= 1);
|
};
|
}
|
});
|
}(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(require); }));
|
|
}).call(this,require('_process'))
|
|
},{"_process":81}],115:[function(require,module,exports){
|
/** @license MIT License (c) copyright 2010-2014 original author or authors */
|
/** @author Brian Cavalier */
|
/** @author John Hann */
|
|
(function(define) { 'use strict';
|
define(function() {
|
|
return {
|
formatError: formatError,
|
formatObject: formatObject,
|
tryStringify: tryStringify
|
};
|
|
/**
|
* Format an error into a string. If e is an Error and has a stack property,
|
* it's returned. Otherwise, e is formatted using formatObject, with a
|
* warning added about e not being a proper Error.
|
* @param {*} e
|
* @returns {String} formatted string, suitable for output to developers
|
*/
|
function formatError(e) {
|
var s = typeof e === 'object' && e !== null && (e.stack || e.message) ? e.stack || e.message : formatObject(e);
|
return e instanceof Error ? s : s + ' (WARNING: non-Error used)';
|
}
|
|
/**
|
* Format an object, detecting "plain" objects and running them through
|
* JSON.stringify if possible.
|
* @param {Object} o
|
* @returns {string}
|
*/
|
function formatObject(o) {
|
var s = String(o);
|
if(s === '[object Object]' && typeof JSON !== 'undefined') {
|
s = tryStringify(o, s);
|
}
|
return s;
|
}
|
|
/**
|
* Try to return the result of JSON.stringify(x). If that fails, return
|
* defaultValue
|
* @param {*} x
|
* @param {*} defaultValue
|
* @returns {String|*} JSON.stringify(x) or defaultValue
|
*/
|
function tryStringify(x, defaultValue) {
|
try {
|
return JSON.stringify(x);
|
} catch(e) {
|
return defaultValue;
|
}
|
}
|
|
});
|
}(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(); }));
|
|
},{}],116:[function(require,module,exports){
|
(function (process){
|
/** @license MIT License (c) copyright 2010-2014 original author or authors */
|
/** @author Brian Cavalier */
|
/** @author John Hann */
|
|
(function(define) { 'use strict';
|
define(function() {
|
|
return function makePromise(environment) {
|
|
var tasks = environment.scheduler;
|
var emitRejection = initEmitRejection();
|
|
var objectCreate = Object.create ||
|
function(proto) {
|
function Child() {}
|
Child.prototype = proto;
|
return new Child();
|
};
|
|
/**
|
* Create a promise whose fate is determined by resolver
|
* @constructor
|
* @returns {Promise} promise
|
* @name Promise
|
*/
|
function Promise(resolver, handler) {
|
this._handler = resolver === Handler ? handler : init(resolver);
|
}
|
|
/**
|
* Run the supplied resolver
|
* @param resolver
|
* @returns {Pending}
|
*/
|
function init(resolver) {
|
var handler = new Pending();
|
|
try {
|
resolver(promiseResolve, promiseReject, promiseNotify);
|
} catch (e) {
|
promiseReject(e);
|
}
|
|
return handler;
|
|
/**
|
* Transition from pre-resolution state to post-resolution state, notifying
|
* all listeners of the ultimate fulfillment or rejection
|
* @param {*} x resolution value
|
*/
|
function promiseResolve (x) {
|
handler.resolve(x);
|
}
|
/**
|
* Reject this promise with reason, which will be used verbatim
|
* @param {Error|*} reason rejection reason, strongly suggested
|
* to be an Error type
|
*/
|
function promiseReject (reason) {
|
handler.reject(reason);
|
}
|
|
/**
|
* @deprecated
|
* Issue a progress event, notifying all progress listeners
|
* @param {*} x progress event payload to pass to all listeners
|
*/
|
function promiseNotify (x) {
|
handler.notify(x);
|
}
|
}
|
|
// Creation
|
|
Promise.resolve = resolve;
|
Promise.reject = reject;
|
Promise.never = never;
|
|
Promise._defer = defer;
|
Promise._handler = getHandler;
|
|
/**
|
* Returns a trusted promise. If x is already a trusted promise, it is
|
* returned, otherwise returns a new trusted Promise which follows x.
|
* @param {*} x
|
* @return {Promise} promise
|
*/
|
function resolve(x) {
|
return isPromise(x) ? x
|
: new Promise(Handler, new Async(getHandler(x)));
|
}
|
|
/**
|
* Return a reject promise with x as its reason (x is used verbatim)
|
* @param {*} x
|
* @returns {Promise} rejected promise
|
*/
|
function reject(x) {
|
return new Promise(Handler, new Async(new Rejected(x)));
|
}
|
|
/**
|
* Return a promise that remains pending forever
|
* @returns {Promise} forever-pending promise.
|
*/
|
function never() {
|
return foreverPendingPromise; // Should be frozen
|
}
|
|
/**
|
* Creates an internal {promise, resolver} pair
|
* @private
|
* @returns {Promise}
|
*/
|
function defer() {
|
return new Promise(Handler, new Pending());
|
}
|
|
// Transformation and flow control
|
|
/**
|
* Transform this promise's fulfillment value, returning a new Promise
|
* for the transformed result. If the promise cannot be fulfilled, onRejected
|
* is called with the reason. onProgress *may* be called with updates toward
|
* this promise's fulfillment.
|
* @param {function=} onFulfilled fulfillment handler
|
* @param {function=} onRejected rejection handler
|
* @param {function=} onProgress @deprecated progress handler
|
* @return {Promise} new promise
|
*/
|
Promise.prototype.then = function(onFulfilled, onRejected, onProgress) {
|
var parent = this._handler;
|
var state = parent.join().state();
|
|
if ((typeof onFulfilled !== 'function' && state > 0) ||
|
(typeof onRejected !== 'function' && state < 0)) {
|
// Short circuit: value will not change, simply share handler
|
return new this.constructor(Handler, parent);
|
}
|
|
var p = this._beget();
|
var child = p._handler;
|
|
parent.chain(child, parent.receiver, onFulfilled, onRejected, onProgress);
|
|
return p;
|
};
|
|
/**
|
* If this promise cannot be fulfilled due to an error, call onRejected to
|
* handle the error. Shortcut for .then(undefined, onRejected)
|
* @param {function?} onRejected
|
* @return {Promise}
|
*/
|
Promise.prototype['catch'] = function(onRejected) {
|
return this.then(void 0, onRejected);
|
};
|
|
/**
|
* Creates a new, pending promise of the same type as this promise
|
* @private
|
* @returns {Promise}
|
*/
|
Promise.prototype._beget = function() {
|
return begetFrom(this._handler, this.constructor);
|
};
|
|
function begetFrom(parent, Promise) {
|
var child = new Pending(parent.receiver, parent.join().context);
|
return new Promise(Handler, child);
|
}
|
|
// Array combinators
|
|
Promise.all = all;
|
Promise.race = race;
|
Promise._traverse = traverse;
|
|
/**
|
* Return a promise that will fulfill when all promises in the
|
* input array have fulfilled, or will reject when one of the
|
* promises rejects.
|
* @param {array} promises array of promises
|
* @returns {Promise} promise for array of fulfillment values
|
*/
|
function all(promises) {
|
return traverseWith(snd, null, promises);
|
}
|
|
/**
|
* Array<Promise<X>> -> Promise<Array<f(X)>>
|
* @private
|
* @param {function} f function to apply to each promise's value
|
* @param {Array} promises array of promises
|
* @returns {Promise} promise for transformed values
|
*/
|
function traverse(f, promises) {
|
return traverseWith(tryCatch2, f, promises);
|
}
|
|
function traverseWith(tryMap, f, promises) {
|
var handler = typeof f === 'function' ? mapAt : settleAt;
|
|
var resolver = new Pending();
|
var pending = promises.length >>> 0;
|
var results = new Array(pending);
|
|
for (var i = 0, x; i < promises.length && !resolver.resolved; ++i) {
|
x = promises[i];
|
|
if (x === void 0 && !(i in promises)) {
|
--pending;
|
continue;
|
}
|
|
traverseAt(promises, handler, i, x, resolver);
|
}
|
|
if(pending === 0) {
|
resolver.become(new Fulfilled(results));
|
}
|
|
return new Promise(Handler, resolver);
|
|
function mapAt(i, x, resolver) {
|
if(!resolver.resolved) {
|
traverseAt(promises, settleAt, i, tryMap(f, x, i), resolver);
|
}
|
}
|
|
function settleAt(i, x, resolver) {
|
results[i] = x;
|
if(--pending === 0) {
|
resolver.become(new Fulfilled(results));
|
}
|
}
|
}
|
|
function traverseAt(promises, handler, i, x, resolver) {
|
if (maybeThenable(x)) {
|
var h = getHandlerMaybeThenable(x);
|
var s = h.state();
|
|
if (s === 0) {
|
h.fold(handler, i, void 0, resolver);
|
} else if (s > 0) {
|
handler(i, h.value, resolver);
|
} else {
|
resolver.become(h);
|
visitRemaining(promises, i+1, h);
|
}
|
} else {
|
handler(i, x, resolver);
|
}
|
}
|
|
Promise._visitRemaining = visitRemaining;
|
function visitRemaining(promises, start, handler) {
|
for(var i=start; i<promises.length; ++i) {
|
markAsHandled(getHandler(promises[i]), handler);
|
}
|
}
|
|
function markAsHandled(h, handler) {
|
if(h === handler) {
|
return;
|
}
|
|
var s = h.state();
|
if(s === 0) {
|
h.visit(h, void 0, h._unreport);
|
} else if(s < 0) {
|
h._unreport();
|
}
|
}
|
|
/**
|
* Fulfill-reject competitive race. Return a promise that will settle
|
* to the same state as the earliest input promise to settle.
|
*
|
* WARNING: The ES6 Promise spec requires that race()ing an empty array
|
* must return a promise that is pending forever. This implementation
|
* returns a singleton forever-pending promise, the same singleton that is
|
* returned by Promise.never(), thus can be checked with ===
|
*
|
* @param {array} promises array of promises to race
|
* @returns {Promise} if input is non-empty, a promise that will settle
|
* to the same outcome as the earliest input promise to settle. if empty
|
* is empty, returns a promise that will never settle.
|
*/
|
function race(promises) {
|
if(typeof promises !== 'object' || promises === null) {
|
return reject(new TypeError('non-iterable passed to race()'));
|
}
|
|
// Sigh, race([]) is untestable unless we return *something*
|
// that is recognizable without calling .then() on it.
|
return promises.length === 0 ? never()
|
: promises.length === 1 ? resolve(promises[0])
|
: runRace(promises);
|
}
|
|
function runRace(promises) {
|
var resolver = new Pending();
|
var i, x, h;
|
for(i=0; i<promises.length; ++i) {
|
x = promises[i];
|
if (x === void 0 && !(i in promises)) {
|
continue;
|
}
|
|
h = getHandler(x);
|
if(h.state() !== 0) {
|
resolver.become(h);
|
visitRemaining(promises, i+1, h);
|
break;
|
} else {
|
h.visit(resolver, resolver.resolve, resolver.reject);
|
}
|
}
|
return new Promise(Handler, resolver);
|
}
|
|
// Promise internals
|
// Below this, everything is @private
|
|
/**
|
* Get an appropriate handler for x, without checking for cycles
|
* @param {*} x
|
* @returns {object} handler
|
*/
|
function getHandler(x) {
|
if(isPromise(x)) {
|
return x._handler.join();
|
}
|
return maybeThenable(x) ? getHandlerUntrusted(x) : new Fulfilled(x);
|
}
|
|
/**
|
* Get a handler for thenable x.
|
* NOTE: You must only call this if maybeThenable(x) == true
|
* @param {object|function|Promise} x
|
* @returns {object} handler
|
*/
|
function getHandlerMaybeThenable(x) {
|
return isPromise(x) ? x._handler.join() : getHandlerUntrusted(x);
|
}
|
|
/**
|
* Get a handler for potentially untrusted thenable x
|
* @param {*} x
|
* @returns {object} handler
|
*/
|
function getHandlerUntrusted(x) {
|
try {
|
var untrustedThen = x.then;
|
return typeof untrustedThen === 'function'
|
? new Thenable(untrustedThen, x)
|
: new Fulfilled(x);
|
} catch(e) {
|
return new Rejected(e);
|
}
|
}
|
|
/**
|
* Handler for a promise that is pending forever
|
* @constructor
|
*/
|
function Handler() {}
|
|
Handler.prototype.when
|
= Handler.prototype.become
|
= Handler.prototype.notify // deprecated
|
= Handler.prototype.fail
|
= Handler.prototype._unreport
|
= Handler.prototype._report
|
= noop;
|
|
Handler.prototype._state = 0;
|
|
Handler.prototype.state = function() {
|
return this._state;
|
};
|
|
/**
|
* Recursively collapse handler chain to find the handler
|
* nearest to the fully resolved value.
|
* @returns {object} handler nearest the fully resolved value
|
*/
|
Handler.prototype.join = function() {
|
var h = this;
|
while(h.handler !== void 0) {
|
h = h.handler;
|
}
|
return h;
|
};
|
|
Handler.prototype.chain = function(to, receiver, fulfilled, rejected, progress) {
|
this.when({
|
resolver: to,
|
receiver: receiver,
|
fulfilled: fulfilled,
|
rejected: rejected,
|
progress: progress
|
});
|
};
|
|
Handler.prototype.visit = function(receiver, fulfilled, rejected, progress) {
|
this.chain(failIfRejected, receiver, fulfilled, rejected, progress);
|
};
|
|
Handler.prototype.fold = function(f, z, c, to) {
|
this.when(new Fold(f, z, c, to));
|
};
|
|
/**
|
* Handler that invokes fail() on any handler it becomes
|
* @constructor
|
*/
|
function FailIfRejected() {}
|
|
inherit(Handler, FailIfRejected);
|
|
FailIfRejected.prototype.become = function(h) {
|
h.fail();
|
};
|
|
var failIfRejected = new FailIfRejected();
|
|
/**
|
* Handler that manages a queue of consumers waiting on a pending promise
|
* @constructor
|
*/
|
function Pending(receiver, inheritedContext) {
|
Promise.createContext(this, inheritedContext);
|
|
this.consumers = void 0;
|
this.receiver = receiver;
|
this.handler = void 0;
|
this.resolved = false;
|
}
|
|
inherit(Handler, Pending);
|
|
Pending.prototype._state = 0;
|
|
Pending.prototype.resolve = function(x) {
|
this.become(getHandler(x));
|
};
|
|
Pending.prototype.reject = function(x) {
|
if(this.resolved) {
|
return;
|
}
|
|
this.become(new Rejected(x));
|
};
|
|
Pending.prototype.join = function() {
|
if (!this.resolved) {
|
return this;
|
}
|
|
var h = this;
|
|
while (h.handler !== void 0) {
|
h = h.handler;
|
if (h === this) {
|
return this.handler = cycle();
|
}
|
}
|
|
return h;
|
};
|
|
Pending.prototype.run = function() {
|
var q = this.consumers;
|
var handler = this.handler;
|
this.handler = this.handler.join();
|
this.consumers = void 0;
|
|
for (var i = 0; i < q.length; ++i) {
|
handler.when(q[i]);
|
}
|
};
|
|
Pending.prototype.become = function(handler) {
|
if(this.resolved) {
|
return;
|
}
|
|
this.resolved = true;
|
this.handler = handler;
|
if(this.consumers !== void 0) {
|
tasks.enqueue(this);
|
}
|
|
if(this.context !== void 0) {
|
handler._report(this.context);
|
}
|
};
|
|
Pending.prototype.when = function(continuation) {
|
if(this.resolved) {
|
tasks.enqueue(new ContinuationTask(continuation, this.handler));
|
} else {
|
if(this.consumers === void 0) {
|
this.consumers = [continuation];
|
} else {
|
this.consumers.push(continuation);
|
}
|
}
|
};
|
|
/**
|
* @deprecated
|
*/
|
Pending.prototype.notify = function(x) {
|
if(!this.resolved) {
|
tasks.enqueue(new ProgressTask(x, this));
|
}
|
};
|
|
Pending.prototype.fail = function(context) {
|
var c = typeof context === 'undefined' ? this.context : context;
|
this.resolved && this.handler.join().fail(c);
|
};
|
|
Pending.prototype._report = function(context) {
|
this.resolved && this.handler.join()._report(context);
|
};
|
|
Pending.prototype._unreport = function() {
|
this.resolved && this.handler.join()._unreport();
|
};
|
|
/**
|
* Wrap another handler and force it into a future stack
|
* @param {object} handler
|
* @constructor
|
*/
|
function Async(handler) {
|
this.handler = handler;
|
}
|
|
inherit(Handler, Async);
|
|
Async.prototype.when = function(continuation) {
|
tasks.enqueue(new ContinuationTask(continuation, this));
|
};
|
|
Async.prototype._report = function(context) {
|
this.join()._report(context);
|
};
|
|
Async.prototype._unreport = function() {
|
this.join()._unreport();
|
};
|
|
/**
|
* Handler that wraps an untrusted thenable and assimilates it in a future stack
|
* @param {function} then
|
* @param {{then: function}} thenable
|
* @constructor
|
*/
|
function Thenable(then, thenable) {
|
Pending.call(this);
|
tasks.enqueue(new AssimilateTask(then, thenable, this));
|
}
|
|
inherit(Pending, Thenable);
|
|
/**
|
* Handler for a fulfilled promise
|
* @param {*} x fulfillment value
|
* @constructor
|
*/
|
function Fulfilled(x) {
|
Promise.createContext(this);
|
this.value = x;
|
}
|
|
inherit(Handler, Fulfilled);
|
|
Fulfilled.prototype._state = 1;
|
|
Fulfilled.prototype.fold = function(f, z, c, to) {
|
runContinuation3(f, z, this, c, to);
|
};
|
|
Fulfilled.prototype.when = function(cont) {
|
runContinuation1(cont.fulfilled, this, cont.receiver, cont.resolver);
|
};
|
|
var errorId = 0;
|
|
/**
|
* Handler for a rejected promise
|
* @param {*} x rejection reason
|
* @constructor
|
*/
|
function Rejected(x) {
|
Promise.createContext(this);
|
|
this.id = ++errorId;
|
this.value = x;
|
this.handled = false;
|
this.reported = false;
|
|
this._report();
|
}
|
|
inherit(Handler, Rejected);
|
|
Rejected.prototype._state = -1;
|
|
Rejected.prototype.fold = function(f, z, c, to) {
|
to.become(this);
|
};
|
|
Rejected.prototype.when = function(cont) {
|
if(typeof cont.rejected === 'function') {
|
this._unreport();
|
}
|
runContinuation1(cont.rejected, this, cont.receiver, cont.resolver);
|
};
|
|
Rejected.prototype._report = function(context) {
|
tasks.afterQueue(new ReportTask(this, context));
|
};
|
|
Rejected.prototype._unreport = function() {
|
if(this.handled) {
|
return;
|
}
|
this.handled = true;
|
tasks.afterQueue(new UnreportTask(this));
|
};
|
|
Rejected.prototype.fail = function(context) {
|
this.reported = true;
|
emitRejection('unhandledRejection', this);
|
Promise.onFatalRejection(this, context === void 0 ? this.context : context);
|
};
|
|
function ReportTask(rejection, context) {
|
this.rejection = rejection;
|
this.context = context;
|
}
|
|
ReportTask.prototype.run = function() {
|
if(!this.rejection.handled && !this.rejection.reported) {
|
this.rejection.reported = true;
|
emitRejection('unhandledRejection', this.rejection) ||
|
Promise.onPotentiallyUnhandledRejection(this.rejection, this.context);
|
}
|
};
|
|
function UnreportTask(rejection) {
|
this.rejection = rejection;
|
}
|
|
UnreportTask.prototype.run = function() {
|
if(this.rejection.reported) {
|
emitRejection('rejectionHandled', this.rejection) ||
|
Promise.onPotentiallyUnhandledRejectionHandled(this.rejection);
|
}
|
};
|
|
// Unhandled rejection hooks
|
// By default, everything is a noop
|
|
Promise.createContext
|
= Promise.enterContext
|
= Promise.exitContext
|
= Promise.onPotentiallyUnhandledRejection
|
= Promise.onPotentiallyUnhandledRejectionHandled
|
= Promise.onFatalRejection
|
= noop;
|
|
// Errors and singletons
|
|
var foreverPendingHandler = new Handler();
|
var foreverPendingPromise = new Promise(Handler, foreverPendingHandler);
|
|
function cycle() {
|
return new Rejected(new TypeError('Promise cycle'));
|
}
|
|
// Task runners
|
|
/**
|
* Run a single consumer
|
* @constructor
|
*/
|
function ContinuationTask(continuation, handler) {
|
this.continuation = continuation;
|
this.handler = handler;
|
}
|
|
ContinuationTask.prototype.run = function() {
|
this.handler.join().when(this.continuation);
|
};
|
|
/**
|
* Run a queue of progress handlers
|
* @constructor
|
*/
|
function ProgressTask(value, handler) {
|
this.handler = handler;
|
this.value = value;
|
}
|
|
ProgressTask.prototype.run = function() {
|
var q = this.handler.consumers;
|
if(q === void 0) {
|
return;
|
}
|
|
for (var c, i = 0; i < q.length; ++i) {
|
c = q[i];
|
runNotify(c.progress, this.value, this.handler, c.receiver, c.resolver);
|
}
|
};
|
|
/**
|
* Assimilate a thenable, sending it's value to resolver
|
* @param {function} then
|
* @param {object|function} thenable
|
* @param {object} resolver
|
* @constructor
|
*/
|
function AssimilateTask(then, thenable, resolver) {
|
this._then = then;
|
this.thenable = thenable;
|
this.resolver = resolver;
|
}
|
|
AssimilateTask.prototype.run = function() {
|
var h = this.resolver;
|
tryAssimilate(this._then, this.thenable, _resolve, _reject, _notify);
|
|
function _resolve(x) { h.resolve(x); }
|
function _reject(x) { h.reject(x); }
|
function _notify(x) { h.notify(x); }
|
};
|
|
function tryAssimilate(then, thenable, resolve, reject, notify) {
|
try {
|
then.call(thenable, resolve, reject, notify);
|
} catch (e) {
|
reject(e);
|
}
|
}
|
|
/**
|
* Fold a handler value with z
|
* @constructor
|
*/
|
function Fold(f, z, c, to) {
|
this.f = f; this.z = z; this.c = c; this.to = to;
|
this.resolver = failIfRejected;
|
this.receiver = this;
|
}
|
|
Fold.prototype.fulfilled = function(x) {
|
this.f.call(this.c, this.z, x, this.to);
|
};
|
|
Fold.prototype.rejected = function(x) {
|
this.to.reject(x);
|
};
|
|
Fold.prototype.progress = function(x) {
|
this.to.notify(x);
|
};
|
|
// Other helpers
|
|
/**
|
* @param {*} x
|
* @returns {boolean} true iff x is a trusted Promise
|
*/
|
function isPromise(x) {
|
return x instanceof Promise;
|
}
|
|
/**
|
* Test just enough to rule out primitives, in order to take faster
|
* paths in some code
|
* @param {*} x
|
* @returns {boolean} false iff x is guaranteed *not* to be a thenable
|
*/
|
function maybeThenable(x) {
|
return (typeof x === 'object' || typeof x === 'function') && x !== null;
|
}
|
|
function runContinuation1(f, h, receiver, next) {
|
if(typeof f !== 'function') {
|
return next.become(h);
|
}
|
|
Promise.enterContext(h);
|
tryCatchReject(f, h.value, receiver, next);
|
Promise.exitContext();
|
}
|
|
function runContinuation3(f, x, h, receiver, next) {
|
if(typeof f !== 'function') {
|
return next.become(h);
|
}
|
|
Promise.enterContext(h);
|
tryCatchReject3(f, x, h.value, receiver, next);
|
Promise.exitContext();
|
}
|
|
/**
|
* @deprecated
|
*/
|
function runNotify(f, x, h, receiver, next) {
|
if(typeof f !== 'function') {
|
return next.notify(x);
|
}
|
|
Promise.enterContext(h);
|
tryCatchReturn(f, x, receiver, next);
|
Promise.exitContext();
|
}
|
|
function tryCatch2(f, a, b) {
|
try {
|
return f(a, b);
|
} catch(e) {
|
return reject(e);
|
}
|
}
|
|
/**
|
* Return f.call(thisArg, x), or if it throws return a rejected promise for
|
* the thrown exception
|
*/
|
function tryCatchReject(f, x, thisArg, next) {
|
try {
|
next.become(getHandler(f.call(thisArg, x)));
|
} catch(e) {
|
next.become(new Rejected(e));
|
}
|
}
|
|
/**
|
* Same as above, but includes the extra argument parameter.
|
*/
|
function tryCatchReject3(f, x, y, thisArg, next) {
|
try {
|
f.call(thisArg, x, y, next);
|
} catch(e) {
|
next.become(new Rejected(e));
|
}
|
}
|
|
/**
|
* @deprecated
|
* Return f.call(thisArg, x), or if it throws, *return* the exception
|
*/
|
function tryCatchReturn(f, x, thisArg, next) {
|
try {
|
next.notify(f.call(thisArg, x));
|
} catch(e) {
|
next.notify(e);
|
}
|
}
|
|
function inherit(Parent, Child) {
|
Child.prototype = objectCreate(Parent.prototype);
|
Child.prototype.constructor = Child;
|
}
|
|
function snd(x, y) {
|
return y;
|
}
|
|
function noop() {}
|
|
function hasCustomEvent() {
|
if(typeof CustomEvent === 'function') {
|
try {
|
var ev = new CustomEvent('unhandledRejection');
|
return ev instanceof CustomEvent;
|
} catch (ignoredException) {}
|
}
|
return false;
|
}
|
|
function hasInternetExplorerCustomEvent() {
|
if(typeof document !== 'undefined' && typeof document.createEvent === 'function') {
|
try {
|
// Try to create one event to make sure it's supported
|
var ev = document.createEvent('CustomEvent');
|
ev.initCustomEvent('eventType', false, true, {});
|
return true;
|
} catch (ignoredException) {}
|
}
|
return false;
|
}
|
|
function initEmitRejection() {
|
/*global process, self, CustomEvent*/
|
if(typeof process !== 'undefined' && process !== null
|
&& typeof process.emit === 'function') {
|
// Returning falsy here means to call the default
|
// onPotentiallyUnhandledRejection API. This is safe even in
|
// browserify since process.emit always returns falsy in browserify:
|
// https://github.com/defunctzombie/node-process/blob/master/browser.js#L40-L46
|
return function(type, rejection) {
|
return type === 'unhandledRejection'
|
? process.emit(type, rejection.value, rejection)
|
: process.emit(type, rejection);
|
};
|
} else if(typeof self !== 'undefined' && hasCustomEvent()) {
|
return (function (self, CustomEvent) {
|
return function (type, rejection) {
|
var ev = new CustomEvent(type, {
|
detail: {
|
reason: rejection.value,
|
key: rejection
|
},
|
bubbles: false,
|
cancelable: true
|
});
|
|
return !self.dispatchEvent(ev);
|
};
|
}(self, CustomEvent));
|
} else if(typeof self !== 'undefined' && hasInternetExplorerCustomEvent()) {
|
return (function(self, document) {
|
return function(type, rejection) {
|
var ev = document.createEvent('CustomEvent');
|
ev.initCustomEvent(type, false, true, {
|
reason: rejection.value,
|
key: rejection
|
});
|
|
return !self.dispatchEvent(ev);
|
};
|
}(self, document));
|
}
|
|
return noop;
|
}
|
|
return Promise;
|
};
|
});
|
}(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(); }));
|
|
}).call(this,require('_process'))
|
|
},{"_process":81}],117:[function(require,module,exports){
|
/** @license MIT License (c) copyright 2010-2014 original author or authors */
|
/** @author Brian Cavalier */
|
/** @author John Hann */
|
|
(function(define) { 'use strict';
|
define(function() {
|
|
return {
|
pending: toPendingState,
|
fulfilled: toFulfilledState,
|
rejected: toRejectedState,
|
inspect: inspect
|
};
|
|
function toPendingState() {
|
return { state: 'pending' };
|
}
|
|
function toRejectedState(e) {
|
return { state: 'rejected', reason: e };
|
}
|
|
function toFulfilledState(x) {
|
return { state: 'fulfilled', value: x };
|
}
|
|
function inspect(handler) {
|
var state = handler.state();
|
return state === 0 ? toPendingState()
|
: state > 0 ? toFulfilledState(handler.value)
|
: toRejectedState(handler.value);
|
}
|
|
});
|
}(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(); }));
|
|
},{}],118:[function(require,module,exports){
|
/** @license MIT License (c) copyright 2010-2014 original author or authors */
|
|
/**
|
* Promises/A+ and when() implementation
|
* when is part of the cujoJS family of libraries (http://cujojs.com/)
|
* @author Brian Cavalier
|
* @author John Hann
|
*/
|
(function(define) { 'use strict';
|
define(function (require) {
|
|
var timed = require('./lib/decorators/timed');
|
var array = require('./lib/decorators/array');
|
var flow = require('./lib/decorators/flow');
|
var fold = require('./lib/decorators/fold');
|
var inspect = require('./lib/decorators/inspect');
|
var generate = require('./lib/decorators/iterate');
|
var progress = require('./lib/decorators/progress');
|
var withThis = require('./lib/decorators/with');
|
var unhandledRejection = require('./lib/decorators/unhandledRejection');
|
var TimeoutError = require('./lib/TimeoutError');
|
|
var Promise = [array, flow, fold, generate, progress,
|
inspect, withThis, timed, unhandledRejection]
|
.reduce(function(Promise, feature) {
|
return feature(Promise);
|
}, require('./lib/Promise'));
|
|
var apply = require('./lib/apply')(Promise);
|
|
// Public API
|
|
when.promise = promise; // Create a pending promise
|
when.resolve = Promise.resolve; // Create a resolved promise
|
when.reject = Promise.reject; // Create a rejected promise
|
|
when.lift = lift; // lift a function to return promises
|
when['try'] = attempt; // call a function and return a promise
|
when.attempt = attempt; // alias for when.try
|
|
when.iterate = Promise.iterate; // DEPRECATED (use cujojs/most streams) Generate a stream of promises
|
when.unfold = Promise.unfold; // DEPRECATED (use cujojs/most streams) Generate a stream of promises
|
|
when.join = join; // Join 2 or more promises
|
|
when.all = all; // Resolve a list of promises
|
when.settle = settle; // Settle a list of promises
|
|
when.any = lift(Promise.any); // One-winner race
|
when.some = lift(Promise.some); // Multi-winner race
|
when.race = lift(Promise.race); // First-to-settle race
|
|
when.map = map; // Array.map() for promises
|
when.filter = filter; // Array.filter() for promises
|
when.reduce = lift(Promise.reduce); // Array.reduce() for promises
|
when.reduceRight = lift(Promise.reduceRight); // Array.reduceRight() for promises
|
|
when.isPromiseLike = isPromiseLike; // Is something promise-like, aka thenable
|
|
when.Promise = Promise; // Promise constructor
|
when.defer = defer; // Create a {promise, resolve, reject} tuple
|
|
// Error types
|
|
when.TimeoutError = TimeoutError;
|
|
/**
|
* Get a trusted promise for x, or by transforming x with onFulfilled
|
*
|
* @param {*} x
|
* @param {function?} onFulfilled callback to be called when x is
|
* successfully fulfilled. If promiseOrValue is an immediate value, callback
|
* will be invoked immediately.
|
* @param {function?} onRejected callback to be called when x is
|
* rejected.
|
* @param {function?} onProgress callback to be called when progress updates
|
* are issued for x. @deprecated
|
* @returns {Promise} a new promise that will fulfill with the return
|
* value of callback or errback or the completion value of promiseOrValue if
|
* callback and/or errback is not supplied.
|
*/
|
function when(x, onFulfilled, onRejected, onProgress) {
|
var p = Promise.resolve(x);
|
if (arguments.length < 2) {
|
return p;
|
}
|
|
return p.then(onFulfilled, onRejected, onProgress);
|
}
|
|
/**
|
* Creates a new promise whose fate is determined by resolver.
|
* @param {function} resolver function(resolve, reject, notify)
|
* @returns {Promise} promise whose fate is determine by resolver
|
*/
|
function promise(resolver) {
|
return new Promise(resolver);
|
}
|
|
/**
|
* Lift the supplied function, creating a version of f that returns
|
* promises, and accepts promises as arguments.
|
* @param {function} f
|
* @returns {Function} version of f that returns promises
|
*/
|
function lift(f) {
|
return function() {
|
for(var i=0, l=arguments.length, a=new Array(l); i<l; ++i) {
|
a[i] = arguments[i];
|
}
|
return apply(f, this, a);
|
};
|
}
|
|
/**
|
* Call f in a future turn, with the supplied args, and return a promise
|
* for the result.
|
* @param {function} f
|
* @returns {Promise}
|
*/
|
function attempt(f /*, args... */) {
|
/*jshint validthis:true */
|
for(var i=0, l=arguments.length-1, a=new Array(l); i<l; ++i) {
|
a[i] = arguments[i+1];
|
}
|
return apply(f, this, a);
|
}
|
|
/**
|
* Creates a {promise, resolver} pair, either or both of which
|
* may be given out safely to consumers.
|
* @return {{promise: Promise, resolve: function, reject: function, notify: function}}
|
*/
|
function defer() {
|
return new Deferred();
|
}
|
|
function Deferred() {
|
var p = Promise._defer();
|
|
function resolve(x) { p._handler.resolve(x); }
|
function reject(x) { p._handler.reject(x); }
|
function notify(x) { p._handler.notify(x); }
|
|
this.promise = p;
|
this.resolve = resolve;
|
this.reject = reject;
|
this.notify = notify;
|
this.resolver = { resolve: resolve, reject: reject, notify: notify };
|
}
|
|
/**
|
* Determines if x is promise-like, i.e. a thenable object
|
* NOTE: Will return true for *any thenable object*, and isn't truly
|
* safe, since it may attempt to access the `then` property of x (i.e.
|
* clever/malicious getters may do weird things)
|
* @param {*} x anything
|
* @returns {boolean} true if x is promise-like
|
*/
|
function isPromiseLike(x) {
|
return x && typeof x.then === 'function';
|
}
|
|
/**
|
* Return a promise that will resolve only once all the supplied arguments
|
* have resolved. The resolution value of the returned promise will be an array
|
* containing the resolution values of each of the arguments.
|
* @param {...*} arguments may be a mix of promises and values
|
* @returns {Promise}
|
*/
|
function join(/* ...promises */) {
|
return Promise.all(arguments);
|
}
|
|
/**
|
* Return a promise that will fulfill once all input promises have
|
* fulfilled, or reject when any one input promise rejects.
|
* @param {array|Promise} promises array (or promise for an array) of promises
|
* @returns {Promise}
|
*/
|
function all(promises) {
|
return when(promises, Promise.all);
|
}
|
|
/**
|
* Return a promise that will always fulfill with an array containing
|
* the outcome states of all input promises. The returned promise
|
* will only reject if `promises` itself is a rejected promise.
|
* @param {array|Promise} promises array (or promise for an array) of promises
|
* @returns {Promise} promise for array of settled state descriptors
|
*/
|
function settle(promises) {
|
return when(promises, Promise.settle);
|
}
|
|
/**
|
* Promise-aware array map function, similar to `Array.prototype.map()`,
|
* but input array may contain promises or values.
|
* @param {Array|Promise} promises array of anything, may contain promises and values
|
* @param {function(x:*, index:Number):*} mapFunc map function which may
|
* return a promise or value
|
* @returns {Promise} promise that will fulfill with an array of mapped values
|
* or reject if any input promise rejects.
|
*/
|
function map(promises, mapFunc) {
|
return when(promises, function(promises) {
|
return Promise.map(promises, mapFunc);
|
});
|
}
|
|
/**
|
* Filter the provided array of promises using the provided predicate. Input may
|
* contain promises and values
|
* @param {Array|Promise} promises array of promises and values
|
* @param {function(x:*, index:Number):boolean} predicate filtering predicate.
|
* Must return truthy (or promise for truthy) for items to retain.
|
* @returns {Promise} promise that will fulfill with an array containing all items
|
* for which predicate returned truthy.
|
*/
|
function filter(promises, predicate) {
|
return when(promises, function(promises) {
|
return Promise.filter(promises, predicate);
|
});
|
}
|
|
return when;
|
});
|
})(typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); });
|
|
},{"./lib/Promise":101,"./lib/TimeoutError":103,"./lib/apply":104,"./lib/decorators/array":105,"./lib/decorators/flow":106,"./lib/decorators/fold":107,"./lib/decorators/inspect":108,"./lib/decorators/iterate":109,"./lib/decorators/progress":110,"./lib/decorators/timed":111,"./lib/decorators/unhandledRejection":112,"./lib/decorators/with":113}],119:[function(require,module,exports){
|
function LonLatProjection(width, height) {
|
var imageSize = { width: width, height: height };
|
function getBoundingRect(regions) {
|
var LIMIT = Number.MAX_VALUE
|
var min, max
|
var boundingRect = { xMin: LIMIT, yMin: LIMIT, xMax: -LIMIT, yMax: -LIMIT }
|
|
for (var i = 0, L = regions.length; i < L; i++) {
|
var rect = regions[i].getBoundingRect()
|
|
min = { x: rect.xMin, y: rect.yMin };
|
max = { x: rect.xMax, y: rect.yMax }
|
|
boundingRect.xMin = boundingRect.xMin < min.x ? boundingRect.xMin : min.x
|
boundingRect.yMin = boundingRect.yMin < min.y ? boundingRect.yMin : min.y
|
boundingRect.xMax = boundingRect.xMax > max.x ? boundingRect.xMax : max.x
|
boundingRect.yMax = boundingRect.yMax > max.y ? boundingRect.yMax : max.y
|
}
|
|
return boundingRect
|
}
|
|
function project(coordinate, boundingRect) {
|
var width = boundingRect.xMax - boundingRect.xMin;
|
var height = boundingRect.yMin - boundingRect.yMax;
|
var distanceX = Math.abs(coordinate[0] - boundingRect.xMin);
|
var distanceY = coordinate[1] - boundingRect.yMax;
|
|
var percentX = (distanceX / width);
|
var percentY = (distanceY / height);
|
|
var px = percentX * imageSize.width,
|
py = percentY * imageSize.height;
|
return { x: px, y: py };
|
}
|
|
function unproject(pt, boundingRect) {
|
var width = boundingRect.xMax - boundingRect.xMin;
|
var height = boundingRect.yMin - boundingRect.yMax;
|
var lon = (pt.x / imageSize.width) * width,
|
lat = (pt.y / imageSize.height) * height;
|
return [lon, lat];
|
}
|
|
this.project = project;
|
this.unproject = unproject;
|
this.getBoundingRect = getBoundingRect;
|
}
|
|
module.exports = LonLatProjection;
|
},{}],120:[function(require,module,exports){
|
|
var shp = require('shpjs/lib/index.js');
|
var when = require('when');
|
var readAsArrayBuffer = require('./utils/readAsArrayBuffer');
|
var readAsText = require('./utils/readAsText');
|
var Path = require('./utils/Path');
|
|
shp.groupFiles = function (files) {
|
var group = {};
|
for (var i = 0; i < files.length; i++) {
|
var name = Path.ChangeExtension(files[i].name, "");
|
if (!group[name]) {
|
group[name] = [];
|
}
|
group[name].push(files[i]);
|
}
|
return group;
|
}
|
|
shp.parseShpFiles = function (files, encoding) {
|
if (!files || files.length > 0) {
|
var df = when.defer();
|
var promise = df.promise;
|
var shpFile, dbfFile, prjFile;
|
for (var i = 0; i < files.length; i++) {
|
if (files[i].name.toLocaleLowerCase().indexOf(".shp") > 0) {
|
shpFile = files[i];
|
}
|
if (files[i].name.toLocaleLowerCase().indexOf(".prj") > 0) {
|
prjFile = files[i];
|
}
|
if (files[i].name.toLocaleLowerCase().indexOf(".dbf") > 0) {
|
dbfFile = files[i];
|
}
|
}
|
if (!shpFile || !prjFile || !dbfFile) {
|
// throw new Error("打开文件失败,请通过ctrl+同时选择shp、prj、dbf三个文件");
|
df.reject(new Error("打开文件失败,请通过ctrl+同时选择shp、prj、dbf三个文件"));
|
return promise;
|
}
|
readAsArrayBuffer(shpFile).then(function (shpBuffer) {
|
readAsText(prjFile).then(function (prjBuffer) {
|
readAsArrayBuffer(dbfFile).then(function (dbfBuffer) {
|
var parsed = shp.combine([shp.parseShp(shpBuffer, prjBuffer), shp.parseDbf(dbfBuffer, encoding)]);
|
parsed.fileName = shpFile.name.toLocaleLowerCase();
|
|
df.resolve(parsed);
|
}).otherwise(function (err) {
|
df.reject(err);
|
})
|
}).otherwise(function (err) {
|
df.reject(err);
|
})
|
}).otherwise(function (err) {
|
df.reject(err);
|
})
|
|
return promise;
|
} else {
|
throw new Error("文件列表不能为空");
|
}
|
}
|
|
module.exports = shp;
|
},{"./utils/Path":182,"./utils/readAsArrayBuffer":185,"./utils/readAsText":186,"shpjs/lib/index.js":91,"when":118}],121:[function(require,module,exports){
|
var defaultValue = require('./cesium/Core/defaultValue');
|
var defined = require('./cesium/Core/defined');
|
var when = require('when');
|
|
function getColor(color) {
|
if (typeof Cesium != 'undefined') {
|
if (typeof color == 'string') {
|
color = Cesium.Color.fromCssColorString(color);
|
} else if (Array. isArray(color)) {
|
color = Cesium.Color.fromBytes(color[0], color[1], color[2], color[3]);
|
}
|
}
|
else if (Array.isArray(color)) {
|
color = 'rgba(' + [color[0], color[1], color[2], defaultValue(color[3], 0) / 255].join(',') + ')';
|
}
|
return color
|
}
|
|
/**
|
*
|
*@param {Object} options
|
*@param {Cesium.Color|String}[options.outlineColor=Cesium.Color.YELLOW] 线或边颜色,仅线、面数据有效。
|
*@param {Cesium.Color|String}[options.fillColor=Cesium.Color.fromBytes(0, 255, 255, 30)] 填充颜色,仅面数据有效。
|
*@param {Cesium.Color|String}[options.backgroundColor] 背景色
|
*@param {Number}[options.lineWidth=1.5] 线宽,仅线数据有效。
|
*@param {Boolean}[options.outline=true] 是否显示边,仅面数据有效。
|
*@param {Boolean}[options.fill=true] 是否填充,仅面数据有效。
|
*@param {Cesium.Color|String}[options.fontColor=Cesium.Color.BLACK] 注记文本颜色
|
*@param {Number}[options.fontSize=16] 注记文本字体大小,仅在数据有点时有效。
|
*@param {String}[options.fontFamily="宋体"] 注记文本字体名称,仅在数据有点时有效。
|
*@param {Boolean}[options.labelStroke] 是否显示注记文本轮廓线,仅在数据有点时有效。
|
*@param {String}[options.labelStrokeWidth=1] 注记文本轮廓线宽,仅在数据有点时有效。
|
*@param {Cesium.Color|String}[options.labelStrokeColor] 注记文本轮廓线颜色,仅在数据有点时有效。
|
*
|
*@param {Number}[options.pointSize=4] 注记点大小,仅在数据有点时有效。
|
*@param {Cesium.Color|String}[options.pointColor=Cesium.Color.YELLOW] 注记点颜色,仅在数据有点时有效。
|
*@param {String}[options.labelPropertyName='NAME'] 注记文本属性名称,仅在数据有点时有效。
|
*@param {String}[options.makerImage=undefined] 注记点图标,如果设置点图标,则其他点样式参数无效,仅在数据有点时有效。
|
*@param {Number}[options.ringRadius=2] 注记点样式为Ring时,圆心点大小(半径),仅在数据有点时有效。
|
*@param {String}[options.pointStyle='Ring'] 注记点样式,仅在数据有点时有效。'Solid'为实心圆,'Ring'为带圆心的圆形,'Circle'为空心圆
|
*@param {Number}[options.circleLineWidth=2] 注记点样式为Circle时,圆形线宽
|
*@param {Boolean}[options.showMarker=true] 是否显示注记点,仅在数据有点时有效。
|
*@param {Boolean}[options.showLabel=true] 是否显示文本,仅在数据有点时有效。
|
*@param {Boolean}[options.showCenterLabel=true] 是否显示文本,仅对线和面数据有效。
|
*@param {String}[options.centerLabelPropertyName] 几何中心注记文本属性名称,仅对线和面数据有效。
|
*@param {Number}[options.labelOffsetX=10] 标注文本x方向偏移量,仅在数据有点时有效。以屏幕为参考,左上角为0,向右为正,单位为像素
|
*@param {Number}[options.labelOffsetY=5] 标注文本y方向偏移量,仅在数据有点时有效。以屏幕为参考,左上角为0,向下为正,单位为像素
|
*@param {Array.<Number>}[options.lineDash=undefined] 虚线样式,不设置则为实线
|
*@param {String}[options.lineCap="butt"] 设置线条末端线帽的样式。 butt——默认。向线条的每个末端添加平直的边缘;round——向线条的每个末端添加圆形线帽;square——向线条的每个末端添加正方形线帽。
|
*@param {String}[options.shadowColor=undefined] 设置用于阴影的颜色
|
*@param {Number}[options.shadowBlur=undefined] 设置用于阴影的模糊级别
|
*@param {Number}[options.shadowOffsetX=undefined] 设置阴影距形状的水平距离
|
*@param {Number}[options.shadowOffsetY=undefined] 设置阴影距形状的垂直距离
|
*@param {String}[options.lineJoin="miter"] 设置当两条线交汇时所创建边角的类型。bevel——斜角;round——创建圆角;miter——默认。创建尖角。
|
*@param {Number}[options.miterLimit=10] 设置最大斜接长度。
|
*@memberof Cesium
|
*@constructor
|
*/
|
function VectorStyle(options) {
|
//*@param {Number}[options.lineOffset=undefined] 双线样式参数,两线间距,单位为米(m)。不设置则为单线
|
|
if (typeof document == 'undefined') {
|
return options;
|
}
|
options = defaultValue(options, {});
|
this.fillColor = defaultValue(getColor(options.fillColor), getColor([0, 255, 255, 30]));
|
|
this.fill = defaultValue(options.fill, true);
|
|
this.labelStroke = options.labelStroke;
|
this.labelStrokeWidth = defaultValue(options.labelStrokeWidth, 1);
|
this.labelStrokeColor = defaultValue(getColor(options.labelStrokeColor), getColor([160, 99, 57]));
|
|
//线样式
|
this.outlineColor = defaultValue(getColor(options.outlineColor), getColor('yellow'));
|
|
this.backgroundColor = getColor(options.backgroundColor);
|
|
this.lineWidth = defaultValue(options.lineWidth, 1.5);
|
this.outline = defaultValue(options.outline, true);
|
|
//注记样式
|
this.fontColor = getColor(defaultValue(options.fontColor, 'black'));
|
|
|
this.fontSize = defaultValue(options.fontSize, 16);
|
this.fontFamily = defaultValue(options.fontFamily, "宋体");
|
this.pointSize = defaultValue(options.pointSize, 4);
|
this.pointColor = getColor(defaultValue(options.pointColor, 'yellow'));
|
|
this.pointStyle = defaultValue(options.pointStyle, 'Ring');//'Solid','Ring','Circle'
|
this.labelPropertyName = defaultValue(options.labelPropertyName, 'NAME');
|
this.ringRadius = defaultValue(options.ringRadius, 2);
|
this.circleLineWidth = defaultValue(options.circleLineWidth, 2);
|
if (defined(options.showMaker)) {
|
this.showMarker = defaultValue(options.showMaker, true);
|
}
|
if (defined(options.showMarker)) {
|
this.showMarker = defaultValue(options.showMarker, true);
|
}
|
|
this.showLabel = defaultValue(options.showLabel, true);
|
|
this.showCenterLabel = defaultValue(options.showCenterLabel, false);
|
this.centerLabelPropertyName = options.centerLabelPropertyName;
|
|
this.labelOffsetX = defaultValue(options.labelOffsetX, 0);
|
this.labelOffsetY = defaultValue(options.labelOffsetY, 0);
|
this.markerImage = options.markerImage;
|
|
this.lineDash = options.lineDash;
|
//this.lineOffset = options.lineOffset;
|
this.lineCap = defaultValue(options.lineCap, "butt");
|
this.lineJoin = defaultValue(options.lineJoin, "miter");
|
this.shadowColor = getColor(options.shadowColor);
|
|
this.shadowBlur = options.shadowBlur;
|
this.shadowOffsetX = options.shadowOffsetX;
|
this.shadowOffsetY = options.shadowOffsetY;
|
this.miterLimit = defaultValue(options.miterLimit, 10);
|
|
this.markerImageEl = null;
|
var makerImagePromise = null;
|
var deferred = when.defer()
|
this.readyPromise = deferred.promise;
|
var that = this;
|
if (typeof this.markerImage == 'string') {
|
|
var image = new Image();
|
image.onload = function () {
|
that.markerImageEl = this;
|
deferred.resolve(true);
|
}
|
image.onerror = function (err) {
|
deferred.reject(err);
|
}
|
image.src = this.markerImage;
|
} else {
|
if (this.markerImage instanceof Image
|
|| this.markerImage instanceof HTMLCanvasElement) {
|
this.markerImageEl = this.markerImage;
|
}
|
setTimeout(function () {
|
|
deferred.resolve(true);
|
}, 10)
|
}
|
|
}
|
|
/**
|
*
|
*@return {Cesium.VectorStyle}
|
*/
|
VectorStyle.prototype.clone = function () {
|
var style = new VectorStyle();
|
for (var i in this) {
|
|
if (this.hasOwnProperty(i)) {
|
if (typeof Cesium != 'undefined' && this[i] instanceof Cesium.Color) {
|
style[i] = Cesium.Color.clone(this[i]);
|
} else {
|
style[i] = this[i];
|
}
|
}
|
}
|
return style;
|
}
|
|
/**
|
*
|
*@type {Cesium.VectorStyle}
|
*/
|
VectorStyle.Default = new VectorStyle();
|
|
module.exports = VectorStyle;
|
|
},{"./cesium/Core/defaultValue":158,"./cesium/Core/defined":160,"when":118}],122:[function(require,module,exports){
|
//不支持shp格式,如果需要支持shp格式,请在页面引用shpjs
|
//或者将入口改为VectorTileImageryProvider
|
var loadJson = require('./cesium/Core/Resource').fetchJson;
|
var LonLatProjection = require('./LonLatProjection');
|
var Path = require('./utils/Path');
|
var VectorStyle = require('./VectorStyle');
|
var drawText = require('./utils/drawText');
|
var defineProperties = require('./cesium/Core/defineProperties')
|
var defined = require('./cesium/Core/defined');
|
var defaultValue = require('./cesium/Core/defaultValue');
|
var Event = require('./cesium/Core/Event');
|
var when = require('when');
|
var CesiumMath = require('./cesium/Core/Math');
|
|
var turf = require('./turf-light')
|
var Rectangle = require('./cesium/Core/Rectangle');
|
if (typeof Cesium !== 'undefined') {
|
//Rectangle = Cesium.Rectangle;
|
if (Cesium.ImageryLayerCollection) {
|
|
/**
|
* 根据zIndex属性调整图层顺序
|
* @method orderByZIndex
|
* @name orderByZIndex
|
* @memberof Cesium.ImageryLayerCollection
|
*/
|
|
Cesium.ImageryLayerCollection.prototype.orderByZIndex = function () {
|
//调整带有index的图层顺序
|
var layersHasIndex = [];
|
for (var i = 0; i < this.length; i++) {
|
var l = this.get(i);
|
if ((l.imageryProvider.zIndex || l.zIndex)) {
|
layersHasIndex.push(l);
|
if (!l.zIndex) {
|
l.zIndex = l.imageryProvider.zIndex;
|
} else if (!l.imageryProvider.zIndex) {
|
l.imageryProvider.zIndex = l.zIndex;
|
}
|
}
|
}
|
if (layersHasIndex && layersHasIndex.length) {
|
layersHasIndex.sort(function (a, b) {
|
if (a.zIndex > b.zIndex) {
|
return 1;
|
} else if (a.zIndex < b.zIndex) {
|
return -1;
|
}
|
else {
|
return 0;
|
}
|
})
|
}
|
var that = this;
|
layersHasIndex.forEach(function (l) {
|
that.raiseToTop(l);
|
});
|
|
for (var i = 0; i < this.length; i++) {
|
var l = this.get(i);
|
//调整矢量图层顺序
|
if (!Cesium.defined(l.imageryProvider.zIndex)
|
&& !Cesium.defined(l.zIndex)
|
&& l.imageryProvider instanceof VectorTileImageryProvider) {
|
this.raiseToTop(l);
|
}
|
}
|
|
for (var i = 0; i < this.length; i++) {
|
var l = this.get(i);
|
//调整矢量图层顺序
|
if (!Cesium.defined(l.imageryProvider.zIndex)
|
&& !Cesium.defined(l.zIndex)
|
&& l.imageryProvider instanceof VectorTileImageryProvider
|
&& (l.imageryProvider._lineOnly || l.imageryProvider._onlyPoint)) {
|
this.raiseToTop(l);
|
}
|
}
|
}
|
|
}
|
}
|
// var defaultColor = new Cesium.Color(1.0, 1.0, 1.0, 0.4);
|
// var defaultGlowColor = new Cesium.Color(0.0, 1.0, 0.0, 0.05);
|
// var defaultBackgroundColor = new Cesium.Color(0.0, 0.5, 0.0, 0.2);
|
function isShpLocalFiles(files) {
|
var isFile = files.length >= 3;
|
if (!isFile) return false;
|
var shpFile, dbfFile, prjFile;
|
for (var i = 0; i < files.length; i++) {
|
var file = files[i];
|
if (!(file instanceof File || (file instanceof Blob && file.name))) {
|
return false;
|
}
|
if (files[i].name.toLocaleLowerCase().indexOf(".shp") > 0) {
|
shpFile = files[i];
|
}
|
if (files[i].name.toLocaleLowerCase().indexOf(".prj") > 0) {
|
prjFile = files[i];
|
}
|
if (files[i].name.toLocaleLowerCase().indexOf(".dbf") > 0) {
|
dbfFile = files[i];
|
}
|
}
|
if (!shpFile || !prjFile || !dbfFile) {
|
return false;
|
}
|
return true;
|
}
|
|
/**
|
*动态矢量切片提供程序,支持esri shapefile(需要引用shpjs或者打包的时候加入shpjs)、geojson文件,也可以直接加载geojson对象
|
* <ul class="see-list">
|
* <li><a href="https://mikeswei.github.io/CesiumVectorTile/" target="_blank">VectorTileImageryProviderDemo</a></li>
|
* </ul>
|
*@param {Object}options 参数如下:
|
*@param {String|turf.FeatureCollection|Object|Array<File>}options.source 矢量文件url、矢量文件列表或者geojson对象
|
*@param {Cesium.VectorStyle}[options.defaultStyle=Cesium.VectorStyle.Default] 默认样式
|
*@param {Boolean}[options.simplify=false] true则简化,默认不简化
|
*@param {Boolean}[options.simplifyTolerance=0.01] 简化公差
|
*@param {Boolean}[options.minimumLevel=3] 最小级别
|
*@param {Boolean}[options.maximumLevel=22] 最大级别
|
*@param {Boolean}[options.showMaximumLevel=true] 当超出最大级别时是否继续显示
|
*@param {Boolean}[options.removeDuplicate=true] 是否剔除重复的多边形
|
*@param {Boolean}[options.allowPick=false] 是否支持要素查询,如果支持要素查询则保留原始的geojson,会多占用系统内存
|
*@param {Cesium.VectorTileImageryProvider~clusteringCallback}[options.clustering] 聚类函数
|
*
|
*@param {Cesium.VectorTileImageryProvider~StyleFilterCallback}[options.styleFilter=undefined] 样式函数
|
*@constructor
|
*@memberof Cesium
|
*@extends Cesium.ImageryProvider
|
*@example
|
//1.面数据
|
viewer.imageryLayers.addImageryProvider(new VectorTileImageryProvider({
|
source: appConfig.BaseURL + "Assets/VectorData/中国数据/陕西/榆林/county_sshanxi_yulin.shp",
|
defaultStyle:{ outlineColor: Cesium.Color.WHITE,
|
fill: true
|
},
|
maximumLevel: 22,
|
minimumLevel: 0
|
}))
|
//2.点数据
|
viewer.imageryLayers.addImageryProvider(new VectorTileImageryProvider({
|
source: appConfig.BaseURL + "Assets/VectorData/中国数据/陕西/榆林/town_sshanxi_yulin.shp"
|
,defaultStyle:{
|
fontColor: Cesium.Color.WHITE
|
, fontSize: 20
|
, fontFamily: '微软雅黑'
|
, markerImage: appConfig.BaseURL + "Assets/Images/Stations/autonew.png"
|
, labelOffsetY: 5
|
, labelOffsetX: 10
|
}
|
, maximumLevel: 22
|
, minimumLevel: 9
|
}))
|
//3.线数据
|
viewer.imageryLayers.addImageryProvider(new VectorTileImageryProvider({
|
source: appConfig.BaseURL + "Assets/VectorData/中国数据/中国边界.shp"
|
}))
|
|
//4.geojson
|
viewer.imageryLayers.addImageryProvider(new VectorTileImageryProvider({
|
source: appConfig.BaseURL + "Assets/SampleData/simplestyles.geojson",//VectorData/中国数据/中国边界.shp",
|
defaultStyle:{
|
fill: true
|
},
|
minimumLevel: 0
|
}))
|
|
5.使用样式函数(styleFilter)设置样式
|
viewer.imageryLayers.addImageryProvider(new Cesium.VectorTileImageryProvider({
|
source: appConfig.BaseURL + "Assets/VectorData/世界数据/Countries.shp",
|
defaultStyle: {
|
outlineColor: Cesium.Color.YELLOW,
|
lineWidth: 2,
|
fillColor: Cesium.Color.fromBytes(2, 24, 47, 200),
|
fill: false,
|
tileCacheSize: 200,
|
showMarker: false,
|
showCenterLabel: true,
|
fontColor: "rgba(255,0,0,1)",
|
labelOffsetX: -10,
|
labelOffsetY: -5,
|
fontSize: 13,
|
fontFamily: "黑体",
|
centerLabelPropertyName: "NAME"
|
},
|
maximumLevel: 20,
|
minimumLevel: 1,
|
simplify: false ,
|
styleFilter: function (feature, style) {
|
if (feature.properties.hasOwnProperty("NAME") && feature.properties["NAME"].toLocaleLowerCase().indexOf("china") >= 0) {
|
style.outlineColor = Cesium.Color.RED;
|
style.fill = true;
|
style.fillColor = Cesium.Color.AZURE.withAlpha(0.5);
|
}
|
}
|
}))
|
|
6.配图示例
|
appConfig.map = appConfig.map ? appConfig.map : {
|
focusAdminNames: ['北京', '天津', '河北'],
|
focusPropertyName: "NAME"
|
};
|
imageryProviders.seaLandImgProvider = new VectorTileImageryProvider({
|
source: appConfig.BaseURL + 'Assets/SampleData/sealand.geojson',
|
zIndex: 999,
|
minimumLevel: 0,
|
defaultStyle: {
|
fill: true,//是否填充海陆颜色
|
outlineColor: 'rgba(138,138,138,1)',//边界颜色
|
fillColor: 'rgba(235,235,235,1)',//陆地颜色
|
backgroundColor: 'rgba(89,129,188,1)'//海区颜色
|
}
|
});
|
imageryProviders.chinaBorderImgProvider = new VectorTileImageryProvider({
|
source: appConfig.BaseURL + 'Assets/SampleData/ChinaBorder.geojson',
|
zIndex: 999,
|
minimumLevel: 0,
|
defaultStyle: {
|
lineWidth: 1.25,
|
outlineColor: 'rgba(88,88,88,1)'
|
}
|
});
|
|
imageryProviders.provinceImgProvider = new VectorTileImageryProvider({
|
source: appConfig.BaseURL + 'Assets/SampleData/Province.geojson',
|
zIndex: 998,
|
minimumLevel: 0,
|
defaultStyle: {
|
lineWidth: 1,
|
//lineDash: [1, 4],
|
fill: true,
|
outline: true,
|
shadowColor: Cesium.Color.WHITE,
|
outlineColor: 'rgba(118,118,118,1)',
|
fillColor: 'rgba(225,225,225, .5)'
|
},
|
styleFilter: function (feature, style) {
|
|
if (appConfig.map) {
|
var highlight = false;
|
for (var i = 0; i < appConfig.map.focusAdminNames.length; i++) {
|
highlight = feature.properties[appConfig.map.focusPropertyName]
|
&& feature.properties[appConfig.map.focusPropertyName].indexOf(appConfig.map.focusAdminNames[i]) >= 0;
|
if (highlight) break;
|
}
|
if (highlight) {
|
style.fill = false;
|
style.outlineColor = Cesium.Color.BLACK;
|
style.fillColor = Cesium.Color.WHITE;
|
style.lineWidth = 1.25;
|
style.lineDash = null;
|
}
|
}
|
|
return style;
|
}
|
});
|
|
imageryProviders.adminLabelImgProvider = new VectorTileImageryProvider({
|
source: appConfig.BaseURL + 'Assets/SampleData/placeName.geojson',
|
minimumLevel: 3,
|
defaultStyle: {
|
showLabel: true,
|
labelPropertyName: "name",
|
fontFamily: 'heiti',
|
showMarker: true,
|
labelOffsetY: -12,
|
pointColor: 'rgba(118,118,118,1)',
|
labelStrokeWidth: 4,
|
fontSize: 12,
|
labelStroke: true,
|
fontColor: Cesium.Color.WHITE,
|
labelStrokeColor: 'rgba(118,118,118,1)'//Cesium.Color.BLACK
|
},
|
styleFilter: function (fc, style, x, y, level) {
|
var highlight = false;
|
if (appConfig.map && fc.properties.province) {
|
|
for (var i = 0; i < appConfig.map.focusAdminNames.length; i++) {
|
highlight = fc.properties.province.indexOf(
|
appConfig.map.focusAdminNames[i]
|
) >= 0;
|
if (highlight) break;
|
}
|
}
|
if (highlight) {
|
style.pointColor = Cesium.Color.BLACK;
|
}
|
if (fc.properties.adminType == 'province') {
|
if (level > 14) {
|
style.show = false;
|
}
|
style.showMarker = false;
|
style.labelOffsetY = 0;
|
style.fontSize = 16;
|
if (highlight) {
|
style.labelStrokeColor = Cesium.Color.fromBytes(160, 99, 57);
|
} else {
|
style.labelStrokeColor = Cesium.Color.fromBytes(140, 89, 47);
|
}
|
} else {
|
|
if (fc.properties.adminType == 'city') {
|
if (level < 6) {
|
style.show = false;
|
}
|
}
|
if (fc.properties.adminType == 'county' && level < 10) {
|
style.show = false;
|
}
|
if (fc.properties.adminType == 'country') {
|
style.show = false;
|
}
|
|
if (level > 14) {
|
style.fontSize = 18;
|
}
|
|
if (highlight) {
|
style.labelStrokeColor = Cesium.Color.BLACK;
|
}
|
}
|
if (level < 6) {
|
style.fontSize = 9;
|
}
|
if (level > 4) {
|
style.labelPropertyName = "name";
|
} else {
|
style.labelPropertyName = "nameabbrevation";
|
}
|
|
return style;
|
}
|
})
|
imageryProviderViewModels.push(new Cesium.ProviderViewModel({
|
name: '海陆模版',
|
iconUrl: appConfig.BaseURL + 'Assets/Images/ImageryProviders/sealand.png',
|
tooltip: '海陆模版',
|
creationFunction: function () {
|
setTimeout(function () {
|
imageryProviderViewModels.onSelected(imageryProviders.seaLandImgProvider);
|
}, 200);
|
return imageryProviders.seaLandImgProvider;
|
}
|
}));
|
|
|
//leaflet中使用,必须先引用leafletjs文件后引用MeteoLibjs文件
|
//VectorTileImageryLayer参数和MeteoLib.Scene.VectorTileImageryProvider的参数一样
|
var map = L.map('map', {
|
crs: L.CRS.EPSG4326
|
})
|
var vectorTileImageryLayer = new L.VectorTileImageryLayer({
|
zIndex: 1,
|
source: "../../../examples/Assets/Data/json/china_province.geojson",
|
defaultStyle: {
|
fill: true
|
}
|
})
|
layerCtrl.addOverlay(vectorTileImageryLayer, '自定义矢量瓦片图层')
|
vectorTileImageryLayer.addTo(map)
|
*/
|
function VectorTileImageryProvider(options) {
|
///@param {Boolean}[options.multipleTask=true] 是否使用多个VectorTileImageryProvider实例,使用多个实例是设置该参数为true可以提高ui响应速度,使用唯一一个实例时设置该参数为false则可以提高切片速度。
|
//@param {Boolean}[options.taskWaitTime=10] 使用多个实例时,每个实例的切片任务延迟结束的时间,以此来避免多个矢量图层同时存在时出现某个图层一直更新而其他图层一直没有更新的bug
|
|
options = defaultValue(options, {});
|
if (!defined(options.source)) {
|
return;
|
//throw new Error("source is required");
|
}
|
var ext = null;
|
var isLocalShpFile = false;
|
if (typeof options.source == 'string') {
|
var source = options.source.toLowerCase();
|
ext = Path.GetExtension(source)
|
if (ext !== '.shp' && ext !== '.json' && ext !== '.geojson' && ext !== '.topojson') {
|
throw new Error("The data options.source provider is not supported.");
|
}
|
} else if (options.source.type && options.source.type == "FeatureCollection") {
|
|
} else if (isShpLocalFiles(options.source)) {
|
isLocalShpFile = true;
|
} else {
|
throw new Error("The data options.source provider is not supported.");
|
}
|
|
this._rectangle = options.rectangle;
|
this._tilingScheme = new Cesium.GeographicTilingScheme({ ellipsoid: options.ellipsoid });
|
this._tileWidth = defaultValue(options.tileWidth, 256);
|
this._tileHeight = defaultValue(options.tileHeight, 256);
|
|
//if (ext && ext == '.shp') {
|
// ext = Path.GetExtension(options.source)
|
// this._url = options.source.replace(ext, '');
|
//} else {
|
this._url = options.source;
|
//}
|
this._fileExtension = ext;
|
|
|
this._removeDuplicate = defaultValue(options.removeDuplicate, true);
|
this._allowPick = defaultValue(options.allowPick, false);
|
this._simplifyTolerance = defaultValue(options.simplifyTolerance, 0.01);
|
this._simplify = defaultValue(options.simplify, false);
|
//this._multipleTask = defaultValue(options.multipleTask, true);
|
//this._taskWaitTime = defaultValue(options.taskWaitTime, 10);
|
this._maximumLevel = defaultValue(options.maximumLevel, 22)
|
this._minimumLevel = defaultValue(options.minimumLevel, 3)
|
this._showMaximumLevel = defaultValue(options.showMaximumLevel, true)
|
this._makerImage = options.markerImage;
|
this._tileCacheSize = defaultValue(options.tileCacheSize, 200);
|
if (typeof options.defaultStyle == 'object' && !(options.defaultStyle instanceof VectorStyle)) {
|
options.defaultStyle = new VectorStyle(options.defaultStyle);
|
}
|
this._defaultStyle = defaultValue(options.defaultStyle, VectorStyle.Default.clone());
|
this._styleFilter = typeof options.styleFilter == 'function' ? options.styleFilter : undefined;
|
this.clustering = options.clustering
|
|
this._errorEvent = new Event();
|
this._featuresPicked = new Event();
|
|
var readyDf = when.defer();
|
|
this._readyPromise = readyDf.promise; //Cesium.when.defer();
|
this._ready = false;
|
this._state = VectorTileImageryProvider.State.READY;
|
|
this._cache = {};
|
this._count = 0;
|
this.zIndex = options.zIndex;
|
this._bbox = null;
|
/**
|
* 如果需要支持可以点击拾取要素进行要素查询则存储原始的geojson
|
* @private
|
*/
|
this._geoJSON = null;
|
var that = this;
|
var promises = [];
|
if (typeof this._makerImage == 'string') {
|
var makerImageDf = when.defer();
|
var image = new Image();
|
image.onload = function () {
|
makerImageDf.resolve(this);
|
that._makerImageEl = this;
|
}
|
image.onerror = function (err) {
|
makerImageDf.resolve(err);
|
}
|
image.src = this._makerImage;
|
promises.push(makerImageDf.promise);
|
}
|
|
var shpDf = when.defer();
|
promises.push(shpDf.promise);
|
this._state = VectorTileImageryProvider.State.SHPLOADING;
|
if (ext) {
|
switch (ext) {
|
case '.shp':
|
|
var url = this._url;
|
var ext = Path.GetExtension(url);
|
url = url.replace(ext, "");
|
if (typeof shp == 'function') {
|
shp(url, undefined, "gbk").then(onSuccess, function (err) {
|
console.log("load shp file error:" + err);
|
});
|
} else {
|
if (typeof VectorTileImageryProvider.shp == 'function') {
|
VectorTileImageryProvider.shp(url, undefined, "gbk").then(onSuccess, function (err) {
|
console.log("load shp file error:" + err);
|
that.readyPromise.reject(err)
|
});
|
} else {
|
throw new Error('找不到shp()方法,请确认是否引用了shpjs')
|
}
|
}
|
break;
|
case '.json':
|
case '.geojson':
|
case '.topojson':
|
// Resources.get(this._url)
|
//loadText(this._url)
|
loadJson(this._url)
|
.then(function (geojson) {
|
onSuccess(geojson);
|
}).otherwise(function (err) {
|
console.log(err);
|
})
|
break;
|
default:
|
throw new Error("The file options.source provider is not supported.");
|
}
|
} else {
|
if (isLocalShpFile) {
|
if (typeof shp == 'undefined') {
|
if (typeof VectorTileImageryProvider.shp == 'function') {
|
shp = VectorTileImageryProvider.shp;
|
} else {
|
throw new Error('找不到shp()方法,请确认是否引用了shpjs')
|
}
|
}
|
var prms = shp.parseShpFiles(that._url);
|
if (prms) {
|
prms.then(onSuccess).otherwise(function (err) {
|
readyDf.reject(err);
|
//console.log(err);
|
//throw new Error("The file options.source provider is not supported.");
|
});
|
} else {
|
readyDf.reject(new Error("The file options.source provider is not supported."));
|
}
|
} else {
|
setTimeout(function () {
|
if (Array.isArray(that._url)) {
|
readyDf.reject(new Error("The data options.source provide is not supported."));
|
} else {
|
onSuccess(that._url);
|
}
|
}, 10)
|
}
|
|
}
|
|
this._lineGeoJSON = null;
|
this._outlineGeoJSON = null;
|
this._pointGeoJSON = null;
|
this._polygonJSON = null;
|
this._onlyPoint = false;
|
this._lineOnly = false;
|
this._polygonOnly = false;
|
|
function onSuccess(geoJSON) {
|
if (that._allowPick)
|
that._geoJSON = geoJSON;
|
var tolerance = that._simplifyTolerance;
|
var lines = [], outlines = [], points = [], polygons = [];
|
var onlyPoint = true, lineOnly = true, polygonOnly = true;
|
var simplified;
|
|
function groupByCenterLabelPropertyName(geoJSON, centerLabelPropertyName) {
|
var dic = {};
|
turf.featureEach(geoJSON, function (fc) {
|
|
var geometry = fc.geometry;
|
if (geometry) return;
|
|
if ((geometry.type == 'Polygon'
|
|| geometry.type == 'MultiPolygon')
|
&& that._defaultStyle.showCenterLabel
|
&& that._defaultStyle.centerLabelPropertyName
|
&& fc.properties.hasOwnProperty(centerLabelPropertyName)) {
|
|
if (!dic[fc.properties[centerLabelPropertyName]]) {
|
dic[fc.properties[centerLabelPropertyName]] = [];
|
}
|
dic[fc.properties[centerLabelPropertyName]].push(fc);
|
}
|
|
});
|
var keys = Object.keys(dic);
|
for (var i = 0; i < keys.length; i++) {
|
var fc = dic[keys[i]][0];
|
var fcs = turf.featureCollection(dic[keys[i]]);
|
var center = turf.center(fcs)
|
points.push(center);
|
center.properties = fc.properties;
|
delete dic[keys[i]];
|
}
|
|
}
|
|
if (that._defaultStyle.showCenterLabel
|
&& that._defaultStyle.centerLabelPropertyName) {
|
that._defaultStyle.showLabel = true;
|
that._defaultStyle.labelPropertyName = that._defaultStyle.centerLabelPropertyName;
|
|
groupByCenterLabelPropertyName(geoJSON, that._defaultStyle.centerLabelPropertyName);
|
}
|
|
turf.featureEach(geoJSON, function (fc) {
|
var geometry = fc.geometry;
|
if (!geometry) return;
|
if (geometry.type == 'MultiPolygon') {
|
var polygonCoords = turf.getCoords(fc);
|
polygonCoords.forEach(function (coords) {
|
geoJSON.features.push(turf.polygon(coords, fc.properties));
|
})
|
polygonCoords = [];
|
}
|
})
|
|
for (var i = 0; i < geoJSON.features.length; i++) {
|
var feature = geoJSON.features[i]
|
if (!feature) continue;
|
var geometry = feature.geometry
|
if (!geometry) continue
|
if (geometry.type == 'MultiPolygon') {
|
geoJSON.features.splice(i, 1)
|
}
|
}
|
if (that._removeDuplicate) {
|
geoJSON = turf.removeDuplicate(geoJSON);
|
}
|
|
|
turf.featureEach(geoJSON, function (feature, index) {
|
var geometry = feature.geometry
|
if (!geometry) return
|
if (geometry.type == "Point"
|
|| geometry.type == "MultiPoint") {
|
points.push(feature);
|
lineOnly = false;
|
polygonOnly = false;
|
} else if (that._defaultStyle.showCenterLabel
|
&& that._defaultStyle.centerLabelPropertyName
|
&& geometry.type !== "Polygon"
|
&& geometry.type !== "MultiPolygon") {
|
that._defaultStyle.showLabel = true;
|
that._defaultStyle.labelPropertyName = that._defaultStyle.centerLabelPropertyName;
|
var center = turf.centerOfMass(feature)
|
points.push(center);
|
center.properties = feature.properties;
|
}
|
|
if (geometry.type == "Polygon"
|
|| geometry.type == "MultiPolygon") {
|
var lineString = turf.polygonToLineString(feature);
|
if (lineString) {
|
if (lineString.type == 'FeatureCollection') {
|
outlines = outlines.concat(lineString.features);
|
} else if (lineString.type == 'Feature') {
|
outlines = outlines.concat(lineString);
|
}
|
}
|
|
onlyPoint = false;
|
lineOnly = false;
|
|
if (that._simplify) {
|
simplified = turf.simplify(feature, {
|
tolerance: tolerance, highQuality: false
|
});
|
polygons.push(simplified);
|
|
simplified = null;
|
} else {
|
polygons.push(feature);
|
|
}
|
}
|
if (geometry.type == "MultiLineString"
|
|| geometry.type == "LineString") {
|
|
if (that._simplify) {
|
simplified = turf.simplify(feature, { tolerance: tolerance, highQuality: false });
|
lines.push(simplified);
|
|
simplified = null;
|
|
} else {
|
lines.push(feature);
|
|
}
|
onlyPoint = false;
|
polygonOnly = false;
|
}
|
})
|
|
if (lines.length > 0) {
|
that._lineGeoJSON = turf.featureCollection(lines);
|
lines = null;
|
}
|
|
if (outlines.length > 0) {
|
outlines.forEach(function (outline) {
|
outline.properties.isOutline = true;
|
})
|
that._outlineGeoJSON = turf.featureCollection(outlines);
|
outlines = null;
|
}
|
|
if (points.length > 0) {
|
that._pointGeoJSON = turf.featureCollection(points);
|
points = null;
|
}
|
|
if (polygons.length > 0) {
|
that._polygonJSON = turf.featureCollection(polygons);
|
polygons = null;
|
}
|
|
that._lineOnly = lineOnly;
|
that._polygonOnly = polygonOnly;
|
that._onlyPoint = onlyPoint;
|
that._state = VectorTileImageryProvider.State.LOADED;
|
var bbox = turf.bbox(geoJSON);
|
if (bbox[0] == bbox[2]) {
|
bbox[0] = bbox[0] - 0.1;
|
bbox[2] = bbox[2] + 0.1;
|
}
|
if (bbox[1] == bbox[3]) {
|
bbox[1] = bbox[1] - 0.1;
|
bbox[3] = bbox[3] + 0.1;
|
}
|
// that.rectangle = Cesium.Rectangle.fromDegrees(that._bbox[0], that._bbox[1], that._bbox[2], that._bbox[3]);
|
that._bbox = Rectangle.fromDegrees(bbox[0], bbox[1], bbox[2], bbox[3]);
|
if (!that._rectangle) that._rectangle = that._bbox;
|
geoJSON = null;
|
shpDf.resolve(that);
|
}
|
|
when.all(promises).then(function () {
|
that._ready = that._state == VectorTileImageryProvider.State.LOADED;
|
that._createCanvas();
|
VectorTileImageryProvider.instanceCount++;
|
readyDf.resolve(true);
|
that._state = VectorTileImageryProvider.State.COMPELTED;
|
}).otherwise(function (err) {
|
readyDf.reject(err);
|
});
|
}
|
|
/**
|
*样式设置函数
|
*@callback Cesium.VectorTileImageryProvider~StyleFilterCallback
|
*@param {Geojson.Feature}feature 当前要素(用Geojson.Feature存储)
|
*@param {Cesium.VectorStyle}style 即将应用与当前要素的样式,可以通过修改该参数中的各样式设置选项来针对当前要素进行特殊的样式设置。
|
*修改后只对当前要素有效,不会修改MeteoLib.Scene.VectorTileImageryProvider的默认样式
|
*@param {Number}x
|
*@param {Number}y
|
*@param {Number}level
|
*/
|
|
|
/**
|
*聚类函数
|
*@callback Cesium.VectorTileImageryProvider~clusteringCallback
|
*@param {Array<Feature<Point|MultiPoint>>}features
|
* @param {CanvasRenderingContext2D}context
|
* @param {CanvasRenderingContext2D}tileBBox
|
*@param {Number}x
|
*@param {Number}y
|
*@param {Number}level
|
*/
|
|
|
VectorTileImageryProvider.instanceCount = 0;
|
VectorTileImageryProvider._currentTaskCount = 0;
|
VectorTileImageryProvider._maxTaskCount = 3;
|
VectorTileImageryProvider.State = {
|
READY: 0,
|
SHPLOADING: 1,
|
CLIPPING: 3,
|
GEOJSONDRAWING: 4,
|
COMPELTED: 5
|
}
|
defineProperties(VectorTileImageryProvider.prototype, {
|
/**
|
*
|
* @memberof Cesium.VectorTileImageryProvider.prototype
|
* @type {Cesium.VectorTileImageryProvider~StyleFilterCallback}
|
*/
|
styleFilter: {
|
get: function () {
|
return this._styleFilter;
|
},
|
set: function (val) {
|
this._styleFilter = val;
|
}
|
},
|
/**
|
*
|
* @memberof Cesium.VectorTileImageryProvider.prototype
|
* @type {Cesium.VectorStyle}
|
* @readonly
|
*/
|
defaultStyle: {
|
get: function () {
|
return this._defaultStyle;
|
}
|
},
|
/**
|
* Gets the proxy used by this provider.
|
* @memberof Cesium.VectorTileImageryProvider.prototype
|
* @type {Proxy}
|
* @readonly
|
*/
|
proxy: {
|
get: function () {
|
return undefined;
|
}
|
},
|
|
/**
|
* Gets the width of each tile, in pixels. This function should
|
* not be called before {@link Cesium.VectorTileImageryProvider#ready} returns true.
|
* @memberof Cesium.VectorTileImageryProvider.prototype
|
* @type {Number}
|
* @readonly
|
*/
|
tileWidth: {
|
get: function () {
|
return this._tileWidth;
|
}
|
},
|
|
/**
|
* Gets the height of each tile, in pixels. This function should
|
* not be called before {@link Cesium.VectorTileImageryProvider#ready} returns true.
|
* @memberof Cesium.VectorTileImageryProvider.prototype
|
* @type {Number}
|
* @readonly
|
*/
|
tileHeight: {
|
get: function () {
|
return this._tileHeight;
|
}
|
},
|
|
/**
|
* Gets the maximum level-of-detail that can be requested. This function should
|
* not be called before {@link Cesium.VectorTileImageryProvider#ready} returns true.
|
* @memberof Cesium.VectorTileImageryProvider.prototype
|
* @type {Number}
|
* @readonly
|
*/
|
maximumLevel: {
|
get: function () {
|
return this._showMaximumLevel ? this._maximumLevel : 22;
|
}
|
},
|
|
/**
|
* Gets the minimum level-of-detail that can be requested. This function should
|
* not be called before {@link Cesium.VectorTileImageryProvider#ready} returns true.
|
* @memberof Cesium.VectorTileImageryProvider.prototype
|
* @type {Number}
|
* @readonly
|
*/
|
minimumLevel: {
|
get: function () {
|
//if (this._minimumLevel <5) {
|
// return this._minimumLevel;
|
//}
|
return 0;
|
}
|
},
|
|
/**
|
* Gets the tiling scheme used by this provider. This function should
|
* not be called before {@link Cesium.VectorTileImageryProvider#ready} returns true.
|
* @memberof Cesium.VectorTileImageryProvider.prototype
|
* @type {TilingScheme}
|
* @readonly
|
*/
|
tilingScheme: {
|
get: function () {
|
return this._tilingScheme;
|
}
|
},
|
|
/**
|
* Gets the rectangle, in radians, of the imagery provided by this instance. This function should
|
* not be called before {@link Cesium.VectorTileImageryProvider#ready} returns true.
|
* @memberof Cesium.VectorTileImageryProvider.prototype
|
* @type {Rectangle}
|
* @readonly
|
*/
|
rectangle: {
|
get: function () {
|
return this._rectangle;//_tilingScheme.rectangle;
|
}
|
},
|
|
/**
|
* Gets the tile discard policy. If not undefined, the discard policy is responsible
|
* for filtering out "missing" tiles via its shouldDiscardImage function. If this function
|
* returns undefined, no tiles are filtered. This function should
|
* not be called before {@link Cesium.VectorTileImageryProvider#ready} returns true.
|
* @memberof Cesium.VectorTileImageryProvider.prototype
|
* @type {TileDiscardPolicy}
|
* @readonly
|
*/
|
tileDiscardPolicy: {
|
get: function () {
|
return undefined;
|
}
|
},
|
|
/**
|
* Gets an event that is raised when the imagery provider encounters an asynchronous error. By subscribing
|
* to the event, you will be notified of the error and can potentially recover from it. Event listeners
|
* are passed an instance of {@link TileProviderError}.
|
* @memberof Cesium.VectorTileImageryProvider.prototype
|
* @type {Event}
|
* @readonly
|
*/
|
errorEvent: {
|
get: function () {
|
return this._errorEvent;
|
}
|
},
|
/**
|
* 要素查询有结果时,即要素被点击时触发该事件
|
* @memberof Cesium.VectorTileImageryProvider.prototype
|
* @type {Event}
|
* @readonly
|
*/
|
featuresPicked: {
|
get: function () {
|
return this._featuresPicked;
|
}
|
},
|
/**
|
* Gets a value indicating whether or not the provider is ready for use.
|
* @memberof Cesium.VectorTileImageryProvider.prototype
|
* @type {Boolean}
|
* @readonly
|
*/
|
ready: {
|
get: function () {
|
return this._ready;
|
}
|
},
|
|
/**
|
* Gets a promise that resolves to true when the provider is ready for use.
|
* @memberof Cesium.VectorTileImageryProvider.prototype
|
* @type {Promise.<Boolean>}
|
* @readonly
|
*/
|
readyPromise: {
|
get: function () {
|
return this._readyPromise;
|
}
|
},
|
|
/**
|
* Gets the credit to display when this imagery provider is active. Typically this is used to credit
|
* the source of the imagery. This function should not be called before {@link Cesium.VectorTileImageryProvider#ready} returns true.
|
* @memberof Cesium.VectorTileImageryProvider.prototype
|
* @type {Credit}
|
* @readonly
|
*/
|
credit: {
|
get: function () {
|
return undefined;
|
}
|
},
|
|
/**
|
* Gets a value indicating whether or not the images provided by this imagery provider
|
* include an alpha channel. If this property is false, an alpha channel, if present, will
|
* be ignored. If this property is true, any images without an alpha channel will be treated
|
* as if their alpha is 1.0 everywhere. When this property is false, memory usage
|
* and texture upload time are reduced.
|
* @memberof Cesium.VectorTileImageryProvider.prototype
|
* @type {Boolean}
|
* @readonly
|
*/
|
hasAlphaChannel: {
|
get: function () {
|
return true;
|
}
|
}
|
});
|
|
VectorTileImageryProvider.prototype._createCanvas = function () {
|
this._canvas = document.createElement("canvas");
|
this._canvas.width = this._tileWidth;
|
this._canvas.height = this._tileHeight;
|
this._context = this._canvas.getContext("2d");
|
if (this._defaultStyle.backgroundColor) {
|
if (this._defaultStyle.backgroundColor instanceof Cesium.Color) {
|
this._context.fillStyle = this._defaultStyle.backgroundColor.toCssColorString();
|
} else {
|
this._context.fillStyle = this._defaultStyle.backgroundColor;
|
}
|
this._context.fillRect(0, 0, this._canvas.width, this._canvas.height);
|
}
|
|
this._context.lineWidth = this._defaultStyle.lineWidth;
|
if (this._defaultStyle.outlineColor instanceof Cesium.Color) {
|
this._context.strokeStyle = this._defaultStyle.outlineColor.toCssColorString();// "rgb(255,255,0)";
|
} else {
|
this._context.strokeStyle = this._defaultStyle.outlineColor;// "rgb(255,255,0)";
|
}
|
|
if (this._defaultStyle.fillColor instanceof Cesium.Color) {
|
this._context.fillStyle = this._defaultStyle.fillColor.toCssColorString();// "rgba(0,255,255,0.0)";
|
} else {
|
this._context.fillStyle = this._defaultStyle.fillColor;// "rgba(0,255,255,0.0)";
|
}
|
}
|
|
var isWorking = false;
|
//用当前瓦片(Tile)矩形裁剪geojson并返回裁剪结果
|
VectorTileImageryProvider.prototype._clipGeojson = function (rectangle) {
|
var that = this;
|
var bbox = [CesiumMath.toDegrees(rectangle.west),
|
CesiumMath.toDegrees(rectangle.south),
|
CesiumMath.toDegrees(rectangle.east),
|
CesiumMath.toDegrees(rectangle.north)];
|
var polygonBBox = turf.bboxPolygon(bbox);
|
// turf.polygon([[
|
// [bbox[0], bbox[1]],//sw
|
// [bbox[2], bbox[1]],//se
|
// [bbox[2], bbox[3]],//ne
|
// [bbox[0], bbox[3]],//nw
|
// [bbox[0], bbox[1]],//sw
|
//]]);
|
var pointsBBox = [
|
[bbox[0], bbox[1]],
|
[bbox[2], bbox[1]],
|
[bbox[2], bbox[3]],
|
[bbox[0], bbox[3]],
|
[bbox[0], bbox[1]]
|
];
|
for (var i = 0; i < pointsBBox.length; i++) {
|
var point = turf.point(pointsBBox[i]);
|
pointsBBox[i] = point;
|
}
|
pointsBBox = turf.featureCollection(pointsBBox);
|
|
|
var features = [];
|
if (this._pointGeoJSON) {
|
//为了避免出现在边界的文字只画到一半,同时把周边切片包含的点也放在本切片绘制
|
var lonW = (bbox[2] - bbox[0]) / 2, latH = (bbox[3] - bbox[1]) / 2;
|
var polygonBBox4Points = turf.bboxPolygon([
|
bbox[0] - lonW,
|
bbox[1] - latH,
|
bbox[2] + lonW,
|
bbox[3] + latH,
|
]);
|
var fcBBox = turf.featureCollection([polygonBBox4Points]);
|
var pts = turf.within(this._pointGeoJSON, fcBBox);
|
features = features.concat(pts.features);
|
}
|
var canClipGeojsons = [];
|
|
|
if (this._polygonJSON) {
|
canClipGeojsons.push(this._polygonJSON);
|
}
|
if (this._lineGeoJSON) {
|
canClipGeojsons.push(this._lineGeoJSON);
|
}
|
if (this._outlineGeoJSON) {
|
canClipGeojsons.push(this._outlineGeoJSON);
|
}
|
|
var clipped;
|
function clippedExists() {
|
var clippedCoords = turf.getCoords(clipped);
|
var exists = false;
|
for (var i = 0; i < features.length; i++) {
|
var keys1 = Object.keys(clipped.properties);
|
var keys2 = Object.keys(features[i].properties);
|
|
if (keys1.length != keys2.length) {
|
break;
|
}
|
var kEquals = true;
|
for (var k_i = 0; k_i < keys1.length; k_i++) {
|
if (keys1[k_i] != keys2[k_i]) {
|
kEquals = false;
|
break;
|
}
|
}
|
if (!kEquals) {
|
break;
|
}
|
kEquals = true;
|
for (var k_i = 0; k_i < keys1.length; k_i++) {
|
if (clipped.properties[keys1[k_i]] != features[i].properties[keys1[k_i]]) {
|
kEquals = false;
|
break;
|
}
|
}
|
if (!kEquals) {
|
break;
|
}
|
|
var tempCoords = turf.getCoords(features[i]);
|
|
if (clippedCoords.length && clippedCoords.length == tempCoords.length) {
|
var equals = true;
|
for (var j = 0; j < clippedCoords.length; j++) {
|
var c1 = clippedCoords[j], c2 = tempCoords[j];
|
if (!Array.isArray(c1[0])) {
|
try {
|
equals = c1[0] == c2[0] && c1[1] == c2[1];
|
} catch (e) {
|
console.log(e)
|
}
|
|
} else if (c1.length == c2.length) {
|
for (var k = 0; k < c1.length; k++) {
|
|
if (c1[k][0] != c2[k][0] || c1[k][1] != c2[k][1]) {
|
equals = false;
|
break;
|
}
|
}
|
|
} else {
|
equals = false;
|
break;
|
}
|
if (equals) {
|
break;
|
}
|
}
|
if (equals) {
|
exists = true;
|
break;
|
}
|
}
|
|
}
|
|
return exists;
|
}
|
|
canClipGeojsons.forEach(function (geojson) {
|
turf.featureEach(geojson, function (currentFeature, currentIndex) {
|
if (!currentFeature.geometry) return;
|
|
clipped = null;
|
try {
|
//if (currentFeature.geometry.type == "Polygon"
|
// || currentFeature.geometry.type == "MultiPolygon") {
|
// //var fcs = turf.featureCollection([currentFeature]);
|
// //if (!turf.within(pointsBBox, fcs))
|
// clipped = turf.intersect(currentFeature, polygonBBox);
|
// //else
|
// // clipped = polygonBBox;
|
// //fcs = null;
|
//}
|
if (!clipped) {
|
clipped = turf.bboxClip(currentFeature, bbox);
|
}
|
if (clipped && clipped.geometry.coordinates.length > 0) {
|
var empty = true;
|
for (var i = 0; i < clipped.geometry.coordinates.length; i++) {
|
if (clipped.geometry.coordinates[i].length > 0) {
|
empty = false;
|
break;
|
}
|
}
|
if (!empty) {
|
|
// if (!clippedExists()) {
|
features.push(clipped);
|
//}
|
} else {
|
//clipped = turf.intersect(currentFeature, polygonBBox);
|
//if (clipped) {
|
// features.push(clipped);
|
//}
|
//var fcs = turf.featureCollection([currentFeature]);
|
//if (turf.within(pointsBBox, fcs)) {
|
// features.push(polygonBBox);
|
//}
|
//fcs = null;
|
}
|
|
}
|
} catch (e) {
|
var coordinates = [];
|
currentFeature.geometry.coordinates.forEach(function (contour) {
|
if (contour.length > 3) {
|
coordinates.push(contour);
|
}
|
})
|
currentFeature.geometry.coordinates = coordinates;
|
try {
|
clipped = turf.bboxClip(currentFeature, bbox);
|
if (clipped && clipped.geometry.coordinates.length > 0) {
|
|
//if (!clippedExists()) {
|
features.push(clipped);
|
//}
|
}
|
} catch (error) {
|
console.error(error)
|
}
|
|
}
|
})
|
})
|
clipped = null;
|
if (features.length > 0) {
|
|
features = turf.featureCollection(features);
|
return features;
|
}
|
return null;
|
}
|
|
/**
|
* 挖孔
|
* @param {any} context
|
* @param {any} projection
|
* @param {any} boundingRect
|
* @param {any} x
|
* @param {any} y
|
* @param {any} holes
|
*/
|
function createHoles(context, projection, boundingRect, x, y, holes) {
|
var tileCanvas = context.canvas;
|
var imgData = context.getImageData(0, 0, tileCanvas.width, tileCanvas.height);
|
|
var holeMaskCanvas = document.createElement("canvas");
|
holeMaskCanvas.width = tileCanvas.width;
|
holeMaskCanvas.height = tileCanvas.height;
|
var holeMaskCtx = holeMaskCanvas.getContext("2d");
|
|
var mask = [];
|
holes.map(function (hole) {
|
holeMaskCtx.clearRect(0, 0, holeMaskCanvas.width, holeMaskCanvas.height);
|
holeMaskCtx.beginPath();
|
var pointIndex = 0;
|
hole.map(function (coordinate) {
|
var pt = projection.project(coordinate, boundingRect)
|
if (pointIndex == 0) {
|
holeMaskCtx.moveTo(x + pt.x, y + pt.y);
|
} else {
|
holeMaskCtx.lineTo(x + pt.x, y + pt.y);
|
}
|
pointIndex++;
|
})
|
holeMaskCtx.closePath();
|
|
|
holeMaskCtx.fillStyle = "rgba(255,255,255,1)";
|
holeMaskCtx.fill();
|
mask = holeMaskCtx.getImageData(0, 0, holeMaskCanvas.width, holeMaskCanvas.height).data;
|
for (var i = 3; i < mask.length; i += 4) {
|
if (mask[i] > 0) {
|
imgData.data[i] = 0;
|
}
|
}
|
|
});
|
context.putImageData(imgData, 0, 0);
|
}
|
|
//绘制多边形(面或线)
|
function drawContours(context, projection, boundingRect, x, y, contours, fill, stroke, style) {
|
|
var count = 0;
|
var holes = [];
|
contours.map(function (contour) {
|
if (!fill || count <= 0) {
|
var pointIndex = 0;
|
context.beginPath();
|
contour.map(function (coordinate) {
|
var pt = projection.project(coordinate, boundingRect)
|
if (pointIndex == 0) {
|
context.moveTo(x + pt.x, y + pt.y);
|
} else {
|
context.lineTo(x + pt.x, y + pt.y);
|
}
|
pointIndex++;
|
})
|
|
if (fill) {
|
context.closePath();
|
context.fill(); //context.stroke();
|
}
|
if (stroke) {
|
context.stroke();
|
}
|
|
} else {
|
holes.push(contour);
|
}
|
count++;
|
})
|
if (fill) {
|
return holes;
|
} else {
|
holes = null;
|
}
|
}
|
|
|
//画点
|
function drawMarker(context, projection, boundingRect, x, y, pointFeature, fill, stroke, labelPropertyName, makerStyle) {
|
if (typeof labelPropertyName == 'undefined') {
|
labelPropertyName = "NAME";
|
}
|
|
var style = Object.assign({
|
pointSize: 3,
|
fontSize: 9,
|
fontFamily: 'courier',
|
color: 'rgb(0,0,0)',
|
backgroundColor: 'rgb(255,0,0)',
|
pointStyle: "Solid",//'Solid','Ring','Circle'
|
ringRadius: 2,
|
circleLineWidth: 1,
|
showMarker: true,
|
showLabel: true,
|
labelOffsetX: 0.0,
|
labelOffsetY: 0.0,
|
markerSymbol: undefined
|
}, makerStyle);
|
|
context.font = style.fontSize + 'px ' + style.fontFamily + ' bold'
|
|
var coordinate = pointFeature.geometry.coordinates
|
|
var percentX = (coordinate[0] - boundingRect.xMin) / (boundingRect.xMax - boundingRect.xMin);
|
var percentY = (coordinate[1] - boundingRect.yMax) / (boundingRect.yMin - boundingRect.yMax);
|
|
var pt = { x: percentX * context.canvas.width, y: percentY * context.canvas.height };
|
|
if (style.showMarker || style.showMarker) {
|
|
var px = pt.x + x,
|
py = pt.y + y;
|
|
if (style.markerSymbol && (style.markerSymbol instanceof Image
|
|| style.markerSymbol instanceof HTMLCanvasElement)) {
|
|
|
var textHeight = style.markerSymbol.height;
|
var textWidth = style.markerSymbol.width;
|
px -= textWidth / 2;
|
py -= textHeight / 2;
|
if (style.markerSymbol.width && style.markerSymbol.height)
|
context.drawImage(
|
style.markerSymbol, px, py
|
)
|
|
} else {
|
px -= style.pointSize;
|
py -= style.pointSize;
|
context.fillStyle = style.backgroundColor
|
context.beginPath();
|
context.arc(px, py, style.pointSize, 0, Math.PI * 2);
|
if (style.pointStyle == 'Solid') {
|
context.fill();
|
}
|
else if (style.pointStyle == 'Circle') {
|
context.lineWidth = style.circleLineWidth;
|
context.strokeStyle = style.backgroundColor
|
context.stroke();
|
} else if (style.pointStyle == 'Ring') {
|
context.strokeStyle = style.backgroundColor
|
context.stroke();
|
context.beginPath();
|
context.arc(px, py, style.ringRadius, 0, Math.PI * 2);
|
context.closePath();
|
context.fill();
|
}
|
}
|
}
|
if (style.showLabel) {
|
var text = pointFeature.properties[labelPropertyName];
|
if (text) {
|
if (typeof text != 'string') {
|
text = text.toString();
|
}
|
context.fillStyle = style.color;
|
var px = pt.x + x + style.labelOffsetX;//+ 4,
|
py = pt.y + y + style.labelOffsetY;// + style.fontSize / 2;
|
|
text = text.trim();
|
var textImg = drawText(text, {
|
fill: true,
|
font: style.fontSize + 'px ' + style.fontFamily,
|
stroke: style.labelStroke,
|
strokeWidth: style.labelStrokeWidth,
|
strokeColor:
|
typeof style.labelStrokeColor == 'string' ?
|
Cesium.Color.fromCssColorString(style.labelStrokeColor) :
|
style.labelStrokeColor,
|
fillColor: Cesium.Color.fromCssColorString(style.color)
|
})
|
|
var textHeight = textImg.height;
|
var textWidth = textImg.width;
|
px -= textWidth / 2 + style.pointSize;
|
py -= textHeight / 2 + style.pointSize;
|
if (textImg.width && textImg.height)
|
context.drawImage(textImg, px, py)
|
}
|
}
|
context.restore();
|
}
|
|
/**
|
*
|
*@param {Number}x
|
*@param {Number}y
|
*@param {Object}geojson
|
*@param {Object}[boundingRect=undefined]
|
*@param {Number}width
|
*@param {Number}height
|
*@param {Object}[fill=true]
|
*@param {Object}[stroke=true]
|
*@private
|
*/
|
VectorTileImageryProvider.prototype._drawGeojson = function (context, x, y, geojson, boundingRect, width, height, fill, stroke, row, col, level) {
|
var that = this;
|
if (typeof fill == 'undefined') {
|
fill = true;
|
}
|
if (typeof stroke == 'undefined') {
|
stroke = true;
|
}
|
if (!fill && !stroke) {
|
return undefined;
|
}
|
if (typeof width == 'undefined') {
|
width = context.canvas.width - x;
|
}
|
if (typeof height == 'undefined') {
|
height = context.canvas.height - y;
|
}
|
|
var projection = new LonLatProjection(width, height);
|
|
var style = this._defaultStyle;
|
|
var makerStyle = {
|
labelStroke: style.labelStroke,
|
labelStrokeWidth: style.labelStrokeWidth,
|
labelStrokeColor: style.labelStrokeColor,
|
pointSize: style.pointSize,
|
fontSize: style.fontSize,
|
fontFamily: style.fontFamily,
|
color: style.fontColor instanceof Cesium.Color ? style.fontColor.toCssColorString() : style.fontColor,
|
backgroundColor: style.pointColor instanceof Cesium.Color ? style.pointColor.toCssColorString() : style.pointColor,
|
pointStyle: style.pointStyle,//'Solid','Ring','Circle'
|
ringRadius: style.ringRadius,
|
circleLineWidth: style.circleLineWidth,
|
showMarker: style.showMarker,
|
showLabel: style.showLabel,
|
labelOffsetX: style.labelOffsetX,
|
labelOffsetY: style.labelOffsetY,
|
markerSymbol: (style.markerImage instanceof Image
|
|| style.markerImage instanceof HTMLCanvasElement
|
) ? style.markerImage : style.markerImageEl
|
};
|
var holes = [];
|
if (that._styleFilter) {
|
turf.featureEach(geojson, function (currentFeature, currentFeatureIndex) {
|
if (that._styleFilter) {
|
style = that._defaultStyle.clone();
|
that._styleFilter(currentFeature, style, row, col, level);
|
currentFeature.style = style;
|
}
|
});
|
geojson.features.sort(function (a, b) {
|
if (a.style && a.style.lineDash) {
|
return 1;
|
}
|
if (b.style && b.style.lineDash) {
|
return -1;
|
}
|
return 0;
|
})
|
}
|
|
function drawFeature(currentFeature, currentFeatureIndex) {
|
|
if (that._styleFilter) {
|
style = currentFeature.style;
|
if (style.show == false) {
|
return;
|
}
|
|
makerStyle = {
|
labelStroke: style.labelStroke,
|
labelStrokeWidth: style.labelStrokeWidth,
|
labelStrokeColor: style.labelStrokeColor,
|
pointSize: style.pointSize,
|
fontSize: style.fontSize,
|
fontFamily: style.fontFamily,
|
color: style.fontColor instanceof Cesium.Color ? style.fontColor.toCssColorString() : style.fontColor,
|
backgroundColor: style.pointColor instanceof Cesium.Color ? style.pointColor.toCssColorString() : style.pointColor,
|
pointStyle: style.pointStyle,//'Solid','Ring','Circle'
|
ringRadius: style.ringRadius,
|
circleLineWidth: style.circleLineWidth,
|
showMarker: style.showMarker,
|
showLabel: style.showLabel,
|
labelOffsetX: style.labelOffsetX,
|
labelOffsetY: style.labelOffsetY,
|
markerSymbol: (style.markerImage instanceof Image || style.markerImage instanceof HTMLCanvasElement) ? style.markerImage : style.markerImageEl
|
};
|
} else {
|
style = that._defaultStyle;
|
}
|
|
context.lineWidth = style.lineWidth;
|
|
if (style.outlineColor instanceof Cesium.Color) {
|
context.strokeStyle = style.outlineColor.toCssColorString();// "rgb(255,255,0)";
|
} else {
|
context.strokeStyle = style.outlineColor;// "rgb(255,255,0)";
|
}
|
|
if (style.fillColor instanceof Cesium.Color) {
|
context.fillStyle = style.fillColor.toCssColorString();// "rgba(0,255,255,0.0)";
|
} else {
|
context.fillStyle = style.fillColor;// "rgba(0,255,255,0.0)";
|
}
|
|
if (style.lineDash) {
|
context.setLineDash(style.lineDash);
|
}
|
|
context.lineCap = style.lineCap;
|
if (style.shadowColor && style.shadowColor instanceof Cesium.Color) {
|
context.shadowColor = style.shadowColor.toCssColorString();
|
} else {
|
context.shadowColor = style.shadowColor;
|
}
|
context.shadowBlur = style.shadowBlur;
|
context.shadowOffsetX = style.shadowOffsetX;
|
context.shadowOffsetY = style.shadowOffsetY;
|
context.miterLimit = style.miterLimit;
|
context.lineJoin = style.lineJoin;
|
|
var geometry = currentFeature.geometry
|
|
if (geometry.type == "Point") {
|
drawMarker(context, projection, boundingRect, x, y, currentFeature, fill, stroke, style.labelPropertyName, makerStyle);
|
}
|
else if (geometry.type == "Polygon" && style.fill) {
|
|
var contours = turf.getCoords(currentFeature);
|
var tempHoles = drawContours(context, projection, boundingRect, x, y, contours, true, false, style);
|
if (tempHoles) {
|
tempHoles.map(function (hole) {
|
hole.style = style;
|
holes.push(hole);
|
})
|
}
|
//drawContours(context, projection, boundingRect, x, y, contours, true, false, style);
|
} else if (geometry.type == "MultiPolygon" && style.fill) {
|
var polygons;
|
try {
|
|
polygons = turf.getCoords(currentFeature);
|
polygons.map(function (contours) {
|
var tempHoles = drawContours(context, projection, boundingRect, x, y, contours, true, false, style);
|
if (tempHoles) {
|
tempHoles.map(function (hole) {
|
hole.style = style;
|
holes.push(hole);
|
})
|
|
}
|
})
|
|
} catch (e) {
|
// console.log(e);
|
}
|
} else if (geometry.type == "MultiLineString") {
|
if (currentFeature.properties.isOutline && !style.outline) {
|
|
} else {
|
var contours = turf.getCoords(currentFeature);
|
drawContours(context, projection, boundingRect, x, y, contours, false, true, style);
|
contours = null;
|
}
|
|
}
|
else if (geometry.type == "LineString") {
|
if (currentFeature.properties.isOutline && !style.outline) {
|
|
} else {
|
var contour = turf.getCoords(currentFeature);
|
var contours = [contour]
|
drawContours(context, projection, boundingRect, x, y, contours, false, true, style);
|
contour = null;
|
contours = null;
|
|
}
|
}
|
}
|
|
turf.featureEach(geojson, function (fc, idx) {
|
var geometry = fc.geometry
|
if (!geometry) return;
|
|
if (geometry.type == "Polygon" || geometry.type == "MultiPolygon") {
|
drawFeature(fc, idx)
|
}
|
})
|
if (holes && holes.length) {
|
createHoles(context, projection, boundingRect, x, y, holes)
|
}
|
turf.featureEach(geojson, function (fc, idx) {
|
var geometry = fc.geometry
|
if (!geometry) return;
|
|
if (geometry.type == "LineString" || geometry.type == "MultiLineString") {
|
drawFeature(fc, idx)
|
}
|
})
|
|
|
var pointFcs = [];
|
turf.featureEach(geojson, function (fc, idx) {
|
var geometry = fc.geometry
|
if (!geometry) return;
|
if (geometry.type == "Point" || geometry.type == "MultiPoint") {
|
if (typeof that.clustering !== 'function') drawFeature(fc, idx)
|
else pointFcs.push(fc)
|
}
|
})
|
|
var tileBBox = [
|
boundingRect.xMin, boundingRect.yMin, boundingRect.xMax, boundingRect.yMax
|
]
|
if (typeof that.clustering == 'function') {
|
pointFcs = that.clustering(pointFcs, context, tileBBox, row, col, level)
|
}
|
if (pointFcs && pointFcs.length) {
|
pointFcs.forEach(function (fc, idx) {
|
drawFeature(fc, idx)
|
})
|
}
|
}
|
|
/**
|
* 判断点和绘制符号后的矩形区域是否跨瓦片
|
* @param {CanvasRenderingContext2D}context
|
* @param {Array.<Number>}tileBBox
|
* @param {Feature.<Point|MultiPoint>}pointFeature
|
* @param {Array.<Number>}outDrawBBox
|
* @return {Boolean}
|
*/
|
VectorTileImageryProvider.pointIsCrossTile = function pointIsCrossTile(context, tileBBox, pointFeature, outDrawBBox) {
|
if (outDrawBBox) outDrawBBox.splice(0, outDrawBBox.length)
|
if (!pointFeature.properties) return true;
|
if (!pointFeature.properties.symbol) return true;
|
var symbol = pointFeature.properties.symbol;
|
var coordinate = pointFeature.geometry.coordinates
|
|
var percentX = (coordinate[0] - tileBBox[0]) / (tileBBox[2] - tileBBox[0]);
|
var percentY = (coordinate[1] - tileBBox[3]) / (tileBBox[1] - tileBBox[3]);
|
|
var x = percentX * context.canvas.width,
|
y = percentY * context.canvas.height;
|
var minX = x - symbol.width / 2.0, maxX = x + symbol.width / 2.0;
|
var minY = y - symbol.height / 2.0, maxY = y + symbol.height / 2.0;
|
if (minX < 0 || maxX > context.canvas.width) return true;
|
if (minY < 0 || maxY > context.canvas.height) return true;
|
outDrawBBox[0] = minX;
|
outDrawBBox[1] = minY;
|
outDrawBBox[2] = maxX;
|
outDrawBBox[3] = maxY;
|
return false;
|
}
|
/**
|
*同步导出瓦片
|
*@param {Number}x
|
*@param {Number}y
|
*@param {Number}level
|
*@return {Canvas}
|
*/
|
VectorTileImageryProvider.prototype.requestImageSync = function (x, y, level) {
|
var that = this;
|
var cacheId = x + "," + y + "," + level;
|
|
if (that.cache && that.cache[cacheId]) {
|
return that.cache[cacheId];
|
}
|
var rectangle = this._tilingScheme.tileXYToRectangle(x, y, level);
|
var boundingRect = {
|
xMin: CesiumMath.toDegrees(rectangle.west),
|
yMin: CesiumMath.toDegrees(rectangle.south),
|
xMax: CesiumMath.toDegrees(rectangle.east),
|
yMax: CesiumMath.toDegrees(rectangle.north)
|
};
|
|
var clippedGeojson = that._clipGeojson(rectangle);
|
|
if (!clippedGeojson) {
|
if (that._onlyPoint || (that._polygonOnly && that._defaultStyle.fill)) {
|
return getEmpty(that._defaultStyle.backgroundColor);
|
}
|
else {
|
return undefined;
|
}
|
} else {
|
that._createCanvas();
|
if (!that._defaultStyle.backgroundColor) {
|
that._context.clearRect(0, 0, that._canvas.width, that._canvas.height);
|
}
|
that._drawGeojson(that._context, 0, 0, clippedGeojson, boundingRect, that._tileWidth, that._tileHeight, that._fill, that._outline, x, y, level);
|
return that._canvas;
|
}
|
}
|
VectorTileImageryProvider.prototype._createTileImage = function (x, y, level, rectangle, defer) {
|
|
var that = this;
|
var cacheId = x + "," + y + "," + level;
|
|
var boundingRect = {
|
xMin: CesiumMath.toDegrees(rectangle.west),
|
yMin: CesiumMath.toDegrees(rectangle.south),
|
xMax: CesiumMath.toDegrees(rectangle.east),
|
yMax: CesiumMath.toDegrees(rectangle.north)
|
};
|
this._state = VectorTileImageryProvider.State.CLIPPING;
|
requestAnimationFrame(function () {
|
var clippedGeojson = that._clipGeojson(rectangle);
|
|
if (!clippedGeojson) {
|
if (that._onlyPoint) {
|
defer.resolve(getEmpty(that._defaultStyle.backgroundColor));
|
}
|
else {
|
defer.resolve(undefined);
|
}
|
that._state = VectorTileImageryProvider.State.COMPELTED;
|
VectorTileImageryProvider._currentTaskCount--;
|
} else {
|
|
Cesium.requestAnimationFrame(function () {
|
that._state = VectorTileImageryProvider.State.GEOJSONDRAWING;
|
that._createCanvas();
|
if (!that._defaultStyle.backgroundColor) {
|
that._context.clearRect(0, 0, that._canvas.width, that._canvas.height);
|
}
|
|
//if (level < 8) {
|
// var v = 1.5 / Math.pow(2, (level + 0));
|
// try {
|
// clippedGeojson = turf.simplify(clippedGeojson, v);
|
// } catch (e) {
|
|
// }
|
|
//}
|
|
that._drawGeojson(that._context, 0, 0, clippedGeojson, boundingRect, that._tileWidth, that._tileHeight, that._fill, that._outline, x, y, level);
|
|
that.cache[cacheId] = that._canvas;
|
that.cache[cacheId].srcJson = clippedGeojson;
|
that.cacheCount++;
|
VectorTileImageryProvider._currentTaskCount--;
|
|
defer.resolve(that._canvas);
|
|
Cesium.requestAnimationFrame(function () {
|
that._state = VectorTileImageryProvider.State.COMPELTED;
|
});
|
});
|
|
}
|
});
|
}
|
|
/**
|
*
|
*/
|
VectorTileImageryProvider.prototype.clearCache = function () {
|
var provider = this;
|
for (var cacheId in provider.cache) {
|
if (provider.cache.hasOwnProperty(cacheId)) {
|
provider.cache[cacheId].srcJson = null;
|
delete provider.cache[cacheId];
|
}
|
}
|
provider.cache = {};
|
provider.cacheCount = 0;
|
}
|
|
VectorTileImageryProvider.prototype._getTileImage = function (x, y, level, rectangle) {
|
|
var defer = when.defer();
|
var that = this;
|
|
//从缓存中查询
|
var cacheId = x + "," + y + "," + level;
|
if (!that.cacheCount) {
|
that.cacheCount = 0;
|
}
|
if (!that.cache || that.cacheCount > that._tileCacheSize) {
|
for (var cacheId in that.cache) {
|
if (that.cache.hasOwnProperty(cacheId)) {
|
that.cache[cacheId].srcJson = null;
|
delete that.cache[cacheId];
|
}
|
}
|
that.cache = {};
|
that.cacheCount = 0;
|
}
|
if (that.cache[cacheId]) {
|
return that.cache[cacheId]
|
}
|
|
//处理并发
|
if (VectorTileImageryProvider._maxTaskCount < VectorTileImageryProvider._currentTaskCount) {
|
return undefined;
|
}
|
VectorTileImageryProvider._currentTaskCount++;
|
that._state = VectorTileImageryProvider.State.READY;
|
setTimeout(function () {
|
return that._createTileImage(x, y, level, rectangle, defer)
|
}, 1);
|
return defer.promise;
|
}
|
|
var emptycv;
|
|
function getEmpty(bgColor) {
|
if (!emptycv) {
|
|
emptycv = document.createElement("canvas");
|
emptycv.width = 256;
|
emptycv.height = 256;
|
}
|
if (bgColor) {
|
var ctx = emptycv.getContext('2d');
|
|
if (bgColor instanceof Cesium.Color) {
|
ctx.fillStyle = bgColor.toCssColorString();
|
} else {
|
ctx.fillStyle = bgColor;
|
}
|
|
ctx.fillRect(0, 0, emptycv.width, emptycv.height);
|
}
|
else {
|
var ctx = emptycv.getContext('2d');
|
ctx.clearRect(0, 0, emptycv.width, emptycv.height);
|
}
|
return emptycv;
|
}
|
var scratchRectangleIntersection;
|
if (typeof Rectangle !== 'undefined') {
|
scratchRectangleIntersection = new Rectangle();
|
}
|
VectorTileImageryProvider.prototype.requestImage = function (x, y, level, distance) {
|
if (!this._ready || this._state != VectorTileImageryProvider.State.COMPELTED) {
|
return undefined;
|
}
|
if (level < this._minimumLevel) {
|
|
return new Promise((resolve, reject) => {
|
this._createCanvas();
|
this._context.clearRect(0, 0, this._tileWidth, this._tileHeight);
|
resolve(this._canvas)
|
})
|
|
} else if (level > this._maximumLevel) {
|
return new Promise((resolve, reject) => {
|
resolve(getEmpty(this._defaultStyle.backgroundColor))
|
})
|
}
|
var rectangle = this.tilingScheme.tileXYToRectangle(x, y, level);
|
return this._getTileImage(x, y, level, rectangle);
|
}
|
VectorTileImageryProvider.prototype.pickFeatures = function (x, y, level, longitude, latitude) {
|
//alert(longitude+","+ latitude);
|
}
|
/**
|
*合并图层并出图
|
*@param {Array.<Cesium.VectorTileImageryProvider>}vectorTileImageryProviders
|
*@param {Cesium.Rectangle}rectangle
|
*@param {Number}level
|
*@param {Number}[tileWidth=256]
|
*@param {Number}[tileHeight=256]
|
*@return {Canvas}
|
*/
|
VectorTileImageryProvider.compose = function (
|
vectorTileImageryProviders, rectangle, level,
|
tileWidth, tileHeight
|
) {
|
|
tileWidth = tileWidth ? tileWidth : 256;
|
tileHeight = tileHeight ? tileHeight : 256;
|
|
vectorTileImageryProviders.sort(function (a, b) {
|
if (!Cesium.defined(a.zIndex)) {
|
return -1;
|
}
|
if (!Cesium.defined(b.zIndex)) {
|
return 1;
|
}
|
return a.zIndex - b.zIndex;
|
})
|
|
var tilingScheme = new Cesium.GeographicTilingScheme();
|
|
var nw = Rectangle.northwest(rectangle);
|
var se = Rectangle.southeast(rectangle);
|
var lt = tilingScheme.positionToTileXY(nw, level);
|
var rb = tilingScheme.positionToTileXY(se, level);
|
|
var w = (rb.x - lt.x + 1) * tileWidth,
|
h = (rb.y - lt.y + 1) * tileHeight;
|
var cv = document.createElement('canvas');
|
cv.width = w;
|
cv.height = h;
|
var context = cv.getContext('2d');
|
for (var li = 0; li < vectorTileImageryProviders.length; li++) {
|
|
for (var x = lt.x, i = 0; x <= rb.x; x++, i++) {
|
for (var y = lt.y, j = 0; y <= rb.y; y++, j++) {
|
|
var px = i * tileWidth, py = j * tileHeight;
|
var provider = vectorTileImageryProviders[li];
|
|
try {
|
var image = provider.requestImageSync(x, y, level);
|
if (image && image.width && image.height) {
|
context.drawImage(image, px, py, tileWidth, tileHeight);
|
}
|
} catch (e) {
|
console.error(e);
|
}
|
}
|
}
|
}
|
|
return cv;
|
}
|
|
var scratchRect = new Rectangle();
|
/**
|
* 重写此函数,实现:要素被点击时准备好并返回要素查询结果信息。
|
* @param {Feature}feature geojson要素
|
* @param {Number}x 当前点所在tms瓦片编号x部分
|
* @param {Number}y 当前点所在tms瓦片编号y部分
|
* @param {Number}level 当前点所在tms瓦片级别
|
* @param {Number}longitude 当前点击的点经度(单位是弧度)
|
* @param {Number}latitude 当前点击的点纬度(单位是弧度)
|
* @return {Promise.<Cesium.ImageryLayerFeatureInfo>|Cesium.ImageryLayerFeatureInfo}
|
*/
|
VectorTileImageryProvider.prototype.prepareFeatureInfo = function (feature, x, y, level, longitude, latitude) {
|
return undefined;
|
}
|
/**
|
* 实现Cesium.ImageryProvidery要素查询(拾取)接口,除了返回结果可以在Cesium内置的InfoBox显示之外,还触发featuresPicked事件。
|
* @param {Number}x
|
* @param {Number}y
|
* @param {Number}level
|
* @param {Number}longitude
|
* @param {Number}latitude
|
*/
|
VectorTileImageryProvider.prototype.pickFeatures = function (x, y, level, longitude, latitude) {
|
var that = this;
|
if (!this._allowPick || !this._geoJSON) {
|
that._featuresPicked.raiseEvent(that, undefined);
|
return undefined;
|
}
|
this.tilingScheme.tileXYToRectangle(x, y, level, scratchRect);
|
var res = turf.radiansToLength(scratchRect.width / 256, 'kilometers');//分辨率,单位公里,即当前视图下一个像素点边长所表示距离
|
|
var pt = turf.point([CesiumMath.toDegrees(longitude), CesiumMath.toDegrees(latitude)]);
|
|
var pickedFeatures = [];
|
var style = this.defaultStyle;
|
|
turf.featureEach(this._geoJSON, function (fc) {
|
var srcFc = fc;
|
var found = false;
|
var geometry = fc.geometry
|
if (!geometry) return;
|
|
if (style.fill && (geometry.type == 'Polygon' || geometry.type == 'MultiPolygon')) {
|
if (turf.booleanPointInPolygon(pt, fc)) {
|
found = true;
|
}
|
} else {
|
var dist = turf.pointToFeatureDistance(pt, fc, {
|
units: "kilometers"
|
})
|
|
if ((style.outline && (geometry.type == 'Polygon' || geometry.type == 'MultiPolygon'))
|
|| (geometry.type == "LineString" || geometry.type == "MultiLineString")
|
) {
|
found = dist <= res * 2.0;
|
} else if (style.showMarker && (geometry.type == 'Point' || geometry.type == 'MultiPoint')) {
|
|
switch (style.pointStyle) {
|
case "Solid":
|
found = dist <= style.pointSize * 2.0;
|
break;
|
case "Ring":
|
case "Circle": found = dist <= (style.circleLineWidth + style.ringRadius) * 2.0;
|
break;
|
}
|
}
|
}
|
|
if (found) {//查找成功
|
var fcInfo;
|
if (typeof that.prepareFeatureInfo == 'function') {
|
fcInfo = that.prepareFeatureInfo(srcFc, x, y, level, longitude, latitude)
|
}
|
if (!fcInfo) {
|
var fcInfo = new Cesium.ImageryLayerFeatureInfo();
|
fcInfo.data = srcFc;
|
fcInfo.description = JSON.stringify(srcFc.properties, null, 2);
|
if (style.labelPropertyName) {
|
fcInfo.name = srcFc.properties[style.labelPropertyName]
|
}
|
else if (style.centerLabelPropertyName) {
|
fcInfo.name = srcFc.properties[style.centerLabelPropertyName]
|
}
|
|
var srcGeometry = srcFc.geometry
|
if (srcGeometry.type == 'Point' || srcGeometry.type == 'MultiPoint') {
|
fcInfo.position = new Cesium.Cartographic(longitude, latitude)
|
} else {
|
var centroidPt = turf.centroid(srcFc);
|
var coord = turf.getCoords(centroidPt);
|
fcInfo.position = Cesium.Cartographic.fromDegrees(coord[0], coord[1])
|
}
|
}
|
pickedFeatures.push(fcInfo)
|
}
|
})
|
if (pickedFeatures.length) {
|
var df = when.defer();
|
var startTime = new Date();
|
when.all(pickedFeatures).then(function (pickedFeatures) {
|
var timespan = new Date() - startTime;
|
if (timespan < 100) {
|
setTimeout(function () {
|
that._featuresPicked.raiseEvent(that, pickedFeatures);
|
df.resolve(pickedFeatures);
|
}, 100);
|
} else {
|
that._featuresPicked.raiseEvent(that, pickedFeatures);
|
df.resolve(pickedFeatures);
|
}
|
}).otherwise(function (err) {
|
console.error(err);
|
that._featuresPicked.raiseEvent(that, undefined);
|
})
|
return df.promise;
|
} else {
|
that._featuresPicked.raiseEvent(that, undefined);
|
}
|
}
|
/**
|
* @callback Cesium.VectorTileImageryProvider~featuresPickedCallback
|
* @param {Cesium.VectorTileImageryProvider}ImageryProvider
|
* @param {Array.<Cesium.ImageryLayerFeatureInfo>}pickedFeatures
|
*/
|
|
/**
|
*
|
*/
|
VectorTileImageryProvider.prototype.destroy = function () {
|
for (var key in this) {
|
if (this.hasOwnProperty(key)) {
|
delete this[key];
|
}
|
}
|
}
|
|
//支持leaflet
|
//leaflet图层,仅支持L.CRS.EPSG4326坐标系,使用MeteoLib中的VectorTileImageryProvider动态生成矢量瓦片
|
|
if (typeof L != 'undefined' && L.GridLayer && L.GridLayer.extend) {
|
|
L.VectorTileImageryLayer = L.GridLayer.extend({
|
options: {
|
crs: L.CRS.EPSG4326,
|
defaultZIndex: 1
|
},
|
initialize: function (options) {
|
options.tileCacheSize = options.tileCacheSize ? options.tileCacheSize : 20,
|
this.tileProvider = new VectorTileImageryProvider(options)
|
this.options.defaultZIndex = options.zIndex;
|
},
|
clearCache: function () {
|
if (this.tileProvider) this.tileProvider.clearCache()
|
},
|
onAdd: function (map) {
|
this.setZIndex(this.options.defaultZIndex)
|
L.GridLayer.prototype.onAdd.call(this, map);
|
},
|
createTile: function (coords, done) {
|
|
var tile = L.DomUtil.create('canvas', 'leaflet-tile');
|
var size = this.getTileSize();
|
tile.width = size.x;
|
tile.height = size.y;
|
var ctx = tile.getContext('2d');
|
var invertedY = this._globalTileRange.max.y - coords.y;
|
var vecImgPrvd = this.tileProvider
|
if (!vecImgPrvd.ready) {
|
vecImgPrvd.readyPromise.then(function () {
|
var img = vecImgPrvd.requestImageSync(coords.x, coords.y, coords.z);
|
if (img) ctx.drawImage(img, 0, 0)
|
done(null, tile);
|
})
|
} else {
|
requestAnimationFrame(function () {
|
var img = vecImgPrvd.requestImageSync(coords.x, coords.y, coords.z);
|
if (img) ctx.drawImage(img, 0, 0)
|
done(null, tile)
|
});
|
}
|
return tile;
|
}
|
});
|
}
|
module.exports = VectorTileImageryProvider;
|
|
},{"./LonLatProjection":119,"./VectorStyle":121,"./cesium/Core/Event":133,"./cesium/Core/Math":139,"./cesium/Core/Rectangle":140,"./cesium/Core/Resource":146,"./cesium/Core/defaultValue":158,"./cesium/Core/defineProperties":159,"./cesium/Core/defined":160,"./turf-light":181,"./utils/Path":182,"./utils/drawText":184,"when":118}],123:[function(require,module,exports){
|
//增加对shp格式的支持
|
/**
|
*
|
* @namespace Cesium
|
*/
|
|
|
var VectorTileImageryProvider = require('./VectorTileImageryProvider-light');
|
VectorTileImageryProvider.shp = require('./Shp')
|
module.exports = VectorTileImageryProvider;
|
},{"./Shp":120,"./VectorTileImageryProvider-light":122}],124:[function(require,module,exports){
|
module.exports = {
|
// Resource:require('./cesium/Core/Resource'),
|
when: require('./cesium/ThirdParty/when'),
|
Cartesian2: require('./cesium/Core/Cartesian2'),
|
Cartesian3: require('./cesium/Core/Cartesian3'),
|
Cartesian4: require('./cesium/Core/Cartesian4'),
|
Math: require('./cesium/Core/Math'),
|
CesiumMath: require('./cesium/Core/Math'),
|
TilingScheme: require('./cesium/Core/TilingScheme'),
|
GeographicTilingScheme: require('./cesium/Core/GeographicTilingScheme'),
|
WebMercatorTilingScheme: require('./cesium/Core/WebMercatorTilingScheme'),
|
Color: require('./cesium/Core/Color'),
|
Event: require('./cesium/Core/Event'),
|
TaskProcessor: require('./cesium/Core/TaskProcessor'),
|
Rectangle: require('./cesium/Core/Rectangle'),
|
writeTextToCanvas: require('./cesium/Core/writeTextToCanvas')
|
};
|
},{"./cesium/Core/Cartesian2":125,"./cesium/Core/Cartesian3":126,"./cesium/Core/Cartesian4":127,"./cesium/Core/Color":130,"./cesium/Core/Event":133,"./cesium/Core/GeographicTilingScheme":137,"./cesium/Core/Math":139,"./cesium/Core/Rectangle":140,"./cesium/Core/TaskProcessor":148,"./cesium/Core/TilingScheme":149,"./cesium/Core/WebMercatorTilingScheme":153,"./cesium/Core/writeTextToCanvas":177,"./cesium/ThirdParty/when":179}],125:[function(require,module,exports){
|
var Check=require('./Check');
|
var defaultValue=require('./defaultValue');
|
var defined=require('./defined');
|
var DeveloperError=require('./DeveloperError');
|
var freezeObject=require('./freezeObject');
|
var CesiumMath=require('./Math');
|
|
'use strict';
|
|
/**
|
* A 2D Cartesian point.
|
* @alias Cartesian2
|
* @constructor
|
*
|
* @param {Number} [x=0.0] The X component.
|
* @param {Number} [y=0.0] The Y component.
|
*
|
* @see Cartesian3
|
* @see Cartesian4
|
* @see Packable
|
*/
|
function Cartesian2(x, y) {
|
/**
|
* The X component.
|
* @type {Number}
|
* @default 0.0
|
*/
|
this.x = defaultValue(x, 0.0);
|
|
/**
|
* The Y component.
|
* @type {Number}
|
* @default 0.0
|
*/
|
this.y = defaultValue(y, 0.0);
|
}
|
|
/**
|
* Creates a Cartesian2 instance from x and y coordinates.
|
*
|
* @param {Number} x The x coordinate.
|
* @param {Number} y The y coordinate.
|
* @param {Cartesian2} [result] The object onto which to store the result.
|
* @returns {Cartesian2} The modified result parameter or a new Cartesian2 instance if one was not provided.
|
*/
|
Cartesian2.fromElements = function(x, y, result) {
|
if (!defined(result)) {
|
return new Cartesian2(x, y);
|
}
|
|
result.x = x;
|
result.y = y;
|
return result;
|
};
|
|
/**
|
* Duplicates a Cartesian2 instance.
|
*
|
* @param {Cartesian2} cartesian The Cartesian to duplicate.
|
* @param {Cartesian2} [result] The object onto which to store the result.
|
* @returns {Cartesian2} The modified result parameter or a new Cartesian2 instance if one was not provided. (Returns undefined if cartesian is undefined)
|
*/
|
Cartesian2.clone = function(cartesian, result) {
|
if (!defined(cartesian)) {
|
return undefined;
|
}
|
if (!defined(result)) {
|
return new Cartesian2(cartesian.x, cartesian.y);
|
}
|
|
result.x = cartesian.x;
|
result.y = cartesian.y;
|
return result;
|
};
|
|
/**
|
* Creates a Cartesian2 instance from an existing Cartesian3. This simply takes the
|
* x and y properties of the Cartesian3 and drops z.
|
* @function
|
*
|
* @param {Cartesian3} cartesian The Cartesian3 instance to create a Cartesian2 instance from.
|
* @param {Cartesian2} [result] The object onto which to store the result.
|
* @returns {Cartesian2} The modified result parameter or a new Cartesian2 instance if one was not provided.
|
*/
|
Cartesian2.fromCartesian3 = Cartesian2.clone;
|
|
/**
|
* Creates a Cartesian2 instance from an existing Cartesian4. This simply takes the
|
* x and y properties of the Cartesian4 and drops z and w.
|
* @function
|
*
|
* @param {Cartesian4} cartesian The Cartesian4 instance to create a Cartesian2 instance from.
|
* @param {Cartesian2} [result] The object onto which to store the result.
|
* @returns {Cartesian2} The modified result parameter or a new Cartesian2 instance if one was not provided.
|
*/
|
Cartesian2.fromCartesian4 = Cartesian2.clone;
|
|
/**
|
* The number of elements used to pack the object into an array.
|
* @type {Number}
|
*/
|
Cartesian2.packedLength = 2;
|
|
/**
|
* Stores the provided instance into the provided array.
|
*
|
* @param {Cartesian2} value The value to pack.
|
* @param {Number[]} array The array to pack into.
|
* @param {Number} [startingIndex=0] The index into the array at which to start packing the elements.
|
*
|
* @returns {Number[]} The array that was packed into
|
*/
|
Cartesian2.pack = function(value, array, startingIndex) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('value', value);
|
Check.defined('array', array);
|
//>>includeEnd('debug');
|
|
startingIndex = defaultValue(startingIndex, 0);
|
|
array[startingIndex++] = value.x;
|
array[startingIndex] = value.y;
|
|
return array;
|
};
|
|
/**
|
* Retrieves an instance from a packed array.
|
*
|
* @param {Number[]} array The packed array.
|
* @param {Number} [startingIndex=0] The starting index of the element to be unpacked.
|
* @param {Cartesian2} [result] The object into which to store the result.
|
* @returns {Cartesian2} The modified result parameter or a new Cartesian2 instance if one was not provided.
|
*/
|
Cartesian2.unpack = function(array, startingIndex, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.defined('array', array);
|
//>>includeEnd('debug');
|
|
startingIndex = defaultValue(startingIndex, 0);
|
|
if (!defined(result)) {
|
result = new Cartesian2();
|
}
|
result.x = array[startingIndex++];
|
result.y = array[startingIndex];
|
return result;
|
};
|
|
/**
|
* Flattens an array of Cartesian2s into and array of components.
|
*
|
* @param {Cartesian2[]} array The array of cartesians to pack.
|
* @param {Number[]} result The array onto which to store the result.
|
* @returns {Number[]} The packed array.
|
*/
|
Cartesian2.packArray = function(array, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.defined('array', array);
|
//>>includeEnd('debug');
|
|
var length = array.length;
|
if (!defined(result)) {
|
result = new Array(length * 2);
|
} else {
|
result.length = length * 2;
|
}
|
|
for (var i = 0; i < length; ++i) {
|
Cartesian2.pack(array[i], result, i * 2);
|
}
|
return result;
|
};
|
|
/**
|
* Unpacks an array of cartesian components into and array of Cartesian2s.
|
*
|
* @param {Number[]} array The array of components to unpack.
|
* @param {Cartesian2[]} result The array onto which to store the result.
|
* @returns {Cartesian2[]} The unpacked array.
|
*/
|
Cartesian2.unpackArray = function(array, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.defined('array', array);
|
//>>includeEnd('debug');
|
|
var length = array.length;
|
if (!defined(result)) {
|
result = new Array(length / 2);
|
} else {
|
result.length = length / 2;
|
}
|
|
for (var i = 0; i < length; i += 2) {
|
var index = i / 2;
|
result[index] = Cartesian2.unpack(array, i, result[index]);
|
}
|
return result;
|
};
|
|
/**
|
* Creates a Cartesian2 from two consecutive elements in an array.
|
* @function
|
*
|
* @param {Number[]} array The array whose two consecutive elements correspond to the x and y components, respectively.
|
* @param {Number} [startingIndex=0] The offset into the array of the first element, which corresponds to the x component.
|
* @param {Cartesian2} [result] The object onto which to store the result.
|
* @returns {Cartesian2} The modified result parameter or a new Cartesian2 instance if one was not provided.
|
*
|
* @example
|
* // Create a Cartesian2 with (1.0, 2.0)
|
* var v = [1.0, 2.0];
|
* var p = Cesium.Cartesian2.fromArray(v);
|
*
|
* // Create a Cartesian2 with (1.0, 2.0) using an offset into an array
|
* var v2 = [0.0, 0.0, 1.0, 2.0];
|
* var p2 = Cesium.Cartesian2.fromArray(v2, 2);
|
*/
|
Cartesian2.fromArray = Cartesian2.unpack;
|
|
/**
|
* Computes the value of the maximum component for the supplied Cartesian.
|
*
|
* @param {Cartesian2} cartesian The cartesian to use.
|
* @returns {Number} The value of the maximum component.
|
*/
|
Cartesian2.maximumComponent = function(cartesian) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('cartesian', cartesian);
|
//>>includeEnd('debug');
|
|
return Math.max(cartesian.x, cartesian.y);
|
};
|
|
/**
|
* Computes the value of the minimum component for the supplied Cartesian.
|
*
|
* @param {Cartesian2} cartesian The cartesian to use.
|
* @returns {Number} The value of the minimum component.
|
*/
|
Cartesian2.minimumComponent = function(cartesian) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('cartesian', cartesian);
|
//>>includeEnd('debug');
|
|
return Math.min(cartesian.x, cartesian.y);
|
};
|
|
/**
|
* Compares two Cartesians and computes a Cartesian which contains the minimum components of the supplied Cartesians.
|
*
|
* @param {Cartesian2} first A cartesian to compare.
|
* @param {Cartesian2} second A cartesian to compare.
|
* @param {Cartesian2} result The object into which to store the result.
|
* @returns {Cartesian2} A cartesian with the minimum components.
|
*/
|
Cartesian2.minimumByComponent = function(first, second, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('first', first);
|
Check.typeOf.object('second', second);
|
Check.typeOf.object('result', result);
|
//>>includeEnd('debug');
|
|
result.x = Math.min(first.x, second.x);
|
result.y = Math.min(first.y, second.y);
|
|
return result;
|
};
|
|
/**
|
* Compares two Cartesians and computes a Cartesian which contains the maximum components of the supplied Cartesians.
|
*
|
* @param {Cartesian2} first A cartesian to compare.
|
* @param {Cartesian2} second A cartesian to compare.
|
* @param {Cartesian2} result The object into which to store the result.
|
* @returns {Cartesian2} A cartesian with the maximum components.
|
*/
|
Cartesian2.maximumByComponent = function(first, second, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('first', first);
|
Check.typeOf.object('second', second);
|
Check.typeOf.object('result', result);
|
//>>includeEnd('debug');
|
|
result.x = Math.max(first.x, second.x);
|
result.y = Math.max(first.y, second.y);
|
return result;
|
};
|
|
/**
|
* Computes the provided Cartesian's squared magnitude.
|
*
|
* @param {Cartesian2} cartesian The Cartesian instance whose squared magnitude is to be computed.
|
* @returns {Number} The squared magnitude.
|
*/
|
Cartesian2.magnitudeSquared = function(cartesian) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('cartesian', cartesian);
|
//>>includeEnd('debug');
|
|
return cartesian.x * cartesian.x + cartesian.y * cartesian.y;
|
};
|
|
/**
|
* Computes the Cartesian's magnitude (length).
|
*
|
* @param {Cartesian2} cartesian The Cartesian instance whose magnitude is to be computed.
|
* @returns {Number} The magnitude.
|
*/
|
Cartesian2.magnitude = function(cartesian) {
|
return Math.sqrt(Cartesian2.magnitudeSquared(cartesian));
|
};
|
|
var distanceScratch = new Cartesian2();
|
|
/**
|
* Computes the distance between two points.
|
*
|
* @param {Cartesian2} left The first point to compute the distance from.
|
* @param {Cartesian2} right The second point to compute the distance to.
|
* @returns {Number} The distance between two points.
|
*
|
* @example
|
* // Returns 1.0
|
* var d = Cesium.Cartesian2.distance(new Cesium.Cartesian2(1.0, 0.0), new Cesium.Cartesian2(2.0, 0.0));
|
*/
|
Cartesian2.distance = function(left, right) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('left', left);
|
Check.typeOf.object('right', right);
|
//>>includeEnd('debug');
|
|
Cartesian2.subtract(left, right, distanceScratch);
|
return Cartesian2.magnitude(distanceScratch);
|
};
|
|
/**
|
* Computes the squared distance between two points. Comparing squared distances
|
* using this function is more efficient than comparing distances using {@link Cartesian2#distance}.
|
*
|
* @param {Cartesian2} left The first point to compute the distance from.
|
* @param {Cartesian2} right The second point to compute the distance to.
|
* @returns {Number} The distance between two points.
|
*
|
* @example
|
* // Returns 4.0, not 2.0
|
* var d = Cesium.Cartesian2.distance(new Cesium.Cartesian2(1.0, 0.0), new Cesium.Cartesian2(3.0, 0.0));
|
*/
|
Cartesian2.distanceSquared = function(left, right) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('left', left);
|
Check.typeOf.object('right', right);
|
//>>includeEnd('debug');
|
|
Cartesian2.subtract(left, right, distanceScratch);
|
return Cartesian2.magnitudeSquared(distanceScratch);
|
};
|
|
/**
|
* Computes the normalized form of the supplied Cartesian.
|
*
|
* @param {Cartesian2} cartesian The Cartesian to be normalized.
|
* @param {Cartesian2} result The object onto which to store the result.
|
* @returns {Cartesian2} The modified result parameter.
|
*/
|
Cartesian2.normalize = function(cartesian, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('cartesian', cartesian);
|
Check.typeOf.object('result', result);
|
//>>includeEnd('debug');
|
|
var magnitude = Cartesian2.magnitude(cartesian);
|
|
result.x = cartesian.x / magnitude;
|
result.y = cartesian.y / magnitude;
|
|
//>>includeStart('debug', pragmas.debug);
|
if (isNaN(result.x) || isNaN(result.y)) {
|
throw new DeveloperError('normalized result is not a number');
|
}
|
//>>includeEnd('debug');
|
|
return result;
|
};
|
|
/**
|
* Computes the dot (scalar) product of two Cartesians.
|
*
|
* @param {Cartesian2} left The first Cartesian.
|
* @param {Cartesian2} right The second Cartesian.
|
* @returns {Number} The dot product.
|
*/
|
Cartesian2.dot = function(left, right) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('left', left);
|
Check.typeOf.object('right', right);
|
//>>includeEnd('debug');
|
|
return left.x * right.x + left.y * right.y;
|
};
|
|
/**
|
* Computes the componentwise product of two Cartesians.
|
*
|
* @param {Cartesian2} left The first Cartesian.
|
* @param {Cartesian2} right The second Cartesian.
|
* @param {Cartesian2} result The object onto which to store the result.
|
* @returns {Cartesian2} The modified result parameter.
|
*/
|
Cartesian2.multiplyComponents = function(left, right, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('left', left);
|
Check.typeOf.object('right', right);
|
Check.typeOf.object('result', result);
|
//>>includeEnd('debug');
|
|
result.x = left.x * right.x;
|
result.y = left.y * right.y;
|
return result;
|
};
|
|
/**
|
* Computes the componentwise quotient of two Cartesians.
|
*
|
* @param {Cartesian2} left The first Cartesian.
|
* @param {Cartesian2} right The second Cartesian.
|
* @param {Cartesian2} result The object onto which to store the result.
|
* @returns {Cartesian2} The modified result parameter.
|
*/
|
Cartesian2.divideComponents = function(left, right, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('left', left);
|
Check.typeOf.object('right', right);
|
Check.typeOf.object('result', result);
|
//>>includeEnd('debug');
|
|
result.x = left.x / right.x;
|
result.y = left.y / right.y;
|
return result;
|
};
|
|
/**
|
* Computes the componentwise sum of two Cartesians.
|
*
|
* @param {Cartesian2} left The first Cartesian.
|
* @param {Cartesian2} right The second Cartesian.
|
* @param {Cartesian2} result The object onto which to store the result.
|
* @returns {Cartesian2} The modified result parameter.
|
*/
|
Cartesian2.add = function(left, right, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('left', left);
|
Check.typeOf.object('right', right);
|
Check.typeOf.object('result', result);
|
//>>includeEnd('debug');
|
|
result.x = left.x + right.x;
|
result.y = left.y + right.y;
|
return result;
|
};
|
|
/**
|
* Computes the componentwise difference of two Cartesians.
|
*
|
* @param {Cartesian2} left The first Cartesian.
|
* @param {Cartesian2} right The second Cartesian.
|
* @param {Cartesian2} result The object onto which to store the result.
|
* @returns {Cartesian2} The modified result parameter.
|
*/
|
Cartesian2.subtract = function(left, right, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('left', left);
|
Check.typeOf.object('right', right);
|
Check.typeOf.object('result', result);
|
//>>includeEnd('debug');
|
|
result.x = left.x - right.x;
|
result.y = left.y - right.y;
|
return result;
|
};
|
|
/**
|
* Multiplies the provided Cartesian componentwise by the provided scalar.
|
*
|
* @param {Cartesian2} cartesian The Cartesian to be scaled.
|
* @param {Number} scalar The scalar to multiply with.
|
* @param {Cartesian2} result The object onto which to store the result.
|
* @returns {Cartesian2} The modified result parameter.
|
*/
|
Cartesian2.multiplyByScalar = function(cartesian, scalar, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('cartesian', cartesian);
|
Check.typeOf.number('scalar', scalar);
|
Check.typeOf.object('result', result);
|
//>>includeEnd('debug');
|
|
result.x = cartesian.x * scalar;
|
result.y = cartesian.y * scalar;
|
return result;
|
};
|
|
/**
|
* Divides the provided Cartesian componentwise by the provided scalar.
|
*
|
* @param {Cartesian2} cartesian The Cartesian to be divided.
|
* @param {Number} scalar The scalar to divide by.
|
* @param {Cartesian2} result The object onto which to store the result.
|
* @returns {Cartesian2} The modified result parameter.
|
*/
|
Cartesian2.divideByScalar = function(cartesian, scalar, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('cartesian', cartesian);
|
Check.typeOf.number('scalar', scalar);
|
Check.typeOf.object('result', result);
|
//>>includeEnd('debug');
|
|
result.x = cartesian.x / scalar;
|
result.y = cartesian.y / scalar;
|
return result;
|
};
|
|
/**
|
* Negates the provided Cartesian.
|
*
|
* @param {Cartesian2} cartesian The Cartesian to be negated.
|
* @param {Cartesian2} result The object onto which to store the result.
|
* @returns {Cartesian2} The modified result parameter.
|
*/
|
Cartesian2.negate = function(cartesian, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('cartesian', cartesian);
|
Check.typeOf.object('result', result);
|
//>>includeEnd('debug');
|
|
result.x = -cartesian.x;
|
result.y = -cartesian.y;
|
return result;
|
};
|
|
/**
|
* Computes the absolute value of the provided Cartesian.
|
*
|
* @param {Cartesian2} cartesian The Cartesian whose absolute value is to be computed.
|
* @param {Cartesian2} result The object onto which to store the result.
|
* @returns {Cartesian2} The modified result parameter.
|
*/
|
Cartesian2.abs = function(cartesian, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('cartesian', cartesian);
|
Check.typeOf.object('result', result);
|
//>>includeEnd('debug');
|
|
result.x = Math.abs(cartesian.x);
|
result.y = Math.abs(cartesian.y);
|
return result;
|
};
|
|
var lerpScratch = new Cartesian2();
|
/**
|
* Computes the linear interpolation or extrapolation at t using the provided cartesians.
|
*
|
* @param {Cartesian2} start The value corresponding to t at 0.0.
|
* @param {Cartesian2} end The value corresponding to t at 1.0.
|
* @param {Number} t The point along t at which to interpolate.
|
* @param {Cartesian2} result The object onto which to store the result.
|
* @returns {Cartesian2} The modified result parameter.
|
*/
|
Cartesian2.lerp = function(start, end, t, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('start', start);
|
Check.typeOf.object('end', end);
|
Check.typeOf.number('t', t);
|
Check.typeOf.object('result', result);
|
//>>includeEnd('debug');
|
|
Cartesian2.multiplyByScalar(end, t, lerpScratch);
|
result = Cartesian2.multiplyByScalar(start, 1.0 - t, result);
|
return Cartesian2.add(lerpScratch, result, result);
|
};
|
|
var angleBetweenScratch = new Cartesian2();
|
var angleBetweenScratch2 = new Cartesian2();
|
/**
|
* Returns the angle, in radians, between the provided Cartesians.
|
*
|
* @param {Cartesian2} left The first Cartesian.
|
* @param {Cartesian2} right The second Cartesian.
|
* @returns {Number} The angle between the Cartesians.
|
*/
|
Cartesian2.angleBetween = function(left, right) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('left', left);
|
Check.typeOf.object('right', right);
|
//>>includeEnd('debug');
|
|
Cartesian2.normalize(left, angleBetweenScratch);
|
Cartesian2.normalize(right, angleBetweenScratch2);
|
return CesiumMath.acosClamped(Cartesian2.dot(angleBetweenScratch, angleBetweenScratch2));
|
};
|
|
var mostOrthogonalAxisScratch = new Cartesian2();
|
/**
|
* Returns the axis that is most orthogonal to the provided Cartesian.
|
*
|
* @param {Cartesian2} cartesian The Cartesian on which to find the most orthogonal axis.
|
* @param {Cartesian2} result The object onto which to store the result.
|
* @returns {Cartesian2} The most orthogonal axis.
|
*/
|
Cartesian2.mostOrthogonalAxis = function(cartesian, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('cartesian', cartesian);
|
Check.typeOf.object('result', result);
|
//>>includeEnd('debug');
|
|
var f = Cartesian2.normalize(cartesian, mostOrthogonalAxisScratch);
|
Cartesian2.abs(f, f);
|
|
if (f.x <= f.y) {
|
result = Cartesian2.clone(Cartesian2.UNIT_X, result);
|
} else {
|
result = Cartesian2.clone(Cartesian2.UNIT_Y, result);
|
}
|
|
return result;
|
};
|
|
/**
|
* Compares the provided Cartesians componentwise and returns
|
* <code>true</code> if they are equal, <code>false</code> otherwise.
|
*
|
* @param {Cartesian2} [left] The first Cartesian.
|
* @param {Cartesian2} [right] The second Cartesian.
|
* @returns {Boolean} <code>true</code> if left and right are equal, <code>false</code> otherwise.
|
*/
|
Cartesian2.equals = function(left, right) {
|
return (left === right) ||
|
((defined(left)) &&
|
(defined(right)) &&
|
(left.x === right.x) &&
|
(left.y === right.y));
|
};
|
|
/**
|
* @private
|
*/
|
Cartesian2.equalsArray = function(cartesian, array, offset) {
|
return cartesian.x === array[offset] &&
|
cartesian.y === array[offset + 1];
|
};
|
|
/**
|
* Compares the provided Cartesians componentwise and returns
|
* <code>true</code> if they pass an absolute or relative tolerance test,
|
* <code>false</code> otherwise.
|
*
|
* @param {Cartesian2} [left] The first Cartesian.
|
* @param {Cartesian2} [right] The second Cartesian.
|
* @param {Number} relativeEpsilon The relative epsilon tolerance to use for equality testing.
|
* @param {Number} [absoluteEpsilon=relativeEpsilon] The absolute epsilon tolerance to use for equality testing.
|
* @returns {Boolean} <code>true</code> if left and right are within the provided epsilon, <code>false</code> otherwise.
|
*/
|
Cartesian2.equalsEpsilon = function(left, right, relativeEpsilon, absoluteEpsilon) {
|
return (left === right) ||
|
(defined(left) &&
|
defined(right) &&
|
CesiumMath.equalsEpsilon(left.x, right.x, relativeEpsilon, absoluteEpsilon) &&
|
CesiumMath.equalsEpsilon(left.y, right.y, relativeEpsilon, absoluteEpsilon));
|
};
|
|
/**
|
* An immutable Cartesian2 instance initialized to (0.0, 0.0).
|
*
|
* @type {Cartesian2}
|
* @constant
|
*/
|
Cartesian2.ZERO = freezeObject(new Cartesian2(0.0, 0.0));
|
|
/**
|
* An immutable Cartesian2 instance initialized to (1.0, 0.0).
|
*
|
* @type {Cartesian2}
|
* @constant
|
*/
|
Cartesian2.UNIT_X = freezeObject(new Cartesian2(1.0, 0.0));
|
|
/**
|
* An immutable Cartesian2 instance initialized to (0.0, 1.0).
|
*
|
* @type {Cartesian2}
|
* @constant
|
*/
|
Cartesian2.UNIT_Y = freezeObject(new Cartesian2(0.0, 1.0));
|
|
/**
|
* Duplicates this Cartesian2 instance.
|
*
|
* @param {Cartesian2} [result] The object onto which to store the result.
|
* @returns {Cartesian2} The modified result parameter or a new Cartesian2 instance if one was not provided.
|
*/
|
Cartesian2.prototype.clone = function(result) {
|
return Cartesian2.clone(this, result);
|
};
|
|
/**
|
* Compares this Cartesian against the provided Cartesian componentwise and returns
|
* <code>true</code> if they are equal, <code>false</code> otherwise.
|
*
|
* @param {Cartesian2} [right] The right hand side Cartesian.
|
* @returns {Boolean} <code>true</code> if they are equal, <code>false</code> otherwise.
|
*/
|
Cartesian2.prototype.equals = function(right) {
|
return Cartesian2.equals(this, right);
|
};
|
|
/**
|
* Compares this Cartesian against the provided Cartesian componentwise and returns
|
* <code>true</code> if they pass an absolute or relative tolerance test,
|
* <code>false</code> otherwise.
|
*
|
* @param {Cartesian2} [right] The right hand side Cartesian.
|
* @param {Number} relativeEpsilon The relative epsilon tolerance to use for equality testing.
|
* @param {Number} [absoluteEpsilon=relativeEpsilon] The absolute epsilon tolerance to use for equality testing.
|
* @returns {Boolean} <code>true</code> if they are within the provided epsilon, <code>false</code> otherwise.
|
*/
|
Cartesian2.prototype.equalsEpsilon = function(right, relativeEpsilon, absoluteEpsilon) {
|
return Cartesian2.equalsEpsilon(this, right, relativeEpsilon, absoluteEpsilon);
|
};
|
|
/**
|
* Creates a string representing this Cartesian in the format '(x, y)'.
|
*
|
* @returns {String} A string representing the provided Cartesian in the format '(x, y)'.
|
*/
|
Cartesian2.prototype.toString = function() {
|
return '(' + this.x + ', ' + this.y + ')';
|
};
|
|
module.exports= Cartesian2;
|
|
},{"./Check":129,"./DeveloperError":131,"./Math":139,"./defaultValue":158,"./defined":160,"./freezeObject":163}],126:[function(require,module,exports){
|
var Check=require('./Check');
|
var defaultValue=require('./defaultValue');
|
var defined=require('./defined');
|
var DeveloperError=require('./DeveloperError');
|
var freezeObject=require('./freezeObject');
|
var CesiumMath=require('./Math');
|
|
'use strict';
|
|
/**
|
* A 3D Cartesian point.
|
* @alias Cartesian3
|
* @constructor
|
*
|
* @param {Number} [x=0.0] The X component.
|
* @param {Number} [y=0.0] The Y component.
|
* @param {Number} [z=0.0] The Z component.
|
*
|
* @see Cartesian2
|
* @see Cartesian4
|
* @see Packable
|
*/
|
function Cartesian3(x, y, z) {
|
/**
|
* The X component.
|
* @type {Number}
|
* @default 0.0
|
*/
|
this.x = defaultValue(x, 0.0);
|
|
/**
|
* The Y component.
|
* @type {Number}
|
* @default 0.0
|
*/
|
this.y = defaultValue(y, 0.0);
|
|
/**
|
* The Z component.
|
* @type {Number}
|
* @default 0.0
|
*/
|
this.z = defaultValue(z, 0.0);
|
}
|
|
/**
|
* Converts the provided Spherical into Cartesian3 coordinates.
|
*
|
* @param {Spherical} spherical The Spherical to be converted to Cartesian3.
|
* @param {Cartesian3} [result] The object onto which to store the result.
|
* @returns {Cartesian3} The modified result parameter or a new Cartesian3 instance if one was not provided.
|
*/
|
Cartesian3.fromSpherical = function(spherical, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('spherical', spherical);
|
//>>includeEnd('debug');
|
|
if (!defined(result)) {
|
result = new Cartesian3();
|
}
|
|
var clock = spherical.clock;
|
var cone = spherical.cone;
|
var magnitude = defaultValue(spherical.magnitude, 1.0);
|
var radial = magnitude * Math.sin(cone);
|
result.x = radial * Math.cos(clock);
|
result.y = radial * Math.sin(clock);
|
result.z = magnitude * Math.cos(cone);
|
return result;
|
};
|
|
/**
|
* Creates a Cartesian3 instance from x, y and z coordinates.
|
*
|
* @param {Number} x The x coordinate.
|
* @param {Number} y The y coordinate.
|
* @param {Number} z The z coordinate.
|
* @param {Cartesian3} [result] The object onto which to store the result.
|
* @returns {Cartesian3} The modified result parameter or a new Cartesian3 instance if one was not provided.
|
*/
|
Cartesian3.fromElements = function(x, y, z, result) {
|
if (!defined(result)) {
|
return new Cartesian3(x, y, z);
|
}
|
|
result.x = x;
|
result.y = y;
|
result.z = z;
|
return result;
|
};
|
|
/**
|
* Duplicates a Cartesian3 instance.
|
*
|
* @param {Cartesian3} cartesian The Cartesian to duplicate.
|
* @param {Cartesian3} [result] The object onto which to store the result.
|
* @returns {Cartesian3} The modified result parameter or a new Cartesian3 instance if one was not provided. (Returns undefined if cartesian is undefined)
|
*/
|
Cartesian3.clone = function(cartesian, result) {
|
if (!defined(cartesian)) {
|
return undefined;
|
}
|
if (!defined(result)) {
|
return new Cartesian3(cartesian.x, cartesian.y, cartesian.z);
|
}
|
|
result.x = cartesian.x;
|
result.y = cartesian.y;
|
result.z = cartesian.z;
|
return result;
|
};
|
|
/**
|
* Creates a Cartesian3 instance from an existing Cartesian4. This simply takes the
|
* x, y, and z properties of the Cartesian4 and drops w.
|
* @function
|
*
|
* @param {Cartesian4} cartesian The Cartesian4 instance to create a Cartesian3 instance from.
|
* @param {Cartesian3} [result] The object onto which to store the result.
|
* @returns {Cartesian3} The modified result parameter or a new Cartesian3 instance if one was not provided.
|
*/
|
Cartesian3.fromCartesian4 = Cartesian3.clone;
|
|
/**
|
* The number of elements used to pack the object into an array.
|
* @type {Number}
|
*/
|
Cartesian3.packedLength = 3;
|
|
/**
|
* Stores the provided instance into the provided array.
|
*
|
* @param {Cartesian3} value The value to pack.
|
* @param {Number[]} array The array to pack into.
|
* @param {Number} [startingIndex=0] The index into the array at which to start packing the elements.
|
*
|
* @returns {Number[]} The array that was packed into
|
*/
|
Cartesian3.pack = function(value, array, startingIndex) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('value', value);
|
Check.defined('array', array);
|
//>>includeEnd('debug');
|
|
startingIndex = defaultValue(startingIndex, 0);
|
|
array[startingIndex++] = value.x;
|
array[startingIndex++] = value.y;
|
array[startingIndex] = value.z;
|
|
return array;
|
};
|
|
/**
|
* Retrieves an instance from a packed array.
|
*
|
* @param {Number[]} array The packed array.
|
* @param {Number} [startingIndex=0] The starting index of the element to be unpacked.
|
* @param {Cartesian3} [result] The object into which to store the result.
|
* @returns {Cartesian3} The modified result parameter or a new Cartesian3 instance if one was not provided.
|
*/
|
Cartesian3.unpack = function(array, startingIndex, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.defined('array', array);
|
//>>includeEnd('debug');
|
|
startingIndex = defaultValue(startingIndex, 0);
|
|
if (!defined(result)) {
|
result = new Cartesian3();
|
}
|
result.x = array[startingIndex++];
|
result.y = array[startingIndex++];
|
result.z = array[startingIndex];
|
return result;
|
};
|
|
/**
|
* Flattens an array of Cartesian3s into an array of components.
|
*
|
* @param {Cartesian3[]} array The array of cartesians to pack.
|
* @param {Number[]} result The array onto which to store the result.
|
* @returns {Number[]} The packed array.
|
*/
|
Cartesian3.packArray = function(array, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.defined('array', array);
|
//>>includeEnd('debug');
|
|
var length = array.length;
|
if (!defined(result)) {
|
result = new Array(length * 3);
|
} else {
|
result.length = length * 3;
|
}
|
|
for (var i = 0; i < length; ++i) {
|
Cartesian3.pack(array[i], result, i * 3);
|
}
|
return result;
|
};
|
|
/**
|
* Unpacks an array of cartesian components into an array of Cartesian3s.
|
*
|
* @param {Number[]} array The array of components to unpack.
|
* @param {Cartesian3[]} result The array onto which to store the result.
|
* @returns {Cartesian3[]} The unpacked array.
|
*/
|
Cartesian3.unpackArray = function(array, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.defined('array', array);
|
Check.typeOf.number.greaterThanOrEquals('array.length', array.length, 3);
|
if (array.length % 3 !== 0) {
|
throw new DeveloperError('array length must be a multiple of 3.');
|
}
|
//>>includeEnd('debug');
|
|
var length = array.length;
|
if (!defined(result)) {
|
result = new Array(length / 3);
|
} else {
|
result.length = length / 3;
|
}
|
|
for (var i = 0; i < length; i += 3) {
|
var index = i / 3;
|
result[index] = Cartesian3.unpack(array, i, result[index]);
|
}
|
return result;
|
};
|
|
/**
|
* Creates a Cartesian3 from three consecutive elements in an array.
|
* @function
|
*
|
* @param {Number[]} array The array whose three consecutive elements correspond to the x, y, and z components, respectively.
|
* @param {Number} [startingIndex=0] The offset into the array of the first element, which corresponds to the x component.
|
* @param {Cartesian3} [result] The object onto which to store the result.
|
* @returns {Cartesian3} The modified result parameter or a new Cartesian3 instance if one was not provided.
|
*
|
* @example
|
* // Create a Cartesian3 with (1.0, 2.0, 3.0)
|
* var v = [1.0, 2.0, 3.0];
|
* var p = Cesium.Cartesian3.fromArray(v);
|
*
|
* // Create a Cartesian3 with (1.0, 2.0, 3.0) using an offset into an array
|
* var v2 = [0.0, 0.0, 1.0, 2.0, 3.0];
|
* var p2 = Cesium.Cartesian3.fromArray(v2, 2);
|
*/
|
Cartesian3.fromArray = Cartesian3.unpack;
|
|
/**
|
* Computes the value of the maximum component for the supplied Cartesian.
|
*
|
* @param {Cartesian3} cartesian The cartesian to use.
|
* @returns {Number} The value of the maximum component.
|
*/
|
Cartesian3.maximumComponent = function(cartesian) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('cartesian', cartesian);
|
//>>includeEnd('debug');
|
|
return Math.max(cartesian.x, cartesian.y, cartesian.z);
|
};
|
|
/**
|
* Computes the value of the minimum component for the supplied Cartesian.
|
*
|
* @param {Cartesian3} cartesian The cartesian to use.
|
* @returns {Number} The value of the minimum component.
|
*/
|
Cartesian3.minimumComponent = function(cartesian) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('cartesian', cartesian);
|
//>>includeEnd('debug');
|
|
return Math.min(cartesian.x, cartesian.y, cartesian.z);
|
};
|
|
/**
|
* Compares two Cartesians and computes a Cartesian which contains the minimum components of the supplied Cartesians.
|
*
|
* @param {Cartesian3} first A cartesian to compare.
|
* @param {Cartesian3} second A cartesian to compare.
|
* @param {Cartesian3} result The object into which to store the result.
|
* @returns {Cartesian3} A cartesian with the minimum components.
|
*/
|
Cartesian3.minimumByComponent = function(first, second, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('first', first);
|
Check.typeOf.object('second', second);
|
Check.typeOf.object('result', result);
|
//>>includeEnd('debug');
|
|
result.x = Math.min(first.x, second.x);
|
result.y = Math.min(first.y, second.y);
|
result.z = Math.min(first.z, second.z);
|
|
return result;
|
};
|
|
/**
|
* Compares two Cartesians and computes a Cartesian which contains the maximum components of the supplied Cartesians.
|
*
|
* @param {Cartesian3} first A cartesian to compare.
|
* @param {Cartesian3} second A cartesian to compare.
|
* @param {Cartesian3} result The object into which to store the result.
|
* @returns {Cartesian3} A cartesian with the maximum components.
|
*/
|
Cartesian3.maximumByComponent = function(first, second, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('first', first);
|
Check.typeOf.object('second', second);
|
Check.typeOf.object('result', result);
|
//>>includeEnd('debug');
|
|
result.x = Math.max(first.x, second.x);
|
result.y = Math.max(first.y, second.y);
|
result.z = Math.max(first.z, second.z);
|
return result;
|
};
|
|
/**
|
* Computes the provided Cartesian's squared magnitude.
|
*
|
* @param {Cartesian3} cartesian The Cartesian instance whose squared magnitude is to be computed.
|
* @returns {Number} The squared magnitude.
|
*/
|
Cartesian3.magnitudeSquared = function(cartesian) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('cartesian', cartesian);
|
//>>includeEnd('debug');
|
|
return cartesian.x * cartesian.x + cartesian.y * cartesian.y + cartesian.z * cartesian.z;
|
};
|
|
/**
|
* Computes the Cartesian's magnitude (length).
|
*
|
* @param {Cartesian3} cartesian The Cartesian instance whose magnitude is to be computed.
|
* @returns {Number} The magnitude.
|
*/
|
Cartesian3.magnitude = function(cartesian) {
|
return Math.sqrt(Cartesian3.magnitudeSquared(cartesian));
|
};
|
|
var distanceScratch = new Cartesian3();
|
|
/**
|
* Computes the distance between two points.
|
*
|
* @param {Cartesian3} left The first point to compute the distance from.
|
* @param {Cartesian3} right The second point to compute the distance to.
|
* @returns {Number} The distance between two points.
|
*
|
* @example
|
* // Returns 1.0
|
* var d = Cesium.Cartesian3.distance(new Cesium.Cartesian3(1.0, 0.0, 0.0), new Cesium.Cartesian3(2.0, 0.0, 0.0));
|
*/
|
Cartesian3.distance = function(left, right) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('left', left);
|
Check.typeOf.object('right', right);
|
//>>includeEnd('debug');
|
|
Cartesian3.subtract(left, right, distanceScratch);
|
return Cartesian3.magnitude(distanceScratch);
|
};
|
|
/**
|
* Computes the squared distance between two points. Comparing squared distances
|
* using this function is more efficient than comparing distances using {@link Cartesian3#distance}.
|
*
|
* @param {Cartesian3} left The first point to compute the distance from.
|
* @param {Cartesian3} right The second point to compute the distance to.
|
* @returns {Number} The distance between two points.
|
*
|
* @example
|
* // Returns 4.0, not 2.0
|
* var d = Cesium.Cartesian3.distanceSquared(new Cesium.Cartesian3(1.0, 0.0, 0.0), new Cesium.Cartesian3(3.0, 0.0, 0.0));
|
*/
|
Cartesian3.distanceSquared = function(left, right) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('left', left);
|
Check.typeOf.object('right', right);
|
//>>includeEnd('debug');
|
|
Cartesian3.subtract(left, right, distanceScratch);
|
return Cartesian3.magnitudeSquared(distanceScratch);
|
};
|
|
/**
|
* Computes the normalized form of the supplied Cartesian.
|
*
|
* @param {Cartesian3} cartesian The Cartesian to be normalized.
|
* @param {Cartesian3} result The object onto which to store the result.
|
* @returns {Cartesian3} The modified result parameter.
|
*/
|
Cartesian3.normalize = function(cartesian, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('cartesian', cartesian);
|
Check.typeOf.object('result', result);
|
//>>includeEnd('debug');
|
|
var magnitude = Cartesian3.magnitude(cartesian);
|
|
result.x = cartesian.x / magnitude;
|
result.y = cartesian.y / magnitude;
|
result.z = cartesian.z / magnitude;
|
|
//>>includeStart('debug', pragmas.debug);
|
if (isNaN(result.x) || isNaN(result.y) || isNaN(result.z)) {
|
throw new DeveloperError('normalized result is not a number');
|
}
|
//>>includeEnd('debug');
|
|
return result;
|
};
|
|
/**
|
* Computes the dot (scalar) product of two Cartesians.
|
*
|
* @param {Cartesian3} left The first Cartesian.
|
* @param {Cartesian3} right The second Cartesian.
|
* @returns {Number} The dot product.
|
*/
|
Cartesian3.dot = function(left, right) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('left', left);
|
Check.typeOf.object('right', right);
|
//>>includeEnd('debug');
|
|
return left.x * right.x + left.y * right.y + left.z * right.z;
|
};
|
|
/**
|
* Computes the componentwise product of two Cartesians.
|
*
|
* @param {Cartesian3} left The first Cartesian.
|
* @param {Cartesian3} right The second Cartesian.
|
* @param {Cartesian3} result The object onto which to store the result.
|
* @returns {Cartesian3} The modified result parameter.
|
*/
|
Cartesian3.multiplyComponents = function(left, right, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('left', left);
|
Check.typeOf.object('right', right);
|
Check.typeOf.object('result', result);
|
//>>includeEnd('debug');
|
|
result.x = left.x * right.x;
|
result.y = left.y * right.y;
|
result.z = left.z * right.z;
|
return result;
|
};
|
|
/**
|
* Computes the componentwise quotient of two Cartesians.
|
*
|
* @param {Cartesian3} left The first Cartesian.
|
* @param {Cartesian3} right The second Cartesian.
|
* @param {Cartesian3} result The object onto which to store the result.
|
* @returns {Cartesian3} The modified result parameter.
|
*/
|
Cartesian3.divideComponents = function(left, right, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('left', left);
|
Check.typeOf.object('right', right);
|
Check.typeOf.object('result', result);
|
//>>includeEnd('debug');
|
|
result.x = left.x / right.x;
|
result.y = left.y / right.y;
|
result.z = left.z / right.z;
|
return result;
|
};
|
|
/**
|
* Computes the componentwise sum of two Cartesians.
|
*
|
* @param {Cartesian3} left The first Cartesian.
|
* @param {Cartesian3} right The second Cartesian.
|
* @param {Cartesian3} result The object onto which to store the result.
|
* @returns {Cartesian3} The modified result parameter.
|
*/
|
Cartesian3.add = function(left, right, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('left', left);
|
Check.typeOf.object('right', right);
|
Check.typeOf.object('result', result);
|
//>>includeEnd('debug');
|
|
result.x = left.x + right.x;
|
result.y = left.y + right.y;
|
result.z = left.z + right.z;
|
return result;
|
};
|
|
/**
|
* Computes the componentwise difference of two Cartesians.
|
*
|
* @param {Cartesian3} left The first Cartesian.
|
* @param {Cartesian3} right The second Cartesian.
|
* @param {Cartesian3} result The object onto which to store the result.
|
* @returns {Cartesian3} The modified result parameter.
|
*/
|
Cartesian3.subtract = function(left, right, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('left', left);
|
Check.typeOf.object('right', right);
|
Check.typeOf.object('result', result);
|
//>>includeEnd('debug');
|
|
result.x = left.x - right.x;
|
result.y = left.y - right.y;
|
result.z = left.z - right.z;
|
return result;
|
};
|
|
/**
|
* Multiplies the provided Cartesian componentwise by the provided scalar.
|
*
|
* @param {Cartesian3} cartesian The Cartesian to be scaled.
|
* @param {Number} scalar The scalar to multiply with.
|
* @param {Cartesian3} result The object onto which to store the result.
|
* @returns {Cartesian3} The modified result parameter.
|
*/
|
Cartesian3.multiplyByScalar = function(cartesian, scalar, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('cartesian', cartesian);
|
Check.typeOf.number('scalar', scalar);
|
Check.typeOf.object('result', result);
|
//>>includeEnd('debug');
|
|
result.x = cartesian.x * scalar;
|
result.y = cartesian.y * scalar;
|
result.z = cartesian.z * scalar;
|
return result;
|
};
|
|
/**
|
* Divides the provided Cartesian componentwise by the provided scalar.
|
*
|
* @param {Cartesian3} cartesian The Cartesian to be divided.
|
* @param {Number} scalar The scalar to divide by.
|
* @param {Cartesian3} result The object onto which to store the result.
|
* @returns {Cartesian3} The modified result parameter.
|
*/
|
Cartesian3.divideByScalar = function(cartesian, scalar, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('cartesian', cartesian);
|
Check.typeOf.number('scalar', scalar);
|
Check.typeOf.object('result', result);
|
//>>includeEnd('debug');
|
|
result.x = cartesian.x / scalar;
|
result.y = cartesian.y / scalar;
|
result.z = cartesian.z / scalar;
|
return result;
|
};
|
|
/**
|
* Negates the provided Cartesian.
|
*
|
* @param {Cartesian3} cartesian The Cartesian to be negated.
|
* @param {Cartesian3} result The object onto which to store the result.
|
* @returns {Cartesian3} The modified result parameter.
|
*/
|
Cartesian3.negate = function(cartesian, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('cartesian', cartesian);
|
Check.typeOf.object('result', result);
|
//>>includeEnd('debug');
|
|
result.x = -cartesian.x;
|
result.y = -cartesian.y;
|
result.z = -cartesian.z;
|
return result;
|
};
|
|
/**
|
* Computes the absolute value of the provided Cartesian.
|
*
|
* @param {Cartesian3} cartesian The Cartesian whose absolute value is to be computed.
|
* @param {Cartesian3} result The object onto which to store the result.
|
* @returns {Cartesian3} The modified result parameter.
|
*/
|
Cartesian3.abs = function(cartesian, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('cartesian', cartesian);
|
Check.typeOf.object('result', result);
|
//>>includeEnd('debug');
|
|
result.x = Math.abs(cartesian.x);
|
result.y = Math.abs(cartesian.y);
|
result.z = Math.abs(cartesian.z);
|
return result;
|
};
|
|
var lerpScratch = new Cartesian3();
|
/**
|
* Computes the linear interpolation or extrapolation at t using the provided cartesians.
|
*
|
* @param {Cartesian3} start The value corresponding to t at 0.0.
|
* @param {Cartesian3} end The value corresponding to t at 1.0.
|
* @param {Number} t The point along t at which to interpolate.
|
* @param {Cartesian3} result The object onto which to store the result.
|
* @returns {Cartesian3} The modified result parameter.
|
*/
|
Cartesian3.lerp = function(start, end, t, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('start', start);
|
Check.typeOf.object('end', end);
|
Check.typeOf.number('t', t);
|
Check.typeOf.object('result', result);
|
//>>includeEnd('debug');
|
|
Cartesian3.multiplyByScalar(end, t, lerpScratch);
|
result = Cartesian3.multiplyByScalar(start, 1.0 - t, result);
|
return Cartesian3.add(lerpScratch, result, result);
|
};
|
|
var angleBetweenScratch = new Cartesian3();
|
var angleBetweenScratch2 = new Cartesian3();
|
/**
|
* Returns the angle, in radians, between the provided Cartesians.
|
*
|
* @param {Cartesian3} left The first Cartesian.
|
* @param {Cartesian3} right The second Cartesian.
|
* @returns {Number} The angle between the Cartesians.
|
*/
|
Cartesian3.angleBetween = function(left, right) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('left', left);
|
Check.typeOf.object('right', right);
|
//>>includeEnd('debug');
|
|
Cartesian3.normalize(left, angleBetweenScratch);
|
Cartesian3.normalize(right, angleBetweenScratch2);
|
var cosine = Cartesian3.dot(angleBetweenScratch, angleBetweenScratch2);
|
var sine = Cartesian3.magnitude(Cartesian3.cross(angleBetweenScratch, angleBetweenScratch2, angleBetweenScratch));
|
return Math.atan2(sine, cosine);
|
};
|
|
var mostOrthogonalAxisScratch = new Cartesian3();
|
/**
|
* Returns the axis that is most orthogonal to the provided Cartesian.
|
*
|
* @param {Cartesian3} cartesian The Cartesian on which to find the most orthogonal axis.
|
* @param {Cartesian3} result The object onto which to store the result.
|
* @returns {Cartesian3} The most orthogonal axis.
|
*/
|
Cartesian3.mostOrthogonalAxis = function(cartesian, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('cartesian', cartesian);
|
Check.typeOf.object('result', result);
|
//>>includeEnd('debug');
|
|
var f = Cartesian3.normalize(cartesian, mostOrthogonalAxisScratch);
|
Cartesian3.abs(f, f);
|
|
if (f.x <= f.y) {
|
if (f.x <= f.z) {
|
result = Cartesian3.clone(Cartesian3.UNIT_X, result);
|
} else {
|
result = Cartesian3.clone(Cartesian3.UNIT_Z, result);
|
}
|
} else if (f.y <= f.z) {
|
result = Cartesian3.clone(Cartesian3.UNIT_Y, result);
|
} else {
|
result = Cartesian3.clone(Cartesian3.UNIT_Z, result);
|
}
|
|
return result;
|
};
|
|
/**
|
* Projects vector a onto vector b
|
* @param {Cartesian3} a The vector that needs projecting
|
* @param {Cartesian3} b The vector to project onto
|
* @param {Cartesian3} result The result cartesian
|
* @returns {Cartesian3} The modified result parameter
|
*/
|
Cartesian3.projectVector = function(a, b, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.defined('a', a);
|
Check.defined('b', b);
|
Check.defined('result', result);
|
//>>includeEnd('debug');
|
|
var scalar = Cartesian3.dot(a, b) / Cartesian3.dot(b, b);
|
return Cartesian3.multiplyByScalar(b, scalar, result);
|
};
|
|
/**
|
* Compares the provided Cartesians componentwise and returns
|
* <code>true</code> if they are equal, <code>false</code> otherwise.
|
*
|
* @param {Cartesian3} [left] The first Cartesian.
|
* @param {Cartesian3} [right] The second Cartesian.
|
* @returns {Boolean} <code>true</code> if left and right are equal, <code>false</code> otherwise.
|
*/
|
Cartesian3.equals = function(left, right) {
|
return (left === right) ||
|
((defined(left)) &&
|
(defined(right)) &&
|
(left.x === right.x) &&
|
(left.y === right.y) &&
|
(left.z === right.z));
|
};
|
|
/**
|
* @private
|
*/
|
Cartesian3.equalsArray = function(cartesian, array, offset) {
|
return cartesian.x === array[offset] &&
|
cartesian.y === array[offset + 1] &&
|
cartesian.z === array[offset + 2];
|
};
|
|
/**
|
* Compares the provided Cartesians componentwise and returns
|
* <code>true</code> if they pass an absolute or relative tolerance test,
|
* <code>false</code> otherwise.
|
*
|
* @param {Cartesian3} [left] The first Cartesian.
|
* @param {Cartesian3} [right] The second Cartesian.
|
* @param {Number} relativeEpsilon The relative epsilon tolerance to use for equality testing.
|
* @param {Number} [absoluteEpsilon=relativeEpsilon] The absolute epsilon tolerance to use for equality testing.
|
* @returns {Boolean} <code>true</code> if left and right are within the provided epsilon, <code>false</code> otherwise.
|
*/
|
Cartesian3.equalsEpsilon = function(left, right, relativeEpsilon, absoluteEpsilon) {
|
return (left === right) ||
|
(defined(left) &&
|
defined(right) &&
|
CesiumMath.equalsEpsilon(left.x, right.x, relativeEpsilon, absoluteEpsilon) &&
|
CesiumMath.equalsEpsilon(left.y, right.y, relativeEpsilon, absoluteEpsilon) &&
|
CesiumMath.equalsEpsilon(left.z, right.z, relativeEpsilon, absoluteEpsilon));
|
};
|
|
/**
|
* Computes the cross (outer) product of two Cartesians.
|
*
|
* @param {Cartesian3} left The first Cartesian.
|
* @param {Cartesian3} right The second Cartesian.
|
* @param {Cartesian3} result The object onto which to store the result.
|
* @returns {Cartesian3} The cross product.
|
*/
|
Cartesian3.cross = function(left, right, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('left', left);
|
Check.typeOf.object('right', right);
|
Check.typeOf.object('result', result);
|
//>>includeEnd('debug');
|
|
var leftX = left.x;
|
var leftY = left.y;
|
var leftZ = left.z;
|
var rightX = right.x;
|
var rightY = right.y;
|
var rightZ = right.z;
|
|
var x = leftY * rightZ - leftZ * rightY;
|
var y = leftZ * rightX - leftX * rightZ;
|
var z = leftX * rightY - leftY * rightX;
|
|
result.x = x;
|
result.y = y;
|
result.z = z;
|
return result;
|
};
|
|
/**
|
* Computes the midpoint between the right and left Cartesian.
|
* @param {Cartesian3} left The first Cartesian.
|
* @param {Cartesian3} right The second Cartesian.
|
* @param {Cartesian3} result The object onto which to store the result.
|
* @returns {Cartesian3} The midpoint.
|
*/
|
Cartesian3.midpoint = function(left, right, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('left', left);
|
Check.typeOf.object('right', right);
|
Check.typeOf.object('result', result);
|
//>>includeEnd('debug');
|
|
result.x = (left.x + right.x) * 0.5;
|
result.y = (left.y + right.y) * 0.5;
|
result.z = (left.z + right.z) * 0.5;
|
|
return result;
|
};
|
|
/**
|
* Returns a Cartesian3 position from longitude and latitude values given in degrees.
|
*
|
* @param {Number} longitude The longitude, in degrees
|
* @param {Number} latitude The latitude, in degrees
|
* @param {Number} [height=0.0] The height, in meters, above the ellipsoid.
|
* @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid on which the position lies.
|
* @param {Cartesian3} [result] The object onto which to store the result.
|
* @returns {Cartesian3} The position
|
*
|
* @example
|
* var position = Cesium.Cartesian3.fromDegrees(-115.0, 37.0);
|
*/
|
Cartesian3.fromDegrees = function(longitude, latitude, height, ellipsoid, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.number('longitude', longitude);
|
Check.typeOf.number('latitude', latitude);
|
//>>includeEnd('debug');
|
|
longitude = CesiumMath.toRadians(longitude);
|
latitude = CesiumMath.toRadians(latitude);
|
return Cartesian3.fromRadians(longitude, latitude, height, ellipsoid, result);
|
};
|
|
var scratchN = new Cartesian3();
|
var scratchK = new Cartesian3();
|
var wgs84RadiiSquared = new Cartesian3(6378137.0 * 6378137.0, 6378137.0 * 6378137.0, 6356752.3142451793 * 6356752.3142451793);
|
|
/**
|
* Returns a Cartesian3 position from longitude and latitude values given in radians.
|
*
|
* @param {Number} longitude The longitude, in radians
|
* @param {Number} latitude The latitude, in radians
|
* @param {Number} [height=0.0] The height, in meters, above the ellipsoid.
|
* @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid on which the position lies.
|
* @param {Cartesian3} [result] The object onto which to store the result.
|
* @returns {Cartesian3} The position
|
*
|
* @example
|
* var position = Cesium.Cartesian3.fromRadians(-2.007, 0.645);
|
*/
|
Cartesian3.fromRadians = function(longitude, latitude, height, ellipsoid, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.number('longitude', longitude);
|
Check.typeOf.number('latitude', latitude);
|
//>>includeEnd('debug');
|
|
height = defaultValue(height, 0.0);
|
var radiiSquared = defined(ellipsoid) ? ellipsoid.radiiSquared : wgs84RadiiSquared;
|
|
var cosLatitude = Math.cos(latitude);
|
scratchN.x = cosLatitude * Math.cos(longitude);
|
scratchN.y = cosLatitude * Math.sin(longitude);
|
scratchN.z = Math.sin(latitude);
|
scratchN = Cartesian3.normalize(scratchN, scratchN);
|
|
Cartesian3.multiplyComponents(radiiSquared, scratchN, scratchK);
|
var gamma = Math.sqrt(Cartesian3.dot(scratchN, scratchK));
|
scratchK = Cartesian3.divideByScalar(scratchK, gamma, scratchK);
|
scratchN = Cartesian3.multiplyByScalar(scratchN, height, scratchN);
|
|
if (!defined(result)) {
|
result = new Cartesian3();
|
}
|
return Cartesian3.add(scratchK, scratchN, result);
|
};
|
|
/**
|
* Returns an array of Cartesian3 positions given an array of longitude and latitude values given in degrees.
|
*
|
* @param {Number[]} coordinates A list of longitude and latitude values. Values alternate [longitude, latitude, longitude, latitude...].
|
* @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid on which the coordinates lie.
|
* @param {Cartesian3[]} [result] An array of Cartesian3 objects to store the result.
|
* @returns {Cartesian3[]} The array of positions.
|
*
|
* @example
|
* var positions = Cesium.Cartesian3.fromDegreesArray([-115.0, 37.0, -107.0, 33.0]);
|
*/
|
Cartesian3.fromDegreesArray = function(coordinates, ellipsoid, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.defined('coordinates', coordinates);
|
if (coordinates.length < 2 || coordinates.length % 2 !== 0) {
|
throw new DeveloperError('the number of coordinates must be a multiple of 2 and at least 2');
|
}
|
//>>includeEnd('debug');
|
|
var length = coordinates.length;
|
if (!defined(result)) {
|
result = new Array(length / 2);
|
} else {
|
result.length = length / 2;
|
}
|
|
for (var i = 0; i < length; i += 2) {
|
var longitude = coordinates[i];
|
var latitude = coordinates[i + 1];
|
var index = i / 2;
|
result[index] = Cartesian3.fromDegrees(longitude, latitude, 0, ellipsoid, result[index]);
|
}
|
|
return result;
|
};
|
|
/**
|
* Returns an array of Cartesian3 positions given an array of longitude and latitude values given in radians.
|
*
|
* @param {Number[]} coordinates A list of longitude and latitude values. Values alternate [longitude, latitude, longitude, latitude...].
|
* @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid on which the coordinates lie.
|
* @param {Cartesian3[]} [result] An array of Cartesian3 objects to store the result.
|
* @returns {Cartesian3[]} The array of positions.
|
*
|
* @example
|
* var positions = Cesium.Cartesian3.fromRadiansArray([-2.007, 0.645, -1.867, .575]);
|
*/
|
Cartesian3.fromRadiansArray = function(coordinates, ellipsoid, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.defined('coordinates', coordinates);
|
if (coordinates.length < 2 || coordinates.length % 2 !== 0) {
|
throw new DeveloperError('the number of coordinates must be a multiple of 2 and at least 2');
|
}
|
//>>includeEnd('debug');
|
|
var length = coordinates.length;
|
if (!defined(result)) {
|
result = new Array(length / 2);
|
} else {
|
result.length = length / 2;
|
}
|
|
for (var i = 0; i < length; i += 2) {
|
var longitude = coordinates[i];
|
var latitude = coordinates[i + 1];
|
var index = i / 2;
|
result[index] = Cartesian3.fromRadians(longitude, latitude, 0, ellipsoid, result[index]);
|
}
|
|
return result;
|
};
|
|
/**
|
* Returns an array of Cartesian3 positions given an array of longitude, latitude and height values where longitude and latitude are given in degrees.
|
*
|
* @param {Number[]} coordinates A list of longitude, latitude and height values. Values alternate [longitude, latitude, height, longitude, latitude, height...].
|
* @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid on which the position lies.
|
* @param {Cartesian3[]} [result] An array of Cartesian3 objects to store the result.
|
* @returns {Cartesian3[]} The array of positions.
|
*
|
* @example
|
* var positions = Cesium.Cartesian3.fromDegreesArrayHeights([-115.0, 37.0, 100000.0, -107.0, 33.0, 150000.0]);
|
*/
|
Cartesian3.fromDegreesArrayHeights = function(coordinates, ellipsoid, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.defined('coordinates', coordinates);
|
if (coordinates.length < 3 || coordinates.length % 3 !== 0) {
|
throw new DeveloperError('the number of coordinates must be a multiple of 3 and at least 3');
|
}
|
//>>includeEnd('debug');
|
|
var length = coordinates.length;
|
if (!defined(result)) {
|
result = new Array(length / 3);
|
} else {
|
result.length = length / 3;
|
}
|
|
for (var i = 0; i < length; i += 3) {
|
var longitude = coordinates[i];
|
var latitude = coordinates[i + 1];
|
var height = coordinates[i + 2];
|
var index = i / 3;
|
result[index] = Cartesian3.fromDegrees(longitude, latitude, height, ellipsoid, result[index]);
|
}
|
|
return result;
|
};
|
|
/**
|
* Returns an array of Cartesian3 positions given an array of longitude, latitude and height values where longitude and latitude are given in radians.
|
*
|
* @param {Number[]} coordinates A list of longitude, latitude and height values. Values alternate [longitude, latitude, height, longitude, latitude, height...].
|
* @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid on which the position lies.
|
* @param {Cartesian3[]} [result] An array of Cartesian3 objects to store the result.
|
* @returns {Cartesian3[]} The array of positions.
|
*
|
* @example
|
* var positions = Cesium.Cartesian3.fromRadiansArrayHeights([-2.007, 0.645, 100000.0, -1.867, .575, 150000.0]);
|
*/
|
Cartesian3.fromRadiansArrayHeights = function(coordinates, ellipsoid, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.defined('coordinates', coordinates);
|
if (coordinates.length < 3 || coordinates.length % 3 !== 0) {
|
throw new DeveloperError('the number of coordinates must be a multiple of 3 and at least 3');
|
}
|
//>>includeEnd('debug');
|
|
var length = coordinates.length;
|
if (!defined(result)) {
|
result = new Array(length / 3);
|
} else {
|
result.length = length / 3;
|
}
|
|
for (var i = 0; i < length; i += 3) {
|
var longitude = coordinates[i];
|
var latitude = coordinates[i + 1];
|
var height = coordinates[i + 2];
|
var index = i / 3;
|
result[index] = Cartesian3.fromRadians(longitude, latitude, height, ellipsoid, result[index]);
|
}
|
|
return result;
|
};
|
|
/**
|
* An immutable Cartesian3 instance initialized to (0.0, 0.0, 0.0).
|
*
|
* @type {Cartesian3}
|
* @constant
|
*/
|
Cartesian3.ZERO = freezeObject(new Cartesian3(0.0, 0.0, 0.0));
|
|
/**
|
* An immutable Cartesian3 instance initialized to (1.0, 0.0, 0.0).
|
*
|
* @type {Cartesian3}
|
* @constant
|
*/
|
Cartesian3.UNIT_X = freezeObject(new Cartesian3(1.0, 0.0, 0.0));
|
|
/**
|
* An immutable Cartesian3 instance initialized to (0.0, 1.0, 0.0).
|
*
|
* @type {Cartesian3}
|
* @constant
|
*/
|
Cartesian3.UNIT_Y = freezeObject(new Cartesian3(0.0, 1.0, 0.0));
|
|
/**
|
* An immutable Cartesian3 instance initialized to (0.0, 0.0, 1.0).
|
*
|
* @type {Cartesian3}
|
* @constant
|
*/
|
Cartesian3.UNIT_Z = freezeObject(new Cartesian3(0.0, 0.0, 1.0));
|
|
/**
|
* Duplicates this Cartesian3 instance.
|
*
|
* @param {Cartesian3} [result] The object onto which to store the result.
|
* @returns {Cartesian3} The modified result parameter or a new Cartesian3 instance if one was not provided.
|
*/
|
Cartesian3.prototype.clone = function(result) {
|
return Cartesian3.clone(this, result);
|
};
|
|
/**
|
* Compares this Cartesian against the provided Cartesian componentwise and returns
|
* <code>true</code> if they are equal, <code>false</code> otherwise.
|
*
|
* @param {Cartesian3} [right] The right hand side Cartesian.
|
* @returns {Boolean} <code>true</code> if they are equal, <code>false</code> otherwise.
|
*/
|
Cartesian3.prototype.equals = function(right) {
|
return Cartesian3.equals(this, right);
|
};
|
|
/**
|
* Compares this Cartesian against the provided Cartesian componentwise and returns
|
* <code>true</code> if they pass an absolute or relative tolerance test,
|
* <code>false</code> otherwise.
|
*
|
* @param {Cartesian3} [right] The right hand side Cartesian.
|
* @param {Number} relativeEpsilon The relative epsilon tolerance to use for equality testing.
|
* @param {Number} [absoluteEpsilon=relativeEpsilon] The absolute epsilon tolerance to use for equality testing.
|
* @returns {Boolean} <code>true</code> if they are within the provided epsilon, <code>false</code> otherwise.
|
*/
|
Cartesian3.prototype.equalsEpsilon = function(right, relativeEpsilon, absoluteEpsilon) {
|
return Cartesian3.equalsEpsilon(this, right, relativeEpsilon, absoluteEpsilon);
|
};
|
|
/**
|
* Creates a string representing this Cartesian in the format '(x, y, z)'.
|
*
|
* @returns {String} A string representing this Cartesian in the format '(x, y, z)'.
|
*/
|
Cartesian3.prototype.toString = function() {
|
return '(' + this.x + ', ' + this.y + ', ' + this.z + ')';
|
};
|
|
module.exports= Cartesian3;
|
|
},{"./Check":129,"./DeveloperError":131,"./Math":139,"./defaultValue":158,"./defined":160,"./freezeObject":163}],127:[function(require,module,exports){
|
var Check=require('./Check');
|
var defaultValue=require('./defaultValue');
|
var defined=require('./defined');
|
var DeveloperError=require('./DeveloperError');
|
var freezeObject=require('./freezeObject');
|
var CesiumMath=require('./Math');
|
|
'use strict';
|
|
/**
|
* A 4D Cartesian point.
|
* @alias Cartesian4
|
* @constructor
|
*
|
* @param {Number} [x=0.0] The X component.
|
* @param {Number} [y=0.0] The Y component.
|
* @param {Number} [z=0.0] The Z component.
|
* @param {Number} [w=0.0] The W component.
|
*
|
* @see Cartesian2
|
* @see Cartesian3
|
* @see Packable
|
*/
|
function Cartesian4(x, y, z, w) {
|
/**
|
* The X component.
|
* @type {Number}
|
* @default 0.0
|
*/
|
this.x = defaultValue(x, 0.0);
|
|
/**
|
* The Y component.
|
* @type {Number}
|
* @default 0.0
|
*/
|
this.y = defaultValue(y, 0.0);
|
|
/**
|
* The Z component.
|
* @type {Number}
|
* @default 0.0
|
*/
|
this.z = defaultValue(z, 0.0);
|
|
/**
|
* The W component.
|
* @type {Number}
|
* @default 0.0
|
*/
|
this.w = defaultValue(w, 0.0);
|
}
|
|
/**
|
* Creates a Cartesian4 instance from x, y, z and w coordinates.
|
*
|
* @param {Number} x The x coordinate.
|
* @param {Number} y The y coordinate.
|
* @param {Number} z The z coordinate.
|
* @param {Number} w The w coordinate.
|
* @param {Cartesian4} [result] The object onto which to store the result.
|
* @returns {Cartesian4} The modified result parameter or a new Cartesian4 instance if one was not provided.
|
*/
|
Cartesian4.fromElements = function(x, y, z, w, result) {
|
if (!defined(result)) {
|
return new Cartesian4(x, y, z, w);
|
}
|
|
result.x = x;
|
result.y = y;
|
result.z = z;
|
result.w = w;
|
return result;
|
};
|
|
/**
|
* Creates a Cartesian4 instance from a {@link Color}. <code>red</code>, <code>green</code>, <code>blue</code>,
|
* and <code>alpha</code> map to <code>x</code>, <code>y</code>, <code>z</code>, and <code>w</code>, respectively.
|
*
|
* @param {Color} color The source color.
|
* @param {Cartesian4} [result] The object onto which to store the result.
|
* @returns {Cartesian4} The modified result parameter or a new Cartesian4 instance if one was not provided.
|
*/
|
Cartesian4.fromColor = function(color, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('color', color);
|
//>>includeEnd('debug');
|
if (!defined(result)) {
|
return new Cartesian4(color.red, color.green, color.blue, color.alpha);
|
}
|
|
result.x = color.red;
|
result.y = color.green;
|
result.z = color.blue;
|
result.w = color.alpha;
|
return result;
|
};
|
|
/**
|
* Duplicates a Cartesian4 instance.
|
*
|
* @param {Cartesian4} cartesian The Cartesian to duplicate.
|
* @param {Cartesian4} [result] The object onto which to store the result.
|
* @returns {Cartesian4} The modified result parameter or a new Cartesian4 instance if one was not provided. (Returns undefined if cartesian is undefined)
|
*/
|
Cartesian4.clone = function(cartesian, result) {
|
if (!defined(cartesian)) {
|
return undefined;
|
}
|
|
if (!defined(result)) {
|
return new Cartesian4(cartesian.x, cartesian.y, cartesian.z, cartesian.w);
|
}
|
|
result.x = cartesian.x;
|
result.y = cartesian.y;
|
result.z = cartesian.z;
|
result.w = cartesian.w;
|
return result;
|
};
|
|
/**
|
* The number of elements used to pack the object into an array.
|
* @type {Number}
|
*/
|
Cartesian4.packedLength = 4;
|
|
/**
|
* Stores the provided instance into the provided array.
|
*
|
* @param {Cartesian4} value The value to pack.
|
* @param {Number[]} array The array to pack into.
|
* @param {Number} [startingIndex=0] The index into the array at which to start packing the elements.
|
*
|
* @returns {Number[]} The array that was packed into
|
*/
|
Cartesian4.pack = function(value, array, startingIndex) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('value', value);
|
Check.defined('array', array);
|
//>>includeEnd('debug');
|
|
startingIndex = defaultValue(startingIndex, 0);
|
|
array[startingIndex++] = value.x;
|
array[startingIndex++] = value.y;
|
array[startingIndex++] = value.z;
|
array[startingIndex] = value.w;
|
|
return array;
|
};
|
|
/**
|
* Retrieves an instance from a packed array.
|
*
|
* @param {Number[]} array The packed array.
|
* @param {Number} [startingIndex=0] The starting index of the element to be unpacked.
|
* @param {Cartesian4} [result] The object into which to store the result.
|
* @returns {Cartesian4} The modified result parameter or a new Cartesian4 instance if one was not provided.
|
*/
|
Cartesian4.unpack = function(array, startingIndex, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.defined('array', array);
|
//>>includeEnd('debug');
|
|
startingIndex = defaultValue(startingIndex, 0);
|
|
if (!defined(result)) {
|
result = new Cartesian4();
|
}
|
result.x = array[startingIndex++];
|
result.y = array[startingIndex++];
|
result.z = array[startingIndex++];
|
result.w = array[startingIndex];
|
return result;
|
};
|
|
/**
|
* Flattens an array of Cartesian4s into and array of components.
|
*
|
* @param {Cartesian4[]} array The array of cartesians to pack.
|
* @param {Number[]} result The array onto which to store the result.
|
* @returns {Number[]} The packed array.
|
*/
|
Cartesian4.packArray = function(array, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.defined('array', array);
|
//>>includeEnd('debug');
|
|
var length = array.length;
|
if (!defined(result)) {
|
result = new Array(length * 4);
|
} else {
|
result.length = length * 4;
|
}
|
|
for (var i = 0; i < length; ++i) {
|
Cartesian4.pack(array[i], result, i * 4);
|
}
|
return result;
|
};
|
|
/**
|
* Unpacks an array of cartesian components into and array of Cartesian4s.
|
*
|
* @param {Number[]} array The array of components to unpack.
|
* @param {Cartesian4[]} result The array onto which to store the result.
|
* @returns {Cartesian4[]} The unpacked array.
|
*/
|
Cartesian4.unpackArray = function(array, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.defined('array', array);
|
//>>includeEnd('debug');
|
|
var length = array.length;
|
if (!defined(result)) {
|
result = new Array(length / 4);
|
} else {
|
result.length = length / 4;
|
}
|
|
for (var i = 0; i < length; i += 4) {
|
var index = i / 4;
|
result[index] = Cartesian4.unpack(array, i, result[index]);
|
}
|
return result;
|
};
|
|
/**
|
* Creates a Cartesian4 from four consecutive elements in an array.
|
* @function
|
*
|
* @param {Number[]} array The array whose four consecutive elements correspond to the x, y, z, and w components, respectively.
|
* @param {Number} [startingIndex=0] The offset into the array of the first element, which corresponds to the x component.
|
* @param {Cartesian4} [result] The object onto which to store the result.
|
* @returns {Cartesian4} The modified result parameter or a new Cartesian4 instance if one was not provided.
|
*
|
* @example
|
* // Create a Cartesian4 with (1.0, 2.0, 3.0, 4.0)
|
* var v = [1.0, 2.0, 3.0, 4.0];
|
* var p = Cesium.Cartesian4.fromArray(v);
|
*
|
* // Create a Cartesian4 with (1.0, 2.0, 3.0, 4.0) using an offset into an array
|
* var v2 = [0.0, 0.0, 1.0, 2.0, 3.0, 4.0];
|
* var p2 = Cesium.Cartesian4.fromArray(v2, 2);
|
*/
|
Cartesian4.fromArray = Cartesian4.unpack;
|
|
/**
|
* Computes the value of the maximum component for the supplied Cartesian.
|
*
|
* @param {Cartesian4} cartesian The cartesian to use.
|
* @returns {Number} The value of the maximum component.
|
*/
|
Cartesian4.maximumComponent = function(cartesian) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('cartesian', cartesian);
|
//>>includeEnd('debug');
|
|
return Math.max(cartesian.x, cartesian.y, cartesian.z, cartesian.w);
|
};
|
|
/**
|
* Computes the value of the minimum component for the supplied Cartesian.
|
*
|
* @param {Cartesian4} cartesian The cartesian to use.
|
* @returns {Number} The value of the minimum component.
|
*/
|
Cartesian4.minimumComponent = function(cartesian) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('cartesian', cartesian);
|
//>>includeEnd('debug');
|
|
return Math.min(cartesian.x, cartesian.y, cartesian.z, cartesian.w);
|
};
|
|
/**
|
* Compares two Cartesians and computes a Cartesian which contains the minimum components of the supplied Cartesians.
|
*
|
* @param {Cartesian4} first A cartesian to compare.
|
* @param {Cartesian4} second A cartesian to compare.
|
* @param {Cartesian4} result The object into which to store the result.
|
* @returns {Cartesian4} A cartesian with the minimum components.
|
*/
|
Cartesian4.minimumByComponent = function(first, second, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('first', first);
|
Check.typeOf.object('second', second);
|
Check.typeOf.object('result', result);
|
//>>includeEnd('debug');
|
|
result.x = Math.min(first.x, second.x);
|
result.y = Math.min(first.y, second.y);
|
result.z = Math.min(first.z, second.z);
|
result.w = Math.min(first.w, second.w);
|
|
return result;
|
};
|
|
/**
|
* Compares two Cartesians and computes a Cartesian which contains the maximum components of the supplied Cartesians.
|
*
|
* @param {Cartesian4} first A cartesian to compare.
|
* @param {Cartesian4} second A cartesian to compare.
|
* @param {Cartesian4} result The object into which to store the result.
|
* @returns {Cartesian4} A cartesian with the maximum components.
|
*/
|
Cartesian4.maximumByComponent = function(first, second, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('first', first);
|
Check.typeOf.object('second', second);
|
Check.typeOf.object('result', result);
|
//>>includeEnd('debug');
|
|
result.x = Math.max(first.x, second.x);
|
result.y = Math.max(first.y, second.y);
|
result.z = Math.max(first.z, second.z);
|
result.w = Math.max(first.w, second.w);
|
|
return result;
|
};
|
|
/**
|
* Computes the provided Cartesian's squared magnitude.
|
*
|
* @param {Cartesian4} cartesian The Cartesian instance whose squared magnitude is to be computed.
|
* @returns {Number} The squared magnitude.
|
*/
|
Cartesian4.magnitudeSquared = function(cartesian) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('cartesian', cartesian);
|
//>>includeEnd('debug');
|
|
return cartesian.x * cartesian.x + cartesian.y * cartesian.y + cartesian.z * cartesian.z + cartesian.w * cartesian.w;
|
};
|
|
/**
|
* Computes the Cartesian's magnitude (length).
|
*
|
* @param {Cartesian4} cartesian The Cartesian instance whose magnitude is to be computed.
|
* @returns {Number} The magnitude.
|
*/
|
Cartesian4.magnitude = function(cartesian) {
|
return Math.sqrt(Cartesian4.magnitudeSquared(cartesian));
|
};
|
|
var distanceScratch = new Cartesian4();
|
|
/**
|
* Computes the 4-space distance between two points.
|
*
|
* @param {Cartesian4} left The first point to compute the distance from.
|
* @param {Cartesian4} right The second point to compute the distance to.
|
* @returns {Number} The distance between two points.
|
*
|
* @example
|
* // Returns 1.0
|
* var d = Cesium.Cartesian4.distance(
|
* new Cesium.Cartesian4(1.0, 0.0, 0.0, 0.0),
|
* new Cesium.Cartesian4(2.0, 0.0, 0.0, 0.0));
|
*/
|
Cartesian4.distance = function(left, right) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('left', left);
|
Check.typeOf.object('right', right);
|
//>>includeEnd('debug');
|
|
Cartesian4.subtract(left, right, distanceScratch);
|
return Cartesian4.magnitude(distanceScratch);
|
};
|
|
/**
|
* Computes the squared distance between two points. Comparing squared distances
|
* using this function is more efficient than comparing distances using {@link Cartesian4#distance}.
|
*
|
* @param {Cartesian4} left The first point to compute the distance from.
|
* @param {Cartesian4} right The second point to compute the distance to.
|
* @returns {Number} The distance between two points.
|
*
|
* @example
|
* // Returns 4.0, not 2.0
|
* var d = Cesium.Cartesian4.distance(
|
* new Cesium.Cartesian4(1.0, 0.0, 0.0, 0.0),
|
* new Cesium.Cartesian4(3.0, 0.0, 0.0, 0.0));
|
*/
|
Cartesian4.distanceSquared = function(left, right) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('left', left);
|
Check.typeOf.object('right', right);
|
//>>includeEnd('debug');
|
|
Cartesian4.subtract(left, right, distanceScratch);
|
return Cartesian4.magnitudeSquared(distanceScratch);
|
};
|
|
/**
|
* Computes the normalized form of the supplied Cartesian.
|
*
|
* @param {Cartesian4} cartesian The Cartesian to be normalized.
|
* @param {Cartesian4} result The object onto which to store the result.
|
* @returns {Cartesian4} The modified result parameter.
|
*/
|
Cartesian4.normalize = function(cartesian, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('cartesian', cartesian);
|
Check.typeOf.object('result', result);
|
//>>includeEnd('debug');
|
|
var magnitude = Cartesian4.magnitude(cartesian);
|
|
result.x = cartesian.x / magnitude;
|
result.y = cartesian.y / magnitude;
|
result.z = cartesian.z / magnitude;
|
result.w = cartesian.w / magnitude;
|
|
//>>includeStart('debug', pragmas.debug);
|
if (isNaN(result.x) || isNaN(result.y) || isNaN(result.z) || isNaN(result.w)) {
|
throw new DeveloperError('normalized result is not a number');
|
}
|
//>>includeEnd('debug');
|
|
return result;
|
};
|
|
/**
|
* Computes the dot (scalar) product of two Cartesians.
|
*
|
* @param {Cartesian4} left The first Cartesian.
|
* @param {Cartesian4} right The second Cartesian.
|
* @returns {Number} The dot product.
|
*/
|
Cartesian4.dot = function(left, right) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('left', left);
|
Check.typeOf.object('right', right);
|
//>>includeEnd('debug');
|
|
return left.x * right.x + left.y * right.y + left.z * right.z + left.w * right.w;
|
};
|
|
/**
|
* Computes the componentwise product of two Cartesians.
|
*
|
* @param {Cartesian4} left The first Cartesian.
|
* @param {Cartesian4} right The second Cartesian.
|
* @param {Cartesian4} result The object onto which to store the result.
|
* @returns {Cartesian4} The modified result parameter.
|
*/
|
Cartesian4.multiplyComponents = function(left, right, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('left', left);
|
Check.typeOf.object('right', right);
|
Check.typeOf.object('result', result);
|
//>>includeEnd('debug');
|
|
result.x = left.x * right.x;
|
result.y = left.y * right.y;
|
result.z = left.z * right.z;
|
result.w = left.w * right.w;
|
return result;
|
};
|
|
/**
|
* Computes the componentwise quotient of two Cartesians.
|
*
|
* @param {Cartesian4} left The first Cartesian.
|
* @param {Cartesian4} right The second Cartesian.
|
* @param {Cartesian4} result The object onto which to store the result.
|
* @returns {Cartesian4} The modified result parameter.
|
*/
|
Cartesian4.divideComponents = function(left, right, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('left', left);
|
Check.typeOf.object('right', right);
|
Check.typeOf.object('result', result);
|
//>>includeEnd('debug');
|
|
result.x = left.x / right.x;
|
result.y = left.y / right.y;
|
result.z = left.z / right.z;
|
result.w = left.w / right.w;
|
return result;
|
};
|
|
/**
|
* Computes the componentwise sum of two Cartesians.
|
*
|
* @param {Cartesian4} left The first Cartesian.
|
* @param {Cartesian4} right The second Cartesian.
|
* @param {Cartesian4} result The object onto which to store the result.
|
* @returns {Cartesian4} The modified result parameter.
|
*/
|
Cartesian4.add = function(left, right, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('left', left);
|
Check.typeOf.object('right', right);
|
Check.typeOf.object('result', result);
|
//>>includeEnd('debug');
|
|
result.x = left.x + right.x;
|
result.y = left.y + right.y;
|
result.z = left.z + right.z;
|
result.w = left.w + right.w;
|
return result;
|
};
|
|
/**
|
* Computes the componentwise difference of two Cartesians.
|
*
|
* @param {Cartesian4} left The first Cartesian.
|
* @param {Cartesian4} right The second Cartesian.
|
* @param {Cartesian4} result The object onto which to store the result.
|
* @returns {Cartesian4} The modified result parameter.
|
*/
|
Cartesian4.subtract = function(left, right, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('left', left);
|
Check.typeOf.object('right', right);
|
Check.typeOf.object('result', result);
|
//>>includeEnd('debug');
|
|
result.x = left.x - right.x;
|
result.y = left.y - right.y;
|
result.z = left.z - right.z;
|
result.w = left.w - right.w;
|
return result;
|
};
|
|
/**
|
* Multiplies the provided Cartesian componentwise by the provided scalar.
|
*
|
* @param {Cartesian4} cartesian The Cartesian to be scaled.
|
* @param {Number} scalar The scalar to multiply with.
|
* @param {Cartesian4} result The object onto which to store the result.
|
* @returns {Cartesian4} The modified result parameter.
|
*/
|
Cartesian4.multiplyByScalar = function(cartesian, scalar, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('cartesian', cartesian);
|
Check.typeOf.number('scalar', scalar);
|
Check.typeOf.object('result', result);
|
//>>includeEnd('debug');
|
|
result.x = cartesian.x * scalar;
|
result.y = cartesian.y * scalar;
|
result.z = cartesian.z * scalar;
|
result.w = cartesian.w * scalar;
|
return result;
|
};
|
|
/**
|
* Divides the provided Cartesian componentwise by the provided scalar.
|
*
|
* @param {Cartesian4} cartesian The Cartesian to be divided.
|
* @param {Number} scalar The scalar to divide by.
|
* @param {Cartesian4} result The object onto which to store the result.
|
* @returns {Cartesian4} The modified result parameter.
|
*/
|
Cartesian4.divideByScalar = function(cartesian, scalar, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('cartesian', cartesian);
|
Check.typeOf.number('scalar', scalar);
|
Check.typeOf.object('result', result);
|
//>>includeEnd('debug');
|
|
result.x = cartesian.x / scalar;
|
result.y = cartesian.y / scalar;
|
result.z = cartesian.z / scalar;
|
result.w = cartesian.w / scalar;
|
return result;
|
};
|
|
/**
|
* Negates the provided Cartesian.
|
*
|
* @param {Cartesian4} cartesian The Cartesian to be negated.
|
* @param {Cartesian4} result The object onto which to store the result.
|
* @returns {Cartesian4} The modified result parameter.
|
*/
|
Cartesian4.negate = function(cartesian, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('cartesian', cartesian);
|
Check.typeOf.object('result', result);
|
//>>includeEnd('debug');
|
|
result.x = -cartesian.x;
|
result.y = -cartesian.y;
|
result.z = -cartesian.z;
|
result.w = -cartesian.w;
|
return result;
|
};
|
|
/**
|
* Computes the absolute value of the provided Cartesian.
|
*
|
* @param {Cartesian4} cartesian The Cartesian whose absolute value is to be computed.
|
* @param {Cartesian4} result The object onto which to store the result.
|
* @returns {Cartesian4} The modified result parameter.
|
*/
|
Cartesian4.abs = function(cartesian, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('cartesian', cartesian);
|
Check.typeOf.object('result', result);
|
//>>includeEnd('debug');
|
|
result.x = Math.abs(cartesian.x);
|
result.y = Math.abs(cartesian.y);
|
result.z = Math.abs(cartesian.z);
|
result.w = Math.abs(cartesian.w);
|
return result;
|
};
|
|
var lerpScratch = new Cartesian4();
|
/**
|
* Computes the linear interpolation or extrapolation at t using the provided cartesians.
|
*
|
* @param {Cartesian4} start The value corresponding to t at 0.0.
|
* @param {Cartesian4}end The value corresponding to t at 1.0.
|
* @param {Number} t The point along t at which to interpolate.
|
* @param {Cartesian4} result The object onto which to store the result.
|
* @returns {Cartesian4} The modified result parameter.
|
*/
|
Cartesian4.lerp = function(start, end, t, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('start', start);
|
Check.typeOf.object('end', end);
|
Check.typeOf.number('t', t);
|
Check.typeOf.object('result', result);
|
//>>includeEnd('debug');
|
|
Cartesian4.multiplyByScalar(end, t, lerpScratch);
|
result = Cartesian4.multiplyByScalar(start, 1.0 - t, result);
|
return Cartesian4.add(lerpScratch, result, result);
|
};
|
|
var mostOrthogonalAxisScratch = new Cartesian4();
|
/**
|
* Returns the axis that is most orthogonal to the provided Cartesian.
|
*
|
* @param {Cartesian4} cartesian The Cartesian on which to find the most orthogonal axis.
|
* @param {Cartesian4} result The object onto which to store the result.
|
* @returns {Cartesian4} The most orthogonal axis.
|
*/
|
Cartesian4.mostOrthogonalAxis = function(cartesian, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('cartesian', cartesian);
|
Check.typeOf.object('result', result);
|
//>>includeEnd('debug');
|
|
var f = Cartesian4.normalize(cartesian, mostOrthogonalAxisScratch);
|
Cartesian4.abs(f, f);
|
|
if (f.x <= f.y) {
|
if (f.x <= f.z) {
|
if (f.x <= f.w) {
|
result = Cartesian4.clone(Cartesian4.UNIT_X, result);
|
} else {
|
result = Cartesian4.clone(Cartesian4.UNIT_W, result);
|
}
|
} else if (f.z <= f.w) {
|
result = Cartesian4.clone(Cartesian4.UNIT_Z, result);
|
} else {
|
result = Cartesian4.clone(Cartesian4.UNIT_W, result);
|
}
|
} else if (f.y <= f.z) {
|
if (f.y <= f.w) {
|
result = Cartesian4.clone(Cartesian4.UNIT_Y, result);
|
} else {
|
result = Cartesian4.clone(Cartesian4.UNIT_W, result);
|
}
|
} else if (f.z <= f.w) {
|
result = Cartesian4.clone(Cartesian4.UNIT_Z, result);
|
} else {
|
result = Cartesian4.clone(Cartesian4.UNIT_W, result);
|
}
|
|
return result;
|
};
|
|
/**
|
* Compares the provided Cartesians componentwise and returns
|
* <code>true</code> if they are equal, <code>false</code> otherwise.
|
*
|
* @param {Cartesian4} [left] The first Cartesian.
|
* @param {Cartesian4} [right] The second Cartesian.
|
* @returns {Boolean} <code>true</code> if left and right are equal, <code>false</code> otherwise.
|
*/
|
Cartesian4.equals = function(left, right) {
|
return (left === right) ||
|
((defined(left)) &&
|
(defined(right)) &&
|
(left.x === right.x) &&
|
(left.y === right.y) &&
|
(left.z === right.z) &&
|
(left.w === right.w));
|
};
|
|
/**
|
* @private
|
*/
|
Cartesian4.equalsArray = function(cartesian, array, offset) {
|
return cartesian.x === array[offset] &&
|
cartesian.y === array[offset + 1] &&
|
cartesian.z === array[offset + 2] &&
|
cartesian.w === array[offset + 3];
|
};
|
|
/**
|
* Compares the provided Cartesians componentwise and returns
|
* <code>true</code> if they pass an absolute or relative tolerance test,
|
* <code>false</code> otherwise.
|
*
|
* @param {Cartesian4} [left] The first Cartesian.
|
* @param {Cartesian4} [right] The second Cartesian.
|
* @param {Number} relativeEpsilon The relative epsilon tolerance to use for equality testing.
|
* @param {Number} [absoluteEpsilon=relativeEpsilon] The absolute epsilon tolerance to use for equality testing.
|
* @returns {Boolean} <code>true</code> if left and right are within the provided epsilon, <code>false</code> otherwise.
|
*/
|
Cartesian4.equalsEpsilon = function(left, right, relativeEpsilon, absoluteEpsilon) {
|
return (left === right) ||
|
(defined(left) &&
|
defined(right) &&
|
CesiumMath.equalsEpsilon(left.x, right.x, relativeEpsilon, absoluteEpsilon) &&
|
CesiumMath.equalsEpsilon(left.y, right.y, relativeEpsilon, absoluteEpsilon) &&
|
CesiumMath.equalsEpsilon(left.z, right.z, relativeEpsilon, absoluteEpsilon) &&
|
CesiumMath.equalsEpsilon(left.w, right.w, relativeEpsilon, absoluteEpsilon));
|
};
|
|
/**
|
* An immutable Cartesian4 instance initialized to (0.0, 0.0, 0.0, 0.0).
|
*
|
* @type {Cartesian4}
|
* @constant
|
*/
|
Cartesian4.ZERO = freezeObject(new Cartesian4(0.0, 0.0, 0.0, 0.0));
|
|
/**
|
* An immutable Cartesian4 instance initialized to (1.0, 0.0, 0.0, 0.0).
|
*
|
* @type {Cartesian4}
|
* @constant
|
*/
|
Cartesian4.UNIT_X = freezeObject(new Cartesian4(1.0, 0.0, 0.0, 0.0));
|
|
/**
|
* An immutable Cartesian4 instance initialized to (0.0, 1.0, 0.0, 0.0).
|
*
|
* @type {Cartesian4}
|
* @constant
|
*/
|
Cartesian4.UNIT_Y = freezeObject(new Cartesian4(0.0, 1.0, 0.0, 0.0));
|
|
/**
|
* An immutable Cartesian4 instance initialized to (0.0, 0.0, 1.0, 0.0).
|
*
|
* @type {Cartesian4}
|
* @constant
|
*/
|
Cartesian4.UNIT_Z = freezeObject(new Cartesian4(0.0, 0.0, 1.0, 0.0));
|
|
/**
|
* An immutable Cartesian4 instance initialized to (0.0, 0.0, 0.0, 1.0).
|
*
|
* @type {Cartesian4}
|
* @constant
|
*/
|
Cartesian4.UNIT_W = freezeObject(new Cartesian4(0.0, 0.0, 0.0, 1.0));
|
|
/**
|
* Duplicates this Cartesian4 instance.
|
*
|
* @param {Cartesian4} [result] The object onto which to store the result.
|
* @returns {Cartesian4} The modified result parameter or a new Cartesian4 instance if one was not provided.
|
*/
|
Cartesian4.prototype.clone = function(result) {
|
return Cartesian4.clone(this, result);
|
};
|
|
/**
|
* Compares this Cartesian against the provided Cartesian componentwise and returns
|
* <code>true</code> if they are equal, <code>false</code> otherwise.
|
*
|
* @param {Cartesian4} [right] The right hand side Cartesian.
|
* @returns {Boolean} <code>true</code> if they are equal, <code>false</code> otherwise.
|
*/
|
Cartesian4.prototype.equals = function(right) {
|
return Cartesian4.equals(this, right);
|
};
|
|
/**
|
* Compares this Cartesian against the provided Cartesian componentwise and returns
|
* <code>true</code> if they pass an absolute or relative tolerance test,
|
* <code>false</code> otherwise.
|
*
|
* @param {Cartesian4} [right] The right hand side Cartesian.
|
* @param {Number} relativeEpsilon The relative epsilon tolerance to use for equality testing.
|
* @param {Number} [absoluteEpsilon=relativeEpsilon] The absolute epsilon tolerance to use for equality testing.
|
* @returns {Boolean} <code>true</code> if they are within the provided epsilon, <code>false</code> otherwise.
|
*/
|
Cartesian4.prototype.equalsEpsilon = function(right, relativeEpsilon, absoluteEpsilon) {
|
return Cartesian4.equalsEpsilon(this, right, relativeEpsilon, absoluteEpsilon);
|
};
|
|
/**
|
* Creates a string representing this Cartesian in the format '(x, y)'.
|
*
|
* @returns {String} A string representing the provided Cartesian in the format '(x, y)'.
|
*/
|
Cartesian4.prototype.toString = function() {
|
return '(' + this.x + ', ' + this.y + ', ' + this.z + ', ' + this.w + ')';
|
};
|
|
var scratchFloatArray = new Float32Array(1);
|
var SHIFT_LEFT_8 = 256.0;
|
var SHIFT_LEFT_16 = 65536.0;
|
var SHIFT_LEFT_24 = 16777216.0;
|
|
var SHIFT_RIGHT_8 = 1.0 / SHIFT_LEFT_8;
|
var SHIFT_RIGHT_16 = 1.0 / SHIFT_LEFT_16;
|
var SHIFT_RIGHT_24 = 1.0 / SHIFT_LEFT_24;
|
|
var BIAS = 38.0;
|
|
/**
|
* Packs an arbitrary floating point value to 4 values representable using uint8.
|
*
|
* @param {Number} value A floating point number
|
* @param {Cartesian4} [result] The Cartesian4 that will contain the packed float.
|
* @returns {Cartesian4} A Cartesian4 representing the float packed to values in x, y, z, and w.
|
*/
|
Cartesian4.packFloat = function(value, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.number('value', value);
|
//>>includeEnd('debug');
|
|
if (!defined(result)) {
|
result = new Cartesian4();
|
}
|
|
// Force the value to 32 bit precision
|
scratchFloatArray[0] = value;
|
value = scratchFloatArray[0];
|
|
if (value === 0.0) {
|
return Cartesian4.clone(Cartesian4.ZERO, result);
|
}
|
|
var sign = value < 0.0 ? 1.0 : 0.0;
|
var exponent;
|
|
if (!isFinite(value)) {
|
value = 0.1;
|
exponent = BIAS;
|
} else {
|
value = Math.abs(value);
|
exponent = Math.floor(CesiumMath.logBase(value, 10)) + 1.0;
|
value = value / Math.pow(10.0, exponent);
|
}
|
|
var temp = value * SHIFT_LEFT_8;
|
result.x = Math.floor(temp);
|
temp = (temp - result.x) * SHIFT_LEFT_8;
|
result.y = Math.floor(temp);
|
temp = (temp - result.y) * SHIFT_LEFT_8;
|
result.z = Math.floor(temp);
|
result.w = (exponent + BIAS) * 2.0 + sign;
|
|
return result;
|
};
|
|
/**
|
* Unpacks a float packed using Cartesian4.packFloat.
|
*
|
* @param {Cartesian4} packedFloat A Cartesian4 containing a float packed to 4 values representable using uint8.
|
* @returns {Number} The unpacked float.
|
* @private
|
*/
|
Cartesian4.unpackFloat = function(packedFloat) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('packedFloat', packedFloat);
|
//>>includeEnd('debug');
|
|
var temp = packedFloat.w / 2.0;
|
var exponent = Math.floor(temp);
|
var sign = (temp - exponent) * 2.0;
|
exponent = exponent - BIAS;
|
|
sign = sign * 2.0 - 1.0;
|
sign = -sign;
|
|
if (exponent >= BIAS) {
|
return sign < 0.0 ? Number.NEGATIVE_INFINITY : Number.POSITIVE_INFINITY;
|
}
|
|
var unpacked = sign * packedFloat.x * SHIFT_RIGHT_8;
|
unpacked += sign * packedFloat.y * SHIFT_RIGHT_16;
|
unpacked += sign * packedFloat.z * SHIFT_RIGHT_24;
|
|
return unpacked * Math.pow(10.0, exponent);
|
};
|
|
module.exports= Cartesian4;
|
|
},{"./Check":129,"./DeveloperError":131,"./Math":139,"./defaultValue":158,"./defined":160,"./freezeObject":163}],128:[function(require,module,exports){
|
var Cartesian3=require('./Cartesian3');
|
var Check=require('./Check');
|
var defaultValue=require('./defaultValue');
|
var defined=require('./defined');
|
var freezeObject=require('./freezeObject');
|
var CesiumMath=require('./Math');
|
var scaleToGeodeticSurface=require('./scaleToGeodeticSurface');
|
|
'use strict';
|
|
/**
|
* A position defined by longitude, latitude, and height.
|
* @alias Cartographic
|
* @constructor
|
*
|
* @param {Number} [longitude=0.0] The longitude, in radians.
|
* @param {Number} [latitude=0.0] The latitude, in radians.
|
* @param {Number} [height=0.0] The height, in meters, above the ellipsoid.
|
*
|
* @see Ellipsoid
|
*/
|
function Cartographic(longitude, latitude, height) {
|
/**
|
* The longitude, in radians.
|
* @type {Number}
|
* @default 0.0
|
*/
|
this.longitude = defaultValue(longitude, 0.0);
|
|
/**
|
* The latitude, in radians.
|
* @type {Number}
|
* @default 0.0
|
*/
|
this.latitude = defaultValue(latitude, 0.0);
|
|
/**
|
* The height, in meters, above the ellipsoid.
|
* @type {Number}
|
* @default 0.0
|
*/
|
this.height = defaultValue(height, 0.0);
|
}
|
|
/**
|
* Creates a new Cartographic instance from longitude and latitude
|
* specified in radians.
|
*
|
* @param {Number} longitude The longitude, in radians.
|
* @param {Number} latitude The latitude, in radians.
|
* @param {Number} [height=0.0] The height, in meters, above the ellipsoid.
|
* @param {Cartographic} [result] The object onto which to store the result.
|
* @returns {Cartographic} The modified result parameter or a new Cartographic instance if one was not provided.
|
*/
|
Cartographic.fromRadians = function(longitude, latitude, height, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.number('longitude', longitude);
|
Check.typeOf.number('latitude', latitude);
|
//>>includeEnd('debug');
|
|
height = defaultValue(height, 0.0);
|
|
if (!defined(result)) {
|
return new Cartographic(longitude, latitude, height);
|
}
|
|
result.longitude = longitude;
|
result.latitude = latitude;
|
result.height = height;
|
return result;
|
};
|
|
/**
|
* Creates a new Cartographic instance from longitude and latitude
|
* specified in degrees. The values in the resulting object will
|
* be in radians.
|
*
|
* @param {Number} longitude The longitude, in degrees.
|
* @param {Number} latitude The latitude, in degrees.
|
* @param {Number} [height=0.0] The height, in meters, above the ellipsoid.
|
* @param {Cartographic} [result] The object onto which to store the result.
|
* @returns {Cartographic} The modified result parameter or a new Cartographic instance if one was not provided.
|
*/
|
Cartographic.fromDegrees = function(longitude, latitude, height, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.number('longitude', longitude);
|
Check.typeOf.number('latitude', latitude);
|
//>>includeEnd('debug');
|
longitude = CesiumMath.toRadians(longitude);
|
latitude = CesiumMath.toRadians(latitude);
|
|
return Cartographic.fromRadians(longitude, latitude, height, result);
|
};
|
|
var cartesianToCartographicN = new Cartesian3();
|
var cartesianToCartographicP = new Cartesian3();
|
var cartesianToCartographicH = new Cartesian3();
|
var wgs84OneOverRadii = new Cartesian3(1.0 / 6378137.0, 1.0 / 6378137.0, 1.0 / 6356752.3142451793);
|
var wgs84OneOverRadiiSquared = new Cartesian3(1.0 / (6378137.0 * 6378137.0), 1.0 / (6378137.0 * 6378137.0), 1.0 / (6356752.3142451793 * 6356752.3142451793));
|
var wgs84CenterToleranceSquared = CesiumMath.EPSILON1;
|
|
/**
|
* Creates a new Cartographic instance from a Cartesian position. The values in the
|
* resulting object will be in radians.
|
*
|
* @param {Cartesian3} cartesian The Cartesian position to convert to cartographic representation.
|
* @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid on which the position lies.
|
* @param {Cartographic} [result] The object onto which to store the result.
|
* @returns {Cartographic} The modified result parameter, new Cartographic instance if none was provided, or undefined if the cartesian is at the center of the ellipsoid.
|
*/
|
Cartographic.fromCartesian = function(cartesian, ellipsoid, result) {
|
var oneOverRadii = defined(ellipsoid) ? ellipsoid.oneOverRadii : wgs84OneOverRadii;
|
var oneOverRadiiSquared = defined(ellipsoid) ? ellipsoid.oneOverRadiiSquared : wgs84OneOverRadiiSquared;
|
var centerToleranceSquared = defined(ellipsoid) ? ellipsoid._centerToleranceSquared : wgs84CenterToleranceSquared;
|
|
//`cartesian is required.` is thrown from scaleToGeodeticSurface
|
var p = scaleToGeodeticSurface(cartesian, oneOverRadii, oneOverRadiiSquared, centerToleranceSquared, cartesianToCartographicP);
|
|
if (!defined(p)) {
|
return undefined;
|
}
|
|
var n = Cartesian3.multiplyComponents(p, oneOverRadiiSquared, cartesianToCartographicN);
|
n = Cartesian3.normalize(n, n);
|
|
var h = Cartesian3.subtract(cartesian, p, cartesianToCartographicH);
|
|
var longitude = Math.atan2(n.y, n.x);
|
var latitude = Math.asin(n.z);
|
var height = CesiumMath.sign(Cartesian3.dot(h, cartesian)) * Cartesian3.magnitude(h);
|
|
if (!defined(result)) {
|
return new Cartographic(longitude, latitude, height);
|
}
|
result.longitude = longitude;
|
result.latitude = latitude;
|
result.height = height;
|
return result;
|
};
|
|
/**
|
* Creates a new Cartesian3 instance from a Cartographic input. The values in the inputted
|
* object should be in radians.
|
*
|
* @param {Cartographic} cartographic Input to be converted into a Cartesian3 output.
|
* @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid on which the position lies.
|
* @param {Cartesian3} [result] The object onto which to store the result.
|
* @returns {Cartesian3} The position
|
*/
|
Cartographic.toCartesian = function(cartographic, ellipsoid, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.defined('cartographic', cartographic);
|
//>>includeEnd('debug');
|
|
return Cartesian3.fromRadians(cartographic.longitude, cartographic.latitude, cartographic.height, ellipsoid, result);
|
};
|
|
/**
|
* Duplicates a Cartographic instance.
|
*
|
* @param {Cartographic} cartographic The cartographic to duplicate.
|
* @param {Cartographic} [result] The object onto which to store the result.
|
* @returns {Cartographic} The modified result parameter or a new Cartographic instance if one was not provided. (Returns undefined if cartographic is undefined)
|
*/
|
Cartographic.clone = function(cartographic, result) {
|
if (!defined(cartographic)) {
|
return undefined;
|
}
|
if (!defined(result)) {
|
return new Cartographic(cartographic.longitude, cartographic.latitude, cartographic.height);
|
}
|
result.longitude = cartographic.longitude;
|
result.latitude = cartographic.latitude;
|
result.height = cartographic.height;
|
return result;
|
};
|
|
/**
|
* Compares the provided cartographics componentwise and returns
|
* <code>true</code> if they are equal, <code>false</code> otherwise.
|
*
|
* @param {Cartographic} [left] The first cartographic.
|
* @param {Cartographic} [right] The second cartographic.
|
* @returns {Boolean} <code>true</code> if left and right are equal, <code>false</code> otherwise.
|
*/
|
Cartographic.equals = function(left, right) {
|
return (left === right) ||
|
((defined(left)) &&
|
(defined(right)) &&
|
(left.longitude === right.longitude) &&
|
(left.latitude === right.latitude) &&
|
(left.height === right.height));
|
};
|
|
/**
|
* Compares the provided cartographics componentwise and returns
|
* <code>true</code> if they are within the provided epsilon,
|
* <code>false</code> otherwise.
|
*
|
* @param {Cartographic} [left] The first cartographic.
|
* @param {Cartographic} [right] The second cartographic.
|
* @param {Number} epsilon The epsilon to use for equality testing.
|
* @returns {Boolean} <code>true</code> if left and right are within the provided epsilon, <code>false</code> otherwise.
|
*/
|
Cartographic.equalsEpsilon = function(left, right, epsilon) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.number('epsilon', epsilon);
|
//>>includeEnd('debug');
|
|
return (left === right) ||
|
((defined(left)) &&
|
(defined(right)) &&
|
(Math.abs(left.longitude - right.longitude) <= epsilon) &&
|
(Math.abs(left.latitude - right.latitude) <= epsilon) &&
|
(Math.abs(left.height - right.height) <= epsilon));
|
};
|
|
/**
|
* An immutable Cartographic instance initialized to (0.0, 0.0, 0.0).
|
*
|
* @type {Cartographic}
|
* @constant
|
*/
|
Cartographic.ZERO = freezeObject(new Cartographic(0.0, 0.0, 0.0));
|
|
/**
|
* Duplicates this instance.
|
*
|
* @param {Cartographic} [result] The object onto which to store the result.
|
* @returns {Cartographic} The modified result parameter or a new Cartographic instance if one was not provided.
|
*/
|
Cartographic.prototype.clone = function(result) {
|
return Cartographic.clone(this, result);
|
};
|
|
/**
|
* Compares the provided against this cartographic componentwise and returns
|
* <code>true</code> if they are equal, <code>false</code> otherwise.
|
*
|
* @param {Cartographic} [right] The second cartographic.
|
* @returns {Boolean} <code>true</code> if left and right are equal, <code>false</code> otherwise.
|
*/
|
Cartographic.prototype.equals = function(right) {
|
return Cartographic.equals(this, right);
|
};
|
|
/**
|
* Compares the provided against this cartographic componentwise and returns
|
* <code>true</code> if they are within the provided epsilon,
|
* <code>false</code> otherwise.
|
*
|
* @param {Cartographic} [right] The second cartographic.
|
* @param {Number} epsilon The epsilon to use for equality testing.
|
* @returns {Boolean} <code>true</code> if left and right are within the provided epsilon, <code>false</code> otherwise.
|
*/
|
Cartographic.prototype.equalsEpsilon = function(right, epsilon) {
|
return Cartographic.equalsEpsilon(this, right, epsilon);
|
};
|
|
/**
|
* Creates a string representing this cartographic in the format '(longitude, latitude, height)'.
|
*
|
* @returns {String} A string representing the provided cartographic in the format '(longitude, latitude, height)'.
|
*/
|
Cartographic.prototype.toString = function() {
|
return '(' + this.longitude + ', ' + this.latitude + ', ' + this.height + ')';
|
};
|
|
module.exports= Cartographic;
|
|
},{"./Cartesian3":126,"./Check":129,"./Math":139,"./defaultValue":158,"./defined":160,"./freezeObject":163,"./scaleToGeodeticSurface":176}],129:[function(require,module,exports){
|
var defined=require('./defined');
|
var DeveloperError=require('./DeveloperError');
|
|
'use strict';
|
|
/**
|
* Contains functions for checking that supplied arguments are of a specified type
|
* or meet specified conditions
|
* @private
|
*/
|
var Check = {};
|
|
/**
|
* Contains type checking functions, all using the typeof operator
|
*/
|
Check.typeOf = {};
|
|
function getUndefinedErrorMessage(name) {
|
return name + ' is required, actual value was undefined';
|
}
|
|
function getFailedTypeErrorMessage(actual, expected, name) {
|
return 'Expected ' + name + ' to be typeof ' + expected + ', actual typeof was ' + actual;
|
}
|
|
/**
|
* Throws if test is not defined
|
*
|
* @param {String} name The name of the variable being tested
|
* @param {*} test The value that is to be checked
|
* @exception {DeveloperError} test must be defined
|
*/
|
Check.defined = function (name, test) {
|
if (!defined(test)) {
|
throw new DeveloperError(getUndefinedErrorMessage(name));
|
}
|
};
|
|
/**
|
* Throws if test is not typeof 'function'
|
*
|
* @param {String} name The name of the variable being tested
|
* @param {*} test The value to test
|
* @exception {DeveloperError} test must be typeof 'function'
|
*/
|
Check.typeOf.func = function (name, test) {
|
if (typeof test !== 'function') {
|
throw new DeveloperError(getFailedTypeErrorMessage(typeof test, 'function', name));
|
}
|
};
|
|
/**
|
* Throws if test is not typeof 'string'
|
*
|
* @param {String} name The name of the variable being tested
|
* @param {*} test The value to test
|
* @exception {DeveloperError} test must be typeof 'string'
|
*/
|
Check.typeOf.string = function (name, test) {
|
if (typeof test !== 'string') {
|
throw new DeveloperError(getFailedTypeErrorMessage(typeof test, 'string', name));
|
}
|
};
|
|
/**
|
* Throws if test is not typeof 'number'
|
*
|
* @param {String} name The name of the variable being tested
|
* @param {*} test The value to test
|
* @exception {DeveloperError} test must be typeof 'number'
|
*/
|
Check.typeOf.number = function (name, test) {
|
if (typeof test !== 'number') {
|
throw new DeveloperError(getFailedTypeErrorMessage(typeof test, 'number', name));
|
}
|
};
|
|
/**
|
* Throws if test is not typeof 'number' and less than limit
|
*
|
* @param {String} name The name of the variable being tested
|
* @param {*} test The value to test
|
* @param {Number} limit The limit value to compare against
|
* @exception {DeveloperError} test must be typeof 'number' and less than limit
|
*/
|
Check.typeOf.number.lessThan = function (name, test, limit) {
|
Check.typeOf.number(name, test);
|
if (test >= limit) {
|
throw new DeveloperError('Expected ' + name + ' to be less than ' + limit + ', actual value was ' + test);
|
}
|
};
|
|
/**
|
* Throws if test is not typeof 'number' and less than or equal to limit
|
*
|
* @param {String} name The name of the variable being tested
|
* @param {*} test The value to test
|
* @param {Number} limit The limit value to compare against
|
* @exception {DeveloperError} test must be typeof 'number' and less than or equal to limit
|
*/
|
Check.typeOf.number.lessThanOrEquals = function (name, test, limit) {
|
Check.typeOf.number(name, test);
|
if (test > limit) {
|
throw new DeveloperError('Expected ' + name + ' to be less than or equal to ' + limit + ', actual value was ' + test);
|
}
|
};
|
|
/**
|
* Throws if test is not typeof 'number' and greater than limit
|
*
|
* @param {String} name The name of the variable being tested
|
* @param {*} test The value to test
|
* @param {Number} limit The limit value to compare against
|
* @exception {DeveloperError} test must be typeof 'number' and greater than limit
|
*/
|
Check.typeOf.number.greaterThan = function (name, test, limit) {
|
Check.typeOf.number(name, test);
|
if (test <= limit) {
|
throw new DeveloperError('Expected ' + name + ' to be greater than ' + limit + ', actual value was ' + test);
|
}
|
};
|
|
/**
|
* Throws if test is not typeof 'number' and greater than or equal to limit
|
*
|
* @param {String} name The name of the variable being tested
|
* @param {*} test The value to test
|
* @param {Number} limit The limit value to compare against
|
* @exception {DeveloperError} test must be typeof 'number' and greater than or equal to limit
|
*/
|
Check.typeOf.number.greaterThanOrEquals = function (name, test, limit) {
|
Check.typeOf.number(name, test);
|
if (test < limit) {
|
throw new DeveloperError('Expected ' + name + ' to be greater than or equal to' + limit + ', actual value was ' + test);
|
}
|
};
|
|
/**
|
* Throws if test is not typeof 'object'
|
*
|
* @param {String} name The name of the variable being tested
|
* @param {*} test The value to test
|
* @exception {DeveloperError} test must be typeof 'object'
|
*/
|
Check.typeOf.object = function (name, test) {
|
if (typeof test !== 'object') {
|
throw new DeveloperError(getFailedTypeErrorMessage(typeof test, 'object', name));
|
}
|
};
|
|
/**
|
* Throws if test is not typeof 'boolean'
|
*
|
* @param {String} name The name of the variable being tested
|
* @param {*} test The value to test
|
* @exception {DeveloperError} test must be typeof 'boolean'
|
*/
|
Check.typeOf.bool = function (name, test) {
|
if (typeof test !== 'boolean') {
|
throw new DeveloperError(getFailedTypeErrorMessage(typeof test, 'boolean', name));
|
}
|
};
|
|
/**
|
* Throws if test1 and test2 is not typeof 'number' and not equal in value
|
*
|
* @param {String} name1 The name of the first variable being tested
|
* @param {String} name2 The name of the second variable being tested against
|
* @param {*} test1 The value to test
|
* @param {*} test2 The value to test against
|
* @exception {DeveloperError} test1 and test2 should be type of 'number' and be equal in value
|
*/
|
Check.typeOf.number.equals = function (name1, name2, test1, test2) {
|
Check.typeOf.number(name1, test1);
|
Check.typeOf.number(name2, test2);
|
if (test1 !== test2) {
|
throw new DeveloperError(name1 + ' must be equal to ' + name2 + ', the actual values are ' + test1 + ' and ' + test2);
|
}
|
};
|
|
module.exports= Check;
|
|
},{"./DeveloperError":131,"./defined":160}],130:[function(require,module,exports){
|
var Check=require('./Check');
|
var defaultValue=require('./defaultValue');
|
var defined=require('./defined');
|
var FeatureDetection=require('./FeatureDetection');
|
var freezeObject=require('./freezeObject');
|
var CesiumMath=require('./Math');
|
|
'use strict';
|
|
function hue2rgb(m1, m2, h) {
|
if (h < 0) {
|
h += 1;
|
}
|
if (h > 1) {
|
h -= 1;
|
}
|
if (h * 6 < 1) {
|
return m1 + (m2 - m1) * 6 * h;
|
}
|
if (h * 2 < 1) {
|
return m2;
|
}
|
if (h * 3 < 2) {
|
return m1 + (m2 - m1) * (2 / 3 - h) * 6;
|
}
|
return m1;
|
}
|
|
/**
|
* A color, specified using red, green, blue, and alpha values,
|
* which range from <code>0</code> (no intensity) to <code>1.0</code> (full intensity).
|
* @param {Number} [red=1.0] The red component.
|
* @param {Number} [green=1.0] The green component.
|
* @param {Number} [blue=1.0] The blue component.
|
* @param {Number} [alpha=1.0] The alpha component.
|
*
|
* @constructor
|
* @alias Color
|
*
|
* @see Packable
|
*/
|
function Color(red, green, blue, alpha) {
|
/**
|
* The red component.
|
* @type {Number}
|
* @default 1.0
|
*/
|
this.red = defaultValue(red, 1.0);
|
/**
|
* The green component.
|
* @type {Number}
|
* @default 1.0
|
*/
|
this.green = defaultValue(green, 1.0);
|
/**
|
* The blue component.
|
* @type {Number}
|
* @default 1.0
|
*/
|
this.blue = defaultValue(blue, 1.0);
|
/**
|
* The alpha component.
|
* @type {Number}
|
* @default 1.0
|
*/
|
this.alpha = defaultValue(alpha, 1.0);
|
}
|
|
/**
|
* Creates a Color instance from a {@link Cartesian4}. <code>x</code>, <code>y</code>, <code>z</code>,
|
* and <code>w</code> map to <code>red</code>, <code>green</code>, <code>blue</code>, and <code>alpha</code>, respectively.
|
*
|
* @param {Cartesian4} cartesian The source cartesian.
|
* @param {Color} [result] The object onto which to store the result.
|
* @returns {Color} The modified result parameter or a new Color instance if one was not provided.
|
*/
|
Color.fromCartesian4 = function(cartesian, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('cartesian', cartesian);
|
//>>includeEnd('debug');
|
|
if (!defined(result)) {
|
return new Color(cartesian.x, cartesian.y, cartesian.z, cartesian.w);
|
}
|
|
result.red = cartesian.x;
|
result.green = cartesian.y;
|
result.blue = cartesian.z;
|
result.alpha = cartesian.w;
|
return result;
|
};
|
|
/**
|
* Creates a new Color specified using red, green, blue, and alpha values
|
* that are in the range of 0 to 255, converting them internally to a range of 0.0 to 1.0.
|
*
|
* @param {Number} [red=255] The red component.
|
* @param {Number} [green=255] The green component.
|
* @param {Number} [blue=255] The blue component.
|
* @param {Number} [alpha=255] The alpha component.
|
* @param {Color} [result] The object onto which to store the result.
|
* @returns {Color} The modified result parameter or a new Color instance if one was not provided.
|
*/
|
Color.fromBytes = function(red, green, blue, alpha, result) {
|
red = Color.byteToFloat(defaultValue(red, 255.0));
|
green = Color.byteToFloat(defaultValue(green, 255.0));
|
blue = Color.byteToFloat(defaultValue(blue, 255.0));
|
alpha = Color.byteToFloat(defaultValue(alpha, 255.0));
|
|
if (!defined(result)) {
|
return new Color(red, green, blue, alpha);
|
}
|
|
result.red = red;
|
result.green = green;
|
result.blue = blue;
|
result.alpha = alpha;
|
return result;
|
};
|
|
/**
|
* Creates a new Color that has the same red, green, and blue components
|
* of the specified color, but with the specified alpha value.
|
*
|
* @param {Color} color The base color
|
* @param {Number} alpha The new alpha component.
|
* @param {Color} [result] The object onto which to store the result.
|
* @returns {Color} The modified result parameter or a new Color instance if one was not provided.
|
*
|
* @example var translucentRed = Cesium.Color.fromAlpha(Cesium.Color.RED, 0.9);
|
*/
|
Color.fromAlpha = function(color, alpha, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('color', color);
|
Check.typeOf.number('alpha', alpha);
|
//>>includeEnd('debug');
|
|
if (!defined(result)) {
|
return new Color(color.red, color.green, color.blue, alpha);
|
}
|
|
result.red = color.red;
|
result.green = color.green;
|
result.blue = color.blue;
|
result.alpha = alpha;
|
return result;
|
};
|
|
var scratchArrayBuffer;
|
var scratchUint32Array;
|
var scratchUint8Array;
|
if (FeatureDetection.supportsTypedArrays()) {
|
scratchArrayBuffer = new ArrayBuffer(4);
|
scratchUint32Array = new Uint32Array(scratchArrayBuffer);
|
scratchUint8Array = new Uint8Array(scratchArrayBuffer);
|
}
|
|
/**
|
* Creates a new Color from a single numeric unsigned 32-bit RGBA value, using the endianness
|
* of the system.
|
*
|
* @param {Number} rgba A single numeric unsigned 32-bit RGBA value.
|
* @param {Color} [result] The object to store the result in, if undefined a new instance will be created.
|
* @returns {Color} The color object.
|
*
|
* @example
|
* var color = Cesium.Color.fromRgba(0x67ADDFFF);
|
*
|
* @see Color#toRgba
|
*/
|
Color.fromRgba = function(rgba, result) {
|
// scratchUint32Array and scratchUint8Array share an underlying array buffer
|
scratchUint32Array[0] = rgba;
|
return Color.fromBytes(scratchUint8Array[0], scratchUint8Array[1], scratchUint8Array[2], scratchUint8Array[3], result);
|
};
|
|
/**
|
* Creates a Color instance from hue, saturation, and lightness.
|
*
|
* @param {Number} [hue=0] The hue angle 0...1
|
* @param {Number} [saturation=0] The saturation value 0...1
|
* @param {Number} [lightness=0] The lightness value 0...1
|
* @param {Number} [alpha=1.0] The alpha component 0...1
|
* @param {Color} [result] The object to store the result in, if undefined a new instance will be created.
|
* @returns {Color} The color object.
|
*
|
* @see {@link http://www.w3.org/TR/css3-color/#hsl-color|CSS color values}
|
*/
|
Color.fromHsl = function(hue, saturation, lightness, alpha, result) {
|
hue = defaultValue(hue, 0.0) % 1.0;
|
saturation = defaultValue(saturation, 0.0);
|
lightness = defaultValue(lightness, 0.0);
|
alpha = defaultValue(alpha, 1.0);
|
|
var red = lightness;
|
var green = lightness;
|
var blue = lightness;
|
|
if (saturation !== 0) {
|
var m2;
|
if (lightness < 0.5) {
|
m2 = lightness * (1 + saturation);
|
} else {
|
m2 = lightness + saturation - lightness * saturation;
|
}
|
|
var m1 = 2.0 * lightness - m2;
|
red = hue2rgb(m1, m2, hue + 1 / 3);
|
green = hue2rgb(m1, m2, hue);
|
blue = hue2rgb(m1, m2, hue - 1 / 3);
|
}
|
|
if (!defined(result)) {
|
return new Color(red, green, blue, alpha);
|
}
|
|
result.red = red;
|
result.green = green;
|
result.blue = blue;
|
result.alpha = alpha;
|
return result;
|
};
|
|
/**
|
* Creates a random color using the provided options. For reproducible random colors, you should
|
* call {@link CesiumMath#setRandomNumberSeed} once at the beginning of your application.
|
*
|
* @param {Object} [options] Object with the following properties:
|
* @param {Number} [options.red] If specified, the red component to use instead of a randomized value.
|
* @param {Number} [options.minimumRed=0.0] The maximum red value to generate if none was specified.
|
* @param {Number} [options.maximumRed=1.0] The minimum red value to generate if none was specified.
|
* @param {Number} [options.green] If specified, the green component to use instead of a randomized value.
|
* @param {Number} [options.minimumGreen=0.0] The maximum green value to generate if none was specified.
|
* @param {Number} [options.maximumGreen=1.0] The minimum green value to generate if none was specified.
|
* @param {Number} [options.blue] If specified, the blue component to use instead of a randomized value.
|
* @param {Number} [options.minimumBlue=0.0] The maximum blue value to generate if none was specified.
|
* @param {Number} [options.maximumBlue=1.0] The minimum blue value to generate if none was specified.
|
* @param {Number} [options.alpha] If specified, the alpha component to use instead of a randomized value.
|
* @param {Number} [options.minimumAlpha=0.0] The maximum alpha value to generate if none was specified.
|
* @param {Number} [options.maximumAlpha=1.0] The minimum alpha value to generate if none was specified.
|
* @param {Color} [result] The object to store the result in, if undefined a new instance will be created.
|
* @returns {Color} The modified result parameter or a new instance if result was undefined.
|
*
|
* @exception {DeveloperError} minimumRed must be less than or equal to maximumRed.
|
* @exception {DeveloperError} minimumGreen must be less than or equal to maximumGreen.
|
* @exception {DeveloperError} minimumBlue must be less than or equal to maximumBlue.
|
* @exception {DeveloperError} minimumAlpha must be less than or equal to maximumAlpha.
|
*
|
* @example
|
* //Create a completely random color
|
* var color = Cesium.Color.fromRandom();
|
*
|
* //Create a random shade of yellow.
|
* var color = Cesium.Color.fromRandom({
|
* red : 1.0,
|
* green : 1.0,
|
* alpha : 1.0
|
* });
|
*
|
* //Create a random bright color.
|
* var color = Cesium.Color.fromRandom({
|
* minimumRed : 0.75,
|
* minimumGreen : 0.75,
|
* minimumBlue : 0.75,
|
* alpha : 1.0
|
* });
|
*/
|
Color.fromRandom = function(options, result) {
|
options = defaultValue(options, defaultValue.EMPTY_OBJECT);
|
|
var red = options.red;
|
if (!defined(red)) {
|
var minimumRed = defaultValue(options.minimumRed, 0);
|
var maximumRed = defaultValue(options.maximumRed, 1.0);
|
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.number.lessThanOrEquals('minimumRed', minimumRed, maximumRed);
|
//>>includeEnd('debug');
|
|
red = minimumRed + (CesiumMath.nextRandomNumber() * (maximumRed - minimumRed));
|
}
|
|
var green = options.green;
|
if (!defined(green)) {
|
var minimumGreen = defaultValue(options.minimumGreen, 0);
|
var maximumGreen = defaultValue(options.maximumGreen, 1.0);
|
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.number.lessThanOrEquals('minimumGreen', minimumGreen, maximumGreen);
|
//>>includeEnd('debug');
|
green = minimumGreen + (CesiumMath.nextRandomNumber() * (maximumGreen - minimumGreen));
|
}
|
|
var blue = options.blue;
|
if (!defined(blue)) {
|
var minimumBlue = defaultValue(options.minimumBlue, 0);
|
var maximumBlue = defaultValue(options.maximumBlue, 1.0);
|
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.number.lessThanOrEquals('minimumBlue', minimumBlue, maximumBlue);
|
//>>includeEnd('debug');
|
|
blue = minimumBlue + (CesiumMath.nextRandomNumber() * (maximumBlue - minimumBlue));
|
}
|
|
var alpha = options.alpha;
|
if (!defined(alpha)) {
|
var minimumAlpha = defaultValue(options.minimumAlpha, 0);
|
var maximumAlpha = defaultValue(options.maximumAlpha, 1.0);
|
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.number.lessThanOrEquals('minumumAlpha', minimumAlpha, maximumAlpha);
|
//>>includeEnd('debug');
|
|
alpha = minimumAlpha + (CesiumMath.nextRandomNumber() * (maximumAlpha - minimumAlpha));
|
}
|
|
if (!defined(result)) {
|
return new Color(red, green, blue, alpha);
|
}
|
|
result.red = red;
|
result.green = green;
|
result.blue = blue;
|
result.alpha = alpha;
|
return result;
|
};
|
|
//#rgb
|
var rgbMatcher = /^#([0-9a-f])([0-9a-f])([0-9a-f])$/i;
|
//#rrggbb
|
var rrggbbMatcher = /^#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i;
|
//rgb(), rgba(), or rgb%()
|
var rgbParenthesesMatcher = /^rgba?\(\s*([0-9.]+%?)\s*,\s*([0-9.]+%?)\s*,\s*([0-9.]+%?)(?:\s*,\s*([0-9.]+))?\s*\)$/i;
|
//hsl(), hsla(), or hsl%()
|
var hslParenthesesMatcher = /^hsla?\(\s*([0-9.]+)\s*,\s*([0-9.]+%)\s*,\s*([0-9.]+%)(?:\s*,\s*([0-9.]+))?\s*\)$/i;
|
|
/**
|
* Creates a Color instance from a CSS color value.
|
*
|
* @param {String} color The CSS color value in #rgb, #rrggbb, rgb(), rgba(), hsl(), or hsla() format.
|
* @param {Color} [result] The object to store the result in, if undefined a new instance will be created.
|
* @returns {Color} The color object, or undefined if the string was not a valid CSS color.
|
*
|
*
|
* @example
|
* var cesiumBlue = Cesium.Color.fromCssColorString('#67ADDF');
|
* var green = Cesium.Color.fromCssColorString('green');
|
*
|
* @see {@link http://www.w3.org/TR/css3-color|CSS color values}
|
*/
|
Color.fromCssColorString = function(color, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.string('color', color);
|
//>>includeEnd('debug');
|
|
if (!defined(result)) {
|
result = new Color();
|
}
|
|
var namedColor = Color[color.toUpperCase()];
|
if (defined(namedColor)) {
|
Color.clone(namedColor, result);
|
return result;
|
}
|
|
var matches = rgbMatcher.exec(color);
|
if (matches !== null) {
|
result.red = parseInt(matches[1], 16) / 15;
|
result.green = parseInt(matches[2], 16) / 15.0;
|
result.blue = parseInt(matches[3], 16) / 15.0;
|
result.alpha = 1.0;
|
return result;
|
}
|
|
matches = rrggbbMatcher.exec(color);
|
if (matches !== null) {
|
result.red = parseInt(matches[1], 16) / 255.0;
|
result.green = parseInt(matches[2], 16) / 255.0;
|
result.blue = parseInt(matches[3], 16) / 255.0;
|
result.alpha = 1.0;
|
return result;
|
}
|
|
matches = rgbParenthesesMatcher.exec(color);
|
if (matches !== null) {
|
result.red = parseFloat(matches[1]) / ('%' === matches[1].substr(-1) ? 100.0 : 255.0);
|
result.green = parseFloat(matches[2]) / ('%' === matches[2].substr(-1) ? 100.0 : 255.0);
|
result.blue = parseFloat(matches[3]) / ('%' === matches[3].substr(-1) ? 100.0 : 255.0);
|
result.alpha = parseFloat(defaultValue(matches[4], '1.0'));
|
return result;
|
}
|
|
matches = hslParenthesesMatcher.exec(color);
|
if (matches !== null) {
|
return Color.fromHsl(parseFloat(matches[1]) / 360.0,
|
parseFloat(matches[2]) / 100.0,
|
parseFloat(matches[3]) / 100.0,
|
parseFloat(defaultValue(matches[4], '1.0')), result);
|
}
|
|
result = undefined;
|
return result;
|
};
|
|
/**
|
* The number of elements used to pack the object into an array.
|
* @type {Number}
|
*/
|
Color.packedLength = 4;
|
|
/**
|
* Stores the provided instance into the provided array.
|
*
|
* @param {Color} value The value to pack.
|
* @param {Number[]} array The array to pack into.
|
* @param {Number} [startingIndex=0] The index into the array at which to start packing the elements.
|
*
|
* @returns {Number[]} The array that was packed into
|
*/
|
Color.pack = function(value, array, startingIndex) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('value', value);
|
Check.defined('array', array);
|
//>>includeEnd('debug');
|
|
startingIndex = defaultValue(startingIndex, 0);
|
array[startingIndex++] = value.red;
|
array[startingIndex++] = value.green;
|
array[startingIndex++] = value.blue;
|
array[startingIndex] = value.alpha;
|
|
return array;
|
};
|
|
/**
|
* Retrieves an instance from a packed array.
|
*
|
* @param {Number[]} array The packed array.
|
* @param {Number} [startingIndex=0] The starting index of the element to be unpacked.
|
* @param {Color} [result] The object into which to store the result.
|
* @returns {Color} The modified result parameter or a new Color instance if one was not provided.
|
*/
|
Color.unpack = function(array, startingIndex, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.defined('array', array);
|
//>>includeEnd('debug');
|
|
startingIndex = defaultValue(startingIndex, 0);
|
if (!defined(result)) {
|
result = new Color();
|
}
|
result.red = array[startingIndex++];
|
result.green = array[startingIndex++];
|
result.blue = array[startingIndex++];
|
result.alpha = array[startingIndex];
|
return result;
|
};
|
|
/**
|
* Converts a 'byte' color component in the range of 0 to 255 into
|
* a 'float' color component in the range of 0 to 1.0.
|
*
|
* @param {Number} number The number to be converted.
|
* @returns {Number} The converted number.
|
*/
|
Color.byteToFloat = function(number) {
|
return number / 255.0;
|
};
|
|
/**
|
* Converts a 'float' color component in the range of 0 to 1.0 into
|
* a 'byte' color component in the range of 0 to 255.
|
*
|
* @param {Number} number The number to be converted.
|
* @returns {Number} The converted number.
|
*/
|
Color.floatToByte = function(number) {
|
return number === 1.0 ? 255.0 : (number * 256.0) | 0;
|
};
|
|
/**
|
* Duplicates a Color.
|
*
|
* @param {Color} color The Color to duplicate.
|
* @param {Color} [result] The object to store the result in, if undefined a new instance will be created.
|
* @returns {Color} The modified result parameter or a new instance if result was undefined. (Returns undefined if color is undefined)
|
*/
|
Color.clone = function(color, result) {
|
if (!defined(color)) {
|
return undefined;
|
}
|
if (!defined(result)) {
|
return new Color(color.red, color.green, color.blue, color.alpha);
|
}
|
result.red = color.red;
|
result.green = color.green;
|
result.blue = color.blue;
|
result.alpha = color.alpha;
|
return result;
|
};
|
|
/**
|
* Returns true if the first Color equals the second color.
|
*
|
* @param {Color} left The first Color to compare for equality.
|
* @param {Color} right The second Color to compare for equality.
|
* @returns {Boolean} <code>true</code> if the Colors are equal; otherwise, <code>false</code>.
|
*/
|
Color.equals = function(left, right) {
|
return (left === right) || //
|
(defined(left) && //
|
defined(right) && //
|
left.red === right.red && //
|
left.green === right.green && //
|
left.blue === right.blue && //
|
left.alpha === right.alpha);
|
};
|
|
/**
|
* @private
|
*/
|
Color.equalsArray = function(color, array, offset) {
|
return color.red === array[offset] &&
|
color.green === array[offset + 1] &&
|
color.blue === array[offset + 2] &&
|
color.alpha === array[offset + 3];
|
};
|
|
/**
|
* Returns a duplicate of a Color instance.
|
*
|
* @param {Color} [result] The object to store the result in, if undefined a new instance will be created.
|
* @returns {Color} The modified result parameter or a new instance if result was undefined.
|
*/
|
Color.prototype.clone = function(result) {
|
return Color.clone(this, result);
|
};
|
|
/**
|
* Returns true if this Color equals other.
|
*
|
* @param {Color} other The Color to compare for equality.
|
* @returns {Boolean} <code>true</code> if the Colors are equal; otherwise, <code>false</code>.
|
*/
|
Color.prototype.equals = function(other) {
|
return Color.equals(this, other);
|
};
|
|
/**
|
* Returns <code>true</code> if this Color equals other componentwise within the specified epsilon.
|
*
|
* @param {Color} other The Color to compare for equality.
|
* @param {Number} [epsilon=0.0] The epsilon to use for equality testing.
|
* @returns {Boolean} <code>true</code> if the Colors are equal within the specified epsilon; otherwise, <code>false</code>.
|
*/
|
Color.prototype.equalsEpsilon = function(other, epsilon) {
|
return (this === other) || //
|
((defined(other)) && //
|
(Math.abs(this.red - other.red) <= epsilon) && //
|
(Math.abs(this.green - other.green) <= epsilon) && //
|
(Math.abs(this.blue - other.blue) <= epsilon) && //
|
(Math.abs(this.alpha - other.alpha) <= epsilon));
|
};
|
|
/**
|
* Creates a string representing this Color in the format '(red, green, blue, alpha)'.
|
*
|
* @returns {String} A string representing this Color in the format '(red, green, blue, alpha)'.
|
*/
|
Color.prototype.toString = function() {
|
return '(' + this.red + ', ' + this.green + ', ' + this.blue + ', ' + this.alpha + ')';
|
};
|
|
/**
|
* Creates a string containing the CSS color value for this color.
|
*
|
* @returns {String} The CSS equivalent of this color.
|
*
|
* @see {@link http://www.w3.org/TR/css3-color/#rgba-color|CSS RGB or RGBA color values}
|
*/
|
Color.prototype.toCssColorString = function() {
|
var red = Color.floatToByte(this.red);
|
var green = Color.floatToByte(this.green);
|
var blue = Color.floatToByte(this.blue);
|
if (this.alpha === 1) {
|
return 'rgb(' + red + ',' + green + ',' + blue + ')';
|
}
|
return 'rgba(' + red + ',' + green + ',' + blue + ',' + this.alpha + ')';
|
};
|
|
/**
|
* Converts this color to an array of red, green, blue, and alpha values
|
* that are in the range of 0 to 255.
|
*
|
* @param {Number[]} [result] The array to store the result in, if undefined a new instance will be created.
|
* @returns {Number[]} The modified result parameter or a new instance if result was undefined.
|
*/
|
Color.prototype.toBytes = function(result) {
|
var red = Color.floatToByte(this.red);
|
var green = Color.floatToByte(this.green);
|
var blue = Color.floatToByte(this.blue);
|
var alpha = Color.floatToByte(this.alpha);
|
|
if (!defined(result)) {
|
return [red, green, blue, alpha];
|
}
|
result[0] = red;
|
result[1] = green;
|
result[2] = blue;
|
result[3] = alpha;
|
return result;
|
};
|
|
/**
|
* Converts this color to a single numeric unsigned 32-bit RGBA value, using the endianness
|
* of the system.
|
*
|
* @returns {Number} A single numeric unsigned 32-bit RGBA value.
|
*
|
*
|
* @example
|
* var rgba = Cesium.Color.BLUE.toRgba();
|
*
|
* @see Color.fromRgba
|
*/
|
Color.prototype.toRgba = function() {
|
// scratchUint32Array and scratchUint8Array share an underlying array buffer
|
scratchUint8Array[0] = Color.floatToByte(this.red);
|
scratchUint8Array[1] = Color.floatToByte(this.green);
|
scratchUint8Array[2] = Color.floatToByte(this.blue);
|
scratchUint8Array[3] = Color.floatToByte(this.alpha);
|
return scratchUint32Array[0];
|
};
|
|
/**
|
* Brightens this color by the provided magnitude.
|
*
|
* @param {Number} magnitude A positive number indicating the amount to brighten.
|
* @param {Color} result The object onto which to store the result.
|
* @returns {Color} The modified result parameter.
|
*
|
* @example
|
* var brightBlue = Cesium.Color.BLUE.brighten(0.5, new Cesium.Color());
|
*/
|
Color.prototype.brighten = function(magnitude, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.number('magnitude', magnitude);
|
Check.typeOf.number.greaterThanOrEquals('magnitude', magnitude, 0.0);
|
Check.typeOf.object('result', result);
|
//>>includeEnd('debug');
|
|
magnitude = (1.0 - magnitude);
|
result.red = 1.0 - ((1.0 - this.red) * magnitude);
|
result.green = 1.0 - ((1.0 - this.green) * magnitude);
|
result.blue = 1.0 - ((1.0 - this.blue) * magnitude);
|
result.alpha = this.alpha;
|
return result;
|
};
|
|
/**
|
* Darkens this color by the provided magnitude.
|
*
|
* @param {Number} magnitude A positive number indicating the amount to darken.
|
* @param {Color} result The object onto which to store the result.
|
* @returns {Color} The modified result parameter.
|
*
|
* @example
|
* var darkBlue = Cesium.Color.BLUE.darken(0.5, new Cesium.Color());
|
*/
|
Color.prototype.darken = function(magnitude, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.number('magnitude', magnitude);
|
Check.typeOf.number.greaterThanOrEquals('magnitude', magnitude, 0.0);
|
Check.typeOf.object('result', result);
|
//>>includeEnd('debug');
|
|
magnitude = (1.0 - magnitude);
|
result.red = this.red * magnitude;
|
result.green = this.green * magnitude;
|
result.blue = this.blue * magnitude;
|
result.alpha = this.alpha;
|
return result;
|
};
|
|
/**
|
* Creates a new Color that has the same red, green, and blue components
|
* as this Color, but with the specified alpha value.
|
*
|
* @param {Number} alpha The new alpha component.
|
* @param {Color} [result] The object onto which to store the result.
|
* @returns {Color} The modified result parameter or a new Color instance if one was not provided.
|
*
|
* @example var translucentRed = Cesium.Color.RED.withAlpha(0.9);
|
*/
|
Color.prototype.withAlpha = function(alpha, result) {
|
return Color.fromAlpha(this, alpha, result);
|
};
|
|
/**
|
* Computes the componentwise sum of two Colors.
|
*
|
* @param {Color} left The first Color.
|
* @param {Color} right The second Color.
|
* @param {Color} result The object onto which to store the result.
|
* @returns {Color} The modified result parameter.
|
*/
|
Color.add = function(left, right, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('left', left);
|
Check.typeOf.object('right', right);
|
Check.typeOf.object('result', result);
|
//>>includeEnd('debug');
|
|
result.red = left.red + right.red;
|
result.green = left.green + right.green;
|
result.blue = left.blue + right.blue;
|
result.alpha = left.alpha + right.alpha;
|
return result;
|
};
|
|
/**
|
* Computes the componentwise difference of two Colors.
|
*
|
* @param {Color} left The first Color.
|
* @param {Color} right The second Color.
|
* @param {Color} result The object onto which to store the result.
|
* @returns {Color} The modified result parameter.
|
*/
|
Color.subtract = function(left, right, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('left', left);
|
Check.typeOf.object('right', right);
|
Check.typeOf.object('result', result);
|
//>>includeEnd('debug');
|
|
result.red = left.red - right.red;
|
result.green = left.green - right.green;
|
result.blue = left.blue - right.blue;
|
result.alpha = left.alpha - right.alpha;
|
return result;
|
};
|
|
/**
|
* Computes the componentwise product of two Colors.
|
*
|
* @param {Color} left The first Color.
|
* @param {Color} right The second Color.
|
* @param {Color} result The object onto which to store the result.
|
* @returns {Color} The modified result parameter.
|
*/
|
Color.multiply = function(left, right, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('left', left);
|
Check.typeOf.object('right', right);
|
Check.typeOf.object('result', result);
|
//>>includeEnd('debug');
|
|
result.red = left.red * right.red;
|
result.green = left.green * right.green;
|
result.blue = left.blue * right.blue;
|
result.alpha = left.alpha * right.alpha;
|
return result;
|
};
|
|
/**
|
* Computes the componentwise quotient of two Colors.
|
*
|
* @param {Color} left The first Color.
|
* @param {Color} right The second Color.
|
* @param {Color} result The object onto which to store the result.
|
* @returns {Color} The modified result parameter.
|
*/
|
Color.divide = function(left, right, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('left', left);
|
Check.typeOf.object('right', right);
|
Check.typeOf.object('result', result);
|
//>>includeEnd('debug');
|
|
result.red = left.red / right.red;
|
result.green = left.green / right.green;
|
result.blue = left.blue / right.blue;
|
result.alpha = left.alpha / right.alpha;
|
return result;
|
};
|
|
/**
|
* Computes the componentwise modulus of two Colors.
|
*
|
* @param {Color} left The first Color.
|
* @param {Color} right The second Color.
|
* @param {Color} result The object onto which to store the result.
|
* @returns {Color} The modified result parameter.
|
*/
|
Color.mod = function(left, right, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('left', left);
|
Check.typeOf.object('right', right);
|
Check.typeOf.object('result', result);
|
//>>includeEnd('debug');
|
|
result.red = left.red % right.red;
|
result.green = left.green % right.green;
|
result.blue = left.blue % right.blue;
|
result.alpha = left.alpha % right.alpha;
|
return result;
|
};
|
|
/**
|
* Multiplies the provided Color componentwise by the provided scalar.
|
*
|
* @param {Color} color The Color to be scaled.
|
* @param {Number} scalar The scalar to multiply with.
|
* @param {Color} result The object onto which to store the result.
|
* @returns {Color} The modified result parameter.
|
*/
|
Color.multiplyByScalar = function(color, scalar, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('color', color);
|
Check.typeOf.number('scalar', scalar);
|
Check.typeOf.object('result', result);
|
//>>includeEnd('debug');
|
|
result.red = color.red * scalar;
|
result.green = color.green * scalar;
|
result.blue = color.blue * scalar;
|
result.alpha = color.alpha * scalar;
|
return result;
|
};
|
|
/**
|
* Divides the provided Color componentwise by the provided scalar.
|
*
|
* @param {Color} color The Color to be divided.
|
* @param {Number} scalar The scalar to divide with.
|
* @param {Color} result The object onto which to store the result.
|
* @returns {Color} The modified result parameter.
|
*/
|
Color.divideByScalar = function(color, scalar, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('color', color);
|
Check.typeOf.number('scalar', scalar);
|
Check.typeOf.object('result', result);
|
//>>includeEnd('debug');
|
|
result.red = color.red / scalar;
|
result.green = color.green / scalar;
|
result.blue = color.blue / scalar;
|
result.alpha = color.alpha / scalar;
|
return result;
|
};
|
|
/**
|
* An immutable Color instance initialized to CSS color #F0F8FF
|
* <span class="colorSwath" style="background: #F0F8FF;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.ALICEBLUE = freezeObject(Color.fromCssColorString('#F0F8FF'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #FAEBD7
|
* <span class="colorSwath" style="background: #FAEBD7;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.ANTIQUEWHITE = freezeObject(Color.fromCssColorString('#FAEBD7'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #00FFFF
|
* <span class="colorSwath" style="background: #00FFFF;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.AQUA = freezeObject(Color.fromCssColorString('#00FFFF'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #7FFFD4
|
* <span class="colorSwath" style="background: #7FFFD4;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.AQUAMARINE = freezeObject(Color.fromCssColorString('#7FFFD4'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #F0FFFF
|
* <span class="colorSwath" style="background: #F0FFFF;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.AZURE = freezeObject(Color.fromCssColorString('#F0FFFF'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #F5F5DC
|
* <span class="colorSwath" style="background: #F5F5DC;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.BEIGE = freezeObject(Color.fromCssColorString('#F5F5DC'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #FFE4C4
|
* <span class="colorSwath" style="background: #FFE4C4;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.BISQUE = freezeObject(Color.fromCssColorString('#FFE4C4'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #000000
|
* <span class="colorSwath" style="background: #000000;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.BLACK = freezeObject(Color.fromCssColorString('#000000'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #FFEBCD
|
* <span class="colorSwath" style="background: #FFEBCD;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.BLANCHEDALMOND = freezeObject(Color.fromCssColorString('#FFEBCD'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #0000FF
|
* <span class="colorSwath" style="background: #0000FF;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.BLUE = freezeObject(Color.fromCssColorString('#0000FF'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #8A2BE2
|
* <span class="colorSwath" style="background: #8A2BE2;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.BLUEVIOLET = freezeObject(Color.fromCssColorString('#8A2BE2'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #A52A2A
|
* <span class="colorSwath" style="background: #A52A2A;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.BROWN = freezeObject(Color.fromCssColorString('#A52A2A'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #DEB887
|
* <span class="colorSwath" style="background: #DEB887;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.BURLYWOOD = freezeObject(Color.fromCssColorString('#DEB887'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #5F9EA0
|
* <span class="colorSwath" style="background: #5F9EA0;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.CADETBLUE = freezeObject(Color.fromCssColorString('#5F9EA0'));
|
/**
|
* An immutable Color instance initialized to CSS color #7FFF00
|
* <span class="colorSwath" style="background: #7FFF00;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.CHARTREUSE = freezeObject(Color.fromCssColorString('#7FFF00'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #D2691E
|
* <span class="colorSwath" style="background: #D2691E;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.CHOCOLATE = freezeObject(Color.fromCssColorString('#D2691E'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #FF7F50
|
* <span class="colorSwath" style="background: #FF7F50;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.CORAL = freezeObject(Color.fromCssColorString('#FF7F50'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #6495ED
|
* <span class="colorSwath" style="background: #6495ED;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.CORNFLOWERBLUE = freezeObject(Color.fromCssColorString('#6495ED'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #FFF8DC
|
* <span class="colorSwath" style="background: #FFF8DC;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.CORNSILK = freezeObject(Color.fromCssColorString('#FFF8DC'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #DC143C
|
* <span class="colorSwath" style="background: #DC143C;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.CRIMSON = freezeObject(Color.fromCssColorString('#DC143C'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #00FFFF
|
* <span class="colorSwath" style="background: #00FFFF;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.CYAN = freezeObject(Color.fromCssColorString('#00FFFF'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #00008B
|
* <span class="colorSwath" style="background: #00008B;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.DARKBLUE = freezeObject(Color.fromCssColorString('#00008B'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #008B8B
|
* <span class="colorSwath" style="background: #008B8B;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.DARKCYAN = freezeObject(Color.fromCssColorString('#008B8B'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #B8860B
|
* <span class="colorSwath" style="background: #B8860B;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.DARKGOLDENROD = freezeObject(Color.fromCssColorString('#B8860B'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #A9A9A9
|
* <span class="colorSwath" style="background: #A9A9A9;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.DARKGRAY = freezeObject(Color.fromCssColorString('#A9A9A9'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #006400
|
* <span class="colorSwath" style="background: #006400;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.DARKGREEN = freezeObject(Color.fromCssColorString('#006400'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #A9A9A9
|
* <span class="colorSwath" style="background: #A9A9A9;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.DARKGREY = Color.DARKGRAY;
|
|
/**
|
* An immutable Color instance initialized to CSS color #BDB76B
|
* <span class="colorSwath" style="background: #BDB76B;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.DARKKHAKI = freezeObject(Color.fromCssColorString('#BDB76B'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #8B008B
|
* <span class="colorSwath" style="background: #8B008B;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.DARKMAGENTA = freezeObject(Color.fromCssColorString('#8B008B'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #556B2F
|
* <span class="colorSwath" style="background: #556B2F;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.DARKOLIVEGREEN = freezeObject(Color.fromCssColorString('#556B2F'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #FF8C00
|
* <span class="colorSwath" style="background: #FF8C00;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.DARKORANGE = freezeObject(Color.fromCssColorString('#FF8C00'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #9932CC
|
* <span class="colorSwath" style="background: #9932CC;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.DARKORCHID = freezeObject(Color.fromCssColorString('#9932CC'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #8B0000
|
* <span class="colorSwath" style="background: #8B0000;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.DARKRED = freezeObject(Color.fromCssColorString('#8B0000'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #E9967A
|
* <span class="colorSwath" style="background: #E9967A;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.DARKSALMON = freezeObject(Color.fromCssColorString('#E9967A'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #8FBC8F
|
* <span class="colorSwath" style="background: #8FBC8F;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.DARKSEAGREEN = freezeObject(Color.fromCssColorString('#8FBC8F'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #483D8B
|
* <span class="colorSwath" style="background: #483D8B;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.DARKSLATEBLUE = freezeObject(Color.fromCssColorString('#483D8B'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #2F4F4F
|
* <span class="colorSwath" style="background: #2F4F4F;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.DARKSLATEGRAY = freezeObject(Color.fromCssColorString('#2F4F4F'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #2F4F4F
|
* <span class="colorSwath" style="background: #2F4F4F;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.DARKSLATEGREY = Color.DARKSLATEGRAY;
|
|
/**
|
* An immutable Color instance initialized to CSS color #00CED1
|
* <span class="colorSwath" style="background: #00CED1;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.DARKTURQUOISE = freezeObject(Color.fromCssColorString('#00CED1'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #9400D3
|
* <span class="colorSwath" style="background: #9400D3;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.DARKVIOLET = freezeObject(Color.fromCssColorString('#9400D3'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #FF1493
|
* <span class="colorSwath" style="background: #FF1493;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.DEEPPINK = freezeObject(Color.fromCssColorString('#FF1493'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #00BFFF
|
* <span class="colorSwath" style="background: #00BFFF;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.DEEPSKYBLUE = freezeObject(Color.fromCssColorString('#00BFFF'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #696969
|
* <span class="colorSwath" style="background: #696969;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.DIMGRAY = freezeObject(Color.fromCssColorString('#696969'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #696969
|
* <span class="colorSwath" style="background: #696969;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.DIMGREY = Color.DIMGRAY;
|
|
/**
|
* An immutable Color instance initialized to CSS color #1E90FF
|
* <span class="colorSwath" style="background: #1E90FF;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.DODGERBLUE = freezeObject(Color.fromCssColorString('#1E90FF'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #B22222
|
* <span class="colorSwath" style="background: #B22222;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.FIREBRICK = freezeObject(Color.fromCssColorString('#B22222'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #FFFAF0
|
* <span class="colorSwath" style="background: #FFFAF0;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.FLORALWHITE = freezeObject(Color.fromCssColorString('#FFFAF0'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #228B22
|
* <span class="colorSwath" style="background: #228B22;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.FORESTGREEN = freezeObject(Color.fromCssColorString('#228B22'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #FF00FF
|
* <span class="colorSwath" style="background: #FF00FF;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.FUCHSIA = freezeObject(Color.fromCssColorString('#FF00FF'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #DCDCDC
|
* <span class="colorSwath" style="background: #DCDCDC;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.GAINSBORO = freezeObject(Color.fromCssColorString('#DCDCDC'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #F8F8FF
|
* <span class="colorSwath" style="background: #F8F8FF;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.GHOSTWHITE = freezeObject(Color.fromCssColorString('#F8F8FF'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #FFD700
|
* <span class="colorSwath" style="background: #FFD700;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.GOLD = freezeObject(Color.fromCssColorString('#FFD700'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #DAA520
|
* <span class="colorSwath" style="background: #DAA520;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.GOLDENROD = freezeObject(Color.fromCssColorString('#DAA520'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #808080
|
* <span class="colorSwath" style="background: #808080;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.GRAY = freezeObject(Color.fromCssColorString('#808080'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #008000
|
* <span class="colorSwath" style="background: #008000;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.GREEN = freezeObject(Color.fromCssColorString('#008000'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #ADFF2F
|
* <span class="colorSwath" style="background: #ADFF2F;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.GREENYELLOW = freezeObject(Color.fromCssColorString('#ADFF2F'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #808080
|
* <span class="colorSwath" style="background: #808080;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.GREY = Color.GRAY;
|
|
/**
|
* An immutable Color instance initialized to CSS color #F0FFF0
|
* <span class="colorSwath" style="background: #F0FFF0;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.HONEYDEW = freezeObject(Color.fromCssColorString('#F0FFF0'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #FF69B4
|
* <span class="colorSwath" style="background: #FF69B4;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.HOTPINK = freezeObject(Color.fromCssColorString('#FF69B4'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #CD5C5C
|
* <span class="colorSwath" style="background: #CD5C5C;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.INDIANRED = freezeObject(Color.fromCssColorString('#CD5C5C'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #4B0082
|
* <span class="colorSwath" style="background: #4B0082;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.INDIGO = freezeObject(Color.fromCssColorString('#4B0082'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #FFFFF0
|
* <span class="colorSwath" style="background: #FFFFF0;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.IVORY = freezeObject(Color.fromCssColorString('#FFFFF0'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #F0E68C
|
* <span class="colorSwath" style="background: #F0E68C;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.KHAKI = freezeObject(Color.fromCssColorString('#F0E68C'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #E6E6FA
|
* <span class="colorSwath" style="background: #E6E6FA;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.LAVENDER = freezeObject(Color.fromCssColorString('#E6E6FA'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #FFF0F5
|
* <span class="colorSwath" style="background: #FFF0F5;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.LAVENDAR_BLUSH = freezeObject(Color.fromCssColorString('#FFF0F5'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #7CFC00
|
* <span class="colorSwath" style="background: #7CFC00;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.LAWNGREEN = freezeObject(Color.fromCssColorString('#7CFC00'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #FFFACD
|
* <span class="colorSwath" style="background: #FFFACD;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.LEMONCHIFFON = freezeObject(Color.fromCssColorString('#FFFACD'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #ADD8E6
|
* <span class="colorSwath" style="background: #ADD8E6;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.LIGHTBLUE = freezeObject(Color.fromCssColorString('#ADD8E6'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #F08080
|
* <span class="colorSwath" style="background: #F08080;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.LIGHTCORAL = freezeObject(Color.fromCssColorString('#F08080'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #E0FFFF
|
* <span class="colorSwath" style="background: #E0FFFF;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.LIGHTCYAN = freezeObject(Color.fromCssColorString('#E0FFFF'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #FAFAD2
|
* <span class="colorSwath" style="background: #FAFAD2;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.LIGHTGOLDENRODYELLOW = freezeObject(Color.fromCssColorString('#FAFAD2'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #D3D3D3
|
* <span class="colorSwath" style="background: #D3D3D3;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.LIGHTGRAY = freezeObject(Color.fromCssColorString('#D3D3D3'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #90EE90
|
* <span class="colorSwath" style="background: #90EE90;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.LIGHTGREEN = freezeObject(Color.fromCssColorString('#90EE90'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #D3D3D3
|
* <span class="colorSwath" style="background: #D3D3D3;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.LIGHTGREY = Color.LIGHTGRAY;
|
|
/**
|
* An immutable Color instance initialized to CSS color #FFB6C1
|
* <span class="colorSwath" style="background: #FFB6C1;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.LIGHTPINK = freezeObject(Color.fromCssColorString('#FFB6C1'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #20B2AA
|
* <span class="colorSwath" style="background: #20B2AA;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.LIGHTSEAGREEN = freezeObject(Color.fromCssColorString('#20B2AA'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #87CEFA
|
* <span class="colorSwath" style="background: #87CEFA;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.LIGHTSKYBLUE = freezeObject(Color.fromCssColorString('#87CEFA'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #778899
|
* <span class="colorSwath" style="background: #778899;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.LIGHTSLATEGRAY = freezeObject(Color.fromCssColorString('#778899'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #778899
|
* <span class="colorSwath" style="background: #778899;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.LIGHTSLATEGREY = Color.LIGHTSLATEGRAY;
|
|
/**
|
* An immutable Color instance initialized to CSS color #B0C4DE
|
* <span class="colorSwath" style="background: #B0C4DE;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.LIGHTSTEELBLUE = freezeObject(Color.fromCssColorString('#B0C4DE'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #FFFFE0
|
* <span class="colorSwath" style="background: #FFFFE0;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.LIGHTYELLOW = freezeObject(Color.fromCssColorString('#FFFFE0'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #00FF00
|
* <span class="colorSwath" style="background: #00FF00;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.LIME = freezeObject(Color.fromCssColorString('#00FF00'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #32CD32
|
* <span class="colorSwath" style="background: #32CD32;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.LIMEGREEN = freezeObject(Color.fromCssColorString('#32CD32'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #FAF0E6
|
* <span class="colorSwath" style="background: #FAF0E6;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.LINEN = freezeObject(Color.fromCssColorString('#FAF0E6'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #FF00FF
|
* <span class="colorSwath" style="background: #FF00FF;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.MAGENTA = freezeObject(Color.fromCssColorString('#FF00FF'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #800000
|
* <span class="colorSwath" style="background: #800000;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.MAROON = freezeObject(Color.fromCssColorString('#800000'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #66CDAA
|
* <span class="colorSwath" style="background: #66CDAA;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.MEDIUMAQUAMARINE = freezeObject(Color.fromCssColorString('#66CDAA'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #0000CD
|
* <span class="colorSwath" style="background: #0000CD;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.MEDIUMBLUE = freezeObject(Color.fromCssColorString('#0000CD'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #BA55D3
|
* <span class="colorSwath" style="background: #BA55D3;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.MEDIUMORCHID = freezeObject(Color.fromCssColorString('#BA55D3'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #9370DB
|
* <span class="colorSwath" style="background: #9370DB;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.MEDIUMPURPLE = freezeObject(Color.fromCssColorString('#9370DB'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #3CB371
|
* <span class="colorSwath" style="background: #3CB371;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.MEDIUMSEAGREEN = freezeObject(Color.fromCssColorString('#3CB371'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #7B68EE
|
* <span class="colorSwath" style="background: #7B68EE;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.MEDIUMSLATEBLUE = freezeObject(Color.fromCssColorString('#7B68EE'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #00FA9A
|
* <span class="colorSwath" style="background: #00FA9A;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.MEDIUMSPRINGGREEN = freezeObject(Color.fromCssColorString('#00FA9A'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #48D1CC
|
* <span class="colorSwath" style="background: #48D1CC;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.MEDIUMTURQUOISE = freezeObject(Color.fromCssColorString('#48D1CC'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #C71585
|
* <span class="colorSwath" style="background: #C71585;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.MEDIUMVIOLETRED = freezeObject(Color.fromCssColorString('#C71585'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #191970
|
* <span class="colorSwath" style="background: #191970;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.MIDNIGHTBLUE = freezeObject(Color.fromCssColorString('#191970'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #F5FFFA
|
* <span class="colorSwath" style="background: #F5FFFA;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.MINTCREAM = freezeObject(Color.fromCssColorString('#F5FFFA'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #FFE4E1
|
* <span class="colorSwath" style="background: #FFE4E1;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.MISTYROSE = freezeObject(Color.fromCssColorString('#FFE4E1'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #FFE4B5
|
* <span class="colorSwath" style="background: #FFE4B5;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.MOCCASIN = freezeObject(Color.fromCssColorString('#FFE4B5'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #FFDEAD
|
* <span class="colorSwath" style="background: #FFDEAD;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.NAVAJOWHITE = freezeObject(Color.fromCssColorString('#FFDEAD'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #000080
|
* <span class="colorSwath" style="background: #000080;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.NAVY = freezeObject(Color.fromCssColorString('#000080'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #FDF5E6
|
* <span class="colorSwath" style="background: #FDF5E6;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.OLDLACE = freezeObject(Color.fromCssColorString('#FDF5E6'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #808000
|
* <span class="colorSwath" style="background: #808000;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.OLIVE = freezeObject(Color.fromCssColorString('#808000'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #6B8E23
|
* <span class="colorSwath" style="background: #6B8E23;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.OLIVEDRAB = freezeObject(Color.fromCssColorString('#6B8E23'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #FFA500
|
* <span class="colorSwath" style="background: #FFA500;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.ORANGE = freezeObject(Color.fromCssColorString('#FFA500'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #FF4500
|
* <span class="colorSwath" style="background: #FF4500;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.ORANGERED = freezeObject(Color.fromCssColorString('#FF4500'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #DA70D6
|
* <span class="colorSwath" style="background: #DA70D6;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.ORCHID = freezeObject(Color.fromCssColorString('#DA70D6'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #EEE8AA
|
* <span class="colorSwath" style="background: #EEE8AA;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.PALEGOLDENROD = freezeObject(Color.fromCssColorString('#EEE8AA'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #98FB98
|
* <span class="colorSwath" style="background: #98FB98;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.PALEGREEN = freezeObject(Color.fromCssColorString('#98FB98'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #AFEEEE
|
* <span class="colorSwath" style="background: #AFEEEE;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.PALETURQUOISE = freezeObject(Color.fromCssColorString('#AFEEEE'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #DB7093
|
* <span class="colorSwath" style="background: #DB7093;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.PALEVIOLETRED = freezeObject(Color.fromCssColorString('#DB7093'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #FFEFD5
|
* <span class="colorSwath" style="background: #FFEFD5;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.PAPAYAWHIP = freezeObject(Color.fromCssColorString('#FFEFD5'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #FFDAB9
|
* <span class="colorSwath" style="background: #FFDAB9;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.PEACHPUFF = freezeObject(Color.fromCssColorString('#FFDAB9'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #CD853F
|
* <span class="colorSwath" style="background: #CD853F;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.PERU = freezeObject(Color.fromCssColorString('#CD853F'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #FFC0CB
|
* <span class="colorSwath" style="background: #FFC0CB;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.PINK = freezeObject(Color.fromCssColorString('#FFC0CB'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #DDA0DD
|
* <span class="colorSwath" style="background: #DDA0DD;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.PLUM = freezeObject(Color.fromCssColorString('#DDA0DD'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #B0E0E6
|
* <span class="colorSwath" style="background: #B0E0E6;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.POWDERBLUE = freezeObject(Color.fromCssColorString('#B0E0E6'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #800080
|
* <span class="colorSwath" style="background: #800080;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.PURPLE = freezeObject(Color.fromCssColorString('#800080'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #FF0000
|
* <span class="colorSwath" style="background: #FF0000;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.RED = freezeObject(Color.fromCssColorString('#FF0000'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #BC8F8F
|
* <span class="colorSwath" style="background: #BC8F8F;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.ROSYBROWN = freezeObject(Color.fromCssColorString('#BC8F8F'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #4169E1
|
* <span class="colorSwath" style="background: #4169E1;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.ROYALBLUE = freezeObject(Color.fromCssColorString('#4169E1'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #8B4513
|
* <span class="colorSwath" style="background: #8B4513;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.SADDLEBROWN = freezeObject(Color.fromCssColorString('#8B4513'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #FA8072
|
* <span class="colorSwath" style="background: #FA8072;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.SALMON = freezeObject(Color.fromCssColorString('#FA8072'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #F4A460
|
* <span class="colorSwath" style="background: #F4A460;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.SANDYBROWN = freezeObject(Color.fromCssColorString('#F4A460'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #2E8B57
|
* <span class="colorSwath" style="background: #2E8B57;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.SEAGREEN = freezeObject(Color.fromCssColorString('#2E8B57'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #FFF5EE
|
* <span class="colorSwath" style="background: #FFF5EE;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.SEASHELL = freezeObject(Color.fromCssColorString('#FFF5EE'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #A0522D
|
* <span class="colorSwath" style="background: #A0522D;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.SIENNA = freezeObject(Color.fromCssColorString('#A0522D'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #C0C0C0
|
* <span class="colorSwath" style="background: #C0C0C0;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.SILVER = freezeObject(Color.fromCssColorString('#C0C0C0'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #87CEEB
|
* <span class="colorSwath" style="background: #87CEEB;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.SKYBLUE = freezeObject(Color.fromCssColorString('#87CEEB'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #6A5ACD
|
* <span class="colorSwath" style="background: #6A5ACD;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.SLATEBLUE = freezeObject(Color.fromCssColorString('#6A5ACD'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #708090
|
* <span class="colorSwath" style="background: #708090;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.SLATEGRAY = freezeObject(Color.fromCssColorString('#708090'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #708090
|
* <span class="colorSwath" style="background: #708090;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.SLATEGREY = Color.SLATEGRAY;
|
|
/**
|
* An immutable Color instance initialized to CSS color #FFFAFA
|
* <span class="colorSwath" style="background: #FFFAFA;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.SNOW = freezeObject(Color.fromCssColorString('#FFFAFA'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #00FF7F
|
* <span class="colorSwath" style="background: #00FF7F;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.SPRINGGREEN = freezeObject(Color.fromCssColorString('#00FF7F'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #4682B4
|
* <span class="colorSwath" style="background: #4682B4;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.STEELBLUE = freezeObject(Color.fromCssColorString('#4682B4'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #D2B48C
|
* <span class="colorSwath" style="background: #D2B48C;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.TAN = freezeObject(Color.fromCssColorString('#D2B48C'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #008080
|
* <span class="colorSwath" style="background: #008080;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.TEAL = freezeObject(Color.fromCssColorString('#008080'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #D8BFD8
|
* <span class="colorSwath" style="background: #D8BFD8;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.THISTLE = freezeObject(Color.fromCssColorString('#D8BFD8'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #FF6347
|
* <span class="colorSwath" style="background: #FF6347;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.TOMATO = freezeObject(Color.fromCssColorString('#FF6347'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #40E0D0
|
* <span class="colorSwath" style="background: #40E0D0;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.TURQUOISE = freezeObject(Color.fromCssColorString('#40E0D0'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #EE82EE
|
* <span class="colorSwath" style="background: #EE82EE;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.VIOLET = freezeObject(Color.fromCssColorString('#EE82EE'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #F5DEB3
|
* <span class="colorSwath" style="background: #F5DEB3;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.WHEAT = freezeObject(Color.fromCssColorString('#F5DEB3'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #FFFFFF
|
* <span class="colorSwath" style="background: #FFFFFF;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.WHITE = freezeObject(Color.fromCssColorString('#FFFFFF'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #F5F5F5
|
* <span class="colorSwath" style="background: #F5F5F5;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.WHITESMOKE = freezeObject(Color.fromCssColorString('#F5F5F5'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #FFFF00
|
* <span class="colorSwath" style="background: #FFFF00;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.YELLOW = freezeObject(Color.fromCssColorString('#FFFF00'));
|
|
/**
|
* An immutable Color instance initialized to CSS color #9ACD32
|
* <span class="colorSwath" style="background: #9ACD32;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.YELLOWGREEN = freezeObject(Color.fromCssColorString('#9ACD32'));
|
|
/**
|
* An immutable Color instance initialized to CSS transparent.
|
* <span class="colorSwath" style="background: transparent;"></span>
|
*
|
* @constant
|
* @type {Color}
|
*/
|
Color.TRANSPARENT = freezeObject(new Color(0, 0, 0, 0));
|
|
module.exports= Color;
|
|
},{"./Check":129,"./FeatureDetection":134,"./Math":139,"./defaultValue":158,"./defined":160,"./freezeObject":163}],131:[function(require,module,exports){
|
var defined=require('./defined');
|
|
'use strict';
|
|
/**
|
* Constructs an exception object that is thrown due to a developer error, e.g., invalid argument,
|
* argument out of range, etc. This exception should only be thrown during development;
|
* it usually indicates a bug in the calling code. This exception should never be
|
* caught; instead the calling code should strive not to generate it.
|
* <br /><br />
|
* On the other hand, a {@link RuntimeError} indicates an exception that may
|
* be thrown at runtime, e.g., out of memory, that the calling code should be prepared
|
* to catch.
|
*
|
* @alias DeveloperError
|
* @constructor
|
* @extends Error
|
*
|
* @param {String} [message] The error message for this exception.
|
*
|
* @see RuntimeError
|
*/
|
function DeveloperError(message) {
|
/**
|
* 'DeveloperError' indicating that this exception was thrown due to a developer error.
|
* @type {String}
|
* @readonly
|
*/
|
this.name = 'DeveloperError';
|
|
/**
|
* The explanation for why this exception was thrown.
|
* @type {String}
|
* @readonly
|
*/
|
this.message = message;
|
|
//Browsers such as IE don't have a stack property until you actually throw the error.
|
var stack;
|
try {
|
throw new Error();
|
} catch (e) {
|
stack = e.stack;
|
}
|
|
/**
|
* The stack trace of this exception, if available.
|
* @type {String}
|
* @readonly
|
*/
|
this.stack = stack;
|
}
|
|
if (defined(Object.create)) {
|
DeveloperError.prototype = Object.create(Error.prototype);
|
DeveloperError.prototype.constructor = DeveloperError;
|
}
|
|
DeveloperError.prototype.toString = function() {
|
var str = this.name + ': ' + this.message;
|
|
if (defined(this.stack)) {
|
str += '\n' + this.stack.toString();
|
}
|
|
return str;
|
};
|
|
/**
|
* @private
|
*/
|
DeveloperError.throwInstantiationError = function() {
|
throw new DeveloperError('This function defines an interface and should not be called directly.');
|
};
|
|
module.exports= DeveloperError;
|
|
},{"./defined":160}],132:[function(require,module,exports){
|
var Cartesian3=require('./Cartesian3');
|
var Cartographic=require('./Cartographic');
|
var Check=require('./Check');
|
var defaultValue=require('./defaultValue');
|
var defined=require('./defined');
|
var defineProperties=require('./defineProperties');
|
var DeveloperError=require('./DeveloperError');
|
var freezeObject=require('./freezeObject');
|
var CesiumMath=require('./Math');
|
var scaleToGeodeticSurface=require('./scaleToGeodeticSurface');
|
|
'use strict';
|
|
function initialize(ellipsoid, x, y, z) {
|
x = defaultValue(x, 0.0);
|
y = defaultValue(y, 0.0);
|
z = defaultValue(z, 0.0);
|
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.number.greaterThanOrEquals('x', x, 0.0);
|
Check.typeOf.number.greaterThanOrEquals('y', y, 0.0);
|
Check.typeOf.number.greaterThanOrEquals('z', z, 0.0);
|
//>>includeEnd('debug');
|
|
ellipsoid._radii = new Cartesian3(x, y, z);
|
|
ellipsoid._radiiSquared = new Cartesian3(x * x,
|
y * y,
|
z * z);
|
|
ellipsoid._radiiToTheFourth = new Cartesian3(x * x * x * x,
|
y * y * y * y,
|
z * z * z * z);
|
|
ellipsoid._oneOverRadii = new Cartesian3(x === 0.0 ? 0.0 : 1.0 / x,
|
y === 0.0 ? 0.0 : 1.0 / y,
|
z === 0.0 ? 0.0 : 1.0 / z);
|
|
ellipsoid._oneOverRadiiSquared = new Cartesian3(x === 0.0 ? 0.0 : 1.0 / (x * x),
|
y === 0.0 ? 0.0 : 1.0 / (y * y),
|
z === 0.0 ? 0.0 : 1.0 / (z * z));
|
|
ellipsoid._minimumRadius = Math.min(x, y, z);
|
|
ellipsoid._maximumRadius = Math.max(x, y, z);
|
|
ellipsoid._centerToleranceSquared = CesiumMath.EPSILON1;
|
|
if (ellipsoid._radiiSquared.z !== 0) {
|
ellipsoid._squaredXOverSquaredZ = ellipsoid._radiiSquared.x / ellipsoid._radiiSquared.z;
|
}
|
}
|
|
/**
|
* A quadratic surface defined in Cartesian coordinates by the equation
|
* <code>(x / a)^2 + (y / b)^2 + (z / c)^2 = 1</code>. Primarily used
|
* by Cesium to represent the shape of planetary bodies.
|
*
|
* Rather than constructing this object directly, one of the provided
|
* constants is normally used.
|
* @alias Ellipsoid
|
* @constructor
|
*
|
* @param {Number} [x=0] The radius in the x direction.
|
* @param {Number} [y=0] The radius in the y direction.
|
* @param {Number} [z=0] The radius in the z direction.
|
*
|
* @exception {DeveloperError} All radii components must be greater than or equal to zero.
|
*
|
* @see Ellipsoid.fromCartesian3
|
* @see Ellipsoid.WGS84
|
* @see Ellipsoid.UNIT_SPHERE
|
*/
|
function Ellipsoid(x, y, z) {
|
this._radii = undefined;
|
this._radiiSquared = undefined;
|
this._radiiToTheFourth = undefined;
|
this._oneOverRadii = undefined;
|
this._oneOverRadiiSquared = undefined;
|
this._minimumRadius = undefined;
|
this._maximumRadius = undefined;
|
this._centerToleranceSquared = undefined;
|
this._squaredXOverSquaredZ = undefined;
|
|
initialize(this, x, y, z);
|
}
|
|
defineProperties(Ellipsoid.prototype, {
|
/**
|
* Gets the radii of the ellipsoid.
|
* @memberof Ellipsoid.prototype
|
* @type {Cartesian3}
|
* @readonly
|
*/
|
radii : {
|
get: function() {
|
return this._radii;
|
}
|
},
|
/**
|
* Gets the squared radii of the ellipsoid.
|
* @memberof Ellipsoid.prototype
|
* @type {Cartesian3}
|
* @readonly
|
*/
|
radiiSquared : {
|
get : function() {
|
return this._radiiSquared;
|
}
|
},
|
/**
|
* Gets the radii of the ellipsoid raise to the fourth power.
|
* @memberof Ellipsoid.prototype
|
* @type {Cartesian3}
|
* @readonly
|
*/
|
radiiToTheFourth : {
|
get : function() {
|
return this._radiiToTheFourth;
|
}
|
},
|
/**
|
* Gets one over the radii of the ellipsoid.
|
* @memberof Ellipsoid.prototype
|
* @type {Cartesian3}
|
* @readonly
|
*/
|
oneOverRadii : {
|
get : function() {
|
return this._oneOverRadii;
|
}
|
},
|
/**
|
* Gets one over the squared radii of the ellipsoid.
|
* @memberof Ellipsoid.prototype
|
* @type {Cartesian3}
|
* @readonly
|
*/
|
oneOverRadiiSquared : {
|
get : function() {
|
return this._oneOverRadiiSquared;
|
}
|
},
|
/**
|
* Gets the minimum radius of the ellipsoid.
|
* @memberof Ellipsoid.prototype
|
* @type {Number}
|
* @readonly
|
*/
|
minimumRadius : {
|
get : function() {
|
return this._minimumRadius;
|
}
|
},
|
/**
|
* Gets the maximum radius of the ellipsoid.
|
* @memberof Ellipsoid.prototype
|
* @type {Number}
|
* @readonly
|
*/
|
maximumRadius : {
|
get : function() {
|
return this._maximumRadius;
|
}
|
}
|
});
|
|
/**
|
* Duplicates an Ellipsoid instance.
|
*
|
* @param {Ellipsoid} ellipsoid The ellipsoid to duplicate.
|
* @param {Ellipsoid} [result] The object onto which to store the result, or undefined if a new
|
* instance should be created.
|
* @returns {Ellipsoid} The cloned Ellipsoid. (Returns undefined if ellipsoid is undefined)
|
*/
|
Ellipsoid.clone = function(ellipsoid, result) {
|
if (!defined(ellipsoid)) {
|
return undefined;
|
}
|
var radii = ellipsoid._radii;
|
|
if (!defined(result)) {
|
return new Ellipsoid(radii.x, radii.y, radii.z);
|
}
|
|
Cartesian3.clone(radii, result._radii);
|
Cartesian3.clone(ellipsoid._radiiSquared, result._radiiSquared);
|
Cartesian3.clone(ellipsoid._radiiToTheFourth, result._radiiToTheFourth);
|
Cartesian3.clone(ellipsoid._oneOverRadii, result._oneOverRadii);
|
Cartesian3.clone(ellipsoid._oneOverRadiiSquared, result._oneOverRadiiSquared);
|
result._minimumRadius = ellipsoid._minimumRadius;
|
result._maximumRadius = ellipsoid._maximumRadius;
|
result._centerToleranceSquared = ellipsoid._centerToleranceSquared;
|
|
return result;
|
};
|
|
/**
|
* Computes an Ellipsoid from a Cartesian specifying the radii in x, y, and z directions.
|
*
|
* @param {Cartesian3} [cartesian=Cartesian3.ZERO] The ellipsoid's radius in the x, y, and z directions.
|
* @param {Ellipsoid} [result] The object onto which to store the result, or undefined if a new
|
* instance should be created.
|
* @returns {Ellipsoid} A new Ellipsoid instance.
|
*
|
* @exception {DeveloperError} All radii components must be greater than or equal to zero.
|
*
|
* @see Ellipsoid.WGS84
|
* @see Ellipsoid.UNIT_SPHERE
|
*/
|
Ellipsoid.fromCartesian3 = function(cartesian, result) {
|
if (!defined(result)) {
|
result = new Ellipsoid();
|
}
|
|
if (!defined(cartesian)) {
|
return result;
|
}
|
|
initialize(result, cartesian.x, cartesian.y, cartesian.z);
|
return result;
|
};
|
|
/**
|
* An Ellipsoid instance initialized to the WGS84 standard.
|
*
|
* @type {Ellipsoid}
|
* @constant
|
*/
|
Ellipsoid.WGS84 = freezeObject(new Ellipsoid(6378137.0, 6378137.0, 6356752.3142451793));
|
|
/**
|
* An Ellipsoid instance initialized to radii of (1.0, 1.0, 1.0).
|
*
|
* @type {Ellipsoid}
|
* @constant
|
*/
|
Ellipsoid.UNIT_SPHERE = freezeObject(new Ellipsoid(1.0, 1.0, 1.0));
|
|
/**
|
* An Ellipsoid instance initialized to a sphere with the lunar radius.
|
*
|
* @type {Ellipsoid}
|
* @constant
|
*/
|
Ellipsoid.MOON = freezeObject(new Ellipsoid(CesiumMath.LUNAR_RADIUS, CesiumMath.LUNAR_RADIUS, CesiumMath.LUNAR_RADIUS));
|
|
/**
|
* Duplicates an Ellipsoid instance.
|
*
|
* @param {Ellipsoid} [result] The object onto which to store the result, or undefined if a new
|
* instance should be created.
|
* @returns {Ellipsoid} The cloned Ellipsoid.
|
*/
|
Ellipsoid.prototype.clone = function(result) {
|
return Ellipsoid.clone(this, result);
|
};
|
|
/**
|
* The number of elements used to pack the object into an array.
|
* @type {Number}
|
*/
|
Ellipsoid.packedLength = Cartesian3.packedLength;
|
|
/**
|
* Stores the provided instance into the provided array.
|
*
|
* @param {Ellipsoid} value The value to pack.
|
* @param {Number[]} array The array to pack into.
|
* @param {Number} [startingIndex=0] The index into the array at which to start packing the elements.
|
*
|
* @returns {Number[]} The array that was packed into
|
*/
|
Ellipsoid.pack = function(value, array, startingIndex) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('value', value);
|
Check.defined('array', array);
|
//>>includeEnd('debug');
|
|
startingIndex = defaultValue(startingIndex, 0);
|
|
Cartesian3.pack(value._radii, array, startingIndex);
|
|
return array;
|
};
|
|
/**
|
* Retrieves an instance from a packed array.
|
*
|
* @param {Number[]} array The packed array.
|
* @param {Number} [startingIndex=0] The starting index of the element to be unpacked.
|
* @param {Ellipsoid} [result] The object into which to store the result.
|
* @returns {Ellipsoid} The modified result parameter or a new Ellipsoid instance if one was not provided.
|
*/
|
Ellipsoid.unpack = function(array, startingIndex, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.defined('array', array);
|
//>>includeEnd('debug');
|
|
startingIndex = defaultValue(startingIndex, 0);
|
|
var radii = Cartesian3.unpack(array, startingIndex);
|
return Ellipsoid.fromCartesian3(radii, result);
|
};
|
|
/**
|
* Computes the unit vector directed from the center of this ellipsoid toward the provided Cartesian position.
|
* @function
|
*
|
* @param {Cartesian3} cartesian The Cartesian for which to to determine the geocentric normal.
|
* @param {Cartesian3} [result] The object onto which to store the result.
|
* @returns {Cartesian3} The modified result parameter or a new Cartesian3 instance if none was provided.
|
*/
|
Ellipsoid.prototype.geocentricSurfaceNormal = Cartesian3.normalize;
|
|
/**
|
* Computes the normal of the plane tangent to the surface of the ellipsoid at the provided position.
|
*
|
* @param {Cartographic} cartographic The cartographic position for which to to determine the geodetic normal.
|
* @param {Cartesian3} [result] The object onto which to store the result.
|
* @returns {Cartesian3} The modified result parameter or a new Cartesian3 instance if none was provided.
|
*/
|
Ellipsoid.prototype.geodeticSurfaceNormalCartographic = function(cartographic, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('cartographic', cartographic);
|
//>>includeEnd('debug');
|
|
var longitude = cartographic.longitude;
|
var latitude = cartographic.latitude;
|
var cosLatitude = Math.cos(latitude);
|
|
var x = cosLatitude * Math.cos(longitude);
|
var y = cosLatitude * Math.sin(longitude);
|
var z = Math.sin(latitude);
|
|
if (!defined(result)) {
|
result = new Cartesian3();
|
}
|
result.x = x;
|
result.y = y;
|
result.z = z;
|
return Cartesian3.normalize(result, result);
|
};
|
|
/**
|
* Computes the normal of the plane tangent to the surface of the ellipsoid at the provided position.
|
*
|
* @param {Cartesian3} cartesian The Cartesian position for which to to determine the surface normal.
|
* @param {Cartesian3} [result] The object onto which to store the result.
|
* @returns {Cartesian3} The modified result parameter or a new Cartesian3 instance if none was provided.
|
*/
|
Ellipsoid.prototype.geodeticSurfaceNormal = function(cartesian, result) {
|
if (!defined(result)) {
|
result = new Cartesian3();
|
}
|
result = Cartesian3.multiplyComponents(cartesian, this._oneOverRadiiSquared, result);
|
return Cartesian3.normalize(result, result);
|
};
|
|
var cartographicToCartesianNormal = new Cartesian3();
|
var cartographicToCartesianK = new Cartesian3();
|
|
/**
|
* Converts the provided cartographic to Cartesian representation.
|
*
|
* @param {Cartographic} cartographic The cartographic position.
|
* @param {Cartesian3} [result] The object onto which to store the result.
|
* @returns {Cartesian3} The modified result parameter or a new Cartesian3 instance if none was provided.
|
*
|
* @example
|
* //Create a Cartographic and determine it's Cartesian representation on a WGS84 ellipsoid.
|
* var position = new Cesium.Cartographic(Cesium.Math.toRadians(21), Cesium.Math.toRadians(78), 5000);
|
* var cartesianPosition = Cesium.Ellipsoid.WGS84.cartographicToCartesian(position);
|
*/
|
Ellipsoid.prototype.cartographicToCartesian = function(cartographic, result) {
|
//`cartographic is required` is thrown from geodeticSurfaceNormalCartographic.
|
var n = cartographicToCartesianNormal;
|
var k = cartographicToCartesianK;
|
this.geodeticSurfaceNormalCartographic(cartographic, n);
|
Cartesian3.multiplyComponents(this._radiiSquared, n, k);
|
var gamma = Math.sqrt(Cartesian3.dot(n, k));
|
Cartesian3.divideByScalar(k, gamma, k);
|
Cartesian3.multiplyByScalar(n, cartographic.height, n);
|
|
if (!defined(result)) {
|
result = new Cartesian3();
|
}
|
return Cartesian3.add(k, n, result);
|
};
|
|
/**
|
* Converts the provided array of cartographics to an array of Cartesians.
|
*
|
* @param {Cartographic[]} cartographics An array of cartographic positions.
|
* @param {Cartesian3[]} [result] The object onto which to store the result.
|
* @returns {Cartesian3[]} The modified result parameter or a new Array instance if none was provided.
|
*
|
* @example
|
* //Convert an array of Cartographics and determine their Cartesian representation on a WGS84 ellipsoid.
|
* var positions = [new Cesium.Cartographic(Cesium.Math.toRadians(21), Cesium.Math.toRadians(78), 0),
|
* new Cesium.Cartographic(Cesium.Math.toRadians(21.321), Cesium.Math.toRadians(78.123), 100),
|
* new Cesium.Cartographic(Cesium.Math.toRadians(21.645), Cesium.Math.toRadians(78.456), 250)];
|
* var cartesianPositions = Cesium.Ellipsoid.WGS84.cartographicArrayToCartesianArray(positions);
|
*/
|
Ellipsoid.prototype.cartographicArrayToCartesianArray = function(cartographics, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.defined('cartographics', cartographics);
|
//>>includeEnd('debug')
|
|
var length = cartographics.length;
|
if (!defined(result)) {
|
result = new Array(length);
|
} else {
|
result.length = length;
|
}
|
for ( var i = 0; i < length; i++) {
|
result[i] = this.cartographicToCartesian(cartographics[i], result[i]);
|
}
|
return result;
|
};
|
|
var cartesianToCartographicN = new Cartesian3();
|
var cartesianToCartographicP = new Cartesian3();
|
var cartesianToCartographicH = new Cartesian3();
|
|
/**
|
* Converts the provided cartesian to cartographic representation.
|
* The cartesian is undefined at the center of the ellipsoid.
|
*
|
* @param {Cartesian3} cartesian The Cartesian position to convert to cartographic representation.
|
* @param {Cartographic} [result] The object onto which to store the result.
|
* @returns {Cartographic} The modified result parameter, new Cartographic instance if none was provided, or undefined if the cartesian is at the center of the ellipsoid.
|
*
|
* @example
|
* //Create a Cartesian and determine it's Cartographic representation on a WGS84 ellipsoid.
|
* var position = new Cesium.Cartesian3(17832.12, 83234.52, 952313.73);
|
* var cartographicPosition = Cesium.Ellipsoid.WGS84.cartesianToCartographic(position);
|
*/
|
Ellipsoid.prototype.cartesianToCartographic = function(cartesian, result) {
|
//`cartesian is required.` is thrown from scaleToGeodeticSurface
|
var p = this.scaleToGeodeticSurface(cartesian, cartesianToCartographicP);
|
|
if (!defined(p)) {
|
return undefined;
|
}
|
|
var n = this.geodeticSurfaceNormal(p, cartesianToCartographicN);
|
var h = Cartesian3.subtract(cartesian, p, cartesianToCartographicH);
|
|
var longitude = Math.atan2(n.y, n.x);
|
var latitude = Math.asin(n.z);
|
var height = CesiumMath.sign(Cartesian3.dot(h, cartesian)) * Cartesian3.magnitude(h);
|
|
if (!defined(result)) {
|
return new Cartographic(longitude, latitude, height);
|
}
|
result.longitude = longitude;
|
result.latitude = latitude;
|
result.height = height;
|
return result;
|
};
|
|
/**
|
* Converts the provided array of cartesians to an array of cartographics.
|
*
|
* @param {Cartesian3[]} cartesians An array of Cartesian positions.
|
* @param {Cartographic[]} [result] The object onto which to store the result.
|
* @returns {Cartographic[]} The modified result parameter or a new Array instance if none was provided.
|
*
|
* @example
|
* //Create an array of Cartesians and determine their Cartographic representation on a WGS84 ellipsoid.
|
* var positions = [new Cesium.Cartesian3(17832.12, 83234.52, 952313.73),
|
* new Cesium.Cartesian3(17832.13, 83234.53, 952313.73),
|
* new Cesium.Cartesian3(17832.14, 83234.54, 952313.73)]
|
* var cartographicPositions = Cesium.Ellipsoid.WGS84.cartesianArrayToCartographicArray(positions);
|
*/
|
Ellipsoid.prototype.cartesianArrayToCartographicArray = function(cartesians, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.defined('cartesians', cartesians);
|
//>>includeEnd('debug');
|
|
var length = cartesians.length;
|
if (!defined(result)) {
|
result = new Array(length);
|
} else {
|
result.length = length;
|
}
|
for ( var i = 0; i < length; ++i) {
|
result[i] = this.cartesianToCartographic(cartesians[i], result[i]);
|
}
|
return result;
|
};
|
|
/**
|
* Scales the provided Cartesian position along the geodetic surface normal
|
* so that it is on the surface of this ellipsoid. If the position is
|
* at the center of the ellipsoid, this function returns undefined.
|
*
|
* @param {Cartesian3} cartesian The Cartesian position to scale.
|
* @param {Cartesian3} [result] The object onto which to store the result.
|
* @returns {Cartesian3} The modified result parameter, a new Cartesian3 instance if none was provided, or undefined if the position is at the center.
|
*/
|
Ellipsoid.prototype.scaleToGeodeticSurface = function(cartesian, result) {
|
return scaleToGeodeticSurface(cartesian, this._oneOverRadii, this._oneOverRadiiSquared, this._centerToleranceSquared, result);
|
};
|
|
/**
|
* Scales the provided Cartesian position along the geocentric surface normal
|
* so that it is on the surface of this ellipsoid.
|
*
|
* @param {Cartesian3} cartesian The Cartesian position to scale.
|
* @param {Cartesian3} [result] The object onto which to store the result.
|
* @returns {Cartesian3} The modified result parameter or a new Cartesian3 instance if none was provided.
|
*/
|
Ellipsoid.prototype.scaleToGeocentricSurface = function(cartesian, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('cartesian', cartesian);
|
//>>includeEnd('debug');
|
|
if (!defined(result)) {
|
result = new Cartesian3();
|
}
|
|
var positionX = cartesian.x;
|
var positionY = cartesian.y;
|
var positionZ = cartesian.z;
|
var oneOverRadiiSquared = this._oneOverRadiiSquared;
|
|
var beta = 1.0 / Math.sqrt((positionX * positionX) * oneOverRadiiSquared.x +
|
(positionY * positionY) * oneOverRadiiSquared.y +
|
(positionZ * positionZ) * oneOverRadiiSquared.z);
|
|
return Cartesian3.multiplyByScalar(cartesian, beta, result);
|
};
|
|
/**
|
* Transforms a Cartesian X, Y, Z position to the ellipsoid-scaled space by multiplying
|
* its components by the result of {@link Ellipsoid#oneOverRadii}.
|
*
|
* @param {Cartesian3} position The position to transform.
|
* @param {Cartesian3} [result] The position to which to copy the result, or undefined to create and
|
* return a new instance.
|
* @returns {Cartesian3} The position expressed in the scaled space. The returned instance is the
|
* one passed as the result parameter if it is not undefined, or a new instance of it is.
|
*/
|
Ellipsoid.prototype.transformPositionToScaledSpace = function(position, result) {
|
if (!defined(result)) {
|
result = new Cartesian3();
|
}
|
|
return Cartesian3.multiplyComponents(position, this._oneOverRadii, result);
|
};
|
|
/**
|
* Transforms a Cartesian X, Y, Z position from the ellipsoid-scaled space by multiplying
|
* its components by the result of {@link Ellipsoid#radii}.
|
*
|
* @param {Cartesian3} position The position to transform.
|
* @param {Cartesian3} [result] The position to which to copy the result, or undefined to create and
|
* return a new instance.
|
* @returns {Cartesian3} The position expressed in the unscaled space. The returned instance is the
|
* one passed as the result parameter if it is not undefined, or a new instance of it is.
|
*/
|
Ellipsoid.prototype.transformPositionFromScaledSpace = function(position, result) {
|
if (!defined(result)) {
|
result = new Cartesian3();
|
}
|
|
return Cartesian3.multiplyComponents(position, this._radii, result);
|
};
|
|
/**
|
* Compares this Ellipsoid against the provided Ellipsoid componentwise and returns
|
* <code>true</code> if they are equal, <code>false</code> otherwise.
|
*
|
* @param {Ellipsoid} [right] The other Ellipsoid.
|
* @returns {Boolean} <code>true</code> if they are equal, <code>false</code> otherwise.
|
*/
|
Ellipsoid.prototype.equals = function(right) {
|
return (this === right) ||
|
(defined(right) &&
|
Cartesian3.equals(this._radii, right._radii));
|
};
|
|
/**
|
* Creates a string representing this Ellipsoid in the format '(radii.x, radii.y, radii.z)'.
|
*
|
* @returns {String} A string representing this ellipsoid in the format '(radii.x, radii.y, radii.z)'.
|
*/
|
Ellipsoid.prototype.toString = function() {
|
return this._radii.toString();
|
};
|
|
/**
|
* Computes a point which is the intersection of the surface normal with the z-axis.
|
*
|
* @param {Cartesian3} position the position. must be on the surface of the ellipsoid.
|
* @param {Number} [buffer = 0.0] A buffer to subtract from the ellipsoid size when checking if the point is inside the ellipsoid.
|
* In earth case, with common earth datums, there is no need for this buffer since the intersection point is always (relatively) very close to the center.
|
* In WGS84 datum, intersection point is at max z = +-42841.31151331382 (0.673% of z-axis).
|
* Intersection point could be outside the ellipsoid if the ratio of MajorAxis / AxisOfRotation is bigger than the square root of 2
|
* @param {Cartesian3} [result] The cartesian to which to copy the result, or undefined to create and
|
* return a new instance.
|
* @returns {Cartesian3 | undefined} the intersection point if it's inside the ellipsoid, undefined otherwise
|
*
|
* @exception {DeveloperError} position is required.
|
* @exception {DeveloperError} Ellipsoid must be an ellipsoid of revolution (radii.x == radii.y).
|
* @exception {DeveloperError} Ellipsoid.radii.z must be greater than 0.
|
*/
|
Ellipsoid.prototype.getSurfaceNormalIntersectionWithZAxis = function(position, buffer, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('position', position);
|
|
if (!CesiumMath.equalsEpsilon(this._radii.x, this._radii.y, CesiumMath.EPSILON15)) {
|
throw new DeveloperError('Ellipsoid must be an ellipsoid of revolution (radii.x == radii.y)');
|
}
|
|
Check.typeOf.number.greaterThan('Ellipsoid.radii.z', this._radii.z, 0);
|
//>>includeEnd('debug');
|
|
buffer = defaultValue(buffer, 0.0);
|
|
var squaredXOverSquaredZ = this._squaredXOverSquaredZ;
|
|
if (!defined(result)) {
|
result = new Cartesian3();
|
}
|
|
result.x = 0.0;
|
result.y = 0.0;
|
result.z = position.z * (1 - squaredXOverSquaredZ);
|
|
if (Math.abs(result.z) >= this._radii.z - buffer) {
|
return undefined;
|
}
|
|
return result;
|
};
|
|
module.exports= Ellipsoid;
|
|
},{"./Cartesian3":126,"./Cartographic":128,"./Check":129,"./DeveloperError":131,"./Math":139,"./defaultValue":158,"./defineProperties":159,"./defined":160,"./freezeObject":163,"./scaleToGeodeticSurface":176}],133:[function(require,module,exports){
|
var Check=require('./Check');
|
var defined=require('./defined');
|
var defineProperties=require('./defineProperties');
|
|
'use strict';
|
|
/**
|
* A generic utility class for managing subscribers for a particular event.
|
* This class is usually instantiated inside of a container class and
|
* exposed as a property for others to subscribe to.
|
*
|
* @alias Event
|
* @constructor
|
* @example
|
* MyObject.prototype.myListener = function(arg1, arg2) {
|
* this.myArg1Copy = arg1;
|
* this.myArg2Copy = arg2;
|
* }
|
*
|
* var myObjectInstance = new MyObject();
|
* var evt = new Cesium.Event();
|
* evt.addEventListener(MyObject.prototype.myListener, myObjectInstance);
|
* evt.raiseEvent('1', '2');
|
* evt.removeEventListener(MyObject.prototype.myListener);
|
*/
|
function Event() {
|
this._listeners = [];
|
this._scopes = [];
|
this._toRemove = [];
|
this._insideRaiseEvent = false;
|
}
|
|
defineProperties(Event.prototype, {
|
/**
|
* The number of listeners currently subscribed to the event.
|
* @memberof Event.prototype
|
* @type {Number}
|
* @readonly
|
*/
|
numberOfListeners : {
|
get : function() {
|
return this._listeners.length - this._toRemove.length;
|
}
|
}
|
});
|
|
/**
|
* Registers a callback function to be executed whenever the event is raised.
|
* An optional scope can be provided to serve as the <code>this</code> pointer
|
* in which the function will execute.
|
*
|
* @param {Function} listener The function to be executed when the event is raised.
|
* @param {Object} [scope] An optional object scope to serve as the <code>this</code>
|
* pointer in which the listener function will execute.
|
* @returns {Event~RemoveCallback} A function that will remove this event listener when invoked.
|
*
|
* @see Event#raiseEvent
|
* @see Event#removeEventListener
|
*/
|
Event.prototype.addEventListener = function(listener, scope) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.func('listener', listener);
|
//>>includeEnd('debug');
|
|
this._listeners.push(listener);
|
this._scopes.push(scope);
|
|
var event = this;
|
return function() {
|
event.removeEventListener(listener, scope);
|
};
|
};
|
|
/**
|
* Unregisters a previously registered callback.
|
*
|
* @param {Function} listener The function to be unregistered.
|
* @param {Object} [scope] The scope that was originally passed to addEventListener.
|
* @returns {Boolean} <code>true</code> if the listener was removed; <code>false</code> if the listener and scope are not registered with the event.
|
*
|
* @see Event#addEventListener
|
* @see Event#raiseEvent
|
*/
|
Event.prototype.removeEventListener = function(listener, scope) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.func('listener', listener);
|
//>>includeEnd('debug');
|
|
var listeners = this._listeners;
|
var scopes = this._scopes;
|
|
var index = -1;
|
for (var i = 0; i < listeners.length; i++) {
|
if (listeners[i] === listener && scopes[i] === scope) {
|
index = i;
|
break;
|
}
|
}
|
|
if (index !== -1) {
|
if (this._insideRaiseEvent) {
|
//In order to allow removing an event subscription from within
|
//a callback, we don't actually remove the items here. Instead
|
//remember the index they are at and undefined their value.
|
this._toRemove.push(index);
|
listeners[index] = undefined;
|
scopes[index] = undefined;
|
} else {
|
listeners.splice(index, 1);
|
scopes.splice(index, 1);
|
}
|
return true;
|
}
|
|
return false;
|
};
|
|
function compareNumber(a,b) {
|
return b - a;
|
}
|
|
/**
|
* Raises the event by calling each registered listener with all supplied arguments.
|
*
|
* @param {*} arguments This method takes any number of parameters and passes them through to the listener functions.
|
*
|
* @see Event#addEventListener
|
* @see Event#removeEventListener
|
*/
|
Event.prototype.raiseEvent = function() {
|
this._insideRaiseEvent = true;
|
|
var i;
|
var listeners = this._listeners;
|
var scopes = this._scopes;
|
var length = listeners.length;
|
|
for (i = 0; i < length; i++) {
|
var listener = listeners[i];
|
if (defined(listener)) {
|
listeners[i].apply(scopes[i], arguments);
|
}
|
}
|
|
//Actually remove items removed in removeEventListener.
|
var toRemove = this._toRemove;
|
length = toRemove.length;
|
if (length > 0) {
|
toRemove.sort(compareNumber);
|
for (i = 0; i < length; i++) {
|
var index = toRemove[i];
|
listeners.splice(index, 1);
|
scopes.splice(index, 1);
|
}
|
toRemove.length = 0;
|
}
|
|
this._insideRaiseEvent = false;
|
};
|
|
/**
|
* A function that removes a listener.
|
* @callback Event~RemoveCallback
|
*/
|
|
module.exports= Event;
|
|
},{"./Check":129,"./defineProperties":159,"./defined":160}],134:[function(require,module,exports){
|
var defaultValue=require('./defaultValue');
|
var defined=require('./defined');
|
var defineProperties=require('./defineProperties');
|
var DeveloperError=require('./DeveloperError');
|
var Fullscreen=require('./Fullscreen');
|
var when=require('when');
|
|
'use strict';
|
/*global CanvasPixelArray*/
|
|
var theNavigator;
|
if (typeof navigator !== 'undefined') {
|
theNavigator = navigator;
|
} else {
|
theNavigator = {};
|
}
|
|
function extractVersion(versionString) {
|
var parts = versionString.split('.');
|
for (var i = 0, len = parts.length; i < len; ++i) {
|
parts[i] = parseInt(parts[i], 10);
|
}
|
return parts;
|
}
|
|
var isChromeResult;
|
var chromeVersionResult;
|
function isChrome() {
|
if (!defined(isChromeResult)) {
|
isChromeResult = false;
|
// Edge contains Chrome in the user agent too
|
if (!isEdge()) {
|
var fields = (/ Chrome\/([\.0-9]+)/).exec(theNavigator.userAgent);
|
if (fields !== null) {
|
isChromeResult = true;
|
chromeVersionResult = extractVersion(fields[1]);
|
}
|
}
|
}
|
|
return isChromeResult;
|
}
|
|
function chromeVersion() {
|
return isChrome() && chromeVersionResult;
|
}
|
|
var isSafariResult;
|
var safariVersionResult;
|
function isSafari() {
|
if (!defined(isSafariResult)) {
|
isSafariResult = false;
|
|
// Chrome and Edge contain Safari in the user agent too
|
if (!isChrome() && !isEdge() && (/ Safari\/[\.0-9]+/).test(theNavigator.userAgent)) {
|
var fields = (/ Version\/([\.0-9]+)/).exec(theNavigator.userAgent);
|
if (fields !== null) {
|
isSafariResult = true;
|
safariVersionResult = extractVersion(fields[1]);
|
}
|
}
|
}
|
|
return isSafariResult;
|
}
|
|
function safariVersion() {
|
return isSafari() && safariVersionResult;
|
}
|
|
var isWebkitResult;
|
var webkitVersionResult;
|
function isWebkit() {
|
if (!defined(isWebkitResult)) {
|
isWebkitResult = false;
|
|
var fields = (/ AppleWebKit\/([\.0-9]+)(\+?)/).exec(theNavigator.userAgent);
|
if (fields !== null) {
|
isWebkitResult = true;
|
webkitVersionResult = extractVersion(fields[1]);
|
webkitVersionResult.isNightly = !!fields[2];
|
}
|
}
|
|
return isWebkitResult;
|
}
|
|
function webkitVersion() {
|
return isWebkit() && webkitVersionResult;
|
}
|
|
var isInternetExplorerResult;
|
var internetExplorerVersionResult;
|
function isInternetExplorer() {
|
if (!defined(isInternetExplorerResult)) {
|
isInternetExplorerResult = false;
|
|
var fields;
|
if (theNavigator.appName === 'Microsoft Internet Explorer') {
|
fields = /MSIE ([0-9]{1,}[\.0-9]{0,})/.exec(theNavigator.userAgent);
|
if (fields !== null) {
|
isInternetExplorerResult = true;
|
internetExplorerVersionResult = extractVersion(fields[1]);
|
}
|
} else if (theNavigator.appName === 'Netscape') {
|
fields = /Trident\/.*rv:([0-9]{1,}[\.0-9]{0,})/.exec(theNavigator.userAgent);
|
if (fields !== null) {
|
isInternetExplorerResult = true;
|
internetExplorerVersionResult = extractVersion(fields[1]);
|
}
|
}
|
}
|
return isInternetExplorerResult;
|
}
|
|
function internetExplorerVersion() {
|
return isInternetExplorer() && internetExplorerVersionResult;
|
}
|
|
var isEdgeResult;
|
var edgeVersionResult;
|
function isEdge() {
|
if (!defined(isEdgeResult)) {
|
isEdgeResult = false;
|
var fields = (/ Edge\/([\.0-9]+)/).exec(theNavigator.userAgent);
|
if (fields !== null) {
|
isEdgeResult = true;
|
edgeVersionResult = extractVersion(fields[1]);
|
}
|
}
|
return isEdgeResult;
|
}
|
|
function edgeVersion() {
|
return isEdge() && edgeVersionResult;
|
}
|
|
var isFirefoxResult;
|
var firefoxVersionResult;
|
function isFirefox() {
|
if (!defined(isFirefoxResult)) {
|
isFirefoxResult = false;
|
|
var fields = /Firefox\/([\.0-9]+)/.exec(theNavigator.userAgent);
|
if (fields !== null) {
|
isFirefoxResult = true;
|
firefoxVersionResult = extractVersion(fields[1]);
|
}
|
}
|
return isFirefoxResult;
|
}
|
|
var isWindowsResult;
|
function isWindows() {
|
if (!defined(isWindowsResult)) {
|
isWindowsResult = /Windows/i.test(theNavigator.appVersion);
|
}
|
return isWindowsResult;
|
}
|
|
function firefoxVersion() {
|
return isFirefox() && firefoxVersionResult;
|
}
|
|
var hasPointerEvents;
|
function supportsPointerEvents() {
|
if (!defined(hasPointerEvents)) {
|
//While navigator.pointerEnabled is deprecated in the W3C specification
|
//we still need to use it if it exists in order to support browsers
|
//that rely on it, such as the Windows WebBrowser control which defines
|
//PointerEvent but sets navigator.pointerEnabled to false.
|
|
//Firefox disabled because of https://github.com/AnalyticalGraphicsInc/cesium/issues/6372
|
hasPointerEvents = !isFirefox() && typeof PointerEvent !== 'undefined' && (!defined(theNavigator.pointerEnabled) || theNavigator.pointerEnabled);
|
}
|
return hasPointerEvents;
|
}
|
|
var imageRenderingValueResult;
|
var supportsImageRenderingPixelatedResult;
|
function supportsImageRenderingPixelated() {
|
if (!defined(supportsImageRenderingPixelatedResult)) {
|
var canvas = document.createElement('canvas');
|
canvas.setAttribute('style',
|
'image-rendering: -moz-crisp-edges;' +
|
'image-rendering: pixelated;');
|
//canvas.style.imageRendering will be undefined, null or an empty string on unsupported browsers.
|
var tmp = canvas.style.imageRendering;
|
supportsImageRenderingPixelatedResult = defined(tmp) && tmp !== '';
|
if (supportsImageRenderingPixelatedResult) {
|
imageRenderingValueResult = tmp;
|
}
|
}
|
return supportsImageRenderingPixelatedResult;
|
}
|
|
function imageRenderingValue() {
|
return supportsImageRenderingPixelated() ? imageRenderingValueResult : undefined;
|
}
|
|
function supportsWebP() {
|
//>>includeStart('debug', pragmas.debug);
|
if (!supportsWebP.initialized) {
|
throw new DeveloperError('You must call FeatureDetection.supportsWebP.initialize and wait for the promise to resolve before calling FeatureDetection.supportsWebP');
|
}
|
//>>includeEnd('debug');
|
return supportsWebP._result;
|
}
|
supportsWebP._promise = undefined;
|
supportsWebP._result = undefined;
|
supportsWebP.initialize = function() {
|
// From https://developers.google.com/speed/webp/faq#how_can_i_detect_browser_support_for_webp
|
if (defined(supportsWebP._promise)) {
|
return supportsWebP._promise;
|
}
|
|
var supportsWebPDeferred = when.defer();
|
supportsWebP._promise = supportsWebPDeferred.promise;
|
if (isEdge()) {
|
// Edge's WebP support with WebGL is incomplete.
|
// See bug report: https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/19221241/
|
supportsWebP._result = false;
|
supportsWebPDeferred.resolve(supportsWebP._result);
|
return supportsWebPDeferred.promise;
|
}
|
|
var image = new Image();
|
image.onload = function () {
|
supportsWebP._result = (image.width > 0) && (image.height > 0);
|
supportsWebPDeferred.resolve(supportsWebP._result);
|
};
|
|
image.onerror = function () {
|
supportsWebP._result = false;
|
supportsWebPDeferred.resolve(supportsWebP._result);
|
};
|
|
image.src = 'data:image/webp;base64,UklGRiIAAABXRUJQVlA4IBYAAAAwAQCdASoBAAEADsD+JaQAA3AAAAAA';
|
|
return supportsWebPDeferred.promise;
|
};
|
defineProperties(supportsWebP, {
|
initialized: {
|
get: function() {
|
return defined(supportsWebP._result);
|
}
|
}
|
});
|
|
var typedArrayTypes = [];
|
if (typeof ArrayBuffer !== 'undefined') {
|
typedArrayTypes.push(Int8Array, Uint8Array, Int16Array, Uint16Array, Int32Array, Uint32Array, Float32Array, Float64Array);
|
|
if (typeof Uint8ClampedArray !== 'undefined') {
|
typedArrayTypes.push(Uint8ClampedArray);
|
}
|
|
if (typeof CanvasPixelArray !== 'undefined') {
|
typedArrayTypes.push(CanvasPixelArray);
|
}
|
}
|
|
/**
|
* A set of functions to detect whether the current browser supports
|
* various features.
|
*
|
* @exports FeatureDetection
|
*/
|
var FeatureDetection = {
|
isChrome : isChrome,
|
chromeVersion : chromeVersion,
|
isSafari : isSafari,
|
safariVersion : safariVersion,
|
isWebkit : isWebkit,
|
webkitVersion : webkitVersion,
|
isInternetExplorer : isInternetExplorer,
|
internetExplorerVersion : internetExplorerVersion,
|
isEdge : isEdge,
|
edgeVersion : edgeVersion,
|
isFirefox : isFirefox,
|
firefoxVersion : firefoxVersion,
|
isWindows : isWindows,
|
hardwareConcurrency : defaultValue(theNavigator.hardwareConcurrency, 3),
|
supportsPointerEvents : supportsPointerEvents,
|
supportsImageRenderingPixelated: supportsImageRenderingPixelated,
|
supportsWebP: supportsWebP,
|
imageRenderingValue: imageRenderingValue,
|
typedArrayTypes: typedArrayTypes
|
};
|
|
/**
|
* Detects whether the current browser supports the full screen standard.
|
*
|
* @returns {Boolean} true if the browser supports the full screen standard, false if not.
|
*
|
* @see Fullscreen
|
* @see {@link http://dvcs.w3.org/hg/fullscreen/raw-file/tip/Overview.html|W3C Fullscreen Living Specification}
|
*/
|
FeatureDetection.supportsFullscreen = function() {
|
return Fullscreen.supportsFullscreen();
|
};
|
|
/**
|
* Detects whether the current browser supports typed arrays.
|
*
|
* @returns {Boolean} true if the browser supports typed arrays, false if not.
|
*
|
* @see {@link http://www.khronos.org/registry/typedarray/specs/latest/|Typed Array Specification}
|
*/
|
FeatureDetection.supportsTypedArrays = function() {
|
return typeof ArrayBuffer !== 'undefined';
|
};
|
|
/**
|
* Detects whether the current browser supports Web Workers.
|
*
|
* @returns {Boolean} true if the browsers supports Web Workers, false if not.
|
*
|
* @see {@link http://www.w3.org/TR/workers/}
|
*/
|
FeatureDetection.supportsWebWorkers = function() {
|
return typeof Worker !== 'undefined';
|
};
|
|
/**
|
* Detects whether the current browser supports Web Assembly.
|
*
|
* @returns {Boolean} true if the browsers supports Web Assembly, false if not.
|
*
|
* @see {@link https://developer.mozilla.org/en-US/docs/WebAssembly}
|
*/
|
FeatureDetection.supportsWebAssembly = function() {
|
return typeof WebAssembly !== 'undefined' && !FeatureDetection.isEdge();
|
};
|
|
module.exports= FeatureDetection;
|
|
},{"./DeveloperError":131,"./Fullscreen":135,"./defaultValue":158,"./defineProperties":159,"./defined":160,"when":118}],135:[function(require,module,exports){
|
var defined=require('./defined');
|
var defineProperties=require('./defineProperties');
|
|
'use strict';
|
|
var _supportsFullscreen;
|
var _names = {
|
requestFullscreen : undefined,
|
exitFullscreen : undefined,
|
fullscreenEnabled : undefined,
|
fullscreenElement : undefined,
|
fullscreenchange : undefined,
|
fullscreenerror : undefined
|
};
|
|
/**
|
* Browser-independent functions for working with the standard fullscreen API.
|
*
|
* @exports Fullscreen
|
* @namespace
|
*
|
* @see {@link http://dvcs.w3.org/hg/fullscreen/raw-file/tip/Overview.html|W3C Fullscreen Living Specification}
|
*/
|
var Fullscreen = {};
|
|
defineProperties(Fullscreen, {
|
/**
|
* The element that is currently fullscreen, if any. To simply check if the
|
* browser is in fullscreen mode or not, use {@link Fullscreen#fullscreen}.
|
* @memberof Fullscreen
|
* @type {Object}
|
* @readonly
|
*/
|
element : {
|
get : function() {
|
if (!Fullscreen.supportsFullscreen()) {
|
return undefined;
|
}
|
|
return document[_names.fullscreenElement];
|
}
|
},
|
|
/**
|
* The name of the event on the document that is fired when fullscreen is
|
* entered or exited. This event name is intended for use with addEventListener.
|
* In your event handler, to determine if the browser is in fullscreen mode or not,
|
* use {@link Fullscreen#fullscreen}.
|
* @memberof Fullscreen
|
* @type {String}
|
* @readonly
|
*/
|
changeEventName : {
|
get : function() {
|
if (!Fullscreen.supportsFullscreen()) {
|
return undefined;
|
}
|
|
return _names.fullscreenchange;
|
}
|
},
|
|
/**
|
* The name of the event that is fired when a fullscreen error
|
* occurs. This event name is intended for use with addEventListener.
|
* @memberof Fullscreen
|
* @type {String}
|
* @readonly
|
*/
|
errorEventName : {
|
get : function() {
|
if (!Fullscreen.supportsFullscreen()) {
|
return undefined;
|
}
|
|
return _names.fullscreenerror;
|
}
|
},
|
|
/**
|
* Determine whether the browser will allow an element to be made fullscreen, or not.
|
* For example, by default, iframes cannot go fullscreen unless the containing page
|
* adds an "allowfullscreen" attribute (or prefixed equivalent).
|
* @memberof Fullscreen
|
* @type {Boolean}
|
* @readonly
|
*/
|
enabled : {
|
get : function() {
|
if (!Fullscreen.supportsFullscreen()) {
|
return undefined;
|
}
|
|
return document[_names.fullscreenEnabled];
|
}
|
},
|
|
/**
|
* Determines if the browser is currently in fullscreen mode.
|
* @memberof Fullscreen
|
* @type {Boolean}
|
* @readonly
|
*/
|
fullscreen : {
|
get : function() {
|
if (!Fullscreen.supportsFullscreen()) {
|
return undefined;
|
}
|
|
return Fullscreen.element !== null;
|
}
|
}
|
});
|
|
/**
|
* Detects whether the browser supports the standard fullscreen API.
|
*
|
* @returns {Boolean} <code>true</code> if the browser supports the standard fullscreen API,
|
* <code>false</code> otherwise.
|
*/
|
Fullscreen.supportsFullscreen = function() {
|
if (defined(_supportsFullscreen)) {
|
return _supportsFullscreen;
|
}
|
|
_supportsFullscreen = false;
|
|
var body = document.body;
|
if (typeof body.requestFullscreen === 'function') {
|
// go with the unprefixed, standard set of names
|
_names.requestFullscreen = 'requestFullscreen';
|
_names.exitFullscreen = 'exitFullscreen';
|
_names.fullscreenEnabled = 'fullscreenEnabled';
|
_names.fullscreenElement = 'fullscreenElement';
|
_names.fullscreenchange = 'fullscreenchange';
|
_names.fullscreenerror = 'fullscreenerror';
|
_supportsFullscreen = true;
|
return _supportsFullscreen;
|
}
|
|
//check for the correct combination of prefix plus the various names that browsers use
|
var prefixes = ['webkit', 'moz', 'o', 'ms', 'khtml'];
|
var name;
|
for (var i = 0, len = prefixes.length; i < len; ++i) {
|
var prefix = prefixes[i];
|
|
// casing of Fullscreen differs across browsers
|
name = prefix + 'RequestFullscreen';
|
if (typeof body[name] === 'function') {
|
_names.requestFullscreen = name;
|
_supportsFullscreen = true;
|
} else {
|
name = prefix + 'RequestFullScreen';
|
if (typeof body[name] === 'function') {
|
_names.requestFullscreen = name;
|
_supportsFullscreen = true;
|
}
|
}
|
|
// disagreement about whether it's "exit" as per spec, or "cancel"
|
name = prefix + 'ExitFullscreen';
|
if (typeof document[name] === 'function') {
|
_names.exitFullscreen = name;
|
} else {
|
name = prefix + 'CancelFullScreen';
|
if (typeof document[name] === 'function') {
|
_names.exitFullscreen = name;
|
}
|
}
|
|
// casing of Fullscreen differs across browsers
|
name = prefix + 'FullscreenEnabled';
|
if (document[name] !== undefined) {
|
_names.fullscreenEnabled = name;
|
} else {
|
name = prefix + 'FullScreenEnabled';
|
if (document[name] !== undefined) {
|
_names.fullscreenEnabled = name;
|
}
|
}
|
|
// casing of Fullscreen differs across browsers
|
name = prefix + 'FullscreenElement';
|
if (document[name] !== undefined) {
|
_names.fullscreenElement = name;
|
} else {
|
name = prefix + 'FullScreenElement';
|
if (document[name] !== undefined) {
|
_names.fullscreenElement = name;
|
}
|
}
|
|
// thankfully, event names are all lowercase per spec
|
name = prefix + 'fullscreenchange';
|
// event names do not have 'on' in the front, but the property on the document does
|
if (document['on' + name] !== undefined) {
|
//except on IE
|
if (prefix === 'ms') {
|
name = 'MSFullscreenChange';
|
}
|
_names.fullscreenchange = name;
|
}
|
|
name = prefix + 'fullscreenerror';
|
if (document['on' + name] !== undefined) {
|
//except on IE
|
if (prefix === 'ms') {
|
name = 'MSFullscreenError';
|
}
|
_names.fullscreenerror = name;
|
}
|
}
|
|
return _supportsFullscreen;
|
};
|
|
/**
|
* Asynchronously requests the browser to enter fullscreen mode on the given element.
|
* If fullscreen mode is not supported by the browser, does nothing.
|
*
|
* @param {Object} element The HTML element which will be placed into fullscreen mode.
|
* @param {HMDVRDevice} [vrDevice] The VR device.
|
*
|
* @example
|
* // Put the entire page into fullscreen.
|
* Cesium.Fullscreen.requestFullscreen(document.body)
|
*
|
* // Place only the Cesium canvas into fullscreen.
|
* Cesium.Fullscreen.requestFullscreen(scene.canvas)
|
*/
|
Fullscreen.requestFullscreen = function(element, vrDevice) {
|
if (!Fullscreen.supportsFullscreen()) {
|
return;
|
}
|
|
element[_names.requestFullscreen]({ vrDisplay: vrDevice });
|
};
|
|
/**
|
* Asynchronously exits fullscreen mode. If the browser is not currently
|
* in fullscreen, or if fullscreen mode is not supported by the browser, does nothing.
|
*/
|
Fullscreen.exitFullscreen = function() {
|
if (!Fullscreen.supportsFullscreen()) {
|
return;
|
}
|
|
document[_names.exitFullscreen]();
|
};
|
|
module.exports= Fullscreen;
|
|
},{"./defineProperties":159,"./defined":160}],136:[function(require,module,exports){
|
var Cartesian3 = require('./Cartesian3');
|
var Cartographic = require('./Cartographic');
|
var defaultValue = require('./defaultValue');
|
var defined = require('./defined');
|
var defineProperties = require('./defineProperties');
|
var DeveloperError = require('./DeveloperError');
|
var Ellipsoid = require('./Ellipsoid');
|
|
'use strict';
|
|
/**
|
* A simple map projection where longitude and latitude are linearly mapped to X and Y by multiplying
|
* them by the {@link Ellipsoid#maximumRadius}. This projection
|
* is commonly known as geographic, equirectangular, equidistant cylindrical, or plate carrée. It
|
* is also known as EPSG:4326.
|
*
|
* @alias GeographicProjection
|
* @constructor
|
*
|
* @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid.
|
*
|
* @see WebMercatorProjection
|
*/
|
function GeographicProjection(ellipsoid) {
|
this._ellipsoid = defaultValue(ellipsoid, Ellipsoid.WGS84);
|
this._semimajorAxis = this._ellipsoid.maximumRadius;
|
this._oneOverSemimajorAxis = 1.0 / this._semimajorAxis;
|
}
|
|
defineProperties(GeographicProjection.prototype, {
|
/**
|
* Gets the {@link Ellipsoid}.
|
*
|
* @memberof GeographicProjection.prototype
|
*
|
* @type {Ellipsoid}
|
* @readonly
|
*/
|
ellipsoid: {
|
get: function () {
|
return this._ellipsoid;
|
}
|
}
|
});
|
|
/**
|
* Projects a set of {@link Cartographic} coordinates, in radians, to map coordinates, in meters.
|
* X and Y are the longitude and latitude, respectively, multiplied by the maximum radius of the
|
* ellipsoid. Z is the unmodified height.
|
*
|
* @param {Cartographic} cartographic The coordinates to project.
|
* @param {Cartesian3} [result] An instance into which to copy the result. If this parameter is
|
* undefined, a new instance is created and returned.
|
* @returns {Cartesian3} The projected coordinates. If the result parameter is not undefined, the
|
* coordinates are copied there and that instance is returned. Otherwise, a new instance is
|
* created and returned.
|
*/
|
GeographicProjection.prototype.project = function (cartographic, result) {
|
// Actually this is the special case of equidistant cylindrical called the plate carree
|
var semimajorAxis = this._semimajorAxis;
|
var x = cartographic.longitude * semimajorAxis;
|
var y = cartographic.latitude * semimajorAxis;
|
var z = cartographic.height;
|
|
if (!defined(result)) {
|
return new Cartesian3(x, y, z);
|
}
|
|
result.x = x;
|
result.y = y;
|
result.z = z;
|
return result;
|
};
|
|
/**
|
* Unprojects a set of projected {@link Cartesian3} coordinates, in meters, to {@link Cartographic}
|
* coordinates, in radians. Longitude and Latitude are the X and Y coordinates, respectively,
|
* divided by the maximum radius of the ellipsoid. Height is the unmodified Z coordinate.
|
*
|
* @param {Cartesian3} cartesian The Cartesian position to unproject with height (z) in meters.
|
* @param {Cartographic} [result] An instance into which to copy the result. If this parameter is
|
* undefined, a new instance is created and returned.
|
* @returns {Cartographic} The unprojected coordinates. If the result parameter is not undefined, the
|
* coordinates are copied there and that instance is returned. Otherwise, a new instance is
|
* created and returned.
|
*/
|
GeographicProjection.prototype.unproject = function (cartesian, result) {
|
//>>includeStart('debug', pragmas.debug);
|
if (!defined(cartesian)) {
|
throw new DeveloperError('cartesian is required');
|
}
|
//>>includeEnd('debug');
|
|
var oneOverEarthSemimajorAxis = this._oneOverSemimajorAxis;
|
var longitude = cartesian.x * oneOverEarthSemimajorAxis;
|
var latitude = cartesian.y * oneOverEarthSemimajorAxis;
|
var height = cartesian.z;
|
|
if (!defined(result)) {
|
return new Cartographic(longitude, latitude, height);
|
}
|
|
result.longitude = longitude;
|
result.latitude = latitude;
|
result.height = height;
|
return result;
|
};
|
|
module.exports = GeographicProjection;
|
|
},{"./Cartesian3":126,"./Cartographic":128,"./DeveloperError":131,"./Ellipsoid":132,"./defaultValue":158,"./defineProperties":159,"./defined":160}],137:[function(require,module,exports){
|
var Cartesian2=require('./Cartesian2');
|
var Check=require('./Check');
|
var defaultValue=require('./defaultValue');
|
var defined=require('./defined');
|
var defineProperties=require('./defineProperties');
|
var Ellipsoid=require('./Ellipsoid');
|
var GeographicProjection=require('./GeographicProjection');
|
var CesiumMath=require('./Math');
|
var Rectangle=require('./Rectangle');
|
|
'use strict';
|
|
/**
|
* A tiling scheme for geometry referenced to a simple {@link GeographicProjection} where
|
* longitude and latitude are directly mapped to X and Y. This projection is commonly
|
* known as geographic, equirectangular, equidistant cylindrical, or plate carrée.
|
*
|
* @alias GeographicTilingScheme
|
* @constructor
|
*
|
* @param {Object} [options] Object with the following properties:
|
* @param {Ellipsoid} [options.ellipsoid=Ellipsoid.WGS84] The ellipsoid whose surface is being tiled. Defaults to
|
* the WGS84 ellipsoid.
|
* @param {Rectangle} [options.rectangle=Rectangle.MAX_VALUE] The rectangle, in radians, covered by the tiling scheme.
|
* @param {Number} [options.numberOfLevelZeroTilesX=2] The number of tiles in the X direction at level zero of
|
* the tile tree.
|
* @param {Number} [options.numberOfLevelZeroTilesY=1] The number of tiles in the Y direction at level zero of
|
* the tile tree.
|
*/
|
function GeographicTilingScheme(options) {
|
options = defaultValue(options, {});
|
|
this._ellipsoid = defaultValue(options.ellipsoid, Ellipsoid.WGS84);
|
this._rectangle = defaultValue(options.rectangle, Rectangle.MAX_VALUE);
|
this._projection = new GeographicProjection(this._ellipsoid);
|
this._numberOfLevelZeroTilesX = defaultValue(options.numberOfLevelZeroTilesX, 2);
|
this._numberOfLevelZeroTilesY = defaultValue(options.numberOfLevelZeroTilesY, 1);
|
}
|
|
defineProperties(GeographicTilingScheme.prototype, {
|
/**
|
* Gets the ellipsoid that is tiled by this tiling scheme.
|
* @memberof GeographicTilingScheme.prototype
|
* @type {Ellipsoid}
|
*/
|
ellipsoid : {
|
get : function() {
|
return this._ellipsoid;
|
}
|
},
|
|
/**
|
* Gets the rectangle, in radians, covered by this tiling scheme.
|
* @memberof GeographicTilingScheme.prototype
|
* @type {Rectangle}
|
*/
|
rectangle : {
|
get : function() {
|
return this._rectangle;
|
}
|
},
|
|
/**
|
* Gets the map projection used by this tiling scheme.
|
* @memberof GeographicTilingScheme.prototype
|
* @type {MapProjection}
|
*/
|
projection : {
|
get : function() {
|
return this._projection;
|
}
|
}
|
});
|
|
/**
|
* Gets the total number of tiles in the X direction at a specified level-of-detail.
|
*
|
* @param {Number} level The level-of-detail.
|
* @returns {Number} The number of tiles in the X direction at the given level.
|
*/
|
GeographicTilingScheme.prototype.getNumberOfXTilesAtLevel = function(level) {
|
return this._numberOfLevelZeroTilesX << level;
|
};
|
|
/**
|
* Gets the total number of tiles in the Y direction at a specified level-of-detail.
|
*
|
* @param {Number} level The level-of-detail.
|
* @returns {Number} The number of tiles in the Y direction at the given level.
|
*/
|
GeographicTilingScheme.prototype.getNumberOfYTilesAtLevel = function(level) {
|
return this._numberOfLevelZeroTilesY << level;
|
};
|
|
/**
|
* Transforms a rectangle specified in geodetic radians to the native coordinate system
|
* of this tiling scheme.
|
*
|
* @param {Rectangle} rectangle The rectangle to transform.
|
* @param {Rectangle} [result] The instance to which to copy the result, or undefined if a new instance
|
* should be created.
|
* @returns {Rectangle} The specified 'result', or a new object containing the native rectangle if 'result'
|
* is undefined.
|
*/
|
GeographicTilingScheme.prototype.rectangleToNativeRectangle = function(rectangle, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.defined('rectangle', rectangle);
|
//>>includeEnd('debug');
|
|
var west = CesiumMath.toDegrees(rectangle.west);
|
var south = CesiumMath.toDegrees(rectangle.south);
|
var east = CesiumMath.toDegrees(rectangle.east);
|
var north = CesiumMath.toDegrees(rectangle.north);
|
|
if (!defined(result)) {
|
return new Rectangle(west, south, east, north);
|
}
|
|
result.west = west;
|
result.south = south;
|
result.east = east;
|
result.north = north;
|
return result;
|
};
|
|
/**
|
* Converts tile x, y coordinates and level to a rectangle expressed in the native coordinates
|
* of the tiling scheme.
|
*
|
* @param {Number} x The integer x coordinate of the tile.
|
* @param {Number} y The integer y coordinate of the tile.
|
* @param {Number} level The tile level-of-detail. Zero is the least detailed.
|
* @param {Object} [result] The instance to which to copy the result, or undefined if a new instance
|
* should be created.
|
* @returns {Rectangle} The specified 'result', or a new object containing the rectangle
|
* if 'result' is undefined.
|
*/
|
GeographicTilingScheme.prototype.tileXYToNativeRectangle = function(x, y, level, result) {
|
var rectangleRadians = this.tileXYToRectangle(x, y, level, result);
|
rectangleRadians.west = CesiumMath.toDegrees(rectangleRadians.west);
|
rectangleRadians.south = CesiumMath.toDegrees(rectangleRadians.south);
|
rectangleRadians.east = CesiumMath.toDegrees(rectangleRadians.east);
|
rectangleRadians.north = CesiumMath.toDegrees(rectangleRadians.north);
|
return rectangleRadians;
|
};
|
|
/**
|
* Converts tile x, y coordinates and level to a cartographic rectangle in radians.
|
*
|
* @param {Number} x The integer x coordinate of the tile.
|
* @param {Number} y The integer y coordinate of the tile.
|
* @param {Number} level The tile level-of-detail. Zero is the least detailed.
|
* @param {Object} [result] The instance to which to copy the result, or undefined if a new instance
|
* should be created.
|
* @returns {Rectangle} The specified 'result', or a new object containing the rectangle
|
* if 'result' is undefined.
|
*/
|
GeographicTilingScheme.prototype.tileXYToRectangle = function(x, y, level, result) {
|
var rectangle = this._rectangle;
|
|
var xTiles = this.getNumberOfXTilesAtLevel(level);
|
var yTiles = this.getNumberOfYTilesAtLevel(level);
|
|
var xTileWidth = rectangle.width / xTiles;
|
var west = x * xTileWidth + rectangle.west;
|
var east = (x + 1) * xTileWidth + rectangle.west;
|
|
var yTileHeight = rectangle.height / yTiles;
|
var north = rectangle.north - y * yTileHeight;
|
var south = rectangle.north - (y + 1) * yTileHeight;
|
|
if (!defined(result)) {
|
result = new Rectangle(west, south, east, north);
|
}
|
|
result.west = west;
|
result.south = south;
|
result.east = east;
|
result.north = north;
|
return result;
|
};
|
|
/**
|
* Calculates the tile x, y coordinates of the tile containing
|
* a given cartographic position.
|
*
|
* @param {Cartographic} position The position.
|
* @param {Number} level The tile level-of-detail. Zero is the least detailed.
|
* @param {Cartesian2} [result] The instance to which to copy the result, or undefined if a new instance
|
* should be created.
|
* @returns {Cartesian2} The specified 'result', or a new object containing the tile x, y coordinates
|
* if 'result' is undefined.
|
*/
|
GeographicTilingScheme.prototype.positionToTileXY = function(position, level, result) {
|
var rectangle = this._rectangle;
|
if (!Rectangle.contains(rectangle, position)) {
|
// outside the bounds of the tiling scheme
|
return undefined;
|
}
|
|
var xTiles = this.getNumberOfXTilesAtLevel(level);
|
var yTiles = this.getNumberOfYTilesAtLevel(level);
|
|
var xTileWidth = rectangle.width / xTiles;
|
var yTileHeight = rectangle.height / yTiles;
|
|
var longitude = position.longitude;
|
if (rectangle.east < rectangle.west) {
|
longitude += CesiumMath.TWO_PI;
|
}
|
|
var xTileCoordinate = (longitude - rectangle.west) / xTileWidth | 0;
|
if (xTileCoordinate >= xTiles) {
|
xTileCoordinate = xTiles - 1;
|
}
|
|
var yTileCoordinate = (rectangle.north - position.latitude) / yTileHeight | 0;
|
if (yTileCoordinate >= yTiles) {
|
yTileCoordinate = yTiles - 1;
|
}
|
|
if (!defined(result)) {
|
return new Cartesian2(xTileCoordinate, yTileCoordinate);
|
}
|
|
result.x = xTileCoordinate;
|
result.y = yTileCoordinate;
|
return result;
|
};
|
|
module.exports= GeographicTilingScheme;
|
|
},{"./Cartesian2":125,"./Check":129,"./Ellipsoid":132,"./GeographicProjection":136,"./Math":139,"./Rectangle":140,"./defaultValue":158,"./defineProperties":159,"./defined":160}],138:[function(require,module,exports){
|
var Check=require('./Check');
|
var defaultValue=require('./defaultValue');
|
var defined=require('./defined');
|
var defineProperties=require('./defineProperties');
|
|
'use strict';
|
|
/**
|
* Array implementation of a heap.
|
*
|
* @alias Heap
|
* @constructor
|
* @private
|
*
|
* @param {Object} options Object with the following properties:
|
* @param {Heap~ComparatorCallback} options.comparator The comparator to use for the heap. If comparator(a, b) is less than 0, sort a to a lower index than b, otherwise sort to a higher index.
|
*/
|
function Heap(options) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('options', options);
|
Check.defined('options.comparator', options.comparator);
|
//>>includeEnd('debug');
|
|
this._comparator = options.comparator;
|
this._array = [];
|
this._length = 0;
|
this._maximumLength = undefined;
|
}
|
|
defineProperties(Heap.prototype, {
|
/**
|
* Gets the length of the heap.
|
*
|
* @memberof Heap.prototype
|
*
|
* @type {Number}
|
* @readonly
|
*/
|
length : {
|
get : function() {
|
return this._length;
|
}
|
},
|
|
/**
|
* Gets the internal array.
|
*
|
* @memberof Heap.prototype
|
*
|
* @type {Array}
|
* @readonly
|
*/
|
internalArray : {
|
get : function() {
|
return this._array;
|
}
|
},
|
|
/**
|
* Gets and sets the maximum length of the heap.
|
*
|
* @memberof Heap.prototype
|
*
|
* @type {Number}
|
*/
|
maximumLength : {
|
get : function() {
|
return this._maximumLength;
|
},
|
set : function(value) {
|
this._maximumLength = value;
|
if (this._length > value && value > 0) {
|
this._length = value;
|
this._array.length = value;
|
}
|
}
|
},
|
|
/**
|
* The comparator to use for the heap. If comparator(a, b) is less than 0, sort a to a lower index than b, otherwise sort to a higher index.
|
*
|
* @memberof Heap.prototype
|
*
|
* @type {Heap~ComparatorCallback}
|
*/
|
comparator : {
|
get : function() {
|
return this._comparator;
|
}
|
}
|
});
|
|
function swap(array, a, b) {
|
var temp = array[a];
|
array[a] = array[b];
|
array[b] = temp;
|
}
|
|
/**
|
* Resizes the internal array of the heap.
|
*
|
* @param {Number} [length] The length to resize internal array to. Defaults to the current length of the heap.
|
*/
|
Heap.prototype.reserve = function(length) {
|
length = defaultValue(length, this._length);
|
this._array.length = length;
|
};
|
|
/**
|
* Update the heap so that index and all descendants satisfy the heap property.
|
*
|
* @param {Number} [index=0] The starting index to heapify from.
|
*/
|
Heap.prototype.heapify = function(index) {
|
index = defaultValue(index, 0);
|
var length = this._length;
|
var comparator = this._comparator;
|
var array = this._array;
|
var candidate = -1;
|
var inserting = true;
|
|
while (inserting) {
|
var right = 2 * (index + 1);
|
var left = right - 1;
|
|
if (left < length && comparator(array[left], array[index]) < 0) {
|
candidate = left;
|
} else {
|
candidate = index;
|
}
|
|
if (right < length && comparator(array[right], array[candidate]) < 0) {
|
candidate = right;
|
}
|
if (candidate !== index) {
|
swap(array, candidate, index);
|
index = candidate;
|
} else {
|
inserting = false;
|
}
|
}
|
};
|
|
/**
|
* Resort the heap.
|
*/
|
Heap.prototype.resort = function() {
|
var length = this._length;
|
for (var i = Math.ceil(length / 2); i >= 0; --i) {
|
this.heapify(i);
|
}
|
};
|
|
/**
|
* Insert an element into the heap. If the length would grow greater than maximumLength
|
* of the heap, extra elements are removed.
|
*
|
* @param {*} element The element to insert
|
*
|
* @return {*} The element that was removed from the heap if the heap is at full capacity.
|
*/
|
Heap.prototype.insert = function(element) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.defined('element', element);
|
//>>includeEnd('debug');
|
|
var array = this._array;
|
var comparator = this._comparator;
|
var maximumLength = this._maximumLength;
|
|
var index = this._length++;
|
if (index < array.length) {
|
array[index] = element;
|
} else {
|
array.push(element);
|
}
|
|
while (index !== 0) {
|
var parent = Math.floor((index - 1) / 2);
|
if (comparator(array[index], array[parent]) < 0) {
|
swap(array, index, parent);
|
index = parent;
|
} else {
|
break;
|
}
|
}
|
|
var removedElement;
|
|
if (defined(maximumLength) && (this._length > maximumLength)) {
|
removedElement = array[maximumLength];
|
this._length = maximumLength;
|
}
|
|
return removedElement;
|
};
|
|
/**
|
* Remove the element specified by index from the heap and return it.
|
*
|
* @param {Number} [index=0] The index to remove.
|
* @returns {*} The specified element of the heap.
|
*/
|
Heap.prototype.pop = function(index) {
|
index = defaultValue(index, 0);
|
if (this._length === 0) {
|
return undefined;
|
}
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.number.lessThan('index', index, this._length);
|
//>>includeEnd('debug');
|
|
var array = this._array;
|
var root = array[index];
|
swap(array, index, --this._length);
|
this.heapify(index);
|
return root;
|
};
|
|
/**
|
* The comparator to use for the heap.
|
* @callback Heap~ComparatorCallback
|
* @param {*} a An element in the heap.
|
* @param {*} b An element in the heap.
|
* @returns {Number} If the result of the comparison is less than 0, sort a to a lower index than b, otherwise sort to a higher index.
|
*/
|
|
module.exports= Heap;
|
|
},{"./Check":129,"./defaultValue":158,"./defineProperties":159,"./defined":160}],139:[function(require,module,exports){
|
var MersenneTwister = require('mersenne-twister');
|
var Check = require('./Check');
|
var defaultValue = require('./defaultValue');
|
var defined = require('./defined');
|
var DeveloperError = require('./DeveloperError');
|
|
'use strict';
|
|
/**
|
* Math functions.
|
*
|
* @exports CesiumMath
|
* @alias Math
|
*/
|
var CesiumMath = {};
|
|
/**
|
* 0.1
|
* @type {Number}
|
* @constant
|
*/
|
CesiumMath.EPSILON1 = 0.1;
|
|
/**
|
* 0.01
|
* @type {Number}
|
* @constant
|
*/
|
CesiumMath.EPSILON2 = 0.01;
|
|
/**
|
* 0.001
|
* @type {Number}
|
* @constant
|
*/
|
CesiumMath.EPSILON3 = 0.001;
|
|
/**
|
* 0.0001
|
* @type {Number}
|
* @constant
|
*/
|
CesiumMath.EPSILON4 = 0.0001;
|
|
/**
|
* 0.00001
|
* @type {Number}
|
* @constant
|
*/
|
CesiumMath.EPSILON5 = 0.00001;
|
|
/**
|
* 0.000001
|
* @type {Number}
|
* @constant
|
*/
|
CesiumMath.EPSILON6 = 0.000001;
|
|
/**
|
* 0.0000001
|
* @type {Number}
|
* @constant
|
*/
|
CesiumMath.EPSILON7 = 0.0000001;
|
|
/**
|
* 0.00000001
|
* @type {Number}
|
* @constant
|
*/
|
CesiumMath.EPSILON8 = 0.00000001;
|
|
/**
|
* 0.000000001
|
* @type {Number}
|
* @constant
|
*/
|
CesiumMath.EPSILON9 = 0.000000001;
|
|
/**
|
* 0.0000000001
|
* @type {Number}
|
* @constant
|
*/
|
CesiumMath.EPSILON10 = 0.0000000001;
|
|
/**
|
* 0.00000000001
|
* @type {Number}
|
* @constant
|
*/
|
CesiumMath.EPSILON11 = 0.00000000001;
|
|
/**
|
* 0.000000000001
|
* @type {Number}
|
* @constant
|
*/
|
CesiumMath.EPSILON12 = 0.000000000001;
|
|
/**
|
* 0.0000000000001
|
* @type {Number}
|
* @constant
|
*/
|
CesiumMath.EPSILON13 = 0.0000000000001;
|
|
/**
|
* 0.00000000000001
|
* @type {Number}
|
* @constant
|
*/
|
CesiumMath.EPSILON14 = 0.00000000000001;
|
|
/**
|
* 0.000000000000001
|
* @type {Number}
|
* @constant
|
*/
|
CesiumMath.EPSILON15 = 0.000000000000001;
|
|
/**
|
* 0.0000000000000001
|
* @type {Number}
|
* @constant
|
*/
|
CesiumMath.EPSILON16 = 0.0000000000000001;
|
|
/**
|
* 0.00000000000000001
|
* @type {Number}
|
* @constant
|
*/
|
CesiumMath.EPSILON17 = 0.00000000000000001;
|
|
/**
|
* 0.000000000000000001
|
* @type {Number}
|
* @constant
|
*/
|
CesiumMath.EPSILON18 = 0.000000000000000001;
|
|
/**
|
* 0.0000000000000000001
|
* @type {Number}
|
* @constant
|
*/
|
CesiumMath.EPSILON19 = 0.0000000000000000001;
|
|
/**
|
* 0.00000000000000000001
|
* @type {Number}
|
* @constant
|
*/
|
CesiumMath.EPSILON20 = 0.00000000000000000001;
|
|
/**
|
* 0.000000000000000000001
|
* @type {Number}
|
* @constant
|
*/
|
CesiumMath.EPSILON21 = 0.000000000000000000001;
|
|
/**
|
* The gravitational parameter of the Earth in meters cubed
|
* per second squared as defined by the WGS84 model: 3.986004418e14
|
* @type {Number}
|
* @constant
|
*/
|
CesiumMath.GRAVITATIONALPARAMETER = 3.986004418e14;
|
|
/**
|
* Radius of the sun in meters: 6.955e8
|
* @type {Number}
|
* @constant
|
*/
|
CesiumMath.SOLAR_RADIUS = 6.955e8;
|
|
/**
|
* The mean radius of the moon, according to the "Report of the IAU/IAG Working Group on
|
* Cartographic Coordinates and Rotational Elements of the Planets and satellites: 2000",
|
* Celestial Mechanics 82: 83-110, 2002.
|
* @type {Number}
|
* @constant
|
*/
|
CesiumMath.LUNAR_RADIUS = 1737400.0;
|
|
/**
|
* 64 * 1024
|
* @type {Number}
|
* @constant
|
*/
|
CesiumMath.SIXTY_FOUR_KILOBYTES = 64 * 1024;
|
|
/**
|
* Returns the sign of the value; 1 if the value is positive, -1 if the value is
|
* negative, or 0 if the value is 0.
|
*
|
* @function
|
* @param {Number} value The value to return the sign of.
|
* @returns {Number} The sign of value.
|
*/
|
CesiumMath.sign = defaultValue(Math.sign, function sign(value) {
|
value = +value; // coerce to number
|
if (value === 0 || value !== value) {
|
// zero or NaN
|
return value;
|
}
|
return value > 0 ? 1 : -1;
|
});
|
|
/**
|
* Returns 1.0 if the given value is positive or zero, and -1.0 if it is negative.
|
* This is similar to {@link CesiumMath#sign} except that returns 1.0 instead of
|
* 0.0 when the input value is 0.0.
|
* @param {Number} value The value to return the sign of.
|
* @returns {Number} The sign of value.
|
*/
|
CesiumMath.signNotZero = function (value) {
|
return value < 0.0 ? -1.0 : 1.0;
|
};
|
|
/**
|
* Converts a scalar value in the range [-1.0, 1.0] to a SNORM in the range [0, rangeMax]
|
* @param {Number} value The scalar value in the range [-1.0, 1.0]
|
* @param {Number} [rangeMax=255] The maximum value in the mapped range, 255 by default.
|
* @returns {Number} A SNORM value, where 0 maps to -1.0 and rangeMax maps to 1.0.
|
*
|
* @see CesiumMath.fromSNorm
|
*/
|
CesiumMath.toSNorm = function (value, rangeMax) {
|
rangeMax = defaultValue(rangeMax, 255);
|
return Math.round((CesiumMath.clamp(value, -1.0, 1.0) * 0.5 + 0.5) * rangeMax);
|
};
|
|
/**
|
* Converts a SNORM value in the range [0, rangeMax] to a scalar in the range [-1.0, 1.0].
|
* @param {Number} value SNORM value in the range [0, 255]
|
* @param {Number} [rangeMax=255] The maximum value in the SNORM range, 255 by default.
|
* @returns {Number} Scalar in the range [-1.0, 1.0].
|
*
|
* @see CesiumMath.toSNorm
|
*/
|
CesiumMath.fromSNorm = function (value, rangeMax) {
|
rangeMax = defaultValue(rangeMax, 255);
|
return CesiumMath.clamp(value, 0.0, rangeMax) / rangeMax * 2.0 - 1.0;
|
};
|
|
/**
|
* Returns the hyperbolic sine of a number.
|
* The hyperbolic sine of <em>value</em> is defined to be
|
* (<em>e<sup>x</sup> - e<sup>-x</sup></em>)/2.0
|
* where <i>e</i> is Euler's number, approximately 2.71828183.
|
*
|
* <p>Special cases:
|
* <ul>
|
* <li>If the argument is NaN, then the result is NaN.</li>
|
*
|
* <li>If the argument is infinite, then the result is an infinity
|
* with the same sign as the argument.</li>
|
*
|
* <li>If the argument is zero, then the result is a zero with the
|
* same sign as the argument.</li>
|
* </ul>
|
*</p>
|
*
|
* @function
|
* @param {Number} value The number whose hyperbolic sine is to be returned.
|
* @returns {Number} The hyperbolic sine of <code>value</code>.
|
*/
|
CesiumMath.sinh = defaultValue(Math.sinh, function sinh(value) {
|
return (Math.exp(value) - Math.exp(-value)) / 2.0;
|
});
|
|
/**
|
* Returns the hyperbolic cosine of a number.
|
* The hyperbolic cosine of <strong>value</strong> is defined to be
|
* (<em>e<sup>x</sup> + e<sup>-x</sup></em>)/2.0
|
* where <i>e</i> is Euler's number, approximately 2.71828183.
|
*
|
* <p>Special cases:
|
* <ul>
|
* <li>If the argument is NaN, then the result is NaN.</li>
|
*
|
* <li>If the argument is infinite, then the result is positive infinity.</li>
|
*
|
* <li>If the argument is zero, then the result is 1.0.</li>
|
* </ul>
|
*</p>
|
*
|
* @function
|
* @param {Number} value The number whose hyperbolic cosine is to be returned.
|
* @returns {Number} The hyperbolic cosine of <code>value</code>.
|
*/
|
CesiumMath.cosh = defaultValue(Math.cosh, function cosh(value) {
|
return (Math.exp(value) + Math.exp(-value)) / 2.0;
|
});
|
|
/**
|
* Computes the linear interpolation of two values.
|
*
|
* @param {Number} p The start value to interpolate.
|
* @param {Number} q The end value to interpolate.
|
* @param {Number} time The time of interpolation generally in the range <code>[0.0, 1.0]</code>.
|
* @returns {Number} The linearly interpolated value.
|
*
|
* @example
|
* var n = Cesium.Math.lerp(0.0, 2.0, 0.5); // returns 1.0
|
*/
|
CesiumMath.lerp = function (p, q, time) {
|
return ((1.0 - time) * p) + (time * q);
|
};
|
|
/**
|
* pi
|
*
|
* @type {Number}
|
* @constant
|
*/
|
CesiumMath.PI = Math.PI;
|
|
/**
|
* 1/pi
|
*
|
* @type {Number}
|
* @constant
|
*/
|
CesiumMath.ONE_OVER_PI = 1.0 / Math.PI;
|
|
/**
|
* pi/2
|
*
|
* @type {Number}
|
* @constant
|
*/
|
CesiumMath.PI_OVER_TWO = Math.PI / 2.0;
|
|
/**
|
* pi/3
|
*
|
* @type {Number}
|
* @constant
|
*/
|
CesiumMath.PI_OVER_THREE = Math.PI / 3.0;
|
|
/**
|
* pi/4
|
*
|
* @type {Number}
|
* @constant
|
*/
|
CesiumMath.PI_OVER_FOUR = Math.PI / 4.0;
|
|
/**
|
* pi/6
|
*
|
* @type {Number}
|
* @constant
|
*/
|
CesiumMath.PI_OVER_SIX = Math.PI / 6.0;
|
|
/**
|
* 3pi/2
|
*
|
* @type {Number}
|
* @constant
|
*/
|
CesiumMath.THREE_PI_OVER_TWO = 3.0 * Math.PI / 2.0;
|
|
/**
|
* 2pi
|
*
|
* @type {Number}
|
* @constant
|
*/
|
CesiumMath.TWO_PI = 2.0 * Math.PI;
|
|
/**
|
* 1/2pi
|
*
|
* @type {Number}
|
* @constant
|
*/
|
CesiumMath.ONE_OVER_TWO_PI = 1.0 / (2.0 * Math.PI);
|
|
/**
|
* The number of radians in a degree.
|
*
|
* @type {Number}
|
* @constant
|
* @default Math.PI / 180.0
|
*/
|
CesiumMath.RADIANS_PER_DEGREE = Math.PI / 180.0;
|
|
/**
|
* The number of degrees in a radian.
|
*
|
* @type {Number}
|
* @constant
|
* @default 180.0 / Math.PI
|
*/
|
CesiumMath.DEGREES_PER_RADIAN = 180.0 / Math.PI;
|
|
/**
|
* The number of radians in an arc second.
|
*
|
* @type {Number}
|
* @constant
|
* @default {@link CesiumMath.RADIANS_PER_DEGREE} / 3600.0
|
*/
|
CesiumMath.RADIANS_PER_ARCSECOND = CesiumMath.RADIANS_PER_DEGREE / 3600.0;
|
|
/**
|
* Converts degrees to radians.
|
* @param {Number} degrees The angle to convert in degrees.
|
* @returns {Number} The corresponding angle in radians.
|
*/
|
CesiumMath.toRadians = function (degrees) {
|
//>>includeStart('debug', pragmas.debug);
|
if (!defined(degrees)) {
|
throw new DeveloperError('degrees is required.');
|
}
|
//>>includeEnd('debug');
|
return degrees * CesiumMath.RADIANS_PER_DEGREE;
|
};
|
|
/**
|
* Converts radians to degrees.
|
* @param {Number} radians The angle to convert in radians.
|
* @returns {Number} The corresponding angle in degrees.
|
*/
|
CesiumMath.toDegrees = function (radians) {
|
//>>includeStart('debug', pragmas.debug);
|
if (!defined(radians)) {
|
throw new DeveloperError('radians is required.');
|
}
|
//>>includeEnd('debug');
|
return radians * CesiumMath.DEGREES_PER_RADIAN;
|
};
|
|
/**
|
* Converts a longitude value, in radians, to the range [<code>-Math.PI</code>, <code>Math.PI</code>).
|
*
|
* @param {Number} angle The longitude value, in radians, to convert to the range [<code>-Math.PI</code>, <code>Math.PI</code>).
|
* @returns {Number} The equivalent longitude value in the range [<code>-Math.PI</code>, <code>Math.PI</code>).
|
*
|
* @example
|
* // Convert 270 degrees to -90 degrees longitude
|
* var longitude = Cesium.Math.convertLongitudeRange(Cesium.Math.toRadians(270.0));
|
*/
|
CesiumMath.convertLongitudeRange = function (angle) {
|
//>>includeStart('debug', pragmas.debug);
|
if (!defined(angle)) {
|
throw new DeveloperError('angle is required.');
|
}
|
//>>includeEnd('debug');
|
var twoPi = CesiumMath.TWO_PI;
|
|
var simplified = angle - Math.floor(angle / twoPi) * twoPi;
|
|
if (simplified < -Math.PI) {
|
return simplified + twoPi;
|
}
|
if (simplified >= Math.PI) {
|
return simplified - twoPi;
|
}
|
|
return simplified;
|
};
|
|
/**
|
* Convenience function that clamps a latitude value, in radians, to the range [<code>-Math.PI/2</code>, <code>Math.PI/2</code>).
|
* Useful for sanitizing data before use in objects requiring correct range.
|
*
|
* @param {Number} angle The latitude value, in radians, to clamp to the range [<code>-Math.PI/2</code>, <code>Math.PI/2</code>).
|
* @returns {Number} The latitude value clamped to the range [<code>-Math.PI/2</code>, <code>Math.PI/2</code>).
|
*
|
* @example
|
* // Clamp 108 degrees latitude to 90 degrees latitude
|
* var latitude = Cesium.Math.clampToLatitudeRange(Cesium.Math.toRadians(108.0));
|
*/
|
CesiumMath.clampToLatitudeRange = function (angle) {
|
//>>includeStart('debug', pragmas.debug);
|
if (!defined(angle)) {
|
throw new DeveloperError('angle is required.');
|
}
|
//>>includeEnd('debug');
|
|
return CesiumMath.clamp(angle, -1 * CesiumMath.PI_OVER_TWO, CesiumMath.PI_OVER_TWO);
|
};
|
|
/**
|
* Produces an angle in the range -Pi <= angle <= Pi which is equivalent to the provided angle.
|
*
|
* @param {Number} angle in radians
|
* @returns {Number} The angle in the range [<code>-CesiumMath.PI</code>, <code>CesiumMath.PI</code>].
|
*/
|
CesiumMath.negativePiToPi = function (angle) {
|
//>>includeStart('debug', pragmas.debug);
|
if (!defined(angle)) {
|
throw new DeveloperError('angle is required.');
|
}
|
//>>includeEnd('debug');
|
return CesiumMath.zeroToTwoPi(angle + CesiumMath.PI) - CesiumMath.PI;
|
};
|
|
/**
|
* Produces an angle in the range 0 <= angle <= 2Pi which is equivalent to the provided angle.
|
*
|
* @param {Number} angle in radians
|
* @returns {Number} The angle in the range [0, <code>CesiumMath.TWO_PI</code>].
|
*/
|
CesiumMath.zeroToTwoPi = function (angle) {
|
//>>includeStart('debug', pragmas.debug);
|
if (!defined(angle)) {
|
throw new DeveloperError('angle is required.');
|
}
|
//>>includeEnd('debug');
|
var mod = CesiumMath.mod(angle, CesiumMath.TWO_PI);
|
if (Math.abs(mod) < CesiumMath.EPSILON14 && Math.abs(angle) > CesiumMath.EPSILON14) {
|
return CesiumMath.TWO_PI;
|
}
|
return mod;
|
};
|
|
/**
|
* The modulo operation that also works for negative dividends.
|
*
|
* @param {Number} m The dividend.
|
* @param {Number} n The divisor.
|
* @returns {Number} The remainder.
|
*/
|
CesiumMath.mod = function (m, n) {
|
//>>includeStart('debug', pragmas.debug);
|
if (!defined(m)) {
|
throw new DeveloperError('m is required.');
|
}
|
if (!defined(n)) {
|
throw new DeveloperError('n is required.');
|
}
|
//>>includeEnd('debug');
|
return ((m % n) + n) % n;
|
};
|
|
/**
|
* Determines if two values are equal using an absolute or relative tolerance test. This is useful
|
* to avoid problems due to roundoff error when comparing floating-point values directly. The values are
|
* first compared using an absolute tolerance test. If that fails, a relative tolerance test is performed.
|
* Use this test if you are unsure of the magnitudes of left and right.
|
*
|
* @param {Number} left The first value to compare.
|
* @param {Number} right The other value to compare.
|
* @param {Number} relativeEpsilon The maximum inclusive delta between <code>left</code> and <code>right</code> for the relative tolerance test.
|
* @param {Number} [absoluteEpsilon=relativeEpsilon] The maximum inclusive delta between <code>left</code> and <code>right</code> for the absolute tolerance test.
|
* @returns {Boolean} <code>true</code> if the values are equal within the epsilon; otherwise, <code>false</code>.
|
*
|
* @example
|
* var a = Cesium.Math.equalsEpsilon(0.0, 0.01, Cesium.Math.EPSILON2); // true
|
* var b = Cesium.Math.equalsEpsilon(0.0, 0.1, Cesium.Math.EPSILON2); // false
|
* var c = Cesium.Math.equalsEpsilon(3699175.1634344, 3699175.2, Cesium.Math.EPSILON7); // true
|
* var d = Cesium.Math.equalsEpsilon(3699175.1634344, 3699175.2, Cesium.Math.EPSILON9); // false
|
*/
|
CesiumMath.equalsEpsilon = function (left, right, relativeEpsilon, absoluteEpsilon) {
|
//>>includeStart('debug', pragmas.debug);
|
if (!defined(left)) {
|
throw new DeveloperError('left is required.');
|
}
|
if (!defined(right)) {
|
throw new DeveloperError('right is required.');
|
}
|
if (!defined(relativeEpsilon)) {
|
throw new DeveloperError('relativeEpsilon is required.');
|
}
|
//>>includeEnd('debug');
|
absoluteEpsilon = defaultValue(absoluteEpsilon, relativeEpsilon);
|
var absDiff = Math.abs(left - right);
|
return absDiff <= absoluteEpsilon || absDiff <= relativeEpsilon * Math.max(Math.abs(left), Math.abs(right));
|
};
|
|
/**
|
* Determines if the left value is less than the right value. If the two values are within
|
* <code>absoluteEpsilon</code> of each other, they are considered equal and this function returns false.
|
*
|
* @param {Number} left The first number to compare.
|
* @param {Number} right The second number to compare.
|
* @param {Number} absoluteEpsilon The absolute epsilon to use in comparison.
|
* @returns {Boolean} <code>true</code> if <code>left</code> is less than <code>right</code> by more than
|
* <code>absoluteEpsilon<code>. <code>false</code> if <code>left</code> is greater or if the two
|
* values are nearly equal.
|
*/
|
CesiumMath.lessThan = function (left, right, absoluteEpsilon) {
|
//>>includeStart('debug', pragmas.debug);
|
if (!defined(left)) {
|
throw new DeveloperError('first is required.');
|
}
|
if (!defined(right)) {
|
throw new DeveloperError('second is required.');
|
}
|
if (!defined(absoluteEpsilon)) {
|
throw new DeveloperError('relativeEpsilon is required.');
|
}
|
//>>includeEnd('debug');
|
return left - right < -absoluteEpsilon;
|
};
|
|
/**
|
* Determines if the left value is less than or equal to the right value. If the two values are within
|
* <code>absoluteEpsilon</code> of each other, they are considered equal and this function returns true.
|
*
|
* @param {Number} left The first number to compare.
|
* @param {Number} right The second number to compare.
|
* @param {Number} absoluteEpsilon The absolute epsilon to use in comparison.
|
* @returns {Boolean} <code>true</code> if <code>left</code> is less than <code>right</code> or if the
|
* the values are nearly equal.
|
*/
|
CesiumMath.lessThanOrEquals = function (left, right, absoluteEpsilon) {
|
//>>includeStart('debug', pragmas.debug);
|
if (!defined(left)) {
|
throw new DeveloperError('first is required.');
|
}
|
if (!defined(right)) {
|
throw new DeveloperError('second is required.');
|
}
|
if (!defined(absoluteEpsilon)) {
|
throw new DeveloperError('relativeEpsilon is required.');
|
}
|
//>>includeEnd('debug');
|
return left - right < absoluteEpsilon;
|
};
|
|
/**
|
* Determines if the left value is greater the right value. If the two values are within
|
* <code>absoluteEpsilon</code> of each other, they are considered equal and this function returns false.
|
*
|
* @param {Number} left The first number to compare.
|
* @param {Number} right The second number to compare.
|
* @param {Number} absoluteEpsilon The absolute epsilon to use in comparison.
|
* @returns {Boolean} <code>true</code> if <code>left</code> is greater than <code>right</code> by more than
|
* <code>absoluteEpsilon<code>. <code>false</code> if <code>left</code> is less or if the two
|
* values are nearly equal.
|
*/
|
CesiumMath.greaterThan = function (left, right, absoluteEpsilon) {
|
//>>includeStart('debug', pragmas.debug);
|
if (!defined(left)) {
|
throw new DeveloperError('first is required.');
|
}
|
if (!defined(right)) {
|
throw new DeveloperError('second is required.');
|
}
|
if (!defined(absoluteEpsilon)) {
|
throw new DeveloperError('relativeEpsilon is required.');
|
}
|
//>>includeEnd('debug');
|
return left - right > absoluteEpsilon;
|
};
|
|
/**
|
* Determines if the left value is greater than or equal to the right value. If the two values are within
|
* <code>absoluteEpsilon</code> of each other, they are considered equal and this function returns true.
|
*
|
* @param {Number} left The first number to compare.
|
* @param {Number} right The second number to compare.
|
* @param {Number} absoluteEpsilon The absolute epsilon to use in comparison.
|
* @returns {Boolean} <code>true</code> if <code>left</code> is greater than <code>right</code> or if the
|
* the values are nearly equal.
|
*/
|
CesiumMath.greaterThanOrEquals = function (left, right, absoluteEpsilon) {
|
//>>includeStart('debug', pragmas.debug);
|
if (!defined(left)) {
|
throw new DeveloperError('first is required.');
|
}
|
if (!defined(right)) {
|
throw new DeveloperError('second is required.');
|
}
|
if (!defined(absoluteEpsilon)) {
|
throw new DeveloperError('relativeEpsilon is required.');
|
}
|
//>>includeEnd('debug');
|
return left - right > -absoluteEpsilon;
|
};
|
|
var factorials = [1];
|
|
/**
|
* Computes the factorial of the provided number.
|
*
|
* @param {Number} n The number whose factorial is to be computed.
|
* @returns {Number} The factorial of the provided number or undefined if the number is less than 0.
|
*
|
* @exception {DeveloperError} A number greater than or equal to 0 is required.
|
*
|
*
|
* @example
|
* //Compute 7!, which is equal to 5040
|
* var computedFactorial = Cesium.Math.factorial(7);
|
*
|
* @see {@link http://en.wikipedia.org/wiki/Factorial|Factorial on Wikipedia}
|
*/
|
CesiumMath.factorial = function (n) {
|
//>>includeStart('debug', pragmas.debug);
|
if (typeof n !== 'number' || n < 0) {
|
throw new DeveloperError('A number greater than or equal to 0 is required.');
|
}
|
//>>includeEnd('debug');
|
|
var length = factorials.length;
|
if (n >= length) {
|
var sum = factorials[length - 1];
|
for (var i = length; i <= n; i++) {
|
factorials.push(sum * i);
|
}
|
}
|
return factorials[n];
|
};
|
|
/**
|
* Increments a number with a wrapping to a minimum value if the number exceeds the maximum value.
|
*
|
* @param {Number} [n] The number to be incremented.
|
* @param {Number} [maximumValue] The maximum incremented value before rolling over to the minimum value.
|
* @param {Number} [minimumValue=0.0] The number reset to after the maximum value has been exceeded.
|
* @returns {Number} The incremented number.
|
*
|
* @exception {DeveloperError} Maximum value must be greater than minimum value.
|
*
|
* @example
|
* var n = Cesium.Math.incrementWrap(5, 10, 0); // returns 6
|
* var n = Cesium.Math.incrementWrap(10, 10, 0); // returns 0
|
*/
|
CesiumMath.incrementWrap = function (n, maximumValue, minimumValue) {
|
minimumValue = defaultValue(minimumValue, 0.0);
|
|
//>>includeStart('debug', pragmas.debug);
|
if (!defined(n)) {
|
throw new DeveloperError('n is required.');
|
}
|
if (maximumValue <= minimumValue) {
|
throw new DeveloperError('maximumValue must be greater than minimumValue.');
|
}
|
//>>includeEnd('debug');
|
|
++n;
|
if (n > maximumValue) {
|
n = minimumValue;
|
}
|
return n;
|
};
|
|
/**
|
* Determines if a positive integer is a power of two.
|
*
|
* @param {Number} n The positive integer to test.
|
* @returns {Boolean} <code>true</code> if the number if a power of two; otherwise, <code>false</code>.
|
*
|
* @exception {DeveloperError} A number greater than or equal to 0 is required.
|
*
|
* @example
|
* var t = Cesium.Math.isPowerOfTwo(16); // true
|
* var f = Cesium.Math.isPowerOfTwo(20); // false
|
*/
|
CesiumMath.isPowerOfTwo = function (n) {
|
//>>includeStart('debug', pragmas.debug);
|
if (typeof n !== 'number' || n < 0) {
|
throw new DeveloperError('A number greater than or equal to 0 is required.');
|
}
|
//>>includeEnd('debug');
|
|
return (n !== 0) && ((n & (n - 1)) === 0);
|
};
|
|
/**
|
* Computes the next power-of-two integer greater than or equal to the provided positive integer.
|
*
|
* @param {Number} n The positive integer to test.
|
* @returns {Number} The next power-of-two integer.
|
*
|
* @exception {DeveloperError} A number greater than or equal to 0 is required.
|
*
|
* @example
|
* var n = Cesium.Math.nextPowerOfTwo(29); // 32
|
* var m = Cesium.Math.nextPowerOfTwo(32); // 32
|
*/
|
CesiumMath.nextPowerOfTwo = function (n) {
|
//>>includeStart('debug', pragmas.debug);
|
if (typeof n !== 'number' || n < 0) {
|
throw new DeveloperError('A number greater than or equal to 0 is required.');
|
}
|
//>>includeEnd('debug');
|
|
// From http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
|
--n;
|
n |= n >> 1;
|
n |= n >> 2;
|
n |= n >> 4;
|
n |= n >> 8;
|
n |= n >> 16;
|
++n;
|
|
return n;
|
};
|
|
/**
|
* Constraint a value to lie between two values.
|
*
|
* @param {Number} value The value to constrain.
|
* @param {Number} min The minimum value.
|
* @param {Number} max The maximum value.
|
* @returns {Number} The value clamped so that min <= value <= max.
|
*/
|
CesiumMath.clamp = function (value, min, max) {
|
//>>includeStart('debug', pragmas.debug);
|
if (!defined(value)) {
|
throw new DeveloperError('value is required');
|
}
|
if (!defined(min)) {
|
throw new DeveloperError('min is required.');
|
}
|
if (!defined(max)) {
|
throw new DeveloperError('max is required.');
|
}
|
//>>includeEnd('debug');
|
return value < min ? min : value > max ? max : value;
|
};
|
|
var randomNumberGenerator = new MersenneTwister();
|
|
/**
|
* Sets the seed used by the random number generator
|
* in {@link CesiumMath#nextRandomNumber}.
|
*
|
* @param {Number} seed An integer used as the seed.
|
*/
|
CesiumMath.setRandomNumberSeed = function (seed) {
|
//>>includeStart('debug', pragmas.debug);
|
if (!defined(seed)) {
|
throw new DeveloperError('seed is required.');
|
}
|
//>>includeEnd('debug');
|
|
randomNumberGenerator = new MersenneTwister(seed);
|
};
|
|
/**
|
* Generates a random floating point number in the range of [0.0, 1.0)
|
* using a Mersenne twister.
|
*
|
* @returns {Number} A random number in the range of [0.0, 1.0).
|
*
|
* @see CesiumMath.setRandomNumberSeed
|
* @see {@link http://en.wikipedia.org/wiki/Mersenne_twister|Mersenne twister on Wikipedia}
|
*/
|
CesiumMath.nextRandomNumber = function () {
|
return randomNumberGenerator.random();
|
};
|
|
/**
|
* Generates a random number between two numbers.
|
*
|
* @param {Number} min The minimum value.
|
* @param {Number} max The maximum value.
|
* @returns {Number} A random number between the min and max.
|
*/
|
CesiumMath.randomBetween = function (min, max) {
|
return CesiumMath.nextRandomNumber() * (max - min) + min;
|
};
|
|
/**
|
* Computes <code>Math.acos(value)</code>, but first clamps <code>value</code> to the range [-1.0, 1.0]
|
* so that the function will never return NaN.
|
*
|
* @param {Number} value The value for which to compute acos.
|
* @returns {Number} The acos of the value if the value is in the range [-1.0, 1.0], or the acos of -1.0 or 1.0,
|
* whichever is closer, if the value is outside the range.
|
*/
|
CesiumMath.acosClamped = function (value) {
|
//>>includeStart('debug', pragmas.debug);
|
if (!defined(value)) {
|
throw new DeveloperError('value is required.');
|
}
|
//>>includeEnd('debug');
|
return Math.acos(CesiumMath.clamp(value, -1.0, 1.0));
|
};
|
|
/**
|
* Computes <code>Math.asin(value)</code>, but first clamps <code>value</code> to the range [-1.0, 1.0]
|
* so that the function will never return NaN.
|
*
|
* @param {Number} value The value for which to compute asin.
|
* @returns {Number} The asin of the value if the value is in the range [-1.0, 1.0], or the asin of -1.0 or 1.0,
|
* whichever is closer, if the value is outside the range.
|
*/
|
CesiumMath.asinClamped = function (value) {
|
//>>includeStart('debug', pragmas.debug);
|
if (!defined(value)) {
|
throw new DeveloperError('value is required.');
|
}
|
//>>includeEnd('debug');
|
return Math.asin(CesiumMath.clamp(value, -1.0, 1.0));
|
};
|
|
/**
|
* Finds the chord length between two points given the circle's radius and the angle between the points.
|
*
|
* @param {Number} angle The angle between the two points.
|
* @param {Number} radius The radius of the circle.
|
* @returns {Number} The chord length.
|
*/
|
CesiumMath.chordLength = function (angle, radius) {
|
//>>includeStart('debug', pragmas.debug);
|
if (!defined(angle)) {
|
throw new DeveloperError('angle is required.');
|
}
|
if (!defined(radius)) {
|
throw new DeveloperError('radius is required.');
|
}
|
//>>includeEnd('debug');
|
return 2.0 * radius * Math.sin(angle * 0.5);
|
};
|
|
/**
|
* Finds the logarithm of a number to a base.
|
*
|
* @param {Number} number The number.
|
* @param {Number} base The base.
|
* @returns {Number} The result.
|
*/
|
CesiumMath.logBase = function (number, base) {
|
//>>includeStart('debug', pragmas.debug);
|
if (!defined(number)) {
|
throw new DeveloperError('number is required.');
|
}
|
if (!defined(base)) {
|
throw new DeveloperError('base is required.');
|
}
|
//>>includeEnd('debug');
|
return Math.log(number) / Math.log(base);
|
};
|
|
/**
|
* Finds the cube root of a number.
|
* Returns NaN if <code>number</code> is not provided.
|
*
|
* @function
|
* @param {Number} [number] The number.
|
* @returns {Number} The result.
|
*/
|
CesiumMath.cbrt = defaultValue(Math.cbrt, function cbrt(number) {
|
var result = Math.pow(Math.abs(number), 1.0 / 3.0);
|
return number < 0.0 ? -result : result;
|
});
|
|
/**
|
* Finds the base 2 logarithm of a number.
|
*
|
* @function
|
* @param {Number} number The number.
|
* @returns {Number} The result.
|
*/
|
CesiumMath.log2 = defaultValue(Math.log2, function log2(number) {
|
return Math.log(number) * Math.LOG2E;
|
});
|
|
/**
|
* @private
|
*/
|
CesiumMath.fog = function (distanceToCamera, density) {
|
var scalar = distanceToCamera * density;
|
return 1.0 - Math.exp(-(scalar * scalar));
|
};
|
|
/**
|
* Computes a fast approximation of Atan for input in the range [-1, 1].
|
*
|
* Based on Michal Drobot's approximation from ShaderFastLibs,
|
* which in turn is based on "Efficient approximations for the arctangent function,"
|
* Rajan, S. Sichun Wang Inkol, R. Joyal, A., May 2006.
|
* Adapted from ShaderFastLibs under MIT License.
|
*
|
* @param {Number} x An input number in the range [-1, 1]
|
* @returns {Number} An approximation of atan(x)
|
*/
|
CesiumMath.fastApproximateAtan = function (x) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.number('x', x);
|
//>>includeEnd('debug');
|
|
return x * (-0.1784 * Math.abs(x) - 0.0663 * x * x + 1.0301);
|
};
|
|
/**
|
* Computes a fast approximation of Atan2(x, y) for arbitrary input scalars.
|
*
|
* Range reduction math based on nvidia's cg reference implementation: http://developer.download.nvidia.com/cg/atan2.html
|
*
|
* @param {Number} x An input number that isn't zero if y is zero.
|
* @param {Number} y An input number that isn't zero if x is zero.
|
* @returns {Number} An approximation of atan2(x, y)
|
*/
|
CesiumMath.fastApproximateAtan2 = function (x, y) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.number('x', x);
|
Check.typeOf.number('y', y);
|
//>>includeEnd('debug');
|
|
// atan approximations are usually only reliable over [-1, 1]
|
// So reduce the range by flipping whether x or y is on top based on which is bigger.
|
var opposite;
|
var adjacent;
|
var t = Math.abs(x); // t used as swap and atan result.
|
opposite = Math.abs(y);
|
adjacent = Math.max(t, opposite);
|
opposite = Math.min(t, opposite);
|
|
var oppositeOverAdjacent = opposite / adjacent;
|
//>>includeStart('debug', pragmas.debug);
|
if (isNaN(oppositeOverAdjacent)) {
|
throw new DeveloperError('either x or y must be nonzero');
|
}
|
//>>includeEnd('debug');
|
t = CesiumMath.fastApproximateAtan(oppositeOverAdjacent);
|
|
// Undo range reduction
|
t = Math.abs(y) > Math.abs(x) ? CesiumMath.PI_OVER_TWO - t : t;
|
t = x < 0.0 ? CesiumMath.PI - t : t;
|
t = y < 0.0 ? -t : t;
|
return t;
|
};
|
|
module.exports = CesiumMath;
|
|
},{"./Check":129,"./DeveloperError":131,"./defaultValue":158,"./defined":160,"mersenne-twister":60}],140:[function(require,module,exports){
|
var Cartographic=require('./Cartographic');
|
var Check=require('./Check');
|
var defaultValue=require('./defaultValue');
|
var defined=require('./defined');
|
var defineProperties=require('./defineProperties');
|
var Ellipsoid=require('./Ellipsoid');
|
var freezeObject=require('./freezeObject');
|
var CesiumMath=require('./Math');
|
|
'use strict';
|
|
/**
|
* A two dimensional region specified as longitude and latitude coordinates.
|
*
|
* @alias Rectangle
|
* @constructor
|
*
|
* @param {Number} [west=0.0] The westernmost longitude, in radians, in the range [-Pi, Pi].
|
* @param {Number} [south=0.0] The southernmost latitude, in radians, in the range [-Pi/2, Pi/2].
|
* @param {Number} [east=0.0] The easternmost longitude, in radians, in the range [-Pi, Pi].
|
* @param {Number} [north=0.0] The northernmost latitude, in radians, in the range [-Pi/2, Pi/2].
|
*
|
* @see Packable
|
*/
|
function Rectangle(west, south, east, north) {
|
/**
|
* The westernmost longitude in radians in the range [-Pi, Pi].
|
*
|
* @type {Number}
|
* @default 0.0
|
*/
|
this.west = defaultValue(west, 0.0);
|
|
/**
|
* The southernmost latitude in radians in the range [-Pi/2, Pi/2].
|
*
|
* @type {Number}
|
* @default 0.0
|
*/
|
this.south = defaultValue(south, 0.0);
|
|
/**
|
* The easternmost longitude in radians in the range [-Pi, Pi].
|
*
|
* @type {Number}
|
* @default 0.0
|
*/
|
this.east = defaultValue(east, 0.0);
|
|
/**
|
* The northernmost latitude in radians in the range [-Pi/2, Pi/2].
|
*
|
* @type {Number}
|
* @default 0.0
|
*/
|
this.north = defaultValue(north, 0.0);
|
}
|
|
defineProperties(Rectangle.prototype, {
|
/**
|
* Gets the width of the rectangle in radians.
|
* @memberof Rectangle.prototype
|
* @type {Number}
|
*/
|
width : {
|
get : function() {
|
return Rectangle.computeWidth(this);
|
}
|
},
|
|
/**
|
* Gets the height of the rectangle in radians.
|
* @memberof Rectangle.prototype
|
* @type {Number}
|
*/
|
height : {
|
get : function() {
|
return Rectangle.computeHeight(this);
|
}
|
}
|
});
|
|
/**
|
* The number of elements used to pack the object into an array.
|
* @type {Number}
|
*/
|
Rectangle.packedLength = 4;
|
|
/**
|
* Stores the provided instance into the provided array.
|
*
|
* @param {Rectangle} value The value to pack.
|
* @param {Number[]} array The array to pack into.
|
* @param {Number} [startingIndex=0] The index into the array at which to start packing the elements.
|
*
|
* @returns {Number[]} The array that was packed into
|
*/
|
Rectangle.pack = function(value, array, startingIndex) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('value', value);
|
Check.defined('array', array);
|
//>>includeEnd('debug');
|
|
startingIndex = defaultValue(startingIndex, 0);
|
|
array[startingIndex++] = value.west;
|
array[startingIndex++] = value.south;
|
array[startingIndex++] = value.east;
|
array[startingIndex] = value.north;
|
|
return array;
|
};
|
|
/**
|
* Retrieves an instance from a packed array.
|
*
|
* @param {Number[]} array The packed array.
|
* @param {Number} [startingIndex=0] The starting index of the element to be unpacked.
|
* @param {Rectangle} [result] The object into which to store the result.
|
* @returns {Rectangle} The modified result parameter or a new Rectangle instance if one was not provided.
|
*/
|
Rectangle.unpack = function(array, startingIndex, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.defined('array', array);
|
//>>includeEnd('debug');
|
|
startingIndex = defaultValue(startingIndex, 0);
|
|
if (!defined(result)) {
|
result = new Rectangle();
|
}
|
|
result.west = array[startingIndex++];
|
result.south = array[startingIndex++];
|
result.east = array[startingIndex++];
|
result.north = array[startingIndex];
|
return result;
|
};
|
|
/**
|
* Computes the width of a rectangle in radians.
|
* @param {Rectangle} rectangle The rectangle to compute the width of.
|
* @returns {Number} The width.
|
*/
|
Rectangle.computeWidth = function(rectangle) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('rectangle', rectangle);
|
//>>includeEnd('debug');
|
var east = rectangle.east;
|
var west = rectangle.west;
|
if (east < west) {
|
east += CesiumMath.TWO_PI;
|
}
|
return east - west;
|
};
|
|
/**
|
* Computes the height of a rectangle in radians.
|
* @param {Rectangle} rectangle The rectangle to compute the height of.
|
* @returns {Number} The height.
|
*/
|
Rectangle.computeHeight = function(rectangle) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('rectangle', rectangle);
|
//>>includeEnd('debug');
|
return rectangle.north - rectangle.south;
|
};
|
|
/**
|
* Creates a rectangle given the boundary longitude and latitude in degrees.
|
*
|
* @param {Number} [west=0.0] The westernmost longitude in degrees in the range [-180.0, 180.0].
|
* @param {Number} [south=0.0] The southernmost latitude in degrees in the range [-90.0, 90.0].
|
* @param {Number} [east=0.0] The easternmost longitude in degrees in the range [-180.0, 180.0].
|
* @param {Number} [north=0.0] The northernmost latitude in degrees in the range [-90.0, 90.0].
|
* @param {Rectangle} [result] The object onto which to store the result, or undefined if a new instance should be created.
|
* @returns {Rectangle} The modified result parameter or a new Rectangle instance if none was provided.
|
*
|
* @example
|
* var rectangle = Cesium.Rectangle.fromDegrees(0.0, 20.0, 10.0, 30.0);
|
*/
|
Rectangle.fromDegrees = function(west, south, east, north, result) {
|
west = CesiumMath.toRadians(defaultValue(west, 0.0));
|
south = CesiumMath.toRadians(defaultValue(south, 0.0));
|
east = CesiumMath.toRadians(defaultValue(east, 0.0));
|
north = CesiumMath.toRadians(defaultValue(north, 0.0));
|
|
if (!defined(result)) {
|
return new Rectangle(west, south, east, north);
|
}
|
|
result.west = west;
|
result.south = south;
|
result.east = east;
|
result.north = north;
|
|
return result;
|
};
|
|
/**
|
* Creates a rectangle given the boundary longitude and latitude in radians.
|
*
|
* @param {Number} [west=0.0] The westernmost longitude in radians in the range [-Math.PI, Math.PI].
|
* @param {Number} [south=0.0] The southernmost latitude in radians in the range [-Math.PI/2, Math.PI/2].
|
* @param {Number} [east=0.0] The easternmost longitude in radians in the range [-Math.PI, Math.PI].
|
* @param {Number} [north=0.0] The northernmost latitude in radians in the range [-Math.PI/2, Math.PI/2].
|
* @param {Rectangle} [result] The object onto which to store the result, or undefined if a new instance should be created.
|
* @returns {Rectangle} The modified result parameter or a new Rectangle instance if none was provided.
|
*
|
* @example
|
* var rectangle = Cesium.Rectangle.fromRadians(0.0, Math.PI/4, Math.PI/8, 3*Math.PI/4);
|
*/
|
Rectangle.fromRadians = function(west, south, east, north, result) {
|
if (!defined(result)) {
|
return new Rectangle(west, south, east, north);
|
}
|
|
result.west = defaultValue(west, 0.0);
|
result.south = defaultValue(south, 0.0);
|
result.east = defaultValue(east, 0.0);
|
result.north = defaultValue(north, 0.0);
|
|
return result;
|
};
|
|
/**
|
* Creates the smallest possible Rectangle that encloses all positions in the provided array.
|
*
|
* @param {Cartographic[]} cartographics The list of Cartographic instances.
|
* @param {Rectangle} [result] The object onto which to store the result, or undefined if a new instance should be created.
|
* @returns {Rectangle} The modified result parameter or a new Rectangle instance if none was provided.
|
*/
|
Rectangle.fromCartographicArray = function(cartographics, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.defined('cartographics', cartographics);
|
//>>includeEnd('debug');
|
|
var west = Number.MAX_VALUE;
|
var east = -Number.MAX_VALUE;
|
var westOverIDL = Number.MAX_VALUE;
|
var eastOverIDL = -Number.MAX_VALUE;
|
var south = Number.MAX_VALUE;
|
var north = -Number.MAX_VALUE;
|
|
for ( var i = 0, len = cartographics.length; i < len; i++) {
|
var position = cartographics[i];
|
west = Math.min(west, position.longitude);
|
east = Math.max(east, position.longitude);
|
south = Math.min(south, position.latitude);
|
north = Math.max(north, position.latitude);
|
|
var lonAdjusted = position.longitude >= 0 ? position.longitude : position.longitude + CesiumMath.TWO_PI;
|
westOverIDL = Math.min(westOverIDL, lonAdjusted);
|
eastOverIDL = Math.max(eastOverIDL, lonAdjusted);
|
}
|
|
if(east - west > eastOverIDL - westOverIDL) {
|
west = westOverIDL;
|
east = eastOverIDL;
|
|
if (east > CesiumMath.PI) {
|
east = east - CesiumMath.TWO_PI;
|
}
|
if (west > CesiumMath.PI) {
|
west = west - CesiumMath.TWO_PI;
|
}
|
}
|
|
if (!defined(result)) {
|
return new Rectangle(west, south, east, north);
|
}
|
|
result.west = west;
|
result.south = south;
|
result.east = east;
|
result.north = north;
|
return result;
|
};
|
|
/**
|
* Creates the smallest possible Rectangle that encloses all positions in the provided array.
|
*
|
* @param {Cartesian3[]} cartesians The list of Cartesian instances.
|
* @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid the cartesians are on.
|
* @param {Rectangle} [result] The object onto which to store the result, or undefined if a new instance should be created.
|
* @returns {Rectangle} The modified result parameter or a new Rectangle instance if none was provided.
|
*/
|
Rectangle.fromCartesianArray = function(cartesians, ellipsoid, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.defined('cartesians', cartesians);
|
//>>includeEnd('debug');
|
ellipsoid = defaultValue(ellipsoid, Ellipsoid.WGS84);
|
|
var west = Number.MAX_VALUE;
|
var east = -Number.MAX_VALUE;
|
var westOverIDL = Number.MAX_VALUE;
|
var eastOverIDL = -Number.MAX_VALUE;
|
var south = Number.MAX_VALUE;
|
var north = -Number.MAX_VALUE;
|
|
for ( var i = 0, len = cartesians.length; i < len; i++) {
|
var position = ellipsoid.cartesianToCartographic(cartesians[i]);
|
west = Math.min(west, position.longitude);
|
east = Math.max(east, position.longitude);
|
south = Math.min(south, position.latitude);
|
north = Math.max(north, position.latitude);
|
|
var lonAdjusted = position.longitude >= 0 ? position.longitude : position.longitude + CesiumMath.TWO_PI;
|
westOverIDL = Math.min(westOverIDL, lonAdjusted);
|
eastOverIDL = Math.max(eastOverIDL, lonAdjusted);
|
}
|
|
if(east - west > eastOverIDL - westOverIDL) {
|
west = westOverIDL;
|
east = eastOverIDL;
|
|
if (east > CesiumMath.PI) {
|
east = east - CesiumMath.TWO_PI;
|
}
|
if (west > CesiumMath.PI) {
|
west = west - CesiumMath.TWO_PI;
|
}
|
}
|
|
if (!defined(result)) {
|
return new Rectangle(west, south, east, north);
|
}
|
|
result.west = west;
|
result.south = south;
|
result.east = east;
|
result.north = north;
|
return result;
|
};
|
|
/**
|
* Duplicates a Rectangle.
|
*
|
* @param {Rectangle} rectangle The rectangle to clone.
|
* @param {Rectangle} [result] The object onto which to store the result, or undefined if a new instance should be created.
|
* @returns {Rectangle} The modified result parameter or a new Rectangle instance if none was provided. (Returns undefined if rectangle is undefined)
|
*/
|
Rectangle.clone = function(rectangle, result) {
|
if (!defined(rectangle)) {
|
return undefined;
|
}
|
|
if (!defined(result)) {
|
return new Rectangle(rectangle.west, rectangle.south, rectangle.east, rectangle.north);
|
}
|
|
result.west = rectangle.west;
|
result.south = rectangle.south;
|
result.east = rectangle.east;
|
result.north = rectangle.north;
|
return result;
|
};
|
|
/**
|
* Compares the provided Rectangles componentwise and returns
|
* <code>true</code> if they pass an absolute or relative tolerance test,
|
* <code>false</code> otherwise.
|
*
|
* @param {Rectangle} [left] The first Rectangle.
|
* @param {Rectangle} [right] The second Rectangle.
|
* @param {Number} absoluteEpsilon The absolute epsilon tolerance to use for equality testing.
|
* @returns {Boolean} <code>true</code> if left and right are within the provided epsilon, <code>false</code> otherwise.
|
*/
|
Rectangle.equalsEpsilon = function(left, right, absoluteEpsilon) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.number('absoluteEpsilon', absoluteEpsilon);
|
//>>includeEnd('debug');
|
|
return (left === right) ||
|
(defined(left) &&
|
defined(right) &&
|
(Math.abs(left.west - right.west) <= absoluteEpsilon) &&
|
(Math.abs(left.south - right.south) <= absoluteEpsilon) &&
|
(Math.abs(left.east - right.east) <= absoluteEpsilon) &&
|
(Math.abs(left.north - right.north) <= absoluteEpsilon));
|
};
|
|
/**
|
* Duplicates this Rectangle.
|
*
|
* @param {Rectangle} [result] The object onto which to store the result.
|
* @returns {Rectangle} The modified result parameter or a new Rectangle instance if none was provided.
|
*/
|
Rectangle.prototype.clone = function(result) {
|
return Rectangle.clone(this, result);
|
};
|
|
/**
|
* Compares the provided Rectangle with this Rectangle componentwise and returns
|
* <code>true</code> if they are equal, <code>false</code> otherwise.
|
*
|
* @param {Rectangle} [other] The Rectangle to compare.
|
* @returns {Boolean} <code>true</code> if the Rectangles are equal, <code>false</code> otherwise.
|
*/
|
Rectangle.prototype.equals = function(other) {
|
return Rectangle.equals(this, other);
|
};
|
|
/**
|
* Compares the provided rectangles and returns <code>true</code> if they are equal,
|
* <code>false</code> otherwise.
|
*
|
* @param {Rectangle} [left] The first Rectangle.
|
* @param {Rectangle} [right] The second Rectangle.
|
* @returns {Boolean} <code>true</code> if left and right are equal; otherwise <code>false</code>.
|
*/
|
Rectangle.equals = function(left, right) {
|
return (left === right) ||
|
((defined(left)) &&
|
(defined(right)) &&
|
(left.west === right.west) &&
|
(left.south === right.south) &&
|
(left.east === right.east) &&
|
(left.north === right.north));
|
};
|
|
/**
|
* Compares the provided Rectangle with this Rectangle componentwise and returns
|
* <code>true</code> if they are within the provided epsilon,
|
* <code>false</code> otherwise.
|
*
|
* @param {Rectangle} [other] The Rectangle to compare.
|
* @param {Number} epsilon The epsilon to use for equality testing.
|
* @returns {Boolean} <code>true</code> if the Rectangles are within the provided epsilon, <code>false</code> otherwise.
|
*/
|
Rectangle.prototype.equalsEpsilon = function(other, epsilon) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.number('epsilon', epsilon);
|
//>>includeEnd('debug');
|
|
return Rectangle.equalsEpsilon(this, other, epsilon);
|
};
|
|
/**
|
* Checks a Rectangle's properties and throws if they are not in valid ranges.
|
*
|
* @param {Rectangle} rectangle The rectangle to validate
|
*
|
* @exception {DeveloperError} <code>north</code> must be in the interval [<code>-Pi/2</code>, <code>Pi/2</code>].
|
* @exception {DeveloperError} <code>south</code> must be in the interval [<code>-Pi/2</code>, <code>Pi/2</code>].
|
* @exception {DeveloperError} <code>east</code> must be in the interval [<code>-Pi</code>, <code>Pi</code>].
|
* @exception {DeveloperError} <code>west</code> must be in the interval [<code>-Pi</code>, <code>Pi</code>].
|
*/
|
Rectangle.validate = function(rectangle) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('rectangle', rectangle);
|
|
var north = rectangle.north;
|
Check.typeOf.number.greaterThanOrEquals('north', north, -CesiumMath.PI_OVER_TWO);
|
Check.typeOf.number.lessThanOrEquals('north', north, CesiumMath.PI_OVER_TWO);
|
|
var south = rectangle.south;
|
Check.typeOf.number.greaterThanOrEquals('south', south, -CesiumMath.PI_OVER_TWO);
|
Check.typeOf.number.lessThanOrEquals('south', south, CesiumMath.PI_OVER_TWO);
|
|
var west = rectangle.west;
|
Check.typeOf.number.greaterThanOrEquals('west', west, -Math.PI);
|
Check.typeOf.number.lessThanOrEquals('west', west, Math.PI);
|
|
var east = rectangle.east;
|
Check.typeOf.number.greaterThanOrEquals('east', east, -Math.PI);
|
Check.typeOf.number.lessThanOrEquals('east', east, Math.PI);
|
//>>includeEnd('debug');
|
};
|
|
/**
|
* Computes the southwest corner of a rectangle.
|
*
|
* @param {Rectangle} rectangle The rectangle for which to find the corner
|
* @param {Cartographic} [result] The object onto which to store the result.
|
* @returns {Cartographic} The modified result parameter or a new Cartographic instance if none was provided.
|
*/
|
Rectangle.southwest = function(rectangle, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('rectangle', rectangle);
|
//>>includeEnd('debug');
|
|
if (!defined(result)) {
|
return new Cartographic(rectangle.west, rectangle.south);
|
}
|
result.longitude = rectangle.west;
|
result.latitude = rectangle.south;
|
result.height = 0.0;
|
return result;
|
};
|
|
/**
|
* Computes the northwest corner of a rectangle.
|
*
|
* @param {Rectangle} rectangle The rectangle for which to find the corner
|
* @param {Cartographic} [result] The object onto which to store the result.
|
* @returns {Cartographic} The modified result parameter or a new Cartographic instance if none was provided.
|
*/
|
Rectangle.northwest = function(rectangle, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('rectangle', rectangle);
|
//>>includeEnd('debug');
|
|
if (!defined(result)) {
|
return new Cartographic(rectangle.west, rectangle.north);
|
}
|
result.longitude = rectangle.west;
|
result.latitude = rectangle.north;
|
result.height = 0.0;
|
return result;
|
};
|
|
/**
|
* Computes the northeast corner of a rectangle.
|
*
|
* @param {Rectangle} rectangle The rectangle for which to find the corner
|
* @param {Cartographic} [result] The object onto which to store the result.
|
* @returns {Cartographic} The modified result parameter or a new Cartographic instance if none was provided.
|
*/
|
Rectangle.northeast = function(rectangle, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('rectangle', rectangle);
|
//>>includeEnd('debug');
|
|
if (!defined(result)) {
|
return new Cartographic(rectangle.east, rectangle.north);
|
}
|
result.longitude = rectangle.east;
|
result.latitude = rectangle.north;
|
result.height = 0.0;
|
return result;
|
};
|
|
/**
|
* Computes the southeast corner of a rectangle.
|
*
|
* @param {Rectangle} rectangle The rectangle for which to find the corner
|
* @param {Cartographic} [result] The object onto which to store the result.
|
* @returns {Cartographic} The modified result parameter or a new Cartographic instance if none was provided.
|
*/
|
Rectangle.southeast = function(rectangle, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('rectangle', rectangle);
|
//>>includeEnd('debug');
|
|
if (!defined(result)) {
|
return new Cartographic(rectangle.east, rectangle.south);
|
}
|
result.longitude = rectangle.east;
|
result.latitude = rectangle.south;
|
result.height = 0.0;
|
return result;
|
};
|
|
/**
|
* Computes the center of a rectangle.
|
*
|
* @param {Rectangle} rectangle The rectangle for which to find the center
|
* @param {Cartographic} [result] The object onto which to store the result.
|
* @returns {Cartographic} The modified result parameter or a new Cartographic instance if none was provided.
|
*/
|
Rectangle.center = function(rectangle, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('rectangle', rectangle);
|
//>>includeEnd('debug');
|
|
var east = rectangle.east;
|
var west = rectangle.west;
|
|
if (east < west) {
|
east += CesiumMath.TWO_PI;
|
}
|
|
var longitude = CesiumMath.negativePiToPi((west + east) * 0.5);
|
var latitude = (rectangle.south + rectangle.north) * 0.5;
|
|
if (!defined(result)) {
|
return new Cartographic(longitude, latitude);
|
}
|
|
result.longitude = longitude;
|
result.latitude = latitude;
|
result.height = 0.0;
|
return result;
|
};
|
|
/**
|
* Computes the intersection of two rectangles. This function assumes that the rectangle's coordinates are
|
* latitude and longitude in radians and produces a correct intersection, taking into account the fact that
|
* the same angle can be represented with multiple values as well as the wrapping of longitude at the
|
* anti-meridian. For a simple intersection that ignores these factors and can be used with projected
|
* coordinates, see {@link Rectangle.simpleIntersection}.
|
*
|
* @param {Rectangle} rectangle On rectangle to find an intersection
|
* @param {Rectangle} otherRectangle Another rectangle to find an intersection
|
* @param {Rectangle} [result] The object onto which to store the result.
|
* @returns {Rectangle|undefined} The modified result parameter, a new Rectangle instance if none was provided or undefined if there is no intersection.
|
*/
|
Rectangle.intersection = function(rectangle, otherRectangle, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('rectangle', rectangle);
|
Check.typeOf.object('otherRectangle', otherRectangle);
|
//>>includeEnd('debug');
|
|
var rectangleEast = rectangle.east;
|
var rectangleWest = rectangle.west;
|
|
var otherRectangleEast = otherRectangle.east;
|
var otherRectangleWest = otherRectangle.west;
|
|
if (rectangleEast < rectangleWest && otherRectangleEast > 0.0) {
|
rectangleEast += CesiumMath.TWO_PI;
|
} else if (otherRectangleEast < otherRectangleWest && rectangleEast > 0.0) {
|
otherRectangleEast += CesiumMath.TWO_PI;
|
}
|
|
if (rectangleEast < rectangleWest && otherRectangleWest < 0.0) {
|
otherRectangleWest += CesiumMath.TWO_PI;
|
} else if (otherRectangleEast < otherRectangleWest && rectangleWest < 0.0) {
|
rectangleWest += CesiumMath.TWO_PI;
|
}
|
|
var west = CesiumMath.negativePiToPi(Math.max(rectangleWest, otherRectangleWest));
|
var east = CesiumMath.negativePiToPi(Math.min(rectangleEast, otherRectangleEast));
|
|
if ((rectangle.west < rectangle.east || otherRectangle.west < otherRectangle.east) && east <= west) {
|
return undefined;
|
}
|
|
var south = Math.max(rectangle.south, otherRectangle.south);
|
var north = Math.min(rectangle.north, otherRectangle.north);
|
|
if (south >= north) {
|
return undefined;
|
}
|
|
if (!defined(result)) {
|
return new Rectangle(west, south, east, north);
|
}
|
result.west = west;
|
result.south = south;
|
result.east = east;
|
result.north = north;
|
return result;
|
};
|
|
/**
|
* Computes a simple intersection of two rectangles. Unlike {@link Rectangle.intersection}, this function
|
* does not attempt to put the angular coordinates into a consistent range or to account for crossing the
|
* anti-meridian. As such, it can be used for rectangles where the coordinates are not simply latitude
|
* and longitude (i.e. projected coordinates).
|
*
|
* @param {Rectangle} rectangle On rectangle to find an intersection
|
* @param {Rectangle} otherRectangle Another rectangle to find an intersection
|
* @param {Rectangle} [result] The object onto which to store the result.
|
* @returns {Rectangle|undefined} The modified result parameter, a new Rectangle instance if none was provided or undefined if there is no intersection.
|
*/
|
Rectangle.simpleIntersection = function(rectangle, otherRectangle, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('rectangle', rectangle);
|
Check.typeOf.object('otherRectangle', otherRectangle);
|
//>>includeEnd('debug');
|
|
var west = Math.max(rectangle.west, otherRectangle.west);
|
var south = Math.max(rectangle.south, otherRectangle.south);
|
var east = Math.min(rectangle.east, otherRectangle.east);
|
var north = Math.min(rectangle.north, otherRectangle.north);
|
|
if (south >= north || west >= east) {
|
return undefined;
|
}
|
|
if (!defined(result)) {
|
return new Rectangle(west, south, east, north);
|
}
|
|
result.west = west;
|
result.south = south;
|
result.east = east;
|
result.north = north;
|
return result;
|
};
|
|
/**
|
* Computes a rectangle that is the union of two rectangles.
|
*
|
* @param {Rectangle} rectangle A rectangle to enclose in rectangle.
|
* @param {Rectangle} otherRectangle A rectangle to enclose in a rectangle.
|
* @param {Rectangle} [result] The object onto which to store the result.
|
* @returns {Rectangle} The modified result parameter or a new Rectangle instance if none was provided.
|
*/
|
Rectangle.union = function(rectangle, otherRectangle, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('rectangle', rectangle);
|
Check.typeOf.object('otherRectangle', otherRectangle);
|
//>>includeEnd('debug');
|
|
if (!defined(result)) {
|
result = new Rectangle();
|
}
|
|
var rectangleEast = rectangle.east;
|
var rectangleWest = rectangle.west;
|
|
var otherRectangleEast = otherRectangle.east;
|
var otherRectangleWest = otherRectangle.west;
|
|
if (rectangleEast < rectangleWest && otherRectangleEast > 0.0) {
|
rectangleEast += CesiumMath.TWO_PI;
|
} else if (otherRectangleEast < otherRectangleWest && rectangleEast > 0.0) {
|
otherRectangleEast += CesiumMath.TWO_PI;
|
}
|
|
if (rectangleEast < rectangleWest && otherRectangleWest < 0.0) {
|
otherRectangleWest += CesiumMath.TWO_PI;
|
} else if (otherRectangleEast < otherRectangleWest && rectangleWest < 0.0) {
|
rectangleWest += CesiumMath.TWO_PI;
|
}
|
|
var west = CesiumMath.convertLongitudeRange(Math.min(rectangleWest, otherRectangleWest));
|
var east = CesiumMath.convertLongitudeRange(Math.max(rectangleEast, otherRectangleEast));
|
|
result.west = west;
|
result.south = Math.min(rectangle.south, otherRectangle.south);
|
result.east = east;
|
result.north = Math.max(rectangle.north, otherRectangle.north);
|
|
return result;
|
};
|
|
/**
|
* Computes a rectangle by enlarging the provided rectangle until it contains the provided cartographic.
|
*
|
* @param {Rectangle} rectangle A rectangle to expand.
|
* @param {Cartographic} cartographic A cartographic to enclose in a rectangle.
|
* @param {Rectangle} [result] The object onto which to store the result.
|
* @returns {Rectangle} The modified result parameter or a new Rectangle instance if one was not provided.
|
*/
|
Rectangle.expand = function(rectangle, cartographic, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('rectangle', rectangle);
|
Check.typeOf.object('cartographic', cartographic);
|
//>>includeEnd('debug');
|
|
if (!defined(result)) {
|
result = new Rectangle();
|
}
|
|
result.west = Math.min(rectangle.west, cartographic.longitude);
|
result.south = Math.min(rectangle.south, cartographic.latitude);
|
result.east = Math.max(rectangle.east, cartographic.longitude);
|
result.north = Math.max(rectangle.north, cartographic.latitude);
|
|
return result;
|
};
|
|
/**
|
* Returns true if the cartographic is on or inside the rectangle, false otherwise.
|
*
|
* @param {Rectangle} rectangle The rectangle
|
* @param {Cartographic} cartographic The cartographic to test.
|
* @returns {Boolean} true if the provided cartographic is inside the rectangle, false otherwise.
|
*/
|
Rectangle.contains = function(rectangle, cartographic) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('rectangle', rectangle);
|
Check.typeOf.object('cartographic', cartographic);
|
//>>includeEnd('debug');
|
|
var longitude = cartographic.longitude;
|
var latitude = cartographic.latitude;
|
|
var west = rectangle.west;
|
var east = rectangle.east;
|
|
if (east < west) {
|
east += CesiumMath.TWO_PI;
|
if (longitude < 0.0) {
|
longitude += CesiumMath.TWO_PI;
|
}
|
}
|
return (longitude > west || CesiumMath.equalsEpsilon(longitude, west, CesiumMath.EPSILON14)) &&
|
(longitude < east || CesiumMath.equalsEpsilon(longitude, east, CesiumMath.EPSILON14)) &&
|
latitude >= rectangle.south &&
|
latitude <= rectangle.north;
|
};
|
|
var subsampleLlaScratch = new Cartographic();
|
/**
|
* Samples a rectangle so that it includes a list of Cartesian points suitable for passing to
|
* {@link BoundingSphere#fromPoints}. Sampling is necessary to account
|
* for rectangles that cover the poles or cross the equator.
|
*
|
* @param {Rectangle} rectangle The rectangle to subsample.
|
* @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid to use.
|
* @param {Number} [surfaceHeight=0.0] The height of the rectangle above the ellipsoid.
|
* @param {Cartesian3[]} [result] The array of Cartesians onto which to store the result.
|
* @returns {Cartesian3[]} The modified result parameter or a new Array of Cartesians instances if none was provided.
|
*/
|
Rectangle.subsample = function(rectangle, ellipsoid, surfaceHeight, result) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('rectangle', rectangle);
|
//>>includeEnd('debug');
|
|
ellipsoid = defaultValue(ellipsoid, Ellipsoid.WGS84);
|
surfaceHeight = defaultValue(surfaceHeight, 0.0);
|
|
if (!defined(result)) {
|
result = [];
|
}
|
var length = 0;
|
|
var north = rectangle.north;
|
var south = rectangle.south;
|
var east = rectangle.east;
|
var west = rectangle.west;
|
|
var lla = subsampleLlaScratch;
|
lla.height = surfaceHeight;
|
|
lla.longitude = west;
|
lla.latitude = north;
|
result[length] = ellipsoid.cartographicToCartesian(lla, result[length]);
|
length++;
|
|
lla.longitude = east;
|
result[length] = ellipsoid.cartographicToCartesian(lla, result[length]);
|
length++;
|
|
lla.latitude = south;
|
result[length] = ellipsoid.cartographicToCartesian(lla, result[length]);
|
length++;
|
|
lla.longitude = west;
|
result[length] = ellipsoid.cartographicToCartesian(lla, result[length]);
|
length++;
|
|
if (north < 0.0) {
|
lla.latitude = north;
|
} else if (south > 0.0) {
|
lla.latitude = south;
|
} else {
|
lla.latitude = 0.0;
|
}
|
|
for ( var i = 1; i < 8; ++i) {
|
lla.longitude = -Math.PI + i * CesiumMath.PI_OVER_TWO;
|
if (Rectangle.contains(rectangle, lla)) {
|
result[length] = ellipsoid.cartographicToCartesian(lla, result[length]);
|
length++;
|
}
|
}
|
|
if (lla.latitude === 0.0) {
|
lla.longitude = west;
|
result[length] = ellipsoid.cartographicToCartesian(lla, result[length]);
|
length++;
|
lla.longitude = east;
|
result[length] = ellipsoid.cartographicToCartesian(lla, result[length]);
|
length++;
|
}
|
result.length = length;
|
return result;
|
};
|
|
/**
|
* The largest possible rectangle.
|
*
|
* @type {Rectangle}
|
* @constant
|
*/
|
Rectangle.MAX_VALUE = freezeObject(new Rectangle(-Math.PI, -CesiumMath.PI_OVER_TWO, Math.PI, CesiumMath.PI_OVER_TWO));
|
|
module.exports= Rectangle;
|
|
},{"./Cartographic":128,"./Check":129,"./Ellipsoid":132,"./Math":139,"./defaultValue":158,"./defineProperties":159,"./defined":160,"./freezeObject":163}],141:[function(require,module,exports){
|
var defaultValue=require('./defaultValue');
|
var defined=require('./defined');
|
var RequestState=require('./RequestState');
|
var RequestType=require('./RequestType');
|
|
'use strict';
|
|
/**
|
* Stores information for making a request. In general this does not need to be constructed directly.
|
*
|
* @alias Request
|
* @constructor
|
* @namespace
|
* @exports Request
|
* @param {Object} [options] An object with the following properties:
|
* @param {String} [options.url] The url to request.
|
* @param {Request~RequestCallback} [options.requestFunction] The function that makes the actual data request.
|
* @param {Request~CancelCallback} [options.cancelFunction] The function that is called when the request is cancelled.
|
* @param {Request~PriorityCallback} [options.priorityFunction] The function that is called to update the request's priority, which occurs once per frame.
|
* @param {Number} [options.priority=0.0] The initial priority of the request.
|
* @param {Boolean} [options.throttle=false] Whether to throttle and prioritize the request. If false, the request will be sent immediately. If true, the request will be throttled and sent based on priority.
|
* @param {Boolean} [options.throttleByServer=false] Whether to throttle the request by server.
|
* @param {RequestType} [options.type=RequestType.OTHER] The type of request.
|
*/
|
function Request(options) {
|
options = defaultValue(options, defaultValue.EMPTY_OBJECT);
|
|
var throttleByServer = defaultValue(options.throttleByServer, false);
|
var throttle = defaultValue(options.throttle, false);
|
|
/**
|
* The URL to request.
|
*
|
* @type {String}
|
*/
|
this.url = options.url;
|
|
/**
|
* The function that makes the actual data request.
|
*
|
* @type {Request~RequestCallback}
|
*/
|
this.requestFunction = options.requestFunction;
|
|
/**
|
* The function that is called when the request is cancelled.
|
*
|
* @type {Request~CancelCallback}
|
*/
|
this.cancelFunction = options.cancelFunction;
|
|
/**
|
* The function that is called to update the request's priority, which occurs once per frame.
|
*
|
* @type {Request~PriorityCallback}
|
*/
|
this.priorityFunction = options.priorityFunction;
|
|
/**
|
* Priority is a unit-less value where lower values represent higher priority.
|
* For world-based objects, this is usually the distance from the camera.
|
* A request that does not have a priority function defaults to a priority of 0.
|
*
|
* If priorityFunction is defined, this value is updated every frame with the result of that call.
|
*
|
* @type {Number}
|
* @default 0.0
|
*/
|
this.priority = defaultValue(options.priority, 0.0);
|
|
/**
|
* Whether to throttle and prioritize the request. If false, the request will be sent immediately. If true, the
|
* request will be throttled and sent based on priority.
|
*
|
* @type {Boolean}
|
* @readonly
|
*
|
* @default false
|
*/
|
this.throttle = throttle;
|
|
/**
|
* Whether to throttle the request by server. Browsers typically support about 6-8 parallel connections
|
* for HTTP/1 servers, and an unlimited amount of connections for HTTP/2 servers. Setting this value
|
* to <code>true</code> is preferable for requests going through HTTP/1 servers.
|
*
|
* @type {Boolean}
|
* @readonly
|
*
|
* @default false
|
*/
|
this.throttleByServer = throttleByServer;
|
|
/**
|
* Type of request.
|
*
|
* @type {RequestType}
|
* @readonly
|
*
|
* @default RequestType.OTHER
|
*/
|
this.type = defaultValue(options.type, RequestType.OTHER);
|
|
/**
|
* A key used to identify the server that a request is going to. It is derived from the url's authority and scheme.
|
*
|
* @type {String}
|
*
|
* @private
|
*/
|
this.serverKey = undefined;
|
|
/**
|
* The current state of the request.
|
*
|
* @type {RequestState}
|
* @readonly
|
*/
|
this.state = RequestState.UNISSUED;
|
|
/**
|
* The requests's deferred promise.
|
*
|
* @type {Object}
|
*
|
* @private
|
*/
|
this.deferred = undefined;
|
|
/**
|
* Whether the request was explicitly cancelled.
|
*
|
* @type {Boolean}
|
*
|
* @private
|
*/
|
this.cancelled = false;
|
}
|
|
/**
|
* Mark the request as cancelled.
|
*
|
* @private
|
*/
|
Request.prototype.cancel = function() {
|
this.cancelled = true;
|
};
|
|
/**
|
* Duplicates a Request instance.
|
*
|
* @param {Request} [result] The object onto which to store the result.
|
*
|
* @returns {Request} The modified result parameter or a new Resource instance if one was not provided.
|
*/
|
Request.prototype.clone = function(result) {
|
if (!defined(result)) {
|
return new Request(this);
|
}
|
|
result.url = this.url;
|
result.requestFunction = this.requestFunction;
|
result.cancelFunction = this.cancelFunction;
|
result.priorityFunction = this.priorityFunction;
|
result.priority = this.priority;
|
result.throttle = this.throttle;
|
result.throttleByServer = this.throttleByServer;
|
result.type = this.type;
|
result.serverKey = this.serverKey;
|
|
// These get defaulted because the cloned request hasn't been issued
|
result.state = this.RequestState.UNISSUED;
|
result.deferred = undefined;
|
result.cancelled = false;
|
|
return result;
|
};
|
|
/**
|
* The function that makes the actual data request.
|
* @callback Request~RequestCallback
|
* @returns {Promise} A promise for the requested data.
|
*/
|
|
/**
|
* The function that is called when the request is cancelled.
|
* @callback Request~CancelCallback
|
*/
|
|
/**
|
* The function that is called to update the request's priority, which occurs once per frame.
|
* @callback Request~PriorityCallback
|
* @returns {Number} The updated priority value.
|
*/
|
|
module.exports= Request;
|
|
},{"./RequestState":144,"./RequestType":145,"./defaultValue":158,"./defined":160}],142:[function(require,module,exports){
|
var defined=require('./defined');
|
var parseResponseHeaders=require('./parseResponseHeaders');
|
|
'use strict';
|
|
/**
|
* An event that is raised when a request encounters an error.
|
*
|
* @constructor
|
* @alias RequestErrorEvent
|
*
|
* @param {Number} [statusCode] The HTTP error status code, such as 404.
|
* @param {Object} [response] The response included along with the error.
|
* @param {String|Object} [responseHeaders] The response headers, represented either as an object literal or as a
|
* string in the format returned by XMLHttpRequest's getAllResponseHeaders() function.
|
*/
|
function RequestErrorEvent(statusCode, response, responseHeaders) {
|
/**
|
* The HTTP error status code, such as 404. If the error does not have a particular
|
* HTTP code, this property will be undefined.
|
*
|
* @type {Number}
|
*/
|
this.statusCode = statusCode;
|
|
/**
|
* The response included along with the error. If the error does not include a response,
|
* this property will be undefined.
|
*
|
* @type {Object}
|
*/
|
this.response = response;
|
|
/**
|
* The headers included in the response, represented as an object literal of key/value pairs.
|
* If the error does not include any headers, this property will be undefined.
|
*
|
* @type {Object}
|
*/
|
this.responseHeaders = responseHeaders;
|
|
if (typeof this.responseHeaders === 'string') {
|
this.responseHeaders = parseResponseHeaders(this.responseHeaders);
|
}
|
}
|
|
/**
|
* Creates a string representing this RequestErrorEvent.
|
* @memberof RequestErrorEvent
|
*
|
* @returns {String} A string representing the provided RequestErrorEvent.
|
*/
|
RequestErrorEvent.prototype.toString = function() {
|
var str = 'Request has failed.';
|
if (defined(this.statusCode)) {
|
str += ' Status Code: ' + this.statusCode;
|
}
|
return str;
|
};
|
|
module.exports= RequestErrorEvent;
|
|
},{"./defined":160,"./parseResponseHeaders":174}],143:[function(require,module,exports){
|
var Uri=require('./Uri');
|
var when=require('when');
|
var Check=require('./Check');
|
var defaultValue=require('./defaultValue');
|
var defined=require('./defined');
|
var defineProperties=require('./defineProperties');
|
var Event=require('./Event');
|
var Heap=require('./Heap');
|
var isBlobUri=require('./isBlobUri');
|
var isDataUri=require('./isDataUri');
|
var RequestState=require('./RequestState');
|
|
'use strict';
|
|
function sortRequests(a, b) {
|
return a.priority - b.priority;
|
}
|
|
var statistics = {
|
numberOfAttemptedRequests : 0,
|
numberOfActiveRequests : 0,
|
numberOfCancelledRequests : 0,
|
numberOfCancelledActiveRequests : 0,
|
numberOfFailedRequests : 0,
|
numberOfActiveRequestsEver : 0
|
};
|
|
var priorityHeapLength = 20;
|
var requestHeap = new Heap({
|
comparator : sortRequests
|
});
|
requestHeap.maximumLength = priorityHeapLength;
|
requestHeap.reserve(priorityHeapLength);
|
|
var activeRequests = [];
|
var numberOfActiveRequestsByServer = {};
|
|
var pageUri = typeof document !== 'undefined' ? new Uri(document.location.href) : new Uri();
|
|
var requestCompletedEvent = new Event();
|
|
/**
|
* Tracks the number of active requests and prioritizes incoming requests.
|
*
|
* @exports RequestScheduler
|
*
|
* @private
|
*/
|
function RequestScheduler() {
|
}
|
|
/**
|
* The maximum number of simultaneous active requests. Un-throttled requests do not observe this limit.
|
* @type {Number}
|
* @default 50
|
*/
|
RequestScheduler.maximumRequests = 50;
|
|
/**
|
* The maximum number of simultaneous active requests per server. Un-throttled requests or servers specifically
|
* listed in requestsByServer do not observe this limit.
|
* @type {Number}
|
* @default 6
|
*/
|
RequestScheduler.maximumRequestsPerServer = 6;
|
|
/**
|
* A per serverKey list of overrides to use for throttling instead of maximumRequestsPerServer
|
*/
|
RequestScheduler.requestsByServer = {
|
'api.cesium.com:443': 18,
|
'assets.cesium.com:443': 18
|
};
|
|
/**
|
* Specifies if the request scheduler should throttle incoming requests, or let the browser queue requests under its control.
|
* @type {Boolean}
|
* @default true
|
*/
|
RequestScheduler.throttleRequests = true;
|
|
/**
|
* When true, log statistics to the console every frame
|
* @type {Boolean}
|
* @default false
|
*/
|
RequestScheduler.debugShowStatistics = false;
|
|
/**
|
* An event that's raised when a request is completed. Event handlers are passed
|
* the error object if the request fails.
|
*
|
* @type {Event}
|
* @default Event()
|
*/
|
RequestScheduler.requestCompletedEvent = requestCompletedEvent;
|
|
defineProperties(RequestScheduler, {
|
/**
|
* Returns the statistics used by the request scheduler.
|
*
|
* @memberof RequestScheduler
|
*
|
* @type Object
|
* @readonly
|
*/
|
statistics : {
|
get : function() {
|
return statistics;
|
}
|
},
|
|
/**
|
* The maximum size of the priority heap. This limits the number of requests that are sorted by priority. Only applies to requests that are not yet active.
|
*
|
* @memberof RequestScheduler
|
*
|
* @type {Number}
|
* @default 20
|
*/
|
priorityHeapLength : {
|
get : function() {
|
return priorityHeapLength;
|
},
|
set : function(value) {
|
// If the new length shrinks the heap, need to cancel some of the requests.
|
// Since this value is not intended to be tweaked regularly it is fine to just cancel the high priority requests.
|
if (value < priorityHeapLength) {
|
while (requestHeap.length > value) {
|
var request = requestHeap.pop();
|
cancelRequest(request);
|
}
|
}
|
priorityHeapLength = value;
|
requestHeap.maximumLength = value;
|
requestHeap.reserve(value);
|
}
|
}
|
});
|
|
function updatePriority(request) {
|
if (defined(request.priorityFunction)) {
|
request.priority = request.priorityFunction();
|
}
|
}
|
|
function serverHasOpenSlots(serverKey) {
|
var maxRequests = defaultValue(RequestScheduler.requestsByServer[serverKey], RequestScheduler.maximumRequestsPerServer);
|
return numberOfActiveRequestsByServer[serverKey] < maxRequests;
|
}
|
|
function issueRequest(request) {
|
if (request.state === RequestState.UNISSUED) {
|
request.state = RequestState.ISSUED;
|
request.deferred = when.defer();
|
}
|
return request.deferred.promise;
|
}
|
|
function getRequestReceivedFunction(request) {
|
return function(results) {
|
if (request.state === RequestState.CANCELLED) {
|
// If the data request comes back but the request is cancelled, ignore it.
|
return;
|
}
|
--statistics.numberOfActiveRequests;
|
--numberOfActiveRequestsByServer[request.serverKey];
|
requestCompletedEvent.raiseEvent();
|
request.state = RequestState.RECEIVED;
|
request.deferred.resolve(results);
|
};
|
}
|
|
function getRequestFailedFunction(request) {
|
return function(error) {
|
if (request.state === RequestState.CANCELLED) {
|
// If the data request comes back but the request is cancelled, ignore it.
|
return;
|
}
|
++statistics.numberOfFailedRequests;
|
--statistics.numberOfActiveRequests;
|
--numberOfActiveRequestsByServer[request.serverKey];
|
requestCompletedEvent.raiseEvent(error);
|
request.state = RequestState.FAILED;
|
request.deferred.reject(error);
|
};
|
}
|
|
function startRequest(request) {
|
var promise = issueRequest(request);
|
request.state = RequestState.ACTIVE;
|
activeRequests.push(request);
|
++statistics.numberOfActiveRequests;
|
++statistics.numberOfActiveRequestsEver;
|
++numberOfActiveRequestsByServer[request.serverKey];
|
request.requestFunction().then(getRequestReceivedFunction(request)).otherwise(getRequestFailedFunction(request));
|
return promise;
|
}
|
|
function cancelRequest(request) {
|
var active = request.state === RequestState.ACTIVE;
|
request.state = RequestState.CANCELLED;
|
++statistics.numberOfCancelledRequests;
|
request.deferred.reject();
|
|
if (active) {
|
--statistics.numberOfActiveRequests;
|
--numberOfActiveRequestsByServer[request.serverKey];
|
++statistics.numberOfCancelledActiveRequests;
|
}
|
|
if (defined(request.cancelFunction)) {
|
request.cancelFunction();
|
}
|
}
|
|
/**
|
* Sort requests by priority and start requests.
|
*/
|
RequestScheduler.update = function() {
|
var i;
|
var request;
|
|
// Loop over all active requests. Cancelled, failed, or received requests are removed from the array to make room for new requests.
|
var removeCount = 0;
|
var activeLength = activeRequests.length;
|
for (i = 0; i < activeLength; ++i) {
|
request = activeRequests[i];
|
if (request.cancelled) {
|
// Request was explicitly cancelled
|
cancelRequest(request);
|
}
|
if (request.state !== RequestState.ACTIVE) {
|
// Request is no longer active, remove from array
|
++removeCount;
|
continue;
|
}
|
if (removeCount > 0) {
|
// Shift back to fill in vacated slots from completed requests
|
activeRequests[i - removeCount] = request;
|
}
|
}
|
activeRequests.length -= removeCount;
|
|
// Update priority of issued requests and resort the heap
|
var issuedRequests = requestHeap.internalArray;
|
var issuedLength = requestHeap.length;
|
for (i = 0; i < issuedLength; ++i) {
|
updatePriority(issuedRequests[i]);
|
}
|
requestHeap.resort();
|
|
// Get the number of open slots and fill with the highest priority requests.
|
// Un-throttled requests are automatically added to activeRequests, so activeRequests.length may exceed maximumRequests
|
var openSlots = Math.max(RequestScheduler.maximumRequests - activeRequests.length, 0);
|
var filledSlots = 0;
|
while (filledSlots < openSlots && requestHeap.length > 0) {
|
// Loop until all open slots are filled or the heap becomes empty
|
request = requestHeap.pop();
|
if (request.cancelled) {
|
// Request was explicitly cancelled
|
cancelRequest(request);
|
continue;
|
}
|
|
if (request.throttleByServer && !serverHasOpenSlots(request.serverKey)) {
|
// Open slots are available, but the request is throttled by its server. Cancel and try again later.
|
cancelRequest(request);
|
continue;
|
}
|
|
startRequest(request);
|
++filledSlots;
|
}
|
|
updateStatistics();
|
};
|
|
/**
|
* Get the server key from a given url.
|
*
|
* @param {String} url The url.
|
* @returns {String} The server key.
|
*/
|
RequestScheduler.getServerKey = function(url) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.string('url', url);
|
//>>includeEnd('debug');
|
|
var uri = new Uri(url).resolve(pageUri);
|
uri.normalize();
|
var serverKey = uri.authority;
|
if (!/:/.test(serverKey)) {
|
// If the authority does not contain a port number, add port 443 for https or port 80 for http
|
serverKey = serverKey + ':' + (uri.scheme === 'https' ? '443' : '80');
|
}
|
|
var length = numberOfActiveRequestsByServer[serverKey];
|
if (!defined(length)) {
|
numberOfActiveRequestsByServer[serverKey] = 0;
|
}
|
|
return serverKey;
|
};
|
|
/**
|
* Issue a request. If request.throttle is false, the request is sent immediately. Otherwise the request will be
|
* queued and sorted by priority before being sent.
|
*
|
* @param {Request} request The request object.
|
*
|
* @returns {Promise|undefined} A Promise for the requested data, or undefined if this request does not have high enough priority to be issued.
|
*/
|
RequestScheduler.request = function(request) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.object('request', request);
|
Check.typeOf.string('request.url', request.url);
|
Check.typeOf.func('request.requestFunction', request.requestFunction);
|
//>>includeEnd('debug');
|
|
if (isDataUri(request.url) || isBlobUri(request.url)) {
|
requestCompletedEvent.raiseEvent();
|
request.state = RequestState.RECEIVED;
|
return request.requestFunction();
|
}
|
|
++statistics.numberOfAttemptedRequests;
|
|
if (!defined(request.serverKey)) {
|
request.serverKey = RequestScheduler.getServerKey(request.url);
|
}
|
|
if (request.throttleByServer && !serverHasOpenSlots(request.serverKey)) {
|
// Server is saturated. Try again later.
|
return undefined;
|
}
|
|
if (!RequestScheduler.throttleRequests || !request.throttle) {
|
return startRequest(request);
|
}
|
|
if (activeRequests.length >= RequestScheduler.maximumRequests) {
|
// Active requests are saturated. Try again later.
|
return undefined;
|
}
|
|
// Insert into the priority heap and see if a request was bumped off. If this request is the lowest
|
// priority it will be returned.
|
updatePriority(request);
|
var removedRequest = requestHeap.insert(request);
|
|
if (defined(removedRequest)) {
|
if (removedRequest === request) {
|
// Request does not have high enough priority to be issued
|
return undefined;
|
}
|
// A previously issued request has been bumped off the priority heap, so cancel it
|
cancelRequest(removedRequest);
|
}
|
|
return issueRequest(request);
|
};
|
|
function clearStatistics() {
|
statistics.numberOfAttemptedRequests = 0;
|
statistics.numberOfCancelledRequests = 0;
|
statistics.numberOfCancelledActiveRequests = 0;
|
}
|
|
function updateStatistics() {
|
if (!RequestScheduler.debugShowStatistics) {
|
return;
|
}
|
|
if (statistics.numberOfAttemptedRequests > 0) {
|
console.log('Number of attempted requests: ' + statistics.numberOfAttemptedRequests);
|
}
|
if (statistics.numberOfActiveRequests > 0) {
|
console.log('Number of active requests: ' + statistics.numberOfActiveRequests);
|
}
|
if (statistics.numberOfCancelledRequests > 0) {
|
console.log('Number of cancelled requests: ' + statistics.numberOfCancelledRequests);
|
}
|
if (statistics.numberOfCancelledActiveRequests > 0) {
|
console.log('Number of cancelled active requests: ' + statistics.numberOfCancelledActiveRequests);
|
}
|
if (statistics.numberOfFailedRequests > 0) {
|
console.log('Number of failed requests: ' + statistics.numberOfFailedRequests);
|
}
|
|
clearStatistics();
|
}
|
|
/**
|
* For testing only. Clears any requests that may not have completed from previous tests.
|
*
|
* @private
|
*/
|
RequestScheduler.clearForSpecs = function() {
|
while (requestHeap.length > 0) {
|
var request = requestHeap.pop();
|
cancelRequest(request);
|
}
|
var length = activeRequests.length;
|
for (var i = 0; i < length; ++i) {
|
cancelRequest(activeRequests[i]);
|
}
|
activeRequests.length = 0;
|
numberOfActiveRequestsByServer = {};
|
|
// Clear stats
|
statistics.numberOfAttemptedRequests = 0;
|
statistics.numberOfActiveRequests = 0;
|
statistics.numberOfCancelledRequests = 0;
|
statistics.numberOfCancelledActiveRequests = 0;
|
statistics.numberOfFailedRequests = 0;
|
statistics.numberOfActiveRequestsEver = 0;
|
};
|
|
/**
|
* For testing only.
|
*
|
* @private
|
*/
|
RequestScheduler.numberOfActiveRequestsByServer = function(serverKey) {
|
return numberOfActiveRequestsByServer[serverKey];
|
};
|
|
/**
|
* For testing only.
|
*
|
* @private
|
*/
|
RequestScheduler.requestHeap = requestHeap;
|
|
module.exports= RequestScheduler;
|
|
},{"./Check":129,"./Event":133,"./Heap":138,"./RequestState":144,"./Uri":151,"./defaultValue":158,"./defineProperties":159,"./defined":160,"./isBlobUri":168,"./isDataUri":170,"when":118}],144:[function(require,module,exports){
|
var freezeObject=require('./freezeObject');
|
|
'use strict';
|
|
/**
|
* State of the request.
|
*
|
* @exports RequestState
|
*/
|
var RequestState = {
|
/**
|
* Initial unissued state.
|
*
|
* @type Number
|
* @constant
|
*/
|
UNISSUED : 0,
|
|
/**
|
* Issued but not yet active. Will become active when open slots are available.
|
*
|
* @type Number
|
* @constant
|
*/
|
ISSUED : 1,
|
|
/**
|
* Actual http request has been sent.
|
*
|
* @type Number
|
* @constant
|
*/
|
ACTIVE : 2,
|
|
/**
|
* Request completed successfully.
|
*
|
* @type Number
|
* @constant
|
*/
|
RECEIVED : 3,
|
|
/**
|
* Request was cancelled, either explicitly or automatically because of low priority.
|
*
|
* @type Number
|
* @constant
|
*/
|
CANCELLED : 4,
|
|
/**
|
* Request failed.
|
*
|
* @type Number
|
* @constant
|
*/
|
FAILED : 5
|
};
|
|
module.exports= freezeObject(RequestState);
|
|
},{"./freezeObject":163}],145:[function(require,module,exports){
|
var freezeObject=require('./freezeObject');
|
|
'use strict';
|
|
/**
|
* An enum identifying the type of request. Used for finer grained logging and priority sorting.
|
*
|
* @exports RequestType
|
*/
|
var RequestType = {
|
/**
|
* Terrain request.
|
*
|
* @type Number
|
* @constant
|
*/
|
TERRAIN : 0,
|
|
/**
|
* Imagery request.
|
*
|
* @type Number
|
* @constant
|
*/
|
IMAGERY : 1,
|
|
/**
|
* 3D Tiles request.
|
*
|
* @type Number
|
* @constant
|
*/
|
TILES3D : 2,
|
|
/**
|
* Other request.
|
*
|
* @type Number
|
* @constant
|
*/
|
OTHER : 3
|
};
|
|
module.exports= freezeObject(RequestType);
|
|
},{"./freezeObject":163}],146:[function(require,module,exports){
|
(function (global,Buffer){
|
var Uri=require('uri');
|
var when=require('when');
|
var appendForwardSlash=require('./appendForwardSlash');
|
var Check=require('./Check');
|
var clone=require('./clone');
|
var combine=require('./combine');
|
var defaultValue=require('./defaultValue');
|
var defined=require('./defined');
|
var defineProperties=require('./defineProperties');
|
var deprecationWarning=require('./deprecationWarning');
|
var DeveloperError=require('./DeveloperError');
|
var freezeObject=require('./freezeObject');
|
var FeatureDetection=require('./FeatureDetection');
|
var getAbsoluteUri=require('./getAbsoluteUri');
|
var getBaseUri=require('./getBaseUri');
|
var getExtensionFromUri=require('./getExtensionFromUri');
|
var isBlobUri=require('./isBlobUri');
|
var isCrossOriginUrl=require('./isCrossOriginUrl');
|
var isDataUri=require('./isDataUri');
|
var loadAndExecuteScript=require('./loadAndExecuteScript');
|
var objectToQuery=require('./objectToQuery');
|
var queryToObject=require('./queryToObject');
|
var Request=require('./Request');
|
var RequestErrorEvent=require('./RequestErrorEvent');
|
var RequestScheduler=require('./RequestScheduler');
|
var RequestState=require('./RequestState');
|
var RuntimeError=require('./RuntimeError');
|
var TrustedServers=require('./TrustedServers');
|
|
'use strict';
|
|
var xhrBlobSupported = (function() {
|
try {
|
var xhr = new XMLHttpRequest();
|
xhr.open('GET', '#', true);
|
xhr.responseType = 'blob';
|
return xhr.responseType === 'blob';
|
} catch (e) {
|
return false;
|
}
|
})();
|
|
/**
|
* Parses a query string and returns the object equivalent.
|
*
|
* @param {Uri} uri The Uri with a query object.
|
* @param {Resource} resource The Resource that will be assigned queryParameters.
|
* @param {Boolean} merge If true, we'll merge with the resource's existing queryParameters. Otherwise they will be replaced.
|
* @param {Boolean} preserveQueryParameters If true duplicate parameters will be concatenated into an array. If false, keys in uri will take precedence.
|
*
|
* @private
|
*/
|
function parseQuery(uri, resource, merge, preserveQueryParameters) {
|
var queryString = uri.query;
|
if (!defined(queryString) || (queryString.length === 0)) {
|
return {};
|
}
|
|
var query;
|
// Special case we run into where the querystring is just a string, not key/value pairs
|
if (queryString.indexOf('=') === -1) {
|
var result = {};
|
result[queryString] = undefined;
|
query = result;
|
} else {
|
query = queryToObject(queryString);
|
}
|
|
if (merge) {
|
resource._queryParameters = combineQueryParameters(query, resource._queryParameters, preserveQueryParameters);
|
} else {
|
resource._queryParameters = query;
|
}
|
uri.query = undefined;
|
}
|
|
/**
|
* Converts a query object into a string.
|
*
|
* @param {Uri} uri The Uri object that will have the query object set.
|
* @param {Resource} resource The resource that has queryParameters
|
*
|
* @private
|
*/
|
function stringifyQuery(uri, resource) {
|
var queryObject = resource._queryParameters;
|
|
var keys = Object.keys(queryObject);
|
|
// We have 1 key with an undefined value, so this is just a string, not key/value pairs
|
if (keys.length === 1 && !defined(queryObject[keys[0]])) {
|
uri.query = keys[0];
|
} else {
|
uri.query = objectToQuery(queryObject);
|
}
|
}
|
|
/**
|
* Clones a value if it is defined, otherwise returns the default value
|
*
|
* @param {*} [val] The value to clone.
|
* @param {*} [defaultVal] The default value.
|
*
|
* @returns {*} A clone of val or the defaultVal.
|
*
|
* @private
|
*/
|
function defaultClone(val, defaultVal) {
|
if (!defined(val)) {
|
return defaultVal;
|
}
|
|
return defined(val.clone) ? val.clone() : clone(val);
|
}
|
|
/**
|
* Checks to make sure the Resource isn't already being requested.
|
*
|
* @param {Request} request The request to check.
|
*
|
* @private
|
*/
|
function checkAndResetRequest(request) {
|
if (request.state === RequestState.ISSUED || request.state === RequestState.ACTIVE) {
|
throw new RuntimeError('The Resource is already being fetched.');
|
}
|
|
request.state = RequestState.UNISSUED;
|
request.deferred = undefined;
|
}
|
|
/**
|
* This combines a map of query parameters.
|
*
|
* @param {Object} q1 The first map of query parameters. Values in this map will take precedence if preserveQueryParameters is false.
|
* @param {Object} q2 The second map of query parameters.
|
* @param {Boolean} preserveQueryParameters If true duplicate parameters will be concatenated into an array. If false, keys in q1 will take precedence.
|
*
|
* @returns {Object} The combined map of query parameters.
|
*
|
* @example
|
* var q1 = {
|
* a: 1,
|
* b: 2
|
* };
|
* var q2 = {
|
* a: 3,
|
* c: 4
|
* };
|
* var q3 = {
|
* b: [5, 6],
|
* d: 7
|
* }
|
*
|
* // Returns
|
* // {
|
* // a: [1, 3],
|
* // b: 2,
|
* // c: 4
|
* // };
|
* combineQueryParameters(q1, q2, true);
|
*
|
* // Returns
|
* // {
|
* // a: 1,
|
* // b: 2,
|
* // c: 4
|
* // };
|
* combineQueryParameters(q1, q2, false);
|
*
|
* // Returns
|
* // {
|
* // a: 1,
|
* // b: [2, 5, 6],
|
* // d: 7
|
* // };
|
* combineQueryParameters(q1, q3, true);
|
*
|
* // Returns
|
* // {
|
* // a: 1,
|
* // b: 2,
|
* // d: 7
|
* // };
|
* combineQueryParameters(q1, q3, false);
|
*
|
* @private
|
*/
|
function combineQueryParameters(q1, q2, preserveQueryParameters) {
|
if (!preserveQueryParameters) {
|
return combine(q1, q2);
|
}
|
|
var result = clone(q1, true);
|
for (var param in q2) {
|
if (q2.hasOwnProperty(param)) {
|
var value = result[param];
|
var q2Value = q2[param];
|
if (defined(value)) {
|
if (!Array.isArray(value)) {
|
value = result[param] = [value];
|
}
|
|
result[param] = value.concat(q2Value);
|
} else {
|
result[param] = Array.isArray(q2Value) ? q2Value.slice() : q2Value;
|
}
|
}
|
}
|
|
return result;
|
}
|
|
/**
|
* A resource that includes the location and any other parameters we need to retrieve it or create derived resources. It also provides the ability to retry requests.
|
*
|
* @alias Resource
|
* @constructor
|
*
|
* @param {String|Object} options A url or an object with the following properties
|
* @param {String} options.url The url of the resource.
|
* @param {Object} [options.queryParameters] An object containing query parameters that will be sent when retrieving the resource.
|
* @param {Object} [options.templateValues] Key/Value pairs that are used to replace template values (eg. {x}).
|
* @param {Object} [options.headers={}] Additional HTTP headers that will be sent.
|
* @param {DefaultProxy} [options.proxy] A proxy to be used when loading the resource.
|
* @param {Resource~RetryCallback} [options.retryCallback] The Function to call when a request for this resource fails. If it returns true, the request will be retried.
|
* @param {Number} [options.retryAttempts=0] The number of times the retryCallback should be called before giving up.
|
* @param {Request} [options.request] A Request object that will be used. Intended for internal use only.
|
*
|
* @example
|
* function refreshTokenRetryCallback(resource, error) {
|
* if (error.statusCode === 403) {
|
* // 403 status code means a new token should be generated
|
* return getNewAccessToken()
|
* .then(function(token) {
|
* resource.queryParameters.access_token = token;
|
* return true;
|
* })
|
* .otherwise(function() {
|
* return false;
|
* });
|
* }
|
*
|
* return false;
|
* }
|
*
|
* var resource = new Resource({
|
* url: 'http://server.com/path/to/resource.json',
|
* proxy: new DefaultProxy('/proxy/'),
|
* headers: {
|
* 'X-My-Header': 'valueOfHeader'
|
* },
|
* queryParameters: {
|
* 'access_token': '123-435-456-000'
|
* },
|
* retryCallback: refreshTokenRetryCallback,
|
* retryAttempts: 1
|
* });
|
*/
|
function Resource(options) {
|
options = defaultValue(options, defaultValue.EMPTY_OBJECT);
|
if (typeof options === 'string') {
|
options = {
|
url: options
|
};
|
}
|
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.string('options.url', options.url);
|
//>>includeEnd('debug');
|
|
this._url = undefined;
|
this._templateValues = defaultClone(options.templateValues, {});
|
this._queryParameters = defaultClone(options.queryParameters, {});
|
|
/**
|
* Additional HTTP headers that will be sent with the request.
|
*
|
* @type {Object}
|
*/
|
this.headers = defaultClone(options.headers, {});
|
|
/**
|
* A Request object that will be used. Intended for internal use only.
|
*
|
* @type {Request}
|
*/
|
this.request = defaultValue(options.request, new Request());
|
|
/**
|
* A proxy to be used when loading the resource.
|
*
|
* @type {DefaultProxy}
|
*/
|
this.proxy = options.proxy;
|
|
/**
|
* Function to call when a request for this resource fails. If it returns true or a Promise that resolves to true, the request will be retried.
|
*
|
* @type {Function}
|
*/
|
this.retryCallback = options.retryCallback;
|
|
/**
|
* The number of times the retryCallback should be called before giving up.
|
*
|
* @type {Number}
|
*/
|
this.retryAttempts = defaultValue(options.retryAttempts, 0);
|
this._retryCount = 0;
|
|
var uri = new Uri(options.url);
|
parseQuery(uri, this, true, true);
|
|
// Remove the fragment as it's not sent with a request
|
uri.fragment = undefined;
|
|
this._url = uri.toString();
|
}
|
|
/**
|
* A helper function to create a resource depending on whether we have a String or a Resource
|
*
|
* @param {Resource|String} resource A Resource or a String to use when creating a new Resource.
|
*
|
* @returns {Resource} If resource is a String, a Resource constructed with the url and options. Otherwise the resource parameter is returned.
|
*
|
* @private
|
*/
|
Resource.createIfNeeded = function(resource) {
|
if (resource instanceof Resource) {
|
// Keep existing request object. This function is used internally to duplicate a Resource, so that it can't
|
// be modified outside of a class that holds it (eg. an imagery or terrain provider). Since the Request objects
|
// are managed outside of the providers, by the tile loading code, we want to keep the request property the same so if it is changed
|
// in the underlying tiling code the requests for this resource will use it.
|
return resource.getDerivedResource({
|
request: resource.request
|
});
|
}
|
|
if (typeof resource !== 'string') {
|
return resource;
|
}
|
|
return new Resource({
|
url: resource
|
});
|
};
|
|
var supportsImageBitmapOptionsPromise;
|
/**
|
* A helper function to check whether createImageBitmap supports passing ImageBitmapOptions.
|
*
|
* @returns {Promise<Boolean>} A promise that resolves to true if this browser supports creating an ImageBitmap with options.
|
*
|
* @private
|
*/
|
Resource.supportsImageBitmapOptions = function() {
|
// Until the HTML folks figure out what to do about this, we need to actually try loading an image to
|
// know if this browser supports passing options to the createImageBitmap function.
|
// https://github.com/whatwg/html/pull/4248
|
if (defined(supportsImageBitmapOptionsPromise)) {
|
return supportsImageBitmapOptionsPromise;
|
}
|
|
if (typeof createImageBitmap !== 'function') {
|
supportsImageBitmapOptionsPromise = when.resolve(false);
|
return supportsImageBitmapOptionsPromise;
|
}
|
|
var imageDataUri = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQImWP4////fwAJ+wP9CNHoHgAAAABJRU5ErkJggg==';
|
|
supportsImageBitmapOptionsPromise = Resource.fetchBlob({
|
url : imageDataUri
|
})
|
.then(function(blob) {
|
return createImageBitmap(blob, {
|
imageOrientation: 'flipY'
|
});
|
})
|
.then(function(imageBitmap) {
|
return true;
|
})
|
.otherwise(function() {
|
return false;
|
});
|
|
return supportsImageBitmapOptionsPromise;
|
};
|
|
defineProperties(Resource, {
|
/**
|
* Returns true if blobs are supported.
|
*
|
* @memberof Resource
|
* @type {Boolean}
|
*
|
* @readonly
|
*/
|
isBlobSupported : {
|
get : function() {
|
return xhrBlobSupported;
|
}
|
}
|
});
|
|
defineProperties(Resource.prototype, {
|
/**
|
* Query parameters appended to the url.
|
*
|
* @memberof Resource.prototype
|
* @type {Object}
|
*
|
* @readonly
|
*/
|
queryParameters: {
|
get: function() {
|
return this._queryParameters;
|
}
|
},
|
|
/**
|
* The key/value pairs used to replace template parameters in the url.
|
*
|
* @memberof Resource.prototype
|
* @type {Object}
|
*
|
* @readonly
|
*/
|
templateValues: {
|
get: function() {
|
return this._templateValues;
|
}
|
},
|
|
/**
|
* The url to the resource with template values replaced, query string appended and encoded by proxy if one was set.
|
*
|
* @memberof Resource.prototype
|
* @type {String}
|
*/
|
url: {
|
get: function() {
|
return this.getUrlComponent(true, true);
|
},
|
set: function(value) {
|
var uri = new Uri(value);
|
|
parseQuery(uri, this, false);
|
|
// Remove the fragment as it's not sent with a request
|
uri.fragment = undefined;
|
|
this._url = uri.toString();
|
}
|
},
|
|
/**
|
* The file extension of the resource.
|
*
|
* @memberof Resource.prototype
|
* @type {String}
|
*
|
* @readonly
|
*/
|
extension: {
|
get: function() {
|
return getExtensionFromUri(this._url);
|
}
|
},
|
|
/**
|
* True if the Resource refers to a data URI.
|
*
|
* @memberof Resource.prototype
|
* @type {Boolean}
|
*/
|
isDataUri: {
|
get: function() {
|
return isDataUri(this._url);
|
}
|
},
|
|
/**
|
* True if the Resource refers to a blob URI.
|
*
|
* @memberof Resource.prototype
|
* @type {Boolean}
|
*/
|
isBlobUri: {
|
get: function() {
|
return isBlobUri(this._url);
|
}
|
},
|
|
/**
|
* True if the Resource refers to a cross origin URL.
|
*
|
* @memberof Resource.prototype
|
* @type {Boolean}
|
*/
|
isCrossOriginUrl: {
|
get: function() {
|
return isCrossOriginUrl(this._url);
|
}
|
},
|
|
/**
|
* True if the Resource has request headers. This is equivalent to checking if the headers property has any keys.
|
*
|
* @memberof Resource.prototype
|
* @type {Boolean}
|
*/
|
hasHeaders: {
|
get: function() {
|
return (Object.keys(this.headers).length > 0);
|
}
|
}
|
});
|
|
/**
|
* Returns the url, optional with the query string and processed by a proxy.
|
*
|
* @param {Boolean} [query=false] If true, the query string is included.
|
* @param {Boolean} [proxy=false] If true, the url is processed the proxy object if defined.
|
*
|
* @returns {String} The url with all the requested components.
|
*/
|
Resource.prototype.getUrlComponent = function(query, proxy) {
|
if(this.isDataUri) {
|
return this._url;
|
}
|
|
var uri = new Uri(this._url);
|
|
if (query) {
|
stringifyQuery(uri, this);
|
}
|
|
// objectToQuery escapes the placeholders. Undo that.
|
var url = uri.toString().replace(/%7B/g, '{').replace(/%7D/g, '}');
|
|
var templateValues = this._templateValues;
|
url = url.replace(/{(.*?)}/g, function(match, key) {
|
var replacement = templateValues[key];
|
if (defined(replacement)) {
|
// use the replacement value from templateValues if there is one...
|
return encodeURIComponent(replacement);
|
}
|
// otherwise leave it unchanged
|
return match;
|
});
|
|
if (proxy && defined(this.proxy)) {
|
url = this.proxy.getURL(url);
|
}
|
return url;
|
};
|
|
/**
|
* Combines the specified object and the existing query parameters. This allows you to add many parameters at once,
|
* as opposed to adding them one at a time to the queryParameters property. If a value is already set, it will be replaced with the new value.
|
*
|
* @param {Object} params The query parameters
|
* @param {Boolean} [useAsDefault=false] If true the params will be used as the default values, so they will only be set if they are undefined.
|
*/
|
Resource.prototype.setQueryParameters = function(params, useAsDefault) {
|
if (useAsDefault) {
|
this._queryParameters = combineQueryParameters(this._queryParameters, params, false);
|
} else {
|
this._queryParameters = combineQueryParameters(params, this._queryParameters, false);
|
}
|
};
|
|
/**
|
* Combines the specified object and the existing query parameters. This allows you to add many parameters at once,
|
* as opposed to adding them one at a time to the queryParameters property.
|
*
|
* @param {Object} params The query parameters
|
*/
|
Resource.prototype.appendQueryParameters = function(params) {
|
this._queryParameters = combineQueryParameters(params, this._queryParameters, true);
|
};
|
|
/**
|
* Combines the specified object and the existing template values. This allows you to add many values at once,
|
* as opposed to adding them one at a time to the templateValues property. If a value is already set, it will become an array and the new value will be appended.
|
*
|
* @param {Object} template The template values
|
* @param {Boolean} [useAsDefault=false] If true the values will be used as the default values, so they will only be set if they are undefined.
|
*/
|
Resource.prototype.setTemplateValues = function(template, useAsDefault) {
|
if (useAsDefault) {
|
this._templateValues = combine(this._templateValues, template);
|
} else {
|
this._templateValues = combine(template, this._templateValues);
|
}
|
};
|
|
/**
|
* Returns a resource relative to the current instance. All properties remain the same as the current instance unless overridden in options.
|
*
|
* @param {Object} options An object with the following properties
|
* @param {String} [options.url] The url that will be resolved relative to the url of the current instance.
|
* @param {Object} [options.queryParameters] An object containing query parameters that will be combined with those of the current instance.
|
* @param {Object} [options.templateValues] Key/Value pairs that are used to replace template values (eg. {x}). These will be combined with those of the current instance.
|
* @param {Object} [options.headers={}] Additional HTTP headers that will be sent.
|
* @param {DefaultProxy} [options.proxy] A proxy to be used when loading the resource.
|
* @param {Resource~RetryCallback} [options.retryCallback] The function to call when loading the resource fails.
|
* @param {Number} [options.retryAttempts] The number of times the retryCallback should be called before giving up.
|
* @param {Request} [options.request] A Request object that will be used. Intended for internal use only.
|
* @param {Boolean} [options.preserveQueryParameters=false] If true, this will keep all query parameters from the current resource and derived resource. If false, derived parameters will replace those of the current resource.
|
*
|
* @returns {Resource} The resource derived from the current one.
|
*/
|
Resource.prototype.getDerivedResource = function(options) {
|
var resource = this.clone();
|
resource._retryCount = 0;
|
|
if (defined(options.url)) {
|
var uri = new Uri(options.url);
|
|
var preserveQueryParameters = defaultValue(options.preserveQueryParameters, false);
|
parseQuery(uri, resource, true, preserveQueryParameters);
|
|
// Remove the fragment as it's not sent with a request
|
uri.fragment = undefined;
|
|
resource._url = uri.resolve(new Uri(getAbsoluteUri(this._url))).toString();
|
}
|
|
if (defined(options.queryParameters)) {
|
resource._queryParameters = combine(options.queryParameters, resource._queryParameters);
|
}
|
if (defined(options.templateValues)) {
|
resource._templateValues = combine(options.templateValues, resource.templateValues);
|
}
|
if (defined(options.headers)) {
|
resource.headers = combine(options.headers, resource.headers);
|
}
|
if (defined(options.proxy)) {
|
resource.proxy = options.proxy;
|
}
|
if (defined(options.request)) {
|
resource.request = options.request;
|
}
|
if (defined(options.retryCallback)) {
|
resource.retryCallback = options.retryCallback;
|
}
|
if (defined(options.retryAttempts)) {
|
resource.retryAttempts = options.retryAttempts;
|
}
|
|
return resource;
|
};
|
|
/**
|
* Called when a resource fails to load. This will call the retryCallback function if defined until retryAttempts is reached.
|
*
|
* @param {Error} [error] The error that was encountered.
|
*
|
* @returns {Promise<Boolean>} A promise to a boolean, that if true will cause the resource request to be retried.
|
*
|
* @private
|
*/
|
Resource.prototype.retryOnError = function(error) {
|
var retryCallback = this.retryCallback;
|
if ((typeof retryCallback !== 'function') || (this._retryCount >= this.retryAttempts)) {
|
return when(false);
|
}
|
|
var that = this;
|
return when(retryCallback(this, error))
|
.then(function(result) {
|
++that._retryCount;
|
|
return result;
|
});
|
};
|
|
/**
|
* Duplicates a Resource instance.
|
*
|
* @param {Resource} [result] The object onto which to store the result.
|
*
|
* @returns {Resource} The modified result parameter or a new Resource instance if one was not provided.
|
*/
|
Resource.prototype.clone = function(result) {
|
if (!defined(result)) {
|
result = new Resource({
|
url : this._url
|
});
|
}
|
|
result._url = this._url;
|
result._queryParameters = clone(this._queryParameters);
|
result._templateValues = clone(this._templateValues);
|
result.headers = clone(this.headers);
|
result.proxy = this.proxy;
|
result.retryCallback = this.retryCallback;
|
result.retryAttempts = this.retryAttempts;
|
result._retryCount = 0;
|
result.request = this.request.clone();
|
|
return result;
|
};
|
|
/**
|
* Returns the base path of the Resource.
|
*
|
* @param {Boolean} [includeQuery = false] Whether or not to include the query string and fragment form the uri
|
*
|
* @returns {String} The base URI of the resource
|
*/
|
Resource.prototype.getBaseUri = function(includeQuery) {
|
return getBaseUri(this.getUrlComponent(includeQuery), includeQuery);
|
};
|
|
/**
|
* Appends a forward slash to the URL.
|
*/
|
Resource.prototype.appendForwardSlash = function() {
|
this._url = appendForwardSlash(this._url);
|
};
|
|
/**
|
* Asynchronously loads the resource as raw binary data. Returns a promise that will resolve to
|
* an ArrayBuffer once loaded, or reject if the resource failed to load. The data is loaded
|
* using XMLHttpRequest, which means that in order to make requests to another origin,
|
* the server must have Cross-Origin Resource Sharing (CORS) headers enabled.
|
*
|
* @returns {Promise.<ArrayBuffer>|undefined} a promise that will resolve to the requested data when loaded. Returns undefined if <code>request.throttle</code> is true and the request does not have high enough priority.
|
*
|
* @example
|
* // load a single URL asynchronously
|
* resource.fetchArrayBuffer().then(function(arrayBuffer) {
|
* // use the data
|
* }).otherwise(function(error) {
|
* // an error occurred
|
* });
|
*
|
* @see {@link http://www.w3.org/TR/cors/|Cross-Origin Resource Sharing}
|
* @see {@link http://wiki.commonjs.org/wiki/Promises/A|CommonJS Promises/A}
|
*/
|
Resource.prototype.fetchArrayBuffer = function () {
|
return this.fetch({
|
responseType : 'arraybuffer'
|
});
|
};
|
|
/**
|
* Creates a Resource and calls fetchArrayBuffer() on it.
|
*
|
* @param {String|Object} options A url or an object with the following properties
|
* @param {String} options.url The url of the resource.
|
* @param {Object} [options.queryParameters] An object containing query parameters that will be sent when retrieving the resource.
|
* @param {Object} [options.templateValues] Key/Value pairs that are used to replace template values (eg. {x}).
|
* @param {Object} [options.headers={}] Additional HTTP headers that will be sent.
|
* @param {DefaultProxy} [options.proxy] A proxy to be used when loading the resource.
|
* @param {Resource~RetryCallback} [options.retryCallback] The Function to call when a request for this resource fails. If it returns true, the request will be retried.
|
* @param {Number} [options.retryAttempts=0] The number of times the retryCallback should be called before giving up.
|
* @param {Request} [options.request] A Request object that will be used. Intended for internal use only.
|
* @returns {Promise.<ArrayBuffer>|undefined} a promise that will resolve to the requested data when loaded. Returns undefined if <code>request.throttle</code> is true and the request does not have high enough priority.
|
*/
|
Resource.fetchArrayBuffer = function (options) {
|
var resource = new Resource(options);
|
return resource.fetchArrayBuffer();
|
};
|
|
/**
|
* Asynchronously loads the given resource as a blob. Returns a promise that will resolve to
|
* a Blob once loaded, or reject if the resource failed to load. The data is loaded
|
* using XMLHttpRequest, which means that in order to make requests to another origin,
|
* the server must have Cross-Origin Resource Sharing (CORS) headers enabled.
|
*
|
* @returns {Promise.<Blob>|undefined} a promise that will resolve to the requested data when loaded. Returns undefined if <code>request.throttle</code> is true and the request does not have high enough priority.
|
*
|
* @example
|
* // load a single URL asynchronously
|
* resource.fetchBlob().then(function(blob) {
|
* // use the data
|
* }).otherwise(function(error) {
|
* // an error occurred
|
* });
|
*
|
* @see {@link http://www.w3.org/TR/cors/|Cross-Origin Resource Sharing}
|
* @see {@link http://wiki.commonjs.org/wiki/Promises/A|CommonJS Promises/A}
|
*/
|
Resource.prototype.fetchBlob = function () {
|
return this.fetch({
|
responseType : 'blob'
|
});
|
};
|
|
/**
|
* Creates a Resource and calls fetchBlob() on it.
|
*
|
* @param {String|Object} options A url or an object with the following properties
|
* @param {String} options.url The url of the resource.
|
* @param {Object} [options.queryParameters] An object containing query parameters that will be sent when retrieving the resource.
|
* @param {Object} [options.templateValues] Key/Value pairs that are used to replace template values (eg. {x}).
|
* @param {Object} [options.headers={}] Additional HTTP headers that will be sent.
|
* @param {DefaultProxy} [options.proxy] A proxy to be used when loading the resource.
|
* @param {Resource~RetryCallback} [options.retryCallback] The Function to call when a request for this resource fails. If it returns true, the request will be retried.
|
* @param {Number} [options.retryAttempts=0] The number of times the retryCallback should be called before giving up.
|
* @param {Request} [options.request] A Request object that will be used. Intended for internal use only.
|
* @returns {Promise.<Blob>|undefined} a promise that will resolve to the requested data when loaded. Returns undefined if <code>request.throttle</code> is true and the request does not have high enough priority.
|
*/
|
Resource.fetchBlob = function (options) {
|
var resource = new Resource(options);
|
return resource.fetchBlob();
|
};
|
|
/**
|
* Asynchronously loads the given image resource. Returns a promise that will resolve to
|
* an {@link https://developer.mozilla.org/en-US/docs/Web/API/ImageBitmap|ImageBitmap} if <code>preferImageBitmap</code> is true and the browser supports <code>createImageBitmap</code> or otherwise an
|
* {@link https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement|Image} once loaded, or reject if the image failed to load.
|
*
|
* @param {Object} [options] An object with the following properties.
|
* @param {Boolean} [options.preferBlob=false] If true, we will load the image via a blob.
|
* @param {Boolean} [options.preferImageBitmap=false] If true, image will be decoded during fetch and an <code>ImageBitmap</code> is returned.
|
* @param {Boolean} [options.flipY=false] If true, image will be vertically flipped during decode. Only applies if the browser supports <code>createImageBitmap</code>.
|
* @returns {Promise.<ImageBitmap>|Promise.<Image>|undefined} a promise that will resolve to the requested data when loaded. Returns undefined if <code>request.throttle</code> is true and the request does not have high enough priority.
|
*
|
*
|
* @example
|
* // load a single image asynchronously
|
* resource.fetchImage().then(function(image) {
|
* // use the loaded image
|
* }).otherwise(function(error) {
|
* // an error occurred
|
* });
|
*
|
* // load several images in parallel
|
* when.all([resource1.fetchImage(), resource2.fetchImage()]).then(function(images) {
|
* // images is an array containing all the loaded images
|
* });
|
*
|
* @see {@link http://www.w3.org/TR/cors/|Cross-Origin Resource Sharing}
|
* @see {@link http://wiki.commonjs.org/wiki/Promises/A|CommonJS Promises/A}
|
*/
|
Resource.prototype.fetchImage = function (options) {
|
if (typeof options === 'boolean') {
|
deprecationWarning('fetchImage-parameter-change', 'fetchImage now takes an options object in CesiumJS 1.57. Use resource.fetchImage({ preferBlob: true }) instead of resource.fetchImage(true).');
|
options = {
|
preferBlob : options
|
};
|
}
|
options = defaultValue(options, defaultValue.EMPTY_OBJECT);
|
var preferImageBitmap = defaultValue(options.preferImageBitmap, false);
|
var preferBlob = defaultValue(options.preferBlob, false);
|
var flipY = defaultValue(options.flipY, false);
|
|
checkAndResetRequest(this.request);
|
|
// We try to load the image normally if
|
// 1. Blobs aren't supported
|
// 2. It's a data URI
|
// 3. It's a blob URI
|
// 4. It doesn't have request headers and we preferBlob is false
|
if (!xhrBlobSupported || this.isDataUri || this.isBlobUri || (!this.hasHeaders && !preferBlob)) {
|
return fetchImage({
|
resource: this,
|
flipY: flipY,
|
preferImageBitmap: preferImageBitmap
|
});
|
}
|
|
var blobPromise = this.fetchBlob();
|
if (!defined(blobPromise)) {
|
return;
|
}
|
|
var supportsImageBitmap;
|
var useImageBitmap;
|
var generatedBlobResource;
|
var generatedBlob;
|
return Resource.supportsImageBitmapOptions()
|
.then(function(result) {
|
supportsImageBitmap = result;
|
useImageBitmap = supportsImageBitmap && preferImageBitmap;
|
return blobPromise;
|
})
|
.then(function(blob) {
|
if (!defined(blob)) {
|
return;
|
}
|
generatedBlob = blob;
|
if (useImageBitmap) {
|
return Resource._Implementations.createImageBitmapFromBlob(blob, flipY);
|
}
|
var blobUrl = window.URL.createObjectURL(blob);
|
generatedBlobResource = new Resource({
|
url: blobUrl
|
});
|
|
return fetchImage({
|
resource: generatedBlobResource,
|
flipY: flipY,
|
preferImageBitmap: false
|
});
|
})
|
.then(function(image) {
|
if (!defined(image)) {
|
return;
|
}
|
// This is because the blob object is needed for DiscardMissingTileImagePolicy
|
// See https://github.com/AnalyticalGraphicsInc/cesium/issues/1353
|
image.blob = generatedBlob;
|
if (useImageBitmap) {
|
return image;
|
}
|
|
window.URL.revokeObjectURL(generatedBlobResource.url);
|
return image;
|
})
|
.otherwise(function(error) {
|
if (defined(generatedBlobResource)) {
|
window.URL.revokeObjectURL(generatedBlobResource.url);
|
}
|
|
return when.reject(error);
|
});
|
};
|
|
/**
|
* Fetches an image and returns a promise to it.
|
*
|
* @param {Object} [options] An object with the following properties.
|
* @param {Resource} [options.resource] Resource object that points to an image to fetch.
|
* @param {Boolean} [options.preferImageBitmap] If true, image will be decoded during fetch and an <code>ImageBitmap</code> is returned.
|
* @param {Boolean} [options.flipY] If true, image will be vertically flipped during decode. Only applies if the browser supports <code>createImageBitmap</code>.
|
*
|
* @private
|
*/
|
function fetchImage(options) {
|
var resource = options.resource;
|
var flipY = options.flipY;
|
var preferImageBitmap = options.preferImageBitmap;
|
|
var request = resource.request;
|
request.url = resource.url;
|
request.requestFunction = function() {
|
var url = resource.url;
|
var crossOrigin = false;
|
|
// data URIs can't have crossorigin set.
|
if (!resource.isDataUri && !resource.isBlobUri) {
|
crossOrigin = resource.isCrossOriginUrl;
|
}
|
|
var deferred = when.defer();
|
|
Resource._Implementations.createImage(url, crossOrigin, deferred, flipY, preferImageBitmap);
|
|
return deferred.promise;
|
};
|
|
var promise = RequestScheduler.request(request);
|
if (!defined(promise)) {
|
return;
|
}
|
|
return promise
|
.otherwise(function(e) {
|
// Don't retry cancelled or otherwise aborted requests
|
if (request.state !== RequestState.FAILED) {
|
return when.reject(e);
|
}
|
|
return resource.retryOnError(e)
|
.then(function(retry) {
|
if (retry) {
|
// Reset request so it can try again
|
request.state = RequestState.UNISSUED;
|
request.deferred = undefined;
|
|
return fetchImage({
|
resource: resource,
|
flipY: flipY,
|
preferImageBitmap: preferImageBitmap
|
});
|
}
|
|
return when.reject(e);
|
});
|
});
|
}
|
|
/**
|
* Creates a Resource and calls fetchImage() on it.
|
*
|
* @param {String|Object} options A url or an object with the following properties
|
* @param {String} options.url The url of the resource.
|
* @param {Object} [options.queryParameters] An object containing query parameters that will be sent when retrieving the resource.
|
* @param {Object} [options.templateValues] Key/Value pairs that are used to replace template values (eg. {x}).
|
* @param {Object} [options.headers={}] Additional HTTP headers that will be sent.
|
* @param {DefaultProxy} [options.proxy] A proxy to be used when loading the resource.
|
* @param {Boolean} [options.flipY=false] Whether to vertically flip the image during fetch and decode. Only applies when requesting an image and the browser supports <code>createImageBitmap</code>.
|
* @param {Resource~RetryCallback} [options.retryCallback] The Function to call when a request for this resource fails. If it returns true, the request will be retried.
|
* @param {Number} [options.retryAttempts=0] The number of times the retryCallback should be called before giving up.
|
* @param {Request} [options.request] A Request object that will be used. Intended for internal use only.
|
* @param {Boolean} [options.preferBlob=false] If true, we will load the image via a blob.
|
* @param {Boolean} [options.preferImageBitmap=false] If true, image will be decoded during fetch and an <code>ImageBitmap</code> is returned.
|
* @returns {Promise.<ImageBitmap>|Promise.<Image>|undefined} a promise that will resolve to the requested data when loaded. Returns undefined if <code>request.throttle</code> is true and the request does not have high enough priority.
|
*/
|
Resource.fetchImage = function (options) {
|
var resource = new Resource(options);
|
return resource.fetchImage({
|
flipY: options.flipY,
|
preferBlob: options.preferBlob,
|
preferImageBitmap: options.preferImageBitmap
|
});
|
};
|
|
/**
|
* Asynchronously loads the given resource as text. Returns a promise that will resolve to
|
* a String once loaded, or reject if the resource failed to load. The data is loaded
|
* using XMLHttpRequest, which means that in order to make requests to another origin,
|
* the server must have Cross-Origin Resource Sharing (CORS) headers enabled.
|
*
|
* @returns {Promise.<String>|undefined} a promise that will resolve to the requested data when loaded. Returns undefined if <code>request.throttle</code> is true and the request does not have high enough priority.
|
*
|
* @example
|
* // load text from a URL, setting a custom header
|
* var resource = new Resource({
|
* url: 'http://someUrl.com/someJson.txt',
|
* headers: {
|
* 'X-Custom-Header' : 'some value'
|
* }
|
* });
|
* resource.fetchText().then(function(text) {
|
* // Do something with the text
|
* }).otherwise(function(error) {
|
* // an error occurred
|
* });
|
*
|
* @see {@link https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest|XMLHttpRequest}
|
* @see {@link http://www.w3.org/TR/cors/|Cross-Origin Resource Sharing}
|
* @see {@link http://wiki.commonjs.org/wiki/Promises/A|CommonJS Promises/A}
|
*/
|
Resource.prototype.fetchText = function() {
|
return this.fetch({
|
responseType : 'text'
|
});
|
};
|
|
/**
|
* Creates a Resource and calls fetchText() on it.
|
*
|
* @param {String|Object} options A url or an object with the following properties
|
* @param {String} options.url The url of the resource.
|
* @param {Object} [options.queryParameters] An object containing query parameters that will be sent when retrieving the resource.
|
* @param {Object} [options.templateValues] Key/Value pairs that are used to replace template values (eg. {x}).
|
* @param {Object} [options.headers={}] Additional HTTP headers that will be sent.
|
* @param {DefaultProxy} [options.proxy] A proxy to be used when loading the resource.
|
* @param {Resource~RetryCallback} [options.retryCallback] The Function to call when a request for this resource fails. If it returns true, the request will be retried.
|
* @param {Number} [options.retryAttempts=0] The number of times the retryCallback should be called before giving up.
|
* @param {Request} [options.request] A Request object that will be used. Intended for internal use only.
|
* @returns {Promise.<String>|undefined} a promise that will resolve to the requested data when loaded. Returns undefined if <code>request.throttle</code> is true and the request does not have high enough priority.
|
*/
|
Resource.fetchText = function (options) {
|
var resource = new Resource(options);
|
return resource.fetchText();
|
};
|
|
// note: */* below is */* but that ends the comment block early
|
/**
|
* Asynchronously loads the given resource as JSON. Returns a promise that will resolve to
|
* a JSON object once loaded, or reject if the resource failed to load. The data is loaded
|
* using XMLHttpRequest, which means that in order to make requests to another origin,
|
* the server must have Cross-Origin Resource Sharing (CORS) headers enabled. This function
|
* adds 'Accept: application/json,*/*;q=0.01' to the request headers, if not
|
* already specified.
|
*
|
* @returns {Promise.<Object>|undefined} a promise that will resolve to the requested data when loaded. Returns undefined if <code>request.throttle</code> is true and the request does not have high enough priority.
|
*
|
*
|
* @example
|
* resource.fetchJson().then(function(jsonData) {
|
* // Do something with the JSON object
|
* }).otherwise(function(error) {
|
* // an error occurred
|
* });
|
*
|
* @see {@link http://www.w3.org/TR/cors/|Cross-Origin Resource Sharing}
|
* @see {@link http://wiki.commonjs.org/wiki/Promises/A|CommonJS Promises/A}
|
*/
|
Resource.prototype.fetchJson = function() {
|
var promise = this.fetch({
|
responseType : 'text',
|
headers: {
|
Accept : 'application/json,*/*;q=0.01'
|
}
|
});
|
|
if (!defined(promise)) {
|
return undefined;
|
}
|
|
return promise
|
.then(function(value) {
|
if (!defined(value)) {
|
return;
|
}
|
return JSON.parse(value);
|
});
|
};
|
|
/**
|
* Creates a Resource and calls fetchJson() on it.
|
*
|
* @param {String|Object} options A url or an object with the following properties
|
* @param {String} options.url The url of the resource.
|
* @param {Object} [options.queryParameters] An object containing query parameters that will be sent when retrieving the resource.
|
* @param {Object} [options.templateValues] Key/Value pairs that are used to replace template values (eg. {x}).
|
* @param {Object} [options.headers={}] Additional HTTP headers that will be sent.
|
* @param {DefaultProxy} [options.proxy] A proxy to be used when loading the resource.
|
* @param {Resource~RetryCallback} [options.retryCallback] The Function to call when a request for this resource fails. If it returns true, the request will be retried.
|
* @param {Number} [options.retryAttempts=0] The number of times the retryCallback should be called before giving up.
|
* @param {Request} [options.request] A Request object that will be used. Intended for internal use only.
|
* @returns {Promise.<Object>|undefined} a promise that will resolve to the requested data when loaded. Returns undefined if <code>request.throttle</code> is true and the request does not have high enough priority.
|
*/
|
Resource.fetchJson = function (options) {
|
var resource = new Resource(options);
|
return resource.fetchJson();
|
};
|
|
/**
|
* Asynchronously loads the given resource as XML. Returns a promise that will resolve to
|
* an XML Document once loaded, or reject if the resource failed to load. The data is loaded
|
* using XMLHttpRequest, which means that in order to make requests to another origin,
|
* the server must have Cross-Origin Resource Sharing (CORS) headers enabled.
|
*
|
* @returns {Promise.<XMLDocument>|undefined} a promise that will resolve to the requested data when loaded. Returns undefined if <code>request.throttle</code> is true and the request does not have high enough priority.
|
*
|
*
|
* @example
|
* // load XML from a URL, setting a custom header
|
* Cesium.loadXML('http://someUrl.com/someXML.xml', {
|
* 'X-Custom-Header' : 'some value'
|
* }).then(function(document) {
|
* // Do something with the document
|
* }).otherwise(function(error) {
|
* // an error occurred
|
* });
|
*
|
* @see {@link https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest|XMLHttpRequest}
|
* @see {@link http://www.w3.org/TR/cors/|Cross-Origin Resource Sharing}
|
* @see {@link http://wiki.commonjs.org/wiki/Promises/A|CommonJS Promises/A}
|
*/
|
Resource.prototype.fetchXML = function() {
|
return this.fetch({
|
responseType : 'document',
|
overrideMimeType : 'text/xml'
|
});
|
};
|
|
/**
|
* Creates a Resource and calls fetchXML() on it.
|
*
|
* @param {String|Object} options A url or an object with the following properties
|
* @param {String} options.url The url of the resource.
|
* @param {Object} [options.queryParameters] An object containing query parameters that will be sent when retrieving the resource.
|
* @param {Object} [options.templateValues] Key/Value pairs that are used to replace template values (eg. {x}).
|
* @param {Object} [options.headers={}] Additional HTTP headers that will be sent.
|
* @param {DefaultProxy} [options.proxy] A proxy to be used when loading the resource.
|
* @param {Resource~RetryCallback} [options.retryCallback] The Function to call when a request for this resource fails. If it returns true, the request will be retried.
|
* @param {Number} [options.retryAttempts=0] The number of times the retryCallback should be called before giving up.
|
* @param {Request} [options.request] A Request object that will be used. Intended for internal use only.
|
* @returns {Promise.<XMLDocument>|undefined} a promise that will resolve to the requested data when loaded. Returns undefined if <code>request.throttle</code> is true and the request does not have high enough priority.
|
*/
|
Resource.fetchXML = function (options) {
|
var resource = new Resource(options);
|
return resource.fetchXML();
|
};
|
|
/**
|
* Requests a resource using JSONP.
|
*
|
* @param {String} [callbackParameterName='callback'] The callback parameter name that the server expects.
|
* @returns {Promise.<Object>|undefined} a promise that will resolve to the requested data when loaded. Returns undefined if <code>request.throttle</code> is true and the request does not have high enough priority.
|
*
|
*
|
* @example
|
* // load a data asynchronously
|
* resource.fetchJsonp().then(function(data) {
|
* // use the loaded data
|
* }).otherwise(function(error) {
|
* // an error occurred
|
* });
|
*
|
* @see {@link http://wiki.commonjs.org/wiki/Promises/A|CommonJS Promises/A}
|
*/
|
Resource.prototype.fetchJsonp = function(callbackParameterName) {
|
callbackParameterName = defaultValue(callbackParameterName, 'callback');
|
|
checkAndResetRequest(this.request);
|
|
//generate a unique function name
|
var functionName;
|
do {
|
functionName = 'loadJsonp' + Math.random().toString().substring(2, 8);
|
} while (defined(window[functionName]));
|
|
return fetchJsonp(this, callbackParameterName, functionName);
|
};
|
|
function fetchJsonp(resource, callbackParameterName, functionName) {
|
var callbackQuery = {};
|
callbackQuery[callbackParameterName] = functionName;
|
resource.setQueryParameters(callbackQuery);
|
|
var request = resource.request;
|
request.url = resource.url;
|
request.requestFunction = function() {
|
var deferred = when.defer();
|
|
//assign a function with that name in the global scope
|
window[functionName] = function(data) {
|
deferred.resolve(data);
|
|
try {
|
delete window[functionName];
|
} catch (e) {
|
window[functionName] = undefined;
|
}
|
};
|
|
Resource._Implementations.loadAndExecuteScript(resource.url, functionName, deferred);
|
return deferred.promise;
|
};
|
|
var promise = RequestScheduler.request(request);
|
if (!defined(promise)) {
|
return;
|
}
|
|
return promise
|
.otherwise(function(e) {
|
if (request.state !== RequestState.FAILED) {
|
return when.reject(e);
|
}
|
|
return resource.retryOnError(e)
|
.then(function(retry) {
|
if (retry) {
|
// Reset request so it can try again
|
request.state = RequestState.UNISSUED;
|
request.deferred = undefined;
|
|
return fetchJsonp(resource, callbackParameterName, functionName);
|
}
|
|
return when.reject(e);
|
});
|
});
|
}
|
|
/**
|
* Creates a Resource from a URL and calls fetchJsonp() on it.
|
*
|
* @param {String|Object} options A url or an object with the following properties
|
* @param {String} options.url The url of the resource.
|
* @param {Object} [options.queryParameters] An object containing query parameters that will be sent when retrieving the resource.
|
* @param {Object} [options.templateValues] Key/Value pairs that are used to replace template values (eg. {x}).
|
* @param {Object} [options.headers={}] Additional HTTP headers that will be sent.
|
* @param {DefaultProxy} [options.proxy] A proxy to be used when loading the resource.
|
* @param {Resource~RetryCallback} [options.retryCallback] The Function to call when a request for this resource fails. If it returns true, the request will be retried.
|
* @param {Number} [options.retryAttempts=0] The number of times the retryCallback should be called before giving up.
|
* @param {Request} [options.request] A Request object that will be used. Intended for internal use only.
|
* @param {String} [options.callbackParameterName='callback'] The callback parameter name that the server expects.
|
* @returns {Promise.<Object>|undefined} a promise that will resolve to the requested data when loaded. Returns undefined if <code>request.throttle</code> is true and the request does not have high enough priority.
|
*/
|
Resource.fetchJsonp = function (options) {
|
var resource = new Resource(options);
|
return resource.fetchJsonp(options.callbackParameterName);
|
};
|
|
/**
|
* @private
|
*/
|
Resource.prototype._makeRequest = function(options) {
|
var resource = this;
|
checkAndResetRequest(resource.request);
|
|
var request = resource.request;
|
request.url = resource.url;
|
|
request.requestFunction = function() {
|
var responseType = options.responseType;
|
var headers = combine(options.headers, resource.headers);
|
var overrideMimeType = options.overrideMimeType;
|
var method = options.method;
|
var data = options.data;
|
var deferred = when.defer();
|
var xhr = Resource._Implementations.loadWithXhr(resource.url, responseType, method, data, headers, deferred, overrideMimeType);
|
if (defined(xhr) && defined(xhr.abort)) {
|
request.cancelFunction = function() {
|
xhr.abort();
|
};
|
}
|
return deferred.promise;
|
};
|
|
var promise = RequestScheduler.request(request);
|
if (!defined(promise)) {
|
return;
|
}
|
|
return promise
|
.then(function(data) {
|
return data;
|
})
|
.otherwise(function(e) {
|
if (request.state !== RequestState.FAILED) {
|
return when.reject(e);
|
}
|
|
return resource.retryOnError(e)
|
.then(function(retry) {
|
if (retry) {
|
// Reset request so it can try again
|
request.state = RequestState.UNISSUED;
|
request.deferred = undefined;
|
|
return resource.fetch(options);
|
}
|
|
return when.reject(e);
|
});
|
});
|
};
|
|
var dataUriRegex = /^data:(.*?)(;base64)?,(.*)$/;
|
|
function decodeDataUriText(isBase64, data) {
|
var result = decodeURIComponent(data);
|
if (isBase64) {
|
return atob(result);
|
}
|
return result;
|
}
|
|
function decodeDataUriArrayBuffer(isBase64, data) {
|
var byteString = decodeDataUriText(isBase64, data);
|
var buffer = new ArrayBuffer(byteString.length);
|
var view = new Uint8Array(buffer);
|
for (var i = 0; i < byteString.length; i++) {
|
view[i] = byteString.charCodeAt(i);
|
}
|
return buffer;
|
}
|
|
function decodeDataUri(dataUriRegexResult, responseType) {
|
responseType = defaultValue(responseType, '');
|
var mimeType = dataUriRegexResult[1];
|
var isBase64 = !!dataUriRegexResult[2];
|
var data = dataUriRegexResult[3];
|
|
switch (responseType) {
|
case '':
|
case 'text':
|
return decodeDataUriText(isBase64, data);
|
case 'arraybuffer':
|
return decodeDataUriArrayBuffer(isBase64, data);
|
case 'blob':
|
var buffer = decodeDataUriArrayBuffer(isBase64, data);
|
return new Blob([buffer], {
|
type : mimeType
|
});
|
case 'document':
|
var parser = new DOMParser();
|
return parser.parseFromString(decodeDataUriText(isBase64, data), mimeType);
|
case 'json':
|
return JSON.parse(decodeDataUriText(isBase64, data));
|
default:
|
//>>includeStart('debug', pragmas.debug);
|
throw new DeveloperError('Unhandled responseType: ' + responseType);
|
//>>includeEnd('debug');
|
}
|
}
|
|
/**
|
* Asynchronously loads the given resource. Returns a promise that will resolve to
|
* the result once loaded, or reject if the resource failed to load. The data is loaded
|
* using XMLHttpRequest, which means that in order to make requests to another origin,
|
* the server must have Cross-Origin Resource Sharing (CORS) headers enabled. It's recommended that you use
|
* the more specific functions eg. fetchJson, fetchBlob, etc.
|
*
|
* @param {Object} [options] Object with the following properties:
|
* @param {String} [options.responseType] The type of response. This controls the type of item returned.
|
* @param {Object} [options.headers] Additional HTTP headers to send with the request, if any.
|
* @param {String} [options.overrideMimeType] Overrides the MIME type returned by the server.
|
* @returns {Promise.<Object>|undefined} a promise that will resolve to the requested data when loaded. Returns undefined if <code>request.throttle</code> is true and the request does not have high enough priority.
|
*
|
*
|
* @example
|
* resource.fetch()
|
* .then(function(body) {
|
* // use the data
|
* }).otherwise(function(error) {
|
* // an error occurred
|
* });
|
*
|
* @see {@link http://www.w3.org/TR/cors/|Cross-Origin Resource Sharing}
|
* @see {@link http://wiki.commonjs.org/wiki/Promises/A|CommonJS Promises/A}
|
*/
|
Resource.prototype.fetch = function(options) {
|
options = defaultClone(options, {});
|
options.method = 'GET';
|
|
return this._makeRequest(options);
|
};
|
|
/**
|
* Creates a Resource from a URL and calls fetch() on it.
|
*
|
* @param {String|Object} options A url or an object with the following properties
|
* @param {String} options.url The url of the resource.
|
* @param {Object} [options.queryParameters] An object containing query parameters that will be sent when retrieving the resource.
|
* @param {Object} [options.templateValues] Key/Value pairs that are used to replace template values (eg. {x}).
|
* @param {Object} [options.headers={}] Additional HTTP headers that will be sent.
|
* @param {DefaultProxy} [options.proxy] A proxy to be used when loading the resource.
|
* @param {Resource~RetryCallback} [options.retryCallback] The Function to call when a request for this resource fails. If it returns true, the request will be retried.
|
* @param {Number} [options.retryAttempts=0] The number of times the retryCallback should be called before giving up.
|
* @param {Request} [options.request] A Request object that will be used. Intended for internal use only.
|
* @param {String} [options.responseType] The type of response. This controls the type of item returned.
|
* @param {String} [options.overrideMimeType] Overrides the MIME type returned by the server.
|
* @returns {Promise.<Object>|undefined} a promise that will resolve to the requested data when loaded. Returns undefined if <code>request.throttle</code> is true and the request does not have high enough priority.
|
*/
|
Resource.fetch = function (options) {
|
var resource = new Resource(options);
|
return resource.fetch({
|
// Make copy of just the needed fields because headers can be passed to both the constructor and to fetch
|
responseType: options.responseType,
|
overrideMimeType: options.overrideMimeType
|
});
|
};
|
|
/**
|
* Asynchronously deletes the given resource. Returns a promise that will resolve to
|
* the result once loaded, or reject if the resource failed to load. The data is loaded
|
* using XMLHttpRequest, which means that in order to make requests to another origin,
|
* the server must have Cross-Origin Resource Sharing (CORS) headers enabled.
|
*
|
* @param {Object} [options] Object with the following properties:
|
* @param {String} [options.responseType] The type of response. This controls the type of item returned.
|
* @param {Object} [options.headers] Additional HTTP headers to send with the request, if any.
|
* @param {String} [options.overrideMimeType] Overrides the MIME type returned by the server.
|
* @returns {Promise.<Object>|undefined} a promise that will resolve to the requested data when loaded. Returns undefined if <code>request.throttle</code> is true and the request does not have high enough priority.
|
*
|
*
|
* @example
|
* resource.delete()
|
* .then(function(body) {
|
* // use the data
|
* }).otherwise(function(error) {
|
* // an error occurred
|
* });
|
*
|
* @see {@link http://www.w3.org/TR/cors/|Cross-Origin Resource Sharing}
|
* @see {@link http://wiki.commonjs.org/wiki/Promises/A|CommonJS Promises/A}
|
*/
|
Resource.prototype.delete = function(options) {
|
options = defaultClone(options, {});
|
options.method = 'DELETE';
|
|
return this._makeRequest(options);
|
};
|
|
/**
|
* Creates a Resource from a URL and calls delete() on it.
|
*
|
* @param {String|Object} options A url or an object with the following properties
|
* @param {String} options.url The url of the resource.
|
* @param {Object} [options.data] Data that is posted with the resource.
|
* @param {Object} [options.queryParameters] An object containing query parameters that will be sent when retrieving the resource.
|
* @param {Object} [options.templateValues] Key/Value pairs that are used to replace template values (eg. {x}).
|
* @param {Object} [options.headers={}] Additional HTTP headers that will be sent.
|
* @param {DefaultProxy} [options.proxy] A proxy to be used when loading the resource.
|
* @param {Resource~RetryCallback} [options.retryCallback] The Function to call when a request for this resource fails. If it returns true, the request will be retried.
|
* @param {Number} [options.retryAttempts=0] The number of times the retryCallback should be called before giving up.
|
* @param {Request} [options.request] A Request object that will be used. Intended for internal use only.
|
* @param {String} [options.responseType] The type of response. This controls the type of item returned.
|
* @param {String} [options.overrideMimeType] Overrides the MIME type returned by the server.
|
* @returns {Promise.<Object>|undefined} a promise that will resolve to the requested data when loaded. Returns undefined if <code>request.throttle</code> is true and the request does not have high enough priority.
|
*/
|
Resource.delete = function (options) {
|
var resource = new Resource(options);
|
return resource.delete({
|
// Make copy of just the needed fields because headers can be passed to both the constructor and to fetch
|
responseType: options.responseType,
|
overrideMimeType: options.overrideMimeType,
|
data: options.data
|
});
|
};
|
|
/**
|
* Asynchronously gets headers the given resource. Returns a promise that will resolve to
|
* the result once loaded, or reject if the resource failed to load. The data is loaded
|
* using XMLHttpRequest, which means that in order to make requests to another origin,
|
* the server must have Cross-Origin Resource Sharing (CORS) headers enabled.
|
*
|
* @param {Object} [options] Object with the following properties:
|
* @param {String} [options.responseType] The type of response. This controls the type of item returned.
|
* @param {Object} [options.headers] Additional HTTP headers to send with the request, if any.
|
* @param {String} [options.overrideMimeType] Overrides the MIME type returned by the server.
|
* @returns {Promise.<Object>|undefined} a promise that will resolve to the requested data when loaded. Returns undefined if <code>request.throttle</code> is true and the request does not have high enough priority.
|
*
|
*
|
* @example
|
* resource.head()
|
* .then(function(headers) {
|
* // use the data
|
* }).otherwise(function(error) {
|
* // an error occurred
|
* });
|
*
|
* @see {@link http://www.w3.org/TR/cors/|Cross-Origin Resource Sharing}
|
* @see {@link http://wiki.commonjs.org/wiki/Promises/A|CommonJS Promises/A}
|
*/
|
Resource.prototype.head = function(options) {
|
options = defaultClone(options, {});
|
options.method = 'HEAD';
|
|
return this._makeRequest(options);
|
};
|
|
/**
|
* Creates a Resource from a URL and calls head() on it.
|
*
|
* @param {String|Object} options A url or an object with the following properties
|
* @param {String} options.url The url of the resource.
|
* @param {Object} [options.queryParameters] An object containing query parameters that will be sent when retrieving the resource.
|
* @param {Object} [options.templateValues] Key/Value pairs that are used to replace template values (eg. {x}).
|
* @param {Object} [options.headers={}] Additional HTTP headers that will be sent.
|
* @param {DefaultProxy} [options.proxy] A proxy to be used when loading the resource.
|
* @param {Resource~RetryCallback} [options.retryCallback] The Function to call when a request for this resource fails. If it returns true, the request will be retried.
|
* @param {Number} [options.retryAttempts=0] The number of times the retryCallback should be called before giving up.
|
* @param {Request} [options.request] A Request object that will be used. Intended for internal use only.
|
* @param {String} [options.responseType] The type of response. This controls the type of item returned.
|
* @param {String} [options.overrideMimeType] Overrides the MIME type returned by the server.
|
* @returns {Promise.<Object>|undefined} a promise that will resolve to the requested data when loaded. Returns undefined if <code>request.throttle</code> is true and the request does not have high enough priority.
|
*/
|
Resource.head = function (options) {
|
var resource = new Resource(options);
|
return resource.head({
|
// Make copy of just the needed fields because headers can be passed to both the constructor and to fetch
|
responseType: options.responseType,
|
overrideMimeType: options.overrideMimeType
|
});
|
};
|
|
/**
|
* Asynchronously gets options the given resource. Returns a promise that will resolve to
|
* the result once loaded, or reject if the resource failed to load. The data is loaded
|
* using XMLHttpRequest, which means that in order to make requests to another origin,
|
* the server must have Cross-Origin Resource Sharing (CORS) headers enabled.
|
*
|
* @param {Object} [options] Object with the following properties:
|
* @param {String} [options.responseType] The type of response. This controls the type of item returned.
|
* @param {Object} [options.headers] Additional HTTP headers to send with the request, if any.
|
* @param {String} [options.overrideMimeType] Overrides the MIME type returned by the server.
|
* @returns {Promise.<Object>|undefined} a promise that will resolve to the requested data when loaded. Returns undefined if <code>request.throttle</code> is true and the request does not have high enough priority.
|
*
|
*
|
* @example
|
* resource.options()
|
* .then(function(headers) {
|
* // use the data
|
* }).otherwise(function(error) {
|
* // an error occurred
|
* });
|
*
|
* @see {@link http://www.w3.org/TR/cors/|Cross-Origin Resource Sharing}
|
* @see {@link http://wiki.commonjs.org/wiki/Promises/A|CommonJS Promises/A}
|
*/
|
Resource.prototype.options = function(options) {
|
options = defaultClone(options, {});
|
options.method = 'OPTIONS';
|
|
return this._makeRequest(options);
|
};
|
|
/**
|
* Creates a Resource from a URL and calls options() on it.
|
*
|
* @param {String|Object} options A url or an object with the following properties
|
* @param {String} options.url The url of the resource.
|
* @param {Object} [options.queryParameters] An object containing query parameters that will be sent when retrieving the resource.
|
* @param {Object} [options.templateValues] Key/Value pairs that are used to replace template values (eg. {x}).
|
* @param {Object} [options.headers={}] Additional HTTP headers that will be sent.
|
* @param {DefaultProxy} [options.proxy] A proxy to be used when loading the resource.
|
* @param {Resource~RetryCallback} [options.retryCallback] The Function to call when a request for this resource fails. If it returns true, the request will be retried.
|
* @param {Number} [options.retryAttempts=0] The number of times the retryCallback should be called before giving up.
|
* @param {Request} [options.request] A Request object that will be used. Intended for internal use only.
|
* @param {String} [options.responseType] The type of response. This controls the type of item returned.
|
* @param {String} [options.overrideMimeType] Overrides the MIME type returned by the server.
|
* @returns {Promise.<Object>|undefined} a promise that will resolve to the requested data when loaded. Returns undefined if <code>request.throttle</code> is true and the request does not have high enough priority.
|
*/
|
Resource.options = function (options) {
|
var resource = new Resource(options);
|
return resource.options({
|
// Make copy of just the needed fields because headers can be passed to both the constructor and to fetch
|
responseType: options.responseType,
|
overrideMimeType: options.overrideMimeType
|
});
|
};
|
|
/**
|
* Asynchronously posts data to the given resource. Returns a promise that will resolve to
|
* the result once loaded, or reject if the resource failed to load. The data is loaded
|
* using XMLHttpRequest, which means that in order to make requests to another origin,
|
* the server must have Cross-Origin Resource Sharing (CORS) headers enabled.
|
*
|
* @param {Object} data Data that is posted with the resource.
|
* @param {Object} [options] Object with the following properties:
|
* @param {Object} [options.data] Data that is posted with the resource.
|
* @param {String} [options.responseType] The type of response. This controls the type of item returned.
|
* @param {Object} [options.headers] Additional HTTP headers to send with the request, if any.
|
* @param {String} [options.overrideMimeType] Overrides the MIME type returned by the server.
|
* @returns {Promise.<Object>|undefined} a promise that will resolve to the requested data when loaded. Returns undefined if <code>request.throttle</code> is true and the request does not have high enough priority.
|
*
|
*
|
* @example
|
* resource.post(data)
|
* .then(function(result) {
|
* // use the result
|
* }).otherwise(function(error) {
|
* // an error occurred
|
* });
|
*
|
* @see {@link http://www.w3.org/TR/cors/|Cross-Origin Resource Sharing}
|
* @see {@link http://wiki.commonjs.org/wiki/Promises/A|CommonJS Promises/A}
|
*/
|
Resource.prototype.post = function(data, options) {
|
Check.defined('data', data);
|
|
options = defaultClone(options, {});
|
options.method = 'POST';
|
options.data = data;
|
|
return this._makeRequest(options);
|
};
|
|
/**
|
* Creates a Resource from a URL and calls post() on it.
|
*
|
* @param {Object} options A url or an object with the following properties
|
* @param {String} options.url The url of the resource.
|
* @param {Object} options.data Data that is posted with the resource.
|
* @param {Object} [options.queryParameters] An object containing query parameters that will be sent when retrieving the resource.
|
* @param {Object} [options.templateValues] Key/Value pairs that are used to replace template values (eg. {x}).
|
* @param {Object} [options.headers={}] Additional HTTP headers that will be sent.
|
* @param {DefaultProxy} [options.proxy] A proxy to be used when loading the resource.
|
* @param {Resource~RetryCallback} [options.retryCallback] The Function to call when a request for this resource fails. If it returns true, the request will be retried.
|
* @param {Number} [options.retryAttempts=0] The number of times the retryCallback should be called before giving up.
|
* @param {Request} [options.request] A Request object that will be used. Intended for internal use only.
|
* @param {String} [options.responseType] The type of response. This controls the type of item returned.
|
* @param {String} [options.overrideMimeType] Overrides the MIME type returned by the server.
|
* @returns {Promise.<Object>|undefined} a promise that will resolve to the requested data when loaded. Returns undefined if <code>request.throttle</code> is true and the request does not have high enough priority.
|
*/
|
Resource.post = function (options) {
|
var resource = new Resource(options);
|
return resource.post(options.data, {
|
// Make copy of just the needed fields because headers can be passed to both the constructor and to post
|
responseType: options.responseType,
|
overrideMimeType: options.overrideMimeType
|
});
|
};
|
|
/**
|
* Asynchronously puts data to the given resource. Returns a promise that will resolve to
|
* the result once loaded, or reject if the resource failed to load. The data is loaded
|
* using XMLHttpRequest, which means that in order to make requests to another origin,
|
* the server must have Cross-Origin Resource Sharing (CORS) headers enabled.
|
*
|
* @param {Object} data Data that is posted with the resource.
|
* @param {Object} [options] Object with the following properties:
|
* @param {String} [options.responseType] The type of response. This controls the type of item returned.
|
* @param {Object} [options.headers] Additional HTTP headers to send with the request, if any.
|
* @param {String} [options.overrideMimeType] Overrides the MIME type returned by the server.
|
* @returns {Promise.<Object>|undefined} a promise that will resolve to the requested data when loaded. Returns undefined if <code>request.throttle</code> is true and the request does not have high enough priority.
|
*
|
*
|
* @example
|
* resource.put(data)
|
* .then(function(result) {
|
* // use the result
|
* }).otherwise(function(error) {
|
* // an error occurred
|
* });
|
*
|
* @see {@link http://www.w3.org/TR/cors/|Cross-Origin Resource Sharing}
|
* @see {@link http://wiki.commonjs.org/wiki/Promises/A|CommonJS Promises/A}
|
*/
|
Resource.prototype.put = function(data, options) {
|
Check.defined('data', data);
|
|
options = defaultClone(options, {});
|
options.method = 'PUT';
|
options.data = data;
|
|
return this._makeRequest(options);
|
};
|
|
/**
|
* Creates a Resource from a URL and calls put() on it.
|
*
|
* @param {Object} options A url or an object with the following properties
|
* @param {String} options.url The url of the resource.
|
* @param {Object} options.data Data that is posted with the resource.
|
* @param {Object} [options.queryParameters] An object containing query parameters that will be sent when retrieving the resource.
|
* @param {Object} [options.templateValues] Key/Value pairs that are used to replace template values (eg. {x}).
|
* @param {Object} [options.headers={}] Additional HTTP headers that will be sent.
|
* @param {DefaultProxy} [options.proxy] A proxy to be used when loading the resource.
|
* @param {Resource~RetryCallback} [options.retryCallback] The Function to call when a request for this resource fails. If it returns true, the request will be retried.
|
* @param {Number} [options.retryAttempts=0] The number of times the retryCallback should be called before giving up.
|
* @param {Request} [options.request] A Request object that will be used. Intended for internal use only.
|
* @param {String} [options.responseType] The type of response. This controls the type of item returned.
|
* @param {String} [options.overrideMimeType] Overrides the MIME type returned by the server.
|
* @returns {Promise.<Object>|undefined} a promise that will resolve to the requested data when loaded. Returns undefined if <code>request.throttle</code> is true and the request does not have high enough priority.
|
*/
|
Resource.put = function (options) {
|
var resource = new Resource(options);
|
return resource.put(options.data, {
|
// Make copy of just the needed fields because headers can be passed to both the constructor and to post
|
responseType: options.responseType,
|
overrideMimeType: options.overrideMimeType
|
});
|
};
|
|
/**
|
* Asynchronously patches data to the given resource. Returns a promise that will resolve to
|
* the result once loaded, or reject if the resource failed to load. The data is loaded
|
* using XMLHttpRequest, which means that in order to make requests to another origin,
|
* the server must have Cross-Origin Resource Sharing (CORS) headers enabled.
|
*
|
* @param {Object} data Data that is posted with the resource.
|
* @param {Object} [options] Object with the following properties:
|
* @param {String} [options.responseType] The type of response. This controls the type of item returned.
|
* @param {Object} [options.headers] Additional HTTP headers to send with the request, if any.
|
* @param {String} [options.overrideMimeType] Overrides the MIME type returned by the server.
|
* @returns {Promise.<Object>|undefined} a promise that will resolve to the requested data when loaded. Returns undefined if <code>request.throttle</code> is true and the request does not have high enough priority.
|
*
|
*
|
* @example
|
* resource.patch(data)
|
* .then(function(result) {
|
* // use the result
|
* }).otherwise(function(error) {
|
* // an error occurred
|
* });
|
*
|
* @see {@link http://www.w3.org/TR/cors/|Cross-Origin Resource Sharing}
|
* @see {@link http://wiki.commonjs.org/wiki/Promises/A|CommonJS Promises/A}
|
*/
|
Resource.prototype.patch = function(data, options) {
|
Check.defined('data', data);
|
|
options = defaultClone(options, {});
|
options.method = 'PATCH';
|
options.data = data;
|
|
return this._makeRequest(options);
|
};
|
|
/**
|
* Creates a Resource from a URL and calls patch() on it.
|
*
|
* @param {Object} options A url or an object with the following properties
|
* @param {String} options.url The url of the resource.
|
* @param {Object} options.data Data that is posted with the resource.
|
* @param {Object} [options.queryParameters] An object containing query parameters that will be sent when retrieving the resource.
|
* @param {Object} [options.templateValues] Key/Value pairs that are used to replace template values (eg. {x}).
|
* @param {Object} [options.headers={}] Additional HTTP headers that will be sent.
|
* @param {DefaultProxy} [options.proxy] A proxy to be used when loading the resource.
|
* @param {Resource~RetryCallback} [options.retryCallback] The Function to call when a request for this resource fails. If it returns true, the request will be retried.
|
* @param {Number} [options.retryAttempts=0] The number of times the retryCallback should be called before giving up.
|
* @param {Request} [options.request] A Request object that will be used. Intended for internal use only.
|
* @param {String} [options.responseType] The type of response. This controls the type of item returned.
|
* @param {String} [options.overrideMimeType] Overrides the MIME type returned by the server.
|
* @returns {Promise.<Object>|undefined} a promise that will resolve to the requested data when loaded. Returns undefined if <code>request.throttle</code> is true and the request does not have high enough priority.
|
*/
|
Resource.patch = function (options) {
|
var resource = new Resource(options);
|
return resource.patch(options.data, {
|
// Make copy of just the needed fields because headers can be passed to both the constructor and to post
|
responseType: options.responseType,
|
overrideMimeType: options.overrideMimeType
|
});
|
};
|
|
/**
|
* Contains implementations of functions that can be replaced for testing
|
*
|
* @private
|
*/
|
Resource._Implementations = {};
|
|
function loadImageElement(url, crossOrigin, deferred) {
|
var image = new Image();
|
|
image.onload = function() {
|
deferred.resolve(image);
|
};
|
|
image.onerror = function(e) {
|
deferred.reject(e);
|
};
|
|
if (crossOrigin) {
|
if (TrustedServers.contains(url)) {
|
image.crossOrigin = 'use-credentials';
|
} else {
|
image.crossOrigin = '';
|
}
|
}
|
|
image.src = url;
|
}
|
|
Resource._Implementations.createImage = function(url, crossOrigin, deferred, flipY, preferImageBitmap) {
|
// Passing an Image to createImageBitmap will force it to run on the main thread
|
// since DOM elements don't exist on workers. We convert it to a blob so it's non-blocking.
|
// See:
|
// https://bugzilla.mozilla.org/show_bug.cgi?id=1044102#c38
|
// https://bugs.chromium.org/p/chromium/issues/detail?id=580202#c10
|
Resource.supportsImageBitmapOptions()
|
.then(function(supportsImageBitmap) {
|
// We can only use ImageBitmap if we can flip on decode.
|
// See: https://github.com/AnalyticalGraphicsInc/cesium/pull/7579#issuecomment-466146898
|
if (!(supportsImageBitmap && preferImageBitmap)) {
|
loadImageElement(url, crossOrigin, deferred);
|
return;
|
}
|
|
return Resource.fetchBlob({
|
url: url
|
});
|
})
|
.then(function(blob) {
|
if (!defined(blob)) {
|
return;
|
}
|
|
return Resource._Implementations.createImageBitmapFromBlob(blob, flipY);
|
})
|
.then(function(imageBitmap) {
|
if (!defined(imageBitmap)) {
|
return;
|
}
|
|
deferred.resolve(imageBitmap);
|
})
|
.otherwise(deferred.reject);
|
};
|
|
Resource._Implementations.createImageBitmapFromBlob = function(blob, flipY) {
|
return createImageBitmap(blob, {
|
imageOrientation: flipY ? 'flipY' : 'none'
|
});
|
};
|
|
function decodeResponse(loadWithHttpResponse, responseType) {
|
switch (responseType) {
|
case 'text':
|
return loadWithHttpResponse.toString('utf8');
|
case 'json':
|
return JSON.parse(loadWithHttpResponse.toString('utf8'));
|
default:
|
return new Uint8Array(loadWithHttpResponse).buffer;
|
}
|
}
|
|
function loadWithHttpRequest(url, responseType, method, data, headers, deferred, overrideMimeType) {
|
|
// Specifically use the Node version of require to avoid conflicts with the global
|
// require defined in the built version of Cesium.
|
var nodeRequire = global.require; // eslint-disable-line
|
|
// Note: only the 'json' and 'text' responseTypes transforms the loaded buffer
|
var URL = nodeRequire('url').parse(url);
|
var http = URL.protocol === 'https:' ? nodeRequire('https') : nodeRequire('http');
|
var zlib = nodeRequire('zlib');
|
var options = {
|
protocol : URL.protocol,
|
hostname : URL.hostname,
|
port : URL.port,
|
path : URL.path,
|
query : URL.query,
|
method : method,
|
headers : headers
|
};
|
|
http.request(options)
|
.on('response', function(res) {
|
if (res.statusCode < 200 || res.statusCode >= 300) {
|
deferred.reject(new RequestErrorEvent(res.statusCode, res, res.headers));
|
return;
|
}
|
|
var chunkArray = [];
|
res.on('data', function(chunk) {
|
chunkArray.push(chunk);
|
});
|
|
res.on('end', function() {
|
var result = Buffer.concat(chunkArray); // eslint-disable-line
|
if (res.headers['content-encoding'] === 'gzip') {
|
zlib.gunzip(result, function(error, resultUnzipped) {
|
if (error) {
|
deferred.reject(new RuntimeError('Error decompressing response.'));
|
} else {
|
deferred.resolve(decodeResponse(resultUnzipped, responseType));
|
}
|
});
|
} else {
|
deferred.resolve(decodeResponse(result, responseType));
|
}
|
});
|
}).on('error', function(e) {
|
deferred.reject(new RequestErrorEvent());
|
}).end();
|
}
|
|
var noXMLHttpRequest = typeof XMLHttpRequest === 'undefined';
|
Resource._Implementations.loadWithXhr = function(url, responseType, method, data, headers, deferred, overrideMimeType) {
|
var dataUriRegexResult = dataUriRegex.exec(url);
|
if (dataUriRegexResult !== null) {
|
deferred.resolve(decodeDataUri(dataUriRegexResult, responseType));
|
return;
|
}
|
|
if (noXMLHttpRequest) {
|
loadWithHttpRequest(url, responseType, method, data, headers, deferred, overrideMimeType);
|
return;
|
}
|
|
var xhr = new XMLHttpRequest();
|
|
if (TrustedServers.contains(url)) {
|
xhr.withCredentials = true;
|
}
|
|
xhr.open(method, url, true);
|
|
if (defined(overrideMimeType) && defined(xhr.overrideMimeType)) {
|
xhr.overrideMimeType(overrideMimeType);
|
}
|
|
if (defined(headers)) {
|
for (var key in headers) {
|
if (headers.hasOwnProperty(key)) {
|
xhr.setRequestHeader(key, headers[key]);
|
}
|
}
|
}
|
|
if (defined(responseType)) {
|
xhr.responseType = responseType;
|
}
|
|
// While non-standard, file protocol always returns a status of 0 on success
|
var localFile = false;
|
if (typeof url === 'string') {
|
localFile = (url.indexOf('file://') === 0) || (typeof window !== 'undefined' && window.location.origin === 'file://');
|
}
|
|
xhr.onload = function() {
|
if ((xhr.status < 200 || xhr.status >= 300) && !(localFile && xhr.status === 0)) {
|
deferred.reject(new RequestErrorEvent(xhr.status, xhr.response, xhr.getAllResponseHeaders()));
|
return;
|
}
|
|
var response = xhr.response;
|
var browserResponseType = xhr.responseType;
|
|
if (method === 'HEAD' || method === 'OPTIONS') {
|
var responseHeaderString = xhr.getAllResponseHeaders();
|
var splitHeaders = responseHeaderString.trim().split(/[\r\n]+/);
|
|
var responseHeaders = {};
|
splitHeaders.forEach(function (line) {
|
var parts = line.split(': ');
|
var header = parts.shift();
|
responseHeaders[header] = parts.join(': ');
|
});
|
|
deferred.resolve(responseHeaders);
|
return;
|
}
|
|
//All modern browsers will go into either the first or second if block or last else block.
|
//Other code paths support older browsers that either do not support the supplied responseType
|
//or do not support the xhr.response property.
|
if (xhr.status === 204) {
|
// accept no content
|
deferred.resolve();
|
} else if (defined(response) && (!defined(responseType) || (browserResponseType === responseType))) {
|
deferred.resolve(response);
|
} else if ((responseType === 'json') && typeof response === 'string') {
|
try {
|
deferred.resolve(JSON.parse(response));
|
} catch (e) {
|
deferred.reject(e);
|
}
|
} else if ((browserResponseType === '' || browserResponseType === 'document') && defined(xhr.responseXML) && xhr.responseXML.hasChildNodes()) {
|
deferred.resolve(xhr.responseXML);
|
} else if ((browserResponseType === '' || browserResponseType === 'text') && defined(xhr.responseText)) {
|
deferred.resolve(xhr.responseText);
|
} else {
|
deferred.reject(new RuntimeError('Invalid XMLHttpRequest response type.'));
|
}
|
};
|
|
xhr.onerror = function(e) {
|
deferred.reject(new RequestErrorEvent());
|
};
|
|
xhr.send(data);
|
|
return xhr;
|
};
|
|
Resource._Implementations.loadAndExecuteScript = function(url, functionName, deferred) {
|
return loadAndExecuteScript(url, functionName).otherwise(deferred.reject);
|
};
|
|
/**
|
* The default implementations
|
*
|
* @private
|
*/
|
Resource._DefaultImplementations = {};
|
Resource._DefaultImplementations.createImage = Resource._Implementations.createImage;
|
Resource._DefaultImplementations.loadWithXhr = Resource._Implementations.loadWithXhr;
|
Resource._DefaultImplementations.loadAndExecuteScript = Resource._Implementations.loadAndExecuteScript;
|
|
/**
|
* A resource instance initialized to the current browser location
|
*
|
* @type {Resource}
|
* @constant
|
*/
|
Resource.DEFAULT = freezeObject(new Resource({
|
url: (typeof document === 'undefined') ? '' : document.location.href.split('?')[0]
|
}));
|
|
/**
|
* A function that returns the value of the property.
|
* @callback Resource~RetryCallback
|
*
|
* @param {Resource} [resource] The resource that failed to load.
|
* @param {Error} [error] The error that occurred during the loading of the resource.
|
* @returns {Boolean|Promise<Boolean>} If true or a promise that resolved to true, the resource will be retried. Otherwise the failure will be returned.
|
*/
|
|
module.exports= Resource;
|
|
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {},require("buffer").Buffer)
|
|
},{"./Check":129,"./DeveloperError":131,"./FeatureDetection":134,"./Request":141,"./RequestErrorEvent":142,"./RequestScheduler":143,"./RequestState":144,"./RuntimeError":147,"./TrustedServers":150,"./appendForwardSlash":154,"./clone":156,"./combine":157,"./defaultValue":158,"./defineProperties":159,"./defined":160,"./deprecationWarning":161,"./freezeObject":163,"./getAbsoluteUri":164,"./getBaseUri":165,"./getExtensionFromUri":166,"./isBlobUri":168,"./isCrossOriginUrl":169,"./isDataUri":170,"./loadAndExecuteScript":171,"./objectToQuery":172,"./queryToObject":175,"buffer":30,"uri":100,"when":118}],147:[function(require,module,exports){
|
var defined=require('./defined');
|
|
'use strict';
|
|
/**
|
* Constructs an exception object that is thrown due to an error that can occur at runtime, e.g.,
|
* out of memory, could not compile shader, etc. If a function may throw this
|
* exception, the calling code should be prepared to catch it.
|
* <br /><br />
|
* On the other hand, a {@link DeveloperError} indicates an exception due
|
* to a developer error, e.g., invalid argument, that usually indicates a bug in the
|
* calling code.
|
*
|
* @alias RuntimeError
|
* @constructor
|
* @extends Error
|
*
|
* @param {String} [message] The error message for this exception.
|
*
|
* @see DeveloperError
|
*/
|
function RuntimeError(message) {
|
/**
|
* 'RuntimeError' indicating that this exception was thrown due to a runtime error.
|
* @type {String}
|
* @readonly
|
*/
|
this.name = 'RuntimeError';
|
|
/**
|
* The explanation for why this exception was thrown.
|
* @type {String}
|
* @readonly
|
*/
|
this.message = message;
|
|
//Browsers such as IE don't have a stack property until you actually throw the error.
|
var stack;
|
try {
|
throw new Error();
|
} catch (e) {
|
stack = e.stack;
|
}
|
|
/**
|
* The stack trace of this exception, if available.
|
* @type {String}
|
* @readonly
|
*/
|
this.stack = stack;
|
}
|
|
if (defined(Object.create)) {
|
RuntimeError.prototype = Object.create(Error.prototype);
|
RuntimeError.prototype.constructor = RuntimeError;
|
}
|
|
RuntimeError.prototype.toString = function() {
|
var str = this.name + ': ' + this.message;
|
|
if (defined(this.stack)) {
|
str += '\n' + this.stack.toString();
|
}
|
|
return str;
|
};
|
|
module.exports= RuntimeError;
|
|
},{"./defined":160}],148:[function(require,module,exports){
|
var when = require('when');
|
var buildModuleUrl = require('./buildModuleUrl');
|
var defaultValue = require('./defaultValue');
|
var defined = require('./defined');
|
var destroyObject = require('./destroyObject');
|
var DeveloperError = require('./DeveloperError');
|
var Event = require('./Event');
|
var FeatureDetection = require('./FeatureDetection');
|
var getAbsoluteUri = require('./getAbsoluteUri');
|
var isCrossOriginUrl = require('./isCrossOriginUrl');
|
var Resource = require('./Resource');
|
var RuntimeError = require('./RuntimeError');
|
// var require=require('require');
|
|
'use strict';
|
|
function canTransferArrayBuffer() {
|
if (!defined(TaskProcessor._canTransferArrayBuffer)) {
|
var worker = new Worker(getWorkerUrl('Workers/transferTypedArrayTest.js'));
|
worker.postMessage = defaultValue(worker.webkitPostMessage, worker.postMessage);
|
|
var value = 99;
|
var array = new Int8Array([value]);
|
|
try {
|
// postMessage might fail with a DataCloneError
|
// if transferring array buffers is not supported.
|
worker.postMessage({
|
array: array
|
}, [array.buffer]);
|
} catch (e) {
|
TaskProcessor._canTransferArrayBuffer = false;
|
return TaskProcessor._canTransferArrayBuffer;
|
}
|
|
var deferred = when.defer();
|
|
worker.onmessage = function (event) {
|
var array = event.data.array;
|
|
// some versions of Firefox silently fail to transfer typed arrays.
|
// https://bugzilla.mozilla.org/show_bug.cgi?id=841904
|
// Check to make sure the value round-trips successfully.
|
var result = defined(array) && array[0] === value;
|
deferred.resolve(result);
|
|
worker.terminate();
|
|
TaskProcessor._canTransferArrayBuffer = result;
|
};
|
|
TaskProcessor._canTransferArrayBuffer = deferred.promise;
|
}
|
|
return TaskProcessor._canTransferArrayBuffer;
|
}
|
|
var taskCompletedEvent = new Event();
|
|
function completeTask(processor, data) {
|
--processor._activeTasks;
|
|
var id = data.id;
|
if (!defined(id)) {
|
// This is not one of ours.
|
return;
|
}
|
|
var deferreds = processor._deferreds;
|
var deferred = deferreds[id];
|
|
if (defined(data.error)) {
|
var error = data.error;
|
if (error.name === 'RuntimeError') {
|
error = new RuntimeError(data.error.message);
|
error.stack = data.error.stack;
|
} else if (error.name === 'DeveloperError') {
|
error = new DeveloperError(data.error.message);
|
error.stack = data.error.stack;
|
}
|
taskCompletedEvent.raiseEvent(error);
|
deferred.reject(error);
|
} else {
|
taskCompletedEvent.raiseEvent();
|
deferred.resolve(data.result);
|
}
|
|
delete deferreds[id];
|
}
|
|
function getWorkerUrl(moduleID) {
|
var url = buildModuleUrl(moduleID);
|
|
if (isCrossOriginUrl(url)) {
|
//to load cross-origin, create a shim worker from a blob URL
|
var script = 'importScripts("' + url + '");';
|
|
var blob;
|
try {
|
blob = new Blob([script], {
|
type: 'application/javascript'
|
});
|
} catch (e) {
|
var BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder || window.MSBlobBuilder;
|
var blobBuilder = new BlobBuilder();
|
blobBuilder.append(script);
|
blob = blobBuilder.getBlob('application/javascript');
|
}
|
|
var URL = window.URL || window.webkitURL;
|
url = URL.createObjectURL(blob);
|
}
|
|
return url;
|
}
|
|
var bootstrapperUrlResult;
|
function getBootstrapperUrl() {
|
if (!defined(bootstrapperUrlResult)) {
|
bootstrapperUrlResult = getWorkerUrl('Workers/cesiumWorkerBootstrapper.js');
|
}
|
return bootstrapperUrlResult;
|
}
|
|
function createWorker(processor) {
|
var worker = new Worker(getBootstrapperUrl());
|
worker.postMessage = defaultValue(worker.webkitPostMessage, worker.postMessage);
|
|
var bootstrapMessage = {
|
loaderConfig: {},
|
workerModule: TaskProcessor._workerModulePrefix + processor._workerName
|
};
|
|
if (defined(TaskProcessor._loaderConfig)) {
|
bootstrapMessage.loaderConfig = TaskProcessor._loaderConfig;
|
} else {
|
if (!(defined(define.amd) && !define.amd.toUrlUndefined && defined(require.toUrl))) {
|
bootstrapMessage.loaderConfig.paths = {
|
'Workers': buildModuleUrl('Workers')
|
};
|
}
|
bootstrapMessage.loaderConfig.baseUrl = buildModuleUrl.getCesiumBaseUrl().url;
|
}
|
|
worker.postMessage(bootstrapMessage);
|
|
worker.onmessage = function (event) {
|
completeTask(processor, event.data);
|
};
|
|
return worker;
|
}
|
|
function getWebAssemblyLoaderConfig(processor, wasmOptions) {
|
var config = {
|
modulePath: undefined,
|
wasmBinaryFile: undefined,
|
wasmBinary: undefined
|
};
|
|
// Web assembly not supported, use fallback js module if provided
|
if (!FeatureDetection.supportsWebAssembly()) {
|
if (!defined(wasmOptions.fallbackModulePath)) {
|
throw new RuntimeError('This browser does not support Web Assembly, and no backup module was provided for ' + processor._workerName);
|
}
|
|
config.modulePath = buildModuleUrl(wasmOptions.fallbackModulePath);
|
return when.resolve(config);
|
}
|
|
config.modulePath = buildModuleUrl(wasmOptions.modulePath);
|
config.wasmBinaryFile = buildModuleUrl(wasmOptions.wasmBinaryFile);
|
|
return Resource.fetchArrayBuffer({
|
url: config.wasmBinaryFile
|
}).then(function (arrayBuffer) {
|
config.wasmBinary = arrayBuffer;
|
return config;
|
});
|
}
|
|
/**
|
* A wrapper around a web worker that allows scheduling tasks for a given worker,
|
* returning results asynchronously via a promise.
|
*
|
* The Worker is not constructed until a task is scheduled.
|
*
|
* @alias TaskProcessor
|
* @constructor
|
*
|
* @param {String} workerName The name of the worker. This is expected to be a script
|
* in the Workers folder.
|
* @param {Number} [maximumActiveTasks=5] The maximum number of active tasks. Once exceeded,
|
* scheduleTask will not queue any more tasks, allowing
|
* work to be rescheduled in future frames.
|
*/
|
function TaskProcessor(workerName, maximumActiveTasks) {
|
this._workerName = workerName;
|
this._maximumActiveTasks = defaultValue(maximumActiveTasks, 5);
|
this._activeTasks = 0;
|
this._deferreds = {};
|
this._nextID = 0;
|
}
|
|
var emptyTransferableObjectArray = [];
|
|
/**
|
* Schedule a task to be processed by the web worker asynchronously. If there are currently more
|
* tasks active than the maximum set by the constructor, will immediately return undefined.
|
* Otherwise, returns a promise that will resolve to the result posted back by the worker when
|
* finished.
|
*
|
* @param {Object} parameters Any input data that will be posted to the worker.
|
* @param {Object[]} [transferableObjects] An array of objects contained in parameters that should be
|
* transferred to the worker instead of copied.
|
* @returns {Promise.<Object>|undefined} Either a promise that will resolve to the result when available, or undefined
|
* if there are too many active tasks,
|
*
|
* @example
|
* var taskProcessor = new Cesium.TaskProcessor('myWorkerName');
|
* var promise = taskProcessor.scheduleTask({
|
* someParameter : true,
|
* another : 'hello'
|
* });
|
* if (!Cesium.defined(promise)) {
|
* // too many active tasks - try again later
|
* } else {
|
* Cesium.when(promise, function(result) {
|
* // use the result of the task
|
* });
|
* }
|
*/
|
TaskProcessor.prototype.scheduleTask = function (parameters, transferableObjects) {
|
if (!defined(this._worker)) {
|
this._worker = createWorker(this);
|
}
|
|
if (this._activeTasks >= this._maximumActiveTasks) {
|
return undefined;
|
}
|
|
++this._activeTasks;
|
|
var processor = this;
|
return when(canTransferArrayBuffer(), function (canTransferArrayBuffer) {
|
if (!defined(transferableObjects)) {
|
transferableObjects = emptyTransferableObjectArray;
|
} else if (!canTransferArrayBuffer) {
|
transferableObjects.length = 0;
|
}
|
|
var id = processor._nextID++;
|
var deferred = when.defer();
|
processor._deferreds[id] = deferred;
|
|
processor._worker.postMessage({
|
id: id,
|
parameters: parameters,
|
canTransferArrayBuffer: canTransferArrayBuffer
|
}, transferableObjects);
|
|
return deferred.promise;
|
});
|
};
|
|
/**
|
* Posts a message to a web worker with configuration to initialize loading
|
* and compiling a web assembly module asychronously, as well as an optional
|
* fallback JavaScript module to use if Web Assembly is not supported.
|
*
|
* @param {Object} [webAssemblyOptions] An object with the following properties:
|
* @param {String} [webAssemblyOptions.modulePath] The path of the web assembly JavaScript wrapper module.
|
* @param {String} [webAssemblyOptions.wasmBinaryFile] The path of the web assembly binary file.
|
* @param {String} [webAssemblyOptions.fallbackModulePath] The path of the fallback JavaScript module to use if web assembly is not supported.
|
* @returns {Promise.<Object>} A promise that resolves to the result when the web worker has loaded and compiled the web assembly module and is ready to process tasks.
|
*/
|
TaskProcessor.prototype.initWebAssemblyModule = function (webAssemblyOptions) {
|
if (!defined(this._worker)) {
|
this._worker = createWorker(this);
|
}
|
|
var deferred = when.defer();
|
var processor = this;
|
var worker = this._worker;
|
getWebAssemblyLoaderConfig(this, webAssemblyOptions).then(function (wasmConfig) {
|
return when(canTransferArrayBuffer(), function (canTransferArrayBuffer) {
|
var transferableObjects;
|
var binary = wasmConfig.wasmBinary;
|
if (defined(binary) && canTransferArrayBuffer) {
|
transferableObjects = [binary];
|
}
|
|
worker.onmessage = function (event) {
|
worker.onmessage = function (event) {
|
completeTask(processor, event.data);
|
};
|
|
deferred.resolve(event.data);
|
};
|
|
worker.postMessage({ webAssemblyConfig: wasmConfig }, transferableObjects);
|
});
|
});
|
|
return deferred;
|
};
|
|
/**
|
* Returns true if this object was destroyed; otherwise, false.
|
* <br /><br />
|
* If this object was destroyed, it should not be used; calling any function other than
|
* <code>isDestroyed</code> will result in a {@link DeveloperError} exception.
|
*
|
* @returns {Boolean} True if this object was destroyed; otherwise, false.
|
*
|
* @see TaskProcessor#destroy
|
*/
|
TaskProcessor.prototype.isDestroyed = function () {
|
return false;
|
};
|
|
/**
|
* Destroys this object. This will immediately terminate the Worker.
|
* <br /><br />
|
* Once an object is destroyed, it should not be used; calling any function other than
|
* <code>isDestroyed</code> will result in a {@link DeveloperError} exception.
|
*/
|
TaskProcessor.prototype.destroy = function () {
|
if (defined(this._worker)) {
|
this._worker.terminate();
|
}
|
return destroyObject(this);
|
};
|
|
/**
|
* An event that's raised when a task is completed successfully. Event handlers are passed
|
* the error object is a task fails.
|
*
|
* @type {Event}
|
*
|
* @private
|
*/
|
TaskProcessor.taskCompletedEvent = taskCompletedEvent;
|
|
// exposed for testing purposes
|
TaskProcessor._defaultWorkerModulePrefix = 'Workers/';
|
TaskProcessor._workerModulePrefix = TaskProcessor._defaultWorkerModulePrefix;
|
TaskProcessor._loaderConfig = undefined;
|
TaskProcessor._canTransferArrayBuffer = undefined;
|
|
module.exports = TaskProcessor;
|
|
},{"./DeveloperError":131,"./Event":133,"./FeatureDetection":134,"./Resource":146,"./RuntimeError":147,"./buildModuleUrl":155,"./defaultValue":158,"./defined":160,"./destroyObject":162,"./getAbsoluteUri":164,"./isCrossOriginUrl":169,"when":118}],149:[function(require,module,exports){
|
var defineProperties=require('./defineProperties');
|
var DeveloperError=require('./DeveloperError');
|
|
'use strict';
|
|
/**
|
* A tiling scheme for geometry or imagery on the surface of an ellipsoid. At level-of-detail zero,
|
* the coarsest, least-detailed level, the number of tiles is configurable.
|
* At level of detail one, each of the level zero tiles has four children, two in each direction.
|
* At level of detail two, each of the level one tiles has four children, two in each direction.
|
* This continues for as many levels as are present in the geometry or imagery source.
|
*
|
* @alias TilingScheme
|
* @constructor
|
*
|
* @see WebMercatorTilingScheme
|
* @see GeographicTilingScheme
|
*/
|
function TilingScheme(options) {
|
//>>includeStart('debug', pragmas.debug);
|
throw new DeveloperError('This type should not be instantiated directly. Instead, use WebMercatorTilingScheme or GeographicTilingScheme.');
|
//>>includeEnd('debug');
|
}
|
|
defineProperties(TilingScheme.prototype, {
|
/**
|
* Gets the ellipsoid that is tiled by the tiling scheme.
|
* @memberof TilingScheme.prototype
|
* @type {Ellipsoid}
|
*/
|
ellipsoid: {
|
get : DeveloperError.throwInstantiationError
|
},
|
|
/**
|
* Gets the rectangle, in radians, covered by this tiling scheme.
|
* @memberof TilingScheme.prototype
|
* @type {Rectangle}
|
*/
|
rectangle : {
|
get : DeveloperError.throwInstantiationError
|
},
|
|
/**
|
* Gets the map projection used by the tiling scheme.
|
* @memberof TilingScheme.prototype
|
* @type {MapProjection}
|
*/
|
projection : {
|
get : DeveloperError.throwInstantiationError
|
}
|
});
|
|
/**
|
* Gets the total number of tiles in the X direction at a specified level-of-detail.
|
* @function
|
*
|
* @param {Number} level The level-of-detail.
|
* @returns {Number} The number of tiles in the X direction at the given level.
|
*/
|
TilingScheme.prototype.getNumberOfXTilesAtLevel = DeveloperError.throwInstantiationError;
|
|
/**
|
* Gets the total number of tiles in the Y direction at a specified level-of-detail.
|
* @function
|
*
|
* @param {Number} level The level-of-detail.
|
* @returns {Number} The number of tiles in the Y direction at the given level.
|
*/
|
TilingScheme.prototype.getNumberOfYTilesAtLevel = DeveloperError.throwInstantiationError;
|
|
/**
|
* Transforms a rectangle specified in geodetic radians to the native coordinate system
|
* of this tiling scheme.
|
* @function
|
*
|
* @param {Rectangle} rectangle The rectangle to transform.
|
* @param {Rectangle} [result] The instance to which to copy the result, or undefined if a new instance
|
* should be created.
|
* @returns {Rectangle} The specified 'result', or a new object containing the native rectangle if 'result'
|
* is undefined.
|
*/
|
TilingScheme.prototype.rectangleToNativeRectangle = DeveloperError.throwInstantiationError;
|
|
/**
|
* Converts tile x, y coordinates and level to a rectangle expressed in the native coordinates
|
* of the tiling scheme.
|
* @function
|
*
|
* @param {Number} x The integer x coordinate of the tile.
|
* @param {Number} y The integer y coordinate of the tile.
|
* @param {Number} level The tile level-of-detail. Zero is the least detailed.
|
* @param {Object} [result] The instance to which to copy the result, or undefined if a new instance
|
* should be created.
|
* @returns {Rectangle} The specified 'result', or a new object containing the rectangle
|
* if 'result' is undefined.
|
*/
|
TilingScheme.prototype.tileXYToNativeRectangle = DeveloperError.throwInstantiationError;
|
|
/**
|
* Converts tile x, y coordinates and level to a cartographic rectangle in radians.
|
* @function
|
*
|
* @param {Number} x The integer x coordinate of the tile.
|
* @param {Number} y The integer y coordinate of the tile.
|
* @param {Number} level The tile level-of-detail. Zero is the least detailed.
|
* @param {Object} [result] The instance to which to copy the result, or undefined if a new instance
|
* should be created.
|
* @returns {Rectangle} The specified 'result', or a new object containing the rectangle
|
* if 'result' is undefined.
|
*/
|
TilingScheme.prototype.tileXYToRectangle = DeveloperError.throwInstantiationError;
|
|
/**
|
* Calculates the tile x, y coordinates of the tile containing
|
* a given cartographic position.
|
* @function
|
*
|
* @param {Cartographic} position The position.
|
* @param {Number} level The tile level-of-detail. Zero is the least detailed.
|
* @param {Cartesian2} [result] The instance to which to copy the result, or undefined if a new instance
|
* should be created.
|
* @returns {Cartesian2} The specified 'result', or a new object containing the tile x, y coordinates
|
* if 'result' is undefined.
|
*/
|
TilingScheme.prototype.positionToTileXY = DeveloperError.throwInstantiationError;
|
|
module.exports= TilingScheme;
|
|
},{"./DeveloperError":131,"./defineProperties":159}],150:[function(require,module,exports){
|
var Uri=require('./Uri');
|
var defined=require('./defined');
|
var DeveloperError=require('./DeveloperError');
|
|
'use strict';
|
|
/**
|
* A singleton that contains all of the servers that are trusted. Credentials will be sent with
|
* any requests to these servers.
|
*
|
* @exports TrustedServers
|
*
|
* @see {@link http://www.w3.org/TR/cors/|Cross-Origin Resource Sharing}
|
*/
|
var TrustedServers = {};
|
var _servers = {};
|
|
/**
|
* Adds a trusted server to the registry
|
*
|
* @param {String} host The host to be added.
|
* @param {Number} port The port used to access the host.
|
*
|
* @example
|
* // Add a trusted server
|
* TrustedServers.add('my.server.com', 80);
|
*/
|
TrustedServers.add = function(host, port) {
|
//>>includeStart('debug', pragmas.debug);
|
if (!defined(host)) {
|
throw new DeveloperError('host is required.');
|
}
|
if (!defined(port) || port <= 0) {
|
throw new DeveloperError('port is required to be greater than 0.');
|
}
|
//>>includeEnd('debug');
|
|
var authority = host.toLowerCase() + ':' + port;
|
if (!defined(_servers[authority])) {
|
_servers[authority] = true;
|
}
|
};
|
|
/**
|
* Removes a trusted server from the registry
|
*
|
* @param {String} host The host to be removed.
|
* @param {Number} port The port used to access the host.
|
*
|
* @example
|
* // Remove a trusted server
|
* TrustedServers.remove('my.server.com', 80);
|
*/
|
TrustedServers.remove = function(host, port) {
|
//>>includeStart('debug', pragmas.debug);
|
if (!defined(host)) {
|
throw new DeveloperError('host is required.');
|
}
|
if (!defined(port) || port <= 0) {
|
throw new DeveloperError('port is required to be greater than 0.');
|
}
|
//>>includeEnd('debug');
|
|
var authority = host.toLowerCase() + ':' + port;
|
if (defined(_servers[authority])) {
|
delete _servers[authority];
|
}
|
};
|
|
function getAuthority(url) {
|
var uri = new Uri(url);
|
uri.normalize();
|
|
// Removes username:password@ so we just have host[:port]
|
var authority = uri.getAuthority();
|
if (!defined(authority)) {
|
return undefined; // Relative URL
|
}
|
|
if (authority.indexOf('@') !== -1) {
|
var parts = authority.split('@');
|
authority = parts[1];
|
}
|
|
// If the port is missing add one based on the scheme
|
if (authority.indexOf(':') === -1) {
|
var scheme = uri.getScheme();
|
if (!defined(scheme)) {
|
scheme = window.location.protocol;
|
scheme = scheme.substring(0, scheme.length-1);
|
}
|
if (scheme === 'http') {
|
authority += ':80';
|
} else if (scheme === 'https') {
|
authority += ':443';
|
} else {
|
return undefined;
|
}
|
}
|
|
return authority;
|
}
|
|
/**
|
* Tests whether a server is trusted or not. The server must have been added with the port if it is included in the url.
|
*
|
* @param {String} url The url to be tested against the trusted list
|
*
|
* @returns {boolean} Returns true if url is trusted, false otherwise.
|
*
|
* @example
|
* // Add server
|
* TrustedServers.add('my.server.com', 81);
|
*
|
* // Check if server is trusted
|
* if (TrustedServers.contains('https://my.server.com:81/path/to/file.png')) {
|
* // my.server.com:81 is trusted
|
* }
|
* if (TrustedServers.contains('https://my.server.com/path/to/file.png')) {
|
* // my.server.com isn't trusted
|
* }
|
*/
|
TrustedServers.contains = function(url) {
|
//>>includeStart('debug', pragmas.debug);
|
if (!defined(url)) {
|
throw new DeveloperError('url is required.');
|
}
|
//>>includeEnd('debug');
|
var authority = getAuthority(url);
|
if (defined(authority) && defined(_servers[authority])) {
|
return true;
|
}
|
|
return false;
|
};
|
|
/**
|
* Clears the registry
|
*
|
* @example
|
* // Remove a trusted server
|
* TrustedServers.clear();
|
*/
|
TrustedServers.clear = function() {
|
_servers = {};
|
};
|
|
module.exports= TrustedServers;
|
|
},{"./DeveloperError":131,"./Uri":151,"./defined":160}],151:[function(require,module,exports){
|
/**
|
* @license
|
*
|
* Grauw URI utilities
|
*
|
* See: http://hg.grauw.nl/grauw-lib/file/tip/src/uri.js
|
*
|
* @author Laurens Holst (http://www.grauw.nl/)
|
*
|
* Copyright 2012 Laurens Holst
|
*
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
* you may not use this file except in compliance with the License.
|
* You may obtain a copy of the License at
|
*
|
* http://www.apache.org/licenses/LICENSE-2.0
|
*
|
* Unless required by applicable law or agreed to in writing, software
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* See the License for the specific language governing permissions and
|
* limitations under the License.
|
*
|
*/
|
|
/**
|
* Constructs a URI object.
|
* @constructor
|
* @class Implementation of URI parsing and base URI resolving algorithm in RFC 3986.
|
* @param {string|URI} uri A string or URI object to create the object from.
|
*/
|
function URI(uri) {
|
if (uri instanceof URI) { // copy constructor
|
this.scheme = uri.scheme;
|
this.authority = uri.authority;
|
this.path = uri.path;
|
this.query = uri.query;
|
this.fragment = uri.fragment;
|
} else if (uri) { // uri is URI string or cast to string
|
var c = parseRegex.exec(uri);
|
this.scheme = c[1];
|
this.authority = c[2];
|
this.path = c[3];
|
this.query = c[4];
|
this.fragment = c[5];
|
}
|
}
|
// Initial values on the prototype
|
URI.prototype.scheme = null;
|
URI.prototype.authority = null;
|
URI.prototype.path = '';
|
URI.prototype.query = null;
|
URI.prototype.fragment = null;
|
|
// Regular expression from RFC 3986 appendix B
|
var parseRegex = new RegExp('^(?:([^:/?#]+):)?(?://([^/?#]*))?([^?#]*)(?:\\?([^#]*))?(?:#(.*))?$');
|
|
/**
|
* Returns the scheme part of the URI.
|
* In "http://example.com:80/a/b?x#y" this is "http".
|
*/
|
URI.prototype.getScheme = function () {
|
return this.scheme;
|
};
|
|
/**
|
* Returns the authority part of the URI.
|
* In "http://example.com:80/a/b?x#y" this is "example.com:80".
|
*/
|
URI.prototype.getAuthority = function () {
|
return this.authority;
|
};
|
|
/**
|
* Returns the path part of the URI.
|
* In "http://example.com:80/a/b?x#y" this is "/a/b".
|
* In "mailto:mike@example.com" this is "mike@example.com".
|
*/
|
URI.prototype.getPath = function () {
|
return this.path;
|
};
|
|
/**
|
* Returns the query part of the URI.
|
* In "http://example.com:80/a/b?x#y" this is "x".
|
*/
|
URI.prototype.getQuery = function () {
|
return this.query;
|
};
|
|
/**
|
* Returns the fragment part of the URI.
|
* In "http://example.com:80/a/b?x#y" this is "y".
|
*/
|
URI.prototype.getFragment = function () {
|
return this.fragment;
|
};
|
|
/**
|
* Tests whether the URI is an absolute URI.
|
* See RFC 3986 section 4.3.
|
*/
|
URI.prototype.isAbsolute = function () {
|
return !!this.scheme && !this.fragment;
|
};
|
|
///**
|
//* Extensive validation of the URI against the ABNF in RFC 3986
|
//*/
|
//URI.prototype.validate
|
|
/**
|
* Tests whether the URI is a same-document reference.
|
* See RFC 3986 section 4.4.
|
*
|
* To perform more thorough comparison, you can normalise the URI objects.
|
*/
|
URI.prototype.isSameDocumentAs = function (uri) {
|
return uri.scheme == this.scheme &&
|
uri.authority == this.authority &&
|
uri.path == this.path &&
|
uri.query == this.query;
|
};
|
|
/**
|
* Simple String Comparison of two URIs.
|
* See RFC 3986 section 6.2.1.
|
*
|
* To perform more thorough comparison, you can normalise the URI objects.
|
*/
|
URI.prototype.equals = function (uri) {
|
return this.isSameDocumentAs(uri) && uri.fragment == this.fragment;
|
};
|
|
/**
|
* Normalizes the URI using syntax-based normalization.
|
* This includes case normalization, percent-encoding normalization and path segment normalization.
|
* XXX: Percent-encoding normalization does not escape characters that need to be escaped.
|
* (Although that would not be a valid URI in the first place. See validate().)
|
* See RFC 3986 section 6.2.2.
|
*/
|
URI.prototype.normalize = function () {
|
this.removeDotSegments();
|
if (this.scheme)
|
this.scheme = this.scheme.toLowerCase();
|
if (this.authority)
|
this.authority = this.authority.replace(authorityRegex, replaceAuthority).
|
replace(caseRegex, replaceCase);
|
if (this.path)
|
this.path = this.path.replace(caseRegex, replaceCase);
|
if (this.query)
|
this.query = this.query.replace(caseRegex, replaceCase);
|
if (this.fragment)
|
this.fragment = this.fragment.replace(caseRegex, replaceCase);
|
};
|
|
var caseRegex = /%[0-9a-z]{2}/gi;
|
var percentRegex = /[a-zA-Z0-9\-\._~]/;
|
var authorityRegex = /(.*@)?([^@:]*)(:.*)?/;
|
|
function replaceCase(str) {
|
var dec = unescape(str);
|
return percentRegex.test(dec) ? dec : str.toUpperCase();
|
}
|
|
function replaceAuthority(str, p1, p2, p3) {
|
return (p1 || '') + p2.toLowerCase() + (p3 || '');
|
}
|
|
/**
|
* Resolve a relative URI (this) against a base URI.
|
* The base URI must be an absolute URI.
|
* See RFC 3986 section 5.2
|
*/
|
URI.prototype.resolve = function (baseURI) {
|
var uri = new URI();
|
if (this.scheme) {
|
uri.scheme = this.scheme;
|
uri.authority = this.authority;
|
uri.path = this.path;
|
uri.query = this.query;
|
} else {
|
uri.scheme = baseURI.scheme;
|
if (this.authority) {
|
uri.authority = this.authority;
|
uri.path = this.path;
|
uri.query = this.query;
|
} else {
|
uri.authority = baseURI.authority;
|
if (this.path == '') {
|
uri.path = baseURI.path;
|
uri.query = this.query || baseURI.query;
|
} else {
|
if (this.path.charAt(0) == '/') {
|
uri.path = this.path;
|
uri.removeDotSegments();
|
} else {
|
if (baseURI.authority && baseURI.path == '') {
|
uri.path = '/' + this.path;
|
} else {
|
uri.path = baseURI.path.substring(0, baseURI.path.lastIndexOf('/') + 1) + this.path;
|
}
|
uri.removeDotSegments();
|
}
|
uri.query = this.query;
|
}
|
}
|
}
|
uri.fragment = this.fragment;
|
return uri;
|
};
|
|
/**
|
* Remove dot segments from path.
|
* See RFC 3986 section 5.2.4
|
* @private
|
*/
|
URI.prototype.removeDotSegments = function () {
|
var input = this.path.split('/'),
|
output = [],
|
segment,
|
absPath = input[0] == '';
|
if (absPath)
|
input.shift();
|
var sFirst = input[0] == '' ? input.shift() : null;
|
while (input.length) {
|
segment = input.shift();
|
if (segment == '..') {
|
output.pop();
|
} else if (segment != '.') {
|
output.push(segment);
|
}
|
}
|
if (segment == '.' || segment == '..')
|
output.push('');
|
if (absPath)
|
output.unshift('');
|
this.path = output.join('/');
|
};
|
|
// We don't like this function because it builds up a cache that is never cleared.
|
// /**
|
// * Resolves a relative URI against an absolute base URI.
|
// * Convenience method.
|
// * @param {String} uri the relative URI to resolve
|
// * @param {String} baseURI the base URI (must be absolute) to resolve against
|
// */
|
// URI.resolve = function(sURI, sBaseURI) {
|
// var uri = cache[sURI] || (cache[sURI] = new URI(sURI));
|
// var baseURI = cache[sBaseURI] || (cache[sBaseURI] = new URI(sBaseURI));
|
// return uri.resolve(baseURI).toString();
|
// };
|
|
// var cache = {};
|
|
/**
|
* Serialises the URI to a string.
|
*/
|
URI.prototype.toString = function () {
|
var result = '';
|
if (this.scheme)
|
result += this.scheme + ':';
|
if (this.authority)
|
result += '//' + this.authority;
|
result += this.path;
|
if (this.query)
|
result += '?' + this.query;
|
if (this.fragment)
|
result += '#' + this.fragment;
|
return result;
|
};
|
|
module.exports = URI;
|
|
|
},{}],152:[function(require,module,exports){
|
var Cartesian3=require('./Cartesian3');
|
var Cartographic=require('./Cartographic');
|
var defaultValue=require('./defaultValue');
|
var defined=require('./defined');
|
var defineProperties=require('./defineProperties');
|
var DeveloperError=require('./DeveloperError');
|
var Ellipsoid=require('./Ellipsoid');
|
var CesiumMath=require('./Math');
|
|
'use strict';
|
|
/**
|
* The map projection used by Google Maps, Bing Maps, and most of ArcGIS Online, EPSG:3857. This
|
* projection use longitude and latitude expressed with the WGS84 and transforms them to Mercator using
|
* the spherical (rather than ellipsoidal) equations.
|
*
|
* @alias WebMercatorProjection
|
* @constructor
|
*
|
* @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid.
|
*
|
* @see GeographicProjection
|
*/
|
function WebMercatorProjection(ellipsoid) {
|
this._ellipsoid = defaultValue(ellipsoid, Ellipsoid.WGS84);
|
this._semimajorAxis = this._ellipsoid.maximumRadius;
|
this._oneOverSemimajorAxis = 1.0 / this._semimajorAxis;
|
}
|
|
defineProperties(WebMercatorProjection.prototype, {
|
/**
|
* Gets the {@link Ellipsoid}.
|
*
|
* @memberof WebMercatorProjection.prototype
|
*
|
* @type {Ellipsoid}
|
* @readonly
|
*/
|
ellipsoid : {
|
get : function() {
|
return this._ellipsoid;
|
}
|
}
|
});
|
|
/**
|
* Converts a Mercator angle, in the range -PI to PI, to a geodetic latitude
|
* in the range -PI/2 to PI/2.
|
*
|
* @param {Number} mercatorAngle The angle to convert.
|
* @returns {Number} The geodetic latitude in radians.
|
*/
|
WebMercatorProjection.mercatorAngleToGeodeticLatitude = function(mercatorAngle) {
|
return CesiumMath.PI_OVER_TWO - (2.0 * Math.atan(Math.exp(-mercatorAngle)));
|
};
|
|
/**
|
* Converts a geodetic latitude in radians, in the range -PI/2 to PI/2, to a Mercator
|
* angle in the range -PI to PI.
|
*
|
* @param {Number} latitude The geodetic latitude in radians.
|
* @returns {Number} The Mercator angle.
|
*/
|
WebMercatorProjection.geodeticLatitudeToMercatorAngle = function(latitude) {
|
// Clamp the latitude coordinate to the valid Mercator bounds.
|
if (latitude > WebMercatorProjection.MaximumLatitude) {
|
latitude = WebMercatorProjection.MaximumLatitude;
|
} else if (latitude < -WebMercatorProjection.MaximumLatitude) {
|
latitude = -WebMercatorProjection.MaximumLatitude;
|
}
|
var sinLatitude = Math.sin(latitude);
|
return 0.5 * Math.log((1.0 + sinLatitude) / (1.0 - sinLatitude));
|
};
|
|
/**
|
* The maximum latitude (both North and South) supported by a Web Mercator
|
* (EPSG:3857) projection. Technically, the Mercator projection is defined
|
* for any latitude up to (but not including) 90 degrees, but it makes sense
|
* to cut it off sooner because it grows exponentially with increasing latitude.
|
* The logic behind this particular cutoff value, which is the one used by
|
* Google Maps, Bing Maps, and Esri, is that it makes the projection
|
* square. That is, the rectangle is equal in the X and Y directions.
|
*
|
* The constant value is computed by calling:
|
* WebMercatorProjection.mercatorAngleToGeodeticLatitude(Math.PI)
|
*
|
* @type {Number}
|
*/
|
WebMercatorProjection.MaximumLatitude = WebMercatorProjection.mercatorAngleToGeodeticLatitude(Math.PI);
|
|
/**
|
* Converts geodetic ellipsoid coordinates, in radians, to the equivalent Web Mercator
|
* X, Y, Z coordinates expressed in meters and returned in a {@link Cartesian3}. The height
|
* is copied unmodified to the Z coordinate.
|
*
|
* @param {Cartographic} cartographic The cartographic coordinates in radians.
|
* @param {Cartesian3} [result] The instance to which to copy the result, or undefined if a
|
* new instance should be created.
|
* @returns {Cartesian3} The equivalent web mercator X, Y, Z coordinates, in meters.
|
*/
|
WebMercatorProjection.prototype.project = function(cartographic, result) {
|
var semimajorAxis = this._semimajorAxis;
|
var x = cartographic.longitude * semimajorAxis;
|
var y = WebMercatorProjection.geodeticLatitudeToMercatorAngle(cartographic.latitude) * semimajorAxis;
|
var z = cartographic.height;
|
|
if (!defined(result)) {
|
return new Cartesian3(x, y, z);
|
}
|
|
result.x = x;
|
result.y = y;
|
result.z = z;
|
return result;
|
};
|
|
/**
|
* Converts Web Mercator X, Y coordinates, expressed in meters, to a {@link Cartographic}
|
* containing geodetic ellipsoid coordinates. The Z coordinate is copied unmodified to the
|
* height.
|
*
|
* @param {Cartesian3} cartesian The web mercator Cartesian position to unrproject with height (z) in meters.
|
* @param {Cartographic} [result] The instance to which to copy the result, or undefined if a
|
* new instance should be created.
|
* @returns {Cartographic} The equivalent cartographic coordinates.
|
*/
|
WebMercatorProjection.prototype.unproject = function(cartesian, result) {
|
//>>includeStart('debug', pragmas.debug);
|
if (!defined(cartesian)) {
|
throw new DeveloperError('cartesian is required');
|
}
|
//>>includeEnd('debug');
|
|
var oneOverEarthSemimajorAxis = this._oneOverSemimajorAxis;
|
var longitude = cartesian.x * oneOverEarthSemimajorAxis;
|
var latitude = WebMercatorProjection.mercatorAngleToGeodeticLatitude(cartesian.y * oneOverEarthSemimajorAxis);
|
var height = cartesian.z;
|
|
if (!defined(result)) {
|
return new Cartographic(longitude, latitude, height);
|
}
|
|
result.longitude = longitude;
|
result.latitude = latitude;
|
result.height = height;
|
return result;
|
};
|
|
module.exports= WebMercatorProjection;
|
|
},{"./Cartesian3":126,"./Cartographic":128,"./DeveloperError":131,"./Ellipsoid":132,"./Math":139,"./defaultValue":158,"./defineProperties":159,"./defined":160}],153:[function(require,module,exports){
|
var Cartesian2=require('./Cartesian2');
|
var defaultValue=require('./defaultValue');
|
var defined=require('./defined');
|
var defineProperties=require('./defineProperties');
|
var Ellipsoid=require('./Ellipsoid');
|
var Rectangle=require('./Rectangle');
|
var WebMercatorProjection=require('./WebMercatorProjection');
|
|
'use strict';
|
|
/**
|
* A tiling scheme for geometry referenced to a {@link WebMercatorProjection}, EPSG:3857. This is
|
* the tiling scheme used by Google Maps, Microsoft Bing Maps, and most of ESRI ArcGIS Online.
|
*
|
* @alias WebMercatorTilingScheme
|
* @constructor
|
*
|
* @param {Object} [options] Object with the following properties:
|
* @param {Ellipsoid} [options.ellipsoid=Ellipsoid.WGS84] The ellipsoid whose surface is being tiled. Defaults to
|
* the WGS84 ellipsoid.
|
* @param {Number} [options.numberOfLevelZeroTilesX=1] The number of tiles in the X direction at level zero of
|
* the tile tree.
|
* @param {Number} [options.numberOfLevelZeroTilesY=1] The number of tiles in the Y direction at level zero of
|
* the tile tree.
|
* @param {Cartesian2} [options.rectangleSouthwestInMeters] The southwest corner of the rectangle covered by the
|
* tiling scheme, in meters. If this parameter or rectangleNortheastInMeters is not specified, the entire
|
* globe is covered in the longitude direction and an equal distance is covered in the latitude
|
* direction, resulting in a square projection.
|
* @param {Cartesian2} [options.rectangleNortheastInMeters] The northeast corner of the rectangle covered by the
|
* tiling scheme, in meters. If this parameter or rectangleSouthwestInMeters is not specified, the entire
|
* globe is covered in the longitude direction and an equal distance is covered in the latitude
|
* direction, resulting in a square projection.
|
*/
|
function WebMercatorTilingScheme(options) {
|
options = defaultValue(options, {});
|
|
this._ellipsoid = defaultValue(options.ellipsoid, Ellipsoid.WGS84);
|
this._numberOfLevelZeroTilesX = defaultValue(options.numberOfLevelZeroTilesX, 1);
|
this._numberOfLevelZeroTilesY = defaultValue(options.numberOfLevelZeroTilesY, 1);
|
|
this._projection = new WebMercatorProjection(this._ellipsoid);
|
|
if (defined(options.rectangleSouthwestInMeters) &&
|
defined(options.rectangleNortheastInMeters)) {
|
this._rectangleSouthwestInMeters = options.rectangleSouthwestInMeters;
|
this._rectangleNortheastInMeters = options.rectangleNortheastInMeters;
|
} else {
|
var semimajorAxisTimesPi = this._ellipsoid.maximumRadius * Math.PI;
|
this._rectangleSouthwestInMeters = new Cartesian2(-semimajorAxisTimesPi, -semimajorAxisTimesPi);
|
this._rectangleNortheastInMeters = new Cartesian2(semimajorAxisTimesPi, semimajorAxisTimesPi);
|
}
|
|
var southwest = this._projection.unproject(this._rectangleSouthwestInMeters);
|
var northeast = this._projection.unproject(this._rectangleNortheastInMeters);
|
this._rectangle = new Rectangle(southwest.longitude, southwest.latitude,
|
northeast.longitude, northeast.latitude);
|
}
|
|
defineProperties(WebMercatorTilingScheme.prototype, {
|
/**
|
* Gets the ellipsoid that is tiled by this tiling scheme.
|
* @memberof WebMercatorTilingScheme.prototype
|
* @type {Ellipsoid}
|
*/
|
ellipsoid : {
|
get : function() {
|
return this._ellipsoid;
|
}
|
},
|
|
/**
|
* Gets the rectangle, in radians, covered by this tiling scheme.
|
* @memberof WebMercatorTilingScheme.prototype
|
* @type {Rectangle}
|
*/
|
rectangle : {
|
get : function() {
|
return this._rectangle;
|
}
|
},
|
|
/**
|
* Gets the map projection used by this tiling scheme.
|
* @memberof WebMercatorTilingScheme.prototype
|
* @type {MapProjection}
|
*/
|
projection : {
|
get : function() {
|
return this._projection;
|
}
|
}
|
});
|
|
/**
|
* Gets the total number of tiles in the X direction at a specified level-of-detail.
|
*
|
* @param {Number} level The level-of-detail.
|
* @returns {Number} The number of tiles in the X direction at the given level.
|
*/
|
WebMercatorTilingScheme.prototype.getNumberOfXTilesAtLevel = function(level) {
|
return this._numberOfLevelZeroTilesX << level;
|
};
|
|
/**
|
* Gets the total number of tiles in the Y direction at a specified level-of-detail.
|
*
|
* @param {Number} level The level-of-detail.
|
* @returns {Number} The number of tiles in the Y direction at the given level.
|
*/
|
WebMercatorTilingScheme.prototype.getNumberOfYTilesAtLevel = function(level) {
|
return this._numberOfLevelZeroTilesY << level;
|
};
|
|
/**
|
* Transforms a rectangle specified in geodetic radians to the native coordinate system
|
* of this tiling scheme.
|
*
|
* @param {Rectangle} rectangle The rectangle to transform.
|
* @param {Rectangle} [result] The instance to which to copy the result, or undefined if a new instance
|
* should be created.
|
* @returns {Rectangle} The specified 'result', or a new object containing the native rectangle if 'result'
|
* is undefined.
|
*/
|
WebMercatorTilingScheme.prototype.rectangleToNativeRectangle = function(rectangle, result) {
|
var projection = this._projection;
|
var southwest = projection.project(Rectangle.southwest(rectangle));
|
var northeast = projection.project(Rectangle.northeast(rectangle));
|
|
if (!defined(result)) {
|
return new Rectangle(southwest.x, southwest.y, northeast.x, northeast.y);
|
}
|
|
result.west = southwest.x;
|
result.south = southwest.y;
|
result.east = northeast.x;
|
result.north = northeast.y;
|
return result;
|
};
|
|
/**
|
* Converts tile x, y coordinates and level to a rectangle expressed in the native coordinates
|
* of the tiling scheme.
|
*
|
* @param {Number} x The integer x coordinate of the tile.
|
* @param {Number} y The integer y coordinate of the tile.
|
* @param {Number} level The tile level-of-detail. Zero is the least detailed.
|
* @param {Object} [result] The instance to which to copy the result, or undefined if a new instance
|
* should be created.
|
* @returns {Rectangle} The specified 'result', or a new object containing the rectangle
|
* if 'result' is undefined.
|
*/
|
WebMercatorTilingScheme.prototype.tileXYToNativeRectangle = function(x, y, level, result) {
|
var xTiles = this.getNumberOfXTilesAtLevel(level);
|
var yTiles = this.getNumberOfYTilesAtLevel(level);
|
|
var xTileWidth = (this._rectangleNortheastInMeters.x - this._rectangleSouthwestInMeters.x) / xTiles;
|
var west = this._rectangleSouthwestInMeters.x + x * xTileWidth;
|
var east = this._rectangleSouthwestInMeters.x + (x + 1) * xTileWidth;
|
|
var yTileHeight = (this._rectangleNortheastInMeters.y - this._rectangleSouthwestInMeters.y) / yTiles;
|
var north = this._rectangleNortheastInMeters.y - y * yTileHeight;
|
var south = this._rectangleNortheastInMeters.y - (y + 1) * yTileHeight;
|
|
if (!defined(result)) {
|
return new Rectangle(west, south, east, north);
|
}
|
|
result.west = west;
|
result.south = south;
|
result.east = east;
|
result.north = north;
|
return result;
|
};
|
|
/**
|
* Converts tile x, y coordinates and level to a cartographic rectangle in radians.
|
*
|
* @param {Number} x The integer x coordinate of the tile.
|
* @param {Number} y The integer y coordinate of the tile.
|
* @param {Number} level The tile level-of-detail. Zero is the least detailed.
|
* @param {Object} [result] The instance to which to copy the result, or undefined if a new instance
|
* should be created.
|
* @returns {Rectangle} The specified 'result', or a new object containing the rectangle
|
* if 'result' is undefined.
|
*/
|
WebMercatorTilingScheme.prototype.tileXYToRectangle = function(x, y, level, result) {
|
var nativeRectangle = this.tileXYToNativeRectangle(x, y, level, result);
|
|
var projection = this._projection;
|
var southwest = projection.unproject(new Cartesian2(nativeRectangle.west, nativeRectangle.south));
|
var northeast = projection.unproject(new Cartesian2(nativeRectangle.east, nativeRectangle.north));
|
|
nativeRectangle.west = southwest.longitude;
|
nativeRectangle.south = southwest.latitude;
|
nativeRectangle.east = northeast.longitude;
|
nativeRectangle.north = northeast.latitude;
|
return nativeRectangle;
|
};
|
|
/**
|
* Calculates the tile x, y coordinates of the tile containing
|
* a given cartographic position.
|
*
|
* @param {Cartographic} position The position.
|
* @param {Number} level The tile level-of-detail. Zero is the least detailed.
|
* @param {Cartesian2} [result] The instance to which to copy the result, or undefined if a new instance
|
* should be created.
|
* @returns {Cartesian2} The specified 'result', or a new object containing the tile x, y coordinates
|
* if 'result' is undefined.
|
*/
|
WebMercatorTilingScheme.prototype.positionToTileXY = function(position, level, result) {
|
var rectangle = this._rectangle;
|
if (!Rectangle.contains(rectangle, position)) {
|
// outside the bounds of the tiling scheme
|
return undefined;
|
}
|
|
var xTiles = this.getNumberOfXTilesAtLevel(level);
|
var yTiles = this.getNumberOfYTilesAtLevel(level);
|
|
var overallWidth = this._rectangleNortheastInMeters.x - this._rectangleSouthwestInMeters.x;
|
var xTileWidth = overallWidth / xTiles;
|
var overallHeight = this._rectangleNortheastInMeters.y - this._rectangleSouthwestInMeters.y;
|
var yTileHeight = overallHeight / yTiles;
|
|
var projection = this._projection;
|
|
var webMercatorPosition = projection.project(position);
|
var distanceFromWest = webMercatorPosition.x - this._rectangleSouthwestInMeters.x;
|
var distanceFromNorth = this._rectangleNortheastInMeters.y - webMercatorPosition.y;
|
|
var xTileCoordinate = distanceFromWest / xTileWidth | 0;
|
if (xTileCoordinate >= xTiles) {
|
xTileCoordinate = xTiles - 1;
|
}
|
var yTileCoordinate = distanceFromNorth / yTileHeight | 0;
|
if (yTileCoordinate >= yTiles) {
|
yTileCoordinate = yTiles - 1;
|
}
|
|
if (!defined(result)) {
|
return new Cartesian2(xTileCoordinate, yTileCoordinate);
|
}
|
|
result.x = xTileCoordinate;
|
result.y = yTileCoordinate;
|
return result;
|
};
|
|
module.exports= WebMercatorTilingScheme;
|
|
},{"./Cartesian2":125,"./Ellipsoid":132,"./Rectangle":140,"./WebMercatorProjection":152,"./defaultValue":158,"./defineProperties":159,"./defined":160}],154:[function(require,module,exports){
|
|
'use strict';
|
|
/**
|
* @private
|
*/
|
function appendForwardSlash(url) {
|
if (url.length === 0 || url[url.length - 1] !== '/') {
|
url = url + '/';
|
}
|
return url;
|
}
|
|
module.exports= appendForwardSlash;
|
|
},{}],155:[function(require,module,exports){
|
var defined=require('./defined');
|
var DeveloperError=require('./DeveloperError');
|
var getAbsoluteUri=require('./getAbsoluteUri');
|
var Resource=require('./Resource');
|
// var require=require('require');
|
|
'use strict';
|
/*global CESIUM_BASE_URL*/
|
|
var cesiumScriptRegex = /((?:.*\/)|^)cesium[\w-]*\.js(?:\W|$)/i;
|
function getBaseUrlFromCesiumScript() {
|
var scripts = document.getElementsByTagName('script');
|
for ( var i = 0, len = scripts.length; i < len; ++i) {
|
var src = scripts[i].getAttribute('src');
|
var result = cesiumScriptRegex.exec(src);
|
if (result !== null) {
|
return result[1];
|
}
|
}
|
return undefined;
|
}
|
|
var a;
|
function tryMakeAbsolute(url) {
|
if (typeof document === 'undefined') {
|
//Node.js and Web Workers. In both cases, the URL will already be absolute.
|
return url;
|
}
|
|
if (!defined(a)) {
|
a = document.createElement('a');
|
}
|
a.href = url;
|
|
// IE only absolutizes href on get, not set
|
a.href = a.href; // eslint-disable-line no-self-assign
|
return a.href;
|
}
|
|
var baseResource;
|
function getCesiumBaseUrl() {
|
if (defined(baseResource)) {
|
return baseResource;
|
}
|
|
var baseUrlString;
|
if (typeof CESIUM_BASE_URL !== 'undefined') {
|
baseUrlString = CESIUM_BASE_URL;
|
} else if (defined(define.amd) && !define.amd.toUrlUndefined && defined(require.toUrl)) {
|
baseUrlString = getAbsoluteUri('..', buildModuleUrl('Core/buildModuleUrl.js'));
|
} else {
|
baseUrlString = getBaseUrlFromCesiumScript();
|
}
|
|
//>>includeStart('debug', pragmas.debug);
|
if (!defined(baseUrlString)) {
|
throw new DeveloperError('Unable to determine Cesium base URL automatically, try defining a global variable called CESIUM_BASE_URL.');
|
}
|
//>>includeEnd('debug');
|
|
baseResource = new Resource({
|
url: tryMakeAbsolute(baseUrlString)
|
});
|
baseResource.appendForwardSlash();
|
|
return baseResource;
|
}
|
|
function buildModuleUrlFromRequireToUrl(moduleID) {
|
//moduleID will be non-relative, so require it relative to this module, in Core.
|
return tryMakeAbsolute(require.toUrl('../' + moduleID));
|
}
|
|
function buildModuleUrlFromBaseUrl(moduleID) {
|
var resource = getCesiumBaseUrl().getDerivedResource({
|
url: moduleID
|
});
|
return resource.url;
|
}
|
|
var implementation;
|
|
/**
|
* Given a non-relative moduleID, returns an absolute URL to the file represented by that module ID,
|
* using, in order of preference, require.toUrl, the value of a global CESIUM_BASE_URL, or
|
* the base URL of the Cesium.js script.
|
*
|
* @private
|
*/
|
function buildModuleUrl(moduleID) {
|
if (!defined(implementation)) {
|
//select implementation
|
if (defined(define.amd) && !define.amd.toUrlUndefined && defined(require.toUrl)) {
|
implementation = buildModuleUrlFromRequireToUrl;
|
} else {
|
implementation = buildModuleUrlFromBaseUrl;
|
}
|
}
|
|
var url = implementation(moduleID);
|
return url;
|
}
|
|
// exposed for testing
|
buildModuleUrl._cesiumScriptRegex = cesiumScriptRegex;
|
buildModuleUrl._buildModuleUrlFromBaseUrl = buildModuleUrlFromBaseUrl;
|
buildModuleUrl._clearBaseResource = function() {
|
baseResource = undefined;
|
};
|
|
/**
|
* Sets the base URL for resolving modules.
|
* @param {String} value The new base URL.
|
*/
|
buildModuleUrl.setBaseUrl = function(value) {
|
baseResource = Resource.DEFAULT.getDerivedResource({
|
url: value
|
});
|
};
|
|
/**
|
* Gets the base URL for resolving modules.
|
*/
|
buildModuleUrl.getCesiumBaseUrl = getCesiumBaseUrl;
|
|
module.exports= buildModuleUrl;
|
|
},{"./DeveloperError":131,"./Resource":146,"./defined":160,"./getAbsoluteUri":164}],156:[function(require,module,exports){
|
var defaultValue=require('./defaultValue');
|
|
'use strict';
|
|
/**
|
* Clones an object, returning a new object containing the same properties.
|
*
|
* @exports clone
|
*
|
* @param {Object} object The object to clone.
|
* @param {Boolean} [deep=false] If true, all properties will be deep cloned recursively.
|
* @returns {Object} The cloned object.
|
*/
|
function clone(object, deep) {
|
if (object === null || typeof object !== 'object') {
|
return object;
|
}
|
|
deep = defaultValue(deep, false);
|
|
var result = new object.constructor();
|
for ( var propertyName in object) {
|
if (object.hasOwnProperty(propertyName)) {
|
var value = object[propertyName];
|
if (deep) {
|
value = clone(value, deep);
|
}
|
result[propertyName] = value;
|
}
|
}
|
|
return result;
|
}
|
|
module.exports= clone;
|
|
},{"./defaultValue":158}],157:[function(require,module,exports){
|
var defaultValue=require('./defaultValue');
|
var defined=require('./defined');
|
|
'use strict';
|
|
/**
|
* Merges two objects, copying their properties onto a new combined object. When two objects have the same
|
* property, the value of the property on the first object is used. If either object is undefined,
|
* it will be treated as an empty object.
|
*
|
* @example
|
* var object1 = {
|
* propOne : 1,
|
* propTwo : {
|
* value1 : 10
|
* }
|
* }
|
* var object2 = {
|
* propTwo : 2
|
* }
|
* var final = Cesium.combine(object1, object2);
|
*
|
* // final === {
|
* // propOne : 1,
|
* // propTwo : {
|
* // value1 : 10
|
* // }
|
* // }
|
*
|
* @param {Object} [object1] The first object to merge.
|
* @param {Object} [object2] The second object to merge.
|
* @param {Boolean} [deep=false] Perform a recursive merge.
|
* @returns {Object} The combined object containing all properties from both objects.
|
*
|
* @exports combine
|
*/
|
function combine(object1, object2, deep) {
|
deep = defaultValue(deep, false);
|
|
var result = {};
|
|
var object1Defined = defined(object1);
|
var object2Defined = defined(object2);
|
var property;
|
var object1Value;
|
var object2Value;
|
if (object1Defined) {
|
for (property in object1) {
|
if (object1.hasOwnProperty(property)) {
|
object1Value = object1[property];
|
if (object2Defined && deep && typeof object1Value === 'object' && object2.hasOwnProperty(property)) {
|
object2Value = object2[property];
|
if (typeof object2Value === 'object') {
|
result[property] = combine(object1Value, object2Value, deep);
|
} else {
|
result[property] = object1Value;
|
}
|
} else {
|
result[property] = object1Value;
|
}
|
}
|
}
|
}
|
if (object2Defined) {
|
for (property in object2) {
|
if (object2.hasOwnProperty(property) && !result.hasOwnProperty(property)) {
|
object2Value = object2[property];
|
result[property] = object2Value;
|
}
|
}
|
}
|
return result;
|
}
|
|
module.exports= combine;
|
|
},{"./defaultValue":158,"./defined":160}],158:[function(require,module,exports){
|
var freezeObject=require('./freezeObject');
|
|
'use strict';
|
|
/**
|
* Returns the first parameter if not undefined, otherwise the second parameter.
|
* Useful for setting a default value for a parameter.
|
*
|
* @exports defaultValue
|
*
|
* @param {*} a
|
* @param {*} b
|
* @returns {*} Returns the first parameter if not undefined, otherwise the second parameter.
|
*
|
* @example
|
* param = Cesium.defaultValue(param, 'default');
|
*/
|
function defaultValue(a, b) {
|
if (a !== undefined && a !== null) {
|
return a;
|
}
|
return b;
|
}
|
|
/**
|
* A frozen empty object that can be used as the default value for options passed as
|
* an object literal.
|
* @type {Object}
|
*/
|
defaultValue.EMPTY_OBJECT = freezeObject({});
|
|
module.exports= defaultValue;
|
|
},{"./freezeObject":163}],159:[function(require,module,exports){
|
var defined=require('./defined');
|
|
'use strict';
|
|
var definePropertyWorks = (function() {
|
try {
|
return 'x' in Object.defineProperty({}, 'x', {});
|
} catch (e) {
|
return false;
|
}
|
})();
|
|
/**
|
* Defines properties on an object, using Object.defineProperties if available,
|
* otherwise returns the object unchanged. This function should be used in
|
* setup code to prevent errors from completely halting JavaScript execution
|
* in legacy browsers.
|
*
|
* @private
|
*
|
* @exports defineProperties
|
*/
|
var defineProperties = Object.defineProperties;
|
if (!definePropertyWorks || !defined(defineProperties)) {
|
defineProperties = function(o) {
|
return o;
|
};
|
}
|
|
module.exports= defineProperties;
|
|
},{"./defined":160}],160:[function(require,module,exports){
|
|
'use strict';
|
|
/**
|
* @exports defined
|
*
|
* @param {*} value The object.
|
* @returns {Boolean} Returns true if the object is defined, returns false otherwise.
|
*
|
* @example
|
* if (Cesium.defined(positions)) {
|
* doSomething();
|
* } else {
|
* doSomethingElse();
|
* }
|
*/
|
function defined(value) {
|
return value !== undefined && value !== null;
|
}
|
|
module.exports= defined;
|
|
},{}],161:[function(require,module,exports){
|
var defined=require('./defined');
|
var DeveloperError=require('./DeveloperError');
|
var oneTimeWarning=require('./oneTimeWarning');
|
|
'use strict';
|
|
/**
|
* Logs a deprecation message to the console. Use this function instead of
|
* <code>console.log</code> directly since this does not log duplicate messages
|
* unless it is called from multiple workers.
|
*
|
* @exports deprecationWarning
|
*
|
* @param {String} identifier The unique identifier for this deprecated API.
|
* @param {String} message The message to log to the console.
|
*
|
* @example
|
* // Deprecated function or class
|
* function Foo() {
|
* deprecationWarning('Foo', 'Foo was deprecated in Cesium 1.01. It will be removed in 1.03. Use newFoo instead.');
|
* // ...
|
* }
|
*
|
* // Deprecated function
|
* Bar.prototype.func = function() {
|
* deprecationWarning('Bar.func', 'Bar.func() was deprecated in Cesium 1.01. It will be removed in 1.03. Use Bar.newFunc() instead.');
|
* // ...
|
* };
|
*
|
* // Deprecated property
|
* defineProperties(Bar.prototype, {
|
* prop : {
|
* get : function() {
|
* deprecationWarning('Bar.prop', 'Bar.prop was deprecated in Cesium 1.01. It will be removed in 1.03. Use Bar.newProp instead.');
|
* // ...
|
* },
|
* set : function(value) {
|
* deprecationWarning('Bar.prop', 'Bar.prop was deprecated in Cesium 1.01. It will be removed in 1.03. Use Bar.newProp instead.');
|
* // ...
|
* }
|
* }
|
* });
|
*
|
* @private
|
*/
|
function deprecationWarning(identifier, message) {
|
//>>includeStart('debug', pragmas.debug);
|
if (!defined(identifier) || !defined(message)) {
|
throw new DeveloperError('identifier and message are required.');
|
}
|
//>>includeEnd('debug');
|
|
oneTimeWarning(identifier, message);
|
}
|
|
module.exports= deprecationWarning;
|
|
},{"./DeveloperError":131,"./defined":160,"./oneTimeWarning":173}],162:[function(require,module,exports){
|
var defaultValue=require('./defaultValue');
|
var DeveloperError=require('./DeveloperError');
|
|
'use strict';
|
|
function returnTrue() {
|
return true;
|
}
|
|
/**
|
* Destroys an object. Each of the object's functions, including functions in its prototype,
|
* is replaced with a function that throws a {@link DeveloperError}, except for the object's
|
* <code>isDestroyed</code> function, which is set to a function that returns <code>true</code>.
|
* The object's properties are removed with <code>delete</code>.
|
* <br /><br />
|
* This function is used by objects that hold native resources, e.g., WebGL resources, which
|
* need to be explicitly released. Client code calls an object's <code>destroy</code> function,
|
* which then releases the native resource and calls <code>destroyObject</code> to put itself
|
* in a destroyed state.
|
*
|
* @exports destroyObject
|
*
|
* @param {Object} object The object to destroy.
|
* @param {String} [message] The message to include in the exception that is thrown if
|
* a destroyed object's function is called.
|
*
|
*
|
* @example
|
* // How a texture would destroy itself.
|
* this.destroy = function () {
|
* _gl.deleteTexture(_texture);
|
* return Cesium.destroyObject(this);
|
* };
|
*
|
* @see DeveloperError
|
*/
|
function destroyObject(object, message) {
|
message = defaultValue(message, 'This object was destroyed, i.e., destroy() was called.');
|
|
function throwOnDestroyed() {
|
//>>includeStart('debug', pragmas.debug);
|
throw new DeveloperError(message);
|
//>>includeEnd('debug');
|
}
|
|
for ( var key in object) {
|
if (typeof object[key] === 'function') {
|
object[key] = throwOnDestroyed;
|
}
|
}
|
|
object.isDestroyed = returnTrue;
|
|
return undefined;
|
}
|
|
module.exports= destroyObject;
|
|
},{"./DeveloperError":131,"./defaultValue":158}],163:[function(require,module,exports){
|
var defined=require('./defined');
|
|
'use strict';
|
|
/**
|
* Freezes an object, using Object.freeze if available, otherwise returns
|
* the object unchanged. This function should be used in setup code to prevent
|
* errors from completely halting JavaScript execution in legacy browsers.
|
*
|
* @private
|
*
|
* @exports freezeObject
|
*/
|
var freezeObject = Object.freeze;
|
if (!defined(freezeObject)) {
|
freezeObject = function(o) {
|
return o;
|
};
|
}
|
|
module.exports= freezeObject;
|
|
},{"./defined":160}],164:[function(require,module,exports){
|
var Uri=require('uri');
|
var defaultValue=require('./defaultValue');
|
var defined=require('./defined');
|
var DeveloperError=require('./DeveloperError');
|
|
'use strict';
|
|
/**
|
* Given a relative Uri and a base Uri, returns the absolute Uri of the relative Uri.
|
* @exports getAbsoluteUri
|
*
|
* @param {String} relative The relative Uri.
|
* @param {String} [base] The base Uri.
|
* @returns {String} The absolute Uri of the given relative Uri.
|
*
|
* @example
|
* //absolute Uri will be "https://test.com/awesome.png";
|
* var absoluteUri = Cesium.getAbsoluteUri('awesome.png', 'https://test.com');
|
*/
|
function getAbsoluteUri(relative, base) {
|
var documentObject;
|
if (typeof document !== 'undefined') {
|
documentObject = document;
|
}
|
|
return getAbsoluteUri._implementation(relative, base, documentObject);
|
}
|
|
getAbsoluteUri._implementation = function(relative, base, documentObject) {
|
//>>includeStart('debug', pragmas.debug);
|
if (!defined(relative)) {
|
throw new DeveloperError('relative uri is required.');
|
}
|
//>>includeEnd('debug');
|
|
if (!defined(base)) {
|
if (typeof documentObject === 'undefined') {
|
return relative;
|
}
|
base = defaultValue(documentObject.baseURI, documentObject.location.href);
|
}
|
|
var baseUri = new Uri(base);
|
var relativeUri = new Uri(relative);
|
return relativeUri.resolve(baseUri).toString();
|
};
|
|
module.exports= getAbsoluteUri;
|
|
},{"./DeveloperError":131,"./defaultValue":158,"./defined":160,"uri":100}],165:[function(require,module,exports){
|
var Uri=require('uri');
|
var defined=require('./defined');
|
var DeveloperError=require('./DeveloperError');
|
|
'use strict';
|
|
/**
|
* Given a URI, returns the base path of the URI.
|
* @exports getBaseUri
|
*
|
* @param {String} uri The Uri.
|
* @param {Boolean} [includeQuery = false] Whether or not to include the query string and fragment form the uri
|
* @returns {String} The base path of the Uri.
|
*
|
* @example
|
* // basePath will be "/Gallery/";
|
* var basePath = Cesium.getBaseUri('/Gallery/simple.czml?value=true&example=false');
|
*
|
* // basePath will be "/Gallery/?value=true&example=false";
|
* var basePath = Cesium.getBaseUri('/Gallery/simple.czml?value=true&example=false', true);
|
*/
|
function getBaseUri(uri, includeQuery) {
|
//>>includeStart('debug', pragmas.debug);
|
if (!defined(uri)) {
|
throw new DeveloperError('uri is required.');
|
}
|
//>>includeEnd('debug');
|
|
var basePath = '';
|
var i = uri.lastIndexOf('/');
|
if (i !== -1) {
|
basePath = uri.substring(0, i + 1);
|
}
|
|
if (!includeQuery) {
|
return basePath;
|
}
|
|
uri = new Uri(uri);
|
if (defined(uri.query)) {
|
basePath += '?' + uri.query;
|
}
|
if (defined(uri.fragment)){
|
basePath += '#' + uri.fragment;
|
}
|
|
return basePath;
|
}
|
|
module.exports= getBaseUri;
|
|
},{"./DeveloperError":131,"./defined":160,"uri":100}],166:[function(require,module,exports){
|
var Uri=require('uri');
|
var defined=require('./defined');
|
var DeveloperError=require('./DeveloperError');
|
|
'use strict';
|
|
/**
|
* Given a URI, returns the extension of the URI.
|
* @exports getExtensionFromUri
|
*
|
* @param {String} uri The Uri.
|
* @returns {String} The extension of the Uri.
|
*
|
* @example
|
* //extension will be "czml";
|
* var extension = Cesium.getExtensionFromUri('/Gallery/simple.czml?value=true&example=false');
|
*/
|
function getExtensionFromUri(uri) {
|
//>>includeStart('debug', pragmas.debug);
|
if (!defined(uri)) {
|
throw new DeveloperError('uri is required.');
|
}
|
//>>includeEnd('debug');
|
|
var uriObject = new Uri(uri);
|
uriObject.normalize();
|
var path = uriObject.path;
|
var index = path.lastIndexOf('/');
|
if (index !== -1) {
|
path = path.substr(index + 1);
|
}
|
index = path.lastIndexOf('.');
|
if (index === -1) {
|
path = '';
|
} else {
|
path = path.substr(index + 1);
|
}
|
return path;
|
}
|
|
module.exports= getExtensionFromUri;
|
|
},{"./DeveloperError":131,"./defined":160,"uri":100}],167:[function(require,module,exports){
|
var defined=require('./defined');
|
|
'use strict';
|
|
/**
|
* Tests an object to see if it is an array.
|
* @exports isArray
|
*
|
* @param {*} value The value to test.
|
* @returns {Boolean} true if the value is an array, false otherwise.
|
*/
|
var isArray = Array.isArray;
|
if (!defined(isArray)) {
|
isArray = function(value) {
|
return Object.prototype.toString.call(value) === '[object Array]';
|
};
|
}
|
|
module.exports= isArray;
|
|
},{"./defined":160}],168:[function(require,module,exports){
|
var Check=require('./Check');
|
|
'use strict';
|
|
var blobUriRegex = /^blob:/i;
|
|
/**
|
* Determines if the specified uri is a blob uri.
|
*
|
* @exports isBlobUri
|
*
|
* @param {String} uri The uri to test.
|
* @returns {Boolean} true when the uri is a blob uri; otherwise, false.
|
*
|
* @private
|
*/
|
function isBlobUri(uri) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.string('uri', uri);
|
//>>includeEnd('debug');
|
|
return blobUriRegex.test(uri);
|
}
|
|
module.exports= isBlobUri;
|
|
},{"./Check":129}],169:[function(require,module,exports){
|
var defined=require('./defined');
|
|
'use strict';
|
|
var a;
|
|
/**
|
* Given a URL, determine whether that URL is considered cross-origin to the current page.
|
*
|
* @private
|
*/
|
function isCrossOriginUrl(url) {
|
if (!defined(a)) {
|
a = document.createElement('a');
|
}
|
|
// copy window location into the anchor to get consistent results
|
// when the port is default for the protocol (e.g. 80 for HTTP)
|
a.href = window.location.href;
|
|
// host includes both hostname and port if the port is not standard
|
var host = a.host;
|
var protocol = a.protocol;
|
|
a.href = url;
|
// IE only absolutizes href on get, not set
|
a.href = a.href; // eslint-disable-line no-self-assign
|
|
return protocol !== a.protocol || host !== a.host;
|
}
|
|
module.exports= isCrossOriginUrl;
|
|
},{"./defined":160}],170:[function(require,module,exports){
|
var Check=require('./Check');
|
|
'use strict';
|
|
var dataUriRegex = /^data:/i;
|
|
/**
|
* Determines if the specified uri is a data uri.
|
*
|
* @exports isDataUri
|
*
|
* @param {String} uri The uri to test.
|
* @returns {Boolean} true when the uri is a data uri; otherwise, false.
|
*
|
* @private
|
*/
|
function isDataUri(uri) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.typeOf.string('uri', uri);
|
//>>includeEnd('debug');
|
|
return dataUriRegex.test(uri);
|
}
|
|
module.exports= isDataUri;
|
|
},{"./Check":129}],171:[function(require,module,exports){
|
var when=require('when');
|
|
'use strict';
|
|
/**
|
* @private
|
*/
|
function loadAndExecuteScript(url) {
|
var deferred = when.defer();
|
var script = document.createElement('script');
|
script.async = true;
|
script.src = url;
|
|
var head = document.getElementsByTagName('head')[0];
|
script.onload = function() {
|
script.onload = undefined;
|
head.removeChild(script);
|
deferred.resolve();
|
};
|
script.onerror = function(e) {
|
deferred.reject(e);
|
};
|
|
head.appendChild(script);
|
|
return deferred.promise;
|
}
|
|
module.exports= loadAndExecuteScript;
|
|
},{"when":118}],172:[function(require,module,exports){
|
var defined=require('./defined');
|
var DeveloperError=require('./DeveloperError');
|
var isArray=require('./isArray');
|
|
'use strict';
|
|
/**
|
* Converts an object representing a set of name/value pairs into a query string,
|
* with names and values encoded properly for use in a URL. Values that are arrays
|
* will produce multiple values with the same name.
|
* @exports objectToQuery
|
*
|
* @param {Object} obj The object containing data to encode.
|
* @returns {String} An encoded query string.
|
*
|
*
|
* @example
|
* var str = Cesium.objectToQuery({
|
* key1 : 'some value',
|
* key2 : 'a/b',
|
* key3 : ['x', 'y']
|
* });
|
*
|
* @see queryToObject
|
* // str will be:
|
* // 'key1=some%20value&key2=a%2Fb&key3=x&key3=y'
|
*/
|
function objectToQuery(obj) {
|
//>>includeStart('debug', pragmas.debug);
|
if (!defined(obj)) {
|
throw new DeveloperError('obj is required.');
|
}
|
//>>includeEnd('debug');
|
|
var result = '';
|
for ( var propName in obj) {
|
if (obj.hasOwnProperty(propName)) {
|
var value = obj[propName];
|
|
var part = encodeURIComponent(propName) + '=';
|
if (isArray(value)) {
|
for (var i = 0, len = value.length; i < len; ++i) {
|
result += part + encodeURIComponent(value[i]) + '&';
|
}
|
} else {
|
result += part + encodeURIComponent(value) + '&';
|
}
|
}
|
}
|
|
// trim last &
|
result = result.slice(0, -1);
|
|
// This function used to replace %20 with + which is more compact and readable.
|
// However, some servers didn't properly handle + as a space.
|
// https://github.com/AnalyticalGraphicsInc/cesium/issues/2192
|
|
return result;
|
}
|
|
module.exports= objectToQuery;
|
|
},{"./DeveloperError":131,"./defined":160,"./isArray":167}],173:[function(require,module,exports){
|
var defaultValue=require('./defaultValue');
|
var defined=require('./defined');
|
var DeveloperError=require('./DeveloperError');
|
|
'use strict';
|
|
var warnings = {};
|
|
/**
|
* Logs a one time message to the console. Use this function instead of
|
* <code>console.log</code> directly since this does not log duplicate messages
|
* unless it is called from multiple workers.
|
*
|
* @exports oneTimeWarning
|
*
|
* @param {String} identifier The unique identifier for this warning.
|
* @param {String} [message=identifier] The message to log to the console.
|
*
|
* @example
|
* for(var i=0;i<foo.length;++i) {
|
* if (!defined(foo[i].bar)) {
|
* // Something that can be recovered from but may happen a lot
|
* oneTimeWarning('foo.bar undefined', 'foo.bar is undefined. Setting to 0.');
|
* foo[i].bar = 0;
|
* // ...
|
* }
|
* }
|
*
|
* @private
|
*/
|
function oneTimeWarning(identifier, message) {
|
//>>includeStart('debug', pragmas.debug);
|
if (!defined(identifier)) {
|
throw new DeveloperError('identifier is required.');
|
}
|
//>>includeEnd('debug');
|
|
if (!defined(warnings[identifier])) {
|
warnings[identifier] = true;
|
console.warn(defaultValue(message, identifier));
|
}
|
}
|
|
oneTimeWarning.geometryOutlines = 'Entity geometry outlines are unsupported on terrain. Outlines will be disabled. To enable outlines, disable geometry terrain clamping by explicitly setting height to 0.';
|
|
oneTimeWarning.geometryZIndex = 'Entity geometry with zIndex are unsupported when height or extrudedHeight are defined. zIndex will be ignored';
|
|
oneTimeWarning.geometryHeightReference = 'Entity corridor, ellipse, polygon or rectangle with heightReference must also have a defined height. heightReference will be ignored';
|
oneTimeWarning.geometryExtrudedHeightReference = 'Entity corridor, ellipse, polygon or rectangle with extrudedHeightReference must also have a defined extrudedHeight. extrudedHeightReference will be ignored';
|
|
module.exports= oneTimeWarning;
|
|
},{"./DeveloperError":131,"./defaultValue":158,"./defined":160}],174:[function(require,module,exports){
|
|
'use strict';
|
|
/**
|
* Parses the result of XMLHttpRequest's getAllResponseHeaders() method into
|
* a dictionary.
|
*
|
* @exports parseResponseHeaders
|
*
|
* @param {String} headerString The header string returned by getAllResponseHeaders(). The format is
|
* described here: http://www.w3.org/TR/XMLHttpRequest/#the-getallresponseheaders()-method
|
* @returns {Object} A dictionary of key/value pairs, where each key is the name of a header and the corresponding value
|
* is that header's value.
|
*
|
* @private
|
*/
|
function parseResponseHeaders(headerString) {
|
var headers = {};
|
|
if (!headerString) {
|
return headers;
|
}
|
|
var headerPairs = headerString.split('\u000d\u000a');
|
|
for (var i = 0; i < headerPairs.length; ++i) {
|
var headerPair = headerPairs[i];
|
// Can't use split() here because it does the wrong thing
|
// if the header value has the string ": " in it.
|
var index = headerPair.indexOf('\u003a\u0020');
|
if (index > 0) {
|
var key = headerPair.substring(0, index);
|
var val = headerPair.substring(index + 2);
|
headers[key] = val;
|
}
|
}
|
|
return headers;
|
}
|
|
module.exports= parseResponseHeaders;
|
|
},{}],175:[function(require,module,exports){
|
var defined=require('./defined');
|
var DeveloperError=require('./DeveloperError');
|
var isArray=require('./isArray');
|
|
'use strict';
|
|
/**
|
* Parses a query string into an object, where the keys and values of the object are the
|
* name/value pairs from the query string, decoded. If a name appears multiple times,
|
* the value in the object will be an array of values.
|
* @exports queryToObject
|
*
|
* @param {String} queryString The query string.
|
* @returns {Object} An object containing the parameters parsed from the query string.
|
*
|
*
|
* @example
|
* var obj = Cesium.queryToObject('key1=some%20value&key2=a%2Fb&key3=x&key3=y');
|
* // obj will be:
|
* // {
|
* // key1 : 'some value',
|
* // key2 : 'a/b',
|
* // key3 : ['x', 'y']
|
* // }
|
*
|
* @see objectToQuery
|
*/
|
function queryToObject(queryString) {
|
//>>includeStart('debug', pragmas.debug);
|
if (!defined(queryString)) {
|
throw new DeveloperError('queryString is required.');
|
}
|
//>>includeEnd('debug');
|
|
var result = {};
|
if (queryString === '') {
|
return result;
|
}
|
var parts = queryString.replace(/\+/g, '%20').split(/[&;]/);
|
for (var i = 0, len = parts.length; i < len; ++i) {
|
var subparts = parts[i].split('=');
|
|
var name = decodeURIComponent(subparts[0]);
|
var value = subparts[1];
|
if (defined(value)) {
|
value = decodeURIComponent(value);
|
} else {
|
value = '';
|
}
|
|
var resultValue = result[name];
|
if (typeof resultValue === 'string') {
|
// expand the single value to an array
|
result[name] = [resultValue, value];
|
} else if (isArray(resultValue)) {
|
resultValue.push(value);
|
} else {
|
result[name] = value;
|
}
|
}
|
return result;
|
}
|
|
module.exports= queryToObject;
|
|
},{"./DeveloperError":131,"./defined":160,"./isArray":167}],176:[function(require,module,exports){
|
var Cartesian3=require('./Cartesian3');
|
var defined=require('./defined');
|
var DeveloperError=require('./DeveloperError');
|
var CesiumMath=require('./Math');
|
|
'use strict';
|
|
var scaleToGeodeticSurfaceIntersection = new Cartesian3();
|
var scaleToGeodeticSurfaceGradient = new Cartesian3();
|
|
/**
|
* Scales the provided Cartesian position along the geodetic surface normal
|
* so that it is on the surface of this ellipsoid. If the position is
|
* at the center of the ellipsoid, this function returns undefined.
|
*
|
* @param {Cartesian3} cartesian The Cartesian position to scale.
|
* @param {Cartesian3} oneOverRadii One over radii of the ellipsoid.
|
* @param {Cartesian3} oneOverRadiiSquared One over radii squared of the ellipsoid.
|
* @param {Number} centerToleranceSquared Tolerance for closeness to the center.
|
* @param {Cartesian3} [result] The object onto which to store the result.
|
* @returns {Cartesian3} The modified result parameter, a new Cartesian3 instance if none was provided, or undefined if the position is at the center.
|
*
|
* @exports scaleToGeodeticSurface
|
*
|
* @private
|
*/
|
function scaleToGeodeticSurface(cartesian, oneOverRadii, oneOverRadiiSquared, centerToleranceSquared, result) {
|
//>>includeStart('debug', pragmas.debug);
|
if (!defined(cartesian)) {
|
throw new DeveloperError('cartesian is required.');
|
}
|
if (!defined(oneOverRadii)) {
|
throw new DeveloperError('oneOverRadii is required.');
|
}
|
if (!defined(oneOverRadiiSquared)) {
|
throw new DeveloperError('oneOverRadiiSquared is required.');
|
}
|
if (!defined(centerToleranceSquared)) {
|
throw new DeveloperError('centerToleranceSquared is required.');
|
}
|
//>>includeEnd('debug');
|
|
var positionX = cartesian.x;
|
var positionY = cartesian.y;
|
var positionZ = cartesian.z;
|
|
var oneOverRadiiX = oneOverRadii.x;
|
var oneOverRadiiY = oneOverRadii.y;
|
var oneOverRadiiZ = oneOverRadii.z;
|
|
var x2 = positionX * positionX * oneOverRadiiX * oneOverRadiiX;
|
var y2 = positionY * positionY * oneOverRadiiY * oneOverRadiiY;
|
var z2 = positionZ * positionZ * oneOverRadiiZ * oneOverRadiiZ;
|
|
// Compute the squared ellipsoid norm.
|
var squaredNorm = x2 + y2 + z2;
|
var ratio = Math.sqrt(1.0 / squaredNorm);
|
|
// As an initial approximation, assume that the radial intersection is the projection point.
|
var intersection = Cartesian3.multiplyByScalar(cartesian, ratio, scaleToGeodeticSurfaceIntersection);
|
|
// If the position is near the center, the iteration will not converge.
|
if (squaredNorm < centerToleranceSquared) {
|
return !isFinite(ratio) ? undefined : Cartesian3.clone(intersection, result);
|
}
|
|
var oneOverRadiiSquaredX = oneOverRadiiSquared.x;
|
var oneOverRadiiSquaredY = oneOverRadiiSquared.y;
|
var oneOverRadiiSquaredZ = oneOverRadiiSquared.z;
|
|
// Use the gradient at the intersection point in place of the true unit normal.
|
// The difference in magnitude will be absorbed in the multiplier.
|
var gradient = scaleToGeodeticSurfaceGradient;
|
gradient.x = intersection.x * oneOverRadiiSquaredX * 2.0;
|
gradient.y = intersection.y * oneOverRadiiSquaredY * 2.0;
|
gradient.z = intersection.z * oneOverRadiiSquaredZ * 2.0;
|
|
// Compute the initial guess at the normal vector multiplier, lambda.
|
var lambda = (1.0 - ratio) * Cartesian3.magnitude(cartesian) / (0.5 * Cartesian3.magnitude(gradient));
|
var correction = 0.0;
|
|
var func;
|
var denominator;
|
var xMultiplier;
|
var yMultiplier;
|
var zMultiplier;
|
var xMultiplier2;
|
var yMultiplier2;
|
var zMultiplier2;
|
var xMultiplier3;
|
var yMultiplier3;
|
var zMultiplier3;
|
|
do {
|
lambda -= correction;
|
|
xMultiplier = 1.0 / (1.0 + lambda * oneOverRadiiSquaredX);
|
yMultiplier = 1.0 / (1.0 + lambda * oneOverRadiiSquaredY);
|
zMultiplier = 1.0 / (1.0 + lambda * oneOverRadiiSquaredZ);
|
|
xMultiplier2 = xMultiplier * xMultiplier;
|
yMultiplier2 = yMultiplier * yMultiplier;
|
zMultiplier2 = zMultiplier * zMultiplier;
|
|
xMultiplier3 = xMultiplier2 * xMultiplier;
|
yMultiplier3 = yMultiplier2 * yMultiplier;
|
zMultiplier3 = zMultiplier2 * zMultiplier;
|
|
func = x2 * xMultiplier2 + y2 * yMultiplier2 + z2 * zMultiplier2 - 1.0;
|
|
// "denominator" here refers to the use of this expression in the velocity and acceleration
|
// computations in the sections to follow.
|
denominator = x2 * xMultiplier3 * oneOverRadiiSquaredX + y2 * yMultiplier3 * oneOverRadiiSquaredY + z2 * zMultiplier3 * oneOverRadiiSquaredZ;
|
|
var derivative = -2.0 * denominator;
|
|
correction = func / derivative;
|
} while (Math.abs(func) > CesiumMath.EPSILON12);
|
|
if (!defined(result)) {
|
return new Cartesian3(positionX * xMultiplier, positionY * yMultiplier, positionZ * zMultiplier);
|
}
|
result.x = positionX * xMultiplier;
|
result.y = positionY * yMultiplier;
|
result.z = positionZ * zMultiplier;
|
return result;
|
}
|
|
module.exports= scaleToGeodeticSurface;
|
|
},{"./Cartesian3":126,"./DeveloperError":131,"./Math":139,"./defined":160}],177:[function(require,module,exports){
|
var measureText=require('../ThirdParty/measureText');
|
var Color=require('./Color');
|
var defaultValue=require('./defaultValue');
|
var defined=require('./defined');
|
var DeveloperError=require('./DeveloperError');
|
|
'use strict';
|
|
var imageSmoothingEnabledName;
|
|
/**
|
* Writes the given text into a new canvas. The canvas will be sized to fit the text.
|
* If text is blank, returns undefined.
|
*
|
* @param {String} text The text to write.
|
* @param {Object} [options] Object with the following properties:
|
* @param {String} [options.font='10px sans-serif'] The CSS font to use.
|
* @param {String} [options.textBaseline='bottom'] The baseline of the text.
|
* @param {Boolean} [options.fill=true] Whether to fill the text.
|
* @param {Boolean} [options.stroke=false] Whether to stroke the text.
|
* @param {Color} [options.fillColor=Color.WHITE] The fill color.
|
* @param {Color} [options.strokeColor=Color.BLACK] The stroke color.
|
* @param {Number} [options.strokeWidth=1] The stroke width.
|
* @param {Color} [options.backgroundColor=Color.TRANSPARENT] The background color of the canvas.
|
* @param {Number} [options.padding=0] The pixel size of the padding to add around the text.
|
* @returns {Canvas} A new canvas with the given text drawn into it. The dimensions object
|
* from measureText will also be added to the returned canvas. If text is
|
* blank, returns undefined.
|
* @exports writeTextToCanvas
|
*/
|
function writeTextToCanvas(text, options) {
|
//>>includeStart('debug', pragmas.debug);
|
if (!defined(text)) {
|
throw new DeveloperError('text is required.');
|
}
|
//>>includeEnd('debug');
|
if (text === '') {
|
return undefined;
|
}
|
|
options = defaultValue(options, defaultValue.EMPTY_OBJECT);
|
var font = defaultValue(options.font, '10px sans-serif');
|
var stroke = defaultValue(options.stroke, false);
|
var fill = defaultValue(options.fill, true);
|
var strokeWidth = defaultValue(options.strokeWidth, 1);
|
var backgroundColor = defaultValue(options.backgroundColor, Color.TRANSPARENT);
|
var padding = defaultValue(options.padding, 0);
|
var doublePadding = padding * 2.0;
|
|
var canvas = document.createElement('canvas');
|
canvas.width = 1;
|
canvas.height = 1;
|
canvas.style.font = font;
|
|
var context2D = canvas.getContext('2d');
|
|
if (!defined(imageSmoothingEnabledName)) {
|
if (defined(context2D.imageSmoothingEnabled)) {
|
imageSmoothingEnabledName = 'imageSmoothingEnabled';
|
} else if (defined(context2D.mozImageSmoothingEnabled)) {
|
imageSmoothingEnabledName = 'mozImageSmoothingEnabled';
|
} else if (defined(context2D.webkitImageSmoothingEnabled)) {
|
imageSmoothingEnabledName = 'webkitImageSmoothingEnabled';
|
} else if (defined(context2D.msImageSmoothingEnabled)) {
|
imageSmoothingEnabledName = 'msImageSmoothingEnabled';
|
}
|
}
|
|
context2D.font = font;
|
context2D.lineJoin = 'round';
|
context2D.lineWidth = strokeWidth;
|
context2D[imageSmoothingEnabledName] = false;
|
|
// textBaseline needs to be set before the measureText call. It won't work otherwise.
|
// It's magic.
|
context2D.textBaseline = defaultValue(options.textBaseline, 'bottom');
|
|
// in order for measureText to calculate style, the canvas has to be
|
// (temporarily) added to the DOM.
|
canvas.style.visibility = 'hidden';
|
document.body.appendChild(canvas);
|
|
var dimensions = measureText(context2D, text, stroke, fill);
|
canvas.dimensions = dimensions;
|
|
document.body.removeChild(canvas);
|
canvas.style.visibility = '';
|
|
//Some characters, such as the letter j, have a non-zero starting position.
|
//This value is used for kerning later, but we need to take it into account
|
//now in order to draw the text completely on the canvas
|
var x = -dimensions.bounds.minx;
|
|
//Expand the width to include the starting position.
|
var width = Math.ceil(dimensions.width) + x + doublePadding;
|
|
//While the height of the letter is correct, we need to adjust
|
//where we start drawing it so that letters like j and y properly dip
|
//below the line.
|
var height = dimensions.height + doublePadding;
|
var baseline = height - dimensions.ascent + doublePadding;
|
var y = height - baseline + doublePadding;
|
|
canvas.width = width;
|
canvas.height = height;
|
|
// Properties must be explicitly set again after changing width and height
|
context2D.font = font;
|
context2D.lineJoin = 'round';
|
context2D.lineWidth = strokeWidth;
|
context2D[imageSmoothingEnabledName] = false;
|
|
// Draw background
|
if (backgroundColor !== Color.TRANSPARENT) {
|
context2D.fillStyle = backgroundColor.toCssColorString();
|
context2D.fillRect(0, 0, canvas.width, canvas.height);
|
}
|
|
if (stroke) {
|
var strokeColor = defaultValue(options.strokeColor, Color.BLACK);
|
context2D.strokeStyle = strokeColor.toCssColorString();
|
context2D.strokeText(text, x + padding, y);
|
}
|
|
if (fill) {
|
var fillColor = defaultValue(options.fillColor, Color.WHITE);
|
context2D.fillStyle = fillColor.toCssColorString();
|
context2D.fillText(text, x + padding, y);
|
}
|
|
return canvas;
|
}
|
|
module.exports= writeTextToCanvas;
|
|
},{"../ThirdParty/measureText":178,"./Color":130,"./DeveloperError":131,"./defaultValue":158,"./defined":160}],178:[function(require,module,exports){
|
/*
|
This library rewrites the Canvas2D "measureText" function
|
so that it returns a more complete metrics object.
|
|
** -----------------------------------------------------------------------------
|
|
CHANGELOG:
|
|
2012-01-21 - Whitespace handling added by Joe Turner
|
(https://github.com/oampo)
|
|
** -----------------------------------------------------------------------------
|
*/
|
/**
|
@license
|
fontmetrics.js - https://github.com/Pomax/fontmetrics.js
|
|
Copyright (C) 2011 by Mike "Pomax" Kamermans
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
of this software and associated documentation files (the "Software"), to deal
|
in the Software without restriction, including without limitation the rights
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
copies of the Software, and to permit persons to whom the Software is
|
furnished to do so, subject to the following conditions:
|
|
The above copyright notice and this permission notice shall be included in
|
all copies or substantial portions of the Software.
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
THE SOFTWARE.
|
**/
|
// define(function() {
|
/*jshint strict:false*/
|
/*
|
var NAME = "FontMetrics Library"
|
var VERSION = "1-2012.0121.1300";
|
|
// if there is no getComputedStyle, this library won't work.
|
if(!document.defaultView.getComputedStyle) {
|
throw("ERROR: 'document.defaultView.getComputedStyle' not found. This library only works in browsers that can report computed CSS values.");
|
}
|
|
// store the old text metrics function on the Canvas2D prototype
|
CanvasRenderingContext2D.prototype.measureTextWidth = CanvasRenderingContext2D.prototype.measureText;
|
*/
|
/**
|
* shortcut function for getting computed CSS values
|
*/
|
var getCSSValue = function (element, property) {
|
return document.defaultView.getComputedStyle(element, null).getPropertyValue(property);
|
};
|
/*
|
// debug function
|
var show = function(canvas, ctx, xstart, w, h, metrics)
|
{
|
document.body.appendChild(canvas);
|
ctx.strokeStyle = 'rgba(0, 0, 0, 0.5)';
|
|
ctx.beginPath();
|
ctx.moveTo(xstart,0);
|
ctx.lineTo(xstart,h);
|
ctx.closePath();
|
ctx.stroke();
|
|
ctx.beginPath();
|
ctx.moveTo(xstart+metrics.bounds.maxx,0);
|
ctx.lineTo(xstart+metrics.bounds.maxx,h);
|
ctx.closePath();
|
ctx.stroke();
|
|
ctx.beginPath();
|
ctx.moveTo(0,h/2-metrics.ascent);
|
ctx.lineTo(w,h/2-metrics.ascent);
|
ctx.closePath();
|
ctx.stroke();
|
|
ctx.beginPath();
|
ctx.moveTo(0,h/2+metrics.descent);
|
ctx.lineTo(w,h/2+metrics.descent);
|
ctx.closePath();
|
ctx.stroke();
|
}
|
*/
|
/**
|
* The new text metrics function
|
*/
|
var measureText = function (context2D, textstring, stroke, fill) {
|
var metrics = context2D.measureText(textstring),
|
fontFamily = getCSSValue(context2D.canvas, "font-family"),
|
fontSize = getCSSValue(context2D.canvas, "font-size").replace("px", ""),
|
fontStyle = getCSSValue(context2D.canvas, "font-style"),
|
fontWeight = getCSSValue(context2D.canvas, "font-weight"),
|
isSpace = !(/\S/.test(textstring));
|
metrics.fontsize = fontSize;
|
|
// for text lead values, we meaure a multiline text container.
|
var leadDiv = document.createElement("div");
|
leadDiv.style.position = "absolute";
|
leadDiv.style.opacity = 0;
|
leadDiv.style.font = fontStyle + " " + fontWeight + " " + fontSize + "px " + fontFamily;
|
leadDiv.innerHTML = textstring + "<br/>" + textstring;
|
document.body.appendChild(leadDiv);
|
|
// make some initial guess at the text leading (using the standard TeX ratio)
|
metrics.leading = 1.2 * fontSize;
|
|
// then we try to get the real value from the browser
|
var leadDivHeight = getCSSValue(leadDiv, "height");
|
leadDivHeight = leadDivHeight.replace("px", "");
|
if (leadDivHeight >= fontSize * 2) { metrics.leading = (leadDivHeight / 2) | 0; }
|
document.body.removeChild(leadDiv);
|
|
// if we're not dealing with white space, we can compute metrics
|
if (!isSpace) {
|
// Have characters, so measure the text
|
var canvas = document.createElement("canvas");
|
var padding = 100;
|
canvas.width = metrics.width + padding;
|
canvas.height = 3 * fontSize;
|
canvas.style.opacity = 1;
|
canvas.style.fontFamily = fontFamily;
|
canvas.style.fontSize = fontSize;
|
canvas.style.fontStyle = fontStyle;
|
canvas.style.fontWeight = fontWeight;
|
var ctx = canvas.getContext("2d");
|
ctx.font = fontStyle + " " + fontWeight + " " + fontSize + "px " + fontFamily;
|
|
var w = canvas.width,
|
h = canvas.height,
|
baseline = h / 2;
|
|
// Set all canvas pixeldata values to 255, with all the content
|
// data being 0. This lets us scan for data[i] != 255.
|
ctx.fillStyle = "white";
|
ctx.fillRect(-1, -1, w + 2, h + 2);
|
|
if (stroke) {
|
ctx.strokeStyle = "black";
|
ctx.lineWidth = context2D.lineWidth;
|
ctx.strokeText(textstring, (padding / 2), baseline);
|
}
|
|
if (fill) {
|
ctx.fillStyle = "black";
|
ctx.fillText(textstring, padding / 2, baseline);
|
}
|
|
var pixelData = ctx.getImageData(0, 0, w, h).data;
|
|
// canvas pixel data is w*4 by h*4, because R, G, B and A are separate,
|
// consecutive values in the array, rather than stored as 32 bit ints.
|
var i = 0,
|
w4 = w * 4,
|
len = pixelData.length;
|
|
// Finding the ascent uses a normal, forward scanline
|
while (++i < len && pixelData[i] === 255) { }
|
var ascent = (i / w4) | 0;
|
|
// Finding the descent uses a reverse scanline
|
i = len - 1;
|
while (--i > 0 && pixelData[i] === 255) { }
|
var descent = (i / w4) | 0;
|
|
// find the min-x coordinate
|
for (i = 0; i < len && pixelData[i] === 255;) {
|
i += w4;
|
if (i >= len) { i = (i - len) + 4; }
|
}
|
var minx = ((i % w4) / 4) | 0;
|
|
// find the max-x coordinate
|
var step = 1;
|
for (i = len - 3; i >= 0 && pixelData[i] === 255;) {
|
i -= w4;
|
if (i < 0) { i = (len - 3) - (step++) * 4; }
|
}
|
var maxx = ((i % w4) / 4) + 1 | 0;
|
|
// set font metrics
|
metrics.ascent = (baseline - ascent);
|
metrics.descent = (descent - baseline);
|
metrics.bounds = {
|
minx: minx - (padding / 2),
|
maxx: maxx - (padding / 2),
|
miny: 0,
|
maxy: descent - ascent
|
};
|
metrics.height = 1 + (descent - ascent);
|
}
|
|
// if we ARE dealing with whitespace, most values will just be zero.
|
else {
|
// Only whitespace, so we can't measure the text
|
metrics.ascent = 0;
|
metrics.descent = 0;
|
metrics.bounds = {
|
minx: 0,
|
maxx: metrics.width, // Best guess
|
miny: 0,
|
maxy: 0
|
};
|
metrics.height = 0;
|
}
|
return metrics;
|
};
|
|
module.exports = measureText;
|
// });
|
|
},{}],179:[function(require,module,exports){
|
/**
|
@license
|
when.js - https://github.com/cujojs/when
|
|
MIT License (c) copyright B Cavalier & J Hann
|
|
* A lightweight CommonJS Promises/A and when() implementation
|
* when is part of the cujo.js family of libraries (http://cujojs.com/)
|
*
|
* Licensed under the MIT License at:
|
* http://www.opensource.org/licenses/mit-license.php
|
*
|
* @version 1.7.1
|
*/
|
|
(function(define) { 'use strict';
|
define(function () {
|
var reduceArray, slice, undef;
|
|
//
|
// Public API
|
//
|
|
when.defer = defer; // Create a deferred
|
when.resolve = resolve; // Create a resolved promise
|
when.reject = reject; // Create a rejected promise
|
|
when.join = join; // Join 2 or more promises
|
|
when.all = all; // Resolve a list of promises
|
when.map = map; // Array.map() for promises
|
when.reduce = reduce; // Array.reduce() for promises
|
|
when.any = any; // One-winner race
|
when.some = some; // Multi-winner race
|
|
when.chain = chain; // Make a promise trigger another resolver
|
|
when.isPromise = isPromise; // Determine if a thing is a promise
|
|
/**
|
* Register an observer for a promise or immediate value.
|
*
|
* @param {*} promiseOrValue
|
* @param {function?} [onFulfilled] callback to be called when promiseOrValue is
|
* successfully fulfilled. If promiseOrValue is an immediate value, callback
|
* will be invoked immediately.
|
* @param {function?} [onRejected] callback to be called when promiseOrValue is
|
* rejected.
|
* @param {function?} [onProgress] callback to be called when progress updates
|
* are issued for promiseOrValue.
|
* @returns {Promise} a new {@link Promise} that will complete with the return
|
* value of callback or errback or the completion value of promiseOrValue if
|
* callback and/or errback is not supplied.
|
*/
|
function when(promiseOrValue, onFulfilled, onRejected, onProgress) {
|
// Get a trusted promise for the input promiseOrValue, and then
|
// register promise handlers
|
return resolve(promiseOrValue).then(onFulfilled, onRejected, onProgress);
|
}
|
|
/**
|
* Returns promiseOrValue if promiseOrValue is a {@link Promise}, a new Promise if
|
* promiseOrValue is a foreign promise, or a new, already-fulfilled {@link Promise}
|
* whose value is promiseOrValue if promiseOrValue is an immediate value.
|
*
|
* @param {*} promiseOrValue
|
* @returns Guaranteed to return a trusted Promise. If promiseOrValue is a when.js {@link Promise}
|
* returns promiseOrValue, otherwise, returns a new, already-resolved, when.js {@link Promise}
|
* whose resolution value is:
|
* * the resolution value of promiseOrValue if it's a foreign promise, or
|
* * promiseOrValue if it's a value
|
*/
|
function resolve(promiseOrValue) {
|
var promise, deferred;
|
|
if(promiseOrValue instanceof Promise) {
|
// It's a when.js promise, so we trust it
|
promise = promiseOrValue;
|
|
} else {
|
// It's not a when.js promise. See if it's a foreign promise or a value.
|
if(isPromise(promiseOrValue)) {
|
// It's a thenable, but we don't know where it came from, so don't trust
|
// its implementation entirely. Introduce a trusted middleman when.js promise
|
deferred = defer();
|
|
// IMPORTANT: This is the only place when.js should ever call .then() on an
|
// untrusted promise. Don't expose the return value to the untrusted promise
|
promiseOrValue.then(
|
function(value) { deferred.resolve(value); },
|
function(reason) { deferred.reject(reason); },
|
function(update) { deferred.progress(update); }
|
);
|
|
promise = deferred.promise;
|
|
} else {
|
// It's a value, not a promise. Create a resolved promise for it.
|
promise = fulfilled(promiseOrValue);
|
}
|
}
|
|
return promise;
|
}
|
|
/**
|
* Returns a rejected promise for the supplied promiseOrValue. The returned
|
* promise will be rejected with:
|
* - promiseOrValue, if it is a value, or
|
* - if promiseOrValue is a promise
|
* - promiseOrValue's value after it is fulfilled
|
* - promiseOrValue's reason after it is rejected
|
* @param {*} promiseOrValue the rejected value of the returned {@link Promise}
|
* @returns {Promise} rejected {@link Promise}
|
*/
|
function reject(promiseOrValue) {
|
return when(promiseOrValue, rejected);
|
}
|
|
/**
|
* Trusted Promise constructor. A Promise created from this constructor is
|
* a trusted when.js promise. Any other duck-typed promise is considered
|
* untrusted.
|
* @constructor
|
* @name Promise
|
*/
|
function Promise(then) {
|
this.then = then;
|
}
|
|
Promise.prototype = {
|
/**
|
* Register a callback that will be called when a promise is
|
* fulfilled or rejected. Optionally also register a progress handler.
|
* Shortcut for .then(onFulfilledOrRejected, onFulfilledOrRejected, onProgress)
|
* @param {function?} [onFulfilledOrRejected]
|
* @param {function?} [onProgress]
|
* @returns {Promise}
|
*/
|
always: function(onFulfilledOrRejected, onProgress) {
|
return this.then(onFulfilledOrRejected, onFulfilledOrRejected, onProgress);
|
},
|
|
/**
|
* Register a rejection handler. Shortcut for .then(undefined, onRejected)
|
* @param {function?} onRejected
|
* @returns {Promise}
|
*/
|
otherwise: function(onRejected) {
|
return this.then(undef, onRejected);
|
},
|
|
/**
|
* Shortcut for .then(function() { return value; })
|
* @param {*} value
|
* @returns {Promise} a promise that:
|
* - is fulfilled if value is not a promise, or
|
* - if value is a promise, will fulfill with its value, or reject
|
* with its reason.
|
*/
|
yield: function(value) {
|
return this.then(function() {
|
return value;
|
});
|
},
|
|
/**
|
* Assumes that this promise will fulfill with an array, and arranges
|
* for the onFulfilled to be called with the array as its argument list
|
* i.e. onFulfilled.spread(undefined, array).
|
* @param {function} onFulfilled function to receive spread arguments
|
* @returns {Promise}
|
*/
|
spread: function(onFulfilled) {
|
return this.then(function(array) {
|
// array may contain promises, so resolve its contents.
|
return all(array, function(array) {
|
return onFulfilled.apply(undef, array);
|
});
|
});
|
}
|
};
|
|
/**
|
* Create an already-resolved promise for the supplied value
|
* @private
|
*
|
* @param {*} value
|
* @returns {Promise} fulfilled promise
|
*/
|
function fulfilled(value) {
|
var p = new Promise(function(onFulfilled) {
|
// TODO: Promises/A+ check typeof onFulfilled
|
try {
|
return resolve(onFulfilled ? onFulfilled(value) : value);
|
} catch(e) {
|
return rejected(e);
|
}
|
});
|
|
return p;
|
}
|
|
/**
|
* Create an already-rejected {@link Promise} with the supplied
|
* rejection reason.
|
* @private
|
*
|
* @param {*} reason
|
* @returns {Promise} rejected promise
|
*/
|
function rejected(reason) {
|
var p = new Promise(function(_, onRejected) {
|
// TODO: Promises/A+ check typeof onRejected
|
try {
|
return onRejected ? resolve(onRejected(reason)) : rejected(reason);
|
} catch(e) {
|
return rejected(e);
|
}
|
});
|
|
return p;
|
}
|
|
/**
|
* Creates a new, Deferred with fully isolated resolver and promise parts,
|
* either or both of which may be given out safely to consumers.
|
* The Deferred itself has the full API: resolve, reject, progress, and
|
* then. The resolver has resolve, reject, and progress. The promise
|
* only has then.
|
*
|
* @returns {Deferred}
|
*/
|
function defer() {
|
var deferred, promise, handlers, progressHandlers,
|
_then, _progress, _resolve;
|
|
/**
|
* The promise for the new deferred
|
* @type {Promise}
|
*/
|
promise = new Promise(then);
|
|
/**
|
* The full Deferred object, with {@link Promise} and {@link Resolver} parts
|
* @class Deferred
|
* @name Deferred
|
*/
|
deferred = {
|
then: then, // DEPRECATED: use deferred.promise.then
|
resolve: promiseResolve,
|
reject: promiseReject,
|
// TODO: Consider renaming progress() to notify()
|
progress: promiseProgress,
|
|
promise: promise,
|
|
resolver: {
|
resolve: promiseResolve,
|
reject: promiseReject,
|
progress: promiseProgress
|
}
|
};
|
|
handlers = [];
|
progressHandlers = [];
|
|
/**
|
* Pre-resolution then() that adds the supplied callback, errback, and progback
|
* functions to the registered listeners
|
* @private
|
*
|
* @param {function?} [onFulfilled] resolution handler
|
* @param {function?} [onRejected] rejection handler
|
* @param {function?} [onProgress] progress handler
|
*/
|
_then = function(onFulfilled, onRejected, onProgress) {
|
// TODO: Promises/A+ check typeof onFulfilled, onRejected, onProgress
|
var deferred, progressHandler;
|
|
deferred = defer();
|
|
progressHandler = typeof onProgress === 'function'
|
? function(update) {
|
try {
|
// Allow progress handler to transform progress event
|
deferred.progress(onProgress(update));
|
} catch(e) {
|
// Use caught value as progress
|
deferred.progress(e);
|
}
|
}
|
: function(update) { deferred.progress(update); };
|
|
handlers.push(function(promise) {
|
promise.then(onFulfilled, onRejected)
|
.then(deferred.resolve, deferred.reject, progressHandler);
|
});
|
|
progressHandlers.push(progressHandler);
|
|
return deferred.promise;
|
};
|
|
/**
|
* Issue a progress event, notifying all progress listeners
|
* @private
|
* @param {*} update progress event payload to pass to all listeners
|
*/
|
_progress = function(update) {
|
processQueue(progressHandlers, update);
|
return update;
|
};
|
|
/**
|
* Transition from pre-resolution state to post-resolution state, notifying
|
* all listeners of the resolution or rejection
|
* @private
|
* @param {*} value the value of this deferred
|
*/
|
_resolve = function(value) {
|
value = resolve(value);
|
|
// Replace _then with one that directly notifies with the result.
|
_then = value.then;
|
// Replace _resolve so that this Deferred can only be resolved once
|
_resolve = resolve;
|
// Make _progress a noop, to disallow progress for the resolved promise.
|
_progress = noop;
|
|
// Notify handlers
|
processQueue(handlers, value);
|
|
// Free progressHandlers array since we'll never issue progress events
|
progressHandlers = handlers = undef;
|
|
return value;
|
};
|
|
return deferred;
|
|
/**
|
* Wrapper to allow _then to be replaced safely
|
* @param {function?} [onFulfilled] resolution handler
|
* @param {function?} [onRejected] rejection handler
|
* @param {function?} [onProgress] progress handler
|
* @returns {Promise} new promise
|
*/
|
function then(onFulfilled, onRejected, onProgress) {
|
// TODO: Promises/A+ check typeof onFulfilled, onRejected, onProgress
|
return _then(onFulfilled, onRejected, onProgress);
|
}
|
|
/**
|
* Wrapper to allow _resolve to be replaced
|
*/
|
function promiseResolve(val) {
|
return _resolve(val);
|
}
|
|
/**
|
* Wrapper to allow _reject to be replaced
|
*/
|
function promiseReject(err) {
|
return _resolve(rejected(err));
|
}
|
|
/**
|
* Wrapper to allow _progress to be replaced
|
*/
|
function promiseProgress(update) {
|
return _progress(update);
|
}
|
}
|
|
/**
|
* Determines if promiseOrValue is a promise or not. Uses the feature
|
* test from http://wiki.commonjs.org/wiki/Promises/A to determine if
|
* promiseOrValue is a promise.
|
*
|
* @param {*} promiseOrValue anything
|
* @returns {boolean} true if promiseOrValue is a {@link Promise}
|
*/
|
function isPromise(promiseOrValue) {
|
return promiseOrValue && typeof promiseOrValue.then === 'function';
|
}
|
|
/**
|
* Initiates a competitive race, returning a promise that will resolve when
|
* howMany of the supplied promisesOrValues have resolved, or will reject when
|
* it becomes impossible for howMany to resolve, for example, when
|
* (promisesOrValues.length - howMany) + 1 input promises reject.
|
*
|
* @param {Array} promisesOrValues array of anything, may contain a mix
|
* of promises and values
|
* @param howMany {number} number of promisesOrValues to resolve
|
* @param {function?} [onFulfilled] resolution handler
|
* @param {function?} [onRejected] rejection handler
|
* @param {function?} [onProgress] progress handler
|
* @returns {Promise} promise that will resolve to an array of howMany values that
|
* resolved first, or will reject with an array of (promisesOrValues.length - howMany) + 1
|
* rejection reasons.
|
*/
|
function some(promisesOrValues, howMany, onFulfilled, onRejected, onProgress) {
|
|
checkCallbacks(2, arguments);
|
|
return when(promisesOrValues, function(promisesOrValues) {
|
|
var toResolve, toReject, values, reasons, deferred, fulfillOne, rejectOne, progress, len, i;
|
|
len = promisesOrValues.length >>> 0;
|
|
toResolve = Math.max(0, Math.min(howMany, len));
|
values = [];
|
|
toReject = (len - toResolve) + 1;
|
reasons = [];
|
|
deferred = defer();
|
|
// No items in the input, resolve immediately
|
if (!toResolve) {
|
deferred.resolve(values);
|
|
} else {
|
progress = deferred.progress;
|
|
rejectOne = function(reason) {
|
reasons.push(reason);
|
if(!--toReject) {
|
fulfillOne = rejectOne = noop;
|
deferred.reject(reasons);
|
}
|
};
|
|
fulfillOne = function(val) {
|
// This orders the values based on promise resolution order
|
// Another strategy would be to use the original position of
|
// the corresponding promise.
|
values.push(val);
|
|
if (!--toResolve) {
|
fulfillOne = rejectOne = noop;
|
deferred.resolve(values);
|
}
|
};
|
|
for(i = 0; i < len; ++i) {
|
if(i in promisesOrValues) {
|
when(promisesOrValues[i], fulfiller, rejecter, progress);
|
}
|
}
|
}
|
|
return deferred.then(onFulfilled, onRejected, onProgress);
|
|
function rejecter(reason) {
|
rejectOne(reason);
|
}
|
|
function fulfiller(val) {
|
fulfillOne(val);
|
}
|
|
});
|
}
|
|
/**
|
* Initiates a competitive race, returning a promise that will resolve when
|
* any one of the supplied promisesOrValues has resolved or will reject when
|
* *all* promisesOrValues have rejected.
|
*
|
* @param {Array|Promise} promisesOrValues array of anything, may contain a mix
|
* of {@link Promise}s and values
|
* @param {function?} [onFulfilled] resolution handler
|
* @param {function?} [onRejected] rejection handler
|
* @param {function?} [onProgress] progress handler
|
* @returns {Promise} promise that will resolve to the value that resolved first, or
|
* will reject with an array of all rejected inputs.
|
*/
|
function any(promisesOrValues, onFulfilled, onRejected, onProgress) {
|
|
function unwrapSingleResult(val) {
|
return onFulfilled ? onFulfilled(val[0]) : val[0];
|
}
|
|
return some(promisesOrValues, 1, unwrapSingleResult, onRejected, onProgress);
|
}
|
|
/**
|
* Return a promise that will resolve only once all the supplied promisesOrValues
|
* have resolved. The resolution value of the returned promise will be an array
|
* containing the resolution values of each of the promisesOrValues.
|
* @memberOf when
|
*
|
* @param {Array|Promise} promisesOrValues array of anything, may contain a mix
|
* of {@link Promise}s and values
|
* @param {function?} [onFulfilled] resolution handler
|
* @param {function?} [onRejected] rejection handler
|
* @param {function?} [onProgress] progress handler
|
* @returns {Promise}
|
*/
|
function all(promisesOrValues, onFulfilled, onRejected, onProgress) {
|
checkCallbacks(1, arguments);
|
return map(promisesOrValues, identity).then(onFulfilled, onRejected, onProgress);
|
}
|
|
/**
|
* Joins multiple promises into a single returned promise.
|
* @returns {Promise} a promise that will fulfill when *all* the input promises
|
* have fulfilled, or will reject when *any one* of the input promises rejects.
|
*/
|
function join(/* ...promises */) {
|
return map(arguments, identity);
|
}
|
|
/**
|
* Traditional map function, similar to `Array.prototype.map()`, but allows
|
* input to contain {@link Promise}s and/or values, and mapFunc may return
|
* either a value or a {@link Promise}
|
*
|
* @param {Array|Promise} promise array of anything, may contain a mix
|
* of {@link Promise}s and values
|
* @param {function} mapFunc mapping function mapFunc(value) which may return
|
* either a {@link Promise} or value
|
* @returns {Promise} a {@link Promise} that will resolve to an array containing
|
* the mapped output values.
|
*/
|
function map(promise, mapFunc) {
|
return when(promise, function(array) {
|
var results, len, toResolve, resolve, i, d;
|
|
// Since we know the resulting length, we can preallocate the results
|
// array to avoid array expansions.
|
toResolve = len = array.length >>> 0;
|
results = [];
|
d = defer();
|
|
if(!toResolve) {
|
d.resolve(results);
|
} else {
|
|
resolve = function resolveOne(item, i) {
|
when(item, mapFunc).then(function(mapped) {
|
results[i] = mapped;
|
|
if(!--toResolve) {
|
d.resolve(results);
|
}
|
}, d.reject);
|
};
|
|
// Since mapFunc may be async, get all invocations of it into flight
|
for(i = 0; i < len; i++) {
|
if(i in array) {
|
resolve(array[i], i);
|
} else {
|
--toResolve;
|
}
|
}
|
|
}
|
|
return d.promise;
|
|
});
|
}
|
|
/**
|
* Traditional reduce function, similar to `Array.prototype.reduce()`, but
|
* input may contain promises and/or values, and reduceFunc
|
* may return either a value or a promise, *and* initialValue may
|
* be a promise for the starting value.
|
*
|
* @param {Array|Promise} promise array or promise for an array of anything,
|
* may contain a mix of promises and values.
|
* @param {function} reduceFunc reduce function reduce(currentValue, nextValue, index, total),
|
* where total is the total number of items being reduced, and will be the same
|
* in each call to reduceFunc.
|
* @returns {Promise} that will resolve to the final reduced value
|
*/
|
function reduce(promise, reduceFunc /*, initialValue */) {
|
var args = slice.call(arguments, 1);
|
|
return when(promise, function(array) {
|
var total;
|
|
total = array.length;
|
|
// Wrap the supplied reduceFunc with one that handles promises and then
|
// delegates to the supplied.
|
args[0] = function (current, val, i) {
|
return when(current, function (c) {
|
return when(val, function (value) {
|
return reduceFunc(c, value, i, total);
|
});
|
});
|
};
|
|
return reduceArray.apply(array, args);
|
});
|
}
|
|
/**
|
* Ensure that resolution of promiseOrValue will trigger resolver with the
|
* value or reason of promiseOrValue, or instead with resolveValue if it is provided.
|
*
|
* @param promiseOrValue
|
* @param {Object} resolver
|
* @param {function} resolver.resolve
|
* @param {function} resolver.reject
|
* @param {*} [resolveValue]
|
* @returns {Promise}
|
*/
|
function chain(promiseOrValue, resolver, resolveValue) {
|
var useResolveValue = arguments.length > 2;
|
|
return when(promiseOrValue,
|
function(val) {
|
val = useResolveValue ? resolveValue : val;
|
resolver.resolve(val);
|
return val;
|
},
|
function(reason) {
|
resolver.reject(reason);
|
return rejected(reason);
|
},
|
resolver.progress
|
);
|
}
|
|
//
|
// Utility functions
|
//
|
|
/**
|
* Apply all functions in queue to value
|
* @param {Array} queue array of functions to execute
|
* @param {*} value argument passed to each function
|
*/
|
function processQueue(queue, value) {
|
var handler, i = 0;
|
|
while (handler = queue[i++]) {
|
handler(value);
|
}
|
}
|
|
/**
|
* Helper that checks arrayOfCallbacks to ensure that each element is either
|
* a function, or null or undefined.
|
* @private
|
* @param {number} start index at which to start checking items in arrayOfCallbacks
|
* @param {Array} arrayOfCallbacks array to check
|
* @throws {Error} if any element of arrayOfCallbacks is something other than
|
* a functions, null, or undefined.
|
*/
|
function checkCallbacks(start, arrayOfCallbacks) {
|
// TODO: Promises/A+ update type checking and docs
|
var arg, i = arrayOfCallbacks.length;
|
|
while(i > start) {
|
arg = arrayOfCallbacks[--i];
|
|
if (arg != null && typeof arg != 'function') {
|
throw new Error('arg '+i+' must be a function');
|
}
|
}
|
}
|
|
/**
|
* No-Op function used in method replacement
|
* @private
|
*/
|
function noop() {}
|
|
slice = [].slice;
|
|
// ES5 reduce implementation if native not available
|
// See: http://es5.github.com/#x15.4.4.21 as there are many
|
// specifics and edge cases.
|
reduceArray = [].reduce ||
|
function(reduceFunc /*, initialValue */) {
|
/*jshint maxcomplexity: 7*/
|
|
// ES5 dictates that reduce.length === 1
|
|
// This implementation deviates from ES5 spec in the following ways:
|
// 1. It does not check if reduceFunc is a Callable
|
|
var arr, args, reduced, len, i;
|
|
i = 0;
|
// This generates a jshint warning, despite being valid
|
// "Missing 'new' prefix when invoking a constructor."
|
// See https://github.com/jshint/jshint/issues/392
|
arr = Object(this);
|
len = arr.length >>> 0;
|
args = arguments;
|
|
// If no initialValue, use first item of array (we know length !== 0 here)
|
// and adjust i to start at second item
|
if(args.length <= 1) {
|
// Skip to the first real element in the array
|
for(;;) {
|
if(i in arr) {
|
reduced = arr[i++];
|
break;
|
}
|
|
// If we reached the end of the array without finding any real
|
// elements, it's a TypeError
|
if(++i >= len) {
|
throw new TypeError();
|
}
|
}
|
} else {
|
// If initialValue provided, use it
|
reduced = args[1];
|
}
|
|
// Do the actual reduce
|
for(;i < len; ++i) {
|
// Skip holes
|
if(i in arr) {
|
reduced = reduceFunc(reduced, arr[i], i, arr);
|
}
|
}
|
|
return reduced;
|
};
|
|
function identity(x) {
|
return x;
|
}
|
|
return when;
|
});
|
})(typeof define == 'function' && define.amd
|
? define
|
: function (factory) { typeof exports === 'object'
|
? (module.exports = factory())
|
: (this.when = factory());
|
}
|
// Boilerplate for AMD, Node, and browser global
|
);
|
|
},{}],180:[function(require,module,exports){
|
(function (global){
|
|
var g = typeof window != "undefined" ? window : global;
|
if (typeof g.Cesium == 'undefined') {
|
g.Cesium = require('./cesium-core');
|
}
|
g.Cesium.VectorTileImageryProvider = require('./VectorTileImageryProvider');
|
g.Cesium.proj4=require('proj4');
|
module.exports = g.Cesium;
|
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
|
|
},{"./VectorTileImageryProvider":123,"./cesium-core":124,"proj4":82}],181:[function(require,module,exports){
|
|
var turf = require('@turf/helpers');
|
turf = Object.assign(turf, {
|
bbox: require('@turf/bbox').default,
|
bboxPolygon: require('@turf/bbox-polygon').default,
|
bboxClip: require('@turf/bbox-clip').default,
|
polygonToLine: require('@turf/polygon-to-line').default,
|
pointToLineDistance: require('@turf/point-to-line-distance').default,
|
booleanPointInPolygon: require('@turf/boolean-point-in-polygon').default,
|
featureEach: function (geojson, callback) {
|
if (geojson.type === 'Feature') {
|
callback(geojson, 0);
|
} else if (geojson.type === 'FeatureCollection') {
|
for (var i = 0; i < geojson.features.length; i++) {
|
var feature = geojson.features[i];
|
if (!feature) continue;
|
if (callback(feature, i) === false) break;
|
}
|
}
|
},
|
featureCollection: function (features) {
|
return {
|
type: 'FeatureCollection',
|
features: features
|
}
|
},
|
simplify: require('@turf/simplify').default,
|
polygonToLineString: require('@turf/polygon-to-line').default,
|
center: require('@turf/center').default,
|
centerOfMass: require('@turf/center-of-mass').default,
|
centroid: require('@turf/centroid').default,
|
lineEquals: function (coords1, coords2) {
|
var equals = coords1.length == coords2.length;
|
if (equals) {
|
for (var i = 0; i < coords1.length; i++) {
|
if (coords1[i][0] != coords2[i][0]
|
|| coords1[i][1] != coords2[i][1]) {
|
equals = false
|
break;
|
}
|
}
|
}
|
return equals;
|
},
|
polygonEquals: function (ply1, ply2) {
|
var lines1 = turf.getCoords(ply1);
|
var lines2 = turf.getCoords(ply2);
|
var equals = lines1.length == lines2.length
|
if (equals) {
|
|
for (var i = 0; i < lines1.length; i++) {
|
equals = turf.lineEquals(lines1[i], lines2[i]);
|
if (!equals) {
|
break;
|
}
|
}
|
}
|
return equals;
|
|
},
|
removeDuplicate: function (geoJSON) {
|
var fcs = [];
|
turf.featureEach(geoJSON, function (fc) {
|
var geometry = fc.geometry;
|
if (!geometry) return;
|
|
if (geometry.type == "Polygon") {
|
var contains = false;
|
for (var i = 0; i < fcs.length; i++) {
|
if (turf.polygonEquals(fc, fcs[i])) {
|
contains = true;
|
break;
|
}
|
}
|
if (!contains) {
|
fcs.push(fc);
|
}
|
}
|
else {
|
fcs.push(fc);
|
}
|
});
|
|
fcs = turf.featureCollection(fcs);
|
|
return fcs;
|
},
|
within: require('@turf/within')
|
})
|
turf = Object.assign(turf, require('@turf/invariant'))
|
turf.distance = require('@turf/distance').default
|
|
turf.pointToPolygonDistance = function (pt, polygon, options) {
|
|
var line = turf.polygonToLine(polygon);
|
if (line.type == 'Feature') {
|
if (line.geometry.type == 'LineString') {
|
return turf.pointToLineDistance(pt, line, options)
|
} else {
|
return turf.pointToMultiLineDistance(pt, line, options)
|
}
|
} else if (line.type == 'FeatureCollection') {
|
var dist = Number.MAX_VALUE;
|
var fcs = line;
|
turf.featureEach(fcs, function (fc) {
|
var geometry = fc.geometry;
|
if (!geometry) return;
|
if (geometry.type == 'LineString') {
|
dist = Math.min(turf.pointToLineDistance(pt, line, options), dist);
|
} else {
|
dist = Math.min(turf.pointToMultiLineDistance(pt, line, options), dist);
|
}
|
})
|
if (dist == Number.MAX_VALUE) {
|
return undefined
|
}
|
return dist;
|
}
|
}
|
|
turf.pointToMultiPolygonDistance = function (pt, multiPolygon, options) {
|
var coordinates = turf.getCoords(multiPolygon);
|
var lineString = null;
|
var dist = Number.MAX_VALUE;
|
coordinates.forEach(function (polygonCoords) {
|
polygon = turf.polygon(polygonCoords)
|
var timepDist = turf.pointToPolygonDistance(pt, polygon, options);
|
dist = Math.min(timepDist, dist);
|
})
|
coordinates = [];
|
if (dist == Number.MAX_VALUE) {
|
return undefined
|
}
|
|
return dist;
|
}
|
|
turf.pointToMultiLineDistance = function (pt, multiLineString, options) {
|
|
var coordinates = turf.getCoords(multiLineString);
|
var lineString = null;
|
var dist = Number.MAX_VALUE;
|
coordinates.forEach(function (lineCoords) {
|
lineString = turf.lineString(lineCoords)
|
var timepDist = turf.pointToLineDistance(pt, lineString, options);
|
dist = Math.min(timepDist, dist);
|
})
|
coordinates = [];
|
if (dist == Number.MAX_VALUE) {
|
return undefined
|
}
|
|
return dist;
|
}
|
|
/**
|
* @param {Feature<Point>}pt
|
* @param {Feature}fc
|
* @param {Object}options
|
* @param {String}options.units
|
* @return {Number|undefined}
|
*/
|
turf.pointToFeatureDistance = function (pt, fc, options) {
|
var dist = undefined;
|
switch (fc.geometry.type) {
|
case 'Point':
|
dist = turf.distance(pt, fc, options);
|
break;
|
case 'MultiPoint':
|
var coordinates = turf.getCoords(fc);
|
var pts = []
|
coordinates.forEach(function (coord) {
|
pts.push(turf.point(coord))
|
})
|
pts = turf.featureCollection(pts);
|
nearest = turf.nearestPoint(pt, pts);
|
pts = [];
|
dist = nearest.properties.distanceToPoint
|
break;
|
case "LineString":
|
dist = turf.pointToLineDistance(pt, fc, options)
|
break;
|
case "MultiLineString":
|
dist = turf.pointToMultiLineDistance(pt, fc, options)
|
break;
|
case "Polygon":
|
dist = turf.pointToPolygonDistance(pt, fc, options)
|
break;
|
case "MultiPolygon":
|
dist = turf.pointToMultiPolygonDistance(pt, fc, options)
|
break;
|
}
|
return dist;
|
}
|
|
module.exports = turf;
|
},{"@turf/bbox":4,"@turf/bbox-clip":1,"@turf/bbox-polygon":3,"@turf/boolean-point-in-polygon":5,"@turf/center":7,"@turf/center-of-mass":6,"@turf/centroid":8,"@turf/distance":13,"@turf/helpers":14,"@turf/invariant":17,"@turf/point-to-line-distance":19,"@turf/polygon-to-line":20,"@turf/simplify":22,"@turf/within":26}],182:[function(require,module,exports){
|
|
/**
|
*@class
|
*@memberof Cesium
|
*/
|
function Path() { }
|
/**
|
*
|
*获取文件扩展名(后缀)
|
*@param {String}fname 文件名
|
*/
|
Path.GetExtension = function (fname) {
|
var start = fname.lastIndexOf(".");
|
if (start >= 0) {
|
return fname.substring(start, fname.length);
|
}
|
return "";
|
}
|
|
/**
|
*
|
*获取文件扩展名(后缀)
|
*@param {String}fname 文件名
|
*/
|
Path.GetFileName = function (fname) {
|
var start = fname.lastIndexOf("/");
|
if (start < 0) {
|
return fname;
|
}
|
return fname.substring(start + 1, fname.length);
|
}
|
/**
|
*
|
*获取文件夹
|
*@param {String}fname 文件名
|
*/
|
Path.GetDirectoryName = function (fname) {
|
var start = fname.lastIndexOf("/");
|
if (start < 0) {
|
return "";
|
}
|
return fname.substring(0, start);
|
}
|
/**
|
*
|
*获取文件夹
|
*@param {String}fname 文件名
|
*/
|
Path.Combine = function (dir, fname) {
|
return dir + fname;
|
}
|
Path.ChangeExtension = function (fname, newExt) {
|
return fname.replace(Path.GetExtension(fname), newExt);
|
}
|
|
module.exports = Path;
|
},{}],183:[function(require,module,exports){
|
|
function Rect(x, y, w, h) {
|
return { x: x, y: y, width: w, height: h };
|
}
|
|
var Point = function (x, y) {
|
return { x: x, y: y };
|
}
|
/**
|
*
|
* @memberof Cesium.Util
|
* @method
|
* @name drawRoundedRect
|
* @param {Object} rect
|
* @param {Number} radius
|
* @param {CanvasRenderingContext2D} context2d
|
*/
|
function drawRoundedRect(rect, r, ctx) {
|
var ptA = Point(rect.x + r, rect.y);
|
var ptB = Point(rect.x + rect.width, rect.y);
|
var ptC = Point(rect.x + rect.width, rect.y + rect.height);
|
var ptD = Point(rect.x, rect.y + rect.height);
|
var ptE = Point(rect.x, rect.y);
|
|
ctx.beginPath();
|
|
ctx.moveTo(ptA.x, ptA.y);
|
ctx.arcTo(ptB.x, ptB.y, ptC.x, ptC.y, r);
|
ctx.arcTo(ptC.x, ptC.y, ptD.x, ptD.y, r);
|
ctx.arcTo(ptD.x, ptD.y, ptE.x, ptE.y, r);
|
ctx.arcTo(ptE.x, ptE.y, ptA.x, ptA.y, r);
|
|
|
ctx.fill();
|
ctx.stroke();
|
}
|
|
module.exports = drawRoundedRect;
|
},{}],184:[function(require,module,exports){
|
|
var drawRoundedRect = require('./drawRoundedRect');
|
var writeTextToCanvas=require('../cesium/Core/writeTextToCanvas');
|
|
/**
|
* Writes the given text into a new canvas. The canvas will be sized to fit the text.
|
* If text is blank, returns undefined.
|
* - 依赖Cesium.writeTextToCanvas
|
* @memberof Cesium.Util
|
* @method
|
* @name drawText
|
* @param {String} text The text to write.
|
* @param {Object} [options] Object with the following properties:
|
* @param {String} [options.font='10px sans-serif'] The CSS font to use.
|
* @param {String} [options.textBaseline='bottom'] The baseline of the text.
|
* @param {Boolean} [options.fill=true] Whether to fill the text.
|
* @param {Boolean} [options.stroke=false] Whether to stroke the text.
|
* @param {Color} [options.fillColor=Cesium.Color.WHITE] The fill color.
|
* @param {Color} [options.strokeColor=Cesium.Color.BLACK] The stroke color.
|
* @param {Number} [options.strokeWidth=1] The stroke width.
|
* @param {Color} [options.backgroundColor=Cesium.Color.TRANSPARENT] The background color of the canvas.
|
* @param {Number} [options.padding=0] The pixel size of the padding to add around the text.
|
* @returns {Canvas} A new canvas with the given text drawn into it. The dimensions object
|
* from measureText will also be added to the returned canvas. If text is
|
* blank, returns undefined.
|
*@example
|
var opts={
|
font:'10px sans-serif',
|
textBaseline:'bottom',
|
fill:true,
|
stroke:false,
|
strokeWidth:1,
|
fillColor:Cesium.Color.WHITE,
|
strokeColor:Cesium.Color.BLACK,
|
backgroundColor:Cesium.Color.TRANSPARENT,
|
padding:0
|
};
|
var textCanvas=drawText('hello world',opts)
|
*
|
*/
|
function drawText(text, options) {
|
options = options ? options : {
|
font: "20px sans-serif"
|
};
|
var backcolor = options.backgroundColor;
|
var padding = options.padding ? options.padding : 0;
|
delete options.backgroundColor;
|
delete options.padding;
|
|
var lines = text.split(/[\r]?\n+/);
|
var lineImgs = [];
|
var w = 0, h = 0;
|
for (var i = 0; i < lines.length; i++) {
|
var tempCv = writeTextToCanvas(lines[i], options)
|
if (tempCv) {
|
lineImgs.push(tempCv);
|
h += tempCv.height;
|
w = Math.max(w, tempCv.width);
|
}
|
}
|
options.backgroundColor = backcolor;
|
options.padding = padding;
|
|
var cv = options.canvas;
|
if (!cv) {
|
w += padding * 2;
|
h += padding * 2.25;
|
cv = document.createElement("canvas");
|
cv.width = w;
|
cv.height = h;
|
}
|
|
var ctx = cv.getContext("2d");
|
if (backcolor) {
|
ctx.fillStyle = backcolor.toCssColorString();
|
} else {
|
ctx.fillStyle = undefined;
|
}
|
|
if (options.border) {
|
ctx.lineWidth = options.borderWidth;
|
ctx.strokeStyle = options.borderColor.toCssColorString();
|
}
|
|
if (!options.borderRadius) {
|
if (backcolor) {
|
ctx.fillRect(0, 0, cv.width, cv.height);
|
}
|
|
if (options.border) {
|
ctx.strokeRect(0, 0, cv.width, cv.height);
|
}
|
} else {
|
drawRoundedRect({
|
x: 0, y: 0, width: cv.width, height: cv.height
|
}, options.borderRadius, ctx);
|
}
|
|
delete ctx.strokeStyle;
|
delete ctx.fillStyle;
|
var y = 0;
|
for (var i = 0; i < lineImgs.length; i++) {
|
ctx.drawImage(lineImgs[i], 0 + padding, y + padding);
|
y += lineImgs[i].height;
|
}
|
return cv;
|
}
|
|
module.exports = drawText;
|
},{"../cesium/Core/writeTextToCanvas":177,"./drawRoundedRect":183}],185:[function(require,module,exports){
|
var when = require('when');
|
|
function readAsArrayBuffer(file) {
|
var df = when.defer();
|
var fr = new FileReader();
|
fr.onload = function (e) {
|
df.resolve(e.target.result);
|
}
|
fr.onprogress = function (e) {
|
if (df.progress) df.progress(e.target.result);
|
}
|
fr.onerror = function (e) {
|
df.reject(e.error);
|
}
|
fr.readAsArrayBuffer(file);
|
return df.promise;
|
}
|
module.exports = readAsArrayBuffer;
|
},{"when":118}],186:[function(require,module,exports){
|
var when = require('when');
|
function readAsText(file) {
|
var df = when.defer();
|
var fr = new FileReader();
|
fr.onload = function (e) {
|
df.resolve(e.target.result);
|
}
|
fr.onprogress = function (e) {
|
if (df.progress) df.progress(e.target.result);
|
}
|
fr.onerror = function (e) {
|
df.reject(e.error);
|
}
|
fr.readAsText(file);
|
return df.promise;
|
}
|
module.exports = readAsText;
|
},{"when":118}]},{},[180])(180)
|
});
|